mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 17:00:45 +00:00
Add Alt+Up hotkey to restore queued messages (#604)
This commit is contained in:
parent
60f5a03576
commit
902d5d3d05
2 changed files with 42 additions and 10 deletions
|
|
@ -26,7 +26,8 @@ export type AppAction =
|
||||||
| "expandTools"
|
| "expandTools"
|
||||||
| "toggleThinking"
|
| "toggleThinking"
|
||||||
| "externalEditor"
|
| "externalEditor"
|
||||||
| "followUp";
|
| "followUp"
|
||||||
|
| "dequeue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All configurable actions.
|
* All configurable actions.
|
||||||
|
|
@ -56,6 +57,7 @@ export const DEFAULT_APP_KEYBINDINGS: Record<AppAction, KeyId | KeyId[]> = {
|
||||||
toggleThinking: "ctrl+t",
|
toggleThinking: "ctrl+t",
|
||||||
externalEditor: "ctrl+g",
|
externalEditor: "ctrl+g",
|
||||||
followUp: "alt+enter",
|
followUp: "alt+enter",
|
||||||
|
dequeue: "alt+up",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -80,6 +82,7 @@ const APP_ACTIONS: AppAction[] = [
|
||||||
"toggleThinking",
|
"toggleThinking",
|
||||||
"externalEditor",
|
"externalEditor",
|
||||||
"followUp",
|
"followUp",
|
||||||
|
"dequeue",
|
||||||
];
|
];
|
||||||
|
|
||||||
function isAppAction(action: string): action is AppAction {
|
function isAppAction(action: string): action is AppAction {
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,7 @@ export class InteractiveMode {
|
||||||
const toggleThinking = formatStartupKey(kb.getKeys("toggleThinking"));
|
const toggleThinking = formatStartupKey(kb.getKeys("toggleThinking"));
|
||||||
const externalEditor = formatStartupKey(kb.getKeys("externalEditor"));
|
const externalEditor = formatStartupKey(kb.getKeys("externalEditor"));
|
||||||
const followUp = formatStartupKey(kb.getKeys("followUp"));
|
const followUp = formatStartupKey(kb.getKeys("followUp"));
|
||||||
|
const dequeue = formatStartupKey(kb.getKeys("dequeue"));
|
||||||
|
|
||||||
const instructions =
|
const instructions =
|
||||||
theme.fg("dim", interrupt) +
|
theme.fg("dim", interrupt) +
|
||||||
|
|
@ -361,6 +362,9 @@ export class InteractiveMode {
|
||||||
theme.fg("dim", followUp) +
|
theme.fg("dim", followUp) +
|
||||||
theme.fg("muted", " to queue follow-up") +
|
theme.fg("muted", " to queue follow-up") +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
theme.fg("dim", dequeue) +
|
||||||
|
theme.fg("muted", " to restore queued messages") +
|
||||||
|
"\n" +
|
||||||
theme.fg("dim", "ctrl+v") +
|
theme.fg("dim", "ctrl+v") +
|
||||||
theme.fg("muted", " to paste image") +
|
theme.fg("muted", " to paste image") +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
|
@ -1274,15 +1278,7 @@ export class InteractiveMode {
|
||||||
// so they work correctly regardless of which editor is active
|
// so they work correctly regardless of which editor is active
|
||||||
this.defaultEditor.onEscape = () => {
|
this.defaultEditor.onEscape = () => {
|
||||||
if (this.loadingAnimation) {
|
if (this.loadingAnimation) {
|
||||||
// Abort and restore queued messages to editor
|
this.restoreQueuedMessagesToEditor({ abort: true });
|
||||||
const { steering, followUp } = this.session.clearQueue();
|
|
||||||
const allQueued = [...steering, ...followUp];
|
|
||||||
const queuedText = allQueued.join("\n\n");
|
|
||||||
const currentText = this.editor.getText();
|
|
||||||
const combinedText = [queuedText, currentText].filter((t) => t.trim()).join("\n\n");
|
|
||||||
this.editor.setText(combinedText);
|
|
||||||
this.updatePendingMessagesDisplay();
|
|
||||||
this.agent.abort();
|
|
||||||
} else if (this.session.isBashRunning) {
|
} else if (this.session.isBashRunning) {
|
||||||
this.session.abortBash();
|
this.session.abortBash();
|
||||||
} else if (this.isBashMode) {
|
} else if (this.isBashMode) {
|
||||||
|
|
@ -1320,6 +1316,7 @@ export class InteractiveMode {
|
||||||
this.defaultEditor.onAction("toggleThinking", () => this.toggleThinkingBlockVisibility());
|
this.defaultEditor.onAction("toggleThinking", () => this.toggleThinkingBlockVisibility());
|
||||||
this.defaultEditor.onAction("externalEditor", () => this.openExternalEditor());
|
this.defaultEditor.onAction("externalEditor", () => this.openExternalEditor());
|
||||||
this.defaultEditor.onAction("followUp", () => this.handleFollowUp());
|
this.defaultEditor.onAction("followUp", () => this.handleFollowUp());
|
||||||
|
this.defaultEditor.onAction("dequeue", () => this.handleDequeue());
|
||||||
|
|
||||||
this.defaultEditor.onChange = (text: string) => {
|
this.defaultEditor.onChange = (text: string) => {
|
||||||
const wasBashMode = this.isBashMode;
|
const wasBashMode = this.isBashMode;
|
||||||
|
|
@ -2080,6 +2077,15 @@ export class InteractiveMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleDequeue(): void {
|
||||||
|
const restored = this.restoreQueuedMessagesToEditor();
|
||||||
|
if (restored === 0) {
|
||||||
|
this.showStatus("No queued messages to restore");
|
||||||
|
} else {
|
||||||
|
this.showStatus(`Restored ${restored} queued message${restored > 1 ? "s" : ""} to editor`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private updateEditorBorderColor(): void {
|
private updateEditorBorderColor(): void {
|
||||||
if (this.isBashMode) {
|
if (this.isBashMode) {
|
||||||
this.editor.borderColor = theme.getBashModeBorderColor();
|
this.editor.borderColor = theme.getBashModeBorderColor();
|
||||||
|
|
@ -2253,6 +2259,27 @@ export class InteractiveMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private restoreQueuedMessagesToEditor(options?: { abort?: boolean; currentText?: string }): number {
|
||||||
|
const { steering, followUp } = this.session.clearQueue();
|
||||||
|
const allQueued = [...steering, ...followUp];
|
||||||
|
if (allQueued.length === 0) {
|
||||||
|
this.updatePendingMessagesDisplay();
|
||||||
|
if (options?.abort) {
|
||||||
|
this.agent.abort();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const queuedText = allQueued.join("\n\n");
|
||||||
|
const currentText = options?.currentText ?? this.editor.getText();
|
||||||
|
const combinedText = [queuedText, currentText].filter((t) => t.trim()).join("\n\n");
|
||||||
|
this.editor.setText(combinedText);
|
||||||
|
this.updatePendingMessagesDisplay();
|
||||||
|
if (options?.abort) {
|
||||||
|
this.agent.abort();
|
||||||
|
}
|
||||||
|
return allQueued.length;
|
||||||
|
}
|
||||||
|
|
||||||
private queueCompactionMessage(text: string, mode: "steer" | "followUp"): void {
|
private queueCompactionMessage(text: string, mode: "steer" | "followUp"): void {
|
||||||
this.compactionQueuedMessages.push({ text, mode });
|
this.compactionQueuedMessages.push({ text, mode });
|
||||||
this.editor.addToHistory?.(text);
|
this.editor.addToHistory?.(text);
|
||||||
|
|
@ -3049,6 +3076,7 @@ export class InteractiveMode {
|
||||||
const toggleThinking = this.getAppKeyDisplay("toggleThinking");
|
const toggleThinking = this.getAppKeyDisplay("toggleThinking");
|
||||||
const externalEditor = this.getAppKeyDisplay("externalEditor");
|
const externalEditor = this.getAppKeyDisplay("externalEditor");
|
||||||
const followUp = this.getAppKeyDisplay("followUp");
|
const followUp = this.getAppKeyDisplay("followUp");
|
||||||
|
const dequeue = this.getAppKeyDisplay("dequeue");
|
||||||
|
|
||||||
let hotkeys = `
|
let hotkeys = `
|
||||||
**Navigation**
|
**Navigation**
|
||||||
|
|
@ -3082,6 +3110,7 @@ export class InteractiveMode {
|
||||||
| \`${toggleThinking}\` | Toggle thinking block visibility |
|
| \`${toggleThinking}\` | Toggle thinking block visibility |
|
||||||
| \`${externalEditor}\` | Edit message in external editor |
|
| \`${externalEditor}\` | Edit message in external editor |
|
||||||
| \`${followUp}\` | Queue follow-up message |
|
| \`${followUp}\` | Queue follow-up message |
|
||||||
|
| \`${dequeue}\` | Restore queued messages |
|
||||||
| \`Ctrl+V\` | Paste image from clipboard |
|
| \`Ctrl+V\` | Paste image from clipboard |
|
||||||
| \`/\` | Slash commands |
|
| \`/\` | Slash commands |
|
||||||
| \`!\` | Run bash command |
|
| \`!\` | Run bash command |
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue