mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-19 11:03:41 +00:00
Merge branch 'built-in-copy-slash-command'
This commit is contained in:
commit
6a4a2fdfe9
2 changed files with 82 additions and 0 deletions
28
packages/coding-agent/src/clipboard.ts
Normal file
28
packages/coding-agent/src/clipboard.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
import { platform } from "os";
|
||||||
|
|
||||||
|
export function copyToClipboard(text: string): void {
|
||||||
|
const p = platform();
|
||||||
|
const options = { input: text, timeout: 5000 };
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (p === "darwin") {
|
||||||
|
execSync("pbcopy", options);
|
||||||
|
} else if (p === "win32") {
|
||||||
|
execSync("clip", options);
|
||||||
|
} else {
|
||||||
|
// Linux - try xclip first, fall back to xsel
|
||||||
|
try {
|
||||||
|
execSync("xclip -selection clipboard", options);
|
||||||
|
} catch {
|
||||||
|
execSync("xsel --clipboard --input", options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const msg = error instanceof Error ? error.message : String(error);
|
||||||
|
if (p === "linux") {
|
||||||
|
throw new Error(`Failed to copy to clipboard. Install xclip or xsel: ${msg}`);
|
||||||
|
}
|
||||||
|
throw new Error(`Failed to copy to clipboard: ${msg}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ import {
|
||||||
} from "@mariozechner/pi-tui";
|
} from "@mariozechner/pi-tui";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
import { getChangelogPath, parseChangelog } from "../changelog.js";
|
import { getChangelogPath, parseChangelog } from "../changelog.js";
|
||||||
|
import { copyToClipboard } from "../clipboard.js";
|
||||||
import { calculateContextTokens, compact, shouldCompact } from "../compaction.js";
|
import { calculateContextTokens, compact, shouldCompact } from "../compaction.js";
|
||||||
import { APP_NAME, getDebugLogPath, getModelsPath, getOAuthPath } from "../config.js";
|
import { APP_NAME, getDebugLogPath, getModelsPath, getOAuthPath } from "../config.js";
|
||||||
import { exportSessionToHtml } from "../export-html.js";
|
import { exportSessionToHtml } from "../export-html.js";
|
||||||
|
|
@ -155,6 +156,11 @@ export class TuiRenderer {
|
||||||
description: "Export session to HTML file",
|
description: "Export session to HTML file",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const copyCommand: SlashCommand = {
|
||||||
|
name: "copy",
|
||||||
|
description: "Copy last agent message to clipboard",
|
||||||
|
};
|
||||||
|
|
||||||
const sessionCommand: SlashCommand = {
|
const sessionCommand: SlashCommand = {
|
||||||
name: "session",
|
name: "session",
|
||||||
description: "Show session info and stats",
|
description: "Show session info and stats",
|
||||||
|
|
@ -221,6 +227,7 @@ export class TuiRenderer {
|
||||||
modelCommand,
|
modelCommand,
|
||||||
themeCommand,
|
themeCommand,
|
||||||
exportCommand,
|
exportCommand,
|
||||||
|
copyCommand,
|
||||||
sessionCommand,
|
sessionCommand,
|
||||||
changelogCommand,
|
changelogCommand,
|
||||||
branchCommand,
|
branchCommand,
|
||||||
|
|
@ -383,6 +390,13 @@ export class TuiRenderer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for /copy command
|
||||||
|
if (text === "/copy") {
|
||||||
|
this.handleCopyCommand();
|
||||||
|
this.editor.setText("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for /session command
|
// Check for /session command
|
||||||
if (text === "/session") {
|
if (text === "/session") {
|
||||||
this.handleSessionCommand();
|
this.handleSessionCommand();
|
||||||
|
|
@ -1573,6 +1587,46 @@ export class TuiRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleCopyCommand(): void {
|
||||||
|
// Find the last assistant message
|
||||||
|
const lastAssistantMessage = this.agent.state.messages
|
||||||
|
.slice()
|
||||||
|
.reverse()
|
||||||
|
.find((m) => m.role === "assistant");
|
||||||
|
|
||||||
|
if (!lastAssistantMessage) {
|
||||||
|
this.showError("No agent messages to copy yet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract raw text content from all text blocks
|
||||||
|
let textContent = "";
|
||||||
|
|
||||||
|
for (const content of lastAssistantMessage.content) {
|
||||||
|
if (content.type === "text") {
|
||||||
|
textContent += content.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!textContent.trim()) {
|
||||||
|
this.showError("Last agent message contains no text content.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy to clipboard using cross-platform compatible method
|
||||||
|
try {
|
||||||
|
copyToClipboard(textContent);
|
||||||
|
} catch (error) {
|
||||||
|
this.showError(error instanceof Error ? error.message : String(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show confirmation message
|
||||||
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
|
this.chatContainer.addChild(new Text(theme.fg("dim", "Copied last agent message to clipboard"), 1, 0));
|
||||||
|
this.ui.requestRender();
|
||||||
|
}
|
||||||
|
|
||||||
private handleSessionCommand(): void {
|
private handleSessionCommand(): void {
|
||||||
// Get session info
|
// Get session info
|
||||||
const sessionFile = this.sessionManager.getSessionFile();
|
const sessionFile = this.sessionManager.getSessionFile();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue