@leanandmean/coding-agent 0.74.1-scramjet.24 → 0.74.1-scramjet.25
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 +4 -0
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -15
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts +4 -2
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +14 -8
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +8 -2
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +4 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +14 -6
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +2 -2
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -13
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +11 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +69 -18
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +213 -59
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/settings.md +0 -1
- package/docs/tui.md +12 -0
- package/package.json +2 -2
|
@@ -108,7 +108,9 @@ export class InteractiveMode {
|
|
|
108
108
|
options;
|
|
109
109
|
runtimeHost;
|
|
110
110
|
ui;
|
|
111
|
+
committedChatContainer;
|
|
111
112
|
chatContainer;
|
|
113
|
+
mutableChatComponents = new Set();
|
|
112
114
|
pendingMessagesContainer;
|
|
113
115
|
statusContainer;
|
|
114
116
|
defaultEditor;
|
|
@@ -150,6 +152,8 @@ export class InteractiveMode {
|
|
|
150
152
|
streamingMessage = undefined;
|
|
151
153
|
// Tool execution tracking: toolCallId -> component
|
|
152
154
|
pendingTools = new Map();
|
|
155
|
+
pendingToolFinalizations = new Set();
|
|
156
|
+
agentRunGeneration = 0;
|
|
153
157
|
// Tool output expansion state
|
|
154
158
|
toolOutputExpanded = false;
|
|
155
159
|
// Thinking block visibility state
|
|
@@ -217,9 +221,10 @@ export class InteractiveMode {
|
|
|
217
221
|
await this.rebindCurrentSession();
|
|
218
222
|
});
|
|
219
223
|
this.version = VERSION;
|
|
220
|
-
|
|
221
|
-
this.ui.
|
|
224
|
+
// SCRAMJET-DIVERGENCE: mandatory committed/live rendering and injectable terminals (#389).
|
|
225
|
+
this.ui = new TUI(options.terminal ?? new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
|
222
226
|
this.headerContainer = new Container();
|
|
227
|
+
this.committedChatContainer = new Container();
|
|
223
228
|
this.chatContainer = new Container();
|
|
224
229
|
this.pendingMessagesContainer = new Container();
|
|
225
230
|
this.statusContainer = new Container();
|
|
@@ -250,6 +255,73 @@ export class InteractiveMode {
|
|
|
250
255
|
this.detectedClassification = detectThemeFromEnvironment()?.theme;
|
|
251
256
|
initTheme(this.settingsManager.getTheme(), true);
|
|
252
257
|
}
|
|
258
|
+
// SCRAMJET-DIVERGENCE: finalized transcript components are promoted atomically into append-only history (#389).
|
|
259
|
+
promoteFinalizedChatPrefix() {
|
|
260
|
+
let promoted = false;
|
|
261
|
+
while (this.chatContainer.children.length > 0) {
|
|
262
|
+
const child = this.chatContainer.children[0];
|
|
263
|
+
if (this.mutableChatComponents.has(child))
|
|
264
|
+
break;
|
|
265
|
+
this.chatContainer.removeChild(child);
|
|
266
|
+
if (child instanceof ToolExecutionComponent)
|
|
267
|
+
child.markCommitted();
|
|
268
|
+
this.committedChatContainer.addChild(child);
|
|
269
|
+
promoted = true;
|
|
270
|
+
}
|
|
271
|
+
if (promoted)
|
|
272
|
+
this.ui.commit();
|
|
273
|
+
}
|
|
274
|
+
setChatComponentMutable(component, mutable) {
|
|
275
|
+
if (mutable)
|
|
276
|
+
this.mutableChatComponents.add(component);
|
|
277
|
+
else
|
|
278
|
+
this.mutableChatComponents.delete(component);
|
|
279
|
+
}
|
|
280
|
+
sealStatus() {
|
|
281
|
+
if (this.lastStatusSpacer)
|
|
282
|
+
this.mutableChatComponents.delete(this.lastStatusSpacer);
|
|
283
|
+
if (this.lastStatusText)
|
|
284
|
+
this.mutableChatComponents.delete(this.lastStatusText);
|
|
285
|
+
this.lastStatusSpacer = undefined;
|
|
286
|
+
this.lastStatusText = undefined;
|
|
287
|
+
this.promoteFinalizedChatPrefix();
|
|
288
|
+
}
|
|
289
|
+
clearTranscript() {
|
|
290
|
+
this.pendingToolFinalizations = new Set();
|
|
291
|
+
const tools = new Set([
|
|
292
|
+
...this.pendingTools.values(),
|
|
293
|
+
...this.committedChatContainer.children.filter((component) => component instanceof ToolExecutionComponent),
|
|
294
|
+
...this.chatContainer.children.filter((component) => component instanceof ToolExecutionComponent),
|
|
295
|
+
]);
|
|
296
|
+
for (const tool of tools)
|
|
297
|
+
tool.detach();
|
|
298
|
+
this.committedChatContainer.clear();
|
|
299
|
+
this.chatContainer.clear();
|
|
300
|
+
this.mutableChatComponents.clear();
|
|
301
|
+
this.lastStatusSpacer = undefined;
|
|
302
|
+
this.lastStatusText = undefined;
|
|
303
|
+
this.ui.rebuild();
|
|
304
|
+
}
|
|
305
|
+
updateToolImagePresentation(update) {
|
|
306
|
+
for (const container of [this.committedChatContainer, this.chatContainer]) {
|
|
307
|
+
for (const child of container.children) {
|
|
308
|
+
if (child instanceof ToolExecutionComponent)
|
|
309
|
+
update(child);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
this.ui.rebuild();
|
|
313
|
+
}
|
|
314
|
+
commitFinalizedChatOutput() {
|
|
315
|
+
this.sealStatus();
|
|
316
|
+
this.ui.requestRender();
|
|
317
|
+
}
|
|
318
|
+
bindThemeChangeHandler() {
|
|
319
|
+
onThemeChange(() => {
|
|
320
|
+
this.ui.invalidate();
|
|
321
|
+
this.updateEditorBorderColor();
|
|
322
|
+
this.ui.rebuild();
|
|
323
|
+
});
|
|
324
|
+
}
|
|
253
325
|
// SCRAMJET-DIVERGENCE: re-resolve the theme after extension themes register (or after a reload),
|
|
254
326
|
// so scramjet-dark can take effect once it becomes available. An explicit user setting still wins
|
|
255
327
|
// via the resolver; the captured classification (env-seeded + OSC-updated) drives auto-detection.
|
|
@@ -408,6 +480,7 @@ export class InteractiveMode {
|
|
|
408
480
|
this.chatContainer.addChild(new Spacer(1));
|
|
409
481
|
}
|
|
410
482
|
this.chatContainer.addChild(new DynamicBorder());
|
|
483
|
+
this.promoteFinalizedChatPrefix();
|
|
411
484
|
}
|
|
412
485
|
async init() {
|
|
413
486
|
if (this.isInitialized)
|
|
@@ -434,7 +507,9 @@ export class InteractiveMode {
|
|
|
434
507
|
}
|
|
435
508
|
// Add header container as first child (content built after theme detection below)
|
|
436
509
|
this.ui.addChild(this.headerContainer);
|
|
510
|
+
this.ui.addChild(this.committedChatContainer);
|
|
437
511
|
this.ui.addChild(this.chatContainer);
|
|
512
|
+
this.ui.setLiveRegionStart(this.chatContainer);
|
|
438
513
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
439
514
|
this.ui.addChild(this.statusContainer);
|
|
440
515
|
this.renderWidgets(); // Initialize with default spacer
|
|
@@ -512,11 +587,7 @@ export class InteractiveMode {
|
|
|
512
587
|
// Render initial messages AFTER showing loaded resources
|
|
513
588
|
this.renderInitialMessages();
|
|
514
589
|
// Set up theme file watcher
|
|
515
|
-
|
|
516
|
-
this.ui.invalidate();
|
|
517
|
-
this.updateEditorBorderColor();
|
|
518
|
-
this.ui.requestRender();
|
|
519
|
-
});
|
|
590
|
+
this.bindThemeChangeHandler();
|
|
520
591
|
// Set up git branch watcher (uses provider instead of footer)
|
|
521
592
|
this.footerDataProvider.onBranchChange(() => {
|
|
522
593
|
this.ui.requestRender();
|
|
@@ -1169,7 +1240,7 @@ export class InteractiveMode {
|
|
|
1169
1240
|
if (result.cancelled) {
|
|
1170
1241
|
return { cancelled: true };
|
|
1171
1242
|
}
|
|
1172
|
-
this.
|
|
1243
|
+
this.clearTranscript();
|
|
1173
1244
|
this.renderInitialMessages();
|
|
1174
1245
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
1175
1246
|
this.editor.setText(result.editorText);
|
|
@@ -1204,6 +1275,7 @@ export class InteractiveMode {
|
|
|
1204
1275
|
this.setupExtensionShortcuts(extensionRunner);
|
|
1205
1276
|
this.showLoadedResources({ force: false, showDiagnosticsWhenQuiet: true });
|
|
1206
1277
|
this.showStartupNoticesIfNeeded();
|
|
1278
|
+
this.promoteFinalizedChatPrefix();
|
|
1207
1279
|
}
|
|
1208
1280
|
applyRuntimeSettings() {
|
|
1209
1281
|
this.footer.setSession(this.session);
|
|
@@ -1211,7 +1283,6 @@ export class InteractiveMode {
|
|
|
1211
1283
|
this.footerDataProvider.setCwd(this.sessionManager.getCwd());
|
|
1212
1284
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
1213
1285
|
this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
|
|
1214
|
-
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
1215
1286
|
const editorPaddingX = this.settingsManager.getEditorPaddingX();
|
|
1216
1287
|
const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
|
|
1217
1288
|
this.defaultEditor.setPaddingX(editorPaddingX);
|
|
@@ -1262,7 +1333,7 @@ export class InteractiveMode {
|
|
|
1262
1333
|
process.exit(1);
|
|
1263
1334
|
}
|
|
1264
1335
|
renderCurrentSessionState() {
|
|
1265
|
-
this.
|
|
1336
|
+
this.clearTranscript();
|
|
1266
1337
|
this.pendingMessagesContainer.clear();
|
|
1267
1338
|
this.compactionQueuedMessages = [];
|
|
1268
1339
|
this.streamingComponent = undefined;
|
|
@@ -1372,7 +1443,7 @@ export class InteractiveMode {
|
|
|
1372
1443
|
}
|
|
1373
1444
|
setHiddenThinkingLabel(label) {
|
|
1374
1445
|
this.hiddenThinkingLabel = label ?? this.defaultHiddenThinkingLabel;
|
|
1375
|
-
for (const child of this.chatContainer.children) {
|
|
1446
|
+
for (const child of [...this.committedChatContainer.children, ...this.chatContainer.children]) {
|
|
1376
1447
|
if (child instanceof AssistantMessageComponent) {
|
|
1377
1448
|
child.setHiddenThinkingLabel(this.hiddenThinkingLabel);
|
|
1378
1449
|
}
|
|
@@ -1380,7 +1451,7 @@ export class InteractiveMode {
|
|
|
1380
1451
|
if (this.streamingComponent) {
|
|
1381
1452
|
this.streamingComponent.setHiddenThinkingLabel(this.hiddenThinkingLabel);
|
|
1382
1453
|
}
|
|
1383
|
-
this.ui.
|
|
1454
|
+
this.ui.rebuild();
|
|
1384
1455
|
}
|
|
1385
1456
|
/**
|
|
1386
1457
|
* Set an extension widget (string array or custom component).
|
|
@@ -1554,7 +1625,7 @@ export class InteractiveMode {
|
|
|
1554
1625
|
this.headerContainer.children[index] = this.builtInHeader;
|
|
1555
1626
|
}
|
|
1556
1627
|
}
|
|
1557
|
-
this.ui.
|
|
1628
|
+
this.ui.rebuild();
|
|
1558
1629
|
}
|
|
1559
1630
|
addExtensionTerminalInputListener(handler) {
|
|
1560
1631
|
const unsubscribe = this.ui.addInputListener(handler);
|
|
@@ -1913,7 +1984,7 @@ export class InteractiveMode {
|
|
|
1913
1984
|
this.chatContainer.addChild(new Text(stackLines, 1, 0));
|
|
1914
1985
|
}
|
|
1915
1986
|
}
|
|
1916
|
-
this.
|
|
1987
|
+
this.commitFinalizedChatOutput();
|
|
1917
1988
|
}
|
|
1918
1989
|
// =========================================================================
|
|
1919
1990
|
// Key Handlers
|
|
@@ -2187,7 +2258,9 @@ export class InteractiveMode {
|
|
|
2187
2258
|
this.footer.invalidate();
|
|
2188
2259
|
switch (event.type) {
|
|
2189
2260
|
case "agent_start":
|
|
2261
|
+
this.agentRunGeneration += 1;
|
|
2190
2262
|
this.pendingTools.clear();
|
|
2263
|
+
this.pendingToolFinalizations = new Set();
|
|
2191
2264
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2192
2265
|
this.ui.terminal.setProgress(true);
|
|
2193
2266
|
}
|
|
@@ -2226,6 +2299,7 @@ export class InteractiveMode {
|
|
|
2226
2299
|
this.updateEditorBorderColor();
|
|
2227
2300
|
break;
|
|
2228
2301
|
case "message_start":
|
|
2302
|
+
this.sealStatus();
|
|
2229
2303
|
if (event.message.role === "custom") {
|
|
2230
2304
|
this.addMessageToChat(event.message);
|
|
2231
2305
|
this.ui.requestRender();
|
|
@@ -2236,9 +2310,10 @@ export class InteractiveMode {
|
|
|
2236
2310
|
this.ui.requestRender();
|
|
2237
2311
|
}
|
|
2238
2312
|
else if (event.message.role === "assistant") {
|
|
2239
|
-
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel);
|
|
2313
|
+
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, false);
|
|
2240
2314
|
this.streamingMessage = event.message;
|
|
2241
2315
|
this.chatContainer.addChild(this.streamingComponent);
|
|
2316
|
+
this.setChatComponentMutable(this.streamingComponent, true);
|
|
2242
2317
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
2243
2318
|
this.ui.requestRender();
|
|
2244
2319
|
}
|
|
@@ -2256,6 +2331,7 @@ export class InteractiveMode {
|
|
|
2256
2331
|
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
2257
2332
|
component.setExpanded(this.toolOutputExpanded);
|
|
2258
2333
|
this.chatContainer.addChild(component);
|
|
2334
|
+
this.setChatComponentMutable(component, true);
|
|
2259
2335
|
this.pendingTools.set(content.id, component);
|
|
2260
2336
|
}
|
|
2261
2337
|
else {
|
|
@@ -2284,6 +2360,8 @@ export class InteractiveMode {
|
|
|
2284
2360
|
this.streamingMessage.errorMessage = errorMessage;
|
|
2285
2361
|
}
|
|
2286
2362
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
2363
|
+
this.streamingComponent.setFinalized(true);
|
|
2364
|
+
this.setChatComponentMutable(this.streamingComponent, false);
|
|
2287
2365
|
if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
|
|
2288
2366
|
if (!errorMessage) {
|
|
2289
2367
|
errorMessage = this.streamingMessage.errorMessage || "Error";
|
|
@@ -2293,6 +2371,8 @@ export class InteractiveMode {
|
|
|
2293
2371
|
content: [{ type: "text", text: errorMessage }],
|
|
2294
2372
|
isError: true,
|
|
2295
2373
|
});
|
|
2374
|
+
component.seal();
|
|
2375
|
+
this.setChatComponentMutable(component, false);
|
|
2296
2376
|
}
|
|
2297
2377
|
this.pendingTools.clear();
|
|
2298
2378
|
}
|
|
@@ -2302,6 +2382,7 @@ export class InteractiveMode {
|
|
|
2302
2382
|
component.setArgsComplete();
|
|
2303
2383
|
}
|
|
2304
2384
|
}
|
|
2385
|
+
this.promoteFinalizedChatPrefix();
|
|
2305
2386
|
this.streamingComponent = undefined;
|
|
2306
2387
|
this.streamingMessage = undefined;
|
|
2307
2388
|
this.footer.invalidate();
|
|
@@ -2309,6 +2390,7 @@ export class InteractiveMode {
|
|
|
2309
2390
|
this.ui.requestRender();
|
|
2310
2391
|
break;
|
|
2311
2392
|
case "tool_execution_start": {
|
|
2393
|
+
this.sealStatus();
|
|
2312
2394
|
let component = this.pendingTools.get(event.toolCallId);
|
|
2313
2395
|
if (!component) {
|
|
2314
2396
|
component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
|
|
@@ -2317,6 +2399,7 @@ export class InteractiveMode {
|
|
|
2317
2399
|
}, this.getRegisteredToolDefinition(event.toolName), this.ui, this.sessionManager.getCwd());
|
|
2318
2400
|
component.setExpanded(this.toolOutputExpanded);
|
|
2319
2401
|
this.chatContainer.addChild(component);
|
|
2402
|
+
this.setChatComponentMutable(component, true);
|
|
2320
2403
|
this.pendingTools.set(event.toolCallId, component);
|
|
2321
2404
|
}
|
|
2322
2405
|
component.markExecutionStarted();
|
|
@@ -2335,12 +2418,34 @@ export class InteractiveMode {
|
|
|
2335
2418
|
const component = this.pendingTools.get(event.toolCallId);
|
|
2336
2419
|
if (component) {
|
|
2337
2420
|
component.updateResult({ ...event.result, isError: event.isError });
|
|
2338
|
-
this.
|
|
2339
|
-
|
|
2421
|
+
const pendingToolFinalizations = this.pendingToolFinalizations;
|
|
2422
|
+
const finalization = component.waitForImageConversions().then(() => {
|
|
2423
|
+
component.seal();
|
|
2424
|
+
if (this.pendingTools.get(event.toolCallId) === component) {
|
|
2425
|
+
this.pendingTools.delete(event.toolCallId);
|
|
2426
|
+
}
|
|
2427
|
+
if (this.mutableChatComponents.has(component) && this.chatContainer.children.includes(component)) {
|
|
2428
|
+
this.setChatComponentMutable(component, false);
|
|
2429
|
+
this.promoteFinalizedChatPrefix();
|
|
2430
|
+
this.ui.requestRender();
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
pendingToolFinalizations.add(finalization);
|
|
2434
|
+
try {
|
|
2435
|
+
await finalization;
|
|
2436
|
+
}
|
|
2437
|
+
finally {
|
|
2438
|
+
pendingToolFinalizations.delete(finalization);
|
|
2439
|
+
}
|
|
2340
2440
|
}
|
|
2341
2441
|
break;
|
|
2342
2442
|
}
|
|
2343
|
-
case "agent_end":
|
|
2443
|
+
case "agent_end": {
|
|
2444
|
+
const runGeneration = this.agentRunGeneration;
|
|
2445
|
+
const pendingToolFinalizations = this.pendingToolFinalizations;
|
|
2446
|
+
await Promise.all(pendingToolFinalizations);
|
|
2447
|
+
if (runGeneration !== this.agentRunGeneration || pendingToolFinalizations !== this.pendingToolFinalizations)
|
|
2448
|
+
break;
|
|
2344
2449
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2345
2450
|
this.ui.terminal.setProgress(false);
|
|
2346
2451
|
}
|
|
@@ -2351,13 +2456,20 @@ export class InteractiveMode {
|
|
|
2351
2456
|
}
|
|
2352
2457
|
if (this.streamingComponent) {
|
|
2353
2458
|
this.chatContainer.removeChild(this.streamingComponent);
|
|
2459
|
+
this.setChatComponentMutable(this.streamingComponent, false);
|
|
2354
2460
|
this.streamingComponent = undefined;
|
|
2355
2461
|
this.streamingMessage = undefined;
|
|
2356
2462
|
}
|
|
2463
|
+
for (const component of this.pendingTools.values()) {
|
|
2464
|
+
component.seal();
|
|
2465
|
+
this.setChatComponentMutable(component, false);
|
|
2466
|
+
}
|
|
2357
2467
|
this.pendingTools.clear();
|
|
2468
|
+
this.promoteFinalizedChatPrefix();
|
|
2358
2469
|
await this.checkShutdownRequested();
|
|
2359
2470
|
this.ui.requestRender();
|
|
2360
2471
|
break;
|
|
2472
|
+
}
|
|
2361
2473
|
case "compaction_start": {
|
|
2362
2474
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2363
2475
|
this.ui.terminal.setProgress(true);
|
|
@@ -2399,7 +2511,6 @@ export class InteractiveMode {
|
|
|
2399
2511
|
}
|
|
2400
2512
|
}
|
|
2401
2513
|
else if (event.result) {
|
|
2402
|
-
this.chatContainer.clear();
|
|
2403
2514
|
this.rebuildChatFromMessages();
|
|
2404
2515
|
this.addMessageToChat(createCompactionSummaryMessage(event.result.summary, event.result.tokensBefore, new Date().toISOString()));
|
|
2405
2516
|
this.footer.invalidate();
|
|
@@ -2411,6 +2522,7 @@ export class InteractiveMode {
|
|
|
2411
2522
|
else {
|
|
2412
2523
|
this.chatContainer.addChild(new Spacer(1));
|
|
2413
2524
|
this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
|
|
2525
|
+
this.commitFinalizedChatOutput();
|
|
2414
2526
|
}
|
|
2415
2527
|
}
|
|
2416
2528
|
void this.flushCompactionQueue({ willRetry: event.willRetry });
|
|
@@ -2496,11 +2608,14 @@ export class InteractiveMode {
|
|
|
2496
2608
|
const text = new Text(theme.fg("dim", message), 1, 0);
|
|
2497
2609
|
this.chatContainer.addChild(spacer);
|
|
2498
2610
|
this.chatContainer.addChild(text);
|
|
2611
|
+
this.setChatComponentMutable(spacer, true);
|
|
2612
|
+
this.setChatComponentMutable(text, true);
|
|
2499
2613
|
this.lastStatusSpacer = spacer;
|
|
2500
2614
|
this.lastStatusText = text;
|
|
2501
2615
|
this.ui.requestRender();
|
|
2502
2616
|
}
|
|
2503
2617
|
addMessageToChat(message, options) {
|
|
2618
|
+
this.sealStatus();
|
|
2504
2619
|
switch (message.role) {
|
|
2505
2620
|
case "bashExecution": {
|
|
2506
2621
|
const component = new BashExecutionComponent(message.command, this.ui, message.excludeFromContext);
|
|
@@ -2592,6 +2707,7 @@ export class InteractiveMode {
|
|
|
2592
2707
|
const _exhaustive = message;
|
|
2593
2708
|
}
|
|
2594
2709
|
}
|
|
2710
|
+
this.promoteFinalizedChatPrefix();
|
|
2595
2711
|
}
|
|
2596
2712
|
/**
|
|
2597
2713
|
* Render session context to chat. Used for initial load and rebuild after compaction.
|
|
@@ -2619,6 +2735,7 @@ export class InteractiveMode {
|
|
|
2619
2735
|
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
2620
2736
|
component.setExpanded(this.toolOutputExpanded);
|
|
2621
2737
|
this.chatContainer.addChild(component);
|
|
2738
|
+
this.setChatComponentMutable(component, true);
|
|
2622
2739
|
if (message.stopReason === "aborted" || message.stopReason === "error") {
|
|
2623
2740
|
let errorMessage;
|
|
2624
2741
|
if (message.stopReason === "aborted") {
|
|
@@ -2632,6 +2749,8 @@ export class InteractiveMode {
|
|
|
2632
2749
|
errorMessage = message.errorMessage || "Error";
|
|
2633
2750
|
}
|
|
2634
2751
|
component.updateResult({ content: [{ type: "text", text: errorMessage }], isError: true });
|
|
2752
|
+
component.seal();
|
|
2753
|
+
this.setChatComponentMutable(component, false);
|
|
2635
2754
|
}
|
|
2636
2755
|
else {
|
|
2637
2756
|
renderedPendingTools.set(content.id, component);
|
|
@@ -2647,6 +2766,26 @@ export class InteractiveMode {
|
|
|
2647
2766
|
component.setArgsComplete();
|
|
2648
2767
|
component.updateResult(message);
|
|
2649
2768
|
renderedPendingTools.delete(message.toolCallId);
|
|
2769
|
+
if (component.hasPendingImageConversions()) {
|
|
2770
|
+
const pendingToolFinalizations = this.pendingToolFinalizations;
|
|
2771
|
+
const finalization = component.waitForImageConversions().then(() => {
|
|
2772
|
+
if (!this.mutableChatComponents.has(component) ||
|
|
2773
|
+
!this.chatContainer.children.includes(component)) {
|
|
2774
|
+
component.seal();
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
component.seal();
|
|
2778
|
+
this.setChatComponentMutable(component, false);
|
|
2779
|
+
this.promoteFinalizedChatPrefix();
|
|
2780
|
+
this.ui.requestRender();
|
|
2781
|
+
});
|
|
2782
|
+
pendingToolFinalizations.add(finalization);
|
|
2783
|
+
void finalization.finally(() => pendingToolFinalizations.delete(finalization));
|
|
2784
|
+
}
|
|
2785
|
+
else {
|
|
2786
|
+
component.seal();
|
|
2787
|
+
this.setChatComponentMutable(component, false);
|
|
2788
|
+
}
|
|
2650
2789
|
}
|
|
2651
2790
|
}
|
|
2652
2791
|
else {
|
|
@@ -2657,6 +2796,7 @@ export class InteractiveMode {
|
|
|
2657
2796
|
for (const [toolCallId, component] of renderedPendingTools) {
|
|
2658
2797
|
this.pendingTools.set(toolCallId, component);
|
|
2659
2798
|
}
|
|
2799
|
+
this.promoteFinalizedChatPrefix();
|
|
2660
2800
|
this.ui.requestRender();
|
|
2661
2801
|
}
|
|
2662
2802
|
renderInitialMessages() {
|
|
@@ -2683,7 +2823,7 @@ export class InteractiveMode {
|
|
|
2683
2823
|
});
|
|
2684
2824
|
}
|
|
2685
2825
|
rebuildChatFromMessages() {
|
|
2686
|
-
this.
|
|
2826
|
+
this.clearTranscript();
|
|
2687
2827
|
const context = this.sessionManager.buildSessionContext();
|
|
2688
2828
|
this.renderSessionContext(context);
|
|
2689
2829
|
}
|
|
@@ -2828,7 +2968,7 @@ export class InteractiveMode {
|
|
|
2828
2968
|
clearInterval(suspendKeepAlive);
|
|
2829
2969
|
process.removeListener("SIGINT", ignoreSigint);
|
|
2830
2970
|
this.ui.start();
|
|
2831
|
-
this.ui.
|
|
2971
|
+
this.ui.rebuild();
|
|
2832
2972
|
});
|
|
2833
2973
|
try {
|
|
2834
2974
|
// Stop the TUI (restore terminal to normal mode)
|
|
@@ -2931,24 +3071,24 @@ export class InteractiveMode {
|
|
|
2931
3071
|
if (isExpandable(activeHeader)) {
|
|
2932
3072
|
activeHeader.setExpanded(expanded);
|
|
2933
3073
|
}
|
|
2934
|
-
for (const child of this.chatContainer.children) {
|
|
3074
|
+
for (const child of [...this.committedChatContainer.children, ...this.chatContainer.children]) {
|
|
2935
3075
|
if (isExpandable(child)) {
|
|
2936
3076
|
child.setExpanded(expanded);
|
|
2937
3077
|
}
|
|
2938
3078
|
}
|
|
2939
|
-
this.ui.
|
|
3079
|
+
this.ui.rebuild();
|
|
2940
3080
|
}
|
|
2941
3081
|
toggleThinkingBlockVisibility() {
|
|
2942
3082
|
this.hideThinkingBlock = !this.hideThinkingBlock;
|
|
2943
3083
|
this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
|
|
2944
3084
|
// Rebuild chat from session messages
|
|
2945
|
-
this.chatContainer.clear();
|
|
2946
3085
|
this.rebuildChatFromMessages();
|
|
2947
3086
|
// If streaming, re-add the streaming component with updated visibility and re-render
|
|
2948
3087
|
if (this.streamingComponent && this.streamingMessage) {
|
|
2949
3088
|
this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);
|
|
2950
3089
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
2951
3090
|
this.chatContainer.addChild(this.streamingComponent);
|
|
3091
|
+
this.setChatComponentMutable(this.streamingComponent, true);
|
|
2952
3092
|
}
|
|
2953
3093
|
this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
|
|
2954
3094
|
}
|
|
@@ -2990,8 +3130,7 @@ export class InteractiveMode {
|
|
|
2990
3130
|
}
|
|
2991
3131
|
// Restart TUI
|
|
2992
3132
|
this.ui.start();
|
|
2993
|
-
|
|
2994
|
-
this.ui.requestRender(true);
|
|
3133
|
+
this.ui.rebuild();
|
|
2995
3134
|
}
|
|
2996
3135
|
}
|
|
2997
3136
|
// =========================================================================
|
|
@@ -3002,14 +3141,18 @@ export class InteractiveMode {
|
|
|
3002
3141
|
this.ui.requestRender();
|
|
3003
3142
|
}
|
|
3004
3143
|
showError(errorMessage) {
|
|
3144
|
+
this.sealStatus();
|
|
3005
3145
|
this.chatContainer.addChild(new Spacer(1));
|
|
3006
3146
|
this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
|
|
3007
3147
|
this.chatContainer.addChild(new Spacer(1));
|
|
3148
|
+
this.promoteFinalizedChatPrefix();
|
|
3008
3149
|
this.ui.requestRender();
|
|
3009
3150
|
}
|
|
3010
3151
|
showWarning(warningMessage) {
|
|
3152
|
+
this.sealStatus();
|
|
3011
3153
|
this.chatContainer.addChild(new Spacer(1));
|
|
3012
3154
|
this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
|
|
3155
|
+
this.promoteFinalizedChatPrefix();
|
|
3013
3156
|
this.ui.requestRender();
|
|
3014
3157
|
}
|
|
3015
3158
|
// SCRAMJET-DIVERGENCE: showNewVersionNotification removed (version check gutted).
|
|
@@ -3021,7 +3164,7 @@ export class InteractiveMode {
|
|
|
3021
3164
|
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
3022
3165
|
this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Package Updates Available"))}\n${updateInstruction}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, 1, 0));
|
|
3023
3166
|
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
3024
|
-
this.
|
|
3167
|
+
this.commitFinalizedChatOutput();
|
|
3025
3168
|
}
|
|
3026
3169
|
/**
|
|
3027
3170
|
* Get all queued messages (read-only).
|
|
@@ -3181,11 +3324,14 @@ export class InteractiveMode {
|
|
|
3181
3324
|
}
|
|
3182
3325
|
/** Move pending bash components from pending area to chat */
|
|
3183
3326
|
flushPendingBashComponents() {
|
|
3327
|
+
if (this.pendingBashComponents.length > 0)
|
|
3328
|
+
this.sealStatus();
|
|
3184
3329
|
for (const component of this.pendingBashComponents) {
|
|
3185
3330
|
this.pendingMessagesContainer.removeChild(component);
|
|
3186
3331
|
this.chatContainer.addChild(component);
|
|
3187
3332
|
}
|
|
3188
3333
|
this.pendingBashComponents = [];
|
|
3334
|
+
this.promoteFinalizedChatPrefix();
|
|
3189
3335
|
}
|
|
3190
3336
|
// =========================================================================
|
|
3191
3337
|
// Selectors
|
|
@@ -3232,7 +3378,6 @@ export class InteractiveMode {
|
|
|
3232
3378
|
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
|
3233
3379
|
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
|
3234
3380
|
quietStartup: this.settingsManager.getQuietStartup(),
|
|
3235
|
-
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
|
3236
3381
|
showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
|
|
3237
3382
|
warnings: this.settingsManager.getWarnings(),
|
|
3238
3383
|
}, {
|
|
@@ -3242,19 +3387,11 @@ export class InteractiveMode {
|
|
|
3242
3387
|
},
|
|
3243
3388
|
onShowImagesChange: (enabled) => {
|
|
3244
3389
|
this.settingsManager.setShowImages(enabled);
|
|
3245
|
-
|
|
3246
|
-
if (child instanceof ToolExecutionComponent) {
|
|
3247
|
-
child.setShowImages(enabled);
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3390
|
+
this.updateToolImagePresentation((component) => component.setShowImages(enabled));
|
|
3250
3391
|
},
|
|
3251
3392
|
onImageWidthCellsChange: (width) => {
|
|
3252
3393
|
this.settingsManager.setImageWidthCells(width);
|
|
3253
|
-
|
|
3254
|
-
if (child instanceof ToolExecutionComponent) {
|
|
3255
|
-
child.setImageWidthCells(width);
|
|
3256
|
-
}
|
|
3257
|
-
}
|
|
3394
|
+
this.updateToolImagePresentation((component) => component.setImageWidthCells(width));
|
|
3258
3395
|
},
|
|
3259
3396
|
onAutoResizeImagesChange: (enabled) => {
|
|
3260
3397
|
this.settingsManager.setImageAutoResize(enabled);
|
|
@@ -3300,12 +3437,11 @@ export class InteractiveMode {
|
|
|
3300
3437
|
onHideThinkingBlockChange: (hidden) => {
|
|
3301
3438
|
this.hideThinkingBlock = hidden;
|
|
3302
3439
|
this.settingsManager.setHideThinkingBlock(hidden);
|
|
3303
|
-
for (const child of this.chatContainer.children) {
|
|
3440
|
+
for (const child of [...this.committedChatContainer.children, ...this.chatContainer.children]) {
|
|
3304
3441
|
if (child instanceof AssistantMessageComponent) {
|
|
3305
3442
|
child.setHideThinkingBlock(hidden);
|
|
3306
3443
|
}
|
|
3307
3444
|
}
|
|
3308
|
-
this.chatContainer.clear();
|
|
3309
3445
|
this.rebuildChatFromMessages();
|
|
3310
3446
|
},
|
|
3311
3447
|
onCollapseChangelogChange: (collapsed) => {
|
|
@@ -3341,10 +3477,6 @@ export class InteractiveMode {
|
|
|
3341
3477
|
this.editor.setAutocompleteMaxVisible(maxVisible);
|
|
3342
3478
|
}
|
|
3343
3479
|
},
|
|
3344
|
-
onClearOnShrinkChange: (enabled) => {
|
|
3345
|
-
this.settingsManager.setClearOnShrink(enabled);
|
|
3346
|
-
this.ui.setClearOnShrink(enabled);
|
|
3347
|
-
},
|
|
3348
3480
|
onShowTerminalProgressChange: (enabled) => {
|
|
3349
3481
|
this.settingsManager.setShowTerminalProgress(enabled);
|
|
3350
3482
|
},
|
|
@@ -3646,7 +3778,7 @@ export class InteractiveMode {
|
|
|
3646
3778
|
return;
|
|
3647
3779
|
}
|
|
3648
3780
|
// Update UI
|
|
3649
|
-
this.
|
|
3781
|
+
this.clearTranscript();
|
|
3650
3782
|
this.renderInitialMessages();
|
|
3651
3783
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
3652
3784
|
this.editor.setText(result.editorText);
|
|
@@ -4081,7 +4213,7 @@ export class InteractiveMode {
|
|
|
4081
4213
|
this.editorContainer.clear();
|
|
4082
4214
|
this.editorContainer.addChild(reloadBox);
|
|
4083
4215
|
this.ui.setFocus(reloadBox);
|
|
4084
|
-
this.ui.
|
|
4216
|
+
this.ui.rebuild();
|
|
4085
4217
|
await new Promise((resolve) => process.nextTick(resolve));
|
|
4086
4218
|
const dismissReloadBox = (editor) => {
|
|
4087
4219
|
this.editorContainer.clear();
|
|
@@ -4111,7 +4243,6 @@ export class InteractiveMode {
|
|
|
4111
4243
|
this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
|
|
4112
4244
|
}
|
|
4113
4245
|
this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
|
|
4114
|
-
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
4115
4246
|
this.setupAutocompleteProvider();
|
|
4116
4247
|
const runner = this.session.extensionRunner;
|
|
4117
4248
|
this.setupExtensionShortcuts(runner);
|
|
@@ -4247,13 +4378,13 @@ export class InteractiveMode {
|
|
|
4247
4378
|
else {
|
|
4248
4379
|
this.showWarning("Usage: /name <name>");
|
|
4249
4380
|
}
|
|
4250
|
-
this.
|
|
4381
|
+
this.commitFinalizedChatOutput();
|
|
4251
4382
|
return;
|
|
4252
4383
|
}
|
|
4253
4384
|
this.session.setSessionName(name);
|
|
4254
4385
|
this.chatContainer.addChild(new Spacer(1));
|
|
4255
4386
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${name}`), 1, 0));
|
|
4256
|
-
this.
|
|
4387
|
+
this.commitFinalizedChatOutput();
|
|
4257
4388
|
}
|
|
4258
4389
|
handleSessionCommand() {
|
|
4259
4390
|
const stats = this.session.getSessionStats();
|
|
@@ -4286,7 +4417,7 @@ export class InteractiveMode {
|
|
|
4286
4417
|
}
|
|
4287
4418
|
this.chatContainer.addChild(new Spacer(1));
|
|
4288
4419
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
4289
|
-
this.
|
|
4420
|
+
this.commitFinalizedChatOutput();
|
|
4290
4421
|
}
|
|
4291
4422
|
handleChangelogCommand() {
|
|
4292
4423
|
const changelogPath = getChangelogPath();
|
|
@@ -4303,7 +4434,7 @@ export class InteractiveMode {
|
|
|
4303
4434
|
this.chatContainer.addChild(new Spacer(1));
|
|
4304
4435
|
this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, this.getMarkdownThemeWithSettings()));
|
|
4305
4436
|
this.chatContainer.addChild(new DynamicBorder());
|
|
4306
|
-
this.
|
|
4437
|
+
this.commitFinalizedChatOutput();
|
|
4307
4438
|
}
|
|
4308
4439
|
/**
|
|
4309
4440
|
* Get capitalized display string for an app keybinding action.
|
|
@@ -4424,7 +4555,7 @@ export class InteractiveMode {
|
|
|
4424
4555
|
this.chatContainer.addChild(new Spacer(1));
|
|
4425
4556
|
this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, this.getMarkdownThemeWithSettings()));
|
|
4426
4557
|
this.chatContainer.addChild(new DynamicBorder());
|
|
4427
|
-
this.
|
|
4558
|
+
this.commitFinalizedChatOutput();
|
|
4428
4559
|
}
|
|
4429
4560
|
async handleClearCommand() {
|
|
4430
4561
|
if (this.loadingAnimation) {
|
|
@@ -4440,7 +4571,7 @@ export class InteractiveMode {
|
|
|
4440
4571
|
this.renderCurrentSessionState();
|
|
4441
4572
|
this.chatContainer.addChild(new Spacer(1));
|
|
4442
4573
|
this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
|
|
4443
|
-
this.
|
|
4574
|
+
this.commitFinalizedChatOutput();
|
|
4444
4575
|
}
|
|
4445
4576
|
catch (error) {
|
|
4446
4577
|
await this.handleFatalRuntimeError("Failed to create session", error);
|
|
@@ -4471,22 +4602,38 @@ export class InteractiveMode {
|
|
|
4471
4602
|
fs.writeFileSync(debugLogPath, debugData);
|
|
4472
4603
|
this.chatContainer.addChild(new Spacer(1));
|
|
4473
4604
|
this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
|
|
4474
|
-
this.
|
|
4605
|
+
this.commitFinalizedChatOutput();
|
|
4475
4606
|
}
|
|
4476
4607
|
handleArminSaysHi() {
|
|
4608
|
+
const component = new ArminComponent(this.ui, () => {
|
|
4609
|
+
if (!this.mutableChatComponents.has(component) || !this.chatContainer.children.includes(component))
|
|
4610
|
+
return;
|
|
4611
|
+
this.setChatComponentMutable(component, false);
|
|
4612
|
+
this.promoteFinalizedChatPrefix();
|
|
4613
|
+
this.ui.requestRender();
|
|
4614
|
+
});
|
|
4477
4615
|
this.chatContainer.addChild(new Spacer(1));
|
|
4478
|
-
this.chatContainer.addChild(
|
|
4479
|
-
this.
|
|
4616
|
+
this.chatContainer.addChild(component);
|
|
4617
|
+
this.setChatComponentMutable(component, true);
|
|
4618
|
+
this.commitFinalizedChatOutput();
|
|
4480
4619
|
}
|
|
4481
4620
|
handleDementedDelves() {
|
|
4482
4621
|
this.chatContainer.addChild(new Spacer(1));
|
|
4483
4622
|
this.chatContainer.addChild(new EarendilAnnouncementComponent());
|
|
4484
|
-
this.
|
|
4623
|
+
this.commitFinalizedChatOutput();
|
|
4485
4624
|
}
|
|
4486
4625
|
handleDaxnuts() {
|
|
4626
|
+
const component = new DaxnutsComponent(this.ui, () => {
|
|
4627
|
+
if (!this.mutableChatComponents.has(component) || !this.chatContainer.children.includes(component))
|
|
4628
|
+
return;
|
|
4629
|
+
this.setChatComponentMutable(component, false);
|
|
4630
|
+
this.promoteFinalizedChatPrefix();
|
|
4631
|
+
this.ui.requestRender();
|
|
4632
|
+
});
|
|
4487
4633
|
this.chatContainer.addChild(new Spacer(1));
|
|
4488
|
-
this.chatContainer.addChild(
|
|
4489
|
-
this.
|
|
4634
|
+
this.chatContainer.addChild(component);
|
|
4635
|
+
this.setChatComponentMutable(component, true);
|
|
4636
|
+
this.commitFinalizedChatOutput();
|
|
4490
4637
|
}
|
|
4491
4638
|
checkDaxnutsEasterEgg(model) {
|
|
4492
4639
|
if (model.provider === "opencode" && model.id.toLowerCase().includes("kimi-k2.5")) {
|
|
@@ -4512,6 +4659,7 @@ export class InteractiveMode {
|
|
|
4512
4659
|
this.pendingBashComponents.push(this.bashComponent);
|
|
4513
4660
|
}
|
|
4514
4661
|
else {
|
|
4662
|
+
this.sealStatus();
|
|
4515
4663
|
this.chatContainer.addChild(this.bashComponent);
|
|
4516
4664
|
}
|
|
4517
4665
|
// Show output and complete
|
|
@@ -4521,6 +4669,7 @@ export class InteractiveMode {
|
|
|
4521
4669
|
this.bashComponent.setComplete(result.exitCode, result.cancelled, result.truncated ? { truncated: true, content: result.output } : undefined, result.fullOutputPath);
|
|
4522
4670
|
// Record the result in session
|
|
4523
4671
|
this.session.recordBashResult(command, result, { excludeFromContext });
|
|
4672
|
+
this.promoteFinalizedChatPrefix();
|
|
4524
4673
|
this.bashComponent = undefined;
|
|
4525
4674
|
this.ui.requestRender();
|
|
4526
4675
|
return;
|
|
@@ -4528,6 +4677,7 @@ export class InteractiveMode {
|
|
|
4528
4677
|
// Normal execution path (possibly with custom operations)
|
|
4529
4678
|
const isDeferred = this.session.isStreaming;
|
|
4530
4679
|
this.bashComponent = new BashExecutionComponent(command, this.ui, excludeFromContext);
|
|
4680
|
+
this.setChatComponentMutable(this.bashComponent, true);
|
|
4531
4681
|
if (isDeferred) {
|
|
4532
4682
|
// Show in pending area when agent is streaming
|
|
4533
4683
|
this.pendingMessagesContainer.addChild(this.bashComponent);
|
|
@@ -4535,6 +4685,7 @@ export class InteractiveMode {
|
|
|
4535
4685
|
}
|
|
4536
4686
|
else {
|
|
4537
4687
|
// Show in chat immediately when agent is idle
|
|
4688
|
+
this.sealStatus();
|
|
4538
4689
|
this.chatContainer.addChild(this.bashComponent);
|
|
4539
4690
|
}
|
|
4540
4691
|
this.ui.requestRender();
|
|
@@ -4555,6 +4706,9 @@ export class InteractiveMode {
|
|
|
4555
4706
|
}
|
|
4556
4707
|
this.showError(`Bash command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4557
4708
|
}
|
|
4709
|
+
if (this.bashComponent)
|
|
4710
|
+
this.setChatComponentMutable(this.bashComponent, false);
|
|
4711
|
+
this.promoteFinalizedChatPrefix();
|
|
4558
4712
|
this.bashComponent = undefined;
|
|
4559
4713
|
this.ui.requestRender();
|
|
4560
4714
|
}
|