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
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin facts → graph mapper.
|
|
3
|
+
*
|
|
4
|
+
* Consumes the move-flow `facts` query response (the compiler's full-fidelity,
|
|
5
|
+
* per-module structured facts) and produces standard GraphNode / GraphRelationship
|
|
6
|
+
* objects. This is the heart of the compiler-first Move ingestion: there is
|
|
7
|
+
* **no raw-source scanning** — every fact (visibility, entry/view, attributes,
|
|
8
|
+
* acquires, resource reads/writes, enum variants, friends, locations) comes
|
|
9
|
+
* straight from move-flow.
|
|
10
|
+
*/
|
|
11
|
+
import { moveModuleNodeId, moveFunctionNodeId, moveStructNodeId, moveEnumNodeId, moveConstNodeId, moveEnumVariantNodeId, moveFieldNodeId, moveLocalName, moveRelId, parseMoveLambdaHostName, parseMoveModuleQualifiedName, } from './symbol-id.js';
|
|
12
|
+
import { ERROR_CODE_PATTERN, MOVE_ABILITY, MOVE_ATTR, MOVE_EDGE_REASON, MOVE_LANGUAGE, moveRepoRelativePath, } from './constants.js';
|
|
13
|
+
import { extractTypeNames } from './type-parser.js';
|
|
14
|
+
import { toZeroBasedLine } from '../ingestion/utils/line-base.js';
|
|
15
|
+
const spanLine = (span, idx) => span ? toZeroBasedLine(span[idx]) : undefined;
|
|
16
|
+
/** Strip generic type arguments: `CoinStore<CoinType>` → `CoinStore`. */
|
|
17
|
+
function stripTypeArgs(typeName) {
|
|
18
|
+
const idx = typeName.indexOf('<');
|
|
19
|
+
return (idx === -1 ? typeName : typeName.slice(0, idx)).trim();
|
|
20
|
+
}
|
|
21
|
+
/** Defensive: move-flow omits optional array fields for some symbols. */
|
|
22
|
+
function arr(value) {
|
|
23
|
+
return Array.isArray(value) ? value : [];
|
|
24
|
+
}
|
|
25
|
+
function typeParamsJson(typeParams) {
|
|
26
|
+
const list = arr(typeParams).map((tp) => ({
|
|
27
|
+
name: tp.name,
|
|
28
|
+
constraints: arr(tp.abilities),
|
|
29
|
+
isPhantom: tp.isPhantom,
|
|
30
|
+
}));
|
|
31
|
+
return JSON.stringify(list);
|
|
32
|
+
}
|
|
33
|
+
function attributeNames(attributes) {
|
|
34
|
+
return arr(attributes).map((a) => a.name);
|
|
35
|
+
}
|
|
36
|
+
/** Full attribute payload (nested `args` / assignment `value`s) as JSON;
|
|
37
|
+
* undefined (not `"[]"`) when the symbol carries no attributes. */
|
|
38
|
+
function attributesJson(attributes) {
|
|
39
|
+
const list = arr(attributes);
|
|
40
|
+
return list.length > 0 ? JSON.stringify(list) : undefined;
|
|
41
|
+
}
|
|
42
|
+
/** `#[resource_group_member(group = <qualified struct>)]` -> the group struct ref. */
|
|
43
|
+
function resourceGroupOf(attributes) {
|
|
44
|
+
for (const a of arr(attributes)) {
|
|
45
|
+
if (a.name !== MOVE_ATTR.RESOURCE_GROUP_MEMBER)
|
|
46
|
+
continue;
|
|
47
|
+
for (const groupArg of arr(a.args)) {
|
|
48
|
+
if (groupArg.name === 'group' && typeof groupArg.value === 'string') {
|
|
49
|
+
return groupArg.value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Scalar projection of `returnTypes` for the lbug `returnType` STRING column:
|
|
57
|
+
* `[]` -> undefined, single -> the element, tuple -> `'(a, b)'`.
|
|
58
|
+
*/
|
|
59
|
+
function returnTypeProjection(returnTypes) {
|
|
60
|
+
if (returnTypes.length === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
return returnTypes.length === 1 ? returnTypes[0] : `(${returnTypes.join(', ')})`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Boundary shape sentinel: reject the legacy scalar `returnType` shape. The
|
|
66
|
+
* mapper requires `returnTypes: string[]`; silently mapping the old scalar
|
|
67
|
+
* `returnType` would drop every return-type fact, so hard-fail with an
|
|
68
|
+
* operator-actionable upgrade message. The shape is uniform across a payload,
|
|
69
|
+
* so the first function encountered decides for all of them.
|
|
70
|
+
*/
|
|
71
|
+
function assertFactsShape(facts) {
|
|
72
|
+
for (const mod of Object.values(facts)) {
|
|
73
|
+
for (const fn of arr(mod.functions)) {
|
|
74
|
+
if (!Array.isArray(fn.returnTypes) && 'returnType' in fn) {
|
|
75
|
+
throw Object.assign(new Error('move-flow returned the legacy scalar `returnType` facts shape - upgrade ' +
|
|
76
|
+
'move-flow to a build that emits `returnTypes: string[]` (>=2.0.0).'), { userActionable: true });
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Map a full `facts` response (covering every module in a package) to graph
|
|
84
|
+
* nodes + edges. `packageRoot` is used only as a location fallback when the
|
|
85
|
+
* compiler omits a per-symbol file (it never does today, but the field is
|
|
86
|
+
* optional in the schema). When `repoPath` is given, absolute file paths from
|
|
87
|
+
* the compiler are made repo-relative so node IDs align with `File:` nodes.
|
|
88
|
+
*/
|
|
89
|
+
export function mapFactsToGraph(facts, packageRoot, repoPath) {
|
|
90
|
+
assertFactsShape(facts);
|
|
91
|
+
const nodes = [];
|
|
92
|
+
const edges = [];
|
|
93
|
+
const moduleFileMap = new Map();
|
|
94
|
+
const functionNodeMap = new Map();
|
|
95
|
+
const structNodeMap = new Map();
|
|
96
|
+
const edge = (sourceId, targetId, type, confidence, reason) => {
|
|
97
|
+
edges.push({
|
|
98
|
+
id: moveRelId(sourceId, type, targetId, reason),
|
|
99
|
+
sourceId,
|
|
100
|
+
targetId,
|
|
101
|
+
type,
|
|
102
|
+
confidence,
|
|
103
|
+
reason,
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
// Deferred work that needs the full struct/module index (pass B).
|
|
107
|
+
const pendingResource = [];
|
|
108
|
+
const pendingFriends = [];
|
|
109
|
+
const pendingTypeRef = [];
|
|
110
|
+
const pendingLambdaHosts = [];
|
|
111
|
+
// ── Pass A: nodes (modules, functions, types, constants) ─────────────────
|
|
112
|
+
for (const [moduleQualified, mod] of Object.entries(facts)) {
|
|
113
|
+
const moduleFileAbs = mod.file ?? packageRoot;
|
|
114
|
+
const file = moveRepoRelativePath(moduleFileAbs, repoPath);
|
|
115
|
+
const { address, moduleName } = parseMoveModuleQualifiedName(moduleQualified);
|
|
116
|
+
moduleFileMap.set(moduleQualified, file);
|
|
117
|
+
const moduleNodeId = moveModuleNodeId(moduleQualified, file);
|
|
118
|
+
nodes.push({
|
|
119
|
+
id: moduleNodeId,
|
|
120
|
+
label: 'Module',
|
|
121
|
+
properties: {
|
|
122
|
+
name: moduleName,
|
|
123
|
+
filePath: file,
|
|
124
|
+
language: MOVE_LANGUAGE,
|
|
125
|
+
qualifiedName: moduleQualified,
|
|
126
|
+
moduleQualifiedName: moduleQualified,
|
|
127
|
+
moduleAddress: address,
|
|
128
|
+
startLine: spanLine(mod.span, 0),
|
|
129
|
+
endLine: spanLine(mod.span, 1),
|
|
130
|
+
attributes: attributeNames(mod.attributes),
|
|
131
|
+
attributesJson: attributesJson(mod.attributes),
|
|
132
|
+
locationFidelity: mod.file ? 'precise' : 'package',
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
for (const friend of arr(mod.friends)) {
|
|
136
|
+
pendingFriends.push({ moduleNodeId, friend: friend.module });
|
|
137
|
+
}
|
|
138
|
+
// Functions
|
|
139
|
+
for (const fn of arr(mod.functions)) {
|
|
140
|
+
const fnQualified = `${moduleQualified}::${fn.name}`;
|
|
141
|
+
const fnFile = moveRepoRelativePath(fn.file ?? moduleFileAbs, repoPath);
|
|
142
|
+
const fnNodeId = moveFunctionNodeId(fnQualified, fnFile);
|
|
143
|
+
functionNodeMap.set(fnQualified, fnNodeId);
|
|
144
|
+
const attrs = attributeNames(fn.attributes);
|
|
145
|
+
const seenTypeRefs = new Set();
|
|
146
|
+
// Skip the function's own type parameters (e.g. `CoinType`): they are not
|
|
147
|
+
// nominal types and would create spurious USES_TYPE edges.
|
|
148
|
+
const fnTypeParamNames = new Set(arr(fn.typeParams).map((tp) => tp.name));
|
|
149
|
+
const addSignatureTypes = (typeExpr, reason) => {
|
|
150
|
+
if (!typeExpr)
|
|
151
|
+
return;
|
|
152
|
+
for (const typeName of extractTypeNames(typeExpr)) {
|
|
153
|
+
if (fnTypeParamNames.has(typeName))
|
|
154
|
+
continue;
|
|
155
|
+
const key = `${reason}\0${typeName}`;
|
|
156
|
+
if (seenTypeRefs.has(key))
|
|
157
|
+
continue;
|
|
158
|
+
seenTypeRefs.add(key);
|
|
159
|
+
pendingTypeRef.push({
|
|
160
|
+
sourceNodeId: fnNodeId,
|
|
161
|
+
moduleQualified,
|
|
162
|
+
target: typeName,
|
|
163
|
+
reason,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
for (const p of arr(fn.params)) {
|
|
168
|
+
addSignatureTypes(p.type, MOVE_EDGE_REASON.fnParamType);
|
|
169
|
+
}
|
|
170
|
+
for (const rt of arr(fn.returnTypes)) {
|
|
171
|
+
addSignatureTypes(rt, MOVE_EDGE_REASON.fnReturnType);
|
|
172
|
+
}
|
|
173
|
+
const fnProps = {
|
|
174
|
+
name: fn.name,
|
|
175
|
+
filePath: fnFile,
|
|
176
|
+
language: MOVE_LANGUAGE,
|
|
177
|
+
qualifiedName: fnQualified,
|
|
178
|
+
moduleQualifiedName: moduleQualified,
|
|
179
|
+
startLine: spanLine(fn.span, 0),
|
|
180
|
+
endLine: spanLine(fn.span, 1),
|
|
181
|
+
visibility: fn.visibility === 'internal' ? 'private' : fn.visibility,
|
|
182
|
+
visibilityModifier: fn.visibility,
|
|
183
|
+
isEntry: fn.isEntry,
|
|
184
|
+
isView: fn.isView,
|
|
185
|
+
isInline: fn.isInline,
|
|
186
|
+
isNative: fn.isNative,
|
|
187
|
+
attributes: attrs,
|
|
188
|
+
attributesJson: attributesJson(fn.attributes),
|
|
189
|
+
typeParamsJson: typeParamsJson(fn.typeParams),
|
|
190
|
+
acquires: arr(fn.acquiresInferred),
|
|
191
|
+
usedTypes: [],
|
|
192
|
+
returnType: returnTypeProjection(arr(fn.returnTypes)),
|
|
193
|
+
parameterCount: arr(fn.params).length,
|
|
194
|
+
locationFidelity: fn.file ? 'precise' : 'package',
|
|
195
|
+
};
|
|
196
|
+
// Lambda → host link queued for Pass 2 (host fn node may not yet exist
|
|
197
|
+
// when this lambda is mapped). The canonical Cypher path for "is this a
|
|
198
|
+
// lambda?" is the inbound CALLS edge with reason 'move-lambda-of-host';
|
|
199
|
+
// we do not project an `isLambda` boolean property because the lbug
|
|
200
|
+
// Function table does not carry it. move-flow reports the host explicitly
|
|
201
|
+
// via `definedIn` (resolved through nested closures); the
|
|
202
|
+
// `__lambda__N__<host>` name parse remains as fallback.
|
|
203
|
+
const lambdaHostLocal = (fn.isLambdaLifted ? fn.definedIn : undefined) ?? parseMoveLambdaHostName(fn.name);
|
|
204
|
+
if (lambdaHostLocal) {
|
|
205
|
+
pendingLambdaHosts.push({
|
|
206
|
+
lambdaFnNodeId: fnNodeId,
|
|
207
|
+
hostQualified: `${moduleQualified}::${lambdaHostLocal}`,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
nodes.push({
|
|
211
|
+
id: fnNodeId,
|
|
212
|
+
label: 'Function',
|
|
213
|
+
properties: fnProps,
|
|
214
|
+
});
|
|
215
|
+
edge(moduleNodeId, fnNodeId, 'DEFINES', 1.0, MOVE_EDGE_REASON.definesFunction);
|
|
216
|
+
for (const r of arr(fn.resourceAccess?.reads)) {
|
|
217
|
+
pendingResource.push({
|
|
218
|
+
fnNodeId,
|
|
219
|
+
moduleQualified,
|
|
220
|
+
type: 'READS_RESOURCE',
|
|
221
|
+
target: stripTypeArgs(r),
|
|
222
|
+
reason: MOVE_EDGE_REASON.readsResource,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
for (const w of arr(fn.resourceAccess?.writes)) {
|
|
226
|
+
pendingResource.push({
|
|
227
|
+
fnNodeId,
|
|
228
|
+
moduleQualified,
|
|
229
|
+
type: 'WRITES_RESOURCE',
|
|
230
|
+
target: stripTypeArgs(w),
|
|
231
|
+
reason: MOVE_EDGE_REASON.writesResource,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
for (const a of arr(fn.acquiresInferred)) {
|
|
235
|
+
pendingResource.push({
|
|
236
|
+
fnNodeId,
|
|
237
|
+
moduleQualified,
|
|
238
|
+
type: 'ACQUIRES',
|
|
239
|
+
target: a,
|
|
240
|
+
reason: MOVE_EDGE_REASON.acquires,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Types (structs + enums)
|
|
245
|
+
for (const ty of arr(mod.structs)) {
|
|
246
|
+
const tyQualified = `${moduleQualified}::${ty.name}`;
|
|
247
|
+
const tyFile = moveRepoRelativePath(ty.file ?? moduleFileAbs, repoPath);
|
|
248
|
+
const attrs = attributeNames(ty.attributes);
|
|
249
|
+
if (ty.kind === 'struct') {
|
|
250
|
+
const structNodeId = moveStructNodeId(tyQualified, tyFile);
|
|
251
|
+
structNodeMap.set(tyQualified, structNodeId);
|
|
252
|
+
nodes.push({
|
|
253
|
+
id: structNodeId,
|
|
254
|
+
label: 'Struct',
|
|
255
|
+
properties: {
|
|
256
|
+
name: ty.name,
|
|
257
|
+
filePath: tyFile,
|
|
258
|
+
language: MOVE_LANGUAGE,
|
|
259
|
+
qualifiedName: tyQualified,
|
|
260
|
+
moduleQualifiedName: moduleQualified,
|
|
261
|
+
moduleAddress: address,
|
|
262
|
+
startLine: spanLine(ty.span, 0),
|
|
263
|
+
endLine: spanLine(ty.span, 1),
|
|
264
|
+
abilities: arr(ty.abilities),
|
|
265
|
+
isResource: arr(ty.abilities).includes(MOVE_ABILITY.KEY),
|
|
266
|
+
isEvent: attrs.includes(MOVE_ATTR.EVENT),
|
|
267
|
+
attributes: attrs,
|
|
268
|
+
attributesJson: attributesJson(ty.attributes),
|
|
269
|
+
typeParamsJson: typeParamsJson(ty.typeParams),
|
|
270
|
+
fields: (ty.fields ?? []).map((f) => ({
|
|
271
|
+
name: f.name,
|
|
272
|
+
type: f.type,
|
|
273
|
+
positional: f.positional,
|
|
274
|
+
})),
|
|
275
|
+
// STRING[] projection persisted to lbug (`fieldList` column).
|
|
276
|
+
fieldList: (ty.fields ?? []).map((f) => `${f.name}: ${f.type}`),
|
|
277
|
+
moveDeclarationKind: 'struct',
|
|
278
|
+
locationFidelity: ty.file ? 'precise' : 'package',
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
edge(moduleNodeId, structNodeId, 'DEFINES', 1.0, MOVE_EDGE_REASON.definesStruct);
|
|
282
|
+
// `#[resource_group_member(group = ...)]` carries an exact qualified
|
|
283
|
+
// struct ref (e.g. '0xa::vault::Group') - queue a membership USES_TYPE
|
|
284
|
+
// edge resolved against the cross-package type index in Pass B.
|
|
285
|
+
const resourceGroup = resourceGroupOf(ty.attributes);
|
|
286
|
+
if (resourceGroup) {
|
|
287
|
+
pendingTypeRef.push({
|
|
288
|
+
sourceNodeId: structNodeId,
|
|
289
|
+
moduleQualified,
|
|
290
|
+
target: resourceGroup,
|
|
291
|
+
reason: MOVE_EDGE_REASON.resourceGroupMember,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
// Per-field Property nodes + HAS_PROPERTY edges so ACCESSES queries and
|
|
295
|
+
// field-level taint can target individual fields. The composite name +
|
|
296
|
+
// type live on the Struct as a `fields` array projection, but only the
|
|
297
|
+
// per-field nodes let Cypher join on `(:Struct)-[:HAS_PROPERTY]->(:Property)`.
|
|
298
|
+
for (const field of arr(ty.fields)) {
|
|
299
|
+
const propId = moveFieldNodeId(tyQualified, field.name, tyFile);
|
|
300
|
+
nodes.push({
|
|
301
|
+
id: propId,
|
|
302
|
+
label: 'Property',
|
|
303
|
+
properties: {
|
|
304
|
+
name: field.name,
|
|
305
|
+
filePath: tyFile,
|
|
306
|
+
language: MOVE_LANGUAGE,
|
|
307
|
+
qualifiedName: `${tyQualified}.${field.name}`,
|
|
308
|
+
parentStruct: tyQualified,
|
|
309
|
+
moduleQualifiedName: moduleQualified,
|
|
310
|
+
declaredType: field.type,
|
|
311
|
+
positional: field.positional,
|
|
312
|
+
startLine: spanLine(ty.span, 0),
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
edge(structNodeId, propId, 'HAS_PROPERTY', 1.0, MOVE_EDGE_REASON.hasField);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
const eId = moveEnumNodeId(tyQualified, tyFile);
|
|
320
|
+
structNodeMap.set(tyQualified, eId);
|
|
321
|
+
nodes.push({
|
|
322
|
+
id: eId,
|
|
323
|
+
label: 'Enum',
|
|
324
|
+
properties: {
|
|
325
|
+
name: ty.name,
|
|
326
|
+
filePath: tyFile,
|
|
327
|
+
language: MOVE_LANGUAGE,
|
|
328
|
+
qualifiedName: tyQualified,
|
|
329
|
+
moduleQualifiedName: moduleQualified,
|
|
330
|
+
moduleAddress: address,
|
|
331
|
+
startLine: spanLine(ty.span, 0),
|
|
332
|
+
endLine: spanLine(ty.span, 1),
|
|
333
|
+
abilities: arr(ty.abilities),
|
|
334
|
+
isResource: arr(ty.abilities).includes(MOVE_ABILITY.KEY),
|
|
335
|
+
isEvent: attrs.includes(MOVE_ATTR.EVENT),
|
|
336
|
+
attributes: attrs,
|
|
337
|
+
attributesJson: attributesJson(ty.attributes),
|
|
338
|
+
typeParamsJson: typeParamsJson(ty.typeParams),
|
|
339
|
+
moveDeclarationKind: 'enum',
|
|
340
|
+
locationFidelity: ty.file ? 'precise' : 'package',
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
edge(moduleNodeId, eId, 'DEFINES', 1.0, MOVE_EDGE_REASON.definesEnum);
|
|
344
|
+
for (const variant of arr(ty.variants)) {
|
|
345
|
+
const vId = moveEnumVariantNodeId(tyQualified, variant.name, tyFile);
|
|
346
|
+
nodes.push({
|
|
347
|
+
id: vId,
|
|
348
|
+
label: 'EnumVariant',
|
|
349
|
+
properties: {
|
|
350
|
+
name: variant.name,
|
|
351
|
+
filePath: tyFile,
|
|
352
|
+
language: MOVE_LANGUAGE,
|
|
353
|
+
qualifiedName: `${tyQualified}::${variant.name}`,
|
|
354
|
+
parentEnum: tyQualified,
|
|
355
|
+
moduleQualifiedName: moduleQualified,
|
|
356
|
+
variantKind: variant.kind,
|
|
357
|
+
fieldsJson: JSON.stringify(arr(variant.fields).map((f) => ({
|
|
358
|
+
name: f.name,
|
|
359
|
+
type: f.type,
|
|
360
|
+
positional: f.positional,
|
|
361
|
+
}))),
|
|
362
|
+
attributes: attributeNames(variant.attributes),
|
|
363
|
+
attributesJson: attributesJson(variant.attributes),
|
|
364
|
+
locationFidelity: ty.file ? 'module' : 'package',
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
edge(eId, vId, 'CONTAINS', 1.0, MOVE_EDGE_REASON.containsVariant);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// Constants
|
|
372
|
+
for (const c of arr(mod.constants)) {
|
|
373
|
+
const cQualified = `${moduleQualified}::${c.name}`;
|
|
374
|
+
const cNodeId = moveConstNodeId(cQualified, file);
|
|
375
|
+
nodes.push({
|
|
376
|
+
id: cNodeId,
|
|
377
|
+
label: 'Const',
|
|
378
|
+
properties: {
|
|
379
|
+
name: c.name,
|
|
380
|
+
filePath: file,
|
|
381
|
+
language: MOVE_LANGUAGE,
|
|
382
|
+
qualifiedName: cQualified,
|
|
383
|
+
moduleQualifiedName: moduleQualified,
|
|
384
|
+
constType: c.type,
|
|
385
|
+
constValue: c.value,
|
|
386
|
+
isErrorCode: ERROR_CODE_PATTERN.test(c.name),
|
|
387
|
+
locationFidelity: mod.file ? 'module' : 'package',
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
edge(moduleNodeId, cNodeId, 'DEFINES', 1.0, MOVE_EDGE_REASON.definesConst);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
nodes,
|
|
395
|
+
edges,
|
|
396
|
+
moduleFileMap,
|
|
397
|
+
functionNodeMap,
|
|
398
|
+
structNodeMap,
|
|
399
|
+
pendingResource,
|
|
400
|
+
pendingFriends,
|
|
401
|
+
pendingTypeRef,
|
|
402
|
+
pendingLambdaHosts,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Resolve queued lambda→host links into CALLS edges. Run after every package's
|
|
407
|
+
* facts have been mapped so the host's Function node is guaranteed to exist
|
|
408
|
+
* (the host may be defined in a different module within the package, or — for
|
|
409
|
+
* cross-package lambda capture — in another package altogether).
|
|
410
|
+
*/
|
|
411
|
+
export function resolveLambdaHostEdges(pendingLambdaHosts, functionNodeMap, edgeSink) {
|
|
412
|
+
const seen = new Set();
|
|
413
|
+
for (const p of pendingLambdaHosts) {
|
|
414
|
+
const hostId = functionNodeMap.get(p.hostQualified);
|
|
415
|
+
if (!hostId)
|
|
416
|
+
continue;
|
|
417
|
+
const key = `${hostId}\0${p.lambdaFnNodeId}`;
|
|
418
|
+
if (seen.has(key))
|
|
419
|
+
continue;
|
|
420
|
+
seen.add(key);
|
|
421
|
+
edgeSink({
|
|
422
|
+
id: moveRelId(hostId, 'CALLS', p.lambdaFnNodeId, MOVE_EDGE_REASON.lambdaHost),
|
|
423
|
+
sourceId: hostId,
|
|
424
|
+
targetId: p.lambdaFnNodeId,
|
|
425
|
+
type: 'CALLS',
|
|
426
|
+
confidence: 0.9,
|
|
427
|
+
reason: MOVE_EDGE_REASON.lambdaHost,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
export function buildLocalNameIndex(structNodeMap) {
|
|
432
|
+
const structIdsByLocalName = new Map();
|
|
433
|
+
for (const [qn, id] of structNodeMap) {
|
|
434
|
+
const key = moveLocalName(qn);
|
|
435
|
+
const list = structIdsByLocalName.get(key);
|
|
436
|
+
if (list)
|
|
437
|
+
list.push(id);
|
|
438
|
+
else
|
|
439
|
+
structIdsByLocalName.set(key, [id]);
|
|
440
|
+
}
|
|
441
|
+
return structIdsByLocalName;
|
|
442
|
+
}
|
|
443
|
+
function resolveStructRef(localOrQualified, callerModule, structNodeMap, structIdsByLocalName) {
|
|
444
|
+
const exact = structNodeMap.get(localOrQualified);
|
|
445
|
+
if (exact)
|
|
446
|
+
return { targetId: exact };
|
|
447
|
+
const base = stripTypeArgs(localOrQualified);
|
|
448
|
+
const baseExact = structNodeMap.get(base);
|
|
449
|
+
if (baseExact)
|
|
450
|
+
return { targetId: baseExact };
|
|
451
|
+
// move-flow emits every resourceAccess/param/return ref fully qualified, so a
|
|
452
|
+
// qualified ref that misses the exact lookup is a type outside the indexed
|
|
453
|
+
// graph (e.g. a dependency-only 0x1::coin::CoinStore). Falling through to the
|
|
454
|
+
// bare-name heuristic would silently mis-bind it to a same-named repo struct
|
|
455
|
+
// under a different address - report unresolved instead. The heuristics below
|
|
456
|
+
// remain only for unqualified inputs.
|
|
457
|
+
if (base.includes('::'))
|
|
458
|
+
return { unresolved: true };
|
|
459
|
+
const sameModule = structNodeMap.get(`${callerModule}::${base}`);
|
|
460
|
+
if (sameModule)
|
|
461
|
+
return { targetId: sameModule };
|
|
462
|
+
const matches = structIdsByLocalName.get(moveLocalName(base)) ?? [];
|
|
463
|
+
if (matches.length === 1)
|
|
464
|
+
return { targetId: matches[0] };
|
|
465
|
+
return matches.length > 1 ? { ambiguous: true } : { unresolved: true };
|
|
466
|
+
}
|
|
467
|
+
export function resolveResourceEdges(pendingResource, structNodeMap, structIdsByLocalName, edgeSink, onUnresolved, onAmbiguous) {
|
|
468
|
+
const seenResourceEdges = new Set();
|
|
469
|
+
for (const pr of pendingResource) {
|
|
470
|
+
const resolved = resolveStructRef(pr.target, pr.moduleQualified, structNodeMap, structIdsByLocalName);
|
|
471
|
+
if ('unresolved' in resolved) {
|
|
472
|
+
onUnresolved?.(pr);
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if ('ambiguous' in resolved) {
|
|
476
|
+
onAmbiguous?.(pr);
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const key = `${pr.fnNodeId}\0${pr.type}\0${resolved.targetId}`;
|
|
480
|
+
if (seenResourceEdges.has(key))
|
|
481
|
+
continue;
|
|
482
|
+
seenResourceEdges.add(key);
|
|
483
|
+
edgeSink({
|
|
484
|
+
id: moveRelId(pr.fnNodeId, pr.type, resolved.targetId, pr.reason),
|
|
485
|
+
sourceId: pr.fnNodeId,
|
|
486
|
+
targetId: resolved.targetId,
|
|
487
|
+
type: pr.type,
|
|
488
|
+
confidence: 1.0,
|
|
489
|
+
reason: pr.reason,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
export function resolveFriendEdges(pendingFriends, moduleFileMap, edgeSink) {
|
|
494
|
+
for (const pf of pendingFriends) {
|
|
495
|
+
const friendFile = moduleFileMap.get(pf.friend);
|
|
496
|
+
if (!friendFile)
|
|
497
|
+
continue;
|
|
498
|
+
const targetId = moveModuleNodeId(pf.friend, friendFile);
|
|
499
|
+
edgeSink({
|
|
500
|
+
id: moveRelId(pf.moduleNodeId, 'FRIEND_OF', targetId, MOVE_EDGE_REASON.friend),
|
|
501
|
+
sourceId: pf.moduleNodeId,
|
|
502
|
+
targetId,
|
|
503
|
+
type: 'FRIEND_OF',
|
|
504
|
+
confidence: 1.0,
|
|
505
|
+
reason: MOVE_EDGE_REASON.friend,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
export function resolveTypeRefEdges(pendingTypeRef, structNodeMap, structIdsByLocalName, edgeSink, onUnresolved, onAmbiguous) {
|
|
510
|
+
const seenTypeEdges = new Set();
|
|
511
|
+
for (const pr of pendingTypeRef) {
|
|
512
|
+
const resolved = resolveStructRef(pr.target, pr.moduleQualified, structNodeMap, structIdsByLocalName);
|
|
513
|
+
if ('unresolved' in resolved) {
|
|
514
|
+
onUnresolved?.(pr);
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
if ('ambiguous' in resolved) {
|
|
518
|
+
onAmbiguous?.(pr);
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
const key = `${pr.sourceNodeId}\0${pr.reason}\0${resolved.targetId}`;
|
|
522
|
+
if (seenTypeEdges.has(key))
|
|
523
|
+
continue;
|
|
524
|
+
seenTypeEdges.add(key);
|
|
525
|
+
edgeSink({
|
|
526
|
+
id: moveRelId(pr.sourceNodeId, 'USES_TYPE', resolved.targetId, pr.reason),
|
|
527
|
+
sourceId: pr.sourceNodeId,
|
|
528
|
+
targetId: resolved.targetId,
|
|
529
|
+
type: 'USES_TYPE',
|
|
530
|
+
confidence: 1.0,
|
|
531
|
+
reason: pr.reason,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type FileHandle } from 'node:fs/promises';
|
|
2
|
+
export interface LockOptions {
|
|
3
|
+
waitTimeoutMs?: number;
|
|
4
|
+
leaseMs?: number;
|
|
5
|
+
heartbeatMs?: number;
|
|
6
|
+
retryMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface InstallLockIo {
|
|
9
|
+
openLock(lockPath: string): Promise<FileHandle>;
|
|
10
|
+
removeLock(lockPath: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/** Allow for the artifact download, extraction, publication, and version probe. */
|
|
13
|
+
export declare const moveFlowInstallLockWaitMs: (httpTimeoutMs: number) => number;
|
|
14
|
+
export declare function acquireInstallLock(lockPath: string, options?: LockOptions, io?: InstallLockIo): Promise<() => Promise<void>>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile, rm, stat, utimes } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { setTimeout as wait } from 'node:timers/promises';
|
|
5
|
+
const DEFAULT_LOCK_WAIT_MS = 60_000;
|
|
6
|
+
const INSTALL_COMPLETION_GRACE_MS = 60_000;
|
|
7
|
+
const DEFAULT_LOCK_LEASE_MS = 60_000;
|
|
8
|
+
const DEFAULT_HEARTBEAT_MS = 5_000;
|
|
9
|
+
const DEFAULT_LOCK_RETRY_MS = 100;
|
|
10
|
+
const defaultLockIo = {
|
|
11
|
+
openLock: (lockPath) => open(lockPath, 'wx'),
|
|
12
|
+
removeLock: async (lockPath) => {
|
|
13
|
+
await rm(lockPath, { force: true });
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
/** Allow for the artifact download, extraction, publication, and version probe. */
|
|
17
|
+
export const moveFlowInstallLockWaitMs = (httpTimeoutMs) => Math.max(DEFAULT_LOCK_WAIT_MS, httpTimeoutMs * 2 + INSTALL_COMPLETION_GRACE_MS);
|
|
18
|
+
const readLock = async (lockPath) => {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(await readFile(lockPath, 'utf8'));
|
|
21
|
+
return typeof parsed.token === 'string' ? parsed.token : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const statOrNull = async (file) => {
|
|
28
|
+
try {
|
|
29
|
+
return await stat(file);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const removeStaleLock = async (lockPath, leaseMs) => {
|
|
36
|
+
const first = await statOrNull(lockPath);
|
|
37
|
+
if (!first || Date.now() - first.mtimeMs <= leaseMs)
|
|
38
|
+
return;
|
|
39
|
+
const token = await readLock(lockPath);
|
|
40
|
+
await wait(25);
|
|
41
|
+
const second = await statOrNull(lockPath);
|
|
42
|
+
if (!second ||
|
|
43
|
+
second.mtimeMs !== first.mtimeMs ||
|
|
44
|
+
Date.now() - second.mtimeMs <= leaseMs ||
|
|
45
|
+
(await readLock(lockPath)) !== token) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await rm(lockPath, { force: true });
|
|
49
|
+
};
|
|
50
|
+
export async function acquireInstallLock(lockPath, options = {}, io = defaultLockIo) {
|
|
51
|
+
const waitTimeoutMs = options.waitTimeoutMs ?? DEFAULT_LOCK_WAIT_MS;
|
|
52
|
+
const leaseMs = options.leaseMs ?? DEFAULT_LOCK_LEASE_MS;
|
|
53
|
+
const heartbeatMs = options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;
|
|
54
|
+
const retryMs = options.retryMs ?? DEFAULT_LOCK_RETRY_MS;
|
|
55
|
+
const deadline = Date.now() + waitTimeoutMs;
|
|
56
|
+
const token = randomUUID();
|
|
57
|
+
await mkdir(path.dirname(lockPath), { recursive: true });
|
|
58
|
+
while (Date.now() < deadline) {
|
|
59
|
+
let created = false;
|
|
60
|
+
try {
|
|
61
|
+
const handle = await io.openLock(lockPath);
|
|
62
|
+
created = true;
|
|
63
|
+
try {
|
|
64
|
+
await handle.writeFile(JSON.stringify({ token, pid: process.pid }));
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await handle.close();
|
|
68
|
+
}
|
|
69
|
+
let heartbeatRunning = false;
|
|
70
|
+
const heartbeat = setInterval(() => {
|
|
71
|
+
if (heartbeatRunning)
|
|
72
|
+
return;
|
|
73
|
+
heartbeatRunning = true;
|
|
74
|
+
void (async () => {
|
|
75
|
+
if ((await readLock(lockPath)) !== token)
|
|
76
|
+
return;
|
|
77
|
+
const now = new Date();
|
|
78
|
+
await utimes(lockPath, now, now);
|
|
79
|
+
})()
|
|
80
|
+
.catch(() => { })
|
|
81
|
+
.finally(() => {
|
|
82
|
+
heartbeatRunning = false;
|
|
83
|
+
});
|
|
84
|
+
}, heartbeatMs);
|
|
85
|
+
heartbeat.unref();
|
|
86
|
+
return async () => {
|
|
87
|
+
clearInterval(heartbeat);
|
|
88
|
+
if ((await readLock(lockPath)) === token)
|
|
89
|
+
await rm(lockPath, { force: true });
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (created)
|
|
94
|
+
await io.removeLock(lockPath).catch(() => { });
|
|
95
|
+
if (error.code !== 'EEXIST')
|
|
96
|
+
throw error;
|
|
97
|
+
await removeStaleLock(lockPath, leaseMs);
|
|
98
|
+
await wait(retryMs);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
throw new Error('timed out waiting for another move-flow installation');
|
|
102
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { MoveFlowReleaseSelection } from './constants.js';
|
|
2
|
+
export interface VerifiedMoveFlowBinary {
|
|
3
|
+
binaryPath: string;
|
|
4
|
+
version: string;
|
|
5
|
+
fingerprint: string;
|
|
6
|
+
}
|
|
7
|
+
export type MoveFlowInstallStatus = 'available' | 'installed' | 'skipped' | 'unsupported' | 'failed';
|
|
8
|
+
export interface MoveFlowInstallResult {
|
|
9
|
+
status: MoveFlowInstallStatus;
|
|
10
|
+
message?: string;
|
|
11
|
+
/** Verified runtime descriptor, set on 'available' and 'installed'. */
|
|
12
|
+
binary?: VerifiedMoveFlowBinary;
|
|
13
|
+
}
|
|
14
|
+
export interface MoveFlowInstallConfig {
|
|
15
|
+
version: string;
|
|
16
|
+
repository: string;
|
|
17
|
+
tag: string;
|
|
18
|
+
releaseTarget: string;
|
|
19
|
+
assetName: string;
|
|
20
|
+
releaseBase: string;
|
|
21
|
+
binaryName: string;
|
|
22
|
+
installDir: string;
|
|
23
|
+
binaryPath: string;
|
|
24
|
+
metadataPath: string;
|
|
25
|
+
lockPath: string;
|
|
26
|
+
httpTimeoutMs: number;
|
|
27
|
+
}
|
|
28
|
+
interface PowerShellInvocation {
|
|
29
|
+
args: string[];
|
|
30
|
+
env: NodeJS.ProcessEnv;
|
|
31
|
+
}
|
|
32
|
+
export declare function getMoveFlowInstallConfig(env?: NodeJS.ProcessEnv): Promise<MoveFlowInstallConfig | null>;
|
|
33
|
+
/** Resolve the configured release without downloading or starting move-flow. */
|
|
34
|
+
export declare function getMoveFlowReleaseSelection(env?: NodeJS.ProcessEnv): Promise<MoveFlowReleaseSelection | undefined>;
|
|
35
|
+
export declare const powershellExpandArchiveInvocation: (archive: string, destination: string) => PowerShellInvocation;
|
|
36
|
+
export declare const reportedMoveFlowVersion: (output: string) => string | null;
|
|
37
|
+
export declare function findCachedMoveFlowBinary(env?: NodeJS.ProcessEnv): Promise<VerifiedMoveFlowBinary | null>;
|
|
38
|
+
export declare function installMoveFlow(env?: NodeJS.ProcessEnv): Promise<MoveFlowInstallResult>;
|
|
39
|
+
export {};
|