gitnexus 1.6.11-rc.2 → 1.6.11-rc.21

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 (158) hide show
  1. package/README.md +43 -1
  2. package/dist/_shared/impact-risk.d.ts +37 -0
  3. package/dist/_shared/impact-risk.d.ts.map +1 -0
  4. package/dist/_shared/impact-risk.js +92 -0
  5. package/dist/_shared/impact-risk.js.map +1 -0
  6. package/dist/_shared/index.d.ts +2 -0
  7. package/dist/_shared/index.d.ts.map +1 -1
  8. package/dist/_shared/index.js +2 -0
  9. package/dist/_shared/index.js.map +1 -1
  10. package/dist/cli/ai-context.js +4 -4
  11. package/dist/cli/analyze-config.d.ts +2 -0
  12. package/dist/cli/analyze-config.js +16 -0
  13. package/dist/cli/analyze-options.d.ts +4 -0
  14. package/dist/cli/analyze.d.ts +17 -0
  15. package/dist/cli/analyze.js +43 -7
  16. package/dist/cli/eval-server.js +22 -5
  17. package/dist/cli/group.js +7 -1
  18. package/dist/cli/help-i18n.js +2 -0
  19. package/dist/cli/i18n/en.d.ts +12 -2
  20. package/dist/cli/i18n/en.js +12 -2
  21. package/dist/cli/i18n/resources.d.ts +22 -2
  22. package/dist/cli/i18n/zh-CN.d.ts +10 -0
  23. package/dist/cli/i18n/zh-CN.js +12 -2
  24. package/dist/cli/index.js +11 -4
  25. package/dist/cli/status.js +91 -6
  26. package/dist/cli/watch-queue.d.ts +41 -0
  27. package/dist/cli/watch-queue.js +184 -0
  28. package/dist/cli/watch.d.ts +20 -0
  29. package/dist/cli/watch.js +372 -0
  30. package/dist/cli/wiki.js +15 -2
  31. package/dist/config/ignore-service.d.ts +11 -0
  32. package/dist/config/ignore-service.js +41 -4
  33. package/dist/config/repo-control-file.d.ts +3 -0
  34. package/dist/config/repo-control-file.js +115 -0
  35. package/dist/core/group/config-parser.js +20 -2
  36. package/dist/core/group/cross-impact.d.ts +2 -1
  37. package/dist/core/group/cross-impact.js +33 -2
  38. package/dist/core/group/extractors/fs-utils.d.ts +2 -0
  39. package/dist/core/group/extractors/fs-utils.js +86 -0
  40. package/dist/core/group/extractors/graphql-extractor.d.ts +17 -0
  41. package/dist/core/group/extractors/graphql-extractor.js +652 -0
  42. package/dist/core/group/extractors/java-workspace-extractor.js +244 -31
  43. package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
  44. package/dist/core/group/extractors/manifest-extractor.js +1 -1
  45. package/dist/core/group/matching.js +8 -1
  46. package/dist/core/group/service.js +5 -1
  47. package/dist/core/group/storage.js +1 -0
  48. package/dist/core/group/sync.d.ts +3 -1
  49. package/dist/core/group/sync.js +43 -5
  50. package/dist/core/group/types.d.ts +19 -5
  51. package/dist/core/incremental/derived-writeback.d.ts +36 -0
  52. package/dist/core/incremental/derived-writeback.js +68 -0
  53. package/dist/core/incremental/subgraph-extract.d.ts +6 -4
  54. package/dist/core/incremental/subgraph-extract.js +7 -5
  55. package/dist/core/index-content-drift.d.ts +54 -0
  56. package/dist/core/index-content-drift.js +127 -0
  57. package/dist/core/ingestion/filesystem-walker.d.ts +15 -5
  58. package/dist/core/ingestion/filesystem-walker.js +20 -3
  59. package/dist/core/ingestion/frameworks/spring/dynamic-lookups.d.ts +22 -0
  60. package/dist/core/ingestion/frameworks/spring/dynamic-lookups.js +124 -0
  61. package/dist/core/ingestion/language-provider.d.ts +43 -0
  62. package/dist/core/ingestion/languages/csharp/razor-view-components.d.ts +62 -0
  63. package/dist/core/ingestion/languages/csharp/razor-view-components.js +954 -0
  64. package/dist/core/ingestion/languages/csharp/resolution-config.d.ts +3 -0
  65. package/dist/core/ingestion/languages/csharp/resolution-config.js +6 -1
  66. package/dist/core/ingestion/languages/csharp/scope-resolver.js +8 -0
  67. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +4 -0
  68. package/dist/core/ingestion/languages/java/capture-side-channel.js +16 -0
  69. package/dist/core/ingestion/languages/java/captures.js +14 -1
  70. package/dist/core/ingestion/languages/java/lombok-synthesizer.d.ts +42 -0
  71. package/dist/core/ingestion/languages/java/lombok-synthesizer.js +439 -0
  72. package/dist/core/ingestion/languages/java/scope-resolver.js +2 -0
  73. package/dist/core/ingestion/languages/java/spring-dynamic-lookup.d.ts +8 -0
  74. package/dist/core/ingestion/languages/java/spring-dynamic-lookup.js +62 -0
  75. package/dist/core/ingestion/languages/java.js +2 -0
  76. package/dist/core/ingestion/languages/jvm/accessor-synthesis.d.ts +99 -0
  77. package/dist/core/ingestion/languages/jvm/accessor-synthesis.js +173 -0
  78. package/dist/core/ingestion/languages/jvm/beanspec.d.ts +17 -0
  79. package/dist/core/ingestion/languages/jvm/beanspec.js +42 -0
  80. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +5 -0
  81. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +16 -0
  82. package/dist/core/ingestion/languages/kotlin/captures.js +14 -1
  83. package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.d.ts +26 -0
  84. package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.js +417 -0
  85. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +2 -0
  86. package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.d.ts +8 -0
  87. package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.js +77 -0
  88. package/dist/core/ingestion/languages/kotlin.js +2 -0
  89. package/dist/core/ingestion/pipeline-phases/di.js +47 -14
  90. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +3 -1
  91. package/dist/core/ingestion/pipeline-phases/parse-impl.js +57 -86
  92. package/dist/core/ingestion/pipeline-phases/parse.d.ts +2 -0
  93. package/dist/core/ingestion/pipeline-phases/runner.d.ts +4 -1
  94. package/dist/core/ingestion/pipeline-phases/runner.js +34 -14
  95. package/dist/core/ingestion/pipeline-phases/scan.js +25 -13
  96. package/dist/core/ingestion/pipeline.d.ts +6 -0
  97. package/dist/core/ingestion/pipeline.js +44 -12
  98. package/dist/core/ingestion/scope-extractor.js +1 -0
  99. package/dist/core/ingestion/utils/symbol-labels.d.ts +2 -2
  100. package/dist/core/ingestion/utils/symbol-labels.js +2 -2
  101. package/dist/core/ingestion/workers/parse-worker.js +28 -2
  102. package/dist/core/lbug/lbug-adapter.d.ts +59 -0
  103. package/dist/core/lbug/lbug-adapter.js +154 -1
  104. package/dist/core/run-analyze.d.ts +17 -0
  105. package/dist/core/run-analyze.js +231 -23
  106. package/dist/core/search/fts-indexes.d.ts +19 -1
  107. package/dist/core/search/fts-indexes.js +28 -1
  108. package/dist/core/wiki/generator.js +8 -0
  109. package/dist/core/wiki/grok-client.d.ts +21 -0
  110. package/dist/core/wiki/grok-client.js +287 -0
  111. package/dist/core/wiki/llm-client.d.ts +1 -1
  112. package/dist/core/wiki/llm-client.js +5 -2
  113. package/dist/core/wiki/local-cli-client.d.ts +11 -0
  114. package/dist/core/wiki/local-cli-client.js +22 -9
  115. package/dist/mcp/local/local-backend.d.ts +24 -7
  116. package/dist/mcp/local/local-backend.js +190 -81
  117. package/dist/mcp/local/pdg-impact.d.ts +8 -4
  118. package/dist/mcp/local/pdg-impact.js +7 -2
  119. package/dist/mcp/repository-policy.d.ts +5 -1
  120. package/dist/mcp/repository-policy.js +48 -4
  121. package/dist/mcp/resources.js +2 -1
  122. package/dist/mcp/server.js +6 -5
  123. package/dist/mcp/tools.js +31 -19
  124. package/dist/server/api.js +23 -64
  125. package/dist/server/grep-params.d.ts +18 -0
  126. package/dist/server/grep-params.js +83 -0
  127. package/dist/server/grep-scan.d.ts +23 -0
  128. package/dist/server/grep-scan.js +107 -0
  129. package/dist/server/grep-worker.d.ts +1 -0
  130. package/dist/server/grep-worker.js +12 -0
  131. package/dist/server/mcp-http.d.ts +8 -0
  132. package/dist/server/mcp-http.js +16 -1
  133. package/dist/storage/file-hash.d.ts +5 -0
  134. package/dist/storage/file-hash.js +16 -6
  135. package/dist/storage/fs-atomic.d.ts +24 -0
  136. package/dist/storage/fs-atomic.js +86 -2
  137. package/dist/storage/git.d.ts +19 -8
  138. package/dist/storage/git.js +83 -24
  139. package/dist/storage/gitnexus-managed-paths.d.ts +36 -0
  140. package/dist/storage/gitnexus-managed-paths.js +46 -0
  141. package/dist/storage/parse-cache.d.ts +22 -4
  142. package/dist/storage/parse-cache.js +106 -29
  143. package/dist/storage/parsedfile-store.d.ts +34 -60
  144. package/dist/storage/parsedfile-store.js +177 -171
  145. package/dist/storage/repo-manager.d.ts +11 -1
  146. package/dist/storage/repo-manager.js +23 -2
  147. package/dist/storage/repo-meta.d.ts +12 -0
  148. package/dist/storage/v8-sidecar.d.ts +48 -0
  149. package/dist/storage/v8-sidecar.js +347 -0
  150. package/dist/types/pipeline.d.ts +14 -0
  151. package/package.json +4 -1
  152. package/scripts/cross-platform-shard.ts +4 -2
  153. package/scripts/cross-platform-tests.ts +7 -1
  154. package/skills/gitnexus-cli.md +11 -3
  155. package/skills/gitnexus-impact-analysis.md +9 -0
  156. package/web/assets/{agent-Dr4l5EOp.js → agent-CFqT4hjR.js} +108 -104
  157. package/web/assets/{index-2zdvEdzg.js → index-BMIniRtX.js} +3 -3
  158. package/web/index.html +1 -1
@@ -385,7 +385,66 @@ export declare const DELETE_FILES_CHUNK_SIZE = 200;
385
385
  */
386
386
  export declare const deleteNodesForFiles: (filePaths: readonly string[], options?: {
387
387
  onChunk?: (filesDone: number, filesTotal: number) => void;
388
+ /** When set, only these node tables are DETACH DELETEd (#3016). */
389
+ nodeTables?: readonly string[];
388
390
  }) => Promise<void>;
391
+ /**
392
+ * Which of `candidateTables` currently hold at least one row for `filePaths`.
393
+ *
394
+ * The incremental writeback uses this to decide which FTS-backed tables it is
395
+ * about to DML (#3016). It has to be a question about the DB, not about the
396
+ * freshly built graph: an edit that DELETES the last Rust trait in a file
397
+ * leaves no Trait node in the new graph, but the old row is still in the index
398
+ * and still has to be deleted — and its FTS index still has to come down first.
399
+ */
400
+ export declare const nodeTablesWithRowsForFiles: (filePaths: readonly string[], candidateTables: readonly string[]) => Promise<Set<string>>;
401
+ /**
402
+ * One MEMBER_OF / STEP_IN_PROCESS edge, carrying everything needed to recreate
403
+ * it byte-for-byte: both endpoint labels (so the re-MATCH is label-scoped
404
+ * rather than a scan of every node) and every column of the relationship
405
+ * table, `step` included — process traces order by it (`ORDER BY r.step`), so
406
+ * an edge restored without it silently scrambles the flow it belongs to.
407
+ */
408
+ export interface DerivedRelSnapshot {
409
+ sourceId: string;
410
+ sourceLabel: string;
411
+ targetId: string;
412
+ targetLabel: string;
413
+ type: string;
414
+ confidence: number;
415
+ reason: string;
416
+ step: number;
417
+ }
418
+ /**
419
+ * Capture the MEMBER_OF / STEP_IN_PROCESS / ENTRY_POINT_OF edges owned by `filePaths`, before a
420
+ * surgical incremental write DETACH DELETEs their file-side endpoints (#3016).
421
+ *
422
+ * Only meaningful on the write plan that keeps the persisted Community/Process
423
+ * nodes: those nodes survive the delete, but the edges tying this run's changed
424
+ * files to them do not, and the pipeline did not re-derive them.
425
+ *
426
+ * Both endpoints are matched by an EXPLICIT label — `sourceTables` on one side,
427
+ * the edge type's fixed target table on the other — so the labels come from the
428
+ * query rather than the rows. `labels(n)[0]` over an unlabelled match returns
429
+ * an empty string on this engine, which silently produced a snapshot that
430
+ * restored nothing.
431
+ *
432
+ * Read failures propagate. This runs against a warm index whose derived tables
433
+ * the caller has already established exist, so a failure here is a real fault —
434
+ * and swallowing it would drop the edges silently, which looks identical to a
435
+ * repo that genuinely has no communities.
436
+ */
437
+ export declare const snapshotDerivedRelsForFiles: (filePaths: readonly string[], sourceTables: readonly string[]) => Promise<DerivedRelSnapshot[]>;
438
+ /**
439
+ * Re-create the edges captured by `snapshotDerivedRelsForFiles`, after the
440
+ * incremental subgraph load has put their file-side endpoints back.
441
+ *
442
+ * Endpoints are matched by label + id, mirroring `fallbackRelationshipInserts`:
443
+ * an unlabelled `MATCH (a), (b)` is a cartesian product over the whole graph
444
+ * and does not finish on a real index. An endpoint the load did not restore
445
+ * simply matches nothing, so the edge is dropped rather than mis-attached.
446
+ */
447
+ export declare const restoreDerivedRels: (rels: readonly DerivedRelSnapshot[]) => Promise<void>;
389
448
  export declare const getEmbeddingTableName: () => string;
390
449
  /**
391
450
  * Return the distinct repo-relative paths of files that import
@@ -2303,7 +2303,8 @@ export const deleteNodesForFiles = async (filePaths, options = {}) => {
2303
2303
  'skipping embedding-row deletes for this writeback.');
2304
2304
  }
2305
2305
  }
2306
- for (const tableName of NODE_TABLES) {
2306
+ const tables = options.nodeTables ?? NODE_TABLES;
2307
+ for (const tableName of tables) {
2307
2308
  // Community/Process are graph-wide (no filePath); the orchestrator
2308
2309
  // drops them wholesale via deleteAllCommunitiesAndProcesses.
2309
2310
  if (tableName === 'Community' || tableName === 'Process')
@@ -2314,6 +2315,158 @@ export const deleteNodesForFiles = async (filePaths, options = {}) => {
2314
2315
  options.onChunk?.(Math.min((chunkIndex + 1) * DELETE_FILES_CHUNK_SIZE, filePaths.length), filePaths.length);
2315
2316
  }
2316
2317
  };
2318
+ /**
2319
+ * Which of `candidateTables` currently hold at least one row for `filePaths`.
2320
+ *
2321
+ * The incremental writeback uses this to decide which FTS-backed tables it is
2322
+ * about to DML (#3016). It has to be a question about the DB, not about the
2323
+ * freshly built graph: an edit that DELETES the last Rust trait in a file
2324
+ * leaves no Trait node in the new graph, but the old row is still in the index
2325
+ * and still has to be deleted — and its FTS index still has to come down first.
2326
+ */
2327
+ export const nodeTablesWithRowsForFiles = async (filePaths, candidateTables) => {
2328
+ const c = conn;
2329
+ if (!c) {
2330
+ throw new Error('LadybugDB not initialized. Call initLbug first.');
2331
+ }
2332
+ const found = new Set();
2333
+ return withConnLock(async () => {
2334
+ for (const batch of chunk(filePaths, DELETE_FILES_CHUNK_SIZE)) {
2335
+ const listLiteral = `[${batch.map((p) => formatCypherValue(p)).join(', ')}]`;
2336
+ for (const tableName of candidateTables) {
2337
+ // Graph-wide tables have no filePath column to filter on.
2338
+ if (tableName === 'Community' || tableName === 'Process')
2339
+ continue;
2340
+ if (found.has(tableName))
2341
+ continue;
2342
+ // determinism: probe — asks only whether the table has any row for
2343
+ // these files, so which row comes back cannot change the answer.
2344
+ const queryResult = await c.query(`MATCH (n:${escapeTableName(tableName)}) WHERE n.filePath IN ${listLiteral} ` +
2345
+ `RETURN n.id LIMIT 1`);
2346
+ try {
2347
+ const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
2348
+ if ((await result.getAll()).length > 0)
2349
+ found.add(tableName);
2350
+ }
2351
+ finally {
2352
+ await closeQueryResults(queryResult);
2353
+ }
2354
+ }
2355
+ }
2356
+ return found;
2357
+ });
2358
+ };
2359
+ /**
2360
+ * The graph-wide derived edges and the node table each one points at. Both are
2361
+ * produced by the derived phases (Leiden, flow extraction) rather than by
2362
+ * parsing, which is why an incremental run that skips those phases has to carry
2363
+ * them across the writeback itself.
2364
+ */
2365
+ const DERIVED_REL_KINDS = [
2366
+ { type: 'MEMBER_OF', targetLabel: 'Community' },
2367
+ { type: 'STEP_IN_PROCESS', targetLabel: 'Process' },
2368
+ { type: 'ENTRY_POINT_OF', targetLabel: 'Process' },
2369
+ ];
2370
+ /**
2371
+ * Capture the MEMBER_OF / STEP_IN_PROCESS / ENTRY_POINT_OF edges owned by `filePaths`, before a
2372
+ * surgical incremental write DETACH DELETEs their file-side endpoints (#3016).
2373
+ *
2374
+ * Only meaningful on the write plan that keeps the persisted Community/Process
2375
+ * nodes: those nodes survive the delete, but the edges tying this run's changed
2376
+ * files to them do not, and the pipeline did not re-derive them.
2377
+ *
2378
+ * Both endpoints are matched by an EXPLICIT label — `sourceTables` on one side,
2379
+ * the edge type's fixed target table on the other — so the labels come from the
2380
+ * query rather than the rows. `labels(n)[0]` over an unlabelled match returns
2381
+ * an empty string on this engine, which silently produced a snapshot that
2382
+ * restored nothing.
2383
+ *
2384
+ * Read failures propagate. This runs against a warm index whose derived tables
2385
+ * the caller has already established exist, so a failure here is a real fault —
2386
+ * and swallowing it would drop the edges silently, which looks identical to a
2387
+ * repo that genuinely has no communities.
2388
+ */
2389
+ export const snapshotDerivedRelsForFiles = async (filePaths, sourceTables) => {
2390
+ const c = conn;
2391
+ if (!c) {
2392
+ throw new Error('LadybugDB not initialized. Call initLbug first.');
2393
+ }
2394
+ const out = [];
2395
+ return withConnLock(async () => {
2396
+ for (const batch of chunk(filePaths, DELETE_FILES_CHUNK_SIZE)) {
2397
+ const listLiteral = `[${batch.map((p) => formatCypherValue(p)).join(', ')}]`;
2398
+ for (const sourceLabel of sourceTables) {
2399
+ if (sourceLabel === 'Community' || sourceLabel === 'Process')
2400
+ continue;
2401
+ for (const { type, targetLabel } of DERIVED_REL_KINDS) {
2402
+ const queryResult = await c.query(`MATCH (n:${escapeTableName(sourceLabel)})-[r:${REL_TABLE_NAME}]->` +
2403
+ `(m:${escapeTableName(targetLabel)}) ` +
2404
+ `WHERE n.filePath IN ${listLiteral} AND r.type = ${formatCypherValue(type)} ` +
2405
+ `RETURN n.id AS sourceId, m.id AS targetId, ` +
2406
+ `r.confidence AS confidence, r.reason AS reason, r.step AS step`);
2407
+ try {
2408
+ const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
2409
+ for (const row of await result.getAll()) {
2410
+ const rec = row;
2411
+ if (typeof rec.sourceId !== 'string' || typeof rec.targetId !== 'string')
2412
+ continue;
2413
+ out.push({
2414
+ sourceId: rec.sourceId,
2415
+ sourceLabel,
2416
+ targetId: rec.targetId,
2417
+ targetLabel,
2418
+ type,
2419
+ confidence: typeof rec.confidence === 'number' ? rec.confidence : 1.0,
2420
+ reason: typeof rec.reason === 'string' ? rec.reason : '',
2421
+ step: typeof rec.step === 'number'
2422
+ ? rec.step
2423
+ : typeof rec.step === 'bigint'
2424
+ ? Number(rec.step)
2425
+ : 0,
2426
+ });
2427
+ }
2428
+ }
2429
+ finally {
2430
+ await closeQueryResults(queryResult);
2431
+ }
2432
+ }
2433
+ }
2434
+ }
2435
+ return out;
2436
+ });
2437
+ };
2438
+ /**
2439
+ * Re-create the edges captured by `snapshotDerivedRelsForFiles`, after the
2440
+ * incremental subgraph load has put their file-side endpoints back.
2441
+ *
2442
+ * Endpoints are matched by label + id, mirroring `fallbackRelationshipInserts`:
2443
+ * an unlabelled `MATCH (a), (b)` is a cartesian product over the whole graph
2444
+ * and does not finish on a real index. An endpoint the load did not restore
2445
+ * simply matches nothing, so the edge is dropped rather than mis-attached.
2446
+ */
2447
+ export const restoreDerivedRels = async (rels) => {
2448
+ const c = conn;
2449
+ if (!c) {
2450
+ throw new Error('LadybugDB not initialized. Call initLbug first.');
2451
+ }
2452
+ if (rels.length === 0)
2453
+ return;
2454
+ const escapeLabel = (label) => BACKTICK_TABLES.has(label) ? `\`${label}\`` : label;
2455
+ // No outer `withConnLock`: `queryAndDrain` takes the lock per statement, and
2456
+ // wrapping the loop as well trips the re-entry guard in conn-lock.ts. Same
2457
+ // shape as `fallbackRelationshipInserts`, the other per-edge CREATE loop.
2458
+ for (const rel of rels) {
2459
+ if (!NODE_TABLES.includes(rel.sourceLabel))
2460
+ continue;
2461
+ if (!NODE_TABLES.includes(rel.targetLabel))
2462
+ continue;
2463
+ await queryAndDrain(c, `MATCH (a:${escapeLabel(rel.sourceLabel)} {id: ${formatCypherValue(rel.sourceId)}}), ` +
2464
+ `(b:${escapeLabel(rel.targetLabel)} {id: ${formatCypherValue(rel.targetId)}}) ` +
2465
+ `CREATE (a)-[:${REL_TABLE_NAME} {type: ${formatCypherValue(rel.type)}, ` +
2466
+ `confidence: ${rel.confidence}, reason: ${formatCypherValue(rel.reason)}, ` +
2467
+ `step: ${rel.step}}]->(b)`);
2468
+ }
2469
+ };
2317
2470
  export const getEmbeddingTableName = () => EMBEDDING_TABLE_NAME;
2318
2471
  /**
2319
2472
  * Return the distinct repo-relative paths of files that import
@@ -158,7 +158,16 @@ export interface AnalyzeOptions {
158
158
  * Process exit reclaims the handles. Long-lived callers (MCP server, tests)
159
159
  * leave this unset so they get a real close. See `closeLbug`. */
160
160
  skipNativeCloseOnExit?: boolean;
161
+ /**
162
+ * Stage an incremental write in a copy of the live index before publishing
163
+ * it. Used by long-lived watch mode so a failed refresh leaves the previous
164
+ * graph readable. Currently supported on POSIX, where an open DB can be
165
+ * atomically renamed; Windows retains the established in-place path.
166
+ */
167
+ atomicIncremental?: boolean;
161
168
  }
169
+ /** Whether a failed analyze may already have changed the live DB. */
170
+ export declare function analyzeFailureMayHaveMutatedLiveIndex(error: unknown): boolean;
162
171
  export interface AnalyzeResult {
163
172
  repoName: string;
164
173
  repoPath: string;
@@ -211,6 +220,14 @@ export interface AnalyzeResult {
211
220
  * (The historical "primary" name is kept — it is public API surface.)
212
221
  */
213
222
  isPrimaryBranch?: boolean;
223
+ /** Measured work performed by a successful incremental refresh. */
224
+ incrementalStats?: {
225
+ changedFiles: number;
226
+ reparsedFiles: number;
227
+ affectedDependents: number;
228
+ deletedFiles: number;
229
+ writeMode: 'incremental' | 'full';
230
+ };
214
231
  }
215
232
  export { deriveEmbeddingMode, DEFAULT_EMBEDDING_NODE_LIMIT } from './embedding-mode.js';
216
233
  export type { EmbeddingMode } from './embedding-mode.js';