@mariozechner/pi-coding-agent 0.60.0 → 0.61.0
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 +40 -0
- package/README.md +1 -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/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/register-bedrock.js +3 -84
- package/dist/bun/register-bedrock.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/core/agent-session.d.ts +17 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +61 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +7 -3
- package/dist/core/exec.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/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 +45 -33
- 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/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 +85 -13
- package/dist/core/footer-data-provider.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 +221 -143
- package/dist/core/keybindings.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 +23 -14
- package/dist/core/model-registry.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 +2 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +12 -10
- package/dist/core/tools/bash.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/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/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/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -4
- 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 -1
- 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 +2 -2
- 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 +2 -2
- 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 +8 -8
- package/dist/modes/interactive/components/config-selector.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 +6 -6
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +9 -9
- 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 +5 -5
- 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 +8 -8
- package/dist/modes/interactive/components/extension-selector.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 +6 -6
- 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 +12 -8
- 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 +6 -6
- 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 +4 -4
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +32 -35
- package/dist/modes/interactive/components/session-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 +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.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 +51 -6
- 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 +15 -15
- 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 +6 -6
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +140 -87
- 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 -37
- package/dist/modes/interactive/theme/theme.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/child-process.d.ts +11 -0
- package/dist/utils/child-process.d.ts.map +1 -0
- package/dist/utils/child-process.js +78 -0
- package/dist/utils/child-process.js.map +1 -0
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +11 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/docs/extensions.md +44 -7
- package/docs/keybindings.md +101 -112
- package/docs/providers.md +7 -0
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +2 -2
- 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";
|
|
@@ -65,6 +65,7 @@ export class InteractiveMode {
|
|
|
65
65
|
editorContainer;
|
|
66
66
|
footer;
|
|
67
67
|
footerDataProvider;
|
|
68
|
+
// Stored so the same manager can be injected into custom editors, selectors, and extension UI.
|
|
68
69
|
keybindings;
|
|
69
70
|
version;
|
|
70
71
|
isInitialized = false;
|
|
@@ -148,6 +149,7 @@ export class InteractiveMode {
|
|
|
148
149
|
this.widgetContainerAbove = new Container();
|
|
149
150
|
this.widgetContainerBelow = new Container();
|
|
150
151
|
this.keybindings = KeybindingsManager.create();
|
|
152
|
+
setKeybindings(this.keybindings);
|
|
151
153
|
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
152
154
|
const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
|
|
153
155
|
this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, {
|
|
@@ -242,27 +244,26 @@ export class InteractiveMode {
|
|
|
242
244
|
if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
|
|
243
245
|
const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
|
|
244
246
|
// Build startup instructions using keybinding hint helpers
|
|
245
|
-
const
|
|
246
|
-
const hint = (action, desc) => appKeyHint(kb, action, desc);
|
|
247
|
+
const hint = (keybinding, description) => keyHint(keybinding, description);
|
|
247
248
|
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("
|
|
249
|
+
hint("app.interrupt", "to interrupt"),
|
|
250
|
+
hint("app.clear", "to clear"),
|
|
251
|
+
rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
|
|
252
|
+
hint("app.exit", "to exit (empty)"),
|
|
253
|
+
hint("app.suspend", "to suspend"),
|
|
254
|
+
keyHint("tui.editor.deleteToLineEnd", "to delete to end"),
|
|
255
|
+
hint("app.thinking.cycle", "to cycle thinking level"),
|
|
256
|
+
rawKeyHint(`${keyText("app.model.cycleForward")}/${keyText("app.model.cycleBackward")}`, "to cycle models"),
|
|
257
|
+
hint("app.model.select", "to select model"),
|
|
258
|
+
hint("app.tools.expand", "to expand tools"),
|
|
259
|
+
hint("app.thinking.toggle", "to expand thinking"),
|
|
260
|
+
hint("app.editor.external", "for external editor"),
|
|
260
261
|
rawKeyHint("/", "for commands"),
|
|
261
262
|
rawKeyHint("!", "to run bash"),
|
|
262
263
|
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"),
|
|
264
|
+
hint("app.message.followUp", "to queue follow-up"),
|
|
265
|
+
hint("app.message.dequeue", "to edit all queued messages"),
|
|
266
|
+
hint("app.clipboard.pasteImage", "to paste image"),
|
|
266
267
|
rawKeyHint("drop files", "to attach"),
|
|
267
268
|
].join("\n");
|
|
268
269
|
this.builtInHeader = new Text(`${logo}\n${instructions}`, 1, 0);
|
|
@@ -1049,7 +1050,7 @@ export class InteractiveMode {
|
|
|
1049
1050
|
this.defaultEditor.onExtensionShortcut = undefined;
|
|
1050
1051
|
this.updateTerminalTitle();
|
|
1051
1052
|
if (this.loadingAnimation) {
|
|
1052
|
-
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${
|
|
1053
|
+
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1053
1054
|
}
|
|
1054
1055
|
}
|
|
1055
1056
|
// Maximum total widget lines to prevent viewport overflow
|
|
@@ -1172,7 +1173,7 @@ export class InteractiveMode {
|
|
|
1172
1173
|
this.loadingAnimation.setMessage(message);
|
|
1173
1174
|
}
|
|
1174
1175
|
else {
|
|
1175
|
-
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${
|
|
1176
|
+
this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1176
1177
|
}
|
|
1177
1178
|
}
|
|
1178
1179
|
else {
|
|
@@ -1530,24 +1531,24 @@ export class InteractiveMode {
|
|
|
1530
1531
|
}
|
|
1531
1532
|
};
|
|
1532
1533
|
// Register app action handlers
|
|
1533
|
-
this.defaultEditor.onAction("clear", () => this.handleCtrlC());
|
|
1534
|
+
this.defaultEditor.onAction("app.clear", () => this.handleCtrlC());
|
|
1534
1535
|
this.defaultEditor.onCtrlD = () => this.handleCtrlD();
|
|
1535
|
-
this.defaultEditor.onAction("suspend", () => this.handleCtrlZ());
|
|
1536
|
-
this.defaultEditor.onAction("
|
|
1537
|
-
this.defaultEditor.onAction("
|
|
1538
|
-
this.defaultEditor.onAction("
|
|
1536
|
+
this.defaultEditor.onAction("app.suspend", () => this.handleCtrlZ());
|
|
1537
|
+
this.defaultEditor.onAction("app.thinking.cycle", () => this.cycleThinkingLevel());
|
|
1538
|
+
this.defaultEditor.onAction("app.model.cycleForward", () => this.cycleModel("forward"));
|
|
1539
|
+
this.defaultEditor.onAction("app.model.cycleBackward", () => this.cycleModel("backward"));
|
|
1539
1540
|
// Global debug handler on TUI (works regardless of focus)
|
|
1540
1541
|
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());
|
|
1542
|
+
this.defaultEditor.onAction("app.model.select", () => this.showModelSelector());
|
|
1543
|
+
this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
|
|
1544
|
+
this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
|
|
1545
|
+
this.defaultEditor.onAction("app.editor.external", () => this.openExternalEditor());
|
|
1546
|
+
this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
|
|
1547
|
+
this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
|
|
1548
|
+
this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
|
|
1549
|
+
this.defaultEditor.onAction("app.session.tree", () => this.showTreeSelector());
|
|
1550
|
+
this.defaultEditor.onAction("app.session.fork", () => this.showUserMessageSelector());
|
|
1551
|
+
this.defaultEditor.onAction("app.session.resume", () => this.showSessionSelector());
|
|
1551
1552
|
this.defaultEditor.onChange = (text) => {
|
|
1552
1553
|
const wasBashMode = this.isBashMode;
|
|
1553
1554
|
this.isBashMode = text.trimStart().startsWith("!");
|
|
@@ -1607,13 +1608,18 @@ export class InteractiveMode {
|
|
|
1607
1608
|
this.editor.setText("");
|
|
1608
1609
|
return;
|
|
1609
1610
|
}
|
|
1611
|
+
if (text.startsWith("/import")) {
|
|
1612
|
+
await this.handleImportCommand(text);
|
|
1613
|
+
this.editor.setText("");
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1610
1616
|
if (text === "/share") {
|
|
1611
1617
|
await this.handleShareCommand();
|
|
1612
1618
|
this.editor.setText("");
|
|
1613
1619
|
return;
|
|
1614
1620
|
}
|
|
1615
1621
|
if (text === "/copy") {
|
|
1616
|
-
this.handleCopyCommand();
|
|
1622
|
+
await this.handleCopyCommand();
|
|
1617
1623
|
this.editor.setText("");
|
|
1618
1624
|
return;
|
|
1619
1625
|
}
|
|
@@ -1861,15 +1867,17 @@ export class InteractiveMode {
|
|
|
1861
1867
|
this.ui.requestRender();
|
|
1862
1868
|
break;
|
|
1863
1869
|
case "tool_execution_start": {
|
|
1864
|
-
|
|
1865
|
-
|
|
1870
|
+
let component = this.pendingTools.get(event.toolCallId);
|
|
1871
|
+
if (!component) {
|
|
1872
|
+
component = new ToolExecutionComponent(event.toolName, event.args, {
|
|
1866
1873
|
showImages: this.settingsManager.getShowImages(),
|
|
1867
1874
|
}, this.getRegisteredToolDefinition(event.toolName), this.ui);
|
|
1868
1875
|
component.setExpanded(this.toolOutputExpanded);
|
|
1869
1876
|
this.chatContainer.addChild(component);
|
|
1870
1877
|
this.pendingTools.set(event.toolCallId, component);
|
|
1871
|
-
this.ui.requestRender();
|
|
1872
1878
|
}
|
|
1879
|
+
component.markExecutionStarted();
|
|
1880
|
+
this.ui.requestRender();
|
|
1873
1881
|
break;
|
|
1874
1882
|
}
|
|
1875
1883
|
case "tool_execution_update": {
|
|
@@ -1914,7 +1922,7 @@ export class InteractiveMode {
|
|
|
1914
1922
|
// Show compacting indicator with reason
|
|
1915
1923
|
this.statusContainer.clear();
|
|
1916
1924
|
const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
|
|
1917
|
-
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting... (${
|
|
1925
|
+
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting... (${keyText("app.interrupt")} to cancel)`);
|
|
1918
1926
|
this.statusContainer.addChild(this.autoCompactionLoader);
|
|
1919
1927
|
this.ui.requestRender();
|
|
1920
1928
|
break;
|
|
@@ -1966,7 +1974,7 @@ export class InteractiveMode {
|
|
|
1966
1974
|
// Show retry indicator
|
|
1967
1975
|
this.statusContainer.clear();
|
|
1968
1976
|
const delaySeconds = Math.round(event.delayMs / 1000);
|
|
1969
|
-
this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${
|
|
1977
|
+
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)`);
|
|
1970
1978
|
this.statusContainer.addChild(this.retryLoader);
|
|
1971
1979
|
this.ui.requestRender();
|
|
1972
1980
|
break;
|
|
@@ -2481,7 +2489,7 @@ export class InteractiveMode {
|
|
|
2481
2489
|
const text = theme.fg("dim", `Follow-up: ${message}`);
|
|
2482
2490
|
this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));
|
|
2483
2491
|
}
|
|
2484
|
-
const dequeueHint = this.getAppKeyDisplay("dequeue");
|
|
2492
|
+
const dequeueHint = this.getAppKeyDisplay("app.message.dequeue");
|
|
2485
2493
|
const hintText = theme.fg("dim", `↳ ${dequeueHint} to edit all queued messages`);
|
|
2486
2494
|
this.pendingMessagesContainer.addChild(new TruncatedText(hintText, 1, 0));
|
|
2487
2495
|
}
|
|
@@ -3003,7 +3011,7 @@ export class InteractiveMode {
|
|
|
3003
3011
|
this.session.abortBranchSummary();
|
|
3004
3012
|
};
|
|
3005
3013
|
this.chatContainer.addChild(new Spacer(1));
|
|
3006
|
-
summaryLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `Summarizing branch... (${
|
|
3014
|
+
summaryLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `Summarizing branch... (${keyText("app.interrupt")} to cancel)`);
|
|
3007
3015
|
this.statusContainer.addChild(summaryLoader);
|
|
3008
3016
|
this.ui.requestRender();
|
|
3009
3017
|
}
|
|
@@ -3285,13 +3293,58 @@ export class InteractiveMode {
|
|
|
3285
3293
|
const parts = text.split(/\s+/);
|
|
3286
3294
|
const outputPath = parts.length > 1 ? parts[1] : undefined;
|
|
3287
3295
|
try {
|
|
3288
|
-
|
|
3289
|
-
|
|
3296
|
+
if (outputPath?.endsWith(".jsonl")) {
|
|
3297
|
+
const filePath = this.session.exportToJsonl(outputPath);
|
|
3298
|
+
this.showStatus(`Session exported to: ${filePath}`);
|
|
3299
|
+
}
|
|
3300
|
+
else {
|
|
3301
|
+
const filePath = await this.session.exportToHtml(outputPath);
|
|
3302
|
+
this.showStatus(`Session exported to: ${filePath}`);
|
|
3303
|
+
}
|
|
3290
3304
|
}
|
|
3291
3305
|
catch (error) {
|
|
3292
3306
|
this.showError(`Failed to export session: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3293
3307
|
}
|
|
3294
3308
|
}
|
|
3309
|
+
async handleImportCommand(text) {
|
|
3310
|
+
const parts = text.split(/\s+/);
|
|
3311
|
+
if (parts.length < 2 || !parts[1]) {
|
|
3312
|
+
this.showError("Usage: /import <path.jsonl>");
|
|
3313
|
+
return;
|
|
3314
|
+
}
|
|
3315
|
+
const inputPath = parts[1];
|
|
3316
|
+
const confirmed = await this.showExtensionConfirm("Import session", `Replace current session with ${inputPath}?`);
|
|
3317
|
+
if (!confirmed) {
|
|
3318
|
+
this.showStatus("Import cancelled");
|
|
3319
|
+
return;
|
|
3320
|
+
}
|
|
3321
|
+
try {
|
|
3322
|
+
// Stop loading animation
|
|
3323
|
+
if (this.loadingAnimation) {
|
|
3324
|
+
this.loadingAnimation.stop();
|
|
3325
|
+
this.loadingAnimation = undefined;
|
|
3326
|
+
}
|
|
3327
|
+
this.statusContainer.clear();
|
|
3328
|
+
// Clear UI state
|
|
3329
|
+
this.pendingMessagesContainer.clear();
|
|
3330
|
+
this.compactionQueuedMessages = [];
|
|
3331
|
+
this.streamingComponent = undefined;
|
|
3332
|
+
this.streamingMessage = undefined;
|
|
3333
|
+
this.pendingTools.clear();
|
|
3334
|
+
const success = await this.session.importFromJsonl(inputPath);
|
|
3335
|
+
if (!success) {
|
|
3336
|
+
this.showWarning("Import cancelled");
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
// Clear and re-render the chat
|
|
3340
|
+
this.chatContainer.clear();
|
|
3341
|
+
this.renderInitialMessages();
|
|
3342
|
+
this.showStatus(`Session imported from: ${inputPath}`);
|
|
3343
|
+
}
|
|
3344
|
+
catch (error) {
|
|
3345
|
+
this.showError(`Failed to import session: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3295
3348
|
async handleShareCommand() {
|
|
3296
3349
|
// Check if gh is available and logged in
|
|
3297
3350
|
try {
|
|
@@ -3379,14 +3432,14 @@ export class InteractiveMode {
|
|
|
3379
3432
|
}
|
|
3380
3433
|
}
|
|
3381
3434
|
}
|
|
3382
|
-
handleCopyCommand() {
|
|
3435
|
+
async handleCopyCommand() {
|
|
3383
3436
|
const text = this.session.getLastAssistantText();
|
|
3384
3437
|
if (!text) {
|
|
3385
3438
|
this.showError("No agent messages to copy yet.");
|
|
3386
3439
|
return;
|
|
3387
3440
|
}
|
|
3388
3441
|
try {
|
|
3389
|
-
copyToClipboard(text);
|
|
3442
|
+
await copyToClipboard(text);
|
|
3390
3443
|
this.showStatus("Copied last agent message to clipboard");
|
|
3391
3444
|
}
|
|
3392
3445
|
catch (error) {
|
|
@@ -3479,54 +3532,54 @@ export class InteractiveMode {
|
|
|
3479
3532
|
* Get capitalized display string for an app keybinding action.
|
|
3480
3533
|
*/
|
|
3481
3534
|
getAppKeyDisplay(action) {
|
|
3482
|
-
return this.capitalizeKey(
|
|
3535
|
+
return this.capitalizeKey(keyText(action));
|
|
3483
3536
|
}
|
|
3484
3537
|
/**
|
|
3485
3538
|
* Get capitalized display string for an editor keybinding action.
|
|
3486
3539
|
*/
|
|
3487
3540
|
getEditorKeyDisplay(action) {
|
|
3488
|
-
return this.capitalizeKey(
|
|
3541
|
+
return this.capitalizeKey(keyText(action));
|
|
3489
3542
|
}
|
|
3490
3543
|
handleHotkeysCommand() {
|
|
3491
3544
|
// Navigation keybindings
|
|
3492
|
-
const cursorUp = this.getEditorKeyDisplay("cursorUp");
|
|
3493
|
-
const cursorDown = this.getEditorKeyDisplay("cursorDown");
|
|
3494
|
-
const cursorLeft = this.getEditorKeyDisplay("cursorLeft");
|
|
3495
|
-
const cursorRight = this.getEditorKeyDisplay("cursorRight");
|
|
3496
|
-
const cursorWordLeft = this.getEditorKeyDisplay("cursorWordLeft");
|
|
3497
|
-
const cursorWordRight = this.getEditorKeyDisplay("cursorWordRight");
|
|
3498
|
-
const cursorLineStart = this.getEditorKeyDisplay("cursorLineStart");
|
|
3499
|
-
const cursorLineEnd = this.getEditorKeyDisplay("cursorLineEnd");
|
|
3500
|
-
const jumpForward = this.getEditorKeyDisplay("jumpForward");
|
|
3501
|
-
const jumpBackward = this.getEditorKeyDisplay("jumpBackward");
|
|
3502
|
-
const pageUp = this.getEditorKeyDisplay("pageUp");
|
|
3503
|
-
const pageDown = this.getEditorKeyDisplay("pageDown");
|
|
3545
|
+
const cursorUp = this.getEditorKeyDisplay("tui.editor.cursorUp");
|
|
3546
|
+
const cursorDown = this.getEditorKeyDisplay("tui.editor.cursorDown");
|
|
3547
|
+
const cursorLeft = this.getEditorKeyDisplay("tui.editor.cursorLeft");
|
|
3548
|
+
const cursorRight = this.getEditorKeyDisplay("tui.editor.cursorRight");
|
|
3549
|
+
const cursorWordLeft = this.getEditorKeyDisplay("tui.editor.cursorWordLeft");
|
|
3550
|
+
const cursorWordRight = this.getEditorKeyDisplay("tui.editor.cursorWordRight");
|
|
3551
|
+
const cursorLineStart = this.getEditorKeyDisplay("tui.editor.cursorLineStart");
|
|
3552
|
+
const cursorLineEnd = this.getEditorKeyDisplay("tui.editor.cursorLineEnd");
|
|
3553
|
+
const jumpForward = this.getEditorKeyDisplay("tui.editor.jumpForward");
|
|
3554
|
+
const jumpBackward = this.getEditorKeyDisplay("tui.editor.jumpBackward");
|
|
3555
|
+
const pageUp = this.getEditorKeyDisplay("tui.editor.pageUp");
|
|
3556
|
+
const pageDown = this.getEditorKeyDisplay("tui.editor.pageDown");
|
|
3504
3557
|
// Editing keybindings
|
|
3505
|
-
const submit = this.getEditorKeyDisplay("submit");
|
|
3506
|
-
const newLine = this.getEditorKeyDisplay("newLine");
|
|
3507
|
-
const deleteWordBackward = this.getEditorKeyDisplay("deleteWordBackward");
|
|
3508
|
-
const deleteWordForward = this.getEditorKeyDisplay("deleteWordForward");
|
|
3509
|
-
const deleteToLineStart = this.getEditorKeyDisplay("deleteToLineStart");
|
|
3510
|
-
const deleteToLineEnd = this.getEditorKeyDisplay("deleteToLineEnd");
|
|
3511
|
-
const yank = this.getEditorKeyDisplay("yank");
|
|
3512
|
-
const yankPop = this.getEditorKeyDisplay("yankPop");
|
|
3513
|
-
const undo = this.getEditorKeyDisplay("undo");
|
|
3514
|
-
const tab = this.getEditorKeyDisplay("tab");
|
|
3558
|
+
const submit = this.getEditorKeyDisplay("tui.input.submit");
|
|
3559
|
+
const newLine = this.getEditorKeyDisplay("tui.input.newLine");
|
|
3560
|
+
const deleteWordBackward = this.getEditorKeyDisplay("tui.editor.deleteWordBackward");
|
|
3561
|
+
const deleteWordForward = this.getEditorKeyDisplay("tui.editor.deleteWordForward");
|
|
3562
|
+
const deleteToLineStart = this.getEditorKeyDisplay("tui.editor.deleteToLineStart");
|
|
3563
|
+
const deleteToLineEnd = this.getEditorKeyDisplay("tui.editor.deleteToLineEnd");
|
|
3564
|
+
const yank = this.getEditorKeyDisplay("tui.editor.yank");
|
|
3565
|
+
const yankPop = this.getEditorKeyDisplay("tui.editor.yankPop");
|
|
3566
|
+
const undo = this.getEditorKeyDisplay("tui.editor.undo");
|
|
3567
|
+
const tab = this.getEditorKeyDisplay("tui.input.tab");
|
|
3515
3568
|
// App keybindings
|
|
3516
|
-
const interrupt = this.getAppKeyDisplay("interrupt");
|
|
3517
|
-
const clear = this.getAppKeyDisplay("clear");
|
|
3518
|
-
const exit = this.getAppKeyDisplay("exit");
|
|
3519
|
-
const suspend = this.getAppKeyDisplay("suspend");
|
|
3520
|
-
const cycleThinkingLevel = this.getAppKeyDisplay("
|
|
3521
|
-
const cycleModelForward = this.getAppKeyDisplay("
|
|
3522
|
-
const selectModel = this.getAppKeyDisplay("
|
|
3523
|
-
const expandTools = this.getAppKeyDisplay("
|
|
3524
|
-
const toggleThinking = this.getAppKeyDisplay("
|
|
3525
|
-
const externalEditor = this.getAppKeyDisplay("
|
|
3526
|
-
const cycleModelBackward = this.getAppKeyDisplay("
|
|
3527
|
-
const followUp = this.getAppKeyDisplay("followUp");
|
|
3528
|
-
const dequeue = this.getAppKeyDisplay("dequeue");
|
|
3529
|
-
const pasteImage = this.getAppKeyDisplay("pasteImage");
|
|
3569
|
+
const interrupt = this.getAppKeyDisplay("app.interrupt");
|
|
3570
|
+
const clear = this.getAppKeyDisplay("app.clear");
|
|
3571
|
+
const exit = this.getAppKeyDisplay("app.exit");
|
|
3572
|
+
const suspend = this.getAppKeyDisplay("app.suspend");
|
|
3573
|
+
const cycleThinkingLevel = this.getAppKeyDisplay("app.thinking.cycle");
|
|
3574
|
+
const cycleModelForward = this.getAppKeyDisplay("app.model.cycleForward");
|
|
3575
|
+
const selectModel = this.getAppKeyDisplay("app.model.select");
|
|
3576
|
+
const expandTools = this.getAppKeyDisplay("app.tools.expand");
|
|
3577
|
+
const toggleThinking = this.getAppKeyDisplay("app.thinking.toggle");
|
|
3578
|
+
const externalEditor = this.getAppKeyDisplay("app.editor.external");
|
|
3579
|
+
const cycleModelBackward = this.getAppKeyDisplay("app.model.cycleBackward");
|
|
3580
|
+
const followUp = this.getAppKeyDisplay("app.message.followUp");
|
|
3581
|
+
const dequeue = this.getAppKeyDisplay("app.message.dequeue");
|
|
3582
|
+
const pasteImage = this.getAppKeyDisplay("app.clipboard.pasteImage");
|
|
3530
3583
|
let hotkeys = `
|
|
3531
3584
|
**Navigation**
|
|
3532
3585
|
| Key | Action |
|
|
@@ -3751,7 +3804,7 @@ export class InteractiveMode {
|
|
|
3751
3804
|
};
|
|
3752
3805
|
// Show compacting status
|
|
3753
3806
|
this.chatContainer.addChild(new Spacer(1));
|
|
3754
|
-
const cancelHint = `(${
|
|
3807
|
+
const cancelHint = `(${keyText("app.interrupt")} to cancel)`;
|
|
3755
3808
|
const label = isAuto ? `Auto-compacting context... ${cancelHint}` : `Compacting context... ${cancelHint}`;
|
|
3756
3809
|
const compactingLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label);
|
|
3757
3810
|
this.statusContainer.addChild(compactingLoader);
|