pi-lens 3.3.0 → 3.6.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 (53) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +175 -13
  3. package/clients/cache/rule-cache.js +72 -0
  4. package/clients/cache/rule-cache.ts +104 -0
  5. package/clients/dispatch/integration.js +48 -1
  6. package/clients/dispatch/integration.ts +60 -2
  7. package/clients/dispatch/plan.js +5 -2
  8. package/clients/dispatch/plan.ts +5 -2
  9. package/clients/dispatch/runners/ast-grep-napi.js +175 -56
  10. package/clients/dispatch/runners/ast-grep-napi.test.js +2 -1
  11. package/clients/dispatch/runners/ast-grep-napi.test.ts +2 -1
  12. package/clients/dispatch/runners/ast-grep-napi.ts +191 -79
  13. package/clients/dispatch/runners/similarity.js +1 -1
  14. package/clients/dispatch/runners/similarity.ts +2 -2
  15. package/clients/dispatch/runners/tree-sitter.js +137 -10
  16. package/clients/dispatch/runners/tree-sitter.ts +168 -13
  17. package/clients/dispatch/runners/ts-lsp.js +3 -2
  18. package/clients/dispatch/runners/ts-lsp.ts +3 -2
  19. package/clients/dispatch/runners/yaml-rule-parser.js +70 -2
  20. package/clients/dispatch/runners/yaml-rule-parser.ts +71 -2
  21. package/clients/dispatch/types.js +1 -1
  22. package/clients/dispatch/types.ts +1 -1
  23. package/clients/lsp/__tests__/service.test.js +3 -0
  24. package/clients/lsp/__tests__/service.test.ts +3 -0
  25. package/clients/lsp/client.js +42 -0
  26. package/clients/lsp/client.ts +79 -0
  27. package/clients/lsp/index.js +27 -0
  28. package/clients/lsp/index.ts +35 -0
  29. package/clients/lsp/launch.js +11 -6
  30. package/clients/lsp/launch.ts +11 -6
  31. package/clients/metrics-client.js +3 -160
  32. package/clients/metrics-client.tdr.test.js +78 -0
  33. package/clients/metrics-client.test.js +30 -43
  34. package/clients/metrics-client.test.ts +30 -54
  35. package/clients/metrics-client.ts +5 -219
  36. package/clients/metrics-history.js +33 -7
  37. package/clients/metrics-history.ts +47 -10
  38. package/clients/pipeline.js +272 -0
  39. package/clients/pipeline.ts +371 -0
  40. package/clients/sg-runner.js +21 -3
  41. package/clients/sg-runner.ts +22 -3
  42. package/clients/tree-sitter-client.js +23 -2
  43. package/clients/tree-sitter-client.ts +27 -2
  44. package/index.ts +604 -771
  45. package/package.json +1 -1
  46. package/rules/ast-grep-rules/rules/no-architecture-violation.yml +7 -4
  47. package/rules/ast-grep-rules/rules/no-single-char-var.yml +3 -3
  48. package/rules/ast-grep-rules/slop-patterns.yml +85 -62
  49. package/skills/ast-grep/SKILL.md +42 -1
  50. package/skills/lsp-navigation/SKILL.md +62 -0
  51. package/tsconfig.json +1 -1
  52. package/rules/ast-grep-rules/rules/no-console-log.yml +0 -10
  53. package/rules/ast-grep-rules/rules/no-default-export.yml +0 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lens",
3
- "version": "3.3.0",
3
+ "version": "3.6.0",
4
4
  "type": "module",
5
5
  "description": "pi extension for real-time code quality — 31 LSP servers, tree-sitter structural analysis, AST pattern matching, auto-install for TypeScript/Python tooling, duplicate detection, complexity metrics, and inline blockers with comprehensive /lens-booboo reports",
6
6
  "repository": {
@@ -9,7 +9,10 @@ note: |
9
9
  BAD: import { User } from '../models/user';
10
10
  GOOD: import { User } from '../types/user';
11
11
  rule:
12
- pattern: import { $$$ } from "$PATH"
13
- constraints:
14
- PATH:
15
- regex: ".*models.*|.*database.*|.*prisma.*"
12
+ any:
13
+ - pattern: import { $$$ } from "../models/$_"
14
+ - pattern: import { $$$ } from "../../models/$_"
15
+ - pattern: import { $$$ } from "../database/$_"
16
+ - pattern: import { $$$ } from "../../database/$_"
17
+ - pattern: import { $$$ } from "../prisma/$_"
18
+ - pattern: import { $$$ } from "../../prisma/$_"
@@ -6,7 +6,7 @@ note: |
6
6
  Single-character variable names reduce readability.
7
7
  Exception: loop counters (i, j, k, n) and underscore (_) are acceptable.
8
8
  rule:
9
- pattern: const $VAR = $VALUE
10
- constraints:
11
- VAR:
9
+ kind: variable_declarator
10
+ has:
11
+ kind: identifier
12
12
  regex: "^[a-df-hm-z]$" # Excludes i, j, k, n
@@ -23,19 +23,27 @@ rule:
23
23
  kind: while_statement
24
24
  pattern: "while ($I < $ARR.length) { $$$ }"
25
25
  ---
26
- id: ts-manual-min-max
27
- language: typescript
28
- severity: warning
29
- message: Manual min/max logic - use Math.min() or Math.max()
30
- metadata:
31
- weight: 3
32
- category: slop
33
- rule:
34
- kind: if_statement
35
- any:
36
- - pattern: "if ($A > $B) { $M = $A; } else { $M = $B; }"
37
- - pattern: "if ($A < $B) { $M = $A; } else { $M = $B; }"
38
- ---
26
+ # DISABLED: Complex block patterns don't match with current ast-grep-napi runner
27
+ # Requires implementation support for multi-statement patterns with blocks
28
+ # Consider migrating to tree-sitter for better structural matching
29
+ # id: ts-manual-min-max
30
+ # language: typescript
31
+ # severity: warning
32
+ # message: Manual min/max logic - use Math.min() or Math.max()
33
+ # metadata:
34
+ # weight: 3
35
+ # category: slop
36
+ # rule:
37
+ # any:
38
+ # # Pattern for MAX: if (a > b) result = a else result = b
39
+ # - pattern: "if ($A > $B) { $M = $A; } else { $M = $B; }"
40
+ # # Pattern for MIN: if (a < b) result = a else result = b
41
+ # - pattern: "if ($A < $B) { $M = $A; } else { $M = $B; }"
42
+ # # Pattern for MAX (reversed): if (a < b) result = b else result = a
43
+ # - pattern: "if ($A < $B) { $M = $B; } else { $M = $A; }"
44
+ # # Pattern for MIN (reversed): if (a > b) result = b else result = a
45
+ # - pattern: "if ($A > $B) { $M = $B; } else { $M = $A; }"
46
+ # ---
39
47
  id: ts-array-map-ceremony
40
48
  language: typescript
41
49
  severity: warning
@@ -129,17 +137,18 @@ rule:
129
137
  - pattern: "if ($X === null || $X === undefined) { return null; }"
130
138
  - pattern: "if ($X == null) { return null; }"
131
139
  ---
132
- id: ts-optional-chain-opportunity
133
- language: typescript
134
- severity: warning
135
- message: obj && obj.prop && obj.prop.nested - use optional chaining obj?.prop?.nested
136
- metadata:
137
- weight: 3
138
- category: slop
139
- rule:
140
- kind: binary_expression
141
- pattern: "$A && $A.$B && $A.$B.$C"
142
- ---
140
+ # DISABLED: Duplicate of prefer-optional-chain.yml which has more comprehensive patterns
141
+ # id: ts-optional-chain-opportunity
142
+ # language: typescript
143
+ # severity: warning
144
+ # message: obj && obj.prop && obj.prop.nested - use optional chaining obj?.prop?.nested
145
+ # metadata:
146
+ # weight: 3
147
+ # category: slop
148
+ # rule:
149
+ # kind: binary_expression
150
+ # pattern: "$A && $A.$B && $A.$B.$C"
151
+ # ---
143
152
  id: ts-explicit-undefined-check
144
153
  language: typescript
145
154
  severity: warning
@@ -189,19 +198,20 @@ rule:
189
198
  kind: call_expression
190
199
  pattern: "$ARR.filter($F).map($G)"
191
200
  ---
192
- id: ts-unnecessary-ternary-boolean
193
- language: typescript
194
- severity: warning
195
- message: cond ? true : false - use Boolean(cond) or cond directly
196
- metadata:
197
- weight: 2
198
- category: slop
199
- rule:
200
- kind: conditional_expression
201
- any:
202
- - pattern: "$COND ? true : false"
203
- - pattern: "$COND ? false : true"
204
- ---
201
+ # DISABLED: Pattern doesn't match with current ast-grep-napi runner
202
+ # The AST representation of boolean literals differs from string patterns
203
+ # id: ts-unnecessary-ternary-boolean
204
+ # language: typescript
205
+ # severity: warning
206
+ # message: cond ? true : false - use Boolean(cond) or cond directly
207
+ # metadata:
208
+ # weight: 2
209
+ # category: slop
210
+ # rule:
211
+ # any:
212
+ # - pattern: "$COND ? true : false"
213
+ # - pattern: "$COND ? false : true"
214
+ # ---
205
215
  id: ts-typeof-equality
206
216
  language: typescript
207
217
  severity: warning
@@ -232,12 +242,32 @@ metadata:
232
242
  weight: 2
233
243
  category: slop
234
244
  rule:
235
- kind: call_expression
236
245
  pattern: "$ARR.slice()"
237
246
  not:
238
- has:
239
- kind: arguments
247
+ pattern: "$ARR.slice($START)"
240
248
  ---
249
+ # DISABLED: nthChild is unsupported - need to rewrite without it
250
+ # id: ts-parseint-no-radix
251
+ # language: typescript
252
+ # severity: warning
253
+ # message: parseInt(x) without radix - use parseInt(x, 10)
254
+ # metadata:
255
+ # weight: 2
256
+ # category: slop
257
+ # rule:
258
+ # kind: call_expression
259
+ # all:
260
+ # - has:
261
+ # kind: identifier
262
+ # regex: ^parseInt$
263
+ # - has:
264
+ # kind: arguments
265
+ # not:
266
+ # has:
267
+ # nthChild:
268
+ # position: 2
269
+ # ---
270
+ # Rewritten rule using pattern matching instead of nthChild:
241
271
  id: ts-parseint-no-radix
242
272
  language: typescript
243
273
  severity: warning
@@ -246,17 +276,9 @@ metadata:
246
276
  weight: 2
247
277
  category: slop
248
278
  rule:
249
- kind: call_expression
250
- all:
251
- - has:
252
- kind: identifier
253
- regex: ^parseInt$
254
- - has:
255
- kind: arguments
256
- not:
257
- has:
258
- nthChild:
259
- position: 2
279
+ pattern: "parseInt($X)"
280
+ not:
281
+ pattern: "parseInt($X, $RADIX)"
260
282
  ---
261
283
  id: ts-isnan-check
262
284
  language: typescript
@@ -304,17 +326,18 @@ rule:
304
326
  kind: call_expression
305
327
  pattern: "$FN.bind(this)"
306
328
  ---
307
- id: ts-empty-array-check
308
- language: typescript
309
- severity: warning
310
- message: arr.length === 0 - use !arr.length or arr.length (truthiness)
311
- metadata:
312
- weight: 2
313
- category: slop
314
- rule:
315
- kind: binary_expression
316
- pattern: "$ARR.length === 0"
317
- ---
329
+ # DISABLED: Debatable value - arr.length === 0 is often clearer than !arr.length
330
+ # id: ts-empty-array-check
331
+ # language: typescript
332
+ # severity: warning
333
+ # message: arr.length === 0 - use !arr.length or arr.length (truthiness)
334
+ # metadata:
335
+ # weight: 2
336
+ # category: slop
337
+ # rule:
338
+ # kind: binary_expression
339
+ # pattern: "$ARR.length === 0"
340
+ # ---
318
341
  id: ts-array-every-some
319
342
  language: typescript
320
343
  severity: warning
@@ -62,6 +62,40 @@ class $CLASS($$$BASE):
62
62
  $$$BODY
63
63
  ```
64
64
 
65
+ ## Testing Tips
66
+
67
+ **Workflow: Search → Dry-run → Apply**
68
+
69
+ ```typescript
70
+ // Step 1: Verify pattern matches what you expect
71
+ ast_grep_search
72
+ pattern: "console.log($MSG)"
73
+ lang: typescript
74
+ paths: ["src/"]
75
+ // → Check the matches are correct
76
+
77
+ // Step 2: Then do dry-run replace
78
+ ast_grep_replace
79
+ pattern: "console.log($MSG)"
80
+ rewrite: "logger.debug($MSG)"
81
+ lang: typescript
82
+ paths: ["src/"]
83
+ apply: false
84
+
85
+ // Step 3: Finally apply
86
+ // apply: true
87
+ ```
88
+
89
+ **Metavariable selection guide:**
90
+ | Use | Pattern | Matches |
91
+ |-----|---------|---------|
92
+ | Single arg | `console.log($MSG)` | `console.log("hi")` |
93
+ | Multiple args | `console.log($$$ARGS)` | `console.log("hi", obj, 42)` |
94
+ | Single node | `const $X = $Y` | `const x = 1` |
95
+ | Many nodes | `const $X = $$$REST` | `const x = 1 + 2 + 3` |
96
+
97
+ **Indentation doesn't matter:** ast-grep normalizes whitespace, so tabs vs spaces work the same.
98
+
65
99
  ## Examples
66
100
 
67
101
  ```typescript
@@ -86,7 +120,12 @@ ast_grep_search
86
120
  ## Common Failures
87
121
 
88
122
  ```typescript
89
- // ❌ INVALID: Incomplete
123
+ // ❌ INVALID: Multiple AST nodes (missing parentheses)
124
+ pattern: "it\"test name\""
125
+ // ✅ VALID: Single AST node with metavariable
126
+ pattern: "it($TEST)"
127
+
128
+ // ❌ INVALID: Incomplete code
90
129
  pattern: "function $NAME("
91
130
  // ✅ VALID: Complete code
92
131
  pattern: "function $NAME($$$PARAMS) { $$$BODY }"
@@ -102,6 +141,8 @@ pattern: "console.log(.*)"
102
141
  pattern: "console.log($$$ARGS)"
103
142
  ```
104
143
 
144
+ **Error: "Multiple AST nodes detected"** → Your pattern has multiple code fragments. Use metavariables like `$TEST` instead of literal text in quotes.
145
+
105
146
  **Fallback:** If pattern fails twice → `grep -rn "pattern" src/`
106
147
 
107
148
  **Debug:** https://ast-grep.github.io/playground.html
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: lsp-navigation
3
+ description: Navigate code with IDE features - definitions, references, types, call hierarchy. Use as PRIMARY for code intelligence.
4
+ ---
5
+
6
+ # LSP Navigation
7
+
8
+ Use `lsp_navigation` as **PRIMARY** for code intelligence. Do NOT use grep/glob/ast-grep first.
9
+
10
+ **Requires:** `--lens-lsp` flag
11
+
12
+ ## When to Use (Code Intelligence)
13
+
14
+ | Question | Operation | Parameters |
15
+ |----------|-----------|------------|
16
+ | "Where is this defined?" | `definition` | filePath, line, character |
17
+ | "Find all usages" | `references` | filePath, line, character |
18
+ | "What type is this?" | `hover` | filePath, line, character |
19
+ | "What symbols in this file?" | `documentSymbol` | filePath |
20
+ | "Find symbol across project" | `workspaceSymbol` | filePath, query |
21
+ | "Who implements this interface?" | `implementation` | filePath, line, character |
22
+ | "Who calls this function?" | `prepareCallHierarchy` → `incomingCalls` | filePath, line, character |
23
+ | "What does this function call?" | `prepareCallHierarchy` → `outgoingCalls` | filePath, line, character |
24
+
25
+ ## Call Hierarchy Pattern
26
+
27
+ ```typescript
28
+ // Step 1: Prepare (get the callable item)
29
+ const items = await lsp_navigation({
30
+ operation: "prepareCallHierarchy",
31
+ filePath: "src/api.ts",
32
+ line: 42,
33
+ character: 10
34
+ });
35
+
36
+ // Step 2: Get callers (who calls this function)
37
+ const callers = await lsp_navigation({
38
+ operation: "incomingCalls",
39
+ filePath: "src/api.ts",
40
+ callHierarchyItem: items[0]
41
+ });
42
+
43
+ // Step 2: Get callees (what this function calls)
44
+ const callees = await lsp_navigation({
45
+ operation: "outgoingCalls",
46
+ filePath: "src/api.ts",
47
+ callHierarchyItem: items[0]
48
+ });
49
+ ```
50
+
51
+ ## When NOT to Use LSP
52
+
53
+ | Task | Use Instead | Why |
54
+ |------|-------------|-----|
55
+ | Find patterns (console.log) | `ast_grep_search` | Pattern matching |
56
+ | Find text/TODOs | `grep` | Text search |
57
+ | Find files by name | `glob` | File discovery |
58
+ | Read file content | `read` | Direct access |
59
+
60
+ ## Golden Rule
61
+
62
+ **Code intelligence → LSP first. Text/pattern search → grep/ast-grep.**
package/tsconfig.json CHANGED
@@ -10,5 +10,5 @@
10
10
  "types": ["node"]
11
11
  },
12
12
  "include": ["**/*.ts"],
13
- "exclude": ["node_modules", "test-lsp-files"]
13
+ "exclude": ["node_modules", "test-lsp-files", "_trigger-test.ts"]
14
14
  }
@@ -1,10 +0,0 @@
1
- id: no-console-log
2
- language: TypeScript
3
- message: "console.log found — remove or replace with proper logging"
4
- severity: warning
5
- note: |
6
- console.log statements should not be left in production code.
7
- Use a proper logging framework or remove before committing.
8
- Grade 2.8 — low complexity, improved production quality.
9
- rule:
10
- pattern: console.log($$$ARGS)
@@ -1,19 +0,0 @@
1
- id: no-default-export
2
- message: >-
3
- Use named exports instead of default exports.
4
- Named exports improve grep-ability: agents can precisely locate
5
- `export const Foo` and all `import { Foo } from` usages.
6
- severity: info
7
- language: typescript
8
- rule:
9
- pattern: export default $X
10
- note: |
11
- Named exports make code searchable for agents and humans.
12
-
13
- Before:
14
- export default function helper() { }
15
-
16
- After:
17
- export function helper() { }
18
-
19
- Exception: Entry points (index.ts) typically require default exports.