SIGN IN SIGN UP

perf: parse each file once in extract-structure; reuse tree-sitter parsers

`extract-structure.mjs` calls `analyzeFile` then `extractCallGraph` on every
code file (lines 100 + 109) — two full tree-sitter parses of identical
content, on the indexing hot path that runs on every `/understand`.

- Add `TreeSitterPlugin.analyzeFileFull()` (and an optional `AnalyzerPlugin`
  interface method + `PluginRegistry` delegation) that parses once and runs
  both extractors on the same rootNode. Both extractors are pure functions of
  the tree, so output is byte-identical to the two separate calls.
- `extract-structure.mjs` uses it when present and falls back to the original
  two-call path (preserving their independent error degradation) when the
  registry/plugin lacks it or it throws.
- `getParser` now caches one reusable parser per language instead of
  allocating `new Parser()` + `setLanguage` and `delete()`-ing it on every
  call. Trees are still deleted per parse.

Verified [executed]:
- Project's own suites green before+after: tree-sitter-plugin, plugin-registry,
  parsers, tour-generator, layer-detector, embedding-search — 132/132.
- Against the real tree-sitter TS grammar: analyzeFileFull.structure ≡
  analyzeFile and analyzeFileFull.callGraph ≡ extractCallGraph (0 mismatches
  over many files and repeated reuse of the cached parser); single-parse is
  ~39% less parse work per code file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
D
DashBot-0001 committed
a781a6159ebc5938b573dfaf6aa144196348b7b1
Parent: f074fd0