@leanandmean/coding-agent 0.74.1-scramjet.24 → 0.74.1-scramjet.26
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/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +2 -10
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +58 -24
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +30 -4
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +13 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/scramjet-command-parser.d.ts +4 -0
- package/dist/core/scramjet-command-parser.d.ts.map +1 -1
- package/dist/core/scramjet-command-parser.js +72 -1
- package/dist/core/scramjet-command-parser.js.map +1 -1
- package/dist/core/session-manager.d.ts +10 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +36 -11
- package/dist/core/session-manager.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/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.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 +228 -64
- 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
|
@@ -19,7 +19,7 @@ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScop
|
|
|
19
19
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
20
20
|
import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "../../core/provider-display-names.js";
|
|
21
21
|
import { describeRuntimeError } from "../../core/resource-loader.js";
|
|
22
|
-
import { parseScramjetCommandBlock } from "../../core/scramjet-command-parser.js"; // SCRAMJET-DIVERGENCE: scramjet-command
|
|
22
|
+
import { indexScramjetCommandStarts, parseScramjetCommandBlock, restoreScramjetCommandInvocation, } from "../../core/scramjet-command-parser.js"; // SCRAMJET-DIVERGENCE: scramjet-command restoration (issues 82, 414)
|
|
23
23
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
24
24
|
import { SessionManager } from "../../core/session-manager.js";
|
|
25
25
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
@@ -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);
|
|
@@ -2551,9 +2666,10 @@ export class InteractiveMode {
|
|
|
2551
2666
|
this.chatContainer.addChild(userComponent);
|
|
2552
2667
|
}
|
|
2553
2668
|
if (options?.populateHistory) {
|
|
2554
|
-
const compactForm =
|
|
2555
|
-
|
|
2556
|
-
|
|
2669
|
+
const compactForm = options.historyText ??
|
|
2670
|
+
(scramjetBlock.userContext
|
|
2671
|
+
? `/${scramjetBlock.name} ${scramjetBlock.userContext}`
|
|
2672
|
+
: `/${scramjetBlock.name}`);
|
|
2557
2673
|
this.editor.addToHistory?.(compactForm);
|
|
2558
2674
|
}
|
|
2559
2675
|
}
|
|
@@ -2592,6 +2708,7 @@ export class InteractiveMode {
|
|
|
2592
2708
|
const _exhaustive = message;
|
|
2593
2709
|
}
|
|
2594
2710
|
}
|
|
2711
|
+
this.promoteFinalizedChatPrefix();
|
|
2595
2712
|
}
|
|
2596
2713
|
/**
|
|
2597
2714
|
* Render session context to chat. Used for initial load and rebuild after compaction.
|
|
@@ -2602,6 +2719,11 @@ export class InteractiveMode {
|
|
|
2602
2719
|
renderSessionContext(sessionContext, options = {}) {
|
|
2603
2720
|
this.pendingTools.clear();
|
|
2604
2721
|
const renderedPendingTools = new Map();
|
|
2722
|
+
const entries = options.populateHistory ? this.sessionManager.getEntries() : [];
|
|
2723
|
+
const commandStarts = indexScramjetCommandStarts(entries);
|
|
2724
|
+
const entriesByMessage = new Map(entries
|
|
2725
|
+
.filter((entry) => entry.type === "message")
|
|
2726
|
+
.map((entry) => [entry.message, entry]));
|
|
2605
2727
|
if (options.updateFooter) {
|
|
2606
2728
|
this.footer.invalidate();
|
|
2607
2729
|
this.updateEditorBorderColor();
|
|
@@ -2619,6 +2741,7 @@ export class InteractiveMode {
|
|
|
2619
2741
|
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
2620
2742
|
component.setExpanded(this.toolOutputExpanded);
|
|
2621
2743
|
this.chatContainer.addChild(component);
|
|
2744
|
+
this.setChatComponentMutable(component, true);
|
|
2622
2745
|
if (message.stopReason === "aborted" || message.stopReason === "error") {
|
|
2623
2746
|
let errorMessage;
|
|
2624
2747
|
if (message.stopReason === "aborted") {
|
|
@@ -2632,6 +2755,8 @@ export class InteractiveMode {
|
|
|
2632
2755
|
errorMessage = message.errorMessage || "Error";
|
|
2633
2756
|
}
|
|
2634
2757
|
component.updateResult({ content: [{ type: "text", text: errorMessage }], isError: true });
|
|
2758
|
+
component.seal();
|
|
2759
|
+
this.setChatComponentMutable(component, false);
|
|
2635
2760
|
}
|
|
2636
2761
|
else {
|
|
2637
2762
|
renderedPendingTools.set(content.id, component);
|
|
@@ -2647,16 +2772,41 @@ export class InteractiveMode {
|
|
|
2647
2772
|
component.setArgsComplete();
|
|
2648
2773
|
component.updateResult(message);
|
|
2649
2774
|
renderedPendingTools.delete(message.toolCallId);
|
|
2775
|
+
if (component.hasPendingImageConversions()) {
|
|
2776
|
+
const pendingToolFinalizations = this.pendingToolFinalizations;
|
|
2777
|
+
const finalization = component.waitForImageConversions().then(() => {
|
|
2778
|
+
if (!this.mutableChatComponents.has(component) ||
|
|
2779
|
+
!this.chatContainer.children.includes(component)) {
|
|
2780
|
+
component.seal();
|
|
2781
|
+
return;
|
|
2782
|
+
}
|
|
2783
|
+
component.seal();
|
|
2784
|
+
this.setChatComponentMutable(component, false);
|
|
2785
|
+
this.promoteFinalizedChatPrefix();
|
|
2786
|
+
this.ui.requestRender();
|
|
2787
|
+
});
|
|
2788
|
+
pendingToolFinalizations.add(finalization);
|
|
2789
|
+
void finalization.finally(() => pendingToolFinalizations.delete(finalization));
|
|
2790
|
+
}
|
|
2791
|
+
else {
|
|
2792
|
+
component.seal();
|
|
2793
|
+
this.setChatComponentMutable(component, false);
|
|
2794
|
+
}
|
|
2650
2795
|
}
|
|
2651
2796
|
}
|
|
2652
2797
|
else {
|
|
2653
2798
|
// All other messages use standard rendering
|
|
2654
|
-
|
|
2799
|
+
const entry = entriesByMessage.get(message);
|
|
2800
|
+
this.addMessageToChat(message, {
|
|
2801
|
+
...options,
|
|
2802
|
+
historyText: entry ? restoreScramjetCommandInvocation(entry, commandStarts) : undefined,
|
|
2803
|
+
});
|
|
2655
2804
|
}
|
|
2656
2805
|
}
|
|
2657
2806
|
for (const [toolCallId, component] of renderedPendingTools) {
|
|
2658
2807
|
this.pendingTools.set(toolCallId, component);
|
|
2659
2808
|
}
|
|
2809
|
+
this.promoteFinalizedChatPrefix();
|
|
2660
2810
|
this.ui.requestRender();
|
|
2661
2811
|
}
|
|
2662
2812
|
renderInitialMessages() {
|
|
@@ -2683,7 +2833,7 @@ export class InteractiveMode {
|
|
|
2683
2833
|
});
|
|
2684
2834
|
}
|
|
2685
2835
|
rebuildChatFromMessages() {
|
|
2686
|
-
this.
|
|
2836
|
+
this.clearTranscript();
|
|
2687
2837
|
const context = this.sessionManager.buildSessionContext();
|
|
2688
2838
|
this.renderSessionContext(context);
|
|
2689
2839
|
}
|
|
@@ -2828,7 +2978,7 @@ export class InteractiveMode {
|
|
|
2828
2978
|
clearInterval(suspendKeepAlive);
|
|
2829
2979
|
process.removeListener("SIGINT", ignoreSigint);
|
|
2830
2980
|
this.ui.start();
|
|
2831
|
-
this.ui.
|
|
2981
|
+
this.ui.rebuild();
|
|
2832
2982
|
});
|
|
2833
2983
|
try {
|
|
2834
2984
|
// Stop the TUI (restore terminal to normal mode)
|
|
@@ -2931,24 +3081,24 @@ export class InteractiveMode {
|
|
|
2931
3081
|
if (isExpandable(activeHeader)) {
|
|
2932
3082
|
activeHeader.setExpanded(expanded);
|
|
2933
3083
|
}
|
|
2934
|
-
for (const child of this.chatContainer.children) {
|
|
3084
|
+
for (const child of [...this.committedChatContainer.children, ...this.chatContainer.children]) {
|
|
2935
3085
|
if (isExpandable(child)) {
|
|
2936
3086
|
child.setExpanded(expanded);
|
|
2937
3087
|
}
|
|
2938
3088
|
}
|
|
2939
|
-
this.ui.
|
|
3089
|
+
this.ui.rebuild();
|
|
2940
3090
|
}
|
|
2941
3091
|
toggleThinkingBlockVisibility() {
|
|
2942
3092
|
this.hideThinkingBlock = !this.hideThinkingBlock;
|
|
2943
3093
|
this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
|
|
2944
3094
|
// Rebuild chat from session messages
|
|
2945
|
-
this.chatContainer.clear();
|
|
2946
3095
|
this.rebuildChatFromMessages();
|
|
2947
3096
|
// If streaming, re-add the streaming component with updated visibility and re-render
|
|
2948
3097
|
if (this.streamingComponent && this.streamingMessage) {
|
|
2949
3098
|
this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);
|
|
2950
3099
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
2951
3100
|
this.chatContainer.addChild(this.streamingComponent);
|
|
3101
|
+
this.setChatComponentMutable(this.streamingComponent, true);
|
|
2952
3102
|
}
|
|
2953
3103
|
this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
|
|
2954
3104
|
}
|
|
@@ -2990,8 +3140,7 @@ export class InteractiveMode {
|
|
|
2990
3140
|
}
|
|
2991
3141
|
// Restart TUI
|
|
2992
3142
|
this.ui.start();
|
|
2993
|
-
|
|
2994
|
-
this.ui.requestRender(true);
|
|
3143
|
+
this.ui.rebuild();
|
|
2995
3144
|
}
|
|
2996
3145
|
}
|
|
2997
3146
|
// =========================================================================
|
|
@@ -3002,14 +3151,18 @@ export class InteractiveMode {
|
|
|
3002
3151
|
this.ui.requestRender();
|
|
3003
3152
|
}
|
|
3004
3153
|
showError(errorMessage) {
|
|
3154
|
+
this.sealStatus();
|
|
3005
3155
|
this.chatContainer.addChild(new Spacer(1));
|
|
3006
3156
|
this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
|
|
3007
3157
|
this.chatContainer.addChild(new Spacer(1));
|
|
3158
|
+
this.promoteFinalizedChatPrefix();
|
|
3008
3159
|
this.ui.requestRender();
|
|
3009
3160
|
}
|
|
3010
3161
|
showWarning(warningMessage) {
|
|
3162
|
+
this.sealStatus();
|
|
3011
3163
|
this.chatContainer.addChild(new Spacer(1));
|
|
3012
3164
|
this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
|
|
3165
|
+
this.promoteFinalizedChatPrefix();
|
|
3013
3166
|
this.ui.requestRender();
|
|
3014
3167
|
}
|
|
3015
3168
|
// SCRAMJET-DIVERGENCE: showNewVersionNotification removed (version check gutted).
|
|
@@ -3021,7 +3174,7 @@ export class InteractiveMode {
|
|
|
3021
3174
|
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
3022
3175
|
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
3176
|
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
3024
|
-
this.
|
|
3177
|
+
this.commitFinalizedChatOutput();
|
|
3025
3178
|
}
|
|
3026
3179
|
/**
|
|
3027
3180
|
* Get all queued messages (read-only).
|
|
@@ -3181,11 +3334,14 @@ export class InteractiveMode {
|
|
|
3181
3334
|
}
|
|
3182
3335
|
/** Move pending bash components from pending area to chat */
|
|
3183
3336
|
flushPendingBashComponents() {
|
|
3337
|
+
if (this.pendingBashComponents.length > 0)
|
|
3338
|
+
this.sealStatus();
|
|
3184
3339
|
for (const component of this.pendingBashComponents) {
|
|
3185
3340
|
this.pendingMessagesContainer.removeChild(component);
|
|
3186
3341
|
this.chatContainer.addChild(component);
|
|
3187
3342
|
}
|
|
3188
3343
|
this.pendingBashComponents = [];
|
|
3344
|
+
this.promoteFinalizedChatPrefix();
|
|
3189
3345
|
}
|
|
3190
3346
|
// =========================================================================
|
|
3191
3347
|
// Selectors
|
|
@@ -3232,7 +3388,6 @@ export class InteractiveMode {
|
|
|
3232
3388
|
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
|
3233
3389
|
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
|
3234
3390
|
quietStartup: this.settingsManager.getQuietStartup(),
|
|
3235
|
-
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
|
3236
3391
|
showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
|
|
3237
3392
|
warnings: this.settingsManager.getWarnings(),
|
|
3238
3393
|
}, {
|
|
@@ -3242,19 +3397,11 @@ export class InteractiveMode {
|
|
|
3242
3397
|
},
|
|
3243
3398
|
onShowImagesChange: (enabled) => {
|
|
3244
3399
|
this.settingsManager.setShowImages(enabled);
|
|
3245
|
-
|
|
3246
|
-
if (child instanceof ToolExecutionComponent) {
|
|
3247
|
-
child.setShowImages(enabled);
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3400
|
+
this.updateToolImagePresentation((component) => component.setShowImages(enabled));
|
|
3250
3401
|
},
|
|
3251
3402
|
onImageWidthCellsChange: (width) => {
|
|
3252
3403
|
this.settingsManager.setImageWidthCells(width);
|
|
3253
|
-
|
|
3254
|
-
if (child instanceof ToolExecutionComponent) {
|
|
3255
|
-
child.setImageWidthCells(width);
|
|
3256
|
-
}
|
|
3257
|
-
}
|
|
3404
|
+
this.updateToolImagePresentation((component) => component.setImageWidthCells(width));
|
|
3258
3405
|
},
|
|
3259
3406
|
onAutoResizeImagesChange: (enabled) => {
|
|
3260
3407
|
this.settingsManager.setImageAutoResize(enabled);
|
|
@@ -3300,12 +3447,11 @@ export class InteractiveMode {
|
|
|
3300
3447
|
onHideThinkingBlockChange: (hidden) => {
|
|
3301
3448
|
this.hideThinkingBlock = hidden;
|
|
3302
3449
|
this.settingsManager.setHideThinkingBlock(hidden);
|
|
3303
|
-
for (const child of this.chatContainer.children) {
|
|
3450
|
+
for (const child of [...this.committedChatContainer.children, ...this.chatContainer.children]) {
|
|
3304
3451
|
if (child instanceof AssistantMessageComponent) {
|
|
3305
3452
|
child.setHideThinkingBlock(hidden);
|
|
3306
3453
|
}
|
|
3307
3454
|
}
|
|
3308
|
-
this.chatContainer.clear();
|
|
3309
3455
|
this.rebuildChatFromMessages();
|
|
3310
3456
|
},
|
|
3311
3457
|
onCollapseChangelogChange: (collapsed) => {
|
|
@@ -3341,10 +3487,6 @@ export class InteractiveMode {
|
|
|
3341
3487
|
this.editor.setAutocompleteMaxVisible(maxVisible);
|
|
3342
3488
|
}
|
|
3343
3489
|
},
|
|
3344
|
-
onClearOnShrinkChange: (enabled) => {
|
|
3345
|
-
this.settingsManager.setClearOnShrink(enabled);
|
|
3346
|
-
this.ui.setClearOnShrink(enabled);
|
|
3347
|
-
},
|
|
3348
3490
|
onShowTerminalProgressChange: (enabled) => {
|
|
3349
3491
|
this.settingsManager.setShowTerminalProgress(enabled);
|
|
3350
3492
|
},
|
|
@@ -3646,7 +3788,7 @@ export class InteractiveMode {
|
|
|
3646
3788
|
return;
|
|
3647
3789
|
}
|
|
3648
3790
|
// Update UI
|
|
3649
|
-
this.
|
|
3791
|
+
this.clearTranscript();
|
|
3650
3792
|
this.renderInitialMessages();
|
|
3651
3793
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
3652
3794
|
this.editor.setText(result.editorText);
|
|
@@ -4081,7 +4223,7 @@ export class InteractiveMode {
|
|
|
4081
4223
|
this.editorContainer.clear();
|
|
4082
4224
|
this.editorContainer.addChild(reloadBox);
|
|
4083
4225
|
this.ui.setFocus(reloadBox);
|
|
4084
|
-
this.ui.
|
|
4226
|
+
this.ui.rebuild();
|
|
4085
4227
|
await new Promise((resolve) => process.nextTick(resolve));
|
|
4086
4228
|
const dismissReloadBox = (editor) => {
|
|
4087
4229
|
this.editorContainer.clear();
|
|
@@ -4111,7 +4253,6 @@ export class InteractiveMode {
|
|
|
4111
4253
|
this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
|
|
4112
4254
|
}
|
|
4113
4255
|
this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
|
|
4114
|
-
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
4115
4256
|
this.setupAutocompleteProvider();
|
|
4116
4257
|
const runner = this.session.extensionRunner;
|
|
4117
4258
|
this.setupExtensionShortcuts(runner);
|
|
@@ -4247,13 +4388,13 @@ export class InteractiveMode {
|
|
|
4247
4388
|
else {
|
|
4248
4389
|
this.showWarning("Usage: /name <name>");
|
|
4249
4390
|
}
|
|
4250
|
-
this.
|
|
4391
|
+
this.commitFinalizedChatOutput();
|
|
4251
4392
|
return;
|
|
4252
4393
|
}
|
|
4253
4394
|
this.session.setSessionName(name);
|
|
4254
4395
|
this.chatContainer.addChild(new Spacer(1));
|
|
4255
4396
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${name}`), 1, 0));
|
|
4256
|
-
this.
|
|
4397
|
+
this.commitFinalizedChatOutput();
|
|
4257
4398
|
}
|
|
4258
4399
|
handleSessionCommand() {
|
|
4259
4400
|
const stats = this.session.getSessionStats();
|
|
@@ -4286,7 +4427,7 @@ export class InteractiveMode {
|
|
|
4286
4427
|
}
|
|
4287
4428
|
this.chatContainer.addChild(new Spacer(1));
|
|
4288
4429
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
4289
|
-
this.
|
|
4430
|
+
this.commitFinalizedChatOutput();
|
|
4290
4431
|
}
|
|
4291
4432
|
handleChangelogCommand() {
|
|
4292
4433
|
const changelogPath = getChangelogPath();
|
|
@@ -4303,7 +4444,7 @@ export class InteractiveMode {
|
|
|
4303
4444
|
this.chatContainer.addChild(new Spacer(1));
|
|
4304
4445
|
this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, this.getMarkdownThemeWithSettings()));
|
|
4305
4446
|
this.chatContainer.addChild(new DynamicBorder());
|
|
4306
|
-
this.
|
|
4447
|
+
this.commitFinalizedChatOutput();
|
|
4307
4448
|
}
|
|
4308
4449
|
/**
|
|
4309
4450
|
* Get capitalized display string for an app keybinding action.
|
|
@@ -4424,7 +4565,7 @@ export class InteractiveMode {
|
|
|
4424
4565
|
this.chatContainer.addChild(new Spacer(1));
|
|
4425
4566
|
this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, this.getMarkdownThemeWithSettings()));
|
|
4426
4567
|
this.chatContainer.addChild(new DynamicBorder());
|
|
4427
|
-
this.
|
|
4568
|
+
this.commitFinalizedChatOutput();
|
|
4428
4569
|
}
|
|
4429
4570
|
async handleClearCommand() {
|
|
4430
4571
|
if (this.loadingAnimation) {
|
|
@@ -4440,7 +4581,7 @@ export class InteractiveMode {
|
|
|
4440
4581
|
this.renderCurrentSessionState();
|
|
4441
4582
|
this.chatContainer.addChild(new Spacer(1));
|
|
4442
4583
|
this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
|
|
4443
|
-
this.
|
|
4584
|
+
this.commitFinalizedChatOutput();
|
|
4444
4585
|
}
|
|
4445
4586
|
catch (error) {
|
|
4446
4587
|
await this.handleFatalRuntimeError("Failed to create session", error);
|
|
@@ -4471,22 +4612,38 @@ export class InteractiveMode {
|
|
|
4471
4612
|
fs.writeFileSync(debugLogPath, debugData);
|
|
4472
4613
|
this.chatContainer.addChild(new Spacer(1));
|
|
4473
4614
|
this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
|
|
4474
|
-
this.
|
|
4615
|
+
this.commitFinalizedChatOutput();
|
|
4475
4616
|
}
|
|
4476
4617
|
handleArminSaysHi() {
|
|
4618
|
+
const component = new ArminComponent(this.ui, () => {
|
|
4619
|
+
if (!this.mutableChatComponents.has(component) || !this.chatContainer.children.includes(component))
|
|
4620
|
+
return;
|
|
4621
|
+
this.setChatComponentMutable(component, false);
|
|
4622
|
+
this.promoteFinalizedChatPrefix();
|
|
4623
|
+
this.ui.requestRender();
|
|
4624
|
+
});
|
|
4477
4625
|
this.chatContainer.addChild(new Spacer(1));
|
|
4478
|
-
this.chatContainer.addChild(
|
|
4479
|
-
this.
|
|
4626
|
+
this.chatContainer.addChild(component);
|
|
4627
|
+
this.setChatComponentMutable(component, true);
|
|
4628
|
+
this.commitFinalizedChatOutput();
|
|
4480
4629
|
}
|
|
4481
4630
|
handleDementedDelves() {
|
|
4482
4631
|
this.chatContainer.addChild(new Spacer(1));
|
|
4483
4632
|
this.chatContainer.addChild(new EarendilAnnouncementComponent());
|
|
4484
|
-
this.
|
|
4633
|
+
this.commitFinalizedChatOutput();
|
|
4485
4634
|
}
|
|
4486
4635
|
handleDaxnuts() {
|
|
4636
|
+
const component = new DaxnutsComponent(this.ui, () => {
|
|
4637
|
+
if (!this.mutableChatComponents.has(component) || !this.chatContainer.children.includes(component))
|
|
4638
|
+
return;
|
|
4639
|
+
this.setChatComponentMutable(component, false);
|
|
4640
|
+
this.promoteFinalizedChatPrefix();
|
|
4641
|
+
this.ui.requestRender();
|
|
4642
|
+
});
|
|
4487
4643
|
this.chatContainer.addChild(new Spacer(1));
|
|
4488
|
-
this.chatContainer.addChild(
|
|
4489
|
-
this.
|
|
4644
|
+
this.chatContainer.addChild(component);
|
|
4645
|
+
this.setChatComponentMutable(component, true);
|
|
4646
|
+
this.commitFinalizedChatOutput();
|
|
4490
4647
|
}
|
|
4491
4648
|
checkDaxnutsEasterEgg(model) {
|
|
4492
4649
|
if (model.provider === "opencode" && model.id.toLowerCase().includes("kimi-k2.5")) {
|
|
@@ -4512,6 +4669,7 @@ export class InteractiveMode {
|
|
|
4512
4669
|
this.pendingBashComponents.push(this.bashComponent);
|
|
4513
4670
|
}
|
|
4514
4671
|
else {
|
|
4672
|
+
this.sealStatus();
|
|
4515
4673
|
this.chatContainer.addChild(this.bashComponent);
|
|
4516
4674
|
}
|
|
4517
4675
|
// Show output and complete
|
|
@@ -4521,6 +4679,7 @@ export class InteractiveMode {
|
|
|
4521
4679
|
this.bashComponent.setComplete(result.exitCode, result.cancelled, result.truncated ? { truncated: true, content: result.output } : undefined, result.fullOutputPath);
|
|
4522
4680
|
// Record the result in session
|
|
4523
4681
|
this.session.recordBashResult(command, result, { excludeFromContext });
|
|
4682
|
+
this.promoteFinalizedChatPrefix();
|
|
4524
4683
|
this.bashComponent = undefined;
|
|
4525
4684
|
this.ui.requestRender();
|
|
4526
4685
|
return;
|
|
@@ -4528,6 +4687,7 @@ export class InteractiveMode {
|
|
|
4528
4687
|
// Normal execution path (possibly with custom operations)
|
|
4529
4688
|
const isDeferred = this.session.isStreaming;
|
|
4530
4689
|
this.bashComponent = new BashExecutionComponent(command, this.ui, excludeFromContext);
|
|
4690
|
+
this.setChatComponentMutable(this.bashComponent, true);
|
|
4531
4691
|
if (isDeferred) {
|
|
4532
4692
|
// Show in pending area when agent is streaming
|
|
4533
4693
|
this.pendingMessagesContainer.addChild(this.bashComponent);
|
|
@@ -4535,6 +4695,7 @@ export class InteractiveMode {
|
|
|
4535
4695
|
}
|
|
4536
4696
|
else {
|
|
4537
4697
|
// Show in chat immediately when agent is idle
|
|
4698
|
+
this.sealStatus();
|
|
4538
4699
|
this.chatContainer.addChild(this.bashComponent);
|
|
4539
4700
|
}
|
|
4540
4701
|
this.ui.requestRender();
|
|
@@ -4555,6 +4716,9 @@ export class InteractiveMode {
|
|
|
4555
4716
|
}
|
|
4556
4717
|
this.showError(`Bash command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4557
4718
|
}
|
|
4719
|
+
if (this.bashComponent)
|
|
4720
|
+
this.setChatComponentMutable(this.bashComponent, false);
|
|
4721
|
+
this.promoteFinalizedChatPrefix();
|
|
4558
4722
|
this.bashComponent = undefined;
|
|
4559
4723
|
this.ui.requestRender();
|
|
4560
4724
|
}
|