lsd-pi 1.1.4 → 1.1.6
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/README.md +2 -1
- package/dist/headless-ui.js +2 -0
- package/dist/onboarding.js +11 -8
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/await-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/cancel-job-tool.js +7 -0
- package/dist/resources/extensions/cache-timer/index.js +5 -0
- package/dist/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/dist/resources/extensions/codex-rotate/README.md +9 -3
- package/dist/resources/extensions/codex-rotate/commands.js +15 -8
- package/dist/resources/extensions/codex-rotate/index.js +17 -8
- package/dist/resources/extensions/memory/auto-extract.js +196 -80
- package/dist/resources/extensions/memory/dream.js +86 -19
- package/dist/resources/extensions/shared/rtk.js +89 -87
- package/dist/resources/extensions/subagent/index.js +33 -7
- package/dist/startup-model-validation.js +12 -2
- package/dist/update-check.js +2 -2
- package/dist/update-cmd.js +3 -3
- package/dist/welcome-screen.js +43 -14
- package/package.json +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +43 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts +48 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js +173 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +16 -3
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +18 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.js +2 -2
- package/packages/pi-coding-agent/dist/core/tool-approval.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +23 -2
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +50 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js +289 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +36 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +3 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +23 -62
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts +39 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +182 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -77
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +4 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +49 -13
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +27 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +251 -39
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts +10 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts +7 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js.map +1 -0
- package/packages/pi-coding-agent/package.json +9 -4
- package/packages/pi-coding-agent/src/core/agent-session.clear-queue.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +50 -4
- package/packages/pi-coding-agent/src/core/extensions/types.ts +1 -1
- package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
- package/packages/pi-coding-agent/src/core/pty-executor.ts +229 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +16 -3
- package/packages/pi-coding-agent/src/core/settings-manager.ts +27 -0
- package/packages/pi-coding-agent/src/core/tool-approval.ts +2 -2
- package/packages/pi-coding-agent/src/core/tools/index.ts +35 -2
- package/packages/pi-coding-agent/src/core/tools/pty.ts +354 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +37 -24
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +22 -70
- package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +224 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +45 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +104 -81
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +5 -19
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +55 -13
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +296 -48
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +2 -2
- package/packages/pi-coding-agent/src/utils/terminal-screen.ts +77 -0
- package/packages/pi-coding-agent/src/utils/terminal-serializer.ts +72 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js +105 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +4 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +57 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/loader.d.ts +26 -6
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +178 -18
- package/packages/pi-tui/dist/components/loader.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +65 -3
- package/packages/pi-tui/src/components/loader.ts +196 -19
- package/pkg/dist/modes/interactive/theme/themes.js +2 -2
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/cancel-job-tool.ts +8 -0
- package/src/resources/extensions/cache-timer/index.ts +102 -96
- package/src/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/src/resources/extensions/codex-rotate/README.md +9 -3
- package/src/resources/extensions/codex-rotate/commands.ts +335 -329
- package/src/resources/extensions/codex-rotate/index.ts +85 -75
- package/src/resources/extensions/memory/auto-extract.ts +330 -204
- package/src/resources/extensions/memory/dream.ts +88 -21
- package/src/resources/extensions/memory/tests/auto-extract.test.ts +200 -144
- package/src/resources/extensions/shared/rtk.js +112 -0
- package/src/resources/extensions/subagent/index.ts +35 -6
|
@@ -16,6 +16,7 @@ import { allTools } from "../../../core/tools/index.js";
|
|
|
16
16
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "../../../core/tools/truncate.js";
|
|
17
17
|
import { convertToPng } from "../../../utils/image-convert.js";
|
|
18
18
|
import { sanitizeBinaryOutput } from "../../../utils/shell.js";
|
|
19
|
+
import { renderTerminalText } from "../../../utils/terminal-serializer.js";
|
|
19
20
|
import { getLanguageFromPath, highlightCode, theme } from "../theme/theme.js";
|
|
20
21
|
import { type EditorScheme, editorLink } from "../utils/editor-link.js";
|
|
21
22
|
import { shortenPath } from "../utils/shorten-path.js";
|
|
@@ -25,17 +26,9 @@ import { truncateToVisualLines } from "./visual-truncate.js";
|
|
|
25
26
|
|
|
26
27
|
// Preview line limit for bash when not expanded
|
|
27
28
|
const BASH_PREVIEW_LINES = 5;
|
|
28
|
-
// Flash interval for RTK badge animation (ms)
|
|
29
|
-
const RTK_FLASH_INTERVAL_MS = 400;
|
|
30
29
|
// Flash interval for tool status spinner (ms)
|
|
31
30
|
const SPINNER_INTERVAL_MS = 150;
|
|
32
31
|
|
|
33
|
-
/** Returns true when RTK is active in this process. */
|
|
34
|
-
function isRtkEnabled(): boolean {
|
|
35
|
-
const v = (process.env["GSD_RTK_DISABLED"] ?? "").trim().toLowerCase();
|
|
36
|
-
return v !== "1" && v !== "true" && v !== "yes";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
32
|
// Spinner animation frames
|
|
40
33
|
const SPINNER_FRAMES = ["◯", "◔", "◑", "◕", "●"];
|
|
41
34
|
let spinnerFrame = 0;
|
|
@@ -112,9 +105,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
112
105
|
private writeHighlightCache?: WriteHighlightCache;
|
|
113
106
|
// When true, this component intentionally renders no lines
|
|
114
107
|
private hideComponent = false;
|
|
115
|
-
|
|
116
|
-
private rtkFlashOn = true;
|
|
117
|
-
private rtkFlashTimer: NodeJS.Timeout | null = null;
|
|
108
|
+
|
|
118
109
|
// Tool status spinner state
|
|
119
110
|
private spinnerTimer: NodeJS.Timeout | null = null;
|
|
120
111
|
private spinnerFrame = 0;
|
|
@@ -138,8 +129,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
138
129
|
this.cwd = cwd;
|
|
139
130
|
|
|
140
131
|
// Always create both - contentBox for custom tools/bash, contentText for other built-ins
|
|
141
|
-
this.contentBox = new Box(1,
|
|
142
|
-
this.contentText = new Text("", 1,
|
|
132
|
+
this.contentBox = new Box(1, 0, (text: string) => theme.bg("toolPendingBg", text));
|
|
133
|
+
this.contentText = new Text("", 1, 0, (text: string) => theme.bg("toolPendingBg", text));
|
|
143
134
|
|
|
144
135
|
// Use contentBox for bash (visual truncation) or custom tools with custom renderers
|
|
145
136
|
// Use contentText for built-in tools (including overrides without custom renderers)
|
|
@@ -321,12 +312,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
321
312
|
): void {
|
|
322
313
|
this.result = result;
|
|
323
314
|
this.isPartial = isPartial;
|
|
324
|
-
|
|
325
|
-
if (!isPartial && this.rtkFlashTimer) {
|
|
326
|
-
clearInterval(this.rtkFlashTimer);
|
|
327
|
-
this.rtkFlashTimer = null;
|
|
328
|
-
this.rtkFlashOn = false;
|
|
329
|
-
}
|
|
315
|
+
|
|
330
316
|
if (this.toolName === "write" && !isPartial) {
|
|
331
317
|
const rawPath = str(this.args?.file_path ?? this.args?.path);
|
|
332
318
|
const fileContent = str(this.args?.content);
|
|
@@ -393,10 +379,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
393
379
|
}
|
|
394
380
|
|
|
395
381
|
dispose(): void {
|
|
396
|
-
if (this.rtkFlashTimer) {
|
|
397
|
-
clearInterval(this.rtkFlashTimer);
|
|
398
|
-
this.rtkFlashTimer = null;
|
|
399
|
-
}
|
|
400
382
|
if (this.spinnerTimer) {
|
|
401
383
|
clearInterval(this.spinnerTimer);
|
|
402
384
|
this.spinnerTimer = null;
|
|
@@ -412,7 +394,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
412
394
|
if (this.hideComponent) {
|
|
413
395
|
return [];
|
|
414
396
|
}
|
|
415
|
-
return super.render(width);
|
|
397
|
+
return [...super.render(width), ""];
|
|
416
398
|
}
|
|
417
399
|
|
|
418
400
|
private updateDisplay(): void {
|
|
@@ -471,7 +453,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
471
453
|
// Render call component
|
|
472
454
|
if (this.toolDefinition.renderCall) {
|
|
473
455
|
try {
|
|
474
|
-
const callComponent = this.toolDefinition.renderCall(this.args, theme);
|
|
456
|
+
const callComponent = this.toolDefinition.renderCall(this.args, theme, { statusIndicator });
|
|
475
457
|
if (callComponent !== undefined) {
|
|
476
458
|
this.contentBox.addChild(callComponent);
|
|
477
459
|
customRendererHasContent = true;
|
|
@@ -493,8 +475,9 @@ export class ToolExecutionComponent extends Container {
|
|
|
493
475
|
if (this.shouldHideCollapsedPreview()) {
|
|
494
476
|
const output = this.getTextOutput();
|
|
495
477
|
const hasDetails = output.trim().length > 0 || this.imageComponents.length > 0 || this.result.details !== undefined;
|
|
496
|
-
|
|
497
|
-
|
|
478
|
+
const collapsedHint = this.collapsedHintWithPrefix("\n");
|
|
479
|
+
if (hasDetails && collapsedHint) {
|
|
480
|
+
this.contentBox.addChild(new Text(collapsedHint, 0, 0));
|
|
498
481
|
customRendererHasContent = true;
|
|
499
482
|
}
|
|
500
483
|
} else {
|
|
@@ -521,7 +504,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
521
504
|
const output = this.getTextOutput();
|
|
522
505
|
if (output) {
|
|
523
506
|
if (this.shouldHideCollapsedPreview()) {
|
|
524
|
-
this.
|
|
507
|
+
const collapsedHint = this.collapsedHintWithPrefix("\n");
|
|
508
|
+
if (collapsedHint) {
|
|
509
|
+
this.contentBox.addChild(new Text(collapsedHint, 0, 0));
|
|
510
|
+
}
|
|
525
511
|
} else {
|
|
526
512
|
this.contentBox.addChild(new Text(theme.fg("toolOutput", output), 0, 0));
|
|
527
513
|
}
|
|
@@ -591,65 +577,55 @@ export class ToolExecutionComponent extends Container {
|
|
|
591
577
|
private renderBashContent(statusIndicator: string): void {
|
|
592
578
|
const command = str(this.args?.command);
|
|
593
579
|
const timeout = this.args?.timeout as number | undefined;
|
|
594
|
-
const
|
|
580
|
+
const body = new Container();
|
|
595
581
|
|
|
596
|
-
|
|
597
|
-
if (rtkActive && this.isPartial && !this.result && !this.rtkFlashTimer) {
|
|
598
|
-
this.rtkFlashTimer = setInterval(() => {
|
|
599
|
-
this.rtkFlashOn = !this.rtkFlashOn;
|
|
600
|
-
this.updateDisplay();
|
|
601
|
-
this.ui.requestRender();
|
|
602
|
-
}, RTK_FLASH_INTERVAL_MS);
|
|
603
|
-
}
|
|
582
|
+
this.contentBox.addChild(body);
|
|
604
583
|
|
|
605
|
-
// Header with status indicator
|
|
606
584
|
const timeoutSuffix = timeout ? theme.fg("muted", ` (timeout ${timeout}s)`) : "";
|
|
607
585
|
const commandDisplay =
|
|
608
|
-
command === null
|
|
586
|
+
command === null
|
|
587
|
+
? theme.fg("error", "[invalid arg]")
|
|
588
|
+
: command
|
|
589
|
+
? theme.fg("toolOutput", command)
|
|
590
|
+
: theme.fg("toolOutput", "...");
|
|
609
591
|
const sandboxBadge = this.result?.details?.sandboxed ? ` ${theme.fg("success", "[sandboxed]")}` : "";
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
this.contentBox.addChild(
|
|
614
|
-
new Text(`${statusIndicator} ${theme.fg("toolTitle", theme.bold(`$ ${commandDisplay}`))}${timeoutSuffix}${sandboxBadge}${rtkBadge}`, 0, 0),
|
|
615
|
-
);
|
|
592
|
+
const toolLabel = theme.fg("toolTitle", theme.bold("bash"));
|
|
593
|
+
const shellPrompt = theme.fg("muted", "$ ");
|
|
594
|
+
body.addChild(new Text(`${statusIndicator} ${toolLabel} ${shellPrompt}${commandDisplay}${timeoutSuffix}${sandboxBadge}`, 0, 0));
|
|
616
595
|
|
|
617
596
|
if (this.result) {
|
|
618
597
|
const output = this.getTextOutput().trim();
|
|
619
598
|
|
|
620
599
|
if (output) {
|
|
621
|
-
// Style each line for the output
|
|
622
600
|
const styledOutput = output
|
|
623
601
|
.split("\n")
|
|
624
602
|
.map((line) => theme.fg("toolOutput", line))
|
|
625
603
|
.join("\n");
|
|
626
604
|
|
|
627
605
|
if (this.expanded) {
|
|
628
|
-
|
|
629
|
-
this.contentBox.addChild(new Text(`\n${styledOutput}`, 0, 0));
|
|
606
|
+
body.addChild(new Text(`\n${styledOutput}`, 0, 0));
|
|
630
607
|
} else if (this.renderMode === "minimal") {
|
|
631
|
-
this.
|
|
608
|
+
const collapsedHint = this.collapsedHintWithPrefix("\n");
|
|
609
|
+
if (collapsedHint) {
|
|
610
|
+
body.addChild(new Text(collapsedHint, 1, 0));
|
|
611
|
+
}
|
|
632
612
|
} else {
|
|
633
|
-
// Use visual line truncation when collapsed with width-aware caching
|
|
634
613
|
let cachedWidth: number | undefined;
|
|
635
614
|
let cachedLines: string[] | undefined;
|
|
636
615
|
let cachedSkipped: number | undefined;
|
|
637
616
|
|
|
638
|
-
|
|
617
|
+
body.addChild({
|
|
639
618
|
render: (width: number) => {
|
|
640
619
|
if (cachedLines === undefined || cachedWidth !== width) {
|
|
641
|
-
const result = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);
|
|
642
|
-
cachedLines = result.visualLines;
|
|
620
|
+
const result = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, Math.max(1, width - 1));
|
|
621
|
+
cachedLines = result.visualLines.map((line) => ` ${line}`);
|
|
643
622
|
cachedSkipped = result.skippedCount;
|
|
644
623
|
cachedWidth = width;
|
|
645
624
|
}
|
|
646
625
|
if (cachedSkipped && cachedSkipped > 0) {
|
|
647
|
-
const hint =
|
|
648
|
-
|
|
649
|
-
` ${keyHint("expandTools", "to expand")})`;
|
|
650
|
-
return ["", truncateToWidth(hint, width, "..."), ...cachedLines];
|
|
626
|
+
const hint = theme.fg("muted", `... (${cachedSkipped} earlier lines)`);
|
|
627
|
+
return ["", truncateToWidth(` ${hint}`, width, "..."), ...cachedLines];
|
|
651
628
|
}
|
|
652
|
-
// Add blank line for spacing (matches expanded case)
|
|
653
629
|
return ["", ...cachedLines];
|
|
654
630
|
},
|
|
655
631
|
invalidate: () => {
|
|
@@ -661,7 +637,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
661
637
|
}
|
|
662
638
|
}
|
|
663
639
|
|
|
664
|
-
// Truncation warnings
|
|
665
640
|
const truncation = this.result.details?.truncation;
|
|
666
641
|
const fullOutputPath = this.result.details?.fullOutputPath;
|
|
667
642
|
if (truncation?.truncated || fullOutputPath) {
|
|
@@ -678,7 +653,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
678
653
|
);
|
|
679
654
|
}
|
|
680
655
|
}
|
|
681
|
-
|
|
656
|
+
body.addChild(new Text(`\n${theme.fg("warning", `[${warnings.join(". ")}]`)}`, 0, 0));
|
|
682
657
|
}
|
|
683
658
|
}
|
|
684
659
|
}
|
|
@@ -689,13 +664,20 @@ export class ToolExecutionComponent extends Container {
|
|
|
689
664
|
const textBlocks = this.result.content?.filter((c: any) => c.type === "text") || [];
|
|
690
665
|
const imageBlocks = this.result.content?.filter((c: any) => c.type === "image") || [];
|
|
691
666
|
|
|
692
|
-
|
|
667
|
+
let output = textBlocks
|
|
693
668
|
.map((c: any) => {
|
|
694
669
|
// Use sanitizeBinaryOutput to handle binary data that crashes string-width
|
|
695
|
-
return sanitizeBinaryOutput(
|
|
670
|
+
return sanitizeBinaryOutput(c.text || "");
|
|
696
671
|
})
|
|
697
672
|
.join("\n");
|
|
698
673
|
|
|
674
|
+
if (this.toolName === "bash") {
|
|
675
|
+
output = renderTerminalText(output);
|
|
676
|
+
} else {
|
|
677
|
+
output = output.replace(/\r/g, "");
|
|
678
|
+
output = stripAnsi(output);
|
|
679
|
+
}
|
|
680
|
+
|
|
699
681
|
const caps = getCapabilities();
|
|
700
682
|
if (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {
|
|
701
683
|
const imageIndicators = imageBlocks
|
|
@@ -718,8 +700,13 @@ export class ToolExecutionComponent extends Container {
|
|
|
718
700
|
return !this.expanded && this.renderMode === "minimal" && !this.result?.isError;
|
|
719
701
|
}
|
|
720
702
|
|
|
721
|
-
private collapsedExpandHint(
|
|
722
|
-
return
|
|
703
|
+
private collapsedExpandHint(_label?: string): string {
|
|
704
|
+
return ""; // hint is shown in editor bottom border instead
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
private collapsedHintWithPrefix(prefix = "\n\n"): string {
|
|
708
|
+
const hint = this.collapsedExpandHint();
|
|
709
|
+
return hint ? `${prefix}${hint}` : "";
|
|
723
710
|
}
|
|
724
711
|
|
|
725
712
|
private collapsedFirstLine(output: string): string | undefined {
|
|
@@ -763,7 +750,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
763
750
|
|
|
764
751
|
if (hideCollapsedPreview) {
|
|
765
752
|
if (output.trim()) {
|
|
766
|
-
text +=
|
|
753
|
+
text += this.collapsedHintWithPrefix();
|
|
767
754
|
}
|
|
768
755
|
} else {
|
|
769
756
|
const maxLines = this.expanded ? lines.length : 10;
|
|
@@ -776,7 +763,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
776
763
|
.map((line: string) => (lang ? replaceTabs(line) : theme.fg("toolOutput", replaceTabs(line))))
|
|
777
764
|
.join("\n");
|
|
778
765
|
if (remaining > 0) {
|
|
779
|
-
text +=
|
|
766
|
+
text += theme.fg("muted", `\n... (${remaining} more lines)`);
|
|
780
767
|
}
|
|
781
768
|
}
|
|
782
769
|
|
|
@@ -845,7 +832,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
845
832
|
}
|
|
846
833
|
|
|
847
834
|
if (hideCollapsedPreview) {
|
|
848
|
-
text +=
|
|
835
|
+
text += this.collapsedHintWithPrefix();
|
|
849
836
|
} else {
|
|
850
837
|
const totalLines = lines.length;
|
|
851
838
|
const maxLines = this.expanded ? lines.length : 10;
|
|
@@ -856,9 +843,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
856
843
|
"\n\n" +
|
|
857
844
|
displayLines.map((line: string) => (lang ? line : theme.fg("toolOutput", replaceTabs(line)))).join("\n");
|
|
858
845
|
if (remaining > 0) {
|
|
859
|
-
text +=
|
|
860
|
-
theme.fg("muted", `\n... (${remaining} more lines, ${totalLines} total,`) +
|
|
861
|
-
` ${keyHint("expandTools", "to expand")})`;
|
|
846
|
+
text += theme.fg("muted", `\n... (${remaining} more lines, ${totalLines} total)`);
|
|
862
847
|
}
|
|
863
848
|
}
|
|
864
849
|
}
|
|
@@ -907,7 +892,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
907
892
|
// This takes priority over editDiffPreview which may have a stale error
|
|
908
893
|
// due to race condition (async preview computed after file was modified)
|
|
909
894
|
text += hideCollapsedPreview
|
|
910
|
-
?
|
|
895
|
+
? this.collapsedHintWithPrefix()
|
|
911
896
|
: `\n\n${renderDiff(this.result.details.diff, { filePath: rawPath ?? undefined })}`;
|
|
912
897
|
} else if (this.editDiffPreview) {
|
|
913
898
|
// Use cached diff preview (before tool executes)
|
|
@@ -915,7 +900,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
915
900
|
text += `\n\n${theme.fg("error", this.editDiffPreview.error)}`;
|
|
916
901
|
} else if (this.editDiffPreview.diff) {
|
|
917
902
|
text += hideCollapsedPreview
|
|
918
|
-
?
|
|
903
|
+
? this.collapsedHintWithPrefix()
|
|
919
904
|
: `\n\n${renderDiff(this.editDiffPreview.diff, { filePath: rawPath ?? undefined })}`;
|
|
920
905
|
}
|
|
921
906
|
}
|
|
@@ -937,7 +922,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
937
922
|
const output = this.getTextOutput().trim();
|
|
938
923
|
if (output) {
|
|
939
924
|
if (hideCollapsedPreview) {
|
|
940
|
-
text +=
|
|
925
|
+
text += this.collapsedHintWithPrefix();
|
|
941
926
|
} else {
|
|
942
927
|
const lines = output.split("\n");
|
|
943
928
|
const maxLines = this.expanded ? lines.length : 20;
|
|
@@ -946,7 +931,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
946
931
|
|
|
947
932
|
text += `\n\n${displayLines.map((line: string) => theme.fg("toolOutput", line)).join("\n")}`;
|
|
948
933
|
if (remaining > 0) {
|
|
949
|
-
text +=
|
|
934
|
+
text += theme.fg("muted", `\n... (${remaining} more lines)`);
|
|
950
935
|
}
|
|
951
936
|
}
|
|
952
937
|
}
|
|
@@ -990,7 +975,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
990
975
|
const output = this.getTextOutput().trim();
|
|
991
976
|
if (output) {
|
|
992
977
|
if (hideCollapsedPreview) {
|
|
993
|
-
text +=
|
|
978
|
+
text += this.collapsedHintWithPrefix();
|
|
994
979
|
} else {
|
|
995
980
|
const lines = output.split("\n");
|
|
996
981
|
const maxLines = this.expanded ? lines.length : 20;
|
|
@@ -999,7 +984,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
999
984
|
|
|
1000
985
|
text += `\n\n${displayLines.map((line: string) => theme.fg("toolOutput", line)).join("\n")}`;
|
|
1001
986
|
if (remaining > 0) {
|
|
1002
|
-
text +=
|
|
987
|
+
text += theme.fg("muted", `\n... (${remaining} more lines)`);
|
|
1003
988
|
}
|
|
1004
989
|
}
|
|
1005
990
|
}
|
|
@@ -1047,7 +1032,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1047
1032
|
const output = this.getTextOutput().trim();
|
|
1048
1033
|
if (output) {
|
|
1049
1034
|
if (hideCollapsedPreview) {
|
|
1050
|
-
text +=
|
|
1035
|
+
text += this.collapsedHintWithPrefix();
|
|
1051
1036
|
} else {
|
|
1052
1037
|
const lines = output.split("\n");
|
|
1053
1038
|
const maxLines = this.expanded ? lines.length : 15;
|
|
@@ -1056,7 +1041,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1056
1041
|
|
|
1057
1042
|
text += `\n\n${displayLines.map((line: string) => theme.fg("toolOutput", line)).join("\n")}`;
|
|
1058
1043
|
if (remaining > 0) {
|
|
1059
|
-
text +=
|
|
1044
|
+
text += theme.fg("muted", `\n... (${remaining} more lines)`);
|
|
1060
1045
|
}
|
|
1061
1046
|
}
|
|
1062
1047
|
}
|
|
@@ -1088,7 +1073,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
1088
1073
|
const output = this.getTextOutput().trim();
|
|
1089
1074
|
if (output) {
|
|
1090
1075
|
if (hideCollapsedPreview) {
|
|
1091
|
-
text +=
|
|
1076
|
+
text += this.collapsedHintWithPrefix();
|
|
1092
1077
|
} else {
|
|
1093
1078
|
const lines = output.split("\n");
|
|
1094
1079
|
const maxLines = this.expanded ? lines.length : 10;
|
|
@@ -1097,17 +1082,55 @@ export class ToolExecutionComponent extends Container {
|
|
|
1097
1082
|
|
|
1098
1083
|
text += `\n\n${displayLines.map((line: string) => theme.fg("toolOutput", line)).join("\n")}`;
|
|
1099
1084
|
if (remaining > 0) {
|
|
1100
|
-
text +=
|
|
1085
|
+
text += theme.fg("muted", `\n... (${remaining} more lines)`);
|
|
1101
1086
|
}
|
|
1102
1087
|
}
|
|
1103
1088
|
}
|
|
1104
1089
|
}
|
|
1090
|
+
} else if (this.toolName === "lsp") {
|
|
1091
|
+
const action = this.args?.action as string | undefined;
|
|
1092
|
+
const file = this.args?.file as string | undefined;
|
|
1093
|
+
const line = this.args?.line as number | undefined;
|
|
1094
|
+
const symbol = this.args?.symbol as string | undefined;
|
|
1095
|
+
const query = this.args?.query as string | undefined;
|
|
1096
|
+
const newName = this.args?.new_name as string | undefined;
|
|
1097
|
+
|
|
1098
|
+
text = `${statusIndicator} ${theme.fg("toolTitle", theme.bold("lsp"))}`;
|
|
1099
|
+
if (action) text += ` ${theme.fg("accent", action)}`;
|
|
1100
|
+
if (file) {
|
|
1101
|
+
const shortFile = shortenPath(file);
|
|
1102
|
+
let styledFile = theme.fg("muted", shortFile);
|
|
1103
|
+
if (file && shortFile) {
|
|
1104
|
+
styledFile = editorLink(file, styledFile, { cwd: this.cwd, line, scheme: this.editorScheme });
|
|
1105
|
+
}
|
|
1106
|
+
text += ` ${styledFile}`;
|
|
1107
|
+
if (line !== undefined) text += theme.fg("warning", `:${line}`);
|
|
1108
|
+
}
|
|
1109
|
+
if (symbol) text += ` ${theme.fg("toolOutput", symbol)}`;
|
|
1110
|
+
if (query) text += ` ${theme.fg("muted", `"${query}"`)}`;
|
|
1111
|
+
if (newName) text += ` → ${theme.fg("accent", newName)}`;
|
|
1112
|
+
|
|
1113
|
+
if (this.result) {
|
|
1114
|
+
const output = this.getTextOutput().trim();
|
|
1115
|
+
if (output) {
|
|
1116
|
+
if (hideCollapsedPreview) {
|
|
1117
|
+
text += this.collapsedHintWithPrefix();
|
|
1118
|
+
} else {
|
|
1119
|
+
const lines = output.split("\n");
|
|
1120
|
+
const maxLines = this.expanded ? lines.length : 10;
|
|
1121
|
+
const displayLines = lines.slice(0, maxLines);
|
|
1122
|
+
const remaining = lines.length - maxLines;
|
|
1123
|
+
text += `\n\n${displayLines.map((l: string) => theme.fg("toolOutput", l)).join("\n")}`;
|
|
1124
|
+
if (remaining > 0) text += theme.fg("muted", `\n... (${remaining} more lines)`);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1105
1128
|
} else {
|
|
1106
1129
|
// Generic tool (shouldn't reach here for custom tools)
|
|
1107
1130
|
text = `${statusIndicator} ${theme.fg("toolTitle", theme.bold(this.toolName))}`;
|
|
1108
1131
|
|
|
1109
1132
|
const content = JSON.stringify(this.args, null, 2);
|
|
1110
|
-
text += hideCollapsedPreview ?
|
|
1133
|
+
text += hideCollapsedPreview ? this.collapsedHintWithPrefix() : `\n\n${content}`;
|
|
1111
1134
|
const output = this.getTextOutput();
|
|
1112
1135
|
if (output && !hideCollapsedPreview) {
|
|
1113
1136
|
text += `\n${output}`;
|
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
import { Container, Markdown, type MarkdownTheme, Spacer
|
|
1
|
+
import { Container, Markdown, type MarkdownTheme, Spacer } from "@gsd/pi-tui";
|
|
2
2
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
|
-
import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
|
|
4
3
|
|
|
5
4
|
const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
6
5
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* Component that renders a user message with a
|
|
8
|
+
* Component that renders a user message with a visual prompt marker.
|
|
10
9
|
*/
|
|
11
10
|
export class UserMessageComponent extends Container {
|
|
12
|
-
|
|
13
|
-
private timestampFormat: TimestampFormat;
|
|
14
|
-
|
|
15
|
-
constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), timestamp?: number, timestampFormat: TimestampFormat = "date-time-iso") {
|
|
11
|
+
constructor(text: string, markdownTheme: MarkdownTheme = getMarkdownTheme(), _timestamp?: number, _timestampFormat: string = "date-time-iso") {
|
|
16
12
|
super();
|
|
17
|
-
this.timestamp = timestamp;
|
|
18
|
-
this.timestampFormat = timestampFormat;
|
|
19
13
|
this.addChild(new Spacer(1));
|
|
14
|
+
const promptMarker = `${theme.fg("accent", "▶")} `;
|
|
20
15
|
this.addChild(
|
|
21
|
-
new Markdown(text
|
|
16
|
+
new Markdown(`${promptMarker}${text}`, 1, 1, markdownTheme, {
|
|
22
17
|
bgColor: (text: string) => theme.bg("userMessageBg", text),
|
|
23
18
|
color: (text: string) => theme.fg("userMessageText", text),
|
|
24
19
|
}),
|
|
@@ -31,15 +26,6 @@ export class UserMessageComponent extends Container {
|
|
|
31
26
|
return lines;
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
// Timestamp display removed
|
|
35
|
-
// if (this.timestamp) {
|
|
36
|
-
// const timeStr = formatTimestamp(this.timestamp, this.timestampFormat);
|
|
37
|
-
// const label = theme.fg("dim", timeStr);
|
|
38
|
-
// const padding = Math.max(0, width - timeStr.length - 1);
|
|
39
|
-
// const timestampLine = " ".repeat(padding) + label;
|
|
40
|
-
// lines.splice(0, 0, timestampLine);
|
|
41
|
-
// }
|
|
42
|
-
|
|
43
29
|
lines[0] = OSC133_ZONE_START + lines[0];
|
|
44
30
|
lines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;
|
|
45
31
|
return lines;
|
|
@@ -20,6 +20,11 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
20
20
|
updatePendingMessagesDisplay: () => void;
|
|
21
21
|
updateTerminalTitle: () => void;
|
|
22
22
|
updateEditorBorderColor: () => void;
|
|
23
|
+
updateEditorExpandHint: () => void;
|
|
24
|
+
getAgentPtyComponent: (sessionId: string) => any;
|
|
25
|
+
ensureAgentPtyComponent: (sessionId: string, command?: string) => any;
|
|
26
|
+
updateAgentPtyComponent: (sessionId: string, options?: { command?: string; screenText?: string; completed?: boolean; cancelled?: boolean; exitCode?: number }) => void;
|
|
27
|
+
clearAgentPtyComponents: () => void;
|
|
23
28
|
pendingMessagesContainer: { clear: () => void };
|
|
24
29
|
}, event: InteractiveModeEvent): Promise<void> {
|
|
25
30
|
if (!host.isInitialized) {
|
|
@@ -37,6 +42,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
37
42
|
host.streamingComponent = undefined;
|
|
38
43
|
host.streamingMessage = undefined;
|
|
39
44
|
host.pendingTools.clear();
|
|
45
|
+
host.clearAgentPtyComponents();
|
|
40
46
|
host.pendingMessagesContainer.clear();
|
|
41
47
|
host.compactionQueuedMessages = [];
|
|
42
48
|
host.rebuildChatFromMessages();
|
|
@@ -73,19 +79,14 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
73
79
|
host.statusContainer.clear();
|
|
74
80
|
host.loadingAnimation = new Loader(
|
|
75
81
|
host.ui,
|
|
76
|
-
(spinner) => theme.fg("
|
|
77
|
-
(text) => theme.fg("
|
|
82
|
+
(spinner) => theme.fg("text", spinner),
|
|
83
|
+
(text) => theme.fg("accent", text),
|
|
78
84
|
host.defaultWorkingMessage,
|
|
79
85
|
);
|
|
86
|
+
host.loadingAnimation.setCycleMessages(host.workingMessages, 3000);
|
|
80
87
|
host.statusContainer.addChild(host.loadingAnimation);
|
|
81
|
-
// Show steer/queue hint in editor bottom border while agent is running
|
|
82
|
-
|
|
83
|
-
const enterKey = theme.fg("dim", "↵");
|
|
84
|
-
const followUpKey = theme.fg("dim", appKey(host.keybindings, "followUp"));
|
|
85
|
-
const steerLabel = theme.fg("muted", " steer");
|
|
86
|
-
const queueLabel = theme.fg("muted", " queue");
|
|
87
|
-
host.defaultEditor.bottomHint = `${enterKey}${steerLabel} ${followUpKey}${queueLabel}`;
|
|
88
|
-
}
|
|
88
|
+
// Show steer/queue + expand hint in editor bottom border while agent is running
|
|
89
|
+
host.updateEditorExpandHint();
|
|
89
90
|
if (host.pendingWorkingMessage !== undefined) {
|
|
90
91
|
if (host.pendingWorkingMessage) {
|
|
91
92
|
host.loadingAnimation.setMessage(host.pendingWorkingMessage);
|
|
@@ -109,6 +110,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
109
110
|
host.hideThinkingBlock,
|
|
110
111
|
host.getMarkdownThemeWithSettings(),
|
|
111
112
|
host.settingsManager.getTimestampFormat(),
|
|
113
|
+
host.session?.thinkingLevel || "off",
|
|
112
114
|
);
|
|
113
115
|
host.streamingMessage = event.message;
|
|
114
116
|
host.chatContainer.addChild(host.streamingComponent);
|
|
@@ -123,6 +125,9 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
123
125
|
host.streamingComponent.updateContent(host.streamingMessage);
|
|
124
126
|
for (const content of host.streamingMessage.content) {
|
|
125
127
|
if (content.type === "toolCall") {
|
|
128
|
+
if (content.name === "pty_start" || content.name === "pty_send" || content.name === "pty_read" || content.name === "pty_wait" || content.name === "pty_resize" || content.name === "pty_kill") {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
126
131
|
if (!host.pendingTools.has(content.id)) {
|
|
127
132
|
const component = new ToolExecutionComponent(
|
|
128
133
|
content.name,
|
|
@@ -215,6 +220,12 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
215
220
|
break;
|
|
216
221
|
|
|
217
222
|
case "tool_execution_start":
|
|
223
|
+
if (event.toolName === "pty_start") {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (event.toolName === "pty_send" || event.toolName === "pty_read" || event.toolName === "pty_wait" || event.toolName === "pty_resize" || event.toolName === "pty_kill") {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
218
229
|
if (!host.pendingTools.has(event.toolCallId)) {
|
|
219
230
|
const component = new ToolExecutionComponent(
|
|
220
231
|
event.toolName,
|
|
@@ -235,6 +246,21 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
235
246
|
break;
|
|
236
247
|
|
|
237
248
|
case "tool_execution_update": {
|
|
249
|
+
if (event.toolName === "pty_start" || event.toolName === "pty_send" || event.toolName === "pty_read" || event.toolName === "pty_wait" || event.toolName === "pty_resize" || event.toolName === "pty_kill") {
|
|
250
|
+
const details = event.partialResult?.details as { sessionId?: string; screenText?: string; exitCode?: number; cancelled?: boolean; completed?: boolean } | undefined;
|
|
251
|
+
const sessionId = details?.sessionId ?? (event.args as { sessionId?: string } | undefined)?.sessionId;
|
|
252
|
+
if (sessionId) {
|
|
253
|
+
host.updateAgentPtyComponent(sessionId, {
|
|
254
|
+
command: event.toolName === "pty_start" ? (event.args as { command?: string } | undefined)?.command : undefined,
|
|
255
|
+
screenText: details?.screenText,
|
|
256
|
+
completed: details?.completed,
|
|
257
|
+
cancelled: details?.cancelled,
|
|
258
|
+
exitCode: details?.exitCode,
|
|
259
|
+
});
|
|
260
|
+
host.ui.requestRender();
|
|
261
|
+
}
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
238
264
|
const component = host.pendingTools.get(event.toolCallId);
|
|
239
265
|
if (component) {
|
|
240
266
|
component.updateResult({ ...event.partialResult, isError: false }, true);
|
|
@@ -244,6 +270,21 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
244
270
|
}
|
|
245
271
|
|
|
246
272
|
case "tool_execution_end": {
|
|
273
|
+
if (event.toolName === "pty_start" || event.toolName === "pty_send" || event.toolName === "pty_read" || event.toolName === "pty_wait" || event.toolName === "pty_resize" || event.toolName === "pty_kill") {
|
|
274
|
+
const details = event.result?.details as { sessionId?: string; screenText?: string; exitCode?: number; cancelled?: boolean; completed?: boolean } | undefined;
|
|
275
|
+
const sessionId = details?.sessionId;
|
|
276
|
+
if (sessionId) {
|
|
277
|
+
host.updateAgentPtyComponent(sessionId, {
|
|
278
|
+
command: undefined,
|
|
279
|
+
screenText: details?.screenText,
|
|
280
|
+
completed: event.toolName === "pty_kill" || !!details?.completed,
|
|
281
|
+
cancelled: details?.cancelled ?? event.toolName === "pty_kill",
|
|
282
|
+
exitCode: details?.exitCode,
|
|
283
|
+
});
|
|
284
|
+
host.ui.requestRender();
|
|
285
|
+
}
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
247
288
|
const component = host.pendingTools.get(event.toolCallId);
|
|
248
289
|
if (component) {
|
|
249
290
|
component.updateResult({ ...event.result, isError: event.isError });
|
|
@@ -265,8 +306,9 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
265
306
|
host.streamingMessage = undefined;
|
|
266
307
|
}
|
|
267
308
|
host.pendingTools.clear();
|
|
268
|
-
//
|
|
309
|
+
// Update hint: show expand/collapse if tool outputs exist, else clear
|
|
269
310
|
host.defaultEditor.bottomHint = "";
|
|
311
|
+
host.updateEditorExpandHint();
|
|
270
312
|
await host.checkShutdownRequested();
|
|
271
313
|
host.ui.requestRender();
|
|
272
314
|
break;
|
|
@@ -277,7 +319,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
277
319
|
host.statusContainer.clear();
|
|
278
320
|
host.autoCompactionLoader = new Loader(
|
|
279
321
|
host.ui,
|
|
280
|
-
(spinner) => theme.fg("
|
|
322
|
+
(spinner) => theme.fg("text", spinner),
|
|
281
323
|
(text) => theme.fg("muted", text),
|
|
282
324
|
`${event.reason === "overflow" ? "Context overflow detected, " : ""}Auto-compacting... (${appKey(host.keybindings, "interrupt")} to cancel)`,
|
|
283
325
|
);
|
|
@@ -323,7 +365,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
323
365
|
host.statusContainer.clear();
|
|
324
366
|
host.retryLoader = new Loader(
|
|
325
367
|
host.ui,
|
|
326
|
-
(spinner) => theme.fg("
|
|
368
|
+
(spinner) => theme.fg("text", spinner),
|
|
327
369
|
(text) => theme.fg("muted", text),
|
|
328
370
|
`Retrying (${event.attempt}/${event.maxAttempts}) in ${Math.round(event.delayMs / 1000)}s... (${appKey(host.keybindings, "interrupt")} to cancel)`,
|
|
329
371
|
);
|
package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts
CHANGED
|
@@ -17,6 +17,7 @@ export function createExtensionUIContext(host: any): ExtensionUIContext {
|
|
|
17
17
|
host.loadingAnimation.setMessage(message);
|
|
18
18
|
} else {
|
|
19
19
|
host.loadingAnimation.setMessage(`${host.defaultWorkingMessage} (${appKey(host.keybindings, "interrupt")} to interrupt)`);
|
|
20
|
+
host.loadingAnimation.resumeCycle();
|
|
20
21
|
}
|
|
21
22
|
} else {
|
|
22
23
|
host.pendingWorkingMessage = message;
|
|
@@ -56,6 +56,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
56
56
|
if (host.session.isStreaming) {
|
|
57
57
|
host.editor.addToHistory?.(text);
|
|
58
58
|
host.editor.setText("");
|
|
59
|
+
host.recordLastSentPrompt?.(text);
|
|
59
60
|
await host.session.prompt(text, { streamingBehavior: "steer" });
|
|
60
61
|
host.updatePendingMessagesDisplay();
|
|
61
62
|
host.ui.requestRender();
|
|
@@ -72,6 +73,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
72
73
|
|
|
73
74
|
if (host.options?.submitPromptsDirectly) {
|
|
74
75
|
host.editor.addToHistory?.(text);
|
|
76
|
+
host.recordLastSentPrompt?.(text);
|
|
75
77
|
try {
|
|
76
78
|
await host.session.prompt(text);
|
|
77
79
|
} catch (error: unknown) {
|
|
@@ -19,6 +19,7 @@ export interface InteractiveModeStateHost {
|
|
|
19
19
|
loadingAnimation?: any;
|
|
20
20
|
pendingWorkingMessage?: string;
|
|
21
21
|
defaultWorkingMessage: string;
|
|
22
|
+
workingMessages: string[];
|
|
22
23
|
streamingComponent?: any;
|
|
23
24
|
streamingMessage?: any;
|
|
24
25
|
retryEscapeHandler?: () => void;
|
|
@@ -31,6 +32,8 @@ export interface InteractiveModeStateHost {
|
|
|
31
32
|
extensionEditor?: any;
|
|
32
33
|
editorContainer: any;
|
|
33
34
|
keybindingsManager?: any;
|
|
35
|
+
updateEditorExpandHint(): void;
|
|
36
|
+
recordLastSentPrompt?(text: string): void;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export type InteractiveModeEvent = AgentSessionEvent;
|