@oh-my-pi/pi-coding-agent 16.1.14 → 16.1.16

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 (111) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/cli.js +3705 -4015
  3. package/dist/types/advisor/runtime.d.ts +3 -0
  4. package/dist/types/cli/args.d.ts +2 -5
  5. package/dist/types/cli/flag-tables.d.ts +2 -2
  6. package/dist/types/cli/session-picker.d.ts +4 -2
  7. package/dist/types/commands/launch.d.ts +1 -1
  8. package/dist/types/config/settings-schema.d.ts +32 -1
  9. package/dist/types/eval/agent-bridge.d.ts +19 -0
  10. package/dist/types/eval/js/shared/helpers.d.ts +1 -13
  11. package/dist/types/eval/js/shared/types.d.ts +1 -1
  12. package/dist/types/eval/js/worker-protocol.d.ts +1 -1
  13. package/dist/types/eval/py/executor.d.ts +1 -1
  14. package/dist/types/export/share.d.ts +8 -1
  15. package/dist/types/internal-urls/local-protocol.d.ts +18 -1
  16. package/dist/types/main.d.ts +2 -0
  17. package/dist/types/mcp/transports/stdio.d.ts +12 -1
  18. package/dist/types/modes/components/plugin-settings.d.ts +5 -0
  19. package/dist/types/modes/components/session-selector.d.ts +25 -0
  20. package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -3
  21. package/dist/types/modes/components/status-line/types.d.ts +1 -0
  22. package/dist/types/secrets/obfuscator.d.ts +3 -3
  23. package/dist/types/task/isolation-runner.d.ts +128 -0
  24. package/dist/types/task/worktree.d.ts +14 -1
  25. package/dist/types/thinking.d.ts +15 -0
  26. package/dist/types/tools/eval-render.d.ts +3 -0
  27. package/dist/types/tools/eval.d.ts +11 -17
  28. package/dist/types/tools/todo.d.ts +26 -28
  29. package/dist/types/tui/output-block.d.ts +8 -0
  30. package/dist/types/utils/image-resize.d.ts +2 -0
  31. package/dist/types/utils/shell-snapshot.d.ts +10 -0
  32. package/dist/types/web/search/providers/exa.d.ts +2 -0
  33. package/dist/types/web/search/providers/perplexity.d.ts +17 -3
  34. package/package.json +12 -12
  35. package/scripts/build-binary.ts +18 -4
  36. package/src/advisor/__tests__/advisor.test.ts +114 -0
  37. package/src/advisor/runtime.ts +129 -1
  38. package/src/cli/args.ts +4 -5
  39. package/src/cli/flag-tables.ts +3 -3
  40. package/src/cli/gallery-fixtures/interaction.ts +6 -9
  41. package/src/cli/gallery-fixtures/shell.ts +15 -23
  42. package/src/cli/session-picker.ts +17 -3
  43. package/src/commands/launch.ts +3 -3
  44. package/src/config/model-registry.ts +12 -4
  45. package/src/config/settings-schema.ts +37 -1
  46. package/src/edit/renderer.ts +34 -12
  47. package/src/eval/__tests__/agent-bridge.test.ts +462 -3
  48. package/src/eval/__tests__/helpers-local-roots.test.ts +2 -5
  49. package/src/eval/__tests__/julia-prelude.test.ts +1 -30
  50. package/src/eval/__tests__/prelude-agent.test.ts +42 -8
  51. package/src/eval/agent-bridge.ts +301 -71
  52. package/src/eval/jl/prelude.jl +32 -227
  53. package/src/eval/jl/runner.jl +38 -12
  54. package/src/eval/js/shared/helpers.ts +1 -114
  55. package/src/eval/js/shared/prelude.txt +13 -27
  56. package/src/eval/js/shared/runtime.ts +0 -6
  57. package/src/eval/js/shared/types.ts +1 -1
  58. package/src/eval/js/worker-protocol.ts +1 -1
  59. package/src/eval/py/__tests__/prelude.test.ts +13 -0
  60. package/src/eval/py/executor.ts +1 -1
  61. package/src/eval/py/prelude.py +47 -105
  62. package/src/eval/py/runner.py +0 -6
  63. package/src/eval/rb/prelude.rb +21 -189
  64. package/src/eval/rb/runner.rb +116 -9
  65. package/src/exec/bash-executor.ts +44 -0
  66. package/src/export/html/tool-views.generated.js +29 -29
  67. package/src/export/share.ts +51 -28
  68. package/src/internal-urls/docs-index.generated.txt +1 -1
  69. package/src/internal-urls/local-protocol.ts +100 -53
  70. package/src/main.ts +15 -4
  71. package/src/mcp/transports/stdio.ts +20 -4
  72. package/src/modes/acp/acp-event-mapper.ts +7 -2
  73. package/src/modes/components/custom-editor.test.ts +22 -0
  74. package/src/modes/components/custom-editor.ts +10 -1
  75. package/src/modes/components/footer.ts +4 -3
  76. package/src/modes/components/plugin-settings.ts +7 -1
  77. package/src/modes/components/session-selector.ts +143 -29
  78. package/src/modes/components/status-line/component.ts +5 -1
  79. package/src/modes/components/status-line/context-thresholds.ts +11 -3
  80. package/src/modes/components/status-line/segments.ts +1 -1
  81. package/src/modes/components/status-line/types.ts +1 -0
  82. package/src/modes/controllers/command-controller.ts +6 -0
  83. package/src/modes/rpc/rpc-mode.ts +6 -0
  84. package/src/modes/utils/copy-targets.ts +7 -2
  85. package/src/prompts/system/system-prompt.md +6 -6
  86. package/src/prompts/system/workflow-notice.md +3 -3
  87. package/src/prompts/tools/bash.md +18 -2
  88. package/src/prompts/tools/eval.md +19 -19
  89. package/src/prompts/tools/search.md +1 -0
  90. package/src/prompts/tools/todo.md +1 -1
  91. package/src/secrets/obfuscator.ts +3 -9
  92. package/src/session/agent-session.ts +264 -52
  93. package/src/slash-commands/builtin-registry.ts +2 -1
  94. package/src/task/index.ts +61 -207
  95. package/src/task/isolation-runner.ts +354 -0
  96. package/src/task/worktree.ts +46 -9
  97. package/src/thinking.ts +20 -0
  98. package/src/tools/ask.ts +44 -38
  99. package/src/tools/bash.ts +9 -2
  100. package/src/tools/browser/tab-worker.ts +1 -1
  101. package/src/tools/eval-render.ts +34 -27
  102. package/src/tools/eval.ts +100 -103
  103. package/src/tools/index.ts +8 -1
  104. package/src/tools/read.ts +136 -60
  105. package/src/tools/todo.ts +60 -64
  106. package/src/tui/code-cell.ts +1 -1
  107. package/src/tui/output-block.ts +11 -0
  108. package/src/utils/image-resize.ts +30 -0
  109. package/src/utils/shell-snapshot.ts +63 -1
  110. package/src/web/search/providers/exa.ts +85 -1
  111. package/src/web/search/providers/perplexity.ts +18 -6
@@ -5,17 +5,14 @@ export const interactionFixtures: Record<string, GalleryFixture> = {
5
5
  todo: {
6
6
  label: "Todo",
7
7
  streamingArgs: {
8
- ops: [{ op: "init", list: [{ phase: "Foundation", items: ["Scaffold crate"] }] }],
8
+ op: "init",
9
+ list: [{ phase: "Foundation", items: ["Scaffold crate"] }],
9
10
  },
10
11
  args: {
11
- ops: [
12
- {
13
- op: "init",
14
- list: [
15
- { phase: "Foundation", items: ["Scaffold crate", "Wire workspace"] },
16
- { phase: "Auth", items: ["Port credential store", "Wire OAuth providers"] },
17
- ],
18
- },
12
+ op: "init",
13
+ list: [
14
+ { phase: "Foundation", items: ["Scaffold crate", "Wire workspace"] },
15
+ { phase: "Auth", items: ["Port credential store", "Wire OAuth providers"] },
19
16
  ],
20
17
  },
21
18
  result: {
@@ -59,31 +59,23 @@ export const shellFixtures: Record<string, GalleryFixture> = {
59
59
  eval: {
60
60
  label: "Eval",
61
61
  streamingArgs: {
62
- cells: [
63
- {
64
- language: "py",
65
- code: 'import json\nfrom pathlib import Path\n\ndata = json.loads(Path("package.js',
66
- title: "load config",
67
- },
68
- ],
62
+ language: "py",
63
+ code: 'import json\nfrom pathlib import Path\n\ndata = json.loads(Path("package.js',
64
+ title: "load config",
69
65
  },
70
66
  args: {
71
- cells: [
72
- {
73
- language: "py",
74
- title: "load config",
75
- code: [
76
- "import json",
77
- "from pathlib import Path",
78
- "",
79
- 'data = json.loads(Path("package.json").read_text())',
80
- 'deps = data.get("dependencies", {})',
81
- 'print(f"{data[\\"name\\"]} v{data[\\"version\\"]}")',
82
- 'print(f"{len(deps)} dependencies")',
83
- "display(sorted(deps)[:3])",
84
- ].join("\n"),
85
- },
86
- ],
67
+ language: "py",
68
+ title: "load config",
69
+ code: [
70
+ "import json",
71
+ "from pathlib import Path",
72
+ "",
73
+ 'data = json.loads(Path("package.json").read_text())',
74
+ 'deps = data.get("dependencies", {})',
75
+ 'print(f"{data[\\"name\\"]} v{data[\\"version\\"]}")',
76
+ 'print(f"{len(deps)} dependencies")',
77
+ "display(sorted(deps)[:3])",
78
+ ].join("\n"),
87
79
  },
88
80
  result: {
89
81
  content: [
@@ -8,8 +8,10 @@ import { FileSessionStorage } from "../session/session-storage";
8
8
 
9
9
  /**
10
10
  * Show the TUI session selector and return the selected session, or null if
11
- * cancelled. Tab toggles between current-folder and all-projects scope; the
12
- * all-projects list is loaded lazily via `SessionManager.listAll`.
11
+ * cancelled. Rendered as a fullscreen overlay on the terminal's alternate
12
+ * screen, so the list scrolls and rows are clickable with the mouse. Tab
13
+ * toggles between current-folder and all-projects scope; the all-projects list
14
+ * is loaded lazily via `SessionManager.listAll`.
13
15
  */
14
16
  export async function selectSession(
15
17
  sessions: SessionInfo[],
@@ -65,6 +67,7 @@ export async function selectSession(
65
67
  loadAllSessions: () => SessionManager.listAll(storage),
66
68
  allSessions: options?.allSessions,
67
69
  getTerminalRows: () => ui.terminal.rows,
70
+ fillHeight: true,
68
71
  },
69
72
  );
70
73
  return selector;
@@ -72,7 +75,18 @@ export async function selectSession(
72
75
 
73
76
  const selector = showSelector();
74
77
  selector.setOnRequestRender(() => ui.requestRender());
75
- ui.addChild(selector);
78
+ // Present as a fullscreen overlay so the picker borrows the terminal's
79
+ // alternate screen buffer (vim/less idiom): the list scrolls and rows are
80
+ // clickable via the mouse tracking the overlay enables for its lifetime.
81
+ // Anchored top-left at full size so a mouse row maps directly to a rendered
82
+ // line (the overlay paints from screen row 0).
83
+ ui.showOverlay(selector, {
84
+ anchor: "top-left",
85
+ width: "100%",
86
+ maxHeight: "100%",
87
+ margin: 0,
88
+ fullscreen: true,
89
+ });
76
90
  ui.setFocus(selector);
77
91
  ui.start();
78
92
  return promise;
@@ -2,12 +2,12 @@
2
2
  * Root command for the coding agent CLI.
3
3
  */
4
4
 
5
- import { THINKING_EFFORTS } from "@oh-my-pi/pi-catalog/effort";
6
5
  import { APP_NAME } from "@oh-my-pi/pi-utils";
7
6
  import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
8
7
  import { parseArgs } from "../cli/args";
9
8
  import { runRootCommand } from "../main";
10
9
  import { prepareAcpTerminalAuthArgs } from "../modes/acp/terminal-auth";
10
+ import { CLI_THINKING_LEVELS } from "../thinking";
11
11
 
12
12
  export default class Index extends Command {
13
13
  static description = "AI coding assistant";
@@ -100,8 +100,8 @@ export default class Index extends Command {
100
100
  description: "Comma-separated list of tools to enable (default: all)",
101
101
  }),
102
102
  thinking: Flags.string({
103
- description: `Set thinking level: ${THINKING_EFFORTS.join(", ")}`,
104
- options: [...THINKING_EFFORTS],
103
+ description: `Set thinking level: ${CLI_THINKING_LEVELS.join(", ")}`,
104
+ options: [...CLI_THINKING_LEVELS],
105
105
  }),
106
106
  "hide-thinking": Flags.boolean({
107
107
  description: "Hide thinking blocks in TUI output (display only, does not disable model thinking)",
@@ -992,6 +992,7 @@ export class ModelRegistry {
992
992
  });
993
993
  continue;
994
994
  }
995
+ const configStale = this.#isDiscoveryCacheOlderThanModelsConfig(cache.updatedAt);
995
996
  const models = this.#applyProviderModelOverrides(
996
997
  providerConfig.provider,
997
998
  this.#normalizeDiscoverableModels(
@@ -1007,7 +1008,7 @@ export class ModelRegistry {
1007
1008
  provider: providerConfig.provider,
1008
1009
  status: "cached",
1009
1010
  optional: providerConfig.optional ?? false,
1010
- stale: !cache.fresh || !cache.authoritative,
1011
+ stale: !cache.fresh || !cache.authoritative || configStale,
1011
1012
  fetchedAt: cache.updatedAt,
1012
1013
  models: models.map(model => model.id),
1013
1014
  });
@@ -1259,12 +1260,19 @@ export class ModelRegistry {
1259
1260
  return providerConfig.provider;
1260
1261
  }
1261
1262
 
1263
+ #isDiscoveryCacheOlderThanModelsConfig(cacheUpdatedAt: number): boolean {
1264
+ const configMtime = this.#modelsConfigFile.getMtimeMs();
1265
+ return configMtime !== null && cacheUpdatedAt < Math.floor(configMtime);
1266
+ }
1267
+
1262
1268
  async #discoverProviderModels(
1263
1269
  providerConfig: DiscoveryProviderConfig,
1264
1270
  strategy: ModelRefreshStrategy,
1265
1271
  ): Promise<Model<Api>[]> {
1266
1272
  const cacheProviderId = this.#configuredDiscoveryCacheProviderId(providerConfig);
1267
1273
  const cached = readModelCache<Api>(cacheProviderId, 24 * 60 * 60 * 1000, Date.now, this.#cacheDbPath);
1274
+ const cacheOlderThanConfig = cached !== null && this.#isDiscoveryCacheOlderThanModelsConfig(cached.updatedAt);
1275
+ const effectiveStrategy = strategy === "online-if-uncached" && cacheOlderThanConfig ? "online" : strategy;
1268
1276
  const requiresAuth = !this.#keylessProviders.has(providerConfig.provider);
1269
1277
  if (requiresAuth) {
1270
1278
  const apiKey = await this.#peekApiKeyForProvider(providerConfig.provider);
@@ -1311,12 +1319,12 @@ export class ModelRegistry {
1311
1319
  cacheTtlMs: 24 * 60 * 60 * 1000,
1312
1320
  fetchDynamicModels,
1313
1321
  });
1314
- const result = await manager.refresh(strategy);
1322
+ const result = await manager.refresh(effectiveStrategy);
1315
1323
  const status = discoveryError
1316
1324
  ? result.models.length > 0
1317
1325
  ? "cached"
1318
1326
  : "unavailable"
1319
- : strategy === "offline"
1327
+ : effectiveStrategy === "offline"
1320
1328
  ? cached
1321
1329
  ? "cached"
1322
1330
  : "idle"
@@ -1327,7 +1335,7 @@ export class ModelRegistry {
1327
1335
  provider: providerId,
1328
1336
  status,
1329
1337
  optional: providerConfig.optional ?? false,
1330
- stale: result.stale || status === "cached",
1338
+ stale: result.stale || status === "cached" || (cacheOlderThanConfig && status !== "ok"),
1331
1339
  fetchedAt: discoveryError ? cached?.updatedAt : Date.now(),
1332
1340
  models: result.models.map(model => model.id),
1333
1341
  error: discoveryError,
@@ -1592,6 +1592,30 @@ export const SETTINGS_SCHEMA = {
1592
1592
  },
1593
1593
  },
1594
1594
 
1595
+ "share.store": {
1596
+ type: "enum",
1597
+ values: ["blob", "gist"] as const,
1598
+ default: "blob",
1599
+ ui: {
1600
+ tab: "interaction",
1601
+ group: "Collab",
1602
+ label: "Share Store",
1603
+ description: "Where /share uploads the encrypted session blob",
1604
+ options: [
1605
+ {
1606
+ value: "blob",
1607
+ label: "Encrypted Blob",
1608
+ description: "Upload to the share server (no GitHub account needed; avoids gist API rate limits)",
1609
+ },
1610
+ {
1611
+ value: "gist",
1612
+ label: "GitHub Gist",
1613
+ description: "Push to a secret gist (needs authenticated gh), falling back to the share server",
1614
+ },
1615
+ ],
1616
+ },
1617
+ },
1618
+
1595
1619
  "share.redactSecrets": {
1596
1620
  type: "boolean",
1597
1621
  default: true,
@@ -3548,7 +3572,7 @@ export const SETTINGS_SCHEMA = {
3548
3572
  group: "Discovery & MCP",
3549
3573
  label: "Essential Tools Override",
3550
3574
  description:
3551
- "Override the always-loaded built-in tools (default: read, bash, edit). Leave empty to use defaults.",
3575
+ "Override the always-loaded built-in tools (default: read, bash, edit, write, find, eval). Leave empty to use defaults.",
3552
3576
  },
3553
3577
  },
3554
3578
 
@@ -4455,6 +4479,17 @@ export const SETTINGS_SCHEMA = {
4455
4479
  },
4456
4480
  },
4457
4481
 
4482
+ "exa.searchDelayMs": {
4483
+ type: "number",
4484
+ default: 1_000,
4485
+ ui: {
4486
+ tab: "providers",
4487
+ group: "Services",
4488
+ label: "Exa Search Delay",
4489
+ description: "Minimum delay between Exa web search requests in milliseconds; set 0 to disable pacing",
4490
+ },
4491
+ },
4492
+
4458
4493
  "exa.enableResearcher": {
4459
4494
  type: "boolean",
4460
4495
  default: false,
@@ -4761,6 +4796,7 @@ export interface TtsrSettings {
4761
4796
  export interface ExaSettings {
4762
4797
  enabled: boolean;
4763
4798
  enableSearch: boolean;
4799
+ searchDelayMs: number;
4764
4800
  enableResearcher: boolean;
4765
4801
  enableWebsets: boolean;
4766
4802
  }
@@ -22,6 +22,7 @@ import {
22
22
  invalidateRenderedStringCache,
23
23
  type LspBatchRequest,
24
24
  PREVIEW_LIMITS,
25
+ previewWindowRows,
25
26
  type RenderedStringCache,
26
27
  replaceTabs,
27
28
  shortenPath,
@@ -340,6 +341,7 @@ function renderPlainTextPreview(text: string, uiTheme: Theme, _filePath?: string
340
341
  function formatStreamingDiff(
341
342
  diff: string,
342
343
  rawPath: string,
344
+ width: number,
343
345
  uiTheme: Theme,
344
346
  expanded: boolean,
345
347
  label = "streaming",
@@ -347,15 +349,32 @@ function formatStreamingDiff(
347
349
  cache?: RenderedStringCache,
348
350
  ): string {
349
351
  if (!diff) return "";
350
- let text = cachedRenderedString(cache, uiTheme, expanded, rawPath, diff, () => {
351
- // Collapsed uses a "Cursor" tail window: pin the last
352
- // EDIT_STREAMING_PREVIEW_LINES rows to the bottom so freshly streamed changes
353
- // stay on screen. The whole-file diff is recomputed on every streamed chunk
354
- // and its Myers alignment is not monotonic in payload length, so a hunk-aware
355
- // window stutters as rows move between hunks. Expanded deliberately lifts that
356
- // cap for the approval-time full view.
352
+ // Clamp the collapsed tail to the viewport so a tall or fast-growing diff
353
+ // cannot outgrow the live window. Otherwise its mutating tail scrolls above
354
+ // the native-scrollback commit boundary and the engine re-commits a fresh
355
+ // snapshot every streamed frame, stacking duplicate "… more lines above"
356
+ // previews in history. The budget is VISUAL rows (a long wrapped line counts
357
+ // for more than one) at the framed block's inner width (border only —
358
+ // contentPaddingLeft is 0); only the visible suffix is syntax-colored, so the
359
+ // cheap raw-line wrap walk keeps the per-chunk cost bounded. innerWidth/budget
360
+ // are in the cache salt so a resize re-slices.
361
+ const innerWidth = Math.max(1, width - 2);
362
+ const budget = expanded ? Number.POSITIVE_INFINITY : Math.min(EDIT_STREAMING_PREVIEW_LINES, previewWindowRows());
363
+ let text = cachedRenderedString(cache, uiTheme, expanded, `${rawPath}:${innerWidth}:${budget}`, diff, () => {
364
+ // "Cursor" tail window: pin the last rows to the bottom so freshly streamed
365
+ // changes stay on screen. The whole-file diff is recomputed every chunk and
366
+ // its Myers alignment is not monotonic in payload length, so a hunk-aware
367
+ // window stutters as rows move between hunks. Expanded lifts the cap.
357
368
  const allLines = diff.replace(/\n+$/u, "").split("\n");
358
- const hiddenLines = expanded ? 0 : Math.max(0, allLines.length - EDIT_STREAMING_PREVIEW_LINES);
369
+ let visualUsed = 0;
370
+ let cut = allLines.length;
371
+ for (let i = allLines.length - 1; i >= 0; i--) {
372
+ const lineRows = Math.max(1, wrapTextWithAnsi(replaceTabs(allLines[i]!), innerWidth).length);
373
+ if (visualUsed + lineRows > budget && visualUsed > 0) break;
374
+ visualUsed += lineRows;
375
+ cut = i;
376
+ }
377
+ const hiddenLines = cut;
359
378
  const visible = hiddenLines > 0 ? allLines.slice(hiddenLines) : allLines;
360
379
  let rendered = "\n\n";
361
380
  if (hiddenLines > 0) {
@@ -384,6 +403,7 @@ function formatStreamingDiff(
384
403
 
385
404
  function formatMultiFileStreamingDiff(
386
405
  previews: PerFileDiffPreview[],
406
+ width: number,
387
407
  uiTheme: Theme,
388
408
  expanded: boolean,
389
409
  spinnerFrame?: number,
@@ -405,7 +425,7 @@ function formatMultiFileStreamingDiff(
405
425
  const isLast = index === previews.length - 1;
406
426
  const cache = previewCacheAt(caches, index);
407
427
  parts.push(
408
- `${header}${formatStreamingDiff(preview.diff, preview.path, uiTheme, expanded, "preview", isLast ? spinnerFrame : undefined, cache)}`,
428
+ `${header}${formatStreamingDiff(preview.diff, preview.path, width, uiTheme, expanded, "preview", isLast ? spinnerFrame : undefined, cache)}`,
409
429
  );
410
430
  }
411
431
  }
@@ -415,6 +435,7 @@ function formatMultiFileStreamingDiff(
415
435
  function getCallPreview(
416
436
  args: EditRenderArgs,
417
437
  rawPath: string,
438
+ width: number,
418
439
  uiTheme: Theme,
419
440
  renderContext: EditRenderContext | undefined,
420
441
  expanded: boolean,
@@ -423,14 +444,14 @@ function getCallPreview(
423
444
  ): string {
424
445
  const multi = renderContext?.perFileDiffPreview;
425
446
  if (multi && multi.length > 1 && multi.some(p => p.diff || p.error)) {
426
- return formatMultiFileStreamingDiff(multi, uiTheme, expanded, spinnerFrame, caches);
447
+ return formatMultiFileStreamingDiff(multi, width, uiTheme, expanded, spinnerFrame, caches);
427
448
  }
428
449
  const cache = previewCacheAt(caches, 0);
429
450
  if (args.previewDiff) {
430
- return formatStreamingDiff(args.previewDiff, rawPath, uiTheme, expanded, "preview", spinnerFrame, cache);
451
+ return formatStreamingDiff(args.previewDiff, rawPath, width, uiTheme, expanded, "preview", spinnerFrame, cache);
431
452
  }
432
453
  if (args.diff && args.op) {
433
- return formatStreamingDiff(args.diff, rawPath, uiTheme, expanded, "streaming", spinnerFrame, cache);
454
+ return formatStreamingDiff(args.diff, rawPath, width, uiTheme, expanded, "streaming", spinnerFrame, cache);
434
455
  }
435
456
  if (args.diff) {
436
457
  return renderPlainTextPreview(args.diff, uiTheme, rawPath);
@@ -628,6 +649,7 @@ export const editToolRenderer = {
628
649
  let body = getCallPreview(
629
650
  editArgs,
630
651
  rawPath,
652
+ width,
631
653
  uiTheme,
632
654
  renderContext,
633
655
  options.expanded,