gitnexus 1.6.11-rc.8 → 1.6.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -26
- package/dist/_shared/graph/types.d.ts +81 -2
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/integrations/circuit-breaker.d.ts.map +1 -1
- package/dist/_shared/integrations/circuit-breaker.js.map +1 -1
- package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
- package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +2 -1
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +2 -2
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +4 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/evidence-weights.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.d.ts +3 -0
- package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.js +4 -0
- package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
- package/dist/_shared/scope-resolution/reference-site.d.ts +10 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +15 -0
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +4 -0
- package/dist/cli/ai-context.js +90 -14
- package/dist/cli/analyze-config.js +14 -0
- package/dist/cli/analyze-options.d.ts +14 -0
- package/dist/cli/analyze-watch.d.ts +20 -0
- package/dist/cli/analyze-watch.js +434 -0
- package/dist/cli/analyze.js +27 -9
- package/dist/cli/auto-sync.d.ts +1 -0
- package/dist/cli/auto-sync.js +107 -0
- package/dist/cli/command-banner.d.ts +15 -0
- package/dist/cli/command-banner.js +42 -0
- package/dist/cli/detect-changes-format.js +21 -0
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.js +14 -0
- package/dist/cli/group.js +7 -1
- package/dist/cli/help-i18n.js +4 -0
- package/dist/cli/i18n/en.d.ts +18 -3
- package/dist/cli/i18n/en.js +18 -3
- package/dist/cli/i18n/resources.d.ts +33 -3
- package/dist/cli/i18n/zh-CN.d.ts +15 -0
- package/dist/cli/i18n/zh-CN.js +18 -3
- package/dist/cli/index.js +34 -7
- package/dist/cli/mcp.d.ts +15 -0
- package/dist/cli/mcp.js +44 -0
- package/dist/cli/optional-grammars.d.ts +3 -2
- package/dist/cli/optional-grammars.js +19 -3
- package/dist/cli/setup.js +41 -15
- package/dist/cli/update-notice.d.ts +34 -0
- package/dist/cli/update-notice.js +91 -0
- package/dist/cli/update.d.ts +21 -0
- package/dist/cli/update.js +93 -0
- package/dist/cli/watch.d.ts +1 -20
- package/dist/cli/watch.js +5 -371
- package/dist/core/analysis-feature-registry.d.ts +2 -0
- package/dist/core/analysis-feature-registry.js +15 -0
- package/dist/core/analyzer-identity.js +21 -3
- package/dist/core/auto-sync/analysis-worker-launch.d.ts +30 -0
- package/dist/core/auto-sync/analysis-worker-launch.js +166 -0
- package/dist/core/auto-sync/config.d.ts +33 -0
- package/dist/core/auto-sync/config.js +320 -0
- package/dist/core/auto-sync/index.d.ts +6 -0
- package/dist/core/auto-sync/index.js +6 -0
- package/dist/core/auto-sync/path-security.d.ts +9 -0
- package/dist/core/auto-sync/path-security.js +251 -0
- package/dist/core/auto-sync/repo.d.ts +1 -0
- package/dist/core/auto-sync/repo.js +6 -0
- package/dist/core/auto-sync/runner.d.ts +44 -0
- package/dist/core/auto-sync/runner.js +428 -0
- package/dist/core/auto-sync/starter.d.ts +50 -0
- package/dist/core/auto-sync/starter.js +497 -0
- package/dist/core/auto-sync/state.d.ts +37 -0
- package/dist/core/auto-sync/state.js +119 -0
- package/dist/core/group/config-parser.js +8 -1
- package/dist/core/group/cross-impact.d.ts +3 -0
- package/dist/core/group/cross-impact.js +36 -4
- package/dist/core/group/extractors/http-patterns/java.js +22 -8
- package/dist/core/group/extractors/http-patterns/kotlin.js +86 -31
- package/dist/core/group/extractors/http-patterns/node.js +145 -8
- package/dist/core/group/extractors/http-patterns/python.js +11 -7
- package/dist/core/group/extractors/http-route-extractor.js +63 -17
- package/dist/core/group/extractors/java-workspace-extractor.js +244 -31
- package/dist/core/group/group-lock.js +5 -6
- package/dist/core/group/normalization.d.ts +38 -1
- package/dist/core/group/normalization.js +59 -3
- package/dist/core/group/service.d.ts +11 -0
- package/dist/core/group/service.js +13 -1
- package/dist/core/group/storage.js +2 -2
- package/dist/core/group/sync.d.ts +24 -1
- package/dist/core/group/sync.js +46 -8
- package/dist/core/group/types.d.ts +13 -0
- package/dist/core/incremental/derived-writeback.d.ts +36 -0
- package/dist/core/incremental/derived-writeback.js +68 -0
- package/dist/core/incremental/spring-config-drift.d.ts +12 -0
- package/dist/core/incremental/spring-config-drift.js +46 -0
- package/dist/core/incremental/subgraph-extract.d.ts +7 -4
- package/dist/core/incremental/subgraph-extract.js +30 -5
- package/dist/core/ingestion/asyncapi/document.d.ts +226 -0
- package/dist/core/ingestion/asyncapi/document.js +758 -0
- package/dist/core/ingestion/asyncapi/protocol.d.ts +79 -0
- package/dist/core/ingestion/asyncapi/protocol.js +203 -0
- package/dist/core/ingestion/call-extractors/configs/zig.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/zig.js +4 -0
- package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +100 -0
- package/dist/core/ingestion/call-extractors/zig-static-gating.js +319 -0
- package/dist/core/ingestion/call-processor.js +3 -1
- package/dist/core/ingestion/class-extractors/configs/zig.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/zig.js +32 -0
- package/dist/core/ingestion/class-extractors/generic.js +4 -1
- package/dist/core/ingestion/class-types.d.ts +6 -2
- package/dist/core/ingestion/destination-key.d.ts +59 -0
- package/dist/core/ingestion/destination-key.js +61 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +6 -2
- package/dist/core/ingestion/entry-point-scoring.js +8 -44
- package/dist/core/ingestion/export-detection.d.ts +37 -0
- package/dist/core/ingestion/export-detection.js +60 -0
- package/dist/core/ingestion/field-extractors/configs/zig.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/zig.js +49 -0
- package/dist/core/ingestion/field-extractors/generic.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/generic.js +12 -1
- package/dist/core/ingestion/frameworks/spring/actuator-runtime.d.ts +26 -0
- package/dist/core/ingestion/frameworks/spring/actuator-runtime.js +843 -0
- package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +5 -0
- package/dist/core/ingestion/frameworks/spring/analysis-features.js +9 -0
- package/dist/core/ingestion/frameworks/spring/annotation-arguments.js +8 -1
- package/dist/core/ingestion/frameworks/spring/argument-facts.d.ts +80 -0
- package/dist/core/ingestion/frameworks/spring/argument-facts.js +85 -0
- package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +1 -0
- package/dist/core/ingestion/frameworks/spring/config-bindings.js +2 -1
- package/dist/core/ingestion/frameworks/spring/destinations.d.ts +539 -0
- package/dist/core/ingestion/frameworks/spring/destinations.js +840 -0
- 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/frameworks/spring/message-producers.d.ts +78 -0
- package/dist/core/ingestion/frameworks/spring/message-producers.js +90 -0
- package/dist/core/ingestion/frameworks/spring/non-http-handlers.d.ts +29 -0
- package/dist/core/ingestion/frameworks/spring/vendor-prefixes.d.ts +7 -0
- package/dist/core/ingestion/frameworks/spring/vendor-prefixes.js +22 -0
- package/dist/core/ingestion/import-resolvers/configs/zig.d.ts +13 -0
- package/dist/core/ingestion/import-resolvers/configs/zig.js +26 -0
- package/dist/core/ingestion/import-resolvers/zig.d.ts +34 -0
- package/dist/core/ingestion/import-resolvers/zig.js +193 -0
- package/dist/core/ingestion/language-config.d.ts +177 -0
- package/dist/core/ingestion/language-config.js +719 -0
- package/dist/core/ingestion/language-provider.d.ts +178 -1
- package/dist/core/ingestion/language-provider.js +22 -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/index.d.ts +1 -0
- package/dist/core/ingestion/languages/index.js +2 -0
- package/dist/core/ingestion/languages/java/analysis-features.d.ts +1 -1
- package/dist/core/ingestion/languages/java/analysis-features.js +14 -6
- package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +8 -0
- package/dist/core/ingestion/languages/java/capture-side-channel.js +34 -0
- package/dist/core/ingestion/languages/java/captures.js +22 -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-actuator.d.ts +2 -0
- package/dist/core/ingestion/languages/java/spring-actuator.js +62 -0
- package/dist/core/ingestion/languages/java/spring-di.d.ts +17 -1
- package/dist/core/ingestion/languages/java/spring-di.js +44 -2
- 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/spring-message-producers.d.ts +20 -0
- package/dist/core/ingestion/languages/java/spring-message-producers.js +83 -0
- package/dist/core/ingestion/languages/java/spring-non-http-handlers.d.ts +11 -1
- package/dist/core/ingestion/languages/java/spring-non-http-handlers.js +13 -3
- package/dist/core/ingestion/languages/java.js +18 -8
- 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 +15 -0
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +50 -0
- package/dist/core/ingestion/languages/kotlin/captures.js +24 -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 +4 -0
- package/dist/core/ingestion/languages/kotlin/spring-actuator.d.ts +4 -0
- package/dist/core/ingestion/languages/kotlin/spring-actuator.js +172 -0
- package/dist/core/ingestion/languages/kotlin/spring-config-bindings.d.ts +18 -0
- package/dist/core/ingestion/languages/kotlin/spring-config-bindings.js +411 -0
- package/dist/core/ingestion/languages/kotlin/spring-di.d.ts +51 -1
- package/dist/core/ingestion/languages/kotlin/spring-di.js +86 -6
- 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/spring-message-producers.d.ts +17 -0
- package/dist/core/ingestion/languages/kotlin/spring-message-producers.js +119 -0
- package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.d.ts +16 -0
- package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.js +77 -2
- package/dist/core/ingestion/languages/kotlin.js +24 -0
- package/dist/core/ingestion/languages/python.js +2 -0
- package/dist/core/ingestion/languages/rust/query.js +8 -8
- package/dist/core/ingestion/languages/zig/captures.d.ts +260 -0
- package/dist/core/ingestion/languages/zig/captures.js +2070 -0
- package/dist/core/ingestion/languages/zig/index.d.ts +4 -0
- package/dist/core/ingestion/languages/zig/index.js +4 -0
- package/dist/core/ingestion/languages/zig/interpret.d.ts +36 -0
- package/dist/core/ingestion/languages/zig/interpret.js +176 -0
- package/dist/core/ingestion/languages/zig/query.d.ts +3 -0
- package/dist/core/ingestion/languages/zig/query.js +426 -0
- package/dist/core/ingestion/languages/zig/range-binding.d.ts +37 -0
- package/dist/core/ingestion/languages/zig/range-binding.js +373 -0
- package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +12 -0
- package/dist/core/ingestion/languages/zig/scope-resolver.js +58 -0
- package/dist/core/ingestion/languages/zig/simple-hooks.d.ts +25 -0
- package/dist/core/ingestion/languages/zig/simple-hooks.js +143 -0
- package/dist/core/ingestion/languages/zig.d.ts +32 -0
- package/dist/core/ingestion/languages/zig.js +130 -0
- package/dist/core/ingestion/method-extractors/configs/zig.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/zig.js +120 -0
- package/dist/core/ingestion/method-extractors/generic.js +16 -4
- package/dist/core/ingestion/method-types.d.ts +10 -4
- package/dist/core/ingestion/model/field-registry.d.ts +3 -3
- package/dist/core/ingestion/model/field-registry.js +11 -7
- package/dist/core/ingestion/model/method-registry.d.ts +3 -3
- package/dist/core/ingestion/model/method-registry.js +13 -8
- package/dist/core/ingestion/model/registration-table.js +3 -0
- package/dist/core/ingestion/model/type-registry.js +8 -4
- package/dist/core/ingestion/pipeline-phases/di.js +47 -14
- package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/index.js +1 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +7 -1
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +79 -91
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/processes.d.ts +2 -1
- package/dist/core/ingestion/pipeline-phases/processes.js +39 -4
- package/dist/core/ingestion/pipeline-phases/routes.js +27 -18
- 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 +82 -1
- package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.js +8 -0
- package/dist/core/ingestion/pipeline-phases/spring-destinations.d.ts +123 -0
- package/dist/core/ingestion/pipeline-phases/spring-destinations.js +688 -0
- package/dist/core/ingestion/pipeline.d.ts +30 -1
- package/dist/core/ingestion/pipeline.js +52 -14
- package/dist/core/ingestion/resolve-references.js +5 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +16 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.js +10 -0
- package/dist/core/ingestion/route-extractors/java-const-resolver.d.ts +27 -1
- package/dist/core/ingestion/route-extractors/java-const-resolver.js +161 -13
- package/dist/core/ingestion/route-extractors/kotlin-const-resolver.d.ts +12 -18
- package/dist/core/ingestion/route-extractors/kotlin-const-resolver.js +214 -33
- package/dist/core/ingestion/route-extractors/kotlin-spring.d.ts +13 -0
- package/dist/core/ingestion/route-extractors/kotlin-spring.js +259 -0
- package/dist/core/ingestion/route-extractors/python-decorator-handler.d.ts +6 -0
- package/dist/core/ingestion/route-extractors/python-decorator-handler.js +16 -0
- package/dist/core/ingestion/route-extractors/spring-shared.d.ts +30 -1
- package/dist/core/ingestion/route-extractors/spring-shared.js +77 -9
- package/dist/core/ingestion/route-extractors/spring.js +9 -5
- package/dist/core/ingestion/scope-extractor.js +8 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +62 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +4 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +2 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +28 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +11 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +23 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +24 -3
- package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +11 -1
- package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +26 -6
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +11 -0
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +29 -3
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +8 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +35 -9
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +1 -4
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +277 -9
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +7 -3
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +43 -9
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +71 -10
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -0
- package/dist/core/ingestion/tree-sitter-queries.js +161 -0
- package/dist/core/ingestion/type-extractors/zig.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/zig.js +17 -0
- package/dist/core/ingestion/utils/ast-helpers.d.ts +40 -1
- package/dist/core/ingestion/utils/ast-helpers.js +124 -6
- package/dist/core/ingestion/utils/callable-flow-captures.d.ts +9 -0
- package/dist/core/ingestion/utils/callable-flow-captures.js +75 -14
- package/dist/core/ingestion/utils/test-file-path.d.ts +28 -0
- package/dist/core/ingestion/utils/test-file-path.js +87 -0
- package/dist/core/ingestion/variable-extractors/configs/zig.d.ts +2 -0
- package/dist/core/ingestion/variable-extractors/configs/zig.js +71 -0
- package/dist/core/ingestion/workers/parse-worker.js +85 -14
- package/dist/core/install-context.d.ts +4 -0
- package/dist/core/install-context.js +152 -0
- package/dist/core/lbug/csv-generator.d.ts +10 -1
- package/dist/core/lbug/csv-generator.js +92 -22
- package/dist/core/lbug/graph-emit-sink.d.ts +3 -2
- package/dist/core/lbug/graph-emit-sink.js +4 -2
- package/dist/core/lbug/lbug-adapter.d.ts +100 -5
- package/dist/core/lbug/lbug-adapter.js +236 -24
- package/dist/core/lbug/schema.d.ts +6 -5
- package/dist/core/lbug/schema.js +84 -22
- package/dist/core/net/url-guard.d.ts +6 -0
- package/dist/core/net/url-guard.js +147 -0
- package/dist/core/package-version.d.ts +5 -0
- package/dist/core/package-version.js +10 -0
- package/dist/core/run-analyze.d.ts +21 -4
- package/dist/core/run-analyze.js +426 -117
- package/dist/core/search/fts-indexes.d.ts +19 -1
- package/dist/core/search/fts-indexes.js +28 -1
- package/dist/core/tree-sitter/parser-loader.js +16 -0
- package/dist/core/update-cache.d.ts +39 -0
- package/dist/core/update-cache.js +141 -0
- package/dist/core/update-check.d.ts +31 -0
- package/dist/core/update-check.js +274 -0
- package/dist/mcp/local/local-backend.d.ts +27 -13
- package/dist/mcp/local/local-backend.js +148 -60
- package/dist/mcp/repository-policy.d.ts +5 -1
- package/dist/mcp/repository-policy.js +48 -4
- package/dist/mcp/resources.js +10 -1
- package/dist/mcp/server.js +8 -9
- package/dist/mcp/tools.js +32 -22
- package/dist/server/analyze-launch.d.ts +2 -0
- package/dist/server/analyze-launch.js +2 -0
- package/dist/server/analyze-worker-protocol.d.ts +6 -1
- package/dist/server/analyze-worker.d.ts +1 -0
- package/dist/server/analyze-worker.js +38 -20
- package/dist/server/api.d.ts +5 -1
- package/dist/server/api.js +105 -88
- package/dist/server/git-clone.d.ts +40 -16
- package/dist/server/git-clone.js +253 -199
- 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/server/update-controller.d.ts +29 -0
- package/dist/server/update-controller.js +82 -0
- package/dist/storage/file-lock.d.ts +15 -0
- package/dist/storage/file-lock.js +155 -0
- package/dist/storage/fs-atomic.d.ts +24 -0
- package/dist/storage/fs-atomic.js +86 -2
- package/dist/storage/global-dir.d.ts +2 -0
- package/dist/storage/global-dir.js +6 -0
- package/dist/storage/parse-cache.d.ts +45 -7
- package/dist/storage/parse-cache.js +189 -42
- package/dist/storage/parsedfile-store.d.ts +41 -60
- package/dist/storage/parsedfile-store.js +247 -171
- package/dist/storage/repo-manager.d.ts +10 -4
- package/dist/storage/repo-manager.js +35 -25
- package/dist/storage/repo-meta.d.ts +34 -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/dist/utils/process-identity.d.ts +2 -0
- package/dist/utils/process-identity.js +35 -0
- package/package.json +10 -4
- package/scripts/assert-web-assets.mjs +35 -0
- package/scripts/build-web.js +72 -0
- package/scripts/build.js +31 -28
- package/scripts/cross-platform-tests.ts +5 -0
- package/skills/gitnexus-cli.md +5 -1
- package/web/assets/ProcessFlowModal-DAeX2BHW.js +24 -0
- package/web/assets/{abnfDiagram-QNN2D4NM-Cq2djWWe.js → abnfDiagram-PAR5IXJI-J3OdeHLl.js} +1 -1
- package/web/assets/{agent-BWAXPjC5.js → agent-BMRqXorA.js} +6 -4
- package/web/assets/architecture-7GRP2DOG-M7G3SWCO-G3sWyX6M.js +1 -0
- package/web/assets/architectureDiagram-2PNWDENW-ysKcRlGT.js +36 -0
- package/web/assets/blockDiagram-PUWGUBOA-oLXTa1lY.js +129 -0
- package/web/assets/c4Diagram-3NLNHZP5-D3iu4eC0.js +38 -0
- package/web/assets/{chunk-2SREHG4O-Dip42xOq.js → chunk-2NMSUPJH-B24w-wng.js} +1 -1
- package/web/assets/{chunk-VJFVEZTB-CX66F2ep.js → chunk-32MCUW2P-ByUyt0Sa.js} +3 -3
- package/web/assets/{chunk-4RFN2BYJ-DHHWuC-n.js → chunk-3NPNU5GP-DocZ07Sg.js} +1 -1
- package/web/assets/{chunk-XNMVGMAZ-Cg_LnPtj.js → chunk-3SMGFRGC-CAu4JRLv.js} +1 -1
- package/web/assets/{chunk-W44A43WB-BN8EQc_u.js → chunk-4CAJECRU-DRYMwG9z.js} +1 -1
- package/web/assets/chunk-4OADUZ5Q-CxrSvOwZ.js +10 -0
- package/web/assets/{chunk-DMV4VAQV-Bn6WXDSX.js → chunk-5IQCK5RY-CCMhl4so.js} +2 -2
- package/web/assets/{chunk-RRFMTAIC-CMN0wcYA.js → chunk-5MVFYWFU-Db9KvrYO.js} +1 -1
- package/web/assets/chunk-CLS4B6BI-Uvx5QNsu.js +168 -0
- package/web/assets/chunk-DZP67EKU-B3Mt380j.js +70 -0
- package/web/assets/{chunk-6L755F7B-CMhLBxi2.js → chunk-EICP7K5X-CqwE9hui.js} +1 -1
- package/web/assets/{chunk-BI6VK774-D0oaWk8V.js → chunk-GDY2UAB4-CtQQR0a8.js} +1 -1
- package/web/assets/chunk-H7VHZCWX-CE1nAmt6.js +1 -0
- package/web/assets/chunk-IJBDOHL6-BUKtY6oF.js +1 -0
- package/web/assets/{chunk-OIYT25JQ-CQ6KOZGX.js → chunk-JFFVMJIA-0fJenqia.js} +1 -1
- package/web/assets/{chunk-HNC4WDU7-DoU3KnA7.js → chunk-JZGDI5JK-BeTMSSkJ.js} +1 -1
- package/web/assets/{chunk-EQFTRU2I-1ix7TzW9.js → chunk-KD6SPIPN-Qp1Pflah.js} +1 -1
- package/web/assets/chunk-NF366YI6-CpSpya3n.js +231 -0
- package/web/assets/chunk-NUDPKBEF-CU1-BQIW.js +34 -0
- package/web/assets/{chunk-SATU7PGQ-B1zhgOvc.js → chunk-OJINMHTS-zOCQe4eI.js} +1 -1
- package/web/assets/{chunk-E5QJAATJ-dh-5CtIV.js → chunk-Q6NGPIAH-yyBomb63.js} +1 -1
- package/web/assets/chunk-QJSWEUOL-D_rf9gPD.js +128 -0
- package/web/assets/chunk-R7JDMUKV-CRoqKpD6.js +1 -0
- package/web/assets/{chunk-VE5CLXGZ-C1vB7wpY.js → chunk-RCXAM2GK-CUqrWQDV.js} +1 -1
- package/web/assets/{chunk-66DQ2XMT-CM0xjFAN.js → chunk-RT4MAWR3-zXy9-Lvt.js} +1 -1
- package/web/assets/{chunk-TZUXEDM2-B7p9AcTw.js → chunk-SFMINX4W-J2UrvMpD.js} +1 -1
- package/web/assets/{chunk-LORZLZWG-B57uGw2N.js → chunk-SLDQ463B-CHY6e_bQ.js} +2 -2
- package/web/assets/{chunk-FWYVLQTC-BgDItRzJ.js → chunk-TCEHX7R3-CXPDEVbm.js} +1 -1
- package/web/assets/{chunk-224SPVON-B8gxtXpy.js → chunk-VQC2EELJ-Dc8fIy4R.js} +1 -1
- package/web/assets/chunk-VRZKL3EH-DB3KixTQ.js +1 -0
- package/web/assets/{chunk-A7VWPJGB-B4O3oQdQ.js → chunk-VTHDQ7BV-b7FsPQZO.js} +1 -1
- package/web/assets/chunk-VY2OSTJR-Dkgc3Brg.js +2 -0
- package/web/assets/chunk-WUBWJARI-7FwILJ3k.js +2 -0
- package/web/assets/{chunk-D6VWDJW2-BxcBdZ9c.js → chunk-YBMQ5JGJ-BSnyWZmd.js} +1 -1
- package/web/assets/chunk-YDMLL4PJ-IHhMngTz.js +2 -0
- package/web/assets/chunk-Z6V44ARX-BjCEsF0Q.js +62 -0
- package/web/assets/chunk-ZJJ7VQJP-Dz089b-K.js +321 -0
- package/web/assets/chunk-ZNLK7HRR-B0iFpmW4.js +1 -0
- package/web/assets/chunk-ZQN7UHIL-Cy7KAjQt.js +1 -0
- package/web/assets/{chunk-L5GCOVLC-CE2w8Nm_.js → chunk-ZS6VBONO-DBjJO0w9.js} +2 -2
- package/web/assets/{chunk-NV3KIAZN-5yvcpMiu.js → chunk-ZUNWM646-DNRJyNPe.js} +1 -1
- package/web/assets/classDiagram-FGAMPOII-C5Ibyode.js +1 -0
- package/web/assets/classDiagram-v2-AI5RJEK4-C5Ibyode.js +1 -0
- package/web/assets/{cose-bilkent-RZA4XIPR-BHpK4Crp.js → cose-bilkent-Q72C2OJ3-DMeFXnK8.js} +1 -1
- package/web/assets/cynefin-OW5HDTMX-6OCTWOGG-vlqakYcO.js +1 -0
- package/web/assets/{cynefinDiagram-TR7LZUCG-C3Iar9lZ.js → cynefinDiagram-2OOWUY4M-BY6DZkTt.js} +1 -1
- package/web/assets/dagre-MPVFI544-DWO70fy_.js +4 -0
- package/web/assets/diagram-AE4NWXFW-f7JRVRUL.js +24 -0
- package/web/assets/{diagram-L7DVE3PN-GIRyVUtt.js → diagram-BUJID5UG-BXZv1rCS.js} +2 -2
- package/web/assets/{diagram-JCD7PQ7C-DC5-9FRr.js → diagram-C44CZ5NI-CRNfvjCq.js} +1 -1
- package/web/assets/diagram-EYOLEXXS-DZOjKQVE.js +30 -0
- package/web/assets/diagram-P7B6PWOJ-D3SQmw3_.js +3 -0
- package/web/assets/{ebnfDiagram-DRHRQJWO-D8_CI4ZF.js → ebnfDiagram-FTPZ3PV6-jKWpIDN2.js} +1 -1
- package/web/assets/erDiagram-H3ERR26V-BqJntEuJ.js +99 -0
- package/web/assets/eventmodeling-NTZA5JFV-WKSWQHFS-Bq4FqtBL.js +1 -0
- package/web/assets/flowDiagram-YHGXBVSY-Dnlk2bEu.js +1 -0
- package/web/assets/ganttDiagram-RWFTB7ED-Bl6Y1K5T.js +292 -0
- package/web/assets/gitGraph-4MIJSDKK-JH2HKYUO-B3yc4GkH.js +1 -0
- package/web/assets/gitGraphDiagram-MAR6GKOP-CkNvsrdw.js +106 -0
- package/web/assets/{index-CJDpyH-n.css → index-C2_aej58.css} +1 -1
- package/web/assets/{index-DDRie6_8.js → index-Dj3vQOHK.js} +51 -51
- package/web/assets/info-A6RAGUB7-3TX3OFWW-BM3N5_Dv.js +1 -0
- package/web/assets/infoDiagram-LV547AFH-COkFutAf.js +2 -0
- package/web/assets/{ishikawaDiagram-4JDSWWDM-DmqWtjkl.js → ishikawaDiagram-PUJQGNDS-Bb8FylSR.js} +2 -2
- package/web/assets/{journeyDiagram-QUS3FAKT-XAzVzrQW.js → journeyDiagram-EW5QJT4W-BzoHUBhM.js} +4 -4
- package/web/assets/{kanban-definition-D4L7SQKK-YurRnmYn.js → kanban-definition-JSQERAZB-Uy2Pi0yQ.js} +4 -4
- package/web/assets/katex-CZ4GXH2S-C0Fcou7U.js +257 -0
- package/web/assets/{mindmap-definition-66QP5TD6-ChrWWnil.js → mindmap-definition-VBJCLQLM-B-CnOnt_.js} +3 -3
- package/web/assets/packet-AYTQ26CC-MKII6P3Y-Bd52ZE3V.js +1 -0
- package/web/assets/{pegDiagram-YKIO5C6U-QGeQLEq2.js → pegDiagram-7WILOQTJ-D9sneKXg.js} +1 -1
- package/web/assets/pie-WAS4IAKB-6B4OPMJ5-DW5Xy69Z.js +1 -0
- package/web/assets/pieDiagram-EFA7CBSB-Dx2NQofL.js +39 -0
- package/web/assets/{quadrantDiagram-VO5QLCXA-B7098wSc.js → quadrantDiagram-WARVYA7P-DPKL9_0A.js} +3 -3
- package/web/assets/radar-RG4KPBEZ-UPTR3XUL-CkzibT2h.js +1 -0
- package/web/assets/railroad-74A4TZTK-MEFUPFMS-D9zF-mDN.js +1 -0
- package/web/assets/railroad-abnf-HS5TGJTU-R5YG2S5D-ruacjUbX.js +1 -0
- package/web/assets/railroad-ebnf-LZEXJU2U-G5QEX2L6-S1zc5OiO.js +1 -0
- package/web/assets/railroad-peg-WCYAUIDC-H5I2ZRY2-Cbcr0XzY.js +1 -0
- package/web/assets/{railroadDiagram-M77LTMSB-AXu4vxk_.js → railroadDiagram-5NIQVNLQ-DsweTo14.js} +1 -1
- package/web/assets/{requirementDiagram-RASO5HTO-B-l8InpK.js → requirementDiagram-SXREGOKZ-CXwdNSVR.js} +4 -4
- package/web/assets/{sankeyDiagram-F32LOJ6L-Kd7zjJgX.js → sankeyDiagram-VV74M2VP-CA6jtP9P.js} +3 -3
- package/web/assets/{sequenceDiagram-URATNSBD-BlcdY9DS.js → sequenceDiagram-52ZFIFDL-k_5rEbzm.js} +15 -15
- package/web/assets/src-Df5C1Nz4.js +1 -0
- package/web/assets/stateDiagram-3QAKPIVI-BejHTf31.js +1 -0
- package/web/assets/stateDiagram-v2-HN2P4RDZ-BrfoRuOc.js +1 -0
- package/web/assets/swimlanes-QLVP42QD-CQSVO5D6.js +1 -0
- package/web/assets/swimlanesDiagram-JKPDBFCN-DrWB9kcD.js +8 -0
- package/web/assets/{timeline-definition-WJXWRH4I-DUfp1R3E.js → timeline-definition-GS45XAXW-C0Ks8rPP.js} +4 -4
- package/web/assets/treeView-Q6P3EWNA-ZRJGANNQ-DmKOCo6L.js +1 -0
- package/web/assets/treemap-WGGIJYW6-K64VN5AS-DO3xY92U.js +1 -0
- package/web/assets/{vennDiagram-K3VCMQLI-Bj-FN-XS.js → vennDiagram-QIQU2ZRJ-rgPiS837.js} +3 -3
- package/web/assets/wardley-WFR3VGLG-D67OWCCH-DiDPBNft.js +1 -0
- package/web/assets/wardleyDiagram-U6YNM66N-DRVr7SPi.js +78 -0
- package/web/assets/{xychartDiagram-5VRUVLCW-CK_rbSWE.js → xychartDiagram-XJAZEDNM-COtlZzYb.js} +3 -3
- package/web/index.html +19 -17
- package/web/assets/ProcessFlowModal-Badh2Pbg.js +0 -24
- package/web/assets/architecture-TIHT7OUA-V6N4J3SY-fTePvLoe.js +0 -1
- package/web/assets/architectureDiagram-OT7VKSJ7-mKEXxkeF.js +0 -36
- package/web/assets/blockDiagram-54WLDVWM-Dg_hrRWE.js +0 -132
- package/web/assets/c4Diagram-X2LASM7V-CnhoT4aV.js +0 -10
- package/web/assets/chunk-2AEHWXPW-CV4r6-1I.js +0 -127
- package/web/assets/chunk-5VCL7Z4A-CQ-2dYWj.js +0 -1
- package/web/assets/chunk-6BELYETK-ChsYtfHW.js +0 -1
- package/web/assets/chunk-7CWYLC5S-DRgGkkpF.js +0 -2
- package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +0 -32
- package/web/assets/chunk-KRXBNO2N-C-UNuKKf.js +0 -1
- package/web/assets/chunk-LAHSG3N2-Bz4hcn0N.js +0 -321
- package/web/assets/chunk-LIEV3EAG-pyKGssV3.js +0 -1
- package/web/assets/chunk-NLANEA3F-XpH_NPA5.js +0 -62
- package/web/assets/chunk-PE7DX7ZZ-CCvRVj43.js +0 -10
- package/web/assets/chunk-Q67WD55A-BWCH2SVz.js +0 -156
- package/web/assets/chunk-SZD42YQK-ijyKKVr1.js +0 -70
- package/web/assets/chunk-TFPGFQPA-Dj6a-0pC.js +0 -231
- package/web/assets/chunk-TGVD4F4B-BMc31Gj2.js +0 -2
- package/web/assets/chunk-UAT7B5JY-DW-A_fpI.js +0 -1
- package/web/assets/chunk-VY5UBI4V-yxPQAWxw.js +0 -1
- package/web/assets/chunk-WJBAP47W-BckNkuEN.js +0 -1
- package/web/assets/classDiagram-VPOSVPXH-BjOiXA_C.js +0 -1
- package/web/assets/classDiagram-v2-5VFNUXQA-BjOiXA_C.js +0 -1
- package/web/assets/cynefin-VYW2F7L2-2VAHYKR6-DAsF6GZv.js +0 -1
- package/web/assets/dagre-K64A6Z3X-CUwi79mA.js +0 -4
- package/web/assets/diagram-2TLGJV2N-C2F5Nfym.js +0 -30
- package/web/assets/diagram-KFBZAVDW-Dfmf_4ti.js +0 -3
- package/web/assets/diagram-YP3FGXHI-CyNFYtkd.js +0 -24
- package/web/assets/erDiagram-SZLJLQMB-CohQjznC.js +0 -85
- package/web/assets/eventmodeling-45OFAUF4-AOUJWSLX-BvTc6iQi.js +0 -1
- package/web/assets/flowDiagram-BWE6NHOH-B6RnEvD9.js +0 -1
- package/web/assets/ganttDiagram-2QTCJSNI-Cks_mEcF.js +0 -292
- package/web/assets/gitGraph-TEB2WS4Q-U5VWYIBC-Dy7CCSZ5.js +0 -1
- package/web/assets/gitGraphDiagram-VVZAVV5G-CG41cIVc.js +0 -106
- package/web/assets/info-DKCQHKI2-DX6KST54-BLJg1ikX.js +0 -1
- package/web/assets/infoDiagram-FY4PZKRE-BJ3vPVwW.js +0 -2
- package/web/assets/katex-C5OPUE3Q-Bnbavtmu.js +0 -257
- package/web/assets/packet-7NZHBO7P-5WG45QPS-KUxcuvaA.js +0 -1
- package/web/assets/pie-RZYD4A2V-2OCZ2VTD-DPs08kJY.js +0 -1
- package/web/assets/pieDiagram-YPY3TKG5-BuT3MYzm.js +0 -39
- package/web/assets/radar-I7S5WNFK-EPLSA35B-w5F0K3a7.js +0 -1
- package/web/assets/railroad-3IZDKUUU-PWFQV6Y6-Bu668yqY.js +0 -1
- package/web/assets/railroad-abnf-AHOZXSZD-JYYJX3BS-B6ghpETS.js +0 -1
- package/web/assets/railroad-ebnf-EBAXGLYW-RBZ4ONAP-D-XmHh3M.js +0 -1
- package/web/assets/railroad-peg-LSFZ7HO6-KHNPXGPG-mhkrhzEn.js +0 -1
- package/web/assets/src-C5sx_gMp.js +0 -1
- package/web/assets/stateDiagram-DODFXNG5-DTdHc-fF.js +0 -1
- package/web/assets/stateDiagram-v2-JNMM5JRA-DioNLDDo.js +0 -1
- package/web/assets/swimlanes-OSWOYLSK-CA0ofdwY.js +0 -2
- package/web/assets/swimlanesDiagram-RHGX2RDE-PkwUdckC.js +0 -8
- package/web/assets/treeView-QDETBFTQ-EHYTSQNO-C5lpBgPm.js +0 -1
- package/web/assets/treemap-6X3UGDF4-CCWCF7EK-BB0ZyO-B.js +0 -1
- package/web/assets/wardley-OPB4EBWU-6OWERDVT-CEA3Nq0j.js +0 -1
- package/web/assets/wardleyDiagram-XK6FUAWV-CVV0dHFr.js +0 -78
- /package/web/assets/{sizeCapture-5GORAGP4-BEqQzsxs.js → sizeCapture-FGA5AGYP-BEqQzsxs.js} +0 -0
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
import fs from 'fs/promises';
|
|
17
17
|
import { realpathSync } from 'fs';
|
|
18
18
|
import path from 'path';
|
|
19
|
-
import os from 'os';
|
|
20
19
|
import { getInferredRepoName, resolveRepoIdentityRoot, stripUrlCredentials } from './git.js';
|
|
21
20
|
import { stripWindowsLongPathPrefix } from '../lib/utils.js';
|
|
22
21
|
import { writeFileAtomic } from './fs-atomic.js';
|
|
22
|
+
import { getGlobalDir } from './global-dir.js';
|
|
23
23
|
import { logger } from '../core/logger.js';
|
|
24
24
|
import { acquireIndexLock, IndexLockTimeoutError } from './index-lock.js';
|
|
25
25
|
import { branchSlug, BRANCHES_DIR, resolveBranchPlacement, } from './branch-index.js';
|
|
@@ -33,6 +33,7 @@ export { branchSlug, resolveBranchPlacement };
|
|
|
33
33
|
// cycle that made the extraction necessary. `LEGACY_METADATA_FILE` and
|
|
34
34
|
// `tryReadMetaFile` stay module-private here, exactly as before.
|
|
35
35
|
export { getStoragePath, INDEX_METADATA_FILE, isMissingFilesystemError, loadMeta };
|
|
36
|
+
export { getGlobalDir } from './global-dir.js';
|
|
36
37
|
/**
|
|
37
38
|
* Normalise a repo path for registry comparison across platforms
|
|
38
39
|
* (#664 review feedback from @evander-wang).
|
|
@@ -436,12 +437,6 @@ const ensureGitInfoExclude = async (repoPath) => {
|
|
|
436
437
|
}
|
|
437
438
|
};
|
|
438
439
|
// ─── Global Registry (~/.gitnexus/registry.json) ───────────────────────
|
|
439
|
-
/**
|
|
440
|
-
* Get the path to the global GitNexus directory
|
|
441
|
-
*/
|
|
442
|
-
export const getGlobalDir = () => {
|
|
443
|
-
return process.env.GITNEXUS_HOME || path.join(os.homedir(), '.gitnexus');
|
|
444
|
-
};
|
|
445
440
|
/**
|
|
446
441
|
* Get the path to the global registry file
|
|
447
442
|
*/
|
|
@@ -478,11 +473,9 @@ const REGISTRY_LOCK_TIMEOUT_MS = 5_000;
|
|
|
478
473
|
* registry-private lock namespace; the handle is kernel-owned on supported
|
|
479
474
|
* platforms and crash-reclaimable by the existing fallback.
|
|
480
475
|
*
|
|
481
|
-
* On timeout the transaction
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* `analyze`/`list`/`augment` outright on a wedged lock (a stale pid-reuse
|
|
485
|
-
* ghost on platforms without start-time verification can look live forever).
|
|
476
|
+
* On timeout the transaction fails closed: continuing unlocked would reintroduce
|
|
477
|
+
* the lost-update race this lock exists to prevent and can silently discard a
|
|
478
|
+
* concurrent registration.
|
|
486
479
|
*/
|
|
487
480
|
const withRegistryLock = async (operation) => {
|
|
488
481
|
let lock = null;
|
|
@@ -496,9 +489,10 @@ const withRegistryLock = async (operation) => {
|
|
|
496
489
|
});
|
|
497
490
|
}
|
|
498
491
|
catch (err) {
|
|
499
|
-
if (
|
|
500
|
-
|
|
501
|
-
|
|
492
|
+
if (err instanceof IndexLockTimeoutError) {
|
|
493
|
+
logger.error({ timeoutMs: REGISTRY_LOCK_TIMEOUT_MS }, 'Timed out waiting for the global registry lock; refusing an unlocked registry transaction.');
|
|
494
|
+
}
|
|
495
|
+
throw err;
|
|
502
496
|
}
|
|
503
497
|
try {
|
|
504
498
|
return await operation();
|
|
@@ -666,14 +660,11 @@ export const readRegistryStrict = async () => readRegistryFile(true);
|
|
|
666
660
|
* Atomic tmp+rename: a crash mid-write can never leave a truncated
|
|
667
661
|
* registry.json that the next load would treat as empty and silently drop
|
|
668
662
|
* every registered repo (#2106 R9). The tmp path must stay per-write — the
|
|
669
|
-
* registry is the one file every gitnexus process on the machine writes
|
|
670
|
-
* `withRegistryLock` degrades to unlocked on timeout, so the write cannot rely
|
|
671
|
-
* on the lock to keep two writers off one staging path (#2888).
|
|
672
|
-
*
|
|
673
|
-
* `attempts` is forwarded to the rename retry; best-effort callers pass `1`.
|
|
663
|
+
* registry is the one file every gitnexus process on the machine writes (#2888).
|
|
674
664
|
*/
|
|
675
665
|
const writeRegistry = async (entries, attempts) => {
|
|
676
|
-
|
|
666
|
+
const dir = getGlobalDir();
|
|
667
|
+
await fs.mkdir(dir, { recursive: true });
|
|
677
668
|
await writeFileAtomic(getGlobalRegistryPath(), JSON.stringify(sanitizeEntries(entries), null, 2), attempts);
|
|
678
669
|
};
|
|
679
670
|
/**
|
|
@@ -771,7 +762,10 @@ const registerRepoUnlocked = async (repoPath, meta, opts) => {
|
|
|
771
762
|
// expands macOS /var → /private/var and Windows 8.3 → long-name,
|
|
772
763
|
// falling back to `path.resolve` when the path doesn't exist.
|
|
773
764
|
const canonicalInput = canonicalizePath(repoPath);
|
|
774
|
-
|
|
765
|
+
// Mutating writes must not treat an unreadable/truncated registry as empty
|
|
766
|
+
// (#3094): lenient `readRegistry()` returns `[]` on parse failure and would
|
|
767
|
+
// replace the machine-wide file with only this entry. ENOENT stays empty.
|
|
768
|
+
const entries = await readRegistryStrict();
|
|
775
769
|
const existingIdx = entries.findIndex((e) => {
|
|
776
770
|
// Canonicalise the STORED entry too so pre-canonicalisation
|
|
777
771
|
// registries (written by older versions, or paths passed in a
|
|
@@ -881,7 +875,7 @@ const registerRepoUnlocked = async (repoPath, meta, opts) => {
|
|
|
881
875
|
// R9): re-derive THIS run's delta against the FRESHEST snapshot so a
|
|
882
876
|
// concurrent change to the OTHER axis (a branch upsert vs a primary refresh)
|
|
883
877
|
// survives instead of being clobbered by a stale entry-time view.
|
|
884
|
-
const fresh = await
|
|
878
|
+
const fresh = await readRegistryStrict();
|
|
885
879
|
const freshIdx = fresh.findIndex((e) => {
|
|
886
880
|
const a = canonicalizePath(e.path);
|
|
887
881
|
return registryPathEquals(a, canonicalInput);
|
|
@@ -1301,6 +1295,24 @@ export const resolveRegistryEntry = (entries, target) => {
|
|
|
1301
1295
|
const availableNames = entries.map((e) => (nameCounts.get(e.name.toLowerCase()) ?? 0) > 1 ? `${e.name} (${e.path})` : e.name);
|
|
1302
1296
|
throw new RegistryNotFoundError(target, availableNames);
|
|
1303
1297
|
};
|
|
1298
|
+
/**
|
|
1299
|
+
* Name-only registry match (the name tier of {@link resolveRegistryEntry},
|
|
1300
|
+
* without path matching). Used by `group.yaml` member *values*, which are
|
|
1301
|
+
* registry aliases, not filesystem paths.
|
|
1302
|
+
*
|
|
1303
|
+
* Zero matches → `undefined` (caller treats as missing). One match → that
|
|
1304
|
+
* entry. Two or more → {@link RegistryAmbiguousTargetError}.
|
|
1305
|
+
*/
|
|
1306
|
+
export const findRegistryEntryByName = (entries, name) => {
|
|
1307
|
+
const targetLower = name.toLowerCase();
|
|
1308
|
+
const nameMatches = entries.filter((e) => e.name.toLowerCase() === targetLower);
|
|
1309
|
+
if (nameMatches.length === 1)
|
|
1310
|
+
return nameMatches[0];
|
|
1311
|
+
if (nameMatches.length > 1) {
|
|
1312
|
+
throw new RegistryAmbiguousTargetError(name, nameMatches);
|
|
1313
|
+
}
|
|
1314
|
+
return undefined;
|
|
1315
|
+
};
|
|
1304
1316
|
/**
|
|
1305
1317
|
* List all registered repos from the global registry.
|
|
1306
1318
|
*
|
|
@@ -1374,8 +1386,6 @@ export const listRegisteredRepos = async (opts) => {
|
|
|
1374
1386
|
try {
|
|
1375
1387
|
await withRegistryLock(async () => {
|
|
1376
1388
|
const fresh = await readRegistry();
|
|
1377
|
-
// attempts: 1 — the catch below discards a failure, so the rename
|
|
1378
|
-
// backoff would only make every other process wait out this lock.
|
|
1379
1389
|
await writeRegistry(fresh.filter((entry) => !pruned.has(entry.path)), 1);
|
|
1380
1390
|
});
|
|
1381
1391
|
}
|
|
@@ -78,6 +78,35 @@ export interface RepoMeta {
|
|
|
78
78
|
repoPath: string;
|
|
79
79
|
lastCommit: string;
|
|
80
80
|
indexedAt: string;
|
|
81
|
+
/**
|
|
82
|
+
* Runtime enrichment mode plus redacted scan exclusions. Payload data and
|
|
83
|
+
* absolute/external paths are deliberately excluded from metadata.
|
|
84
|
+
*/
|
|
85
|
+
springActuator?: {
|
|
86
|
+
enabled: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Normalized repo-relative inputs that must remain excluded from all future
|
|
89
|
+
* source scans. The list is empty when every configured input was external.
|
|
90
|
+
*/
|
|
91
|
+
repoRelativeInputs: string[];
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Whether the index was built with AsyncAPI document reading enabled.
|
|
95
|
+
*
|
|
96
|
+
* Only the FLAG is recorded, unlike `springActuator` above, because the two
|
|
97
|
+
* options need different things from this field. Actuator inputs are retained
|
|
98
|
+
* so future scans keep excluding them; documents are deliberately NOT
|
|
99
|
+
* excluded from scanning — a committed one wants its real `File` node — so
|
|
100
|
+
* there is nothing to retain, and recording the configured path would put an
|
|
101
|
+
* operator's absolute directory layout into index metadata for no consumer.
|
|
102
|
+
*
|
|
103
|
+
* The flag alone is what the disable transition needs: without it, dropping
|
|
104
|
+
* the option leaves document-derived destinations in an index with nothing
|
|
105
|
+
* able to notice they should go.
|
|
106
|
+
*/
|
|
107
|
+
asyncApiSpec?: {
|
|
108
|
+
enabled: boolean;
|
|
109
|
+
};
|
|
81
110
|
/**
|
|
82
111
|
* Analyzer/runtime receipt for the successful run represented by this
|
|
83
112
|
* metadata. Optional so indexes written by older GitNexus releases remain
|
|
@@ -185,6 +214,11 @@ export interface RepoMeta {
|
|
|
185
214
|
* containing relevant source files.
|
|
186
215
|
*/
|
|
187
216
|
analysisFeatures?: Record<string, number>;
|
|
217
|
+
/**
|
|
218
|
+
* Canonical registered-prefix list used to resolve vendor Spring mapping
|
|
219
|
+
* annotations. A changed value invalidates persisted JVM Route evidence.
|
|
220
|
+
*/
|
|
221
|
+
springVendorPrefixes?: string;
|
|
188
222
|
/**
|
|
189
223
|
* The resolved GITNEXUS_FTS_CJK_SEGMENTATION mode ('none' | 'bigram') the
|
|
190
224
|
* existing index's content/description columns were last written under
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Envelope version — independent of PARSE_CACHE_VERSION / SCHEMA_BUMP. */
|
|
2
|
+
export declare const V8_CACHE_FORMAT = 5;
|
|
3
|
+
/**
|
|
4
|
+
* Collapse duplicate strings in a live deserialized graph into `pool`, mutating
|
|
5
|
+
* in place so object identity (shared `SymbolDefinition`s, Maps) is preserved.
|
|
6
|
+
* Required after `v8.deserialize` of ParsedFile shards: V8 does not recreate
|
|
7
|
+
* the JSON reviver's cross-shard string intern, and skipping it regresses
|
|
8
|
+
* retained heap (~+59% measured vs interned JSON).
|
|
9
|
+
*/
|
|
10
|
+
export declare const internGraphStrings: (root: unknown, pool: Map<string, string>) => unknown;
|
|
11
|
+
/** NDJSON listing cannot encode paths that themselves contain CR/LF/NUL. */
|
|
12
|
+
export declare const encodeCachePathListing: (paths: readonly string[]) => Buffer;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a counted NDJSON path listing. Returns `null` when it must not be
|
|
15
|
+
* trusted to skip the payload: missing trailing newline, CR/NUL, or a count
|
|
16
|
+
* that does not match the remaining lines.
|
|
17
|
+
*/
|
|
18
|
+
export declare const parseCachePathListing: (raw: Buffer) => string[] | null;
|
|
19
|
+
export type V8CacheHit = {
|
|
20
|
+
kind: 'hit';
|
|
21
|
+
value: unknown;
|
|
22
|
+
bytes: number;
|
|
23
|
+
};
|
|
24
|
+
export type V8CacheSkip = {
|
|
25
|
+
kind: 'skip';
|
|
26
|
+
bytes: number;
|
|
27
|
+
};
|
|
28
|
+
export type V8CacheLoad = V8CacheHit | V8CacheSkip;
|
|
29
|
+
export type V8CacheInspection = {
|
|
30
|
+
paths: readonly string[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Validate the immutable envelope metadata needed by the durable ParsedFile
|
|
34
|
+
* warm-hit gate without deserializing its payload. Atomic publication means a
|
|
35
|
+
* runtime-compatible envelope whose exact file length and counted path listing
|
|
36
|
+
* validate is a stable snapshot candidate; malformed/truncated envelopes miss.
|
|
37
|
+
*/
|
|
38
|
+
export declare const inspectV8Cache: (filePath: string) => Promise<V8CacheInspection | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* Load a cache file. When `wantPaths` is set and a digest-verified non-empty
|
|
41
|
+
* path listing has no intersection, returns `{ kind: 'skip' }` without
|
|
42
|
+
* deserializing. An authentic listing that does not parse deserializes (fail
|
|
43
|
+
* closed). Envelope/runtime/digest failure returns undefined (miss).
|
|
44
|
+
*/
|
|
45
|
+
export declare const tryLoadV8Cache: (filePath: string, internPool?: Map<string, string>, wantPaths?: ReadonlySet<string>) => Promise<V8CacheLoad | undefined>;
|
|
46
|
+
export declare const writeV8CacheFile: (filePath: string, graph: unknown, paths?: readonly string[]) => Promise<boolean>;
|
|
47
|
+
export declare const writeV8CacheFileSync: (filePath: string, graph: unknown, paths?: readonly string[]) => boolean;
|
|
48
|
+
export declare const copyV8CacheIfPresent: (srcPath: string, dstPath: string) => Promise<boolean>;
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-file V8 cache envelope for parse-cache and ParsedFile shards.
|
|
3
|
+
*
|
|
4
|
+
* Each object-graph shard is a single immutable `.v8` file published by
|
|
5
|
+
* tmp+rename. JSON is not a fallback: a missing, corrupt, runtime-incompatible,
|
|
6
|
+
* or deserialize-failed envelope is a cache miss (re-extract / re-dispatch).
|
|
7
|
+
* Tiny JSON manifests (`index.json`) stay outside this module.
|
|
8
|
+
*
|
|
9
|
+
* Envelope: magic, format, Node major, V8 version, optional path listing,
|
|
10
|
+
* `v8.serialize` of the live graph, then SHA-256 of listing||payload. Path
|
|
11
|
+
* bytes live before the payload so a ParsedFile loader can skip a shard whose
|
|
12
|
+
* authenticated listing misses `wantPaths` without deserializing. An
|
|
13
|
+
* unreadable/invalid listing is fail-closed: deserialize, never skip.
|
|
14
|
+
*/
|
|
15
|
+
import { promises as fs } from 'node:fs';
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import v8 from 'node:v8';
|
|
18
|
+
import { logger } from '../core/logger.js';
|
|
19
|
+
import { linkOrCopyFile, writeFileAtomicBytes, writeFileAtomicBytesSync } from './fs-atomic.js';
|
|
20
|
+
const MAGIC = Buffer.from('GNXV8CF1', 'ascii');
|
|
21
|
+
/** Envelope version — independent of PARSE_CACHE_VERSION / SCHEMA_BUMP. */
|
|
22
|
+
export const V8_CACHE_FORMAT = 5;
|
|
23
|
+
const U32 = 4;
|
|
24
|
+
const U16 = 2;
|
|
25
|
+
const PAYLOAD_HASH_LEN = 32;
|
|
26
|
+
const MAGIC_LEN = 8;
|
|
27
|
+
const FIXED_PREFIX = MAGIC_LEN + U32 + U16 + U16; // magic + format + nodeMajor + v8len
|
|
28
|
+
const internString = (value, pool) => {
|
|
29
|
+
const hit = pool.get(value);
|
|
30
|
+
if (hit !== undefined)
|
|
31
|
+
return hit;
|
|
32
|
+
pool.set(value, value);
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Collapse duplicate strings in a live deserialized graph into `pool`, mutating
|
|
37
|
+
* in place so object identity (shared `SymbolDefinition`s, Maps) is preserved.
|
|
38
|
+
* Required after `v8.deserialize` of ParsedFile shards: V8 does not recreate
|
|
39
|
+
* the JSON reviver's cross-shard string intern, and skipping it regresses
|
|
40
|
+
* retained heap (~+59% measured vs interned JSON).
|
|
41
|
+
*/
|
|
42
|
+
export const internGraphStrings = (root, pool) => {
|
|
43
|
+
const seen = new WeakSet();
|
|
44
|
+
const walk = (value) => {
|
|
45
|
+
if (typeof value === 'string')
|
|
46
|
+
return internString(value, pool);
|
|
47
|
+
if (value === null || typeof value !== 'object')
|
|
48
|
+
return value;
|
|
49
|
+
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer)
|
|
50
|
+
return value;
|
|
51
|
+
if (seen.has(value))
|
|
52
|
+
return value;
|
|
53
|
+
seen.add(value);
|
|
54
|
+
if (value instanceof Map) {
|
|
55
|
+
const entries = [...value];
|
|
56
|
+
value.clear();
|
|
57
|
+
for (const [k, v] of entries)
|
|
58
|
+
value.set(walk(k), walk(v));
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
if (value instanceof Set) {
|
|
62
|
+
const entries = [...value];
|
|
63
|
+
value.clear();
|
|
64
|
+
for (const v of entries)
|
|
65
|
+
value.add(walk(v));
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
for (let i = 0; i < value.length; i++)
|
|
70
|
+
value[i] = walk(value[i]);
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
const rec = value;
|
|
74
|
+
for (const key of Object.keys(rec)) {
|
|
75
|
+
rec[key] = walk(rec[key]);
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
};
|
|
79
|
+
return walk(root);
|
|
80
|
+
};
|
|
81
|
+
const nodeMajor = () => Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10);
|
|
82
|
+
const isEnoent = (err) => err.code === 'ENOENT';
|
|
83
|
+
const warnCache = (err, filePath, msg) => {
|
|
84
|
+
logger.warn({ err, filePath }, msg);
|
|
85
|
+
};
|
|
86
|
+
/** NDJSON listing cannot encode paths that themselves contain CR/LF/NUL. */
|
|
87
|
+
export const encodeCachePathListing = (paths) => {
|
|
88
|
+
if (paths.length === 0)
|
|
89
|
+
return Buffer.alloc(0);
|
|
90
|
+
if (paths.some((p) => /[\r\n\0]/.test(p)))
|
|
91
|
+
return Buffer.alloc(0);
|
|
92
|
+
return Buffer.from(`${paths.length}\n${paths.join('\n')}\n`, 'utf8');
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Parse a counted NDJSON path listing. Returns `null` when it must not be
|
|
96
|
+
* trusted to skip the payload: missing trailing newline, CR/NUL, or a count
|
|
97
|
+
* that does not match the remaining lines.
|
|
98
|
+
*/
|
|
99
|
+
export const parseCachePathListing = (raw) => {
|
|
100
|
+
if (raw.byteLength === 0)
|
|
101
|
+
return [];
|
|
102
|
+
let sidecarRaw;
|
|
103
|
+
try {
|
|
104
|
+
sidecarRaw = new TextDecoder('utf-8', { fatal: true }).decode(raw);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
if (sidecarRaw.includes('\0') || sidecarRaw.includes('\r') || !sidecarRaw.endsWith('\n')) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const nl = sidecarRaw.indexOf('\n');
|
|
113
|
+
if (nl < 0)
|
|
114
|
+
return null;
|
|
115
|
+
const countToken = sidecarRaw.slice(0, nl);
|
|
116
|
+
if (!/^[0-9]+$/.test(countToken))
|
|
117
|
+
return null;
|
|
118
|
+
const count = Number(countToken);
|
|
119
|
+
const body = sidecarRaw.slice(nl + 1);
|
|
120
|
+
const listed = body === '' ? [] : body.slice(0, -1).split('\n');
|
|
121
|
+
if (listed.length !== count)
|
|
122
|
+
return null;
|
|
123
|
+
return listed;
|
|
124
|
+
};
|
|
125
|
+
const encodeEnvelope = (graph, paths) => {
|
|
126
|
+
let payload;
|
|
127
|
+
try {
|
|
128
|
+
payload = v8.serialize(graph);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
warnCache(err, '', 'v8 cache: serialize failed; treating as miss on next load');
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const pathListing = encodeCachePathListing(paths);
|
|
135
|
+
const listed = parseCachePathListing(pathListing);
|
|
136
|
+
const pathCount = listed === null ? 0 : listed.length;
|
|
137
|
+
if (payload.byteLength > 0xffff_ffff || pathListing.byteLength > 0xffff_ffff)
|
|
138
|
+
return undefined;
|
|
139
|
+
const v8ver = Buffer.from(process.versions.v8, 'utf8');
|
|
140
|
+
if (v8ver.byteLength > 0xffff)
|
|
141
|
+
return undefined;
|
|
142
|
+
const header = Buffer.allocUnsafe(FIXED_PREFIX + v8ver.length + U32 * 3);
|
|
143
|
+
MAGIC.copy(header, 0);
|
|
144
|
+
header.writeUInt32LE(V8_CACHE_FORMAT, MAGIC_LEN);
|
|
145
|
+
header.writeUInt16LE(nodeMajor(), MAGIC_LEN + U32);
|
|
146
|
+
header.writeUInt16LE(v8ver.length, MAGIC_LEN + U32 + U16);
|
|
147
|
+
v8ver.copy(header, FIXED_PREFIX);
|
|
148
|
+
let off = FIXED_PREFIX + v8ver.length;
|
|
149
|
+
header.writeUInt32LE(pathCount, off);
|
|
150
|
+
off += U32;
|
|
151
|
+
header.writeUInt32LE(pathListing.byteLength, off);
|
|
152
|
+
off += U32;
|
|
153
|
+
header.writeUInt32LE(payload.byteLength, off);
|
|
154
|
+
const payloadHash = createHash('sha256').update(pathListing).update(payload).digest();
|
|
155
|
+
return Buffer.concat([header, pathListing, payload, payloadHash]);
|
|
156
|
+
};
|
|
157
|
+
const decodePrefix = (buf) => {
|
|
158
|
+
if (buf.byteLength < FIXED_PREFIX)
|
|
159
|
+
return undefined;
|
|
160
|
+
if (!buf.subarray(0, MAGIC_LEN).equals(MAGIC))
|
|
161
|
+
return undefined;
|
|
162
|
+
if (buf.readUInt32LE(MAGIC_LEN) !== V8_CACHE_FORMAT)
|
|
163
|
+
return undefined;
|
|
164
|
+
const recordedNodeMajor = buf.readUInt16LE(MAGIC_LEN + U32);
|
|
165
|
+
const v8len = buf.readUInt16LE(MAGIC_LEN + U32 + U16);
|
|
166
|
+
const v8off = FIXED_PREFIX;
|
|
167
|
+
const countsOff = v8off + v8len;
|
|
168
|
+
if (buf.byteLength < countsOff + U32 * 3)
|
|
169
|
+
return undefined;
|
|
170
|
+
const recordedV8 = buf.subarray(v8off, v8off + v8len).toString('utf8');
|
|
171
|
+
const pathCount = buf.readUInt32LE(countsOff);
|
|
172
|
+
const pathBytes = buf.readUInt32LE(countsOff + U32);
|
|
173
|
+
const payloadLen = buf.readUInt32LE(countsOff + U32 * 2);
|
|
174
|
+
const pathsOff = countsOff + U32 * 3;
|
|
175
|
+
const payloadOff = pathsOff + pathBytes;
|
|
176
|
+
return {
|
|
177
|
+
recordedNodeMajor,
|
|
178
|
+
recordedV8,
|
|
179
|
+
pathCount,
|
|
180
|
+
pathBytes,
|
|
181
|
+
payloadLen,
|
|
182
|
+
pathsOff,
|
|
183
|
+
payloadOff,
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
const runtimeCompatible = (meta) => meta.recordedNodeMajor === nodeMajor() && meta.recordedV8 === process.versions.v8;
|
|
187
|
+
const readExact = async (fh, offset, length) => {
|
|
188
|
+
const buf = Buffer.allocUnsafe(length);
|
|
189
|
+
let got = 0;
|
|
190
|
+
while (got < length) {
|
|
191
|
+
const { bytesRead } = await fh.read(buf, got, length - got, offset + got);
|
|
192
|
+
if (bytesRead === 0)
|
|
193
|
+
return undefined;
|
|
194
|
+
got += bytesRead;
|
|
195
|
+
}
|
|
196
|
+
return buf;
|
|
197
|
+
};
|
|
198
|
+
const readVerifiedPayload = async (fh, meta, pathRaw) => {
|
|
199
|
+
const payloadAndHash = await readExact(fh, meta.payloadOff, meta.payloadLen + PAYLOAD_HASH_LEN);
|
|
200
|
+
if (!payloadAndHash)
|
|
201
|
+
return undefined;
|
|
202
|
+
const payload = payloadAndHash.subarray(0, meta.payloadLen);
|
|
203
|
+
const expected = payloadAndHash.subarray(meta.payloadLen);
|
|
204
|
+
const digest = createHash('sha256').update(pathRaw).update(payload).digest();
|
|
205
|
+
return digest.equals(expected) ? payload : undefined;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Validate the immutable envelope metadata needed by the durable ParsedFile
|
|
209
|
+
* warm-hit gate without deserializing its payload. Atomic publication means a
|
|
210
|
+
* runtime-compatible envelope whose exact file length and counted path listing
|
|
211
|
+
* validate is a stable snapshot candidate; malformed/truncated envelopes miss.
|
|
212
|
+
*/
|
|
213
|
+
export const inspectV8Cache = async (filePath) => {
|
|
214
|
+
let fh;
|
|
215
|
+
try {
|
|
216
|
+
fh = await fs.open(filePath, 'r');
|
|
217
|
+
const st = await fh.stat();
|
|
218
|
+
const prefix = await readExact(fh, 0, Math.min(st.size, FIXED_PREFIX + 256 + U32 * 3));
|
|
219
|
+
if (!prefix)
|
|
220
|
+
return undefined;
|
|
221
|
+
const meta = decodePrefix(prefix);
|
|
222
|
+
if (!meta || !runtimeCompatible(meta))
|
|
223
|
+
return undefined;
|
|
224
|
+
if (meta.payloadOff + meta.payloadLen + PAYLOAD_HASH_LEN !== st.size || meta.pathBytes === 0) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
const pathRaw = prefix.byteLength >= meta.payloadOff
|
|
228
|
+
? Buffer.from(prefix.subarray(meta.pathsOff, meta.payloadOff))
|
|
229
|
+
: await readExact(fh, meta.pathsOff, meta.pathBytes);
|
|
230
|
+
if (!pathRaw)
|
|
231
|
+
return undefined;
|
|
232
|
+
const listed = parseCachePathListing(pathRaw);
|
|
233
|
+
if (listed === null || listed.length !== meta.pathCount || listed.length === 0) {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
if (!(await readVerifiedPayload(fh, meta, pathRaw)))
|
|
237
|
+
return undefined;
|
|
238
|
+
return { paths: listed };
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
if (!isEnoent(err)) {
|
|
242
|
+
logger.debug({ err, filePath }, 'v8 cache: inspection failed; treating as miss');
|
|
243
|
+
}
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
await fh?.close().catch(() => { });
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* Load a cache file. When `wantPaths` is set and a digest-verified non-empty
|
|
252
|
+
* path listing has no intersection, returns `{ kind: 'skip' }` without
|
|
253
|
+
* deserializing. An authentic listing that does not parse deserializes (fail
|
|
254
|
+
* closed). Envelope/runtime/digest failure returns undefined (miss).
|
|
255
|
+
*/
|
|
256
|
+
export const tryLoadV8Cache = async (filePath, internPool, wantPaths) => {
|
|
257
|
+
let fh;
|
|
258
|
+
try {
|
|
259
|
+
fh = await fs.open(filePath, 'r');
|
|
260
|
+
const st = await fh.stat();
|
|
261
|
+
const prefix = await readExact(fh, 0, Math.min(st.size, FIXED_PREFIX + 256 + U32 * 3));
|
|
262
|
+
if (!prefix)
|
|
263
|
+
return undefined;
|
|
264
|
+
const meta = decodePrefix(prefix);
|
|
265
|
+
if (!meta)
|
|
266
|
+
return undefined;
|
|
267
|
+
if (!runtimeCompatible(meta))
|
|
268
|
+
return undefined;
|
|
269
|
+
if (meta.payloadOff + meta.payloadLen + PAYLOAD_HASH_LEN !== st.size)
|
|
270
|
+
return undefined;
|
|
271
|
+
let pathRaw = Buffer.alloc(0);
|
|
272
|
+
if (meta.pathBytes > 0) {
|
|
273
|
+
if (prefix.byteLength >= meta.payloadOff) {
|
|
274
|
+
pathRaw = Buffer.from(prefix.subarray(meta.pathsOff, meta.payloadOff));
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const raw = await readExact(fh, meta.pathsOff, meta.pathBytes);
|
|
278
|
+
if (!raw)
|
|
279
|
+
return undefined;
|
|
280
|
+
pathRaw = Buffer.from(raw);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const payload = await readVerifiedPayload(fh, meta, pathRaw);
|
|
284
|
+
if (!payload)
|
|
285
|
+
return undefined;
|
|
286
|
+
if (wantPaths && wantPaths.size > 0 && meta.pathBytes > 0) {
|
|
287
|
+
const listed = parseCachePathListing(pathRaw);
|
|
288
|
+
if (listed !== null &&
|
|
289
|
+
listed.length === meta.pathCount &&
|
|
290
|
+
listed.length > 0 &&
|
|
291
|
+
!listed.some((p) => wantPaths.has(p))) {
|
|
292
|
+
return { kind: 'skip', bytes: st.size };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const value = v8.deserialize(payload);
|
|
296
|
+
if (internPool)
|
|
297
|
+
internGraphStrings(value, internPool);
|
|
298
|
+
return { kind: 'hit', value, bytes: st.size };
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (!isEnoent(err)) {
|
|
302
|
+
logger.debug({ err, filePath }, 'v8 cache: load failed; treating as miss');
|
|
303
|
+
}
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
await fh?.close().catch(() => { });
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
export const writeV8CacheFile = async (filePath, graph, paths) => {
|
|
311
|
+
const blob = encodeEnvelope(graph, paths ?? []);
|
|
312
|
+
if (!blob)
|
|
313
|
+
return false;
|
|
314
|
+
try {
|
|
315
|
+
await writeFileAtomicBytes(filePath, blob, 1);
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
warnCache(err, filePath, 'v8 cache: write failed; treating as miss');
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
export const writeV8CacheFileSync = (filePath, graph, paths) => {
|
|
324
|
+
const blob = encodeEnvelope(graph, paths ?? []);
|
|
325
|
+
if (!blob)
|
|
326
|
+
return false;
|
|
327
|
+
try {
|
|
328
|
+
writeFileAtomicBytesSync(filePath, blob);
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
warnCache(err, filePath, 'v8 cache: write failed; treating as miss');
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
export const copyV8CacheIfPresent = async (srcPath, dstPath) => {
|
|
337
|
+
try {
|
|
338
|
+
await linkOrCopyFile(srcPath, dstPath);
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
catch (copyErr) {
|
|
342
|
+
if (!isEnoent(copyErr)) {
|
|
343
|
+
warnCache(copyErr, srcPath, 'v8 cache: copy failed; treating as miss');
|
|
344
|
+
}
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
};
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -13,6 +13,18 @@ export interface PipelineResult {
|
|
|
13
13
|
totalFileCount: number;
|
|
14
14
|
communityResult?: CommunityDetectionResult;
|
|
15
15
|
processResult?: ProcessDetectionResult;
|
|
16
|
+
/**
|
|
17
|
+
* Runs the community/process phases that `skipDerivedGraphPhases` held back
|
|
18
|
+
* (#3016), against the same graph and phase outputs the pipeline already
|
|
19
|
+
* produced, and populates `communityResult`/`processResult` on this object.
|
|
20
|
+
*
|
|
21
|
+
* Present ONLY when those phases were skipped for that reason, so a caller
|
|
22
|
+
* that optimistically skipped them can still get a byte-identical derived
|
|
23
|
+
* layer on the paths that turn out to need one (full rebuild, escalated
|
|
24
|
+
* write, or an incremental run with deleted files). Absent means the phases
|
|
25
|
+
* either already ran or were disabled for an unrelated reason.
|
|
26
|
+
*/
|
|
27
|
+
runDeferredDerivedPhases?: () => Promise<void>;
|
|
16
28
|
/**
|
|
17
29
|
* Additive diagnostics for registry-primary resolution decisions that
|
|
18
30
|
* deliberately suppress edge emission. Empty means no diagnostic was
|
|
@@ -40,6 +52,8 @@ export interface PipelineResult {
|
|
|
40
52
|
usedWorkerPool: boolean;
|
|
41
53
|
/** Files actually dispatched to parser workers after parse-cache lookup. */
|
|
42
54
|
reparsedFileCount: number;
|
|
55
|
+
/** Files restored from parse-cache chunks without parser-worker dispatch. */
|
|
56
|
+
parseCacheHitFileCount?: number;
|
|
43
57
|
/** Files omitted from scope-resolution while the rest of analysis continued. */
|
|
44
58
|
scopeExtractionFailures: readonly string[];
|
|
45
59
|
/** Files scope resolution could not inspect because their parser was unavailable. */
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
export function isProcessAlive(pid) {
|
|
3
|
+
try {
|
|
4
|
+
process.kill(pid, 0);
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
return error.code !== 'ESRCH';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function readProcessStartTime(pid) {
|
|
12
|
+
try {
|
|
13
|
+
const startedAt = process.platform === 'win32'
|
|
14
|
+
? execFileSync('powershell.exe', [
|
|
15
|
+
'-NoProfile',
|
|
16
|
+
'-NonInteractive',
|
|
17
|
+
'-Command',
|
|
18
|
+
`$p = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}"; if ($p) { $p.CreationDate.ToUniversalTime().ToString("O") }`,
|
|
19
|
+
], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
|
|
20
|
+
: // `lstart` is rendered through localtime and the active locale, so the
|
|
21
|
+
// same live process yields a different string under a different TZ or
|
|
22
|
+
// LC_TIME. That string is a lock owner's identity, and a mismatch is
|
|
23
|
+
// read as PID reuse — an unpinned render lets one daemon reclaim a
|
|
24
|
+
// mutex another still holds. Pin both so the identity is absolute.
|
|
25
|
+
execFileSync('ps', ['-p', String(pid), '-o', 'lstart='], {
|
|
26
|
+
encoding: 'utf-8',
|
|
27
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
28
|
+
env: { ...process.env, TZ: 'UTC', LC_ALL: 'C' },
|
|
29
|
+
}).trim();
|
|
30
|
+
return startedAt || undefined;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|