@ashx-j/lunr 0.2.9 → 0.2.10

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.
Files changed (108) hide show
  1. package/dist/builtin-extensions/ashxj-spinners.d.ts +1 -4
  2. package/dist/builtin-extensions/ashxj-spinners.d.ts.map +1 -1
  3. package/dist/builtin-extensions/ashxj-spinners.js +3 -29
  4. package/dist/builtin-extensions/ashxj-spinners.js.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  6. package/dist/builtin-extensions/ashxj-tui.js +5 -4
  7. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  8. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  9. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +2 -2
  10. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  11. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +1 -1
  12. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  13. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  16. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +5 -1
  17. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +2 -2
  19. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js +2 -2
  21. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +2 -2
  23. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +2 -2
  25. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +4 -6
  27. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +26 -18
  29. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  30. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  31. package/dist/builtin-extensions/pi-web-access/index.js +3 -1
  32. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  33. package/dist/catalog/models.json +1 -1
  34. package/dist/catalog/providers/nvidia.json +1 -1
  35. package/dist/catalog/providers/opencode-go.json +1 -1
  36. package/dist/catalog/providers/opencode.json +1 -1
  37. package/dist/catalog/providers/openrouter.json +1 -1
  38. package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
  39. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  40. package/dist/catalog/providers/xai.json +1 -1
  41. package/dist/catalog/publication.json +3 -3
  42. package/dist/core/agent-session.d.ts +2 -0
  43. package/dist/core/agent-session.d.ts.map +1 -1
  44. package/dist/core/agent-session.js +9 -1
  45. package/dist/core/agent-session.js.map +1 -1
  46. package/dist/core/customize.d.ts +1 -0
  47. package/dist/core/customize.d.ts.map +1 -1
  48. package/dist/core/customize.js +3 -0
  49. package/dist/core/customize.js.map +1 -1
  50. package/dist/core/settings-manager.d.ts +3 -0
  51. package/dist/core/settings-manager.d.ts.map +1 -1
  52. package/dist/core/settings-manager.js +8 -0
  53. package/dist/core/settings-manager.js.map +1 -1
  54. package/dist/core/tools/bash.d.ts.map +1 -1
  55. package/dist/core/tools/bash.js +2 -1
  56. package/dist/core/tools/bash.js.map +1 -1
  57. package/dist/core/tools/edit.d.ts.map +1 -1
  58. package/dist/core/tools/edit.js +9 -6
  59. package/dist/core/tools/edit.js.map +1 -1
  60. package/dist/core/tools/find.d.ts.map +1 -1
  61. package/dist/core/tools/find.js +2 -1
  62. package/dist/core/tools/find.js.map +1 -1
  63. package/dist/core/tools/grep.d.ts.map +1 -1
  64. package/dist/core/tools/grep.js +2 -1
  65. package/dist/core/tools/grep.js.map +1 -1
  66. package/dist/core/tools/ls.d.ts.map +1 -1
  67. package/dist/core/tools/ls.js +2 -1
  68. package/dist/core/tools/ls.js.map +1 -1
  69. package/dist/core/tools/read.d.ts.map +1 -1
  70. package/dist/core/tools/read.js +2 -1
  71. package/dist/core/tools/read.js.map +1 -1
  72. package/dist/core/tools/render-utils.d.ts +13 -3
  73. package/dist/core/tools/render-utils.d.ts.map +1 -1
  74. package/dist/core/tools/render-utils.js +10 -2
  75. package/dist/core/tools/render-utils.js.map +1 -1
  76. package/dist/core/tools/write.d.ts.map +1 -1
  77. package/dist/core/tools/write.js +5 -3
  78. package/dist/core/tools/write.js.map +1 -1
  79. package/dist/gateway/agent-bridge.d.ts +1 -0
  80. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  81. package/dist/gateway/agent-bridge.js.map +1 -1
  82. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  83. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  84. package/dist/modes/interactive/components/settings-selector.js +11 -1
  85. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  86. package/dist/modes/interactive/components/thinking-tail.d.ts +1 -0
  87. package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
  88. package/dist/modes/interactive/components/thinking-tail.js +2 -6
  89. package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
  90. package/dist/modes/interactive/components/tool-execution.d.ts +6 -0
  91. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  92. package/dist/modes/interactive/components/tool-execution.js +75 -16
  93. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  94. package/dist/modes/interactive/interactive-mode.d.ts +15 -1
  95. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  96. package/dist/modes/interactive/interactive-mode.js +139 -34
  97. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  98. package/docs/terminal-setup.md +2 -2
  99. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  100. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  101. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  102. package/examples/extensions/gondolin/package-lock.json +2 -2
  103. package/examples/extensions/gondolin/package.json +1 -1
  104. package/examples/extensions/sandbox/package-lock.json +2 -2
  105. package/examples/extensions/sandbox/package.json +1 -1
  106. package/examples/extensions/with-deps/package-lock.json +2 -2
  107. package/examples/extensions/with-deps/package.json +1 -1
  108. package/package.json +4 -4
@@ -7,7 +7,7 @@ import * as fs from "node:fs";
7
7
  import * as os from "node:os";
8
8
  import * as path from "node:path";
9
9
  import { getSupportedThinkingLevels, } from "@ashx-j/lunr-ai/compat";
10
- import { CombinedAutocompleteProvider, Container, fuzzyFilter, isFocusable, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@ashx-j/lunr-tui";
10
+ import { collectImageMarkerIds, CombinedAutocompleteProvider, Container, formatImageMarker, fuzzyFilter, isFocusable, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@ashx-j/lunr-tui";
11
11
  import chalk from "chalk";
12
12
  import { spawn, spawnSync } from "child_process";
13
13
  import { APP_NAME, APP_TITLE, appendDebugLog, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
@@ -49,6 +49,7 @@ import { modelToUserEntry } from "../../core/user-models.js";
49
49
  import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
50
50
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
51
51
  import { parseGitUrl } from "../../utils/git.js";
52
+ import { processImage } from "../../utils/image-process.js";
52
53
  import { getCwdRelativePath } from "../../utils/paths.js";
53
54
  import { killTrackedDetachedChildren } from "../../utils/shell.js";
54
55
  import { ensureTool, getToolPath } from "../../utils/tools-manager.js";
@@ -236,6 +237,8 @@ export class InteractiveMode {
236
237
  isInitialized = false;
237
238
  onInputCallback;
238
239
  pendingUserInputs = [];
240
+ stagedSubmitImages;
241
+ fallbackImageAttachments = new Map();
239
242
  activeStatusIndicator = undefined;
240
243
  idleStatus = new IdleStatus();
241
244
  workingMessage = undefined;
@@ -605,7 +608,7 @@ export class InteractiveMode {
605
608
  const decision = typeof resp === "string" ? resp : resp.decision;
606
609
  if (decision !== "reject") {
607
610
  this.swarmMode = true;
608
- this.setExtensionStatus("swarm", "swarm ● active");
611
+ this.setExtensionStatus("swarm", "swarm");
609
612
  }
610
613
  return resp;
611
614
  }
@@ -768,7 +771,7 @@ export class InteractiveMode {
768
771
  while (true) {
769
772
  const userInput = await this.getUserInput();
770
773
  try {
771
- await this.promptAfterDeferredBuiltins(userInput);
774
+ await this.promptAfterDeferredBuiltins(userInput.text, { images: userInput.images });
772
775
  }
773
776
  catch (error) {
774
777
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
@@ -1342,7 +1345,7 @@ export class InteractiveMode {
1342
1345
  this.chatContainer.clear();
1343
1346
  this.renderInitialMessages();
1344
1347
  if (result.editorText && !this.editor.getText().trim()) {
1345
- this.editor.setText(result.editorText);
1348
+ this.restoreEditorFromTreeResult(result);
1346
1349
  }
1347
1350
  this.showStatus("Navigated to selected point");
1348
1351
  void this.flushCompactionQueue({ willRetry: false });
@@ -2173,8 +2176,8 @@ export class InteractiveMode {
2173
2176
  }
2174
2177
  };
2175
2178
  // Handle clipboard paste (keybinding: app.clipboard.pasteImage, Alt+V on Windows —
2176
- // Ctrl+V is owned by the terminal and never reaches us). Images are attached by path;
2177
- // otherwise, paste plain text from the system clipboard.
2179
+ // Ctrl+V is owned by the terminal and never reaches us). Images become `[image_n]`
2180
+ // chips; otherwise, paste plain text from the system clipboard.
2178
2181
  this.defaultEditor.onPasteImage = () => {
2179
2182
  void this.handleClipboardPaste();
2180
2183
  };
@@ -2209,18 +2212,104 @@ export class InteractiveMode {
2209
2212
  }
2210
2213
  });
2211
2214
  }
2215
+ writeClipboardImageFile(image) {
2216
+ const ext = extensionForImageMimeType(image.mimeType) ?? "png";
2217
+ const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
2218
+ const filePath = path.join(os.tmpdir(), fileName);
2219
+ fs.writeFileSync(filePath, Buffer.from(image.bytes));
2220
+ return { path: filePath, mimeType: image.mimeType };
2221
+ }
2222
+ insertImageChip(attachment) {
2223
+ if (this.editor.insertImageMarker) {
2224
+ return this.editor.insertImageMarker(attachment);
2225
+ }
2226
+ const existing = collectImageMarkerIds(this.editor.getText());
2227
+ const used = new Set([...existing, ...this.fallbackImageAttachments.keys()]);
2228
+ let id = 1;
2229
+ while (used.has(id))
2230
+ id++;
2231
+ this.fallbackImageAttachments.set(id, { id, path: attachment.path, mimeType: attachment.mimeType });
2232
+ this.editor.insertTextAtCursor?.(formatImageMarker(id));
2233
+ return id;
2234
+ }
2235
+ takeSubmittedImages(submittedText) {
2236
+ if (this.editor.takePendingImages) {
2237
+ this.fallbackImageAttachments.clear();
2238
+ return this.editor.takePendingImages();
2239
+ }
2240
+ if (this.editor.getPendingImages) {
2241
+ this.fallbackImageAttachments.clear();
2242
+ return this.editor.getPendingImages();
2243
+ }
2244
+ const pending = [];
2245
+ for (const id of collectImageMarkerIds(submittedText ?? this.editor.getText())) {
2246
+ const attachment = this.fallbackImageAttachments.get(id);
2247
+ if (attachment)
2248
+ pending.push(attachment);
2249
+ }
2250
+ this.fallbackImageAttachments.clear();
2251
+ return pending;
2252
+ }
2253
+ consumeStagedSubmitImages() {
2254
+ const staged = this.stagedSubmitImages;
2255
+ this.stagedSubmitImages = undefined;
2256
+ return staged;
2257
+ }
2258
+ async loadImageAttachments(attachments) {
2259
+ if (attachments.length === 0)
2260
+ return undefined;
2261
+ const images = [];
2262
+ const autoResizeImages = this.settingsManager.getImageAutoResize();
2263
+ for (const attachment of attachments) {
2264
+ try {
2265
+ const bytes = fs.readFileSync(attachment.path);
2266
+ const processed = await processImage(bytes, attachment.mimeType, { autoResizeImages });
2267
+ if (!processed.ok) {
2268
+ this.showStatus(processed.message);
2269
+ continue;
2270
+ }
2271
+ images.push({
2272
+ type: "image",
2273
+ mimeType: processed.mimeType,
2274
+ data: processed.data,
2275
+ });
2276
+ }
2277
+ catch (err) {
2278
+ this.showStatus(`Could not attach ${formatImageMarker(attachment.id)}: ${err instanceof Error ? err.message : String(err)}`);
2279
+ }
2280
+ }
2281
+ return images.length > 0 ? images : undefined;
2282
+ }
2283
+ restoreEditorDraft(text, images) {
2284
+ this.editor.setText(text);
2285
+ if (!images || images.length === 0)
2286
+ return;
2287
+ const ids = collectImageMarkerIds(text);
2288
+ if (ids.length === 0 || !this.editor.restoreImageMarkers)
2289
+ return;
2290
+ const attachments = [];
2291
+ for (let i = 0; i < Math.min(ids.length, images.length); i++) {
2292
+ const id = ids[i];
2293
+ const image = images[i];
2294
+ const saved = this.writeClipboardImageFile({
2295
+ bytes: Buffer.from(image.data, "base64"),
2296
+ mimeType: image.mimeType,
2297
+ });
2298
+ attachments.push({ id, path: saved.path, mimeType: saved.mimeType });
2299
+ }
2300
+ this.editor.restoreImageMarkers(attachments);
2301
+ }
2302
+ restoreEditorFromTreeResult(result) {
2303
+ this.restoreEditorDraft(result.editorText ?? "", result.editorImages);
2304
+ }
2212
2305
  async handleClipboardPaste() {
2213
2306
  try {
2214
2307
  const image = await readClipboardImage();
2215
2308
  if (image) {
2216
- const tmpDir = os.tmpdir();
2217
- const ext = extensionForImageMimeType(image.mimeType) ?? "png";
2218
- const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
2219
- const filePath = path.join(tmpDir, fileName);
2220
- fs.writeFileSync(filePath, Buffer.from(image.bytes));
2221
- this.editor.insertTextAtCursor?.(filePath);
2309
+ const saved = this.writeClipboardImageFile(image);
2310
+ const id = this.insertImageChip(saved);
2222
2311
  this.ui.requestRender();
2223
- this.showStatus(`Pasted clipboard image → ${fileName}`);
2312
+ this.showStatus(`Pasted ${formatImageMarker(id)}`);
2224
2313
  return;
2225
2314
  }
2226
2315
  const text = await readClipboardText();
@@ -2238,8 +2327,11 @@ export class InteractiveMode {
2238
2327
  setupEditorSubmitHandler() {
2239
2328
  this.defaultEditor.onSubmit = async (text) => {
2240
2329
  text = text.trim();
2241
- if (!text)
2330
+ if (!text) {
2331
+ this.takeSubmittedImages(text);
2242
2332
  return;
2333
+ }
2334
+ const images = this.consumeStagedSubmitImages() ?? (await this.loadImageAttachments(this.takeSubmittedImages(text)));
2243
2335
  this.ui.setChatScroll(0);
2244
2336
  // Handle commands
2245
2337
  if (text === "/settings") {
@@ -2460,7 +2552,7 @@ export class InteractiveMode {
2460
2552
  await this.promptAfterDeferredBuiltins(text);
2461
2553
  }
2462
2554
  else {
2463
- this.queueCompactionMessage(text, "steer");
2555
+ this.queueCompactionMessage(text, "steer", images);
2464
2556
  }
2465
2557
  return;
2466
2558
  }
@@ -2469,7 +2561,7 @@ export class InteractiveMode {
2469
2561
  if (this.session.isStreaming) {
2470
2562
  this.editor.addToHistory?.(text);
2471
2563
  this.editor.setText("");
2472
- await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "steer" });
2564
+ await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "steer", images });
2473
2565
  this.updatePendingMessagesDisplay();
2474
2566
  this.ui.requestRender();
2475
2567
  return;
@@ -2478,10 +2570,10 @@ export class InteractiveMode {
2478
2570
  // First, move any pending bash components to chat
2479
2571
  this.flushPendingBashComponents();
2480
2572
  if (this.onInputCallback) {
2481
- this.onInputCallback(text);
2573
+ this.onInputCallback({ text, images });
2482
2574
  }
2483
2575
  else {
2484
- this.pendingUserInputs.push(text);
2576
+ this.pendingUserInputs.push({ text, images });
2485
2577
  }
2486
2578
  this.editor.addToHistory?.(text);
2487
2579
  };
@@ -3194,9 +3286,9 @@ export class InteractiveMode {
3194
3286
  return queuedInput;
3195
3287
  }
3196
3288
  return new Promise((resolve) => {
3197
- this.onInputCallback = (text) => {
3289
+ this.onInputCallback = (input) => {
3198
3290
  this.onInputCallback = undefined;
3199
- resolve(text);
3291
+ resolve(input);
3200
3292
  };
3201
3293
  });
3202
3294
  }
@@ -3429,21 +3521,25 @@ export class InteractiveMode {
3429
3521
  await this.promptAfterDeferredBuiltins(text);
3430
3522
  }
3431
3523
  else {
3432
- this.queueCompactionMessage(text, "followUp");
3524
+ const images = await this.loadImageAttachments(this.takeSubmittedImages(text));
3525
+ this.queueCompactionMessage(text, "followUp", images);
3433
3526
  }
3434
3527
  return;
3435
3528
  }
3436
3529
  // Alt+Enter queues a follow-up message (waits until agent finishes)
3437
3530
  // This handles extension commands (execute immediately), prompt template expansion, and queueing
3438
3531
  if (this.session.isStreaming) {
3532
+ const images = await this.loadImageAttachments(this.takeSubmittedImages(text));
3439
3533
  this.editor.addToHistory?.(text);
3440
3534
  this.editor.setText("");
3441
- await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "followUp" });
3535
+ await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "followUp", images });
3442
3536
  this.updatePendingMessagesDisplay();
3443
3537
  this.ui.requestRender();
3444
3538
  }
3445
3539
  // If not streaming, Alt+Enter acts like regular Enter (trigger onSubmit)
3446
3540
  else if (this.editor.onSubmit) {
3541
+ const images = await this.loadImageAttachments(this.takeSubmittedImages(text));
3542
+ this.stagedSubmitImages = images;
3447
3543
  this.editor.setText("");
3448
3544
  this.editor.onSubmit(text);
3449
3545
  }
@@ -3695,8 +3791,8 @@ export class InteractiveMode {
3695
3791
  }
3696
3792
  return allQueued.length;
3697
3793
  }
3698
- queueCompactionMessage(text, mode) {
3699
- this.compactionQueuedMessages.push({ text, mode });
3794
+ queueCompactionMessage(text, mode, images) {
3795
+ this.compactionQueuedMessages.push({ text, mode, images });
3700
3796
  this.editor.addToHistory?.(text);
3701
3797
  this.editor.setText("");
3702
3798
  this.updatePendingMessagesDisplay();
@@ -3731,10 +3827,10 @@ export class InteractiveMode {
3731
3827
  await this.promptAfterDeferredBuiltins(message.text);
3732
3828
  }
3733
3829
  else if (message.mode === "followUp") {
3734
- await this.session.followUp(message.text);
3830
+ await this.session.followUp(message.text, message.images);
3735
3831
  }
3736
3832
  else {
3737
- await this.session.steer(message.text);
3833
+ await this.session.steer(message.text, message.images);
3738
3834
  }
3739
3835
  }
3740
3836
  this.updatePendingMessagesDisplay();
@@ -3757,7 +3853,9 @@ export class InteractiveMode {
3757
3853
  await this.promptAfterDeferredBuiltins(message.text);
3758
3854
  }
3759
3855
  // Send first prompt (starts streaming)
3760
- const promptPromise = this.promptAfterDeferredBuiltins(firstPrompt.text).catch((error) => {
3856
+ const promptPromise = this.promptAfterDeferredBuiltins(firstPrompt.text, {
3857
+ images: firstPrompt.images,
3858
+ }).catch((error) => {
3761
3859
  restoreQueue(error);
3762
3860
  });
3763
3861
  // Queue remaining messages
@@ -3766,10 +3864,10 @@ export class InteractiveMode {
3766
3864
  await this.promptAfterDeferredBuiltins(message.text);
3767
3865
  }
3768
3866
  else if (message.mode === "followUp") {
3769
- await this.session.followUp(message.text);
3867
+ await this.session.followUp(message.text, message.images);
3770
3868
  }
3771
3869
  else {
3772
- await this.session.steer(message.text);
3870
+ await this.session.steer(message.text, message.images);
3773
3871
  }
3774
3872
  }
3775
3873
  this.updatePendingMessagesDisplay();
@@ -3853,6 +3951,7 @@ export class InteractiveMode {
3853
3951
  footerLsp: this.settingsManager.getFooterLsp(),
3854
3952
  footerContext: this.settingsManager.getFooterContext(),
3855
3953
  footerTokens: this.settingsManager.getFooterTokens(),
3954
+ footerTps: this.settingsManager.getFooterTps(),
3856
3955
  footerStatuses: this.settingsManager.getFooterStatuses(),
3857
3956
  footerGit: this.settingsManager.getFooterGit(),
3858
3957
  footerPlan: this.settingsManager.getFooterPlan(),
@@ -4067,6 +4166,9 @@ export class InteractiveMode {
4067
4166
  onFooterTokensChange: (enabled) => {
4068
4167
  this.settingsManager.setFooterTokens(enabled);
4069
4168
  },
4169
+ onFooterTpsChange: (enabled) => {
4170
+ this.settingsManager.setFooterTps(enabled);
4171
+ },
4070
4172
  onFooterStatusesChange: (enabled) => {
4071
4173
  this.settingsManager.setFooterStatuses(enabled);
4072
4174
  },
@@ -4685,7 +4787,7 @@ export class InteractiveMode {
4685
4787
  this.chatContainer.clear();
4686
4788
  this.renderInitialMessages();
4687
4789
  if (result.editorText && !this.editor.getText().trim()) {
4688
- this.editor.setText(result.editorText);
4790
+ this.restoreEditorFromTreeResult(result);
4689
4791
  }
4690
4792
  this.showStatus("Navigated to selected point");
4691
4793
  void this.flushCompactionQueue({ willRetry: false });
@@ -5504,7 +5606,7 @@ export class InteractiveMode {
5504
5606
  return;
5505
5607
  }
5506
5608
  this.swarmMode = true;
5507
- this.setExtensionStatus("swarm", "swarm ● active");
5609
+ this.setExtensionStatus("swarm", "swarm");
5508
5610
  await this.sendUserMessageAfterDeferredBuiltins(buildSwarmPrompt(task));
5509
5611
  }
5510
5612
  async handleResearchCommand(args) {
@@ -5602,7 +5704,7 @@ export class InteractiveMode {
5602
5704
  this.chatContainer.clear();
5603
5705
  this.renderInitialMessages();
5604
5706
  void this.flushCompactionQueue({ willRetry: false });
5605
- return { editorText: result.editorText };
5707
+ return { editorText: result.editorText, editorImages: result.editorImages };
5606
5708
  }
5607
5709
  catch (error) {
5608
5710
  this.showError(error instanceof Error ? error.message : String(error));
@@ -5619,7 +5721,10 @@ export class InteractiveMode {
5619
5721
  const result = await this.rewindLastTurn("edit");
5620
5722
  if (!result)
5621
5723
  return;
5622
- this.editor.setText(result.editorText ?? "");
5724
+ this.restoreEditorFromTreeResult({
5725
+ editorText: result.editorText ?? "",
5726
+ editorImages: result.editorImages,
5727
+ });
5623
5728
  this.showStatus("Editing last message. /redo to restore.");
5624
5729
  }
5625
5730
  async handleRedoCommand() {
@@ -5642,7 +5747,7 @@ export class InteractiveMode {
5642
5747
  this.chatContainer.clear();
5643
5748
  this.renderInitialMessages();
5644
5749
  if (result.editorText && !this.editor.getText().trim()) {
5645
- this.editor.setText(result.editorText);
5750
+ this.restoreEditorFromTreeResult(result);
5646
5751
  }
5647
5752
  this.showStatus("Redone");
5648
5753
  void this.flushCompactionQueue({ willRetry: false });