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.
- package/README.md +43 -1
- package/dist/_shared/impact-risk.d.ts +37 -0
- package/dist/_shared/impact-risk.d.ts.map +1 -0
- package/dist/_shared/impact-risk.js +92 -0
- package/dist/_shared/impact-risk.js.map +1 -0
- package/dist/_shared/index.d.ts +2 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +2 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/cli/ai-context.js +4 -4
- package/dist/cli/analyze-config.d.ts +2 -0
- package/dist/cli/analyze-config.js +16 -0
- package/dist/cli/analyze-options.d.ts +4 -0
- package/dist/cli/analyze.d.ts +17 -0
- package/dist/cli/analyze.js +43 -7
- package/dist/cli/eval-server.js +22 -5
- package/dist/cli/group.js +7 -1
- package/dist/cli/help-i18n.js +2 -0
- package/dist/cli/i18n/en.d.ts +12 -2
- package/dist/cli/i18n/en.js +12 -2
- package/dist/cli/i18n/resources.d.ts +22 -2
- package/dist/cli/i18n/zh-CN.d.ts +10 -0
- package/dist/cli/i18n/zh-CN.js +12 -2
- package/dist/cli/index.js +11 -4
- package/dist/cli/status.js +91 -6
- package/dist/cli/watch-queue.d.ts +41 -0
- package/dist/cli/watch-queue.js +184 -0
- package/dist/cli/watch.d.ts +20 -0
- package/dist/cli/watch.js +372 -0
- package/dist/cli/wiki.js +15 -2
- package/dist/config/ignore-service.d.ts +11 -0
- package/dist/config/ignore-service.js +41 -4
- package/dist/config/repo-control-file.d.ts +3 -0
- package/dist/config/repo-control-file.js +115 -0
- package/dist/core/group/config-parser.js +20 -2
- package/dist/core/group/cross-impact.d.ts +2 -1
- package/dist/core/group/cross-impact.js +33 -2
- package/dist/core/group/extractors/fs-utils.d.ts +2 -0
- package/dist/core/group/extractors/fs-utils.js +86 -0
- package/dist/core/group/extractors/graphql-extractor.d.ts +17 -0
- package/dist/core/group/extractors/graphql-extractor.js +652 -0
- package/dist/core/group/extractors/java-workspace-extractor.js +244 -31
- package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
- package/dist/core/group/extractors/manifest-extractor.js +1 -1
- package/dist/core/group/matching.js +8 -1
- package/dist/core/group/service.js +5 -1
- package/dist/core/group/storage.js +1 -0
- package/dist/core/group/sync.d.ts +3 -1
- package/dist/core/group/sync.js +43 -5
- package/dist/core/group/types.d.ts +19 -5
- package/dist/core/incremental/derived-writeback.d.ts +36 -0
- package/dist/core/incremental/derived-writeback.js +68 -0
- package/dist/core/incremental/subgraph-extract.d.ts +6 -4
- package/dist/core/incremental/subgraph-extract.js +7 -5
- package/dist/core/index-content-drift.d.ts +54 -0
- package/dist/core/index-content-drift.js +127 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +15 -5
- package/dist/core/ingestion/filesystem-walker.js +20 -3
- package/dist/core/ingestion/frameworks/spring/dynamic-lookups.d.ts +22 -0
- package/dist/core/ingestion/frameworks/spring/dynamic-lookups.js +124 -0
- package/dist/core/ingestion/language-provider.d.ts +43 -0
- package/dist/core/ingestion/languages/csharp/razor-view-components.d.ts +62 -0
- package/dist/core/ingestion/languages/csharp/razor-view-components.js +954 -0
- package/dist/core/ingestion/languages/csharp/resolution-config.d.ts +3 -0
- package/dist/core/ingestion/languages/csharp/resolution-config.js +6 -1
- package/dist/core/ingestion/languages/csharp/scope-resolver.js +8 -0
- package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +4 -0
- package/dist/core/ingestion/languages/java/capture-side-channel.js +16 -0
- package/dist/core/ingestion/languages/java/captures.js +14 -1
- package/dist/core/ingestion/languages/java/lombok-synthesizer.d.ts +42 -0
- package/dist/core/ingestion/languages/java/lombok-synthesizer.js +439 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +2 -0
- package/dist/core/ingestion/languages/java/spring-dynamic-lookup.d.ts +8 -0
- package/dist/core/ingestion/languages/java/spring-dynamic-lookup.js +62 -0
- package/dist/core/ingestion/languages/java.js +2 -0
- package/dist/core/ingestion/languages/jvm/accessor-synthesis.d.ts +99 -0
- package/dist/core/ingestion/languages/jvm/accessor-synthesis.js +173 -0
- package/dist/core/ingestion/languages/jvm/beanspec.d.ts +17 -0
- package/dist/core/ingestion/languages/jvm/beanspec.js +42 -0
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +5 -0
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +16 -0
- package/dist/core/ingestion/languages/kotlin/captures.js +14 -1
- package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.d.ts +26 -0
- package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.js +417 -0
- package/dist/core/ingestion/languages/kotlin/scope-resolver.js +2 -0
- package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.d.ts +8 -0
- package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.js +77 -0
- package/dist/core/ingestion/languages/kotlin.js +2 -0
- package/dist/core/ingestion/pipeline-phases/di.js +47 -14
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +3 -1
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +57 -86
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/runner.d.ts +4 -1
- package/dist/core/ingestion/pipeline-phases/runner.js +34 -14
- package/dist/core/ingestion/pipeline-phases/scan.js +25 -13
- package/dist/core/ingestion/pipeline.d.ts +6 -0
- package/dist/core/ingestion/pipeline.js +44 -12
- package/dist/core/ingestion/scope-extractor.js +1 -0
- package/dist/core/ingestion/utils/symbol-labels.d.ts +2 -2
- package/dist/core/ingestion/utils/symbol-labels.js +2 -2
- package/dist/core/ingestion/workers/parse-worker.js +28 -2
- package/dist/core/lbug/lbug-adapter.d.ts +59 -0
- package/dist/core/lbug/lbug-adapter.js +154 -1
- package/dist/core/run-analyze.d.ts +17 -0
- package/dist/core/run-analyze.js +231 -23
- package/dist/core/search/fts-indexes.d.ts +19 -1
- package/dist/core/search/fts-indexes.js +28 -1
- package/dist/core/wiki/generator.js +8 -0
- package/dist/core/wiki/grok-client.d.ts +21 -0
- package/dist/core/wiki/grok-client.js +287 -0
- package/dist/core/wiki/llm-client.d.ts +1 -1
- package/dist/core/wiki/llm-client.js +5 -2
- package/dist/core/wiki/local-cli-client.d.ts +11 -0
- package/dist/core/wiki/local-cli-client.js +22 -9
- package/dist/mcp/local/local-backend.d.ts +24 -7
- package/dist/mcp/local/local-backend.js +190 -81
- package/dist/mcp/local/pdg-impact.d.ts +8 -4
- package/dist/mcp/local/pdg-impact.js +7 -2
- package/dist/mcp/repository-policy.d.ts +5 -1
- package/dist/mcp/repository-policy.js +48 -4
- package/dist/mcp/resources.js +2 -1
- package/dist/mcp/server.js +6 -5
- package/dist/mcp/tools.js +31 -19
- package/dist/server/api.js +23 -64
- package/dist/server/grep-params.d.ts +18 -0
- package/dist/server/grep-params.js +83 -0
- package/dist/server/grep-scan.d.ts +23 -0
- package/dist/server/grep-scan.js +107 -0
- package/dist/server/grep-worker.d.ts +1 -0
- package/dist/server/grep-worker.js +12 -0
- package/dist/server/mcp-http.d.ts +8 -0
- package/dist/server/mcp-http.js +16 -1
- package/dist/storage/file-hash.d.ts +5 -0
- package/dist/storage/file-hash.js +16 -6
- package/dist/storage/fs-atomic.d.ts +24 -0
- package/dist/storage/fs-atomic.js +86 -2
- package/dist/storage/git.d.ts +19 -8
- package/dist/storage/git.js +83 -24
- package/dist/storage/gitnexus-managed-paths.d.ts +36 -0
- package/dist/storage/gitnexus-managed-paths.js +46 -0
- package/dist/storage/parse-cache.d.ts +22 -4
- package/dist/storage/parse-cache.js +106 -29
- package/dist/storage/parsedfile-store.d.ts +34 -60
- package/dist/storage/parsedfile-store.js +177 -171
- package/dist/storage/repo-manager.d.ts +11 -1
- package/dist/storage/repo-manager.js +23 -2
- package/dist/storage/repo-meta.d.ts +12 -0
- package/dist/storage/v8-sidecar.d.ts +48 -0
- package/dist/storage/v8-sidecar.js +347 -0
- package/dist/types/pipeline.d.ts +14 -0
- package/package.json +4 -1
- package/scripts/cross-platform-shard.ts +4 -2
- package/scripts/cross-platform-tests.ts +7 -1
- package/skills/gitnexus-cli.md +11 -3
- package/skills/gitnexus-impact-analysis.md +9 -0
- package/web/assets/{agent-Dr4l5EOp.js → agent-CFqT4hjR.js} +108 -104
- package/web/assets/{index-2zdvEdzg.js → index-BMIniRtX.js} +3 -3
- 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
|
-
|
|
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';
|