lsp-intelligence 0.1.2 → 0.2.1

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.
Files changed (208) hide show
  1. package/README.md +48 -15
  2. package/dist/analysis/pattern/collectSearchFiles.d.ts +6 -0
  3. package/dist/analysis/pattern/collectSearchFiles.js +38 -0
  4. package/dist/analysis/pattern/collectSearchFiles.js.map +1 -0
  5. package/dist/analysis/pattern/runPatternSearch.d.ts +17 -0
  6. package/dist/analysis/pattern/runPatternSearch.js +65 -0
  7. package/dist/analysis/pattern/runPatternSearch.js.map +1 -0
  8. package/dist/analysis/ts/extractDeclarations.d.ts +7 -0
  9. package/dist/analysis/ts/extractDeclarations.js +93 -0
  10. package/dist/analysis/ts/extractDeclarations.js.map +1 -0
  11. package/dist/analysis/ts/extractUsages.d.ts +7 -0
  12. package/dist/analysis/ts/extractUsages.js +139 -0
  13. package/dist/analysis/ts/extractUsages.js.map +1 -0
  14. package/dist/analysis/ts/parseSourceFile.d.ts +11 -0
  15. package/dist/analysis/ts/parseSourceFile.js +24 -0
  16. package/dist/analysis/ts/parseSourceFile.js.map +1 -0
  17. package/dist/analysis/ts/reactState.d.ts +9 -0
  18. package/dist/analysis/ts/reactState.js +57 -0
  19. package/dist/analysis/ts/reactState.js.map +1 -0
  20. package/dist/analysis/ts/snippets.d.ts +14 -0
  21. package/dist/analysis/ts/snippets.js +29 -0
  22. package/dist/analysis/ts/snippets.js.map +1 -0
  23. package/dist/analysis/ts/structuralPredicates.d.ts +10 -0
  24. package/dist/analysis/ts/structuralPredicates.js +199 -0
  25. package/dist/analysis/ts/structuralPredicates.js.map +1 -0
  26. package/dist/ast/diffDeclarationShapes.d.ts +16 -0
  27. package/dist/ast/diffDeclarationShapes.js +179 -0
  28. package/dist/ast/diffDeclarationShapes.js.map +1 -0
  29. package/dist/ast/extractExportDeclarations.d.ts +21 -0
  30. package/dist/ast/extractExportDeclarations.js +218 -0
  31. package/dist/ast/extractExportDeclarations.js.map +1 -0
  32. package/dist/ast/findNodeAtPosition.d.ts +12 -0
  33. package/dist/ast/findNodeAtPosition.js +75 -0
  34. package/dist/ast/findNodeAtPosition.js.map +1 -0
  35. package/dist/ast/parseFile.d.ts +11 -0
  36. package/dist/ast/parseFile.js +46 -0
  37. package/dist/ast/parseFile.js.map +1 -0
  38. package/dist/engine/LspEngine.js +23 -1
  39. package/dist/engine/LspEngine.js.map +1 -1
  40. package/dist/engine/waitForDiagnostics.d.ts +7 -0
  41. package/dist/engine/waitForDiagnostics.js +16 -0
  42. package/dist/engine/waitForDiagnostics.js.map +1 -0
  43. package/dist/git/getBaseFileContent.d.ts +6 -0
  44. package/dist/git/getBaseFileContent.js +23 -0
  45. package/dist/git/getBaseFileContent.js.map +1 -0
  46. package/dist/git/getChangedFiles.d.ts +5 -0
  47. package/dist/git/getChangedFiles.js +27 -0
  48. package/dist/git/getChangedFiles.js.map +1 -0
  49. package/dist/git/getChangedHunks.d.ts +14 -0
  50. package/dist/git/getChangedHunks.js +56 -0
  51. package/dist/git/getChangedHunks.js.map +1 -0
  52. package/dist/git/getGitRoot.d.ts +15 -0
  53. package/dist/git/getGitRoot.js +33 -0
  54. package/dist/git/getGitRoot.js.map +1 -0
  55. package/dist/git/getMergeBase.d.ts +5 -0
  56. package/dist/git/getMergeBase.js +23 -0
  57. package/dist/git/getMergeBase.js.map +1 -0
  58. package/dist/index.js +10 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/resolve/searchScope.d.ts +17 -0
  61. package/dist/resolve/searchScope.js +64 -0
  62. package/dist/resolve/searchScope.js.map +1 -0
  63. package/dist/resolve/targetResolver.d.ts +33 -0
  64. package/dist/resolve/targetResolver.js +84 -0
  65. package/dist/resolve/targetResolver.js.map +1 -0
  66. package/dist/search/adapters/config.d.ts +5 -0
  67. package/dist/search/adapters/config.js +56 -0
  68. package/dist/search/adapters/config.js.map +1 -0
  69. package/dist/search/adapters/http.d.ts +6 -0
  70. package/dist/search/adapters/http.js +58 -0
  71. package/dist/search/adapters/http.js.map +1 -0
  72. package/dist/search/adapters/react.d.ts +12 -0
  73. package/dist/search/adapters/react.js +92 -0
  74. package/dist/search/adapters/react.js.map +1 -0
  75. package/dist/search/adapters/registry.d.ts +6 -0
  76. package/dist/search/adapters/registry.js +20 -0
  77. package/dist/search/adapters/registry.js.map +1 -0
  78. package/dist/search/adapters/types.d.ts +5 -0
  79. package/dist/search/adapters/types.js +2 -0
  80. package/dist/search/adapters/types.js.map +1 -0
  81. package/dist/search/debug/trace.d.ts +6 -0
  82. package/dist/search/debug/trace.js +25 -0
  83. package/dist/search/debug/trace.js.map +1 -0
  84. package/dist/search/expand/graphExpansion.d.ts +16 -0
  85. package/dist/search/expand/graphExpansion.js +168 -0
  86. package/dist/search/expand/graphExpansion.js.map +1 -0
  87. package/dist/search/families/behaviorFamilies.d.ts +22 -0
  88. package/dist/search/families/behaviorFamilies.js +90 -0
  89. package/dist/search/families/behaviorFamilies.js.map +1 -0
  90. package/dist/search/fileKinds.d.ts +13 -0
  91. package/dist/search/fileKinds.js +74 -0
  92. package/dist/search/fileKinds.js.map +1 -0
  93. package/dist/search/index/configIndex.d.ts +6 -0
  94. package/dist/search/index/configIndex.js +196 -0
  95. package/dist/search/index/configIndex.js.map +1 -0
  96. package/dist/search/index/declarationIndex.d.ts +6 -0
  97. package/dist/search/index/declarationIndex.js +13 -0
  98. package/dist/search/index/declarationIndex.js.map +1 -0
  99. package/dist/search/index/docIndex.d.ts +7 -0
  100. package/dist/search/index/docIndex.js +116 -0
  101. package/dist/search/index/docIndex.js.map +1 -0
  102. package/dist/search/index/types.d.ts +1 -0
  103. package/dist/search/index/types.js +2 -0
  104. package/dist/search/index/types.js.map +1 -0
  105. package/dist/search/index/usageIndex.d.ts +6 -0
  106. package/dist/search/index/usageIndex.js +13 -0
  107. package/dist/search/index/usageIndex.js.map +1 -0
  108. package/dist/search/index/workspaceIndex.d.ts +14 -0
  109. package/dist/search/index/workspaceIndex.js +127 -0
  110. package/dist/search/index/workspaceIndex.js.map +1 -0
  111. package/dist/search/query/compileEffectiveSearchSpec.d.ts +24 -0
  112. package/dist/search/query/compileEffectiveSearchSpec.js +67 -0
  113. package/dist/search/query/compileEffectiveSearchSpec.js.map +1 -0
  114. package/dist/search/query/parseQuery.d.ts +10 -0
  115. package/dist/search/query/parseQuery.js +284 -0
  116. package/dist/search/query/parseQuery.js.map +1 -0
  117. package/dist/search/query/phraseRules.d.ts +10 -0
  118. package/dist/search/query/phraseRules.js +58 -0
  119. package/dist/search/query/phraseRules.js.map +1 -0
  120. package/dist/search/query/planQuery.d.ts +10 -0
  121. package/dist/search/query/planQuery.js +91 -0
  122. package/dist/search/query/planQuery.js.map +1 -0
  123. package/dist/search/ranking/assessConfidence.d.ts +6 -0
  124. package/dist/search/ranking/assessConfidence.js +31 -0
  125. package/dist/search/ranking/assessConfidence.js.map +1 -0
  126. package/dist/search/ranking/candidateIdentity.d.ts +21 -0
  127. package/dist/search/ranking/candidateIdentity.js +29 -0
  128. package/dist/search/ranking/candidateIdentity.js.map +1 -0
  129. package/dist/search/ranking/coalesceCandidates.d.ts +9 -0
  130. package/dist/search/ranking/coalesceCandidates.js +48 -0
  131. package/dist/search/ranking/coalesceCandidates.js.map +1 -0
  132. package/dist/search/ranking/fieldedTextRanker.d.ts +26 -0
  133. package/dist/search/ranking/fieldedTextRanker.js +79 -0
  134. package/dist/search/ranking/fieldedTextRanker.js.map +1 -0
  135. package/dist/search/ranking/mergeCandidates.d.ts +13 -0
  136. package/dist/search/ranking/mergeCandidates.js +85 -0
  137. package/dist/search/ranking/mergeCandidates.js.map +1 -0
  138. package/dist/search/ranking/rankCandidates.d.ts +12 -0
  139. package/dist/search/ranking/rankCandidates.js +106 -0
  140. package/dist/search/ranking/rankCandidates.js.map +1 -0
  141. package/dist/search/retrievers/behaviorRetriever.d.ts +7 -0
  142. package/dist/search/retrievers/behaviorRetriever.js +86 -0
  143. package/dist/search/retrievers/behaviorRetriever.js.map +1 -0
  144. package/dist/search/retrievers/configRetriever.d.ts +7 -0
  145. package/dist/search/retrievers/configRetriever.js +46 -0
  146. package/dist/search/retrievers/configRetriever.js.map +1 -0
  147. package/dist/search/retrievers/docRetriever.d.ts +7 -0
  148. package/dist/search/retrievers/docRetriever.js +46 -0
  149. package/dist/search/retrievers/docRetriever.js.map +1 -0
  150. package/dist/search/retrievers/identifierRetriever.d.ts +7 -0
  151. package/dist/search/retrievers/identifierRetriever.js +67 -0
  152. package/dist/search/retrievers/identifierRetriever.js.map +1 -0
  153. package/dist/search/retrievers/structuralRetriever.d.ts +9 -0
  154. package/dist/search/retrievers/structuralRetriever.js +104 -0
  155. package/dist/search/retrievers/structuralRetriever.js.map +1 -0
  156. package/dist/search/retrievers/textPatternRetriever.d.ts +7 -0
  157. package/dist/search/retrievers/textPatternRetriever.js +90 -0
  158. package/dist/search/retrievers/textPatternRetriever.js.map +1 -0
  159. package/dist/search/structural/locators/callLocator.d.ts +6 -0
  160. package/dist/search/structural/locators/callLocator.js +57 -0
  161. package/dist/search/structural/locators/callLocator.js.map +1 -0
  162. package/dist/search/structural/locators/declarationLocator.d.ts +6 -0
  163. package/dist/search/structural/locators/declarationLocator.js +57 -0
  164. package/dist/search/structural/locators/declarationLocator.js.map +1 -0
  165. package/dist/search/structural/locators/statementLocator.d.ts +6 -0
  166. package/dist/search/structural/locators/statementLocator.js +65 -0
  167. package/dist/search/structural/locators/statementLocator.js.map +1 -0
  168. package/dist/search/structural/locators/types.d.ts +12 -0
  169. package/dist/search/structural/locators/types.js +2 -0
  170. package/dist/search/structural/locators/types.js.map +1 -0
  171. package/dist/search/structural/selectLocators.d.ts +7 -0
  172. package/dist/search/structural/selectLocators.js +21 -0
  173. package/dist/search/structural/selectLocators.js.map +1 -0
  174. package/dist/search/types.d.ts +191 -0
  175. package/dist/search/types.js +11 -0
  176. package/dist/search/types.js.map +1 -0
  177. package/dist/tools/composites/apiGuard.d.ts +1 -0
  178. package/dist/tools/composites/apiGuard.js +172 -0
  179. package/dist/tools/composites/apiGuard.js.map +1 -0
  180. package/dist/tools/composites/explainError.js +3 -2
  181. package/dist/tools/composites/explainError.js.map +1 -1
  182. package/dist/tools/composites/findCode.d.ts +1 -0
  183. package/dist/tools/composites/findCode.js +145 -0
  184. package/dist/tools/composites/findCode.js.map +1 -0
  185. package/dist/tools/composites/findPattern.d.ts +5 -0
  186. package/dist/tools/composites/findPattern.js +41 -0
  187. package/dist/tools/composites/findPattern.js.map +1 -0
  188. package/dist/tools/composites/rootCauseTrace.d.ts +1 -0
  189. package/dist/tools/composites/rootCauseTrace.js +213 -0
  190. package/dist/tools/composites/rootCauseTrace.js.map +1 -0
  191. package/dist/tools/composites/semanticDiff.js +24 -77
  192. package/dist/tools/composites/semanticDiff.js.map +1 -1
  193. package/dist/tools/live/clearIndex.d.ts +1 -0
  194. package/dist/tools/live/clearIndex.js +19 -0
  195. package/dist/tools/live/clearIndex.js.map +1 -0
  196. package/dist/tools/live/liveDiagnostics.js +3 -2
  197. package/dist/tools/live/liveDiagnostics.js.map +1 -1
  198. package/dist/tools/primitives/callHierarchy.js +1 -1
  199. package/dist/tools/primitives/callHierarchy.js.map +1 -1
  200. package/dist/tools/primitives/diagnostics.js +2 -2
  201. package/dist/tools/primitives/diagnostics.js.map +1 -1
  202. package/dist/tools/registry.d.ts +10 -2
  203. package/dist/tools/registry.js +7 -2
  204. package/dist/tools/registry.js.map +1 -1
  205. package/package.json +11 -5
  206. package/dist/tools/primitives/typeHierarchy.d.ts +0 -1
  207. package/dist/tools/primitives/typeHierarchy.js +0 -55
  208. package/dist/tools/primitives/typeHierarchy.js.map +0 -1
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # lsp-intelligence
2
2
 
3
- Type-aware code intelligence for AI agents — impact analysis, semantic diff, and context building via LSP.
3
+ Local code intelligence for real engineering workflows.
4
4
 
5
- **24 MCP tools** across 5 layers from basic navigation to "what breaks if I change this?" in one call.
5
+ **Find** implementations, API usage, structural patterns, configs, and routes. **Explain** why something broke. **Guard** the API contract before merging.
6
6
 
7
- Currently supports **TypeScript and JavaScript** projects. The architecture supports other LSP serversadditional language support is planned.
7
+ 29 MCP tools across 5 layers. Supports **TypeScript and JavaScript** (TS, TSX, JS, JSX, MJS, CJS). Local-onlyno paid API, no external calls.
8
8
 
9
9
  ## Why this exists
10
10
 
@@ -78,7 +78,7 @@ Use npm source in `marketplace.json` for version pinning and built-in dependency
78
78
  "source": {
79
79
  "source": "npm",
80
80
  "package": "lsp-intelligence",
81
- "version": "0.1.2"
81
+ "version": "0.2.0"
82
82
  }
83
83
  }
84
84
  ```
@@ -142,15 +142,19 @@ Direct LSP wrappers. Every tool accepts **symbol names** — agents never need t
142
142
  | `file_imports` | List all imports of a file. |
143
143
  | `file_exports` | List a file's public API including re-exports. |
144
144
 
145
- ### Layer 2: Composites (6 tools)
145
+ ### Layer 2: Intelligence Tools (10 tools)
146
146
 
147
- Combine multiple primitives into high-level operations.
147
+ Combine LSP, AST, and Git substrates into high-level operations.
148
148
 
149
149
  | Tool | Description |
150
150
  |------|-------------|
151
+ | `api_guard` | Detect public API contract changes — export diffs, structural classification, consumer impact, semver summary. |
152
+ | `root_cause_trace` | Trace the root cause of a TypeScript error — find the originating declaration change, not just the symptom. |
153
+ | `find_code` | Unified code search: behavior discovery, identifier/API usage, structural queries, config/route lookup, and implementation-root discovery. Routes automatically. |
154
+ | `find_pattern` | AST structural search — find code by pattern (e.g. `useEffect($$$)`, `try { $$$ } catch ($E) { $$$ }`). |
151
155
  | `inspect_symbol` | Hover + definition + references in one call. Full context about any symbol. |
152
156
  | `batch_query` | Look up multiple symbols at once. Saves round-trips when exploring. |
153
- | `impact_trace` | Follow a symbol through type aliases and re-exports to find ALL transitive usages. Answers **"what breaks if I change X?"** in one call. |
157
+ | `impact_trace` | Follow a symbol through type aliases and re-exports to find ALL transitive usages. |
154
158
  | `semantic_diff` | Analyze git diff semantically: identify changed symbols and their blast radius. |
155
159
  | `find_test_files` | Find all test/spec/stories files that reference a symbol. |
156
160
  | `explain_error` | Turn a TypeScript error into actionable context: expected type, actual type, and fix suggestion. |
@@ -174,6 +178,18 @@ Post-edit verification.
174
178
  | `find_unused_exports` | Find exported symbols with zero cross-package importers. |
175
179
  | `auto_import` | Resolve the correct import path for a symbol name. |
176
180
 
181
+ ## find_code query classes
182
+
183
+ `find_code` supports five query classes, routed automatically:
184
+
185
+ | Class | Example query | What happens |
186
+ |-------|--------------|-------------|
187
+ | **Identifier / API usage** | `useEffect`, `Promise.all` | Usage index → exact call/import sites with enclosing context |
188
+ | **Structural** | `useEffect that returns cleanup conditionally` | Identifier + structural predicates → AST evaluation on located nodes |
189
+ | **Behavior / entrypoint** | `where do we validate permissions` | Fielded BM25 over declarations + JSDoc/comments + family hints |
190
+ | **Config / route / flag** | `where is the feature flag configured` | Config index → JSON/YAML/package.json + env usage in code |
191
+ | **Implementation root** | `where is this actually implemented` | Graph expansion → wrapper detection → root promotion |
192
+
177
193
  ## Architecture
178
194
 
179
195
  ```
@@ -184,7 +200,8 @@ Post-edit verification.
184
200
  │ Layer 3: Context Engine [read-only] │
185
201
  │ gather_context, outline │
186
202
  ├─────────────────────────────────────────────────────────┤
187
- │ Layer 2: Composites [read-only] │
203
+ │ Layer 2: Intelligence Tools [read-only] │
204
+ │ find_code, find_pattern, root_cause_trace, api_guard, │
188
205
  │ impact_trace, semantic_diff, inspect_symbol, │
189
206
  │ batch_query, find_test_files, explain_error │
190
207
  ├─────────────────────────────────────────────────────────┤
@@ -192,9 +209,13 @@ Post-edit verification.
192
209
  │ find_references, hover, definition, call_hierarchy, │
193
210
  │ rename, diagnostics, symbols, imports, exports │
194
211
  ├─────────────────────────────────────────────────────────┤
195
- │ Layer 0: LSP Engine [infrastructure] │
196
- │ TypeScript Server spawn, monorepo preopen,
197
- symbol resolver, document manager
212
+ │ Layer 0: Analysis Substrates [infrastructure] │
213
+ LSP Engine (TypeScript Server, symbol resolver)
214
+ TypeScript AST (declarations, usages, predicates)
215
+ │ Local text/regex search (recipe-compiled patterns) │
216
+ │ Config/doc indexes (JSON, YAML, env, JSDoc, comments) │
217
+ │ Graph expansion (wrapper detection, root promotion) │
218
+ │ Git integration (semantic diff, base comparison) │
198
219
  └─────────────────────────────────────────────────────────┘
199
220
  ```
200
221
 
@@ -220,7 +241,7 @@ Requires **Node.js 20+**.
220
241
 
221
242
  ### Option 1: Claude Code plugin (recommended)
222
243
 
223
- Installs the MCP server, hooks, and skills (`/impact`, `/context`, `/check`) as a single package.
244
+ Installs the MCP server, hooks, and skills (`/find`, `/why`, `/api-check`, `/verify`, `/check`, `/impact`, `/context`, `/diff`) as a single package.
224
245
 
225
246
  ```bash
226
247
  claude plugin add perilevy/lsp-intelligence
@@ -280,18 +301,30 @@ Then in `.mcp.json`:
280
301
  git clone https://github.com/perilevy/lsp-intelligence.git
281
302
  cd lsp-intelligence
282
303
  yarn install
283
- yarn build # compile TypeScript dist/
304
+ yarn build # clean build (rm -rf dist && tsc)
284
305
  yarn test # vitest
285
306
  yarn typecheck # TypeScript strict mode — no emit
307
+ yarn bench # search quality benchmarks
286
308
  ```
287
309
 
288
310
  ### Testing
289
311
 
290
- Tests verify cross-package reference resolution, symbol-name lookup, type alias tracing, impact trace traversal, context building, and output formatting — all against a self-contained 3-package fixture monorepo at `test-fixtures/monorepo/`. No external dependencies needed.
312
+ Tests verify cross-package reference resolution, symbol-name lookup, type alias tracing, impact trace traversal, search quality, context building, and output formatting — all against self-contained fixture repos at `test-fixtures/`. No external dependencies needed.
313
+
314
+ ### Benchmarks
315
+
316
+ `benchmarks/` contains reproducible quality cases for `find_code`, `root_cause_trace`, and `api_guard`. Every serious real-world failure should become a benchmark case.
317
+
318
+ ## What this is not
319
+
320
+ - **Not a universal semantic search engine.** Strong on code structure, API usage, configs, and known patterns. Does not understand arbitrary business logic.
321
+ - **Not a replacement for full-text search.** Use grep for literal string matching. `find_code` uses text patterns internally but optimizes for code-aware ranking.
322
+ - **Not an AI model.** All intelligence is local: AST analysis, LSP queries, fielded text ranking, adapter recipes. No paid API calls, no external services.
323
+ - **Does not index secret-bearing `.env` files.** Env variable usage in code (`process.env.X`, `import.meta.env.X`) is indexed and searchable. Non-secret template/example files (`.env.example`, `.env.template`) are indexed. Real `.env` files are excluded by default.
291
324
 
292
325
  ## Dependencies
293
326
 
294
- All dependencies are installed automatically. Under the hood: [`typescript-language-server`](https://github.com/typescript-language-server/typescript-language-server) for LSP, [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) for MCP, and supporting libraries from Microsoft. Uses your project's own TypeScript version.
327
+ All dependencies are installed automatically. Under the hood: [`typescript-language-server`](https://github.com/typescript-language-server/typescript-language-server) for LSP, [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) for MCP, [`@ast-grep/napi`](https://github.com/ast-grep/ast-grep) for structural patterns. Uses your project's own TypeScript version.
295
328
 
296
329
  ## License
297
330
 
@@ -0,0 +1,6 @@
1
+ import type { SearchScope } from '../../search/types.js';
2
+ /**
3
+ * Collect files matching a set of extensions within a search scope.
4
+ * Skips dot-prefixed dirs, build output, minified/bundled files, and oversized files.
5
+ */
6
+ export declare function collectSearchFiles(scope: SearchScope, extensions: string[], maxFiles: number): string[];
@@ -0,0 +1,38 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { isTestFile, shouldSkipDir, shouldSkipFile } from '../../search/fileKinds.js';
4
+ /**
5
+ * Collect files matching a set of extensions within a search scope.
6
+ * Skips dot-prefixed dirs, build output, minified/bundled files, and oversized files.
7
+ */
8
+ export function collectSearchFiles(scope, extensions, maxFiles) {
9
+ const files = [];
10
+ for (const root of scope.roots) {
11
+ walkDir(root, files, extensions, scope.includeTests, maxFiles, 0);
12
+ if (files.length >= maxFiles)
13
+ break;
14
+ }
15
+ return files;
16
+ }
17
+ function walkDir(dir, files, extensions, includeTests, maxFiles, depth) {
18
+ if (depth > 8 || files.length >= maxFiles)
19
+ return;
20
+ try {
21
+ for (const entry of fs.readdirSync(dir)) {
22
+ if (shouldSkipDir(entry))
23
+ continue;
24
+ const full = path.join(dir, entry);
25
+ const stat = fs.statSync(full);
26
+ if (stat.isDirectory()) {
27
+ walkDir(full, files, extensions, includeTests, maxFiles, depth + 1);
28
+ }
29
+ else if (extensions.some((e) => entry.endsWith(e)) && !shouldSkipFile(full, stat.size)) {
30
+ if (!includeTests && isTestFile(full))
31
+ continue;
32
+ files.push(full);
33
+ }
34
+ }
35
+ }
36
+ catch { }
37
+ }
38
+ //# sourceMappingURL=collectSearchFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectSearchFiles.js","sourceRoot":"","sources":["../../../src/analysis/pattern/collectSearchFiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEtF;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAkB,EAClB,UAAoB,EACpB,QAAgB;IAEhB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;YAAE,MAAM;IACtC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,OAAO,CACd,GAAW,EACX,KAAe,EACf,UAAoB,EACpB,YAAqB,EACrB,QAAgB,EAChB,KAAa;IAEb,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO;IAClD,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACxC,IAAI,aAAa,CAAC,KAAK,CAAC;gBAAE,SAAS;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACtE,CAAC;iBAAM,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzF,IAAI,CAAC,YAAY,IAAI,UAAU,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAChD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;AACZ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { SearchScope, PatternMatch } from '../../search/types.js';
2
+ /**
3
+ * Run an ast-grep pattern search across files in scope.
4
+ * This is the engine behind find_pattern. Structural retrievers may also use it.
5
+ */
6
+ export declare function runPatternSearch(input: {
7
+ pattern: string;
8
+ language: 'typescript' | 'tsx' | 'javascript' | 'jsx';
9
+ scope: SearchScope;
10
+ maxResults: number;
11
+ contextLines: number;
12
+ workspaceRoot: string;
13
+ }): {
14
+ filesScanned: number;
15
+ matches: PatternMatch[];
16
+ warnings: string[];
17
+ };
@@ -0,0 +1,65 @@
1
+ import * as fs from 'fs';
2
+ import { parse, Lang } from '@ast-grep/napi';
3
+ import { collectSearchFiles } from './collectSearchFiles.js';
4
+ import { relativePath } from '../../engine/positions.js';
5
+ const LANG_MAP = {
6
+ typescript: Lang.TypeScript,
7
+ tsx: Lang.Tsx,
8
+ javascript: Lang.JavaScript,
9
+ jsx: Lang.Tsx, // ast-grep uses Tsx parser for JSX
10
+ };
11
+ const EXT_MAP = {
12
+ typescript: ['.ts', '.mjs', '.cjs'],
13
+ tsx: ['.tsx', '.ts'],
14
+ javascript: ['.js', '.mjs', '.cjs'],
15
+ jsx: ['.jsx', '.js'],
16
+ };
17
+ /**
18
+ * Run an ast-grep pattern search across files in scope.
19
+ * This is the engine behind find_pattern. Structural retrievers may also use it.
20
+ */
21
+ export function runPatternSearch(input) {
22
+ const lang = LANG_MAP[input.language];
23
+ if (!lang)
24
+ return { filesScanned: 0, matches: [], warnings: [`Unsupported language: ${input.language}`] };
25
+ const extensions = EXT_MAP[input.language];
26
+ const files = collectSearchFiles(input.scope, extensions, 500);
27
+ const matches = [];
28
+ const warnings = [];
29
+ for (const file of files) {
30
+ if (matches.length >= input.maxResults)
31
+ break;
32
+ try {
33
+ const content = fs.readFileSync(file, 'utf-8');
34
+ const root = parse(lang, content).root();
35
+ const found = root.findAll(input.pattern);
36
+ for (const match of found) {
37
+ if (matches.length >= input.maxResults)
38
+ break;
39
+ const range = match.range();
40
+ const line = range.start.line + 1;
41
+ matches.push({
42
+ filePath: relativePath(file, input.workspaceRoot),
43
+ line,
44
+ column: range.start.column,
45
+ text: match.text().substring(0, 200),
46
+ context: getContextLines(content, range.start.line, input.contextLines),
47
+ });
48
+ }
49
+ }
50
+ catch (err) {
51
+ warnings.push(`Parse failed for ${relativePath(file, input.workspaceRoot)}: ${err instanceof Error ? err.message : String(err)}`);
52
+ }
53
+ }
54
+ return { filesScanned: files.length, matches, warnings };
55
+ }
56
+ function getContextLines(content, line0, ctx) {
57
+ const lines = content.split('\n');
58
+ const start = Math.max(0, line0 - ctx);
59
+ const end = Math.min(lines.length - 1, line0 + ctx);
60
+ return lines
61
+ .slice(start, end + 1)
62
+ .map((l, i) => `${start + i + 1}| ${l}`)
63
+ .join('\n');
64
+ }
65
+ //# sourceMappingURL=runPatternSearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runPatternSearch.js","sourceRoot":"","sources":["../../../src/analysis/pattern/runPatternSearch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import ts from 'typescript';
2
+ import type { DeclarationIndexEntry } from '../../search/types.js';
3
+ /**
4
+ * Extract all declarations from a TypeScript source file using the TS compiler API.
5
+ * Returns top-level and exported declarations with symbol tokens for searching.
6
+ */
7
+ export declare function extractDeclarations(sf: ts.SourceFile): DeclarationIndexEntry[];
@@ -0,0 +1,93 @@
1
+ import ts from 'typescript';
2
+ import * as path from 'path';
3
+ /**
4
+ * Tokenize a symbol name: split camelCase, PascalCase, snake_case.
5
+ */
6
+ function tokenize(name) {
7
+ return name
8
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
9
+ .split(/[^a-zA-Z0-9]+/)
10
+ .map((t) => t.toLowerCase())
11
+ .filter((t) => t.length > 1);
12
+ }
13
+ function pathTokenize(filePath) {
14
+ const rel = path.basename(filePath, path.extname(filePath));
15
+ return tokenize(rel);
16
+ }
17
+ /**
18
+ * Extract all declarations from a TypeScript source file using the TS compiler API.
19
+ * Returns top-level and exported declarations with symbol tokens for searching.
20
+ */
21
+ export function extractDeclarations(sf) {
22
+ const entries = [];
23
+ const filePath = sf.fileName;
24
+ const pathToks = pathTokenize(filePath);
25
+ function visit(node) {
26
+ // Function declarations
27
+ if (ts.isFunctionDeclaration(node) && node.name) {
28
+ entries.push(makeEntry(node.name.text, 'function', node, sf, filePath, pathToks));
29
+ }
30
+ // Variable statements: export const/let/var
31
+ else if (ts.isVariableStatement(node)) {
32
+ const isExported = hasExportModifier(node);
33
+ for (const decl of node.declarationList.declarations) {
34
+ if (ts.isIdentifier(decl.name)) {
35
+ const kind = decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))
36
+ ? 'function' : 'variable';
37
+ entries.push({
38
+ symbol: decl.name.text,
39
+ kind,
40
+ filePath,
41
+ line: sf.getLineAndCharacterOfPosition(decl.getStart(sf)).line + 1,
42
+ column: sf.getLineAndCharacterOfPosition(decl.getStart(sf)).character,
43
+ isExported,
44
+ pathTokens: pathToks,
45
+ symbolTokens: tokenize(decl.name.text),
46
+ });
47
+ }
48
+ }
49
+ }
50
+ // Class declarations
51
+ else if (ts.isClassDeclaration(node) && node.name) {
52
+ entries.push(makeEntry(node.name.text, 'class', node, sf, filePath, pathToks));
53
+ }
54
+ // Interface declarations
55
+ else if (ts.isInterfaceDeclaration(node)) {
56
+ entries.push(makeEntry(node.name.text, 'interface', node, sf, filePath, pathToks));
57
+ }
58
+ // Type alias declarations
59
+ else if (ts.isTypeAliasDeclaration(node)) {
60
+ entries.push(makeEntry(node.name.text, 'type', node, sf, filePath, pathToks));
61
+ }
62
+ // Enum declarations
63
+ else if (ts.isEnumDeclaration(node)) {
64
+ entries.push(makeEntry(node.name.text, 'enum', node, sf, filePath, pathToks));
65
+ }
66
+ // Only visit top-level children
67
+ if (node === sf) {
68
+ ts.forEachChild(node, visit);
69
+ }
70
+ }
71
+ visit(sf);
72
+ return entries;
73
+ }
74
+ function makeEntry(name, kind, node, sf, filePath, pathToks) {
75
+ const pos = sf.getLineAndCharacterOfPosition(node.getStart(sf));
76
+ return {
77
+ symbol: name,
78
+ kind,
79
+ filePath,
80
+ line: pos.line + 1,
81
+ column: pos.character,
82
+ isExported: hasExportModifier(node),
83
+ pathTokens: pathToks,
84
+ symbolTokens: tokenize(name),
85
+ };
86
+ }
87
+ function hasExportModifier(node) {
88
+ if (!ts.canHaveModifiers(node))
89
+ return false;
90
+ const mods = ts.getModifiers(node);
91
+ return mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
92
+ }
93
+ //# sourceMappingURL=extractDeclarations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractDeclarations.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractDeclarations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import ts from 'typescript';
2
+ import type { UsageIndexEntry } from '../../search/types.js';
3
+ /**
4
+ * Extract all identifier usage sites from a TypeScript source file.
5
+ * Indexes: call expressions, member calls, import specifiers, JSX tags.
6
+ */
7
+ export declare function extractUsages(sf: ts.SourceFile): UsageIndexEntry[];
@@ -0,0 +1,139 @@
1
+ import ts from 'typescript';
2
+ import * as path from 'path';
3
+ function pathTokenize(filePath) {
4
+ return path.basename(filePath, path.extname(filePath))
5
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
6
+ .split(/[^a-zA-Z0-9]+/)
7
+ .map((t) => t.toLowerCase())
8
+ .filter((t) => t.length > 1);
9
+ }
10
+ /**
11
+ * Extract all identifier usage sites from a TypeScript source file.
12
+ * Indexes: call expressions, member calls, import specifiers, JSX tags.
13
+ */
14
+ export function extractUsages(sf) {
15
+ const entries = [];
16
+ const filePath = sf.fileName;
17
+ const pathToks = pathTokenize(filePath);
18
+ // Track enclosing symbol for context
19
+ let enclosingSymbol;
20
+ let enclosingKind;
21
+ function visit(node) {
22
+ // Save enclosing context so it restores correctly on recursion unwind
23
+ const prevSymbol = enclosingSymbol;
24
+ const prevKind = enclosingKind;
25
+ // Track enclosing function/class/method for context
26
+ if (ts.isFunctionDeclaration(node) && node.name) {
27
+ enclosingSymbol = node.name.text;
28
+ enclosingKind = 'function';
29
+ }
30
+ else if (ts.isVariableStatement(node)) {
31
+ for (const decl of node.declarationList.declarations) {
32
+ if (ts.isIdentifier(decl.name) && decl.initializer &&
33
+ (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
34
+ enclosingSymbol = decl.name.text;
35
+ enclosingKind = 'function';
36
+ }
37
+ }
38
+ }
39
+ else if (ts.isClassDeclaration(node) && node.name) {
40
+ enclosingSymbol = node.name.text;
41
+ enclosingKind = 'class';
42
+ }
43
+ else if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
44
+ enclosingSymbol = node.name.text;
45
+ enclosingKind = 'method';
46
+ }
47
+ // Call expressions: foo(), bar.baz()
48
+ if (ts.isCallExpression(node)) {
49
+ const expr = node.expression;
50
+ // Simple call: useEffect(...)
51
+ if (ts.isIdentifier(expr)) {
52
+ entries.push(makeUsage(expr.text, expr.text, 'call', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind));
53
+ }
54
+ // Member call: Promise.all(...), sdk.Items.get(...)
55
+ else if (ts.isPropertyAccessExpression(expr)) {
56
+ const fullName = getPropertyAccessText(expr);
57
+ const leafName = expr.name.text;
58
+ entries.push(makeUsage(fullName, leafName, 'member-call', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind));
59
+ }
60
+ }
61
+ // Import declarations: import { X } from "module"
62
+ if (ts.isImportDeclaration(node) && node.importClause) {
63
+ const clause = node.importClause;
64
+ // Default import
65
+ if (clause.name) {
66
+ entries.push(makeUsage(clause.name.text, clause.name.text, 'import', clause.name, sf, filePath, pathToks, undefined, undefined));
67
+ }
68
+ // Named imports: { A, B }
69
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
70
+ for (const spec of clause.namedBindings.elements) {
71
+ entries.push(makeUsage(spec.name.text, spec.name.text, 'import', spec, sf, filePath, pathToks, undefined, undefined));
72
+ }
73
+ }
74
+ // Namespace import: * as X
75
+ if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) {
76
+ entries.push(makeUsage(clause.namedBindings.name.text, clause.namedBindings.name.text, 'import', clause.namedBindings, sf, filePath, pathToks, undefined, undefined));
77
+ }
78
+ }
79
+ // JSX elements: <Component ... />
80
+ if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
81
+ const tagName = node.tagName;
82
+ if (ts.isIdentifier(tagName) && /^[A-Z]/.test(tagName.text)) {
83
+ entries.push(makeUsage(tagName.text, tagName.text, 'jsx-tag', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind));
84
+ }
85
+ }
86
+ // Env usage: process.env.X, import.meta.env.X
87
+ // Only match the exact env access (3 parts for process.env.X, 4 for import.meta.env.X)
88
+ // Skip if parent is also a PropertyAccessExpression (e.g. process.env.X.includes → skip, let process.env.X match)
89
+ if (ts.isPropertyAccessExpression(node) && !ts.isPropertyAccessExpression(node.parent)) {
90
+ const text = getPropertyAccessText(node);
91
+ const parts = text.split('.');
92
+ if (parts[0] === 'process' && parts[1] === 'env' && parts.length === 3) {
93
+ const envKey = parts[2];
94
+ const entry = makeUsage(`process.env.${envKey}`, envKey.toLowerCase(), 'env-usage', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind);
95
+ entry.metadata = { envKey };
96
+ entries.push(entry);
97
+ }
98
+ else if (parts[0] === 'import' && parts[1] === 'meta' && parts[2] === 'env' && parts.length === 4) {
99
+ const envKey = parts[3];
100
+ const entry = makeUsage(`import.meta.env.${envKey}`, envKey.toLowerCase(), 'env-usage', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind);
101
+ entry.metadata = { envKey };
102
+ entries.push(entry);
103
+ }
104
+ }
105
+ ts.forEachChild(node, visit);
106
+ // Restore enclosing context on unwind
107
+ enclosingSymbol = prevSymbol;
108
+ enclosingKind = prevKind;
109
+ }
110
+ visit(sf);
111
+ return entries;
112
+ }
113
+ function makeUsage(identifier, normalizedIdentifier, kind, node, sf, filePath, pathToks, enclosingSymbol, enclosingKind) {
114
+ const pos = sf.getLineAndCharacterOfPosition(node.getStart(sf));
115
+ return {
116
+ identifier,
117
+ normalizedIdentifier,
118
+ kind,
119
+ filePath,
120
+ line: pos.line + 1,
121
+ column: pos.character,
122
+ enclosingSymbol,
123
+ enclosingKind,
124
+ pathTokens: pathToks,
125
+ };
126
+ }
127
+ function getPropertyAccessText(node) {
128
+ const parts = [node.name.text];
129
+ let current = node.expression;
130
+ while (ts.isPropertyAccessExpression(current)) {
131
+ parts.unshift(current.name.text);
132
+ current = current.expression;
133
+ }
134
+ if (ts.isIdentifier(current)) {
135
+ parts.unshift(current.text);
136
+ }
137
+ return parts.join('.');
138
+ }
139
+ //# sourceMappingURL=extractUsages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractUsages.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractUsages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import ts from 'typescript';
2
+ /**
3
+ * Parse a TypeScript/JavaScript file into a ts.SourceFile using the TypeScript compiler API.
4
+ * Supports: .ts, .tsx, .js, .jsx, .mjs, .cjs
5
+ * Returns null if the file doesn't exist or can't be parsed.
6
+ */
7
+ export declare function parseSourceFile(filePath: string): ts.SourceFile | null;
8
+ /**
9
+ * Parse source content directly (for base-version comparison).
10
+ */
11
+ export declare function parseSourceContent(content: string, fileName: string): ts.SourceFile;
@@ -0,0 +1,24 @@
1
+ import ts from 'typescript';
2
+ import * as fs from 'fs';
3
+ import { scriptKindForFile } from '../../search/fileKinds.js';
4
+ /**
5
+ * Parse a TypeScript/JavaScript file into a ts.SourceFile using the TypeScript compiler API.
6
+ * Supports: .ts, .tsx, .js, .jsx, .mjs, .cjs
7
+ * Returns null if the file doesn't exist or can't be parsed.
8
+ */
9
+ export function parseSourceFile(filePath) {
10
+ try {
11
+ const content = fs.readFileSync(filePath, 'utf-8');
12
+ return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKindForFile(filePath));
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ /**
19
+ * Parse source content directly (for base-version comparison).
20
+ */
21
+ export function parseSourceContent(content, fileName) {
22
+ return ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, scriptKindForFile(fileName));
23
+ }
24
+ //# sourceMappingURL=parseSourceFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseSourceFile.js","sourceRoot":"","sources":["../../../src/analysis/ts/parseSourceFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3G,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,QAAgB;IAClE,OAAO,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3G,CAAC"}
@@ -0,0 +1,9 @@
1
+ import ts from 'typescript';
2
+ /**
3
+ * Detect if a node contains a functional state updater pattern.
4
+ * Matches: setState(prev => ...), setCount(current => current + 1), etc.
5
+ *
6
+ * Only matches when the updater parameter is actually used in the body.
7
+ * Does NOT match: setState(() => 1) — that's a constant updater.
8
+ */
9
+ export declare function hasFunctionalStateUpdater(node: ts.Node): boolean;