ai-code-map 0.0.0-stage → 0.1.0-alpha.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/AGENTS.md +26 -0
- package/CHANGELOG.md +54 -0
- package/CONTRIBUTING.md +43 -0
- package/LICENSE +21 -0
- package/README.md +369 -2
- package/SECURITY.md +18 -0
- package/config.schema.json +130 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +7690 -0
- package/dist/cli.js.map +1 -0
- package/dist/compiler-worker.d.ts +2 -0
- package/dist/compiler-worker.js +4395 -0
- package/dist/compiler-worker.js.map +1 -0
- package/dist/index.d.ts +1339 -0
- package/dist/index.js +7426 -0
- package/dist/index.js.map +1 -0
- package/docs/api.md +152 -0
- package/docs/architecture/ADR-0001-hybrid-syntax-and-semantics.md +140 -0
- package/docs/artifacts.md +156 -0
- package/docs/backlog.md +43 -0
- package/docs/limitations.md +82 -0
- package/docs/post-alpha-roadmap.md +341 -0
- package/docs/schema.md +133 -0
- package/examples/cli-workflow.sh +9 -0
- package/examples/programmatic-scan.ts +33 -0
- package/package.json +79 -3
- package/schemas/code-map.schema.json +1078 -0
- package/schemas/diagnostics.schema.json +60 -0
- package/schemas/file.schema.json +247 -0
- package/schemas/manifest.schema.json +307 -0
- package/schemas/project.schema.json +192 -0
- package/schemas/relation.schema.json +142 -0
- package/schemas/symbol.schema.json +165 -0
- package/skills/ai-code-map/SKILL.md +39 -0
package/docs/api.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Programmatic API
|
|
2
|
+
|
|
3
|
+
Import path: `import { ... } from "ai-code-map"`.
|
|
4
|
+
|
|
5
|
+
## Runtime-safe API
|
|
6
|
+
|
|
7
|
+
The library API does not call `process.exit`; all failures throw `CodeMapError` or surfaced errors.
|
|
8
|
+
|
|
9
|
+
Persisted artifacts are written in schema `v4`. Older maps return an actionable rescan error.
|
|
10
|
+
Schema v4 adds redundant source ownership and line-count fields so direct loads can reject
|
|
11
|
+
one-sided coherent corruption; a rescan is required.
|
|
12
|
+
|
|
13
|
+
## Core functions
|
|
14
|
+
|
|
15
|
+
- `initProject(options?) -> Promise<InitResult>`
|
|
16
|
+
- writes default config if missing
|
|
17
|
+
- options: `{ root?, config?, output?, force? }`
|
|
18
|
+
- `scanProject(options?) -> Promise<ScanResult>`
|
|
19
|
+
- scans and writes artifacts
|
|
20
|
+
- auto-initializes config if absent
|
|
21
|
+
- options: `{ root?, config?, output?, strict?, analyzers?, parser?, semanticResolver? }`
|
|
22
|
+
- discovers config candidates (`tsconfig*.json`, `jsconfig.json`) and resolves transitive `extends` and project `references`
|
|
23
|
+
- computes exact ownership per normalized compiler unit and builds one deterministic TypeScript `Program` per unit
|
|
24
|
+
- processes compiler units sequentially in stable compiler-unit order, then merges normalized owned facts globally
|
|
25
|
+
- only owned files are persisted
|
|
26
|
+
- reuses a complete validated current map for the default pipeline; stale inputs, invalid companion artifacts, or custom parser/analyzer/resolver components run full analysis
|
|
27
|
+
- `checkFreshness(options?) -> Promise<FreshnessResult>`
|
|
28
|
+
- validates the complete persisted artifact set and its raw-byte integrity index
|
|
29
|
+
- compares indexed sources, compiler-consumed files, project/toolchain-scoped typed resolution probes, observed directory listings and symlinks, consumed TypeScript libraries, configuration, and producer compatibility with current project state
|
|
30
|
+
- `loadCodeMap(options?) -> Promise<CodeMap>`
|
|
31
|
+
- loads persisted map from resolved output directory
|
|
32
|
+
- `buildProjectMap(map) -> ProjectMapView`
|
|
33
|
+
- projects a validated `CodeMap` into all indexed files, symbols, other endpoints, and grouped relations; does not mutate the input or check freshness
|
|
34
|
+
- returns `{ project, counts, files, symbols, endpoints, relations }`; nodes carry output-local `ref` values and original stable IDs
|
|
35
|
+
- symbol `file` points to a file ref; symbol `range` retains source coordinates
|
|
36
|
+
- relation groups contain `{ from, type, classification, targets: [{ ref, count }] }`; counts preserve all occurrence records, including heuristic and derived relations
|
|
37
|
+
- excludes source text, signatures, facts, and individual origin/confidence records; use the original map for that evidence
|
|
38
|
+
- `formatProjectMap(view) -> string`
|
|
39
|
+
- deterministic complete text with short references, stable symbol IDs, source lines, evidence classifications, and occurrence counts; no pagination or row limit
|
|
40
|
+
- the CLI `map` command checks freshness and reuses the validated map before calling these functions; missing/stale/invalid artifacts return exit code 2
|
|
41
|
+
- `computeManifestIntegrityHash(manifest) -> string`
|
|
42
|
+
- computes the canonical code-point-ordered manifest integrity hash used by persistence and tests
|
|
43
|
+
- `buildSourceContext(map, query, { root, maxLines?, maxChars?, seeds? }) -> Promise<ContextResult>`
|
|
44
|
+
- selects lexical matches (exact IDs/names take precedence), then expands one direct graph hop using the bounded `read` navigation rules
|
|
45
|
+
- for partial queries, ranks callable candidates using missing query words in their current source bodies and expands the strongest ties; inspects at most the 50 lexical candidates, with per-term occurrence counts capped at three
|
|
46
|
+
- skips reference-only class neighbors and counts them as omitted navigation; an explicitly selected class still expands normally
|
|
47
|
+
- includes up to four exact/framework-derived incoming file-level calls/references outside test files; a file of at most 80 lines is included in full, otherwise the mapped site has eight context lines on either side, within the shared budgets
|
|
48
|
+
- after primary source and file references, includes up to four outgoing exact/framework-derived dependencies of direct outgoing neighbors: functions or variables with bodies of at most 80 lines, calls before references; does not recurse or expand incoming callers
|
|
49
|
+
- defaults: 3 matches (1..5), 800 source lines (1..2000), 32,000 source characters including separators (256..64000)
|
|
50
|
+
- verifies paths, hashes and ranges for source-ranking candidates, selected symbols and file references; coalesces overlapping/adjacent source intervals
|
|
51
|
+
- returns `{ query, matches, moreMatches, selected, snippets, omitted, fileReferences, tests, omittedNavigation, usedLines, usedChars, limits }`
|
|
52
|
+
- `snippets` contain `{ file, startLine, endLine, source }`; `omitted` lists unread source ranges and symbol/file IDs excluded by the shared budget; file IDs are navigation targets, so read their printed source ranges directly
|
|
53
|
+
- test call sites are bounded navigation hints; omitted-navigation counts sum entries excluded by each seed's navigation limits, the shared test-site limit, and the small-dependency size/count limits
|
|
54
|
+
- the API validates selected source files; the CLI `context` also checks full map freshness before calling it
|
|
55
|
+
- `formatSourceContext(result) -> string`
|
|
56
|
+
- renders numbered source windows once per contiguous range, with bounded selection/test/omission metadata; metadata is additional to the source budgets
|
|
57
|
+
- `readSymbolSource(map, id, { root, limit?, offset? }) -> Promise<ReadSourceResult>`
|
|
58
|
+
- requires an exact stable ID; reads current source with two context lines per side
|
|
59
|
+
- `root` is the project root; `limit` defaults to 80 (integer 1..200); `offset` defaults to zero within that window
|
|
60
|
+
- returns `{ id, file, symbolRange, startLine, endLine, source, truncated, nextOffset?, navigation? }`
|
|
61
|
+
- at offset zero, `navigation` contains `{ links, tests, omittedLinks, omittedTests }`; continuation pages omit it
|
|
62
|
+
- each link has `{ direction, type, id, file, startLine, endLine, classification }`; exact and framework-derived internal neighbors only, deduplicated by direction and ID
|
|
63
|
+
- `tests` contains exact incoming call sites `{ file, line }` in `*.test.*`, `*.spec.*`, or `__tests__/` paths; this is a navigation hint, not a coverage claim
|
|
64
|
+
- limits navigation to eight links, four test sites, and fewer than 4,000 compact JSON characters; omission counts refer to eligible unique neighbors/sites excluded by these limits
|
|
65
|
+
- verifies source path containment and indexed file hash; rejects symbolic files, stale source, invalid offsets, and pages over 12,000 characters
|
|
66
|
+
- does not validate all project dependencies; use `checkFreshness` before navigation
|
|
67
|
+
- `showSymbol(map, selector) -> ShowResult`
|
|
68
|
+
- selectors: exact ID, `kind:name`, `path#name`, exact name/path
|
|
69
|
+
- returns all matching symbols and full relation records; no display filtering
|
|
70
|
+
- `formatShowResult(result, options?) -> string`
|
|
71
|
+
- compact by default: up to five symbols and 12 relation groups in total, with omission counts
|
|
72
|
+
- options: `{ full?: boolean, limit?: number }`; `limit` is an integer 1..50
|
|
73
|
+
- `{ full: true }` preserves the previous verbose text view
|
|
74
|
+
- `findSymbols(map, query, options?) -> SymbolSearchResult`
|
|
75
|
+
- searches indexed names and paths; returns stable IDs and source ranges
|
|
76
|
+
- options: `{ limit?: number }`, default 10, integer 1..50; invalid limits throw `RangeError`
|
|
77
|
+
- empty/whitespace query throws; no matches returns an empty array
|
|
78
|
+
- returns `{ query, total, truncated, matches: [{ id, name, kind, file, range, unmatchedTerms? }] }`
|
|
79
|
+
- deterministic lexical ranking and bounded typo hints; does not resolve guessed names as exact symbols
|
|
80
|
+
- word matching normalizes common English plurals and favors name matches over path matches
|
|
81
|
+
- whitespace-separated queries with at least three distinct normalized words may return partial matches after full matches and typo hints; at least two words and half the query must match, including a word in the symbol name
|
|
82
|
+
- only partial matches include `unmatchedTerms`, listing normalized query words absent from that symbol's name and path; this is lexical overlap, not semantic equivalence
|
|
83
|
+
- qualified file selectors remain restricted to that file; partial matching does not broaden them
|
|
84
|
+
|
|
85
|
+
## Analyzer constructors
|
|
86
|
+
|
|
87
|
+
- `createAnalyzer({ analyzers?, parser?, semanticResolver? })`
|
|
88
|
+
- returns `{ analyzers, parser, scan(...) }`
|
|
89
|
+
- `scanProject` uses analyzer defaults: `CoreAnalyzer`, `ReactAnalyzer`
|
|
90
|
+
- Optional analyzers are available:
|
|
91
|
+
- `NextJsAnalyzer`
|
|
92
|
+
- `NestJsAnalyzer`
|
|
93
|
+
|
|
94
|
+
## Parser adapters
|
|
95
|
+
|
|
96
|
+
- `TypeScriptParserAdapter` and `FallbackParserAdapter`
|
|
97
|
+
- Custom parser adapters implement `SyntaxParserAdapter` and can be passed into `scanProject`/`createAnalyzer`.
|
|
98
|
+
|
|
99
|
+
## Semantic resolver
|
|
100
|
+
|
|
101
|
+
- `TypeScriptSemanticResolver` is the compiler-backed default.
|
|
102
|
+
- TypeScript `Program`/`TypeChecker` facts remain authoritative even when a syntax adapter is supplied.
|
|
103
|
+
- Parser and semantic implementations never enter persisted Code Map records. Display names/versions are recorded, while a separate producer record and capability fingerprint determine default-pipeline reuse eligibility. Explicit built-in parser equivalence requires a directly registered, unmodified adapter instance; proxies, subclasses, and method overrides remain custom.
|
|
104
|
+
- Public `SemanticResolver` contracts are additive:
|
|
105
|
+
- `SemanticResolveInput` has optional `compilerUnit`
|
|
106
|
+
- `SemanticResolution` may return an optional unit-anchored `resolveModule` helper
|
|
107
|
+
- `SemanticResolution` may return an optional `semanticInputs()` closure containing raw-byte file/toolchain hashes plus typed resolution probes, directory listings, and symlink mappings scoped to `project` or `toolchain`; omitted observation scope defaults to `project` for extension compatibility
|
|
108
|
+
- Coordinator may invoke resolver once per owning compiler unit; custom analyzers receive unit-scoped `Program` and `TypeChecker`.
|
|
109
|
+
- Rooted host/type/module resolution is used to avoid caller working-directory effects.
|
|
110
|
+
- Text contributed by custom parsers, resolvers, and analyzers is sanitized before persistence; unsafe structural paths supplied by an extension fail schema validation rather than escaping the selected-root boundary. Supplied analyzer trust is resolved through registered instance identity at each invocation, so proxies and overridden instances receive isolated persistence context.
|
|
111
|
+
|
|
112
|
+
## Types exported
|
|
113
|
+
|
|
114
|
+
The package exports major record/contract types including:
|
|
115
|
+
|
|
116
|
+
- `CodeMap`, `CodeMapConfig`, `ManifestRecord`, `ProjectRecord`
|
|
117
|
+
- `FileRecord`, `SymbolRecord`, `RelationRecord`, `DiagnosticRecord`
|
|
118
|
+
- `CompilerUnitRecord`, `ProducerRecord`, `SemanticInputRecord`, `ArtifactIntegrityRecord`
|
|
119
|
+
- `ScanResult`, `FreshnessResult`, `ShowResult`, `ShowFormatOptions`
|
|
120
|
+
- `SymbolSearchResult`, `SymbolSearchOptions`, `SymbolSearchMatch`
|
|
121
|
+
- `ScanOptions`, `LoadCodeMapOptions`, `AnalysisContext`
|
|
122
|
+
|
|
123
|
+
## Example
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import {
|
|
127
|
+
initProject,
|
|
128
|
+
scanProject,
|
|
129
|
+
checkFreshness,
|
|
130
|
+
loadCodeMap,
|
|
131
|
+
showSymbol,
|
|
132
|
+
NextJsAnalyzer,
|
|
133
|
+
createAnalyzer,
|
|
134
|
+
TypeScriptParserAdapter,
|
|
135
|
+
} from "ai-code-map";
|
|
136
|
+
|
|
137
|
+
await initProject({ root: process.cwd() });
|
|
138
|
+
const scan = await scanProject({ root: process.cwd(), strict: false });
|
|
139
|
+
console.log(scan.counts);
|
|
140
|
+
|
|
141
|
+
const fresh = await checkFreshness({ root: process.cwd() });
|
|
142
|
+
console.log(fresh.current, fresh.reasons);
|
|
143
|
+
|
|
144
|
+
const map = await loadCodeMap({ root: process.cwd() });
|
|
145
|
+
console.log(showSymbol(map, "component:UserList").matches[0]?.symbol.kind);
|
|
146
|
+
|
|
147
|
+
const analyzer = createAnalyzer({
|
|
148
|
+
analyzers: [new NextJsAnalyzer()],
|
|
149
|
+
parser: new TypeScriptParserAdapter(),
|
|
150
|
+
});
|
|
151
|
+
await analyzer.scan({ root: process.cwd() });
|
|
152
|
+
```
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# ADR-0001: Hybrid syntax candidates and TypeScript semantics
|
|
2
|
+
|
|
3
|
+
- Status: accepted for alpha
|
|
4
|
+
- Date: 2026-08-06
|
|
5
|
+
- Decision owners: project maintainers
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
The scanner needs error-tolerant syntax discovery without weakening facts that only the TypeScript compiler can prove. Parsing every TypeScript file twice in every one-shot scan would add installation, memory, and maintenance cost before it has demonstrated a repository-level benefit.
|
|
10
|
+
|
|
11
|
+
The public Code Map IR must not expose Tree-sitter nodes, ast-grep objects, TypeScript AST objects, or library-specific IDs.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
The target pipeline is:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
source files
|
|
19
|
+
-> replaceable syntax-candidate adapter
|
|
20
|
+
-> normalized syntax facts
|
|
21
|
+
-> TypeScript Program / TypeChecker semantic confirmation
|
|
22
|
+
-> versioned framework analyzers
|
|
23
|
+
-> versioned Code Map IR
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For the alpha production path, the TypeScript `Program` supplies both its reusable syntax tree and authoritative semantic layer. This avoids a second parse. A custom `SyntaxParserAdapter` is opt-in; failure or a fatal parse result falls back to the compiler without aborting the scan. Adapter error text is not persisted because third-party errors may contain source text, absolute paths, or environment-derived values.
|
|
27
|
+
|
|
28
|
+
`@ast-grep/napi@0.45.0` is the selected bounded Tree-sitter prototype. It is pinned as a development dependency, exercised only by the parser microbenchmark, and is not in the published runtime dependency set. It provides built-in TypeScript and TSX languages and substantially less visitor/rule boilerplate than a raw Tree-sitter binding.
|
|
29
|
+
|
|
30
|
+
Tree-sitter is therefore **deferred as a default production pass**. The public adapter and normalized IR are in place; the compiler-only path remains the safe fallback and default.
|
|
31
|
+
|
|
32
|
+
### Milestone 1 and 1.1 closure updates
|
|
33
|
+
|
|
34
|
+
- Persisted schema is now `v4`; v3 added semantic-input closure, producer provenance, companion
|
|
35
|
+
integrity hashes, and collision-safe unit IDs, while v4 adds redundant per-source compiler
|
|
36
|
+
ownership and line counts for direct-load integrity. Existing maps require a rescan.
|
|
37
|
+
- A bounded config walk now discovers and fingerprints `tsconfig`/`jsconfig` candidates and resolves transitive `extends` and `references`; workspace/config manifests participate in ownership and freshness.
|
|
38
|
+
- Ownership is assigned only via parsed `fileNames` and chooses the deepest validated boundary in priority order:
|
|
39
|
+
- deepest shared validated workspace/package boundary,
|
|
40
|
+
- deepest config directory ancestor,
|
|
41
|
+
- lexical normalized config path fallback.
|
|
42
|
+
- One compiler `Program` is built per non-empty owning compiler unit. Programs are processed sequentially and only owned files are analyzed/persisted; zero-owned solution nodes remain graph metadata, and unit facts are merged after normalizing root-relative paths.
|
|
43
|
+
- File ownership is enforced by a single compiler unit per scanned file, with exactly one `fallback` unit when no configured owner exists.
|
|
44
|
+
- The source import graph is resolved in-module during scan. Direct referenced packages use parsed project references plus static package metadata to resolve back to in-root source when an emitted `.d.ts` target is absent.
|
|
45
|
+
- TypeScript remains the semantic authority; Tree-sitter/ast-grep remains development-only for now.
|
|
46
|
+
- `manifest.configHash` includes normalized scanner semantics, ownership/config graph inputs, and versioned tool/parser/analyzer/TS/schema vectors. A separate deterministic closure records additional in-root files TypeScript consumed plus typed resolution probes, directory listings, symlink mappings, and raw-byte file hashes scoped to the selected project or active TypeScript library root.
|
|
47
|
+
- A current default scan reuses the complete persisted map only after every companion's raw bytes match the manifest integrity index and all schemas/cross-record invariants validate. Stale semantic inputs, invalid/missing companions, or custom analysis components use the full compiler path.
|
|
48
|
+
- Initial and freshness source identities are SHA-256 over identical raw bytes; UTF-8 decoding is analysis input only.
|
|
49
|
+
- External call identities use import provenance where it is provable (`external:react#useState`); unknown module provenance remains explicit and heuristic (`external:unresolved#...`).
|
|
50
|
+
- Generated and configured compiler-unit IDs have disjoint structural prefixes. Persisted paths are repository-relative POSIX values, with cross-platform absolute import text redacted at the persistence boundary.
|
|
51
|
+
|
|
52
|
+
Compatibility notes:
|
|
53
|
+
|
|
54
|
+
- `ProjectRecord.tsconfig` and `ProjectRecord.pathAliases` are retained as compatibility projections.
|
|
55
|
+
- `CompilerUnitRecord.pathAliases` is authoritative for unit analysis.
|
|
56
|
+
- Bounded host/type/module resolution avoids caller working-directory dependence.
|
|
57
|
+
- The manifest integrity index is a deterministic corruption/tamper signal, not a cryptographic signature over an untrusted producer.
|
|
58
|
+
|
|
59
|
+
## Fact ownership
|
|
60
|
+
|
|
61
|
+
| Layer | Responsibility | Authority label |
|
|
62
|
+
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
63
|
+
| Syntax adapter / future Tree-sitter pass | Error-tolerant candidates for calls, hooks, JSX, decorators, and file conventions | candidate only; never semantic proof |
|
|
64
|
+
| TypeScript `Program` / `TypeChecker` | Symbol identity, definitions, aliases, re-exports, module resolution, types, public signatures, overloads, references, calls, and JSX symbol resolution | exact when resolved |
|
|
65
|
+
| React rule pack | Components, props, hooks, state/effects/dependencies, and rendered JSX derived from compiler nodes and imports | `framework-derived`, or `heuristic` when not fully confirmed |
|
|
66
|
+
| Next.js / NestJS rule packs | Convention and decorator facts after semantic confirmation | experimental and default-off in alpha |
|
|
67
|
+
| Relation normalizer | Inverse edges and canonical endpoint replacement | `derived` |
|
|
68
|
+
|
|
69
|
+
Persisted relations carry `confidence` plus an `origin` containing repository-relative file, line, explanation, evidence classification, and analyzer version identity. The canonical format remains independent of parser implementation.
|
|
70
|
+
|
|
71
|
+
## Prototype comparison
|
|
72
|
+
|
|
73
|
+
### `@ast-grep/napi` (selected prototype)
|
|
74
|
+
|
|
75
|
+
- Version: exactly `0.45.0`.
|
|
76
|
+
- Grammars: built-in `Lang.TypeScript` and `Lang.Tsx`.
|
|
77
|
+
- Distribution: N-API native optional packages for macOS x64/arm64, Windows x64/arm64/ia32, and Linux x64/arm64 glibc plus x64/arm64 musl.
|
|
78
|
+
- Local darwin-arm64 install observation: approximately 392 KiB for the JavaScript/type package and 6.8 MiB for the platform binary package on disk.
|
|
79
|
+
- Benefit: concise query/traversal API and prebuilt binaries, without a local `node-gyp` build in the tested install.
|
|
80
|
+
- Risk: native optional-package coverage and corporate/supply-chain policies still require CI verification on every supported OS/architecture.
|
|
81
|
+
|
|
82
|
+
### Raw native `tree-sitter`
|
|
83
|
+
|
|
84
|
+
Evaluated versions were `tree-sitter@0.25.1` and `tree-sitter-typescript@0.23.2`. The grammar declares a peer range around the older `tree-sitter` line, while the native binding has install/build-tooling costs. This combination was not added to the alpha because it increases packaging risk without reducing the amount of rule code.
|
|
85
|
+
|
|
86
|
+
### `web-tree-sitter`
|
|
87
|
+
|
|
88
|
+
`web-tree-sitter@0.26.11` with vendored TypeScript/TSX WASM grammars avoids platform-native binaries and remains the portability fallback. It was not selected for the first prototype because the package must explicitly locate and ship loader/grammar WASM assets, initialize them, and keep ABI compatibility tested.
|
|
89
|
+
|
|
90
|
+
References:
|
|
91
|
+
|
|
92
|
+
- [ast-grep JavaScript API](https://ast-grep.github.io/guide/api-usage/js-api.html)
|
|
93
|
+
- [ast-grep performance guidance](https://ast-grep.github.io/guide/api-usage/performance-tip.html)
|
|
94
|
+
- [Tree-sitter web binding](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md)
|
|
95
|
+
- [Node Tree-sitter binding](https://github.com/tree-sitter/node-tree-sitter)
|
|
96
|
+
- [TypeScript grammar](https://github.com/tree-sitter/tree-sitter-typescript)
|
|
97
|
+
|
|
98
|
+
## Bounded microbenchmark
|
|
99
|
+
|
|
100
|
+
Command:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pnpm benchmark
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Environment for the checkpoint below: Node `v22.16.0`, darwin-arm64, TypeScript `5.9.3`, `@ast-grep/napi@0.45.0`; 5 warmups and 30 measured in-process parse iterations. Candidate inspection is outside the timed samples. RSS is observed for the shared process, not an isolated parser peak.
|
|
107
|
+
|
|
108
|
+
| Fixture | Normalized candidates agree | Error nodes agree | TypeScript warm median | ast-grep warm median |
|
|
109
|
+
| --------------------- | --------------------------: | ----------------: | ---------------------: | -------------------: |
|
|
110
|
+
| valid TS | yes | 0 / 0 | 0.292 ms | 0.069 ms |
|
|
111
|
+
| valid TSX | yes | 0 / 0 | 0.186 ms | 0.076 ms |
|
|
112
|
+
| partially invalid TSX | yes | 1 / 1 | 0.152 ms | 0.073 ms |
|
|
113
|
+
| syntax-error TSX | yes | 1 / 1 | 0.013 ms | 0.010 ms |
|
|
114
|
+
|
|
115
|
+
This result demonstrates a promising parser-only candidate pass on four small fixtures. It does **not** demonstrate faster repository scans: a production hybrid would still pay TypeScript program construction and would add a second tree. It also does not establish representative peak memory, cold package-load cost, watch performance, or cross-platform installation success.
|
|
116
|
+
|
|
117
|
+
## Promotion gates
|
|
118
|
+
|
|
119
|
+
Tree-sitter or ast-grep may become an optional production observer only after all of the following are measured:
|
|
120
|
+
|
|
121
|
+
1. Representative React, Next.js, NestJS, malformed-source, monorepo, and project-reference repositories.
|
|
122
|
+
2. Cold one-shot scan time, warm/watch time, peak RSS in isolated processes, output/map diff, and precision/recall.
|
|
123
|
+
3. macOS, Linux glibc/musl, and Windows installation and package tests on supported architectures.
|
|
124
|
+
4. A demonstrated maintenance or performance improvement after including the still-required TypeScript semantic pass.
|
|
125
|
+
5. Byte-identical canonical output when the candidate layer contributes no new confirmed facts.
|
|
126
|
+
6. Compiler fallback coverage for missing binaries, unsupported languages, parse failures, and partial trees.
|
|
127
|
+
|
|
128
|
+
Until those gates pass, the default remains compiler-only and no Tree-sitter object enters the public IR.
|
|
129
|
+
|
|
130
|
+
## Reuse decisions in the alpha
|
|
131
|
+
|
|
132
|
+
- Commander, fast-glob, Node crypto, Vitest, tsup, and sorted JSONL remain in place.
|
|
133
|
+
- `@manypkg/get-packages` is behind `WorkspaceDiscovery`; selected-root and realpath containment are enforced before workspace metadata is persisted.
|
|
134
|
+
- `ignore` is behind `IgnoreAdapter`; discovery disables symlink following and verifies realpaths.
|
|
135
|
+
- Zod schemas own configuration and every persisted record type. TypeScript types are inferred from them, runtime reads/writes are validated, and checked-in Draft 2020-12 JSON Schemas are generated with `z.toJSONSchema`.
|
|
136
|
+
- The TypeScript semantic layer is behind `SemanticResolver`; its normalized public outputs remain Code Map records rather than compiler objects.
|
|
137
|
+
|
|
138
|
+
## Consequences
|
|
139
|
+
|
|
140
|
+
The alpha retains a reliable installation and one authoritative semantic model. It accepts that a syntax-only speedup has not yet been realized and that malformed-file recovery is currently limited by TypeScript's tolerant parser. The adapter boundary makes the experiment replaceable without rewriting framework analyzers or changing persisted artifacts.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Artifacts and output schema
|
|
2
|
+
|
|
3
|
+
All persisted artifacts are written as JSON or line-delimited JSON under the selected output directory (default `.ai/code-map`).
|
|
4
|
+
|
|
5
|
+
## `manifest.json`
|
|
6
|
+
|
|
7
|
+
Source inventory and analyzer provenance used for freshness:
|
|
8
|
+
|
|
9
|
+
- `schemaVersion`
|
|
10
|
+
- `analyzerVersion`
|
|
11
|
+
- `producer`
|
|
12
|
+
- `id`: centrally assigned built-in/custom pipeline identity
|
|
13
|
+
- `kind`: `built-in` or `custom`
|
|
14
|
+
- `fingerprint`: stable capability/component fingerprint used by default-map reuse
|
|
15
|
+
- `semanticResolver`
|
|
16
|
+
- `name`
|
|
17
|
+
- `version`
|
|
18
|
+
- `syntaxParser`
|
|
19
|
+
- `name`
|
|
20
|
+
- `version`
|
|
21
|
+
- `analyzers`: stable list of enabled analyzers and versions
|
|
22
|
+
- `configHash`: serialized analysis configuration and project metadata hash
|
|
23
|
+
- `sourceFiles`: `[{ path, hash, compilerUnit, lines }]` for all persisted source files; ownership
|
|
24
|
+
and line count redundantly cross-check `files.jsonl`
|
|
25
|
+
- `semanticInputs`: deterministic compiler-observed closure
|
|
26
|
+
- consumed file: `{ path, kind: "file", hash }`, where `hash` is SHA-256 of the exact raw bytes
|
|
27
|
+
- typed lookup: `{ path, kind: "resolution-probe", scope, targetKind, exists }`, where `scope` is `project` or `toolchain` and `targetKind` is `file`, `directory`, or `readable-file`
|
|
28
|
+
- child-directory enumeration: `{ path, kind: "directory-listing", scope, hash }`
|
|
29
|
+
- scoped lexical-to-realpath mapping: `{ path, kind: "symlink", scope, target }`; an out-of-scope target is the opaque `<outside-root>` marker
|
|
30
|
+
- TypeScript standard-library input: `{ path, kind: "toolchain-file", hash }`, relative to the active TypeScript library directory
|
|
31
|
+
- `artifacts`: SHA-256 of the exact raw bytes of every companion artifact
|
|
32
|
+
- `integrityHash`: SHA-256 binding all other manifest fields, including producer identity, semantic inputs, and companion hashes
|
|
33
|
+
|
|
34
|
+
Freshness inputs now include:
|
|
35
|
+
|
|
36
|
+
- normalized scanner semantics, config graph structure, ownership resolution, and all `tsconfig`/`jsconfig` / `extends` / `references` inputs
|
|
37
|
+
- selected root/workspace manifests (including workspace dependency ranges), lockfiles, and tool/analyzer/parser/TypeScript/schema version identities
|
|
38
|
+
- additional in-root sources, declarations, nested package scopes, package metadata, readable/unreadable candidates, child-directory enumerations, symlink targets, and failed/present resolution candidates actually observed by TypeScript
|
|
39
|
+
- exact TypeScript library files plus failed/present toolchain probes observed by the active compiler, so same-version patched, restored, or replaced library inputs invalidate reuse
|
|
40
|
+
|
|
41
|
+
The minimum complete map is `manifest.json` plus `overview.md`, `project.json`, `files.jsonl`, `symbols.jsonl`, `relations.jsonl`, and `diagnostics.json`. An unchanged default scan opens, hashes, parses, schema-validates, and cross-validates the complete set before reuse. Missing, invalid, incompatible, inconsistent, or hash-mismatched companions force full analysis and repair rather than trusting `manifest.json` alone.
|
|
42
|
+
|
|
43
|
+
The manifest is the commit marker and is written last. Companion hashes and `integrityHash` are tamper-evident for ordinary corruption or partial edits; they are not authenticated signatures against an actor able to rewrite the whole map coherently. Source remains authoritative.
|
|
44
|
+
|
|
45
|
+
Loading and reuse additionally enforce cross-record invariants: canonical compiler-unit IDs/references,
|
|
46
|
+
manifest-to-file compiler ownership and line counts, exact symbol ownership, import-to-relation
|
|
47
|
+
agreement, internal import targets, record counts, local endpoints, range/line bounds, relation
|
|
48
|
+
evidence origin, and containment/export ownership. Schema v4 is intentionally incompatible with v3;
|
|
49
|
+
existing maps must be rescanned.
|
|
50
|
+
|
|
51
|
+
## `project.json`
|
|
52
|
+
|
|
53
|
+
Project context:
|
|
54
|
+
|
|
55
|
+
- `schemaVersion`
|
|
56
|
+
- `name`
|
|
57
|
+
- `packageManager` (if present)
|
|
58
|
+
- `frameworks`: detected and selected frameworks
|
|
59
|
+
- `tsconfig` (if found): compatibility projection of the primary configured unit
|
|
60
|
+
- `pathAliases`: compatibility projection from the default compatibility compiler unit
|
|
61
|
+
- `compilerUnits[]`:
|
|
62
|
+
- `id` (`compiler-unit:configured:<config-path>` or structurally distinct `compiler-unit:generated:<name>`)
|
|
63
|
+
- `kind` (`configured` | `fallback`)
|
|
64
|
+
- `root`
|
|
65
|
+
- `config?` (normalized selected config path)
|
|
66
|
+
- `references` (compiler-unit-level `references` paths)
|
|
67
|
+
- `extends` (compiler-unit-level `extends` values)
|
|
68
|
+
- `pathAliases` (authoritative per-unit aliases)
|
|
69
|
+
- exactly one `fallback` compiler unit exists (it may own zero files)
|
|
70
|
+
- `entryPoints`, `workspaces`
|
|
71
|
+
- `counts`: number of files/symbols/relations/diagnostics
|
|
72
|
+
|
|
73
|
+
## `files.jsonl`
|
|
74
|
+
|
|
75
|
+
One JSON object per scanned source file (`FileRecord`):
|
|
76
|
+
|
|
77
|
+
- `schemaVersion`
|
|
78
|
+
- `id` (`file:<path>`)
|
|
79
|
+
- `path`
|
|
80
|
+
- `language`
|
|
81
|
+
- `frameworks`
|
|
82
|
+
- `compilerUnit` (required)
|
|
83
|
+
- `hash` (content hash)
|
|
84
|
+
- `lines`
|
|
85
|
+
- `imports` (`[{ source, specifiers, resolved, external, kind, line }]`)
|
|
86
|
+
- `exports` (`[{ name, local, source, default, typeOnly }]`)
|
|
87
|
+
- `symbolIds` (sorted)
|
|
88
|
+
- `env` (identifier names only)
|
|
89
|
+
- `operations` (filesystem/http/database/queue usage)
|
|
90
|
+
- `syntax` summary (`parser`, `factCount`, `hadErrors`, optional `fallbackFrom`)
|
|
91
|
+
- paths are repository-relative POSIX strings; unresolved absolute module specifiers are replaced by an opaque marker instead of being persisted
|
|
92
|
+
- alias targets with absolute, drive, UNC, or parent-traversal syntax are omitted before host-native
|
|
93
|
+
path resolution; valid relative wildcard targets remain portable
|
|
94
|
+
|
|
95
|
+
## `symbols.jsonl`
|
|
96
|
+
|
|
97
|
+
One JSON object per symbol (`SymbolRecord`):
|
|
98
|
+
|
|
99
|
+
- `schemaVersion`
|
|
100
|
+
- `id` (stable)
|
|
101
|
+
- `name`
|
|
102
|
+
- `kind` (`function`, `react-component`, `next-page`, `nest-controller`, ...)
|
|
103
|
+
- `file`
|
|
104
|
+
- `range`
|
|
105
|
+
- `exported`
|
|
106
|
+
- `defaultExport` (optional)
|
|
107
|
+
- `signature` (source-derived)
|
|
108
|
+
- `documentation` (optional; not emitted by the base scanner)
|
|
109
|
+
- `facts` (framework-aware structured facts)
|
|
110
|
+
- `sourceHash`
|
|
111
|
+
|
|
112
|
+
## `relations.jsonl`
|
|
113
|
+
|
|
114
|
+
Directed edges between files and symbols:
|
|
115
|
+
|
|
116
|
+
- `schemaVersion`
|
|
117
|
+
- `from`
|
|
118
|
+
- `to`
|
|
119
|
+
- `type` (e.g. `calls`, `instantiates`, `renders`, `uses-hook`, `handles-route`, `injects`, ...)
|
|
120
|
+
- `confidence` (must be between `0` and `1`)
|
|
121
|
+
- `origin.file`
|
|
122
|
+
- `origin.line`
|
|
123
|
+
- `origin.range`
|
|
124
|
+
- `origin.explanation`
|
|
125
|
+
- `origin.classification` (`exact`, `framework-derived`, `heuristic`, `derived`)
|
|
126
|
+
- `origin.analyzer`
|
|
127
|
+
|
|
128
|
+
Unresolved heuristic edges continue to receive deterministic `used-by` inverses for graph
|
|
129
|
+
traversal. Their unresolved external endpoint remains present on the inverse, so audits can identify
|
|
130
|
+
the uncertainty from either direction. Future default compact context excludes heuristic/unresolved
|
|
131
|
+
edges unless explicitly requested.
|
|
132
|
+
|
|
133
|
+
## `diagnostics.json`
|
|
134
|
+
|
|
135
|
+
Validation and analysis issues:
|
|
136
|
+
|
|
137
|
+
- `schemaVersion`
|
|
138
|
+
- `code` (`parse-error`, `unresolved-import`, `invalid-config`, `unsupported-file`,
|
|
139
|
+
`analysis-error`, `parser-fallback`, `compiler-config`)
|
|
140
|
+
- `severity` (`info`, `warning`, `error`)
|
|
141
|
+
- `message`
|
|
142
|
+
- `file`/`line`/`column` (optional)
|
|
143
|
+
|
|
144
|
+
## `overview.md`
|
|
145
|
+
|
|
146
|
+
Human-readable summary containing project names, frameworks, counts, entry points, and an indexed file listing.
|
|
147
|
+
|
|
148
|
+
## Ordering and determinism
|
|
149
|
+
|
|
150
|
+
Records are sorted deterministically before write:
|
|
151
|
+
|
|
152
|
+
- files by path
|
|
153
|
+
- symbols by ID
|
|
154
|
+
- relations by endpoint, type, evidence file, and full evidence range
|
|
155
|
+
|
|
156
|
+
Mtime stability is preserved by avoiding rewrites when the map is unchanged.
|
package/docs/backlog.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Delivery backlog
|
|
2
|
+
|
|
3
|
+
`PROJECT.md` is the product source of truth. This page records implementation sequencing; it is not a promise that later capabilities exist in the alpha.
|
|
4
|
+
|
|
5
|
+
## Alpha contract
|
|
6
|
+
|
|
7
|
+
- Deterministic local TypeScript/JavaScript and React scanning.
|
|
8
|
+
- TypeScript compiler-authoritative semantic facts.
|
|
9
|
+
- Replaceable syntax and semantic boundaries with safe fallback.
|
|
10
|
+
- `init`, `scan`, `check`, and `show` only.
|
|
11
|
+
- Zod-owned configuration/persisted schemas, stable IDs, evidence, confidence, hashes, and freshness.
|
|
12
|
+
- Deterministic compiler units for multiple TypeScript configs, project references, workspace
|
|
13
|
+
boundaries, and unowned-file fallback analysis.
|
|
14
|
+
- Focused security, malformed-source, determinism, API, and CLI behavioral tests.
|
|
15
|
+
|
|
16
|
+
## Next milestone: bounded context foundation
|
|
17
|
+
|
|
18
|
+
1. Add a deterministic, structured query API with strict output budgets, ranking, truncation, and omission accounting.
|
|
19
|
+
2. Compare compact map context with relevant source slices and return the smaller useful representation.
|
|
20
|
+
3. Keep the alpha.2 peak-memory regression gates while expanding query capabilities.
|
|
21
|
+
4. Mature and independently validate the existing experimental Next.js and NestJS analyzers before enabling either by default.
|
|
22
|
+
5. Run the parser evaluation corpus on representative repositories and supported CI platforms; decide whether ast-grep stays dev-only, becomes optional, or becomes a default candidate observer.
|
|
23
|
+
6. Add accuracy fixtures and precision/recall reporting for framework rule packs.
|
|
24
|
+
7. Only after bounded retrieval is validated, add rebuildable local impact indexes, watch mode, lexical search, and an official-SDK read-only stdio MCP adapter.
|
|
25
|
+
|
|
26
|
+
## Deferred adapters
|
|
27
|
+
|
|
28
|
+
- Graphology as a rebuildable in-memory index; JSONL remains canonical.
|
|
29
|
+
- MiniSearch for deterministic local lexical search.
|
|
30
|
+
- Chokidar for a long-lived watcher.
|
|
31
|
+
- Official MCP TypeScript SDK over local stdio.
|
|
32
|
+
- SCIP import/export and SARIF output.
|
|
33
|
+
- Safe optional importers for OpenAPI, GraphQL, coverage, CODEOWNERS, Storybook, and existing generated artifacts.
|
|
34
|
+
|
|
35
|
+
## Explicitly not core
|
|
36
|
+
|
|
37
|
+
- LLMs, embeddings, API keys, network calls, or telemetry in deterministic map generation.
|
|
38
|
+
- Model-interpreted natural-language tasks. The bounded `context` command uses lexical matches and stored graph edges only.
|
|
39
|
+
- Web UI, cloud service, billing, authentication, or deployment in this package.
|
|
40
|
+
- ts-morph, dependency-cruiser, or react-docgen as authoritative analyzers.
|
|
41
|
+
- Next.js private internals or NestJS runtime reflection.
|
|
42
|
+
- SQLite, Neo4j, or a vector database before profiling demonstrates a need.
|
|
43
|
+
- Dynamic execution/loading of scanned application modules or configuration.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Known limitations and backlog
|
|
2
|
+
|
|
3
|
+
## In-scope alpha
|
|
4
|
+
|
|
5
|
+
- CLI commands are `init`, `scan`, `check`, `show`, `find`, `read`, `map`, and `context`.
|
|
6
|
+
- `scan` output is static analysis only; no code execution.
|
|
7
|
+
- No remote service, account linking, or telemetry is part of the alpha.
|
|
8
|
+
- Framework analyzers included by default are TypeScript/Node and React only.
|
|
9
|
+
|
|
10
|
+
## Next.js and NestJS
|
|
11
|
+
|
|
12
|
+
- Analyzer classes for Next.js and NestJS are exported and callable through the programmatic API.
|
|
13
|
+
- These analyzers are considered **experimental** and are **not enabled by default** in CLI.
|
|
14
|
+
- They are intentionally not part of the minimal default analyzer contract.
|
|
15
|
+
|
|
16
|
+
## Parser extensibility
|
|
17
|
+
|
|
18
|
+
- TypeScript compiler parser is authoritative in this alpha.
|
|
19
|
+
- The parser adapter interface supports custom adapters and fallback wrappers.
|
|
20
|
+
- A bounded `@ast-grep/napi` spike and fixture microbenchmark are present, but the adapter is development-only and is not enabled in production scans.
|
|
21
|
+
- `TypeScript` compiler semantics are the authoritative source of truth for persisted facts.
|
|
22
|
+
- Evidence and confidence still require explicit provenance in output and freshness contracts.
|
|
23
|
+
- Freshness tracks indexed raw-byte hashes, the deterministic compiler-observed semantic closure, config/package inputs, producer identity, and tool identities.
|
|
24
|
+
|
|
25
|
+
## Not yet implemented
|
|
26
|
+
|
|
27
|
+
- No global search/context query language in CLI.
|
|
28
|
+
- No impact/risk scoring commands.
|
|
29
|
+
- No source snippet persistence in public artifacts.
|
|
30
|
+
- No runtime evidence importer layer.
|
|
31
|
+
- No watch/incremental compiler mode. Current default maps are validated and reused, but stale scans rebuild compiler state from scratch.
|
|
32
|
+
- No multi-process Program reuse between scans.
|
|
33
|
+
|
|
34
|
+
## Dependencies and scan exclusions
|
|
35
|
+
|
|
36
|
+
- Default source discovery excludes `**/node_modules/**`. Dependency files are not indexed as
|
|
37
|
+
project files or symbols.
|
|
38
|
+
- Source exclusion does not prohibit compiler reads. TypeScript still needs dependency declarations
|
|
39
|
+
and package metadata to resolve imports and types; consumed inputs participate in freshness checks.
|
|
40
|
+
- Keep installed dependencies inside the selected project root. Replacing `node_modules` with a
|
|
41
|
+
symlink to another checkout can cause unresolved imports because the bounded compiler host does
|
|
42
|
+
not follow dependency paths outside that root.
|
|
43
|
+
- The repository's `node_modules/` Git ignore rule already covers nested dependency directories.
|
|
44
|
+
Git ignore rules do not remove the compiler's need for dependency type information.
|
|
45
|
+
|
|
46
|
+
## Non-goals for this baseline
|
|
47
|
+
|
|
48
|
+
- No task-planner reasoning is provided by the map itself.
|
|
49
|
+
- No cloud CI/reporting extension is assumed from the local alpha artifacts.
|
|
50
|
+
|
|
51
|
+
## Milestone risks and limitations
|
|
52
|
+
|
|
53
|
+
- Package-manager dependency symlinks outside the selected root are not indexed or read by the bounded host.
|
|
54
|
+
- The fallback compiler unit mixes unowned files with conservative defaults.
|
|
55
|
+
- Every fallback-owned JavaScript/JSX-family file receives a portable reason diagnostic and is still
|
|
56
|
+
analyzed exactly once.
|
|
57
|
+
- Direct in-root project-reference package imports are mapped from static package metadata back to referenced source when declaration outputs are absent. Complex conditional exports and references outside the selected root remain bounded and may be unresolved.
|
|
58
|
+
- Project/toolchain-scoped typed resolution probes, directory listings, symlink mappings, and consumed TypeScript library hashes make warm validation proportional to the compiler-observed semantic closure rather than only the indexed file count. Warm scans remain much faster than fresh scans, but are slower than Milestone 1's incomplete freshness check.
|
|
59
|
+
- Custom extensions are treated as untrusted persistence contributors: their textual symbol facts, names, signatures, documentation, diagnostics, and relation metadata are path-sanitized. Structural file/config paths still must satisfy the public relative-path schemas, and invalid custom records make the scan fail instead of being persisted.
|
|
60
|
+
- Portable alias persistence intentionally drops absolute, Windows-drive, UNC, and parent-traversing
|
|
61
|
+
targets before host-native resolution. This stricter policy can omit an otherwise in-root
|
|
62
|
+
parent-relative TypeScript alias; direct relative wildcard targets remain supported.
|
|
63
|
+
- Heuristic/unresolved forward relations retain derived `used-by` inverses for graph traversability.
|
|
64
|
+
The unresolved endpoint remains machine-visible in either direction, and these relations are
|
|
65
|
+
excluded from future default compact context unless explicitly requested.
|
|
66
|
+
- Schema v4 redundancy detects ordinary and one-sided coherent corruption, including false compiler
|
|
67
|
+
ownership and line counts. It is not a cryptographic signature against rewriting every redundant
|
|
68
|
+
ownership record and integrity hash.
|
|
69
|
+
- Default scans use a separate sequential worker for each compiler unit. Each worker exits before
|
|
70
|
+
the next unit starts. A local V8 inspector session collects unreachable compiler objects before
|
|
71
|
+
the result is cloned into the parent; it opens no network port. This releases compiler memory
|
|
72
|
+
before normalization and persistence, but adds collection and
|
|
73
|
+
startup overhead, particularly for small projects with many configs. A single large compiler unit
|
|
74
|
+
can still use substantial memory; there is no fixed heap cap or partial-analysis fallback.
|
|
75
|
+
- Custom analyzers, parsers, and semantic resolvers run in-process to preserve extension behavior.
|
|
76
|
+
Their memory use is not covered by the default-pipeline resource guarantee. Full JSDoc remains
|
|
77
|
+
available to custom analyzers; default workers parse only the JSDoc needed for type information.
|
|
78
|
+
- The [alpha.2 release benchmark](../benchmarks/results/release-alpha-2-2026-11-01.md) records the
|
|
79
|
+
current resource measurements. August source commits were restored with copied installed
|
|
80
|
+
dependencies; those dependency trees are not claimed to reproduce the August installation.
|
|
81
|
+
- Next.js and NestJS analyzers remain experimental and default-off.
|
|
82
|
+
- Any future Tree-sitter production path is still explicitly off for this milestone.
|