gitnexus 1.6.8-rc.8 → 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 +23 -2
- package/dist/core/ingestion/languages/c-cpp.js +17 -5
- 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 +8 -1
- 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 +44 -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/clone-safety.d.ts +109 -0
- package/dist/core/ingestion/workers/clone-safety.js +465 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
- package/dist/core/ingestion/workers/parse-worker.js +81 -53
- package/dist/core/ingestion/workers/post-result.d.ts +22 -0
- package/dist/core/ingestion/workers/post-result.js +87 -0
- package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
- package/dist/core/ingestion/workers/result-merge.js +43 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
- package/dist/core/ingestion/workers/worker-pool.js +43 -16
- 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-ipc.d.ts +58 -0
- package/dist/server/analyze-worker-ipc.js +16 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/analyze-worker.js +7 -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 +44 -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
package/dist/mcp/resources.js
CHANGED
|
@@ -234,7 +234,7 @@ async function getReposResource(backend) {
|
|
|
234
234
|
if (repos.length > 1) {
|
|
235
235
|
lines.push('');
|
|
236
236
|
lines.push('# Multiple repos indexed. Use repo parameter in tool calls:');
|
|
237
|
-
lines.push(`# query({
|
|
237
|
+
lines.push(`# query({search_query: "auth", repo: "${repos[0].name}"})`);
|
|
238
238
|
}
|
|
239
239
|
return lines.join('\n');
|
|
240
240
|
}
|
|
@@ -270,6 +270,7 @@ async function getContextResource(backend, repoName) {
|
|
|
270
270
|
lines.push(' - query: Process-grouped code intelligence (execution flows related to a concept)');
|
|
271
271
|
lines.push(' - context: 360-degree symbol view (categorized refs, process participation)');
|
|
272
272
|
lines.push(' - impact: Blast radius analysis (what breaks if you change a symbol)');
|
|
273
|
+
lines.push(' - explain: Persisted taint findings — source→sink data flows with per-hop variables (requires analyze --pdg)');
|
|
273
274
|
lines.push(' - detect_changes: Git-diff impact analysis (what do your changes affect)');
|
|
274
275
|
lines.push(' - rename: Multi-file coordinated rename with confidence tags');
|
|
275
276
|
lines.push(' - cypher: Raw graph queries');
|
|
@@ -386,6 +387,12 @@ relationships:
|
|
|
386
387
|
- MEMBER_OF: Symbol belongs to community
|
|
387
388
|
- STEP_IN_PROCESS: Symbol is step N in process
|
|
388
389
|
|
|
390
|
+
pdg_layers: "Recorded ONLY when indexed with 'gitnexus analyze --pdg'. Intra-procedural, basic-block granular; both endpoints are BasicBlock nodes. Prefer the pdg_query tool over raw Cypher."
|
|
391
|
+
- BasicBlock: "Basic-block node. Columns: id, filePath, startLine, endLine, text. id = 'BasicBlock:<filePath>:<fnStartLine>:<fnStartCol>:<blockIndex>'."
|
|
392
|
+
- CFG: "Control-flow edge BasicBlock->BasicBlock. Edge kind (seq/cond-true/cond-false/loop-back/...) is in reason."
|
|
393
|
+
- CDG: "Control-DEPENDENCE edge BasicBlock->BasicBlock — the source predicate gates the target's execution. Branch sense 'T'|'F' in reason. Query via pdg_query mode:'controls'."
|
|
394
|
+
- REACHING_DEF: "Data-dependence (def->use) edge BasicBlock->BasicBlock. Source-level variable name is in reason. Query via pdg_query mode:'flows'."
|
|
395
|
+
|
|
389
396
|
relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
|
|
390
397
|
|
|
391
398
|
example_queries:
|
|
@@ -403,6 +410,11 @@ example_queries:
|
|
|
403
410
|
WHERE p.heuristicLabel = "LoginFlow"
|
|
404
411
|
RETURN s.name, r.step
|
|
405
412
|
ORDER BY r.step
|
|
413
|
+
|
|
414
|
+
guard_clauses (--pdg only; prefer pdg_query mode:'controls'): |
|
|
415
|
+
MATCH (pred:BasicBlock)-[r:CodeRelation {type: 'CDG'}]->(dep:BasicBlock)
|
|
416
|
+
WHERE dep.text STARTS WITH 'return' OR dep.text STARTS WITH 'throw'
|
|
417
|
+
RETURN pred.startLine, r.reason AS branch, dep.startLine, dep.text
|
|
406
418
|
`;
|
|
407
419
|
}
|
|
408
420
|
/**
|
package/dist/mcp/tools.d.ts
CHANGED
|
@@ -36,4 +36,16 @@ export interface ToolDefinition {
|
|
|
36
36
|
*/
|
|
37
37
|
export declare const LIST_REPOS_DEFAULT_LIMIT = 50;
|
|
38
38
|
export declare const LIST_REPOS_MAX_LIMIT = 200;
|
|
39
|
+
/**
|
|
40
|
+
* Pagination bounds for the `explain` tool (#2083 M3 U6). Findings are sparse
|
|
41
|
+
* and capped per function at analyze time, but a large repo can still
|
|
42
|
+
* accumulate enough TAINTED rows to blow MCP/LLM token limits — the response
|
|
43
|
+
* is page-bounded like `list_repos`. Exported so the backend clamp
|
|
44
|
+
* (`local-backend.ts`) and the schema stay a single source of truth.
|
|
45
|
+
*/
|
|
46
|
+
export declare const EXPLAIN_DEFAULT_LIMIT = 50;
|
|
47
|
+
export declare const EXPLAIN_MAX_LIMIT = 200;
|
|
48
|
+
export declare const PDG_QUERY_DEFAULT_LIMIT = 50;
|
|
49
|
+
export declare const PDG_QUERY_MAX_LIMIT = 200;
|
|
50
|
+
export declare const IMPACT_MAX_DEPTH = 32;
|
|
39
51
|
export declare const GITNEXUS_TOOLS: ToolDefinition[];
|
package/dist/mcp/tools.js
CHANGED
|
@@ -32,6 +32,22 @@ const DESTRUCTIVE_TOOL_ANNOTATIONS = {
|
|
|
32
32
|
*/
|
|
33
33
|
export const LIST_REPOS_DEFAULT_LIMIT = 50;
|
|
34
34
|
export const LIST_REPOS_MAX_LIMIT = 200;
|
|
35
|
+
/**
|
|
36
|
+
* Pagination bounds for the `explain` tool (#2083 M3 U6). Findings are sparse
|
|
37
|
+
* and capped per function at analyze time, but a large repo can still
|
|
38
|
+
* accumulate enough TAINTED rows to blow MCP/LLM token limits — the response
|
|
39
|
+
* is page-bounded like `list_repos`. Exported so the backend clamp
|
|
40
|
+
* (`local-backend.ts`) and the schema stay a single source of truth.
|
|
41
|
+
*/
|
|
42
|
+
export const EXPLAIN_DEFAULT_LIMIT = 50;
|
|
43
|
+
export const EXPLAIN_MAX_LIMIT = 200;
|
|
44
|
+
// pdg_query result-page bounds (#2086 M6). Mirror the EXPLAIN_* limits — the
|
|
45
|
+
// no-rel-index path means every page must be anchored + LIMIT-bounded.
|
|
46
|
+
export const PDG_QUERY_DEFAULT_LIMIT = 50;
|
|
47
|
+
export const PDG_QUERY_MAX_LIMIT = 200;
|
|
48
|
+
// Shared impact traversal depth cap. The MCP schema advertises this bound;
|
|
49
|
+
// PDG direct backend callers also enforce it before running traversal.
|
|
50
|
+
export const IMPACT_MAX_DEPTH = 32;
|
|
35
51
|
export const GITNEXUS_TOOLS = [
|
|
36
52
|
{
|
|
37
53
|
name: 'list_repos',
|
|
@@ -89,7 +105,14 @@ SERVICE: optional monorepo path prefix (POSIX-style, case-sensitive segments). W
|
|
|
89
105
|
inputSchema: {
|
|
90
106
|
type: 'object',
|
|
91
107
|
properties: {
|
|
92
|
-
|
|
108
|
+
// #2175: the legacy `query` key is still accepted by the handler
|
|
109
|
+
// (resolveAliasString in local-backend.ts), but is deliberately NOT named in the
|
|
110
|
+
// advertised property or its description — surfacing "query" in the schema an LLM
|
|
111
|
+
// reads would nudge it to send `query`, the exact argument Claude Code drops.
|
|
112
|
+
search_query: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'Natural language or keyword search query.',
|
|
115
|
+
},
|
|
93
116
|
task_context: {
|
|
94
117
|
type: 'string',
|
|
95
118
|
description: 'What you are working on (e.g., "adding OAuth support"). Helps ranking.',
|
|
@@ -127,7 +150,7 @@ SERVICE: optional monorepo path prefix (POSIX-style, case-sensitive segments). W
|
|
|
127
150
|
description: 'Optional monorepo service root (relative path, "/" separators). In group mode (@repo), prefix-matches symbol file paths; ignored for a normal repo name. Empty string is rejected server-side.',
|
|
128
151
|
},
|
|
129
152
|
},
|
|
130
|
-
required: ['
|
|
153
|
+
required: ['search_query'],
|
|
131
154
|
},
|
|
132
155
|
},
|
|
133
156
|
{
|
|
@@ -175,12 +198,20 @@ TIPS:
|
|
|
175
198
|
- All relationships use single CodeRelation table — filter with {type: 'CALLS'} etc.
|
|
176
199
|
- Community = auto-detected functional area (Leiden algorithm). Properties: heuristicLabel, cohesion, symbolCount, keywords, description, enrichedBy
|
|
177
200
|
- Process = execution flow trace from entry point to terminal. Properties: heuristicLabel, processType, stepCount, communities, entryPointId, terminalId
|
|
178
|
-
- Use heuristicLabel (not label) for human-readable community/process names
|
|
201
|
+
- Use heuristicLabel (not label) for human-readable community/process names
|
|
202
|
+
- PDG layers (only when indexed with \`--pdg\`): BasicBlock nodes + CFG / CDG (control dependence, branch sense 'T'|'F' in reason) / REACHING_DEF (def→use, variable in reason) edges, all BasicBlock→BasicBlock. Prefer the \`pdg_query\` tool — it anchors + bounds these for you (raw \`[:CDG*]\`/\`[:REACHING_DEF*]\` path scans are unindexed and unbounded).`,
|
|
179
203
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
180
204
|
inputSchema: {
|
|
181
205
|
type: 'object',
|
|
182
206
|
properties: {
|
|
183
|
-
|
|
207
|
+
// #2175: the legacy `query` key is still accepted by the handler
|
|
208
|
+
// (resolveAliasString in local-backend.ts), but is deliberately NOT named in the
|
|
209
|
+
// advertised property or its description — surfacing "query" in the schema an LLM
|
|
210
|
+
// reads would nudge it to send `query`, the exact argument Claude Code drops.
|
|
211
|
+
statement: {
|
|
212
|
+
type: 'string',
|
|
213
|
+
description: 'Cypher statement to execute.',
|
|
214
|
+
},
|
|
184
215
|
params: {
|
|
185
216
|
type: 'object',
|
|
186
217
|
description: 'Optional query parameters for placeholders (e.g. $name) to execute via prepared statement binding.',
|
|
@@ -190,7 +221,7 @@ TIPS:
|
|
|
190
221
|
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
191
222
|
},
|
|
192
223
|
},
|
|
193
|
-
required: ['
|
|
224
|
+
required: ['statement'],
|
|
194
225
|
},
|
|
195
226
|
},
|
|
196
227
|
{
|
|
@@ -277,6 +308,29 @@ Returns: changed symbols, affected processes, and a risk summary.`,
|
|
|
277
308
|
required: [],
|
|
278
309
|
},
|
|
279
310
|
},
|
|
311
|
+
{
|
|
312
|
+
name: 'check',
|
|
313
|
+
description: `Run read-only structural checks against the indexed graph.
|
|
314
|
+
|
|
315
|
+
Currently detects directed cycles between File nodes connected by IMPORTS edges.
|
|
316
|
+
Returns deterministic cycle paths and a cycle count suitable for CI automation.`,
|
|
317
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
318
|
+
inputSchema: {
|
|
319
|
+
type: 'object',
|
|
320
|
+
properties: {
|
|
321
|
+
cycles: {
|
|
322
|
+
type: 'boolean',
|
|
323
|
+
description: 'Detect circular file imports (default: true).',
|
|
324
|
+
default: true,
|
|
325
|
+
},
|
|
326
|
+
repo: {
|
|
327
|
+
type: 'string',
|
|
328
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
required: [],
|
|
332
|
+
},
|
|
333
|
+
},
|
|
280
334
|
{
|
|
281
335
|
name: 'rename',
|
|
282
336
|
description: `Multi-file coordinated rename using the knowledge graph + text search.
|
|
@@ -317,11 +371,17 @@ Each edit is tagged with confidence:
|
|
|
317
371
|
description: `Analyze the blast radius of changing a code symbol.
|
|
318
372
|
Returns affected symbols grouped by depth, plus risk assessment, affected execution flows, and affected modules.
|
|
319
373
|
|
|
374
|
+
MODE (opt-in): "callgraph" (default) walks symbol→symbol edges (CALLS/IMPORTS/EXTENDS/IMPLEMENTS) — inter-procedural, the established comparator/default behavior. "pdg" requires an index built with \`gitnexus analyze --pdg\` and returns one unified PDG-facing result: statement-level control/data dependence from the persisted PDG plus inter-procedural symbol reach. The explicit interprocedural surface is interproceduralByDepth/pdgInterprocedural; byDepth remains the compatibility symbol bucket. pdg remains incompatible with crossDepth and @group targets; relationTypes/minConfidence filter the inter-symbol reach.
|
|
375
|
+
|
|
376
|
+
STATEMENT-ANCHORED PDG SLICE: with mode:'pdg', pass "line" (1-based source line within the target symbol) to seed the dependence slice on the statement at that line and return what depends on it in affectedStatements (line + text). Inter-procedural symbols are still reported through interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket. Without "line", pdg returns whole-symbol inter-procedural reach plus local whole-symbol PDG diagnostics.
|
|
377
|
+
|
|
378
|
+
PDG OUTPUT CONTRACT: every mode:'pdg' result (success, empty, degraded, or error) carries pdgResultVersion:1 — a stable discriminator for external consumers that bumps on any breaking change to the PDG result shape (distinct from the DB schema version). Successful PDG results include mode:'pdg', a full target envelope (id/name/type/filePath), affectedStatements, affectedStatementCount, interproceduralByDepth/pdgInterprocedural for cross-function reach, compatibility byDepth/byDepthCounts, risk:'UNKNOWN', and a note describing the unified contract. Degraded PDG results (no-layer, sub-layer-missing, unknown) keep mode:'pdg', pdgResultVersion:1, target metadata when the target resolves, risk:'UNKNOWN', note/remediation, and empty byDepth parity fields — never a false-safe zero. If depth and limit both bound the slice, truncatedByReasons reports both causes while truncatedBy remains scalar.
|
|
379
|
+
|
|
320
380
|
WHEN TO USE: Before making code changes — especially refactoring, renaming, or modifying shared code. Shows what would break.
|
|
321
381
|
AFTER THIS: Review d=1 items (WILL BREAK). Use context() on high-risk symbols.
|
|
322
382
|
|
|
323
383
|
Output includes:
|
|
324
|
-
- risk: LOW / MEDIUM / HIGH / CRITICAL
|
|
384
|
+
- risk: LOW / MEDIUM / HIGH / CRITICAL / UNKNOWN
|
|
325
385
|
- summary: direct callers, processes affected, modules affected
|
|
326
386
|
- affected_processes: which execution flows break and at which step
|
|
327
387
|
- affected_modules: which functional areas are hit (direct vs indirect)
|
|
@@ -357,6 +417,17 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep
|
|
|
357
417
|
type: 'string',
|
|
358
418
|
description: 'upstream (what depends on this) or downstream (what this depends on)',
|
|
359
419
|
},
|
|
420
|
+
mode: {
|
|
421
|
+
type: 'string',
|
|
422
|
+
enum: ['callgraph', 'pdg'],
|
|
423
|
+
default: 'callgraph',
|
|
424
|
+
description: "Blast-radius engine. 'callgraph' (default) = inter-procedural symbol→symbol traversal (established comparator). 'pdg' = unified PDG-facing impact: intra-procedural statement-level affectedStatements from the persisted control/data dependence layer plus inter-procedural symbols in interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket; requires `gitnexus analyze --pdg`. PDG symbol reach is labeled as a PDG evidence bridge, not pure statement-level dependence, and successful PDG results are UNKNOWN-risk. PDG is incompatible with crossDepth and @group targets; relationTypes/minConfidence filter the inter-symbol reach.",
|
|
425
|
+
},
|
|
426
|
+
line: {
|
|
427
|
+
type: 'integer',
|
|
428
|
+
minimum: 1,
|
|
429
|
+
description: "1-based source line — PDG statement anchor (mode:'pdg'). Seeds affectedStatements on the statement at this line; inter-procedural symbols are still returned in interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket.",
|
|
430
|
+
},
|
|
360
431
|
file_path: {
|
|
361
432
|
type: 'string',
|
|
362
433
|
description: 'File path hint to disambiguate common names',
|
|
@@ -370,7 +441,7 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep
|
|
|
370
441
|
description: 'Max relationship depth (default: 3, server clamps to 1–32)',
|
|
371
442
|
default: 3,
|
|
372
443
|
minimum: 1,
|
|
373
|
-
maximum:
|
|
444
|
+
maximum: IMPACT_MAX_DEPTH,
|
|
374
445
|
},
|
|
375
446
|
crossDepth: {
|
|
376
447
|
type: 'number',
|
|
@@ -439,6 +510,99 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep
|
|
|
439
510
|
required: ['target', 'direction'],
|
|
440
511
|
},
|
|
441
512
|
},
|
|
513
|
+
{
|
|
514
|
+
name: 'explain',
|
|
515
|
+
description: `Explain persisted taint findings recorded by \`gitnexus analyze --pdg\`: intra-procedural source→sink data flows (TAINTED edges, statement-level hops) AND cross-function flows (TAINT_PATH edges, function-level hops, marked \`interprocedural: true\`).
|
|
516
|
+
|
|
517
|
+
Each finding carries the sink category (command-injection, code-injection, path-traversal, sql-injection, xss) and the ordered hop path. Intra-procedural findings carry source/sink lines and the variable on each hop; interprocedural findings carry the source and sink FUNCTION names and the chain of functions the taint crossed (decoded from the persisted path encoding).
|
|
518
|
+
|
|
519
|
+
WHEN TO USE: Security review — "what taint findings exist in this repo / file / function?". Requires the repo to be indexed with \`gitnexus analyze --pdg\`; without that layer the tool returns a clear "no taint layer" note, not an error.
|
|
520
|
+
|
|
521
|
+
ANCHORLESS (no "target"): enumerates all persisted findings for the repo — bounded ("limit", deterministic order), with "totalFindings" and a "truncated" flag.
|
|
522
|
+
ANCHORED ("target" = file path or symbol/function name): full hop detail for that anchor. A file-ish target (contains "/" or an extension) filters by file; a symbol name resolves like context() — ambiguous names return ranked candidates, unknown names return not-found. Symbol anchoring is line-range granular for intra-procedural findings; cross-function findings match when the symbol is the source OR sink function.
|
|
523
|
+
|
|
524
|
+
CONTRACT CAVEATS (absent flows are NOT proof of safety):
|
|
525
|
+
- Cross-function flows ARE modeled (#2084 M4): a source flowing through helper functions into a sink is found, via summary composition over the call graph (context-insensitive — return/call-site merging is accepted).
|
|
526
|
+
- Cross-function matching is by callee NAME (context-insensitive): when one caller invokes two distinct same-named callees, a flow into one over-attributes to both — a cross-function finding does not prove the taint reached every same-named function (sound over-report, never a missed flow).
|
|
527
|
+
- Closure/callback flows are invisible in both directions (e.g. arr.forEach(() => sink(y))) — the largest false-negative class.
|
|
528
|
+
- Property/field flows are not tracked (obj.x = taint; sink(obj.y) has no chain).
|
|
529
|
+
- Guard-style sanitizers (if (isValid(x))) and implicit/control-dependence flows are not modeled.
|
|
530
|
+
- CommonJS aliasing is partially modeled (require('<literal>') joins resolve; dynamic requires do not).
|
|
531
|
+
- Exception-path over-approximation can produce false-positive noise.
|
|
532
|
+
|
|
533
|
+
Findings are deliberately NOT part of impact()'s traversal or the web schema — explain is the dedicated taint consumer. SANITIZES (kill) edges are queryable via cypher.`,
|
|
534
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
535
|
+
inputSchema: {
|
|
536
|
+
type: 'object',
|
|
537
|
+
properties: {
|
|
538
|
+
target: {
|
|
539
|
+
type: 'string',
|
|
540
|
+
description: 'Optional anchor: a file path (e.g. "src/handlers/run.ts" — suffix match accepted) or a symbol/function name (resolved like context()). Omit to enumerate all findings for the repo.',
|
|
541
|
+
},
|
|
542
|
+
limit: {
|
|
543
|
+
type: 'integer',
|
|
544
|
+
description: `Max findings returned (default: ${EXPLAIN_DEFAULT_LIMIT}, max: ${EXPLAIN_MAX_LIMIT}). "totalFindings" reports the full matched count; "truncated" is set when the page is smaller.`,
|
|
545
|
+
default: EXPLAIN_DEFAULT_LIMIT,
|
|
546
|
+
minimum: 1,
|
|
547
|
+
maximum: EXPLAIN_MAX_LIMIT,
|
|
548
|
+
},
|
|
549
|
+
repo: {
|
|
550
|
+
type: 'string',
|
|
551
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
required: [],
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
name: 'pdg_query',
|
|
559
|
+
description: `Query the persisted Program Dependence Graph recorded by \`gitnexus analyze --pdg\` — control dependence (CDG) and data dependence (REACHING_DEF) at basic-block granularity. The control/data analog of \`explain\` (which is the taint consumer).
|
|
560
|
+
|
|
561
|
+
MODES:
|
|
562
|
+
- \`controls\` — "under what condition does X run?". Returns, for the anchored function, each control-dependence edge: the controlling predicate block, the dependent block, and the branch sense ('T' = the predicate's true/taken arm, 'F' = its false/fall-through arm). An edge into an early return/throw block is flagged \`guard: true\` (subsumes the #559 guard heuristic); the branch sense of a guard depends on its predicate — \`if (!ok) return;\` rides the 'T' arm — so don't filter guards by a fixed label.
|
|
563
|
+
- \`flows\` — "where does variable Y flow?". Returns REACHING_DEF def→use edges for the anchored function; pass \`variable\` to filter to one binding.
|
|
564
|
+
|
|
565
|
+
WHEN TO USE: comprehension ("what guards this statement?"), data-flow tracing within a function, guard-clause discovery. Requires \`gitnexus analyze --pdg\`; without that layer the tool returns a clear "no PDG layer" note, not an error.
|
|
566
|
+
|
|
567
|
+
ANCHORING (required): \`target\` is a file path or a symbol/function name (resolved like context()). PDG queries are ALWAYS anchored — there is no whole-repo enumeration (an unanchored basic-block path scan is unbounded; LadybugDB has no rel-property index). A symbol target is line-range granular; an ambiguous name returns ranked candidates, unknown returns not-found.
|
|
568
|
+
|
|
569
|
+
CONTRACT CAVEATS:
|
|
570
|
+
- CDG labels are binary 'T'/'F' in M5/M6; per-case \`switch\` arm conditions are not yet distinguished (every case dispatch is 'T').
|
|
571
|
+
- Granularity is basic-block, reconstructed to the function via the BasicBlock id + line span (no Function→BasicBlock edge); deeply same-line-packed functions may anchor coarsely.
|
|
572
|
+
- Control/data dependence is intra-procedural (per function). Cross-function flow is taint's domain (\`explain\`).
|
|
573
|
+
- These edges are deliberately NOT part of impact()'s traversal — \`pdg_query\` is the dedicated consumer; raw edges are also queryable via \`cypher\`.`,
|
|
574
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
575
|
+
inputSchema: {
|
|
576
|
+
type: 'object',
|
|
577
|
+
properties: {
|
|
578
|
+
mode: {
|
|
579
|
+
type: 'string',
|
|
580
|
+
enum: ['controls', 'flows'],
|
|
581
|
+
description: "'controls' = control dependence (CDG: what condition gates X); 'flows' = data dependence (REACHING_DEF: where variable Y flows).",
|
|
582
|
+
},
|
|
583
|
+
target: {
|
|
584
|
+
type: 'string',
|
|
585
|
+
description: 'Required anchor: a file path (e.g. "src/handlers/run.ts" — suffix match accepted) or a symbol/function name (resolved like context()).',
|
|
586
|
+
},
|
|
587
|
+
variable: {
|
|
588
|
+
type: 'string',
|
|
589
|
+
description: 'Optional (flows mode only): restrict REACHING_DEF results to this source-level variable name.',
|
|
590
|
+
},
|
|
591
|
+
limit: {
|
|
592
|
+
type: 'integer',
|
|
593
|
+
description: `Max edges returned (default: ${PDG_QUERY_DEFAULT_LIMIT}, max: ${PDG_QUERY_MAX_LIMIT}). "total" reports the full matched count; "truncated" is set when the page is smaller.`,
|
|
594
|
+
default: PDG_QUERY_DEFAULT_LIMIT,
|
|
595
|
+
minimum: 1,
|
|
596
|
+
maximum: PDG_QUERY_MAX_LIMIT,
|
|
597
|
+
},
|
|
598
|
+
repo: {
|
|
599
|
+
type: 'string',
|
|
600
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
required: ['mode', 'target'],
|
|
604
|
+
},
|
|
605
|
+
},
|
|
442
606
|
{
|
|
443
607
|
name: 'route_map',
|
|
444
608
|
description: `Show API route mappings: which components/hooks fetch which API endpoints, and which handler files serve them.
|
|
@@ -559,6 +723,45 @@ WHEN TO USE: After changing group.yaml or re-indexing member repos.`,
|
|
|
559
723
|
required: ['name'],
|
|
560
724
|
},
|
|
561
725
|
},
|
|
726
|
+
{
|
|
727
|
+
name: 'trace',
|
|
728
|
+
description: `Find the shortest directed path between two symbols over call and class-member edges.
|
|
729
|
+
|
|
730
|
+
WHEN TO USE: Debugging "how does A reach B?" — answers in one call what would take 3-8 manual context/impact hops. Shows the exact chain with file:line positions plus a per-hop edge type and confidence.
|
|
731
|
+
|
|
732
|
+
Traverses CALLS edges plus HAS_METHOD (class → member) edges, so a trace can descend from a class into its methods. Each hop's edge type is reported in edges[], so call hops and containment hops remain distinguishable.
|
|
733
|
+
|
|
734
|
+
Returns: ordered hops with file:line, and an aligned edges[] of edge type + confidence. When no path exists, reports the furthest reachable node so you know where the chain breaks (and truncated: true if a traversal cap was hit first).`,
|
|
735
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
736
|
+
inputSchema: {
|
|
737
|
+
type: 'object',
|
|
738
|
+
properties: {
|
|
739
|
+
from: { type: 'string', description: 'Source symbol name' },
|
|
740
|
+
from_uid: { type: 'string', description: 'Source symbol UID (zero-ambiguity)' },
|
|
741
|
+
from_file: { type: 'string', description: 'Source file path hint for disambiguation' },
|
|
742
|
+
to: { type: 'string', description: 'Target symbol name' },
|
|
743
|
+
to_uid: { type: 'string', description: 'Target symbol UID (zero-ambiguity)' },
|
|
744
|
+
to_file: { type: 'string', description: 'Target file path hint for disambiguation' },
|
|
745
|
+
maxDepth: {
|
|
746
|
+
type: 'number',
|
|
747
|
+
description: 'Maximum path length in hops (default: 10)',
|
|
748
|
+
default: 10,
|
|
749
|
+
minimum: 1,
|
|
750
|
+
maximum: 30,
|
|
751
|
+
},
|
|
752
|
+
includeTests: {
|
|
753
|
+
type: 'boolean',
|
|
754
|
+
description: 'Include test-file symbols in traversal (default: false)',
|
|
755
|
+
default: false,
|
|
756
|
+
},
|
|
757
|
+
repo: {
|
|
758
|
+
type: 'string',
|
|
759
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
760
|
+
},
|
|
761
|
+
},
|
|
762
|
+
required: [],
|
|
763
|
+
},
|
|
764
|
+
},
|
|
562
765
|
];
|
|
563
766
|
/**
|
|
564
767
|
* Per-repo tools that accept an optional `branch` scope (#2106). Single source
|
|
@@ -572,12 +775,16 @@ const BRANCH_SCOPED_TOOLS = new Set([
|
|
|
572
775
|
'cypher',
|
|
573
776
|
'context',
|
|
574
777
|
'detect_changes',
|
|
778
|
+
'explain',
|
|
779
|
+
'pdg_query',
|
|
780
|
+
'check',
|
|
575
781
|
'impact',
|
|
576
782
|
'rename',
|
|
577
783
|
'route_map',
|
|
578
784
|
'tool_map',
|
|
579
785
|
'shape_check',
|
|
580
786
|
'api_impact',
|
|
787
|
+
'trace',
|
|
581
788
|
]);
|
|
582
789
|
for (const tool of GITNEXUS_TOOLS) {
|
|
583
790
|
if (!BRANCH_SCOPED_TOOLS.has(tool.name))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared analyze-worker launcher.
|
|
3
|
+
*
|
|
4
|
+
* Forks the analyze worker for an already-resolved repo directory and owns the
|
|
5
|
+
* lock + auto-retry + IPC machinery. Used by both the JSON `/api/analyze` route
|
|
6
|
+
* and the multipart `/api/analyze/upload` route. Dependency-injected (like
|
|
7
|
+
* createAnalyzeUploadHandler) so the seam is testable and api.ts stays smaller.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: this module must live alongside analyze-worker.{ts,js} — the worker
|
|
10
|
+
* path is resolved relative to `import.meta.url`.
|
|
11
|
+
*/
|
|
12
|
+
import type { JobManager } from './analyze-job.js';
|
|
13
|
+
export interface LaunchDeps {
|
|
14
|
+
jobManager: JobManager;
|
|
15
|
+
backend: {
|
|
16
|
+
init: () => Promise<unknown>;
|
|
17
|
+
};
|
|
18
|
+
acquireRepoLock: (key: string) => string | null;
|
|
19
|
+
releaseRepoLock: (key: string) => void;
|
|
20
|
+
}
|
|
21
|
+
export interface LaunchOptions {
|
|
22
|
+
force?: boolean;
|
|
23
|
+
embeddings?: boolean;
|
|
24
|
+
dropEmbeddings?: boolean;
|
|
25
|
+
registryName?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function createLaunchAnalysisWorker(deps: LaunchDeps): (job: {
|
|
28
|
+
id: string;
|
|
29
|
+
}, targetPath: string, opts: LaunchOptions) => void;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared analyze-worker launcher.
|
|
3
|
+
*
|
|
4
|
+
* Forks the analyze worker for an already-resolved repo directory and owns the
|
|
5
|
+
* lock + auto-retry + IPC machinery. Used by both the JSON `/api/analyze` route
|
|
6
|
+
* and the multipart `/api/analyze/upload` route. Dependency-injected (like
|
|
7
|
+
* createAnalyzeUploadHandler) so the seam is testable and api.ts stays smaller.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: this module must live alongside analyze-worker.{ts,js} — the worker
|
|
10
|
+
* path is resolved relative to `import.meta.url`.
|
|
11
|
+
*/
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { fork } from 'child_process';
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
15
|
+
import { createRequire } from 'node:module';
|
|
16
|
+
import { getStoragePath } from '../storage/repo-manager.js';
|
|
17
|
+
import { logger } from '../core/logger.js';
|
|
18
|
+
const _require = createRequire(import.meta.url);
|
|
19
|
+
const MAX_WORKER_RETRIES = 2;
|
|
20
|
+
export function createLaunchAnalysisWorker(deps) {
|
|
21
|
+
const { jobManager, backend, acquireRepoLock, releaseRepoLock } = deps;
|
|
22
|
+
return function launchAnalysisWorker(job, targetPath, opts) {
|
|
23
|
+
// Acquire shared repo lock (keyed on storagePath to match embed handler)
|
|
24
|
+
const analyzeLockKey = getStoragePath(targetPath);
|
|
25
|
+
const lockErr = acquireRepoLock(analyzeLockKey);
|
|
26
|
+
if (lockErr) {
|
|
27
|
+
jobManager.updateJob(job.id, { status: 'failed', error: lockErr });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
jobManager.updateJob(job.id, { repoPath: targetPath, status: 'analyzing' });
|
|
31
|
+
// ── Worker fork with auto-retry ──────────────────────────────
|
|
32
|
+
const callerPath = fileURLToPath(import.meta.url);
|
|
33
|
+
const isDev = callerPath.endsWith('.ts');
|
|
34
|
+
const workerFile = isDev ? 'analyze-worker.ts' : 'analyze-worker.js';
|
|
35
|
+
const workerPath = path.join(path.dirname(callerPath), workerFile);
|
|
36
|
+
const tsxHookArgs = isDev
|
|
37
|
+
? ['--import', pathToFileURL(_require.resolve('tsx/esm')).href]
|
|
38
|
+
: [];
|
|
39
|
+
const forkWorker = () => {
|
|
40
|
+
const currentJob = jobManager.getJob(job.id);
|
|
41
|
+
if (!currentJob || currentJob.status === 'complete' || currentJob.status === 'failed')
|
|
42
|
+
return;
|
|
43
|
+
const child = fork(workerPath, [], {
|
|
44
|
+
execArgv: [...tsxHookArgs, '--max-old-space-size=8192'],
|
|
45
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
46
|
+
});
|
|
47
|
+
// Capture stderr for crash diagnostics
|
|
48
|
+
let stderrChunks = '';
|
|
49
|
+
child.stderr?.on('data', (chunk) => {
|
|
50
|
+
stderrChunks += chunk.toString();
|
|
51
|
+
if (stderrChunks.length > 4096)
|
|
52
|
+
stderrChunks = stderrChunks.slice(-4096);
|
|
53
|
+
});
|
|
54
|
+
child.on('message', (msg) => {
|
|
55
|
+
if (msg.type === 'progress') {
|
|
56
|
+
jobManager.updateJob(job.id, {
|
|
57
|
+
status: 'analyzing',
|
|
58
|
+
progress: { phase: msg.phase, percent: msg.percent, message: msg.message },
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else if (msg.type === 'complete') {
|
|
62
|
+
releaseRepoLock(analyzeLockKey);
|
|
63
|
+
// Reinitialize backend BEFORE marking complete — ensures the new repo
|
|
64
|
+
// is queryable when the client receives the SSE complete event.
|
|
65
|
+
backend
|
|
66
|
+
.init()
|
|
67
|
+
.then(() => {
|
|
68
|
+
jobManager.updateJob(job.id, { status: 'complete', repoName: msg.result.repoName });
|
|
69
|
+
})
|
|
70
|
+
.catch((err) => {
|
|
71
|
+
logger.error({ err }, 'backend.init() failed after analyze:');
|
|
72
|
+
jobManager.updateJob(job.id, {
|
|
73
|
+
status: 'failed',
|
|
74
|
+
error: 'Server failed to reload after analysis. Try again.',
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (msg.type === 'error') {
|
|
79
|
+
releaseRepoLock(analyzeLockKey);
|
|
80
|
+
jobManager.updateJob(job.id, { status: 'failed', error: msg.message });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
child.on('error', (err) => {
|
|
84
|
+
releaseRepoLock(analyzeLockKey);
|
|
85
|
+
jobManager.updateJob(job.id, {
|
|
86
|
+
status: 'failed',
|
|
87
|
+
error: `Worker process error: ${err.message}`,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
child.on('exit', (code) => {
|
|
91
|
+
const j = jobManager.getJob(job.id);
|
|
92
|
+
if (!j || j.status === 'complete' || j.status === 'failed')
|
|
93
|
+
return;
|
|
94
|
+
// Worker crashed — attempt retry if under the limit
|
|
95
|
+
if (j.retryCount < MAX_WORKER_RETRIES) {
|
|
96
|
+
j.retryCount++;
|
|
97
|
+
const delay = 1000 * Math.pow(2, j.retryCount - 1); // 1s, 2s
|
|
98
|
+
const lastErr = stderrChunks.trim().split('\n').pop() || '';
|
|
99
|
+
logger.warn(`Analyze worker crashed (code ${code}), retry ${j.retryCount}/${MAX_WORKER_RETRIES} in ${delay}ms` +
|
|
100
|
+
(lastErr ? `: ${lastErr}` : ''));
|
|
101
|
+
jobManager.updateJob(job.id, {
|
|
102
|
+
status: 'analyzing',
|
|
103
|
+
progress: {
|
|
104
|
+
phase: 'retrying',
|
|
105
|
+
percent: j.progress.percent,
|
|
106
|
+
message: `Worker crashed, retrying (${j.retryCount}/${MAX_WORKER_RETRIES})...`,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
stderrChunks = '';
|
|
110
|
+
setTimeout(forkWorker, delay);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// Exhausted retries — permanent failure
|
|
114
|
+
releaseRepoLock(analyzeLockKey);
|
|
115
|
+
jobManager.updateJob(job.id, {
|
|
116
|
+
status: 'failed',
|
|
117
|
+
error: `Worker crashed ${MAX_WORKER_RETRIES + 1} times (code ${code})${stderrChunks ? ': ' + stderrChunks.trim().split('\n').pop() : ''}`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
// Register child for cancellation + timeout tracking
|
|
122
|
+
jobManager.registerChild(job.id, child);
|
|
123
|
+
// Send start command to child
|
|
124
|
+
child.send({
|
|
125
|
+
type: 'start',
|
|
126
|
+
repoPath: targetPath,
|
|
127
|
+
options: {
|
|
128
|
+
force: !!opts.force,
|
|
129
|
+
embeddings: !!opts.embeddings,
|
|
130
|
+
dropEmbeddings: !!opts.dropEmbeddings,
|
|
131
|
+
...(opts.registryName ? { registryName: opts.registryName } : {}),
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
forkWorker();
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/analyze/upload — analyze a browser folder upload.
|
|
3
|
+
*
|
|
4
|
+
* Securely ingests the multipart upload into a sandbox (upload-ingest.ts),
|
|
5
|
+
* promotes it to a persistent app-controlled directory, and analyzes it via
|
|
6
|
+
* the same job/worker machinery as a git clone — never returning a server
|
|
7
|
+
* path to the client. Factored as a dependency-injected handler so the job
|
|
8
|
+
* machinery (createJob + the worker launcher) can be mocked in unit tests.
|
|
9
|
+
*/
|
|
10
|
+
import type { Request, Response } from 'express';
|
|
11
|
+
import { ingestUpload } from './upload-ingest.js';
|
|
12
|
+
import type { AnalyzeJob } from './analyze-job.js';
|
|
13
|
+
/** Minimal job shape the handler needs (a subset of the real AnalyzeJob). */
|
|
14
|
+
export type UploadJobRef = Pick<AnalyzeJob, 'id' | 'status'>;
|
|
15
|
+
export interface AnalyzeUploadDeps {
|
|
16
|
+
/** Create (or throw on busy) an analysis job for the given upload dir. */
|
|
17
|
+
createJob: (params: {
|
|
18
|
+
repoPath: string;
|
|
19
|
+
}) => UploadJobRef;
|
|
20
|
+
/** Launch the analyze worker against an already-resolved repo directory. */
|
|
21
|
+
launch: (job: UploadJobRef, targetPath: string, opts: {
|
|
22
|
+
registryName: string;
|
|
23
|
+
}) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Mark a created job failed. The job occupies the single analysis slot from
|
|
26
|
+
* createJob onward, so ANY error before launch must release it — otherwise a
|
|
27
|
+
* leaked non-terminal job wedges all future analyses until restart.
|
|
28
|
+
*/
|
|
29
|
+
failJob: (jobId: string, error: string) => void;
|
|
30
|
+
/** Injectable for tests (defaults to the real ingestUpload). */
|
|
31
|
+
ingest?: typeof ingestUpload;
|
|
32
|
+
}
|
|
33
|
+
export declare function createAnalyzeUploadHandler(deps: AnalyzeUploadDeps): (req: Request, res: Response) => Promise<void>;
|