gitnexus 1.6.8-rc.9 → 1.6.8
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 +3 -3
- package/dist/_shared/graph/types.d.ts +31 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +11 -1
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +6 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +31 -1
- package/dist/cli/ai-context.js +18 -16
- package/dist/cli/analyze-config.js +11 -0
- package/dist/cli/analyze.d.ts +14 -0
- package/dist/cli/analyze.js +98 -0
- package/dist/cli/embedding-dims.d.ts +33 -0
- package/dist/cli/embedding-dims.js +39 -0
- package/dist/cli/eval-server.d.ts +8 -0
- package/dist/cli/eval-server.js +242 -2
- package/dist/cli/help-i18n.js +19 -0
- package/dist/cli/i18n/en.d.ts +15 -1
- package/dist/cli/i18n/en.js +15 -1
- package/dist/cli/i18n/resources.d.ts +29 -1
- package/dist/cli/i18n/zh-CN.d.ts +14 -0
- package/dist/cli/i18n/zh-CN.js +15 -1
- package/dist/cli/index.js +89 -1
- package/dist/cli/mcp.d.ts +6 -1
- package/dist/cli/mcp.js +26 -1
- package/dist/cli/optional-grammars.d.ts +6 -8
- package/dist/cli/optional-grammars.js +8 -11
- package/dist/cli/setup.d.ts +3 -1
- package/dist/cli/setup.js +67 -17
- package/dist/cli/skill-gen.js +2 -1
- package/dist/cli/tool.d.ts +19 -1
- package/dist/cli/tool.js +96 -3
- package/dist/core/embeddings/hf-env.d.ts +0 -66
- package/dist/core/embeddings/http-client.d.ts +7 -0
- package/dist/core/embeddings/http-client.js +5 -3
- package/dist/core/embeddings/server-mapping.d.ts +1 -1
- package/dist/core/embeddings/server-mapping.js +7 -3
- package/dist/core/graph/import-cycles.d.ts +10 -0
- package/dist/core/graph/import-cycles.js +103 -0
- package/dist/core/group/cross-impact.d.ts +2 -1
- package/dist/core/group/cross-impact.js +5 -1
- package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
- package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +22 -4
- package/dist/core/group/extractors/include-extractor.js +22 -13
- package/dist/core/group/sync.d.ts +27 -1
- package/dist/core/group/sync.js +0 -0
- package/dist/core/incremental/subgraph-extract.js +18 -1
- package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
- package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
- package/dist/core/ingestion/cfg/collect.d.ts +51 -0
- package/dist/core/ingestion/cfg/collect.js +77 -0
- package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
- package/dist/core/ingestion/cfg/control-dependence.js +182 -0
- package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
- package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
- package/dist/core/ingestion/cfg/emit.d.ts +293 -0
- package/dist/core/ingestion/cfg/emit.js +646 -0
- package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
- package/dist/core/ingestion/cfg/post-dominators.js +176 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
- package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
- package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
- package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
- package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
- package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
- package/dist/core/ingestion/cfg/traversal-result.js +2 -0
- package/dist/core/ingestion/cfg/types.d.ts +274 -0
- package/dist/core/ingestion/cfg/types.js +13 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
- package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
- package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
- package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
- package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/go.js +638 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
- package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
- package/dist/core/ingestion/cfg/visitors/java.js +812 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
- package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
- package/dist/core/ingestion/cfg/visitors/php.js +721 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
- package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
- package/dist/core/ingestion/cfg/visitors/python.js +558 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
- package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
- package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
- package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
- package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
- package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
- package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
- package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
- package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
- package/dist/core/ingestion/import-resolvers/utils.js +2 -0
- package/dist/core/ingestion/language-provider.d.ts +11 -0
- package/dist/core/ingestion/languages/c-cpp.js +6 -1
- package/dist/core/ingestion/languages/cobol.js +4 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
- package/dist/core/ingestion/languages/cpp/captures.js +50 -1
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
- package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
- package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
- package/dist/core/ingestion/languages/cpp/query.js +23 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
- package/dist/core/ingestion/languages/csharp.js +2 -0
- package/dist/core/ingestion/languages/dart.js +2 -0
- package/dist/core/ingestion/languages/go.js +2 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/kotlin/query.js +3 -2
- package/dist/core/ingestion/languages/kotlin.js +3 -0
- package/dist/core/ingestion/languages/php.js +2 -0
- package/dist/core/ingestion/languages/python.js +2 -0
- package/dist/core/ingestion/languages/ruby.js +2 -0
- package/dist/core/ingestion/languages/rust.js +2 -0
- package/dist/core/ingestion/languages/swift.js +2 -0
- package/dist/core/ingestion/languages/typescript.js +5 -0
- package/dist/core/ingestion/languages/vue.js +6 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
- package/dist/core/ingestion/method-extractors/generic.js +1 -0
- package/dist/core/ingestion/method-types.d.ts +2 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +1 -0
- package/dist/core/ingestion/mro-processor.js +109 -0
- package/dist/core/ingestion/parsing-processor.js +23 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/index.js +2 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
- package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
- package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
- package/dist/core/ingestion/pipeline.d.ts +92 -10
- package/dist/core/ingestion/pipeline.js +11 -2
- package/dist/core/ingestion/scope-extractor.js +12 -2
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
- package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
- package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
- package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
- package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
- package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
- package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
- package/dist/core/ingestion/taint/call-summary-model.js +25 -0
- package/dist/core/ingestion/taint/emit.d.ts +125 -0
- package/dist/core/ingestion/taint/emit.js +208 -0
- package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
- package/dist/core/ingestion/taint/interproc-emit.js +88 -0
- package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
- package/dist/core/ingestion/taint/interproc-solver.js +312 -0
- package/dist/core/ingestion/taint/match.d.ts +153 -0
- package/dist/core/ingestion/taint/match.js +278 -0
- package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
- package/dist/core/ingestion/taint/path-codec.js +190 -0
- package/dist/core/ingestion/taint/propagate.d.ts +216 -0
- package/dist/core/ingestion/taint/propagate.js +659 -0
- package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
- package/dist/core/ingestion/taint/site-safety.js +98 -0
- package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
- package/dist/core/ingestion/taint/source-sink-config.js +35 -12
- package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
- package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
- package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
- package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
- package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
- package/dist/core/ingestion/taint/summary-harvest.js +537 -0
- package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
- package/dist/core/ingestion/taint/summary-model.js +86 -0
- package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
- package/dist/core/ingestion/taint/typescript-model.js +102 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
- package/dist/core/ingestion/utils/env.d.ts +7 -0
- package/dist/core/ingestion/utils/env.js +12 -0
- package/dist/core/ingestion/utils/method-props.js +1 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +13 -0
- package/dist/core/ingestion/workers/parse-worker.js +76 -17
- package/dist/core/ingestion/workers/worker-pool.d.ts +9 -40
- package/dist/core/ingestion/workers/worker-pool.js +15 -2
- package/dist/core/lbug/csv-generator.d.ts +51 -3
- package/dist/core/lbug/csv-generator.js +369 -255
- package/dist/core/lbug/lbug-adapter.d.ts +58 -18
- package/dist/core/lbug/lbug-adapter.js +346 -84
- package/dist/core/lbug/lbug-config.d.ts +19 -0
- package/dist/core/lbug/lbug-config.js +29 -0
- package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
- package/dist/core/lbug/pdg-emit-sink.js +358 -0
- package/dist/core/lbug/pool-adapter.d.ts +35 -0
- package/dist/core/lbug/pool-adapter.js +90 -1
- package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
- package/dist/core/lbug/rel-pair-routing.js +140 -0
- package/dist/core/lbug/schema.d.ts +2 -2
- package/dist/core/lbug/schema.js +3 -0
- package/dist/core/logger.d.ts +0 -5
- package/dist/core/run-analyze.d.ts +96 -0
- package/dist/core/run-analyze.js +207 -3
- package/dist/core/tree-sitter/parser-loader.js +5 -4
- package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
- package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
- package/dist/core/tree-sitter/vendored-grammars.js +57 -0
- package/dist/core/wiki/generator.js +3 -1
- package/dist/core/wiki/graph-queries.d.ts +6 -0
- package/dist/core/wiki/graph-queries.js +9 -1
- package/dist/mcp/http-transport.d.ts +134 -0
- package/dist/mcp/http-transport.js +503 -0
- package/dist/mcp/local/local-backend.d.ts +110 -24
- package/dist/mcp/local/local-backend.js +1225 -19
- package/dist/mcp/local/pdg-impact.d.ts +384 -0
- package/dist/mcp/local/pdg-impact.js +1972 -0
- package/dist/mcp/resources.js +13 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/mcp/tools.js +214 -7
- package/dist/server/analyze-launch.d.ts +29 -0
- package/dist/server/analyze-launch.js +137 -0
- package/dist/server/analyze-upload.d.ts +33 -0
- package/dist/server/analyze-upload.js +123 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/api.d.ts +17 -0
- package/dist/server/api.js +132 -168
- package/dist/server/git-clone.d.ts +43 -2
- package/dist/server/git-clone.js +211 -16
- package/dist/server/mcp-http.d.ts +5 -6
- package/dist/server/mcp-http.js +9 -82
- package/dist/server/middleware.d.ts +40 -0
- package/dist/server/middleware.js +92 -0
- package/dist/server/private-ip.d.ts +1 -0
- package/dist/server/private-ip.js +15 -0
- package/dist/server/upload-ingest.d.ts +56 -0
- package/dist/server/upload-ingest.js +276 -0
- package/dist/server/upload-paths.d.ts +37 -0
- package/dist/server/upload-paths.js +57 -0
- package/dist/server/upload-sweep.d.ts +20 -0
- package/dist/server/upload-sweep.js +57 -0
- package/dist/storage/git.js +5 -8
- package/dist/storage/parse-cache.d.ts +22 -1
- package/dist/storage/parse-cache.js +41 -10
- package/dist/storage/repo-manager.d.ts +121 -10
- package/dist/storage/repo-manager.js +43 -5
- package/dist/types/pipeline.d.ts +9 -0
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
- package/hooks/claude/gitnexus-hook.cjs +110 -13
- package/hooks/claude/hook-db-lock-probe.cjs +513 -26
- package/package.json +8 -2
- package/scripts/assert-publish-grammar-coverage.cjs +31 -0
- package/scripts/build-tree-sitter-grammars.cjs +16 -10
- package/scripts/cross-platform-tests.ts +1 -0
- package/skills/gitnexus-debugging.md +16 -4
- package/skills/gitnexus-exploring.md +3 -3
- package/skills/gitnexus-guide.md +33 -0
- package/skills/gitnexus-pdg-query.md +89 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/skills/gitnexus-taint-analysis.md +178 -0
- package/vendor/tree-sitter-c/package.json +1 -1
- package/vendor/tree-sitter-dart/package.json +1 -1
- package/vendor/tree-sitter-kotlin/package.json +1 -1
- package/vendor/tree-sitter-proto/package.json +1 -1
- package/vendor/tree-sitter-swift/package.json +1 -1
- package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
- package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
- package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
- package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
- package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
- package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
- package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
- package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
- package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
- package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
- package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
- package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
- package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
- package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
- package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
- package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
- package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
- package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
- package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
- package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
- package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
- package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
- package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
- package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
- package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
- package/web/assets/index-BvYev1UJ.js +635 -0
- package/web/assets/index-_lgn7hs5.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
- package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
- package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
- package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
- package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
- package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
- package/web/index.html +13 -15
- package/scripts/materialize-vendor-grammars.cjs +0 -97
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
- package/web/assets/chunk-CilyBKbf.js +0 -1
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
- package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
- package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
- package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
- package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
- package/web/assets/index-BKWA-m7o.css +0 -2
- package/web/assets/index-CG6q8eTs.js +0 -626
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
- /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
|
@@ -4,20 +4,28 @@ import { createInterface } from 'readline';
|
|
|
4
4
|
import { once } from 'events';
|
|
5
5
|
import { finished } from 'stream/promises';
|
|
6
6
|
import path from 'path';
|
|
7
|
-
import os from 'os';
|
|
8
|
-
import crypto from 'crypto';
|
|
9
7
|
import lbug from '@ladybugdb/core';
|
|
10
8
|
import { closeQueryResults } from './query-result-utils.js';
|
|
11
9
|
import { NODE_TABLES, REL_TABLE_NAME, SCHEMA_QUERIES, EMBEDDING_TABLE_NAME, CREATE_VECTOR_INDEX_QUERY, STALE_HASH_SENTINEL, } from './schema.js';
|
|
12
10
|
import { streamAllCSVsToDisk } from './csv-generator.js';
|
|
11
|
+
import { getNodeLabel as deriveNodeLabel } from './rel-pair-routing.js';
|
|
13
12
|
import { extensionManager } from './extension-loader.js';
|
|
14
|
-
import { closeLbugConnection, isDbBusyError, isOpenRetryExhausted, isWalCorruptionError, openLbugConnection, toNativeSafePath, WAL_RECOVERY_SUGGESTION, waitForWindowsHandleRelease, } from './lbug-config.js';
|
|
13
|
+
import { closeLbugConnection, isDbBusyError, isOpenRetryExhausted, isWalCorruptionError, openLbugConnection, toNativeSafePath, resolveNativeSafeStorageDir, WAL_RECOVERY_SUGGESTION, waitForWindowsHandleRelease, } from './lbug-config.js';
|
|
15
14
|
import { finalizeLbugSidecarsAfterClose, inspectLbugSidecars, isMissingShadowSidecarError, isReadOnlyShadowReplayError, preflightLbugSidecars, quarantineWalForMissingShadow, renameFailureMessage, shadowSidecarRecoveryMessage, } from './sidecar-recovery.js';
|
|
16
15
|
import { isVectorExtensionSupportedByPlatform } from '../platform/capabilities.js';
|
|
17
16
|
import { logger } from '../logger.js';
|
|
18
17
|
/**
|
|
19
18
|
* Split a relationship CSV into per-label-pair files on disk.
|
|
20
19
|
*
|
|
20
|
+
* @internal RETAINED AS A DIFFERENTIAL ORACLE. As of #2203 U2, production emit
|
|
21
|
+
* routes relationships to per-pair files directly during the single pass (see
|
|
22
|
+
* RelPairRouter in `rel-pair-routing.ts`), so this function has NO production
|
|
23
|
+
* callers — it is kept ONLY so the byte-identity test in
|
|
24
|
+
* `test/integration/csv-pipeline.test.ts` ("direct per-pair emit matches the
|
|
25
|
+
* split oracle") can diff the direct-emit output against this proven path. Do
|
|
26
|
+
* NOT delete it as dead code without also removing that test and accepting the
|
|
27
|
+
* loss of the byte-identity guard (and likewise `test/unit/rel-csv-split.test.ts`).
|
|
28
|
+
*
|
|
21
29
|
* Streams the CSV line-by-line, routing each relationship to a file named
|
|
22
30
|
* `rel_{fromLabel}_{toLabel}.csv`. Handles backpressure correctly: only one
|
|
23
31
|
* drain listener per stream at a time, and readline resumes only when ALL
|
|
@@ -732,91 +740,212 @@ const doInitLbug = async (dbPath, readOnly = false) => {
|
|
|
732
740
|
currentDbPath = dbPath;
|
|
733
741
|
return { db, conn };
|
|
734
742
|
};
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
743
|
+
/**
|
|
744
|
+
* Run a COPY, retrying once with IGNORE_ERRORS=true (which skips row-level
|
|
745
|
+
* errors) on first failure. On a second failure, hand the RAW retry error to
|
|
746
|
+
* `onError` — each call site formats + slices its own message (#2226 F5: node
|
|
747
|
+
* COPY slices to 200 chars and throws; relationship COPY slices to 80 and warns,
|
|
748
|
+
* so the helper must not pre-format and lose that distinction). `onError` may
|
|
749
|
+
* throw to propagate the failure.
|
|
750
|
+
*/
|
|
751
|
+
const copyCsvWithRetry = async (targetConn, copyQuery, onError) => {
|
|
752
|
+
try {
|
|
753
|
+
await queryAndDrain(targetConn, copyQuery);
|
|
744
754
|
}
|
|
745
|
-
|
|
746
|
-
|
|
755
|
+
catch {
|
|
756
|
+
try {
|
|
757
|
+
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
|
758
|
+
await queryAndDrain(targetConn, retryQuery);
|
|
759
|
+
}
|
|
760
|
+
catch (retryErr) {
|
|
761
|
+
onError(retryErr);
|
|
762
|
+
}
|
|
747
763
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
// Bulk COPY all node CSVs (sequential — LadybugDB allows only one write txn at a time)
|
|
759
|
-
const nodeFiles = [...csvResult.nodeFiles.entries()];
|
|
760
|
-
const totalSteps = nodeFiles.length + 1; // +1 for relationships
|
|
764
|
+
};
|
|
765
|
+
/**
|
|
766
|
+
* Bulk-COPY every node CSV sequentially on the single writable connection
|
|
767
|
+
* (LadybugDB allows one write txn at a time). Extracted from loadGraphToLbug so
|
|
768
|
+
* it can run either at the node-phase boundary — overlapping the relationship
|
|
769
|
+
* emit pass (#2203) — or after emit in the serial escape-hatch path. Each COPY
|
|
770
|
+
* keeps the IGNORE_ERRORS=true retry; a hard failure throws (no node rows ⇒ the
|
|
771
|
+
* relationship COPY would dangle on missing endpoints).
|
|
772
|
+
*/
|
|
773
|
+
const copyNodeCSVs = async (targetConn, nodeFileEntries, log, totalSteps) => {
|
|
761
774
|
let stepsDone = 0;
|
|
762
|
-
for (const [table, { csvPath, rows }] of
|
|
775
|
+
for (const [table, { csvPath, rows }] of nodeFileEntries) {
|
|
763
776
|
stepsDone++;
|
|
764
777
|
log(`Loading nodes ${stepsDone}/${totalSteps}: ${table} (${rows.toLocaleString()} rows)`);
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
+
const copyQuery = getCopyQuery(table, normalizeCopyPath(csvPath));
|
|
779
|
+
await copyCsvWithRetry(targetConn, copyQuery, (retryErr) => {
|
|
780
|
+
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
781
|
+
throw new Error(`COPY failed for ${table}: ${retryMsg.slice(0, 200)}`);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
/**
|
|
786
|
+
* Persist a KnowledgeGraph: stream CSVs, then bulk-COPY nodes (overlapped with
|
|
787
|
+
* relationship emit — see the body) and relationships.
|
|
788
|
+
*
|
|
789
|
+
* NOT TRANSACTIONAL (#2226). Each `COPY` commits independently and there is no
|
|
790
|
+
* surrounding transaction, so a failure partway through — a node `COPY` that
|
|
791
|
+
* throws at the FK barrier, a relationship `COPY` failure, or a `pdgEmitManifest`
|
|
792
|
+
* collision raised after node rows have already committed in the overlap path —
|
|
793
|
+
* leaves a partially-loaded DB. The caller surfaces the error; recovery is a
|
|
794
|
+
* `--force` re-analyze (a full rebuild), not a partial retry. Callers must not
|
|
795
|
+
* assume the DB is either fully loaded or untouched after a rejection.
|
|
796
|
+
*/
|
|
797
|
+
export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress,
|
|
798
|
+
/**
|
|
799
|
+
* Streamed PDG-emit manifest (#2202). When present (streaming was on, full
|
|
800
|
+
* rebuild), the BasicBlock node CSV + per-pair PDG-edge CSVs it points at
|
|
801
|
+
* were already flushed to disk during the emit loop; they are merged into the
|
|
802
|
+
* COPY plan below so they load alongside the structural CSVs. When streaming
|
|
803
|
+
* was on the in-memory `graph` holds zero BasicBlocks, so `streamAllCSVsToDisk`
|
|
804
|
+
* emits none — the manifest is the sole source and there is no double-COPY.
|
|
805
|
+
*/
|
|
806
|
+
pdgEmitManifest) => {
|
|
807
|
+
if (!conn) {
|
|
808
|
+
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
809
|
+
}
|
|
810
|
+
const log = onProgress || (() => { });
|
|
811
|
+
// ── #2203 persistence-path profiling ──────────────────────────────────
|
|
812
|
+
// Mirrors the PROF_SCOPE_RESOLUTION pattern (scope-resolution/pipeline/
|
|
813
|
+
// run.ts): zero-cost when off — process.hrtime.bigint() is only read under
|
|
814
|
+
// PROF_LBUG_LOAD=1, and the summary is logged behind the same gate. Fills
|
|
815
|
+
// the gap that the DB-persistence path is un-timed today (the analyze
|
|
816
|
+
// "emit" number is the scope-resolution emit bucket, not this COPY path).
|
|
817
|
+
const PROF = process.env.PROF_LBUG_LOAD === '1';
|
|
818
|
+
// Escape hatch / differential oracle (#2203): force the legacy strictly-serial
|
|
819
|
+
// load order (emit everything, THEN COPY nodes, THEN COPY rels) instead of the
|
|
820
|
+
// default node-COPY ‖ rel-emit overlap. Lets an operator revert the behavior at
|
|
821
|
+
// runtime, and lets a test load the same graph both ways and assert identical
|
|
822
|
+
// persisted content.
|
|
823
|
+
const SERIAL = process.env.GITNEXUS_SERIAL_LBUG_LOAD === '1';
|
|
824
|
+
const mark = () => (PROF ? process.hrtime.bigint() : 0n);
|
|
825
|
+
const span = (a, b) => (Number(b - a) / 1e6).toFixed(1);
|
|
826
|
+
const tStart = mark();
|
|
827
|
+
const csvDir = resolveNativeSafeStorageDir(storagePath, 'csv');
|
|
828
|
+
// The single writable connection (LadybugDB is single-writer). Captured as a
|
|
829
|
+
// const so the node-COPY closure has a non-null reference — TS cannot narrow
|
|
830
|
+
// the reassignable module-level `conn` across the callback boundary.
|
|
831
|
+
const writeConn = conn;
|
|
832
|
+
const validTables = new Set(NODE_TABLES);
|
|
833
|
+
// Merge the streamed PDG-emit node CSVs (#2202) into a node-file map. Collision
|
|
834
|
+
// guard: a BasicBlock in the in-memory graph during a streamed run is an
|
|
835
|
+
// invariant violation (streamAllCSVsToDisk would also emit basicblock.csv), so
|
|
836
|
+
// fail loudly rather than drop rows (#2202 review #3). Runs at the node-phase
|
|
837
|
+
// boundary so the manifest BasicBlock table COPYs with the structural CSVs.
|
|
838
|
+
const mergeManifestNodeFiles = (nodeFilesMap) => {
|
|
839
|
+
if (!pdgEmitManifest)
|
|
840
|
+
return;
|
|
841
|
+
for (const [table, meta] of pdgEmitManifest.nodeFiles) {
|
|
842
|
+
if (nodeFilesMap.has(table)) {
|
|
843
|
+
throw new Error(`Streaming PDG manifest collides with a structural node CSV for "${table}" — ` +
|
|
844
|
+
`the in-memory graph should hold zero ${table} nodes when streaming. ` +
|
|
845
|
+
`A ${table} node leaked into the graph during a streamed emit.`);
|
|
778
846
|
}
|
|
847
|
+
nodeFilesMap.set(table, meta);
|
|
779
848
|
}
|
|
780
|
-
}
|
|
781
|
-
//
|
|
782
|
-
|
|
783
|
-
//
|
|
784
|
-
//
|
|
785
|
-
//
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
849
|
+
};
|
|
850
|
+
// Node COPY is the only DB write that can overlap relationship CSV emit: the
|
|
851
|
+
// rel pass writes new rel_*.csv files and never touches `conn`, while node COPY
|
|
852
|
+
// uses `conn` and never touches the rel files. We start node COPY at the
|
|
853
|
+
// node-phase boundary and let the rel pass run concurrently — the only
|
|
854
|
+
// single-writer-safe parallelism (#2203). The rel COPY still waits for node
|
|
855
|
+
// COPY (FK precondition), so the DB load order is unchanged.
|
|
856
|
+
let nodeCopyPromise;
|
|
857
|
+
let nodeCopyError;
|
|
858
|
+
const beginNodeCopy = (nodeFilesMap) => {
|
|
859
|
+
mergeManifestNodeFiles(nodeFilesMap);
|
|
860
|
+
const entries = [...nodeFilesMap.entries()];
|
|
861
|
+
// copyNodeCSVs logs node progress as step/total; it processes only node
|
|
862
|
+
// tables (the rel COPY has its own "Loading edges" progress line), so the
|
|
863
|
+
// denominator is the node-table count — not +1 reserving a rel step.
|
|
864
|
+
// .catch captures the failure so an overlapped (mid-emit) rejection cannot
|
|
865
|
+
// surface as an unhandled rejection; it is rethrown at the FK barrier below.
|
|
866
|
+
nodeCopyPromise = copyNodeCSVs(writeConn, entries, log, entries.length).catch((e) => {
|
|
867
|
+
nodeCopyError = e;
|
|
868
|
+
});
|
|
869
|
+
};
|
|
870
|
+
log('Streaming CSVs to disk...');
|
|
871
|
+
let csvResult;
|
|
872
|
+
try {
|
|
873
|
+
csvResult = SERIAL
|
|
874
|
+
? await streamAllCSVsToDisk(graph, repoPath, csvDir)
|
|
875
|
+
: await streamAllCSVsToDisk(graph, repoPath, csvDir, beginNodeCopy);
|
|
876
|
+
}
|
|
877
|
+
catch (emitErr) {
|
|
878
|
+
// Relationship emit failed. In overlap mode a node COPY may be in flight —
|
|
879
|
+
// settle it (the .catch above means this never rejects) before rethrowing so
|
|
880
|
+
// it cannot leak as an unhandled rejection.
|
|
881
|
+
if (nodeCopyPromise)
|
|
882
|
+
await nodeCopyPromise;
|
|
883
|
+
// If node COPY ALSO failed, emitErr wins the throw — log the swallowed node
|
|
884
|
+
// error so a half-loaded DB isn't misattributed to the emit failure alone.
|
|
885
|
+
if (nodeCopyError) {
|
|
886
|
+
logger.warn({ err: nodeCopyError }, '[lbug-load] node COPY also failed while relationship emit was failing');
|
|
887
|
+
}
|
|
888
|
+
throw emitErr;
|
|
889
|
+
}
|
|
890
|
+
const tCsv = mark();
|
|
891
|
+
// Merge the streamed PDG-emit per-pair rel CSVs (#2202) into the COPY plan —
|
|
892
|
+
// collision-guarded. Done BEFORE node COPY so the serial escape hatch detects a
|
|
893
|
+
// manifest/structural pair collision before committing any node rows (legacy
|
|
894
|
+
// parity with the pre-overlap path), and the overlap path detects it as early
|
|
895
|
+
// as csvResult is available. When a manifest is present, streaming was on and
|
|
896
|
+
// the in-memory graph held zero BasicBlocks, so a structural collision means a
|
|
897
|
+
// streaming-invariant violation — fail loudly rather than load corrupt data.
|
|
898
|
+
if (pdgEmitManifest) {
|
|
899
|
+
for (const [pairKey, meta] of pdgEmitManifest.relsByPair) {
|
|
900
|
+
if (csvResult.relsByPair.has(pairKey)) {
|
|
901
|
+
throw new Error(`Streaming PDG manifest collides with a structural relationship CSV for pair ` +
|
|
902
|
+
`"${pairKey}" — a PDG edge leaked into the in-memory graph during a streamed emit.`);
|
|
903
|
+
}
|
|
904
|
+
csvResult.relsByPair.set(pairKey, meta);
|
|
905
|
+
csvResult.totalValidRels += meta.rows;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
// Serial path: all CSVs are on disk and node COPY has not started — start it
|
|
909
|
+
// here so the barrier below blocks on it exactly as the legacy path did.
|
|
910
|
+
if (SERIAL)
|
|
911
|
+
beginNodeCopy(csvResult.nodeFiles);
|
|
912
|
+
// FK barrier: node rows must exist before the relationship COPY resolves their
|
|
913
|
+
// endpoints. In overlap mode most of node COPY was hidden behind rel emit, so
|
|
914
|
+
// this await is the *residual* node-COPY time (≈0 when fully overlapped).
|
|
915
|
+
if (nodeCopyPromise)
|
|
916
|
+
await nodeCopyPromise;
|
|
917
|
+
if (nodeCopyError) {
|
|
918
|
+
throw nodeCopyError instanceof Error ? nodeCopyError : new Error(String(nodeCopyError));
|
|
919
|
+
}
|
|
920
|
+
const tCopyNodes = mark();
|
|
921
|
+
// Bulk COPY relationships. They were already routed to per-FROM→TO-label-pair
|
|
922
|
+
// files during the emit pass (#2203 U2) — there is no monolithic relations.csv
|
|
923
|
+
// to re-read/re-split here; we COPY each pair file directly.
|
|
924
|
+
const { relsByPair, relHeader, skippedRels, totalValidRels } = csvResult;
|
|
925
|
+
let tCopyRels = tCopyNodes;
|
|
926
|
+
let tFallback = tCopyNodes;
|
|
790
927
|
const insertedRels = totalValidRels;
|
|
791
928
|
const warnings = [];
|
|
792
929
|
if (insertedRels > 0) {
|
|
793
|
-
log(`Loading edges: ${insertedRels.toLocaleString()} across ${
|
|
930
|
+
log(`Loading edges: ${insertedRels.toLocaleString()} across ${relsByPair.size} types`);
|
|
794
931
|
let pairIdx = 0;
|
|
795
932
|
let failedPairEdges = 0;
|
|
796
933
|
const failedPairCsvPaths = new Set();
|
|
797
|
-
for (const [pairKey, { csvPath: pairCsvPath, rows }] of
|
|
934
|
+
for (const [pairKey, { csvPath: pairCsvPath, rows }] of relsByPair) {
|
|
798
935
|
pairIdx++;
|
|
799
936
|
const [fromLabel, toLabel] = pairKey.split('|');
|
|
800
937
|
const normalizedPath = normalizeCopyPath(pairCsvPath);
|
|
938
|
+
// PARALLEL=false is load-bearing here too — see COPY_CSV_OPTS (#2203 / kuzudb/kuzu#5778).
|
|
801
939
|
const copyQuery = `COPY ${REL_TABLE_NAME} FROM "${normalizedPath}" (from="${fromLabel}", to="${toLabel}", HEADER=true, ESCAPE='"', DELIM=',', QUOTE='"', PARALLEL=false, auto_detect=false)`;
|
|
802
940
|
if (pairIdx % 5 === 0 || rows > 1000) {
|
|
803
|
-
log(`Loading edges: ${pairIdx}/${
|
|
804
|
-
}
|
|
805
|
-
try {
|
|
806
|
-
await queryAndDrain(conn, copyQuery);
|
|
807
|
-
}
|
|
808
|
-
catch (err) {
|
|
809
|
-
try {
|
|
810
|
-
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
|
811
|
-
await queryAndDrain(conn, retryQuery);
|
|
812
|
-
}
|
|
813
|
-
catch (retryErr) {
|
|
814
|
-
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
815
|
-
warnings.push(`${fromLabel}->${toLabel} (${rows} edges): ${retryMsg.slice(0, 80)}`);
|
|
816
|
-
failedPairEdges += rows;
|
|
817
|
-
failedPairCsvPaths.add(pairCsvPath);
|
|
818
|
-
}
|
|
941
|
+
log(`Loading edges: ${pairIdx}/${relsByPair.size} types (${fromLabel} -> ${toLabel})`);
|
|
819
942
|
}
|
|
943
|
+
await copyCsvWithRetry(conn, copyQuery, (retryErr) => {
|
|
944
|
+
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
945
|
+
warnings.push(`${fromLabel}->${toLabel} (${rows} edges): ${retryMsg.slice(0, 80)}`);
|
|
946
|
+
failedPairEdges += rows;
|
|
947
|
+
failedPairCsvPaths.add(pairCsvPath);
|
|
948
|
+
});
|
|
820
949
|
// Only delete if not in failedPairCsvPaths (needed for fallback)
|
|
821
950
|
if (!failedPairCsvPaths.has(pairCsvPath)) {
|
|
822
951
|
try {
|
|
@@ -825,6 +954,7 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
825
954
|
catch { }
|
|
826
955
|
}
|
|
827
956
|
}
|
|
957
|
+
tCopyRels = mark();
|
|
828
958
|
if (failedPairCsvPaths.size > 0) {
|
|
829
959
|
log(`Inserting ${failedPairEdges} edges individually (missing schema pairs)`);
|
|
830
960
|
// Read failed pair files and merge for fallback inserts
|
|
@@ -846,15 +976,13 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
846
976
|
catch { }
|
|
847
977
|
}
|
|
848
978
|
if (allLines.length > 1) {
|
|
849
|
-
await fallbackRelationshipInserts(allLines, validTables,
|
|
979
|
+
await fallbackRelationshipInserts(allLines, validTables, deriveNodeLabel);
|
|
850
980
|
}
|
|
851
981
|
}
|
|
982
|
+
tFallback = mark();
|
|
852
983
|
}
|
|
853
|
-
// Cleanup all CSVs
|
|
854
|
-
|
|
855
|
-
await fs.unlink(csvResult.relCsvPath);
|
|
856
|
-
}
|
|
857
|
-
catch { }
|
|
984
|
+
// Cleanup all CSVs (per-pair rel files are unlinked in the COPY loop above;
|
|
985
|
+
// the remaining sweep below catches node CSVs + any leftover pair files).
|
|
858
986
|
for (const [, { csvPath }] of csvResult.nodeFiles) {
|
|
859
987
|
try {
|
|
860
988
|
await fs.unlink(csvPath);
|
|
@@ -875,13 +1003,39 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
875
1003
|
await fs.rmdir(csvDir);
|
|
876
1004
|
}
|
|
877
1005
|
catch { }
|
|
1006
|
+
if (PROF) {
|
|
1007
|
+
const tEnd = mark();
|
|
1008
|
+
let totalNodeRows = 0;
|
|
1009
|
+
for (const [, { rows }] of csvResult.nodeFiles)
|
|
1010
|
+
totalNodeRows += rows;
|
|
1011
|
+
// `mode` records which load path ran. In overlap mode `csv-emit` is the wall
|
|
1012
|
+
// to streamAllCSVsToDisk's return (node COPY overlapped part of it) and
|
|
1013
|
+
// `copy-nodes` is the RESIDUAL node-COPY await after emit returned — it
|
|
1014
|
+
// trends to 0 as the overlap hides node COPY behind relationship emit. In
|
|
1015
|
+
// serial mode the buckets carry their legacy, disjoint meaning.
|
|
1016
|
+
logger.warn(`[lbug-load prof] mode=${SERIAL ? 'serial' : 'overlap'} csv-emit=${span(tStart, tCsv)}ms ` +
|
|
1017
|
+
`copy-nodes=${span(tCsv, tCopyNodes)}ms copy-rels=${span(tCopyNodes, tCopyRels)}ms ` +
|
|
1018
|
+
`fallback=${span(tCopyRels, tFallback)}ms total=${span(tStart, tEnd)}ms ` +
|
|
1019
|
+
`(${totalNodeRows} nodes, ${insertedRels} rels)`);
|
|
1020
|
+
}
|
|
878
1021
|
return { success: true, insertedRels, skippedRels, warnings };
|
|
879
1022
|
};
|
|
880
1023
|
// LadybugDB default ESCAPE is '\' (backslash), but our CSV uses RFC 4180 escaping ("" for literal quotes).
|
|
881
1024
|
// Source code content is full of backslashes which confuse the auto-detection.
|
|
882
1025
|
// We MUST explicitly set ESCAPE='"' to use RFC 4180 escaping, and disable auto_detect to prevent
|
|
883
1026
|
// LadybugDB from overriding our settings based on sample rows.
|
|
884
|
-
|
|
1027
|
+
//
|
|
1028
|
+
// PARALLEL=false IS LOAD-BEARING FOR CORRECTNESS — DO NOT FLIP IT (#2203).
|
|
1029
|
+
// LadybugDB's parallel CSV reader (Kuzu-derived; default PARALLEL=true) splits the
|
|
1030
|
+
// file into byte ranges parsed concurrently, and CANNOT determine line boundaries
|
|
1031
|
+
// when a quoted field contains an embedded newline — it errors with "Quoted newlines
|
|
1032
|
+
// are not supported in parallel CSV reader. Please specify PARALLEL=FALSE", or worse,
|
|
1033
|
+
// mis-parses silently (upstream kuzudb/kuzu#5778, still open). Our `content`/`text`
|
|
1034
|
+
// columns hold source code, so quoted multiline fields are guaranteed. PARALLEL=false
|
|
1035
|
+
// is therefore required, not conservative. The multiline-quoted round-trip in
|
|
1036
|
+
// test/integration/copy-parallel-invariant.test.ts fails loudly if this is ever flipped.
|
|
1037
|
+
// Exported so that test asserts the invariant statically as well.
|
|
1038
|
+
export const COPY_CSV_OPTS = `(HEADER=true, ESCAPE='"', DELIM=',', QUOTE='"', PARALLEL=false, auto_detect=false)`;
|
|
885
1039
|
// Multi-language table names that were created with backticks in CODE_ELEMENT_BASE
|
|
886
1040
|
// and must always be referenced with backticks in queries
|
|
887
1041
|
const BACKTICK_TABLES = new Set([
|
|
@@ -947,7 +1101,7 @@ const TABLES_WITH_EXPORTED = new Set([
|
|
|
947
1101
|
'Method',
|
|
948
1102
|
'CodeElement',
|
|
949
1103
|
]);
|
|
950
|
-
const getCopyQuery = (table, filePath) => {
|
|
1104
|
+
export const getCopyQuery = (table, filePath) => {
|
|
951
1105
|
const t = escapeTableName(table);
|
|
952
1106
|
if (table === 'File') {
|
|
953
1107
|
return `COPY ${t}(id, name, filePath, content) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
@@ -965,14 +1119,16 @@ const getCopyQuery = (table, filePath) => {
|
|
|
965
1119
|
return `COPY ${t}(id, name, filePath, startLine, endLine, level, content, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
966
1120
|
}
|
|
967
1121
|
if (table === 'Route') {
|
|
968
|
-
return `COPY ${t}(id, name, filePath, responseKeys, errorKeys, middleware) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
1122
|
+
return `COPY ${t}(id, name, filePath, responseKeys, errorKeys, middleware, method) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
969
1123
|
}
|
|
970
1124
|
if (table === 'Tool') {
|
|
971
1125
|
return `COPY ${t}(id, name, filePath, description) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
972
1126
|
}
|
|
973
1127
|
if (table === 'BasicBlock') {
|
|
974
|
-
// Taint/PDG substrate (issue #2080) — no name column.
|
|
975
|
-
|
|
1128
|
+
// Taint/PDG substrate (issue #2080) — no name column. `callees` is the
|
|
1129
|
+
// statement-precise inter-procedural reach substrate (space-joined leaf names);
|
|
1130
|
+
// `calleeIds` is its SOUND parallel (space-joined resolved callee ids, #2227).
|
|
1131
|
+
return `COPY ${t}(id, filePath, startLine, endLine, text, callees, calleeIds) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
976
1132
|
}
|
|
977
1133
|
if (table === 'Method') {
|
|
978
1134
|
return `COPY ${t}(id, name, filePath, startLine, endLine, isExported, content, description, parameterCount, returnType) FROM "${filePath}" ${COPY_CSV_OPTS}`;
|
|
@@ -1024,8 +1180,9 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
|
|
|
1024
1180
|
query = `CREATE (n:Section {id: ${escapeValue(properties.id)}, name: ${escapeValue(properties.name)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, level: ${properties.level || 1}, content: ${escapeValue(properties.content || '')}${descPart}})`;
|
|
1025
1181
|
}
|
|
1026
1182
|
else if (label === 'BasicBlock') {
|
|
1027
|
-
// Taint/PDG substrate (issue #2080) — no name column.
|
|
1028
|
-
|
|
1183
|
+
// Taint/PDG substrate (issue #2080) — no name column. `calleeIds` (#2227)
|
|
1184
|
+
// is the sound resolved-id parallel to the leaf-name `callees` set.
|
|
1185
|
+
query = `CREATE (n:BasicBlock {id: ${escapeValue(properties.id)}, filePath: ${escapeValue(properties.filePath)}, startLine: ${properties.startLine || 0}, endLine: ${properties.endLine || 0}, text: ${escapeValue(properties.text || '')}, callees: ${escapeValue(properties.callees || '')}, calleeIds: ${escapeValue(properties.calleeIds || '')}})`;
|
|
1029
1186
|
}
|
|
1030
1187
|
else if (TABLES_WITH_EXPORTED.has(label)) {
|
|
1031
1188
|
const descPart = properties.description
|
|
@@ -1111,8 +1268,9 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
|
|
|
1111
1268
|
query = `MERGE (n:Section {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.level = ${properties.level || 1}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
|
|
1112
1269
|
}
|
|
1113
1270
|
else if (label === 'BasicBlock') {
|
|
1114
|
-
// Taint/PDG substrate (issue #2080) — no name column.
|
|
1115
|
-
|
|
1271
|
+
// Taint/PDG substrate (issue #2080) — no name column. `calleeIds`
|
|
1272
|
+
// (#2227) is the sound resolved-id parallel to the `callees` set.
|
|
1273
|
+
query = `MERGE (n:BasicBlock {id: ${escapeValue(properties.id)}}) SET n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.text = ${escapeValue(properties.text || '')}, n.callees = ${escapeValue(properties.callees || '')}, n.calleeIds = ${escapeValue(properties.calleeIds || '')}`;
|
|
1116
1274
|
}
|
|
1117
1275
|
else if (TABLES_WITH_EXPORTED.has(label)) {
|
|
1118
1276
|
const descPart = properties.description
|
|
@@ -1629,6 +1787,110 @@ export const deleteAllCommunitiesAndProcesses = async () => {
|
|
|
1629
1787
|
}
|
|
1630
1788
|
return { nodesDeleted };
|
|
1631
1789
|
};
|
|
1790
|
+
/**
|
|
1791
|
+
* Drop every interprocedural `TAINT_PATH` relationship (#2084 M4 U6). Used at
|
|
1792
|
+
* the start of an incremental `--pdg` writeback so the `taintSummaries` phase
|
|
1793
|
+
* re-materialises them from scratch on the FULL recomputed graph.
|
|
1794
|
+
*
|
|
1795
|
+
* TAINT_PATH validity is a WHOLE-PROGRAM property (a flow A→C can be
|
|
1796
|
+
* invalidated by a change to an INTERMEDIATE function whose file is neither A
|
|
1797
|
+
* nor C). The endpoint-writability extract rule (`extractChangedSubgraph`)
|
|
1798
|
+
* cannot see that — an A→C edge between two unchanged files would be skipped
|
|
1799
|
+
* and a stale finding would survive. So, exactly like Community/Process, the
|
|
1800
|
+
* sound move is delete-all-then-rebuild: cheap because TAINT_PATH is sparse
|
|
1801
|
+
* (per-run capped), and the compute side already rebuilds every summary each
|
|
1802
|
+
* run. Relationship-level (TAINT_PATH is an edge type, not a node label), so a
|
|
1803
|
+
* plain DELETE on the typed CodeRelation rows — endpoints are untouched.
|
|
1804
|
+
*/
|
|
1805
|
+
export const deleteAllInterprocTaintPaths = async () => {
|
|
1806
|
+
if (!conn) {
|
|
1807
|
+
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
1808
|
+
}
|
|
1809
|
+
let edgesDeleted = 0;
|
|
1810
|
+
let countResult;
|
|
1811
|
+
try {
|
|
1812
|
+
countResult = await conn.query(`MATCH ()-[r:CodeRelation]->() WHERE r.type = 'TAINT_PATH' RETURN count(r) AS cnt`);
|
|
1813
|
+
const result = Array.isArray(countResult) ? countResult[0] : countResult;
|
|
1814
|
+
const rows = await result.getAll();
|
|
1815
|
+
const count = Number(rows[0]?.cnt ?? rows[0]?.[0] ?? 0);
|
|
1816
|
+
if (count > 0) {
|
|
1817
|
+
await conn.query(`MATCH ()-[r:CodeRelation]->() WHERE r.type = 'TAINT_PATH' DELETE r`);
|
|
1818
|
+
edgesDeleted = count;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
catch (err) {
|
|
1822
|
+
// A missing table on a freshly-initialized DB is the benign, expected case
|
|
1823
|
+
// (the count query above is what throws) — stay silent. Any OTHER failure
|
|
1824
|
+
// (lock, disk, native error) would leave stale TAINT_PATH rows that the
|
|
1825
|
+
// subsequent re-extract then DUPLICATES (CodeRelation has no PK), so it
|
|
1826
|
+
// must ABORT the writeback (#2084 review P2-5): re-throw so the caller's
|
|
1827
|
+
// crash-recovery dirty flag forces a clean full rebuild on the next run,
|
|
1828
|
+
// rather than silently writing duplicate cross-function findings.
|
|
1829
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1830
|
+
if (/no table|not exist|not found|does not exist|Table .* does not exist/i.test(msg)) {
|
|
1831
|
+
if (countResult)
|
|
1832
|
+
await closeQueryResults(countResult);
|
|
1833
|
+
return { edgesDeleted };
|
|
1834
|
+
}
|
|
1835
|
+
if (countResult)
|
|
1836
|
+
await closeQueryResults(countResult);
|
|
1837
|
+
throw new Error(`[taint-interproc] failed to clear existing TAINT_PATH edges before incremental ` +
|
|
1838
|
+
`re-write (${msg}) — aborting to avoid duplicate cross-function findings; ` +
|
|
1839
|
+
`the next run will full-rebuild`);
|
|
1840
|
+
}
|
|
1841
|
+
if (countResult)
|
|
1842
|
+
await closeQueryResults(countResult);
|
|
1843
|
+
return { edgesDeleted };
|
|
1844
|
+
};
|
|
1845
|
+
/**
|
|
1846
|
+
* Drop every `CALL_SUMMARY` relationship (PDG FU-C, U-C3). Used at the start of
|
|
1847
|
+
* an incremental `--pdg` writeback so the `callSummaries` phase re-materialises
|
|
1848
|
+
* them from scratch on the FULL recomputed graph.
|
|
1849
|
+
*
|
|
1850
|
+
* Mirrors {@link deleteAllInterprocTaintPaths}: CALL_SUMMARY is a self-loop edge
|
|
1851
|
+
* type (not a node label), so a plain DELETE on the typed CodeRelation rows
|
|
1852
|
+
* leaves endpoints untouched. `extractChangedSubgraph` re-includes ALL of them
|
|
1853
|
+
* from the fresh graph (`isGraphWideRelType`), so delete-all-then-rebuild keeps
|
|
1854
|
+
* an unchanged function's summary from being lost.
|
|
1855
|
+
*/
|
|
1856
|
+
export const deleteAllCallSummaries = async () => {
|
|
1857
|
+
if (!conn) {
|
|
1858
|
+
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
1859
|
+
}
|
|
1860
|
+
let edgesDeleted = 0;
|
|
1861
|
+
let countResult;
|
|
1862
|
+
try {
|
|
1863
|
+
countResult = await conn.query(`MATCH ()-[r:CodeRelation]->() WHERE r.type = 'CALL_SUMMARY' RETURN count(r) AS cnt`);
|
|
1864
|
+
const result = Array.isArray(countResult) ? countResult[0] : countResult;
|
|
1865
|
+
const rows = await result.getAll();
|
|
1866
|
+
const count = Number(rows[0]?.cnt ?? rows[0]?.[0] ?? 0);
|
|
1867
|
+
if (count > 0) {
|
|
1868
|
+
await conn.query(`MATCH ()-[r:CodeRelation]->() WHERE r.type = 'CALL_SUMMARY' DELETE r`);
|
|
1869
|
+
edgesDeleted = count;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
catch (err) {
|
|
1873
|
+
// A missing table on a freshly-initialized DB is the benign, expected case
|
|
1874
|
+
// (the count query is what throws) — stay silent. Any OTHER failure would
|
|
1875
|
+
// leave stale rows that the re-extract then DUPLICATES (CodeRelation has no
|
|
1876
|
+
// PK), so it must ABORT the writeback: re-throw so the caller's crash-
|
|
1877
|
+
// recovery dirty flag forces a clean full rebuild on the next run.
|
|
1878
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1879
|
+
if (/no table|not exist|not found|does not exist|Table .* does not exist/i.test(msg)) {
|
|
1880
|
+
if (countResult)
|
|
1881
|
+
await closeQueryResults(countResult);
|
|
1882
|
+
return { edgesDeleted };
|
|
1883
|
+
}
|
|
1884
|
+
if (countResult)
|
|
1885
|
+
await closeQueryResults(countResult);
|
|
1886
|
+
throw new Error(`[call-summary] failed to clear existing CALL_SUMMARY edges before incremental ` +
|
|
1887
|
+
`re-write (${msg}) — aborting to avoid duplicate summaries; ` +
|
|
1888
|
+
`the next run will full-rebuild`);
|
|
1889
|
+
}
|
|
1890
|
+
if (countResult)
|
|
1891
|
+
await closeQueryResults(countResult);
|
|
1892
|
+
return { edgesDeleted };
|
|
1893
|
+
};
|
|
1632
1894
|
// ============================================================================
|
|
1633
1895
|
// Full-Text Search (FTS) Functions
|
|
1634
1896
|
// ============================================================================
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import type lbug from '@ladybugdb/core';
|
|
2
2
|
export declare function cleanupNativePathJunctions(): void;
|
|
3
3
|
export declare function toNativeSafePath(p: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the on-disk CSV staging dir for `<storagePath>/<subdir>`, applying the
|
|
6
|
+
* same ASCII-safe relocation `toNativeSafePath` enables: on Windows with a
|
|
7
|
+
* non-ASCII storage path, LadybugDB's bulk COPY cannot open files under that
|
|
8
|
+
* path, so the dir is relocated under `os.tmpdir()`. Shared by the structural
|
|
9
|
+
* `csv/` dir and the streaming `pdg-csv/` dir (#2202) so the two can never
|
|
10
|
+
* diverge on platform handling; the `gitnexus-<subdir>-` prefix keeps their tmp
|
|
11
|
+
* locations distinct and recognizable.
|
|
12
|
+
*
|
|
13
|
+
* The relocated dir is created with `fs.mkdtempSync` (a unique, mode-0700,
|
|
14
|
+
* guaranteed-not-pre-existing suffix) rather than a deterministic
|
|
15
|
+
* `gitnexus-<subdir>-<hash>` name. A predictable name in the world-readable OS
|
|
16
|
+
* temp dir is information-disclosure-prone and pre-plantable
|
|
17
|
+
* (CWE-377/378 / CodeQL `js/insecure-temporary-file`); mkdtemp's random suffix
|
|
18
|
+
* is the documented mitigation and is what reaches the streaming sink's
|
|
19
|
+
* `fs.openSync`. The non-Windows / ASCII path stays a pure `path.join` (no dir
|
|
20
|
+
* created) and is byte-identical to before.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveNativeSafeStorageDir(storagePath: string, subdir: string): string;
|
|
4
23
|
/**
|
|
5
24
|
* Shared configuration for `@ladybugdb/core` `Database` construction.
|
|
6
25
|
*
|
|
@@ -179,6 +179,35 @@ export function toNativeSafePath(p) {
|
|
|
179
179
|
'(fsutil 8dot3name set 0).');
|
|
180
180
|
return p;
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolve the on-disk CSV staging dir for `<storagePath>/<subdir>`, applying the
|
|
184
|
+
* same ASCII-safe relocation `toNativeSafePath` enables: on Windows with a
|
|
185
|
+
* non-ASCII storage path, LadybugDB's bulk COPY cannot open files under that
|
|
186
|
+
* path, so the dir is relocated under `os.tmpdir()`. Shared by the structural
|
|
187
|
+
* `csv/` dir and the streaming `pdg-csv/` dir (#2202) so the two can never
|
|
188
|
+
* diverge on platform handling; the `gitnexus-<subdir>-` prefix keeps their tmp
|
|
189
|
+
* locations distinct and recognizable.
|
|
190
|
+
*
|
|
191
|
+
* The relocated dir is created with `fs.mkdtempSync` (a unique, mode-0700,
|
|
192
|
+
* guaranteed-not-pre-existing suffix) rather than a deterministic
|
|
193
|
+
* `gitnexus-<subdir>-<hash>` name. A predictable name in the world-readable OS
|
|
194
|
+
* temp dir is information-disclosure-prone and pre-plantable
|
|
195
|
+
* (CWE-377/378 / CodeQL `js/insecure-temporary-file`); mkdtemp's random suffix
|
|
196
|
+
* is the documented mitigation and is what reaches the streaming sink's
|
|
197
|
+
* `fs.openSync`. The non-Windows / ASCII path stays a pure `path.join` (no dir
|
|
198
|
+
* created) and is byte-identical to before.
|
|
199
|
+
*/
|
|
200
|
+
export function resolveNativeSafeStorageDir(storagePath, subdir) {
|
|
201
|
+
if (process.platform === 'win32' && NON_ASCII_RE.test(storagePath)) {
|
|
202
|
+
// 8.3-shorten the tmpdir base first (a non-ASCII Windows *profile* path can
|
|
203
|
+
// make os.tmpdir() itself non-ASCII), THEN mkdtemp so the returned path —
|
|
204
|
+
// the one that flows into fs.openSync — is provably mkdtemp-sourced (random,
|
|
205
|
+
// exclusive) and clears the insecure-temp-file dataflow.
|
|
206
|
+
const base = toNativeSafePath(os.tmpdir());
|
|
207
|
+
return fsSync.mkdtempSync(path.join(base, `gitnexus-${subdir}-`));
|
|
208
|
+
}
|
|
209
|
+
return path.join(storagePath, subdir);
|
|
210
|
+
}
|
|
182
211
|
/**
|
|
183
212
|
* Shared configuration for `@ladybugdb/core` `Database` construction.
|
|
184
213
|
*
|