pi-lens 3.3.1 → 3.6.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 (58) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +75 -196
  3. package/clients/biome-client.js +28 -0
  4. package/clients/biome-client.ts +32 -0
  5. package/clients/cache/rule-cache.js +72 -0
  6. package/clients/cache/rule-cache.ts +104 -0
  7. package/clients/dispatch/integration.js +48 -1
  8. package/clients/dispatch/integration.ts +60 -2
  9. package/clients/dispatch/plan.js +5 -2
  10. package/clients/dispatch/plan.ts +5 -2
  11. package/clients/dispatch/runners/ast-grep-napi.js +175 -56
  12. package/clients/dispatch/runners/ast-grep-napi.test.js +2 -1
  13. package/clients/dispatch/runners/ast-grep-napi.test.ts +2 -1
  14. package/clients/dispatch/runners/ast-grep-napi.ts +191 -79
  15. package/clients/dispatch/runners/biome.js +1 -2
  16. package/clients/dispatch/runners/biome.ts +1 -2
  17. package/clients/dispatch/runners/similarity.js +1 -1
  18. package/clients/dispatch/runners/similarity.ts +2 -2
  19. package/clients/dispatch/runners/tree-sitter.js +137 -10
  20. package/clients/dispatch/runners/tree-sitter.ts +168 -13
  21. package/clients/dispatch/runners/ts-lsp.js +3 -2
  22. package/clients/dispatch/runners/ts-lsp.ts +3 -2
  23. package/clients/dispatch/runners/yaml-rule-parser.js +70 -2
  24. package/clients/dispatch/runners/yaml-rule-parser.ts +71 -2
  25. package/clients/dispatch/types.js +1 -1
  26. package/clients/dispatch/types.ts +1 -1
  27. package/clients/installer/index.js +0 -21
  28. package/clients/installer/index.ts +0 -22
  29. package/clients/lsp/__tests__/service.test.js +3 -0
  30. package/clients/lsp/__tests__/service.test.ts +3 -0
  31. package/clients/lsp/client.js +42 -0
  32. package/clients/lsp/client.ts +79 -0
  33. package/clients/lsp/index.js +27 -0
  34. package/clients/lsp/index.ts +35 -0
  35. package/clients/lsp/server.js +68 -5
  36. package/clients/lsp/server.ts +75 -7
  37. package/clients/metrics-client.js +3 -160
  38. package/clients/metrics-client.test.js +30 -43
  39. package/clients/metrics-client.test.ts +30 -54
  40. package/clients/metrics-client.ts +5 -219
  41. package/clients/metrics-history.js +33 -7
  42. package/clients/metrics-history.ts +47 -10
  43. package/clients/pipeline.js +272 -0
  44. package/clients/pipeline.ts +371 -0
  45. package/clients/sg-runner.js +21 -3
  46. package/clients/sg-runner.ts +22 -3
  47. package/clients/tree-sitter-client.js +23 -2
  48. package/clients/tree-sitter-client.ts +27 -2
  49. package/index.ts +604 -824
  50. package/package.json +2 -2
  51. package/rules/ast-grep-rules/rules/no-architecture-violation.yml +7 -4
  52. package/rules/ast-grep-rules/rules/no-single-char-var.yml +3 -3
  53. package/rules/ast-grep-rules/slop-patterns.yml +85 -62
  54. package/skills/ast-grep/SKILL.md +42 -1
  55. package/skills/lsp-navigation/SKILL.md +62 -0
  56. package/tsconfig.json +1 -1
  57. package/rules/ast-grep-rules/rules/no-console-log.yml +0 -10
  58. package/rules/ast-grep-rules/rules/no-default-export.yml +0 -19
package/CHANGELOG.md CHANGED
@@ -2,6 +2,89 @@
2
2
 
3
3
  All notable changes to pi-lens will be documented in this file.
4
4
 
5
+ ## [3.6.0] - 2026-04-02
6
+
7
+ ### Added
8
+ - **LSP Call Hierarchy Support** — Added 3 new operations to `lsp_navigation` tool:
9
+ - `prepareCallHierarchy` — Get callable item at position
10
+ - `incomingCalls` — Find all functions/methods that CALL this function
11
+ - `outgoingCalls` — Find all functions/methods CALLED by this function
12
+ - Use case: "Who calls this function?" and "What does this function depend on?"
13
+ - **LSP Navigation Skill** — New built-in skill (`skills/lsp-navigation/SKILL.md`) that guides LLM on when to use LSP for code intelligence vs other tools
14
+ - **AST-Grep Skill Improvements** — Enhanced `skills/ast-grep/SKILL.md` with:
15
+ - Testing Tips section (Search → Dry-run → Apply workflow)
16
+ - Metavariable selection guide ($ vs $$$)
17
+ - Specific guidance for "Multiple AST nodes" error
18
+ - **Skills Registration** — Extension now registers `skills/` directory via `resources_discover` event, exposing both `ast-grep` and `lsp-navigation` skills to pi
19
+ - **Enhanced TDI (Technical Debt Index) with 5-factor formula** — Now captures "worst offender" functions and code unpredictability:
20
+ - **Max Cyclomatic (10%)**: Catches worst function complexity (avg hides bad apples)
21
+ - **Entropy (5%)**: Measures code unpredictability/vocabulary richness in bits
22
+ - Rebalanced weights: MI (45%), Cognitive (30%), Nesting (10%), MaxCyc (10%), Entropy (5%)
23
+ - New thresholds: MaxCyc >10 bad, >30 critical; Entropy >4.0 bits risky, >7.0 critical
24
+
25
+ ### Removed
26
+ - **TDR (Technical Debt Ratio)** — Removed orphaned metric tracking system:
27
+ - Deleted `TDREntry`, `TDRCategory` types, `tdrFindings` Map, `updateTDR()` method
28
+ - Removed `convertDiagnosticsToTDREntries()` helper and all `tdrCategory` assignments
29
+ - Deleted TDR test file
30
+ - TDI is sufficient for code health tracking; inline diagnostics provide immediate feedback
31
+
32
+ ### Changed
33
+ - **Updated `/lens-tdi` display** — Shows 5 category breakdown with descriptions:
34
+ ```
35
+ Debt breakdown:
36
+ Maintainability: 45% (MI-based)
37
+ Cognitive: 30%
38
+ Nesting: 10%
39
+ Max Cyclomatic: 10% (worst function)
40
+ Entropy: 5% (code unpredictability)
41
+ ```
42
+ - **Extended MetricSnapshot** — Added `maxCyclomatic` and `entropy` fields for historical tracking
43
+
44
+ ---
45
+
46
+ ## [3.5.0] - 2026-04-02
47
+
48
+ ### Added
49
+ - **Tree-sitter query compilation cache** — 10× performance improvement for structural analysis. Query files (`.yml`) are compiled to binary `.wasm-cache` format once and cached to disk. Subsequent loads use the compiled cache directly, reducing tree-sitter startup from ~50ms to ~5ms per query. Cache uses mtime-based invalidation — automatically recompiles when source `.yml` changes.
50
+ - **Rule cache infrastructure** (`clients/cache/`) — New disk-backed cache system with:
51
+ - `RuleCache` class for storing compiled artifacts
52
+ - mtime-based invalidation (auto-refresh when source files change)
53
+ - JSON metadata tracking for cache entries
54
+ - TTL and integrity validation
55
+
56
+ ### Fixed
57
+ - **YAML parser colon truncation** — Fixed regex-based parser that incorrectly truncated values containing colons. Changed from `split(':', 2)` to `indexOf(':')` for proper value extraction.
58
+ - **Tree-sitter rules directory resolution** — Fixed path resolution to use `ctx.cwd` instead of hardcoded `.pi-lens/rules/` path. Rules now load correctly from the actual project root regardless of where pi is invoked.
59
+ - **Tree-sitter post_filter support** — Implemented missing `post_filter` functionality for tree-sitter queries. Rules with post-filters (e.g., semantic validation for `bare-except` vs specific exception handlers) now work correctly instead of being silently skipped.
60
+ - **Event handler silent crashes** — Wrapped all event handlers in try/catch to prevent unhandled exceptions from crashing the extension silently. Errors are now logged to stderr instead of terminating the process.
61
+ - **Latency logging restored** — Fixed missing latency logging in `tool_result` handler. Runner timing data now correctly flows to `~/.pi-lens/latency.log` again.
62
+
63
+ ### Removed
64
+ - **Broken ast-grep rules** — Removed overlapping rules that were causing false positives or conflicts with tree-sitter coverage.
65
+
66
+ ---
67
+
68
+ ## [3.4.0] - 2026-04-02
69
+
70
+ ### Fixed
71
+ - **Delta mode was broken** — `dispatchLint()` created a fresh empty baseline store on every call, making delta filtering a complete no-op. Every issue looked "new" every time. Now uses a persistent session-level baseline store. First write captures baseline, subsequent writes only show NEW issues.
72
+ - **Duplicate type-checking with `--lens-lsp`** — Both the `lsp` runner (priority 4) and `ts-lsp` runner (priority 5) were calling the same LSP service for TypeScript files. `ts-lsp` now skips when `--lens-lsp` is active.
73
+
74
+ ### Added
75
+ - **Inline security rules via ast-grep-napi** — Re-enabled the ast-grep-napi runner for real-time blocking on security violations (`no-eval`, `jwt-no-verify`, `no-hardcoded-secrets`, `weak-rsa-key`, `no-open-redirect`, etc.). Only error-severity rules fire inline; warnings remain in `/lens-booboo`. Skips 5 rules already covered by tree-sitter to avoid duplicates. ~9ms execution time.
76
+ - **Pre-write duplicate detection (two layers):**
77
+ - **Exact name match** — Checks exported names in new content against the session’s cached export index. If a function/class/type already exists in another file, blocks the write: `🔴 STOP — function X already exists in utils.ts. Import instead.`
78
+ - **Structural similarity** — Parses new functions, builds AST state matrices, compares against the project index (built at session start). Functions with ≥80% structural similarity trigger a warning with the match location. Non-blocking.
79
+ - **Project similarity index at session start** — Builds 57×72 state matrices for all TS functions at session start (cached to `.pi-lens/index.json`). Makes pre-write similarity checks ~50ms instead of seconds.
80
+
81
+ ### Changed
82
+ - **Extracted post-write pipeline** — Moved the entire post-write pipeline (secrets, format, autofix, dispatch, tests, cascade diagnostics) from `index.ts` into `clients/pipeline.ts`. `index.ts` reduced from 1764 to 1439 lines.
83
+ - **Removed inline complexity warnings** — `⚠️ Complexity increased: +4 cognitive` no longer shown on every write. No agent acts on this mid-task. Complexity data still captured for `/lens-booboo` and `/lens-tdi`.
84
+ - **Simplified pre-write handler** — Removed pre-write TypeScript and LSP diagnostics checks (checked old content before write landed — post-write catches everything). Kept only complexity baseline capture and duplicate detection.
85
+
86
+ ---
87
+
5
88
  ## [3.3.1] - 2026-04-02
6
89
 
7
90
  ### Fixed
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  3. **Scans for secrets** — Blocks on hardcoded API keys, tokens, passwords
11
11
  4. **Runs linters** — Biome (TS/JS), Ruff (Python), plus structural analysis
12
12
  5. **Tree-sitter analysis** — Deep structural patterns (empty catch, eval, deep nesting, mixed async styles)
13
- 6. **Auto-installs** — TypeScript, Python, Biome, Ruff tools install automatically on first use
13
+ 6. **Auto-installs** — TypeScript, Python, Biome, Ruff, and analysis tools auto-install on first use
14
14
  7. **Only shows NEW issues** — Delta-mode tracks baselines and filters pre-existing problems
15
15
 
16
16
  **🔴 Blockers** (type errors, secrets, empty catches) appear inline and stop the agent until fixed.
@@ -28,10 +28,7 @@ pi
28
28
  # Disable auto-formatting if needed
29
29
  pi --no-autoformat
30
30
 
31
- # Full LSP mode (31 language servers)
32
- pi --lens-lsp
33
-
34
- # LSP mode (recommended for large projects)
31
+ # Full LSP mode (31 language servers) — recommended for large/multi-language projects
35
32
  pi --lens-lsp
36
33
  ```
37
34
 
@@ -131,7 +128,7 @@ Enable full Language Server Protocol support with `--lens-lsp`:
131
128
  | **Config** | YAML, JSON, Prisma |
132
129
  | **Web** | Vue, Svelte, CSS/SCSS/Sass/Less |
133
130
 
134
- **Auto-installation (4 core tools):** TypeScript, Python, and formatting tools auto-install on first use to `.pi-lens/tools/`. Other LSP servers are launched via `npx` when available or require manual installation.
131
+ **Auto-installation (8 tools):** TypeScript, Python, Biome, Ruff, and analysis tools (Madge, jscpd, ast-grep, Knip) auto-install on first use to `.pi-lens/tools/`. Other LSP servers are launched via `npx` when available or require manual installation.
135
132
 
136
133
  **Usage:**
137
134
  ```bash
@@ -156,14 +153,6 @@ See [docs/LSP_CONFIG.md](docs/LSP_CONFIG.md) for configuration options.
156
153
 
157
154
  ---
158
155
 
159
- ### Execution Modes
160
-
161
- | Mode | Flag | Description |
162
- |------|------|-------------|
163
- | **Sequential** | (default) | Runners execute one at a time |
164
-
165
- ---
166
-
167
156
  ### On every write / edit
168
157
 
169
158
  Every file write/edit triggers multiple analysis phases:
@@ -202,12 +191,12 @@ pi-lens uses a **dispatcher-runner architecture** for extensible multi-language
202
191
  | **ruff** | Python | 10 | Warning | Python linting (delta-tracked) |
203
192
  | **oxlint** | TS/JS | 12 | Warning | Fast Rust-based JS/TS linter |
204
193
  | **tree-sitter** | TS/JS, Python | 14 | Mixed | AST-based structural analysis (21 patterns) — **singleton WASM client** |
205
- | **ast-grep-napi** | TS/JS | 15 | | **Disabled by default** heavy; use `/lens-booboo` for full analysis |
194
+ | **ast-grep-napi** | TS/JS | 15 | Blocking | Security rules inline (no-eval, jwt-no-verify, no-hardcoded-secrets, etc.) |
206
195
  | **type-safety** | TS | 20 | Mixed | Switch exhaustiveness (blocking), other (warning) |
207
196
  | **shellcheck** | Shell | 20 | Warning | Bash/sh/zsh/fish linting |
208
197
  | **python-slop** | Python | 25 | Warning | AI slop detection (~40 patterns) |
209
198
  | **spellcheck** | Markdown | 30 | Warning | Typo detection in docs |
210
- | **similarity** | TS | 35 | Silent | Semantic duplicate detection (metrics only) |
199
+ | **similarity** | TS | 35 | Warning | Semantic duplicate detection (structural similarity) |
211
200
  | **architect** | All | 40 | Warning | Architectural rule violations |
212
201
  | **go-vet** | Go | 50 | Warning | Go static analysis |
213
202
  | **rust-clippy** | Rust | 50 | Warning | Rust linting |
@@ -224,7 +213,7 @@ pi-lens uses a **dispatcher-runner architecture** for extensible multi-language
224
213
  - **Warning** — Shown in `/lens-booboo`, not inline (noise reduction)
225
214
  - **Silent** — Tracked in metrics only, never shown
226
215
 
227
- **Consolidated runners:** `ts-slop` merged into `ast-grep-napi` (disabled by default) — CLI ast-grep used for full linter only
216
+ **Consolidated runners:** `ts-slop` merged into `ast-grep-napi` — CLI ast-grep used for full linter via `/lens-booboo`
228
217
 
229
218
  **Tree-sitter runner patterns** (priority 14, AST-based structural analysis):
230
219
 
@@ -244,7 +233,7 @@ Python (6 patterns):
244
233
 
245
234
  **AI Slop Detection:**
246
235
  - `python-slop` runner (priority 25): ~40 patterns for Python code quality
247
- - `ast-grep-napi` runner (priority 15): 33 slop patterns + 68 security/architecture rules for TypeScript/JavaScript (disabled by default — use `/lens-booboo` for full ast-grep analysis via CLI)
236
+ - `ast-grep-napi` runner (priority 15): Security rules fire inline (blocking); slop/architecture warnings via `/lens-booboo` only. Skips 5 rules already covered by tree-sitter.
248
237
 
249
238
  ---
250
239
 
@@ -294,7 +283,7 @@ message: "Remove console statements before production"
294
283
  severity: warning
295
284
  ```
296
285
 
297
- See [docs/ast-grep-rules.md](docs/ast-grep-rules.md) for full guide.
286
+ See [AST_GREP_RULES.md](AST_GREP_RULES.md) for full guide.
298
287
 
299
288
  ---
300
289
 
@@ -393,26 +382,20 @@ Running the full suite on every edit would be too slow. Targeted testing gives i
393
382
 
394
383
  ### Complexity Metrics
395
384
 
396
- pi-lens calculates comprehensive code quality metrics for every source file:
385
+ pi-lens tracks code quality metrics for every file:
397
386
 
398
- | Metric | Range | Description | Thresholds |
399
- |--------|-------|-------------|------------|
400
- | **Maintainability Index (MI)** | 0-100 | Composite score combining complexity, size, and structure | <20: 🔴 Unmaintainable, 20-40: 🟡 Poor, >60: ✅ Good |
401
- | **Cognitive Complexity** | 0+ | Human mental effort to understand code (nesting penalties) | >20: 🟡 Hard to understand, >50: 🔴 Very complex |
402
- | **Cyclomatic Complexity** | 1+ | Independent code paths (branch points + 1) | >10: 🟡 Complex function, >20: 🔴 Highly complex |
403
- | **Max Cyclomatic** | 1+ | Worst function in file | >10 flagged |
404
- | **Nesting Depth** | 0+ | Maximum block nesting level | >4: 🟡 Deep nesting, >6: 🔴 Excessive |
405
- | **Code Entropy** | 0-8+ bits | Shannon entropy — unpredictability of code patterns | >3.5: 🟡 Risky AI-induced complexity |
406
- | **Halstead Volume** | 0+ | Vocabulary × length — unique ops/operands | High = many different operations |
387
+ | Metric | Description | Threshold |
388
+ |--------|-------------|-----------|
389
+ | **Maintainability Index** | 0-100 composite score | >60 <20 🔴 |
390
+ | **Cognitive Complexity** | Mental effort to understand | >20 🟡 >50 🔴 |
391
+ | **Cyclomatic Complexity** | Independent code paths | >10 🟡 >20 🔴 |
392
+ | **Code Entropy** | Shannon entropy in bits | >4.0 🟡 >7.0 🔴 |
407
393
 
408
- **AI Slop Indicators:**
409
- - Low MI + high cognitive complexity + high entropy = potential AI-generated spaghetti code
410
- - Excessive comments (>40%) + low MI = hand-holding anti-patterns
411
- - Single-use helpers with high entropy = over-abstraction
394
+ **Commands:**
395
+ - `/lens-tdi` Technical Debt Index (0-100) with grades A-F
396
+ - `/lens-booboo` Full complexity table for all files
412
397
 
413
- **Usage:**
414
- - `/lens-booboo` — Shows complexity table for all files
415
- - `tool_result` — Complexity tracked per file, AI slop warnings inline
398
+ See [docs/COMPLEXITY_METRICS.md](docs/COMPLEXITY_METRICS.md) for formulas and detailed calculations.
416
399
 
417
400
  ---
418
401
 
@@ -429,7 +412,7 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
429
412
  | `knip` | `npm i -D knip` | Dead code / unused exports |
430
413
  | `jscpd` | `npm i -D jscpd` | Copy-paste detection |
431
414
  | `type-coverage` | `npm i -D type-coverage` | TypeScript `any` coverage % |
432
- | `@ast-grep/napi` | `npm i -D @ast-grep/napi` | Fast structural analysis (TS/JS) — currently disabled in realtime |
415
+ | `@ast-grep/napi` | `npm i -D @ast-grep/napi` | Fast structural analysis (TS/JS) — security rules inline, slop in booboo |
433
416
  | `@ast-grep/cli` | `npm i -D @ast-grep/cli` | Structural pattern matching (all languages) |
434
417
  | `typos-cli` | `cargo install typos-cli` | Spellcheck for Markdown |
435
418
 
@@ -465,7 +448,6 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
465
448
  | Command | Description |
466
449
  |---------|-------------|
467
450
  | `/lens-booboo` | Full codebase review (10 analysis runners) |
468
- | `/lens-format` | Apply Biome formatting |
469
451
  | `/lens-tdi` | Technical Debt Index and trends |
470
452
 
471
453
  ---
@@ -476,7 +458,6 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
476
458
  |------|---------|--------------|
477
459
  | **Standard** (default) | `pi` | Auto-formatting, TS/Python type-checking, sequential execution |
478
460
  | **Full LSP** | `pi --lens-lsp` | Real LSP servers (31 languages), sequential execution |
479
- | **Fastest** | `pi --lens-lsp` | Real LSP + full runner suite |
480
461
 
481
462
 
482
463
  ### Flag Reference
@@ -502,193 +483,90 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
502
483
  ```bash
503
484
  pi # Default: auto-format, auto-fix, built-in type-checking
504
485
  pi --lens-lsp # LSP type-checking (31 languages)
505
- pi --lens-lsp # LSP mode (recommended)
506
486
  ```
507
487
 
508
488
  ---
509
489
 
510
490
  ## TypeScript LSP — tsconfig detection
511
491
 
512
- The LSP walks up from the edited file's directory until it finds a `tsconfig.json`. If found, it uses that project's exact `compilerOptions` (paths, strict settings, lib, etc.). If not found, it falls back to sensible defaults:
513
-
514
- - `target: ES2020`
515
- - `lib: ["es2020", "dom", "dom.iterable"]`
516
- - `moduleResolution: bundler`
517
- - `strict: true`
518
-
519
- The compiler options are refreshed automatically when you switch between projects within a session.
492
+ The LSP walks up from edited files to find `tsconfig.json`, using its `compilerOptions` (paths, strict settings, etc.). Falls back to sensible defaults if not found.
520
493
 
521
494
  ---
522
495
 
523
- ## Exclusion Criteria
524
-
525
- pi-lens automatically excludes certain files from analysis to reduce noise and focus on production code.
526
-
527
- ### Test Files
528
-
529
- All runners respect test file exclusions — both in the dispatch system (`skipTestFiles: true`) and the `/lens-booboo` command.
530
-
531
- **Excluded patterns:**
532
- ```
533
- **/*.test.ts **/*.test.tsx **/*.test.js **/*.test.jsx
534
- **/*.spec.ts **/*.spec.tsx **/*.spec.js **/*.spec.jsx
535
- **/*.poc.test.ts **/*.poc.test.tsx
536
- **/test-utils.ts **/test-*.ts
537
- **/__tests__/** **/tests/** **/test/**
538
- ```
539
-
540
- **Why:** Test files intentionally duplicate patterns (test fixtures, mock setups) and have different complexity standards. Including them creates false positives.
541
-
542
- ### Build Artifacts (TypeScript Projects)
543
-
544
- In TypeScript projects (detected by `tsconfig.json` presence), compiled `.js` files are excluded:
496
+ ## Project Structure
545
497
 
546
498
  ```
547
- **/*.js **/*.jsx (when corresponding .ts/.tsx exists)
499
+ pi-lens/
500
+ ├── clients/ # Lint tools, LSP clients, formatters
501
+ ├── commands/ # /lens-booboo, /lens-format commands
502
+ ├── docs/ # Documentation
503
+ ├── rules/ # AST-grep rules
504
+ ├── skills/ # Built-in pi skills
505
+ ├── index.ts # Main extension entry point
506
+ └── package.json
548
507
  ```
549
508
 
550
- **Why:** In TS projects, `.js` files are build artifacts. Analyzing them duplicates every issue (once in source `.ts`, once in compiled `.js`).
551
-
552
- **Note:** In pure JavaScript projects (no `tsconfig.json`), `.js` files are **included** as they are the source files.
553
-
554
- ### Excluded Directories
555
-
556
- | Directory | Reason |
557
- |-----------|--------|
558
- | `node_modules/` | Third-party dependencies |
559
- | `.git/` | Version control metadata |
560
- | `dist/`, `build/` | Build outputs |
561
- | `.pi-lens/`, `.pi/` | pi agent internal files |
562
- | `.next/`, `.ruff_cache/` | Framework/build caches |
563
- | `coverage/` | Test coverage reports |
564
-
565
- ### Per-Runner Exclusion Summary
566
-
567
- | Runner | Test Files | Build Artifacts | Directories |
568
- |--------|-----------|-----------------|-------------|
569
- | **dispatch runners** | ✅ `skipTestFiles` | ✅ `.js` excluded in TS | ✅ `EXCLUDED_DIRS` |
570
- | **booboo /lens-booboo** | ✅ `shouldIncludeFile()` | ✅ `isTsProject` check | ✅ `EXCLUDED_DIRS` |
571
- | **Secrets scan** | ❌ No exclusion (security) | ❌ No exclusion | ✅ Dirs excluded |
509
+ See source for detailed structure.
572
510
 
573
511
  ---
574
512
 
575
- ## Caching Architecture
513
+ ## Skills
576
514
 
577
- pi-lens uses a multi-layer caching strategy to avoid redundant work:
515
+ pi-lens includes two built-in skills that guide the LLM on when to use specific tools:
578
516
 
579
- ### 1. Tool Availability Cache
517
+ ### ast-grep
580
518
 
581
- **Location:** `clients/tool-availability.ts`
519
+ **Purpose:** Guide AST-aware pattern matching for semantic code search/replace.
582
520
 
583
- ```
584
- ┌─────────────────────────────────────────┐
585
- │ TOOL AVAILABILITY CACHE │
586
- │ Map<toolName, {available, version}> │
587
- │ • Persisted for session lifetime │
588
- │ • Refreshed on extension restart │
589
- └─────────────────────────────────────────┘
590
- ```
591
-
592
- Avoids repeated `which`/`where` calls to check if `biome`, `ruff`, `pyright`, etc. are installed.
521
+ **When to load:** Use `/skill:ast-grep` when performing structural code searches (finding function calls, class methods, imports) or replacements across files.
593
522
 
594
- ### 2. Dispatch Baselines (Delta Mode)
523
+ **Key guidance:**
524
+ - Use `$VAR` for single nodes, `$$$` for multiple
525
+ - Patterns must be **complete valid code** (not fragments)
526
+ - **Workflow:** Search → Dry-run (`apply: false`) → Apply (`apply: true`)
527
+ - **Error "Multiple AST nodes":** Use metavariables like `it($TEST)` not raw text like `it"test"`
595
528
 
596
- **Location:** `clients/dispatch/dispatcher.ts`
529
+ ```typescript
530
+ // ✅ GOOD: Complete code with metavariables
531
+ ast_grep_search
532
+ pattern: "console.log($MSG)"
533
+ lang: typescript
534
+ paths: ["src/"]
597
535
 
598
- ```
599
- ┌─────────────────────────────────────────┐
600
- │ DISPATCH BASELINES │
601
- │ Map<filePath, Diagnostic[]> │
602
- │ • Cleared at turn start │
603
- │ • Updated after each runner execution │
604
- │ • Filters: only NEW issues shown │
605
- └─────────────────────────────────────────┘
536
+ // ❌ BAD: Incomplete pattern
537
+ pattern: "console.log(" // Missing args/body
606
538
  ```
607
539
 
608
- Delta mode tracking: first edit shows all issues, subsequent edits only show issues that weren't there before.
540
+ ### lsp-navigation
609
541
 
610
- ### 3. Client-Level Caches
542
+ **Purpose:** Guide code intelligence via Language Server Protocol.
611
543
 
612
- | Client | Cache | TTL | Purpose |
613
- |--------|-------|-----|---------|
614
- | **Knip** | `clients/cache-manager.ts` | 5 min | Dead code analysis (slow) |
615
- | **jscpd** | `clients/cache-manager.ts` | 5 min | Duplicate detection (slow) |
616
- | **Type Coverage** | In-memory | Session | `any` type percentage |
617
- | **Complexity** | In-memory | File-level | MI, cognitive complexity per file |
544
+ **When to load:** Use `/skill:lsp-navigation` for understanding code structure — definitions, references, types, call hierarchy.
618
545
 
619
- ### 4. Session Turn State
546
+ **Key guidance:**
547
+ - **LSP is PRIMARY** for code intelligence — NOT grep/glob/ast-grep
548
+ - Requires `--lens-lsp` flag
549
+ - Call hierarchy: `prepareCallHierarchy` → `incomingCalls`/`outgoingCalls`
620
550
 
621
- **Location:** `clients/cache-manager.ts`
551
+ | Task | Use LSP | Use Other |
552
+ |------|---------|-----------|
553
+ | "Where is this defined?" | `definition` | — |
554
+ | "Find all usages" | `references` | — |
555
+ | "What type is this?" | `hover` | — |
556
+ | "Who calls this function?" | `prepareCallHierarchy` → `incomingCalls` | — |
557
+ | Find patterns (console.log) | — | `ast_grep_search` |
558
+ | Find TODO comments | — | `grep` |
622
559
 
623
- ```
624
- ┌─────────────────────────────────────────┐
625
- │ TURN STATE TRACKING │
626
- Modified files this turn │
627
- Modified line ranges per file │
628
- Import changes detected │
629
- Turn cycle counter (max 10) │
630
- └─────────────────────────────────────────┘
631
- ```
560
+ ```typescript
561
+ // ✅ Code intelligence → LSP
562
+ lsp_navigation
563
+ operation: "references"
564
+ filePath: "src/utils.ts"
565
+ line: 42
566
+ character: 10
632
567
 
633
- Tracks which files were edited in the current agent turn for:
634
- - jscpd: Only re-scan modified files
635
- - Madge: Only check deps if imports changed
636
- - Cycle detection: Prevents infinite fix loops
637
-
638
- ### 5. Runner Internal Caches
639
-
640
- | Runner | Cache | Notes |
641
- |--------|-------|-------|
642
- | `ast-grep-napi` | Rule descriptions | Loaded once per session (disabled by default) |
643
- | `biome` | Tool availability | Checked once, cached |
644
- | `pyright` | Command path | Venv lookup cached |
645
- | `ruff` | Command path | Venv lookup cached |
646
-
647
- ---
648
-
649
- ## Project Structure
650
-
651
- ```
652
- pi-lens/
653
- ├── clients/ # Lint tool wrappers and utilities
654
- │ ├── bus/ # Event bus system (Phase 1)
655
- │ │ ├── bus.ts
656
- │ │ ├── events.ts
657
- │ │ └── integration.ts
658
- │ ├── dispatch/ # Dispatcher and runners
659
- │ │ ├── dispatcher.ts
660
- │ │ └── runners/ # Individual runners
661
- │ │ ├── ast-grep-napi.ts # Fast TS/JS runner (disabled by default)
662
- │ │ ├── python-slop.ts # Python slop detection
663
- │ │ ├── ts-lsp.ts # TS type checking
664
- │ │ ├── biome.ts
665
- │ │ ├── ruff.ts
666
- │ │ ├── pyright.ts
667
- │ │ ├── go-vet.ts
668
- │ │ └── rust-clippy.ts
669
- │ ├── lsp/ # LSP client system (Phase 3)
670
- │ │ ├── client.ts
671
- │ │ ├── server.ts # 31 LSP server definitions
672
- │ │ ├── language.ts
673
- │ │ ├── launch.ts
674
- │ │ └── config.ts # Custom LSP configuration
675
- │ ├── installer/ # Auto-installation (Phase 4)
676
- │ │ └── index.ts
677
- │ ├── services/ # Effect-TS services (Phase 2)
678
- │ │ ├── runner-service.ts
679
- │ │ └── effect-integration.ts
680
- │ ├── complexity-client.ts
681
- │ ├── type-safety-client.ts
682
- │ └── secrets-scanner.ts
683
- ├── commands/ # pi commands
684
- │ ├── booboo.ts
685
- │ └── fix-simplified.ts
686
- ├── docs/ # Documentation
687
- │ └── LSP_CONFIG.md # LSP configuration guide
688
- ├── rules/ # AST-grep rules
689
- │ └── ast-grep-rules/ # General structural rules
690
- ├── index.ts # Main entry point
691
- └── package.json
568
+ // Don't use LSP for text patterns
569
+ pattern: "TODO" // Use grep instead
692
570
  ```
693
571
 
694
572
  ---
@@ -699,8 +577,9 @@ See [CHANGELOG.md](CHANGELOG.md) for full history.
699
577
 
700
578
  ### Latest Highlights
701
579
 
580
+ - **Tree-sitter Query Cache:** Compiled query cache with mtime-based invalidation — 10× faster structural analysis startup
702
581
  - **LSP Support:** 31 Language Server Protocol clients (4 core auto-installed, others via npx or manual)
703
- - **NAPI Runner:** 100x faster TypeScript/JavaScript structural analysis (~9ms vs ~1200ms) — currently disabled in realtime due to stability
582
+ - **NAPI Runner:** 100x faster TypeScript/JavaScript structural analysis (~9ms vs ~1200ms) — security rules fire inline
704
583
  - **Slop Detection:** 33+ TypeScript and 40+ Python patterns for AI-generated code quality issues
705
584
 
706
585
  ---
@@ -73,6 +73,34 @@ export class BiomeClient {
73
73
  }
74
74
  return this.biomeAvailable;
75
75
  }
76
+ /**
77
+ * Ensure Biome is available, auto-installing if necessary.
78
+ * Prefer this over isAvailable() for auto-install behavior.
79
+ */
80
+ async ensureAvailable() {
81
+ if (this.biomeAvailable !== null)
82
+ return this.biomeAvailable;
83
+ // Check if already available
84
+ const result = this.spawnBiome(["--version"], 10000);
85
+ if (!result.error && result.status === 0) {
86
+ this.biomeAvailable = true;
87
+ return true;
88
+ }
89
+ // Auto-install via pi-lens installer
90
+ this.log("Biome not found, attempting auto-install...");
91
+ const { ensureTool } = await import("./installer/index.js");
92
+ const installedPath = await ensureTool("biome");
93
+ if (installedPath) {
94
+ this.log(`Biome auto-installed: ${installedPath}`);
95
+ // Set the installed path as local binary to avoid npx overhead
96
+ this.localBinaryPath = installedPath;
97
+ this.biomeAvailable = true;
98
+ return true;
99
+ }
100
+ this.log("Biome auto-install failed");
101
+ this.biomeAvailable = false;
102
+ return false;
103
+ }
76
104
  /**
77
105
  * Check if a file is supported by Biome
78
106
  */
@@ -110,6 +110,38 @@ export class BiomeClient {
110
110
  return this.biomeAvailable;
111
111
  }
112
112
 
113
+ /**
114
+ * Ensure Biome is available, auto-installing if necessary.
115
+ * Prefer this over isAvailable() for auto-install behavior.
116
+ */
117
+ async ensureAvailable(): Promise<boolean> {
118
+ if (this.biomeAvailable !== null) return this.biomeAvailable;
119
+
120
+ // Check if already available
121
+ const result = this.spawnBiome(["--version"], 10000);
122
+ if (!result.error && result.status === 0) {
123
+ this.biomeAvailable = true;
124
+ return true;
125
+ }
126
+
127
+ // Auto-install via pi-lens installer
128
+ this.log("Biome not found, attempting auto-install...");
129
+ const { ensureTool } = await import("./installer/index.js");
130
+ const installedPath = await ensureTool("biome");
131
+
132
+ if (installedPath) {
133
+ this.log(`Biome auto-installed: ${installedPath}`);
134
+ // Set the installed path as local binary to avoid npx overhead
135
+ this.localBinaryPath = installedPath;
136
+ this.biomeAvailable = true;
137
+ return true;
138
+ }
139
+
140
+ this.log("Biome auto-install failed");
141
+ this.biomeAvailable = false;
142
+ return false;
143
+ }
144
+
113
145
  /**
114
146
  * Check if a file is supported by Biome
115
147
  */
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Rule Cache for pi-lens
3
+ *
4
+ * Provides disk-based caching for parsed tree-sitter rules with
5
+ * automatic invalidation based on rule file modification times.
6
+ */
7
+ import * as crypto from "node:crypto";
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+ const CACHE_DIR = path.join(process.cwd(), ".pi-lens", "cache");
11
+ const CACHE_VERSION = "v1";
12
+ export class RuleCache {
13
+ constructor(language) {
14
+ this.cacheFile = path.join(CACHE_DIR, `${language}-rules-${CACHE_VERSION}.json`);
15
+ }
16
+ ensureCacheDir() {
17
+ if (!fs.existsSync(CACHE_DIR)) {
18
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
19
+ }
20
+ }
21
+ computeRuleHash(ruleFiles) {
22
+ const hash = crypto.createHash("sha256");
23
+ for (const file of ruleFiles.sort()) {
24
+ if (fs.existsSync(file)) {
25
+ const stat = fs.statSync(file);
26
+ hash.update(`${file}:${stat.mtimeMs}:${stat.size}`);
27
+ }
28
+ }
29
+ return hash.digest("hex").slice(0, 16);
30
+ }
31
+ get(ruleFiles) {
32
+ try {
33
+ this.ensureCacheDir();
34
+ if (!fs.existsSync(this.cacheFile))
35
+ return null;
36
+ const cached = JSON.parse(fs.readFileSync(this.cacheFile, "utf-8"));
37
+ const currentHash = this.computeRuleHash(ruleFiles);
38
+ if (cached.version !== CACHE_VERSION || cached.ruleHash !== currentHash) {
39
+ return null; // Cache invalid
40
+ }
41
+ return cached;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ set(ruleFiles, queries) {
48
+ try {
49
+ this.ensureCacheDir();
50
+ const entry = {
51
+ version: CACHE_VERSION,
52
+ timestamp: Date.now(),
53
+ ruleHash: this.computeRuleHash(ruleFiles),
54
+ queries,
55
+ };
56
+ fs.writeFileSync(this.cacheFile, JSON.stringify(entry, null, 2));
57
+ }
58
+ catch {
59
+ // Cache write failure is non-fatal
60
+ }
61
+ }
62
+ clear() {
63
+ try {
64
+ if (fs.existsSync(this.cacheFile)) {
65
+ fs.unlinkSync(this.cacheFile);
66
+ }
67
+ }
68
+ catch {
69
+ // Ignore
70
+ }
71
+ }
72
+ }