@cesarandreslopez/occ 0.8.10 → 0.8.11

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 (72) hide show
  1. package/README.md +4 -3
  2. package/dist/src/code/build.d.ts +49 -1
  3. package/dist/src/code/build.js +127 -33
  4. package/dist/src/code/build.js.map +1 -1
  5. package/dist/src/code/chunk.d.ts +10 -0
  6. package/dist/src/code/chunk.js +14 -1
  7. package/dist/src/code/chunk.js.map +1 -1
  8. package/dist/src/code/discover.d.ts +13 -0
  9. package/dist/src/code/discover.js +49 -2
  10. package/dist/src/code/discover.js.map +1 -1
  11. package/dist/src/code/incremental.d.ts +75 -0
  12. package/dist/src/code/incremental.js +257 -0
  13. package/dist/src/code/incremental.js.map +1 -0
  14. package/dist/src/code/map.d.ts +8 -1
  15. package/dist/src/code/map.js +13 -3
  16. package/dist/src/code/map.js.map +1 -1
  17. package/dist/src/code/parsers.d.ts +1 -0
  18. package/dist/src/code/parsers.js +1 -1
  19. package/dist/src/code/parsers.js.map +1 -1
  20. package/dist/src/code/rank.d.ts +14 -0
  21. package/dist/src/code/rank.js +58 -0
  22. package/dist/src/code/rank.js.map +1 -1
  23. package/dist/src/code/store.d.ts +20 -0
  24. package/dist/src/code/store.js +262 -109
  25. package/dist/src/code/store.js.map +1 -1
  26. package/dist/src/doc/chunk.d.ts +17 -0
  27. package/dist/src/doc/chunk.js +47 -18
  28. package/dist/src/doc/chunk.js.map +1 -1
  29. package/dist/src/doc/inspect-docx.js +13 -3
  30. package/dist/src/doc/inspect-docx.js.map +1 -1
  31. package/dist/src/doc/inspect-pdf.js +12 -17
  32. package/dist/src/doc/inspect-pdf.js.map +1 -1
  33. package/dist/src/index.d.ts +12 -7
  34. package/dist/src/index.js +9 -5
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/inspect/xlsx-cells.d.ts +8 -0
  37. package/dist/src/inspect/xlsx-cells.js +17 -2
  38. package/dist/src/inspect/xlsx-cells.js.map +1 -1
  39. package/dist/src/markdown/convert.js +45 -27
  40. package/dist/src/markdown/convert.js.map +1 -1
  41. package/dist/src/parsers/docx.js +10 -2
  42. package/dist/src/parsers/docx.js.map +1 -1
  43. package/dist/src/parsers/index.js +5 -0
  44. package/dist/src/parsers/index.js.map +1 -1
  45. package/dist/src/parsers/pdf.js +12 -32
  46. package/dist/src/parsers/pdf.js.map +1 -1
  47. package/dist/src/parsers/xlsx.js +11 -1
  48. package/dist/src/parsers/xlsx.js.map +1 -1
  49. package/dist/src/progress-event.d.ts +3 -1
  50. package/dist/src/progress-event.js +31 -1
  51. package/dist/src/progress-event.js.map +1 -1
  52. package/dist/src/sheet/inspect.js +20 -10
  53. package/dist/src/sheet/inspect.js.map +1 -1
  54. package/dist/src/table/inspect-docx.js +10 -1
  55. package/dist/src/table/inspect-docx.js.map +1 -1
  56. package/dist/src/table/inspect-xlsx.js +15 -5
  57. package/dist/src/table/inspect-xlsx.js.map +1 -1
  58. package/dist/src/utils.d.ts +24 -0
  59. package/dist/src/utils.js +91 -2
  60. package/dist/src/utils.js.map +1 -1
  61. package/dist/src/workspace/bundle.d.ts +24 -0
  62. package/dist/src/workspace/bundle.js +303 -97
  63. package/dist/src/workspace/bundle.js.map +1 -1
  64. package/dist/src/workspace/documents.d.ts +4 -0
  65. package/dist/src/workspace/documents.js +15 -2
  66. package/dist/src/workspace/documents.js.map +1 -1
  67. package/dist/src/workspace/prepare-types.d.ts +15 -0
  68. package/dist/src/workspace/prepare-types.js +18 -1
  69. package/dist/src/workspace/prepare-types.js.map +1 -1
  70. package/dist/src/workspace/prepare.js +10 -2
  71. package/dist/src/workspace/prepare.js.map +1 -1
  72. package/package.json +9 -2
@@ -82,5 +82,19 @@ export type RankResult = z.infer<typeof RankResultSchema>;
82
82
  * skipped because their importance cannot be attributed.
83
83
  */
84
84
  export declare function rankNodes(index: CodebaseIndex, options?: RankOptions): RankResult;
85
+ /**
86
+ * Memoized `rankNodes`. Repeated rankings of the same index object (e.g.
87
+ * per-focused-map calls) skip PageRank entirely; up to
88
+ * `RANK_CACHE_MAX_VARIANTS` option variants are retained per index, evicting
89
+ * the oldest. The returned `RankResult` is shared between callers — treat it
90
+ * as immutable. `rankNodes` itself stays pure and uncached.
91
+ *
92
+ * The index should be treated as immutable after construction. The cache key
93
+ * carries only a `files`/`nodes`/`edges` length fingerprint, so in-place
94
+ * mutations that change those lengths recompute, but mutations that keep them
95
+ * constant (e.g. rewriting a node's name in place) are NOT detected and will
96
+ * return a stale ranking.
97
+ */
98
+ export declare function rankNodesCached(index: CodebaseIndex, options?: RankOptions): RankResult;
85
99
  export declare function topRankedFiles(result: RankResult, limit: number): RankedFile[];
86
100
  export declare function topRankedSymbols(result: RankResult, limit: number): RankedNode[];
@@ -199,6 +199,64 @@ export function rankNodes(index, options = {}) {
199
199
  .sort((a, b) => b.score - a.score);
200
200
  return { nodes: rankedNodes, fileScores, iterations, converged };
201
201
  }
202
+ const RANK_CACHE_MAX_VARIANTS = 8;
203
+ // Per-index ranking memo. The WeakMap keys on the CodebaseIndex object itself,
204
+ // so building a new index naturally invalidates every cached ranking for the
205
+ // old one. Each index keeps a small insertion-order LRU of option variants.
206
+ const rankCache = new WeakMap();
207
+ /**
208
+ * Cache key for a RankOptions variant on a given index. The key is prefixed
209
+ * with a cheap content fingerprint (`files`/`nodes`/`edges` lengths) so the
210
+ * common in-place mutations — pushing files, nodes, or edges onto a cached
211
+ * index — invalidate stale rankings at zero cost. Defaults are applied in a
212
+ * fixed key order (mirroring `rankNodes`), so `{}` and explicitly-passed
213
+ * defaults share one cache entry.
214
+ */
215
+ function rankCacheKey(index, options) {
216
+ const weights = { ...DEFAULT_WEIGHTS, ...options.edgeWeights };
217
+ return `${index.files.length}:${index.nodes.length}:${index.edges.length}:` + JSON.stringify({
218
+ damping: options.damping ?? DEFAULT_DAMPING,
219
+ maxIterations: options.maxIterations ?? DEFAULT_MAX_ITERATIONS,
220
+ epsilon: options.epsilon ?? DEFAULT_EPSILON,
221
+ imports: weights.imports,
222
+ calls: weights.calls,
223
+ inherits: weights.inherits,
224
+ biasExports: options.biasExports ?? true,
225
+ includeExternal: options.includeExternal ?? false,
226
+ });
227
+ }
228
+ /**
229
+ * Memoized `rankNodes`. Repeated rankings of the same index object (e.g.
230
+ * per-focused-map calls) skip PageRank entirely; up to
231
+ * `RANK_CACHE_MAX_VARIANTS` option variants are retained per index, evicting
232
+ * the oldest. The returned `RankResult` is shared between callers — treat it
233
+ * as immutable. `rankNodes` itself stays pure and uncached.
234
+ *
235
+ * The index should be treated as immutable after construction. The cache key
236
+ * carries only a `files`/`nodes`/`edges` length fingerprint, so in-place
237
+ * mutations that change those lengths recompute, but mutations that keep them
238
+ * constant (e.g. rewriting a node's name in place) are NOT detected and will
239
+ * return a stale ranking.
240
+ */
241
+ export function rankNodesCached(index, options = {}) {
242
+ let variants = rankCache.get(index);
243
+ if (!variants) {
244
+ variants = new Map();
245
+ rankCache.set(index, variants);
246
+ }
247
+ const key = rankCacheKey(index, options);
248
+ const cached = variants.get(key);
249
+ if (cached)
250
+ return cached;
251
+ const result = rankNodes(index, options);
252
+ variants.set(key, result);
253
+ if (variants.size > RANK_CACHE_MAX_VARIANTS) {
254
+ const oldest = variants.keys().next();
255
+ if (!oldest.done)
256
+ variants.delete(oldest.value);
257
+ }
258
+ return result;
259
+ }
202
260
  export function topRankedFiles(result, limit) {
203
261
  return result.fileScores.slice(0, limit);
204
262
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rank.js","sourceRoot":"","sources":["../../../src/code/rank.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rank.js","sourceRoot":"","sources":["../../../src/code/rank.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ export interface CodeIndexStoreOptions {
17
17
  maxFiles?: number;
18
18
  maxBytes?: number;
19
19
  onBudgetExceeded?: BudgetExceededBehavior;
20
+ parseConcurrency?: number;
20
21
  }
21
22
  export interface StoreSessionOptions {
22
23
  strategy?: StoreStrategy;
@@ -32,6 +33,8 @@ export interface StoreMetadata {
32
33
  nodeCount: number;
33
34
  edgeCount: number;
34
35
  loadSource: 'cache' | 'build';
36
+ /** How the most recent build was produced. Absent when loaded from cache. */
37
+ updateKind?: 'full' | 'incremental';
35
38
  buildOptionFingerprint: string;
36
39
  contentMode: ContentMode;
37
40
  }
@@ -41,11 +44,28 @@ export interface CodeIndexStore {
41
44
  signal?: AbortSignal;
42
45
  onProgress?: OnProgress;
43
46
  }): Promise<CodeQuerySession>;
47
+ /**
48
+ * Incrementally reconcile the index with the working tree.
49
+ *
50
+ * Freshness is a stat heuristic: a cached file counts as unchanged when its
51
+ * size and mtimeMs both match the manifest, so a content change that
52
+ * preserves byte length within the filesystem's mtime granularity is missed
53
+ * by the no-argument diff. Files explicitly listed in `changedFiles` are
54
+ * always re-parsed regardless of the heuristic; refresh() is the
55
+ * force-full-rebuild escape hatch when neither applies.
56
+ */
44
57
  update(changedFiles?: string[], options?: {
45
58
  signal?: AbortSignal;
46
59
  onProgress?: OnProgress;
47
60
  }): Promise<CodeQuerySession>;
48
61
  exportIndex(options?: StoreSessionOptions): Promise<CodebaseIndex>;
62
+ /**
63
+ * Synchronously drops the in-memory session, metadata, and manifest. Does
64
+ * not serialize against or interrupt in-flight operations — a concurrent
65
+ * update/getSession keeps running and repopulates the state (and the
66
+ * on-disk cache) when it settles. Use clearCache() to also remove the
67
+ * on-disk cache with mutual exclusion against in-flight operations.
68
+ */
49
69
  dispose(): void;
50
70
  clearCache(): Promise<void>;
51
71
  clear(): Promise<void>;
@@ -2,10 +2,11 @@ import { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
2
2
  import { createHash } from 'node:crypto';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { buildCodebaseIndex } from './build.js';
5
+ import { assembleCodebaseIndex, buildCodebaseIndex, CodeIndexBudgetExceededError, parseCodeFiles, } from './build.js';
6
+ import { classifyChangedFiles, computeManifestDiff, findResolutionImpactedFiles, spliceIndexInputs, } from './incremental.js';
6
7
  import { readSectionedCodeIndex, writeSectionedCodeIndex, } from './index-io.js';
8
+ import { normalizePath } from './languages.js';
7
9
  import { createCodeQuerySessionFromIndex } from './session.js';
8
- import { discoverCodeFiles } from './discover.js';
9
10
  import { abortIfNeeded } from '../utils.js';
10
11
  // ---------------------------------------------------------------------------
11
12
  // Constants
@@ -109,25 +110,37 @@ async function loadManifest(cacheDir, signal) {
109
110
  return undefined;
110
111
  }
111
112
  }
112
- async function persistCache(cacheDir, index, buildOpts, signal, onProgress) {
113
+ async function persistCache(cacheDir, index, buildOpts, signal, onProgress, precomputedManifest) {
113
114
  const cacheRoot = path.dirname(path.dirname(cacheDir));
114
115
  const tempDir = path.join(cacheRoot, `.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
115
116
  await mkdir(path.dirname(cacheDir), { recursive: true });
116
117
  await mkdir(tempDir, { recursive: true });
117
118
  abortIfNeeded(signal);
118
119
  onProgress?.({ phase: 'serialize', total: 3, completed: 0, detail: 'writing cache' });
119
- // Build and write manifest (stat calls in parallel)
120
+ // Build and write manifest (stat calls in parallel). The manifest must
121
+ // cover guardrail-skipped files too, or freshness checks would treat them
122
+ // as perpetually new and rebuild forever.
120
123
  const repoRoot = path.resolve(buildOpts.repoRoot);
121
- const statResults = await Promise.all(index.files.map(async (file) => {
122
- try {
123
- const fileStat = await stat(path.join(repoRoot, file.relativePath));
124
- return { relativePath: file.relativePath, size: fileStat.size, mtimeMs: fileStat.mtimeMs };
125
- }
126
- catch {
127
- return null; // File may have been deleted between build and persist
128
- }
129
- }));
130
- const manifest = statResults.filter((e) => e !== null);
124
+ let manifest;
125
+ if (precomputedManifest) {
126
+ manifest = precomputedManifest;
127
+ }
128
+ else {
129
+ const manifestPaths = [
130
+ ...index.files.map((file) => file.relativePath),
131
+ ...index.skippedFiles.map((skipped) => skipped.relativePath),
132
+ ];
133
+ const statResults = await Promise.all(manifestPaths.map(async (relativePath) => {
134
+ try {
135
+ const fileStat = await stat(path.join(repoRoot, relativePath));
136
+ return { relativePath, size: fileStat.size, mtimeMs: fileStat.mtimeMs };
137
+ }
138
+ catch {
139
+ return null; // File may have been deleted between build and persist
140
+ }
141
+ }));
142
+ manifest = statResults.filter((e) => e !== null);
143
+ }
131
144
  // Write metadata
132
145
  const occVersion = await getOccVersion();
133
146
  const meta = {
@@ -159,43 +172,6 @@ async function persistCache(cacheDir, index, buildOpts, signal, onProgress) {
159
172
  return { meta, manifest };
160
173
  }
161
174
  // ---------------------------------------------------------------------------
162
- // Manifest freshness check
163
- // ---------------------------------------------------------------------------
164
- async function isManifestFresh(manifest, repoRoot, buildOpts, signal) {
165
- // Discover current files to detect additions/deletions
166
- abortIfNeeded(signal);
167
- const currentFiles = await discoverCodeFiles(repoRoot, {
168
- excludeDir: buildOpts.excludeDir,
169
- noGitignore: buildOpts.noGitignore,
170
- ignorePatterns: buildOpts.ignorePatterns,
171
- overlayIgnorePatterns: buildOpts.overlayIgnorePatterns,
172
- signal,
173
- });
174
- const currentRelPaths = new Set(currentFiles.map(f => path.relative(repoRoot, f)));
175
- const manifestRelPaths = new Set(manifest.map(e => e.relativePath));
176
- // Check for added or deleted files
177
- if (currentRelPaths.size !== manifestRelPaths.size)
178
- return false;
179
- for (const rel of currentRelPaths) {
180
- if (!manifestRelPaths.has(rel))
181
- return false;
182
- }
183
- // Check size and mtime for each file
184
- for (const entry of manifest) {
185
- abortIfNeeded(signal);
186
- try {
187
- const fileStat = await stat(path.join(repoRoot, entry.relativePath));
188
- if (fileStat.size !== entry.size || fileStat.mtimeMs !== entry.mtimeMs) {
189
- return false;
190
- }
191
- }
192
- catch {
193
- return false; // File disappeared
194
- }
195
- }
196
- return true;
197
- }
198
- // ---------------------------------------------------------------------------
199
175
  // Store implementation
200
176
  // ---------------------------------------------------------------------------
201
177
  export function openCodeIndexStore(options) {
@@ -217,10 +193,25 @@ export function openCodeIndexStore(options) {
217
193
  maxFiles: options.maxFiles,
218
194
  maxBytes: options.maxBytes,
219
195
  onBudgetExceeded: options.onBudgetExceeded,
196
+ parseConcurrency: options.parseConcurrency,
197
+ };
198
+ const discoverOpts = {
199
+ excludeDir: options.excludeDir,
200
+ noGitignore: options.noGitignore,
201
+ ignorePatterns: options.ignorePatterns,
202
+ overlayIgnorePatterns: options.overlayIgnorePatterns,
220
203
  };
221
204
  let currentSession = null;
222
205
  let currentMeta = null;
223
206
  let currentManifest = null;
207
+ // Operation mutex: rapid watcher-driven update() calls (and concurrent
208
+ // getSession/refresh) must not race the persistCache temp-dir rename.
209
+ let pending = Promise.resolve();
210
+ function serialized(fn) {
211
+ const run = pending.then(fn, fn);
212
+ pending = run.catch(() => undefined);
213
+ return run;
214
+ }
224
215
  async function buildAndPersist(signal, onProgress) {
225
216
  abortIfNeeded(signal);
226
217
  const index = await buildCodebaseIndex(buildOpts, onProgress, signal);
@@ -230,6 +221,93 @@ export function openCodeIndexStore(options) {
230
221
  const meta = {
231
222
  ...cacheMeta,
232
223
  loadSource: 'build',
224
+ updateKind: 'full',
225
+ };
226
+ return { session, meta, manifest };
227
+ }
228
+ /**
229
+ * Re-parse only the changed files and splice them into the cached parse
230
+ * set. Returns undefined when an incremental update cannot be applied
231
+ * safely — the caller falls back to a full buildAndPersist.
232
+ */
233
+ async function applyIncrementalUpdate(diff, base, signal, onProgress) {
234
+ // A truncated index dropped files non-deterministically relative to the
235
+ // diff; a contentMode mismatch means the cache cannot seed this store.
236
+ // Known limitation (intended, conservative v1): a truncated index
237
+ // therefore falls back to a full rebuild on every ensure-fresh/update,
238
+ // even when nothing changed — the manifest only covers retained files,
239
+ // so fixing this requires it to also cover the truncated-out ones.
240
+ if (base.index.truncated)
241
+ return undefined;
242
+ if (base.index.contentMode !== contentMode)
243
+ return undefined;
244
+ const deletedPaths = new Set(diff.deleted.map((entry) => entry.path));
245
+ const deletedRel = new Set(diff.deleted.map((entry) => entry.relativePath));
246
+ const survivors = base.index.files.filter((file) => !deletedPaths.has(file.path));
247
+ const impacted = findResolutionImpactedFiles(survivors, diff, repoRoot);
248
+ const reparseSet = new Set([
249
+ ...diff.added.map((entry) => entry.path),
250
+ ...diff.modified.map((entry) => entry.path),
251
+ ...impacted,
252
+ ]);
253
+ const reparseList = [...reparseSet].sort();
254
+ const freshStats = [...diff.added, ...diff.modified];
255
+ const freshRel = new Set(freshStats.map((entry) => entry.relativePath));
256
+ // Budget re-check using projected totals (manifest survivors + fresh stats).
257
+ if (options.maxFiles != null || options.maxBytes != null) {
258
+ const survivingEntries = base.manifest.filter((entry) => !deletedRel.has(entry.relativePath) && !freshRel.has(entry.relativePath));
259
+ const totalFiles = survivingEntries.length + freshStats.length;
260
+ const totalBytes = survivingEntries.reduce((sum, entry) => sum + entry.size, 0)
261
+ + freshStats.reduce((sum, entry) => sum + entry.size, 0);
262
+ const overFiles = options.maxFiles != null && totalFiles > options.maxFiles;
263
+ const overBytes = options.maxBytes != null && totalBytes > options.maxBytes;
264
+ if (overFiles || overBytes) {
265
+ if ((options.onBudgetExceeded ?? 'throw') === 'throw') {
266
+ throw new CodeIndexBudgetExceededError({
267
+ maxFiles: options.maxFiles,
268
+ maxBytes: options.maxBytes,
269
+ totalFiles,
270
+ totalBytes,
271
+ });
272
+ }
273
+ return undefined; // 'truncate' — let the full build apply truncation.
274
+ }
275
+ }
276
+ const fresh = await parseCodeFiles(reparseList, {
277
+ repoRoot,
278
+ contentMode,
279
+ maxFileSizeBytes: options.maxFileSizeBytes,
280
+ maxLines: options.maxLines,
281
+ skipMinified: options.skipMinified,
282
+ concurrency: options.parseConcurrency,
283
+ }, onProgress, signal);
284
+ abortIfNeeded(signal);
285
+ const removals = new Set([...deletedPaths, ...reparseList]);
286
+ const { parsedFiles, skippedFiles } = spliceIndexInputs(base.index.files, base.index.skippedFiles, removals, fresh);
287
+ const index = assembleCodebaseIndex({
288
+ repoRoot,
289
+ contentMode,
290
+ parsedFiles,
291
+ skippedFiles,
292
+ truncated: undefined,
293
+ }, onProgress, signal);
294
+ // New manifest: untouched survivors + fresh stats + the (on-disk
295
+ // unchanged) entries for resolution-impacted re-parses. Skipped and
296
+ // parsed files are both covered.
297
+ const reparseRel = new Set(reparseList.map((filePath) => normalizePath(path.relative(repoRoot, filePath))));
298
+ const untouched = base.manifest.filter((entry) => !deletedRel.has(entry.relativePath) && !reparseRel.has(entry.relativePath));
299
+ const impactedEntries = base.manifest.filter((entry) => reparseRel.has(entry.relativePath) && !freshRel.has(entry.relativePath) && !deletedRel.has(entry.relativePath));
300
+ const manifest = [
301
+ ...untouched,
302
+ ...freshStats.map((entry) => ({ relativePath: entry.relativePath, size: entry.size, mtimeMs: entry.mtimeMs })),
303
+ ...impactedEntries,
304
+ ];
305
+ const { meta: cacheMeta } = await persistCache(cacheDir, index, options, signal, onProgress, manifest);
306
+ const session = createCodeQuerySessionFromIndex(buildOpts, index);
307
+ const meta = {
308
+ ...cacheMeta,
309
+ loadSource: 'build',
310
+ updateKind: 'incremental',
233
311
  };
234
312
  return { session, meta, manifest };
235
313
  }
@@ -262,40 +340,19 @@ export function openCodeIndexStore(options) {
262
340
  }
263
341
  return {
264
342
  async getSession(opts) {
265
- const strategy = opts?.strategy ?? 'prefer-cache';
266
- const { signal, onProgress } = opts ?? {};
267
- abortIfNeeded(signal);
268
- if (strategy === 'rebuild') {
269
- const result = await buildAndPersist(signal, onProgress);
270
- currentSession = result.session;
271
- currentMeta = result.meta;
272
- currentManifest = result.manifest;
273
- return result.session;
274
- }
275
- if (strategy === 'prefer-cache') {
276
- if (currentSession) {
277
- return currentSession;
343
+ abortIfNeeded(opts?.signal);
344
+ return serialized(async () => {
345
+ const strategy = opts?.strategy ?? 'prefer-cache';
346
+ const { signal, onProgress } = opts ?? {};
347
+ abortIfNeeded(signal);
348
+ if (strategy === 'rebuild') {
349
+ const result = await buildAndPersist(signal, onProgress);
350
+ currentSession = result.session;
351
+ currentMeta = result.meta;
352
+ currentManifest = result.manifest;
353
+ return result.session;
278
354
  }
279
- const cached = await loadFromCache(signal, onProgress);
280
- if (cached) {
281
- currentSession = cached.session;
282
- currentMeta = cached.meta;
283
- currentManifest = cached.manifest;
284
- return cached.session;
285
- }
286
- // Cache miss — build
287
- const result = await buildAndPersist(signal, onProgress);
288
- currentSession = result.session;
289
- currentMeta = result.meta;
290
- currentManifest = result.manifest;
291
- return result.session;
292
- }
293
- // ensure-fresh
294
- const manifest = currentManifest ?? await loadManifest(cacheDir, signal);
295
- if (manifest) {
296
- onProgress?.({ phase: 'cache-check', total: 1, completed: 0, detail: 'checking freshness' });
297
- const fresh = await isManifestFresh(manifest, repoRoot, options, signal);
298
- if (fresh) {
355
+ if (strategy === 'prefer-cache') {
299
356
  if (currentSession) {
300
357
  return currentSession;
301
358
  }
@@ -306,28 +363,118 @@ export function openCodeIndexStore(options) {
306
363
  currentManifest = cached.manifest;
307
364
  return cached.session;
308
365
  }
366
+ // Cache miss — build
367
+ const result = await buildAndPersist(signal, onProgress);
368
+ currentSession = result.session;
369
+ currentMeta = result.meta;
370
+ currentManifest = result.manifest;
371
+ return result.session;
309
372
  }
310
- }
311
- // Stale or no cache rebuild
312
- const result = await buildAndPersist(signal, onProgress);
313
- currentSession = result.session;
314
- currentMeta = result.meta;
315
- currentManifest = result.manifest;
316
- return result.session;
373
+ // ensure-fresh
374
+ const manifest = currentManifest ?? await loadManifest(cacheDir, signal);
375
+ if (manifest) {
376
+ onProgress?.({ phase: 'cache-check', total: 1, completed: 0, detail: 'checking freshness' });
377
+ const diff = await computeManifestDiff(manifest, repoRoot, discoverOpts, signal);
378
+ onProgress?.({ phase: 'cache-check', total: 1, completed: 1, detail: diff.hasChanges ? 'changes detected' : 'cache fresh' });
379
+ if (!diff.hasChanges) {
380
+ if (currentSession) {
381
+ return currentSession;
382
+ }
383
+ const cached = await loadFromCache(signal, onProgress);
384
+ if (cached) {
385
+ currentSession = cached.session;
386
+ currentMeta = cached.meta;
387
+ currentManifest = cached.manifest;
388
+ return cached.session;
389
+ }
390
+ }
391
+ else {
392
+ const baseIndex = currentSession?.getIndex() ?? (await loadFromCache(signal, onProgress))?.session.getIndex();
393
+ if (baseIndex) {
394
+ const incremental = await applyIncrementalUpdate(diff, { index: baseIndex, manifest }, signal, onProgress);
395
+ if (incremental) {
396
+ currentSession = incremental.session;
397
+ currentMeta = incremental.meta;
398
+ currentManifest = incremental.manifest;
399
+ return incremental.session;
400
+ }
401
+ }
402
+ }
403
+ }
404
+ // Stale or no cache — rebuild
405
+ const result = await buildAndPersist(signal, onProgress);
406
+ currentSession = result.session;
407
+ currentMeta = result.meta;
408
+ currentManifest = result.manifest;
409
+ return result.session;
410
+ });
317
411
  },
318
412
  async refresh(opts) {
319
- const result = await buildAndPersist(opts?.signal, opts?.onProgress);
320
- currentSession = result.session;
321
- currentMeta = result.meta;
322
- currentManifest = result.manifest;
323
- return result.session;
413
+ return serialized(async () => {
414
+ const result = await buildAndPersist(opts?.signal, opts?.onProgress);
415
+ currentSession = result.session;
416
+ currentMeta = result.meta;
417
+ currentManifest = result.manifest;
418
+ return result.session;
419
+ });
324
420
  },
325
- async update(_changedFiles, opts) {
326
- const result = await buildAndPersist(opts?.signal, opts?.onProgress);
327
- currentSession = result.session;
328
- currentMeta = result.meta;
329
- currentManifest = result.manifest;
330
- return result.session;
421
+ async update(changedFiles, opts) {
422
+ abortIfNeeded(opts?.signal);
423
+ return serialized(async () => {
424
+ const { signal, onProgress } = opts ?? {};
425
+ abortIfNeeded(signal);
426
+ // Acquire a base index + manifest; missing either forces a full build.
427
+ let baseIndex;
428
+ let baseManifest = currentManifest;
429
+ let cachedLoad = undefined;
430
+ if (currentSession) {
431
+ baseIndex = currentSession.getIndex();
432
+ }
433
+ else {
434
+ cachedLoad = await loadFromCache(signal, onProgress);
435
+ if (cachedLoad) {
436
+ baseIndex = cachedLoad.session.getIndex();
437
+ baseManifest = cachedLoad.manifest;
438
+ }
439
+ }
440
+ if (!baseManifest)
441
+ baseManifest = await loadManifest(cacheDir, signal) ?? null;
442
+ if (!baseIndex || !baseManifest) {
443
+ const result = await buildAndPersist(signal, onProgress);
444
+ currentSession = result.session;
445
+ currentMeta = result.meta;
446
+ currentManifest = result.manifest;
447
+ return result.session;
448
+ }
449
+ onProgress?.({ phase: 'cache-check', total: 1, completed: 0, detail: 'diffing changed files' });
450
+ const diff = changedFiles && changedFiles.length > 0
451
+ ? await classifyChangedFiles(changedFiles, baseManifest, repoRoot, discoverOpts, signal)
452
+ : await computeManifestDiff(baseManifest, repoRoot, discoverOpts, signal);
453
+ onProgress?.({ phase: 'cache-check', total: 1, completed: 1, detail: diff.hasChanges ? 'changes detected' : 'no changes' });
454
+ if (!diff.hasChanges) {
455
+ if (currentSession)
456
+ return currentSession;
457
+ if (cachedLoad) {
458
+ currentSession = cachedLoad.session;
459
+ currentMeta = cachedLoad.meta;
460
+ currentManifest = cachedLoad.manifest;
461
+ return cachedLoad.session;
462
+ }
463
+ // baseIndex always comes from one of the two branches above.
464
+ }
465
+ const incremental = await applyIncrementalUpdate(diff, { index: baseIndex, manifest: baseManifest }, signal, onProgress);
466
+ if (incremental) {
467
+ currentSession = incremental.session;
468
+ currentMeta = incremental.meta;
469
+ currentManifest = incremental.manifest;
470
+ return incremental.session;
471
+ }
472
+ const result = await buildAndPersist(signal, onProgress);
473
+ currentSession = result.session;
474
+ currentMeta = result.meta;
475
+ currentManifest = result.manifest;
476
+ return result.session;
477
+ });
331
478
  },
332
479
  async exportIndex(opts) {
333
480
  if (currentSession)
@@ -341,13 +488,19 @@ export function openCodeIndexStore(options) {
341
488
  currentManifest = null;
342
489
  },
343
490
  async clearCache() {
344
- this.dispose();
345
- try {
346
- await rm(cacheRoot, { recursive: true, force: true });
347
- }
348
- catch {
349
- // Ignore if already missing
350
- }
491
+ // Serialized so an in-flight update's persistCache cannot recreate the
492
+ // cache directory right after the rm, or race the temp-dir rename.
493
+ await serialized(async () => {
494
+ currentSession = null;
495
+ currentMeta = null;
496
+ currentManifest = null;
497
+ try {
498
+ await rm(cacheRoot, { recursive: true, force: true });
499
+ }
500
+ catch {
501
+ // Ignore if already missing
502
+ }
503
+ });
351
504
  },
352
505
  async clear() {
353
506
  await this.clearCache();