arceus-s 1.6.4
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 +395 -0
- package/dist/_shared/graph/types.d.ts +81 -0
- package/dist/_shared/graph/types.d.ts.map +1 -0
- package/dist/_shared/graph/types.js +8 -0
- package/dist/_shared/graph/types.js.map +1 -0
- package/dist/_shared/index.d.ts +63 -0
- package/dist/_shared/index.d.ts.map +1 -0
- package/dist/_shared/index.js +48 -0
- package/dist/_shared/index.js.map +1 -0
- package/dist/_shared/integrations/circuit-breaker.d.ts +183 -0
- package/dist/_shared/integrations/circuit-breaker.d.ts.map +1 -0
- package/dist/_shared/integrations/circuit-breaker.js +236 -0
- package/dist/_shared/integrations/circuit-breaker.js.map +1 -0
- package/dist/_shared/integrations/resilient-fetch.d.ts +99 -0
- package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -0
- package/dist/_shared/integrations/resilient-fetch.js +204 -0
- package/dist/_shared/integrations/resilient-fetch.js.map +1 -0
- package/dist/_shared/integrations/retry.d.ts +60 -0
- package/dist/_shared/integrations/retry.d.ts.map +1 -0
- package/dist/_shared/integrations/retry.js +67 -0
- package/dist/_shared/integrations/retry.js.map +1 -0
- package/dist/_shared/integrations/understand-quickly.d.ts +77 -0
- package/dist/_shared/integrations/understand-quickly.d.ts.map +1 -0
- package/dist/_shared/integrations/understand-quickly.js +176 -0
- package/dist/_shared/integrations/understand-quickly.js.map +1 -0
- package/dist/_shared/language-detection.d.ts +23 -0
- package/dist/_shared/language-detection.d.ts.map +1 -0
- package/dist/_shared/language-detection.js +139 -0
- package/dist/_shared/language-detection.js.map +1 -0
- package/dist/_shared/languages.d.ts +26 -0
- package/dist/_shared/languages.d.ts.map +1 -0
- package/dist/_shared/languages.js +27 -0
- package/dist/_shared/languages.js.map +1 -0
- package/dist/_shared/lbug/schema-constants.d.ts +16 -0
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -0
- package/dist/_shared/lbug/schema-constants.js +67 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -0
- package/dist/_shared/mro-strategy.d.ts +41 -0
- package/dist/_shared/mro-strategy.d.ts.map +1 -0
- package/dist/_shared/mro-strategy.js +2 -0
- package/dist/_shared/mro-strategy.js.map +1 -0
- package/dist/_shared/pipeline.d.ts +16 -0
- package/dist/_shared/pipeline.d.ts.map +1 -0
- package/dist/_shared/pipeline.js +5 -0
- package/dist/_shared/pipeline.js.map +1 -0
- package/dist/_shared/scope-resolution/def-index.d.ts +36 -0
- package/dist/_shared/scope-resolution/def-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/def-index.js +51 -0
- package/dist/_shared/scope-resolution/def-index.js.map +1 -0
- package/dist/_shared/scope-resolution/evidence-weights.d.ts +69 -0
- package/dist/_shared/scope-resolution/evidence-weights.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/evidence-weights.js +84 -0
- package/dist/_shared/scope-resolution/evidence-weights.js.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +149 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js +795 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -0
- package/dist/_shared/scope-resolution/language-classification.d.ts +26 -0
- package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/language-classification.js +44 -0
- package/dist/_shared/scope-resolution/language-classification.js.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +106 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js +98 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts +46 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/module-scope-index.js +58 -0
- package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -0
- package/dist/_shared/scope-resolution/origin-priority.d.ts +14 -0
- package/dist/_shared/scope-resolution/origin-priority.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/origin-priority.js +21 -0
- package/dist/_shared/scope-resolution/origin-priority.js.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts +76 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.js +54 -0
- package/dist/_shared/scope-resolution/parsed-file.js.map +1 -0
- package/dist/_shared/scope-resolution/position-index.d.ts +62 -0
- package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/position-index.js +134 -0
- package/dist/_shared/scope-resolution/position-index.js.map +1 -0
- package/dist/_shared/scope-resolution/qualified-name-index.d.ts +44 -0
- package/dist/_shared/scope-resolution/qualified-name-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/qualified-name-index.js +75 -0
- package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts +75 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.js +24 -0
- package/dist/_shared/scope-resolution/reference-site.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts +27 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js +30 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts +69 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.js +44 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts +56 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.js +150 -0
- package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts +26 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js +31 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +81 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js +349 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts +33 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js +56 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts +36 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js +32 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts +43 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js +60 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +53 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js +126 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts +43 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.js +46 -0
- package/dist/_shared/scope-resolution/scope-id.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts +83 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.js +220 -0
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +63 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js +122 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -0
- package/dist/_shared/scope-resolution/shadow/diff.d.ts +59 -0
- package/dist/_shared/scope-resolution/shadow/diff.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/shadow/diff.js +79 -0
- package/dist/_shared/scope-resolution/shadow/diff.js.map +1 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +34 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/symbol-definition.js +12 -0
- package/dist/_shared/scope-resolution/symbol-definition.js.map +1 -0
- package/dist/_shared/scope-resolution/types.d.ts +400 -0
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/types.js +25 -0
- package/dist/_shared/scope-resolution/types.js.map +1 -0
- package/dist/_shared/test-helpers.d.ts +13 -0
- package/dist/_shared/test-helpers.d.ts.map +1 -0
- package/dist/_shared/test-helpers.js +13 -0
- package/dist/_shared/test-helpers.js.map +1 -0
- package/dist/cli/ai-context.d.ts +28 -0
- package/dist/cli/ai-context.js +289 -0
- package/dist/cli/analyze.d.ts +80 -0
- package/dist/cli/analyze.js +525 -0
- package/dist/cli/augment.d.ts +13 -0
- package/dist/cli/augment.js +33 -0
- package/dist/cli/clean.d.ts +10 -0
- package/dist/cli/clean.js +79 -0
- package/dist/cli/cli-message.d.ts +16 -0
- package/dist/cli/cli-message.js +71 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +31 -0
- package/dist/cli/eval-server.d.ts +37 -0
- package/dist/cli/eval-server.js +423 -0
- package/dist/cli/group.d.ts +1 -0
- package/dist/cli/group.js +323 -0
- package/dist/cli/index-repo.d.ts +15 -0
- package/dist/cli/index-repo.js +120 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +492 -0
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +40 -0
- package/dist/cli/mcp.d.ts +29 -0
- package/dist/cli/mcp.js +73 -0
- package/dist/cli/optional-grammars.d.ts +47 -0
- package/dist/cli/optional-grammars.js +87 -0
- package/dist/cli/publish.d.ts +29 -0
- package/dist/cli/publish.js +174 -0
- package/dist/cli/remove.d.ts +30 -0
- package/dist/cli/remove.js +102 -0
- package/dist/cli/serve.d.ts +4 -0
- package/dist/cli/serve.js +55 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +642 -0
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +555 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +36 -0
- package/dist/cli/tool.d.ts +43 -0
- package/dist/cli/tool.js +169 -0
- package/dist/cli/wiki.d.ts +23 -0
- package/dist/cli/wiki.js +616 -0
- package/dist/config/ignore-service.d.ts +35 -0
- package/dist/config/ignore-service.js +439 -0
- package/dist/config/supported-languages.d.ts +13 -0
- package/dist/config/supported-languages.js +13 -0
- package/dist/core/augmentation/engine.d.ts +26 -0
- package/dist/core/augmentation/engine.js +272 -0
- package/dist/core/embedding-mode.d.ts +51 -0
- package/dist/core/embedding-mode.js +48 -0
- package/dist/core/embeddings/ast-utils.d.ts +22 -0
- package/dist/core/embeddings/ast-utils.js +106 -0
- package/dist/core/embeddings/character-chunk.d.ts +12 -0
- package/dist/core/embeddings/character-chunk.js +43 -0
- package/dist/core/embeddings/chunker.d.ts +14 -0
- package/dist/core/embeddings/chunker.js +239 -0
- package/dist/core/embeddings/config.d.ts +2 -0
- package/dist/core/embeddings/config.js +36 -0
- package/dist/core/embeddings/embedder.d.ts +65 -0
- package/dist/core/embeddings/embedder.js +349 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +68 -0
- package/dist/core/embeddings/embedding-pipeline.js +552 -0
- package/dist/core/embeddings/exact-search.d.ts +15 -0
- package/dist/core/embeddings/exact-search.js +27 -0
- package/dist/core/embeddings/hf-env.d.ts +135 -0
- package/dist/core/embeddings/hf-env.js +232 -0
- package/dist/core/embeddings/http-client.d.ts +37 -0
- package/dist/core/embeddings/http-client.js +199 -0
- package/dist/core/embeddings/index.d.ts +10 -0
- package/dist/core/embeddings/index.js +10 -0
- package/dist/core/embeddings/line-index.d.ts +7 -0
- package/dist/core/embeddings/line-index.js +42 -0
- package/dist/core/embeddings/server-mapping.d.ts +15 -0
- package/dist/core/embeddings/server-mapping.js +33 -0
- package/dist/core/embeddings/structural-extractor.d.ts +15 -0
- package/dist/core/embeddings/structural-extractor.js +58 -0
- package/dist/core/embeddings/text-generator.d.ts +31 -0
- package/dist/core/embeddings/text-generator.js +208 -0
- package/dist/core/embeddings/types.d.ts +211 -0
- package/dist/core/embeddings/types.js +202 -0
- package/dist/core/git-staleness.d.ts +37 -0
- package/dist/core/git-staleness.js +167 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +173 -0
- package/dist/core/graph/types.d.ts +36 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/group/bridge-db.d.ts +82 -0
- package/dist/core/group/bridge-db.js +609 -0
- package/dist/core/group/bridge-schema.d.ts +27 -0
- package/dist/core/group/bridge-schema.js +55 -0
- package/dist/core/group/config-parser.d.ts +7 -0
- package/dist/core/group/config-parser.js +122 -0
- package/dist/core/group/contract-extractor.d.ts +7 -0
- package/dist/core/group/contract-extractor.js +1 -0
- package/dist/core/group/cross-impact.d.ts +85 -0
- package/dist/core/group/cross-impact.js +515 -0
- package/dist/core/group/extractors/elixir-workspace-extractor.d.ts +15 -0
- package/dist/core/group/extractors/elixir-workspace-extractor.js +204 -0
- package/dist/core/group/extractors/fs-utils.d.ts +10 -0
- package/dist/core/group/extractors/fs-utils.js +24 -0
- package/dist/core/group/extractors/go-workspace-extractor.d.ts +14 -0
- package/dist/core/group/extractors/go-workspace-extractor.js +217 -0
- package/dist/core/group/extractors/grpc-extractor.d.ts +25 -0
- package/dist/core/group/extractors/grpc-extractor.js +414 -0
- package/dist/core/group/extractors/grpc-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/go.js +97 -0
- package/dist/core/group/extractors/grpc-patterns/index.d.ts +19 -0
- package/dist/core/group/extractors/grpc-patterns/index.js +46 -0
- package/dist/core/group/extractors/grpc-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/java.js +173 -0
- package/dist/core/group/extractors/grpc-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/grpc-patterns/node.js +290 -0
- package/dist/core/group/extractors/grpc-patterns/proto.d.ts +9 -0
- package/dist/core/group/extractors/grpc-patterns/proto.js +134 -0
- package/dist/core/group/extractors/grpc-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/grpc-patterns/python.js +67 -0
- package/dist/core/group/extractors/grpc-patterns/types.d.ts +50 -0
- package/dist/core/group/extractors/grpc-patterns/types.js +1 -0
- package/dist/core/group/extractors/http-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/go.js +215 -0
- package/dist/core/group/extractors/http-patterns/index.d.ts +17 -0
- package/dist/core/group/extractors/http-patterns/index.js +44 -0
- package/dist/core/group/extractors/http-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/java.js +253 -0
- package/dist/core/group/extractors/http-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/http-patterns/node.js +484 -0
- package/dist/core/group/extractors/http-patterns/php.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/php.js +178 -0
- package/dist/core/group/extractors/http-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/http-patterns/python.js +308 -0
- package/dist/core/group/extractors/http-patterns/types.d.ts +61 -0
- package/dist/core/group/extractors/http-patterns/types.js +1 -0
- package/dist/core/group/extractors/http-route-extractor.d.ts +21 -0
- package/dist/core/group/extractors/http-route-extractor.js +430 -0
- package/dist/core/group/extractors/include-extractor.d.ts +39 -0
- package/dist/core/group/extractors/include-extractor.js +566 -0
- package/dist/core/group/extractors/java-workspace-extractor.d.ts +16 -0
- package/dist/core/group/extractors/java-workspace-extractor.js +204 -0
- package/dist/core/group/extractors/manifest-extractor.d.ts +54 -0
- package/dist/core/group/extractors/manifest-extractor.js +320 -0
- package/dist/core/group/extractors/node-workspace-extractor.d.ts +14 -0
- package/dist/core/group/extractors/node-workspace-extractor.js +207 -0
- package/dist/core/group/extractors/python-workspace-extractor.d.ts +15 -0
- package/dist/core/group/extractors/python-workspace-extractor.js +205 -0
- package/dist/core/group/extractors/rust-workspace-extractor.d.ts +44 -0
- package/dist/core/group/extractors/rust-workspace-extractor.js +240 -0
- package/dist/core/group/extractors/thrift-extractor.d.ts +22 -0
- package/dist/core/group/extractors/thrift-extractor.js +283 -0
- package/dist/core/group/extractors/thrift-patterns/index.d.ts +4 -0
- package/dist/core/group/extractors/thrift-patterns/index.js +10 -0
- package/dist/core/group/extractors/thrift-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/thrift-patterns/java.js +220 -0
- package/dist/core/group/extractors/thrift-patterns/types.d.ts +17 -0
- package/dist/core/group/extractors/thrift-patterns/types.js +1 -0
- package/dist/core/group/extractors/topic-extractor.d.ts +8 -0
- package/dist/core/group/extractors/topic-extractor.js +97 -0
- package/dist/core/group/extractors/topic-patterns/go.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/go.js +120 -0
- package/dist/core/group/extractors/topic-patterns/index.d.ts +14 -0
- package/dist/core/group/extractors/topic-patterns/index.js +38 -0
- package/dist/core/group/extractors/topic-patterns/java.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/java.js +80 -0
- package/dist/core/group/extractors/topic-patterns/node.d.ts +4 -0
- package/dist/core/group/extractors/topic-patterns/node.js +155 -0
- package/dist/core/group/extractors/topic-patterns/python.d.ts +2 -0
- package/dist/core/group/extractors/topic-patterns/python.js +116 -0
- package/dist/core/group/extractors/topic-patterns/types.d.ts +25 -0
- package/dist/core/group/extractors/topic-patterns/types.js +10 -0
- package/dist/core/group/extractors/tree-sitter-scanner.d.ts +113 -0
- package/dist/core/group/extractors/tree-sitter-scanner.js +95 -0
- package/dist/core/group/extractors/workspace-extractor.d.ts +13 -0
- package/dist/core/group/extractors/workspace-extractor.js +65 -0
- package/dist/core/group/group-path-utils.d.ts +17 -0
- package/dist/core/group/group-path-utils.js +40 -0
- package/dist/core/group/matching.d.ts +13 -0
- package/dist/core/group/matching.js +284 -0
- package/dist/core/group/normalization.d.ts +3 -0
- package/dist/core/group/normalization.js +115 -0
- package/dist/core/group/resolve-at-member.d.ts +10 -0
- package/dist/core/group/resolve-at-member.js +31 -0
- package/dist/core/group/service-boundary-detector.d.ts +8 -0
- package/dist/core/group/service-boundary-detector.js +155 -0
- package/dist/core/group/service.d.ts +56 -0
- package/dist/core/group/service.js +395 -0
- package/dist/core/group/storage.d.ts +9 -0
- package/dist/core/group/storage.js +157 -0
- package/dist/core/group/sync.d.ts +21 -0
- package/dist/core/group/sync.js +267 -0
- package/dist/core/group/types.d.ts +181 -0
- package/dist/core/group/types.js +1 -0
- package/dist/core/incremental/shadow-candidates.d.ts +44 -0
- package/dist/core/incremental/shadow-candidates.js +74 -0
- package/dist/core/incremental/subgraph-extract.d.ts +64 -0
- package/dist/core/incremental/subgraph-extract.js +111 -0
- package/dist/core/ingestion/ast-cache.d.ts +26 -0
- package/dist/core/ingestion/ast-cache.js +48 -0
- package/dist/core/ingestion/binding-accumulator.d.ts +212 -0
- package/dist/core/ingestion/binding-accumulator.js +336 -0
- package/dist/core/ingestion/call-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/call-extractors/configs/c-cpp.js +8 -0
- package/dist/core/ingestion/call-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/csharp.js +6 -0
- package/dist/core/ingestion/call-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/dart.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/go.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/call-extractors/configs/jvm.js +51 -0
- package/dist/core/ingestion/call-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/php.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/python.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/ruby.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/rust.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/call-extractors/configs/swift.js +5 -0
- package/dist/core/ingestion/call-extractors/configs/typescript-javascript.d.ts +3 -0
- package/dist/core/ingestion/call-extractors/configs/typescript-javascript.js +8 -0
- package/dist/core/ingestion/call-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/call-extractors/generic.js +59 -0
- package/dist/core/ingestion/call-processor.d.ts +235 -0
- package/dist/core/ingestion/call-processor.js +2754 -0
- package/dist/core/ingestion/call-routing.d.ts +55 -0
- package/dist/core/ingestion/call-routing.js +95 -0
- package/dist/core/ingestion/call-types.d.ts +135 -0
- package/dist/core/ingestion/call-types.js +2 -0
- package/dist/core/ingestion/class-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/class-extractors/configs/c-cpp.js +11 -0
- package/dist/core/ingestion/class-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/csharp.js +21 -0
- package/dist/core/ingestion/class-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/dart.js +7 -0
- package/dist/core/ingestion/class-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/go.js +20 -0
- package/dist/core/ingestion/class-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/class-extractors/configs/jvm.js +35 -0
- package/dist/core/ingestion/class-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/php.js +7 -0
- package/dist/core/ingestion/class-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/python.js +7 -0
- package/dist/core/ingestion/class-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/ruby.js +7 -0
- package/dist/core/ingestion/class-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/rust.js +7 -0
- package/dist/core/ingestion/class-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/configs/swift.js +18 -0
- package/dist/core/ingestion/class-extractors/configs/typescript-javascript.d.ts +4 -0
- package/dist/core/ingestion/class-extractors/configs/typescript-javascript.js +28 -0
- package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/generic.js +135 -0
- package/dist/core/ingestion/class-types.d.ts +34 -0
- package/dist/core/ingestion/class-types.js +1 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +169 -0
- package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +376 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +212 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +1727 -0
- package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
- package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
- package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
- package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
- package/dist/core/ingestion/cobol-processor.d.ts +54 -0
- package/dist/core/ingestion/cobol-processor.js +1232 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +336 -0
- package/dist/core/ingestion/constants.d.ts +17 -0
- package/dist/core/ingestion/constants.js +21 -0
- package/dist/core/ingestion/cpp-ue-preprocessor.d.ts +12 -0
- package/dist/core/ingestion/cpp-ue-preprocessor.js +260 -0
- package/dist/core/ingestion/emit-references.d.ts +88 -0
- package/dist/core/ingestion/emit-references.js +229 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +40 -0
- package/dist/core/ingestion/entry-point-scoring.js +196 -0
- package/dist/core/ingestion/export-detection.d.ts +57 -0
- package/dist/core/ingestion/export-detection.js +233 -0
- package/dist/core/ingestion/field-extractor.d.ts +29 -0
- package/dist/core/ingestion/field-extractor.js +25 -0
- package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +104 -0
- package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/csharp.js +121 -0
- package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/dart.js +78 -0
- package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
- package/dist/core/ingestion/field-extractors/configs/go.js +60 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +53 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +158 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
- package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/php.js +65 -0
- package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
- package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
- package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
- package/dist/core/ingestion/field-extractors/configs/ruby.js +76 -0
- package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
- package/dist/core/ingestion/field-extractors/configs/rust.js +52 -0
- package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
- package/dist/core/ingestion/field-extractors/configs/swift.js +65 -0
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +56 -0
- package/dist/core/ingestion/field-extractors/generic.d.ts +49 -0
- package/dist/core/ingestion/field-extractors/generic.js +117 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
- package/dist/core/ingestion/field-extractors/typescript.js +291 -0
- package/dist/core/ingestion/field-types.d.ts +61 -0
- package/dist/core/ingestion/field-types.js +2 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
- package/dist/core/ingestion/filesystem-walker.js +92 -0
- package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
- package/dist/core/ingestion/finalize-orchestrator.js +142 -0
- package/dist/core/ingestion/framework-detection.d.ts +30 -0
- package/dist/core/ingestion/framework-detection.js +428 -0
- package/dist/core/ingestion/heritage-extractors/configs/go.d.ts +13 -0
- package/dist/core/ingestion/heritage-extractors/configs/go.js +20 -0
- package/dist/core/ingestion/heritage-extractors/configs/ruby.d.ts +18 -0
- package/dist/core/ingestion/heritage-extractors/configs/ruby.js +65 -0
- package/dist/core/ingestion/heritage-extractors/generic.d.ts +23 -0
- package/dist/core/ingestion/heritage-extractors/generic.js +47 -0
- package/dist/core/ingestion/heritage-processor.d.ts +54 -0
- package/dist/core/ingestion/heritage-processor.js +367 -0
- package/dist/core/ingestion/heritage-types.d.ts +73 -0
- package/dist/core/ingestion/heritage-types.js +2 -0
- package/dist/core/ingestion/import-processor.d.ts +23 -0
- package/dist/core/ingestion/import-processor.js +377 -0
- package/dist/core/ingestion/import-resolvers/configs/c-cpp.d.ts +7 -0
- package/dist/core/ingestion/import-resolvers/configs/c-cpp.js +14 -0
- package/dist/core/ingestion/import-resolvers/configs/csharp.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/configs/csharp.js +27 -0
- package/dist/core/ingestion/import-resolvers/configs/dart.d.ts +17 -0
- package/dist/core/ingestion/import-resolvers/configs/dart.js +54 -0
- package/dist/core/ingestion/import-resolvers/configs/go.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/configs/go.js +26 -0
- package/dist/core/ingestion/import-resolvers/configs/jvm.d.ts +13 -0
- package/dist/core/ingestion/import-resolvers/configs/jvm.js +68 -0
- package/dist/core/ingestion/import-resolvers/configs/php.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/configs/php.js +15 -0
- package/dist/core/ingestion/import-resolvers/configs/python.d.ts +12 -0
- package/dist/core/ingestion/import-resolvers/configs/python.js +41 -0
- package/dist/core/ingestion/import-resolvers/configs/ruby.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/configs/ruby.js +16 -0
- package/dist/core/ingestion/import-resolvers/configs/rust.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/configs/rust.js +54 -0
- package/dist/core/ingestion/import-resolvers/configs/swift.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/configs/swift.js +29 -0
- package/dist/core/ingestion/import-resolvers/configs/typescript-javascript.d.ts +9 -0
- package/dist/core/ingestion/import-resolvers/configs/typescript-javascript.js +23 -0
- package/dist/core/ingestion/import-resolvers/csharp.d.ts +18 -0
- package/dist/core/ingestion/import-resolvers/csharp.js +115 -0
- package/dist/core/ingestion/import-resolvers/go.d.ts +17 -0
- package/dist/core/ingestion/import-resolvers/go.js +46 -0
- package/dist/core/ingestion/import-resolvers/jvm.d.ts +27 -0
- package/dist/core/ingestion/import-resolvers/jvm.js +106 -0
- package/dist/core/ingestion/import-resolvers/php.d.ts +24 -0
- package/dist/core/ingestion/import-resolvers/php.js +77 -0
- package/dist/core/ingestion/import-resolvers/python.d.ts +22 -0
- package/dist/core/ingestion/import-resolvers/python.js +72 -0
- package/dist/core/ingestion/import-resolvers/resolver-factory.d.ts +24 -0
- package/dist/core/ingestion/import-resolvers/resolver-factory.js +33 -0
- package/dist/core/ingestion/import-resolvers/ruby.d.ts +14 -0
- package/dist/core/ingestion/import-resolvers/ruby.js +17 -0
- package/dist/core/ingestion/import-resolvers/rust.d.ts +17 -0
- package/dist/core/ingestion/import-resolvers/rust.js +75 -0
- package/dist/core/ingestion/import-resolvers/standard.d.ts +35 -0
- package/dist/core/ingestion/import-resolvers/standard.js +168 -0
- package/dist/core/ingestion/import-resolvers/types.d.ts +68 -0
- package/dist/core/ingestion/import-resolvers/types.js +6 -0
- package/dist/core/ingestion/import-resolvers/utils.d.ts +35 -0
- package/dist/core/ingestion/import-resolvers/utils.js +153 -0
- package/dist/core/ingestion/import-target-adapter.d.ts +73 -0
- package/dist/core/ingestion/import-target-adapter.js +95 -0
- package/dist/core/ingestion/language-config.d.ts +52 -0
- package/dist/core/ingestion/language-config.js +182 -0
- package/dist/core/ingestion/language-provider.d.ts +465 -0
- package/dist/core/ingestion/language-provider.js +24 -0
- package/dist/core/ingestion/languages/c/arity-metadata.d.ts +14 -0
- package/dist/core/ingestion/languages/c/arity-metadata.js +94 -0
- package/dist/core/ingestion/languages/c/arity.d.ts +6 -0
- package/dist/core/ingestion/languages/c/arity.js +18 -0
- package/dist/core/ingestion/languages/c/captures.d.ts +2 -0
- package/dist/core/ingestion/languages/c/captures.js +105 -0
- package/dist/core/ingestion/languages/c/header-scan.d.ts +7 -0
- package/dist/core/ingestion/languages/c/header-scan.js +55 -0
- package/dist/core/ingestion/languages/c/import-decomposer.d.ts +8 -0
- package/dist/core/ingestion/languages/c/import-decomposer.js +50 -0
- package/dist/core/ingestion/languages/c/import-target.d.ts +14 -0
- package/dist/core/ingestion/languages/c/import-target.js +57 -0
- package/dist/core/ingestion/languages/c/index.d.ts +11 -0
- package/dist/core/ingestion/languages/c/index.js +11 -0
- package/dist/core/ingestion/languages/c/interpret.d.ts +14 -0
- package/dist/core/ingestion/languages/c/interpret.js +48 -0
- package/dist/core/ingestion/languages/c/merge-bindings.d.ts +7 -0
- package/dist/core/ingestion/languages/c/merge-bindings.js +23 -0
- package/dist/core/ingestion/languages/c/query.d.ts +3 -0
- package/dist/core/ingestion/languages/c/query.js +161 -0
- package/dist/core/ingestion/languages/c/scope-resolver.d.ts +13 -0
- package/dist/core/ingestion/languages/c/scope-resolver.js +60 -0
- package/dist/core/ingestion/languages/c/simple-hooks.d.ts +14 -0
- package/dist/core/ingestion/languages/c/simple-hooks.js +19 -0
- package/dist/core/ingestion/languages/c/static-linkage.d.ts +13 -0
- package/dist/core/ingestion/languages/c/static-linkage.js +57 -0
- package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
- package/dist/core/ingestion/languages/c-cpp.js +411 -0
- package/dist/core/ingestion/languages/cobol.d.ts +1 -0
- package/dist/core/ingestion/languages/cobol.js +28 -0
- package/dist/core/ingestion/languages/csharp/accessor-unwrap.d.ts +21 -0
- package/dist/core/ingestion/languages/csharp/accessor-unwrap.js +56 -0
- package/dist/core/ingestion/languages/csharp/arity-metadata.d.ts +26 -0
- package/dist/core/ingestion/languages/csharp/arity-metadata.js +46 -0
- package/dist/core/ingestion/languages/csharp/arity.d.ts +23 -0
- package/dist/core/ingestion/languages/csharp/arity.js +37 -0
- package/dist/core/ingestion/languages/csharp/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/csharp/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/csharp/captures.d.ts +19 -0
- package/dist/core/ingestion/languages/csharp/captures.js +346 -0
- package/dist/core/ingestion/languages/csharp/import-decomposer.d.ts +19 -0
- package/dist/core/ingestion/languages/csharp/import-decomposer.js +93 -0
- package/dist/core/ingestion/languages/csharp/import-target.d.ts +25 -0
- package/dist/core/ingestion/languages/csharp/import-target.js +123 -0
- package/dist/core/ingestion/languages/csharp/index.d.ts +82 -0
- package/dist/core/ingestion/languages/csharp/index.js +82 -0
- package/dist/core/ingestion/languages/csharp/interpret.d.ts +15 -0
- package/dist/core/ingestion/languages/csharp/interpret.js +132 -0
- package/dist/core/ingestion/languages/csharp/merge-bindings.d.ts +27 -0
- package/dist/core/ingestion/languages/csharp/merge-bindings.js +55 -0
- package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +51 -0
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +387 -0
- package/dist/core/ingestion/languages/csharp/query.d.ts +35 -0
- package/dist/core/ingestion/languages/csharp/query.js +521 -0
- package/dist/core/ingestion/languages/csharp/receiver-binding.d.ts +31 -0
- package/dist/core/ingestion/languages/csharp/receiver-binding.js +135 -0
- package/dist/core/ingestion/languages/csharp/scope-resolver.d.ts +10 -0
- package/dist/core/ingestion/languages/csharp/scope-resolver.js +63 -0
- package/dist/core/ingestion/languages/csharp/simple-hooks.d.ts +53 -0
- package/dist/core/ingestion/languages/csharp/simple-hooks.js +76 -0
- package/dist/core/ingestion/languages/csharp.d.ts +8 -0
- package/dist/core/ingestion/languages/csharp.js +201 -0
- package/dist/core/ingestion/languages/dart.d.ts +12 -0
- package/dist/core/ingestion/languages/dart.js +138 -0
- package/dist/core/ingestion/languages/go/arity-metadata.d.ts +8 -0
- package/dist/core/ingestion/languages/go/arity-metadata.js +37 -0
- package/dist/core/ingestion/languages/go/arity.d.ts +2 -0
- package/dist/core/ingestion/languages/go/arity.js +14 -0
- package/dist/core/ingestion/languages/go/cache-stats.d.ts +7 -0
- package/dist/core/ingestion/languages/go/cache-stats.js +15 -0
- package/dist/core/ingestion/languages/go/captures.d.ts +2 -0
- package/dist/core/ingestion/languages/go/captures.js +129 -0
- package/dist/core/ingestion/languages/go/expand-wildcards.d.ts +15 -0
- package/dist/core/ingestion/languages/go/expand-wildcards.js +93 -0
- package/dist/core/ingestion/languages/go/import-decomposer.d.ts +3 -0
- package/dist/core/ingestion/languages/go/import-decomposer.js +44 -0
- package/dist/core/ingestion/languages/go/import-target.d.ts +21 -0
- package/dist/core/ingestion/languages/go/import-target.js +67 -0
- package/dist/core/ingestion/languages/go/index.d.ts +17 -0
- package/dist/core/ingestion/languages/go/index.js +17 -0
- package/dist/core/ingestion/languages/go/interface-impls.d.ts +4 -0
- package/dist/core/ingestion/languages/go/interface-impls.js +72 -0
- package/dist/core/ingestion/languages/go/interpret.d.ts +11 -0
- package/dist/core/ingestion/languages/go/interpret.js +146 -0
- package/dist/core/ingestion/languages/go/merge-bindings.d.ts +2 -0
- package/dist/core/ingestion/languages/go/merge-bindings.js +18 -0
- package/dist/core/ingestion/languages/go/method-owners.d.ts +17 -0
- package/dist/core/ingestion/languages/go/method-owners.js +96 -0
- package/dist/core/ingestion/languages/go/namespace-mirror.d.ts +15 -0
- package/dist/core/ingestion/languages/go/namespace-mirror.js +53 -0
- package/dist/core/ingestion/languages/go/package-siblings.d.ts +11 -0
- package/dist/core/ingestion/languages/go/package-siblings.js +84 -0
- package/dist/core/ingestion/languages/go/query.d.ts +3 -0
- package/dist/core/ingestion/languages/go/query.js +207 -0
- package/dist/core/ingestion/languages/go/range-binding.d.ts +8 -0
- package/dist/core/ingestion/languages/go/range-binding.js +109 -0
- package/dist/core/ingestion/languages/go/receiver-binding.d.ts +3 -0
- package/dist/core/ingestion/languages/go/receiver-binding.js +21 -0
- package/dist/core/ingestion/languages/go/scope-resolver.d.ts +2 -0
- package/dist/core/ingestion/languages/go/scope-resolver.js +33 -0
- package/dist/core/ingestion/languages/go/simple-hooks.d.ts +4 -0
- package/dist/core/ingestion/languages/go/simple-hooks.js +21 -0
- package/dist/core/ingestion/languages/go/type-binding.d.ts +3 -0
- package/dist/core/ingestion/languages/go/type-binding.js +237 -0
- package/dist/core/ingestion/languages/go.d.ts +11 -0
- package/dist/core/ingestion/languages/go.js +94 -0
- package/dist/core/ingestion/languages/index.d.ts +39 -0
- package/dist/core/ingestion/languages/index.js +64 -0
- package/dist/core/ingestion/languages/java/arity-metadata.d.ts +18 -0
- package/dist/core/ingestion/languages/java/arity-metadata.js +40 -0
- package/dist/core/ingestion/languages/java/arity.d.ts +10 -0
- package/dist/core/ingestion/languages/java/arity.js +24 -0
- package/dist/core/ingestion/languages/java/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/java/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/java/captures.d.ts +17 -0
- package/dist/core/ingestion/languages/java/captures.js +187 -0
- package/dist/core/ingestion/languages/java/import-decomposer.d.ts +18 -0
- package/dist/core/ingestion/languages/java/import-decomposer.js +85 -0
- package/dist/core/ingestion/languages/java/import-target.d.ts +17 -0
- package/dist/core/ingestion/languages/java/import-target.js +100 -0
- package/dist/core/ingestion/languages/java/index.d.ts +29 -0
- package/dist/core/ingestion/languages/java/index.js +29 -0
- package/dist/core/ingestion/languages/java/interpret.d.ts +13 -0
- package/dist/core/ingestion/languages/java/interpret.js +131 -0
- package/dist/core/ingestion/languages/java/merge-bindings.d.ts +12 -0
- package/dist/core/ingestion/languages/java/merge-bindings.js +40 -0
- package/dist/core/ingestion/languages/java/query.d.ts +30 -0
- package/dist/core/ingestion/languages/java/query.js +192 -0
- package/dist/core/ingestion/languages/java/receiver-binding.d.ts +11 -0
- package/dist/core/ingestion/languages/java/receiver-binding.js +95 -0
- package/dist/core/ingestion/languages/java/scope-resolver.d.ts +50 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +74 -0
- package/dist/core/ingestion/languages/java/simple-hooks.d.ts +13 -0
- package/dist/core/ingestion/languages/java/simple-hooks.js +34 -0
- package/dist/core/ingestion/languages/java.d.ts +9 -0
- package/dist/core/ingestion/languages/java.js +76 -0
- package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
- package/dist/core/ingestion/languages/kotlin.js +164 -0
- package/dist/core/ingestion/languages/php/arity-metadata.d.ts +28 -0
- package/dist/core/ingestion/languages/php/arity-metadata.js +63 -0
- package/dist/core/ingestion/languages/php/arity.d.ts +25 -0
- package/dist/core/ingestion/languages/php/arity.js +40 -0
- package/dist/core/ingestion/languages/php/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/php/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/php/captures.d.ts +34 -0
- package/dist/core/ingestion/languages/php/captures.js +739 -0
- package/dist/core/ingestion/languages/php/import-decomposer.d.ts +28 -0
- package/dist/core/ingestion/languages/php/import-decomposer.js +265 -0
- package/dist/core/ingestion/languages/php/import-target.d.ts +47 -0
- package/dist/core/ingestion/languages/php/import-target.js +100 -0
- package/dist/core/ingestion/languages/php/index.d.ts +68 -0
- package/dist/core/ingestion/languages/php/index.js +72 -0
- package/dist/core/ingestion/languages/php/interpret.d.ts +36 -0
- package/dist/core/ingestion/languages/php/interpret.js +241 -0
- package/dist/core/ingestion/languages/php/merge-bindings.d.ts +19 -0
- package/dist/core/ingestion/languages/php/merge-bindings.js +47 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.d.ts +51 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.js +288 -0
- package/dist/core/ingestion/languages/php/query.d.ts +32 -0
- package/dist/core/ingestion/languages/php/query.js +326 -0
- package/dist/core/ingestion/languages/php/receiver-binding.d.ts +36 -0
- package/dist/core/ingestion/languages/php/receiver-binding.js +128 -0
- package/dist/core/ingestion/languages/php/scope-resolver.d.ts +23 -0
- package/dist/core/ingestion/languages/php/scope-resolver.js +358 -0
- package/dist/core/ingestion/languages/php/simple-hooks.d.ts +42 -0
- package/dist/core/ingestion/languages/php/simple-hooks.js +111 -0
- package/dist/core/ingestion/languages/php.d.ts +1 -0
- package/dist/core/ingestion/languages/php.js +290 -0
- package/dist/core/ingestion/languages/python/arity-metadata.d.ts +24 -0
- package/dist/core/ingestion/languages/python/arity-metadata.js +45 -0
- package/dist/core/ingestion/languages/python/arity.d.ts +22 -0
- package/dist/core/ingestion/languages/python/arity.js +38 -0
- package/dist/core/ingestion/languages/python/cache-stats.d.ts +17 -0
- package/dist/core/ingestion/languages/python/cache-stats.js +28 -0
- package/dist/core/ingestion/languages/python/captures.d.ts +19 -0
- package/dist/core/ingestion/languages/python/captures.js +130 -0
- package/dist/core/ingestion/languages/python/import-decomposer.d.ts +15 -0
- package/dist/core/ingestion/languages/python/import-decomposer.js +112 -0
- package/dist/core/ingestion/languages/python/import-target.d.ts +21 -0
- package/dist/core/ingestion/languages/python/import-target.js +195 -0
- package/dist/core/ingestion/languages/python/index.d.ts +80 -0
- package/dist/core/ingestion/languages/python/index.js +80 -0
- package/dist/core/ingestion/languages/python/interpret.d.ts +15 -0
- package/dist/core/ingestion/languages/python/interpret.js +191 -0
- package/dist/core/ingestion/languages/python/merge-bindings.d.ts +16 -0
- package/dist/core/ingestion/languages/python/merge-bindings.js +44 -0
- package/dist/core/ingestion/languages/python/query.d.ts +9 -0
- package/dist/core/ingestion/languages/python/query.js +267 -0
- package/dist/core/ingestion/languages/python/receiver-binding.d.ts +21 -0
- package/dist/core/ingestion/languages/python/receiver-binding.js +116 -0
- package/dist/core/ingestion/languages/python/scope-resolver.d.ts +16 -0
- package/dist/core/ingestion/languages/python/scope-resolver.js +53 -0
- package/dist/core/ingestion/languages/python/simple-hooks.d.ts +25 -0
- package/dist/core/ingestion/languages/python/simple-hooks.js +43 -0
- package/dist/core/ingestion/languages/python.d.ts +12 -0
- package/dist/core/ingestion/languages/python.js +133 -0
- package/dist/core/ingestion/languages/ruby.d.ts +9 -0
- package/dist/core/ingestion/languages/ruby.js +235 -0
- package/dist/core/ingestion/languages/rust.d.ts +12 -0
- package/dist/core/ingestion/languages/rust.js +167 -0
- package/dist/core/ingestion/languages/swift.d.ts +12 -0
- package/dist/core/ingestion/languages/swift.js +312 -0
- package/dist/core/ingestion/languages/typescript/arity-metadata.d.ts +59 -0
- package/dist/core/ingestion/languages/typescript/arity-metadata.js +103 -0
- package/dist/core/ingestion/languages/typescript/arity.d.ts +37 -0
- package/dist/core/ingestion/languages/typescript/arity.js +54 -0
- package/dist/core/ingestion/languages/typescript/cache-stats.d.ts +17 -0
- package/dist/core/ingestion/languages/typescript/cache-stats.js +28 -0
- package/dist/core/ingestion/languages/typescript/captures.d.ts +28 -0
- package/dist/core/ingestion/languages/typescript/captures.js +474 -0
- package/dist/core/ingestion/languages/typescript/import-decomposer.d.ts +49 -0
- package/dist/core/ingestion/languages/typescript/import-decomposer.js +371 -0
- package/dist/core/ingestion/languages/typescript/import-target.d.ts +50 -0
- package/dist/core/ingestion/languages/typescript/import-target.js +61 -0
- package/dist/core/ingestion/languages/typescript/index.d.ts +94 -0
- package/dist/core/ingestion/languages/typescript/index.js +94 -0
- package/dist/core/ingestion/languages/typescript/interpret.d.ts +35 -0
- package/dist/core/ingestion/languages/typescript/interpret.js +317 -0
- package/dist/core/ingestion/languages/typescript/merge-bindings.d.ts +62 -0
- package/dist/core/ingestion/languages/typescript/merge-bindings.js +158 -0
- package/dist/core/ingestion/languages/typescript/query.d.ts +84 -0
- package/dist/core/ingestion/languages/typescript/query.js +978 -0
- package/dist/core/ingestion/languages/typescript/receiver-binding.d.ts +59 -0
- package/dist/core/ingestion/languages/typescript/receiver-binding.js +171 -0
- package/dist/core/ingestion/languages/typescript/scope-resolver.d.ts +16 -0
- package/dist/core/ingestion/languages/typescript/scope-resolver.js +113 -0
- package/dist/core/ingestion/languages/typescript/simple-hooks.d.ts +71 -0
- package/dist/core/ingestion/languages/typescript/simple-hooks.js +131 -0
- package/dist/core/ingestion/languages/typescript.d.ts +11 -0
- package/dist/core/ingestion/languages/typescript.js +324 -0
- package/dist/core/ingestion/languages/vue.d.ts +13 -0
- package/dist/core/ingestion/languages/vue.js +79 -0
- package/dist/core/ingestion/markdown-processor.d.ts +17 -0
- package/dist/core/ingestion/markdown-processor.js +124 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +287 -0
- package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
- package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +336 -0
- package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
- package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.js +286 -0
- package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
- package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +276 -0
- package/dist/core/ingestion/method-extractors/configs/typescript-javascript.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +338 -0
- package/dist/core/ingestion/method-extractors/generic.d.ts +11 -0
- package/dist/core/ingestion/method-extractors/generic.js +205 -0
- package/dist/core/ingestion/method-types.d.ts +90 -0
- package/dist/core/ingestion/method-types.js +2 -0
- package/dist/core/ingestion/model/field-registry.d.ts +18 -0
- package/dist/core/ingestion/model/field-registry.js +22 -0
- package/dist/core/ingestion/model/heritage-map.d.ts +105 -0
- package/dist/core/ingestion/model/heritage-map.js +260 -0
- package/dist/core/ingestion/model/index.d.ts +20 -0
- package/dist/core/ingestion/model/index.js +43 -0
- package/dist/core/ingestion/model/method-registry.d.ts +71 -0
- package/dist/core/ingestion/model/method-registry.js +134 -0
- package/dist/core/ingestion/model/registration-table.d.ts +138 -0
- package/dist/core/ingestion/model/registration-table.js +224 -0
- package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
- package/dist/core/ingestion/model/resolution-context.js +337 -0
- package/dist/core/ingestion/model/resolve.d.ts +61 -0
- package/dist/core/ingestion/model/resolve.js +401 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +72 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +150 -0
- package/dist/core/ingestion/model/semantic-model.js +175 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +200 -0
- package/dist/core/ingestion/model/symbol-table.js +206 -0
- package/dist/core/ingestion/model/type-registry.d.ts +39 -0
- package/dist/core/ingestion/model/type-registry.js +62 -0
- package/dist/core/ingestion/mro-processor.d.ts +46 -0
- package/dist/core/ingestion/mro-processor.js +597 -0
- package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/csharp.js +37 -0
- package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/java.js +29 -0
- package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
- package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/php.js +61 -0
- package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/python.js +49 -0
- package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/rust.js +66 -0
- package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
- package/dist/core/ingestion/named-bindings/types.js +6 -0
- package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
- package/dist/core/ingestion/named-bindings/typescript.js +58 -0
- package/dist/core/ingestion/parsing-processor.d.ts +60 -0
- package/dist/core/ingestion/parsing-processor.js +627 -0
- package/dist/core/ingestion/pipeline-phases/cobol.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/cobol.js +46 -0
- package/dist/core/ingestion/pipeline-phases/communities.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/communities.js +63 -0
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +157 -0
- package/dist/core/ingestion/pipeline-phases/cross-file.d.ts +37 -0
- package/dist/core/ingestion/pipeline-phases/cross-file.js +64 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/index.js +23 -0
- package/dist/core/ingestion/pipeline-phases/markdown.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/markdown.js +34 -0
- package/dist/core/ingestion/pipeline-phases/mro.d.ts +18 -0
- package/dist/core/ingestion/pipeline-phases/mro.js +37 -0
- package/dist/core/ingestion/pipeline-phases/orm-extraction.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/orm-extraction.js +92 -0
- package/dist/core/ingestion/pipeline-phases/orm.d.ts +15 -0
- package/dist/core/ingestion/pipeline-phases/orm.js +75 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +63 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +567 -0
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +88 -0
- package/dist/core/ingestion/pipeline-phases/parse.js +33 -0
- package/dist/core/ingestion/pipeline-phases/processes.d.ts +16 -0
- package/dist/core/ingestion/pipeline-phases/processes.js +149 -0
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +244 -0
- package/dist/core/ingestion/pipeline-phases/runner.d.ts +22 -0
- package/dist/core/ingestion/pipeline-phases/runner.js +204 -0
- package/dist/core/ingestion/pipeline-phases/scan.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/scan.js +46 -0
- package/dist/core/ingestion/pipeline-phases/structure.d.ts +27 -0
- package/dist/core/ingestion/pipeline-phases/structure.js +35 -0
- package/dist/core/ingestion/pipeline-phases/tools.d.ts +21 -0
- package/dist/core/ingestion/pipeline-phases/tools.js +86 -0
- package/dist/core/ingestion/pipeline-phases/types.d.ts +79 -0
- package/dist/core/ingestion/pipeline-phases/types.js +37 -0
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.d.ts +70 -0
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.js +312 -0
- package/dist/core/ingestion/pipeline.d.ts +49 -0
- package/dist/core/ingestion/pipeline.js +89 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +318 -0
- package/dist/core/ingestion/registry-primary-flag.d.ts +88 -0
- package/dist/core/ingestion/registry-primary-flag.js +117 -0
- package/dist/core/ingestion/resolve-references.d.ts +63 -0
- package/dist/core/ingestion/resolve-references.js +175 -0
- package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
- package/dist/core/ingestion/route-extractors/expo.js +36 -0
- package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
- package/dist/core/ingestion/route-extractors/middleware.js +167 -0
- package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
- package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
- package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
- package/dist/core/ingestion/route-extractors/php.js +22 -0
- package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
- package/dist/core/ingestion/route-extractors/response-shapes.js +294 -0
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +35 -0
- package/dist/core/ingestion/scope-extractor-bridge.js +49 -0
- package/dist/core/ingestion/scope-extractor.d.ts +86 -0
- package/dist/core/ingestion/scope-extractor.js +772 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +558 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +250 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +43 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +79 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +57 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +142 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +46 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +19 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +40 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.d.ts +37 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +118 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +38 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +73 -0
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +42 -0
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +467 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +53 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +251 -0
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +202 -0
- package/dist/core/ingestion/scope-resolution/passes/mro.d.ts +42 -0
- package/dist/core/ingestion/scope-resolution/passes/mro.js +102 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +30 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +81 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +46 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +377 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +47 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +152 -0
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.d.ts +68 -0
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +125 -0
- package/dist/core/ingestion/scope-resolution/pipeline/registry.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +31 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +91 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +218 -0
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.d.ts +39 -0
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +65 -0
- package/dist/core/ingestion/scope-resolution/scope/namespace-targets.d.ts +36 -0
- package/dist/core/ingestion/scope-resolution/scope/namespace-targets.js +58 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +170 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +447 -0
- package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +52 -0
- package/dist/core/ingestion/scope-resolution/workspace-index.js +61 -0
- package/dist/core/ingestion/shadow-harness.d.ts +113 -0
- package/dist/core/ingestion/shadow-harness.js +148 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +16 -0
- package/dist/core/ingestion/tree-sitter-queries.js +1497 -0
- package/dist/core/ingestion/type-env.d.ts +86 -0
- package/dist/core/ingestion/type-env.js +1129 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +7 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +532 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +583 -0
- package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
- package/dist/core/ingestion/type-extractors/dart.js +369 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +513 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +856 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +534 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +474 -0
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +377 -0
- package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +515 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +131 -0
- package/dist/core/ingestion/type-extractors/shared.js +796 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +487 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +172 -0
- package/dist/core/ingestion/type-extractors/types.js +1 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +661 -0
- package/dist/core/ingestion/utils/ast-helpers.d.ts +102 -0
- package/dist/core/ingestion/utils/ast-helpers.js +561 -0
- package/dist/core/ingestion/utils/call-analysis.d.ts +75 -0
- package/dist/core/ingestion/utils/call-analysis.js +574 -0
- package/dist/core/ingestion/utils/env.d.ts +20 -0
- package/dist/core/ingestion/utils/env.js +24 -0
- package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
- package/dist/core/ingestion/utils/event-loop.js +5 -0
- package/dist/core/ingestion/utils/graph-sort.d.ts +58 -0
- package/dist/core/ingestion/utils/graph-sort.js +100 -0
- package/dist/core/ingestion/utils/max-file-size.d.ts +20 -0
- package/dist/core/ingestion/utils/max-file-size.js +53 -0
- package/dist/core/ingestion/utils/method-props.d.ts +32 -0
- package/dist/core/ingestion/utils/method-props.js +147 -0
- package/dist/core/ingestion/utils/ruby-self-call.d.ts +52 -0
- package/dist/core/ingestion/utils/ruby-self-call.js +59 -0
- package/dist/core/ingestion/utils/verbose.d.ts +1 -0
- package/dist/core/ingestion/utils/verbose.js +7 -0
- package/dist/core/ingestion/variable-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/variable-extractors/configs/c-cpp.js +81 -0
- package/dist/core/ingestion/variable-extractors/configs/csharp.d.ts +9 -0
- package/dist/core/ingestion/variable-extractors/configs/csharp.js +63 -0
- package/dist/core/ingestion/variable-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/variable-extractors/configs/dart.js +94 -0
- package/dist/core/ingestion/variable-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/variable-extractors/configs/go.js +83 -0
- package/dist/core/ingestion/variable-extractors/configs/jvm.d.ts +18 -0
- package/dist/core/ingestion/variable-extractors/configs/jvm.js +115 -0
- package/dist/core/ingestion/variable-extractors/configs/php.d.ts +14 -0
- package/dist/core/ingestion/variable-extractors/configs/php.js +58 -0
- package/dist/core/ingestion/variable-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/variable-extractors/configs/python.js +101 -0
- package/dist/core/ingestion/variable-extractors/configs/ruby.d.ts +11 -0
- package/dist/core/ingestion/variable-extractors/configs/ruby.js +52 -0
- package/dist/core/ingestion/variable-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/variable-extractors/configs/rust.js +76 -0
- package/dist/core/ingestion/variable-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/variable-extractors/configs/swift.js +88 -0
- package/dist/core/ingestion/variable-extractors/configs/typescript-javascript.d.ts +3 -0
- package/dist/core/ingestion/variable-extractors/configs/typescript-javascript.js +83 -0
- package/dist/core/ingestion/variable-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/variable-extractors/generic.js +80 -0
- package/dist/core/ingestion/variable-types.d.ts +82 -0
- package/dist/core/ingestion/variable-types.js +2 -0
- package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
- package/dist/core/ingestion/vue-sfc-extractor.js +111 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +199 -0
- package/dist/core/ingestion/workers/parse-worker.js +1940 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +23 -0
- package/dist/core/ingestion/workers/worker-pool.js +380 -0
- package/dist/core/lbug/csv-generator.d.ts +33 -0
- package/dist/core/lbug/csv-generator.js +463 -0
- package/dist/core/lbug/extension-loader.d.ts +86 -0
- package/dist/core/lbug/extension-loader.js +186 -0
- package/dist/core/lbug/lbug-adapter.d.ts +243 -0
- package/dist/core/lbug/lbug-adapter.js +1377 -0
- package/dist/core/lbug/lbug-config.d.ts +102 -0
- package/dist/core/lbug/lbug-config.js +303 -0
- package/dist/core/lbug/pool-adapter.d.ts +90 -0
- package/dist/core/lbug/pool-adapter.js +592 -0
- package/dist/core/lbug/schema.d.ts +62 -0
- package/dist/core/lbug/schema.js +495 -0
- package/dist/core/logger.d.ts +125 -0
- package/dist/core/logger.js +323 -0
- package/dist/core/platform/capabilities.d.ts +24 -0
- package/dist/core/platform/capabilities.js +54 -0
- package/dist/core/run-analyze.d.ts +92 -0
- package/dist/core/run-analyze.js +672 -0
- package/dist/core/search/bm25-index.d.ts +29 -0
- package/dist/core/search/bm25-index.js +118 -0
- package/dist/core/search/fts-indexes.d.ts +1 -0
- package/dist/core/search/fts-indexes.js +7 -0
- package/dist/core/search/fts-schema.d.ts +6 -0
- package/dist/core/search/fts-schema.js +7 -0
- package/dist/core/search/hybrid-search.d.ts +53 -0
- package/dist/core/search/hybrid-search.js +136 -0
- package/dist/core/search/phase-timer.d.ts +72 -0
- package/dist/core/search/phase-timer.js +106 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +8 -0
- package/dist/core/tree-sitter/parser-loader.js +189 -0
- package/dist/core/tree-sitter/safe-parse.d.ts +6 -0
- package/dist/core/tree-sitter/safe-parse.js +32 -0
- package/dist/core/wiki/cursor-client.d.ts +31 -0
- package/dist/core/wiki/cursor-client.js +123 -0
- package/dist/core/wiki/generator.d.ts +129 -0
- package/dist/core/wiki/generator.js +899 -0
- package/dist/core/wiki/graph-queries.d.ts +84 -0
- package/dist/core/wiki/graph-queries.js +244 -0
- package/dist/core/wiki/html-viewer.d.ts +10 -0
- package/dist/core/wiki/html-viewer.js +304 -0
- package/dist/core/wiki/llm-client.d.ts +83 -0
- package/dist/core/wiki/llm-client.js +267 -0
- package/dist/core/wiki/mermaid-sanitizer.d.ts +2 -0
- package/dist/core/wiki/mermaid-sanitizer.js +100 -0
- package/dist/core/wiki/prompts.d.ts +53 -0
- package/dist/core/wiki/prompts.js +181 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +206 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +145 -0
- package/dist/mcp/core/lbug-adapter.d.ts +11 -0
- package/dist/mcp/core/lbug-adapter.js +11 -0
- package/dist/mcp/local/local-backend.d.ts +356 -0
- package/dist/mcp/local/local-backend.js +3251 -0
- package/dist/mcp/resources.d.ts +62 -0
- package/dist/mcp/resources.js +512 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +314 -0
- package/dist/mcp/staleness.d.ts +5 -0
- package/dist/mcp/staleness.js +4 -0
- package/dist/mcp/stdio-capture.d.ts +40 -0
- package/dist/mcp/stdio-capture.js +53 -0
- package/dist/mcp/stdio-context.d.ts +47 -0
- package/dist/mcp/stdio-context.js +145 -0
- package/dist/mcp/tools.d.ts +29 -0
- package/dist/mcp/tools.js +506 -0
- package/dist/server/analyze-job.d.ts +55 -0
- package/dist/server/analyze-job.js +150 -0
- package/dist/server/analyze-worker.d.ts +13 -0
- package/dist/server/analyze-worker.js +59 -0
- package/dist/server/api.d.ts +72 -0
- package/dist/server/api.js +1638 -0
- package/dist/server/git-clone.d.ts +99 -0
- package/dist/server/git-clone.js +397 -0
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +101 -0
- package/dist/server/validation.d.ts +98 -0
- package/dist/server/validation.js +142 -0
- package/dist/storage/file-hash.d.ts +47 -0
- package/dist/storage/file-hash.js +86 -0
- package/dist/storage/git.d.ts +148 -0
- package/dist/storage/git.js +346 -0
- package/dist/storage/parse-cache.d.ts +67 -0
- package/dist/storage/parse-cache.js +182 -0
- package/dist/storage/repo-manager.d.ts +467 -0
- package/dist/storage/repo-manager.js +804 -0
- package/dist/types/pipeline.d.ts +18 -0
- package/dist/types/pipeline.js +1 -0
- package/hooks/claude/arc-hook.cjs +334 -0
- package/hooks/claude/hook-lock.cjs +119 -0
- package/hooks/claude/pre-tool-use.sh +79 -0
- package/hooks/claude/session-start.sh +42 -0
- package/package.json +122 -0
- package/scripts/bench-scope-resolution.ts +134 -0
- package/scripts/build-tree-sitter-dart.cjs +53 -0
- package/scripts/build-tree-sitter-proto.cjs +93 -0
- package/scripts/build.js +99 -0
- package/scripts/ci-list-migrated-languages.ts +24 -0
- package/scripts/install-duckdb-extension.mjs +48 -0
- package/skills/arc-cli.md +83 -0
- package/skills/arc-debugging.md +89 -0
- package/skills/arc-exploring.md +78 -0
- package/skills/arc-guide.md +64 -0
- package/skills/arc-impact-analysis.md +97 -0
- package/skills/arc-pr-review.md +163 -0
- package/skills/arc-refactoring.md +121 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
- package/vendor/tree-sitter-dart/README.md +18 -0
- package/vendor/tree-sitter-dart/binding.gyp +31 -0
- package/vendor/tree-sitter-dart/bindings/node/binding.cc +20 -0
- package/vendor/tree-sitter-dart/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-dart/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-dart/grammar.js +2895 -0
- package/vendor/tree-sitter-dart/package.json +18 -0
- package/vendor/tree-sitter-dart/queries/highlights.scm +246 -0
- package/vendor/tree-sitter-dart/queries/tags.scm +92 -0
- package/vendor/tree-sitter-dart/queries/test.scm +1 -0
- package/vendor/tree-sitter-dart/src/grammar.json +12459 -0
- package/vendor/tree-sitter-dart/src/node-types.json +15055 -0
- package/vendor/tree-sitter-dart/src/parser.c +196127 -0
- package/vendor/tree-sitter-dart/src/scanner.c +130 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/array.h +290 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/parser.h +265 -0
- package/vendor/tree-sitter-proto/binding.gyp +30 -0
- package/vendor/tree-sitter-proto/bindings/node/binding.cc +20 -0
- package/vendor/tree-sitter-proto/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-proto/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-proto/package.json +12 -0
- package/vendor/tree-sitter-proto/src/node-types.json +1145 -0
- package/vendor/tree-sitter-proto/src/parser.c +10149 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/array.h +291 -0
- package/vendor/tree-sitter-proto/src/tree_sitter/parser.h +266 -0
- package/vendor/tree-sitter-swift/LICENSE +21 -0
- package/vendor/tree-sitter-swift/README.md +139 -0
- package/vendor/tree-sitter-swift/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-swift/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-swift/package.json +28 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/src/node-types.json +30694 -0
- package/web/assets/__vite-browser-external-CLwMvL_q.js +1 -0
- package/web/assets/agent-DaYmiVrk.js +601 -0
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-aGTGQQQG.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-613o-OfM.js +36 -0
- package/web/assets/blockDiagram-7IZFK4PR-BBJRt4vF.js +132 -0
- package/web/assets/c4Diagram-Y2BXMSZH-BhR2CErx.js +10 -0
- package/web/assets/chunk-3SSMPTDK-DWfEAoKy.js +321 -0
- package/web/assets/chunk-6764PJDD-NOXEgi3n.js +1 -0
- package/web/assets/chunk-AZZRMDJM-DVvcxwI7.js +15 -0
- package/web/assets/chunk-JQRUD6KW-CQgkrimK.js +1 -0
- package/web/assets/chunk-KGYTTC2M-DxOdSoAJ.js +161 -0
- package/web/assets/chunk-KRXBNO2N-BlnQTnxv.js +1 -0
- package/web/assets/chunk-LCXTWHL2-Dhf_u-1F.js +231 -0
- package/web/assets/chunk-LII3EMHJ-Cb3HLCZX.js +1 -0
- package/web/assets/chunk-RG4AUYOV-DLCfNede.js +206 -0
- package/web/assets/chunk-T5OCTHI4-B0CGAG7q.js +1 -0
- package/web/assets/chunk-W44A43WB-ZyrAMwtT.js +1 -0
- package/web/assets/chunk-ZXARS5L4-B0TJPmj5.js +1 -0
- package/web/assets/classDiagram-KGZ6W3CR-CvSnsfJD.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-CvSnsfJD.js +1 -0
- package/web/assets/context-builder-BREgwful.js +15 -0
- package/web/assets/cose-bilkent-UX7MHV2Q-BsPIaeag.js +1 -0
- package/web/assets/dagre-ND4H6XIP-CV4l9vOZ.js +4 -0
- package/web/assets/diagram-3NCE3AQN-9kSzEbS8.js +43 -0
- package/web/assets/diagram-GF46GFSD-qRvqbex6.js +24 -0
- package/web/assets/diagram-HNR7UZ2L-Dj_ye4Ua.js +3 -0
- package/web/assets/diagram-QXG6HAR7-COwBV6B0.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-C9xjn5dU.js +10 -0
- package/web/assets/erDiagram-L5TCEMPS-fRp0t1Yd.js +85 -0
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BR0Ygfrw.js +1 -0
- package/web/assets/flowDiagram-H6V6AXG4-Ccr8FDLD.js +162 -0
- package/web/assets/ganttDiagram-JCBTUEKG-DfBPqAGN.js +292 -0
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-CYihBz6Z.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CHvG_UQ0.js +106 -0
- package/web/assets/index-B7cw1L6-.css +2 -0
- package/web/assets/index-CJJQgfSH.js +886 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-BmmoeX4D.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-C7cMy-GP.js +2 -0
- package/web/assets/ishikawaDiagram-BNXS4ZKH-C80yCPYi.js +70 -0
- package/web/assets/journeyDiagram-M6C3CM3L-BHxH1zjE.js +139 -0
- package/web/assets/kanban-definition-75IXJCU3-DNZo1hOE.js +89 -0
- package/web/assets/katex-K3KEBU37-CbyuvTf1.js +261 -0
- package/web/assets/mindmap-definition-2TDM6QVE-Dpgl3Elt.js +96 -0
- package/web/assets/packet-YPE3B663-LP52Z2RK-7JAqDnUy.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-Bv9vE7io.js +1 -0
- package/web/assets/pieDiagram-CU6KROY3-BW0mr0ek.js +30 -0
- package/web/assets/quadrantDiagram-VICAPDV7-C1dCMBbk.js +7 -0
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-dtZpcOZd.js +1 -0
- package/web/assets/requirementDiagram-JXO7QTGE-Dyqqny4j.js +84 -0
- package/web/assets/sankeyDiagram-URQDO5SZ-B3FGr5SL.js +40 -0
- package/web/assets/sequenceDiagram-VS2MUI6T-B4LlGP9C.js +162 -0
- package/web/assets/stateDiagram-7D4R322I-V9F-klBP.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-CKDYYzqR.js +1 -0
- package/web/assets/timeline-definition-O6YCAMPW-CX2WjkZA.js +120 -0
- package/web/assets/treeView-BLDUP644-QA4HXRO3-BQaKTdhr.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-Bqlxdyrq.js +1 -0
- package/web/assets/vennDiagram-MWXL3ELB-BxZPYqOF.js +34 -0
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-dofeprUr.js +1 -0
- package/web/assets/wardleyDiagram-CUQ6CDDI-BLdJJYkV.js +78 -0
- package/web/assets/xychartDiagram-N2JHSOCM-DqDgigLa.js +7 -0
- package/web/index.html +19 -0
|
@@ -0,0 +1,1638 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP API Server
|
|
3
|
+
*
|
|
4
|
+
* REST API for browser-based clients to query the local .arc/ index.
|
|
5
|
+
* Also hosts the MCP server over StreamableHTTP for remote AI tool access.
|
|
6
|
+
*
|
|
7
|
+
* Security: binds to localhost by default (use --host to override).
|
|
8
|
+
* CORS is restricted to localhost, private/LAN networks, and the deployed site.
|
|
9
|
+
*/
|
|
10
|
+
import express from 'express';
|
|
11
|
+
import cors from 'cors';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import fs from 'fs/promises';
|
|
14
|
+
import { createRequire } from 'node:module';
|
|
15
|
+
import { loadMeta, listRegisteredRepos, getStoragePath } from '../storage/repo-manager.js';
|
|
16
|
+
import { executeQuery, executePrepared, executeWithReusedStatement, streamQuery, flushWAL, closeLbug, withLbugDb, } from '../core/lbug/lbug-adapter.js';
|
|
17
|
+
import { isWriteQuery } from '../core/lbug/pool-adapter.js';
|
|
18
|
+
import { NODE_TABLES } from '../_shared/index.js';
|
|
19
|
+
import { searchFTSFromLbug } from '../core/search/bm25-index.js';
|
|
20
|
+
import { hybridSearch } from '../core/search/hybrid-search.js';
|
|
21
|
+
import { LocalBackend } from '../mcp/local/local-backend.js';
|
|
22
|
+
import { mountMCPEndpoints } from './mcp-http.js';
|
|
23
|
+
import { fork } from 'child_process';
|
|
24
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
25
|
+
import { JobManager } from './analyze-job.js';
|
|
26
|
+
import { assertString, escapeRegExp, BadRequestError, createRouteLimiter } from './validation.js';
|
|
27
|
+
import { extractRepoName, getCloneDir, cloneOrPull } from './git-clone.js';
|
|
28
|
+
import { logger, flushLoggerSync } from '../core/logger.js';
|
|
29
|
+
const _require = createRequire(import.meta.url);
|
|
30
|
+
const pkg = _require('../../package.json');
|
|
31
|
+
/**
|
|
32
|
+
* Determine whether an HTTP Origin header value is allowed by CORS policy.
|
|
33
|
+
*
|
|
34
|
+
* Permitted origins:
|
|
35
|
+
* - No origin (non-browser requests such as curl or server-to-server calls)
|
|
36
|
+
* - http://localhost:<port> — local development
|
|
37
|
+
* - http://127.0.0.1:<port> — loopback alias
|
|
38
|
+
* - RFC 1918 private/LAN networks (any port):
|
|
39
|
+
* 10.0.0.0/8 → 10.x.x.x
|
|
40
|
+
* 172.16.0.0/12 → 172.16.x.x – 172.31.x.x
|
|
41
|
+
* 192.168.0.0/16 → 192.168.x.x
|
|
42
|
+
* - https://arc.vercel.app — the deployed Arceus web UI
|
|
43
|
+
*
|
|
44
|
+
* @param origin - The value of the HTTP `Origin` request header, or `undefined`
|
|
45
|
+
* when the header is absent (non-browser request).
|
|
46
|
+
* @returns `true` if the origin is allowed, `false` otherwise.
|
|
47
|
+
*/
|
|
48
|
+
export const isAllowedOrigin = (origin) => {
|
|
49
|
+
if (origin === undefined) {
|
|
50
|
+
// Non-browser requests (curl, server-to-server) have no Origin header
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (origin.startsWith('http://localhost:') ||
|
|
54
|
+
origin === 'http://localhost' ||
|
|
55
|
+
origin.startsWith('http://127.0.0.1:') ||
|
|
56
|
+
origin === 'http://127.0.0.1' ||
|
|
57
|
+
origin.startsWith('http://[::1]:') ||
|
|
58
|
+
origin === 'http://[::1]' ||
|
|
59
|
+
origin === 'https://arc.vercel.app') {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
// RFC 1918 private network ranges — allow any port on these hosts.
|
|
63
|
+
// We parse the hostname out of the origin URL and check against each range.
|
|
64
|
+
let hostname;
|
|
65
|
+
let protocol;
|
|
66
|
+
try {
|
|
67
|
+
const parsed = new URL(origin);
|
|
68
|
+
hostname = parsed.hostname;
|
|
69
|
+
protocol = parsed.protocol;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Malformed origin — reject
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
// Only allow HTTP(S) origins — reject ftp://, file://, etc.
|
|
76
|
+
if (protocol !== 'http:' && protocol !== 'https:')
|
|
77
|
+
return false;
|
|
78
|
+
const octets = hostname.split('.').map(Number);
|
|
79
|
+
if (octets.length !== 4 || octets.some((o) => !Number.isInteger(o) || o < 0 || o > 255)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const [a, b] = octets;
|
|
83
|
+
// 10.0.0.0/8
|
|
84
|
+
if (a === 10)
|
|
85
|
+
return true;
|
|
86
|
+
// 172.16.0.0/12 → 172.16.x.x – 172.31.x.x
|
|
87
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
88
|
+
return true;
|
|
89
|
+
// 192.168.0.0/16
|
|
90
|
+
if (a === 192 && b === 168)
|
|
91
|
+
return true;
|
|
92
|
+
return false;
|
|
93
|
+
};
|
|
94
|
+
export class ClientDisconnectedError extends Error {
|
|
95
|
+
constructor() {
|
|
96
|
+
super('Client disconnected during graph stream');
|
|
97
|
+
this.name = 'ClientDisconnectedError';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export const isIgnorableGraphQueryError = (err) => {
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
return (message.includes('does not exist') ||
|
|
103
|
+
message.includes('not found') ||
|
|
104
|
+
message.includes('No table named'));
|
|
105
|
+
};
|
|
106
|
+
export const SPA_FALLBACK_REGEX = /^(?!\/api(?:\/|$))(?!.*\.\w{1,10}$).*/;
|
|
107
|
+
export const resolveWebDistDir = async (primaryDir, fallbackDir) => {
|
|
108
|
+
const envDir = process.env.ARC_WEB_DIST;
|
|
109
|
+
const dirs = envDir ? [envDir, primaryDir, fallbackDir] : [primaryDir, fallbackDir];
|
|
110
|
+
for (const dir of dirs) {
|
|
111
|
+
try {
|
|
112
|
+
await fs.access(path.join(dir, 'index.html'));
|
|
113
|
+
return dir;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
if (err?.code !== 'ENOENT') {
|
|
117
|
+
logger.warn({ err: err.message }, `[serve] could not access web UI dir ${dir}:`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
};
|
|
123
|
+
export const landingPageHtml = () => `<!DOCTYPE html>
|
|
124
|
+
<html lang="en">
|
|
125
|
+
<head>
|
|
126
|
+
<meta charset="utf-8">
|
|
127
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
128
|
+
<title>Arceus</title>
|
|
129
|
+
<style>
|
|
130
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
131
|
+
body{font-family:Outfit,system-ui,-apple-system,sans-serif;background:#06060a;color:#e4e4ed;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:1.5rem}
|
|
132
|
+
.card{background:#101018;border:1px solid #2a2a3a;border-radius:0.75rem;padding:2rem;max-width:480px;width:100%}
|
|
133
|
+
.logo{font-size:1.5rem;font-weight:700;color:#e4e4ed;letter-spacing:-0.02em;margin-bottom:0.25rem}
|
|
134
|
+
.subtitle{font-size:0.875rem;color:#8888a0;margin-bottom:1.5rem}
|
|
135
|
+
.section-title{font-size:0.75rem;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#5a5a70;margin-bottom:0.75rem}
|
|
136
|
+
.endpoint{margin:0.25rem 0;font-size:0.875rem}
|
|
137
|
+
.endpoint a{color:#f59e0b;text-decoration:none}
|
|
138
|
+
.endpoint a:hover{text-decoration:underline}
|
|
139
|
+
.endpoint code{background:#16161f;padding:0.15em 0.4em;border-radius:0.25rem;font-size:0.8rem;color:#8888a0}
|
|
140
|
+
.divider{height:1px;background:#1e1e2a;margin:1.25rem 0}
|
|
141
|
+
.terminal{background:#0a0a10;border:1px solid #1e1e2a;border-radius:0.5rem;padding:0.75rem 1rem;font-family:'SF Mono',SFMono-Regular,Consolas,'Liberation Mono',Menlo,monospace;font-size:0.8rem;color:#8888a0;margin-bottom:1rem;overflow-x:auto}
|
|
142
|
+
.terminal .prompt{color:#f59e0b;user-select:none}
|
|
143
|
+
.terminal .cmd{color:#e4e4ed}
|
|
144
|
+
.link-row{display:flex;align-items:center;gap:0.5rem;font-size:0.875rem;margin-top:0.5rem}
|
|
145
|
+
.link-row svg{flex-shrink:0}
|
|
146
|
+
a.ext{color:#f59e0b;text-decoration:none;display:inline-flex;align-items:center;gap:0.25rem}
|
|
147
|
+
a.ext:hover{text-decoration:underline}
|
|
148
|
+
</style>
|
|
149
|
+
</head>
|
|
150
|
+
<body>
|
|
151
|
+
<div class="card">
|
|
152
|
+
<div class="logo">Arceus</div>
|
|
153
|
+
<div class="subtitle">API server is running</div>
|
|
154
|
+
<div class="section-title">Endpoints</div>
|
|
155
|
+
<p class="endpoint"><a href="/api/info">/api/info</a> <span style="color:#5a5a70">— Server version & context</span></p>
|
|
156
|
+
<p class="endpoint"><a href="/api/repos">/api/repos</a> <span style="color:#5a5a70">— Indexed repositories</span></p>
|
|
157
|
+
<p class="endpoint"><code>/api/health</code> <span style="color:#5a5a70">— Docker/orchestrator healthcheck</span></p>
|
|
158
|
+
<p class="endpoint"><code>/api/heartbeat</code> <span style="color:#5a5a70">— SSE heartbeat</span></p>
|
|
159
|
+
<p class="endpoint"><code>/api/graph</code> <code>/api/query</code> <code>/api/search</code> <span style="color:#5a5a70">— Data</span></p>
|
|
160
|
+
<p class="endpoint"><code>/api/mcp</code> <span style="color:#5a5a70">— MCP over StreamableHTTP</span></p>
|
|
161
|
+
<div class="divider"></div>
|
|
162
|
+
<div class="section-title">Web UI not found</div>
|
|
163
|
+
<div class="terminal"><span class="prompt">$ </span><span class="cmd">cd arceus-web && npm run build</span></div>
|
|
164
|
+
<div class="link-row">
|
|
165
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
|
166
|
+
<a class="ext" href="https://arc.vercel.app" target="_blank" rel="noopener noreferrer">arc.vercel.app</a>
|
|
167
|
+
<span style="color:#5a5a70">— connects to this server</span>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</body>
|
|
171
|
+
</html>`;
|
|
172
|
+
export const staticCacheControlSetHeaders = (res, filePath) => {
|
|
173
|
+
if (filePath.endsWith('.html')) {
|
|
174
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
export const registerWebUI = (app, staticDir) => {
|
|
181
|
+
if (staticDir) {
|
|
182
|
+
app.use(express.static(staticDir, {
|
|
183
|
+
setHeaders: staticCacheControlSetHeaders,
|
|
184
|
+
}));
|
|
185
|
+
// ⚠ This must remain the LAST route before the global error handler.
|
|
186
|
+
// The regex excludes /api paths AND paths with file extensions (.js, .css, etc.)
|
|
187
|
+
// so missing assets get real 404s instead of the SPA HTML.
|
|
188
|
+
// Adding routes below this will be unreachable for non-API, non-asset paths.
|
|
189
|
+
// Rate-limited (CodeQL js/missing-rate-limiting): the SPA fallback
|
|
190
|
+
// serves a constant index.html, but the FS access from a route handler
|
|
191
|
+
// is enough to trip the analyzer. The limit is generous (300 rpm/IP =
|
|
192
|
+
// 5 req/s sustained) so that multi-tab browser navigation, prefetch,
|
|
193
|
+
// and service-worker revalidation do not produce 429s for legitimate
|
|
194
|
+
// SPA users. At this rate, real browser navigation is extremely
|
|
195
|
+
// unlikely to hit the limit in practice, so the cosmetic issue of
|
|
196
|
+
// JSON-on-429 to a browser is a low-likelihood path. Content
|
|
197
|
+
// negotiation on the 429 (returning the SPA shell to HTML clients
|
|
198
|
+
// instead of `{ error: '...' }`) would require swapping
|
|
199
|
+
// express-rate-limit's `message` for a `handler` function and is
|
|
200
|
+
// deferred to keep this PR focused on closing the CodeQL alert.
|
|
201
|
+
app.get(SPA_FALLBACK_REGEX, createRouteLimiter({ limit: 300 }), (_req, res) => {
|
|
202
|
+
res.sendFile(path.join(staticDir, 'index.html'));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
app.get('/', (_req, res) => {
|
|
207
|
+
res.type('html').send(landingPageHtml());
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const ensureStreamIsWritable = (res, signal) => {
|
|
212
|
+
if (signal?.aborted || res.destroyed || res.writableEnded) {
|
|
213
|
+
throw new ClientDisconnectedError();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const waitForDrain = async (res, signal) => {
|
|
217
|
+
ensureStreamIsWritable(res, signal);
|
|
218
|
+
await new Promise((resolve, reject) => {
|
|
219
|
+
const cleanup = () => {
|
|
220
|
+
res.off('drain', onDrain);
|
|
221
|
+
res.off('close', onClose);
|
|
222
|
+
signal?.removeEventListener('abort', onAbort);
|
|
223
|
+
};
|
|
224
|
+
const onDrain = () => {
|
|
225
|
+
cleanup();
|
|
226
|
+
resolve();
|
|
227
|
+
};
|
|
228
|
+
const onClose = () => {
|
|
229
|
+
cleanup();
|
|
230
|
+
reject(new ClientDisconnectedError());
|
|
231
|
+
};
|
|
232
|
+
const onAbort = () => {
|
|
233
|
+
cleanup();
|
|
234
|
+
reject(new ClientDisconnectedError());
|
|
235
|
+
};
|
|
236
|
+
res.once('drain', onDrain);
|
|
237
|
+
res.once('close', onClose);
|
|
238
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
239
|
+
if (signal?.aborted || res.destroyed || res.writableEnded) {
|
|
240
|
+
onAbort();
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
ensureStreamIsWritable(res, signal);
|
|
244
|
+
};
|
|
245
|
+
const isClientDisconnectWriteError = (err) => {
|
|
246
|
+
if (!(err instanceof Error))
|
|
247
|
+
return false;
|
|
248
|
+
return (err.code === 'ERR_STREAM_DESTROYED' ||
|
|
249
|
+
err.code === 'EPIPE' ||
|
|
250
|
+
err.code === 'ECONNRESET' ||
|
|
251
|
+
err.message.includes('write after end'));
|
|
252
|
+
};
|
|
253
|
+
export const writeNdjsonRecord = async (res, record, signal) => {
|
|
254
|
+
ensureStreamIsWritable(res, signal);
|
|
255
|
+
try {
|
|
256
|
+
const canContinue = res.write(JSON.stringify(record) + '\n');
|
|
257
|
+
if (!canContinue) {
|
|
258
|
+
await waitForDrain(res, signal);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
if (isClientDisconnectWriteError(err)) {
|
|
263
|
+
throw new ClientDisconnectedError();
|
|
264
|
+
}
|
|
265
|
+
throw err;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const buildGraph = async (includeContent = false) => {
|
|
269
|
+
const nodes = [];
|
|
270
|
+
for (const table of NODE_TABLES) {
|
|
271
|
+
try {
|
|
272
|
+
const rows = await executeQuery(getNodeQuery(table, includeContent));
|
|
273
|
+
for (const row of rows) {
|
|
274
|
+
nodes.push(mapGraphNodeRow(table, row, includeContent));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
if (!isIgnorableGraphQueryError(err)) {
|
|
279
|
+
throw err;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const relationships = [];
|
|
284
|
+
const relRows = await executeQuery(GRAPH_RELATIONSHIP_QUERY);
|
|
285
|
+
for (const row of relRows) {
|
|
286
|
+
relationships.push(mapGraphRelationshipRow(row));
|
|
287
|
+
}
|
|
288
|
+
return { nodes, relationships };
|
|
289
|
+
};
|
|
290
|
+
const GRAPH_RELATIONSHIP_QUERY = `MATCH (a)-[r:CodeRelation]->(b) RETURN a.id AS sourceId, b.id AS targetId, ` +
|
|
291
|
+
`r.type AS type, r.confidence AS confidence, r.reason AS reason, r.step AS step`;
|
|
292
|
+
const quoteNodeTable = (table) => `\`${table.replace(/`/g, '``')}\``;
|
|
293
|
+
const getNodeQuery = (table, includeContent) => {
|
|
294
|
+
const tableLabel = quoteNodeTable(table);
|
|
295
|
+
if (table === 'File') {
|
|
296
|
+
return includeContent
|
|
297
|
+
? `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath, n.content AS content`
|
|
298
|
+
: `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath`;
|
|
299
|
+
}
|
|
300
|
+
if (table === 'Folder') {
|
|
301
|
+
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath`;
|
|
302
|
+
}
|
|
303
|
+
if (table === 'Community') {
|
|
304
|
+
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.label AS label, n.heuristicLabel AS heuristicLabel, n.cohesion AS cohesion, n.symbolCount AS symbolCount`;
|
|
305
|
+
}
|
|
306
|
+
if (table === 'Process') {
|
|
307
|
+
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.label AS label, n.heuristicLabel AS heuristicLabel, n.processType AS processType, n.stepCount AS stepCount, n.communities AS communities, n.entryPointId AS entryPointId, n.terminalId AS terminalId`;
|
|
308
|
+
}
|
|
309
|
+
if (table === 'Route') {
|
|
310
|
+
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath, n.responseKeys AS responseKeys, n.errorKeys AS errorKeys, n.middleware AS middleware`;
|
|
311
|
+
}
|
|
312
|
+
if (table === 'Tool') {
|
|
313
|
+
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath, n.description AS description`;
|
|
314
|
+
}
|
|
315
|
+
return includeContent
|
|
316
|
+
? `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.content AS content`
|
|
317
|
+
: `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine`;
|
|
318
|
+
};
|
|
319
|
+
const mapGraphNodeRow = (table, row, includeContent) => ({
|
|
320
|
+
id: row.id ?? row[0],
|
|
321
|
+
label: table,
|
|
322
|
+
properties: {
|
|
323
|
+
name: row.name ?? row.label ?? row[1],
|
|
324
|
+
filePath: row.filePath ?? row[2],
|
|
325
|
+
startLine: row.startLine,
|
|
326
|
+
endLine: row.endLine,
|
|
327
|
+
content: includeContent ? row.content : undefined,
|
|
328
|
+
responseKeys: row.responseKeys,
|
|
329
|
+
errorKeys: row.errorKeys,
|
|
330
|
+
middleware: row.middleware,
|
|
331
|
+
heuristicLabel: row.heuristicLabel,
|
|
332
|
+
cohesion: row.cohesion,
|
|
333
|
+
symbolCount: row.symbolCount,
|
|
334
|
+
description: row.description,
|
|
335
|
+
processType: row.processType,
|
|
336
|
+
stepCount: row.stepCount,
|
|
337
|
+
communities: row.communities,
|
|
338
|
+
entryPointId: row.entryPointId,
|
|
339
|
+
terminalId: row.terminalId,
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
const mapGraphRelationshipRow = (row) => ({
|
|
343
|
+
id: `${row.sourceId}_${row.type}_${row.targetId}`,
|
|
344
|
+
type: row.type,
|
|
345
|
+
sourceId: row.sourceId,
|
|
346
|
+
targetId: row.targetId,
|
|
347
|
+
confidence: row.confidence,
|
|
348
|
+
reason: row.reason,
|
|
349
|
+
step: row.step,
|
|
350
|
+
});
|
|
351
|
+
export const streamGraphNdjson = async (res, includeContent = false, signal) => {
|
|
352
|
+
for (const table of NODE_TABLES) {
|
|
353
|
+
try {
|
|
354
|
+
await streamQuery(getNodeQuery(table, includeContent), async (row) => {
|
|
355
|
+
await writeNdjsonRecord(res, {
|
|
356
|
+
type: 'node',
|
|
357
|
+
data: mapGraphNodeRow(table, row, includeContent),
|
|
358
|
+
}, signal);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
if (!isIgnorableGraphQueryError(err)) {
|
|
363
|
+
throw err;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
await streamQuery(GRAPH_RELATIONSHIP_QUERY, async (row) => {
|
|
368
|
+
await writeNdjsonRecord(res, {
|
|
369
|
+
type: 'relationship',
|
|
370
|
+
data: mapGraphRelationshipRow(row),
|
|
371
|
+
}, signal);
|
|
372
|
+
});
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* Mounts the SSE progress route using a custom decoupled handler structure.
|
|
376
|
+
*/
|
|
377
|
+
function mountSSEProgress(app, routePath, jm) {
|
|
378
|
+
const sseProgressHandler = (req, res) => {
|
|
379
|
+
const { jobId } = req.params;
|
|
380
|
+
const currentJob = jm.getJob(jobId);
|
|
381
|
+
if (!currentJob) {
|
|
382
|
+
res.status(404).json({ error: 'Job not found' });
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
let streamEventId = 0;
|
|
386
|
+
res.writeHead(200, {
|
|
387
|
+
'Content-Type': 'text/event-stream',
|
|
388
|
+
'Cache-Control': 'no-cache',
|
|
389
|
+
Connection: 'keep-alive',
|
|
390
|
+
'X-Accel-Buffering': 'no',
|
|
391
|
+
});
|
|
392
|
+
streamEventId++;
|
|
393
|
+
res.write(`id: ${streamEventId}\ndata: ${JSON.stringify(currentJob.progress)}\n\n`);
|
|
394
|
+
if (currentJob.status === 'complete' || currentJob.status === 'failed') {
|
|
395
|
+
streamEventId++;
|
|
396
|
+
res.write(`id: ${streamEventId}\nevent: ${currentJob.status}\ndata: ${JSON.stringify({
|
|
397
|
+
repoName: currentJob.repoName,
|
|
398
|
+
error: currentJob.error,
|
|
399
|
+
})}\n\n`);
|
|
400
|
+
res.end();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const sseHeartbeatTimer = setInterval(() => {
|
|
404
|
+
try {
|
|
405
|
+
res.write(':heartbeat\n\n');
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
clearInterval(sseHeartbeatTimer);
|
|
409
|
+
removeSubscription();
|
|
410
|
+
}
|
|
411
|
+
}, 30_000);
|
|
412
|
+
const removeSubscription = jm.onProgress(currentJob.id, (prog) => {
|
|
413
|
+
try {
|
|
414
|
+
streamEventId++;
|
|
415
|
+
if (prog.phase === 'complete' || prog.phase === 'failed') {
|
|
416
|
+
const freshJob = jm.getJob(jobId);
|
|
417
|
+
res.write(`id: ${streamEventId}\nevent: ${prog.phase}\ndata: ${JSON.stringify({
|
|
418
|
+
repoName: freshJob?.repoName,
|
|
419
|
+
error: freshJob?.error,
|
|
420
|
+
})}\n\n`);
|
|
421
|
+
clearInterval(sseHeartbeatTimer);
|
|
422
|
+
res.end();
|
|
423
|
+
removeSubscription();
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
res.write(`id: ${streamEventId}\ndata: ${JSON.stringify(prog)}\n\n`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
clearInterval(sseHeartbeatTimer);
|
|
431
|
+
removeSubscription();
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
req.on('close', () => {
|
|
435
|
+
clearInterval(sseHeartbeatTimer);
|
|
436
|
+
removeSubscription();
|
|
437
|
+
});
|
|
438
|
+
};
|
|
439
|
+
app.get(routePath, sseProgressHandler);
|
|
440
|
+
}
|
|
441
|
+
const statusFromError = (err) => {
|
|
442
|
+
// Validation helpers throw BadRequestError / ForbiddenError with a typed
|
|
443
|
+
// .status field — honor it before falling back to message-string matching.
|
|
444
|
+
if (err instanceof BadRequestError)
|
|
445
|
+
return err.status;
|
|
446
|
+
const msg = String(err?.message ?? '');
|
|
447
|
+
if (msg.includes('No indexed repositories') || msg.includes('not found'))
|
|
448
|
+
return 404;
|
|
449
|
+
if (msg.includes('Multiple repositories'))
|
|
450
|
+
return 400;
|
|
451
|
+
return 500;
|
|
452
|
+
};
|
|
453
|
+
const requestedRepo = (req) => {
|
|
454
|
+
const fromQuery = typeof req.query.repo === 'string' ? req.query.repo : undefined;
|
|
455
|
+
if (fromQuery)
|
|
456
|
+
return fromQuery;
|
|
457
|
+
if (req.body && typeof req.body === 'object' && typeof req.body.repo === 'string') {
|
|
458
|
+
return req.body.repo;
|
|
459
|
+
}
|
|
460
|
+
return undefined;
|
|
461
|
+
};
|
|
462
|
+
/**
|
|
463
|
+
* Handle a GET /api/file request body. Extracted from createServer's route
|
|
464
|
+
* registration so it can be unit-tested without spinning up an HTTP server
|
|
465
|
+
* — calling app.get(...) inside a test triggers CodeQL's
|
|
466
|
+
* js/missing-rate-limiting query, which is appropriate for production
|
|
467
|
+
* route handlers but a false positive for tests of the handler logic.
|
|
468
|
+
*
|
|
469
|
+
* The function takes the express req and res (typed loosely so test code
|
|
470
|
+
* can pass minimal mocks) plus the resolved repo path. All path-traversal
|
|
471
|
+
* containment is done inline at the readFile sink with the canonical
|
|
472
|
+
* path.relative idiom for CodeQL js/path-injection recognition.
|
|
473
|
+
*/
|
|
474
|
+
export const handleFileRequest = async (req, res, repoPath) => {
|
|
475
|
+
try {
|
|
476
|
+
// Type-confusion guard — req.query.path is `string | string[] | ParsedQs`.
|
|
477
|
+
// Without this, an attacker could pass `?path=a&path=b` to bypass the
|
|
478
|
+
// length-bound traversal check below (CodeQL js/type-confusion-through-
|
|
479
|
+
// parameter-tampering, same class as the /api/grep critical fix).
|
|
480
|
+
const rawFilePath = req.query.path;
|
|
481
|
+
if (rawFilePath === undefined || rawFilePath === '') {
|
|
482
|
+
res.status(400).json({ error: 'Missing path' });
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const filePath = assertString(rawFilePath, 'path');
|
|
486
|
+
// Path-injection containment — inline at the sink with the canonical
|
|
487
|
+
// path.relative idiom that CodeQL's js/path-injection sanitizer
|
|
488
|
+
// recognizes. assertSafePath in validation.ts performs the equivalent
|
|
489
|
+
// check, but cross-module helpers are not followed by CodeQL's
|
|
490
|
+
// interprocedural analysis for path-traversal sanitization in JS, so
|
|
491
|
+
// the barrier must be visible inline at the readFile sink.
|
|
492
|
+
const repoRoot = path.resolve(repoPath);
|
|
493
|
+
const fullPath = path.resolve(repoRoot, filePath);
|
|
494
|
+
const fullRel = path.relative(repoRoot, fullPath);
|
|
495
|
+
if (fullRel.startsWith('..') || path.isAbsolute(fullRel)) {
|
|
496
|
+
res.status(403).json({ error: 'Path traversal denied' });
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const raw = await fs.readFile(fullPath, 'utf-8');
|
|
500
|
+
// Optional line-range support: ?startLine=10&endLine=50
|
|
501
|
+
// Returns only the requested slice (0-indexed), plus metadata.
|
|
502
|
+
const startLine = req.query.startLine !== undefined ? Number(req.query.startLine) : undefined;
|
|
503
|
+
const endLine = req.query.endLine !== undefined ? Number(req.query.endLine) : undefined;
|
|
504
|
+
if (startLine !== undefined && Number.isFinite(startLine)) {
|
|
505
|
+
const lines = raw.split('\n');
|
|
506
|
+
const start = Math.max(0, startLine);
|
|
507
|
+
const end = endLine !== undefined && Number.isFinite(endLine)
|
|
508
|
+
? Math.min(lines.length, endLine + 1)
|
|
509
|
+
: lines.length;
|
|
510
|
+
res.json({
|
|
511
|
+
content: lines.slice(start, end).join('\n'),
|
|
512
|
+
startLine: start,
|
|
513
|
+
endLine: end - 1,
|
|
514
|
+
totalLines: lines.length,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
res.json({ content: raw, totalLines: raw.split('\n').length });
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
if (err.code === 'ENOENT') {
|
|
523
|
+
res.status(404).json({ error: 'File not found' });
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
// statusFromError returns err.status for BadRequestError / ForbiddenError
|
|
527
|
+
// (assertString → 400 on array-form ?path=a&path=b; ForbiddenError → 403
|
|
528
|
+
// on traversal). Falls back to 500 for unrecognized failures.
|
|
529
|
+
res.status(statusFromError(err)).json({ error: err.message || 'Failed to read file' });
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
export const createServer = async (port, host = '127.0.0.1') => {
|
|
534
|
+
const app = express();
|
|
535
|
+
app.disable('x-powered-by');
|
|
536
|
+
// Trust X-Forwarded-* headers only when the connection comes from the
|
|
537
|
+
// local loopback or RFC1918 private/link-local addresses — exactly the
|
|
538
|
+
// origins the CORS allowlist accepts. Without this, every request behind
|
|
539
|
+
// any reverse proxy / Docker bridge counts as the same `req.ip` and a
|
|
540
|
+
// single user can trip the per-IP rate limiter for everyone.
|
|
541
|
+
//
|
|
542
|
+
// SCOPE: this setting is process-wide. Every middleware and route in this
|
|
543
|
+
// Express app sees req.ip resolved from X-Forwarded-For when the upstream
|
|
544
|
+
// hop is in the trusted set above — not just the rate-limited routes.
|
|
545
|
+
// Future IP-based middleware (audit logging, IP-bound authz) inherits this
|
|
546
|
+
// behavior.
|
|
547
|
+
//
|
|
548
|
+
// CLOUD-DEPLOY CAVEAT: a public cloud LB (AWS ALB, Cloudflare, Fly.io
|
|
549
|
+
// edge, CGNAT 100.64/10) is NOT in the trusted set. In those topologies
|
|
550
|
+
// req.ip will collapse to the LB hop IP for every request and the per-IP
|
|
551
|
+
// rate limiter degrades to per-server. Add an explicit env-var override
|
|
552
|
+
// and document the cloud-deploy story before binding to a non-loopback
|
|
553
|
+
// host in those topologies (tracked as a follow-up; not blocking for the
|
|
554
|
+
// local-bound default).
|
|
555
|
+
app.set('trust proxy', 'loopback, linklocal, uniquelocal');
|
|
556
|
+
// CORS: allow localhost, private/LAN networks, and the deployed site.
|
|
557
|
+
// Non-browser requests (curl, server-to-server) have no origin and are allowed.
|
|
558
|
+
// Disallowed origins get the response without Access-Control-Allow-Origin,
|
|
559
|
+
// so the browser blocks it. We pass `false` instead of throwing an Error to
|
|
560
|
+
// avoid crashing into Express's default error handler (which returned 500).
|
|
561
|
+
app.use(cors({
|
|
562
|
+
origin: (origin, callback) => {
|
|
563
|
+
callback(null, isAllowedOrigin(origin));
|
|
564
|
+
},
|
|
565
|
+
}));
|
|
566
|
+
app.use(express.json({ limit: '10mb' }));
|
|
567
|
+
// Support Chromium Private Network Access (required since Chrome 130+).
|
|
568
|
+
// Without this header, Chrome/Edge/Brave/Arc block public->loopback requests
|
|
569
|
+
// which breaks bridge mode entirely.
|
|
570
|
+
app.use((_req, res, next) => {
|
|
571
|
+
res.setHeader('Access-Control-Allow-Private-Network', 'true');
|
|
572
|
+
next();
|
|
573
|
+
});
|
|
574
|
+
// Handle PNA preflight: Chromium sends Access-Control-Request-Private-Network
|
|
575
|
+
// on OPTIONS requests and expects the allow header in the response.
|
|
576
|
+
// Note: the actual Allow-Private-Network header is already set by the global
|
|
577
|
+
// middleware above, so we just need to call next() here.
|
|
578
|
+
app.options('*', (_req, res, next) => {
|
|
579
|
+
next();
|
|
580
|
+
});
|
|
581
|
+
// Initialize MCP backend (multi-repo, shared across all MCP sessions)
|
|
582
|
+
const backend = new LocalBackend();
|
|
583
|
+
await backend.init();
|
|
584
|
+
const cleanupMcp = mountMCPEndpoints(app, backend);
|
|
585
|
+
const jobManager = new JobManager();
|
|
586
|
+
const embedJobManager = new JobManager();
|
|
587
|
+
// Shared repo lock — prevents concurrent analyze + embed on the same repo path,
|
|
588
|
+
// which would corrupt LadybugDB (analyze calls closeLbug + initLbug while embed has queries in flight).
|
|
589
|
+
const activeRepoPaths = new Set();
|
|
590
|
+
const acquireRepoLock = (repoPath) => {
|
|
591
|
+
if (activeRepoPaths.has(repoPath)) {
|
|
592
|
+
return `Another job is already active for this repository`;
|
|
593
|
+
}
|
|
594
|
+
activeRepoPaths.add(repoPath);
|
|
595
|
+
return null;
|
|
596
|
+
};
|
|
597
|
+
const releaseRepoLock = (repoPath) => {
|
|
598
|
+
activeRepoPaths.delete(repoPath);
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* Maximum time the hold-queue will wait for an active analysis job to complete.
|
|
602
|
+
* Must stay in sync with the frontend's `fetchRepoInfo({ awaitAnalysis: true })` timeout.
|
|
603
|
+
*/
|
|
604
|
+
const HOLD_QUEUE_TIMEOUT_SECS = 300; // 5 minutes
|
|
605
|
+
// Helper: resolve a repo by name from the global registry, or default to first.
|
|
606
|
+
// Pass `req` to enable early exit if the client disconnects during the hold-queue wait.
|
|
607
|
+
const resolveRepo = async (repoName, isRetry = false, req) => {
|
|
608
|
+
const repos = await listRegisteredRepos();
|
|
609
|
+
let found = null;
|
|
610
|
+
// Normalize: if a full path is passed, extract just the basename.
|
|
611
|
+
// e.g. "C:\Users\LENOVO\.arc\repos\todo.txt-cli" -> "todo.txt-cli"
|
|
612
|
+
const normalizedName = repoName ? path.basename(repoName) : undefined;
|
|
613
|
+
if (normalizedName) {
|
|
614
|
+
found =
|
|
615
|
+
repos.find((r) => r.name === normalizedName) ||
|
|
616
|
+
repos.find((r) => r.name.toLowerCase() === normalizedName.toLowerCase()) ||
|
|
617
|
+
null;
|
|
618
|
+
}
|
|
619
|
+
else if (repos.length > 0) {
|
|
620
|
+
found = repos[0]; // default to first repo
|
|
621
|
+
}
|
|
622
|
+
// If not yet in the registry, check whether a background job is actively cloning or
|
|
623
|
+
// analyzing this repo. Hold the connection open (up to 5 minutes) until it completes.
|
|
624
|
+
// We only wait for in-progress jobs ('queued'|'cloning'|'analyzing') — a 'complete' job
|
|
625
|
+
// whose repo is still missing means the registry sync failed; the fallback below handles it.
|
|
626
|
+
if (!found && normalizedName) {
|
|
627
|
+
const lower = normalizedName.toLowerCase();
|
|
628
|
+
// Track client disconnect to cancel the wait early
|
|
629
|
+
let clientGone = false;
|
|
630
|
+
req?.on('close', () => {
|
|
631
|
+
clientGone = true;
|
|
632
|
+
});
|
|
633
|
+
for (const job of jobManager.listJobs()) {
|
|
634
|
+
const isMatch = job.repoName?.toLowerCase() === lower ||
|
|
635
|
+
(job.repoUrl && path.basename(job.repoUrl).replace('.git', '').toLowerCase() === lower) ||
|
|
636
|
+
(job.repoPath && path.basename(job.repoPath).toLowerCase() === lower);
|
|
637
|
+
if (isMatch && ['queued', 'cloning', 'analyzing'].includes(job.status)) {
|
|
638
|
+
if (process.env.DEBUG) {
|
|
639
|
+
// Sanitize user-controlled values to prevent log injection (CodeQL js/log-injection).
|
|
640
|
+
logger.debug({
|
|
641
|
+
jobId: String(job.id).replace(/[\r\n]/g, ' '),
|
|
642
|
+
repoName: String(normalizedName).replace(/[\r\n]/g, ' '),
|
|
643
|
+
}, '[debug] resolveRepo waiting for active job');
|
|
644
|
+
}
|
|
645
|
+
for (let wait = 0; wait < HOLD_QUEUE_TIMEOUT_SECS; wait++) {
|
|
646
|
+
if (clientGone)
|
|
647
|
+
return null; // client disconnected — stop polling
|
|
648
|
+
const currentJob = jobManager.getJob(job.id);
|
|
649
|
+
if (!currentJob || currentJob.status === 'failed')
|
|
650
|
+
break;
|
|
651
|
+
if (currentJob.status === 'complete') {
|
|
652
|
+
await backend.init();
|
|
653
|
+
const freshRepos = await listRegisteredRepos();
|
|
654
|
+
return freshRepos.find((r) => r.name === normalizedName) || null;
|
|
655
|
+
}
|
|
656
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
657
|
+
}
|
|
658
|
+
// Timed out — signal to the caller with a specific message
|
|
659
|
+
return { __timedOut: true, repoName: normalizedName };
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
// Emergency fallback: re-sync the registry to handle Windows file-system race conditions
|
|
664
|
+
// (e.g. registry file not yet flushed after clone completes).
|
|
665
|
+
if (!found && normalizedName && !isRetry) {
|
|
666
|
+
if (process.env.DEBUG) {
|
|
667
|
+
// Sanitize user-controlled values to prevent log injection (CodeQL js/log-injection).
|
|
668
|
+
logger.debug({ repoName: String(normalizedName).replace(/[\r\n]/g, ' ') }, '[debug] resolveRepo 404, triggering deep init');
|
|
669
|
+
}
|
|
670
|
+
await backend.init();
|
|
671
|
+
return await resolveRepo(normalizedName, true, req);
|
|
672
|
+
}
|
|
673
|
+
return found;
|
|
674
|
+
};
|
|
675
|
+
const apiEndpoints = [
|
|
676
|
+
{
|
|
677
|
+
method: 'get',
|
|
678
|
+
path: '/api/health',
|
|
679
|
+
handler: (_req, res) => {
|
|
680
|
+
res.json({ status: 'ok' });
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
method: 'get',
|
|
685
|
+
path: '/api/heartbeat',
|
|
686
|
+
handler: (_req, res) => {
|
|
687
|
+
res.set({
|
|
688
|
+
'Content-Type': 'text/event-stream',
|
|
689
|
+
'Cache-Control': 'no-cache',
|
|
690
|
+
Connection: 'keep-alive',
|
|
691
|
+
});
|
|
692
|
+
res.flushHeaders();
|
|
693
|
+
res.write(':ok\n\n');
|
|
694
|
+
const interval = setInterval(() => res.write(':ping\n\n'), 15_000);
|
|
695
|
+
_req.on('close', () => clearInterval(interval));
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
method: 'get',
|
|
700
|
+
path: '/api/info',
|
|
701
|
+
handler: (_req, res) => {
|
|
702
|
+
const execPath = process.env.npm_execpath ?? '';
|
|
703
|
+
const argv0 = process.argv[1] ?? '';
|
|
704
|
+
let launchContext;
|
|
705
|
+
if (execPath.includes('npx') ||
|
|
706
|
+
argv0.includes('_npx') ||
|
|
707
|
+
process.env.npm_config_prefix?.includes('_npx')) {
|
|
708
|
+
launchContext = 'npx';
|
|
709
|
+
}
|
|
710
|
+
else if (argv0.includes('node_modules')) {
|
|
711
|
+
launchContext = 'local';
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
launchContext = 'global';
|
|
715
|
+
}
|
|
716
|
+
res.json({ version: pkg.version, launchContext, nodeVersion: process.version });
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
method: 'get',
|
|
721
|
+
path: '/api/repos',
|
|
722
|
+
handler: async (_req, res) => {
|
|
723
|
+
try {
|
|
724
|
+
const repos = await listRegisteredRepos();
|
|
725
|
+
res.json(repos.map((r) => ({
|
|
726
|
+
name: r.name,
|
|
727
|
+
path: r.path,
|
|
728
|
+
indexedAt: r.indexedAt,
|
|
729
|
+
lastCommit: r.lastCommit,
|
|
730
|
+
stats: r.stats,
|
|
731
|
+
})));
|
|
732
|
+
}
|
|
733
|
+
catch (err) {
|
|
734
|
+
res.status(500).json({ error: err.message || 'Failed to list repos' });
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
method: 'get',
|
|
740
|
+
path: '/api/repo',
|
|
741
|
+
handler: async (req, res) => {
|
|
742
|
+
try {
|
|
743
|
+
const entry = await resolveRepo(requestedRepo(req), false, req);
|
|
744
|
+
if (!entry) {
|
|
745
|
+
res.status(404).json({ error: 'Repository not found. Run: arc analyze' });
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (entry.__timedOut) {
|
|
749
|
+
res.status(503).json({
|
|
750
|
+
error: `Repository analysis for "${entry.repoName}" is taking longer than expected. Please try again in a moment.`,
|
|
751
|
+
});
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
const meta = await loadMeta(entry.storagePath);
|
|
755
|
+
res.json({
|
|
756
|
+
name: entry.name,
|
|
757
|
+
repoPath: entry.path,
|
|
758
|
+
indexedAt: meta?.indexedAt ?? entry.indexedAt,
|
|
759
|
+
stats: meta?.stats ?? entry.stats ?? {},
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
catch (err) {
|
|
763
|
+
res.status(500).json({ error: err.message || 'Failed to get repo info' });
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
method: 'delete',
|
|
769
|
+
path: '/api/repo',
|
|
770
|
+
middlewares: [createRouteLimiter()],
|
|
771
|
+
handler: async (req, res) => {
|
|
772
|
+
try {
|
|
773
|
+
const repoName = requestedRepo(req);
|
|
774
|
+
if (!repoName) {
|
|
775
|
+
res.status(400).json({ error: 'Missing repo name' });
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
const entry = await resolveRepo(repoName);
|
|
779
|
+
if (!entry) {
|
|
780
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
const lockKey = getStoragePath(entry.path);
|
|
784
|
+
const lockErr = acquireRepoLock(lockKey);
|
|
785
|
+
if (lockErr) {
|
|
786
|
+
res.status(409).json({ error: lockErr });
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
try {
|
|
790
|
+
try {
|
|
791
|
+
await closeLbug();
|
|
792
|
+
}
|
|
793
|
+
catch { }
|
|
794
|
+
const storagePath = getStoragePath(entry.path);
|
|
795
|
+
await fs.rm(storagePath, { recursive: true, force: true }).catch(() => { });
|
|
796
|
+
let cloneDir = null;
|
|
797
|
+
try {
|
|
798
|
+
cloneDir = getCloneDir(entry.name);
|
|
799
|
+
}
|
|
800
|
+
catch { }
|
|
801
|
+
if (cloneDir) {
|
|
802
|
+
try {
|
|
803
|
+
const stat = await fs.stat(cloneDir);
|
|
804
|
+
if (stat.isDirectory()) {
|
|
805
|
+
await fs.rm(cloneDir, { recursive: true, force: true });
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
catch { }
|
|
809
|
+
}
|
|
810
|
+
const { unregisterRepo } = await import('../storage/repo-manager.js');
|
|
811
|
+
await unregisterRepo(entry.path);
|
|
812
|
+
await backend.init().catch(() => { });
|
|
813
|
+
res.json({ deleted: entry.name });
|
|
814
|
+
}
|
|
815
|
+
finally {
|
|
816
|
+
releaseRepoLock(lockKey);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
catch (err) {
|
|
820
|
+
res.status(500).json({ error: err.message || 'Failed to delete repo' });
|
|
821
|
+
}
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
method: 'get',
|
|
826
|
+
path: '/api/graph',
|
|
827
|
+
handler: async (req, res) => {
|
|
828
|
+
try {
|
|
829
|
+
const entry = await resolveRepo(requestedRepo(req));
|
|
830
|
+
if (!entry) {
|
|
831
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const lbugPath = path.join(entry.storagePath, 'lbug');
|
|
835
|
+
const includeContent = req.query.includeContent === 'true';
|
|
836
|
+
const stream = req.query.stream === 'true';
|
|
837
|
+
if (stream) {
|
|
838
|
+
const abortController = new AbortController();
|
|
839
|
+
let responseFinished = false;
|
|
840
|
+
const markFinished = () => {
|
|
841
|
+
responseFinished = true;
|
|
842
|
+
};
|
|
843
|
+
const abortStreaming = () => {
|
|
844
|
+
if (!responseFinished) {
|
|
845
|
+
abortController.abort();
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
res.setHeader('Content-Type', 'application/x-ndjson; charset=utf-8');
|
|
849
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
850
|
+
res.flushHeaders();
|
|
851
|
+
req.once('aborted', abortStreaming);
|
|
852
|
+
res.once('finish', markFinished);
|
|
853
|
+
res.once('close', abortStreaming);
|
|
854
|
+
try {
|
|
855
|
+
await withLbugDb(lbugPath, async () => streamGraphNdjson(res, includeContent, abortController.signal));
|
|
856
|
+
if (!abortController.signal.aborted && !res.writableEnded) {
|
|
857
|
+
res.end();
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
finally {
|
|
861
|
+
req.off('aborted', abortStreaming);
|
|
862
|
+
res.off('finish', markFinished);
|
|
863
|
+
res.off('close', abortStreaming);
|
|
864
|
+
}
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const graph = await withLbugDb(lbugPath, async () => buildGraph(includeContent));
|
|
868
|
+
res.json(graph);
|
|
869
|
+
}
|
|
870
|
+
catch (err) {
|
|
871
|
+
if (err instanceof ClientDisconnectedError) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
const message = err.message || 'Failed to build graph';
|
|
875
|
+
if (res.headersSent) {
|
|
876
|
+
try {
|
|
877
|
+
res.write(JSON.stringify({ type: 'error', error: message }) + '\n');
|
|
878
|
+
}
|
|
879
|
+
catch { }
|
|
880
|
+
res.end();
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
res.status(500).json({ error: message });
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
method: 'post',
|
|
889
|
+
path: '/api/query',
|
|
890
|
+
handler: async (req, res) => {
|
|
891
|
+
try {
|
|
892
|
+
const cypher = req.body.cypher;
|
|
893
|
+
if (!cypher) {
|
|
894
|
+
res.status(400).json({ error: 'Missing "cypher" in request body' });
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
if (isWriteQuery(cypher)) {
|
|
898
|
+
res.status(403).json({ error: 'Write queries are not allowed via the HTTP API' });
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
const entry = await resolveRepo(requestedRepo(req));
|
|
902
|
+
if (!entry) {
|
|
903
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
const lbugPath = path.join(entry.storagePath, 'lbug');
|
|
907
|
+
const result = await withLbugDb(lbugPath, () => executeQuery(cypher));
|
|
908
|
+
res.json({ result });
|
|
909
|
+
}
|
|
910
|
+
catch (err) {
|
|
911
|
+
res.status(500).json({ error: err.message || 'Query failed' });
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
method: 'post',
|
|
917
|
+
path: '/api/search',
|
|
918
|
+
handler: async (req, res) => {
|
|
919
|
+
try {
|
|
920
|
+
const query = (req.body.query ?? '').trim();
|
|
921
|
+
if (!query) {
|
|
922
|
+
res.status(400).json({ error: 'Missing "query" in request body' });
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
const entry = await resolveRepo(requestedRepo(req));
|
|
926
|
+
if (!entry) {
|
|
927
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
const lbugPath = path.join(entry.storagePath, 'lbug');
|
|
931
|
+
const parsedLimit = Number(req.body.limit ?? 10);
|
|
932
|
+
const limit = Number.isFinite(parsedLimit)
|
|
933
|
+
? Math.max(1, Math.min(100, Math.trunc(parsedLimit)))
|
|
934
|
+
: 10;
|
|
935
|
+
const mode = req.body.mode ?? 'hybrid';
|
|
936
|
+
const enrich = req.body.enrich !== false;
|
|
937
|
+
const results = await withLbugDb(lbugPath, async () => {
|
|
938
|
+
let searchResults;
|
|
939
|
+
let ftsAvailable;
|
|
940
|
+
if (mode === 'semantic') {
|
|
941
|
+
const { isEmbedderReady } = await import('../core/embeddings/embedder.js');
|
|
942
|
+
if (!isEmbedderReady()) {
|
|
943
|
+
return { searchResults: [], ftsAvailable: undefined };
|
|
944
|
+
}
|
|
945
|
+
const { semanticSearch: semSearch } = await import('../core/embeddings/embedding-pipeline.js');
|
|
946
|
+
searchResults = await semSearch(executeQuery, query, limit);
|
|
947
|
+
searchResults = searchResults.map((r, i) => ({
|
|
948
|
+
...r,
|
|
949
|
+
score: r.score ?? 1 - (r.distance ?? 0),
|
|
950
|
+
rank: i + 1,
|
|
951
|
+
sources: ['semantic'],
|
|
952
|
+
}));
|
|
953
|
+
}
|
|
954
|
+
else if (mode === 'bm25') {
|
|
955
|
+
const ftsResponse = await searchFTSFromLbug(query, limit);
|
|
956
|
+
ftsAvailable = ftsResponse.ftsAvailable;
|
|
957
|
+
searchResults = ftsResponse.results.map((r, i) => ({
|
|
958
|
+
...r,
|
|
959
|
+
rank: i + 1,
|
|
960
|
+
sources: ['bm25'],
|
|
961
|
+
}));
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
const { isEmbedderReady } = await import('../core/embeddings/embedder.js');
|
|
965
|
+
if (isEmbedderReady()) {
|
|
966
|
+
const { semanticSearch: semSearch } = await import('../core/embeddings/embedding-pipeline.js');
|
|
967
|
+
searchResults = await hybridSearch(query, limit, executeQuery, semSearch);
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
const ftsResponse = await searchFTSFromLbug(query, limit);
|
|
971
|
+
ftsAvailable = ftsResponse.ftsAvailable;
|
|
972
|
+
searchResults = ftsResponse.results;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (!enrich)
|
|
976
|
+
return { searchResults, ftsAvailable };
|
|
977
|
+
const validLabel = (label) => NODE_TABLES.includes(label);
|
|
978
|
+
const enriched = await Promise.all(searchResults.slice(0, limit).map(async (r) => {
|
|
979
|
+
const nodeId = r.nodeId || r.id || '';
|
|
980
|
+
const nodeLabel = nodeId.split(':')[0];
|
|
981
|
+
const enrichment = {};
|
|
982
|
+
if (!nodeId || !validLabel(nodeLabel))
|
|
983
|
+
return { ...r, ...enrichment };
|
|
984
|
+
const [connRes, clusterRes, procRes] = await Promise.all([
|
|
985
|
+
executePrepared(`
|
|
986
|
+
MATCH (n:${nodeLabel} {id: $nid})
|
|
987
|
+
OPTIONAL MATCH (n)-[r1:CodeRelation]->(dst)
|
|
988
|
+
OPTIONAL MATCH (src)-[r2:CodeRelation]->(n)
|
|
989
|
+
RETURN
|
|
990
|
+
collect(DISTINCT {name: dst.name, type: r1.type, confidence: r1.confidence}) AS outgoing,
|
|
991
|
+
collect(DISTINCT {name: src.name, type: r2.type, confidence: r2.confidence}) AS incoming
|
|
992
|
+
LIMIT 1
|
|
993
|
+
`, { nid: nodeId }).catch(() => []),
|
|
994
|
+
executePrepared(`
|
|
995
|
+
MATCH (n:${nodeLabel} {id: $nid})
|
|
996
|
+
MATCH (n)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
|
|
997
|
+
RETURN c.label AS label, c.description AS description
|
|
998
|
+
LIMIT 1
|
|
999
|
+
`, { nid: nodeId }).catch(() => []),
|
|
1000
|
+
executePrepared(`
|
|
1001
|
+
MATCH (n:${nodeLabel} {id: $nid})
|
|
1002
|
+
MATCH (n)-[rel:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
|
|
1003
|
+
RETURN p.id AS id, p.label AS label, rel.step AS step, p.stepCount AS stepCount
|
|
1004
|
+
ORDER BY rel.step
|
|
1005
|
+
`, { nid: nodeId }).catch(() => []),
|
|
1006
|
+
]);
|
|
1007
|
+
if (connRes.length > 0) {
|
|
1008
|
+
const row = connRes[0];
|
|
1009
|
+
const outgoing = (Array.isArray(row) ? row[0] : row.outgoing || [])
|
|
1010
|
+
.filter((c) => c?.name)
|
|
1011
|
+
.slice(0, 5);
|
|
1012
|
+
const incoming = (Array.isArray(row) ? row[1] : row.incoming || [])
|
|
1013
|
+
.filter((c) => c?.name)
|
|
1014
|
+
.slice(0, 5);
|
|
1015
|
+
enrichment.connections = { outgoing, incoming };
|
|
1016
|
+
}
|
|
1017
|
+
if (clusterRes.length > 0) {
|
|
1018
|
+
const row = clusterRes[0];
|
|
1019
|
+
enrichment.cluster = Array.isArray(row) ? row[0] : row.label;
|
|
1020
|
+
}
|
|
1021
|
+
if (procRes.length > 0) {
|
|
1022
|
+
enrichment.processes = procRes
|
|
1023
|
+
.map((row) => ({
|
|
1024
|
+
id: Array.isArray(row) ? row[0] : row.id,
|
|
1025
|
+
label: Array.isArray(row) ? row[1] : row.label,
|
|
1026
|
+
step: Array.isArray(row) ? row[2] : row.step,
|
|
1027
|
+
stepCount: Array.isArray(row) ? row[3] : row.stepCount,
|
|
1028
|
+
}))
|
|
1029
|
+
.filter((p) => p.id && p.label);
|
|
1030
|
+
}
|
|
1031
|
+
return { ...r, ...enrichment };
|
|
1032
|
+
}));
|
|
1033
|
+
return { searchResults: enriched, ftsAvailable };
|
|
1034
|
+
});
|
|
1035
|
+
const response = { results: results.searchResults ?? results };
|
|
1036
|
+
if (results.ftsAvailable === false) {
|
|
1037
|
+
response.warning =
|
|
1038
|
+
'FTS indexes missing — keyword search degraded. Run: arc analyze --force to rebuild indexes.';
|
|
1039
|
+
}
|
|
1040
|
+
res.json(response);
|
|
1041
|
+
}
|
|
1042
|
+
catch (err) {
|
|
1043
|
+
res.status(500).json({ error: err.message || 'Search failed' });
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
},
|
|
1047
|
+
{
|
|
1048
|
+
method: 'get',
|
|
1049
|
+
path: '/api/file',
|
|
1050
|
+
middlewares: [createRouteLimiter()],
|
|
1051
|
+
handler: async (req, res) => {
|
|
1052
|
+
const entry = await resolveRepo(requestedRepo(req));
|
|
1053
|
+
if (!entry) {
|
|
1054
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
await handleFileRequest(req, res, entry.path);
|
|
1058
|
+
},
|
|
1059
|
+
},
|
|
1060
|
+
{
|
|
1061
|
+
method: 'get',
|
|
1062
|
+
path: '/api/grep',
|
|
1063
|
+
middlewares: [createRouteLimiter()],
|
|
1064
|
+
handler: async (req, res) => {
|
|
1065
|
+
try {
|
|
1066
|
+
const entry = await resolveRepo(requestedRepo(req));
|
|
1067
|
+
if (!entry) {
|
|
1068
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
const rawPattern = req.query.pattern;
|
|
1072
|
+
if (rawPattern === undefined) {
|
|
1073
|
+
res.status(400).json({ error: 'Missing "pattern" query parameter' });
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
const pattern = assertString(rawPattern, 'pattern');
|
|
1077
|
+
if (pattern.length === 0) {
|
|
1078
|
+
res.status(400).json({ error: 'Missing "pattern" query parameter' });
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
if (pattern.length > 200) {
|
|
1082
|
+
res.status(400).json({ error: 'Pattern too long (max 200 characters)' });
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
const effectivePattern = escapeRegExp(pattern);
|
|
1086
|
+
let regex;
|
|
1087
|
+
try {
|
|
1088
|
+
regex = new RegExp(effectivePattern, 'gim');
|
|
1089
|
+
}
|
|
1090
|
+
catch {
|
|
1091
|
+
res.status(400).json({ error: 'Invalid regex pattern' });
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
const parsedLimit = Number(req.query.limit ?? 50);
|
|
1095
|
+
const limit = Number.isFinite(parsedLimit)
|
|
1096
|
+
? Math.max(1, Math.min(200, Math.trunc(parsedLimit)))
|
|
1097
|
+
: 50;
|
|
1098
|
+
const results = [];
|
|
1099
|
+
const repoRoot = path.resolve(entry.path);
|
|
1100
|
+
const lbugPath = path.join(entry.storagePath, 'lbug');
|
|
1101
|
+
const fileRows = await withLbugDb(lbugPath, () => executeQuery(`MATCH (n:File) WHERE n.content IS NOT NULL RETURN n.filePath AS filePath`));
|
|
1102
|
+
for (const row of fileRows) {
|
|
1103
|
+
if (results.length >= limit)
|
|
1104
|
+
break;
|
|
1105
|
+
const filePath = row.filePath || '';
|
|
1106
|
+
const fullPath = path.resolve(repoRoot, filePath);
|
|
1107
|
+
if (!fullPath.startsWith(repoRoot + path.sep) && fullPath !== repoRoot)
|
|
1108
|
+
continue;
|
|
1109
|
+
let content;
|
|
1110
|
+
try {
|
|
1111
|
+
content = await fs.readFile(fullPath, 'utf-8');
|
|
1112
|
+
}
|
|
1113
|
+
catch {
|
|
1114
|
+
continue;
|
|
1115
|
+
}
|
|
1116
|
+
const lines = content.split('\n');
|
|
1117
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1118
|
+
if (results.length >= limit)
|
|
1119
|
+
break;
|
|
1120
|
+
if (regex.test(lines[i])) {
|
|
1121
|
+
results.push({ filePath, line: i + 1, text: lines[i].trim().slice(0, 200) });
|
|
1122
|
+
}
|
|
1123
|
+
regex.lastIndex = 0;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
res.json({ results });
|
|
1127
|
+
}
|
|
1128
|
+
catch (err) {
|
|
1129
|
+
res.status(statusFromError(err)).json({ error: err.message || 'Grep failed' });
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
method: 'get',
|
|
1135
|
+
path: '/api/processes',
|
|
1136
|
+
handler: async (req, res) => {
|
|
1137
|
+
try {
|
|
1138
|
+
const result = await backend.queryProcesses(requestedRepo(req));
|
|
1139
|
+
res.json(result);
|
|
1140
|
+
}
|
|
1141
|
+
catch (err) {
|
|
1142
|
+
res.status(statusFromError(err)).json({ error: err.message || 'Failed to query processes' });
|
|
1143
|
+
}
|
|
1144
|
+
},
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
method: 'get',
|
|
1148
|
+
path: '/api/process',
|
|
1149
|
+
handler: async (req, res) => {
|
|
1150
|
+
try {
|
|
1151
|
+
const name = String(req.query.name ?? '').trim();
|
|
1152
|
+
if (!name) {
|
|
1153
|
+
res.status(400).json({ error: 'Missing "name" query parameter' });
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
const result = await backend.queryProcessDetail(name, requestedRepo(req));
|
|
1157
|
+
if (result?.error) {
|
|
1158
|
+
res.status(404).json({ error: result.error });
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
res.json(result);
|
|
1162
|
+
}
|
|
1163
|
+
catch (err) {
|
|
1164
|
+
res
|
|
1165
|
+
.status(statusFromError(err))
|
|
1166
|
+
.json({ error: err.message || 'Failed to query process detail' });
|
|
1167
|
+
}
|
|
1168
|
+
},
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
method: 'get',
|
|
1172
|
+
path: '/api/clusters',
|
|
1173
|
+
handler: async (req, res) => {
|
|
1174
|
+
try {
|
|
1175
|
+
const result = await backend.queryClusters(requestedRepo(req));
|
|
1176
|
+
res.json(result);
|
|
1177
|
+
}
|
|
1178
|
+
catch (err) {
|
|
1179
|
+
res.status(statusFromError(err)).json({ error: err.message || 'Failed to query clusters' });
|
|
1180
|
+
}
|
|
1181
|
+
},
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
method: 'get',
|
|
1185
|
+
path: '/api/cluster',
|
|
1186
|
+
handler: async (req, res) => {
|
|
1187
|
+
try {
|
|
1188
|
+
const name = String(req.query.name ?? '').trim();
|
|
1189
|
+
if (!name) {
|
|
1190
|
+
res.status(400).json({ error: 'Missing "name" query parameter' });
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const result = await backend.queryClusterDetail(name, requestedRepo(req));
|
|
1194
|
+
if (result?.error) {
|
|
1195
|
+
res.status(404).json({ error: result.error });
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
res.json(result);
|
|
1199
|
+
}
|
|
1200
|
+
catch (err) {
|
|
1201
|
+
res
|
|
1202
|
+
.status(statusFromError(err))
|
|
1203
|
+
.json({ error: err.message || 'Failed to query cluster detail' });
|
|
1204
|
+
}
|
|
1205
|
+
},
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
method: 'post',
|
|
1209
|
+
path: '/api/analyze',
|
|
1210
|
+
middlewares: [createRouteLimiter({ limit: 10 })],
|
|
1211
|
+
handler: async (req, res) => {
|
|
1212
|
+
try {
|
|
1213
|
+
const { url: repoUrl, path: repoLocalPath, force, embeddings, dropEmbeddings } = req.body;
|
|
1214
|
+
if (repoUrl !== undefined && typeof repoUrl !== 'string') {
|
|
1215
|
+
res.status(400).json({ error: '"url" must be a string' });
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
if (repoLocalPath !== undefined && typeof repoLocalPath !== 'string') {
|
|
1219
|
+
res.status(400).json({ error: '"path" must be a string' });
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
if (!repoUrl && !repoLocalPath) {
|
|
1223
|
+
res.status(400).json({ error: 'Provide "url" (git URL) or "path" (local path)' });
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
if (repoLocalPath) {
|
|
1227
|
+
if (!path.isAbsolute(repoLocalPath)) {
|
|
1228
|
+
res.status(400).json({ error: '"path" must be an absolute path' });
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
if (path.normalize(repoLocalPath) !== path.resolve(repoLocalPath)) {
|
|
1232
|
+
res.status(400).json({ error: '"path" must not contain traversal sequences' });
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
const job = jobManager.createJob({ repoUrl, repoPath: repoLocalPath });
|
|
1237
|
+
if (job.status !== 'queued') {
|
|
1238
|
+
res.status(202).json({ jobId: job.id, status: job.status });
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
jobManager.updateJob(job.id, { status: 'cloning' });
|
|
1242
|
+
(async () => {
|
|
1243
|
+
let targetPath = repoLocalPath;
|
|
1244
|
+
try {
|
|
1245
|
+
if (repoUrl && !repoLocalPath) {
|
|
1246
|
+
const repoName = extractRepoName(repoUrl);
|
|
1247
|
+
targetPath = getCloneDir(repoName);
|
|
1248
|
+
jobManager.updateJob(job.id, {
|
|
1249
|
+
status: 'cloning',
|
|
1250
|
+
repoName,
|
|
1251
|
+
progress: { phase: 'cloning', percent: 0, message: `Cloning ${repoUrl}...` },
|
|
1252
|
+
});
|
|
1253
|
+
await cloneOrPull(repoUrl, targetPath, (progress) => {
|
|
1254
|
+
jobManager.updateJob(job.id, {
|
|
1255
|
+
progress: { phase: progress.phase, percent: 5, message: progress.message },
|
|
1256
|
+
});
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
if (!targetPath) {
|
|
1260
|
+
throw new Error('No target path resolved');
|
|
1261
|
+
}
|
|
1262
|
+
const analyzeLockKey = getStoragePath(targetPath);
|
|
1263
|
+
const lockErr = acquireRepoLock(analyzeLockKey);
|
|
1264
|
+
if (lockErr) {
|
|
1265
|
+
jobManager.updateJob(job.id, { status: 'failed', error: lockErr });
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
jobManager.updateJob(job.id, { repoPath: targetPath, status: 'analyzing' });
|
|
1269
|
+
const MAX_WORKER_RETRIES = 2;
|
|
1270
|
+
const callerPath = fileURLToPath(import.meta.url);
|
|
1271
|
+
const isDev = callerPath.endsWith('.ts');
|
|
1272
|
+
const workerFile = isDev ? 'analyze-worker.ts' : 'analyze-worker.js';
|
|
1273
|
+
const workerPath = path.join(path.dirname(callerPath), workerFile);
|
|
1274
|
+
const tsxHookArgs = isDev
|
|
1275
|
+
? ['--import', pathToFileURL(_require.resolve('tsx/esm')).href]
|
|
1276
|
+
: [];
|
|
1277
|
+
const forkWorker = () => {
|
|
1278
|
+
const currentJob = jobManager.getJob(job.id);
|
|
1279
|
+
if (!currentJob || currentJob.status === 'complete' || currentJob.status === 'failed')
|
|
1280
|
+
return;
|
|
1281
|
+
const child = fork(workerPath, [], {
|
|
1282
|
+
execArgv: [...tsxHookArgs, '--max-old-space-size=8192'],
|
|
1283
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
1284
|
+
});
|
|
1285
|
+
let stderrChunks = '';
|
|
1286
|
+
child.stderr?.on('data', (chunk) => {
|
|
1287
|
+
stderrChunks += chunk.toString();
|
|
1288
|
+
if (stderrChunks.length > 4096)
|
|
1289
|
+
stderrChunks = stderrChunks.slice(-4096);
|
|
1290
|
+
});
|
|
1291
|
+
child.on('message', (msg) => {
|
|
1292
|
+
if (msg.type === 'progress') {
|
|
1293
|
+
jobManager.updateJob(job.id, {
|
|
1294
|
+
status: 'analyzing',
|
|
1295
|
+
progress: { phase: msg.phase, percent: msg.percent, message: msg.message },
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
else if (msg.type === 'complete') {
|
|
1299
|
+
releaseRepoLock(analyzeLockKey);
|
|
1300
|
+
backend
|
|
1301
|
+
.init()
|
|
1302
|
+
.then(() => {
|
|
1303
|
+
jobManager.updateJob(job.id, {
|
|
1304
|
+
status: 'complete',
|
|
1305
|
+
repoName: msg.result.repoName,
|
|
1306
|
+
});
|
|
1307
|
+
})
|
|
1308
|
+
.catch((err) => {
|
|
1309
|
+
logger.error({ err }, 'backend.init() failed after analyze:');
|
|
1310
|
+
jobManager.updateJob(job.id, {
|
|
1311
|
+
status: 'failed',
|
|
1312
|
+
error: 'Server failed to reload after analysis. Try again.',
|
|
1313
|
+
});
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
else if (msg.type === 'error') {
|
|
1317
|
+
releaseRepoLock(analyzeLockKey);
|
|
1318
|
+
jobManager.updateJob(job.id, {
|
|
1319
|
+
status: 'failed',
|
|
1320
|
+
error: msg.message,
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
});
|
|
1324
|
+
child.on('error', (err) => {
|
|
1325
|
+
releaseRepoLock(analyzeLockKey);
|
|
1326
|
+
jobManager.updateJob(job.id, {
|
|
1327
|
+
status: 'failed',
|
|
1328
|
+
error: `Worker process error: ${err.message}`,
|
|
1329
|
+
});
|
|
1330
|
+
});
|
|
1331
|
+
child.on('exit', (code) => {
|
|
1332
|
+
const j = jobManager.getJob(job.id);
|
|
1333
|
+
if (!j || j.status === 'complete' || j.status === 'failed')
|
|
1334
|
+
return;
|
|
1335
|
+
if (j.retryCount < MAX_WORKER_RETRIES) {
|
|
1336
|
+
j.retryCount++;
|
|
1337
|
+
const delay = 1000 * Math.pow(2, j.retryCount - 1);
|
|
1338
|
+
const lastErr = stderrChunks.trim().split('\n').pop() || '';
|
|
1339
|
+
logger.warn(`Analyze worker crashed (code ${code}), retry ${j.retryCount}/${MAX_WORKER_RETRIES} in ${delay}ms` +
|
|
1340
|
+
(lastErr ? `: ${lastErr}` : ''));
|
|
1341
|
+
jobManager.updateJob(job.id, {
|
|
1342
|
+
status: 'analyzing',
|
|
1343
|
+
progress: {
|
|
1344
|
+
phase: 'retrying',
|
|
1345
|
+
percent: j.progress.percent,
|
|
1346
|
+
message: `Worker crashed, retrying (${j.retryCount}/${MAX_WORKER_RETRIES})...`,
|
|
1347
|
+
},
|
|
1348
|
+
});
|
|
1349
|
+
stderrChunks = '';
|
|
1350
|
+
setTimeout(forkWorker, delay);
|
|
1351
|
+
}
|
|
1352
|
+
else {
|
|
1353
|
+
releaseRepoLock(analyzeLockKey);
|
|
1354
|
+
jobManager.updateJob(job.id, {
|
|
1355
|
+
status: 'failed',
|
|
1356
|
+
error: `Worker crashed ${MAX_WORKER_RETRIES + 1} times (code ${code})${stderrChunks ? ': ' + stderrChunks.trim().split('\n').pop() : ''}`,
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1360
|
+
jobManager.registerChild(job.id, child);
|
|
1361
|
+
child.send({
|
|
1362
|
+
type: 'start',
|
|
1363
|
+
repoPath: targetPath,
|
|
1364
|
+
options: {
|
|
1365
|
+
force: !!force,
|
|
1366
|
+
embeddings: !!embeddings,
|
|
1367
|
+
dropEmbeddings: !!dropEmbeddings,
|
|
1368
|
+
},
|
|
1369
|
+
});
|
|
1370
|
+
};
|
|
1371
|
+
forkWorker();
|
|
1372
|
+
}
|
|
1373
|
+
catch (err) {
|
|
1374
|
+
if (targetPath)
|
|
1375
|
+
releaseRepoLock(getStoragePath(targetPath));
|
|
1376
|
+
jobManager.updateJob(job.id, {
|
|
1377
|
+
status: 'failed',
|
|
1378
|
+
error: err.message || 'Analysis failed',
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
})();
|
|
1382
|
+
res.status(202).json({ jobId: job.id, status: job.status });
|
|
1383
|
+
}
|
|
1384
|
+
catch (err) {
|
|
1385
|
+
if (err.message?.includes('already in progress')) {
|
|
1386
|
+
res.status(409).json({ error: err.message });
|
|
1387
|
+
}
|
|
1388
|
+
else {
|
|
1389
|
+
res.status(500).json({ error: err.message || 'Failed to start analysis' });
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
},
|
|
1393
|
+
},
|
|
1394
|
+
{
|
|
1395
|
+
method: 'get',
|
|
1396
|
+
path: '/api/analyze/:jobId',
|
|
1397
|
+
handler: (req, res) => {
|
|
1398
|
+
const job = jobManager.getJob(req.params.jobId);
|
|
1399
|
+
if (!job) {
|
|
1400
|
+
res.status(404).json({ error: 'Job not found' });
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
res.json({
|
|
1404
|
+
id: job.id,
|
|
1405
|
+
status: job.status,
|
|
1406
|
+
repoUrl: job.repoUrl,
|
|
1407
|
+
repoPath: job.repoPath,
|
|
1408
|
+
repoName: job.repoName,
|
|
1409
|
+
progress: job.progress,
|
|
1410
|
+
error: job.error,
|
|
1411
|
+
startedAt: job.startedAt,
|
|
1412
|
+
completedAt: job.completedAt,
|
|
1413
|
+
});
|
|
1414
|
+
},
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
method: 'delete',
|
|
1418
|
+
path: '/api/analyze/:jobId',
|
|
1419
|
+
handler: (req, res) => {
|
|
1420
|
+
const job = jobManager.getJob(req.params.jobId);
|
|
1421
|
+
if (!job) {
|
|
1422
|
+
res.status(404).json({ error: 'Job not found' });
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
if (job.status === 'complete' || job.status === 'failed') {
|
|
1426
|
+
res.status(400).json({ error: `Job already ${job.status}` });
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
jobManager.cancelJob(req.params.jobId, 'Cancelled by user');
|
|
1430
|
+
res.json({ id: job.id, status: 'failed', error: 'Cancelled by user' });
|
|
1431
|
+
},
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
method: 'post',
|
|
1435
|
+
path: '/api/embed',
|
|
1436
|
+
middlewares: [createRouteLimiter({ limit: 20 })],
|
|
1437
|
+
handler: async (req, res) => {
|
|
1438
|
+
try {
|
|
1439
|
+
const entry = await resolveRepo(requestedRepo(req));
|
|
1440
|
+
if (!entry) {
|
|
1441
|
+
res.status(404).json({ error: 'Repository not found' });
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
const repoLockPath = entry.storagePath;
|
|
1445
|
+
const lockErr = acquireRepoLock(repoLockPath);
|
|
1446
|
+
if (lockErr) {
|
|
1447
|
+
res.status(409).json({ error: lockErr });
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
const job = embedJobManager.createJob({ repoPath: entry.storagePath });
|
|
1451
|
+
embedJobManager.updateJob(job.id, {
|
|
1452
|
+
repoName: entry.name,
|
|
1453
|
+
status: 'analyzing',
|
|
1454
|
+
progress: { phase: 'analyzing', percent: 0, message: 'Starting embedding generation...' },
|
|
1455
|
+
});
|
|
1456
|
+
const EMBED_TIMEOUT_MS = 30 * 60 * 1000;
|
|
1457
|
+
const embedTimeout = setTimeout(() => {
|
|
1458
|
+
const current = embedJobManager.getJob(job.id);
|
|
1459
|
+
if (current && current.status !== 'complete' && current.status !== 'failed') {
|
|
1460
|
+
releaseRepoLock(repoLockPath);
|
|
1461
|
+
embedJobManager.updateJob(job.id, {
|
|
1462
|
+
status: 'failed',
|
|
1463
|
+
error: 'Embedding timed out (30 minute limit)',
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
}, EMBED_TIMEOUT_MS);
|
|
1467
|
+
(async () => {
|
|
1468
|
+
try {
|
|
1469
|
+
const lbugPath = path.join(entry.storagePath, 'lbug');
|
|
1470
|
+
await withLbugDb(lbugPath, async () => {
|
|
1471
|
+
const { runEmbeddingPipeline } = await import('../core/embeddings/embedding-pipeline.js');
|
|
1472
|
+
const { fetchExistingEmbeddingHashes } = await import('../core/lbug/lbug-adapter.js');
|
|
1473
|
+
const existingEmbeddings = await fetchExistingEmbeddingHashes(executeQuery);
|
|
1474
|
+
if (existingEmbeddings && existingEmbeddings.size > 0) {
|
|
1475
|
+
console.log(`[embed] ${existingEmbeddings.size} nodes already embedded — incremental run with content-hash comparison`);
|
|
1476
|
+
}
|
|
1477
|
+
await runEmbeddingPipeline(executeQuery, executeWithReusedStatement, (p) => {
|
|
1478
|
+
embedJobManager.updateJob(job.id, {
|
|
1479
|
+
progress: {
|
|
1480
|
+
phase: p.phase === 'ready' ? 'complete' : p.phase === 'error' ? 'failed' : p.phase,
|
|
1481
|
+
percent: p.percent,
|
|
1482
|
+
message: p.phase === 'loading-model'
|
|
1483
|
+
? 'Loading embedding model...'
|
|
1484
|
+
: p.phase === 'embedding'
|
|
1485
|
+
? `Embedding nodes (${p.percent}%)...`
|
|
1486
|
+
: p.phase === 'indexing'
|
|
1487
|
+
? 'Creating vector index...'
|
|
1488
|
+
: p.phase === 'ready'
|
|
1489
|
+
? 'Embeddings complete'
|
|
1490
|
+
: `${p.phase} (${p.percent}%)`,
|
|
1491
|
+
},
|
|
1492
|
+
});
|
|
1493
|
+
}, {}, undefined, undefined, existingEmbeddings);
|
|
1494
|
+
await flushWAL();
|
|
1495
|
+
});
|
|
1496
|
+
clearTimeout(embedTimeout);
|
|
1497
|
+
releaseRepoLock(repoLockPath);
|
|
1498
|
+
const current = embedJobManager.getJob(job.id);
|
|
1499
|
+
if (!current || current.status !== 'failed') {
|
|
1500
|
+
embedJobManager.updateJob(job.id, { status: 'complete' });
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
catch (err) {
|
|
1504
|
+
clearTimeout(embedTimeout);
|
|
1505
|
+
releaseRepoLock(repoLockPath);
|
|
1506
|
+
const current = embedJobManager.getJob(job.id);
|
|
1507
|
+
if (!current || current.status !== 'failed') {
|
|
1508
|
+
embedJobManager.updateJob(job.id, {
|
|
1509
|
+
status: 'failed',
|
|
1510
|
+
error: err.message || 'Embedding generation failed',
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
})();
|
|
1515
|
+
res.status(202).json({ jobId: job.id, status: 'analyzing' });
|
|
1516
|
+
}
|
|
1517
|
+
catch (err) {
|
|
1518
|
+
if (err.message?.includes('already in progress')) {
|
|
1519
|
+
res.status(409).json({ error: err.message });
|
|
1520
|
+
}
|
|
1521
|
+
else {
|
|
1522
|
+
res.status(500).json({ error: err.message || 'Failed to start embedding generation' });
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
},
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
method: 'get',
|
|
1529
|
+
path: '/api/embed/:jobId',
|
|
1530
|
+
handler: (req, res) => {
|
|
1531
|
+
const job = embedJobManager.getJob(req.params.jobId);
|
|
1532
|
+
if (!job) {
|
|
1533
|
+
res.status(404).json({ error: 'Job not found' });
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
res.json({
|
|
1537
|
+
id: job.id,
|
|
1538
|
+
status: job.status,
|
|
1539
|
+
repoName: job.repoName,
|
|
1540
|
+
progress: job.progress,
|
|
1541
|
+
error: job.error,
|
|
1542
|
+
startedAt: job.startedAt,
|
|
1543
|
+
completedAt: job.completedAt,
|
|
1544
|
+
});
|
|
1545
|
+
},
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
method: 'delete',
|
|
1549
|
+
path: '/api/embed/:jobId',
|
|
1550
|
+
handler: (req, res) => {
|
|
1551
|
+
const job = embedJobManager.getJob(req.params.jobId);
|
|
1552
|
+
if (!job) {
|
|
1553
|
+
res.status(404).json({ error: 'Job not found' });
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
if (job.status === 'complete' || job.status === 'failed') {
|
|
1557
|
+
res.status(400).json({ error: `Job already ${job.status}` });
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
embedJobManager.cancelJob(req.params.jobId, 'Cancelled by user');
|
|
1561
|
+
res.json({ id: job.id, status: 'failed', error: 'Cancelled by user' });
|
|
1562
|
+
},
|
|
1563
|
+
},
|
|
1564
|
+
];
|
|
1565
|
+
for (const endpoint of apiEndpoints) {
|
|
1566
|
+
const middlewaresChain = endpoint.middlewares ?? [];
|
|
1567
|
+
app[endpoint.method](endpoint.path, ...middlewaresChain, async (req, res, next) => {
|
|
1568
|
+
try {
|
|
1569
|
+
await endpoint.handler(req, res);
|
|
1570
|
+
}
|
|
1571
|
+
catch (err) {
|
|
1572
|
+
next(err);
|
|
1573
|
+
}
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
// ── Web UI (served at root) ───────────────────────────────────────
|
|
1577
|
+
// Resolve the arceus-web dist directory relative to this file's location.
|
|
1578
|
+
// In the published package: <pkg>/dist/server/api.js → <pkg>/web/
|
|
1579
|
+
// In dev (tsx): arc/src/server/api.ts → arceus-web/dist/
|
|
1580
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
1581
|
+
const webDistDir = path.resolve(__dirname, '..', '..', 'web');
|
|
1582
|
+
const devWebDistDir = path.resolve(__dirname, '..', '..', '..', 'arceus-web', 'dist');
|
|
1583
|
+
const staticDir = await resolveWebDistDir(webDistDir, devWebDistDir);
|
|
1584
|
+
registerWebUI(app, staticDir);
|
|
1585
|
+
// Global error handler — catch anything the route handlers miss
|
|
1586
|
+
app.use((err, _req, res, _next) => {
|
|
1587
|
+
logger.error({ err }, 'Unhandled error:');
|
|
1588
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
1589
|
+
});
|
|
1590
|
+
// Wrap listen in a promise so errors (EADDRINUSE, EACCES, etc.) propagate
|
|
1591
|
+
// to the caller instead of crashing with an unhandled 'error' event.
|
|
1592
|
+
await new Promise((resolve, reject) => {
|
|
1593
|
+
const server = app.listen(port, host, () => {
|
|
1594
|
+
const displayHost = host === '::' || host === '0.0.0.0' ? 'localhost' : host;
|
|
1595
|
+
console.log(`Arceus server running on http://${displayHost}:${port}`);
|
|
1596
|
+
resolve();
|
|
1597
|
+
});
|
|
1598
|
+
server.on('error', (err) => reject(err));
|
|
1599
|
+
// Graceful shutdown — close Express + LadybugDB cleanly. Pino's default
|
|
1600
|
+
// destination is `sync: false` (buffered); `flushLoggerSync()` before
|
|
1601
|
+
// `process.exit` so records emitted during cleanup reach stderr.
|
|
1602
|
+
const shutdown = async () => {
|
|
1603
|
+
console.log('\nShutting down...');
|
|
1604
|
+
server.close();
|
|
1605
|
+
jobManager.dispose();
|
|
1606
|
+
embedJobManager.dispose();
|
|
1607
|
+
await cleanupMcp();
|
|
1608
|
+
await closeLbug();
|
|
1609
|
+
await backend.disconnect();
|
|
1610
|
+
const { flushLoggerSync } = await import('../core/logger.js');
|
|
1611
|
+
flushLoggerSync();
|
|
1612
|
+
process.exit(0);
|
|
1613
|
+
};
|
|
1614
|
+
process.once('SIGINT', shutdown);
|
|
1615
|
+
process.once('SIGTERM', shutdown);
|
|
1616
|
+
// Catch-all crash guards (mirrors startMCPServer in mcp/server.ts).
|
|
1617
|
+
// Pino v10's default destination is buffered (`sync: false`) — call
|
|
1618
|
+
// `flushLoggerSync()` after logging and before triggering shutdown
|
|
1619
|
+
// so the crash record reaches stderr regardless of how cleanup goes.
|
|
1620
|
+
// Worker-thread transports (pino-pretty under TTY) handle their own
|
|
1621
|
+
// flush on process exit in v10. `pino.final` was removed in v10
|
|
1622
|
+
// because the new transport architecture made it unnecessary.
|
|
1623
|
+
let shuttingDown = false;
|
|
1624
|
+
process.on('uncaughtException', (err) => {
|
|
1625
|
+
logger.error({ err }, 'Arceus uncaughtException');
|
|
1626
|
+
flushLoggerSync();
|
|
1627
|
+
if (!shuttingDown) {
|
|
1628
|
+
shuttingDown = true;
|
|
1629
|
+
shutdown().catch(() => { });
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1632
|
+
process.on('unhandledRejection', (reason) => {
|
|
1633
|
+
// Availability-first: log the rejection without exiting.
|
|
1634
|
+
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
1635
|
+
logger.error({ err }, 'Arceus unhandledRejection');
|
|
1636
|
+
});
|
|
1637
|
+
});
|
|
1638
|
+
};
|