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/server/api.js
CHANGED
|
@@ -20,11 +20,16 @@ import { searchFTSFromLbug } from '../core/search/bm25-index.js';
|
|
|
20
20
|
import { hybridSearch } from '../core/search/hybrid-search.js';
|
|
21
21
|
import { LocalBackend } from '../mcp/local/local-backend.js';
|
|
22
22
|
import { mountMCPEndpoints } from './mcp-http.js';
|
|
23
|
-
import {
|
|
24
|
-
import { fileURLToPath, pathToFileURL } from 'url';
|
|
23
|
+
import { fileURLToPath } from 'url';
|
|
25
24
|
import { JobManager } from './analyze-job.js';
|
|
26
25
|
import { assertString, escapeRegExp, BadRequestError, createRouteLimiter } from './validation.js';
|
|
27
|
-
import { extractRepoName, getCloneDir, cloneOrPull } from './git-clone.js';
|
|
26
|
+
import { extractRepoName, getCloneDir, cloneOrPull, warnIfInsecureAzureConfig, GITHUB_TOKEN_HOSTS, } from './git-clone.js';
|
|
27
|
+
import { createAnalyzeUploadHandler } from './analyze-upload.js';
|
|
28
|
+
import { createLocalhostOriginGuard, normalizeBoundHost } from './middleware.js';
|
|
29
|
+
import { createLaunchAnalysisWorker } from './analyze-launch.js';
|
|
30
|
+
import { UPLOAD_ROOT } from './upload-paths.js';
|
|
31
|
+
import { sweepStaleUploads } from './upload-sweep.js';
|
|
32
|
+
import { isRfc1918PrivateIpv4 } from './private-ip.js';
|
|
28
33
|
import { logger, flushLoggerSync } from '../core/logger.js';
|
|
29
34
|
const _require = createRequire(import.meta.url);
|
|
30
35
|
const pkg = _require('../../package.json');
|
|
@@ -75,21 +80,7 @@ export const isAllowedOrigin = (origin) => {
|
|
|
75
80
|
// Only allow HTTP(S) origins — reject ftp://, file://, etc.
|
|
76
81
|
if (protocol !== 'http:' && protocol !== 'https:')
|
|
77
82
|
return false;
|
|
78
|
-
|
|
79
|
-
if (octets.length !== 4 || octets.some((o) => !Number.isInteger(o) || o < 0 || o > 255)) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
const [a, b] = octets;
|
|
83
|
-
// 10.0.0.0/8
|
|
84
|
-
if (a === 10)
|
|
85
|
-
return true;
|
|
86
|
-
// 172.16.0.0/12 → 172.16.x.x – 172.31.x.x
|
|
87
|
-
if (a === 172 && b >= 16 && b <= 31)
|
|
88
|
-
return true;
|
|
89
|
-
// 192.168.0.0/16
|
|
90
|
-
if (a === 192 && b === 168)
|
|
91
|
-
return true;
|
|
92
|
-
return false;
|
|
83
|
+
return isRfc1918PrivateIpv4(hostname);
|
|
93
84
|
};
|
|
94
85
|
export class ClientDisconnectedError extends Error {
|
|
95
86
|
constructor() {
|
|
@@ -589,7 +580,45 @@ export const handleQueryRequest = async (req, res, resolveRepo) => {
|
|
|
589
580
|
res.status(500).json({ error: err.message || 'Query failed' });
|
|
590
581
|
}
|
|
591
582
|
};
|
|
583
|
+
/**
|
|
584
|
+
* Validate the optional `token` field of POST /api/analyze. Returns an
|
|
585
|
+
* { status, error } to send, or null when the token is absent or valid.
|
|
586
|
+
*
|
|
587
|
+
* The token is a GitHub PAT: charset-restricted (blocks CRLF header
|
|
588
|
+
* smuggling), length-bounded (1–256), and bound to github.com using the SAME
|
|
589
|
+
* GITHUB_TOKEN_HOSTS allowlist + hostname parse as resolveGitCredential, so a
|
|
590
|
+
* token the API accepts is exactly the one buildGitEnv will inject — and one
|
|
591
|
+
* it rejects is never sent off github.com.
|
|
592
|
+
*
|
|
593
|
+
* Exported for unit tests (the route validation is otherwise only reachable
|
|
594
|
+
* by booting the server).
|
|
595
|
+
*/
|
|
596
|
+
export function validateAnalyzeToken(repoToken, repoUrl) {
|
|
597
|
+
if (repoToken === undefined)
|
|
598
|
+
return null;
|
|
599
|
+
if (typeof repoToken !== 'string')
|
|
600
|
+
return { status: 400, error: '"token" must be a string' };
|
|
601
|
+
if (repoToken.length === 0 || repoToken.length > 256)
|
|
602
|
+
return { status: 400, error: '"token" length must be between 1 and 256' };
|
|
603
|
+
if (!/^[A-Za-z0-9._~+/=-]+$/.test(repoToken))
|
|
604
|
+
return { status: 400, error: '"token" contains invalid characters' };
|
|
605
|
+
if (!repoUrl || typeof repoUrl !== 'string')
|
|
606
|
+
return { status: 400, error: '"token" requires "url"' };
|
|
607
|
+
let tokenHost;
|
|
608
|
+
try {
|
|
609
|
+
tokenHost = new URL(repoUrl).hostname.toLowerCase();
|
|
610
|
+
}
|
|
611
|
+
catch {
|
|
612
|
+
return { status: 400, error: '"url" must be a valid URL when "token" is provided' };
|
|
613
|
+
}
|
|
614
|
+
if (!GITHUB_TOKEN_HOSTS.has(tokenHost))
|
|
615
|
+
return { status: 400, error: '"token" is only supported for github.com URLs' };
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
592
618
|
export const createServer = async (port, host = '127.0.0.1') => {
|
|
619
|
+
// Surface a cleartext Azure DevOps PAT config at boot (operators rarely
|
|
620
|
+
// read per-request logs). Warn-only — http:// self-hosted stays supported.
|
|
621
|
+
warnIfInsecureAzureConfig();
|
|
593
622
|
const app = express();
|
|
594
623
|
app.disable('x-powered-by');
|
|
595
624
|
// Trust X-Forwarded-* headers only when the connection comes from the
|
|
@@ -630,6 +659,17 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
630
659
|
},
|
|
631
660
|
}));
|
|
632
661
|
app.use(express.json({ limit: '10mb' }));
|
|
662
|
+
// Same-host origin guard for write routes. Only allows loopback and the
|
|
663
|
+
// server's own bound host — scoped to prevent CSRF from other LAN devices.
|
|
664
|
+
const requireLocalhostOrigin = createLocalhostOriginGuard(host);
|
|
665
|
+
// A wildcard bind (`0.0.0.0`/`::`) has no single host identity for the
|
|
666
|
+
// same-host check, so browser write routes accept only loopback origins.
|
|
667
|
+
// Warn the operator so a remote-access deployment isn't silently write-blocked.
|
|
668
|
+
if (host && normalizeBoundHost(host) === undefined) {
|
|
669
|
+
logger.warn({ host }, `[gitnexus serve] Bound to a wildcard address (${host}); browser write routes ` +
|
|
670
|
+
`accept only loopback origins (localhost/127.0.0.1/[::1]). To allow writes from a ` +
|
|
671
|
+
`specific LAN address, bind --host <that-address> instead of a wildcard.`);
|
|
672
|
+
}
|
|
633
673
|
// No explicit OPTIONS route is registered. The Chromium Private Network
|
|
634
674
|
// Access header is set by the global middleware above (pre-cors), and
|
|
635
675
|
// `cors()` itself handles OPTIONS preflights for every path. Registering a
|
|
@@ -640,6 +680,8 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
640
680
|
await backend.init();
|
|
641
681
|
const cleanupMcp = mountMCPEndpoints(app, backend);
|
|
642
682
|
const jobManager = new JobManager();
|
|
683
|
+
// Backstop: remove any upload staging dirs orphaned by a previous crash.
|
|
684
|
+
void sweepStaleUploads().catch(() => { });
|
|
643
685
|
// Shared repo lock — prevents concurrent analyze + embed on the same repo path,
|
|
644
686
|
// which would corrupt LadybugDB (analyze calls closeLbug + initLbug while embed has queries in flight).
|
|
645
687
|
const activeRepoPaths = new Set();
|
|
@@ -653,6 +695,14 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
653
695
|
const releaseRepoLock = (repoPath) => {
|
|
654
696
|
activeRepoPaths.delete(repoPath);
|
|
655
697
|
};
|
|
698
|
+
// Launch the analyze worker for an already-resolved repo directory. Shared by
|
|
699
|
+
// the JSON /api/analyze route and the multipart /api/analyze/upload route.
|
|
700
|
+
const launchAnalysisWorker = createLaunchAnalysisWorker({
|
|
701
|
+
jobManager,
|
|
702
|
+
backend,
|
|
703
|
+
acquireRepoLock,
|
|
704
|
+
releaseRepoLock,
|
|
705
|
+
});
|
|
656
706
|
/**
|
|
657
707
|
* Maximum time the hold-queue will wait for an active analysis job to complete.
|
|
658
708
|
* Must stay in sync with the frontend's `fetchRepoInfo({ awaitAnalysis: true })` timeout.
|
|
@@ -816,7 +866,7 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
816
866
|
// Rate-limited (CodeQL js/missing-rate-limiting): destructive operation
|
|
817
867
|
// doing fs.rm of clone + storage dirs. Default 60 rpm/IP is generous for
|
|
818
868
|
// delete; tighten if abuse is observed.
|
|
819
|
-
app.delete('/api/repo', createRouteLimiter(), async (req, res) => {
|
|
869
|
+
app.delete('/api/repo', createRouteLimiter(), requireLocalhostOrigin, async (req, res) => {
|
|
820
870
|
try {
|
|
821
871
|
const repoName = requestedRepo(req);
|
|
822
872
|
if (!repoName) {
|
|
@@ -867,6 +917,13 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
867
917
|
/* clone dir may not exist */
|
|
868
918
|
}
|
|
869
919
|
}
|
|
920
|
+
// 2b. Delete the uploaded repo dir if entry.path lives under
|
|
921
|
+
// UPLOAD_ROOT. Drive this off entry.path (not a name-rederived dir) so
|
|
922
|
+
// a same-named clone is never affected.
|
|
923
|
+
const resolvedEntry = path.resolve(entry.path);
|
|
924
|
+
if (resolvedEntry === UPLOAD_ROOT || resolvedEntry.startsWith(UPLOAD_ROOT + path.sep)) {
|
|
925
|
+
await fs.rm(resolvedEntry, { recursive: true, force: true }).catch(() => { });
|
|
926
|
+
}
|
|
870
927
|
// 3. Unregister from the global registry
|
|
871
928
|
const { unregisterRepo } = await import('../storage/repo-manager.js');
|
|
872
929
|
await unregisterRepo(entry.path);
|
|
@@ -1251,9 +1308,9 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1251
1308
|
});
|
|
1252
1309
|
// ── Analyze API ──────────────────────────────────────────────────────
|
|
1253
1310
|
// POST /api/analyze — start a new analysis job
|
|
1254
|
-
app.post('/api/analyze', createRouteLimiter({ limit: 10 }), async (req, res) => {
|
|
1311
|
+
app.post('/api/analyze', createRouteLimiter({ limit: 10 }), requireLocalhostOrigin, async (req, res) => {
|
|
1255
1312
|
try {
|
|
1256
|
-
const { url: repoUrl, path: repoLocalPath, force, embeddings, dropEmbeddings } = req.body;
|
|
1313
|
+
const { url: repoUrl, path: repoLocalPath, force, embeddings, dropEmbeddings, token: repoToken, } = req.body;
|
|
1257
1314
|
// Input type validation
|
|
1258
1315
|
if (repoUrl !== undefined && typeof repoUrl !== 'string') {
|
|
1259
1316
|
res.status(400).json({ error: '"url" must be a string' });
|
|
@@ -1267,21 +1324,43 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1267
1324
|
res.status(400).json({ error: 'Provide "url" (git URL) or "path" (local path)' });
|
|
1268
1325
|
return;
|
|
1269
1326
|
}
|
|
1270
|
-
//
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1327
|
+
// Token: optional, restricted charset to prevent header smuggling
|
|
1328
|
+
// (CRLF), bound length, and bound to github.com (see validateAnalyzeToken).
|
|
1329
|
+
const tokenError = validateAnalyzeToken(repoToken, repoUrl);
|
|
1330
|
+
if (tokenError) {
|
|
1331
|
+
res.status(tokenError.status).json({ error: tokenError.error });
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
// Path validation. The previous `normalize !== resolve` guard was inert
|
|
1335
|
+
// (both collapse `..` identically) and only false-rejected trailing
|
|
1336
|
+
// slashes, so it is dropped. Analyzing a local path the operator names
|
|
1337
|
+
// is the tool's intended capability (same as the CLI); the dangerous
|
|
1338
|
+
// part was cross-origin reach, which is closed by requireLocalhostOrigin
|
|
1339
|
+
// on this route (scoped to the server's own bound host — other LAN
|
|
1340
|
+
// devices are NOT trusted). We only require an absolute path here and
|
|
1341
|
+
// let the analyze worker surface a clear error if it does not exist.
|
|
1342
|
+
// (We do NOT realpath/stat the path in-route: that would be a
|
|
1343
|
+
// user-controlled filesystem read — CodeQL js/path-injection — for no
|
|
1344
|
+
// security gain.)
|
|
1345
|
+
if (repoLocalPath && !path.isAbsolute(repoLocalPath)) {
|
|
1346
|
+
res.status(400).json({ error: '"path" must be an absolute path' });
|
|
1347
|
+
return;
|
|
1280
1348
|
}
|
|
1281
1349
|
const job = jobManager.createJob({ repoUrl, repoPath: repoLocalPath });
|
|
1282
|
-
// If job was already running (dedup), just return its id
|
|
1350
|
+
// If job was already running (dedup), just return its id. The token is
|
|
1351
|
+
// not part of the dedup identity and is never stored on the job, so a
|
|
1352
|
+
// token on THIS request had no effect — the existing job already
|
|
1353
|
+
// cloned (or is cloning) with whatever credentials its originating
|
|
1354
|
+
// request supplied. Surface `tokenIgnored` so an authenticated caller
|
|
1355
|
+
// isn't misled into thinking their PAT took effect on a reused job.
|
|
1283
1356
|
if (job.status !== 'queued') {
|
|
1284
|
-
|
|
1357
|
+
const body = {
|
|
1358
|
+
jobId: job.id,
|
|
1359
|
+
status: job.status,
|
|
1360
|
+
};
|
|
1361
|
+
if (repoToken !== undefined)
|
|
1362
|
+
body.tokenIgnored = true;
|
|
1363
|
+
res.status(202).json(body);
|
|
1285
1364
|
return;
|
|
1286
1365
|
}
|
|
1287
1366
|
// Mark as active synchronously to prevent race with concurrent requests
|
|
@@ -1303,138 +1382,12 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1303
1382
|
jobManager.updateJob(job.id, {
|
|
1304
1383
|
progress: { phase: progress.phase, percent: 5, message: progress.message },
|
|
1305
1384
|
});
|
|
1306
|
-
});
|
|
1385
|
+
}, repoToken ? { token: repoToken } : undefined);
|
|
1307
1386
|
}
|
|
1308
1387
|
if (!targetPath) {
|
|
1309
1388
|
throw new Error('No target path resolved');
|
|
1310
1389
|
}
|
|
1311
|
-
|
|
1312
|
-
const analyzeLockKey = getStoragePath(targetPath);
|
|
1313
|
-
const lockErr = acquireRepoLock(analyzeLockKey);
|
|
1314
|
-
if (lockErr) {
|
|
1315
|
-
jobManager.updateJob(job.id, { status: 'failed', error: lockErr });
|
|
1316
|
-
return;
|
|
1317
|
-
}
|
|
1318
|
-
jobManager.updateJob(job.id, { repoPath: targetPath, status: 'analyzing' });
|
|
1319
|
-
// ── Worker fork with auto-retry ──────────────────────────────
|
|
1320
|
-
//
|
|
1321
|
-
// Forks a child process with 8GB heap. If the worker crashes
|
|
1322
|
-
// (OOM, native addon segfault, etc.), it retries up to
|
|
1323
|
-
// MAX_WORKER_RETRIES times with exponential backoff before
|
|
1324
|
-
// marking the job as permanently failed.
|
|
1325
|
-
//
|
|
1326
|
-
// In dev mode (tsx), registers the tsx ESM hook via a file://
|
|
1327
|
-
// URL so the child can compile TypeScript on-the-fly.
|
|
1328
|
-
const MAX_WORKER_RETRIES = 2;
|
|
1329
|
-
const callerPath = fileURLToPath(import.meta.url);
|
|
1330
|
-
const isDev = callerPath.endsWith('.ts');
|
|
1331
|
-
const workerFile = isDev ? 'analyze-worker.ts' : 'analyze-worker.js';
|
|
1332
|
-
const workerPath = path.join(path.dirname(callerPath), workerFile);
|
|
1333
|
-
const tsxHookArgs = isDev
|
|
1334
|
-
? ['--import', pathToFileURL(_require.resolve('tsx/esm')).href]
|
|
1335
|
-
: [];
|
|
1336
|
-
const forkWorker = () => {
|
|
1337
|
-
const currentJob = jobManager.getJob(job.id);
|
|
1338
|
-
if (!currentJob || currentJob.status === 'complete' || currentJob.status === 'failed')
|
|
1339
|
-
return;
|
|
1340
|
-
const child = fork(workerPath, [], {
|
|
1341
|
-
execArgv: [...tsxHookArgs, '--max-old-space-size=8192'],
|
|
1342
|
-
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
1343
|
-
});
|
|
1344
|
-
// Capture stderr for crash diagnostics
|
|
1345
|
-
let stderrChunks = '';
|
|
1346
|
-
child.stderr?.on('data', (chunk) => {
|
|
1347
|
-
stderrChunks += chunk.toString();
|
|
1348
|
-
if (stderrChunks.length > 4096)
|
|
1349
|
-
stderrChunks = stderrChunks.slice(-4096);
|
|
1350
|
-
});
|
|
1351
|
-
child.on('message', (msg) => {
|
|
1352
|
-
if (msg.type === 'progress') {
|
|
1353
|
-
jobManager.updateJob(job.id, {
|
|
1354
|
-
status: 'analyzing',
|
|
1355
|
-
progress: { phase: msg.phase, percent: msg.percent, message: msg.message },
|
|
1356
|
-
});
|
|
1357
|
-
}
|
|
1358
|
-
else if (msg.type === 'complete') {
|
|
1359
|
-
releaseRepoLock(analyzeLockKey);
|
|
1360
|
-
// Reinitialize backend BEFORE marking complete — ensures the new
|
|
1361
|
-
// repo is queryable when the client receives the SSE complete event.
|
|
1362
|
-
backend
|
|
1363
|
-
.init()
|
|
1364
|
-
.then(() => {
|
|
1365
|
-
jobManager.updateJob(job.id, {
|
|
1366
|
-
status: 'complete',
|
|
1367
|
-
repoName: msg.result.repoName,
|
|
1368
|
-
});
|
|
1369
|
-
})
|
|
1370
|
-
.catch((err) => {
|
|
1371
|
-
logger.error({ err }, 'backend.init() failed after analyze:');
|
|
1372
|
-
jobManager.updateJob(job.id, {
|
|
1373
|
-
status: 'failed',
|
|
1374
|
-
error: 'Server failed to reload after analysis. Try again.',
|
|
1375
|
-
});
|
|
1376
|
-
});
|
|
1377
|
-
}
|
|
1378
|
-
else if (msg.type === 'error') {
|
|
1379
|
-
releaseRepoLock(analyzeLockKey);
|
|
1380
|
-
jobManager.updateJob(job.id, {
|
|
1381
|
-
status: 'failed',
|
|
1382
|
-
error: msg.message,
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
});
|
|
1386
|
-
child.on('error', (err) => {
|
|
1387
|
-
releaseRepoLock(analyzeLockKey);
|
|
1388
|
-
jobManager.updateJob(job.id, {
|
|
1389
|
-
status: 'failed',
|
|
1390
|
-
error: `Worker process error: ${err.message}`,
|
|
1391
|
-
});
|
|
1392
|
-
});
|
|
1393
|
-
child.on('exit', (code) => {
|
|
1394
|
-
const j = jobManager.getJob(job.id);
|
|
1395
|
-
if (!j || j.status === 'complete' || j.status === 'failed')
|
|
1396
|
-
return;
|
|
1397
|
-
// Worker crashed — attempt retry if under the limit
|
|
1398
|
-
if (j.retryCount < MAX_WORKER_RETRIES) {
|
|
1399
|
-
j.retryCount++;
|
|
1400
|
-
const delay = 1000 * Math.pow(2, j.retryCount - 1); // 1s, 2s
|
|
1401
|
-
const lastErr = stderrChunks.trim().split('\n').pop() || '';
|
|
1402
|
-
logger.warn(`Analyze worker crashed (code ${code}), retry ${j.retryCount}/${MAX_WORKER_RETRIES} in ${delay}ms` +
|
|
1403
|
-
(lastErr ? `: ${lastErr}` : ''));
|
|
1404
|
-
jobManager.updateJob(job.id, {
|
|
1405
|
-
status: 'analyzing',
|
|
1406
|
-
progress: {
|
|
1407
|
-
phase: 'retrying',
|
|
1408
|
-
percent: j.progress.percent,
|
|
1409
|
-
message: `Worker crashed, retrying (${j.retryCount}/${MAX_WORKER_RETRIES})...`,
|
|
1410
|
-
},
|
|
1411
|
-
});
|
|
1412
|
-
stderrChunks = '';
|
|
1413
|
-
setTimeout(forkWorker, delay);
|
|
1414
|
-
}
|
|
1415
|
-
else {
|
|
1416
|
-
// Exhausted retries — permanent failure
|
|
1417
|
-
releaseRepoLock(analyzeLockKey);
|
|
1418
|
-
jobManager.updateJob(job.id, {
|
|
1419
|
-
status: 'failed',
|
|
1420
|
-
error: `Worker crashed ${MAX_WORKER_RETRIES + 1} times (code ${code})${stderrChunks ? ': ' + stderrChunks.trim().split('\n').pop() : ''}`,
|
|
1421
|
-
});
|
|
1422
|
-
}
|
|
1423
|
-
});
|
|
1424
|
-
// Register child for cancellation + timeout tracking
|
|
1425
|
-
jobManager.registerChild(job.id, child);
|
|
1426
|
-
// Send start command to child
|
|
1427
|
-
child.send({
|
|
1428
|
-
type: 'start',
|
|
1429
|
-
repoPath: targetPath,
|
|
1430
|
-
options: {
|
|
1431
|
-
force: !!force,
|
|
1432
|
-
embeddings: !!embeddings,
|
|
1433
|
-
dropEmbeddings: !!dropEmbeddings,
|
|
1434
|
-
},
|
|
1435
|
-
});
|
|
1436
|
-
};
|
|
1437
|
-
forkWorker();
|
|
1390
|
+
launchAnalysisWorker(job, targetPath, { force, embeddings, dropEmbeddings });
|
|
1438
1391
|
}
|
|
1439
1392
|
catch (err) {
|
|
1440
1393
|
if (targetPath)
|
|
@@ -1456,6 +1409,15 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1456
1409
|
}
|
|
1457
1410
|
}
|
|
1458
1411
|
});
|
|
1412
|
+
// POST /api/analyze/upload — analyze a browser folder upload.
|
|
1413
|
+
// Securely ingests the multipart upload into a sandbox, promotes it to a
|
|
1414
|
+
// persistent dir, and analyzes it via the shared job/worker machinery.
|
|
1415
|
+
// localhost-only (no cross-origin write reach) + conservative rate limit.
|
|
1416
|
+
app.post('/api/analyze/upload', createRouteLimiter({ limit: 5 }), requireLocalhostOrigin, createAnalyzeUploadHandler({
|
|
1417
|
+
createJob: (params) => jobManager.createJob(params),
|
|
1418
|
+
launch: (job, targetPath, opts) => launchAnalysisWorker(job, targetPath, opts),
|
|
1419
|
+
failJob: (jobId, error) => jobManager.updateJob(jobId, { status: 'failed', error }),
|
|
1420
|
+
}));
|
|
1459
1421
|
// GET /api/analyze/:jobId — poll job status
|
|
1460
1422
|
app.get('/api/analyze/:jobId', (req, res) => {
|
|
1461
1423
|
const job = jobManager.getJob(req.params.jobId);
|
|
@@ -1478,8 +1440,9 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1478
1440
|
// GET /api/analyze/:jobId/progress — SSE stream (shared helper)
|
|
1479
1441
|
mountSSEProgress(app, '/api/analyze/:jobId/progress', jobManager);
|
|
1480
1442
|
// DELETE /api/analyze/:jobId — cancel a running analysis job
|
|
1481
|
-
app.delete('/api/analyze/:jobId', (req, res) => {
|
|
1482
|
-
const
|
|
1443
|
+
app.delete('/api/analyze/:jobId', requireLocalhostOrigin, (req, res) => {
|
|
1444
|
+
const jobId = req.params.jobId;
|
|
1445
|
+
const job = jobManager.getJob(jobId);
|
|
1483
1446
|
if (!job) {
|
|
1484
1447
|
res.status(404).json({ error: 'Job not found' });
|
|
1485
1448
|
return;
|
|
@@ -1488,13 +1451,13 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1488
1451
|
res.status(400).json({ error: `Job already ${job.status}` });
|
|
1489
1452
|
return;
|
|
1490
1453
|
}
|
|
1491
|
-
jobManager.cancelJob(
|
|
1454
|
+
jobManager.cancelJob(jobId, 'Cancelled by user');
|
|
1492
1455
|
res.json({ id: job.id, status: 'failed', error: 'Cancelled by user' });
|
|
1493
1456
|
});
|
|
1494
1457
|
// ── Embedding endpoints ────────────────────────────────────────────
|
|
1495
1458
|
const embedJobManager = new JobManager();
|
|
1496
1459
|
// POST /api/embed — trigger server-side embedding generation
|
|
1497
|
-
app.post('/api/embed', createRouteLimiter({ limit: 20 }), async (req, res) => {
|
|
1460
|
+
app.post('/api/embed', createRouteLimiter({ limit: 20 }), requireLocalhostOrigin, async (req, res) => {
|
|
1498
1461
|
try {
|
|
1499
1462
|
const entry = await resolveRepo(requestedRepo(req));
|
|
1500
1463
|
if (!entry) {
|
|
@@ -1616,8 +1579,9 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1616
1579
|
// GET /api/embed/:jobId/progress — SSE stream (shared helper)
|
|
1617
1580
|
mountSSEProgress(app, '/api/embed/:jobId/progress', embedJobManager);
|
|
1618
1581
|
// DELETE /api/embed/:jobId — cancel embedding job
|
|
1619
|
-
app.delete('/api/embed/:jobId', (req, res) => {
|
|
1620
|
-
const
|
|
1582
|
+
app.delete('/api/embed/:jobId', requireLocalhostOrigin, (req, res) => {
|
|
1583
|
+
const jobId = req.params.jobId;
|
|
1584
|
+
const job = embedJobManager.getJob(jobId);
|
|
1621
1585
|
if (!job) {
|
|
1622
1586
|
res.status(404).json({ error: 'Job not found' });
|
|
1623
1587
|
return;
|
|
@@ -1626,7 +1590,7 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1626
1590
|
res.status(400).json({ error: `Job already ${job.status}` });
|
|
1627
1591
|
return;
|
|
1628
1592
|
}
|
|
1629
|
-
embedJobManager.cancelJob(
|
|
1593
|
+
embedJobManager.cancelJob(jobId, 'Cancelled by user');
|
|
1630
1594
|
res.json({ id: job.id, status: 'failed', error: 'Cancelled by user' });
|
|
1631
1595
|
});
|
|
1632
1596
|
// ── Web UI (served at root) ───────────────────────────────────────
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Git Clone Utility
|
|
3
3
|
*
|
|
4
|
-
* Shallow-clones repositories into
|
|
4
|
+
* Shallow-clones repositories into the clone root (getGlobalDir()/repos/{name}/).
|
|
5
5
|
* If already cloned, does git pull instead.
|
|
6
6
|
*/
|
|
7
|
+
export declare const REPO_NAME_PATTERN: RegExp;
|
|
7
8
|
/**
|
|
8
9
|
* Extract the repository name from a git URL (HTTPS or SSH).
|
|
9
10
|
*
|
|
@@ -34,6 +35,25 @@ export interface CloneProgress {
|
|
|
34
35
|
*
|
|
35
36
|
* Exported so the separator placement is testable without mocking spawn.
|
|
36
37
|
*/
|
|
38
|
+
/**
|
|
39
|
+
* Detect Azure DevOps URLs — both self-hosted (via AZURE_DEVOPS_URL env)
|
|
40
|
+
* and cloud (dev.azure.com / *.visualstudio.com).
|
|
41
|
+
*
|
|
42
|
+
* Self-hosted Azure DevOps Server instances use arbitrary hostnames
|
|
43
|
+
* (e.g. `http://tfs.corp.example/Collection/Project/_git/Repo`), so the
|
|
44
|
+
* function checks `AZURE_DEVOPS_URL` first. Cloud addresses are a
|
|
45
|
+
* hardcoded fallback so PAT injection works out-of-the-box for
|
|
46
|
+
* dev.azure.com without extra configuration.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isAzureDevOpsUrl(url: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* One-time startup warning when AZURE_DEVOPS_URL is configured over cleartext
|
|
51
|
+
* http:// — the Azure DevOps PAT would then be sent unencrypted on every
|
|
52
|
+
* clone. Self-hosted instances that only serve http are still supported (we
|
|
53
|
+
* do not refuse), but operators rarely read request-time logs, so surface it
|
|
54
|
+
* at boot too. Call once from server startup.
|
|
55
|
+
*/
|
|
56
|
+
export declare function warnIfInsecureAzureConfig(): void;
|
|
37
57
|
export declare function buildCloneArgs(url: string, targetDir: string): string[];
|
|
38
58
|
/**
|
|
39
59
|
* Normalize a git URL into a comparable form.
|
|
@@ -96,4 +116,25 @@ export declare function assertRemoteMatchesRequestedUrl(targetDir: string, reque
|
|
|
96
116
|
* `--` (e.g. `--upload-pack=evil`) cannot be interpreted as a git option
|
|
97
117
|
* (CodeQL js/second-order-command-line-injection).
|
|
98
118
|
*/
|
|
99
|
-
export declare function cloneOrPull(url: string, targetDir: string, onProgress?: (progress: CloneProgress) => void
|
|
119
|
+
export declare function cloneOrPull(url: string, targetDir: string, onProgress?: (progress: CloneProgress) => void, options?: {
|
|
120
|
+
token?: string;
|
|
121
|
+
}): Promise<string>;
|
|
122
|
+
/**
|
|
123
|
+
* Hosts the per-request GitHub PAT may be sent to. Exported so the
|
|
124
|
+
* /api/analyze boundary check and this injection-site check share one
|
|
125
|
+
* allowlist (they must agree, or a token accepted by the API could be
|
|
126
|
+
* silently dropped — or worse — at injection).
|
|
127
|
+
*/
|
|
128
|
+
export declare const GITHUB_TOKEN_HOSTS: ReadonlySet<string>;
|
|
129
|
+
/**
|
|
130
|
+
* Build the spawn env for `git`. Suppresses credential prompts and, when a
|
|
131
|
+
* credential resolves (see resolveGitCredential), injects a single
|
|
132
|
+
* host-scoped Authorization header via the `GIT_CONFIG_*` env protocol
|
|
133
|
+
* (git ≥2.31) so credentials never appear in argv or the URL. Appends after
|
|
134
|
+
* any existing `GIT_CONFIG_COUNT` rather than overwriting it. Exported for
|
|
135
|
+
* unit tests.
|
|
136
|
+
*/
|
|
137
|
+
export declare function buildGitEnv(baseEnv: NodeJS.ProcessEnv, options?: {
|
|
138
|
+
token?: string;
|
|
139
|
+
url?: string;
|
|
140
|
+
}): NodeJS.ProcessEnv;
|