@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.
- package/CHANGELOG.md +63 -1
- package/dist/cli.js +8106 -7708
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/collab/crypto.d.ts +7 -0
- package/dist/types/collab/guest.d.ts +23 -0
- package/dist/types/collab/host.d.ts +29 -0
- package/dist/types/collab/protocol.d.ts +113 -0
- package/dist/types/collab/relay-client.d.ts +22 -0
- package/dist/types/commands/join.d.ts +12 -0
- package/dist/types/config/settings-schema.d.ts +60 -5
- package/dist/types/export/custom-share.d.ts +1 -2
- package/dist/types/export/html/index.d.ts +39 -1
- package/dist/types/export/share.d.ts +43 -0
- package/dist/types/extensibility/slash-commands.d.ts +1 -11
- package/dist/types/main.d.ts +2 -0
- package/dist/types/modes/components/agent-hub.d.ts +32 -1
- package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
- package/dist/types/modes/components/hook-selector.d.ts +4 -6
- package/dist/types/modes/components/segment-track.d.ts +11 -6
- package/dist/types/modes/components/status-line/component.d.ts +10 -2
- package/dist/types/modes/components/status-line/types.d.ts +11 -0
- package/dist/types/modes/controllers/event-controller.d.ts +7 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -1
- package/dist/types/modes/controllers/session-focus-controller.d.ts +31 -0
- package/dist/types/modes/interactive-mode.d.ts +16 -0
- package/dist/types/modes/session-observer-registry.d.ts +7 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/types.d.ts +20 -0
- package/dist/types/session/agent-session.d.ts +13 -0
- package/dist/types/session/codex-auto-reset.d.ts +8 -4
- package/dist/types/session/session-manager.d.ts +21 -0
- package/dist/types/session/snapcompact-inline.d.ts +6 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +9 -0
- package/dist/types/task/executor.d.ts +7 -0
- package/dist/types/task/types.d.ts +9 -0
- package/package.json +14 -13
- package/scripts/bench-guard.ts +71 -0
- package/scripts/build-binary.ts +4 -0
- package/scripts/bundle-dist.ts +4 -0
- package/scripts/generate-share-viewer.ts +34 -0
- package/src/cli/args.ts +2 -0
- package/src/cli-commands.ts +1 -0
- package/src/collab/crypto.ts +63 -0
- package/src/collab/guest.ts +450 -0
- package/src/collab/host.ts +556 -0
- package/src/collab/protocol.ts +232 -0
- package/src/collab/relay-client.ts +216 -0
- package/src/commands/join.ts +39 -0
- package/src/config/model-registry.ts +22 -14
- package/src/config/settings-schema.ts +67 -5
- package/src/config/settings.ts +12 -0
- package/src/export/custom-share.ts +1 -1
- package/src/export/html/index.ts +122 -17
- package/src/export/html/share-loader.js +102 -0
- package/src/export/html/template.css +745 -459
- package/src/export/html/template.html +6 -3
- package/src/export/html/template.js +240 -915
- package/src/export/html/tool-views.generated.js +38 -0
- package/src/export/share.ts +268 -0
- package/src/extensibility/slash-commands.ts +1 -97
- package/src/internal-urls/docs-index.generated.ts +74 -73
- package/src/main.ts +33 -11
- package/src/modes/components/agent-hub.ts +659 -431
- package/src/modes/components/assistant-message.ts +126 -6
- package/src/modes/components/collab-prompt-message.ts +30 -0
- package/src/modes/components/hook-selector.ts +4 -5
- package/src/modes/components/segment-track.ts +44 -7
- package/src/modes/components/status-line/component.ts +59 -6
- package/src/modes/components/status-line/presets.ts +1 -1
- package/src/modes/components/status-line/segments.ts +18 -1
- package/src/modes/components/status-line/types.ts +12 -0
- package/src/modes/components/tips.txt +4 -1
- package/src/modes/controllers/command-controller.ts +55 -96
- package/src/modes/controllers/event-controller.ts +45 -16
- package/src/modes/controllers/input-controller.ts +175 -9
- package/src/modes/controllers/selector-controller.ts +13 -15
- package/src/modes/controllers/session-focus-controller.ts +112 -0
- package/src/modes/controllers/streaming-reveal.ts +7 -0
- package/src/modes/interactive-mode.ts +56 -6
- package/src/modes/session-observer-registry.ts +11 -0
- package/src/modes/theme/theme.ts +6 -0
- package/src/modes/types.ts +20 -0
- package/src/modes/utils/ui-helpers.ts +23 -13
- package/src/prompts/tools/job.md +1 -1
- package/src/sdk.ts +239 -36
- package/src/session/agent-session.ts +82 -7
- package/src/session/codex-auto-reset.ts +23 -11
- package/src/session/session-manager.ts +44 -0
- package/src/session/snapcompact-inline.ts +9 -3
- package/src/slash-commands/builtin-registry.ts +261 -24
- package/src/task/executor.ts +14 -0
- package/src/task/index.ts +5 -1
- package/src/task/render.ts +76 -5
- package/src/task/types.ts +9 -0
- package/src/tiny/worker.ts +17 -95
- package/src/tools/job.ts +6 -9
- package/src/tools/read.ts +38 -5
- package/src/tools/write.ts +13 -42
- package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
- package/dist/types/export/html/template.generated.d.ts +0 -1
- package/dist/types/export/html/template.macro.d.ts +0 -5
- package/dist/types/tiny/compiled-runtime.d.ts +0 -35
- package/scripts/generate-template.ts +0 -33
- package/src/bun-imports.d.ts +0 -28
- package/src/export/html/template.generated.ts +0 -2
- package/src/export/html/template.macro.ts +0 -25
- package/src/tiny/compiled-runtime.ts +0 -179
package/src/tiny/worker.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
|
1621
|
-
minCommentLines
|
|
1622
|
-
unfoldUntilLines
|
|
1623
|
-
unfoldLimitLines
|
|
1651
|
+
minBodyLines,
|
|
1652
|
+
minCommentLines,
|
|
1653
|
+
unfoldUntilLines,
|
|
1654
|
+
unfoldLimitLines,
|
|
1624
1655
|
});
|
|
1625
|
-
|
|
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
|
}
|
package/src/tools/write.ts
CHANGED
|
@@ -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
|
-
*
|
|
588
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
823
|
-
|
|
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
|
|
889
|
-
: await this.#resolveSingleConflictById(conflictUri.id, cleanContent, stripped, signal
|
|
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,
|
|
Binary file
|