gitnexus 1.6.3-rc.9 → 1.6.3
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 +21 -5
- package/dist/_shared/graph/types.d.ts +16 -0
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +4 -2
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +2 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/def-index.js +2 -2
- package/dist/_shared/scope-resolution/def-index.js.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +8 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.js +2 -2
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
- package/dist/_shared/scope-resolution/module-scope-index.d.ts +8 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/module-scope-index.js +10 -2
- package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -1
- 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 +12 -0
- package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/position-index.js +2 -2
- package/dist/_shared/scope-resolution/position-index.js.map +1 -1
- package/dist/_shared/scope-resolution/qualified-name-index.js +2 -2
- package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -1
- 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/evidence.js +5 -0
- package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js +21 -5
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +1 -10
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.js +6 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts +4 -4
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.js +3 -2
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +6 -2
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/shadow/aggregate.js +5 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +11 -0
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/ai-context.js +35 -4
- package/dist/cli/analyze.d.ts +27 -0
- package/dist/cli/analyze.js +31 -1
- package/dist/cli/clean.js +19 -1
- package/dist/cli/group.js +73 -0
- package/dist/cli/index-repo.js +8 -1
- package/dist/cli/index.js +26 -1
- package/dist/cli/list.js +11 -1
- package/dist/cli/remove.d.ts +30 -0
- package/dist/cli/remove.js +99 -0
- package/dist/cli/setup.js +185 -57
- package/dist/cli/tool.d.ts +5 -0
- package/dist/cli/tool.js +42 -0
- package/dist/config/ignore-service.d.ts +9 -0
- package/dist/config/ignore-service.js +80 -13
- package/dist/core/embedding-mode.d.ts +30 -0
- package/dist/core/embedding-mode.js +30 -0
- package/dist/core/embeddings/ast-utils.js +22 -22
- package/dist/core/embeddings/chunker.js +30 -25
- package/dist/core/embeddings/embedding-pipeline.d.ts +6 -0
- package/dist/core/embeddings/embedding-pipeline.js +15 -6
- package/dist/core/embeddings/text-generator.d.ts +1 -1
- package/dist/core/embeddings/text-generator.js +33 -24
- package/dist/core/embeddings/types.d.ts +43 -1
- package/dist/core/embeddings/types.js +101 -29
- package/dist/core/git-staleness.d.ts +18 -0
- package/dist/core/git-staleness.js +108 -0
- package/dist/core/graph/graph.js +115 -20
- package/dist/core/graph/types.d.ts +12 -1
- package/dist/core/group/config-parser.d.ts +4 -0
- package/dist/core/group/config-parser.js +18 -1
- package/dist/core/group/cross-impact.d.ts +41 -0
- package/dist/core/group/cross-impact.js +441 -0
- package/dist/core/group/extractors/http-patterns/php.js +126 -18
- 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/resolve-at-member.d.ts +10 -0
- package/dist/core/group/resolve-at-member.js +31 -0
- package/dist/core/group/service.d.ts +9 -0
- package/dist/core/group/service.js +259 -25
- package/dist/core/group/types.d.ts +30 -0
- package/dist/core/ingestion/ast-cache.d.ts +16 -1
- package/dist/core/ingestion/ast-cache.js +14 -2
- package/dist/core/ingestion/call-processor.js +9 -0
- package/dist/core/ingestion/emit-references.d.ts +88 -0
- package/dist/core/ingestion/emit-references.js +229 -0
- package/dist/core/ingestion/filesystem-walker.js +6 -4
- package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
- package/dist/core/ingestion/finalize-orchestrator.js +139 -0
- package/dist/core/ingestion/framework-detection.js +6 -2
- package/dist/core/ingestion/import-processor.js +4 -0
- package/dist/core/ingestion/import-resolvers/python.js +9 -6
- 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-provider.d.ts +36 -33
- 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 +249 -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 +50 -0
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +374 -0
- package/dist/core/ingestion/languages/csharp/query.d.ts +35 -0
- package/dist/core/ingestion/languages/csharp/query.js +515 -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.js +14 -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 +106 -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 +99 -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 +23 -0
- package/dist/core/ingestion/languages/python/simple-hooks.js +35 -0
- package/dist/core/ingestion/languages/python.js +14 -0
- package/dist/core/ingestion/model/method-registry.d.ts +9 -0
- package/dist/core/ingestion/model/method-registry.js +4 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +59 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +64 -0
- package/dist/core/ingestion/model/semantic-model.js +55 -0
- package/dist/core/ingestion/mro-processor.js +38 -22
- package/dist/core/ingestion/parsing-processor.d.ts +18 -1
- package/dist/core/ingestion/parsing-processor.js +45 -11
- package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/index.js +1 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +17 -2
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +18 -0
- package/dist/core/ingestion/pipeline.js +2 -1
- package/dist/core/ingestion/registry-primary-flag.d.ts +86 -0
- package/dist/core/ingestion/registry-primary-flag.js +111 -0
- package/dist/core/ingestion/resolve-references.d.ts +63 -0
- package/dist/core/ingestion/resolve-references.js +175 -0
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +32 -0
- package/dist/core/ingestion/scope-extractor-bridge.js +44 -0
- package/dist/core/ingestion/scope-extractor.d.ts +86 -0
- package/dist/core/ingestion/scope-extractor.js +758 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +372 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +212 -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 +112 -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 +30 -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 +113 -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 +198 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +27 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +131 -0
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +48 -0
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +130 -0
- package/dist/core/ingestion/scope-resolution/passes/mro.d.ts +42 -0
- package/dist/core/ingestion/scope-resolution/passes/mro.js +99 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +26 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +61 -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 +327 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +47 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +130 -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 +21 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +66 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +157 -0
- package/dist/core/ingestion/scope-resolution/scope/namespace-targets.d.ts +36 -0
- package/dist/core/ingestion/scope-resolution/scope/namespace-targets.js +52 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +127 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +349 -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/utils/ast-helpers.d.ts +19 -1
- package/dist/core/ingestion/utils/ast-helpers.js +70 -0
- package/dist/core/ingestion/utils/max-file-size.d.ts +20 -0
- package/dist/core/ingestion/utils/max-file-size.js +52 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +9 -0
- package/dist/core/ingestion/workers/parse-worker.js +57 -21
- package/dist/core/lbug/lbug-adapter.d.ts +22 -2
- package/dist/core/lbug/lbug-adapter.js +58 -14
- package/dist/core/lbug/pool-adapter.d.ts +17 -0
- package/dist/core/lbug/pool-adapter.js +24 -14
- package/dist/core/run-analyze.d.ts +32 -0
- package/dist/core/run-analyze.js +74 -19
- package/dist/core/search/bm25-index.d.ts +18 -0
- package/dist/core/search/bm25-index.js +125 -12
- package/dist/core/tree-sitter/parser-loader.js +6 -1
- package/dist/mcp/local/local-backend.d.ts +67 -3
- package/dist/mcp/local/local-backend.js +296 -34
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +100 -17
- package/dist/mcp/tools.d.ts +4 -1
- package/dist/mcp/tools.js +75 -54
- package/dist/server/api.js +6 -2
- package/dist/storage/git.d.ts +49 -0
- package/dist/storage/git.js +111 -0
- package/dist/storage/repo-manager.d.ts +246 -1
- package/dist/storage/repo-manager.js +391 -9
- package/package.json +7 -6
- package/scripts/bench-scope-resolution.ts +134 -0
- package/scripts/ci-list-migrated-languages.ts +24 -0
- package/skills/gitnexus-cli.md +1 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ScopeResolutionIndexes` — the bundle of materialized indexes produced
|
|
3
|
+
* by the finalize-orchestrator (RFC #909 Ring 2 PKG #921) and attached
|
|
4
|
+
* to `MutableSemanticModel`.
|
|
5
|
+
*
|
|
6
|
+
* Produced by `finalizeScopeModel(parsedFiles, hooks)` in
|
|
7
|
+
* `finalize-orchestrator.ts`. Consumed by the resolution phase (future
|
|
8
|
+
* tickets) where `Registry.lookup` / `resolveTypeRef` query this bundle
|
|
9
|
+
* to answer call-resolution questions without re-walking any AST.
|
|
10
|
+
*
|
|
11
|
+
* ## Lifecycle
|
|
12
|
+
*
|
|
13
|
+
* 1. Pipeline collects `ParsedFile[]` from the parsing-processor (#920).
|
|
14
|
+
* 2. Pipeline invokes `finalizeScopeModel(parsedFiles, hooks)` →
|
|
15
|
+
* returns a `ScopeResolutionIndexes` (this interface).
|
|
16
|
+
* 3. Pipeline calls `model.attachScopeIndexes(indexes)` to stamp them
|
|
17
|
+
* onto the `MutableSemanticModel`. This is a **one-shot write**;
|
|
18
|
+
* subsequent calls throw. After attachment, the indexes are frozen
|
|
19
|
+
* at the type level (everything is `readonly`) and at runtime via
|
|
20
|
+
* `Object.freeze` on the bundle.
|
|
21
|
+
* 4. Resolution callers hold a `SemanticModel` reference and read
|
|
22
|
+
* `model.scopes` to query.
|
|
23
|
+
*
|
|
24
|
+
* ## Content
|
|
25
|
+
*
|
|
26
|
+
* - `scopeTree` / `moduleScopes` / `defs` / `qualifiedNames` — the
|
|
27
|
+
* four Ring 2 SHARED indexes built over per-file artifacts.
|
|
28
|
+
* - `methodDispatch` — MRO + implements materialized view (#914).
|
|
29
|
+
* - `imports` — finalized `ImportEdge[]` per module scope (`parsedImports`
|
|
30
|
+
* resolved through cross-file link + wildcard expansion).
|
|
31
|
+
* - `bindings` — merged bindings per module scope (local + import +
|
|
32
|
+
* wildcard + re-export), with the provider's precedence applied.
|
|
33
|
+
* - `referenceSites` — union of every file's pre-resolution usage
|
|
34
|
+
* facts. Consumed by the resolution phase (future) to emit
|
|
35
|
+
* `Reference` records into `ReferenceIndex`.
|
|
36
|
+
* - `stats` — coarse-grained counts from the shared finalize algorithm
|
|
37
|
+
* (total files/edges, linked vs unresolved, SCC topology).
|
|
38
|
+
*
|
|
39
|
+
* `ReferenceIndex` is deliberately NOT here — it is populated in a later
|
|
40
|
+
* phase (RFC §3.2 Phase 4 / Ring 2 PKG #925) and owned separately.
|
|
41
|
+
*/
|
|
42
|
+
export {};
|
|
@@ -44,11 +44,51 @@
|
|
|
44
44
|
* direct `createSymbolTable()` caller (e.g. an isolated unit test) gets
|
|
45
45
|
* the pure, registry-free behavior — no surprises, no hidden side
|
|
46
46
|
* effects.
|
|
47
|
+
*
|
|
48
|
+
* ## Single-source-of-truth invariant
|
|
49
|
+
*
|
|
50
|
+
* `SemanticModel` is the authoritative symbol store for the whole
|
|
51
|
+
* ingestion pipeline. Both the legacy Call-Resolution DAG and the
|
|
52
|
+
* new scope-resolution pipeline read symbol-keyed lookups from here
|
|
53
|
+
* exclusively — no parallel owner-keyed, name-keyed, or file-keyed
|
|
54
|
+
* symbol indexes exist outside this module. The scope-resolution
|
|
55
|
+
* pipeline does carry a small `WorkspaceResolutionIndex` for
|
|
56
|
+
* `Scope`-valued maps (`classScopeByDefId`, `moduleScopeByFile`) that
|
|
57
|
+
* `SemanticModel` structurally cannot hold, but nothing else.
|
|
58
|
+
*
|
|
59
|
+
* ## Write / read phase contract
|
|
60
|
+
*
|
|
61
|
+
* Writes to the model happen in three clearly-ordered phases during a
|
|
62
|
+
* single ingestion run:
|
|
63
|
+
*
|
|
64
|
+
* 1. **Legacy parse phase** (`parsing-processor`) calls
|
|
65
|
+
* `symbols.add(...)` per extracted symbol, which fans out via
|
|
66
|
+
* the dispatch table into `types` / `methods` / `fields`.
|
|
67
|
+
* 2. **Scope-resolution reconciliation** (`reconcileOwnership` in
|
|
68
|
+
* `scope-resolution/pipeline/reconcile-ownership.ts`) registers
|
|
69
|
+
* any `parsed.localDefs[i]` with a scope-resolution-corrected
|
|
70
|
+
* `ownerId` that the legacy pass missed (Python class-body
|
|
71
|
+
* methods are the canonical case). Idempotent.
|
|
72
|
+
* 3. **Finalize-orchestrator** calls `attachScopeIndexes(...)` to
|
|
73
|
+
* stamp the materialized `ScopeResolutionIndexes` bundle onto
|
|
74
|
+
* `model.scopes`. One-shot; throws on a second call.
|
|
75
|
+
*
|
|
76
|
+
* After these three phases, the model is effectively frozen:
|
|
77
|
+
* - `attachScopeIndexes` applied `Object.freeze` to its bundle.
|
|
78
|
+
* - Downstream passes receive the narrowed `SemanticModel` reader
|
|
79
|
+
* handle (not `MutableSemanticModel`), so `.register()` /
|
|
80
|
+
* `.clear()` / `attachScopeIndexes()` are structurally absent.
|
|
81
|
+
*
|
|
82
|
+
* See `scope-resolution/contract/scope-resolver.ts` Contract
|
|
83
|
+
* Invariant I9 for the scope-resolution-side rule and
|
|
84
|
+
* `ARCHITECTURE.md` § "Semantic-model source of truth" for the
|
|
85
|
+
* overall architecture.
|
|
47
86
|
*/
|
|
48
87
|
import type { TypeRegistry, MutableTypeRegistry } from './type-registry.js';
|
|
49
88
|
import type { MethodRegistry, MutableMethodRegistry } from './method-registry.js';
|
|
50
89
|
import type { FieldRegistry, MutableFieldRegistry } from './field-registry.js';
|
|
51
90
|
import type { SymbolTableReader, SymbolTableWriter } from './symbol-table.js';
|
|
91
|
+
import type { ScopeResolutionIndexes } from './scope-resolution-indexes.js';
|
|
52
92
|
/**
|
|
53
93
|
* Aggregated read-only view of the semantic registries plus the nested
|
|
54
94
|
* file/callable SymbolTable.
|
|
@@ -70,6 +110,19 @@ export interface SemanticModel {
|
|
|
70
110
|
readonly methods: MethodRegistry;
|
|
71
111
|
readonly fields: FieldRegistry;
|
|
72
112
|
readonly symbols: SymbolTableReader;
|
|
113
|
+
/**
|
|
114
|
+
* Materialized scope-resolution indexes from RFC #909 Ring 2 PKG #921.
|
|
115
|
+
*
|
|
116
|
+
* `undefined` until the finalize-orchestrator attaches them. While
|
|
117
|
+
* `undefined`, the legacy DAG is the sole resolution surface; once set,
|
|
118
|
+
* resolvers whose language has `REGISTRY_PRIMARY_<LANG>=true` consult
|
|
119
|
+
* these indexes instead.
|
|
120
|
+
*
|
|
121
|
+
* The attach is a one-shot write (see `MutableSemanticModel`). Callers
|
|
122
|
+
* holding a read-only `SemanticModel` handle see either `undefined` or
|
|
123
|
+
* the final frozen bundle — never a half-populated view.
|
|
124
|
+
*/
|
|
125
|
+
readonly scopes?: ScopeResolutionIndexes;
|
|
73
126
|
}
|
|
74
127
|
/** Mutable variant — exposes the MutableX registries, a Writer-typed
|
|
75
128
|
* `symbols` facade, and a full-cascade reset. This is the interface
|
|
@@ -82,5 +135,16 @@ export interface MutableSemanticModel extends SemanticModel {
|
|
|
82
135
|
readonly symbols: SymbolTableWriter;
|
|
83
136
|
/** Clear all registries AND the nested SymbolTable. */
|
|
84
137
|
clear(): void;
|
|
138
|
+
/**
|
|
139
|
+
* Stamp the finalize-orchestrator's output onto this model.
|
|
140
|
+
*
|
|
141
|
+
* **One-shot write.** Throws when called a second time — the indexes are
|
|
142
|
+
* meant to be materialized once per ingestion run. `Object.freeze` is
|
|
143
|
+
* applied to the attached bundle so consumers cannot mutate after attach.
|
|
144
|
+
*
|
|
145
|
+
* `clear()` resets the attached bundle back to `undefined`, enabling a
|
|
146
|
+
* fresh re-ingestion to attach a new bundle.
|
|
147
|
+
*/
|
|
148
|
+
attachScopeIndexes(indexes: ScopeResolutionIndexes): void;
|
|
85
149
|
}
|
|
86
150
|
export declare const createSemanticModel: () => MutableSemanticModel;
|
|
@@ -44,6 +44,45 @@
|
|
|
44
44
|
* direct `createSymbolTable()` caller (e.g. an isolated unit test) gets
|
|
45
45
|
* the pure, registry-free behavior — no surprises, no hidden side
|
|
46
46
|
* effects.
|
|
47
|
+
*
|
|
48
|
+
* ## Single-source-of-truth invariant
|
|
49
|
+
*
|
|
50
|
+
* `SemanticModel` is the authoritative symbol store for the whole
|
|
51
|
+
* ingestion pipeline. Both the legacy Call-Resolution DAG and the
|
|
52
|
+
* new scope-resolution pipeline read symbol-keyed lookups from here
|
|
53
|
+
* exclusively — no parallel owner-keyed, name-keyed, or file-keyed
|
|
54
|
+
* symbol indexes exist outside this module. The scope-resolution
|
|
55
|
+
* pipeline does carry a small `WorkspaceResolutionIndex` for
|
|
56
|
+
* `Scope`-valued maps (`classScopeByDefId`, `moduleScopeByFile`) that
|
|
57
|
+
* `SemanticModel` structurally cannot hold, but nothing else.
|
|
58
|
+
*
|
|
59
|
+
* ## Write / read phase contract
|
|
60
|
+
*
|
|
61
|
+
* Writes to the model happen in three clearly-ordered phases during a
|
|
62
|
+
* single ingestion run:
|
|
63
|
+
*
|
|
64
|
+
* 1. **Legacy parse phase** (`parsing-processor`) calls
|
|
65
|
+
* `symbols.add(...)` per extracted symbol, which fans out via
|
|
66
|
+
* the dispatch table into `types` / `methods` / `fields`.
|
|
67
|
+
* 2. **Scope-resolution reconciliation** (`reconcileOwnership` in
|
|
68
|
+
* `scope-resolution/pipeline/reconcile-ownership.ts`) registers
|
|
69
|
+
* any `parsed.localDefs[i]` with a scope-resolution-corrected
|
|
70
|
+
* `ownerId` that the legacy pass missed (Python class-body
|
|
71
|
+
* methods are the canonical case). Idempotent.
|
|
72
|
+
* 3. **Finalize-orchestrator** calls `attachScopeIndexes(...)` to
|
|
73
|
+
* stamp the materialized `ScopeResolutionIndexes` bundle onto
|
|
74
|
+
* `model.scopes`. One-shot; throws on a second call.
|
|
75
|
+
*
|
|
76
|
+
* After these three phases, the model is effectively frozen:
|
|
77
|
+
* - `attachScopeIndexes` applied `Object.freeze` to its bundle.
|
|
78
|
+
* - Downstream passes receive the narrowed `SemanticModel` reader
|
|
79
|
+
* handle (not `MutableSemanticModel`), so `.register()` /
|
|
80
|
+
* `.clear()` / `attachScopeIndexes()` are structurally absent.
|
|
81
|
+
*
|
|
82
|
+
* See `scope-resolution/contract/scope-resolver.ts` Contract
|
|
83
|
+
* Invariant I9 for the scope-resolution-side rule and
|
|
84
|
+
* `ARCHITECTURE.md` § "Semantic-model source of truth" for the
|
|
85
|
+
* overall architecture.
|
|
47
86
|
*/
|
|
48
87
|
import { createTypeRegistry } from './type-registry.js';
|
|
49
88
|
import { createMethodRegistry } from './method-registry.js';
|
|
@@ -85,6 +124,17 @@ export const createSemanticModel = () => {
|
|
|
85
124
|
}
|
|
86
125
|
return def;
|
|
87
126
|
};
|
|
127
|
+
// Scope-resolution bundle slot. Starts `undefined`; populated by a
|
|
128
|
+
// one-shot `attachScopeIndexes(...)` from the finalize-orchestrator.
|
|
129
|
+
// Held inside the factory closure so the returned `SemanticModel`
|
|
130
|
+
// surface exposes it as a plain `readonly` property without a setter.
|
|
131
|
+
let attachedScopes;
|
|
132
|
+
const attachScopeIndexes = (indexes) => {
|
|
133
|
+
if (attachedScopes !== undefined) {
|
|
134
|
+
throw new Error('SemanticModel: scope indexes already attached. ' + 'Call `clear()` before re-attaching.');
|
|
135
|
+
}
|
|
136
|
+
attachedScopes = Object.freeze(indexes);
|
|
137
|
+
};
|
|
88
138
|
// Cascade clear: single source of truth for "reset the entire model".
|
|
89
139
|
// Wired into both `model.clear()` AND `model.symbols.clear()` so that a
|
|
90
140
|
// caller holding only a SymbolTable reference can't leave the
|
|
@@ -95,6 +145,7 @@ export const createSemanticModel = () => {
|
|
|
95
145
|
methods.clear();
|
|
96
146
|
fields.clear();
|
|
97
147
|
rawSymbols.clear();
|
|
148
|
+
attachedScopes = undefined;
|
|
98
149
|
};
|
|
99
150
|
// Writer-typed facade: exposes reads + add, but NO `clear` field.
|
|
100
151
|
// Callers holding a `SemanticModel.symbols` reference cannot desync
|
|
@@ -115,6 +166,10 @@ export const createSemanticModel = () => {
|
|
|
115
166
|
methods,
|
|
116
167
|
fields,
|
|
117
168
|
symbols,
|
|
169
|
+
get scopes() {
|
|
170
|
+
return attachedScopes;
|
|
171
|
+
},
|
|
118
172
|
clear: cascadeClear,
|
|
173
|
+
attachScopeIndexes,
|
|
119
174
|
};
|
|
120
175
|
};
|
|
@@ -32,30 +32,46 @@ function buildAdjacency(graph) {
|
|
|
32
32
|
const methodMap = new Map();
|
|
33
33
|
// Track which edge type each parent link came from
|
|
34
34
|
const parentEdgeType = new Map();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
parents
|
|
43
|
-
|
|
44
|
-
if (!edgeTypes) {
|
|
45
|
-
edgeTypes = new Map();
|
|
46
|
-
parentEdgeType.set(rel.sourceId, edgeTypes);
|
|
47
|
-
}
|
|
48
|
-
edgeTypes.set(rel.targetId, rel.type);
|
|
35
|
+
// Three typed iterations replace one full-relationship-map scan
|
|
36
|
+
// with per-edge type checks. Each consumes only the edges of the
|
|
37
|
+
// type it cares about — see plan
|
|
38
|
+
// docs/plans/2026-04-20-002-perf-parse-heritage-mro-plan.md (Unit 2).
|
|
39
|
+
for (const rel of graph.iterRelationshipsByType('EXTENDS')) {
|
|
40
|
+
let parents = parentMap.get(rel.sourceId);
|
|
41
|
+
if (!parents) {
|
|
42
|
+
parents = [];
|
|
43
|
+
parentMap.set(rel.sourceId, parents);
|
|
49
44
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
parents.push(rel.targetId);
|
|
46
|
+
let edgeTypes = parentEdgeType.get(rel.sourceId);
|
|
47
|
+
if (!edgeTypes) {
|
|
48
|
+
edgeTypes = new Map();
|
|
49
|
+
parentEdgeType.set(rel.sourceId, edgeTypes);
|
|
50
|
+
}
|
|
51
|
+
edgeTypes.set(rel.targetId, 'EXTENDS');
|
|
52
|
+
}
|
|
53
|
+
for (const rel of graph.iterRelationshipsByType('IMPLEMENTS')) {
|
|
54
|
+
let parents = parentMap.get(rel.sourceId);
|
|
55
|
+
if (!parents) {
|
|
56
|
+
parents = [];
|
|
57
|
+
parentMap.set(rel.sourceId, parents);
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
+
parents.push(rel.targetId);
|
|
60
|
+
let edgeTypes = parentEdgeType.get(rel.sourceId);
|
|
61
|
+
if (!edgeTypes) {
|
|
62
|
+
edgeTypes = new Map();
|
|
63
|
+
parentEdgeType.set(rel.sourceId, edgeTypes);
|
|
64
|
+
}
|
|
65
|
+
edgeTypes.set(rel.targetId, 'IMPLEMENTS');
|
|
66
|
+
}
|
|
67
|
+
for (const rel of graph.iterRelationshipsByType('HAS_METHOD')) {
|
|
68
|
+
let methods = methodMap.get(rel.sourceId);
|
|
69
|
+
if (!methods) {
|
|
70
|
+
methods = [];
|
|
71
|
+
methodMap.set(rel.sourceId, methods);
|
|
72
|
+
}
|
|
73
|
+
methods.push(rel.targetId);
|
|
74
|
+
}
|
|
59
75
|
return { parentMap, methodMap, parentEdgeType };
|
|
60
76
|
}
|
|
61
77
|
/** Resolve by MRO order — first ancestor in linearized order wins. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { KnowledgeGraph } from '../graph/types.js';
|
|
2
2
|
import type { SymbolTableWriter, ExtractedHeritage } from './model/index.js';
|
|
3
3
|
import { ASTCache } from './ast-cache.js';
|
|
4
|
+
import type { ParsedFile } from '../../_shared/index.js';
|
|
4
5
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
5
6
|
import type { ExtractedImport, ExtractedCall, ExtractedAssignment, ExtractedRoute, ExtractedFetchCall, ExtractedDecoratorRoute, ExtractedToolDef, FileConstructorBindings, FileScopeBindings, ExtractedORMQuery } from './workers/parse-worker.js';
|
|
6
7
|
export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
|
|
@@ -16,8 +17,24 @@ export interface WorkerExtractedData {
|
|
|
16
17
|
ormQueries: ExtractedORMQuery[];
|
|
17
18
|
constructorBindings: FileConstructorBindings[];
|
|
18
19
|
fileScopeBindings: FileScopeBindings[];
|
|
20
|
+
/**
|
|
21
|
+
* Per-file `ParsedFile` artifacts from the new scope-based resolution
|
|
22
|
+
* pipeline (RFC #909 Ring 2). Empty until a provider implements
|
|
23
|
+
* `emitScopeCaptures` — additive to the legacy DAG path. Aggregated
|
|
24
|
+
* from every worker chunk; consumed downstream by #921's
|
|
25
|
+
* finalize-orchestrator.
|
|
26
|
+
*/
|
|
27
|
+
parsedFiles: ParsedFile[];
|
|
19
28
|
}
|
|
20
29
|
export declare const processParsing: (graph: KnowledgeGraph, files: {
|
|
21
30
|
path: string;
|
|
22
31
|
content: string;
|
|
23
|
-
}[], symbolTable: SymbolTableWriter, astCache: ASTCache,
|
|
32
|
+
}[], symbolTable: SymbolTableWriter, astCache: ASTCache,
|
|
33
|
+
/**
|
|
34
|
+
* Persistent tree cache (separate from `astCache`, which the caller
|
|
35
|
+
* clears between chunks). Sequential parses additionally write the
|
|
36
|
+
* Tree here so cross-phase consumers (scope-resolution) can read it.
|
|
37
|
+
* Worker-mode parses skip — Trees can't cross MessageChannels.
|
|
38
|
+
* Pass `undefined` if no consumer needs cross-phase access.
|
|
39
|
+
*/
|
|
40
|
+
scopeTreeCache: ASTCache | undefined, onFileProgress?: FileProgressCallback, workerPool?: WorkerPool) => Promise<WorkerExtractedData | null>;
|
|
@@ -5,6 +5,7 @@ import { generateId } from '../../lib/utils.js';
|
|
|
5
5
|
import { getLanguageFromFilename, SupportedLanguages } from '../../_shared/index.js';
|
|
6
6
|
import { extractVueScript, isVueSetupTopLevel } from './vue-sfc-extractor.js';
|
|
7
7
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
8
|
+
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
8
9
|
import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
|
|
9
10
|
import { detectFrameworkFromAST } from './framework-detection.js';
|
|
10
11
|
import { buildTypeEnv } from './type-env.js';
|
|
@@ -34,6 +35,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
34
35
|
ormQueries: [],
|
|
35
36
|
constructorBindings: [],
|
|
36
37
|
fileScopeBindings: [],
|
|
38
|
+
parsedFiles: [],
|
|
37
39
|
};
|
|
38
40
|
const total = files.length;
|
|
39
41
|
// Dispatch to worker pool — pool handles splitting into chunks and sub-batching
|
|
@@ -52,6 +54,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
52
54
|
const allORMQueries = [];
|
|
53
55
|
const allConstructorBindings = [];
|
|
54
56
|
const fileScopeBindingsByFile = [];
|
|
57
|
+
const allParsedFiles = [];
|
|
55
58
|
for (const result of chunkResults) {
|
|
56
59
|
for (const node of result.nodes) {
|
|
57
60
|
graph.addNode({
|
|
@@ -98,6 +101,13 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
98
101
|
if (result.fileScopeBindings)
|
|
99
102
|
for (const item of result.fileScopeBindings)
|
|
100
103
|
fileScopeBindingsByFile.push(item);
|
|
104
|
+
// RFC #909 Ring 2: aggregate per-file scope artifacts. Tolerant of
|
|
105
|
+
// workers that don't emit the field yet (older worker builds or
|
|
106
|
+
// partial rollouts), since the additive contract means undefined =
|
|
107
|
+
// "this worker produced no ParsedFiles for this chunk".
|
|
108
|
+
if (result.parsedFiles)
|
|
109
|
+
for (const item of result.parsedFiles)
|
|
110
|
+
allParsedFiles.push(item);
|
|
101
111
|
}
|
|
102
112
|
// Merge and log skipped languages from workers
|
|
103
113
|
const skippedLanguages = new Map();
|
|
@@ -126,6 +136,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
126
136
|
ormQueries: allORMQueries,
|
|
127
137
|
constructorBindings: allConstructorBindings,
|
|
128
138
|
fileScopeBindings: fileScopeBindingsByFile,
|
|
139
|
+
parsedFiles: allParsedFiles,
|
|
129
140
|
};
|
|
130
141
|
};
|
|
131
142
|
// ============================================================================
|
|
@@ -210,10 +221,11 @@ function seqGetFieldInfo(classNode, provider, context) {
|
|
|
210
221
|
seqFieldInfoCache.set(cacheKey, cached);
|
|
211
222
|
return cached;
|
|
212
223
|
}
|
|
213
|
-
const processParsingSequential = async (graph, files, symbolTable, astCache, onFileProgress) => {
|
|
224
|
+
const processParsingSequential = async (graph, files, symbolTable, astCache, scopeTreeCache, onFileProgress) => {
|
|
214
225
|
const parser = await loadParser();
|
|
215
226
|
const total = files.length;
|
|
216
|
-
const
|
|
227
|
+
const logSkipped = isVerboseIngestionEnabled();
|
|
228
|
+
const skippedByLang = logSkipped ? new Map() : null;
|
|
217
229
|
for (let i = 0; i < files.length; i++) {
|
|
218
230
|
const file = files[i];
|
|
219
231
|
// Reset memoization before each new file (node refs are per-tree)
|
|
@@ -228,9 +240,10 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
228
240
|
const language = getLanguageFromFilename(file.path);
|
|
229
241
|
if (!language)
|
|
230
242
|
continue;
|
|
231
|
-
// Skip unsupported languages (e.g. Swift when tree-sitter-swift not installed)
|
|
232
243
|
if (!isLanguageAvailable(language)) {
|
|
233
|
-
|
|
244
|
+
if (skippedByLang) {
|
|
245
|
+
skippedByLang.set(language, (skippedByLang.get(language) ?? 0) + 1);
|
|
246
|
+
}
|
|
234
247
|
continue;
|
|
235
248
|
}
|
|
236
249
|
// Skip files larger than the max tree-sitter buffer (32 MB)
|
|
@@ -266,6 +279,13 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
266
279
|
}
|
|
267
280
|
astCache.set(file.path, tree);
|
|
268
281
|
const provider = getProvider(language);
|
|
282
|
+
// Mirror into the cross-phase cache only when the language has a
|
|
283
|
+
// scope-resolution consumer — otherwise we retain Trees no one
|
|
284
|
+
// reads. parse-impl clears `astCache` between chunks;
|
|
285
|
+
// `scopeTreeCache` survives until scope-resolution disposes it.
|
|
286
|
+
if (provider.emitScopeCaptures !== undefined) {
|
|
287
|
+
scopeTreeCache?.set(file.path, tree);
|
|
288
|
+
}
|
|
269
289
|
const queryString = provider.treeSitterQueries;
|
|
270
290
|
if (!queryString) {
|
|
271
291
|
continue;
|
|
@@ -517,18 +537,32 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
517
537
|
}
|
|
518
538
|
});
|
|
519
539
|
}
|
|
520
|
-
if (
|
|
521
|
-
const
|
|
522
|
-
.
|
|
523
|
-
|
|
524
|
-
console.warn(` Skipped unsupported languages: ${summary}`);
|
|
540
|
+
if (skippedByLang && skippedByLang.size > 0) {
|
|
541
|
+
for (const [lang, count] of skippedByLang.entries()) {
|
|
542
|
+
console.warn(`[ingestion] Skipped ${count} ${lang} file(s) in parsing processing — ${lang} parser not available.`);
|
|
543
|
+
}
|
|
525
544
|
}
|
|
526
545
|
};
|
|
527
546
|
// ============================================================================
|
|
528
547
|
// Public API
|
|
529
548
|
// ============================================================================
|
|
530
|
-
export const processParsing = async (graph, files, symbolTable, astCache,
|
|
549
|
+
export const processParsing = async (graph, files, symbolTable, astCache,
|
|
550
|
+
/**
|
|
551
|
+
* Persistent tree cache (separate from `astCache`, which the caller
|
|
552
|
+
* clears between chunks). Sequential parses additionally write the
|
|
553
|
+
* Tree here so cross-phase consumers (scope-resolution) can read it.
|
|
554
|
+
* Worker-mode parses skip — Trees can't cross MessageChannels.
|
|
555
|
+
* Pass `undefined` if no consumer needs cross-phase access.
|
|
556
|
+
*/
|
|
557
|
+
scopeTreeCache, onFileProgress, workerPool) => {
|
|
531
558
|
if (workerPool) {
|
|
559
|
+
if (scopeTreeCache !== undefined && process.env.PROF_SCOPE_RESOLUTION === '1') {
|
|
560
|
+
// Trees can't cross MessageChannels, so worker-parsed files land
|
|
561
|
+
// in scope-resolution with an empty cache and get re-parsed.
|
|
562
|
+
// Surfacing this in PROF mode prevents silent perf cliffs when
|
|
563
|
+
// a repo crosses the worker-pool threshold.
|
|
564
|
+
console.warn(`[scope-resolution prof] worker pool engaged for ${files.length} files — cross-phase tree cache will be empty; scope-resolution re-parses.`);
|
|
565
|
+
}
|
|
532
566
|
try {
|
|
533
567
|
return await processParsingWithWorkers(graph, files, symbolTable, astCache, workerPool, onFileProgress);
|
|
534
568
|
}
|
|
@@ -537,6 +571,6 @@ export const processParsing = async (graph, files, symbolTable, astCache, onFile
|
|
|
537
571
|
}
|
|
538
572
|
}
|
|
539
573
|
// Fallback: sequential parsing (no pre-extracted data)
|
|
540
|
-
await processParsingSequential(graph, files, symbolTable, astCache, onFileProgress);
|
|
574
|
+
await processParsingSequential(graph, files, symbolTable, astCache, scopeTreeCache, onFileProgress);
|
|
541
575
|
return null;
|
|
542
576
|
};
|
|
@@ -13,6 +13,7 @@ export { routesPhase, type RoutesOutput, type RouteEntry } from './routes.js';
|
|
|
13
13
|
export { toolsPhase, type ToolsOutput, type ToolDef } from './tools.js';
|
|
14
14
|
export { ormPhase, type ORMOutput } from './orm.js';
|
|
15
15
|
export { crossFilePhase, type CrossFileOutput } from './cross-file.js';
|
|
16
|
+
export { scopeResolutionPhase, type ScopeResolutionOutput, } from '../scope-resolution/pipeline/phase.js';
|
|
16
17
|
export { mroPhase, type MROOutput } from './mro.js';
|
|
17
18
|
export { communitiesPhase, type CommunitiesOutput } from './communities.js';
|
|
18
19
|
export { processesPhase, type ProcessesOutput } from './processes.js';
|
|
@@ -14,6 +14,7 @@ export { routesPhase } from './routes.js';
|
|
|
14
14
|
export { toolsPhase } from './tools.js';
|
|
15
15
|
export { ormPhase } from './orm.js';
|
|
16
16
|
export { crossFilePhase } from './cross-file.js';
|
|
17
|
+
export { scopeResolutionPhase, } from '../scope-resolution/pipeline/phase.js';
|
|
17
18
|
export { mroPhase } from './mro.js';
|
|
18
19
|
export { communitiesPhase } from './communities.js';
|
|
19
20
|
export { processesPhase } from './processes.js';
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { BindingAccumulator } from '../binding-accumulator.js';
|
|
15
15
|
import { type ExportedTypeMap } from '../call-processor.js';
|
|
16
16
|
import { createResolutionContext } from '../model/resolution-context.js';
|
|
17
|
+
import { ASTCache } from '../ast-cache.js';
|
|
17
18
|
import { type PipelineProgress } from '../../../_shared/index.js';
|
|
18
19
|
import type { ExtractedDecoratorRoute, ExtractedFetchCall, ExtractedORMQuery, ExtractedRoute, ExtractedToolDef } from '../workers/parse-worker.js';
|
|
19
20
|
import type { KnowledgeGraph } from '../../graph/types.js';
|
|
@@ -44,5 +45,14 @@ export declare function runChunkedParseAndResolve(graph: KnowledgeGraph, scanned
|
|
|
44
45
|
bindingAccumulator: BindingAccumulator;
|
|
45
46
|
resolutionContext: ReturnType<typeof createResolutionContext>;
|
|
46
47
|
usedWorkerPool: boolean;
|
|
48
|
+
/** Cross-phase tree-sitter Tree cache populated by the sequential
|
|
49
|
+
* parse path. Distinct from the chunk-local `astCache` used inside
|
|
50
|
+
* the parse loop (that one is cleared between chunks). Empty when
|
|
51
|
+
* every chunk ran via the worker pool (workers can't return native
|
|
52
|
+
* tree-sitter Trees across the MessageChannel). Downstream phases
|
|
53
|
+
* (scope-resolution) read from this to skip re-parsing the same
|
|
54
|
+
* source. See plan
|
|
55
|
+
* docs/plans/2026-04-20-002-perf-parse-heritage-mro-plan.md (Unit 4). */
|
|
56
|
+
scopeTreeCache: ASTCache;
|
|
47
57
|
}>;
|
|
48
58
|
export {};
|
|
@@ -126,9 +126,18 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
let filesParsedSoFar = 0;
|
|
129
|
-
//
|
|
129
|
+
// Two caches with different lifetimes:
|
|
130
|
+
// - `astCache` (chunk-local, cleared between chunks) — call /
|
|
131
|
+
// heritage / import processors read it during parse to avoid
|
|
132
|
+
// re-parsing within the same chunk.
|
|
133
|
+
// - `scopeTreeCache` (total-parseable-sized, never cleared by
|
|
134
|
+
// parse-impl) — exposed via ParseOutput so scope-resolution can
|
|
135
|
+
// skip a second tree-sitter parse. Worker-mode parses don't
|
|
136
|
+
// populate either; consumers fall back to a fresh parse.
|
|
137
|
+
// See plan docs/plans/2026-04-20-002-perf-parse-heritage-mro-plan.md (Unit 4).
|
|
130
138
|
const maxChunkFiles = chunks.reduce((max, c) => Math.max(max, c.length), 0);
|
|
131
139
|
let astCache = createASTCache(maxChunkFiles);
|
|
140
|
+
const scopeTreeCache = createASTCache(Math.max(parseableScanned.length, 1));
|
|
132
141
|
// Build import resolution context once — suffix index, file lists, resolve cache.
|
|
133
142
|
const importCtx = buildImportResolutionContext(allPaths);
|
|
134
143
|
const allPathObjects = allPaths.map((p) => ({ path: p }));
|
|
@@ -161,7 +170,7 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
|
|
|
161
170
|
const chunkFiles = chunkPaths
|
|
162
171
|
.filter((p) => chunkContents.has(p))
|
|
163
172
|
.map((p) => ({ path: p, content: chunkContents.get(p) }));
|
|
164
|
-
const chunkWorkerData = await processParsing(graph, chunkFiles, symbolTable, astCache, (current, _total, filePath) => {
|
|
173
|
+
const chunkWorkerData = await processParsing(graph, chunkFiles, symbolTable, astCache, scopeTreeCache, (current, _total, filePath) => {
|
|
165
174
|
const globalCurrent = filesParsedSoFar + current;
|
|
166
175
|
const parsingProgress = 20 + (globalCurrent / totalParseable) * 62;
|
|
167
176
|
onProgress({
|
|
@@ -439,5 +448,11 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
|
|
|
439
448
|
// sequential fallback handled every chunk (either due to `skipWorkers`,
|
|
440
449
|
// the file-count/byte thresholds, or a pool-creation failure).
|
|
441
450
|
usedWorkerPool: workerPool !== undefined,
|
|
451
|
+
// Surface the persistent scope cache so downstream phases
|
|
452
|
+
// (scope-resolution) can skip re-parsing files that the
|
|
453
|
+
// sequential path already parsed. Survives chunk boundaries; the
|
|
454
|
+
// chunk-local `astCache` above is intentionally NOT exposed
|
|
455
|
+
// because parse-impl clears it between chunks.
|
|
456
|
+
scopeTreeCache,
|
|
442
457
|
};
|
|
443
458
|
}
|
|
@@ -19,6 +19,7 @@ import type { PipelinePhase } from './types.js';
|
|
|
19
19
|
import type { BindingAccumulator } from '../binding-accumulator.js';
|
|
20
20
|
import type { ExtractedFetchCall, ExtractedRoute, ExtractedDecoratorRoute, ExtractedToolDef, ExtractedORMQuery } from '../workers/parse-worker.js';
|
|
21
21
|
import type { createResolutionContext } from '../model/resolution-context.js';
|
|
22
|
+
import type { ASTCache } from '../ast-cache.js';
|
|
22
23
|
export interface ParseOutput {
|
|
23
24
|
/**
|
|
24
25
|
* Read-only snapshot of exported type bindings keyed by file path.
|
|
@@ -52,5 +53,22 @@ export interface ParseOutput {
|
|
|
52
53
|
* see `PipelineOptions.workerThresholdsForTest`.
|
|
53
54
|
*/
|
|
54
55
|
readonly usedWorkerPool: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Cross-phase tree-sitter Tree cache populated by the sequential
|
|
58
|
+
* parse path. Separate from the chunk-local `astCache` used *inside*
|
|
59
|
+
* the parse phase (which is cleared between chunks) — this one
|
|
60
|
+
* survives the whole phase and hands Trees to scope-resolution so
|
|
61
|
+
* it can skip a second parse.
|
|
62
|
+
*
|
|
63
|
+
* Empty entries for files that ran through the worker pool
|
|
64
|
+
* (workers can't return native tree-sitter Trees across the
|
|
65
|
+
* MessageChannel). Cache miss is safe — consumers fall back to a
|
|
66
|
+
* fresh parse. See plan
|
|
67
|
+
* docs/plans/2026-04-20-002-perf-parse-heritage-mro-plan.md (Unit 4).
|
|
68
|
+
*
|
|
69
|
+
* Disposed by `scopeResolutionPhase` (the sole consumer) via
|
|
70
|
+
* `scopeTreeCache.clear()` after its extract loop finishes.
|
|
71
|
+
*/
|
|
72
|
+
readonly scopeTreeCache: ASTCache;
|
|
55
73
|
}
|
|
56
74
|
export declare const parsePhase: PipelinePhase<ParseOutput>;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* See ARCHITECTURE.md for the full phase dependency diagram.
|
|
16
16
|
*/
|
|
17
17
|
import { createKnowledgeGraph } from '../graph/graph.js';
|
|
18
|
-
import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase, cobolPhase, parsePhase, routesPhase, toolsPhase, ormPhase, crossFilePhase, mroPhase, communitiesPhase, processesPhase, } from './pipeline-phases/index.js';
|
|
18
|
+
import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase, cobolPhase, parsePhase, routesPhase, toolsPhase, ormPhase, crossFilePhase, scopeResolutionPhase, mroPhase, communitiesPhase, processesPhase, } from './pipeline-phases/index.js';
|
|
19
19
|
// ── Phase registry ─────────────────────────────────────────────────────────
|
|
20
20
|
/**
|
|
21
21
|
* All pipeline phases with their dependency relationships.
|
|
@@ -39,6 +39,7 @@ function buildPhaseList(options) {
|
|
|
39
39
|
toolsPhase,
|
|
40
40
|
ormPhase,
|
|
41
41
|
crossFilePhase,
|
|
42
|
+
scopeResolutionPhase,
|
|
42
43
|
];
|
|
43
44
|
if (!options?.skipGraphPhases) {
|
|
44
45
|
phases.push(mroPhase, communitiesPhase, processesPhase);
|