@apholdings/jensen-code 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3061 -3061
- package/README.md +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +6 -6
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +17 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +55 -28
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +10 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +1 -6
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +10 -40
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +5 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +1 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/top-bar.d.ts.map +1 -1
- package/dist/modes/interactive/components/top-bar.js +1 -1
- package/dist/modes/interactive/components/top-bar.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +6 -3
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +204 -86
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +8 -4
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +2 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +592 -592
- package/docs/session.md +412 -412
- package/examples/extensions/osgrep.ts +643 -0
- package/examples/extensions/subagent/agents.ts +150 -37
- package/examples/extensions/subagent/index.ts +634 -513
- package/package.json +3 -3
- package/examples/README.md +0 -25
- package/examples/extensions/README.md +0 -206
- package/examples/extensions/antigravity-image-gen.ts +0 -415
- package/examples/extensions/auto-commit-on-exit.ts +0 -49
- package/examples/extensions/bash-spawn-hook.ts +0 -30
- package/examples/extensions/bookmark.ts +0 -50
- package/examples/extensions/built-in-tool-renderer.ts +0 -246
- package/examples/extensions/claude-rules.ts +0 -86
- package/examples/extensions/commands.ts +0 -72
- package/examples/extensions/confirm-destructive.ts +0 -59
- package/examples/extensions/custom-compaction.ts +0 -114
- package/examples/extensions/custom-footer.ts +0 -64
- package/examples/extensions/custom-header.ts +0 -73
- package/examples/extensions/custom-provider-anthropic/index.ts +0 -604
- package/examples/extensions/custom-provider-anthropic/package-lock.json +0 -24
- package/examples/extensions/custom-provider-anthropic/package.json +0 -19
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +0 -349
- package/examples/extensions/custom-provider-gitlab-duo/package.json +0 -16
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +0 -82
- package/examples/extensions/custom-provider-qwen-cli/index.ts +0 -345
- package/examples/extensions/custom-provider-qwen-cli/package.json +0 -16
- package/examples/extensions/dirty-repo-guard.ts +0 -56
- package/examples/extensions/doom-overlay/README.md +0 -46
- package/examples/extensions/doom-overlay/doom/build/doom.js +0 -21
- package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
- package/examples/extensions/doom-overlay/doom/build.sh +0 -152
- package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +0 -72
- package/examples/extensions/doom-overlay/doom-component.ts +0 -132
- package/examples/extensions/doom-overlay/doom-engine.ts +0 -173
- package/examples/extensions/doom-overlay/doom-keys.ts +0 -104
- package/examples/extensions/doom-overlay/index.ts +0 -74
- package/examples/extensions/doom-overlay/wad-finder.ts +0 -51
- package/examples/extensions/dynamic-resources/SKILL.md +0 -8
- package/examples/extensions/dynamic-resources/dynamic.json +0 -79
- package/examples/extensions/dynamic-resources/dynamic.md +0 -5
- package/examples/extensions/dynamic-resources/index.ts +0 -15
- package/examples/extensions/dynamic-tools.ts +0 -74
- package/examples/extensions/event-bus.ts +0 -43
- package/examples/extensions/file-trigger.ts +0 -41
- package/examples/extensions/git-checkpoint.ts +0 -53
- package/examples/extensions/handoff.ts +0 -150
- package/examples/extensions/hello.ts +0 -25
- package/examples/extensions/inline-bash.ts +0 -94
- package/examples/extensions/input-transform.ts +0 -43
- package/examples/extensions/interactive-shell.ts +0 -196
- package/examples/extensions/mac-system-theme.ts +0 -47
- package/examples/extensions/message-renderer.ts +0 -59
- package/examples/extensions/minimal-mode.ts +0 -426
- package/examples/extensions/modal-editor.ts +0 -85
- package/examples/extensions/model-status.ts +0 -31
- package/examples/extensions/notify.ts +0 -55
- package/examples/extensions/overlay-qa-tests.ts +0 -1348
- package/examples/extensions/overlay-test.ts +0 -150
- package/examples/extensions/permission-gate.ts +0 -34
- package/examples/extensions/pirate.ts +0 -47
- package/examples/extensions/plan-mode/README.md +0 -65
- package/examples/extensions/plan-mode/index.ts +0 -340
- package/examples/extensions/plan-mode/utils.ts +0 -168
- package/examples/extensions/preset.ts +0 -398
- package/examples/extensions/protected-paths.ts +0 -30
- package/examples/extensions/provider-payload.ts +0 -14
- package/examples/extensions/qna.ts +0 -119
- package/examples/extensions/question.ts +0 -264
- package/examples/extensions/questionnaire.ts +0 -427
- package/examples/extensions/rainbow-editor.ts +0 -88
- package/examples/extensions/reload-runtime.ts +0 -37
- package/examples/extensions/rpc-demo.ts +0 -124
- package/examples/extensions/sandbox/index.ts +0 -318
- package/examples/extensions/sandbox/package-lock.json +0 -92
- package/examples/extensions/sandbox/package.json +0 -19
- package/examples/extensions/send-user-message.ts +0 -97
- package/examples/extensions/session-name.ts +0 -27
- package/examples/extensions/shutdown-command.ts +0 -63
- package/examples/extensions/snake.ts +0 -343
- package/examples/extensions/space-invaders.ts +0 -560
- package/examples/extensions/ssh.ts +0 -220
- package/examples/extensions/status-line.ts +0 -40
- package/examples/extensions/subagent/README.md +0 -172
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
- package/examples/extensions/summarize.ts +0 -195
- package/examples/extensions/system-prompt-header.ts +0 -17
- package/examples/extensions/timed-confirm.ts +0 -70
- package/examples/extensions/titlebar-spinner.ts +0 -58
- package/examples/extensions/todo.ts +0 -299
- package/examples/extensions/tool-override.ts +0 -143
- package/examples/extensions/tools.ts +0 -146
- package/examples/extensions/trigger-compact.ts +0 -40
- package/examples/extensions/truncated-tool.ts +0 -192
- package/examples/extensions/widget-placement.ts +0 -17
- package/examples/extensions/with-deps/index.ts +0 -32
- package/examples/extensions/with-deps/package-lock.json +0 -31
- package/examples/extensions/with-deps/package.json +0 -22
- package/examples/rpc-extension-ui.ts +0 -632
- package/examples/sdk/01-minimal.ts +0 -22
- package/examples/sdk/02-custom-model.ts +0 -49
- package/examples/sdk/03-custom-prompt.ts +0 -55
- package/examples/sdk/04-skills.ts +0 -46
- package/examples/sdk/05-tools.ts +0 -56
- package/examples/sdk/06-extensions.ts +0 -88
- package/examples/sdk/07-context-files.ts +0 -40
- package/examples/sdk/08-prompt-templates.ts +0 -47
- package/examples/sdk/09-api-keys-and-oauth.ts +0 -48
- package/examples/sdk/10-settings.ts +0 -51
- package/examples/sdk/11-sessions.ts +0 -48
- package/examples/sdk/12-full-control.ts +0 -82
- package/examples/sdk/README.md +0 -145
|
@@ -122,6 +122,10 @@ export class InteractiveMode {
|
|
|
122
122
|
// Epoch hardening
|
|
123
123
|
uiEpoch = 0;
|
|
124
124
|
sessionEpoch = 0;
|
|
125
|
+
isInitialMessagesRendered = false;
|
|
126
|
+
// Visual region ownership
|
|
127
|
+
statusOwner = undefined;
|
|
128
|
+
promptOwner = undefined;
|
|
125
129
|
// Extension UI state
|
|
126
130
|
extensionSelector = undefined;
|
|
127
131
|
extensionInput = undefined;
|
|
@@ -357,6 +361,7 @@ export class InteractiveMode {
|
|
|
357
361
|
// Invalidate all stale async callbacks
|
|
358
362
|
this.uiEpoch++;
|
|
359
363
|
this.sessionEpoch++;
|
|
364
|
+
this.isInitialMessagesRendered = false;
|
|
360
365
|
// Stop all loaders
|
|
361
366
|
if (this.loadingAnimation) {
|
|
362
367
|
this.loadingAnimation.dispose();
|
|
@@ -421,57 +426,63 @@ export class InteractiveMode {
|
|
|
421
426
|
// Both are needed: fd for autocomplete, rg for grep tool and bash commands
|
|
422
427
|
const [fdPath] = await Promise.all([ensureTool("fd"), ensureTool("rg")]);
|
|
423
428
|
this.fdPath = fdPath;
|
|
429
|
+
// Add containers only if they're not already children
|
|
430
|
+
const addIfMissing = (parent, child) => {
|
|
431
|
+
if (!parent.children.includes(child)) {
|
|
432
|
+
parent.addChild(child);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
424
435
|
// Add header container as first child
|
|
425
|
-
this.ui
|
|
436
|
+
addIfMissing(this.ui, this.headerContainer);
|
|
426
437
|
// Always show the branded header/logo, even when quietStartup is enabled
|
|
427
|
-
this.headerContainer
|
|
428
|
-
this.headerContainer
|
|
438
|
+
addIfMissing(this.headerContainer, this.header);
|
|
439
|
+
addIfMissing(this.headerContainer, new Spacer(1));
|
|
429
440
|
// Add startup instructions only when not silenced
|
|
430
441
|
if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
|
|
431
442
|
const instructions = this.buildStartupInstructionsText();
|
|
432
443
|
this.builtInHeader = new Text(instructions, 1, 0);
|
|
433
|
-
this.headerContainer
|
|
434
|
-
this.headerContainer
|
|
444
|
+
addIfMissing(this.headerContainer, this.builtInHeader);
|
|
445
|
+
addIfMissing(this.headerContainer, new Spacer(1));
|
|
435
446
|
// Add changelog if provided
|
|
436
447
|
if (this.changelogMarkdown) {
|
|
437
|
-
this.headerContainer
|
|
448
|
+
addIfMissing(this.headerContainer, new DynamicBorder());
|
|
438
449
|
if (this.settingsManager.getCollapseChangelog()) {
|
|
439
450
|
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
440
451
|
const latestVersion = versionMatch ? versionMatch[1] : this.version;
|
|
441
452
|
const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
|
|
442
|
-
this.headerContainer
|
|
453
|
+
addIfMissing(this.headerContainer, new Text(condensedText, 1, 0));
|
|
443
454
|
}
|
|
444
455
|
else {
|
|
445
|
-
this.headerContainer
|
|
446
|
-
this.headerContainer
|
|
447
|
-
this.headerContainer
|
|
448
|
-
this.headerContainer
|
|
456
|
+
addIfMissing(this.headerContainer, new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
|
|
457
|
+
addIfMissing(this.headerContainer, new Spacer(1));
|
|
458
|
+
addIfMissing(this.headerContainer, new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
|
|
459
|
+
addIfMissing(this.headerContainer, new Spacer(1));
|
|
449
460
|
}
|
|
450
|
-
this.headerContainer
|
|
461
|
+
addIfMissing(this.headerContainer, new DynamicBorder());
|
|
451
462
|
}
|
|
452
463
|
}
|
|
453
464
|
else {
|
|
454
465
|
// Quiet startup: keep the logo visible, but suppress instruction text
|
|
455
466
|
this.builtInHeader = new Text("", 0, 0);
|
|
456
|
-
this.headerContainer
|
|
467
|
+
addIfMissing(this.headerContainer, this.builtInHeader);
|
|
457
468
|
if (this.changelogMarkdown) {
|
|
458
|
-
this.headerContainer
|
|
469
|
+
addIfMissing(this.headerContainer, new Spacer(1));
|
|
459
470
|
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
460
471
|
const latestVersion = versionMatch ? versionMatch[1] : this.version;
|
|
461
472
|
const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
|
|
462
|
-
this.headerContainer
|
|
473
|
+
addIfMissing(this.headerContainer, new Text(condensedText, 1, 0));
|
|
463
474
|
}
|
|
464
475
|
}
|
|
465
|
-
this.ui
|
|
466
|
-
this.ui
|
|
467
|
-
this.ui
|
|
476
|
+
addIfMissing(this.ui, this.chatContainer);
|
|
477
|
+
addIfMissing(this.ui, this.pendingMessagesContainer);
|
|
478
|
+
addIfMissing(this.ui, this.statusContainer);
|
|
468
479
|
this.renderWidgets(); // Initialize with default spacer
|
|
469
480
|
// The prompt area consists of an optional widget strip, the editor, and a bottom widget strip.
|
|
470
481
|
// Extensions should use ctx.ui.setWidget(..., { placement: "aboveEditor" }) for the top strip.
|
|
471
|
-
this.ui
|
|
472
|
-
this.ui
|
|
473
|
-
this.ui
|
|
474
|
-
this.ui
|
|
482
|
+
addIfMissing(this.ui, this.widgetContainerAbove);
|
|
483
|
+
addIfMissing(this.ui, this.editorContainer);
|
|
484
|
+
addIfMissing(this.ui, this.widgetContainerBelow);
|
|
485
|
+
addIfMissing(this.ui, this.footer);
|
|
475
486
|
this.ui.setFocus(this.editor);
|
|
476
487
|
this.updatePromptChrome();
|
|
477
488
|
this.setupKeyHandlers();
|
|
@@ -1210,7 +1221,7 @@ export class InteractiveMode {
|
|
|
1210
1221
|
this.widgetContainerAbove.clear();
|
|
1211
1222
|
this.widgetContainerBelow.clear();
|
|
1212
1223
|
}
|
|
1213
|
-
mountPromptOwner(component, options) {
|
|
1224
|
+
mountPromptOwner(component, owner, options) {
|
|
1214
1225
|
const focus = options?.focus ?? component;
|
|
1215
1226
|
const showWidgets = options?.showWidgets ?? false;
|
|
1216
1227
|
const requestRender = options?.requestRender ?? true;
|
|
@@ -1218,6 +1229,7 @@ export class InteractiveMode {
|
|
|
1218
1229
|
this.editorContainer.children.length === 1 &&
|
|
1219
1230
|
this.editorContainer.children[0] === component;
|
|
1220
1231
|
if (!isMounted) {
|
|
1232
|
+
this.promptOwner = owner;
|
|
1221
1233
|
this.editorContainer.clear();
|
|
1222
1234
|
this.editorContainer.addChild(component);
|
|
1223
1235
|
this.promptAreaComponent = component;
|
|
@@ -1236,6 +1248,9 @@ export class InteractiveMode {
|
|
|
1236
1248
|
}
|
|
1237
1249
|
}
|
|
1238
1250
|
restoreCanonicalEditor(options) {
|
|
1251
|
+
if (options?.owner !== undefined && this.promptOwner !== options.owner) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1239
1254
|
if (options?.text !== undefined) {
|
|
1240
1255
|
this.editor.setText(options.text);
|
|
1241
1256
|
}
|
|
@@ -1244,6 +1259,7 @@ export class InteractiveMode {
|
|
|
1244
1259
|
this.editorContainer.children.length === 1 &&
|
|
1245
1260
|
this.editorContainer.children[0] === editorComponent;
|
|
1246
1261
|
if (!isMounted) {
|
|
1262
|
+
this.promptOwner = undefined;
|
|
1247
1263
|
this.editorContainer.clear();
|
|
1248
1264
|
this.editorContainer.addChild(editorComponent);
|
|
1249
1265
|
this.promptAreaComponent = editorComponent;
|
|
@@ -1264,12 +1280,13 @@ export class InteractiveMode {
|
|
|
1264
1280
|
this.ui.requestRender();
|
|
1265
1281
|
}
|
|
1266
1282
|
}
|
|
1267
|
-
mountStatusOwner(component, options) {
|
|
1283
|
+
mountStatusOwner(component, owner, options) {
|
|
1268
1284
|
const requestRender = options?.requestRender ?? true;
|
|
1269
1285
|
const isMounted = this.statusComponent === component &&
|
|
1270
1286
|
this.statusContainer.children.length === 1 &&
|
|
1271
1287
|
this.statusContainer.children[0] === component;
|
|
1272
1288
|
if (!isMounted) {
|
|
1289
|
+
this.statusOwner = owner;
|
|
1273
1290
|
this.statusContainer.clear();
|
|
1274
1291
|
this.statusContainer.addChild(component);
|
|
1275
1292
|
this.statusComponent = component;
|
|
@@ -1287,11 +1304,15 @@ export class InteractiveMode {
|
|
|
1287
1304
|
const row = new Container();
|
|
1288
1305
|
row.addChild(new Spacer(1));
|
|
1289
1306
|
row.addChild(loader);
|
|
1290
|
-
this.mountStatusOwner(row, options);
|
|
1307
|
+
this.mountStatusOwner(row, loader, options);
|
|
1291
1308
|
}
|
|
1292
1309
|
clearStatusOwner(options) {
|
|
1310
|
+
if (options?.owner !== undefined && this.statusOwner !== options.owner) {
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1293
1313
|
const requestRender = options?.requestRender ?? true;
|
|
1294
1314
|
if (this.statusComponent !== undefined || this.statusContainer.children.length > 0) {
|
|
1315
|
+
this.statusOwner = undefined;
|
|
1295
1316
|
this.statusContainer.clear();
|
|
1296
1317
|
this.statusComponent = undefined;
|
|
1297
1318
|
}
|
|
@@ -1337,7 +1358,7 @@ export class InteractiveMode {
|
|
|
1337
1358
|
return;
|
|
1338
1359
|
}
|
|
1339
1360
|
if (leadingSpacer) {
|
|
1340
|
-
container.addChild(new Spacer(
|
|
1361
|
+
container.addChild(new Spacer(1));
|
|
1341
1362
|
}
|
|
1342
1363
|
if (builtInComponent) {
|
|
1343
1364
|
container.addChild(builtInComponent);
|
|
@@ -1426,14 +1447,44 @@ export class InteractiveMode {
|
|
|
1426
1447
|
* Create the ExtensionUIContext for extensions.
|
|
1427
1448
|
*/
|
|
1428
1449
|
createExtensionUIContext() {
|
|
1450
|
+
const capturedUiEpoch = this.uiEpoch;
|
|
1451
|
+
const capturedSessionEpoch = this.sessionEpoch;
|
|
1452
|
+
const guard = (fn) => {
|
|
1453
|
+
return ((...args) => {
|
|
1454
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1455
|
+
return undefined;
|
|
1456
|
+
}
|
|
1457
|
+
return fn(...args);
|
|
1458
|
+
});
|
|
1459
|
+
};
|
|
1429
1460
|
return {
|
|
1430
|
-
select: (title, options, opts) =>
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1461
|
+
select: (title, options, opts) => {
|
|
1462
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1463
|
+
return Promise.resolve(undefined);
|
|
1464
|
+
}
|
|
1465
|
+
return this.showExtensionSelector(title, options, opts);
|
|
1466
|
+
},
|
|
1467
|
+
confirm: (title, message, opts) => {
|
|
1468
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1469
|
+
return Promise.resolve(false);
|
|
1470
|
+
}
|
|
1471
|
+
return this.showExtensionConfirm(title, message, opts);
|
|
1472
|
+
},
|
|
1473
|
+
input: (title, placeholder, opts) => {
|
|
1474
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1475
|
+
return Promise.resolve(undefined);
|
|
1476
|
+
}
|
|
1477
|
+
return this.showExtensionInput(title, placeholder, opts);
|
|
1478
|
+
},
|
|
1479
|
+
notify: guard((message, type) => this.showExtensionNotify(message, type)),
|
|
1480
|
+
onTerminalInput: (handler) => {
|
|
1481
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1482
|
+
return () => { };
|
|
1483
|
+
}
|
|
1484
|
+
return this.addExtensionTerminalInputListener(handler);
|
|
1485
|
+
},
|
|
1486
|
+
setStatus: guard((key, text) => this.setExtensionStatus(key, text)),
|
|
1487
|
+
setWorkingMessage: guard((message) => {
|
|
1437
1488
|
if (this.loadingAnimation) {
|
|
1438
1489
|
if (message) {
|
|
1439
1490
|
this.loadingAnimation.setMessage(message);
|
|
@@ -1446,23 +1497,41 @@ export class InteractiveMode {
|
|
|
1446
1497
|
// Queue message for when loadingAnimation is created (handles agent_start race)
|
|
1447
1498
|
this.pendingWorkingMessage = message;
|
|
1448
1499
|
}
|
|
1500
|
+
}),
|
|
1501
|
+
setWidget: guard((key, content, options) => this.setExtensionWidget(key, content, options)),
|
|
1502
|
+
setFooter: guard((factory) => this.setExtensionFooter(factory)),
|
|
1503
|
+
setHeader: guard((factory) => this.setExtensionHeader(factory)),
|
|
1504
|
+
setTitle: guard((title) => this.ui.terminal.setTitle(title)),
|
|
1505
|
+
custom: (factory, options) => {
|
|
1506
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1507
|
+
return Promise.resolve(undefined);
|
|
1508
|
+
}
|
|
1509
|
+
return this.showExtensionCustom(factory, options);
|
|
1510
|
+
},
|
|
1511
|
+
pasteToEditor: guard((text) => this.editor.handleInput(`\x1b[200~${text}\x1b[201~`)),
|
|
1512
|
+
setEditorText: guard((text) => this.editor.setText(text)),
|
|
1513
|
+
getEditorText: () => {
|
|
1514
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1515
|
+
return "";
|
|
1516
|
+
}
|
|
1517
|
+
return this.editor.getText();
|
|
1449
1518
|
},
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
getEditorText: () => this.editor.getText(),
|
|
1458
|
-
editor: (title, prefill) => this.showExtensionEditor(title, prefill),
|
|
1459
|
-
setEditorComponent: (factory) => this.setCustomEditorComponent(factory),
|
|
1519
|
+
editor: (title, prefill) => {
|
|
1520
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1521
|
+
return Promise.resolve(undefined);
|
|
1522
|
+
}
|
|
1523
|
+
return this.showExtensionEditor(title, prefill);
|
|
1524
|
+
},
|
|
1525
|
+
setEditorComponent: guard((factory) => this.setCustomEditorComponent(factory)),
|
|
1460
1526
|
get theme() {
|
|
1461
1527
|
return theme;
|
|
1462
1528
|
},
|
|
1463
1529
|
getAllThemes: () => getAvailableThemesWithPaths(),
|
|
1464
1530
|
getTheme: (name) => getThemeByName(name),
|
|
1465
1531
|
setTheme: (themeOrName) => {
|
|
1532
|
+
if (this.uiEpoch !== capturedUiEpoch || this.sessionEpoch !== capturedSessionEpoch) {
|
|
1533
|
+
return { success: false, error: "Stale context" };
|
|
1534
|
+
}
|
|
1466
1535
|
if (themeOrName instanceof Theme) {
|
|
1467
1536
|
setThemeInstance(themeOrName);
|
|
1468
1537
|
this.ui.requestRender();
|
|
@@ -1478,7 +1547,7 @@ export class InteractiveMode {
|
|
|
1478
1547
|
return result;
|
|
1479
1548
|
},
|
|
1480
1549
|
getToolsExpanded: () => this.toolOutputExpanded,
|
|
1481
|
-
setToolsExpanded: (expanded) => this.setToolsExpanded(expanded),
|
|
1550
|
+
setToolsExpanded: guard((expanded) => this.setToolsExpanded(expanded)),
|
|
1482
1551
|
};
|
|
1483
1552
|
}
|
|
1484
1553
|
/**
|
|
@@ -1506,7 +1575,7 @@ export class InteractiveMode {
|
|
|
1506
1575
|
resolve(undefined);
|
|
1507
1576
|
return;
|
|
1508
1577
|
}
|
|
1509
|
-
this.hideExtensionSelector();
|
|
1578
|
+
this.hideExtensionSelector(this.extensionSelector);
|
|
1510
1579
|
resolve(option);
|
|
1511
1580
|
}, () => {
|
|
1512
1581
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
@@ -1514,19 +1583,19 @@ export class InteractiveMode {
|
|
|
1514
1583
|
resolve(undefined);
|
|
1515
1584
|
return;
|
|
1516
1585
|
}
|
|
1517
|
-
this.hideExtensionSelector();
|
|
1586
|
+
this.hideExtensionSelector(this.extensionSelector);
|
|
1518
1587
|
resolve(undefined);
|
|
1519
1588
|
}, { tui: this.ui, timeout: opts?.timeout });
|
|
1520
|
-
this.mountPromptOwner(this.extensionSelector);
|
|
1589
|
+
this.mountPromptOwner(this.extensionSelector, this.extensionSelector);
|
|
1521
1590
|
});
|
|
1522
1591
|
}
|
|
1523
1592
|
/**
|
|
1524
1593
|
* Hide the extension selector.
|
|
1525
1594
|
*/
|
|
1526
|
-
hideExtensionSelector() {
|
|
1595
|
+
hideExtensionSelector(owner) {
|
|
1527
1596
|
this.extensionSelector?.dispose();
|
|
1528
1597
|
this.extensionSelector = undefined;
|
|
1529
|
-
this.restoreCanonicalEditor();
|
|
1598
|
+
this.restoreCanonicalEditor({ owner });
|
|
1530
1599
|
}
|
|
1531
1600
|
/**
|
|
1532
1601
|
* Show a confirmation dialog for extensions.
|
|
@@ -1550,7 +1619,7 @@ export class InteractiveMode {
|
|
|
1550
1619
|
resolve(undefined);
|
|
1551
1620
|
return;
|
|
1552
1621
|
}
|
|
1553
|
-
this.hideExtensionInput();
|
|
1622
|
+
this.hideExtensionInput(this.extensionInput);
|
|
1554
1623
|
resolve(undefined);
|
|
1555
1624
|
};
|
|
1556
1625
|
opts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -1560,7 +1629,7 @@ export class InteractiveMode {
|
|
|
1560
1629
|
resolve(undefined);
|
|
1561
1630
|
return;
|
|
1562
1631
|
}
|
|
1563
|
-
this.hideExtensionInput();
|
|
1632
|
+
this.hideExtensionInput(this.extensionInput);
|
|
1564
1633
|
resolve(value);
|
|
1565
1634
|
}, () => {
|
|
1566
1635
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
@@ -1568,19 +1637,19 @@ export class InteractiveMode {
|
|
|
1568
1637
|
resolve(undefined);
|
|
1569
1638
|
return;
|
|
1570
1639
|
}
|
|
1571
|
-
this.hideExtensionInput();
|
|
1640
|
+
this.hideExtensionInput(this.extensionInput);
|
|
1572
1641
|
resolve(undefined);
|
|
1573
1642
|
}, { tui: this.ui, timeout: opts?.timeout });
|
|
1574
|
-
this.mountPromptOwner(this.extensionInput);
|
|
1643
|
+
this.mountPromptOwner(this.extensionInput, this.extensionInput);
|
|
1575
1644
|
});
|
|
1576
1645
|
}
|
|
1577
1646
|
/**
|
|
1578
1647
|
* Hide the extension input.
|
|
1579
1648
|
*/
|
|
1580
|
-
hideExtensionInput() {
|
|
1649
|
+
hideExtensionInput(owner) {
|
|
1581
1650
|
this.extensionInput?.dispose();
|
|
1582
1651
|
this.extensionInput = undefined;
|
|
1583
|
-
this.restoreCanonicalEditor();
|
|
1652
|
+
this.restoreCanonicalEditor({ owner });
|
|
1584
1653
|
}
|
|
1585
1654
|
/**
|
|
1586
1655
|
* Show a multi-line editor for extensions (with Ctrl+G support).
|
|
@@ -1593,25 +1662,25 @@ export class InteractiveMode {
|
|
|
1593
1662
|
resolve(undefined);
|
|
1594
1663
|
return;
|
|
1595
1664
|
}
|
|
1596
|
-
this.hideExtensionEditor();
|
|
1665
|
+
this.hideExtensionEditor(this.extensionEditor);
|
|
1597
1666
|
resolve(value);
|
|
1598
1667
|
}, () => {
|
|
1599
1668
|
if (this.uiEpoch !== capturedEpoch) {
|
|
1600
1669
|
resolve(undefined);
|
|
1601
1670
|
return;
|
|
1602
1671
|
}
|
|
1603
|
-
this.hideExtensionEditor();
|
|
1672
|
+
this.hideExtensionEditor(this.extensionEditor);
|
|
1604
1673
|
resolve(undefined);
|
|
1605
1674
|
});
|
|
1606
|
-
this.mountPromptOwner(this.extensionEditor);
|
|
1675
|
+
this.mountPromptOwner(this.extensionEditor, this.extensionEditor);
|
|
1607
1676
|
});
|
|
1608
1677
|
}
|
|
1609
1678
|
/**
|
|
1610
1679
|
* Hide the extension editor.
|
|
1611
1680
|
*/
|
|
1612
|
-
hideExtensionEditor() {
|
|
1681
|
+
hideExtensionEditor(owner) {
|
|
1613
1682
|
this.extensionEditor = undefined;
|
|
1614
|
-
this.restoreCanonicalEditor();
|
|
1683
|
+
this.restoreCanonicalEditor({ owner });
|
|
1615
1684
|
}
|
|
1616
1685
|
/**
|
|
1617
1686
|
* Set a custom editor component from an extension.
|
|
@@ -1685,11 +1754,11 @@ export class InteractiveMode {
|
|
|
1685
1754
|
const capturedEpoch = this.uiEpoch;
|
|
1686
1755
|
const savedText = this.editor.getText();
|
|
1687
1756
|
const isOverlay = options?.overlay ?? false;
|
|
1757
|
+
let component;
|
|
1688
1758
|
const restoreEditor = () => {
|
|
1689
|
-
this.restoreCanonicalEditor({ text: savedText });
|
|
1759
|
+
this.restoreCanonicalEditor({ text: savedText, owner: component });
|
|
1690
1760
|
};
|
|
1691
1761
|
return new Promise((resolve, reject) => {
|
|
1692
|
-
let component;
|
|
1693
1762
|
let closed = false;
|
|
1694
1763
|
const close = (result) => {
|
|
1695
1764
|
if (closed)
|
|
@@ -1744,7 +1813,7 @@ export class InteractiveMode {
|
|
|
1744
1813
|
options?.onHandle?.(handle);
|
|
1745
1814
|
}
|
|
1746
1815
|
else {
|
|
1747
|
-
this.mountPromptOwner(component);
|
|
1816
|
+
this.mountPromptOwner(component, component);
|
|
1748
1817
|
}
|
|
1749
1818
|
})
|
|
1750
1819
|
.catch((err) => {
|
|
@@ -2059,8 +2128,13 @@ export class InteractiveMode {
|
|
|
2059
2128
|
}
|
|
2060
2129
|
if (this.loadingAnimation) {
|
|
2061
2130
|
this.loadingAnimation.dispose();
|
|
2131
|
+
const oldLoader = this.loadingAnimation;
|
|
2132
|
+
this.loadingAnimation = undefined;
|
|
2133
|
+
this.clearStatusOwner({ requestRender: false, owner: oldLoader });
|
|
2134
|
+
}
|
|
2135
|
+
else {
|
|
2136
|
+
this.clearStatusOwner({ requestRender: false });
|
|
2062
2137
|
}
|
|
2063
|
-
this.clearStatusOwner({ requestRender: false });
|
|
2064
2138
|
this.loadingAnimation = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.defaultWorkingMessage);
|
|
2065
2139
|
this.mountStatusLoader(this.loadingAnimation, { requestRender: false });
|
|
2066
2140
|
// Apply any pending working message queued before loader existed
|
|
@@ -2089,7 +2163,16 @@ export class InteractiveMode {
|
|
|
2089
2163
|
this.ui.requestRender();
|
|
2090
2164
|
}
|
|
2091
2165
|
else if (event.message.role === "assistant") {
|
|
2092
|
-
|
|
2166
|
+
// Check if we already have a streaming component for this message to prevent duplicates
|
|
2167
|
+
if (this.streamingComponent && this.streamingMessage === event.message) {
|
|
2168
|
+
return;
|
|
2169
|
+
}
|
|
2170
|
+
// If we have a different streaming component, something is wrong, but let's at least not leak it
|
|
2171
|
+
if (this.streamingComponent) {
|
|
2172
|
+
this.chatContainer.removeChild(this.streamingComponent);
|
|
2173
|
+
this.streamingComponent = undefined;
|
|
2174
|
+
}
|
|
2175
|
+
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings());
|
|
2093
2176
|
this.streamingMessage = event.message;
|
|
2094
2177
|
this.chatContainer.addChild(this.streamingComponent);
|
|
2095
2178
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
@@ -2192,8 +2275,9 @@ export class InteractiveMode {
|
|
|
2192
2275
|
case "agent_end":
|
|
2193
2276
|
if (this.loadingAnimation) {
|
|
2194
2277
|
this.loadingAnimation.dispose();
|
|
2278
|
+
const oldLoader = this.loadingAnimation;
|
|
2195
2279
|
this.loadingAnimation = undefined;
|
|
2196
|
-
this.clearStatusOwner({ requestRender: false });
|
|
2280
|
+
this.clearStatusOwner({ requestRender: false, owner: oldLoader });
|
|
2197
2281
|
}
|
|
2198
2282
|
if (this.streamingComponent) {
|
|
2199
2283
|
this.chatContainer.removeChild(this.streamingComponent);
|
|
@@ -2217,8 +2301,13 @@ export class InteractiveMode {
|
|
|
2217
2301
|
this.defaultEditor.onEscape = () => {
|
|
2218
2302
|
this.session.abortCompaction();
|
|
2219
2303
|
};
|
|
2220
|
-
//
|
|
2304
|
+
// Stop loading animation
|
|
2305
|
+
if (this.loadingAnimation) {
|
|
2306
|
+
this.loadingAnimation.dispose();
|
|
2307
|
+
this.loadingAnimation = undefined;
|
|
2308
|
+
}
|
|
2221
2309
|
this.clearStatusOwner({ requestRender: false });
|
|
2310
|
+
// Show compacting indicator with reason
|
|
2222
2311
|
const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
|
|
2223
2312
|
this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting... (${appKey(this.keybindings, "interrupt")} to cancel)`);
|
|
2224
2313
|
this.mountStatusLoader(this.autoCompactionLoader, { requestRender: false });
|
|
@@ -2234,8 +2323,9 @@ export class InteractiveMode {
|
|
|
2234
2323
|
// Stop loader
|
|
2235
2324
|
if (this.autoCompactionLoader) {
|
|
2236
2325
|
this.autoCompactionLoader.dispose();
|
|
2326
|
+
const oldLoader = this.autoCompactionLoader;
|
|
2237
2327
|
this.autoCompactionLoader = undefined;
|
|
2238
|
-
this.clearStatusOwner({ requestRender: false });
|
|
2328
|
+
this.clearStatusOwner({ requestRender: false, owner: oldLoader });
|
|
2239
2329
|
}
|
|
2240
2330
|
// Handle result
|
|
2241
2331
|
if (event.aborted) {
|
|
@@ -2269,8 +2359,13 @@ export class InteractiveMode {
|
|
|
2269
2359
|
this.defaultEditor.onEscape = () => {
|
|
2270
2360
|
this.session.abortRetry();
|
|
2271
2361
|
};
|
|
2272
|
-
//
|
|
2362
|
+
// Stop loading animation
|
|
2363
|
+
if (this.loadingAnimation) {
|
|
2364
|
+
this.loadingAnimation.dispose();
|
|
2365
|
+
this.loadingAnimation = undefined;
|
|
2366
|
+
}
|
|
2273
2367
|
this.clearStatusOwner({ requestRender: false });
|
|
2368
|
+
// Show retry indicator
|
|
2274
2369
|
const delaySeconds = Math.round(event.delayMs / 1000);
|
|
2275
2370
|
this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${appKey(this.keybindings, "interrupt")} to cancel)`);
|
|
2276
2371
|
this.mountStatusLoader(this.retryLoader, { requestRender: false });
|
|
@@ -2286,8 +2381,9 @@ export class InteractiveMode {
|
|
|
2286
2381
|
// Stop loader
|
|
2287
2382
|
if (this.retryLoader) {
|
|
2288
2383
|
this.retryLoader.dispose();
|
|
2384
|
+
const oldLoader = this.retryLoader;
|
|
2289
2385
|
this.retryLoader = undefined;
|
|
2290
|
-
this.clearStatusOwner({ requestRender: false });
|
|
2386
|
+
this.clearStatusOwner({ requestRender: false, owner: oldLoader });
|
|
2291
2387
|
}
|
|
2292
2388
|
// Show error only on final failure (success shows normal response)
|
|
2293
2389
|
if (!event.success) {
|
|
@@ -2313,7 +2409,9 @@ export class InteractiveMode {
|
|
|
2313
2409
|
* If multiple status messages are emitted back-to-back (without anything else being added to the chat),
|
|
2314
2410
|
* we update the previous status line instead of appending new ones to avoid log spam.
|
|
2315
2411
|
*/
|
|
2316
|
-
showStatus(message) {
|
|
2412
|
+
showStatus(message, ownerEpoch) {
|
|
2413
|
+
if (ownerEpoch !== undefined && this.sessionEpoch !== ownerEpoch)
|
|
2414
|
+
return;
|
|
2317
2415
|
const children = this.chatContainer.children;
|
|
2318
2416
|
const last = children.length > 0 ? children[children.length - 1] : undefined;
|
|
2319
2417
|
const secondLast = children.length > 1 ? children[children.length - 2] : undefined;
|
|
@@ -2391,7 +2489,7 @@ export class InteractiveMode {
|
|
|
2391
2489
|
break;
|
|
2392
2490
|
}
|
|
2393
2491
|
case "assistant": {
|
|
2394
|
-
const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings()
|
|
2492
|
+
const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings());
|
|
2395
2493
|
this.chatContainer.addChild(assistantComponent);
|
|
2396
2494
|
break;
|
|
2397
2495
|
}
|
|
@@ -2463,6 +2561,9 @@ export class InteractiveMode {
|
|
|
2463
2561
|
this.ui.requestRender();
|
|
2464
2562
|
}
|
|
2465
2563
|
renderInitialMessages() {
|
|
2564
|
+
if (this.isInitialMessagesRendered)
|
|
2565
|
+
return;
|
|
2566
|
+
this.isInitialMessagesRendered = true;
|
|
2466
2567
|
// Get aligned messages and entries from session context
|
|
2467
2568
|
const context = this.sessionManager.buildSessionContext();
|
|
2468
2569
|
this.renderSessionContext(context, {
|
|
@@ -2747,7 +2848,9 @@ export class InteractiveMode {
|
|
|
2747
2848
|
this.editor.setText("");
|
|
2748
2849
|
this.ui.requestRender();
|
|
2749
2850
|
}
|
|
2750
|
-
showError(errorMessage) {
|
|
2851
|
+
showError(errorMessage, ownerEpoch) {
|
|
2852
|
+
if (ownerEpoch !== undefined && this.sessionEpoch !== ownerEpoch)
|
|
2853
|
+
return;
|
|
2751
2854
|
this.chatContainer.addChild(new Spacer(1));
|
|
2752
2855
|
this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
|
|
2753
2856
|
this.ui.requestRender();
|
|
@@ -2772,13 +2875,17 @@ export class InteractiveMode {
|
|
|
2772
2875
|
this.ui.invalidate();
|
|
2773
2876
|
this.ui.requestRender();
|
|
2774
2877
|
}
|
|
2775
|
-
showWarning(warningMessage) {
|
|
2878
|
+
showWarning(warningMessage, ownerEpoch) {
|
|
2879
|
+
if (ownerEpoch !== undefined && this.sessionEpoch !== ownerEpoch)
|
|
2880
|
+
return;
|
|
2776
2881
|
this.enqueueStartupNotice(() => {
|
|
2777
2882
|
this.chatContainer.addChild(new Spacer(1));
|
|
2778
2883
|
this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
|
|
2779
2884
|
});
|
|
2780
2885
|
}
|
|
2781
|
-
showNewVersionNotification(newVersion) {
|
|
2886
|
+
showNewVersionNotification(newVersion, ownerEpoch) {
|
|
2887
|
+
if (ownerEpoch !== undefined && this.sessionEpoch !== ownerEpoch)
|
|
2888
|
+
return;
|
|
2782
2889
|
const action = theme.fg("accent", getUpdateInstruction(PACKAGE_NAME));
|
|
2783
2890
|
const updateInstruction = theme.fg("muted", `New version ${newVersion} is available. `) + action;
|
|
2784
2891
|
const changelogUrl = theme.fg("accent", "https://github.com/apholdings/jensen-code/blob/main/packages/coding-agent/CHANGELOG.md");
|
|
@@ -2985,10 +3092,10 @@ export class InteractiveMode {
|
|
|
2985
3092
|
const done = () => {
|
|
2986
3093
|
if (this.uiEpoch !== capturedEpoch)
|
|
2987
3094
|
return;
|
|
2988
|
-
this.restoreCanonicalEditor({ requestRender: false });
|
|
3095
|
+
this.restoreCanonicalEditor({ requestRender: false, owner: component });
|
|
2989
3096
|
};
|
|
2990
3097
|
const { component, focus } = create(done);
|
|
2991
|
-
this.mountPromptOwner(component, { focus });
|
|
3098
|
+
this.mountPromptOwner(component, component, { focus });
|
|
2992
3099
|
}
|
|
2993
3100
|
showSettingsSelector() {
|
|
2994
3101
|
this.showSelector((done) => {
|
|
@@ -3436,7 +3543,7 @@ export class InteractiveMode {
|
|
|
3436
3543
|
finally {
|
|
3437
3544
|
if (summaryLoader) {
|
|
3438
3545
|
summaryLoader.dispose();
|
|
3439
|
-
this.clearStatusOwner({ requestRender: false });
|
|
3546
|
+
this.clearStatusOwner({ requestRender: false, owner: summaryLoader });
|
|
3440
3547
|
}
|
|
3441
3548
|
this.defaultEditor.onEscape = originalOnEscape;
|
|
3442
3549
|
}
|
|
@@ -3537,7 +3644,7 @@ export class InteractiveMode {
|
|
|
3537
3644
|
// Completion handled below
|
|
3538
3645
|
});
|
|
3539
3646
|
// Show dialog in editor container
|
|
3540
|
-
this.mountPromptOwner(dialog);
|
|
3647
|
+
this.mountPromptOwner(dialog, dialog);
|
|
3541
3648
|
// Promise for manual code input (racing with callback server)
|
|
3542
3649
|
let manualCodeResolve;
|
|
3543
3650
|
let manualCodeReject;
|
|
@@ -3550,7 +3657,7 @@ export class InteractiveMode {
|
|
|
3550
3657
|
const restoreEditor = () => {
|
|
3551
3658
|
if (this.uiEpoch !== capturedEpoch)
|
|
3552
3659
|
return;
|
|
3553
|
-
this.restoreCanonicalEditor();
|
|
3660
|
+
this.restoreCanonicalEditor({ owner: dialog });
|
|
3554
3661
|
};
|
|
3555
3662
|
try {
|
|
3556
3663
|
await this.session.modelRegistry.authStorage.login(providerId, {
|
|
@@ -3623,13 +3730,13 @@ export class InteractiveMode {
|
|
|
3623
3730
|
cancellable: false,
|
|
3624
3731
|
});
|
|
3625
3732
|
const previousEditor = this.editor;
|
|
3626
|
-
this.mountPromptOwner(loader);
|
|
3733
|
+
this.mountPromptOwner(loader, loader);
|
|
3627
3734
|
const capturedEpoch = this.uiEpoch;
|
|
3628
3735
|
const dismissLoader = (_editor) => {
|
|
3629
3736
|
loader.dispose();
|
|
3630
3737
|
if (this.uiEpoch !== capturedEpoch)
|
|
3631
3738
|
return;
|
|
3632
|
-
this.restoreCanonicalEditor();
|
|
3739
|
+
this.restoreCanonicalEditor({ owner: loader });
|
|
3633
3740
|
};
|
|
3634
3741
|
try {
|
|
3635
3742
|
await this.session.reload();
|
|
@@ -3727,12 +3834,12 @@ export class InteractiveMode {
|
|
|
3727
3834
|
}
|
|
3728
3835
|
// Show cancellable loader, replacing the editor
|
|
3729
3836
|
const loader = new BorderedLoader(this.ui, theme, "Creating gist...");
|
|
3730
|
-
this.mountPromptOwner(loader);
|
|
3837
|
+
this.mountPromptOwner(loader, loader);
|
|
3731
3838
|
const restoreEditor = () => {
|
|
3732
3839
|
loader.dispose();
|
|
3733
3840
|
if (this.uiEpoch !== capturedEpoch)
|
|
3734
3841
|
return;
|
|
3735
|
-
this.restoreCanonicalEditor({ requestRender: false });
|
|
3842
|
+
this.restoreCanonicalEditor({ requestRender: false, owner: loader });
|
|
3736
3843
|
try {
|
|
3737
3844
|
fs.unlinkSync(tmpFile);
|
|
3738
3845
|
}
|
|
@@ -4008,7 +4115,10 @@ export class InteractiveMode {
|
|
|
4008
4115
|
}
|
|
4009
4116
|
async handleClearCommand() {
|
|
4010
4117
|
// New session via session (emits extension session events)
|
|
4011
|
-
await this.session.newSession();
|
|
4118
|
+
const success = await this.session.newSession();
|
|
4119
|
+
if (!success) {
|
|
4120
|
+
return;
|
|
4121
|
+
}
|
|
4012
4122
|
this.resetInteractiveSessionUI(true);
|
|
4013
4123
|
this.ui.requestRender();
|
|
4014
4124
|
}
|
|
@@ -4185,7 +4295,7 @@ export class InteractiveMode {
|
|
|
4185
4295
|
finally {
|
|
4186
4296
|
if (this.sessionEpoch === capturedEpoch) {
|
|
4187
4297
|
compactingLoader.dispose();
|
|
4188
|
-
this.clearStatusOwner({ requestRender: false });
|
|
4298
|
+
this.clearStatusOwner({ requestRender: false, owner: compactingLoader });
|
|
4189
4299
|
this.defaultEditor.onEscape = originalOnEscape;
|
|
4190
4300
|
}
|
|
4191
4301
|
}
|
|
@@ -4199,6 +4309,14 @@ export class InteractiveMode {
|
|
|
4199
4309
|
this.loadingAnimation.dispose();
|
|
4200
4310
|
this.loadingAnimation = undefined;
|
|
4201
4311
|
}
|
|
4312
|
+
if (this.autoCompactionLoader) {
|
|
4313
|
+
this.autoCompactionLoader.dispose();
|
|
4314
|
+
this.autoCompactionLoader = undefined;
|
|
4315
|
+
}
|
|
4316
|
+
if (this.retryLoader) {
|
|
4317
|
+
this.retryLoader.dispose();
|
|
4318
|
+
this.retryLoader = undefined;
|
|
4319
|
+
}
|
|
4202
4320
|
this.clearExtensionTerminalInputListeners();
|
|
4203
4321
|
this.footer.dispose();
|
|
4204
4322
|
this.footerDataProvider.dispose();
|