@oh-my-pi/pi-coding-agent 15.11.7 → 15.12.0

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 (107) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/dist/cli.js +8106 -7708
  3. package/dist/types/cli/args.d.ts +2 -0
  4. package/dist/types/collab/crypto.d.ts +7 -0
  5. package/dist/types/collab/guest.d.ts +23 -0
  6. package/dist/types/collab/host.d.ts +29 -0
  7. package/dist/types/collab/protocol.d.ts +113 -0
  8. package/dist/types/collab/relay-client.d.ts +22 -0
  9. package/dist/types/commands/join.d.ts +12 -0
  10. package/dist/types/config/settings-schema.d.ts +60 -5
  11. package/dist/types/export/custom-share.d.ts +1 -2
  12. package/dist/types/export/html/index.d.ts +39 -1
  13. package/dist/types/export/share.d.ts +43 -0
  14. package/dist/types/extensibility/slash-commands.d.ts +1 -11
  15. package/dist/types/main.d.ts +2 -0
  16. package/dist/types/modes/components/agent-hub.d.ts +32 -1
  17. package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
  18. package/dist/types/modes/components/hook-selector.d.ts +4 -6
  19. package/dist/types/modes/components/segment-track.d.ts +11 -6
  20. package/dist/types/modes/components/status-line/component.d.ts +10 -2
  21. package/dist/types/modes/components/status-line/types.d.ts +11 -0
  22. package/dist/types/modes/controllers/event-controller.d.ts +7 -0
  23. package/dist/types/modes/controllers/input-controller.d.ts +1 -1
  24. package/dist/types/modes/controllers/session-focus-controller.d.ts +31 -0
  25. package/dist/types/modes/interactive-mode.d.ts +16 -0
  26. package/dist/types/modes/session-observer-registry.d.ts +7 -0
  27. package/dist/types/modes/theme/theme.d.ts +2 -1
  28. package/dist/types/modes/types.d.ts +20 -0
  29. package/dist/types/session/agent-session.d.ts +13 -0
  30. package/dist/types/session/codex-auto-reset.d.ts +8 -4
  31. package/dist/types/session/session-manager.d.ts +21 -0
  32. package/dist/types/session/snapcompact-inline.d.ts +6 -3
  33. package/dist/types/slash-commands/builtin-registry.d.ts +9 -0
  34. package/dist/types/task/executor.d.ts +7 -0
  35. package/dist/types/task/types.d.ts +9 -0
  36. package/package.json +14 -13
  37. package/scripts/bench-guard.ts +71 -0
  38. package/scripts/build-binary.ts +4 -0
  39. package/scripts/bundle-dist.ts +4 -0
  40. package/scripts/generate-share-viewer.ts +34 -0
  41. package/src/cli/args.ts +2 -0
  42. package/src/cli-commands.ts +1 -0
  43. package/src/collab/crypto.ts +63 -0
  44. package/src/collab/guest.ts +450 -0
  45. package/src/collab/host.ts +556 -0
  46. package/src/collab/protocol.ts +232 -0
  47. package/src/collab/relay-client.ts +216 -0
  48. package/src/commands/join.ts +39 -0
  49. package/src/config/model-registry.ts +22 -14
  50. package/src/config/settings-schema.ts +67 -5
  51. package/src/config/settings.ts +12 -0
  52. package/src/export/custom-share.ts +1 -1
  53. package/src/export/html/index.ts +122 -17
  54. package/src/export/html/share-loader.js +102 -0
  55. package/src/export/html/template.css +745 -459
  56. package/src/export/html/template.html +6 -3
  57. package/src/export/html/template.js +240 -915
  58. package/src/export/html/tool-views.generated.js +38 -0
  59. package/src/export/share.ts +268 -0
  60. package/src/extensibility/slash-commands.ts +1 -97
  61. package/src/internal-urls/docs-index.generated.ts +74 -73
  62. package/src/main.ts +33 -11
  63. package/src/modes/components/agent-hub.ts +659 -431
  64. package/src/modes/components/assistant-message.ts +126 -6
  65. package/src/modes/components/collab-prompt-message.ts +30 -0
  66. package/src/modes/components/hook-selector.ts +4 -5
  67. package/src/modes/components/segment-track.ts +44 -7
  68. package/src/modes/components/status-line/component.ts +59 -6
  69. package/src/modes/components/status-line/presets.ts +1 -1
  70. package/src/modes/components/status-line/segments.ts +18 -1
  71. package/src/modes/components/status-line/types.ts +12 -0
  72. package/src/modes/components/tips.txt +4 -1
  73. package/src/modes/controllers/command-controller.ts +55 -96
  74. package/src/modes/controllers/event-controller.ts +45 -16
  75. package/src/modes/controllers/input-controller.ts +175 -9
  76. package/src/modes/controllers/selector-controller.ts +13 -15
  77. package/src/modes/controllers/session-focus-controller.ts +112 -0
  78. package/src/modes/controllers/streaming-reveal.ts +7 -0
  79. package/src/modes/interactive-mode.ts +56 -6
  80. package/src/modes/session-observer-registry.ts +11 -0
  81. package/src/modes/theme/theme.ts +6 -0
  82. package/src/modes/types.ts +20 -0
  83. package/src/modes/utils/ui-helpers.ts +23 -13
  84. package/src/prompts/tools/job.md +1 -1
  85. package/src/sdk.ts +239 -36
  86. package/src/session/agent-session.ts +82 -7
  87. package/src/session/codex-auto-reset.ts +23 -11
  88. package/src/session/session-manager.ts +44 -0
  89. package/src/session/snapcompact-inline.ts +9 -3
  90. package/src/slash-commands/builtin-registry.ts +261 -24
  91. package/src/task/executor.ts +14 -0
  92. package/src/task/index.ts +5 -1
  93. package/src/task/render.ts +76 -5
  94. package/src/task/types.ts +9 -0
  95. package/src/tiny/worker.ts +17 -95
  96. package/src/tools/job.ts +6 -9
  97. package/src/tools/read.ts +38 -5
  98. package/src/tools/write.ts +13 -42
  99. package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
  100. package/dist/types/export/html/template.generated.d.ts +0 -1
  101. package/dist/types/export/html/template.macro.d.ts +0 -5
  102. package/dist/types/tiny/compiled-runtime.d.ts +0 -35
  103. package/scripts/generate-template.ts +0 -33
  104. package/src/bun-imports.d.ts +0 -28
  105. package/src/export/html/template.generated.ts +0 -2
  106. package/src/export/html/template.macro.ts +0 -25
  107. package/src/tiny/compiled-runtime.ts +0 -179
@@ -1,4 +1,3 @@
1
- import * as fs from "node:fs/promises";
2
1
  import { createRequire } from "node:module";
3
2
  import * as path from "node:path";
4
3
  import type {
@@ -7,10 +6,16 @@ import type {
7
6
  TextGenerationStringOutput,
8
7
  StoppingCriteria as TransformersStoppingCriteria,
9
8
  } from "@huggingface/transformers";
10
- import { getTinyModelsCacheDir, isCompiledBinary, prompt } from "@oh-my-pi/pi-utils";
9
+ import {
10
+ ensureRuntimeInstalled,
11
+ getTinyModelsCacheDir,
12
+ installRuntimeModuleResolver,
13
+ isCompiledBinary,
14
+ prompt,
15
+ resolveRuntimeModule,
16
+ } from "@oh-my-pi/pi-utils";
11
17
  import packageJson from "../../package.json" with { type: "json" };
12
18
  import tinyTitleSystemPrompt from "../prompts/system/tiny-title-system.md" with { type: "text" };
13
- import { installRuntimeModuleResolver, resolveRuntimeModule } from "./compiled-runtime";
14
19
  import { resolveTinyModelDevicePreference, type TinyModelDevice, tinyModelDeviceLoadOrder } from "./device";
15
20
  import { resolveTinyModelDtypeOverride, type TinyModelDtype } from "./dtype";
16
21
  import {
@@ -31,8 +36,6 @@ const TINY_TITLE_SYSTEM_PROMPT = prompt.render(tinyTitleSystemPrompt);
31
36
  const TRANSFORMERS_PACKAGE = "@huggingface/transformers";
32
37
  const COMPILED_TRANSFORMERS_VERSION = process.env.PI_TINY_TRANSFORMERS_VERSION;
33
38
  const sourceRequire = createRequire(import.meta.url);
34
- const INSTALL_LOCK_ATTEMPTS = 240;
35
- const INSTALL_LOCK_SLEEP_MS = 250;
36
39
 
37
40
  const tinyModelDevicePreference = resolveTinyModelDevicePreference();
38
41
  const tinyModelDtypeOverride = resolveTinyModelDtypeOverride();
@@ -97,10 +100,6 @@ function errorText(error: unknown): string {
97
100
  return error instanceof Error ? (error.stack ?? error.message) : String(error);
98
101
  }
99
102
 
100
- function isErrnoCode(error: unknown, code: string): boolean {
101
- return typeof error === "object" && error !== null && "code" in error && error.code === code;
102
- }
103
-
104
103
  function sendLog(
105
104
  transport: TinyTitleTransport,
106
105
  level: "debug" | "warn" | "error",
@@ -118,69 +117,6 @@ function getTinyTitleRuntimeDir(): string {
118
117
  );
119
118
  }
120
119
 
121
- async function acquireInstallLock(runtimeDir: string): Promise<() => Promise<void>> {
122
- const lockDir = `${runtimeDir}.lock`;
123
- await fs.mkdir(path.dirname(lockDir), { recursive: true });
124
- for (let attempt = 0; attempt < INSTALL_LOCK_ATTEMPTS; attempt++) {
125
- try {
126
- await fs.mkdir(lockDir);
127
- return async () => {
128
- await fs.rm(lockDir, { recursive: true, force: true });
129
- };
130
- } catch (error) {
131
- if (!isErrnoCode(error, "EEXIST")) throw error;
132
- await Bun.sleep(INSTALL_LOCK_SLEEP_MS);
133
- }
134
- }
135
- throw new Error(`Timed out waiting for tiny title runtime install lock: ${lockDir}`);
136
- }
137
-
138
- async function isCompiledRuntimeInstalled(runtimeDir: string): Promise<boolean> {
139
- return Bun.file(path.join(runtimeDir, "node_modules", "@huggingface", "transformers", "package.json")).exists();
140
- }
141
-
142
- async function writeRuntimeManifest(runtimeDir: string): Promise<void> {
143
- await fs.mkdir(runtimeDir, { recursive: true });
144
- await Bun.write(
145
- path.join(runtimeDir, "package.json"),
146
- `${JSON.stringify(
147
- {
148
- private: true,
149
- type: "module",
150
- dependencies: {
151
- [TRANSFORMERS_PACKAGE]: getTransformersVersionSpec(),
152
- },
153
- trustedDependencies: ["onnxruntime-node"],
154
- },
155
- null,
156
- "\t",
157
- )}\n`,
158
- );
159
- }
160
-
161
- async function readPipe(stream: ReadableStream<Uint8Array> | null): Promise<string> {
162
- if (!stream) return "";
163
- return new Response(stream).text();
164
- }
165
-
166
- async function runRuntimeInstall(runtimeDir: string): Promise<void> {
167
- const proc = Bun.spawn([process.execPath, "install", "--cwd", runtimeDir, "--production"], {
168
- env: { ...Bun.env, BUN_BE_BUN: "1" },
169
- stdout: "pipe",
170
- stderr: "pipe",
171
- });
172
- const [stdout, stderr, exitCode] = await Promise.all([
173
- readPipe(proc.stdout as ReadableStream<Uint8Array> | null),
174
- readPipe(proc.stderr as ReadableStream<Uint8Array> | null),
175
- proc.exited,
176
- ]);
177
- if (exitCode === 0) return;
178
- const output = `${stdout}\n${stderr}`.trim();
179
- throw new Error(
180
- `Failed to install tiny title runtime with ${process.execPath} install (exit ${exitCode}): ${output}`,
181
- );
182
- }
183
-
184
120
  function sendRuntimeInstallProgress(
185
121
  transport: TinyTitleTransport,
186
122
  requestId: string,
@@ -198,28 +134,6 @@ function sendRuntimeInstallProgress(
198
134
  });
199
135
  }
200
136
 
201
- async function ensureCompiledTransformersRuntime(
202
- transport: TinyTitleTransport,
203
- requestId: string,
204
- modelKey: TinyLocalModelKey,
205
- ): Promise<string> {
206
- const runtimeDir = getTinyTitleRuntimeDir();
207
- if (await isCompiledRuntimeInstalled(runtimeDir)) return runtimeDir;
208
-
209
- sendRuntimeInstallProgress(transport, requestId, modelKey, "initiate");
210
- const releaseLock = await acquireInstallLock(runtimeDir);
211
- try {
212
- if (await isCompiledRuntimeInstalled(runtimeDir)) return runtimeDir;
213
- await writeRuntimeManifest(runtimeDir);
214
- sendRuntimeInstallProgress(transport, requestId, modelKey, "download");
215
- await runRuntimeInstall(runtimeDir);
216
- sendRuntimeInstallProgress(transport, requestId, modelKey, "done");
217
- return runtimeDir;
218
- } finally {
219
- await releaseLock();
220
- }
221
- }
222
-
223
137
  /**
224
138
  * Prepare the freshly-installed compiled runtime for loading: stub `sharp`
225
139
  * (the tiny models are text-generation only, so the native image pipeline is
@@ -252,7 +166,15 @@ async function loadTransformers(
252
166
  if (transformersRuntime) return transformersRuntime;
253
167
  transformersRuntime = (async () => {
254
168
  if (!isCompiledBinary()) return configureTransformers(sourceRequire(TRANSFORMERS_PACKAGE) as TransformersRuntime);
255
- const runtimeDir = await ensureCompiledTransformersRuntime(transport, requestId, modelKey);
169
+ const runtimeDir = await ensureRuntimeInstalled({
170
+ runtimeDir: getTinyTitleRuntimeDir(),
171
+ install: {
172
+ dependencies: { [TRANSFORMERS_PACKAGE]: getTransformersVersionSpec() },
173
+ trustedDependencies: ["onnxruntime-node"],
174
+ },
175
+ probePackage: TRANSFORMERS_PACKAGE,
176
+ onPhase: phase => sendRuntimeInstallProgress(transport, requestId, modelKey, phase),
177
+ });
256
178
  const entry = await prepareCompiledRuntime(runtimeDir);
257
179
  const require_ = createRequire(entry);
258
180
  return configureTransformers(require_(entry) as TransformersRuntime);
package/src/tools/job.ts CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  import { ToolError } from "./tool-errors";
25
25
 
26
26
  const jobSchema = z.object({
27
- poll: z.array(z.string()).optional().describe("job ids to wait for"),
27
+ poll: z.array(z.string()).optional().describe("job ids to wait for; omit to wait on all running jobs"),
28
28
  cancel: z.array(z.string()).optional().describe("job ids to cancel"),
29
29
  list: z.boolean().optional().describe("snapshot all jobs"),
30
30
  });
@@ -512,14 +512,11 @@ export const jobToolRenderer = {
512
512
  itemType: "job",
513
513
  renderItem: job => {
514
514
  const lines: string[] = [];
515
- const icon =
516
- job.status === "completed"
517
- ? uiTheme.styledSymbol("tool.job", "accent")
518
- : formatStatusIcon(
519
- statusToIcon(job.status),
520
- uiTheme,
521
- job.status === "running" ? options.spinnerFrame : undefined,
522
- );
515
+ const icon = formatStatusIcon(
516
+ statusToIcon(job.status),
517
+ uiTheme,
518
+ job.status === "running" ? options.spinnerFrame : undefined,
519
+ );
523
520
  const typeBadge = formatBadge(job.type, statusToColor(job.status), uiTheme);
524
521
  // Task jobs label themselves with their agent id, which is also
525
522
  // the job id — drop the id column instead of stuttering it twice.
package/src/tools/read.ts CHANGED
@@ -8,6 +8,7 @@ import { glob, type SummaryResult, summarizeCode } from "@oh-my-pi/pi-natives";
8
8
  import type { Component } from "@oh-my-pi/pi-tui";
9
9
  import { Text } from "@oh-my-pi/pi-tui";
10
10
  import { getRemoteDir, logger, prompt, readImageMetadata, untilAborted } from "@oh-my-pi/pi-utils";
11
+ import { LRUCache } from "lru-cache/raw";
11
12
  import * as z from "zod/v4";
12
13
  import {
13
14
  canonicalSnapshotKey,
@@ -100,6 +101,28 @@ import {
100
101
  import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
101
102
  import { toolResult } from "./tool-result";
102
103
 
104
+ // Per-session memo for tree-sitter summaries. `summarizeCode` is a pure function
105
+ // of (code, path, fold settings) but costs ~12-18ms for a ~1500-line file, and a
106
+ // repeat summary read of the same unchanged file re-parses from scratch. Key on
107
+ // the content hash of the freshly-read bytes (+ path + fold settings): the file
108
+ // is still read fresh on every call, so a hit only reuses the deterministic
109
+ // parse — there is no staleness window and no stat guard is needed. Bounded LRU,
110
+ // aged out with the session via WeakMap.
111
+ // Unusable results (not parsed, or nothing elided) are memoized as `false`: the
112
+ // full SummaryResult embeds the whole source in kept segments, and the caller
113
+ // only ever renders `parsed && elided` summaries — caching the segments would
114
+ // retain up to 48 near-2MiB sources just to remember "no summary".
115
+ const SUMMARY_CACHE_MAX = 48;
116
+ const summaryParseCaches = new WeakMap<object, LRUCache<string, SummaryResult | false>>();
117
+ function getSummaryParseCache(session: object): LRUCache<string, SummaryResult | false> {
118
+ let cache = summaryParseCaches.get(session);
119
+ if (!cache) {
120
+ cache = new LRUCache<string, SummaryResult | false>({ max: SUMMARY_CACHE_MAX });
121
+ summaryParseCaches.set(session, cache);
122
+ }
123
+ return cache;
124
+ }
125
+
103
126
  // Document types converted to markdown via markit.
104
127
  const CONVERTIBLE_EXTENSIONS = new Set([".pdf", ".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx", ".rtf", ".epub"]);
105
128
 
@@ -1614,15 +1637,25 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1614
1637
  if (lineCount > MAX_SUMMARY_LINES) return null;
1615
1638
  if (lineCount < this.session.settings.get("read.summarize.minTotalLines")) return null;
1616
1639
 
1640
+ const minBodyLines = this.session.settings.get("read.summarize.minBodyLines");
1641
+ const minCommentLines = this.session.settings.get("read.summarize.minCommentLines");
1642
+ const unfoldUntilLines = this.session.settings.get("read.summarize.unfoldUntil");
1643
+ const unfoldLimitLines = this.session.settings.get("read.summarize.unfoldLimit");
1644
+ const cache = getSummaryParseCache(this.session);
1645
+ const cacheKey = `${absolutePath}\0${Bun.hash(code)}\0${minBodyLines},${minCommentLines},${unfoldUntilLines},${unfoldLimitLines}`;
1646
+ const memoized = cache.get(cacheKey);
1647
+ if (memoized !== undefined) return memoized || null;
1617
1648
  const result = summarizeCode({
1618
1649
  code,
1619
1650
  path: absolutePath,
1620
- minBodyLines: this.session.settings.get("read.summarize.minBodyLines"),
1621
- minCommentLines: this.session.settings.get("read.summarize.minCommentLines"),
1622
- unfoldUntilLines: this.session.settings.get("read.summarize.unfoldUntil"),
1623
- unfoldLimitLines: this.session.settings.get("read.summarize.unfoldLimit"),
1651
+ minBodyLines,
1652
+ minCommentLines,
1653
+ unfoldUntilLines,
1654
+ unfoldLimitLines,
1624
1655
  });
1625
- return result;
1656
+ const usable = result.parsed && result.elided ? result : false;
1657
+ cache.set(cacheKey, usable);
1658
+ return usable || null;
1626
1659
  } catch {
1627
1660
  return null;
1628
1661
  }
@@ -583,9 +583,10 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
583
583
 
584
584
  /**
585
585
  * Resolve a single `conflict://<N>` write by splicing the recorded
586
- * marker region in the registered file with `replacementContent`,
587
- * then routing the new file content through the normal writethrough
588
- * pipeline so LSP format/diagnostics still run.
586
+ * marker region in the registered file with `replacementContent`.
587
+ * The write deliberately bypasses the LSP writethrough: the file may
588
+ * still hold other unresolved marker blocks, so formatting could
589
+ * corrupt them and diagnostics would be marker-noise anyway.
589
590
  *
590
591
  * Entry ids are session-stable: they keep working even after later
591
592
  * writes resolve other blocks in the same file. The recorded range
@@ -597,7 +598,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
597
598
  replacementContent: string,
598
599
  stripped: boolean,
599
600
  signal: AbortSignal | undefined,
600
- context: AgentToolContext | undefined,
601
601
  ): Promise<AgentToolResult<WriteToolDetails>> {
602
602
  const absolutePath = entry.absolutePath;
603
603
  if (!(await fs.exists(absolutePath))) {
@@ -608,8 +608,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
608
608
  const originalText = await Bun.file(absolutePath).text();
609
609
  const newContent = spliceConflict(originalText, entry, expanded);
610
610
 
611
- const batchRequest = getLspBatchRequest(context?.toolCall);
612
- const diagnostics = await this.#writethrough(absolutePath, newContent, signal, undefined, batchRequest);
611
+ await writethroughNoop(absolutePath, newContent, signal);
613
612
  invalidateFsScanAfterWrite(absolutePath);
614
613
  this.session.bumpFileMutationVersion?.(absolutePath);
615
614
  this.session.fileSnapshotStore?.invalidate(absolutePath);
@@ -643,21 +642,9 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
643
642
  resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
644
643
  }
645
644
 
646
- if (!diagnostics) {
647
- return {
648
- content: [{ type: "text", text: resultText }],
649
- details: { resolvedPath: absolutePath },
650
- };
651
- }
652
645
  return {
653
646
  content: [{ type: "text", text: resultText }],
654
- details: {
655
- resolvedPath: absolutePath,
656
- diagnostics,
657
- meta: outputMeta()
658
- .diagnostics(diagnostics.summary, diagnostics.messages ?? [])
659
- .get(),
660
- },
647
+ details: { resolvedPath: absolutePath },
661
648
  };
662
649
  }
663
650
 
@@ -670,7 +657,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
670
657
  replacementContent: string,
671
658
  stripped: boolean,
672
659
  signal: AbortSignal | undefined,
673
- context: AgentToolContext | undefined,
674
660
  ): Promise<AgentToolResult<WriteToolDetails>> {
675
661
  const entry = getConflictHistory(this.session).get(id);
676
662
  if (!entry) {
@@ -678,7 +664,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
678
664
  `Conflict #${id} not found. Conflict ids are registered when \`read\` surfaces a marker block; re-read the file to get a current id.`,
679
665
  );
680
666
  }
681
- return this.#resolveConflict(entry, replacementContent, stripped, signal, context);
667
+ return this.#resolveConflict(entry, replacementContent, stripped, signal);
682
668
  }
683
669
 
684
670
  /**
@@ -700,7 +686,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
700
686
  replacementContent: string,
701
687
  stripped: boolean,
702
688
  signal: AbortSignal | undefined,
703
- context: AgentToolContext | undefined,
704
689
  ): Promise<AgentToolResult<WriteToolDetails>> {
705
690
  const history = getConflictHistory(this.session);
706
691
  const allEntries = history.entries();
@@ -717,8 +702,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
717
702
  byFile.set(entry.absolutePath, bucket);
718
703
  }
719
704
 
720
- const batchRequest = getLspBatchRequest(context?.toolCall);
721
- const allDiagnostics: FileDiagnosticsResult[] = [];
722
705
  const succeededFiles: { displayPath: string; count: number; header?: string }[] = [];
723
706
  const failedFiles: { displayPath: string; count: number; error: string }[] = [];
724
707
  let totalResolvedIds = 0;
@@ -776,7 +759,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
776
759
  continue;
777
760
  }
778
761
 
779
- const diagnostics = await this.#writethrough(absolutePath, text, signal, undefined, batchRequest);
762
+ await writethroughNoop(absolutePath, text, signal);
780
763
  invalidateFsScanAfterWrite(absolutePath);
781
764
  this.session.bumpFileMutationVersion?.(absolutePath);
782
765
  this.session.fileSnapshotStore?.invalidate(absolutePath);
@@ -785,7 +768,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
785
768
  const header = maybeWriteSnapshotHeader(this.session, absolutePath, text);
786
769
  succeededFiles.push({ displayPath: sample.displayPath, count: resolvedEntries.length, header });
787
770
  totalResolvedIds += resolvedEntries.length;
788
- if (diagnostics) allDiagnostics.push(diagnostics);
789
771
  }
790
772
 
791
773
  const summaryLines: string[] = [];
@@ -819,23 +801,12 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
819
801
  }
820
802
  const resultText = summaryLines.join("\n");
821
803
 
822
- if (allDiagnostics.length === 0) {
823
- if (failedFiles.length > 0 && succeededFiles.length === 0) {
824
- throw new ToolError(resultText);
825
- }
826
- return {
827
- content: [{ type: "text", text: resultText }],
828
- details: {},
829
- isError: failedFiles.length > 0 ? true : undefined,
830
- };
804
+ if (failedFiles.length > 0 && succeededFiles.length === 0) {
805
+ throw new ToolError(resultText);
831
806
  }
832
- const mergedSummary = allDiagnostics.map(d => d.summary).join("\n");
833
- const mergedMessages = allDiagnostics.flatMap(d => d.messages ?? []);
834
807
  return {
835
808
  content: [{ type: "text", text: resultText }],
836
- details: {
837
- meta: outputMeta().diagnostics(mergedSummary, mergedMessages).get(),
838
- },
809
+ details: {},
839
810
  isError: failedFiles.length > 0 ? true : undefined,
840
811
  };
841
812
  }
@@ -885,8 +856,8 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
885
856
  }
886
857
  const result =
887
858
  conflictUri.id === "*"
888
- ? await this.#resolveAllConflicts(cleanContent, stripped, signal, context)
889
- : await this.#resolveSingleConflictById(conflictUri.id, cleanContent, stripped, signal, context);
859
+ ? await this.#resolveAllConflicts(cleanContent, stripped, signal)
860
+ : await this.#resolveSingleConflictById(conflictUri.id, cleanContent, stripped, signal);
890
861
  if (conflictUri.recoveredPrefix !== undefined) {
891
862
  appendNoteToResult(
892
863
  result,