@codex-infinity/pi-infinity 0.60.2 → 0.61.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +1 -0
- package/dist/bun/cli.js.map +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +2 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +50 -69
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.js +4 -8
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.css +43 -13
- package/dist/core/export-html/template.html +1 -0
- package/dist/core/export-html/template.js +107 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +4 -4
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +62 -56
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +4 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +9 -2
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +92 -20
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +268 -51
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +220 -143
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +29 -21
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -4
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.js +0 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.js +0 -37
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +5 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +8 -12
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.js +7 -16
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +3 -2
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts +6 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/core/tools/file-mutation-queue.js +37 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -0
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +6 -3
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +10 -5
- package/dist/main.js.map +1 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/armin.js +6 -10
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +0 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +8 -14
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -4
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +3 -5
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +3 -5
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +14 -23
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +0 -5
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +7 -14
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -6
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +6 -8
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +10 -15
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +7 -13
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +9 -16
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -3
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +3 -36
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +5 -44
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +9 -15
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +20 -28
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +8 -13
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +13 -17
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +65 -93
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +0 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +3 -5
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -2
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +7 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +57 -28
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +32 -46
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +9 -12
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +155 -165
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +49 -42
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/jsonl.js.map +1 -1
- package/dist/modes/rpc/rpc-client.js +6 -7
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +4 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/photon.js.map +1 -1
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/sleep.js.map +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/extensions.md +42 -5
- package/docs/keybindings.md +101 -112
- package/examples/extensions/antigravity-image-gen.ts +5 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/subagent/index.ts +7 -5
- package/examples/extensions/tool-override.ts +9 -7
- package/examples/extensions/truncated-tool.ts +6 -3
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -6,7 +6,7 @@ import * as crypto from "node:crypto";
|
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import { CombinedAutocompleteProvider, Container, fuzzyFilter, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, Text, TruncatedText, TUI, visibleWidth, } from "@mariozechner/pi-tui";
|
|
9
|
+
import { CombinedAutocompleteProvider, Container, fuzzyFilter, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@mariozechner/pi-tui";
|
|
10
10
|
import { spawn, spawnSync } from "child_process";
|
|
11
11
|
import { APP_NAME, getAgentDir, getAuthPath, getDebugLogPath, getShareViewerUrl, getUpdateInstruction, VERSION, } from "../../config.js";
|
|
12
12
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
@@ -35,7 +35,7 @@ import { ExtensionEditorComponent } from "./components/extension-editor.js";
|
|
|
35
35
|
import { ExtensionInputComponent } from "./components/extension-input.js";
|
|
36
36
|
import { ExtensionSelectorComponent } from "./components/extension-selector.js";
|
|
37
37
|
import { FooterComponent } from "./components/footer.js";
|
|
38
|
-
import {
|
|
38
|
+
import { keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
|
|
39
39
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
40
40
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
41
41
|
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
@@ -52,79 +52,6 @@ function isExpandable(obj) {
|
|
|
52
52
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
53
53
|
}
|
|
54
54
|
export class InteractiveMode {
|
|
55
|
-
options;
|
|
56
|
-
session;
|
|
57
|
-
ui;
|
|
58
|
-
chatContainer;
|
|
59
|
-
pendingMessagesContainer;
|
|
60
|
-
statusContainer;
|
|
61
|
-
defaultEditor;
|
|
62
|
-
editor;
|
|
63
|
-
autocompleteProvider;
|
|
64
|
-
fdPath;
|
|
65
|
-
editorContainer;
|
|
66
|
-
footer;
|
|
67
|
-
footerDataProvider;
|
|
68
|
-
keybindings;
|
|
69
|
-
version;
|
|
70
|
-
isInitialized = false;
|
|
71
|
-
onInputCallback;
|
|
72
|
-
loadingAnimation = undefined;
|
|
73
|
-
pendingWorkingMessage = undefined;
|
|
74
|
-
defaultWorkingMessage = "Working...";
|
|
75
|
-
lastSigintTime = 0;
|
|
76
|
-
lastEscapeTime = 0;
|
|
77
|
-
changelogMarkdown = undefined;
|
|
78
|
-
// Status line tracking (for mutating immediately-sequential status updates)
|
|
79
|
-
lastStatusSpacer = undefined;
|
|
80
|
-
lastStatusText = undefined;
|
|
81
|
-
// Streaming message tracking
|
|
82
|
-
streamingComponent = undefined;
|
|
83
|
-
streamingMessage = undefined;
|
|
84
|
-
// Tool execution tracking: toolCallId -> component
|
|
85
|
-
pendingTools = new Map();
|
|
86
|
-
// Tool output expansion state
|
|
87
|
-
toolOutputExpanded = false;
|
|
88
|
-
// Thinking block visibility state
|
|
89
|
-
hideThinkingBlock = false;
|
|
90
|
-
// Skill commands: command name -> skill file path
|
|
91
|
-
skillCommands = new Map();
|
|
92
|
-
// Agent subscription unsubscribe function
|
|
93
|
-
unsubscribe;
|
|
94
|
-
// Track if editor is in bash mode (text starts with !)
|
|
95
|
-
isBashMode = false;
|
|
96
|
-
// Track current bash execution component
|
|
97
|
-
bashComponent = undefined;
|
|
98
|
-
// Track pending bash components (shown in pending area, moved to chat on submit)
|
|
99
|
-
pendingBashComponents = [];
|
|
100
|
-
// Auto-compaction state
|
|
101
|
-
autoCompactionLoader = undefined;
|
|
102
|
-
autoCompactionEscapeHandler;
|
|
103
|
-
// Auto-retry state
|
|
104
|
-
retryLoader = undefined;
|
|
105
|
-
retryEscapeHandler;
|
|
106
|
-
// Messages queued while compaction is running
|
|
107
|
-
compactionQueuedMessages = [];
|
|
108
|
-
// Shutdown state
|
|
109
|
-
shutdownRequested = false;
|
|
110
|
-
// Extension UI state
|
|
111
|
-
extensionSelector = undefined;
|
|
112
|
-
extensionInput = undefined;
|
|
113
|
-
extensionEditor = undefined;
|
|
114
|
-
extensionTerminalInputUnsubscribers = new Set();
|
|
115
|
-
// Extension widgets (components rendered above/below the editor)
|
|
116
|
-
extensionWidgetsAbove = new Map();
|
|
117
|
-
extensionWidgetsBelow = new Map();
|
|
118
|
-
widgetContainerAbove;
|
|
119
|
-
widgetContainerBelow;
|
|
120
|
-
// Custom footer from extension (undefined = use built-in footer)
|
|
121
|
-
customFooter = undefined;
|
|
122
|
-
// Header container that holds the built-in or custom header
|
|
123
|
-
headerContainer;
|
|
124
|
-
// Built-in header (logo + keybinding hints + changelog)
|
|
125
|
-
builtInHeader = undefined;
|
|
126
|
-
// Custom header from extension (undefined = use built-in header)
|
|
127
|
-
customHeader = undefined;
|
|
128
55
|
// Convenience accessors
|
|
129
56
|
get agent() {
|
|
130
57
|
return this.session.agent;
|
|
@@ -137,6 +64,60 @@ export class InteractiveMode {
|
|
|
137
64
|
}
|
|
138
65
|
constructor(session, options = {}) {
|
|
139
66
|
this.options = options;
|
|
67
|
+
this.isInitialized = false;
|
|
68
|
+
this.loadingAnimation = undefined;
|
|
69
|
+
this.pendingWorkingMessage = undefined;
|
|
70
|
+
this.defaultWorkingMessage = "Working...";
|
|
71
|
+
this.lastSigintTime = 0;
|
|
72
|
+
this.lastEscapeTime = 0;
|
|
73
|
+
this.changelogMarkdown = undefined;
|
|
74
|
+
// Status line tracking (for mutating immediately-sequential status updates)
|
|
75
|
+
this.lastStatusSpacer = undefined;
|
|
76
|
+
this.lastStatusText = undefined;
|
|
77
|
+
// Streaming message tracking
|
|
78
|
+
this.streamingComponent = undefined;
|
|
79
|
+
this.streamingMessage = undefined;
|
|
80
|
+
// Tool execution tracking: toolCallId -> component
|
|
81
|
+
this.pendingTools = new Map();
|
|
82
|
+
// Tool output expansion state
|
|
83
|
+
this.toolOutputExpanded = false;
|
|
84
|
+
// Thinking block visibility state
|
|
85
|
+
this.hideThinkingBlock = false;
|
|
86
|
+
// Skill commands: command name -> skill file path
|
|
87
|
+
this.skillCommands = new Map();
|
|
88
|
+
// Track if editor is in bash mode (text starts with !)
|
|
89
|
+
this.isBashMode = false;
|
|
90
|
+
// Track current bash execution component
|
|
91
|
+
this.bashComponent = undefined;
|
|
92
|
+
// Track pending bash components (shown in pending area, moved to chat on submit)
|
|
93
|
+
this.pendingBashComponents = [];
|
|
94
|
+
// Auto-compaction state
|
|
95
|
+
this.autoCompactionLoader = undefined;
|
|
96
|
+
// Auto-retry state
|
|
97
|
+
this.retryLoader = undefined;
|
|
98
|
+
// Messages queued while compaction is running
|
|
99
|
+
this.compactionQueuedMessages = [];
|
|
100
|
+
// Shutdown state
|
|
101
|
+
this.shutdownRequested = false;
|
|
102
|
+
// Extension UI state
|
|
103
|
+
this.extensionSelector = undefined;
|
|
104
|
+
this.extensionInput = undefined;
|
|
105
|
+
this.extensionEditor = undefined;
|
|
106
|
+
this.extensionTerminalInputUnsubscribers = new Set();
|
|
107
|
+
// Extension widgets (components rendered above/below the editor)
|
|
108
|
+
this.extensionWidgetsAbove = new Map();
|
|
109
|
+
this.extensionWidgetsBelow = new Map();
|
|
110
|
+
// Custom footer from extension (undefined = use built-in footer)
|
|
111
|
+
this.customFooter = undefined;
|
|
112
|
+
// Built-in header (logo + keybinding hints + changelog)
|
|
113
|
+
this.builtInHeader = undefined;
|
|
114
|
+
// Custom header from extension (undefined = use built-in header)
|
|
115
|
+
this.customHeader = undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Gracefully shutdown the agent.
|
|
118
|
+
* Emits shutdown event to extensions, then exits.
|
|
119
|
+
*/
|
|
120
|
+
this.isShuttingDown = false;
|
|
140
121
|
this.session = session;
|
|
141
122
|
this.version = VERSION;
|
|
142
123
|
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
|
@@ -148,6 +129,7 @@ export class InteractiveMode {
|
|
|
148
129
|
this.widgetContainerAbove = new Container();
|
|
149
130
|
this.widgetContainerBelow = new Container();
|
|
150
131
|
this.keybindings = KeybindingsManager.create();
|
|
132
|
+
setKeybindings(this.keybindings);
|
|
151
133
|
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
152
134
|
const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
|
|
153
135
|
this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, {
|
|
@@ -242,27 +224,26 @@ export class InteractiveMode {
|
|
|
242
224
|
if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
|
|
243
225
|
const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
|
|
244
226
|
// Build startup instructions using keybinding hint helpers
|
|
245
|
-
const
|
|
246
|
-
const hint = (action, desc) => appKeyHint(kb, action, desc);
|
|
227
|
+
const hint = (keybinding, description) => keyHint(keybinding, description);
|
|
247
228
|
const instructions = [
|
|
248
|
-
hint("interrupt", "to interrupt"),
|
|
249
|
-
hint("clear", "to clear"),
|
|
250
|
-
rawKeyHint(`${
|
|
251
|
-
hint("exit", "to exit (empty)"),
|
|
252
|
-
hint("suspend", "to suspend"),
|
|
253
|
-
keyHint("deleteToLineEnd", "to delete to end"),
|
|
254
|
-
hint("
|
|
255
|
-
rawKeyHint(`${
|
|
256
|
-
hint("
|
|
257
|
-
hint("
|
|
258
|
-
hint("
|
|
259
|
-
hint("
|
|
229
|
+
hint("app.interrupt", "to interrupt"),
|
|
230
|
+
hint("app.clear", "to clear"),
|
|
231
|
+
rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
|
|
232
|
+
hint("app.exit", "to exit (empty)"),
|
|
233
|
+
hint("app.suspend", "to suspend"),
|
|
234
|
+
keyHint("tui.editor.deleteToLineEnd", "to delete to end"),
|
|
235
|
+
hint("app.thinking.cycle", "to cycle thinking level"),
|
|
236
|
+
rawKeyHint(`${keyText("app.model.cycleForward")}/${keyText("app.model.cycleBackward")}`, "to cycle models"),
|
|
237
|
+
hint("app.model.select", "to select model"),
|
|
238
|
+
hint("app.tools.expand", "to expand tools"),
|
|
239
|
+
hint("app.thinking.toggle", "to expand thinking"),
|
|
240
|
+
hint("app.editor.external", "for external editor"),
|
|
260
241
|
rawKeyHint("/", "for commands"),
|
|
261
242
|
rawKeyHint("!", "to run bash"),
|
|
262
243
|
rawKeyHint("!!", "to run bash (no context)"),
|
|
263
|
-
hint("followUp", "to queue follow-up"),
|
|
264
|
-
hint("dequeue", "to edit all queued messages"),
|
|
265
|
-
hint("pasteImage", "to paste image"),
|
|
244
|
+
hint("app.message.followUp", "to queue follow-up"),
|
|
245
|
+
hint("app.message.dequeue", "to edit all queued messages"),
|
|
246
|
+
hint("app.clipboard.pasteImage", "to paste image"),
|
|
266
247
|
rawKeyHint("drop files", "to attach"),
|
|
267
248
|
].join("\n");
|
|
268
249
|
this.builtInHeader = new Text(`${logo}\n${instructions}`, 1, 0);
|
|
@@ -1049,11 +1030,11 @@ export class InteractiveMode {
|
|
|
1049
1030
|
this.defaultEditor.onExtensionShortcut = undefined;
|
|
1050
1031
|
this.updateTerminalTitle();
|
|
1051
1032
|
if (this.loadingAnimation) {
|
|
1052
|
-
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${
|
|
1033
|
+
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1053
1034
|
}
|
|
1054
1035
|
}
|
|
1055
1036
|
// Maximum total widget lines to prevent viewport overflow
|
|
1056
|
-
static MAX_WIDGET_LINES = 10;
|
|
1037
|
+
static { this.MAX_WIDGET_LINES = 10; }
|
|
1057
1038
|
/**
|
|
1058
1039
|
* Render all extension widgets to the widget container.
|
|
1059
1040
|
*/
|
|
@@ -1172,7 +1153,7 @@ export class InteractiveMode {
|
|
|
1172
1153
|
this.loadingAnimation.setMessage(message);
|
|
1173
1154
|
}
|
|
1174
1155
|
else {
|
|
1175
|
-
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${
|
|
1156
|
+
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1176
1157
|
}
|
|
1177
1158
|
}
|
|
1178
1159
|
else {
|
|
@@ -1530,24 +1511,24 @@ export class InteractiveMode {
|
|
|
1530
1511
|
}
|
|
1531
1512
|
};
|
|
1532
1513
|
// Register app action handlers
|
|
1533
|
-
this.defaultEditor.onAction("clear", () => this.handleCtrlC());
|
|
1514
|
+
this.defaultEditor.onAction("app.clear", () => this.handleCtrlC());
|
|
1534
1515
|
this.defaultEditor.onCtrlD = () => this.handleCtrlD();
|
|
1535
|
-
this.defaultEditor.onAction("suspend", () => this.handleCtrlZ());
|
|
1536
|
-
this.defaultEditor.onAction("
|
|
1537
|
-
this.defaultEditor.onAction("
|
|
1538
|
-
this.defaultEditor.onAction("
|
|
1516
|
+
this.defaultEditor.onAction("app.suspend", () => this.handleCtrlZ());
|
|
1517
|
+
this.defaultEditor.onAction("app.thinking.cycle", () => this.cycleThinkingLevel());
|
|
1518
|
+
this.defaultEditor.onAction("app.model.cycleForward", () => this.cycleModel("forward"));
|
|
1519
|
+
this.defaultEditor.onAction("app.model.cycleBackward", () => this.cycleModel("backward"));
|
|
1539
1520
|
// Global debug handler on TUI (works regardless of focus)
|
|
1540
1521
|
this.ui.onDebug = () => this.handleDebugCommand();
|
|
1541
|
-
this.defaultEditor.onAction("
|
|
1542
|
-
this.defaultEditor.onAction("
|
|
1543
|
-
this.defaultEditor.onAction("
|
|
1544
|
-
this.defaultEditor.onAction("
|
|
1545
|
-
this.defaultEditor.onAction("followUp", () => this.handleFollowUp());
|
|
1546
|
-
this.defaultEditor.onAction("dequeue", () => this.handleDequeue());
|
|
1547
|
-
this.defaultEditor.onAction("
|
|
1548
|
-
this.defaultEditor.onAction("tree", () => this.showTreeSelector());
|
|
1549
|
-
this.defaultEditor.onAction("fork", () => this.showUserMessageSelector());
|
|
1550
|
-
this.defaultEditor.onAction("resume", () => this.showSessionSelector());
|
|
1522
|
+
this.defaultEditor.onAction("app.model.select", () => this.showModelSelector());
|
|
1523
|
+
this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
|
|
1524
|
+
this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
|
|
1525
|
+
this.defaultEditor.onAction("app.editor.external", () => this.openExternalEditor());
|
|
1526
|
+
this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
|
|
1527
|
+
this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
|
|
1528
|
+
this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
|
|
1529
|
+
this.defaultEditor.onAction("app.session.tree", () => this.showTreeSelector());
|
|
1530
|
+
this.defaultEditor.onAction("app.session.fork", () => this.showUserMessageSelector());
|
|
1531
|
+
this.defaultEditor.onAction("app.session.resume", () => this.showSessionSelector());
|
|
1551
1532
|
this.defaultEditor.onChange = (text) => {
|
|
1552
1533
|
const wasBashMode = this.isBashMode;
|
|
1553
1534
|
this.isBashMode = text.trimStart().startsWith("!");
|
|
@@ -1866,15 +1847,17 @@ export class InteractiveMode {
|
|
|
1866
1847
|
this.ui.requestRender();
|
|
1867
1848
|
break;
|
|
1868
1849
|
case "tool_execution_start": {
|
|
1869
|
-
|
|
1870
|
-
|
|
1850
|
+
let component = this.pendingTools.get(event.toolCallId);
|
|
1851
|
+
if (!component) {
|
|
1852
|
+
component = new ToolExecutionComponent(event.toolName, event.args, {
|
|
1871
1853
|
showImages: this.settingsManager.getShowImages(),
|
|
1872
1854
|
}, this.getRegisteredToolDefinition(event.toolName), this.ui);
|
|
1873
1855
|
component.setExpanded(this.toolOutputExpanded);
|
|
1874
1856
|
this.chatContainer.addChild(component);
|
|
1875
1857
|
this.pendingTools.set(event.toolCallId, component);
|
|
1876
|
-
this.ui.requestRender();
|
|
1877
1858
|
}
|
|
1859
|
+
component.markExecutionStarted();
|
|
1860
|
+
this.ui.requestRender();
|
|
1878
1861
|
break;
|
|
1879
1862
|
}
|
|
1880
1863
|
case "tool_execution_update": {
|
|
@@ -1919,7 +1902,7 @@ export class InteractiveMode {
|
|
|
1919
1902
|
// Show compacting indicator with reason
|
|
1920
1903
|
this.statusContainer.clear();
|
|
1921
1904
|
const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
|
|
1922
|
-
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting... (${
|
|
1905
|
+
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting... (${keyText("app.interrupt")} to cancel)`);
|
|
1923
1906
|
this.statusContainer.addChild(this.autoCompactionLoader);
|
|
1924
1907
|
this.ui.requestRender();
|
|
1925
1908
|
break;
|
|
@@ -1971,7 +1954,7 @@ export class InteractiveMode {
|
|
|
1971
1954
|
// Show retry indicator
|
|
1972
1955
|
this.statusContainer.clear();
|
|
1973
1956
|
const delaySeconds = Math.round(event.delayMs / 1000);
|
|
1974
|
-
this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${
|
|
1957
|
+
this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${keyText("app.interrupt")} to cancel)`);
|
|
1975
1958
|
this.statusContainer.addChild(this.retryLoader);
|
|
1976
1959
|
this.ui.requestRender();
|
|
1977
1960
|
break;
|
|
@@ -2206,11 +2189,6 @@ export class InteractiveMode {
|
|
|
2206
2189
|
// Only called when editor is empty (enforced by CustomEditor)
|
|
2207
2190
|
void this.shutdown();
|
|
2208
2191
|
}
|
|
2209
|
-
/**
|
|
2210
|
-
* Gracefully shutdown the agent.
|
|
2211
|
-
* Emits shutdown event to extensions, then exits.
|
|
2212
|
-
*/
|
|
2213
|
-
isShuttingDown = false;
|
|
2214
2192
|
async shutdown() {
|
|
2215
2193
|
if (this.isShuttingDown)
|
|
2216
2194
|
return;
|
|
@@ -2240,20 +2218,32 @@ export class InteractiveMode {
|
|
|
2240
2218
|
await this.shutdown();
|
|
2241
2219
|
}
|
|
2242
2220
|
handleCtrlZ() {
|
|
2221
|
+
// Keep the event loop alive while suspended. Without this, stopping the TUI
|
|
2222
|
+
// can leave Node with no ref'ed handles, causing the process to exit on fg
|
|
2223
|
+
// before the SIGCONT handler gets a chance to restore the terminal.
|
|
2224
|
+
const suspendKeepAlive = setInterval(() => { }, 2 ** 30);
|
|
2243
2225
|
// Ignore SIGINT while suspended so Ctrl+C in the terminal does not
|
|
2244
2226
|
// kill the backgrounded process. The handler is removed on resume.
|
|
2245
2227
|
const ignoreSigint = () => { };
|
|
2246
2228
|
process.on("SIGINT", ignoreSigint);
|
|
2247
2229
|
// Set up handler to restore TUI when resumed
|
|
2248
2230
|
process.once("SIGCONT", () => {
|
|
2231
|
+
clearInterval(suspendKeepAlive);
|
|
2249
2232
|
process.removeListener("SIGINT", ignoreSigint);
|
|
2250
2233
|
this.ui.start();
|
|
2251
2234
|
this.ui.requestRender(true);
|
|
2252
2235
|
});
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2236
|
+
try {
|
|
2237
|
+
// Stop the TUI (restore terminal to normal mode)
|
|
2238
|
+
this.ui.stop();
|
|
2239
|
+
// Send SIGTSTP to process group (pid=0 means all processes in group)
|
|
2240
|
+
process.kill(0, "SIGTSTP");
|
|
2241
|
+
}
|
|
2242
|
+
catch (error) {
|
|
2243
|
+
clearInterval(suspendKeepAlive);
|
|
2244
|
+
process.removeListener("SIGINT", ignoreSigint);
|
|
2245
|
+
throw error;
|
|
2246
|
+
}
|
|
2257
2247
|
}
|
|
2258
2248
|
async handleFollowUp() {
|
|
2259
2249
|
const text = (this.editor.getExpandedText?.() ?? this.editor.getText()).trim();
|
|
@@ -2486,7 +2476,7 @@ export class InteractiveMode {
|
|
|
2486
2476
|
const text = theme.fg("dim", `Follow-up: ${message}`);
|
|
2487
2477
|
this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));
|
|
2488
2478
|
}
|
|
2489
|
-
const dequeueHint = this.getAppKeyDisplay("dequeue");
|
|
2479
|
+
const dequeueHint = this.getAppKeyDisplay("app.message.dequeue");
|
|
2490
2480
|
const hintText = theme.fg("dim", `↳ ${dequeueHint} to edit all queued messages`);
|
|
2491
2481
|
this.pendingMessagesContainer.addChild(new TruncatedText(hintText, 1, 0));
|
|
2492
2482
|
}
|
|
@@ -3008,7 +2998,7 @@ export class InteractiveMode {
|
|
|
3008
2998
|
this.session.abortBranchSummary();
|
|
3009
2999
|
};
|
|
3010
3000
|
this.chatContainer.addChild(new Spacer(1));
|
|
3011
|
-
summaryLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `Summarizing branch... (${
|
|
3001
|
+
summaryLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `Summarizing branch... (${keyText("app.interrupt")} to cancel)`);
|
|
3012
3002
|
this.statusContainer.addChild(summaryLoader);
|
|
3013
3003
|
this.ui.requestRender();
|
|
3014
3004
|
}
|
|
@@ -3529,54 +3519,54 @@ export class InteractiveMode {
|
|
|
3529
3519
|
* Get capitalized display string for an app keybinding action.
|
|
3530
3520
|
*/
|
|
3531
3521
|
getAppKeyDisplay(action) {
|
|
3532
|
-
return this.capitalizeKey(
|
|
3522
|
+
return this.capitalizeKey(keyText(action));
|
|
3533
3523
|
}
|
|
3534
3524
|
/**
|
|
3535
3525
|
* Get capitalized display string for an editor keybinding action.
|
|
3536
3526
|
*/
|
|
3537
3527
|
getEditorKeyDisplay(action) {
|
|
3538
|
-
return this.capitalizeKey(
|
|
3528
|
+
return this.capitalizeKey(keyText(action));
|
|
3539
3529
|
}
|
|
3540
3530
|
handleHotkeysCommand() {
|
|
3541
3531
|
// Navigation keybindings
|
|
3542
|
-
const cursorUp = this.getEditorKeyDisplay("cursorUp");
|
|
3543
|
-
const cursorDown = this.getEditorKeyDisplay("cursorDown");
|
|
3544
|
-
const cursorLeft = this.getEditorKeyDisplay("cursorLeft");
|
|
3545
|
-
const cursorRight = this.getEditorKeyDisplay("cursorRight");
|
|
3546
|
-
const cursorWordLeft = this.getEditorKeyDisplay("cursorWordLeft");
|
|
3547
|
-
const cursorWordRight = this.getEditorKeyDisplay("cursorWordRight");
|
|
3548
|
-
const cursorLineStart = this.getEditorKeyDisplay("cursorLineStart");
|
|
3549
|
-
const cursorLineEnd = this.getEditorKeyDisplay("cursorLineEnd");
|
|
3550
|
-
const jumpForward = this.getEditorKeyDisplay("jumpForward");
|
|
3551
|
-
const jumpBackward = this.getEditorKeyDisplay("jumpBackward");
|
|
3552
|
-
const pageUp = this.getEditorKeyDisplay("pageUp");
|
|
3553
|
-
const pageDown = this.getEditorKeyDisplay("pageDown");
|
|
3532
|
+
const cursorUp = this.getEditorKeyDisplay("tui.editor.cursorUp");
|
|
3533
|
+
const cursorDown = this.getEditorKeyDisplay("tui.editor.cursorDown");
|
|
3534
|
+
const cursorLeft = this.getEditorKeyDisplay("tui.editor.cursorLeft");
|
|
3535
|
+
const cursorRight = this.getEditorKeyDisplay("tui.editor.cursorRight");
|
|
3536
|
+
const cursorWordLeft = this.getEditorKeyDisplay("tui.editor.cursorWordLeft");
|
|
3537
|
+
const cursorWordRight = this.getEditorKeyDisplay("tui.editor.cursorWordRight");
|
|
3538
|
+
const cursorLineStart = this.getEditorKeyDisplay("tui.editor.cursorLineStart");
|
|
3539
|
+
const cursorLineEnd = this.getEditorKeyDisplay("tui.editor.cursorLineEnd");
|
|
3540
|
+
const jumpForward = this.getEditorKeyDisplay("tui.editor.jumpForward");
|
|
3541
|
+
const jumpBackward = this.getEditorKeyDisplay("tui.editor.jumpBackward");
|
|
3542
|
+
const pageUp = this.getEditorKeyDisplay("tui.editor.pageUp");
|
|
3543
|
+
const pageDown = this.getEditorKeyDisplay("tui.editor.pageDown");
|
|
3554
3544
|
// Editing keybindings
|
|
3555
|
-
const submit = this.getEditorKeyDisplay("submit");
|
|
3556
|
-
const newLine = this.getEditorKeyDisplay("newLine");
|
|
3557
|
-
const deleteWordBackward = this.getEditorKeyDisplay("deleteWordBackward");
|
|
3558
|
-
const deleteWordForward = this.getEditorKeyDisplay("deleteWordForward");
|
|
3559
|
-
const deleteToLineStart = this.getEditorKeyDisplay("deleteToLineStart");
|
|
3560
|
-
const deleteToLineEnd = this.getEditorKeyDisplay("deleteToLineEnd");
|
|
3561
|
-
const yank = this.getEditorKeyDisplay("yank");
|
|
3562
|
-
const yankPop = this.getEditorKeyDisplay("yankPop");
|
|
3563
|
-
const undo = this.getEditorKeyDisplay("undo");
|
|
3564
|
-
const tab = this.getEditorKeyDisplay("tab");
|
|
3545
|
+
const submit = this.getEditorKeyDisplay("tui.input.submit");
|
|
3546
|
+
const newLine = this.getEditorKeyDisplay("tui.input.newLine");
|
|
3547
|
+
const deleteWordBackward = this.getEditorKeyDisplay("tui.editor.deleteWordBackward");
|
|
3548
|
+
const deleteWordForward = this.getEditorKeyDisplay("tui.editor.deleteWordForward");
|
|
3549
|
+
const deleteToLineStart = this.getEditorKeyDisplay("tui.editor.deleteToLineStart");
|
|
3550
|
+
const deleteToLineEnd = this.getEditorKeyDisplay("tui.editor.deleteToLineEnd");
|
|
3551
|
+
const yank = this.getEditorKeyDisplay("tui.editor.yank");
|
|
3552
|
+
const yankPop = this.getEditorKeyDisplay("tui.editor.yankPop");
|
|
3553
|
+
const undo = this.getEditorKeyDisplay("tui.editor.undo");
|
|
3554
|
+
const tab = this.getEditorKeyDisplay("tui.input.tab");
|
|
3565
3555
|
// App keybindings
|
|
3566
|
-
const interrupt = this.getAppKeyDisplay("interrupt");
|
|
3567
|
-
const clear = this.getAppKeyDisplay("clear");
|
|
3568
|
-
const exit = this.getAppKeyDisplay("exit");
|
|
3569
|
-
const suspend = this.getAppKeyDisplay("suspend");
|
|
3570
|
-
const cycleThinkingLevel = this.getAppKeyDisplay("
|
|
3571
|
-
const cycleModelForward = this.getAppKeyDisplay("
|
|
3572
|
-
const selectModel = this.getAppKeyDisplay("
|
|
3573
|
-
const expandTools = this.getAppKeyDisplay("
|
|
3574
|
-
const toggleThinking = this.getAppKeyDisplay("
|
|
3575
|
-
const externalEditor = this.getAppKeyDisplay("
|
|
3576
|
-
const cycleModelBackward = this.getAppKeyDisplay("
|
|
3577
|
-
const followUp = this.getAppKeyDisplay("followUp");
|
|
3578
|
-
const dequeue = this.getAppKeyDisplay("dequeue");
|
|
3579
|
-
const pasteImage = this.getAppKeyDisplay("pasteImage");
|
|
3556
|
+
const interrupt = this.getAppKeyDisplay("app.interrupt");
|
|
3557
|
+
const clear = this.getAppKeyDisplay("app.clear");
|
|
3558
|
+
const exit = this.getAppKeyDisplay("app.exit");
|
|
3559
|
+
const suspend = this.getAppKeyDisplay("app.suspend");
|
|
3560
|
+
const cycleThinkingLevel = this.getAppKeyDisplay("app.thinking.cycle");
|
|
3561
|
+
const cycleModelForward = this.getAppKeyDisplay("app.model.cycleForward");
|
|
3562
|
+
const selectModel = this.getAppKeyDisplay("app.model.select");
|
|
3563
|
+
const expandTools = this.getAppKeyDisplay("app.tools.expand");
|
|
3564
|
+
const toggleThinking = this.getAppKeyDisplay("app.thinking.toggle");
|
|
3565
|
+
const externalEditor = this.getAppKeyDisplay("app.editor.external");
|
|
3566
|
+
const cycleModelBackward = this.getAppKeyDisplay("app.model.cycleBackward");
|
|
3567
|
+
const followUp = this.getAppKeyDisplay("app.message.followUp");
|
|
3568
|
+
const dequeue = this.getAppKeyDisplay("app.message.dequeue");
|
|
3569
|
+
const pasteImage = this.getAppKeyDisplay("app.clipboard.pasteImage");
|
|
3580
3570
|
let hotkeys = `
|
|
3581
3571
|
**Navigation**
|
|
3582
3572
|
| Key | Action |
|
|
@@ -3801,7 +3791,7 @@ export class InteractiveMode {
|
|
|
3801
3791
|
};
|
|
3802
3792
|
// Show compacting status
|
|
3803
3793
|
this.chatContainer.addChild(new Spacer(1));
|
|
3804
|
-
const cancelHint = `(${
|
|
3794
|
+
const cancelHint = `(${keyText("app.interrupt")} to cancel)`;
|
|
3805
3795
|
const label = isAuto ? `Auto-compacting context... ${cancelHint}` : `Compacting context... ${cancelHint}`;
|
|
3806
3796
|
const compactingLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label);
|
|
3807
3797
|
this.statusContainer.addChild(compactingLoader);
|