gitnexus 1.6.9 → 1.6.10-aptos.0
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 +211 -53
- package/dist/_shared/graph/types.d.ts +67 -3
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/integrations/resilient-fetch.d.ts +3 -1
- package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
- package/dist/_shared/integrations/resilient-fetch.js +4 -3
- package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +2 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +2 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +2 -2
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +8 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/pipeline.d.ts +1 -1
- package/dist/_shared/pipeline.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/callable-flow-site.d.ts +110 -0
- package/dist/_shared/scope-resolution/callable-flow-site.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/callable-flow-site.js +11 -0
- package/dist/_shared/scope-resolution/callable-flow-site.js.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.js +1 -0
- package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +7 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/reference-site.d.ts +9 -1
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +20 -3
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +1 -1
- package/dist/cli/ai-context.js +25 -44
- package/dist/cli/analyze.d.ts +5 -2
- package/dist/cli/analyze.js +197 -11
- package/dist/cli/clean.js +17 -3
- package/dist/cli/cli-message.d.ts +1 -1
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/doctor.js +96 -5
- package/dist/cli/editor-targets.d.ts +17 -2
- package/dist/cli/editor-targets.js +44 -0
- package/dist/cli/embeddings.d.ts +12 -0
- package/dist/cli/embeddings.js +49 -0
- package/dist/cli/eval-server.d.ts +23 -1
- package/dist/cli/eval-server.js +126 -8
- package/dist/cli/help-i18n.js +6 -0
- package/dist/cli/i18n/en.d.ts +18 -8
- package/dist/cli/i18n/en.js +18 -8
- package/dist/cli/i18n/resources.d.ts +28 -8
- package/dist/cli/i18n/zh-CN.d.ts +10 -0
- package/dist/cli/i18n/zh-CN.js +18 -8
- package/dist/cli/index.js +21 -7
- package/dist/cli/lazy-action.d.ts +7 -0
- package/dist/cli/lazy-action.js +27 -0
- package/dist/cli/mcp.js +6 -3
- package/dist/cli/move-availability.d.ts +5 -0
- package/dist/cli/move-availability.js +11 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +230 -32
- package/dist/cli/skill-gen.js +38 -18
- package/dist/cli/standard-skills.d.ts +76 -0
- package/dist/cli/standard-skills.js +45 -0
- package/dist/cli/status.d.ts +4 -1
- package/dist/cli/status.js +57 -4
- package/dist/cli/tool.js +11 -0
- package/dist/cli/uninstall.js +77 -18
- package/dist/cli/wiki.d.ts +1 -0
- package/dist/cli/wiki.js +7 -1
- package/dist/config/ignore-service.d.ts +2 -0
- package/dist/config/ignore-service.js +27 -0
- package/dist/core/analysis-features.d.ts +21 -0
- package/dist/core/analysis-features.js +59 -0
- package/dist/core/analyzer-identity.d.ts +74 -0
- package/dist/core/analyzer-identity.js +1820 -0
- package/dist/core/augmentation/engine.js +13 -8
- package/dist/core/embeddings/embedder.d.ts +3 -2
- package/dist/core/embeddings/embedder.js +24 -7
- package/dist/core/embeddings/embedding-identity.d.ts +11 -0
- package/dist/core/embeddings/embedding-identity.js +24 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +36 -1
- package/dist/core/embeddings/embedding-pipeline.js +100 -9
- package/dist/core/embeddings/http-client.d.ts +33 -3
- package/dist/core/embeddings/http-client.js +237 -25
- package/dist/core/embeddings/node-module-compat.d.ts +25 -0
- package/dist/core/embeddings/node-module-compat.js +25 -0
- package/dist/core/embeddings/onnxruntime-common-resolver.js +8 -5
- package/dist/core/embeddings/onnxruntime-node-resolver.js +33 -7
- package/dist/core/embeddings/runtime-install.d.ts +119 -0
- package/dist/core/embeddings/runtime-install.js +372 -0
- package/dist/core/embeddings/runtime-support.d.ts +48 -17
- package/dist/core/embeddings/runtime-support.js +96 -0
- package/dist/core/git-staleness.js +1 -1
- package/dist/core/group/bridge-db.js +2 -0
- package/dist/core/group/extractors/http-patterns/python.js +246 -108
- package/dist/core/group/extractors/manifest-extractor.js +4 -0
- package/dist/core/incremental/escalation-gate.d.ts +38 -0
- package/dist/core/incremental/escalation-gate.js +48 -0
- package/dist/core/incremental/shadow-candidates.d.ts +3 -3
- package/dist/core/incremental/shadow-candidates.js +3 -3
- package/dist/core/incremental/subgraph-extract.d.ts +2 -2
- package/dist/core/incremental/subgraph-extract.js +2 -2
- package/dist/core/index-freshness.d.ts +5 -0
- package/dist/core/index-freshness.js +13 -0
- package/dist/core/ingestion/class-extractors/configs/jvm.js +29 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +1 -1
- package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
- package/dist/core/ingestion/cobol-processor.js +27 -26
- package/dist/core/ingestion/community-processor.d.ts +51 -1
- package/dist/core/ingestion/community-processor.js +323 -64
- package/dist/core/ingestion/emit-references.js +7 -2
- package/dist/core/ingestion/filesystem-walker.js +4 -0
- package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +3 -0
- package/dist/core/ingestion/frameworks/spring/analysis-features.js +7 -0
- package/dist/core/ingestion/frameworks/spring/bean-candidates.d.ts +30 -0
- package/dist/core/ingestion/frameworks/spring/bean-candidates.js +182 -0
- package/dist/core/ingestion/frameworks/spring/bean-catalog.d.ts +12 -0
- package/dist/core/ingestion/frameworks/spring/bean-catalog.js +26 -0
- package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +24 -0
- package/dist/core/ingestion/frameworks/spring/config-bindings.js +115 -0
- package/dist/core/ingestion/languages/c/captures.js +56 -0
- package/dist/core/ingestion/languages/c/query.js +17 -0
- package/dist/core/ingestion/languages/c/scope-resolver.js +6 -0
- package/dist/core/ingestion/languages/cobol/captures.js +93 -0
- package/dist/core/ingestion/languages/cobol/scope-resolver.js +7 -0
- package/dist/core/ingestion/languages/cpp/captures.js +365 -75
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +14 -0
- package/dist/core/ingestion/languages/csharp/captures.js +25 -0
- package/dist/core/ingestion/languages/dart/captures.js +90 -2
- package/dist/core/ingestion/languages/dart/extension-type-preprocess.d.ts +7 -0
- package/dist/core/ingestion/languages/dart/extension-type-preprocess.js +30 -0
- package/dist/core/ingestion/languages/dart.js +2 -0
- package/dist/core/ingestion/languages/go/captures.js +34 -0
- package/dist/core/ingestion/languages/index.d.ts +1 -0
- package/dist/core/ingestion/languages/index.js +2 -0
- package/dist/core/ingestion/languages/java/analysis-features.d.ts +3 -0
- package/dist/core/ingestion/languages/java/analysis-features.js +13 -0
- package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +22 -0
- package/dist/core/ingestion/languages/java/capture-side-channel.js +58 -0
- package/dist/core/ingestion/languages/java/captures.d.ts +4 -3
- package/dist/core/ingestion/languages/java/captures.js +193 -17
- package/dist/core/ingestion/languages/java/package-facts.d.ts +5 -0
- package/dist/core/ingestion/languages/java/package-facts.js +9 -0
- package/dist/core/ingestion/languages/java/package-siblings.d.ts +3 -16
- package/dist/core/ingestion/languages/java/package-siblings.js +8 -147
- package/dist/core/ingestion/languages/java/query.js +23 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +23 -0
- package/dist/core/ingestion/languages/java/spring-bean-metadata.d.ts +2 -0
- package/dist/core/ingestion/languages/java/spring-bean-metadata.js +8 -0
- package/dist/core/ingestion/languages/java/spring-config-bindings.d.ts +23 -0
- package/dist/core/ingestion/languages/java/spring-config-bindings.js +215 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/javascript/captures.js +16 -0
- package/dist/core/ingestion/languages/javascript/query.js +21 -0
- package/dist/core/ingestion/languages/jvm/package-facts.d.ts +35 -0
- package/dist/core/ingestion/languages/jvm/package-facts.js +40 -0
- package/dist/core/ingestion/languages/jvm/package-siblings.d.ts +14 -0
- package/dist/core/ingestion/languages/jvm/package-siblings.js +129 -0
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +17 -3
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +42 -8
- package/dist/core/ingestion/languages/kotlin/captures.js +59 -0
- package/dist/core/ingestion/languages/kotlin/package-facts.d.ts +5 -0
- package/dist/core/ingestion/languages/kotlin/package-facts.js +9 -0
- package/dist/core/ingestion/languages/kotlin/package-siblings.d.ts +4 -0
- package/dist/core/ingestion/languages/kotlin/package-siblings.js +8 -0
- package/dist/core/ingestion/languages/kotlin/query.js +19 -0
- package/dist/core/ingestion/languages/kotlin/scope-resolver.js +9 -1
- package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.d.ts +2 -0
- package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.js +8 -0
- package/dist/core/ingestion/languages/kotlin.js +5 -6
- package/dist/core/ingestion/languages/move.d.ts +1 -0
- package/dist/core/ingestion/languages/move.js +27 -0
- package/dist/core/ingestion/languages/php/captures.js +40 -0
- package/dist/core/ingestion/languages/php/import-decomposer.js +12 -0
- package/dist/core/ingestion/languages/php/import-target.d.ts +2 -1
- package/dist/core/ingestion/languages/php/import-target.js +110 -2
- package/dist/core/ingestion/languages/php/interpret.js +10 -0
- package/dist/core/ingestion/languages/php/scope-resolver.js +1 -1
- package/dist/core/ingestion/languages/python/captures.d.ts +3 -4
- package/dist/core/ingestion/languages/python/captures.js +24 -5
- package/dist/core/ingestion/languages/python/interpret.js +4 -0
- package/dist/core/ingestion/languages/python/receiver-binding.d.ts +15 -2
- package/dist/core/ingestion/languages/python/receiver-binding.js +96 -2
- package/dist/core/ingestion/languages/python/simple-hooks.d.ts +5 -5
- package/dist/core/ingestion/languages/python/simple-hooks.js +15 -5
- package/dist/core/ingestion/languages/ruby/captures.js +42 -0
- package/dist/core/ingestion/languages/rust/captures.js +13 -0
- package/dist/core/ingestion/languages/rust/interpret.js +18 -0
- package/dist/core/ingestion/languages/rust/query.js +9 -0
- package/dist/core/ingestion/languages/rust/range-binding.js +6 -2
- package/dist/core/ingestion/languages/swift/captures.js +12 -0
- package/dist/core/ingestion/languages/typescript/captures.js +21 -0
- package/dist/core/ingestion/languages/typescript/nuxt-auto-imports.js +2 -1
- package/dist/core/ingestion/languages/typescript/query.js +37 -0
- package/dist/core/ingestion/markdown-processor.js +3 -2
- package/dist/core/ingestion/model/registration-table.js +1 -0
- package/dist/core/ingestion/parsing-processor.d.ts +3 -1
- package/dist/core/ingestion/parsing-processor.js +36 -1
- 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.js +56 -2
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +0 -2
- package/dist/core/ingestion/pipeline-phases/parse.js +12 -3
- package/dist/core/ingestion/pipeline-phases/processes.d.ts +8 -0
- package/dist/core/ingestion/pipeline-phases/processes.js +11 -1
- package/dist/core/ingestion/pipeline-phases/spring-config.d.ts +37 -0
- package/dist/core/ingestion/pipeline-phases/spring-config.js +433 -0
- package/dist/core/ingestion/pipeline-phases/standalone-ingest.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/standalone-ingest.js +6 -0
- package/dist/core/ingestion/pipeline.d.ts +4 -2
- package/dist/core/ingestion/pipeline.js +5 -2
- package/dist/core/ingestion/resolve-references.js +12 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +83 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.js +131 -0
- package/dist/core/ingestion/route-extractors/python-const-resolver.d.ts +75 -0
- package/dist/core/ingestion/route-extractors/python-const-resolver.js +299 -0
- package/dist/core/ingestion/scope-extractor.js +306 -43
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +71 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +7 -7
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +8 -7
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +3 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +6 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +1 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +4 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +7 -2
- package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +47 -0
- package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +1138 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +16 -4
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +97 -1
- package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +60 -0
- package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +111 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +4 -3
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +5 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +25 -38
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +6 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +147 -35
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +73 -44
- package/dist/core/ingestion/taint/typescript-model.js +34 -2
- package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
- package/dist/core/ingestion/tree-sitter-queries.js +23 -2
- package/dist/core/ingestion/type-extractors/jvm.js +17 -2
- package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -0
- package/dist/core/ingestion/utils/ast-helpers.js +153 -2
- package/dist/core/ingestion/utils/callable-flow-captures.d.ts +94 -0
- package/dist/core/ingestion/utils/callable-flow-captures.js +878 -0
- package/dist/core/ingestion/utils/line-base.d.ts +20 -0
- package/dist/core/ingestion/utils/line-base.js +20 -0
- package/dist/core/ingestion/utils/symbol-labels.d.ts +21 -0
- package/dist/core/ingestion/utils/symbol-labels.js +45 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +34 -0
- package/dist/core/ingestion/workers/parse-worker.js +40 -5
- package/dist/core/ingestion/workers/result-merge.js +4 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +28 -0
- package/dist/core/ingestion/workers/worker-pool.js +128 -28
- package/dist/core/lbug/csv-generator.d.ts +15 -0
- package/dist/core/lbug/csv-generator.js +124 -27
- package/dist/core/lbug/cypher-escape.d.ts +20 -0
- package/dist/core/lbug/cypher-escape.js +20 -0
- package/dist/core/lbug/extension-load-error.d.ts +67 -0
- package/dist/core/lbug/extension-load-error.js +326 -0
- package/dist/core/lbug/extension-loader.d.ts +17 -2
- package/dist/core/lbug/extension-loader.js +38 -13
- package/dist/core/lbug/lbug-adapter.d.ts +203 -2
- package/dist/core/lbug/lbug-adapter.js +527 -86
- package/dist/core/lbug/lbug-config.d.ts +56 -2
- package/dist/core/lbug/lbug-config.js +267 -7
- package/dist/core/lbug/move-columns.d.ts +7 -0
- package/dist/core/lbug/move-columns.js +86 -0
- package/dist/core/lbug/native-check.d.ts +40 -0
- package/dist/core/lbug/native-check.js +90 -0
- package/dist/core/lbug/node-table-layout.d.ts +29 -0
- package/dist/core/lbug/node-table-layout.js +119 -0
- package/dist/core/lbug/pool-adapter.d.ts +23 -1
- package/dist/core/lbug/pool-adapter.js +115 -8
- package/dist/core/lbug/schema.d.ts +4 -3
- package/dist/core/lbug/schema.js +16 -16
- package/dist/core/lbug/sidecar-recovery.d.ts +172 -0
- package/dist/core/lbug/sidecar-recovery.js +418 -16
- package/dist/core/lbug/wal-checkpoint-driver.js +3 -0
- package/dist/core/move/artifact-download.d.ts +19 -0
- package/dist/core/move/artifact-download.js +179 -0
- package/dist/core/move/compiler-facts.d.ts +120 -0
- package/dist/core/move/compiler-facts.js +9 -0
- package/dist/core/move/consistency.d.ts +28 -0
- package/dist/core/move/consistency.js +98 -0
- package/dist/core/move/constants.d.ts +98 -0
- package/dist/core/move/constants.js +136 -0
- package/dist/core/move/discovery.d.ts +10 -0
- package/dist/core/move/discovery.js +22 -0
- package/dist/core/move/entry-points.d.ts +14 -0
- package/dist/core/move/entry-points.js +40 -0
- package/dist/core/move/facts-mapper.d.ts +75 -0
- package/dist/core/move/facts-mapper.js +534 -0
- package/dist/core/move/install-lock.d.ts +14 -0
- package/dist/core/move/install-lock.js +102 -0
- package/dist/core/move/install.d.ts +39 -0
- package/dist/core/move/install.js +391 -0
- package/dist/core/move/mcp-client.d.ts +115 -0
- package/dist/core/move/mcp-client.js +436 -0
- package/dist/core/move/move-ingest.d.ts +49 -0
- package/dist/core/move/move-ingest.js +320 -0
- package/dist/core/move/provision.d.ts +19 -0
- package/dist/core/move/provision.js +91 -0
- package/dist/core/move/release.d.ts +6 -0
- package/dist/core/move/release.js +10 -0
- package/dist/core/move/symbol-id.d.ts +35 -0
- package/dist/core/move/symbol-id.js +65 -0
- package/dist/core/move/type-parser.d.ts +11 -0
- package/dist/core/move/type-parser.js +38 -0
- package/dist/core/platform/capabilities.d.ts +0 -1
- package/dist/core/platform/capabilities.js +39 -8
- package/dist/core/run-analyze.d.ts +3 -3
- package/dist/core/run-analyze.js +1001 -184
- package/dist/core/search/fts-indexes.d.ts +31 -0
- package/dist/core/search/fts-indexes.js +73 -0
- package/dist/core/search/fts-schema.js +2 -0
- package/dist/core/tree-sitter/safe-parse.d.ts +8 -3
- package/dist/core/tree-sitter/safe-parse.js +21 -7
- package/dist/core/wiki/graph-queries.js +6 -5
- package/dist/core/wiki/llm-client.d.ts +8 -2
- package/dist/core/wiki/llm-client.js +41 -5
- package/dist/mcp/core/embedder.js +16 -2
- package/dist/mcp/http-transport.d.ts +5 -0
- package/dist/mcp/http-transport.js +19 -5
- package/dist/mcp/local/bean-metadata.d.ts +2 -0
- package/dist/mcp/local/bean-metadata.js +25 -0
- package/dist/mcp/local/line-display.d.ts +22 -0
- package/dist/mcp/local/line-display.js +3 -0
- package/dist/mcp/local/local-backend.d.ts +19 -1
- package/dist/mcp/local/local-backend.js +402 -155
- package/dist/mcp/local/pdg-impact.d.ts +5 -3
- package/dist/mcp/local/pdg-impact.js +5 -2
- package/dist/mcp/output-budget.d.ts +5 -0
- package/dist/mcp/output-budget.js +52 -0
- package/dist/mcp/read-only-policy.d.ts +12 -0
- package/dist/mcp/read-only-policy.js +102 -0
- package/dist/mcp/repository-policy.d.ts +34 -0
- package/dist/mcp/repository-policy.js +328 -0
- package/dist/mcp/resources.js +32 -5
- package/dist/mcp/server.d.ts +5 -2
- package/dist/mcp/server.js +29 -9
- package/dist/mcp/tools.d.ts +0 -8
- package/dist/mcp/tools.js +102 -5
- package/dist/server/analyze-job.d.ts +3 -0
- package/dist/server/analyze-job.js +17 -0
- package/dist/server/analyze-launch.d.ts +6 -0
- package/dist/server/analyze-launch.js +82 -6
- package/dist/server/analyze-worker-core.d.ts +2 -1
- package/dist/server/analyze-worker-core.js +5 -2
- package/dist/server/analyze-worker.js +29 -6
- package/dist/server/api.d.ts +30 -0
- package/dist/server/api.js +120 -34
- package/dist/server/mcp-http.d.ts +1 -1
- package/dist/server/mcp-http.js +4 -2
- package/dist/server/upload-ingest.js +2 -1
- package/dist/server/validation.js +2 -1
- package/dist/storage/git.d.ts +31 -0
- package/dist/storage/git.js +111 -1
- package/dist/storage/parse-cache.js +7 -1
- package/dist/storage/parsedfile-store.d.ts +8 -0
- package/dist/storage/parsedfile-store.js +165 -1
- package/dist/storage/repo-manager.d.ts +194 -2
- package/dist/storage/repo-manager.js +56 -1
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +50 -3
- package/hooks/claude/gitnexus-hook.cjs +59 -9
- package/hooks/claude/pre-tool-use.sh +0 -0
- package/hooks/claude/session-start.sh +0 -0
- package/package.json +21 -15
- package/scripts/cross-platform-tests.ts +56 -0
- package/scripts/ensure-fts.ts +43 -0
- package/scripts/install-duckdb-extension.mjs +85 -24
- package/scripts/run-cross-platform.ts +61 -6
- package/scripts/shard-arg.ts +30 -0
- package/scripts/sync-plugin-manifests.mjs +192 -0
- package/skills/gitnexus-lfg/README.md +55 -0
- package/skills/gitnexus-lfg/SKILL.md +86 -0
- package/skills/gitnexus-plan/README.md +142 -0
- package/skills/gitnexus-plan/SKILL.md +348 -0
- package/skills/gitnexus-plan/references/context-ledger.md +137 -0
- package/skills/gitnexus-plan/references/context-pack.md +126 -0
- package/skills/gitnexus-plan/references/evidence-provenance.md +272 -0
- package/skills/gitnexus-plan/references/pdg-slice.md +109 -0
- package/skills/gitnexus-plan/references/plan-template.md +201 -0
- package/skills/gitnexus-plan/scripts/evidence-provenance.mjs +2084 -0
- package/skills/gitnexus-review/SKILL.md +273 -0
- package/skills/gitnexus-review/ci-personas/ci-adversarial-lens.md +42 -0
- package/skills/gitnexus-review/ci-personas/ci-blast-radius-lens.md +39 -0
- package/skills/gitnexus-review/ci-personas/ci-correctness-lens.md +37 -0
- package/skills/gitnexus-review/ci-personas/ci-coverage-lens.md +40 -0
- package/skills/gitnexus-review/ci-personas/ci-critic-lens.md +42 -0
- package/skills/gitnexus-review/ci-personas/ci-security-lens.md +39 -0
- package/skills/gitnexus-work/README.md +71 -0
- package/skills/gitnexus-work/SKILL.md +269 -0
- package/skills/gitnexus-work/references/evidence-provenance.md +272 -0
- package/skills/gitnexus-work/scripts/evidence-provenance.mjs +2084 -0
- package/web/assets/ProcessFlowModal-B_bfBySy.js +22 -0
- package/web/assets/__vite-browser-external-bMKyYQkO.js +1 -0
- package/web/assets/agent-Bqxn-abU.js +626 -0
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-CmG3uPWf.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-BkWhpzWB.js → blockDiagram-7IZFK4PR-DBefcjof.js} +7 -7
- package/web/assets/{c4Diagram-Y2BXMSZH-DtBvpzWD.js → c4Diagram-Y2BXMSZH-EjWnjEJl.js} +6 -6
- package/web/assets/chunk-2T2R6R2M-Bb6Sy3_j.js +4 -0
- package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +1 -0
- package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +321 -0
- package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +159 -0
- package/web/assets/{chunk-6764PJDD-DpIS7hxD.js → chunk-6764PJDD-C7xxk063.js} +1 -1
- package/web/assets/chunk-67TQ5CYL-CA7OhIEf.js +124 -0
- package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +32 -0
- package/web/assets/chunk-7J6CGLKN-BlKwgXKs.js +10 -0
- package/web/assets/chunk-7W6UQGC5-pyKGssV3.js +1 -0
- package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +1 -0
- package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +1 -0
- package/web/assets/{chunk-INKRHTLW-Nu4ri9P-.js → chunk-INKRHTLW-Ckl3_KkO.js} +13 -13
- package/web/assets/chunk-J5EP6P6S-L19oz55R.js +1 -0
- package/web/assets/{chunk-KGFNY3KK-JGMJvKCK.js → chunk-KGFNY3KK-BZeP-55u.js} +17 -17
- package/web/assets/chunk-KGYTTC2M-zm6n242I.js +1 -0
- package/web/assets/{chunk-KRXBNO2N-BW5o0KUN.js → chunk-KRXBNO2N-C-UNuKKf.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-CfLLCywY.js → chunk-LCXTWHL2-C162wE5z.js} +5 -5
- package/web/assets/chunk-LII3EMHJ-BL6lKJ_P.js +1 -0
- package/web/assets/chunk-LRIF4GLE-n59lhprL.js +1 -0
- package/web/assets/chunk-QA3QBVWF-DVXPOIxe.js +2 -0
- package/web/assets/chunk-RERM46MO-B5dAdWpP.js +1 -0
- package/web/assets/chunk-RG4AUYOV-ZNgyLFq6.js +206 -0
- package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +1 -0
- package/web/assets/chunk-RLI5ZMPA-CkXZ0y0U.js +1 -0
- package/web/assets/chunk-T2UQINTJ-BEyXhZWe.js +1 -0
- package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +1 -0
- package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +1 -0
- package/web/assets/chunk-UY5QBCOK-ByqTVLvh.js +1 -0
- package/web/assets/chunk-VU6ZFW4Y-BLeasdkU.js +2 -0
- package/web/assets/{chunk-W44A43WB-JqMLIpR0.js → chunk-W44A43WB-BN8EQc_u.js} +1 -1
- package/web/assets/chunk-ZXARS5L4-C3v-4Fsw.js +1 -0
- package/web/assets/classDiagram-KGZ6W3CR-olpO3fMe.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-olpO3fMe.js +1 -0
- package/web/assets/cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js +1 -0
- package/web/assets/dagre-ND4H6XIP-CY4iIF7v.js +4 -0
- package/web/assets/diagram-3NCE3AQN-CO6QpzEE.js +43 -0
- package/web/assets/diagram-GF46GFSD-B2atbzmU.js +24 -0
- package/web/assets/diagram-HNR7UZ2L-DVRltWbL.js +3 -0
- package/web/assets/diagram-QXG6HAR7-DR6AHD2h.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-DkpoMwTL.js +10 -0
- package/web/assets/erDiagram-L5TCEMPS-n8g_90bc.js +85 -0
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +1 -0
- package/web/assets/flowDiagram-H6V6AXG4-SGMDiCkB.js +162 -0
- package/web/assets/ganttDiagram-JCBTUEKG-Cb3UBqRS.js +292 -0
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-Bs9CR7tq.js +106 -0
- package/web/assets/index-CX_fADmQ.css +2 -0
- package/web/assets/index-D1Z3dGGz.js +575 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-T368on4D.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-DfYpxnE5.js → ishikawaDiagram-BNXS4ZKH-XpjJRU9h.js} +6 -6
- package/web/assets/journeyDiagram-M6C3CM3L-C6wjooas.js +139 -0
- package/web/assets/kanban-definition-75IXJCU3-5_UVY79g.js +89 -0
- package/web/assets/{katex-K3KEBU37-CTc5BslQ.js → katex-K3KEBU37-qRQBy-EZ.js} +2 -2
- package/web/assets/{mindmap-definition-2TDM6QVE-DypvbOMQ.js → mindmap-definition-2TDM6QVE-8xDLzk2e.js} +29 -29
- package/web/assets/node-Ct_zna8U.js +8 -0
- package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +1 -0
- package/web/assets/pieDiagram-CU6KROY3-Bv4LpAbr.js +30 -0
- package/web/assets/preload-helper-Czpn1I53.js +1 -0
- package/web/assets/{quadrantDiagram-VICAPDV7-yXSZ2lLz.js → quadrantDiagram-VICAPDV7-DR54jOeR.js} +6 -6
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +1 -0
- package/web/assets/requirementDiagram-JXO7QTGE-PEkg7sKC.js +84 -0
- package/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/web/assets/sankeyDiagram-URQDO5SZ-DDWEtjcs.js +40 -0
- package/web/assets/sdk-CzHHH8tD.js +37 -0
- package/web/assets/sequenceDiagram-VS2MUI6T-Bv-uwANx.js +162 -0
- package/web/assets/src-JV30wyV8.js +1 -0
- package/web/assets/stateDiagram-7D4R322I-DVNjmkEq.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-CyN4Fh7_.js +1 -0
- package/web/assets/timeline-definition-O6YCAMPW-Qmsuo7qS.js +120 -0
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +1 -0
- package/web/assets/vennDiagram-MWXL3ELB-BD1iK1SX.js +34 -0
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +1 -0
- package/web/assets/wardleyDiagram-CUQ6CDDI-D6TzLVob.js +78 -0
- package/web/assets/{xychartDiagram-N2JHSOCM-BOLm0eNm.js → xychartDiagram-N2JHSOCM-CoZ_Tits.js} +6 -6
- package/web/index.html +18 -10
- package/skills/gitnexus-pr-review.md +0 -163
- package/web/assets/agent-Dli_x7bU.js +0 -660
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-dEkqUZN9.js +0 -36
- package/web/assets/chunk-3SSMPTDK-B4_etUhr.js +0 -321
- package/web/assets/chunk-67TQ5CYL-4sNPJU1q.js +0 -124
- package/web/assets/chunk-7W6UQGC5-KyEG0HQg.js +0 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +0 -161
- package/web/assets/chunk-LII3EMHJ-D-jm-dLa.js +0 -1
- package/web/assets/chunk-QA3QBVWF-BgRW3SXd.js +0 -2
- package/web/assets/chunk-RG4AUYOV-CqWzWsV3.js +0 -206
- package/web/assets/chunk-T2UQINTJ-DSBqkzH7.js +0 -1
- package/web/assets/chunk-UY5QBCOK-DyF0vyGd.js +0 -1
- package/web/assets/chunk-ZXARS5L4-CxN8oiwI.js +0 -1
- package/web/assets/classDiagram-KGZ6W3CR-CMne4tG9.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CMne4tG9.js +0 -1
- package/web/assets/cose-bilkent-UX7MHV2Q-D71wNYRJ.js +0 -1
- package/web/assets/dagre-ND4H6XIP-Co5rRx9X.js +0 -4
- package/web/assets/diagram-3NCE3AQN-DBp4O00j.js +0 -43
- package/web/assets/diagram-GF46GFSD-6N_8yS0i.js +0 -24
- package/web/assets/diagram-HNR7UZ2L-DFCfd5LI.js +0 -3
- package/web/assets/diagram-QXG6HAR7-Di093rFg.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-DZWi4SUN.js +0 -10
- package/web/assets/erDiagram-L5TCEMPS-8X1y6R4Y.js +0 -85
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +0 -1
- package/web/assets/flowDiagram-H6V6AXG4-CMpY8Ufn.js +0 -162
- package/web/assets/ganttDiagram-JCBTUEKG-D3iL2Aet.js +0 -292
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +0 -106
- package/web/assets/index-KctnI3Vq.js +0 -635
- package/web/assets/index-_lgn7hs5.css +0 -2
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-BaLMZkUg.js +0 -2
- package/web/assets/journeyDiagram-M6C3CM3L-CvArszLo.js +0 -139
- package/web/assets/kanban-definition-75IXJCU3-CpfVLLf9.js +0 -89
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +0 -1
- package/web/assets/pieDiagram-CU6KROY3-s27EFWgP.js +0 -30
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +0 -1
- package/web/assets/requirementDiagram-JXO7QTGE-CWhqInuf.js +0 -84
- package/web/assets/sankeyDiagram-URQDO5SZ-1qEjlFIB.js +0 -40
- package/web/assets/sequenceDiagram-VS2MUI6T-RyTlZ5cR.js +0 -162
- package/web/assets/stateDiagram-7D4R322I-DTjVfX4A.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-xY9_k9_Q.js +0 -1
- package/web/assets/timeline-definition-O6YCAMPW-DrrqLYAf.js +0 -120
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +0 -1
- package/web/assets/vennDiagram-MWXL3ELB-B0RkWAim.js +0 -34
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +0 -1
- package/web/assets/wardleyDiagram-CUQ6CDDI-boUxiQ5F.js +0 -78
|
@@ -34,8 +34,10 @@ export declare function splitCalleeIds(raw: unknown): string[];
|
|
|
34
34
|
* Contract version of the mode:'pdg' impact result shape. A stable discriminator
|
|
35
35
|
* for external MCP/agent consumers — distinct from the DB INCREMENTAL_SCHEMA_VERSION.
|
|
36
36
|
* Bump on any breaking change to the PDG result fields.
|
|
37
|
+
* v2: `startLine` in the result is now 1-based display (#2380), matching the
|
|
38
|
+
* context/query/impact tools (was 0-based).
|
|
37
39
|
*/
|
|
38
|
-
export declare const PDG_RESULT_VERSION:
|
|
40
|
+
export declare const PDG_RESULT_VERSION: 2;
|
|
39
41
|
/** A reachable dependence block resolved to its source statement. */
|
|
40
42
|
export interface PdgStatement {
|
|
41
43
|
/** 1-based source line where the statement's block starts. */
|
|
@@ -105,7 +107,7 @@ export interface PdgInterproceduralImpact {
|
|
|
105
107
|
export interface PdgImpactBaseResult extends PdgImpactParityFields {
|
|
106
108
|
mode: 'pdg';
|
|
107
109
|
/** Contract version of the mode:'pdg' impact result shape; bump on any breaking change to the PDG result fields. */
|
|
108
|
-
pdgResultVersion:
|
|
110
|
+
pdgResultVersion: 2;
|
|
109
111
|
target: PdgImpactTarget;
|
|
110
112
|
direction: 'upstream' | 'downstream';
|
|
111
113
|
impactedCount: number;
|
|
@@ -172,7 +174,7 @@ export interface PdgImpactDegradedResult extends PdgImpactBaseResult {
|
|
|
172
174
|
export interface PdgImpactErrorResult {
|
|
173
175
|
mode?: 'pdg';
|
|
174
176
|
/** Contract version of the mode:'pdg' impact result shape; bump on any breaking change to the PDG result fields. */
|
|
175
|
-
pdgResultVersion:
|
|
177
|
+
pdgResultVersion: 2;
|
|
176
178
|
error: string;
|
|
177
179
|
target: PdgImpactTarget;
|
|
178
180
|
direction: 'upstream' | 'downstream';
|
|
@@ -9,6 +9,7 @@ import path from 'path';
|
|
|
9
9
|
import { loadMeta } from '../../storage/repo-manager.js';
|
|
10
10
|
import { IMPACT_MAX_DEPTH, PDG_QUERY_DEFAULT_LIMIT, PDG_QUERY_MAX_LIMIT } from '../tools.js';
|
|
11
11
|
import { CALLEES_TRUNCATED_SENTINEL, CALLEE_ID_SEP } from '../../core/ingestion/cfg/emit.js';
|
|
12
|
+
import { toDisplayLine } from './line-display.js';
|
|
12
13
|
import { decodeCallSummary } from '../../core/ingestion/taint/call-summary-codec.js';
|
|
13
14
|
import { decodeReachingDefReason } from '../../core/ingestion/cfg/reaching-def-reason-codec.js';
|
|
14
15
|
import { getProviderForFile } from '../../core/ingestion/languages/index.js';
|
|
@@ -84,8 +85,10 @@ export function splitCalleeIds(raw) {
|
|
|
84
85
|
* Contract version of the mode:'pdg' impact result shape. A stable discriminator
|
|
85
86
|
* for external MCP/agent consumers — distinct from the DB INCREMENTAL_SCHEMA_VERSION.
|
|
86
87
|
* Bump on any breaking change to the PDG result fields.
|
|
88
|
+
* v2: `startLine` in the result is now 1-based display (#2380), matching the
|
|
89
|
+
* context/query/impact tools (was 0-based).
|
|
87
90
|
*/
|
|
88
|
-
export const PDG_RESULT_VERSION =
|
|
91
|
+
export const PDG_RESULT_VERSION = 2;
|
|
89
92
|
/**
|
|
90
93
|
* FU-B-2 intra-block def→use line walk. Given a block's self REACHING_DEF
|
|
91
94
|
* def→use line PAIRS (every `defLine → useLine` step decoded from the edge
|
|
@@ -519,7 +522,7 @@ function assemblePdgImpactResult(input) {
|
|
|
519
522
|
name: s.name,
|
|
520
523
|
type: s.type,
|
|
521
524
|
filePath: s.filePath,
|
|
522
|
-
...(s.startLine !== undefined ? { startLine: s.startLine } : {}),
|
|
525
|
+
...(s.startLine !== undefined ? { startLine: toDisplayLine(s.startLine) } : {}),
|
|
523
526
|
...(s.ambiguous ? { ambiguous: true } : {}),
|
|
524
527
|
...(s.id === null ? { unresolved: true } : {}),
|
|
525
528
|
pdgEvidence: (s.id === null ? 'degraded' : 'owner-projection'),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const MCP_TOKEN_ESTIMATE_BYTES = 4;
|
|
2
|
+
export declare const MCP_TRUNCATION_MARKER = "\n\u2026";
|
|
3
|
+
export declare function resolveMcpMaxTokens(toolName: string, args: Record<string, unknown> | undefined, env?: NodeJS.ProcessEnv): number | undefined;
|
|
4
|
+
export declare function applyMcpMaxTokens(text: string, maxTokens: number | undefined): string;
|
|
5
|
+
export declare function withoutMcpBudgetArg(args: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const BUDGETED_TOOLS = new Set(['query', 'context', 'impact']);
|
|
2
|
+
export const MCP_TOKEN_ESTIMATE_BYTES = 4;
|
|
3
|
+
export const MCP_TRUNCATION_MARKER = '\n…';
|
|
4
|
+
function parsePositiveInteger(value, source) {
|
|
5
|
+
if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0)
|
|
6
|
+
return value;
|
|
7
|
+
if (typeof value === 'string' && /^[1-9]\d*$/.test(value.trim())) {
|
|
8
|
+
const parsed = Number(value.trim());
|
|
9
|
+
if (Number.isSafeInteger(parsed))
|
|
10
|
+
return parsed;
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`${source} must be a positive integer.`);
|
|
13
|
+
}
|
|
14
|
+
export function resolveMcpMaxTokens(toolName, args, env = process.env) {
|
|
15
|
+
if (!BUDGETED_TOOLS.has(toolName))
|
|
16
|
+
return undefined;
|
|
17
|
+
if (args?.maxTokens !== undefined)
|
|
18
|
+
return parsePositiveInteger(args.maxTokens, 'maxTokens');
|
|
19
|
+
const configured = env.GITNEXUS_MCP_DEFAULT_MAX_TOKENS;
|
|
20
|
+
if (configured === undefined || configured.trim() === '')
|
|
21
|
+
return undefined;
|
|
22
|
+
return parsePositiveInteger(configured, 'GITNEXUS_MCP_DEFAULT_MAX_TOKENS');
|
|
23
|
+
}
|
|
24
|
+
function utf8Prefix(text, maxBytes) {
|
|
25
|
+
let bytes = 0;
|
|
26
|
+
const codePoints = [];
|
|
27
|
+
for (const codePoint of text) {
|
|
28
|
+
const codePointBytes = Buffer.byteLength(codePoint, 'utf8');
|
|
29
|
+
if (bytes + codePointBytes > maxBytes)
|
|
30
|
+
break;
|
|
31
|
+
codePoints.push(codePoint);
|
|
32
|
+
bytes += codePointBytes;
|
|
33
|
+
}
|
|
34
|
+
return codePoints.join('');
|
|
35
|
+
}
|
|
36
|
+
export function applyMcpMaxTokens(text, maxTokens) {
|
|
37
|
+
if (maxTokens === undefined)
|
|
38
|
+
return text;
|
|
39
|
+
const textBytes = Buffer.byteLength(text, 'utf8');
|
|
40
|
+
if (maxTokens >= Math.ceil(textBytes / MCP_TOKEN_ESTIMATE_BYTES))
|
|
41
|
+
return text;
|
|
42
|
+
const maxBytes = maxTokens * MCP_TOKEN_ESTIMATE_BYTES;
|
|
43
|
+
const markerBytes = Buffer.byteLength(MCP_TRUNCATION_MARKER, 'utf8');
|
|
44
|
+
return utf8Prefix(text, Math.max(0, maxBytes - markerBytes)) + MCP_TRUNCATION_MARKER;
|
|
45
|
+
}
|
|
46
|
+
export function withoutMcpBudgetArg(args) {
|
|
47
|
+
if (!args || !Object.prototype.hasOwnProperty.call(args, 'maxTokens'))
|
|
48
|
+
return args;
|
|
49
|
+
const backendArgs = { ...args };
|
|
50
|
+
delete backendArgs.maxTokens;
|
|
51
|
+
return backendArgs;
|
|
52
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GITNEXUS_TOOLS } from './tools.js';
|
|
2
|
+
type GitNexusTool = (typeof GITNEXUS_TOOLS)[number];
|
|
3
|
+
export declare const MCP_READ_ONLY_TOOLS: Set<string>;
|
|
4
|
+
export declare function resolveMcpReadOnlyMode(env?: NodeJS.ProcessEnv): boolean;
|
|
5
|
+
export declare function assertMcpReadOnlyToolCall(toolName: string, args: Record<string, unknown> | undefined, readOnly: boolean): void;
|
|
6
|
+
export declare function readOnlyResourceTemplateAllowed(uriTemplate: string, readOnly: boolean): boolean;
|
|
7
|
+
export declare function assertMcpReadOnlyResource(uri: string, readOnly: boolean): void;
|
|
8
|
+
export declare function filterMcpReadOnlyResourceContent(content: string, readOnly: boolean): string;
|
|
9
|
+
/** Shared with repository-policy.ts so both policies scrub identically. */
|
|
10
|
+
export declare function scrubGroupDescription(description: string): string;
|
|
11
|
+
export declare function toolForReadOnlyMcp(tool: GitNexusTool, readOnly: boolean): GitNexusTool;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export const MCP_READ_ONLY_TOOLS = new Set([
|
|
2
|
+
'list_repos',
|
|
3
|
+
'query',
|
|
4
|
+
'context',
|
|
5
|
+
'detect_changes',
|
|
6
|
+
'check',
|
|
7
|
+
'impact',
|
|
8
|
+
'explain',
|
|
9
|
+
'pdg_query',
|
|
10
|
+
'route_map',
|
|
11
|
+
'tool_map',
|
|
12
|
+
'shape_check',
|
|
13
|
+
'api_impact',
|
|
14
|
+
'trace',
|
|
15
|
+
]);
|
|
16
|
+
const MCP_READ_ONLY_ALIASES = new Set(['search', 'explore', 'overview']);
|
|
17
|
+
export function resolveMcpReadOnlyMode(env = process.env) {
|
|
18
|
+
const value = env.GITNEXUS_MCP_READ_ONLY?.trim();
|
|
19
|
+
if (value === undefined || value === '' || value === '0')
|
|
20
|
+
return false;
|
|
21
|
+
if (value === '1')
|
|
22
|
+
return true;
|
|
23
|
+
throw new Error('GITNEXUS_MCP_READ_ONLY must be 0 or 1.');
|
|
24
|
+
}
|
|
25
|
+
export function assertMcpReadOnlyToolCall(toolName, args, readOnly) {
|
|
26
|
+
if (!readOnly)
|
|
27
|
+
return;
|
|
28
|
+
if (!MCP_READ_ONLY_TOOLS.has(toolName) && !MCP_READ_ONLY_ALIASES.has(toolName)) {
|
|
29
|
+
throw new Error(`Tool "${toolName}" is not available in GitNexus MCP read-only mode.`);
|
|
30
|
+
}
|
|
31
|
+
if (typeof args?.repo === 'string' && args.repo.trim().startsWith('@')) {
|
|
32
|
+
throw new Error('Group routing is not available in GitNexus MCP read-only mode.');
|
|
33
|
+
}
|
|
34
|
+
// crossDepth/subgroup only do anything on the @group path rejected above,
|
|
35
|
+
// but rejecting them here keeps the advertised schema and the dispatch
|
|
36
|
+
// contract in agreement.
|
|
37
|
+
for (const groupOnlyArg of ['crossDepth', 'subgroup']) {
|
|
38
|
+
if (args?.[groupOnlyArg] !== undefined) {
|
|
39
|
+
throw new Error(`Parameter "${groupOnlyArg}" is not available in GitNexus MCP read-only mode.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function readOnlyResourceTemplateAllowed(uriTemplate, readOnly) {
|
|
44
|
+
return !readOnly || !/^gitnexus:\/\/group\//iu.test(uriTemplate);
|
|
45
|
+
}
|
|
46
|
+
export function assertMcpReadOnlyResource(uri, readOnly) {
|
|
47
|
+
if (!readOnly)
|
|
48
|
+
return;
|
|
49
|
+
let isGroupResource = false;
|
|
50
|
+
try {
|
|
51
|
+
const parsed = new URL(uri);
|
|
52
|
+
isGroupResource =
|
|
53
|
+
parsed.protocol.toLowerCase() === 'gitnexus:' && parsed.hostname.toLowerCase() === 'group';
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Invalid resource URIs are rejected by the normal parser. This fallback
|
|
57
|
+
// keeps obviously group-shaped malformed inputs fail-closed as well.
|
|
58
|
+
isGroupResource = /^gitnexus:\/\/group(?:\/|$)/iu.test(uri);
|
|
59
|
+
}
|
|
60
|
+
if (isGroupResource) {
|
|
61
|
+
throw new Error('Group resources are not available in GitNexus MCP read-only mode.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Cosmetic only: dispatch enforcement above is the actual boundary. If the
|
|
65
|
+
// generated resource format drifts and a hidden route slips through here, the
|
|
66
|
+
// caller still gets a clean rejection at dispatch.
|
|
67
|
+
export function filterMcpReadOnlyResourceContent(content, readOnly) {
|
|
68
|
+
if (!readOnly)
|
|
69
|
+
return content;
|
|
70
|
+
return content
|
|
71
|
+
.split('\n')
|
|
72
|
+
.filter((line) => !/^\s*-\s+(?:rename|cypher|group_sync|group_list):/u.test(line) &&
|
|
73
|
+
!/^\|\s*`(?:rename|cypher|group_sync|group_list)`\s*\|/u.test(line) &&
|
|
74
|
+
!line.includes('gitnexus://group/'))
|
|
75
|
+
.join('\n');
|
|
76
|
+
}
|
|
77
|
+
/** Shared with repository-policy.ts so both policies scrub identically. */
|
|
78
|
+
export function scrubGroupDescription(description) {
|
|
79
|
+
return description
|
|
80
|
+
.replace(/\nGROUP MODE:[\s\S]*?(?=\n\n[A-Z][A-Z ()-]*:|$)/gu, '')
|
|
81
|
+
.replace(/\nCROSS-REPO \(experimental\):[\s\S]*?(?=\n\n[A-Z][A-Z ()-]*:|$)/gu, '')
|
|
82
|
+
.replace(/\nDESTINATION TRACE \(cross-repo\):[\s\S]*?(?=\n\n[A-Z][A-Z ()-]*:|$)/gu, '');
|
|
83
|
+
}
|
|
84
|
+
export function toolForReadOnlyMcp(tool, readOnly) {
|
|
85
|
+
if (!readOnly)
|
|
86
|
+
return tool;
|
|
87
|
+
const properties = { ...tool.inputSchema.properties };
|
|
88
|
+
const repo = properties.repo;
|
|
89
|
+
if (repo && typeof repo === 'object') {
|
|
90
|
+
properties.repo = {
|
|
91
|
+
...repo,
|
|
92
|
+
description: 'Indexed repository name or path. Group-mode values beginning with @ are unavailable in MCP read-only mode.',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
delete properties.subgroup;
|
|
96
|
+
delete properties.crossDepth;
|
|
97
|
+
return {
|
|
98
|
+
...tool,
|
|
99
|
+
description: `${scrubGroupDescription(tool.description)}\n\nGitNexus MCP read-only mode excludes raw Cypher, mutation, and group routing.`,
|
|
100
|
+
inputSchema: { ...tool.inputSchema, properties },
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { LocalBackend } from './local/local-backend.js';
|
|
2
|
+
import type { GITNEXUS_TOOLS } from './tools.js';
|
|
3
|
+
type GitNexusTool = (typeof GITNEXUS_TOOLS)[number];
|
|
4
|
+
interface ResolvedRepository {
|
|
5
|
+
name: string;
|
|
6
|
+
path: string;
|
|
7
|
+
pathKey: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class McpRepositoryPolicy {
|
|
10
|
+
readonly restricted: boolean;
|
|
11
|
+
readonly configured: boolean;
|
|
12
|
+
private readonly registry;
|
|
13
|
+
private readonly allowed;
|
|
14
|
+
private readonly allowedPathKeys;
|
|
15
|
+
private readonly defaultRepo?;
|
|
16
|
+
private readonly uniqueAllowedContextNames;
|
|
17
|
+
static unrestricted(): McpRepositoryPolicy;
|
|
18
|
+
constructor(registry: readonly ResolvedRepository[], allowed: readonly ResolvedRepository[] | undefined, defaultRepo: ResolvedRepository | undefined);
|
|
19
|
+
private resolveRuntimeRepo;
|
|
20
|
+
private repoForArgs;
|
|
21
|
+
private normalizeToolArgs;
|
|
22
|
+
private listAllowedRepos;
|
|
23
|
+
private listReposPage;
|
|
24
|
+
private callTool;
|
|
25
|
+
private resolveRepo;
|
|
26
|
+
assertResourceUri(uri: string): void;
|
|
27
|
+
resourceTemplateAllowed(uriTemplate: string): boolean;
|
|
28
|
+
toolAllowed(toolName: string): boolean;
|
|
29
|
+
toolForMcp(tool: GitNexusTool): GitNexusTool;
|
|
30
|
+
scopeBackend(backend: LocalBackend): LocalBackend;
|
|
31
|
+
}
|
|
32
|
+
export declare function mcpRepositoryPolicyConfigured(env?: NodeJS.ProcessEnv): boolean;
|
|
33
|
+
export declare function createMcpRepositoryPolicy(backend: LocalBackend, env?: NodeJS.ProcessEnv): Promise<McpRepositoryPolicy>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { parseListReposPagination } from './local/local-backend.js';
|
|
3
|
+
import { scrubGroupDescription } from './read-only-policy.js';
|
|
4
|
+
import { LIST_REPOS_DEFAULT_LIMIT, LIST_REPOS_MAX_LIMIT } from './tools.js';
|
|
5
|
+
const CANONICAL_ALLOWED = 'GITNEXUS_MCP_ALLOWED_REPOS';
|
|
6
|
+
const CANONICAL_DEFAULT = 'GITNEXUS_MCP_DEFAULT_REPO';
|
|
7
|
+
function configuredValue(env, key) {
|
|
8
|
+
const value = env[key];
|
|
9
|
+
return value === undefined ? undefined : { key, value };
|
|
10
|
+
}
|
|
11
|
+
function parseRepositoryPolicy(env) {
|
|
12
|
+
const allowedRaw = configuredValue(env, CANONICAL_ALLOWED);
|
|
13
|
+
const defaultRaw = configuredValue(env, CANONICAL_DEFAULT);
|
|
14
|
+
let allowed;
|
|
15
|
+
if (allowedRaw) {
|
|
16
|
+
allowed = allowedRaw.value
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((entry) => entry.trim())
|
|
19
|
+
.filter(Boolean);
|
|
20
|
+
if (allowed.length === 0)
|
|
21
|
+
throw new Error(`${allowedRaw.key} must not be blank.`);
|
|
22
|
+
}
|
|
23
|
+
let defaultRepo;
|
|
24
|
+
if (defaultRaw) {
|
|
25
|
+
defaultRepo = defaultRaw.value.trim();
|
|
26
|
+
if (!defaultRepo)
|
|
27
|
+
throw new Error(`${defaultRaw.key} must not be blank.`);
|
|
28
|
+
}
|
|
29
|
+
return { allowed, defaultRepo };
|
|
30
|
+
}
|
|
31
|
+
function normalizedPath(value) {
|
|
32
|
+
const resolved = path.resolve(value);
|
|
33
|
+
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
34
|
+
}
|
|
35
|
+
function isAbsolutePath(value) {
|
|
36
|
+
return path.isAbsolute(value) || path.win32.isAbsolute(value);
|
|
37
|
+
}
|
|
38
|
+
function resolveSpecifier(specifier, registry) {
|
|
39
|
+
const trimmed = specifier.trim();
|
|
40
|
+
const matches = isAbsolutePath(trimmed)
|
|
41
|
+
? registry.filter((repo) => repo.pathKey === normalizedPath(trimmed))
|
|
42
|
+
: registry.filter((repo) => repo.name.toLowerCase() === trimmed.toLowerCase());
|
|
43
|
+
if (matches.length === 0)
|
|
44
|
+
return { reason: 'invalid' };
|
|
45
|
+
if (matches.length > 1)
|
|
46
|
+
return { reason: 'ambiguous' };
|
|
47
|
+
return { repo: matches[0] };
|
|
48
|
+
}
|
|
49
|
+
function startupResolutionError(reason) {
|
|
50
|
+
return new Error(reason === 'ambiguous'
|
|
51
|
+
? 'MCP repository configuration contains an ambiguous repository selection.'
|
|
52
|
+
: 'MCP repository configuration contains an invalid repository selection.');
|
|
53
|
+
}
|
|
54
|
+
function unavailableRepositoryError() {
|
|
55
|
+
return new Error('Repository is not available through this MCP server.');
|
|
56
|
+
}
|
|
57
|
+
export class McpRepositoryPolicy {
|
|
58
|
+
restricted;
|
|
59
|
+
configured;
|
|
60
|
+
registry;
|
|
61
|
+
allowed;
|
|
62
|
+
allowedPathKeys;
|
|
63
|
+
defaultRepo;
|
|
64
|
+
uniqueAllowedContextNames;
|
|
65
|
+
static unrestricted() {
|
|
66
|
+
return new McpRepositoryPolicy([], undefined, undefined);
|
|
67
|
+
}
|
|
68
|
+
constructor(registry, allowed, defaultRepo) {
|
|
69
|
+
this.registry = registry;
|
|
70
|
+
this.restricted = allowed !== undefined;
|
|
71
|
+
this.configured = this.restricted || defaultRepo !== undefined;
|
|
72
|
+
this.allowed = allowed ?? registry;
|
|
73
|
+
this.allowedPathKeys = new Set(this.allowed.map((repo) => repo.pathKey));
|
|
74
|
+
this.defaultRepo = defaultRepo;
|
|
75
|
+
const registryNameCounts = new Map();
|
|
76
|
+
for (const repo of registry) {
|
|
77
|
+
const name = repo.name.toLowerCase();
|
|
78
|
+
registryNameCounts.set(name, (registryNameCounts.get(name) ?? 0) + 1);
|
|
79
|
+
}
|
|
80
|
+
this.uniqueAllowedContextNames = new Set(this.allowed
|
|
81
|
+
.map((repo) => repo.name.toLowerCase())
|
|
82
|
+
.filter((name) => registryNameCounts.get(name) === 1));
|
|
83
|
+
}
|
|
84
|
+
resolveRuntimeRepo(specifier) {
|
|
85
|
+
const result = resolveSpecifier(specifier, this.registry);
|
|
86
|
+
if (!result.repo || (this.restricted && !this.allowedPathKeys.has(result.repo.pathKey))) {
|
|
87
|
+
throw unavailableRepositoryError();
|
|
88
|
+
}
|
|
89
|
+
return result.repo;
|
|
90
|
+
}
|
|
91
|
+
repoForArgs(args) {
|
|
92
|
+
const explicit = args?.repo;
|
|
93
|
+
if (explicit !== undefined) {
|
|
94
|
+
if (typeof explicit !== 'string')
|
|
95
|
+
throw unavailableRepositoryError();
|
|
96
|
+
if (explicit.trim().startsWith('@')) {
|
|
97
|
+
if (this.restricted) {
|
|
98
|
+
throw new Error('Group routing is unavailable when an MCP repository allowlist is set.');
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return this.resolveRuntimeRepo(explicit);
|
|
103
|
+
}
|
|
104
|
+
if (this.defaultRepo)
|
|
105
|
+
return this.defaultRepo;
|
|
106
|
+
if (this.restricted && this.allowed.length === 1)
|
|
107
|
+
return this.allowed[0];
|
|
108
|
+
if (this.restricted && this.allowed.length > 1) {
|
|
109
|
+
throw new Error('Specify an explicit repo because multiple repositories are allowed.');
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
normalizeToolArgs(args) {
|
|
114
|
+
if (!this.configured)
|
|
115
|
+
return args;
|
|
116
|
+
if (!this.restricted && args?.repo !== undefined)
|
|
117
|
+
return args;
|
|
118
|
+
const selected = this.repoForArgs(args);
|
|
119
|
+
if (!selected)
|
|
120
|
+
return args;
|
|
121
|
+
return { ...(args ?? {}), repo: selected.path };
|
|
122
|
+
}
|
|
123
|
+
async listAllowedRepos(backend) {
|
|
124
|
+
const current = await backend.listRepos();
|
|
125
|
+
if (!this.restricted)
|
|
126
|
+
return current;
|
|
127
|
+
return current
|
|
128
|
+
.filter((repo) => this.allowedPathKeys.has(normalizedPath(repo.path)))
|
|
129
|
+
.map((repo) => {
|
|
130
|
+
const siblings = repo.siblings?.filter((sibling) => this.allowedPathKeys.has(normalizedPath(sibling.path)));
|
|
131
|
+
return {
|
|
132
|
+
...repo,
|
|
133
|
+
siblings: siblings && siblings.length > 0 ? siblings : undefined,
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async listReposPage(backend, params) {
|
|
138
|
+
const { limit, offset } = parseListReposPagination(params, {
|
|
139
|
+
defaultLimit: LIST_REPOS_DEFAULT_LIMIT,
|
|
140
|
+
maxLimit: LIST_REPOS_MAX_LIMIT,
|
|
141
|
+
});
|
|
142
|
+
const repositories = await this.listAllowedRepos(backend);
|
|
143
|
+
repositories.sort((a, b) => {
|
|
144
|
+
const an = a.name.toLowerCase();
|
|
145
|
+
const bn = b.name.toLowerCase();
|
|
146
|
+
if (an !== bn)
|
|
147
|
+
return an < bn ? -1 : 1;
|
|
148
|
+
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
149
|
+
});
|
|
150
|
+
const total = repositories.length;
|
|
151
|
+
const page = repositories.slice(offset, offset + limit);
|
|
152
|
+
const returned = page.length;
|
|
153
|
+
const hasMore = offset + returned < total;
|
|
154
|
+
return {
|
|
155
|
+
repositories: page,
|
|
156
|
+
pagination: {
|
|
157
|
+
total,
|
|
158
|
+
limit,
|
|
159
|
+
offset,
|
|
160
|
+
returned,
|
|
161
|
+
hasMore,
|
|
162
|
+
...(hasMore && { nextOffset: offset + returned }),
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async callTool(backend, method, params) {
|
|
167
|
+
if (!this.configured)
|
|
168
|
+
return backend.callTool(method, params);
|
|
169
|
+
if (method === 'list_repos')
|
|
170
|
+
return this.listReposPage(backend, params);
|
|
171
|
+
if (this.restricted && method.startsWith('group_')) {
|
|
172
|
+
throw new Error('Group tools are unavailable when an MCP repository allowlist is set.');
|
|
173
|
+
}
|
|
174
|
+
return backend.callTool(method, this.normalizeToolArgs(params));
|
|
175
|
+
}
|
|
176
|
+
async resolveRepo(backend, repo, branch) {
|
|
177
|
+
if (!this.configured)
|
|
178
|
+
return backend.resolveRepo(repo, branch);
|
|
179
|
+
if (!this.restricted)
|
|
180
|
+
return backend.resolveRepo(repo ?? this.defaultRepo?.path, branch);
|
|
181
|
+
const selected = this.repoForArgs(repo === undefined ? undefined : { repo });
|
|
182
|
+
return backend.resolveRepo(selected?.path, branch);
|
|
183
|
+
}
|
|
184
|
+
assertResourceUri(uri) {
|
|
185
|
+
if (!this.restricted)
|
|
186
|
+
return;
|
|
187
|
+
let parsed;
|
|
188
|
+
try {
|
|
189
|
+
parsed = new URL(uri);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// resources.ts parses with the same URL call, so anything that fails
|
|
193
|
+
// here fails there too today. Keep obviously group- or repo-shaped
|
|
194
|
+
// malformed inputs fail-closed anyway in case the parsers ever drift.
|
|
195
|
+
if (/^gitnexus:\/\/group(?:\/|$)/iu.test(uri)) {
|
|
196
|
+
throw new Error('Group resources are unavailable when an MCP repository allowlist is set.');
|
|
197
|
+
}
|
|
198
|
+
const repoShaped = /^gitnexus:\/\/repo\/([^/]+)/iu.exec(uri);
|
|
199
|
+
if (repoShaped)
|
|
200
|
+
this.resolveRuntimeRepo(decodeURIComponent(repoShaped[1]));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// gitnexus: is a non-special URL scheme, so the host is opaque and NOT
|
|
204
|
+
// lowercased by the parser — compare case-insensitively like
|
|
205
|
+
// read-only-policy.ts does.
|
|
206
|
+
if (parsed.protocol.toLowerCase() !== 'gitnexus:')
|
|
207
|
+
return;
|
|
208
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
209
|
+
if (hostname === 'group') {
|
|
210
|
+
throw new Error('Group resources are unavailable when an MCP repository allowlist is set.');
|
|
211
|
+
}
|
|
212
|
+
if (hostname !== 'repo')
|
|
213
|
+
return;
|
|
214
|
+
const repoName = parsed.pathname.split('/').filter(Boolean)[0];
|
|
215
|
+
if (!repoName)
|
|
216
|
+
return;
|
|
217
|
+
this.resolveRuntimeRepo(decodeURIComponent(repoName));
|
|
218
|
+
}
|
|
219
|
+
resourceTemplateAllowed(uriTemplate) {
|
|
220
|
+
return !this.restricted || !uriTemplate.startsWith('gitnexus://group/');
|
|
221
|
+
}
|
|
222
|
+
toolAllowed(toolName) {
|
|
223
|
+
return !this.restricted || !toolName.startsWith('group_');
|
|
224
|
+
}
|
|
225
|
+
toolForMcp(tool) {
|
|
226
|
+
if (!this.restricted)
|
|
227
|
+
return tool;
|
|
228
|
+
const properties = { ...tool.inputSchema.properties };
|
|
229
|
+
const repo = properties.repo;
|
|
230
|
+
if (repo && typeof repo === 'object') {
|
|
231
|
+
properties.repo = {
|
|
232
|
+
...repo,
|
|
233
|
+
description: 'Allowed indexed repository name or path. Group-mode values are unavailable.',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
delete properties.subgroup;
|
|
237
|
+
delete properties.crossDepth;
|
|
238
|
+
const description = scrubGroupDescription(tool.description);
|
|
239
|
+
return { ...tool, description, inputSchema: { ...tool.inputSchema, properties } };
|
|
240
|
+
}
|
|
241
|
+
scopeBackend(backend) {
|
|
242
|
+
const policy = this;
|
|
243
|
+
return new Proxy(backend, {
|
|
244
|
+
get(target, property, receiver) {
|
|
245
|
+
if (property === 'callTool') {
|
|
246
|
+
return (method, params) => policy.callTool(target, method, params);
|
|
247
|
+
}
|
|
248
|
+
if (property === 'listRepos')
|
|
249
|
+
return () => policy.listAllowedRepos(target);
|
|
250
|
+
if (property === 'resolveRepo') {
|
|
251
|
+
return (repo, branch) => policy.resolveRepo(target, repo, branch);
|
|
252
|
+
}
|
|
253
|
+
if (property === 'getContext' && policy.restricted) {
|
|
254
|
+
return (repoId) => {
|
|
255
|
+
if (!repoId || !policy.uniqueAllowedContextNames.has(repoId.toLowerCase()))
|
|
256
|
+
return null;
|
|
257
|
+
return target.getContext(repoId);
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
if (policy.restricted &&
|
|
261
|
+
(property === 'readGroupContractsResource' || property === 'readGroupStatusResource')) {
|
|
262
|
+
return async () => {
|
|
263
|
+
throw new Error('Group resources are unavailable when an MCP repository allowlist is set.');
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
// Repo-scoped resource reads must not depend on assertResourceUri
|
|
267
|
+
// running first — enforce the allowlist on the query surface too.
|
|
268
|
+
if (policy.restricted && (property === 'queryClusters' || property === 'queryProcesses')) {
|
|
269
|
+
return (repoName, limit) => {
|
|
270
|
+
const selected = policy.repoForArgs(repoName === undefined ? undefined : { repo: repoName });
|
|
271
|
+
return property === 'queryClusters'
|
|
272
|
+
? target.queryClusters(selected?.path ?? repoName, limit)
|
|
273
|
+
: target.queryProcesses(selected?.path ?? repoName, limit);
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
if (policy.restricted &&
|
|
277
|
+
(property === 'queryClusterDetail' || property === 'queryProcessDetail')) {
|
|
278
|
+
return (name, repoName) => {
|
|
279
|
+
const selected = policy.repoForArgs(repoName === undefined ? undefined : { repo: repoName });
|
|
280
|
+
return property === 'queryClusterDetail'
|
|
281
|
+
? target.queryClusterDetail(name, selected?.path ?? repoName)
|
|
282
|
+
: target.queryProcessDetail(name, selected?.path ?? repoName);
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const value = Reflect.get(target, property, receiver);
|
|
286
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
export function mcpRepositoryPolicyConfigured(env = process.env) {
|
|
292
|
+
const raw = parseRepositoryPolicy(env);
|
|
293
|
+
return raw.allowed !== undefined || raw.defaultRepo !== undefined;
|
|
294
|
+
}
|
|
295
|
+
export async function createMcpRepositoryPolicy(backend, env = process.env) {
|
|
296
|
+
const raw = parseRepositoryPolicy(env);
|
|
297
|
+
if (!raw.allowed && !raw.defaultRepo) {
|
|
298
|
+
return McpRepositoryPolicy.unrestricted();
|
|
299
|
+
}
|
|
300
|
+
const registry = (await backend.listRepos()).map((repo) => ({
|
|
301
|
+
name: repo.name,
|
|
302
|
+
path: repo.path,
|
|
303
|
+
pathKey: normalizedPath(repo.path),
|
|
304
|
+
}));
|
|
305
|
+
let allowed;
|
|
306
|
+
if (raw.allowed) {
|
|
307
|
+
const byPath = new Map();
|
|
308
|
+
for (const specifier of raw.allowed) {
|
|
309
|
+
const result = resolveSpecifier(specifier, registry);
|
|
310
|
+
if (!result.repo)
|
|
311
|
+
throw startupResolutionError(result.reason ?? 'invalid');
|
|
312
|
+
byPath.set(result.repo.pathKey, result.repo);
|
|
313
|
+
}
|
|
314
|
+
allowed = [...byPath.values()];
|
|
315
|
+
}
|
|
316
|
+
let defaultRepo;
|
|
317
|
+
if (raw.defaultRepo) {
|
|
318
|
+
const result = resolveSpecifier(raw.defaultRepo, registry);
|
|
319
|
+
if (!result.repo)
|
|
320
|
+
throw startupResolutionError(result.reason ?? 'invalid');
|
|
321
|
+
defaultRepo = result.repo;
|
|
322
|
+
}
|
|
323
|
+
const defaultPathKey = defaultRepo?.pathKey;
|
|
324
|
+
if (defaultPathKey && allowed && !allowed.some((repo) => repo.pathKey === defaultPathKey)) {
|
|
325
|
+
throw new Error('The MCP default repository is not in the configured allowlist.');
|
|
326
|
+
}
|
|
327
|
+
return new McpRepositoryPolicy(registry, allowed, defaultRepo);
|
|
328
|
+
}
|
package/dist/mcp/resources.js
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* All resources use repo-scoped URIs: gitnexus://repo/{name}/context
|
|
6
6
|
*/
|
|
7
7
|
import { checkStaleness } from './staleness.js';
|
|
8
|
+
import { loadMeta } from '../storage/repo-manager.js';
|
|
9
|
+
import { ANALYZER_RUNNER_IDENTITY_SCHEMA_VERSION } from '../core/analyzer-identity.js';
|
|
10
|
+
import { getIndexIncompleteReasons } from '../core/index-freshness.js';
|
|
8
11
|
/**
|
|
9
12
|
* Static resources — includes per-repo resources and the global repos list
|
|
10
13
|
*/
|
|
@@ -249,9 +252,16 @@ async function getContextResource(backend, repoName) {
|
|
|
249
252
|
if (!context) {
|
|
250
253
|
return 'error: No codebase loaded. Run: gitnexus analyze';
|
|
251
254
|
}
|
|
252
|
-
//
|
|
255
|
+
// Read fresh metadata from disk on every context resource read to avoid showing
|
|
256
|
+
// a stale staleness banner or outdated stats after an out-of-process
|
|
257
|
+
// `analyze --index-only` refresh. The RepoHandle is cached in-memory and only
|
|
258
|
+
// refreshes on registry misses, so its lastCommit/stats can lag behind the
|
|
259
|
+
// on-disk state (#2438). Mirrors the ensureInitialized hot-swap pattern.
|
|
260
|
+
const freshMeta = await loadMeta(repo.storagePath).catch(() => null);
|
|
261
|
+
const incompleteReasons = getIndexIncompleteReasons(freshMeta);
|
|
262
|
+
// Check staleness using the current on-disk lastCommit (not the cached handle)
|
|
253
263
|
const repoPath = repo.repoPath;
|
|
254
|
-
const lastCommit = repo.lastCommit
|
|
264
|
+
const lastCommit = freshMeta?.lastCommit ?? repo.lastCommit ?? 'HEAD';
|
|
255
265
|
const staleness = repoPath
|
|
256
266
|
? checkStaleness(repoPath, lastCommit)
|
|
257
267
|
: { isStale: false, commitsBehind: 0 };
|
|
@@ -260,11 +270,27 @@ async function getContextResource(backend, repoName) {
|
|
|
260
270
|
lines.push('');
|
|
261
271
|
lines.push(`staleness: "${staleness.hint}"`);
|
|
262
272
|
}
|
|
273
|
+
// A JSON object is also a valid YAML flow mapping. Keeping the versioned
|
|
274
|
+
// receipt intact lets agents compare every identity field without parsing a
|
|
275
|
+
// lossy human rendering; null explicitly means legacy/unknown provenance.
|
|
276
|
+
lines.push('');
|
|
277
|
+
lines.push('index:');
|
|
278
|
+
lines.push(` commit: ${JSON.stringify(lastCommit)}`);
|
|
279
|
+
lines.push(` indexed_at: ${JSON.stringify(freshMeta?.indexedAt ?? null)}`);
|
|
280
|
+
lines.push(` runner_identity: ${JSON.stringify(freshMeta?.runnerIdentity ?? null)}`);
|
|
281
|
+
lines.push(` incomplete_reasons: ${JSON.stringify(incompleteReasons)}`);
|
|
282
|
+
const indexedRunnerSchema = freshMeta?.runnerIdentity
|
|
283
|
+
?.schemaVersion;
|
|
284
|
+
lines.push(` runner_identity_schema_status: ${JSON.stringify(indexedRunnerSchema === ANALYZER_RUNNER_IDENTITY_SCHEMA_VERSION
|
|
285
|
+
? 'current'
|
|
286
|
+
: 'legacy-or-unknown')}`);
|
|
287
|
+
// Use fresh stats from disk meta when available; fall back to cached context
|
|
288
|
+
const freshStats = freshMeta?.stats;
|
|
263
289
|
lines.push('');
|
|
264
290
|
lines.push('stats:');
|
|
265
|
-
lines.push(` files: ${context.stats.fileCount}`);
|
|
266
|
-
lines.push(` symbols: ${context.stats.functionCount}`);
|
|
267
|
-
lines.push(` processes: ${context.stats.processCount}`);
|
|
291
|
+
lines.push(` files: ${freshStats?.files ?? context.stats.fileCount}`);
|
|
292
|
+
lines.push(` symbols: ${freshStats?.nodes ?? context.stats.functionCount}`);
|
|
293
|
+
lines.push(` processes: ${freshStats?.processes ?? context.stats.processCount}`);
|
|
268
294
|
lines.push('');
|
|
269
295
|
lines.push('tools_available:');
|
|
270
296
|
lines.push(' - query: Process-grouped code intelligence (execution flows related to a concept)');
|
|
@@ -365,6 +391,7 @@ additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Nam
|
|
|
365
391
|
|
|
366
392
|
node_properties:
|
|
367
393
|
common: "name (STRING), filePath (STRING), startLine (INT32), endLine (INT32)"
|
|
394
|
+
line_numbers: "startLine/endLine on symbol nodes are 0-BASED (tree-sitter rows) in storage AND in raw Cypher results. The context, query, impact, group/cross-repo trace, and explain/pdg_query (symbol anchor) tools present them 1-BASED (editor / sed / less -N aligned), so a symbol spans editor lines (startLine+1)..(endLine+1) — e.g. sed '<startLine+1>,<endLine+1>!d' <file>. Single-repo trace symbol lines stay 0-BASED for now (full-parity follow-up). content holds the exact symbol span. (BasicBlock / PDG statement lines are separately 1-based.) (#2377, #2380)"
|
|
368
395
|
Method: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isVirtual (BOOL), isOverride (BOOL), isAsync (BOOL), isPartial (BOOL), requiredParameterCount (INT32), parameterTypes (STRING[]), annotations (STRING[])"
|
|
369
396
|
Function: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isAsync (BOOL), parameterTypes (STRING[]), annotations (STRING[])"
|
|
370
397
|
Property: "declaredType (STRING) — the field's type annotation (e.g., 'Address', 'City'). Used for field-access chain resolution."
|