@mariozechner/pi-coding-agent 0.47.0 → 0.49.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 +61 -1
- package/README.md +43 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +63 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +11 -4
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +11 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +50 -3
- package/dist/core/compaction/compaction.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 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +44 -5
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +5 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +18 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +8 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +43 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +28 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +16 -21
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +4 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +8 -3
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts +0 -1
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +0 -7
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -12
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +52 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +2 -2
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +2 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +3 -3
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +5 -3
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +24 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +3 -1
- package/dist/modes/interactive/components/tool-execution.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 +168 -80
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +23 -3
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +22 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +22 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +8 -2
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +14 -1
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/photon.d.ts +20 -0
- package/dist/utils/photon.d.ts.map +1 -0
- package/dist/utils/photon.js +39 -0
- package/dist/utils/photon.js.map +1 -0
- package/docs/extensions.md +99 -5
- package/docs/rpc.md +2 -0
- package/docs/sdk.md +1 -1
- package/docs/tree.md +20 -2
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/custom-header.ts +2 -1
- package/examples/extensions/trigger-compact.ts +40 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -65,6 +65,7 @@ export class InteractiveMode {
|
|
|
65
65
|
keybindings;
|
|
66
66
|
version;
|
|
67
67
|
isInitialized = false;
|
|
68
|
+
hasRenderedInitialMessages = false;
|
|
68
69
|
onInputCallback;
|
|
69
70
|
loadingAnimation = undefined;
|
|
70
71
|
defaultWorkingMessage = "Working...";
|
|
@@ -130,13 +131,14 @@ export class InteractiveMode {
|
|
|
130
131
|
this.options = options;
|
|
131
132
|
this.session = session;
|
|
132
133
|
this.version = VERSION;
|
|
133
|
-
this.ui = new TUI(new ProcessTerminal());
|
|
134
|
+
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
|
134
135
|
this.chatContainer = new Container();
|
|
135
136
|
this.pendingMessagesContainer = new Container();
|
|
136
137
|
this.statusContainer = new Container();
|
|
137
138
|
this.widgetContainer = new Container();
|
|
138
139
|
this.keybindings = KeybindingsManager.create();
|
|
139
|
-
|
|
140
|
+
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
141
|
+
this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, { paddingX: editorPaddingX });
|
|
140
142
|
this.editor = this.defaultEditor;
|
|
141
143
|
this.editorContainer = new Container();
|
|
142
144
|
this.editorContainer.addChild(this.editor);
|
|
@@ -204,6 +206,7 @@ export class InteractiveMode {
|
|
|
204
206
|
const extensionCommands = (this.session.extensionRunner?.getRegisteredCommands() ?? []).map((cmd) => ({
|
|
205
207
|
name: cmd.name,
|
|
206
208
|
description: cmd.description ?? "(extension command)",
|
|
209
|
+
getArgumentCompletions: cmd.getArgumentCompletions,
|
|
207
210
|
}));
|
|
208
211
|
// Build skill commands from session.skills (if enabled)
|
|
209
212
|
this.skillCommands.clear();
|
|
@@ -230,53 +233,67 @@ export class InteractiveMode {
|
|
|
230
233
|
// Setup autocomplete with fd tool for file path completion
|
|
231
234
|
this.fdPath = await ensureTool("fd");
|
|
232
235
|
this.setupAutocomplete(this.fdPath);
|
|
233
|
-
// Add header with keybindings from config
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
this.
|
|
267
|
-
|
|
236
|
+
// Add header with keybindings from config (unless silenced)
|
|
237
|
+
if (!this.settingsManager.getQuietStartup()) {
|
|
238
|
+
const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
|
|
239
|
+
// Build startup instructions using keybinding hint helpers
|
|
240
|
+
const kb = this.keybindings;
|
|
241
|
+
const hint = (action, desc) => appKeyHint(kb, action, desc);
|
|
242
|
+
const instructions = [
|
|
243
|
+
hint("interrupt", "to interrupt"),
|
|
244
|
+
hint("clear", "to clear"),
|
|
245
|
+
rawKeyHint(`${appKey(kb, "clear")} twice`, "to exit"),
|
|
246
|
+
hint("exit", "to exit (empty)"),
|
|
247
|
+
hint("suspend", "to suspend"),
|
|
248
|
+
keyHint("deleteToLineEnd", "to delete to end"),
|
|
249
|
+
hint("cycleThinkingLevel", "to cycle thinking"),
|
|
250
|
+
rawKeyHint(`${appKey(kb, "cycleModelForward")}/${appKey(kb, "cycleModelBackward")}`, "to cycle models"),
|
|
251
|
+
hint("selectModel", "to select model"),
|
|
252
|
+
hint("expandTools", "to expand tools"),
|
|
253
|
+
hint("toggleThinking", "to toggle thinking"),
|
|
254
|
+
hint("externalEditor", "for external editor"),
|
|
255
|
+
rawKeyHint("/", "for commands"),
|
|
256
|
+
rawKeyHint("!", "to run bash"),
|
|
257
|
+
rawKeyHint("!!", "to run bash (no context)"),
|
|
258
|
+
hint("followUp", "to queue follow-up"),
|
|
259
|
+
hint("dequeue", "to edit all queued messages"),
|
|
260
|
+
hint("pasteImage", "to paste image"),
|
|
261
|
+
rawKeyHint("drop files", "to attach"),
|
|
262
|
+
].join("\n");
|
|
263
|
+
this.builtInHeader = new Text(`${logo}\n${instructions}`, 1, 0);
|
|
264
|
+
// Setup UI layout
|
|
265
|
+
this.ui.addChild(new Spacer(1));
|
|
266
|
+
this.ui.addChild(this.builtInHeader);
|
|
267
|
+
this.ui.addChild(new Spacer(1));
|
|
268
|
+
// Add changelog if provided
|
|
269
|
+
if (this.changelogMarkdown) {
|
|
270
|
+
this.ui.addChild(new DynamicBorder());
|
|
271
|
+
if (this.settingsManager.getCollapseChangelog()) {
|
|
272
|
+
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
273
|
+
const latestVersion = versionMatch ? versionMatch[1] : this.version;
|
|
274
|
+
const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
|
|
275
|
+
this.ui.addChild(new Text(condensedText, 1, 0));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
this.ui.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
|
|
279
|
+
this.ui.addChild(new Spacer(1));
|
|
280
|
+
this.ui.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, getMarkdownTheme()));
|
|
281
|
+
this.ui.addChild(new Spacer(1));
|
|
282
|
+
}
|
|
283
|
+
this.ui.addChild(new DynamicBorder());
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// Minimal header when silenced
|
|
288
|
+
this.builtInHeader = new Text("", 0, 0);
|
|
289
|
+
if (this.changelogMarkdown) {
|
|
290
|
+
// Still show changelog notification even in silent mode
|
|
291
|
+
this.ui.addChild(new Spacer(1));
|
|
268
292
|
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
269
293
|
const latestVersion = versionMatch ? versionMatch[1] : this.version;
|
|
270
294
|
const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
|
|
271
295
|
this.ui.addChild(new Text(condensedText, 1, 0));
|
|
272
296
|
}
|
|
273
|
-
else {
|
|
274
|
-
this.ui.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
|
|
275
|
-
this.ui.addChild(new Spacer(1));
|
|
276
|
-
this.ui.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, getMarkdownTheme()));
|
|
277
|
-
this.ui.addChild(new Spacer(1));
|
|
278
|
-
}
|
|
279
|
-
this.ui.addChild(new DynamicBorder());
|
|
280
297
|
}
|
|
281
298
|
this.ui.addChild(this.chatContainer);
|
|
282
299
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
@@ -421,33 +438,38 @@ export class InteractiveMode {
|
|
|
421
438
|
* Initialize the extension system with TUI-based UI context.
|
|
422
439
|
*/
|
|
423
440
|
async initExtensions() {
|
|
424
|
-
// Show
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
this.
|
|
441
|
+
// Show discovery info unless silenced
|
|
442
|
+
if (!this.settingsManager.getQuietStartup()) {
|
|
443
|
+
// Show loaded project context files
|
|
444
|
+
const contextFiles = loadProjectContextFiles();
|
|
445
|
+
if (contextFiles.length > 0) {
|
|
446
|
+
const contextList = contextFiles.map((f) => theme.fg("dim", ` ${f.path}`)).join("\n");
|
|
447
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", "Loaded context:\n") + contextList, 0, 0));
|
|
448
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
449
|
+
}
|
|
450
|
+
// Show loaded skills (already discovered by SDK)
|
|
451
|
+
const skills = this.session.skills;
|
|
452
|
+
if (skills.length > 0) {
|
|
453
|
+
const skillList = skills.map((s) => theme.fg("dim", ` ${s.filePath}`)).join("\n");
|
|
454
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", "Loaded skills:\n") + skillList, 0, 0));
|
|
455
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
456
|
+
}
|
|
457
|
+
// Show skill warnings if any
|
|
458
|
+
const skillWarnings = this.session.skillWarnings;
|
|
459
|
+
if (skillWarnings.length > 0) {
|
|
460
|
+
const warningList = skillWarnings
|
|
461
|
+
.map((w) => theme.fg("warning", ` ${w.skillPath}: ${w.message}`))
|
|
462
|
+
.join("\n");
|
|
463
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", "Skill warnings:\n") + warningList, 0, 0));
|
|
464
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
465
|
+
}
|
|
466
|
+
// Show loaded prompt templates
|
|
467
|
+
const templates = this.session.promptTemplates;
|
|
468
|
+
if (templates.length > 0) {
|
|
469
|
+
const templateList = templates.map((t) => theme.fg("dim", ` /${t.name} ${t.source}`)).join("\n");
|
|
470
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", "Loaded prompt templates:\n") + templateList, 0, 0));
|
|
471
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
472
|
+
}
|
|
451
473
|
}
|
|
452
474
|
const extensionRunner = this.session.extensionRunner;
|
|
453
475
|
if (!extensionRunner) {
|
|
@@ -463,7 +485,9 @@ export class InteractiveMode {
|
|
|
463
485
|
this.session
|
|
464
486
|
.sendCustomMessage(message, options)
|
|
465
487
|
.then(() => {
|
|
466
|
-
if
|
|
488
|
+
// Don't rebuild if initial render hasn't happened yet
|
|
489
|
+
// (renderInitialMessages will handle it)
|
|
490
|
+
if (!wasStreaming && message.display && this.hasRenderedInitialMessages) {
|
|
467
491
|
this.rebuildChatFromMessages();
|
|
468
492
|
}
|
|
469
493
|
})
|
|
@@ -485,6 +509,9 @@ export class InteractiveMode {
|
|
|
485
509
|
getSessionName: () => {
|
|
486
510
|
return this.sessionManager.getSessionName();
|
|
487
511
|
},
|
|
512
|
+
setLabel: (entryId, label) => {
|
|
513
|
+
this.sessionManager.appendLabelChange(entryId, label);
|
|
514
|
+
},
|
|
488
515
|
getActiveTools: () => this.session.getActiveToolNames(),
|
|
489
516
|
getAllTools: () => this.session.getAllTools(),
|
|
490
517
|
setActiveTools: (toolNames) => this.session.setActiveToolsByName(toolNames),
|
|
@@ -507,6 +534,21 @@ export class InteractiveMode {
|
|
|
507
534
|
shutdown: () => {
|
|
508
535
|
this.shutdownRequested = true;
|
|
509
536
|
},
|
|
537
|
+
getContextUsage: () => this.session.getContextUsage(),
|
|
538
|
+
compact: (options) => {
|
|
539
|
+
void (async () => {
|
|
540
|
+
try {
|
|
541
|
+
const result = await this.executeCompaction(options?.customInstructions, false);
|
|
542
|
+
if (result) {
|
|
543
|
+
options?.onComplete?.(result);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
548
|
+
options?.onError?.(err);
|
|
549
|
+
}
|
|
550
|
+
})();
|
|
551
|
+
},
|
|
510
552
|
},
|
|
511
553
|
// ExtensionCommandContextActions - for ctx.* in command handlers
|
|
512
554
|
{
|
|
@@ -547,7 +589,12 @@ export class InteractiveMode {
|
|
|
547
589
|
return { cancelled: false };
|
|
548
590
|
},
|
|
549
591
|
navigateTree: async (targetId, options) => {
|
|
550
|
-
const result = await this.session.navigateTree(targetId, {
|
|
592
|
+
const result = await this.session.navigateTree(targetId, {
|
|
593
|
+
summarize: options?.summarize,
|
|
594
|
+
customInstructions: options?.customInstructions,
|
|
595
|
+
replaceInstructions: options?.replaceInstructions,
|
|
596
|
+
label: options?.label,
|
|
597
|
+
});
|
|
551
598
|
if (result.cancelled) {
|
|
552
599
|
return { cancelled: true };
|
|
553
600
|
}
|
|
@@ -566,12 +613,14 @@ export class InteractiveMode {
|
|
|
566
613
|
});
|
|
567
614
|
// Set up extension-registered shortcuts
|
|
568
615
|
this.setupExtensionShortcuts(extensionRunner);
|
|
569
|
-
// Show loaded extensions
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
616
|
+
// Show loaded extensions (unless silenced)
|
|
617
|
+
if (!this.settingsManager.getQuietStartup()) {
|
|
618
|
+
const extensionPaths = extensionRunner.getExtensionPaths();
|
|
619
|
+
if (extensionPaths.length > 0) {
|
|
620
|
+
const extList = extensionPaths.map((p) => theme.fg("dim", ` ${p}`)).join("\n");
|
|
621
|
+
this.chatContainer.addChild(new Text(theme.fg("muted", "Loaded extensions:\n") + extList, 0, 0));
|
|
622
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
623
|
+
}
|
|
575
624
|
}
|
|
576
625
|
// Emit session_start event
|
|
577
626
|
await extensionRunner.emit({
|
|
@@ -607,6 +656,21 @@ export class InteractiveMode {
|
|
|
607
656
|
shutdown: () => {
|
|
608
657
|
this.shutdownRequested = true;
|
|
609
658
|
},
|
|
659
|
+
getContextUsage: () => this.session.getContextUsage(),
|
|
660
|
+
compact: (options) => {
|
|
661
|
+
void (async () => {
|
|
662
|
+
try {
|
|
663
|
+
const result = await this.executeCompaction(options?.customInstructions, false);
|
|
664
|
+
if (result) {
|
|
665
|
+
options?.onComplete?.(result);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
catch (error) {
|
|
669
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
670
|
+
options?.onError?.(err);
|
|
671
|
+
}
|
|
672
|
+
})();
|
|
673
|
+
},
|
|
610
674
|
});
|
|
611
675
|
// Set up the extension shortcut handler on the default editor
|
|
612
676
|
this.defaultEditor.onExtensionShortcut = (data) => {
|
|
@@ -1490,6 +1554,11 @@ export class InteractiveMode {
|
|
|
1490
1554
|
});
|
|
1491
1555
|
this.footer.invalidate();
|
|
1492
1556
|
}
|
|
1557
|
+
else if (event.errorMessage) {
|
|
1558
|
+
// Compaction failed (e.g., quota exceeded, API error)
|
|
1559
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
1560
|
+
this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
|
|
1561
|
+
}
|
|
1493
1562
|
void this.flushCompactionQueue({ willRetry: event.willRetry });
|
|
1494
1563
|
this.ui.requestRender();
|
|
1495
1564
|
break;
|
|
@@ -1677,6 +1746,7 @@ export class InteractiveMode {
|
|
|
1677
1746
|
this.ui.requestRender();
|
|
1678
1747
|
}
|
|
1679
1748
|
renderInitialMessages() {
|
|
1749
|
+
this.hasRenderedInitialMessages = true;
|
|
1680
1750
|
// Get aligned messages and entries from session context
|
|
1681
1751
|
const context = this.sessionManager.buildSessionContext();
|
|
1682
1752
|
this.renderSessionContext(context, {
|
|
@@ -2107,6 +2177,8 @@ export class InteractiveMode {
|
|
|
2107
2177
|
hideThinkingBlock: this.hideThinkingBlock,
|
|
2108
2178
|
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
|
2109
2179
|
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
|
2180
|
+
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
2181
|
+
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
|
2110
2182
|
}, {
|
|
2111
2183
|
onAutoCompactChange: (enabled) => {
|
|
2112
2184
|
this.session.setAutoCompactionEnabled(enabled);
|
|
@@ -2173,6 +2245,14 @@ export class InteractiveMode {
|
|
|
2173
2245
|
onDoubleEscapeActionChange: (action) => {
|
|
2174
2246
|
this.settingsManager.setDoubleEscapeAction(action);
|
|
2175
2247
|
},
|
|
2248
|
+
onShowHardwareCursorChange: (enabled) => {
|
|
2249
|
+
this.settingsManager.setShowHardwareCursor(enabled);
|
|
2250
|
+
this.ui.setShowHardwareCursor(enabled);
|
|
2251
|
+
},
|
|
2252
|
+
onEditorPaddingXChange: (padding) => {
|
|
2253
|
+
this.settingsManager.setEditorPaddingX(padding);
|
|
2254
|
+
this.defaultEditor.setPaddingX(padding);
|
|
2255
|
+
},
|
|
2176
2256
|
onCancel: () => {
|
|
2177
2257
|
done();
|
|
2178
2258
|
this.ui.requestRender();
|
|
@@ -2864,8 +2944,11 @@ export class InteractiveMode {
|
|
|
2864
2944
|
const submit = this.getEditorKeyDisplay("submit");
|
|
2865
2945
|
const newLine = this.getEditorKeyDisplay("newLine");
|
|
2866
2946
|
const deleteWordBackward = this.getEditorKeyDisplay("deleteWordBackward");
|
|
2947
|
+
const deleteWordForward = this.getEditorKeyDisplay("deleteWordForward");
|
|
2867
2948
|
const deleteToLineStart = this.getEditorKeyDisplay("deleteToLineStart");
|
|
2868
2949
|
const deleteToLineEnd = this.getEditorKeyDisplay("deleteToLineEnd");
|
|
2950
|
+
const yank = this.getEditorKeyDisplay("yank");
|
|
2951
|
+
const yankPop = this.getEditorKeyDisplay("yankPop");
|
|
2869
2952
|
const tab = this.getEditorKeyDisplay("tab");
|
|
2870
2953
|
// App keybindings
|
|
2871
2954
|
const interrupt = this.getAppKeyDisplay("interrupt");
|
|
@@ -2894,8 +2977,11 @@ export class InteractiveMode {
|
|
|
2894
2977
|
| \`${submit}\` | Send message |
|
|
2895
2978
|
| \`${newLine}\` | New line${process.platform === "win32" ? " (Ctrl+Enter on Windows Terminal)" : ""} |
|
|
2896
2979
|
| \`${deleteWordBackward}\` | Delete word backwards |
|
|
2980
|
+
| \`${deleteWordForward}\` | Delete word forwards |
|
|
2897
2981
|
| \`${deleteToLineStart}\` | Delete to start of line |
|
|
2898
2982
|
| \`${deleteToLineEnd}\` | Delete to end of line |
|
|
2983
|
+
| \`${yank}\` | Paste the most-recently-deleted text |
|
|
2984
|
+
| \`${yankPop}\` | Cycle through the deleted text after pasting |
|
|
2899
2985
|
|
|
2900
2986
|
**Other**
|
|
2901
2987
|
| Key | Action |
|
|
@@ -3087,8 +3173,9 @@ export class InteractiveMode {
|
|
|
3087
3173
|
const compactingLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label);
|
|
3088
3174
|
this.statusContainer.addChild(compactingLoader);
|
|
3089
3175
|
this.ui.requestRender();
|
|
3176
|
+
let result;
|
|
3090
3177
|
try {
|
|
3091
|
-
|
|
3178
|
+
result = await this.session.compact(customInstructions);
|
|
3092
3179
|
// Rebuild UI
|
|
3093
3180
|
this.rebuildChatFromMessages();
|
|
3094
3181
|
// Add compaction component at bottom so user sees it without scrolling
|
|
@@ -3111,6 +3198,7 @@ export class InteractiveMode {
|
|
|
3111
3198
|
this.defaultEditor.onEscape = originalOnEscape;
|
|
3112
3199
|
}
|
|
3113
3200
|
void this.flushCompactionQueue({ willRetry: false });
|
|
3201
|
+
return result;
|
|
3114
3202
|
}
|
|
3115
3203
|
stop() {
|
|
3116
3204
|
if (this.loadingAnimation) {
|