mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 20:03:05 +00:00
add cross-platform clipboard support and /copy command
This commit is contained in:
parent
db6d655ee9
commit
667e7aa730
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";
|
||||
import { exec } from "child_process";
|
||||
import { getChangelogPath, parseChangelog } from "../changelog.js";
|
||||
import { copyToClipboard } from "../clipboard.js";
|
||||
import { calculateContextTokens, compact, shouldCompact } from "../compaction.js";
|
||||
import { APP_NAME, getDebugLogPath, getModelsPath, getOAuthPath } from "../config.js";
|
||||
import { exportSessionToHtml } from "../export-html.js";
|
||||
|
|
@ -155,6 +156,11 @@ export class TuiRenderer {
|
|||
description: "Export session to HTML file",
|
||||
};
|
||||
|
||||
const copyCommand: SlashCommand = {
|
||||
name: "copy",
|
||||
description: "Copy last agent message to clipboard",
|
||||
};
|
||||
|
||||
const sessionCommand: SlashCommand = {
|
||||
name: "session",
|
||||
description: "Show session info and stats",
|
||||
|
|
@ -221,6 +227,7 @@ export class TuiRenderer {
|
|||
modelCommand,
|
||||
themeCommand,
|
||||
exportCommand,
|
||||
copyCommand,
|
||||
sessionCommand,
|
||||
changelogCommand,
|
||||
branchCommand,
|
||||
|
|
@ -383,6 +390,13 @@ export class TuiRenderer {
|
|||
return;
|
||||
}
|
||||
|
||||
// Check for /copy command
|
||||
if (text === "/copy") {
|
||||
this.handleCopyCommand();
|
||||
this.editor.setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for /session command
|
||||
if (text === "/session") {
|
||||
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 {
|
||||
// Get session info
|
||||
const sessionFile = this.sessionManager.getSessionFile();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue