@averyyy/pi-coding-agent 0.85.1-piclient.1 → 0.85.1-piclient.3
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 +3 -0
- package/dist/bundle/chunks/{chunk-ZNXRLOMG.js → chunk-LQDML2ZO.js} +61 -54
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +21 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +26 -7
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +212 -114
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/pi-server-client.d.ts +4 -0
- package/dist/core/pi-server-client.d.ts.map +1 -1
- package/dist/core/pi-server-client.js +162 -46
- package/dist/core/pi-server-client.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +17 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +236 -44
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/package.json +4 -4
|
@@ -254,6 +254,8 @@ export class InteractiveMode {
|
|
|
254
254
|
// Agent subscription unsubscribe function
|
|
255
255
|
unsubscribe;
|
|
256
256
|
signalCleanupHandlers = [];
|
|
257
|
+
abortInputListenerCleanup;
|
|
258
|
+
abortingStatusActive = false;
|
|
257
259
|
// Track if editor is in bash mode (text starts with !)
|
|
258
260
|
isBashMode = false;
|
|
259
261
|
// Track current bash execution component
|
|
@@ -296,6 +298,9 @@ export class InteractiveMode {
|
|
|
296
298
|
get session() {
|
|
297
299
|
return this.runtimeHost.session;
|
|
298
300
|
}
|
|
301
|
+
get sessionAbortError() {
|
|
302
|
+
return this.session.abortError;
|
|
303
|
+
}
|
|
299
304
|
get agent() {
|
|
300
305
|
return this.session.agent;
|
|
301
306
|
}
|
|
@@ -582,6 +587,7 @@ export class InteractiveMode {
|
|
|
582
587
|
}
|
|
583
588
|
this.renderer = nextUi;
|
|
584
589
|
this.options.tuiMode = mode;
|
|
590
|
+
this.bindAbortInputListener();
|
|
585
591
|
this.mountInteractiveTui(nextUi, components);
|
|
586
592
|
nextUi.invalidate();
|
|
587
593
|
nextUi.setFocus(focus);
|
|
@@ -648,6 +654,7 @@ export class InteractiveMode {
|
|
|
648
654
|
this.ui.setFocus(this.editor);
|
|
649
655
|
// Start the UI before initializing extensions so session_start handlers can use interactive dialogs
|
|
650
656
|
this.ui.start();
|
|
657
|
+
this.bindAbortInputListener();
|
|
651
658
|
this.isInitialized = true;
|
|
652
659
|
await this.themeController.applyFromSettings();
|
|
653
660
|
// Add header with keybindings from config (unless silenced)
|
|
@@ -836,7 +843,7 @@ export class InteractiveMode {
|
|
|
836
843
|
while (true) {
|
|
837
844
|
const userInput = await this.getUserInput();
|
|
838
845
|
try {
|
|
839
|
-
await this.session.prompt(userInput);
|
|
846
|
+
await this.session.prompt(userInput, this.session.isStreaming || this.session.isAborting ? { streamingBehavior: "steer" } : undefined);
|
|
840
847
|
}
|
|
841
848
|
catch (error) {
|
|
842
849
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -1618,14 +1625,14 @@ export class InteractiveMode {
|
|
|
1618
1625
|
this.footerDataProvider.setExtensionStatus(key, text);
|
|
1619
1626
|
this.ui.requestRender();
|
|
1620
1627
|
}
|
|
1621
|
-
|
|
1622
|
-
this.
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1628
|
+
showStatusIndicator(indicator, force = false) {
|
|
1629
|
+
if (this.session.isAborting && !force) {
|
|
1630
|
+
indicator.dispose();
|
|
1631
|
+
if (!this.abortingStatusActive) {
|
|
1632
|
+
this.showAbortingStatusIndicator();
|
|
1633
|
+
}
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1629
1636
|
this.activeStatusIndicator?.dispose();
|
|
1630
1637
|
this.activeStatusIndicator = indicator;
|
|
1631
1638
|
this.activeWorkingIndicatorEmbedded = false;
|
|
@@ -1637,12 +1644,38 @@ export class InteractiveMode {
|
|
|
1637
1644
|
}
|
|
1638
1645
|
this.statusContainer.addChild(indicator);
|
|
1639
1646
|
}
|
|
1640
|
-
|
|
1647
|
+
setEditorWorkingStatusIndicator(indicator) {
|
|
1648
|
+
this.defaultEditor.setWorkingStatusIndicator(undefined);
|
|
1649
|
+
if (!isWorkingStatusEditor(this.editor))
|
|
1650
|
+
return false;
|
|
1651
|
+
this.editor.setWorkingStatusIndicator(indicator);
|
|
1652
|
+
return true;
|
|
1653
|
+
}
|
|
1654
|
+
showAbortingStatusIndicator() {
|
|
1655
|
+
if (this.sessionAbortError) {
|
|
1656
|
+
this.showCancellationFailedStatusIndicator();
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
this.abortingStatusActive = true;
|
|
1660
|
+
this.showStatusIndicator(new WorkingStatusIndicator(this.ui, "Aborting..."), true);
|
|
1661
|
+
this.ui.requestRender();
|
|
1662
|
+
}
|
|
1663
|
+
showCancellationFailedStatusIndicator() {
|
|
1664
|
+
this.abortingStatusActive = true;
|
|
1665
|
+
this.showStatusIndicator(new WorkingStatusIndicator(this.ui, `Cancellation not confirmed (${keyText("app.interrupt")} to retry)`), true);
|
|
1666
|
+
this.ui.requestRender();
|
|
1667
|
+
}
|
|
1668
|
+
clearStatusIndicator(kind, force = false) {
|
|
1669
|
+
if (this.session.isAborting && !force) {
|
|
1670
|
+
this.showAbortingStatusIndicator();
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1641
1673
|
if (kind && this.activeStatusIndicator?.kind !== kind) {
|
|
1642
1674
|
return;
|
|
1643
1675
|
}
|
|
1644
1676
|
const clearedIndicator = this.activeStatusIndicator;
|
|
1645
1677
|
const clearedIndicatorWasEmbedded = clearedIndicator?.kind === "working" && this.activeWorkingIndicatorEmbedded;
|
|
1678
|
+
this.abortingStatusActive = false;
|
|
1646
1679
|
clearedIndicator?.dispose();
|
|
1647
1680
|
this.activeStatusIndicator = undefined;
|
|
1648
1681
|
this.activeWorkingIndicatorEmbedded = false;
|
|
@@ -1674,6 +1707,10 @@ export class InteractiveMode {
|
|
|
1674
1707
|
}
|
|
1675
1708
|
setWorkingVisible(visible) {
|
|
1676
1709
|
this.workingVisible = visible;
|
|
1710
|
+
if (this.session.isAborting) {
|
|
1711
|
+
this.showAbortingStatusIndicator();
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1677
1714
|
if (!visible) {
|
|
1678
1715
|
this.clearStatusIndicator("working");
|
|
1679
1716
|
this.ui.requestRender();
|
|
@@ -1684,6 +1721,22 @@ export class InteractiveMode {
|
|
|
1684
1721
|
}
|
|
1685
1722
|
this.ui.requestRender();
|
|
1686
1723
|
}
|
|
1724
|
+
refreshStatusIndicator() {
|
|
1725
|
+
if (this.session.isAborting) {
|
|
1726
|
+
this.showAbortingStatusIndicator();
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
if (this.session.isStreaming) {
|
|
1730
|
+
if (this.workingVisible) {
|
|
1731
|
+
this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));
|
|
1732
|
+
}
|
|
1733
|
+
else {
|
|
1734
|
+
this.clearStatusIndicator(undefined, true);
|
|
1735
|
+
}
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1738
|
+
this.clearStatusIndicator(undefined, true);
|
|
1739
|
+
}
|
|
1687
1740
|
setWorkingIndicator(options) {
|
|
1688
1741
|
this.workingIndicatorOptions = options;
|
|
1689
1742
|
if (this.activeStatusIndicator?.kind === "working") {
|
|
@@ -1776,7 +1829,7 @@ export class InteractiveMode {
|
|
|
1776
1829
|
this.workingMessage = undefined;
|
|
1777
1830
|
this.workingVisible = true;
|
|
1778
1831
|
this.setWorkingIndicator();
|
|
1779
|
-
if (this.activeStatusIndicator?.kind === "working") {
|
|
1832
|
+
if (this.activeStatusIndicator?.kind === "working" && !this.session.isAborting) {
|
|
1780
1833
|
this.activeStatusIndicator.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
|
|
1781
1834
|
}
|
|
1782
1835
|
this.setHiddenThinkingLabel();
|
|
@@ -1884,6 +1937,23 @@ export class InteractiveMode {
|
|
|
1884
1937
|
subscription.unsubscribe = this.ui.addInputListener(subscription.handler);
|
|
1885
1938
|
}
|
|
1886
1939
|
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Keep repeated interrupts from reaching editors or extension input handlers
|
|
1942
|
+
* while the session is completing an abort. Other input remains available so
|
|
1943
|
+
* prompts submitted during this window can be queued by AgentSession.
|
|
1944
|
+
*/
|
|
1945
|
+
bindAbortInputListener() {
|
|
1946
|
+
this.abortInputListenerCleanup?.();
|
|
1947
|
+
this.abortInputListenerCleanup = this.ui.addInputListener((data) => {
|
|
1948
|
+
if (this.session.isAborting && this.keybindings.matches(data, "app.interrupt")) {
|
|
1949
|
+
if (this.sessionAbortError) {
|
|
1950
|
+
this.requestAbort();
|
|
1951
|
+
}
|
|
1952
|
+
return { consume: true };
|
|
1953
|
+
}
|
|
1954
|
+
return undefined;
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1887
1957
|
clearExtensionTerminalInputListeners() {
|
|
1888
1958
|
for (const subscription of this.extensionTerminalInputSubscriptions)
|
|
1889
1959
|
subscription.unsubscribe();
|
|
@@ -1916,7 +1986,7 @@ export class InteractiveMode {
|
|
|
1916
1986
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
1917
1987
|
setWorkingMessage: (message) => {
|
|
1918
1988
|
this.workingMessage = message;
|
|
1919
|
-
if (this.activeStatusIndicator?.kind === "working") {
|
|
1989
|
+
if (this.activeStatusIndicator?.kind === "working" && !this.session.isAborting) {
|
|
1920
1990
|
this.activeStatusIndicator.setMessage(message ?? this.defaultWorkingMessage);
|
|
1921
1991
|
}
|
|
1922
1992
|
},
|
|
@@ -2259,10 +2329,31 @@ export class InteractiveMode {
|
|
|
2259
2329
|
// =========================================================================
|
|
2260
2330
|
// Key Handlers
|
|
2261
2331
|
// =========================================================================
|
|
2332
|
+
requestAbort() {
|
|
2333
|
+
if (this.session.isAborting && !this.sessionAbortError) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
this.showAbortingStatusIndicator();
|
|
2337
|
+
void this.session.abort().catch((error) => {
|
|
2338
|
+
if (!this.sessionAbortError) {
|
|
2339
|
+
this.showAbortError(error instanceof Error ? error.message : String(error));
|
|
2340
|
+
}
|
|
2341
|
+
this.refreshStatusIndicator();
|
|
2342
|
+
});
|
|
2343
|
+
}
|
|
2344
|
+
showAbortError(message) {
|
|
2345
|
+
this.showError(`Cancellation not confirmed: ${message}. Press ${keyText("app.interrupt")} to retry.`);
|
|
2346
|
+
}
|
|
2262
2347
|
setupKeyHandlers() {
|
|
2263
2348
|
// Set up handlers on defaultEditor - they use this.editor for text access
|
|
2264
2349
|
// so they work correctly regardless of which editor is active
|
|
2265
2350
|
this.defaultEditor.onEscape = () => {
|
|
2351
|
+
if (this.session.isAborting) {
|
|
2352
|
+
if (this.sessionAbortError) {
|
|
2353
|
+
this.requestAbort();
|
|
2354
|
+
}
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2266
2357
|
if (this.session.isStreaming) {
|
|
2267
2358
|
this.restoreQueuedMessagesToEditor({ abort: true });
|
|
2268
2359
|
}
|
|
@@ -2310,10 +2401,22 @@ export class InteractiveMode {
|
|
|
2310
2401
|
this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true, preferSelection: true }));
|
|
2311
2402
|
this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
|
|
2312
2403
|
this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
|
|
2313
|
-
this.defaultEditor.onAction("app.session.new", () =>
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2404
|
+
this.defaultEditor.onAction("app.session.new", () => {
|
|
2405
|
+
if (!this.session.isAborting)
|
|
2406
|
+
void this.handleClearCommand();
|
|
2407
|
+
});
|
|
2408
|
+
this.defaultEditor.onAction("app.session.tree", () => {
|
|
2409
|
+
if (!this.session.isAborting)
|
|
2410
|
+
this.showTreeSelector();
|
|
2411
|
+
});
|
|
2412
|
+
this.defaultEditor.onAction("app.session.fork", () => {
|
|
2413
|
+
if (!this.session.isAborting)
|
|
2414
|
+
this.showUserMessageSelector();
|
|
2415
|
+
});
|
|
2416
|
+
this.defaultEditor.onAction("app.session.resume", () => {
|
|
2417
|
+
if (!this.session.isAborting)
|
|
2418
|
+
this.showSessionSelector();
|
|
2419
|
+
});
|
|
2317
2420
|
this.defaultEditor.onChange = (text) => {
|
|
2318
2421
|
const wasBashMode = this.isBashMode;
|
|
2319
2422
|
this.isBashMode = text.trimStart().startsWith("!");
|
|
@@ -2370,11 +2473,37 @@ export class InteractiveMode {
|
|
|
2370
2473
|
this.editor.setText(text);
|
|
2371
2474
|
this.showStatus("Startup is still in progress");
|
|
2372
2475
|
}
|
|
2476
|
+
async submitStreamingMessage(text, streamingBehavior) {
|
|
2477
|
+
this.editor.addToHistory?.(text);
|
|
2478
|
+
this.editor.setText("");
|
|
2479
|
+
try {
|
|
2480
|
+
await this.session.prompt(text, { streamingBehavior });
|
|
2481
|
+
this.updatePendingMessagesDisplay();
|
|
2482
|
+
this.ui.requestRender();
|
|
2483
|
+
}
|
|
2484
|
+
catch (error) {
|
|
2485
|
+
const currentText = this.editor.getText().trim();
|
|
2486
|
+
this.editor.setText([text, currentText].filter((value) => value.length > 0).join("\n\n"));
|
|
2487
|
+
this.showError(`Failed to queue message: ${error instanceof Error ? error.message : String(error)}`);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2373
2490
|
setupEditorSubmitHandler() {
|
|
2374
2491
|
this.defaultEditor.onSubmit = async (text) => {
|
|
2375
2492
|
text = text.trim();
|
|
2376
2493
|
if (!text)
|
|
2377
2494
|
return;
|
|
2495
|
+
// AgentSession owns the post-abort queue. Ordinary prompts can be queued
|
|
2496
|
+
// while cancellation is in flight, but commands must wait so their TUI
|
|
2497
|
+
// semantics are not changed into provider prompt text.
|
|
2498
|
+
if (this.session.isAborting) {
|
|
2499
|
+
if (this.isInteractiveCommand(text)) {
|
|
2500
|
+
this.editor.setText(text);
|
|
2501
|
+
this.showStatus("Wait for cancellation to finish before running commands.");
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
await this.submitStreamingMessage(text, "steer");
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2378
2507
|
// Handle commands
|
|
2379
2508
|
if (text === "/settings") {
|
|
2380
2509
|
this.showSettingsSelector();
|
|
@@ -2542,11 +2671,7 @@ export class InteractiveMode {
|
|
|
2542
2671
|
// If streaming, use prompt() with steer behavior
|
|
2543
2672
|
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
2544
2673
|
if (this.session.isStreaming) {
|
|
2545
|
-
this.
|
|
2546
|
-
this.editor.setText("");
|
|
2547
|
-
await this.session.prompt(text, { streamingBehavior: "steer" });
|
|
2548
|
-
this.updatePendingMessagesDisplay();
|
|
2549
|
-
this.ui.requestRender();
|
|
2674
|
+
await this.submitStreamingMessage(text, "steer");
|
|
2550
2675
|
return;
|
|
2551
2676
|
}
|
|
2552
2677
|
// Normal message submission
|
|
@@ -2580,21 +2705,47 @@ export class InteractiveMode {
|
|
|
2580
2705
|
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
|
2581
2706
|
this.retryEscapeHandler = undefined;
|
|
2582
2707
|
}
|
|
2708
|
+
if (this.session.isAborting) {
|
|
2709
|
+
this.showAbortingStatusIndicator();
|
|
2710
|
+
}
|
|
2711
|
+
else if (this.workingVisible) {
|
|
2712
|
+
this.showWorkingStatusIndicator();
|
|
2713
|
+
}
|
|
2714
|
+
else {
|
|
2715
|
+
this.clearStatusIndicator();
|
|
2716
|
+
}
|
|
2717
|
+
this.ui.requestRender();
|
|
2583
2718
|
break;
|
|
2584
2719
|
case "turn_start":
|
|
2585
2720
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2586
2721
|
this.ui.terminal.setProgress(true);
|
|
2587
2722
|
}
|
|
2588
|
-
if (this.workingVisible) {
|
|
2589
|
-
|
|
2590
|
-
this.showWorkingStatusIndicator();
|
|
2591
|
-
}
|
|
2723
|
+
if (this.workingVisible && this.activeStatusIndicator?.kind !== "working") {
|
|
2724
|
+
this.showWorkingStatusIndicator();
|
|
2592
2725
|
}
|
|
2593
|
-
else {
|
|
2726
|
+
else if (!this.workingVisible) {
|
|
2594
2727
|
this.clearStatusIndicator();
|
|
2595
2728
|
}
|
|
2596
2729
|
this.ui.requestRender();
|
|
2597
2730
|
break;
|
|
2731
|
+
case "abort_start":
|
|
2732
|
+
this.showAbortingStatusIndicator();
|
|
2733
|
+
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2734
|
+
this.ui.terminal.setProgress(true);
|
|
2735
|
+
}
|
|
2736
|
+
break;
|
|
2737
|
+
case "abort_error":
|
|
2738
|
+
this.showAbortError(event.errorMessage);
|
|
2739
|
+
this.showCancellationFailedStatusIndicator();
|
|
2740
|
+
this.ui.requestRender();
|
|
2741
|
+
break;
|
|
2742
|
+
case "abort_end":
|
|
2743
|
+
this.refreshStatusIndicator();
|
|
2744
|
+
if (!this.session.isStreaming && !this.session.isCompacting && !this.session.isRetrying) {
|
|
2745
|
+
this.ui.terminal.setProgress(false);
|
|
2746
|
+
}
|
|
2747
|
+
this.ui.requestRender();
|
|
2748
|
+
break;
|
|
2598
2749
|
case "queue_update":
|
|
2599
2750
|
this.updatePendingMessagesDisplay();
|
|
2600
2751
|
this.ui.requestRender();
|
|
@@ -2744,10 +2895,18 @@ export class InteractiveMode {
|
|
|
2744
2895
|
this.ui.requestRender();
|
|
2745
2896
|
break;
|
|
2746
2897
|
case "agent_settled":
|
|
2747
|
-
if (this.
|
|
2748
|
-
this.
|
|
2898
|
+
if (this.session.isAborting) {
|
|
2899
|
+
this.showAbortingStatusIndicator();
|
|
2900
|
+
}
|
|
2901
|
+
else if (this.session.isStreaming) {
|
|
2902
|
+
this.refreshStatusIndicator();
|
|
2903
|
+
}
|
|
2904
|
+
else if (!this.session.isCompacting && !this.session.isRetrying) {
|
|
2905
|
+
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2906
|
+
this.ui.terminal.setProgress(false);
|
|
2907
|
+
}
|
|
2908
|
+
this.clearStatusIndicator("working", true);
|
|
2749
2909
|
}
|
|
2750
|
-
this.clearStatusIndicator("working");
|
|
2751
2910
|
await this.checkShutdownRequested();
|
|
2752
2911
|
break;
|
|
2753
2912
|
case "compaction_start": {
|
|
@@ -2757,7 +2916,7 @@ export class InteractiveMode {
|
|
|
2757
2916
|
// Keep editor active; submissions are queued during compaction.
|
|
2758
2917
|
this.autoCompactionEscapeHandler = this.defaultEditor.onEscape;
|
|
2759
2918
|
this.defaultEditor.onEscape = () => {
|
|
2760
|
-
this.
|
|
2919
|
+
this.restoreQueuedMessagesToEditor({ abort: true });
|
|
2761
2920
|
};
|
|
2762
2921
|
this.showStatusIndicator(new CompactionStatusIndicator(this.ui, event.reason));
|
|
2763
2922
|
this.ui.requestRender();
|
|
@@ -2807,8 +2966,15 @@ export class InteractiveMode {
|
|
|
2807
2966
|
this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
|
|
2808
2967
|
}
|
|
2809
2968
|
}
|
|
2810
|
-
this.
|
|
2811
|
-
|
|
2969
|
+
if (this.session.isAborting) {
|
|
2970
|
+
this.showAbortingStatusIndicator();
|
|
2971
|
+
}
|
|
2972
|
+
else if (this.session.isStreaming) {
|
|
2973
|
+
this.restoreWorkingStatusIndicatorIfStreaming();
|
|
2974
|
+
}
|
|
2975
|
+
if (!event.aborted && !this.session.isAborting) {
|
|
2976
|
+
void this.flushCompactionQueue({ willRetry: event.willRetry });
|
|
2977
|
+
}
|
|
2812
2978
|
this.ui.requestRender();
|
|
2813
2979
|
break;
|
|
2814
2980
|
}
|
|
@@ -2816,7 +2982,7 @@ export class InteractiveMode {
|
|
|
2816
2982
|
// Set up escape to abort retry
|
|
2817
2983
|
this.retryEscapeHandler = this.defaultEditor.onEscape;
|
|
2818
2984
|
this.defaultEditor.onEscape = () => {
|
|
2819
|
-
this.
|
|
2985
|
+
this.restoreQueuedMessagesToEditor({ abort: true });
|
|
2820
2986
|
};
|
|
2821
2987
|
this.showStatusIndicator(new RetryStatusIndicator(this.ui, event.attempt, event.maxAttempts, event.delayMs));
|
|
2822
2988
|
this.ui.requestRender();
|
|
@@ -2833,7 +2999,12 @@ export class InteractiveMode {
|
|
|
2833
2999
|
if (!event.success) {
|
|
2834
3000
|
this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
|
|
2835
3001
|
}
|
|
2836
|
-
this.
|
|
3002
|
+
if (this.session.isAborting) {
|
|
3003
|
+
this.showAbortingStatusIndicator();
|
|
3004
|
+
}
|
|
3005
|
+
else if (this.session.isStreaming) {
|
|
3006
|
+
this.restoreWorkingStatusIndicatorIfStreaming();
|
|
3007
|
+
}
|
|
2837
3008
|
this.ui.requestRender();
|
|
2838
3009
|
break;
|
|
2839
3010
|
}
|
|
@@ -2856,6 +3027,9 @@ export class InteractiveMode {
|
|
|
2856
3027
|
}
|
|
2857
3028
|
case "summarization_retry_finished": {
|
|
2858
3029
|
this.clearStatusIndicator("retry");
|
|
3030
|
+
if (this.session.isAborting) {
|
|
3031
|
+
this.showAbortingStatusIndicator();
|
|
3032
|
+
}
|
|
2859
3033
|
this.ui.requestRender();
|
|
2860
3034
|
break;
|
|
2861
3035
|
}
|
|
@@ -3392,6 +3566,14 @@ export class InteractiveMode {
|
|
|
3392
3566
|
const text = (this.editor.getExpandedText?.() ?? this.editor.getText()).trim();
|
|
3393
3567
|
if (!text)
|
|
3394
3568
|
return;
|
|
3569
|
+
if (this.session.isAborting) {
|
|
3570
|
+
if (this.isInteractiveCommand(text)) {
|
|
3571
|
+
this.showStatus("Wait for cancellation to finish before running commands.");
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
await this.submitStreamingMessage(text, "followUp");
|
|
3575
|
+
return;
|
|
3576
|
+
}
|
|
3395
3577
|
// Queue input during compaction (extension commands execute immediately)
|
|
3396
3578
|
if (this.session.isCompacting) {
|
|
3397
3579
|
if (this.isExtensionCommand(text)) {
|
|
@@ -3407,16 +3589,12 @@ export class InteractiveMode {
|
|
|
3407
3589
|
// Alt+Enter queues a follow-up message (waits until agent finishes)
|
|
3408
3590
|
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
3409
3591
|
if (this.session.isStreaming) {
|
|
3410
|
-
this.
|
|
3411
|
-
this.editor.setText("");
|
|
3412
|
-
await this.session.prompt(text, { streamingBehavior: "followUp" });
|
|
3413
|
-
this.updatePendingMessagesDisplay();
|
|
3414
|
-
this.ui.requestRender();
|
|
3592
|
+
await this.submitStreamingMessage(text, "followUp");
|
|
3415
3593
|
}
|
|
3416
3594
|
// If not streaming, Alt+Enter acts like regular Enter (trigger onSubmit)
|
|
3417
3595
|
else if (this.editor.onSubmit) {
|
|
3418
3596
|
this.editor.setText("");
|
|
3419
|
-
this.editor.onSubmit(text);
|
|
3597
|
+
await this.editor.onSubmit(text);
|
|
3420
3598
|
}
|
|
3421
3599
|
}
|
|
3422
3600
|
handleDequeue() {
|
|
@@ -3627,12 +3805,15 @@ export class InteractiveMode {
|
|
|
3627
3805
|
}
|
|
3628
3806
|
}
|
|
3629
3807
|
restoreQueuedMessagesToEditor(options) {
|
|
3808
|
+
if (options?.abort && this.session.isAborting) {
|
|
3809
|
+
return 0;
|
|
3810
|
+
}
|
|
3630
3811
|
const { steering, followUp } = this.clearAllQueues();
|
|
3631
3812
|
const allQueued = [...steering, ...followUp];
|
|
3632
3813
|
if (allQueued.length === 0) {
|
|
3633
3814
|
this.updatePendingMessagesDisplay();
|
|
3634
3815
|
if (options?.abort) {
|
|
3635
|
-
this.
|
|
3816
|
+
this.requestAbort();
|
|
3636
3817
|
}
|
|
3637
3818
|
return 0;
|
|
3638
3819
|
}
|
|
@@ -3642,7 +3823,7 @@ export class InteractiveMode {
|
|
|
3642
3823
|
this.editor.setText(combinedText);
|
|
3643
3824
|
this.updatePendingMessagesDisplay();
|
|
3644
3825
|
if (options?.abort) {
|
|
3645
|
-
this.
|
|
3826
|
+
this.requestAbort();
|
|
3646
3827
|
}
|
|
3647
3828
|
return allQueued.length;
|
|
3648
3829
|
}
|
|
@@ -3661,6 +3842,15 @@ export class InteractiveMode {
|
|
|
3661
3842
|
const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
|
|
3662
3843
|
return !!extensionRunner.getCommand(commandName);
|
|
3663
3844
|
}
|
|
3845
|
+
isInteractiveCommand(text) {
|
|
3846
|
+
if (text.startsWith("!"))
|
|
3847
|
+
return true;
|
|
3848
|
+
if (!text.startsWith("/"))
|
|
3849
|
+
return false;
|
|
3850
|
+
const spaceIndex = text.indexOf(" ");
|
|
3851
|
+
const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
|
|
3852
|
+
return BUILTIN_SLASH_COMMANDS.some((command) => command.name === commandName) || this.isExtensionCommand(text);
|
|
3853
|
+
}
|
|
3664
3854
|
async flushCompactionQueue(options) {
|
|
3665
3855
|
if (this.compactionQueuedMessages.length === 0) {
|
|
3666
3856
|
return;
|
|
@@ -4424,7 +4614,7 @@ export class InteractiveMode {
|
|
|
4424
4614
|
const originalOnEscape = this.defaultEditor.onEscape;
|
|
4425
4615
|
if (wantsSummary) {
|
|
4426
4616
|
this.defaultEditor.onEscape = () => {
|
|
4427
|
-
this.
|
|
4617
|
+
this.restoreQueuedMessagesToEditor({ abort: true });
|
|
4428
4618
|
};
|
|
4429
4619
|
this.chatContainer.addChild(new Spacer(1));
|
|
4430
4620
|
this.showStatusIndicator(new BranchSummaryStatusIndicator(this.ui));
|
|
@@ -5543,8 +5733,10 @@ export class InteractiveMode {
|
|
|
5543
5733
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
5544
5734
|
this.ui.terminal.setProgress(false);
|
|
5545
5735
|
}
|
|
5546
|
-
this.clearStatusIndicator();
|
|
5736
|
+
this.clearStatusIndicator(undefined, true);
|
|
5547
5737
|
this.themeController.disableAutoSync();
|
|
5738
|
+
this.abortInputListenerCleanup?.();
|
|
5739
|
+
this.abortInputListenerCleanup = undefined;
|
|
5548
5740
|
this.clearExtensionTerminalInputListeners();
|
|
5549
5741
|
this.footer.dispose();
|
|
5550
5742
|
this.footerDataProvider.dispose();
|