token-goat 2.9.14 → 2.9.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 (46) hide show
  1. package/README.md +15 -1
  2. package/dist/{token-goat-chunk-2ESBO4IN.mjs → token-goat-chunk-2IEIBVVD.mjs} +16 -9
  3. package/dist/{token-goat-chunk-RUDOKYPJ.mjs → token-goat-chunk-2PCFAQAS.mjs} +6582 -6194
  4. package/dist/{token-goat-chunk-AMYCQJX4.mjs → token-goat-chunk-3H6FQT62.mjs} +49 -256
  5. package/dist/{token-goat-chunk-PRJVGIC5.mjs → token-goat-chunk-4DC6DDIB.mjs} +7 -5
  6. package/dist/token-goat-chunk-4EXFN2AW.mjs +29 -0
  7. package/dist/{token-goat-chunk-VZYD4OZB.mjs → token-goat-chunk-5USHO7B6.mjs} +416 -4168
  8. package/dist/token-goat-chunk-63QWJ6UM.mjs +277 -0
  9. package/dist/token-goat-chunk-BFNTLGVA.mjs +4547 -0
  10. package/dist/token-goat-chunk-BGHSSJUA.mjs +102 -0
  11. package/dist/{token-goat-chunk-T2IWWTHB.mjs → token-goat-chunk-DMQ32ZSR.mjs} +35 -1142
  12. package/dist/{token-goat-chunk-DBNY4RLN.mjs → token-goat-chunk-EJCY6KHO.mjs} +5 -3
  13. package/dist/token-goat-chunk-ERTXEKB6.mjs +228 -0
  14. package/dist/{token-goat-chunk-Z6UXPYJA.mjs → token-goat-chunk-F2ARFHLJ.mjs} +1 -1
  15. package/dist/{token-goat-chunk-EG3663UT.mjs → token-goat-chunk-GIMGT34T.mjs} +4 -2
  16. package/dist/{token-goat-chunk-XVZ4MNQC.mjs → token-goat-chunk-GMXBQS6O.mjs} +360 -116
  17. package/dist/{token-goat-chunk-SAQ5PG4L.mjs → token-goat-chunk-H3DXI6VD.mjs} +8 -4
  18. package/dist/token-goat-chunk-LJL6FGDS.mjs +35 -0
  19. package/dist/{token-goat-chunk-NEI4NC54.mjs → token-goat-chunk-LKSXAMJB.mjs} +7 -2
  20. package/dist/token-goat-chunk-LMFO66YD.mjs +331 -0
  21. package/dist/{token-goat-chunk-7OGKZ7AP.mjs → token-goat-chunk-M2R4UQ3B.mjs} +5 -3
  22. package/dist/{token-goat-chunk-YHGTGG6K.mjs → token-goat-chunk-MA5BZ2KI.mjs} +68 -7
  23. package/dist/{token-goat-chunk-ASVVF4JV.mjs → token-goat-chunk-MIL62GMN.mjs} +171 -23
  24. package/dist/{token-goat-chunk-ZFM4PWXL.mjs → token-goat-chunk-NAMH252H.mjs} +10 -7
  25. package/dist/{token-goat-chunk-YTQHZJXW.mjs → token-goat-chunk-NOBZV7PM.mjs} +96 -22
  26. package/dist/{token-goat-chunk-4SDX3QP3.mjs → token-goat-chunk-NQZCSVN2.mjs} +13 -5
  27. package/dist/{token-goat-chunk-XEH6KBWW.mjs → token-goat-chunk-OCI25AXY.mjs} +4 -3
  28. package/dist/token-goat-chunk-OSUFN2FV.mjs +326 -0
  29. package/dist/{token-goat-chunk-O5WAMISC.mjs → token-goat-chunk-QMZMHQRR.mjs} +29 -18
  30. package/dist/{token-goat-chunk-POBYR64E.mjs → token-goat-chunk-R3X5TCPB.mjs} +801 -3
  31. package/dist/token-goat-chunk-RRNZMM3A.mjs +3364 -0
  32. package/dist/{token-goat-chunk-PGGDW7DZ.mjs → token-goat-chunk-ULA4WCED.mjs} +9 -6
  33. package/dist/token-goat-chunk-UMXD2M7O.mjs +975 -0
  34. package/dist/{token-goat-chunk-3XQPEJMV.mjs → token-goat-chunk-UXHDBVUR.mjs} +1 -1
  35. package/dist/{token-goat-chunk-EZNVAIR3.mjs → token-goat-chunk-VVIYEFBI.mjs} +4 -3
  36. package/dist/token-goat-chunk-XOHTFRDH.mjs +10760 -0
  37. package/dist/{token-goat-chunk-HF6H7RNK.mjs → token-goat-chunk-YPS64ACE.mjs} +13 -3
  38. package/dist/{token-goat-chunk-DAMXYVIW.mjs → token-goat-chunk-Z5VPAXTC.mjs} +2560 -820
  39. package/dist/{token-goat-chunk-XQF5J25J.mjs → token-goat-chunk-ZEHFYJ7Z.mjs} +5 -4
  40. package/dist/token-goat-hook.mjs +15 -10
  41. package/dist/token-goat.core.mjs +24 -18
  42. package/docs/cli.md +8 -6
  43. package/package.json +1 -1
  44. package/dist/token-goat-chunk-IT6O3PNN.mjs +0 -15463
  45. package/dist/token-goat-chunk-ZD4EM4LR.mjs +0 -30
  46. package/dist/token-goat-chunk-ZYNNQ36L.mjs +0 -479
@@ -1,30 +0,0 @@
1
- import { createRequire as __cjsRequire } from 'node:module';
2
- const require = __cjsRequire(import.meta.url);
3
- import {
4
- buildEvent,
5
- relay,
6
- relayInProcess
7
- } from "./token-goat-chunk-XVZ4MNQC.mjs";
8
- import "./token-goat-chunk-3XQPEJMV.mjs";
9
- import {
10
- MAX_STDIN_BYTES,
11
- readStdinJson
12
- } from "./token-goat-chunk-ZYNNQ36L.mjs";
13
- import "./token-goat-chunk-IT6O3PNN.mjs";
14
- import "./token-goat-chunk-VZYD4OZB.mjs";
15
- import "./token-goat-chunk-3BTK54F3.mjs";
16
- import "./token-goat-chunk-Y4AFKTHK.mjs";
17
- import "./token-goat-chunk-T2IWWTHB.mjs";
18
- import "./token-goat-chunk-SAQ5PG4L.mjs";
19
- import "./token-goat-chunk-EEIDFMEM.mjs";
20
- import "./token-goat-chunk-POBYR64E.mjs";
21
- import "./token-goat-chunk-AMYCQJX4.mjs";
22
- import "./token-goat-chunk-GMOUBOX4.mjs";
23
- import "./token-goat-chunk-A37V4PBF.mjs";
24
- export {
25
- MAX_STDIN_BYTES,
26
- buildEvent,
27
- readStdinJson,
28
- relay,
29
- relayInProcess
30
- };
@@ -1,479 +0,0 @@
1
- import { createRequire as __cjsRequire } from 'node:module';
2
- const require = __cjsRequire(import.meta.url);
3
- import {
4
- PARSER_FINGERPRINT,
5
- enqueueDirtyPathSafe,
6
- getTrackedFiles
7
- } from "./token-goat-chunk-IT6O3PNN.mjs";
8
- import {
9
- getProjectFileEntries,
10
- indexRecallEntry
11
- } from "./token-goat-chunk-VZYD4OZB.mjs";
12
- import {
13
- getDb,
14
- isBlobStale,
15
- loadBlob,
16
- redactSecrets,
17
- storeBlob
18
- } from "./token-goat-chunk-T2IWWTHB.mjs";
19
- import {
20
- fingerprintFile,
21
- getDisplayRoot,
22
- shortFingerprint
23
- } from "./token-goat-chunk-SAQ5PG4L.mjs";
24
- import {
25
- registerReset
26
- } from "./token-goat-chunk-EEIDFMEM.mjs";
27
- import {
28
- SYMBOL_BODY_CHAR_CAP,
29
- countNoun,
30
- displaySafeJson,
31
- extractErrorMessage,
32
- foldPath,
33
- globalDbPath,
34
- normalizePath,
35
- resolveIndexPath,
36
- toDisplayPath
37
- } from "./token-goat-chunk-AMYCQJX4.mjs";
38
- import {
39
- compileGuardedRegex
40
- } from "./token-goat-chunk-GMOUBOX4.mjs";
41
- import {
42
- init_define_import_meta_env
43
- } from "./token-goat-chunk-A37V4PBF.mjs";
44
-
45
- // src/web_cache.ts
46
- init_define_import_meta_env();
47
- var WEB_OUTPUT_SUBDIR = "web_outputs";
48
- var _byId = /* @__PURE__ */ new Map();
49
- var _rawById = /* @__PURE__ */ new Map();
50
- var _urlIndex = /* @__PURE__ */ new Map();
51
- function cacheIdForUrl(url) {
52
- return shortFingerprint(url);
53
- }
54
- function storeWebOutput(url, content, dedupKey = url, rawContent) {
55
- const cacheId = cacheIdForUrl(dedupKey);
56
- const redactedContent = redactSecrets(content).text;
57
- _byId.set(cacheId, redactedContent);
58
- _urlIndex.set(url, cacheId);
59
- const redactedRaw = rawContent !== void 0 && rawContent !== content ? redactSecrets(rawContent).text : void 0;
60
- if (redactedRaw !== void 0) _rawById.set(cacheId, redactedRaw);
61
- else _rawById.delete(cacheId);
62
- storeBlob(WEB_OUTPUT_SUBDIR, cacheId, redactedRaw !== void 0 ? { url, content: redactedContent, raw: redactedRaw } : { url, content: redactedContent });
63
- const redactedUrl = redactSecrets(url).text;
64
- indexRecallEntry("web", cacheId, redactedUrl, `${redactedUrl}
65
- ${redactedContent}`, Date.now());
66
- return cacheId;
67
- }
68
- function coerceWebBlob(raw) {
69
- if (raw === null || typeof raw !== "object") return null;
70
- const o = raw;
71
- if (typeof o["content"] !== "string") return null;
72
- return { url: typeof o["url"] === "string" ? o["url"] : null, content: o["content"], raw: typeof o["raw"] === "string" ? o["raw"] : null };
73
- }
74
- function getWebOutput(cacheId) {
75
- const hit = _byId.get(cacheId);
76
- if (hit !== void 0) return hit;
77
- if (isBlobStale(WEB_OUTPUT_SUBDIR, cacheId)) return null;
78
- const blob = coerceWebBlob(loadBlob(WEB_OUTPUT_SUBDIR, cacheId));
79
- if (blob === null) return null;
80
- _byId.set(cacheId, blob.content);
81
- if (blob.raw !== null) _rawById.set(cacheId, blob.raw);
82
- if (blob.url !== null) _urlIndex.set(blob.url, cacheId);
83
- return blob.content;
84
- }
85
- function getWebOutputRaw(cacheId) {
86
- const cleaned = getWebOutput(cacheId);
87
- if (cleaned === null) return null;
88
- return _rawById.get(cacheId) ?? cleaned;
89
- }
90
- function getWebOutputByUrlFromDisk(url, dedupKey = url) {
91
- const cacheId = cacheIdForUrl(dedupKey);
92
- const content = getWebOutput(cacheId);
93
- if (content === null) return null;
94
- return { cacheId, content };
95
- }
96
- registerReset(() => {
97
- _byId = /* @__PURE__ */ new Map();
98
- _rawById = /* @__PURE__ */ new Map();
99
- _urlIndex = /* @__PURE__ */ new Map();
100
- });
101
-
102
- // src/stdin_json.ts
103
- init_define_import_meta_env();
104
- var DEFAULT_STDIN_TIMEOUT_MS = 5e3;
105
- var MAX_STDIN_WALL_MS = 6e4;
106
- var MAX_STDIN_BYTES = 64 * 1024 * 1024;
107
- function readStdinJson(timeoutMs = DEFAULT_STDIN_TIMEOUT_MS, maxBytes = MAX_STDIN_BYTES) {
108
- return new Promise((resolve, reject) => {
109
- const chunks = [];
110
- let totalBytes = 0;
111
- let settled = false;
112
- const finish = (fn) => {
113
- if (settled) return;
114
- settled = true;
115
- clearTimeout(idleTimer);
116
- clearTimeout(wallTimer);
117
- process.stdin.removeListener("data", onData);
118
- process.stdin.removeListener("end", onEnd);
119
- process.stdin.removeListener("error", onError);
120
- fn();
121
- };
122
- let idleTimer = setTimeout(() => {
123
- finish(() => reject(new Error("readStdinJson: timed out waiting for stdin")));
124
- }, timeoutMs);
125
- const wallTimer = setTimeout(() => {
126
- finish(() => {
127
- process.stdin.destroy();
128
- reject(new Error(`readStdinJson: stdin took longer than ${MAX_STDIN_WALL_MS} ms`));
129
- });
130
- }, MAX_STDIN_WALL_MS);
131
- const onData = (chunk) => {
132
- clearTimeout(idleTimer);
133
- idleTimer = setTimeout(() => {
134
- finish(() => reject(new Error("readStdinJson: timed out waiting for stdin")));
135
- }, timeoutMs);
136
- totalBytes += chunk.length;
137
- if (totalBytes > maxBytes) {
138
- finish(() => {
139
- process.stdin.destroy();
140
- reject(new Error(`readStdinJson: stdin exceeded ${maxBytes} bytes`));
141
- });
142
- return;
143
- }
144
- chunks.push(chunk);
145
- };
146
- const onEnd = () => {
147
- finish(() => {
148
- const text = Buffer.concat(chunks).toString("utf8").trim();
149
- if (text === "") {
150
- reject(new Error("readStdinJson: empty stdin"));
151
- return;
152
- }
153
- try {
154
- resolve(JSON.parse(text));
155
- } catch (err) {
156
- reject(err instanceof Error ? err : new Error(String(err)));
157
- }
158
- });
159
- };
160
- const onError = (err) => {
161
- finish(() => reject(err instanceof Error ? err : new Error(String(err))));
162
- };
163
- process.stdin.on("data", onData);
164
- process.stdin.on("end", onEnd);
165
- process.stdin.on("error", onError);
166
- });
167
- }
168
-
169
- // src/types.ts
170
- init_define_import_meta_env();
171
- var HOOK_EVENTS = [
172
- "pre_tool_use",
173
- "post_tool_use",
174
- "notification",
175
- "stop",
176
- "pre_compact",
177
- "post_compact",
178
- "user_prompt_submit",
179
- "subagent_stop",
180
- "session_start",
181
- "post_tool_use_failure"
182
- ];
183
-
184
- // src/cli_commands.ts
185
- init_define_import_meta_env();
186
- function toEntry(cmd) {
187
- return {
188
- name: cmd.name(),
189
- description: cmd.description(),
190
- aliases: cmd.aliases(),
191
- options: cmd.options.map((o) => ({ flags: o.flags, description: o.description })),
192
- arguments: cmd.registeredArguments.map((a) => ({ name: a.name(), description: a.description, required: a.required })),
193
- subcommands: cmd.commands.filter((sub) => sub.name() !== "help").map(toEntry)
194
- };
195
- }
196
- function buildCommandManifest(program) {
197
- return program.commands.filter((cmd) => cmd.name() !== "help").map(toEntry);
198
- }
199
- function flattenCommandNames(manifest) {
200
- const names = [];
201
- for (const entry of manifest) {
202
- names.push(entry.name);
203
- for (const sub of entry.subcommands) {
204
- names.push(`${entry.name} ${sub.name}`);
205
- }
206
- }
207
- return names;
208
- }
209
- function entryMatches(entry, re, pattern) {
210
- const haystacks = [entry.name, entry.description, ...entry.aliases];
211
- return haystacks.some((h) => re !== null ? re.test(h) : h.includes(pattern));
212
- }
213
- function filterCommandManifest(manifest, pattern) {
214
- const guarded = compileGuardedRegex(pattern);
215
- const re = guarded.ok ? guarded.re : null;
216
- const result = [];
217
- for (const entry of manifest) {
218
- if (entryMatches(entry, re, pattern)) {
219
- result.push(entry);
220
- continue;
221
- }
222
- const matchingSubs = entry.subcommands.filter((sub) => entryMatches(sub, re, pattern));
223
- if (matchingSubs.length > 0) {
224
- result.push({ ...entry, subcommands: matchingSubs });
225
- }
226
- }
227
- return result;
228
- }
229
- function formatCommandManifest(manifest) {
230
- const lines = [];
231
- lines.push("# token-goat commands");
232
- lines.push("");
233
- for (const entry of manifest) {
234
- lines.push(`## ${entry.name}${entry.aliases.length ? " (alias: " + entry.aliases.join(", ") + ")" : ""}${entry.description ? " -- " + entry.description : ""}`);
235
- for (const arg of entry.arguments) {
236
- lines.push(` arg: ${arg.name}${arg.required ? "" : " (optional)"}${arg.description ? " -- " + arg.description : ""}`);
237
- }
238
- for (const opt of entry.options) {
239
- lines.push(` ${opt.flags}${opt.description ? " -- " + opt.description : ""}`);
240
- }
241
- for (const sub of entry.subcommands) {
242
- lines.push(` ${entry.name} ${sub.name}${sub.description ? " -- " + sub.description : ""}`);
243
- }
244
- lines.push("");
245
- }
246
- return lines.join("\n").trimEnd();
247
- }
248
-
249
- // src/symbol_body_probe.ts
250
- init_define_import_meta_env();
251
- import * as fs from "fs";
252
- var OVERSIZED_BODY_PROBE_SQL = `SELECT 1 FROM symbols WHERE LENGTH(body) > ${SYMBOL_BODY_CHAR_CAP} LIMIT 1`;
253
- function checkSymbolBodySize(dbPath) {
254
- if (!fs.existsSync(dbPath)) {
255
- return { name: "Symbol body size", status: "ok", message: "no database yet" };
256
- }
257
- try {
258
- const db = getDb(dbPath);
259
- const row = db.prepare(OVERSIZED_BODY_PROBE_SQL).get();
260
- if (row !== void 0) {
261
- return {
262
- name: "Symbol body size",
263
- status: "warn",
264
- message: `one or more stored symbol bodies exceed the ${SYMBOL_BODY_CHAR_CAP}-char cap enforced by boundSymbolBody -- likely a pre-fix leftover from a minified/generated file. A plain 'token-goat reclaim-index' (VACUUM only) CANNOT remove these rows -- it only reclaims freed pages, it never deletes row content. Only 'token-goat reclaim-index --rebuild' drops and re-derives them under the cap (stop the worker first with 'token-goat worker stop', since reclaim-index refuses to run while it's live); --rebuild reparses and re-embeds every indexed file across every project and can take a long time on a large multi-project index`
265
- };
266
- }
267
- return { name: "Symbol body size", status: "ok", message: "no stored symbol body exceeds the cap" };
268
- } catch (err) {
269
- return {
270
- name: "Symbol body size",
271
- status: "warn",
272
- message: `could not query symbol body size: ${extractErrorMessage(err)}`
273
- };
274
- }
275
- }
276
-
277
- // src/reconcile.ts
278
- init_define_import_meta_env();
279
- import * as fs2 from "node:fs";
280
- var DEFAULT_RECONCILE_BUDGET_MS = 1500;
281
- function readReconcileCursor(dbPath, root) {
282
- try {
283
- const row = getDb(dbPath).prepare("SELECT last_scanned_path FROM reconcile_cursor WHERE root = ?").get(root);
284
- return row?.last_scanned_path ?? null;
285
- } catch {
286
- return null;
287
- }
288
- }
289
- function writeReconcileCursor(dbPath, root, lastScannedPath) {
290
- try {
291
- getDb(dbPath).prepare(
292
- "INSERT INTO reconcile_cursor (root, last_scanned_path, updated_at) VALUES (?, ?, ?) ON CONFLICT(root) DO UPDATE SET last_scanned_path = excluded.last_scanned_path, updated_at = excluded.updated_at"
293
- ).run(root, lastScannedPath, Date.now());
294
- } catch {
295
- }
296
- }
297
- function clearReconcileCursor(dbPath, root) {
298
- try {
299
- getDb(dbPath).prepare("DELETE FROM reconcile_cursor WHERE root = ?").run(root);
300
- } catch {
301
- }
302
- }
303
- function runReconcile(opts = {}) {
304
- const raw = reconcileProject(opts);
305
- const root = getDisplayRoot(opts.cwd ?? process.cwd());
306
- const display = (paths) => paths.map((p) => toDisplayPath(root, p)).sort();
307
- const result = {
308
- ...raw,
309
- changed: display(raw.changed),
310
- added: display(raw.added),
311
- removed: display(raw.removed)
312
- };
313
- if (opts.json === true) {
314
- process.stdout.write(`${displaySafeJson(result)}
315
- `);
316
- return 0;
317
- }
318
- const lines = [];
319
- if (isReconcileClean(result)) {
320
- if (!result.trackedUnavailable) {
321
- lines.push(`Index matches disk: ${countNoun(result.scanned, "file")} checked in ${result.elapsedMs}ms.`);
322
- }
323
- } else {
324
- const verb = opts.dryRun === true ? "would reindex" : "queued for reindexing";
325
- const dropVerb = opts.dryRun === true ? "would drop from the index" : "queued for removal";
326
- if (result.changed.length > 0) lines.push(`${countNoun(result.changed.length, "file")} changed since indexing (${verb}):`);
327
- for (const f of result.changed) lines.push(` ~ ${f}`);
328
- if (result.added.length > 0) lines.push(`${countNoun(result.added.length, "file")} not in the index (${verb}):`);
329
- for (const f of result.added) lines.push(` + ${f}`);
330
- if (result.removed.length > 0) lines.push(`${countNoun(result.removed.length, "file")} indexed but gone from disk (${dropVerb}):`);
331
- for (const f of result.removed) lines.push(` - ${f}`);
332
- lines.push(`Checked ${countNoun(result.scanned, "file")} in ${result.elapsedMs}ms.`);
333
- }
334
- if (result.mtimeOnly > 0) {
335
- lines.push(`${countNoun(result.mtimeOnly, "file")} had a newer timestamp but identical content, so ${result.mtimeOnly === 1 ? "it was" : "they were"} left alone.`);
336
- }
337
- if (result.parserStale > 0) {
338
- const reparseVerb = opts.dryRun === true ? "would reparse" : "queued for reparse";
339
- lines.push(`${countNoun(result.parserStale, "file")} of the above ${result.parserStale === 1 ? "was" : "were"} unchanged on disk but indexed by an older parser (${reparseVerb}).`);
340
- }
341
- if (result.trackedUnavailable) {
342
- lines.push("This project has an index but git listed no files in it, so nothing could be compared and no deletions were computed. Run token-goat inside the repository, or reindex with --walk if this directory is deliberately not under git.");
343
- }
344
- if (result.budgetExhausted) {
345
- lines.push(`Stopped at the ${result.elapsedMs}ms budget with ${countNoun(result.unscanned, "file")} unchecked, so there may be more drift; deletions were not computed at all, because an unchecked file is indistinguishable from a deleted one. Raise --budget-ms for a complete sweep.`);
346
- }
347
- process.stdout.write(`${lines.join("\n")}
348
- `);
349
- return 0;
350
- }
351
- function isReconcileClean(r) {
352
- return r.changed.length === 0 && r.added.length === 0 && r.removed.length === 0;
353
- }
354
- function reconcileProject(opts = {}) {
355
- const cwd = opts.cwd ?? process.cwd();
356
- const budgetMs = opts.budgetMs ?? DEFAULT_RECONCILE_BUDGET_MS;
357
- const startedAt = Date.now();
358
- const dbPath = opts.dbPath ?? globalDbPath();
359
- const tracked = getTrackedFiles(cwd);
360
- const projectRoot = resolveIndexPath(".", cwd);
361
- const indexed = getProjectFileEntries(projectRoot, dbPath);
362
- let scanOrder = tracked;
363
- const cursorPath = tracked.length > 0 ? readReconcileCursor(dbPath, projectRoot) : null;
364
- if (cursorPath !== null) {
365
- const cursorFolded = foldPath(normalizePath(cursorPath));
366
- const cursorIdx = tracked.findIndex((f) => foldPath(normalizePath(f)) === cursorFolded);
367
- if (cursorIdx !== -1) {
368
- scanOrder = [...tracked.slice(cursorIdx + 1), ...tracked.slice(0, cursorIdx + 1)];
369
- }
370
- }
371
- const changed = [];
372
- const added = [];
373
- const seenOnDisk = /* @__PURE__ */ new Set();
374
- let mtimeOnly = 0;
375
- let parserStale = 0;
376
- let scanned = 0;
377
- let budgetExhausted = false;
378
- let lastScanned = null;
379
- for (const file of scanOrder) {
380
- if (Date.now() - startedAt > budgetMs) {
381
- budgetExhausted = true;
382
- break;
383
- }
384
- scanned++;
385
- lastScanned = file;
386
- const folded = foldPath(normalizePath(file));
387
- seenOnDisk.add(folded);
388
- const entry = indexed.get(folded);
389
- if (entry === void 0) {
390
- added.push(file);
391
- continue;
392
- }
393
- if (entry.parserSha !== PARSER_FINGERPRINT) {
394
- changed.push(file);
395
- parserStale++;
396
- continue;
397
- }
398
- let mtimeMs;
399
- try {
400
- mtimeMs = fs2.statSync(file).mtimeMs;
401
- } catch {
402
- changed.push(file);
403
- continue;
404
- }
405
- if (entry.mtime !== 0 && mtimeMs === entry.mtime) continue;
406
- const diskSha = fingerprintFile(file);
407
- if (diskSha === null) {
408
- changed.push(file);
409
- continue;
410
- }
411
- if (diskSha === entry.sha) {
412
- mtimeOnly++;
413
- continue;
414
- }
415
- changed.push(file);
416
- }
417
- const trackedUnavailable = tracked.length === 0 && indexed.size > 0;
418
- const removed = [];
419
- if (!budgetExhausted && !trackedUnavailable) {
420
- for (const [folded, entry] of indexed) {
421
- if (seenOnDisk.has(folded)) continue;
422
- if (Date.now() - startedAt > budgetMs) {
423
- budgetExhausted = true;
424
- removed.length = 0;
425
- break;
426
- }
427
- try {
428
- fs2.statSync(entry.filePath);
429
- } catch {
430
- removed.push(entry.filePath);
431
- }
432
- }
433
- }
434
- let enqueued = 0;
435
- if (opts.dryRun !== true) {
436
- for (const p of [...changed, ...added, ...removed]) {
437
- enqueueDirtyPathSafe(resolveIndexPath(p, cwd), { alreadyResolved: true });
438
- enqueued++;
439
- }
440
- if (budgetExhausted) {
441
- if (lastScanned !== null) writeReconcileCursor(dbPath, projectRoot, lastScanned);
442
- } else if (tracked.length > 0) {
443
- clearReconcileCursor(dbPath, projectRoot);
444
- }
445
- }
446
- return {
447
- scanned,
448
- changed,
449
- added,
450
- removed,
451
- mtimeOnly,
452
- parserStale,
453
- budgetExhausted,
454
- trackedUnavailable,
455
- unscanned: Math.max(0, tracked.length - scanned),
456
- enqueued,
457
- elapsedMs: Date.now() - startedAt
458
- };
459
- }
460
-
461
- export {
462
- checkSymbolBodySize,
463
- WEB_OUTPUT_SUBDIR,
464
- storeWebOutput,
465
- getWebOutput,
466
- getWebOutputRaw,
467
- getWebOutputByUrlFromDisk,
468
- DEFAULT_RECONCILE_BUDGET_MS,
469
- runReconcile,
470
- isReconcileClean,
471
- reconcileProject,
472
- MAX_STDIN_BYTES,
473
- readStdinJson,
474
- HOOK_EVENTS,
475
- buildCommandManifest,
476
- flattenCommandNames,
477
- filterCommandManifest,
478
- formatCommandManifest
479
- };