@lzehrung/codegraph 2.1.0 → 2.1.1
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 +27 -29
- package/codegraph-skill/codegraph/SKILL.md +23 -21
- package/dist/agent/candidateTests.d.ts +12 -0
- package/dist/agent/candidateTests.d.ts.map +1 -0
- package/dist/agent/candidateTests.js +17 -0
- package/dist/agent/candidateTests.js.map +1 -0
- package/dist/agent/explore.d.ts.map +1 -1
- package/dist/agent/explore.js +9 -6
- package/dist/agent/explore.js.map +1 -1
- package/dist/agent/fileView.d.ts.map +1 -1
- package/dist/agent/fileView.js +113 -120
- package/dist/agent/fileView.js.map +1 -1
- package/dist/agent/orient.d.ts.map +1 -1
- package/dist/agent/orient.js +5 -4
- package/dist/agent/orient.js.map +1 -1
- package/dist/agent/query-index/candidates.d.ts +13 -2
- package/dist/agent/query-index/candidates.d.ts.map +1 -1
- package/dist/agent/query-index/candidates.js +28 -39
- package/dist/agent/query-index/candidates.js.map +1 -1
- package/dist/agent/query-index/schema.d.ts.map +1 -1
- package/dist/agent/query-index/schema.js.map +1 -1
- package/dist/agent/query-index/sessionStore.d.ts.map +1 -1
- package/dist/agent/query-index/sessionStore.js +42 -26
- package/dist/agent/query-index/sessionStore.js.map +1 -1
- package/dist/agent/query-index/store.d.ts +7 -0
- package/dist/agent/query-index/store.d.ts.map +1 -1
- package/dist/agent/query-index/store.js +71 -0
- package/dist/agent/query-index/store.js.map +1 -1
- package/dist/agent/refactorPlan.d.ts.map +1 -1
- package/dist/agent/refactorPlan.js +6 -14
- package/dist/agent/refactorPlan.js.map +1 -1
- package/dist/agent/renamePreview.d.ts +2 -5
- package/dist/agent/renamePreview.d.ts.map +1 -1
- package/dist/agent/renamePreview.js +82 -78
- package/dist/agent/renamePreview.js.map +1 -1
- package/dist/agent/search.d.ts.map +1 -1
- package/dist/agent/search.js +39 -17
- package/dist/agent/search.js.map +1 -1
- package/dist/agent/semanticSymbols.d.ts.map +1 -1
- package/dist/agent/semanticSymbols.js +2 -1
- package/dist/agent/semanticSymbols.js.map +1 -1
- package/dist/agent/session.d.ts +4 -0
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +19 -6
- package/dist/agent/session.js.map +1 -1
- package/dist/agent-tools.d.ts +1 -1
- package/dist/agent-tools.d.ts.map +1 -1
- package/dist/agent-tools.js +6 -15
- package/dist/agent-tools.js.map +1 -1
- package/dist/bin/cli.js +27556 -24941
- package/dist/bin/queryIndexWorker.js +47 -6
- package/dist/bin/rawQueryWorker.js +246 -0
- package/dist/chunking/chunkFile.d.ts +5 -0
- package/dist/chunking/chunkFile.d.ts.map +1 -1
- package/dist/chunking/chunkFile.js +14 -15
- package/dist/chunking/chunkFile.js.map +1 -1
- package/dist/cli/affected.d.ts.map +1 -1
- package/dist/cli/affected.js +17 -10
- package/dist/cli/affected.js.map +1 -1
- package/dist/cli/commandTable.d.ts.map +1 -1
- package/dist/cli/commandTable.js +15 -3
- package/dist/cli/commandTable.js.map +1 -1
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +166 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/graph.d.ts +2 -1
- package/dist/cli/graph.d.ts.map +1 -1
- package/dist/cli/graph.js +8 -0
- package/dist/cli/graph.js.map +1 -1
- package/dist/cli/graphDelta.d.ts +2 -1
- package/dist/cli/graphDelta.d.ts.map +1 -1
- package/dist/cli/graphDelta.js +5 -0
- package/dist/cli/graphDelta.js.map +1 -1
- package/dist/cli/help.d.ts +34 -34
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +17 -8
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/impact.d.ts +2 -1
- package/dist/cli/impact.d.ts.map +1 -1
- package/dist/cli/impact.js +5 -0
- package/dist/cli/impact.js.map +1 -1
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +3 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/indexPolicy.d.ts.map +1 -1
- package/dist/cli/indexPolicy.js.map +1 -1
- package/dist/cli/inspect.d.ts +2 -1
- package/dist/cli/inspect.d.ts.map +1 -1
- package/dist/cli/inspect.js +25 -13
- package/dist/cli/inspect.js.map +1 -1
- package/dist/cli/invocationContext.d.ts.map +1 -1
- package/dist/cli/invocationContext.js +3 -0
- package/dist/cli/invocationContext.js.map +1 -1
- package/dist/cli/links.d.ts +2 -0
- package/dist/cli/links.d.ts.map +1 -1
- package/dist/cli/links.js +1 -1
- package/dist/cli/links.js.map +1 -1
- package/dist/cli/navigation.d.ts +41 -1
- package/dist/cli/navigation.d.ts.map +1 -1
- package/dist/cli/navigation.js +4 -1
- package/dist/cli/navigation.js.map +1 -1
- package/dist/cli/options.d.ts.map +1 -1
- package/dist/cli/options.js +9 -7
- package/dist/cli/options.js.map +1 -1
- package/dist/cli/review.d.ts +2 -1
- package/dist/cli/review.d.ts.map +1 -1
- package/dist/cli/review.js +5 -0
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/skill.js +1 -1
- package/dist/cli/skill.js.map +1 -1
- package/dist/cli/viewer.d.ts.map +1 -1
- package/dist/cli/viewer.js +46 -34
- package/dist/cli/viewer.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -3
- package/dist/config.js.map +1 -1
- package/dist/documentLinks/check.d.ts +2 -1
- package/dist/documentLinks/check.d.ts.map +1 -1
- package/dist/documentLinks/check.js +2 -2
- package/dist/documentLinks/check.js.map +1 -1
- package/dist/duplicate-token-normalization.d.ts.map +1 -1
- package/dist/duplicate-token-normalization.js +10 -2
- package/dist/duplicate-token-normalization.js.map +1 -1
- package/dist/duplicates/scoring.d.ts +0 -10
- package/dist/duplicates/scoring.d.ts.map +1 -1
- package/dist/duplicates/scoring.js +9 -9
- package/dist/duplicates/scoring.js.map +1 -1
- package/dist/duplicates/unitCache.d.ts +15 -9
- package/dist/duplicates/unitCache.d.ts.map +1 -1
- package/dist/duplicates/unitCache.js +184 -33
- package/dist/duplicates/unitCache.js.map +1 -1
- package/dist/duplicates/units.d.ts +6 -15
- package/dist/duplicates/units.d.ts.map +1 -1
- package/dist/duplicates/units.js +36 -18
- package/dist/duplicates/units.js.map +1 -1
- package/dist/frameworks/angularjs.d.ts.map +1 -1
- package/dist/frameworks/angularjs.js +18 -12
- package/dist/frameworks/angularjs.js.map +1 -1
- package/dist/graph-builder.d.ts.map +1 -1
- package/dist/graph-builder.js +12 -9
- package/dist/graph-builder.js.map +1 -1
- package/dist/graph-edge-collector.d.ts +1 -0
- package/dist/graph-edge-collector.d.ts.map +1 -1
- package/dist/graph-edge-collector.js +1 -1
- package/dist/graph-edge-collector.js.map +1 -1
- package/dist/graphs/grep.d.ts.map +1 -1
- package/dist/graphs/grep.js +7 -2
- package/dist/graphs/grep.js.map +1 -1
- package/dist/graphs/specifiers.d.ts.map +1 -1
- package/dist/graphs/specifiers.js +8 -2
- package/dist/graphs/specifiers.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed.js +3 -1
- package/dist/graphs/symbol-graph-detailed.js.map +1 -1
- package/dist/impact/analyzer.d.ts.map +1 -1
- package/dist/impact/analyzer.js +15 -1
- package/dist/impact/analyzer.js.map +1 -1
- package/dist/impact/call-compatibility/textScanner.d.ts +23 -0
- package/dist/impact/call-compatibility/textScanner.d.ts.map +1 -0
- package/dist/impact/call-compatibility/textScanner.js +615 -0
- package/dist/impact/call-compatibility/textScanner.js.map +1 -0
- package/dist/impact/callCompatibility.d.ts.map +1 -1
- package/dist/impact/callCompatibility.js +9 -570
- package/dist/impact/callCompatibility.js.map +1 -1
- package/dist/impact/direct.js +7 -6
- package/dist/impact/direct.js.map +1 -1
- package/dist/impact/index.d.ts +6 -0
- package/dist/impact/index.d.ts.map +1 -1
- package/dist/impact/index.js +0 -8
- package/dist/impact/index.js.map +1 -1
- package/dist/impact/map.js +2 -2
- package/dist/impact/map.js.map +1 -1
- package/dist/impact/memberResolutionCoverage.d.ts.map +1 -1
- package/dist/impact/memberResolutionCoverage.js +5 -1
- package/dist/impact/memberResolutionCoverage.js.map +1 -1
- package/dist/impact/parse.d.ts.map +1 -1
- package/dist/impact/parse.js +98 -36
- package/dist/impact/parse.js.map +1 -1
- package/dist/impact/referenceCache.js +1 -1
- package/dist/impact/referenceCache.js.map +1 -1
- package/dist/impact/report-suggestions.d.ts.map +1 -1
- package/dist/impact/report-suggestions.js +330 -61
- package/dist/impact/report-suggestions.js.map +1 -1
- package/dist/impact/reportCompact.js +7 -0
- package/dist/impact/reportCompact.js.map +1 -1
- package/dist/impact/streaming.d.ts +32 -2
- package/dist/impact/streaming.d.ts.map +1 -1
- package/dist/impact/streaming.js +61 -2
- package/dist/impact/streaming.js.map +1 -1
- package/dist/impact/suggestions.d.ts.map +1 -1
- package/dist/impact/suggestions.js +1 -1
- package/dist/impact/suggestions.js.map +1 -1
- package/dist/impact/types.d.ts +7 -20
- package/dist/impact/types.d.ts.map +1 -1
- package/dist/impact/types.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/indexer/build-cache/location.d.ts +19 -0
- package/dist/indexer/build-cache/location.d.ts.map +1 -0
- package/dist/indexer/build-cache/location.js +132 -0
- package/dist/indexer/build-cache/location.js.map +1 -0
- package/dist/indexer/build-cache/manifest.d.ts +9 -3
- package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
- package/dist/indexer/build-cache/manifest.js +77 -20
- package/dist/indexer/build-cache/manifest.js.map +1 -1
- package/dist/indexer/build-cache/module-cache.d.ts +23 -2
- package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
- package/dist/indexer/build-cache/module-cache.js +92 -32
- package/dist/indexer/build-cache/module-cache.js.map +1 -1
- package/dist/indexer/build-cache/options.d.ts +3 -1
- package/dist/indexer/build-cache/options.d.ts.map +1 -1
- package/dist/indexer/build-cache/options.js +10 -2
- package/dist/indexer/build-cache/options.js.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.d.ts +32 -8
- package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.js +333 -44
- package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
- package/dist/indexer/build-cache/reports.d.ts.map +1 -1
- package/dist/indexer/build-cache/reports.js +10 -1
- package/dist/indexer/build-cache/reports.js.map +1 -1
- package/dist/indexer/build-cache/resolver-environment.d.ts +9 -0
- package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -0
- package/dist/indexer/build-cache/resolver-environment.js +133 -0
- package/dist/indexer/build-cache/resolver-environment.js.map +1 -0
- package/dist/indexer/build-cache.d.ts +4 -3
- package/dist/indexer/build-cache.d.ts.map +1 -1
- package/dist/indexer/build-cache.js +4 -3
- package/dist/indexer/build-cache.js.map +1 -1
- package/dist/indexer/build-index.d.ts.map +1 -1
- package/dist/indexer/build-index.js +154 -47
- package/dist/indexer/build-index.js.map +1 -1
- package/dist/indexer/build-manifest.d.ts +1 -0
- package/dist/indexer/build-manifest.d.ts.map +1 -1
- package/dist/indexer/build-manifest.js +12 -5
- package/dist/indexer/build-manifest.js.map +1 -1
- package/dist/indexer/call-hierarchy.d.ts.map +1 -1
- package/dist/indexer/call-hierarchy.js.map +1 -1
- package/dist/indexer/finalize.d.ts.map +1 -1
- package/dist/indexer/finalize.js +7 -4
- package/dist/indexer/finalize.js.map +1 -1
- package/dist/indexer/imports/jsTextImports.d.ts.map +1 -1
- package/dist/indexer/imports/jsTextImports.js +14 -6
- package/dist/indexer/imports/jsTextImports.js.map +1 -1
- package/dist/indexer/imports/languageSpecific.d.ts.map +1 -1
- package/dist/indexer/imports/languageSpecific.js +10 -5
- package/dist/indexer/imports/languageSpecific.js.map +1 -1
- package/dist/indexer/imports/nativeCaptures.d.ts.map +1 -1
- package/dist/indexer/imports/nativeCaptures.js +4 -1
- package/dist/indexer/imports/nativeCaptures.js.map +1 -1
- package/dist/indexer/imports/python.d.ts.map +1 -1
- package/dist/indexer/imports/python.js +7 -2
- package/dist/indexer/imports/python.js.map +1 -1
- package/dist/indexer/load-current-index.d.ts.map +1 -1
- package/dist/indexer/load-current-index.js.map +1 -1
- package/dist/indexer/locals-and-exports.d.ts.map +1 -1
- package/dist/indexer/locals-and-exports.js +52 -22
- package/dist/indexer/locals-and-exports.js.map +1 -1
- package/dist/indexer/navigation-goto.d.ts.map +1 -1
- package/dist/indexer/navigation-goto.js +26 -16
- package/dist/indexer/navigation-goto.js.map +1 -1
- package/dist/indexer/navigation-local.d.ts.map +1 -1
- package/dist/indexer/navigation-local.js +7 -4
- package/dist/indexer/navigation-local.js.map +1 -1
- package/dist/indexer/navigation-references.d.ts +1 -1
- package/dist/indexer/navigation-references.d.ts.map +1 -1
- package/dist/indexer/navigation-references.js +27 -16
- package/dist/indexer/navigation-references.js.map +1 -1
- package/dist/indexer/navigation-resolve.d.ts.map +1 -1
- package/dist/indexer/navigation-resolve.js +116 -53
- package/dist/indexer/navigation-resolve.js.map +1 -1
- package/dist/indexer/navigation.d.ts +2 -1
- package/dist/indexer/navigation.d.ts.map +1 -1
- package/dist/indexer/navigation.js +24 -20
- package/dist/indexer/navigation.js.map +1 -1
- package/dist/indexer/parse-context.d.ts +1 -1
- package/dist/indexer/parse-context.d.ts.map +1 -1
- package/dist/indexer/parse-context.js +2 -2
- package/dist/indexer/parse-context.js.map +1 -1
- package/dist/indexer/reference-context.d.ts +2 -2
- package/dist/indexer/reference-context.d.ts.map +1 -1
- package/dist/indexer/reference-context.js +4 -2
- package/dist/indexer/reference-context.js.map +1 -1
- package/dist/indexer/scope-types.d.ts +3 -0
- package/dist/indexer/scope-types.d.ts.map +1 -1
- package/dist/indexer/scope.js +37 -38
- package/dist/indexer/scope.js.map +1 -1
- package/dist/indexer/shared.d.ts.map +1 -1
- package/dist/indexer/shared.js +3 -1
- package/dist/indexer/shared.js.map +1 -1
- package/dist/indexer/type-hierarchy.d.ts.map +1 -1
- package/dist/indexer/type-hierarchy.js +12 -8
- package/dist/indexer/type-hierarchy.js.map +1 -1
- package/dist/indexer/types.d.ts +22 -0
- package/dist/indexer/types.d.ts.map +1 -1
- package/dist/indexer/workspace-symbols.d.ts.map +1 -1
- package/dist/indexer/workspace-symbols.js +5 -3
- package/dist/indexer/workspace-symbols.js.map +1 -1
- package/dist/installer/locks.d.ts +10 -0
- package/dist/installer/locks.d.ts.map +1 -0
- package/dist/installer/locks.js +234 -0
- package/dist/installer/locks.js.map +1 -0
- package/dist/installer/registry.d.ts.map +1 -1
- package/dist/installer/registry.js +13 -230
- package/dist/installer/registry.js.map +1 -1
- package/dist/languages/definitions/csharp.d.ts.map +1 -1
- package/dist/languages/definitions/csharp.js +8 -0
- package/dist/languages/definitions/csharp.js.map +1 -1
- package/dist/languages/definitions/java.d.ts.map +1 -1
- package/dist/languages/definitions/java.js +3 -0
- package/dist/languages/definitions/java.js.map +1 -1
- package/dist/languages/definitions/python.d.ts.map +1 -1
- package/dist/languages/definitions/python.js +2 -0
- package/dist/languages/definitions/python.js.map +1 -1
- package/dist/languages/definitions/rust.d.ts.map +1 -1
- package/dist/languages/definitions/rust.js +2 -0
- package/dist/languages/definitions/rust.js.map +1 -1
- package/dist/languages/importStatementParsers.d.ts +2 -0
- package/dist/languages/importStatementParsers.d.ts.map +1 -1
- package/dist/languages/importStatementParsers.js +24 -10
- package/dist/languages/importStatementParsers.js.map +1 -1
- package/dist/mcp/http.d.ts +3 -1
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/http.js +69 -20
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/server.d.ts +43 -16
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +342 -127
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +51 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +121 -2
- package/dist/mcp/tools.js.map +1 -1
- package/dist/native/byteIndex.d.ts +26 -0
- package/dist/native/byteIndex.d.ts.map +1 -0
- package/dist/native/byteIndex.js +70 -0
- package/dist/native/byteIndex.js.map +1 -0
- package/dist/native/projectedTree.d.ts +3 -2
- package/dist/native/projectedTree.d.ts.map +1 -1
- package/dist/native/projectedTree.js +6 -50
- package/dist/native/projectedTree.js.map +1 -1
- package/dist/native/queryResults.d.ts +7 -1
- package/dist/native/queryResults.d.ts.map +1 -1
- package/dist/native/queryResults.js +13 -5
- package/dist/native/queryResults.js.map +1 -1
- package/dist/review/changes.d.ts +2 -0
- package/dist/review/changes.d.ts.map +1 -1
- package/dist/review/changes.js +10 -0
- package/dist/review/changes.js.map +1 -1
- package/dist/review/deleted.d.ts.map +1 -1
- package/dist/review/deleted.js +20 -2
- package/dist/review/deleted.js.map +1 -1
- package/dist/review/summaries.d.ts.map +1 -1
- package/dist/review/summaries.js +13 -10
- package/dist/review/summaries.js.map +1 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +7 -2
- package/dist/review.js.map +1 -1
- package/dist/session.d.ts +20 -4
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +76 -16
- package/dist/session.js.map +1 -1
- package/dist/sql/types.d.ts.map +1 -1
- package/dist/sqlite/query.d.ts +29 -0
- package/dist/sqlite/query.d.ts.map +1 -1
- package/dist/sqlite/query.js +98 -11
- package/dist/sqlite/query.js.map +1 -1
- package/dist/sqlite/rawQueryWorker.d.ts +22 -0
- package/dist/sqlite/rawQueryWorker.d.ts.map +1 -0
- package/dist/sqlite/rawQueryWorker.js +31 -0
- package/dist/sqlite/rawQueryWorker.js.map +1 -0
- package/dist/sqlite/rawQueryWorkerPool.d.ts +66 -0
- package/dist/sqlite/rawQueryWorkerPool.d.ts.map +1 -0
- package/dist/sqlite/rawQueryWorkerPool.js +142 -0
- package/dist/sqlite/rawQueryWorkerPool.js.map +1 -0
- package/dist/sqlite/schema.d.ts.map +1 -1
- package/dist/sqlite/schema.js.map +1 -1
- package/dist/sqlite-driver.d.ts.map +1 -1
- package/dist/sqlite-driver.js +2 -1
- package/dist/sqlite-driver.js.map +1 -1
- package/dist/sqlite.d.ts +1 -1
- package/dist/sqlite.d.ts.map +1 -1
- package/dist/sqlite.js +1 -1
- package/dist/sqlite.js.map +1 -1
- package/dist/util/bloomFilter.d.ts +3 -2
- package/dist/util/bloomFilter.d.ts.map +1 -1
- package/dist/util/bloomFilter.js +8 -8
- package/dist/util/bloomFilter.js.map +1 -1
- package/dist/util/confinedFile.d.ts +41 -2
- package/dist/util/confinedFile.d.ts.map +1 -1
- package/dist/util/confinedFile.js +101 -2
- package/dist/util/confinedFile.js.map +1 -1
- package/dist/util/git.d.ts +2 -0
- package/dist/util/git.d.ts.map +1 -1
- package/dist/util/git.js +109 -26
- package/dist/util/git.js.map +1 -1
- package/dist/util/identifiers.d.ts +75 -0
- package/dist/util/identifiers.d.ts.map +1 -0
- package/dist/util/identifiers.js +82 -0
- package/dist/util/identifiers.js.map +1 -0
- package/dist/util/paths.d.ts.map +1 -1
- package/dist/util/paths.js.map +1 -1
- package/dist/util/projectFiles.d.ts.map +1 -1
- package/dist/util/projectFiles.js +43 -14
- package/dist/util/projectFiles.js.map +1 -1
- package/dist/util/resolution/jvm.d.ts.map +1 -1
- package/dist/util/resolution/jvm.js +9 -4
- package/dist/util/resolution/jvm.js.map +1 -1
- package/dist/util/resolution/php.d.ts.map +1 -1
- package/dist/util/resolution/php.js +6 -5
- package/dist/util/resolution/php.js.map +1 -1
- package/dist/util/rustTestModules.d.ts.map +1 -1
- package/dist/util/rustTestModules.js +4 -2
- package/dist/util/rustTestModules.js.map +1 -1
- package/dist/util/specifiers.d.ts.map +1 -1
- package/dist/util/specifiers.js +10 -3
- package/dist/util/specifiers.js.map +1 -1
- package/dist/util/sqliteSchema.d.ts.map +1 -1
- package/dist/util/sqliteSchema.js +10 -1
- package/dist/util/sqliteSchema.js.map +1 -1
- package/docs/mcp.md +32 -13
- package/package.json +3 -3
|
@@ -6,29 +6,32 @@ import { buildGraphAdjacency } from "../../graphs/adjacency.js";
|
|
|
6
6
|
import { buildReferenceCandidateIndex } from "../reference-candidates.js";
|
|
7
7
|
import { BloomFilter, BloomFilterCache } from "../../util/bloomFilter.js";
|
|
8
8
|
import { summarizeAnalysis } from "../../analysisSummary.js";
|
|
9
|
-
import { fileIdentityKey, isFilePathWithinRoot, normalizePath } from "../../util/paths.js";
|
|
9
|
+
import { assertFilePathWithinRoot, fileIdentityKey, isFilePathWithinRoot, normalizePath } from "../../util/paths.js";
|
|
10
10
|
import { getNativeRuntimeFingerprint } from "../../native/treeSitterNative.js";
|
|
11
11
|
import { SymbolKind } from "../types.js";
|
|
12
12
|
import { buildSymbolGraph, } from "../../graphs/symbol-graph.js";
|
|
13
13
|
import { getImplementationFingerprint, normalizeGraphOptions } from "./options.js";
|
|
14
|
-
import {
|
|
14
|
+
import { cacheAbsolutePath, cacheRelativePath, transformPersistedExportFromModule, } from "./module-cache.js";
|
|
15
|
+
import { cacheRoot } from "./location.js";
|
|
15
16
|
const SNAPSHOT_SYMBOL_KINDS = new Set(Object.values(SymbolKind));
|
|
16
|
-
const PROJECT_SNAPSHOT_VERSION =
|
|
17
|
+
const PROJECT_SNAPSHOT_VERSION = 9;
|
|
18
|
+
export const BLOOM_FILTER_SNAPSHOT_VERSION = 4;
|
|
19
|
+
export const BLOOM_FILTER_SNAPSHOT_FILENAME = "bloom-filters.json";
|
|
17
20
|
const BLOOM_FILTER_MIN_SIZE = 1_000;
|
|
18
21
|
const BLOOM_FILTER_MAX_SIZE = 1_000_000;
|
|
19
22
|
const BLOOM_FILTER_MIN_HASH_COUNT = 1;
|
|
20
23
|
const BLOOM_FILTER_MAX_HASH_COUNT = 10;
|
|
21
|
-
const DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION =
|
|
24
|
+
const DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION = 3;
|
|
22
25
|
const DETAILED_SYMBOL_GRAPH_SNAPSHOT_FILENAME = "detailed-symbol-graph.json";
|
|
23
26
|
const SNAPSHOT_TEMP_RETENTION_MS = 24 * 60 * 60 * 1_000;
|
|
24
27
|
const SNAPSHOT_TEMP_SUFFIX = ".tmp";
|
|
25
28
|
const MAX_SNAPSHOT_CACHE_ENTRIES = 32;
|
|
26
29
|
const parsedSnapshotCache = new Map();
|
|
27
30
|
const detailedSymbolGraphCache = new Map();
|
|
28
|
-
export function projectSnapshotFilesSignature(entries) {
|
|
31
|
+
export function projectSnapshotFilesSignature(entries, projectRoot) {
|
|
29
32
|
const hash = createHash("sha256");
|
|
30
33
|
for (const [file, entry] of [...entries.entries()].sort(([left], [right]) => compareSnapshotPath(left, right))) {
|
|
31
|
-
hash.update(file);
|
|
34
|
+
hash.update(projectRoot ? cacheRelativePath(projectRoot, file) : file);
|
|
32
35
|
hash.update("\0");
|
|
33
36
|
hash.update(entry.sig);
|
|
34
37
|
hash.update("\0");
|
|
@@ -55,8 +58,115 @@ export function createProjectSnapshotIdentity(filesSignature, opts) {
|
|
|
55
58
|
function serializedProjectRoot(projectRoot) {
|
|
56
59
|
return normalizePath(path.resolve(projectRoot));
|
|
57
60
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
61
|
+
function transformPath(root, value, toRelative) {
|
|
62
|
+
if (toRelative) {
|
|
63
|
+
return path.isAbsolute(value) ? cacheRelativePath(root, value) : value;
|
|
64
|
+
}
|
|
65
|
+
return assertFilePathWithinRoot(root, cacheAbsolutePath(root, value), "Persisted cache path");
|
|
66
|
+
}
|
|
67
|
+
function transformHandle(root, value, toRelative) {
|
|
68
|
+
const separator = value.indexOf("::");
|
|
69
|
+
if (separator < 0)
|
|
70
|
+
return transformPath(root, value, toRelative);
|
|
71
|
+
const file = value.slice(0, separator);
|
|
72
|
+
return `${transformPath(root, file, toRelative)}${value.slice(separator)}`;
|
|
73
|
+
}
|
|
74
|
+
function transformModule(root, module, toRelative) {
|
|
75
|
+
const copy = structuredClone(module);
|
|
76
|
+
const file = (value) => transformPath(root, value, toRelative);
|
|
77
|
+
copy.file = file(copy.file);
|
|
78
|
+
for (const local of copy.locals)
|
|
79
|
+
local.file = file(local.file);
|
|
80
|
+
for (const entry of copy.exports) {
|
|
81
|
+
if (entry.type === "local") {
|
|
82
|
+
entry.target.file = file(entry.target.file);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
transformPersistedExportFromModule(root, entry, toRelative);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const binding of copy.imports) {
|
|
89
|
+
if (typeof binding.resolved === "string")
|
|
90
|
+
binding.resolved = file(binding.resolved);
|
|
91
|
+
}
|
|
92
|
+
return copy;
|
|
93
|
+
}
|
|
94
|
+
function transformSnapshotPaths(payload, root, toRelative) {
|
|
95
|
+
const copy = structuredClone(payload);
|
|
96
|
+
copy.graph.nodes = copy.graph.nodes.map((node) => transformPath(root, node, toRelative));
|
|
97
|
+
copy.graph.edges = copy.graph.edges.map((edge) => ({
|
|
98
|
+
...edge,
|
|
99
|
+
from: transformPath(root, edge.from, toRelative),
|
|
100
|
+
to: edge.to.type === "file" ? { ...edge.to, path: transformPath(root, edge.to.path, toRelative) } : edge.to,
|
|
101
|
+
}));
|
|
102
|
+
copy.modules = copy.modules.map((module) => transformModule(root, module, toRelative));
|
|
103
|
+
if (copy.projectFiles) {
|
|
104
|
+
copy.projectFiles = copy.projectFiles.map((file) => ({
|
|
105
|
+
...file,
|
|
106
|
+
path: transformPath(root, file.path, toRelative),
|
|
107
|
+
projectRoot: transformPath(root, file.projectRoot, toRelative),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
if (copy.bloomFilters) {
|
|
111
|
+
const bloomFilters = {};
|
|
112
|
+
for (const [file, filter] of Object.entries(copy.bloomFilters)) {
|
|
113
|
+
bloomFilters[transformPath(root, file, toRelative)] = filter;
|
|
114
|
+
}
|
|
115
|
+
copy.bloomFilters = bloomFilters;
|
|
116
|
+
}
|
|
117
|
+
const fileSignatures = {};
|
|
118
|
+
for (const [file, signature] of Object.entries(copy.fileSignatures ?? {})) {
|
|
119
|
+
fileSignatures[transformPath(root, file, toRelative)] = signature;
|
|
120
|
+
}
|
|
121
|
+
copy.fileSignatures = fileSignatures;
|
|
122
|
+
return copy;
|
|
123
|
+
}
|
|
124
|
+
function migrateProjectSnapshotPayload(value, currentRoot) {
|
|
125
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
126
|
+
return value;
|
|
127
|
+
const payload = value;
|
|
128
|
+
if ((payload.version !== 4 && payload.version !== 5) || typeof payload.projectRoot !== "string")
|
|
129
|
+
return value;
|
|
130
|
+
const relative = transformSnapshotPaths(value, payload.projectRoot, true);
|
|
131
|
+
const migrated = transformSnapshotPaths(relative, currentRoot, false);
|
|
132
|
+
migrated.version = PROJECT_SNAPSHOT_VERSION;
|
|
133
|
+
migrated.projectRoot = serializedProjectRoot(currentRoot);
|
|
134
|
+
return migrated;
|
|
135
|
+
}
|
|
136
|
+
function transformDetailedGraph(graph, root, toRelative) {
|
|
137
|
+
return {
|
|
138
|
+
nodes: graph.nodes.map((node) => {
|
|
139
|
+
const file = transformPath(root, node.file, toRelative);
|
|
140
|
+
return { ...node, file, id: transformHandle(root, node.id, toRelative) };
|
|
141
|
+
}),
|
|
142
|
+
edges: graph.edges.map((edge) => ({
|
|
143
|
+
...edge,
|
|
144
|
+
from: transformHandle(root, edge.from, toRelative),
|
|
145
|
+
to: transformHandle(root, edge.to, toRelative),
|
|
146
|
+
...(edge.site
|
|
147
|
+
? {
|
|
148
|
+
site: {
|
|
149
|
+
...edge.site,
|
|
150
|
+
file: transformPath(root, edge.site.file, toRelative),
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
: {}),
|
|
154
|
+
})),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function migrateDetailedSymbolGraphPayload(value, currentRoot) {
|
|
158
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
159
|
+
return value;
|
|
160
|
+
const payload = value;
|
|
161
|
+
if (payload.version !== 2 || typeof payload.projectRoot !== "string" || !payload.graph)
|
|
162
|
+
return value;
|
|
163
|
+
const relativeGraph = transformDetailedGraph(payload.graph, payload.projectRoot, true);
|
|
164
|
+
return {
|
|
165
|
+
...payload,
|
|
166
|
+
version: DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION,
|
|
167
|
+
projectRoot: serializedProjectRoot(currentRoot),
|
|
168
|
+
graph: transformDetailedGraph(relativeGraph, currentRoot, false),
|
|
169
|
+
};
|
|
60
170
|
}
|
|
61
171
|
function compareSnapshotPath(left, right) {
|
|
62
172
|
if (left < right)
|
|
@@ -182,23 +292,24 @@ function projectIndexManifestEntries(entries) {
|
|
|
182
292
|
]));
|
|
183
293
|
}
|
|
184
294
|
export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEntries) {
|
|
185
|
-
const filesSignature = projectSnapshotFilesSignature(manifestEntries);
|
|
295
|
+
const filesSignature = projectSnapshotFilesSignature(manifestEntries, projectRoot);
|
|
186
296
|
if ((opts?.cache ?? "off") !== "disk")
|
|
187
297
|
return null;
|
|
188
298
|
try {
|
|
189
299
|
const rawPayload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
|
|
300
|
+
const migratedPayload = migrateProjectSnapshotPayload(rawPayload, projectRoot);
|
|
301
|
+
const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
|
|
302
|
+
? transformSnapshotPaths(migratedPayload, projectRoot, false)
|
|
303
|
+
: migratedPayload;
|
|
190
304
|
const nativeRuntimeFingerprint = getNativeRuntimeFingerprint(opts?.native);
|
|
191
305
|
const implementationFingerprint = getImplementationFingerprint();
|
|
192
|
-
if (!isProjectIndexSnapshotPayload(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
rawPayload.implementationFingerprint !== implementationFingerprint) {
|
|
306
|
+
if (!isProjectIndexSnapshotPayload(payload) ||
|
|
307
|
+
payload.filesSignature !== filesSignature ||
|
|
308
|
+
payload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
|
|
309
|
+
payload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
|
|
310
|
+
payload.implementationFingerprint !== implementationFingerprint) {
|
|
198
311
|
return null;
|
|
199
312
|
}
|
|
200
|
-
// Payload is freshly JSON.parsed from memoized compressed bytes (no deep clone).
|
|
201
|
-
const payload = rawPayload;
|
|
202
313
|
const graph = {
|
|
203
314
|
nodes: new Set(payload.graph.nodes),
|
|
204
315
|
edges: payload.graph.edges,
|
|
@@ -211,11 +322,12 @@ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEnt
|
|
|
211
322
|
modules,
|
|
212
323
|
byFile: modules,
|
|
213
324
|
projectRoot: serializedProjectRoot(projectRoot),
|
|
325
|
+
...(payload.languageExtensions ? { languageExtensions: payload.languageExtensions } : {}),
|
|
214
326
|
...(payload.nativeMode ? { nativeMode: payload.nativeMode } : {}),
|
|
215
327
|
exportCache: new Map(),
|
|
216
328
|
scopeCache: new Map(),
|
|
217
329
|
...(shouldHydrateBloomFilters && payload.bloomFilters
|
|
218
|
-
? { bloomFilters: deserializeBloomFilterCache(payload.bloomFilters) }
|
|
330
|
+
? { bloomFilters: deserializeBloomFilterCache(payload.bloomFilters, projectRoot) }
|
|
219
331
|
: {}),
|
|
220
332
|
...(payload.projectFiles ? { projectFiles: payload.projectFiles } : {}),
|
|
221
333
|
referenceCandidates: buildReferenceCandidateIndex(modules),
|
|
@@ -236,51 +348,148 @@ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEnt
|
|
|
236
348
|
}
|
|
237
349
|
}
|
|
238
350
|
/**
|
|
239
|
-
* Load only the bloom-filter section of the last-written project snapshot
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* is safe to reuse after its snapshot's root and implementation fingerprints are validated.
|
|
351
|
+
* Load only the bloom-filter section of the last-written project snapshot. Hydration checks
|
|
352
|
+
* each requested file against its persisted signature before returning a filter, so a stale
|
|
353
|
+
* snapshot can still accelerate unchanged files without suppressing newly added references.
|
|
243
354
|
* Only the bloom section is then read, so a corrupt payload is rejected without walking
|
|
244
355
|
* `graph.edges` / `modules`. Returns `null` when disk caching is off, `useBloomFilters` is
|
|
245
356
|
* disabled, or no valid snapshot with bloom data exists.
|
|
246
357
|
*/
|
|
358
|
+
export async function tryLoadProjectSnapshotModules(projectRoot, opts, fileSignatures) {
|
|
359
|
+
if ((opts?.cache ?? "off") !== "disk")
|
|
360
|
+
return null;
|
|
361
|
+
try {
|
|
362
|
+
const rawPayload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
|
|
363
|
+
const migratedPayload = migrateProjectSnapshotPayload(rawPayload, projectRoot);
|
|
364
|
+
const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
|
|
365
|
+
? transformSnapshotPaths(migratedPayload, projectRoot, false)
|
|
366
|
+
: migratedPayload;
|
|
367
|
+
const nativeRuntimeFingerprint = getNativeRuntimeFingerprint(opts?.native);
|
|
368
|
+
const implementationFingerprint = getImplementationFingerprint();
|
|
369
|
+
if (!isProjectIndexSnapshotPayload(payload) ||
|
|
370
|
+
payload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
|
|
371
|
+
payload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
|
|
372
|
+
payload.implementationFingerprint !== implementationFingerprint) {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
const normalizedFileSignatures = new Map(Object.entries(payload.fileSignatures).map(([file, signature]) => [fileIdentityKey(file), signature]));
|
|
376
|
+
// `fileSignatures` (caller-supplied) is keyed by whatever discovered display path each file
|
|
377
|
+
// was found under, not necessarily `fileIdentityKey`-normalized; on a case-insensitive
|
|
378
|
+
// filesystem an uppercase path segment would otherwise miss this lookup.
|
|
379
|
+
const normalizedCurrentSignatures = new Map(Array.from(fileSignatures, ([file, signature]) => [fileIdentityKey(file), signature]));
|
|
380
|
+
const modules = new Map();
|
|
381
|
+
for (const mod of payload.modules) {
|
|
382
|
+
const moduleKey = fileIdentityKey(mod.file);
|
|
383
|
+
const signature = normalizedCurrentSignatures.get(moduleKey);
|
|
384
|
+
const snapshotSignature = normalizedFileSignatures.get(moduleKey);
|
|
385
|
+
if (!signature || !snapshotSignature || !snapshotSignatureMatches(snapshotSignature, signature))
|
|
386
|
+
continue;
|
|
387
|
+
modules.set(moduleKey, mod);
|
|
388
|
+
}
|
|
389
|
+
return modules;
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
247
395
|
export async function tryLoadPersistedBloomFilters(projectRoot, opts) {
|
|
248
396
|
if ((opts?.cache ?? "off") !== "disk" || (opts?.useBloomFilters ?? true) === false)
|
|
249
397
|
return null;
|
|
398
|
+
try {
|
|
399
|
+
const sidecarPath = bloomFilterSnapshotPath(projectRoot, opts);
|
|
400
|
+
const sidecarParsed = (await readParsedSnapshot(sidecarPath)).payload;
|
|
401
|
+
const sidecarBloom = persistedBloomFiltersFromSidecar(sidecarParsed, projectRoot);
|
|
402
|
+
if (sidecarBloom) {
|
|
403
|
+
return createPersistedBloomFilters(sidecarBloom.bloomFilters, sidecarBloom.fileSignatures, projectRoot);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
// Fall back to legacy project snapshot payload if sidecar is unavailable or corrupt
|
|
408
|
+
}
|
|
250
409
|
try {
|
|
251
410
|
const payload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
|
|
252
411
|
const bloomFilters = persistedBloomFiltersFromSnapshot(payload, projectRoot);
|
|
253
412
|
if (!bloomFilters)
|
|
254
413
|
return null;
|
|
255
|
-
return
|
|
414
|
+
return createPersistedBloomFilters(bloomFilters.bloomFilters, bloomFilters.fileSignatures, projectRoot);
|
|
256
415
|
}
|
|
257
416
|
catch {
|
|
258
417
|
return null;
|
|
259
418
|
}
|
|
260
419
|
}
|
|
261
|
-
|
|
262
|
-
function persistedBloomFiltersFromSnapshot(value, projectRoot) {
|
|
420
|
+
function persistedBloomFiltersFromSidecar(value, projectRoot) {
|
|
263
421
|
if (!value || typeof value !== "object")
|
|
264
422
|
return null;
|
|
265
423
|
const payload = value;
|
|
424
|
+
if (payload.version !== BLOOM_FILTER_SNAPSHOT_VERSION ||
|
|
425
|
+
typeof payload.projectRoot !== "string" ||
|
|
426
|
+
payload.implementationFingerprint !== getImplementationFingerprint() ||
|
|
427
|
+
typeof payload.projectSnapshotIdentity !== "string" ||
|
|
428
|
+
!/^[a-f0-9]{64}$/.test(payload.projectSnapshotIdentity)) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
const bloomFilters = payload.bloomFilters;
|
|
432
|
+
const fileSignatures = payload.fileSignatures;
|
|
433
|
+
if (!isSerializedBloomFilterRecord(bloomFilters) || !isSnapshotFileSignatureRecord(fileSignatures)) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
return { bloomFilters, fileSignatures };
|
|
437
|
+
}
|
|
438
|
+
/** Light validation for bloom hydration: snapshot version, root identity, and bloom section only. */
|
|
439
|
+
function persistedBloomFiltersFromSnapshot(value, projectRoot) {
|
|
440
|
+
const migrated = migrateProjectSnapshotPayload(value, projectRoot);
|
|
441
|
+
if (!migrated || typeof migrated !== "object")
|
|
442
|
+
return null;
|
|
443
|
+
const payload = migrated;
|
|
266
444
|
if (payload.version !== PROJECT_SNAPSHOT_VERSION ||
|
|
267
445
|
typeof payload.projectRoot !== "string" ||
|
|
268
|
-
!projectRootMatches(projectRoot, payload.projectRoot) ||
|
|
269
446
|
payload.implementationFingerprint !== getImplementationFingerprint()) {
|
|
270
447
|
return null;
|
|
271
448
|
}
|
|
272
|
-
|
|
449
|
+
const bloomFilters = payload.bloomFilters;
|
|
450
|
+
const fileSignatures = payload.fileSignatures;
|
|
451
|
+
if (!isSerializedBloomFilterRecord(bloomFilters) || !isSnapshotFileSignatureRecord(fileSignatures)) {
|
|
273
452
|
return null;
|
|
274
|
-
|
|
453
|
+
}
|
|
454
|
+
return { bloomFilters, fileSignatures };
|
|
455
|
+
}
|
|
456
|
+
function createPersistedBloomFilters(bloomFilters, fileSignatures, projectRoot) {
|
|
457
|
+
const filters = deserializeBloomFilterCache(bloomFilters, projectRoot);
|
|
458
|
+
const signatures = new Map(Object.entries(fileSignatures).map(([file, signature]) => [
|
|
459
|
+
fileIdentityKey(cacheAbsolutePath(projectRoot, file)),
|
|
460
|
+
signature,
|
|
461
|
+
]));
|
|
462
|
+
return {
|
|
463
|
+
get: (file, signature) => {
|
|
464
|
+
const persistedSignature = signatures.get(fileIdentityKey(file));
|
|
465
|
+
if (!persistedSignature || !snapshotSignatureMatches(persistedSignature, signature))
|
|
466
|
+
return undefined;
|
|
467
|
+
return filters.get(file);
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function snapshotSignatureMatches(snapshotSignature, currentSignature) {
|
|
472
|
+
const matchingGitSignature = !!snapshotSignature.gitSig && !!currentSignature.gitSig && snapshotSignature.gitSig === currentSignature.gitSig;
|
|
473
|
+
if (matchingGitSignature)
|
|
474
|
+
return true;
|
|
475
|
+
// `cacheSig` is git- or content-hash-derived (forced whenever caching is enabled without a git
|
|
476
|
+
// signature; see `fileSignature()`), so when both sides have it, it is a strictly stronger and
|
|
477
|
+
// authoritative identity check than the cheap `mtime:size` `sig`. Comparing bare `sig` alone
|
|
478
|
+
// would wrongly treat a same-size edit whose mtime got restored as unchanged.
|
|
479
|
+
if (snapshotSignature.cacheSig !== undefined && currentSignature.cacheSig !== undefined) {
|
|
480
|
+
return snapshotSignature.cacheSig === currentSignature.cacheSig;
|
|
481
|
+
}
|
|
482
|
+
return snapshotSignature.sig === currentSignature.sig;
|
|
275
483
|
}
|
|
276
484
|
export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesSignature) {
|
|
277
485
|
const projectSnapshotIdentity = createProjectSnapshotIdentity(filesSignature, opts);
|
|
486
|
+
const fileSignatures = serializeSnapshotFileSignatures(index.manifestEntries, projectRoot);
|
|
278
487
|
const serializedBloomFilters = index.bloomFilters
|
|
279
|
-
? serializeBloomFilterCache(index.bloomFilters, Array.from(index.byFile.values(), (module) => module.file))
|
|
488
|
+
? serializeBloomFilterCache(index.bloomFilters, Array.from(index.byFile.values(), (module) => module.file), projectRoot)
|
|
280
489
|
: undefined;
|
|
281
490
|
const snapshotAnalysisReport = analysisReportFromBuildReport(index.buildReport);
|
|
282
491
|
const snapshotAnalysis = index.buildReport ? summarizeAnalysis({ index, report: index.buildReport }) : index.analysis;
|
|
283
|
-
const payload = {
|
|
492
|
+
const payload = transformSnapshotPaths({
|
|
284
493
|
version: PROJECT_SNAPSHOT_VERSION,
|
|
285
494
|
filesSignature,
|
|
286
495
|
projectRoot: serializedProjectRoot(projectRoot),
|
|
@@ -291,6 +500,8 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
|
|
|
291
500
|
edges: index.graph.edges,
|
|
292
501
|
},
|
|
293
502
|
modules: [...index.byFile.values()],
|
|
503
|
+
fileSignatures,
|
|
504
|
+
...(index.languageExtensions ? { languageExtensions: index.languageExtensions } : {}),
|
|
294
505
|
...(normalizedSnapshotNativeMode(index.nativeMode)
|
|
295
506
|
? { nativeMode: normalizedSnapshotNativeMode(index.nativeMode) }
|
|
296
507
|
: {}),
|
|
@@ -298,7 +509,7 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
|
|
|
298
509
|
...(serializedBloomFilters ? { bloomFilters: serializedBloomFilters } : {}),
|
|
299
510
|
...(snapshotAnalysis ? { analysis: snapshotAnalysis } : {}),
|
|
300
511
|
...(snapshotAnalysisReport ? { analysisReport: snapshotAnalysisReport } : {}),
|
|
301
|
-
};
|
|
512
|
+
}, projectRoot, true);
|
|
302
513
|
try {
|
|
303
514
|
const snapshotPath = projectSnapshotPath(projectRoot, opts);
|
|
304
515
|
const compressed = brotliCompressSync(JSON.stringify(payload), {
|
|
@@ -308,6 +519,31 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
|
|
|
308
519
|
const identity = await snapshotFileIdentity(snapshotPath);
|
|
309
520
|
setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed });
|
|
310
521
|
index.projectSnapshotIdentity = projectSnapshotIdentity;
|
|
522
|
+
if (serializedBloomFilters) {
|
|
523
|
+
try {
|
|
524
|
+
const bloomPayload = {
|
|
525
|
+
version: BLOOM_FILTER_SNAPSHOT_VERSION,
|
|
526
|
+
projectRoot: serializedProjectRoot(projectRoot),
|
|
527
|
+
implementationFingerprint: getImplementationFingerprint(),
|
|
528
|
+
projectSnapshotIdentity,
|
|
529
|
+
fileSignatures,
|
|
530
|
+
bloomFilters: serializedBloomFilters,
|
|
531
|
+
};
|
|
532
|
+
const bloomPath = bloomFilterSnapshotPath(projectRoot, opts);
|
|
533
|
+
const bloomCompressed = brotliCompressSync(JSON.stringify(bloomPayload), {
|
|
534
|
+
params: { [zlibConstants.BROTLI_PARAM_QUALITY]: 4 },
|
|
535
|
+
});
|
|
536
|
+
await writeSnapshotAtomically(bloomPath, bloomCompressed);
|
|
537
|
+
const bloomIdentity = await snapshotFileIdentity(bloomPath);
|
|
538
|
+
setBoundedSnapshotCache(parsedSnapshotCache, bloomPath, {
|
|
539
|
+
identity: bloomIdentity,
|
|
540
|
+
compressed: bloomCompressed,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
// Bloom sidecar write failure must not fail indexing
|
|
545
|
+
}
|
|
546
|
+
}
|
|
311
547
|
}
|
|
312
548
|
catch {
|
|
313
549
|
delete index.projectSnapshotIdentity;
|
|
@@ -317,6 +553,14 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
|
|
|
317
553
|
function projectSnapshotPath(projectRoot, opts) {
|
|
318
554
|
return path.join(cacheRoot(projectRoot, opts), "project-index-snapshot.json");
|
|
319
555
|
}
|
|
556
|
+
function bloomFilterSnapshotPath(projectRoot, opts) {
|
|
557
|
+
const root = path.resolve(cacheRoot(projectRoot, opts));
|
|
558
|
+
const snapshotPath = path.resolve(root, BLOOM_FILTER_SNAPSHOT_FILENAME);
|
|
559
|
+
if (!isFilePathWithinRoot(root, snapshotPath)) {
|
|
560
|
+
throw new Error(`Bloom filter snapshot escaped cache root: ${snapshotPath}`);
|
|
561
|
+
}
|
|
562
|
+
return snapshotPath;
|
|
563
|
+
}
|
|
320
564
|
export async function tryLoadDetailedSymbolGraphSnapshot(projectRoot, opts, index) {
|
|
321
565
|
if ((opts?.cache ?? "off") !== "disk" || !index.projectSnapshotIdentity)
|
|
322
566
|
return null;
|
|
@@ -331,9 +575,14 @@ export async function tryLoadDetailedSymbolGraphSnapshot(projectRoot, opts, inde
|
|
|
331
575
|
return materializeDetailedSymbolGraph(cached.graph);
|
|
332
576
|
}
|
|
333
577
|
const parsed = await readParsedSnapshot(snapshotPath);
|
|
334
|
-
const
|
|
578
|
+
const migratedPayload = migrateDetailedSymbolGraphPayload(parsed.payload, projectRoot);
|
|
579
|
+
const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
|
|
580
|
+
? {
|
|
581
|
+
...migratedPayload,
|
|
582
|
+
graph: transformDetailedGraph(migratedPayload.graph, projectRoot, false),
|
|
583
|
+
}
|
|
584
|
+
: migratedPayload;
|
|
335
585
|
if (!isDetailedSymbolGraphSnapshotPayload(payload) ||
|
|
336
|
-
!projectRootMatches(projectRoot, payload.projectRoot) ||
|
|
337
586
|
payload.implementationFingerprint !== getImplementationFingerprint() ||
|
|
338
587
|
payload.projectSnapshotIdentity !== index.projectSnapshotIdentity) {
|
|
339
588
|
return null;
|
|
@@ -365,10 +614,10 @@ export async function writeDetailedSymbolGraphSnapshot(projectRoot, opts, index,
|
|
|
365
614
|
implementationFingerprint: getImplementationFingerprint(),
|
|
366
615
|
graphHash: detailedSymbolGraphContentHash(index.projectSnapshotIdentity, graph),
|
|
367
616
|
projectSnapshotIdentity: index.projectSnapshotIdentity,
|
|
368
|
-
graph: {
|
|
617
|
+
graph: transformDetailedGraph({
|
|
369
618
|
nodes: [...graph.nodes.values()],
|
|
370
619
|
edges: graph.edges,
|
|
371
|
-
},
|
|
620
|
+
}, projectRoot, true),
|
|
372
621
|
};
|
|
373
622
|
try {
|
|
374
623
|
const snapshotPath = detailedSymbolGraphSnapshotPath(projectRoot, opts);
|
|
@@ -379,12 +628,14 @@ export async function writeDetailedSymbolGraphSnapshot(projectRoot, opts, index,
|
|
|
379
628
|
});
|
|
380
629
|
await writeSnapshotAtomically(snapshotPath, compressed);
|
|
381
630
|
const identity = await snapshotFileIdentity(snapshotPath);
|
|
382
|
-
const cachedPayload = structuredClone(payload);
|
|
383
631
|
setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed });
|
|
384
632
|
setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, {
|
|
385
633
|
identity,
|
|
386
634
|
projectSnapshotIdentity: index.projectSnapshotIdentity,
|
|
387
|
-
graph:
|
|
635
|
+
graph: {
|
|
636
|
+
nodes: [...graph.nodes.values()],
|
|
637
|
+
edges: graph.edges,
|
|
638
|
+
},
|
|
388
639
|
});
|
|
389
640
|
}
|
|
390
641
|
catch {
|
|
@@ -659,7 +910,9 @@ function isProjectIndexSnapshotPayload(value) {
|
|
|
659
910
|
payload.graph.edges.every(isGraphEdge) &&
|
|
660
911
|
Array.isArray(payload.modules) &&
|
|
661
912
|
payload.modules.every(isModuleIndex) &&
|
|
913
|
+
isSnapshotFileSignatureRecord(payload.fileSignatures) &&
|
|
662
914
|
(payload.nativeMode === undefined || isSnapshotNativeMode(payload.nativeMode)) &&
|
|
915
|
+
(payload.languageExtensions === undefined || isLanguageExtensionMap(payload.languageExtensions)) &&
|
|
663
916
|
(payload.bloomFilters === undefined || isSerializedBloomFilterRecord(payload.bloomFilters)) &&
|
|
664
917
|
(payload.analysis === undefined || isAnalysisSummary(payload.analysis)) &&
|
|
665
918
|
(payload.analysisReport === undefined || isSnapshotAnalysisReport(payload.analysisReport)) &&
|
|
@@ -746,14 +999,14 @@ function isAnalysisSummary(value) {
|
|
|
746
999
|
typeof summary.nativeFilesFellBack === "number" &&
|
|
747
1000
|
typeof summary.label === "string");
|
|
748
1001
|
}
|
|
749
|
-
function serializeBloomFilterCache(cache, files) {
|
|
1002
|
+
function serializeBloomFilterCache(cache, files, projectRoot) {
|
|
750
1003
|
const serialized = {};
|
|
751
1004
|
for (const file of files) {
|
|
752
1005
|
const filter = cache.get(file);
|
|
753
1006
|
if (!filter)
|
|
754
1007
|
continue;
|
|
755
1008
|
const metadata = filter.getMetadata();
|
|
756
|
-
serialized[file] = {
|
|
1009
|
+
serialized[cacheRelativePath(projectRoot, file)] = {
|
|
757
1010
|
size: metadata.size,
|
|
758
1011
|
hashCount: metadata.hashCount,
|
|
759
1012
|
bitsBase64: filter.toBuffer().toString("base64"),
|
|
@@ -761,10 +1014,35 @@ function serializeBloomFilterCache(cache, files) {
|
|
|
761
1014
|
}
|
|
762
1015
|
return Object.keys(serialized).length ? serialized : undefined;
|
|
763
1016
|
}
|
|
764
|
-
function
|
|
1017
|
+
function serializeSnapshotFileSignatures(entries, projectRoot) {
|
|
1018
|
+
const serialized = {};
|
|
1019
|
+
for (const [file, entry] of entries ?? []) {
|
|
1020
|
+
serialized[cacheRelativePath(projectRoot, file)] = {
|
|
1021
|
+
sig: entry.sig,
|
|
1022
|
+
...(entry.gitSig ? { gitSig: entry.gitSig } : {}),
|
|
1023
|
+
...(entry.cacheSig ? { cacheSig: entry.cacheSig } : {}),
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
return serialized;
|
|
1027
|
+
}
|
|
1028
|
+
function isSnapshotFileSignatureRecord(value) {
|
|
1029
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1030
|
+
return false;
|
|
1031
|
+
return Object.values(value).every(isSnapshotFileSignature);
|
|
1032
|
+
}
|
|
1033
|
+
function isSnapshotFileSignature(value) {
|
|
1034
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1035
|
+
return false;
|
|
1036
|
+
const signature = value;
|
|
1037
|
+
return (typeof signature.sig === "string" &&
|
|
1038
|
+
(signature.gitSig === undefined || typeof signature.gitSig === "string") &&
|
|
1039
|
+
(signature.cacheSig === undefined || typeof signature.cacheSig === "string"));
|
|
1040
|
+
}
|
|
1041
|
+
function deserializeBloomFilterCache(serialized, projectRoot) {
|
|
765
1042
|
const cache = new BloomFilterCache();
|
|
766
1043
|
for (const [file, filter] of Object.entries(serialized)) {
|
|
767
|
-
|
|
1044
|
+
const absoluteFile = assertFilePathWithinRoot(projectRoot, cacheAbsolutePath(projectRoot, file), "Persisted cache path");
|
|
1045
|
+
cache.set(absoluteFile, BloomFilter.fromBuffer(Buffer.from(filter.bitsBase64, "base64"), filter.size, filter.hashCount));
|
|
768
1046
|
}
|
|
769
1047
|
return cache;
|
|
770
1048
|
}
|
|
@@ -773,6 +1051,11 @@ function isSerializedBloomFilterRecord(value) {
|
|
|
773
1051
|
return false;
|
|
774
1052
|
return Object.values(value).every(isSerializedBloomFilter);
|
|
775
1053
|
}
|
|
1054
|
+
function isLanguageExtensionMap(value) {
|
|
1055
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1056
|
+
return false;
|
|
1057
|
+
return Object.values(value).every((entry) => typeof entry === "string");
|
|
1058
|
+
}
|
|
776
1059
|
function isSerializedBloomFilter(value) {
|
|
777
1060
|
if (!value || typeof value !== "object")
|
|
778
1061
|
return false;
|
|
@@ -788,9 +1071,15 @@ function isSerializedBloomFilter(value) {
|
|
|
788
1071
|
typeof filter.bitsBase64 !== "string") {
|
|
789
1072
|
return false;
|
|
790
1073
|
}
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
1074
|
+
const expectedBytes = Math.ceil(filter.size / 8);
|
|
1075
|
+
let decoded;
|
|
1076
|
+
try {
|
|
1077
|
+
decoded = Buffer.from(filter.bitsBase64, "base64");
|
|
1078
|
+
}
|
|
1079
|
+
catch {
|
|
1080
|
+
return false;
|
|
1081
|
+
}
|
|
1082
|
+
return decoded.length === expectedBytes && decoded.toString("base64") === filter.bitsBase64;
|
|
794
1083
|
}
|
|
795
1084
|
function isModuleIndex(value) {
|
|
796
1085
|
if (!value || typeof value !== "object")
|