@bastani/atomic 0.6.3-0 → 0.6.4-0

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 (49) hide show
  1. package/.agents/skills/ast-grep/SKILL.md +323 -0
  2. package/.agents/skills/ast-grep/references/rule_reference.md +297 -0
  3. package/.agents/skills/ripgrep/SKILL.md +382 -0
  4. package/.mcp.json +5 -6
  5. package/dist/commands/cli/claude-inflight-hook.d.ts +100 -0
  6. package/dist/commands/cli/claude-inflight-hook.d.ts.map +1 -0
  7. package/dist/commands/cli/claude-stop-hook.d.ts +2 -0
  8. package/dist/commands/cli/claude-stop-hook.d.ts.map +1 -1
  9. package/dist/lib/spawn.d.ts +1 -1
  10. package/dist/lib/spawn.d.ts.map +1 -1
  11. package/dist/sdk/providers/claude.d.ts +36 -0
  12. package/dist/sdk/providers/claude.d.ts.map +1 -1
  13. package/dist/sdk/providers/copilot.d.ts +17 -1
  14. package/dist/sdk/providers/copilot.d.ts.map +1 -1
  15. package/dist/sdk/runtime/executor.d.ts.map +1 -1
  16. package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts +49 -34
  17. package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts.map +1 -1
  18. package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts +18 -16
  19. package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts.map +1 -1
  20. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/batching.d.ts +43 -0
  21. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/batching.d.ts.map +1 -0
  22. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.d.ts +30 -0
  23. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.d.ts.map +1 -1
  24. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/scout.d.ts +2 -1
  25. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/scout.d.ts.map +1 -1
  26. package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts +18 -16
  27. package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts.map +1 -1
  28. package/dist/services/config/additional-instructions.d.ts +67 -0
  29. package/dist/services/config/additional-instructions.d.ts.map +1 -0
  30. package/package.json +3 -1
  31. package/src/cli.ts +18 -1
  32. package/src/commands/cli/chat/index.ts +52 -2
  33. package/src/commands/cli/claude-inflight-hook.test.ts +598 -0
  34. package/src/commands/cli/claude-inflight-hook.ts +359 -0
  35. package/src/commands/cli/claude-stop-hook.ts +40 -4
  36. package/src/commands/cli/init/index.ts +9 -0
  37. package/src/lib/spawn.ts +6 -2
  38. package/src/sdk/providers/claude.ts +131 -0
  39. package/src/sdk/providers/copilot.ts +30 -1
  40. package/src/sdk/runtime/executor.ts +43 -2
  41. package/src/sdk/workflows/builtin/deep-research-codebase/claude/index.ts +318 -158
  42. package/src/sdk/workflows/builtin/deep-research-codebase/copilot/index.ts +253 -129
  43. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/batching.ts +65 -0
  44. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/ignore-by-default.d.ts +8 -0
  45. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.ts +203 -12
  46. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/scout.ts +248 -78
  47. package/src/sdk/workflows/builtin/deep-research-codebase/opencode/index.ts +258 -146
  48. package/src/services/config/additional-instructions.ts +273 -0
  49. package/src/services/system/auto-sync.ts +10 -1
@@ -0,0 +1,323 @@
1
+ ---
2
+ name: ast-grep
3
+ description: Guide for writing ast-grep rules to perform structural code search and analysis. Use when users need to search codebases using Abstract Syntax Tree (AST) patterns, find specific code structures, or perform complex code queries that go beyond simple text search. This skill should be used when users ask to search for code patterns, find specific language constructs, or locate code with particular structural characteristics.
4
+ ---
5
+
6
+ # ast-grep Code Search
7
+
8
+ ## Overview
9
+
10
+ This skill helps translate natural language queries into ast-grep rules for structural code search. ast-grep uses Abstract Syntax Tree (AST) patterns to match code based on its structure rather than just text, enabling powerful and precise code search across large codebases.
11
+
12
+ ## When to Use This Skill
13
+
14
+ Use this skill when users:
15
+ - Need to search for code patterns using structural matching (e.g., "find all async functions that don't have error handling")
16
+ - Want to locate specific language constructs (e.g., "find all function calls with specific parameters")
17
+ - Request searches that require understanding code structure rather than just text
18
+ - Ask to search for code with particular AST characteristics
19
+ - Need to perform complex code queries that traditional text search cannot handle
20
+
21
+ ## General Workflow
22
+
23
+ Follow this process to help users write effective ast-grep rules:
24
+
25
+ ### Step 1: Understand the Query
26
+
27
+ Clearly understand what the user wants to find. Ask clarifying questions if needed:
28
+ - What specific code pattern or structure are they looking for?
29
+ - Which programming language?
30
+ - Are there specific edge cases or variations to consider?
31
+ - What should be included or excluded from matches?
32
+
33
+ ### Step 2: Create Example Code
34
+
35
+ Write a simple code snippet that represents what the user wants to match. Save this to a temporary file for testing.
36
+
37
+ **Example:**
38
+ If searching for "async functions that use await", create a test file:
39
+
40
+ ```javascript
41
+ // test_example.js
42
+ async function example() {
43
+ const result = await fetchData();
44
+ return result;
45
+ }
46
+ ```
47
+
48
+ ### Step 3: Write the ast-grep Rule
49
+
50
+ Translate the pattern into an ast-grep rule. Start simple and add complexity as needed.
51
+
52
+ **Key principles:**
53
+ - Always use `stopBy: end` for relational rules (`inside`, `has`) to ensure search goes to the end of the direction
54
+ - Use `pattern` for simple structures
55
+ - Use `kind` with `has`/`inside` for complex structures
56
+ - Break complex queries into smaller sub-rules using `all`, `any`, or `not`
57
+
58
+ **Example rule file (test_rule.yml):**
59
+ ```yaml
60
+ id: async-with-await
61
+ language: javascript
62
+ rule:
63
+ kind: function_declaration
64
+ has:
65
+ pattern: await $EXPR
66
+ stopBy: end
67
+ ```
68
+
69
+ See `references/rule_reference.md` for comprehensive rule documentation.
70
+
71
+ ### Step 4: Test the Rule
72
+
73
+ Use ast-grep CLI to verify the rule matches the example code. There are two main approaches:
74
+
75
+ **Option A: Test with inline rules (for quick iterations)**
76
+ ```bash
77
+ echo "async function test() { await fetch(); }" | ast-grep scan --inline-rules "id: test
78
+ language: javascript
79
+ rule:
80
+ kind: function_declaration
81
+ has:
82
+ pattern: await \$EXPR
83
+ stopBy: end" --stdin
84
+ ```
85
+
86
+ **Option B: Test with rule files (recommended for complex rules)**
87
+ ```bash
88
+ ast-grep scan --rule test_rule.yml test_example.js
89
+ ```
90
+
91
+ **Debugging if no matches:**
92
+ 1. Simplify the rule (remove sub-rules)
93
+ 2. Add `stopBy: end` to relational rules if not present
94
+ 3. Use `--debug-query` to understand the AST structure (see below)
95
+ 4. Check if `kind` values are correct for the language
96
+
97
+ ### Step 5: Search the Codebase
98
+
99
+ Once the rule matches the example code correctly, search the actual codebase:
100
+
101
+ **For simple pattern searches:**
102
+ ```bash
103
+ ast-grep run --pattern 'console.log($ARG)' --lang javascript /path/to/project
104
+ ```
105
+
106
+ **For complex rule-based searches:**
107
+ ```bash
108
+ ast-grep scan --rule my_rule.yml /path/to/project
109
+ ```
110
+
111
+ **For inline rules (without creating files):**
112
+ ```bash
113
+ ast-grep scan --inline-rules "id: my-rule
114
+ language: javascript
115
+ rule:
116
+ pattern: \$PATTERN" /path/to/project
117
+ ```
118
+
119
+ ## ast-grep CLI Commands
120
+
121
+ ### Inspect Code Structure (--debug-query)
122
+
123
+ Dump the AST structure to understand how code is parsed:
124
+
125
+ ```bash
126
+ ast-grep run --pattern 'async function example() { await fetch(); }' \
127
+ --lang javascript \
128
+ --debug-query=cst
129
+ ```
130
+
131
+ **Available formats:**
132
+ - `cst`: Concrete Syntax Tree (shows all nodes including punctuation)
133
+ - `ast`: Abstract Syntax Tree (shows only named nodes)
134
+ - `pattern`: Shows how ast-grep interprets your pattern
135
+
136
+ **Use this to:**
137
+ - Find the correct `kind` values for nodes
138
+ - Understand the structure of code you want to match
139
+ - Debug why patterns aren't matching
140
+
141
+ **Example:**
142
+ ```bash
143
+ # See the structure of your target code
144
+ ast-grep run --pattern 'class User { constructor() {} }' \
145
+ --lang javascript \
146
+ --debug-query=cst
147
+
148
+ # See how ast-grep interprets your pattern
149
+ ast-grep run --pattern 'class $NAME { $$$BODY }' \
150
+ --lang javascript \
151
+ --debug-query=pattern
152
+ ```
153
+
154
+ ### Test Rules (scan with --stdin)
155
+
156
+ Test a rule against code snippet without creating files:
157
+
158
+ ```bash
159
+ echo "const x = await fetch();" | ast-grep scan --inline-rules "id: test
160
+ language: javascript
161
+ rule:
162
+ pattern: await \$EXPR" --stdin
163
+ ```
164
+
165
+ **Add --json for structured output:**
166
+ ```bash
167
+ echo "const x = await fetch();" | ast-grep scan --inline-rules "..." --stdin --json
168
+ ```
169
+
170
+ ### Search with Patterns (run)
171
+
172
+ Simple pattern-based search for single AST node matches:
173
+
174
+ ```bash
175
+ # Basic pattern search
176
+ ast-grep run --pattern 'console.log($ARG)' --lang javascript .
177
+
178
+ # Search specific files
179
+ ast-grep run --pattern 'class $NAME' --lang python /path/to/project
180
+
181
+ # JSON output for programmatic use
182
+ ast-grep run --pattern 'function $NAME($$$)' --lang javascript --json .
183
+ ```
184
+
185
+ **When to use:**
186
+ - Simple, single-node matches
187
+ - Quick searches without complex logic
188
+ - When you don't need relational rules (inside/has)
189
+
190
+ ### Search with Rules (scan)
191
+
192
+ YAML rule-based search for complex structural queries:
193
+
194
+ ```bash
195
+ # With rule file
196
+ ast-grep scan --rule my_rule.yml /path/to/project
197
+
198
+ # With inline rules
199
+ ast-grep scan --inline-rules "id: find-async
200
+ language: javascript
201
+ rule:
202
+ kind: function_declaration
203
+ has:
204
+ pattern: await \$EXPR
205
+ stopBy: end" /path/to/project
206
+
207
+ # JSON output
208
+ ast-grep scan --rule my_rule.yml --json /path/to/project
209
+ ```
210
+
211
+ **When to use:**
212
+ - Complex structural searches
213
+ - Relational rules (inside, has, precedes, follows)
214
+ - Composite logic (all, any, not)
215
+ - When you need the power of full YAML rules
216
+
217
+ **Tip:** For relational rules (inside/has), always add `stopBy: end` to ensure complete traversal.
218
+
219
+ ## Tips for Writing Effective Rules
220
+
221
+ ### Always Use stopBy: end
222
+
223
+ For relational rules, always use `stopBy: end` unless there's a specific reason not to:
224
+
225
+ ```yaml
226
+ has:
227
+ pattern: await $EXPR
228
+ stopBy: end
229
+ ```
230
+
231
+ This ensures the search traverses the entire subtree rather than stopping at the first non-matching node.
232
+
233
+ ### Start Simple, Then Add Complexity
234
+
235
+ Begin with the simplest rule that could work:
236
+ 1. Try a `pattern` first
237
+ 2. If that doesn't work, try `kind` to match the node type
238
+ 3. Add relational rules (`has`, `inside`) as needed
239
+ 4. Combine with composite rules (`all`, `any`, `not`) for complex logic
240
+
241
+ ### Use the Right Rule Type
242
+
243
+ - **Pattern**: For simple, direct code matching (e.g., `console.log($ARG)`)
244
+ - **Kind + Relational**: For complex structures (e.g., "function containing await")
245
+ - **Composite**: For logical combinations (e.g., "function with await but not in try-catch")
246
+
247
+ ### Debug with AST Inspection
248
+
249
+ When rules don't match:
250
+ 1. Use `--debug-query=cst` to see the actual AST structure
251
+ 2. Check if metavariables are being detected correctly
252
+ 3. Verify the node `kind` matches what you expect
253
+ 4. Ensure relational rules are searching in the right direction
254
+
255
+ ### Escaping in Inline Rules
256
+
257
+ When using `--inline-rules`, escape metavariables in shell commands:
258
+ - Use `\$VAR` instead of `$VAR` (shell interprets `$` as variable)
259
+ - Or use single quotes: `'$VAR'` works in most shells
260
+
261
+ **Example:**
262
+ ```bash
263
+ # Correct: escaped $
264
+ ast-grep scan --inline-rules "rule: {pattern: 'console.log(\$ARG)'}" .
265
+
266
+ # Or use single quotes
267
+ ast-grep scan --inline-rules 'rule: {pattern: "console.log($ARG)"}' .
268
+ ```
269
+
270
+ ## Common Use Cases
271
+
272
+ ### Find Functions with Specific Content
273
+
274
+ Find async functions that use await:
275
+ ```bash
276
+ ast-grep scan --inline-rules "id: async-await
277
+ language: javascript
278
+ rule:
279
+ all:
280
+ - kind: function_declaration
281
+ - has:
282
+ pattern: await \$EXPR
283
+ stopBy: end" /path/to/project
284
+ ```
285
+
286
+ ### Find Code Inside Specific Contexts
287
+
288
+ Find console.log inside class methods:
289
+ ```bash
290
+ ast-grep scan --inline-rules "id: console-in-class
291
+ language: javascript
292
+ rule:
293
+ pattern: console.log(\$\$\$)
294
+ inside:
295
+ kind: method_definition
296
+ stopBy: end" /path/to/project
297
+ ```
298
+
299
+ ### Find Code Missing Expected Patterns
300
+
301
+ Find async functions without try-catch:
302
+ ```bash
303
+ ast-grep scan --inline-rules "id: async-no-trycatch
304
+ language: javascript
305
+ rule:
306
+ all:
307
+ - kind: function_declaration
308
+ - has:
309
+ pattern: await \$EXPR
310
+ stopBy: end
311
+ - not:
312
+ has:
313
+ pattern: try { \$\$\$ } catch (\$E) { \$\$\$ }
314
+ stopBy: end" /path/to/project
315
+ ```
316
+
317
+ ## Resources
318
+
319
+ ### references/
320
+ Contains detailed documentation for ast-grep rule syntax:
321
+ - `rule_reference.md`: Comprehensive ast-grep rule documentation covering atomic rules, relational rules, composite rules, and metavariables
322
+
323
+ Load these references when detailed rule syntax information is needed.
@@ -0,0 +1,297 @@
1
+ # ast-grep Rule Reference
2
+
3
+ This document provides comprehensive documentation for ast-grep rule syntax, covering all rule types and metavariables.
4
+
5
+ ## Introduction to ast-grep Rules
6
+
7
+ ast-grep rules are declarative specifications for matching and filtering Abstract Syntax Tree (AST) nodes. They enable structural code search and analysis by defining conditions an AST node must meet to be matched.
8
+
9
+ ### Rule Categories
10
+
11
+ ast-grep rules are categorized into three types:
12
+
13
+ * **Atomic Rules**: Match individual AST nodes based on intrinsic properties like code patterns (`pattern`), node type (`kind`), or text content (`regex`).
14
+ * **Relational Rules**: Define conditions based on a target node's position or relationship to other nodes (e.g., `inside`, `has`, `precedes`, `follows`).
15
+ * **Composite Rules**: Combine other rules using logical operations (AND, OR, NOT) to form complex matching criteria (e.g., `all`, `any`, `not`, `matches`).
16
+
17
+ ## Anatomy of an ast-grep Rule Object
18
+
19
+ The ast-grep rule object is the core configuration unit defining how ast-grep identifies and filters AST nodes. It's typically written in YAML format.
20
+
21
+ ### General Structure
22
+
23
+ Every field within an ast-grep Rule Object is optional, but at least one "positive" key (e.g., `kind`, `pattern`) must be present.
24
+
25
+ A node matches a rule if it satisfies all fields defined within that rule object, implying an implicit logical AND operation.
26
+
27
+ For rules using metavariables that depend on prior matching, explicit `all` composite rules are recommended to guarantee execution order.
28
+
29
+ ### Rule Object Properties
30
+
31
+ | Property | Type | Category | Purpose | Example |
32
+ | :--- | :--- | :--- | :--- | :--- |
33
+ | `pattern` | String or Object | Atomic | Matches AST node by code pattern. | `pattern: console.log($ARG)` |
34
+ | `kind` | String | Atomic | Matches AST node by its kind name. | `kind: call_expression` |
35
+ | `regex` | String | Atomic | Matches node's text by Rust regex. | `regex: ^[a-z]+$` |
36
+ | `nthChild` | number, string, Object | Atomic | Matches nodes by their index within parent's children. | `nthChild: 1` |
37
+ | `range` | RangeObject | Atomic | Matches node by character-based start/end positions. | `range: { start: { line: 0, column: 0 }, end: { line: 0, column: 10 } }` |
38
+ | `inside` | Object | Relational | Target node must be inside node matching sub-rule. | `inside: { pattern: class $C { $$$ }, stopBy: end }` |
39
+ | `has` | Object | Relational | Target node must have descendant matching sub-rule. | `has: { pattern: await $EXPR, stopBy: end }` |
40
+ | `precedes` | Object | Relational | Target node must appear before node matching sub-rule. | `precedes: { pattern: return $VAL }` |
41
+ | `follows` | Object | Relational | Target node must appear after node matching sub-rule. | `follows: { pattern: import $M from '$P' }` |
42
+ | `all` | Array<Rule> | Composite | Matches if all sub-rules match. | `all: [ { kind: call_expression }, { pattern: foo($A) } ]` |
43
+ | `any` | Array<Rule> | Composite | Matches if any sub-rules match. | `any: [ { pattern: foo() }, { pattern: bar() } ]` |
44
+ | `not` | Object | Composite | Matches if sub-rule does not match. | `not: { pattern: console.log($ARG) }` |
45
+ | `matches` | String | Composite | Matches if predefined utility rule matches. | `matches: my-utility-rule-id` |
46
+
47
+ ## Atomic Rules
48
+
49
+ Atomic rules match individual AST nodes based on their intrinsic properties.
50
+
51
+ ### pattern: String and Object Forms
52
+
53
+ The `pattern` rule matches a single AST node based on a code pattern.
54
+
55
+ **String Pattern**: Directly matches using ast-grep's pattern syntax with metavariables.
56
+
57
+ ```yaml
58
+ pattern: console.log($ARG)
59
+ ```
60
+
61
+ **Object Pattern**: Offers granular control for ambiguous patterns or specific contexts.
62
+
63
+ * `selector`: Pinpoints a specific part of the parsed pattern to match.
64
+ ```yaml
65
+ pattern:
66
+ selector: field_definition
67
+ context: class { $F }
68
+ ```
69
+
70
+ * `context`: Provides surrounding code context for correct parsing.
71
+
72
+ * `strictness`: Modifies the pattern's matching algorithm (`cst`, `smart`, `ast`, `relaxed`, `signature`).
73
+ ```yaml
74
+ pattern:
75
+ context: foo($BAR)
76
+ strictness: relaxed
77
+ ```
78
+
79
+ ### kind: Matching by Node Type
80
+
81
+ The `kind` rule matches an AST node by its `tree_sitter_node_kind` name, derived from the language's Tree-sitter grammar. Useful for targeting constructs like `call_expression` or `function_declaration`.
82
+
83
+ ```yaml
84
+ kind: call_expression
85
+ ```
86
+
87
+ ### regex: Text-Based Node Matching
88
+
89
+ The `regex` rule matches the entire text content of an AST node using a Rust regular expression. It's not a "positive" rule, meaning it matches any node whose text satisfies the regex, regardless of its structural kind.
90
+
91
+ ### nthChild: Positional Node Matching
92
+
93
+ The `nthChild` rule finds nodes by their 1-based index within their parent's children list, counting only named nodes by default.
94
+
95
+ * `number`: Matches the exact nth child. Example: `nthChild: 1`
96
+ * `string`: Matches positions using An+B formula. Example: `2n+1`
97
+ * `Object`: Provides granular control:
98
+ * `position`: `number` or An+B string.
99
+ * `reverse`: `true` to count from the end.
100
+ * `ofRule`: An ast-grep rule to filter the sibling list before counting.
101
+
102
+ ### range: Position-Based Node Matching
103
+
104
+ The `range` rule matches an AST node based on its character-based start and end positions. A `RangeObject` defines `start` and `end` fields, each with 0-based `line` and `column`. `start` is inclusive, `end` is exclusive.
105
+
106
+ ## Relational Rules
107
+
108
+ Relational rules filter targets based on their position relative to other AST nodes. They can include `stopBy` and `field` options.
109
+
110
+ ### inside: Matching Within a Parent Node
111
+
112
+ Requires the target node to be inside another node matching the `inside` sub-rule.
113
+
114
+ ```yaml
115
+ inside:
116
+ pattern: class $C { $$$ }
117
+ stopBy: end
118
+ ```
119
+
120
+ ### has: Matching with a Descendant Node
121
+
122
+ Requires the target node to have a descendant node matching the `has` sub-rule.
123
+
124
+ ```yaml
125
+ has:
126
+ pattern: await $EXPR
127
+ stopBy: end
128
+ ```
129
+
130
+ ### precedes and follows: Sequential Node Matching
131
+
132
+ * `precedes`: Target node must appear before a node matching the `precedes` sub-rule.
133
+ * `follows`: Target node must appear after a node matching the `follows` sub-rule.
134
+
135
+ Both include `stopBy` but not `field`.
136
+
137
+ ### stopBy and field: Refining Relational Searches
138
+
139
+ **stopBy**: Controls search termination for relational rules.
140
+
141
+ * `"neighbor"` (default): Stops when immediate surrounding node doesn't match.
142
+ * `"end"`: Searches to the end of the direction (root for `inside`, leaf for `has`).
143
+ * `Rule object`: Stops when a surrounding node matches the provided rule (inclusive).
144
+
145
+ **field**: Specifies a sub-node within the target node that should match the relational rule. Only for `inside` and `has`.
146
+
147
+ **Best Practice**: When unsure, always use `stopBy: end` to ensure the search goes to the end of the direction.
148
+
149
+ ## Composite Rules
150
+
151
+ Composite rules combine atomic and relational rules using logical operations.
152
+
153
+ ### all: Conjunction (AND) of Rules
154
+
155
+ Matches a node only if all sub-rules in the list match. Guarantees order of rule matching, important for metavariables.
156
+
157
+ ```yaml
158
+ all:
159
+ - kind: call_expression
160
+ - pattern: console.log($ARG)
161
+ ```
162
+
163
+ ### any: Disjunction (OR) of Rules
164
+
165
+ Matches a node if any sub-rules in the list match.
166
+
167
+ ```yaml
168
+ any:
169
+ - pattern: console.log($ARG)
170
+ - pattern: console.warn($ARG)
171
+ - pattern: console.error($ARG)
172
+ ```
173
+
174
+ ### not: Negation (NOT) of a Rule
175
+
176
+ Matches a node if the single sub-rule does not match.
177
+
178
+ ```yaml
179
+ not:
180
+ pattern: console.log($ARG)
181
+ ```
182
+
183
+ ### matches: Rule Reuse and Utility Rules
184
+
185
+ Takes a rule-id string, matching if the referenced utility rule matches. Enables rule reuse and recursive rules.
186
+
187
+ ## Metavariables
188
+
189
+ Metavariables are placeholders in patterns to match dynamic content in the AST.
190
+
191
+ ### $VAR: Single Named Node Capture
192
+
193
+ Captures a single named node in the AST.
194
+
195
+ * **Valid**: `$META`, `$META_VAR`, `$_`
196
+ * **Invalid**: `$invalid`, `$123`, `$KEBAB-CASE`
197
+ * **Example**: `console.log($GREETING)` matches `console.log('Hello World')`.
198
+ * **Reuse**: `$A == $A` matches `a == a` but not `a == b`.
199
+
200
+ ### $$VAR: Single Unnamed Node Capture
201
+
202
+ Captures a single unnamed node (e.g., operators, punctuation).
203
+
204
+ **Example**: To match the operator in `a + b`, use `$$OP`.
205
+
206
+ ```yaml
207
+ rule:
208
+ kind: binary_expression
209
+ has:
210
+ field: operator
211
+ pattern: $$OP
212
+ ```
213
+
214
+ ### $$$MULTI_META_VARIABLE: Multi-Node Capture
215
+
216
+ Matches zero or more AST nodes (non-greedy). Useful for variable numbers of arguments or statements.
217
+
218
+ * **Example**: `console.log($$$)` matches `console.log()`, `console.log('hello')`, and `console.log('debug:', key, value)`.
219
+ * **Example**: `function $FUNC($$$ARGS) { $$$ }` matches functions with varying parameters/statements.
220
+
221
+ ### Non-Capturing Metavariables (_VAR)
222
+
223
+ Metavariables starting with an underscore (`_`) are not captured. They can match different content even if named identically, optimizing performance.
224
+
225
+ * **Example**: `$_FUNC($_FUNC)` matches `test(a)` and `testFunc(1 + 1)`.
226
+
227
+ ### Important Considerations for Metavariable Detection
228
+
229
+ * **Syntax Matching**: Only exact metavariable syntax (e.g., `$A`, `$$B`, `$$$C`) is recognized.
230
+ * **Exclusive Content**: Metavariable text must be the only text within an AST node.
231
+ * **Non-working**: `obj.on$EVENT`, `"Hello $WORLD"`, `a $OP b`, `$jq`.
232
+
233
+ The ast-grep playground is useful for debugging patterns and visualizing metavariables.
234
+
235
+ ## Common Patterns and Examples
236
+
237
+ ### Finding Functions with Specific Content
238
+
239
+ Find functions that contain await expressions:
240
+
241
+ ```yaml
242
+ rule:
243
+ kind: function_declaration
244
+ has:
245
+ pattern: await $EXPR
246
+ stopBy: end
247
+ ```
248
+
249
+ ### Finding Code Inside Specific Contexts
250
+
251
+ Find console.log calls inside class methods:
252
+
253
+ ```yaml
254
+ rule:
255
+ pattern: console.log($$$)
256
+ inside:
257
+ kind: method_definition
258
+ stopBy: end
259
+ ```
260
+
261
+ ### Combining Multiple Conditions
262
+
263
+ Find async functions that use await but don't have try-catch:
264
+
265
+ ```yaml
266
+ rule:
267
+ all:
268
+ - kind: function_declaration
269
+ - has:
270
+ pattern: await $EXPR
271
+ stopBy: end
272
+ - not:
273
+ has:
274
+ pattern: try { $$$ } catch ($E) { $$$ }
275
+ stopBy: end
276
+ ```
277
+
278
+ ### Matching Multiple Alternatives
279
+
280
+ Find any type of console method call:
281
+
282
+ ```yaml
283
+ rule:
284
+ any:
285
+ - pattern: console.log($$$)
286
+ - pattern: console.warn($$$)
287
+ - pattern: console.error($$$)
288
+ - pattern: console.debug($$$)
289
+ ```
290
+
291
+ ## Troubleshooting Tips
292
+
293
+ 1. **Rule doesn't match**: Use `dump_syntax_tree` to see the actual AST structure
294
+ 2. **Relational rule issues**: Ensure `stopBy: end` is set for deep searches
295
+ 3. **Wrong node kind**: Check the language's Tree-sitter grammar for correct kind names
296
+ 4. **Metavariable not working**: Ensure it's the only content in its AST node
297
+ 5. **Pattern too complex**: Break it down into simpler sub-rules using `all`