pi-lens 3.7.0 → 3.8.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.
- package/CHANGELOG.md +229 -0
- package/README.md +145 -58
- package/clients/architect-client.ts +7 -2
- package/clients/ast-grep-client.ts +7 -1
- package/clients/dispatch/plan.ts +26 -5
- package/clients/dispatch/runners/architect.ts +20 -7
- package/clients/dispatch/runners/ast-grep-napi.ts +5 -2
- package/clients/dispatch/runners/ast-grep.ts +29 -18
- package/clients/dispatch/runners/biome.ts +4 -4
- package/clients/dispatch/runners/eslint.ts +157 -0
- package/clients/dispatch/runners/golangci-lint.ts +133 -0
- package/clients/dispatch/runners/index.ts +6 -0
- package/clients/dispatch/runners/python-slop.ts +17 -7
- package/clients/dispatch/runners/rubocop.ts +141 -0
- package/clients/dispatch/runners/ruff.ts +4 -4
- package/clients/dispatch/runners/tree-sitter.ts +30 -19
- package/clients/dispatch/runners/ts-slop.ts +17 -7
- package/clients/dispatch/runners/utils/runner-helpers.ts +76 -8
- package/clients/dispatch/utils/format-utils.ts +2 -1
- package/clients/file-kinds.ts +5 -1
- package/clients/fix-scanners.ts +8 -8
- package/clients/installer/index.ts +19 -1
- package/clients/lsp/index.ts +0 -40
- package/clients/lsp/launch.ts +5 -2
- package/clients/package-root.ts +44 -0
- package/clients/pipeline.ts +179 -8
- package/clients/scan-utils.ts +20 -32
- package/clients/sg-runner.ts +7 -5
- package/clients/source-filter.ts +222 -0
- package/clients/startup-scan.ts +142 -0
- package/clients/todo-scanner.ts +44 -55
- package/clients/tree-sitter-cache.ts +315 -0
- package/clients/tree-sitter-client.ts +208 -52
- package/clients/tree-sitter-fixer.ts +217 -0
- package/clients/tree-sitter-navigator.ts +329 -0
- package/clients/tree-sitter-query-loader.ts +55 -32
- package/commands/booboo.ts +47 -35
- package/default-architect.yaml +76 -87
- package/docs/ARCHITECTURE.md +74 -0
- package/docs/AST_GREP_RULES.md +266 -0
- package/docs/COMPLEXITY_METRICS.md +120 -0
- package/docs/EXCLUSIONS.md +83 -0
- package/docs/LSP_CONFIG.md +240 -0
- package/docs/TREE_SITTER_RULES.md +340 -0
- package/docs/WRITING_NEW_AST_GREP_RULES.md +200 -0
- package/index.ts +209 -86
- package/package.json +13 -4
- package/rules/ast-grep-rules/rules/array-callback-return-js.yml +33 -0
- package/rules/ast-grep-rules/rules/array-callback-return.yml +1 -1
- package/rules/ast-grep-rules/rules/constructor-super-js.yml +22 -0
- package/rules/ast-grep-rules/rules/empty-catch-js.yml +45 -0
- package/rules/ast-grep-rules/rules/empty-catch.yml +1 -1
- package/rules/ast-grep-rules/rules/getter-return-js.yml +59 -0
- package/rules/ast-grep-rules/rules/getter-return.yml +1 -1
- package/rules/ast-grep-rules/rules/hardcoded-url-js.yml +12 -0
- package/rules/ast-grep-rules/rules/jsx-boolean-short-circuit.yml +1 -1
- package/rules/ast-grep-rules/rules/jwt-no-verify-js.yml +14 -0
- package/rules/ast-grep-rules/rules/missed-concurrency-js.yml +25 -0
- package/rules/ast-grep-rules/rules/nested-ternary-js.yml +10 -0
- package/rules/ast-grep-rules/rules/no-alert-js.yml +6 -0
- package/rules/ast-grep-rules/rules/no-architecture-violation.yml +21 -18
- package/rules/ast-grep-rules/rules/no-array-constructor-js.yml +10 -0
- package/rules/ast-grep-rules/rules/no-async-promise-executor-js.yml +15 -0
- package/rules/ast-grep-rules/rules/no-async-promise-executor.yml +1 -1
- package/rules/ast-grep-rules/rules/no-await-in-loop-js.yml +30 -0
- package/rules/ast-grep-rules/rules/no-await-in-promise-all-js.yml +20 -0
- package/rules/ast-grep-rules/rules/no-await-in-promise-all.yml +1 -1
- package/rules/ast-grep-rules/rules/no-bare-except.yml +1 -1
- package/rules/ast-grep-rules/rules/no-case-declarations-js.yml +16 -0
- package/rules/ast-grep-rules/rules/no-compare-neg-zero-js.yml +13 -0
- package/rules/ast-grep-rules/rules/no-compare-neg-zero.yml +1 -1
- package/rules/ast-grep-rules/rules/no-comparison-to-none.yml +1 -1
- package/rules/ast-grep-rules/rules/no-cond-assign-js.yml +36 -0
- package/rules/ast-grep-rules/rules/no-cond-assign.yml +1 -1
- package/rules/ast-grep-rules/rules/no-constant-condition-js.yml +25 -0
- package/rules/ast-grep-rules/rules/no-constant-condition.yml +1 -1
- package/rules/ast-grep-rules/rules/no-constructor-return-js.yml +28 -0
- package/rules/ast-grep-rules/rules/no-constructor-return.yml +1 -1
- package/rules/ast-grep-rules/rules/no-discarded-error-js.yml +25 -0
- package/rules/ast-grep-rules/rules/no-discarded-error.yml +25 -0
- package/rules/ast-grep-rules/rules/no-dupe-args-js.yml +15 -0
- package/rules/ast-grep-rules/rules/no-dupe-keys-js.yml +73 -0
- package/rules/ast-grep-rules/rules/no-extra-boolean-cast-js.yml +25 -0
- package/rules/ast-grep-rules/rules/no-hardcoded-secrets-js.yml +17 -0
- package/rules/ast-grep-rules/rules/no-implied-eval-js.yml +15 -0
- package/rules/ast-grep-rules/rules/no-inner-html-js.yml +13 -0
- package/rules/ast-grep-rules/rules/no-insecure-randomness-js.yml +20 -0
- package/rules/ast-grep-rules/rules/no-insecure-randomness.yml +1 -1
- package/rules/ast-grep-rules/rules/no-javascript-url-js.yml +11 -0
- package/rules/ast-grep-rules/rules/no-nan-comparison-js.yml +22 -0
- package/rules/ast-grep-rules/rules/no-nan-comparison.yml +22 -0
- package/rules/ast-grep-rules/rules/no-new-symbol-js.yml +8 -0
- package/rules/ast-grep-rules/rules/no-new-wrappers-js.yml +13 -0
- package/rules/ast-grep-rules/rules/no-open-redirect-js.yml +15 -0
- package/rules/ast-grep-rules/rules/no-prototype-builtins-js.yml +15 -0
- package/rules/ast-grep-rules/rules/no-prototype-builtins.yml +1 -1
- package/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +13 -0
- package/rules/ast-grep-rules/rules/no-sql-in-code.yml +1 -1
- package/rules/ast-grep-rules/rules/no-throw-string-js.yml +12 -0
- package/rules/ast-grep-rules/rules/no-throw-string.yml +1 -1
- package/rules/ast-grep-rules/rules/strict-equality-js.yml +10 -0
- package/rules/ast-grep-rules/rules/strict-inequality-js.yml +10 -0
- package/rules/ast-grep-rules/rules/toctou-js.yml +112 -0
- package/rules/ast-grep-rules/rules/toctou.yml +1 -1
- package/rules/ast-grep-rules/rules/unchecked-sync-fs-js.yml +44 -0
- package/rules/ast-grep-rules/rules/unchecked-sync-fs.yml +44 -0
- package/rules/ast-grep-rules/rules/unchecked-throwing-call-js.yml +31 -0
- package/rules/ast-grep-rules/rules/unchecked-throwing-call-python.yml +48 -0
- package/rules/ast-grep-rules/rules/unchecked-throwing-call-ruby.yml +47 -0
- package/rules/ast-grep-rules/rules/unchecked-throwing-call.yml +31 -0
- package/rules/ast-grep-rules/rules/weak-rsa-key-js.yml +15 -0
- package/rules/tree-sitter-queries/go/go-bare-error.yml +47 -0
- package/rules/tree-sitter-queries/go/go-defer-in-loop.yml +47 -0
- package/rules/tree-sitter-queries/go/go-hardcoded-secrets.yml +54 -0
- package/rules/tree-sitter-queries/python/is-vs-equals.yml +1 -1
- package/rules/tree-sitter-queries/python/python-debugger.yml +46 -0
- package/rules/tree-sitter-queries/python/python-empty-except.yml +48 -0
- package/rules/tree-sitter-queries/python/python-hardcoded-secrets.yml +44 -0
- package/rules/tree-sitter-queries/python/python-mutable-class-attr.yml +57 -0
- package/rules/tree-sitter-queries/python/python-print-statement.yml +53 -0
- package/rules/tree-sitter-queries/python/python-raise-string.yml +38 -0
- package/rules/tree-sitter-queries/python/python-unsafe-regex.yml +58 -0
- package/rules/tree-sitter-queries/ruby/ruby-debugger.yml +44 -0
- package/rules/tree-sitter-queries/ruby/ruby-empty-rescue.yml +47 -0
- package/rules/tree-sitter-queries/ruby/ruby-eval.yml +43 -0
- package/rules/tree-sitter-queries/ruby/ruby-hardcoded-secrets.yml +40 -0
- package/rules/tree-sitter-queries/ruby/ruby-open-struct.yml +48 -0
- package/rules/tree-sitter-queries/ruby/ruby-puts-statement.yml +52 -0
- package/rules/tree-sitter-queries/ruby/ruby-rescue-exception.yml +51 -0
- package/rules/tree-sitter-queries/ruby/ruby-unsafe-regex.yml +49 -0
- package/rules/tree-sitter-queries/rust/rust-clone-in-loop.yml +49 -0
- package/rules/tree-sitter-queries/rust/rust-unwrap.yml +45 -0
- package/rules/tree-sitter-queries/typescript/console-statement.yml +3 -3
- package/rules/tree-sitter-queries/typescript/hardcoded-secrets.yml +13 -27
- package/rules/tree-sitter-queries/typescript/injections.scm +40 -0
- package/rules/tree-sitter-queries/typescript/no-console-in-tests.yml +52 -0
- package/rules/tree-sitter-queries/typescript/sql-injection.yml +55 -0
- package/rules/tree-sitter-queries/typescript/unsafe-regex.yml +71 -0
- package/rules/tree-sitter-queries/typescript/variable-shadowing.yml +51 -0
- package/scripts/download-grammars.ts +155 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,235 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to pi-lens will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [3.8.1] - 2026-04-05
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **`console-statement` hijacking `no-console-in-tests`** — The keyword match for
|
|
9
|
+
`console-statement` (`pattern.includes("console")`) was catching `no-console-in-tests`
|
|
10
|
+
because both contain "console". The simpler rule always won, so both fired on every
|
|
11
|
+
console call. Fixed by excluding test-related patterns: `!pattern.includes("test")`.
|
|
12
|
+
- **`hardcoded-secrets` malformed tree-sitter query** — Had two top-level S-expression
|
|
13
|
+
patterns instead of a single union pattern `[...]`. Replaced with valid union syntax
|
|
14
|
+
and added `post_filter: check_secret_pattern` so variable names are actually filtered
|
|
15
|
+
against credential patterns. Reduced false positives from 58 → 0 on the codebase.
|
|
16
|
+
|
|
17
|
+
## [3.8.0] - 2026-04-05
|
|
18
|
+
|
|
19
|
+
### Added — Tree-sitter Expansion
|
|
20
|
+
|
|
21
|
+
- **Go, Rust, Ruby grammar support** — WASM grammars for 3 new languages downloaded at
|
|
22
|
+
install time via `scripts/download-grammars.ts`. Grammar download script added with
|
|
23
|
+
npm `download-grammars` script and postinstall hook. Tree-sitter structural analysis
|
|
24
|
+
now covers all 7 dispatch languages: TypeScript, TSX, JavaScript, Python, Go, Rust, Ruby.
|
|
25
|
+
|
|
26
|
+
- **Tree-sitter dispatch for Go/Rust/Ruby** — Dispatch runner `appliesTo` extended;
|
|
27
|
+
extension→language map replaces the brittle `endsWith` chain. Tree-sitter runner
|
|
28
|
+
added to Go, Rust, and Ruby dispatch plans.
|
|
29
|
+
|
|
30
|
+
- **Incremental parse cache (`TreeCache`)** — AST trees are cached by SHA-256 content
|
|
31
|
+
hash and mtime. Subsequent queries on the same file (same turn) skip re-parsing.
|
|
32
|
+
Cache stores up to 50 files with LRU eviction. `calculateEdit()` + `incrementalUpdate()`
|
|
33
|
+
infrastructure ready for full incremental parsing when old content is tracked.
|
|
34
|
+
|
|
35
|
+
- **AST navigator (`TreeSitterNavigator`)** — Scope-aware traversal utilities: `findParent()`,
|
|
36
|
+
`isInTryCatch()`, `isInTestBlock()`, `isInLoop()`, `getScopeChain()`, `isShadowed()`,
|
|
37
|
+
`getSiblings()`. Used by post-filters for context-aware rule evaluation.
|
|
38
|
+
|
|
39
|
+
- **Native predicate support in queries** — Query YAML files now support a `predicates:`
|
|
40
|
+
array field. Rules with inline `#eq?` / `#match?` / `#not-eq?` predicates run filtering
|
|
41
|
+
inside WASM rather than in JavaScript post-filters.
|
|
42
|
+
|
|
43
|
+
- **Inline fix hints** — Tree-sitter diagnostics now carry `fixable: true` and
|
|
44
|
+
`fixSuggestion: "remove this statement"` when `has_fix: true` in the rule. Displayed
|
|
45
|
+
as `💡 Fix: remove this statement` inline in the diagnostic output. Tree-sitter runner
|
|
46
|
+
is read-only — linters (Biome/Ruff/ESLint) own the autofix phase.
|
|
47
|
+
|
|
48
|
+
- **New post-filters** — `not_in_try_catch`, `in_try_catch`, `not_in_test_block`,
|
|
49
|
+
`not_in_function`, `check_secret_pattern`, `python_empty_except`, `ruby_empty_rescue`,
|
|
50
|
+
`name_matches_param`.
|
|
51
|
+
|
|
52
|
+
### Added — New Rules (50+)
|
|
53
|
+
|
|
54
|
+
**Structural safety (ast-grep, TypeScript + JavaScript):**
|
|
55
|
+
- `unchecked-sync-fs` — `fs.statSync/readFileSync/writeFileSync/...` outside try/catch (error)
|
|
56
|
+
- `unchecked-throwing-call` — `JSON.parse`, `new URL()`, `execSync` outside try/catch (error)
|
|
57
|
+
- `no-nan-comparison` — `x === NaN` always false, use `Number.isNaN()` (error)
|
|
58
|
+
- `no-discarded-error` — `new Error()` as standalone statement without throw (error)
|
|
59
|
+
|
|
60
|
+
**Structural safety (ast-grep, Python):**
|
|
61
|
+
- `unchecked-throwing-call-python` — `open()`, `json.loads()`, `os.stat()` etc. outside
|
|
62
|
+
try/except (error)
|
|
63
|
+
|
|
64
|
+
**Structural safety (ast-grep, Ruby):**
|
|
65
|
+
- `unchecked-throwing-call-ruby` — `File.read`, `JSON.parse`, `Integer()` etc. outside
|
|
66
|
+
begin/rescue (error)
|
|
67
|
+
|
|
68
|
+
**Tree-sitter Python rules (new):**
|
|
69
|
+
- `python-mutable-class-attr` — class-level `list`/`dict`/`set` shared across all instances (error)
|
|
70
|
+
- `python-debugger` — `breakpoint()`, `pdb.set_trace()` left in code (error)
|
|
71
|
+
- `python-print-statement` — `print()` debug output in production code (warning)
|
|
72
|
+
- `python-hardcoded-secrets` — hardcoded credential assignments (error)
|
|
73
|
+
- `python-empty-except` — except block that only does `pass` (error)
|
|
74
|
+
- `python-unsafe-regex` — `re.compile(variable)` ReDoS risk (error)
|
|
75
|
+
- `python-raise-string` — `raise "string"` is TypeError in Python 3 (error)
|
|
76
|
+
|
|
77
|
+
**Tree-sitter Ruby rules (new):**
|
|
78
|
+
- `ruby-rescue-exception` — `rescue Exception` catches SystemExit and signals (error)
|
|
79
|
+
- `ruby-empty-rescue` — rescue with no body silently swallows errors (error)
|
|
80
|
+
- `ruby-debugger` — `binding.pry` / `binding.irb` left in code (error)
|
|
81
|
+
- `ruby-puts-statement` — `puts`/`p`/`pp` debug output in production (warning)
|
|
82
|
+
- `ruby-hardcoded-secrets` — hardcoded credential assignments (error)
|
|
83
|
+
- `ruby-unsafe-regex` — `Regexp.new(variable)` ReDoS risk (error)
|
|
84
|
+
|
|
85
|
+
**Tree-sitter Go rules (new):**
|
|
86
|
+
- `go-hardcoded-secrets` — hardcoded credentials in short/var/const declarations (error)
|
|
87
|
+
|
|
88
|
+
**JavaScript coverage (38 new rules):**
|
|
89
|
+
All runtime-applicable TypeScript ast-grep rules now have JavaScript equivalents:
|
|
90
|
+
`strict-equality`, `empty-catch`, `no-throw-string`, `no-cond-assign`,
|
|
91
|
+
`no-async-promise-executor`, `toctou`, `no-hardcoded-secrets`, `no-inner-html`,
|
|
92
|
+
`no-insecure-randomness`, `no-sql-in-code`, `jwt-no-verify`, `weak-rsa-key`, and 26 more.
|
|
93
|
+
|
|
94
|
+
### Changed — Severity Upgrades
|
|
95
|
+
|
|
96
|
+
**17 ast-grep rules upgraded from `warning` to `error`** (will crash / produce wrong output):
|
|
97
|
+
`empty-catch`, `array-callback-return`, `getter-return`, `jsx-boolean-short-circuit`,
|
|
98
|
+
`no-async-promise-executor`, `no-await-in-promise-all`, `no-bare-except`,
|
|
99
|
+
`no-compare-neg-zero`, `no-cond-assign`, `no-constant-condition`,
|
|
100
|
+
`no-constructor-return`, `no-insecure-randomness`, `no-prototype-builtins`,
|
|
101
|
+
`no-sql-in-code`, `no-throw-string`, `toctou`, `no-comparison-to-none`.
|
|
102
|
+
|
|
103
|
+
**4 tree-sitter rules upgraded from `warning` to `error`**:
|
|
104
|
+
`go-defer-in-loop`, `is-vs-equals`, `rust-unwrap`, `unsafe-regex`.
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
|
|
108
|
+
- **`console-statement` duplicating `no-console-in-tests`** — `console-statement` now
|
|
109
|
+
uses `post_filter: not_in_test_block` so production and test console detection are
|
|
110
|
+
mutually exclusive.
|
|
111
|
+
|
|
112
|
+
- **`variable-shadowing` never detecting actual shadowing** — Rule now captures both
|
|
113
|
+
`@PARAM` and `@NAME`; `name_matches_param` post-filter only flags when names are
|
|
114
|
+
identical. Previously the rule fired on any variable in a nested function.
|
|
115
|
+
|
|
116
|
+
- **`isInLoop()` false positives** — `call_expression` removed from loop node type list.
|
|
117
|
+
Previously `isInLoop()` returned `true` inside any function call.
|
|
118
|
+
|
|
119
|
+
- **`injectPredicates()` inserting at wrong AST position** — Broken predicate injection
|
|
120
|
+
machinery removed. Predicates already work inline in query S-expressions.
|
|
121
|
+
|
|
122
|
+
- **`sql-injection` rule not matching `db.query()`** — Query now uses union
|
|
123
|
+
`[identifier | member_expression]` to catch both bare `query()` and `db.query()`.
|
|
124
|
+
|
|
125
|
+
- **`contains_sql_keywords` post-filter inverted logic** — Rule was skipping `sql`
|
|
126
|
+
tagged templates (the primary SQL injection vector). Post-filter removed entirely;
|
|
127
|
+
rule relies on inline `#match?` predicate.
|
|
128
|
+
|
|
129
|
+
- **`no-discarded-error` ast-grep `not: inside:` not traversing ancestors** — Required
|
|
130
|
+
`stopBy: end` in ast-grep's `inside` predicate to check all ancestors, not just the
|
|
131
|
+
direct parent. Applied to all `not: inside:` rules.
|
|
132
|
+
|
|
133
|
+
- **Go/Rust/Ruby rules silently skipped** — Runner `appliesTo` was `["jsts", "python"]`
|
|
134
|
+
only. Extended to include `go`, `rust`, `ruby`.
|
|
135
|
+
|
|
136
|
+
### Fixed (from PR #1 — alexx-ftw)
|
|
137
|
+
|
|
138
|
+
- **`process.cwd()` wrong for global npm installs** — All asset resolution (WASM grammars,
|
|
139
|
+
tree-sitter query YAMLs, ast-grep rule directories, `default-architect.yaml`) now uses
|
|
140
|
+
`resolvePackagePath(import.meta.url, ...)` which walks up from the module file to the
|
|
141
|
+
package root. Previously, running pi-lens as a globally installed extension would fail
|
|
142
|
+
to find built-in rules and grammars.
|
|
143
|
+
|
|
144
|
+
- **Session start scanning `$HOME` or generic directories** — `resolveStartupScanContext()`
|
|
145
|
+
gates all heavy startup scans (knip, jscpd, exports index, project index) behind project
|
|
146
|
+
root detection (`.git`, `package.json`, `go.mod`, etc.) and a 2000-source-file budget.
|
|
147
|
+
Pi-lens stays responsive when opened outside a real project.
|
|
148
|
+
|
|
149
|
+
- **`cachedExports` not cleared on session reset** — Export cache from the previous
|
|
150
|
+
session persisted into new sessions, causing false duplicate-export warnings.
|
|
151
|
+
|
|
152
|
+
- **`biomeClient.ensureAvailable()` at session start** — Changed to `isAvailable()` so
|
|
153
|
+
session start no longer blocks on a Biome auto-install. Installs happen lazily on
|
|
154
|
+
first file write.
|
|
155
|
+
|
|
156
|
+
- **Project index not persisted across sessions** — Index now saved to disk after build
|
|
157
|
+
via `saveIndex()`, and `isIndexFresh()` check skips rebuild when the saved index is
|
|
158
|
+
still current.
|
|
159
|
+
|
|
160
|
+
- **`tree-sitter-query-loader` only loading from `process.cwd()`** — Now loads from
|
|
161
|
+
both the user's project rules directory AND the package's built-in rules, merging
|
|
162
|
+
both sets. Project-specific rules coexist with built-in rules.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## [3.7.2] - 2026-04-05
|
|
167
|
+
|
|
168
|
+
### Added
|
|
169
|
+
- **All-clear signal** — When the pipeline runs clean (no blockers, no test failures),
|
|
170
|
+
the agent now receives a confirmation one-liner instead of silence:
|
|
171
|
+
`✓ TypeScript clean · 12/12 tests · 847ms`
|
|
172
|
+
When non-blocking warnings exist: `✓ no blockers · 3 warning(s) -> /lens-booboo · 847ms`
|
|
173
|
+
Agents can now distinguish "checks ran clean" from "checks didn't run".
|
|
174
|
+
|
|
175
|
+
### Fixed
|
|
176
|
+
- **Auto-fix message now names the tool** — `✅ Auto-fixed 3 issue(s) (eslint:2, biome:1)`
|
|
177
|
+
instead of the vague `Auto-fixed 3 issue(s)`. Agents know exactly what was corrected.
|
|
178
|
+
|
|
179
|
+
### Security
|
|
180
|
+
- **Remove `effect` dependency** — Used for 5 trivial `tryPromise` wrappers in one file,
|
|
181
|
+
never consumed via Effect's runtime. Dead dependency removed.
|
|
182
|
+
- **`--ignore-scripts` in auto-installer** — `npm install` for auto-installed tools now
|
|
183
|
+
passes `--ignore-scripts` by default. Only packages that legitimately need postinstall
|
|
184
|
+
scripts to download native binaries (`@biomejs/biome`, `@ast-grep/napi`, `esbuild`) are
|
|
185
|
+
allowlisted.
|
|
186
|
+
- **`npx -y` replaced with `npx --no`** — LSP server launch via npx no longer silently
|
|
187
|
+
downloads uncached packages. `--no` fails fast if the package isn't cached; the
|
|
188
|
+
interactive-install flow is the correct path for first-time installs.
|
|
189
|
+
- **Local-first `sg` (ast-grep) resolution** — All `sg` callers now check
|
|
190
|
+
`node_modules/.bin/sg` → global `sg` → `npx --no sg` (cache-only). No silent
|
|
191
|
+
network downloads of the ast-grep CLI.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## [3.7.2] - 2026-04-05 (previous)
|
|
196
|
+
|
|
197
|
+
### Added
|
|
198
|
+
- **ESLint `--fix` in autofix phase** — Projects with an ESLint config now have fixable
|
|
199
|
+
issues auto-corrected (import ordering, jsx style, etc.) before dispatch runs, using
|
|
200
|
+
`--fix-dry-run` to get the accurate fixed count then `--fix` to apply. Availability
|
|
201
|
+
is cached per session. Only fires on JS/TS files with an ESLint config present.
|
|
202
|
+
|
|
203
|
+
### Fixed
|
|
204
|
+
- **Misleading infinite-loop comment in biome/ruff runners** — The comment incorrectly
|
|
205
|
+
stated that writing files from runners would trigger infinite loops (formatters already
|
|
206
|
+
prove this isn't true). Updated to explain the real reason: dispatch runners report
|
|
207
|
+
issues for agent understanding; silently rewriting would leave the agent's context
|
|
208
|
+
window stale.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## [3.7.1] - 2026-04-05
|
|
213
|
+
|
|
214
|
+
### Added
|
|
215
|
+
- **ESLint dispatch runner** — Projects with `.eslintrc` / `eslint.config.js` (any variant)
|
|
216
|
+
now run ESLint automatically on every JS/TS file write. Prefers local
|
|
217
|
+
`node_modules/.bin/eslint` over global. Skips silently on projects using Biome/OxLint
|
|
218
|
+
(no ESLint config). ESLint errors (severity 2) are blocking; warnings are non-blocking.
|
|
219
|
+
|
|
220
|
+
- **golangci-lint dispatch runner** — Go projects with `.golangci.yml` / `.golangci.yaml`
|
|
221
|
+
now run golangci-lint on every `.go` file write (in addition to `go-vet`). Parses JSON
|
|
222
|
+
output. Skips when no config is present (avoids default-rule noise on non-opted-in
|
|
223
|
+
projects). 60s timeout.
|
|
224
|
+
|
|
225
|
+
- **RuboCop dispatch runner** — Ruby files (`.rb`, `.rake`, `.gemspec`, `.ru`) now run
|
|
226
|
+
RuboCop in lint-only mode on every write. Prefers `bundle exec rubocop` when a Gemfile
|
|
227
|
+
references rubocop. Fatal/error offenses are blocking; convention/refactor are warnings.
|
|
228
|
+
|
|
229
|
+
- **`ruby` file kind** — `.rb`, `.rake`, `.gemspec`, `.ru` files are now recognised as
|
|
230
|
+
`ruby` kind, enabling file-kind-gated runners and formatter detection.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
5
234
|
## [3.7.0] - 2026-04-05
|
|
6
235
|
|
|
7
236
|
### Added
|
package/README.md
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
# pi-lens
|
|
2
2
|
|
|
3
|
-
**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.
|
|
3
|
+
**pi extension for real-time code quality.** 31 LSP servers, tree-sitter structural analysis (7 languages), 112 AST pattern matching rules, auto-install for TypeScript/Python/Go/Rust/Ruby tooling, duplicate detection, complexity metrics, and inline blockers with comprehensive `/lens-booboo` reports.
|
|
4
4
|
|
|
5
5
|
## What pi-lens Does
|
|
6
6
|
|
|
7
7
|
**For every file you edit:**
|
|
8
8
|
1. **Auto-formats** — Detects and runs formatters (Biome, Prettier, Ruff, gofmt, rustfmt, etc.)
|
|
9
|
-
2. **Type-checks** — TypeScript, Python, Go, Rust (31 languages with `--lens-lsp`)
|
|
9
|
+
2. **Type-checks** — TypeScript, Python, Go, Rust, Ruby (31 languages with `--lens-lsp`)
|
|
10
10
|
3. **Scans for secrets** — Blocks on hardcoded API keys, tokens, passwords
|
|
11
|
-
4. **Runs linters** — Biome (TS/JS), Ruff (Python), plus structural analysis
|
|
12
|
-
5. **
|
|
13
|
-
6. **
|
|
14
|
-
7. **
|
|
15
|
-
|
|
16
|
-
**
|
|
11
|
+
4. **Runs linters** — Biome (TS/JS), Ruff (Python), ESLint (opt-in), plus structural analysis
|
|
12
|
+
5. **Auto-fixes** — Biome, Ruff, and ESLint safe fixes applied automatically (named per tool)
|
|
13
|
+
6. **Tree-sitter analysis** — Deep structural patterns across 7 languages (45+ patterns)
|
|
14
|
+
7. **Pre-write duplicate detection** — Blocks export redefinitions and structural similarity clones
|
|
15
|
+
8. **Auto-installs** — TypeScript, Python, Biome, Ruff, Go, Rust, Ruby tools auto-install on first use
|
|
16
|
+
9. **Only shows NEW issues** — Delta-mode tracks baselines and filters pre-existing problems
|
|
17
|
+
10. **Build artifact filtering** — Skips compiled `.js` when `.ts` sibling exists (no duplicate findings)
|
|
18
|
+
|
|
19
|
+
**Blockers** (type errors, secrets, empty catches, duplicate exports) appear inline and stop the agent until fixed.
|
|
17
20
|
**Warnings** (complexity, code smells) go to `/lens-booboo` — run it to see them all.
|
|
18
21
|
|
|
22
|
+
**All-clear signals:** When checks pass, pi-lens confirms with `✓ TypeScript clean · 12/12 tests · 847ms` so you know checks ran (not just skipped).
|
|
23
|
+
|
|
19
24
|
## Quick Start
|
|
20
25
|
|
|
21
26
|
```bash
|
|
@@ -92,26 +97,28 @@ pi-lens **automatically lints** every file you write or edit. Linters are auto-d
|
|
|
92
97
|
|--------|-----------|--------------|------|----------|
|
|
93
98
|
| **Biome** | TS/JS/JSON/CSS | Automatic | **Default** | 10 |
|
|
94
99
|
| **Ruff** | Python | Automatic | **Default** | 10 |
|
|
100
|
+
| **ESLint** | TS/JS/Vue/Svelte | Automatic (with config) | Project-configured | 11 |
|
|
95
101
|
| **oxlint** | TS/JS | Manual (`npm i -g oxlint`) | Fast alternative | 12 |
|
|
96
|
-
| **
|
|
102
|
+
| **golangci-lint** | Go | Manual (with config) | Go meta-linter | 13 |
|
|
103
|
+
| **RuboCop** | Ruby | Manual / Bundler | Ruby standard | 15 |
|
|
97
104
|
| **shellcheck** | Bash/sh/zsh/fish | Manual (`apt install shellcheck`) | Shell scripts | 20 |
|
|
98
105
|
|
|
99
106
|
(*) = Auto-installed (no manual setup required)
|
|
100
107
|
|
|
101
|
-
**Priority:** Lower numbers = run earlier. Biome/Ruff run first, followed by specialized linters.
|
|
102
|
-
|
|
103
108
|
**How it works:**
|
|
104
109
|
1. Agent writes a file
|
|
105
110
|
2. pi-lens detects linters based on config files and file type
|
|
106
|
-
3. Biome takes priority for TS/JS; Ruff takes priority for Python
|
|
107
|
-
4. Multiple linters can run on the same file (e.g., Biome + oxlint)
|
|
111
|
+
3. Biome takes priority for TS/JS; Ruff takes priority for Python; ESLint only runs when `.eslintrc` or `eslint.config.js` is present
|
|
112
|
+
4. Multiple linters can run on the same file (e.g., Biome + oxlint + ESLint)
|
|
108
113
|
5. Issues are delta-tracked (only new issues shown after first write)
|
|
114
|
+
6. **Named autofix**: Auto-fix messages show tool breakdown: `✅ Auto-fixed 3 issue(s) (eslint:2, biome:1)`
|
|
109
115
|
|
|
110
116
|
**Notes:**
|
|
111
|
-
- Biome and Ruff are **dual-purpose** (lint + format)
|
|
117
|
+
- Biome and Ruff are **dual-purpose** (lint + format + auto-fix)
|
|
118
|
+
- ESLint requires a config file (project opts in); skipped on Biome/OxLint projects
|
|
119
|
+
- golangci-lint requires `.golangci.yml` (project opts in)
|
|
112
120
|
- oxlint is a faster Rust-based alternative to ESLint
|
|
113
|
-
- ESLint only runs when `--lens-lsp` is enabled
|
|
114
|
-
- shellcheck requires manual installation on most systems
|
|
121
|
+
- ESLint LSP only runs when `--lens-lsp` is enabled; dispatch runner runs in standard mode too
|
|
115
122
|
|
|
116
123
|
---
|
|
117
124
|
|
|
@@ -137,15 +144,16 @@ pi --lens-lsp # Enable LSP
|
|
|
137
144
|
|
|
138
145
|
### `pi` vs `pi --lens-lsp`
|
|
139
146
|
|
|
140
|
-
|
|
|
147
|
+
| `pi` (Default) | `pi --lens-lsp` |
|
|
141
148
|
|---------|----------------|-----------------|
|
|
142
|
-
| **Type Checking** | Built-in TypeScriptClient | Full LSP (31 language servers) |
|
|
143
|
-
| **Auto-format** | Biome, Prettier, Ruff, etc. | Same |
|
|
144
|
-
| **Auto-fix** |
|
|
149
|
+
| **Type Checking** | Built-in TypeScriptClient, Pyright, go-vet, rust-clippy | Full LSP (31 language servers) |
|
|
150
|
+
| **Auto-format** | Biome, Prettier, Ruff, gofmt, rustfmt, etc. | Same |
|
|
151
|
+
| **Auto-fix** | Biome, Ruff, ESLint (named per tool) | Same |
|
|
145
152
|
| **Secrets scan** | Blocks on hardcoded secrets | Same |
|
|
146
|
-
| **Languages** | TypeScript, Python (built-in) | 31 languages via LSP |
|
|
153
|
+
| **Languages** | TypeScript, Python, Go, Rust, Ruby (built-in) | 31 languages via LSP |
|
|
147
154
|
| **Python** | Ruff/pyright (built-in) | Pyright LSP |
|
|
148
|
-
| **Go
|
|
155
|
+
| **Go** | go-vet, golangci-lint | Full gopls |
|
|
156
|
+
| **Rust** | rust-clippy | Full rust-analyzer |
|
|
149
157
|
|
|
150
158
|
**Recommendation:** Use `pi` for TypeScript/Python projects. Use `pi --lens-lsp` for multi-language projects or when you need full language server features.
|
|
151
159
|
|
|
@@ -160,9 +168,10 @@ Every file write/edit triggers multiple analysis phases:
|
|
|
160
168
|
**Execution flow:**
|
|
161
169
|
1. **Secrets scan** (pre-flight) — Hardcoded secrets block immediately (non-runner check)
|
|
162
170
|
2. **LSP integration** (Phase 3, with `--lens-lsp`) — Real-time type errors from language servers
|
|
163
|
-
3. **Dispatch system** — Routes file to appropriate runners by `FileKind`
|
|
171
|
+
3. **Dispatch system** — Routes file to appropriate runners by `FileKind` (TS, Python, Go, Rust, Ruby, etc.)
|
|
164
172
|
4. **Runners execute** by priority (lower = earlier). See [Runners](#runners) section for full list.
|
|
165
173
|
5. **Test runner detection** (post-write) — Detects Jest/Vitest/Pytest and runs relevant tests
|
|
174
|
+
6. **Cascade deferral** — Errors in OTHER files (caused by this edit) are tracked but not shown inline; surfaced at `turn_end` once all edits complete
|
|
166
175
|
|
|
167
176
|
**Delta mode behavior:**
|
|
168
177
|
- **First write:** All issues tracked and stored in baseline
|
|
@@ -175,7 +184,17 @@ STOP — 1 issue(s) must be fixed:
|
|
|
175
184
|
L23: var total = sum(items); — use 'let' or 'const'
|
|
176
185
|
```
|
|
177
186
|
|
|
178
|
-
|
|
187
|
+
Or when clean:
|
|
188
|
+
```
|
|
189
|
+
✓ TypeScript clean · 12/12 tests · 847ms
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Or with warnings:
|
|
193
|
+
```
|
|
194
|
+
✓ no blockers · 3 warning(s) -> /lens-booboo · 623ms
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
> **Note:** Only **blocking** issues (`ts-lsp`, `pyright` errors, `type-safety` switch errors, secrets, duplicate exports) appear inline. Warnings are tracked but not shown inline (noise reduction) — run `/lens-booboo` to see all warnings.
|
|
179
198
|
|
|
180
199
|
---
|
|
181
200
|
|
|
@@ -187,19 +206,22 @@ pi-lens uses a **dispatcher-runner architecture** for extensible multi-language
|
|
|
187
206
|
|--------|----------|----------|--------|-------------|
|
|
188
207
|
| **ts-lsp** | TypeScript | 5 | Blocking | TypeScript errors (hard stops) |
|
|
189
208
|
| **pyright** | Python | 5 | Blocking | Python type errors (hard stops) |
|
|
190
|
-
| **biome** | TS/JS | 10 | Warning | Linting
|
|
191
|
-
| **ruff** | Python | 10 | Warning | Python linting (delta-tracked) |
|
|
209
|
+
| **biome** | TS/JS/JSON/CSS | 10 | Warning | Linting + auto-fix (delta-tracked) |
|
|
210
|
+
| **ruff** | Python | 10 | Warning | Python linting + auto-fix (delta-tracked) |
|
|
211
|
+
| **eslint** | TS/JS | 11 | Warning | ESLint with auto-fix (project must have config) |
|
|
192
212
|
| **oxlint** | TS/JS | 12 | Warning | Fast Rust-based JS/TS linter |
|
|
193
|
-
| **tree-sitter** | TS/JS, Python | 14 | Mixed | AST-based structural analysis (
|
|
194
|
-
| **ast-grep-napi** | TS/JS | 15 | Blocking | Security rules inline (no-eval, jwt-no-verify, no-hardcoded-secrets, etc.) |
|
|
213
|
+
| **tree-sitter** | TS/JS, Python, Go, Rust, Ruby | 14 | Mixed | AST-based structural analysis (45+ patterns, 7 languages) — **singleton WASM client** |
|
|
214
|
+
| **ast-grep-napi** | TS/JS/Python/Go/Rust | 15 | Blocking | Security rules inline (112 patterns, no-eval, jwt-no-verify, no-hardcoded-secrets, etc.) |
|
|
195
215
|
| **type-safety** | TS | 20 | Mixed | Switch exhaustiveness (blocking), other (warning) |
|
|
196
216
|
| **shellcheck** | Shell | 20 | Warning | Bash/sh/zsh/fish linting |
|
|
197
217
|
| **python-slop** | Python | 25 | Warning | AI slop detection (~40 patterns) |
|
|
198
218
|
| **spellcheck** | Markdown | 30 | Warning | Typo detection in docs |
|
|
199
|
-
| **similarity** | TS | 35 | Warning | Semantic duplicate detection (≥90% structural similarity,
|
|
219
|
+
| **similarity** | TS | 35 | Warning | Semantic duplicate detection (≥90% structural similarity, pre-write check) |
|
|
200
220
|
| **architect** | All | 40 | Warning | Architectural rule violations |
|
|
201
221
|
| **go-vet** | Go | 50 | Warning | Go static analysis |
|
|
222
|
+
| **golangci-lint** | Go | 51 | Warning | Go meta-linter (needs .golangci.yml) |
|
|
202
223
|
| **rust-clippy** | Rust | 50 | Warning | Rust linting |
|
|
224
|
+
| **rubocop** | Ruby | 52 | Warning | Ruby linting (supports bundle exec) |
|
|
203
225
|
|
|
204
226
|
**Priority legend:**
|
|
205
227
|
- **5** — Type checkers (blocking errors)
|
|
@@ -215,25 +237,37 @@ pi-lens uses a **dispatcher-runner architecture** for extensible multi-language
|
|
|
215
237
|
|
|
216
238
|
**Consolidated runners:** `ts-slop` merged into `ast-grep-napi` — CLI ast-grep used for full linter via `/lens-booboo`
|
|
217
239
|
|
|
218
|
-
**Tree-sitter runner patterns** (priority 14, AST-based structural analysis):
|
|
240
|
+
**Tree-sitter runner patterns** (priority 14, AST-based structural analysis, 7 languages, 45+ patterns):
|
|
219
241
|
|
|
220
|
-
TypeScript/JavaScript (
|
|
221
|
-
- **Error**: empty-catch, hardcoded-secrets, eval
|
|
222
|
-
- **Warning**: debugger, await-in-loop, console-statement, long-parameter-list, nested-ternary, deep-promise-chain, mixed-async-styles, deep-nesting, constructor-super, no-dupe-class-members
|
|
242
|
+
**TypeScript/JavaScript (17 patterns):**
|
|
243
|
+
- **Error**: empty-catch, hardcoded-secrets, eval, sql-injection, unsafe-regex
|
|
244
|
+
- **Warning**: debugger, await-in-loop, console-statement (not in tests), long-parameter-list, nested-ternary, deep-promise-chain, mixed-async-styles, deep-nesting, constructor-super, no-dupe-class-members, variable-shadowing
|
|
223
245
|
|
|
224
|
-
TSX (2 patterns)
|
|
246
|
+
**TSX (2 patterns):**
|
|
225
247
|
- **Error**: dangerously-set-inner-html
|
|
226
248
|
- **Warning**: no-nested-links
|
|
227
249
|
|
|
228
|
-
Python (
|
|
229
|
-
- **Error**: bare-except, mutable-default-arg, eval-exec, unreachable-except
|
|
230
|
-
- **Warning**: wildcard-import, is-vs-equals
|
|
250
|
+
**Python (11 patterns):**
|
|
251
|
+
- **Error**: bare-except, mutable-default-arg, eval-exec, unreachable-except, python-empty-except, python-hardcoded-secrets, python-mutable-class-attr, python-unsafe-regex, python-raise-string
|
|
252
|
+
- **Warning**: wildcard-import, is-vs-equals, python-debugger, python-print-statement
|
|
253
|
+
|
|
254
|
+
**Go (3 patterns):**
|
|
255
|
+
- **Error**: go-hardcoded-secrets, go-defer-in-loop
|
|
256
|
+
- **Warning**: go-bare-error
|
|
257
|
+
|
|
258
|
+
**Rust (2 patterns):**
|
|
259
|
+
- **Error**: rust-unwrap
|
|
260
|
+
- **Warning**: rust-clone-in-loop
|
|
231
261
|
|
|
232
|
-
**
|
|
262
|
+
**Ruby (8 patterns):**
|
|
263
|
+
- **Error**: ruby-rescue-exception, ruby-empty-rescue, ruby-hardcoded-secrets, ruby-unsafe-regex, ruby-debugger
|
|
264
|
+
- **Warning**: ruby-puts-statement, ruby-eval, ruby-open-struct
|
|
233
265
|
|
|
234
|
-
**
|
|
266
|
+
**Custom tree-sitter queries:** Add `.yml` files to `.pi-lens/rules/tree-sitter-queries/{typescript,python,go,rust,ruby}/`
|
|
267
|
+
|
|
268
|
+
**AI Slop Detection:**
|
|
235
269
|
- `python-slop` runner (priority 25): ~40 patterns for Python code quality
|
|
236
|
-
- `ast-grep-napi` runner (priority 15): Security rules fire inline (blocking); slop/architecture warnings via `/lens-booboo` only. Skips
|
|
270
|
+
- `ast-grep-napi` runner (priority 15): Security rules fire inline (blocking); slop/architecture warnings via `/lens-booboo` only. Skips rules already covered by tree-sitter.
|
|
237
271
|
|
|
238
272
|
---
|
|
239
273
|
|
|
@@ -241,6 +275,27 @@ Python (6 patterns):
|
|
|
241
275
|
|
|
242
276
|
Safeguards that run **before** the dispatch system:
|
|
243
277
|
|
|
278
|
+
#### Pre-Write Duplicate Detection
|
|
279
|
+
|
|
280
|
+
Blocks the agent **before** the write/edit is applied if the new content would create problems:
|
|
281
|
+
|
|
282
|
+
**Export Duplicate Detection**
|
|
283
|
+
- **Triggers:** New `export function/class/const/type/interface` matches an existing export in another file
|
|
284
|
+
- **Blocks:** `🔴 STOP — Redefining existing export(s). Import instead`
|
|
285
|
+
- **Why:** Prevents accidental redefinitions when agent creates "helper" functions that already exist
|
|
286
|
+
|
|
287
|
+
**Structural Similarity Detection**
|
|
288
|
+
- **Triggers:** New function body is ≥90% similar to an existing utility function
|
|
289
|
+
- **Warns:** `Function 'parseData' has 94% similarity to existing utility 'parseJSON()'. Consider reusing the existing utility.`
|
|
290
|
+
- **How:** 57×72 state matrix comparison (Amain algorithm), runs via Rust core when available (~50ms)
|
|
291
|
+
- **Why:** Prevents proliferation of nearly-identical helper functions
|
|
292
|
+
|
|
293
|
+
**Build Artifact Filtering**
|
|
294
|
+
- **Problem:** Scanning both `.ts` source and `.js` output produces duplicate findings
|
|
295
|
+
- **Solution:** Source-filter module detects higher-precedence siblings (`.ts` shadows `.js`, `.vue` shadows `.js`)
|
|
296
|
+
- **Applies to:** TypeScript→JavaScript, Vue/Svelte→JavaScript, CoffeeScript→JavaScript
|
|
297
|
+
- **Result:** No duplicate diagnostics from compiled outputs
|
|
298
|
+
|
|
244
299
|
#### Secrets Scanning (Pre-flight)
|
|
245
300
|
|
|
246
301
|
Runs on every file write/edit **before** any other checks. Scans for:
|
|
@@ -292,20 +347,23 @@ See [AST_GREP_RULES.md](AST_GREP_RULES.md) for full guide.
|
|
|
292
347
|
When pi starts a new session, pi-lens performs initialization scans to establish baselines and surface existing technical debt:
|
|
293
348
|
|
|
294
349
|
**Initialization sequence:**
|
|
295
|
-
1. **Reset session state** — Clear metrics and
|
|
296
|
-
2. **
|
|
297
|
-
3. **
|
|
298
|
-
4. **
|
|
299
|
-
5. **
|
|
300
|
-
6. **
|
|
301
|
-
|
|
302
|
-
|
|
350
|
+
1. **Reset session state** — Clear metrics, complexity baselines, and cached exports
|
|
351
|
+
2. **Startup scan safety** — Detect project root (`.git`, `package.json`, `go.mod`, etc.) and skip heavy scans if not in a real project (prevents scanning `$HOME`)
|
|
352
|
+
3. **Initialize LSP** (with `--lens-lsp`) — Detect and auto-install language servers
|
|
353
|
+
4. **Pre-install TypeScript LSP** (with `--lens-lsp`) — Warm up cache for instant response
|
|
354
|
+
5. **Detect available tools** — Biome, ast-grep, Ruff, ESLint, Knip, jscpd, Madge, type-coverage, Go, Rust, Ruby
|
|
355
|
+
6. **Load architect rules** — If `architect.yml` or `.architect.yml` present
|
|
356
|
+
7. **Detect test runner** — Jest, Vitest, Pytest, etc.
|
|
357
|
+
|
|
358
|
+
**Cached scans** (with TTL):
|
|
303
359
|
| Scan | Tool | Cached | Purpose |
|
|
304
360
|
|------|------|--------|---------|
|
|
305
|
-
| **TODOs** | Internal |
|
|
306
|
-
| **Dead code** | Knip |
|
|
307
|
-
| **Duplicates** | jscpd |
|
|
308
|
-
| **
|
|
361
|
+
| **TODOs** | Internal | Baseline stored | Tech debt markers (delta reported at turn_end) |
|
|
362
|
+
| **Dead code** | Knip | 5-min TTL | Unused exports/files/deps |
|
|
363
|
+
| **Duplicates** | jscpd | 5-min TTL | Copy-paste detection |
|
|
364
|
+
| **Circular deps** | Madge | Turn-end | Import cycle detection (runs async) |
|
|
365
|
+
| **Exports** | ast-grep | Session | Function index for duplicate detection |
|
|
366
|
+
| **Project index** | Amain | Persisted to disk | Structural similarity for pre-write checks |
|
|
309
367
|
|
|
310
368
|
**Error debt tracking** (with `--error-debt` flag):
|
|
311
369
|
- If tests passed at end of previous session but fail now → **regression detected**
|
|
@@ -325,17 +383,19 @@ Full codebase analysis with **10 tracked runners** producing a comprehensive rep
|
|
|
325
383
|
|
|
326
384
|
| # | Runner | What it finds |
|
|
327
385
|
|---|--------|---------------|
|
|
328
|
-
| 1 | **ast-grep (design smells)** | Structural issues (empty catch, no-debugger, etc.) |
|
|
386
|
+
| 1 | **ast-grep (design smells)** | Structural issues (empty catch, no-debugger, unchecked throws, etc.) |
|
|
329
387
|
| 2 | **ast-grep (similar functions)** | Duplicate function patterns across files |
|
|
330
388
|
| 3 | **semantic similarity (Amain)** | 57×72 matrix semantic clones (≥90% similarity) |
|
|
331
389
|
| 4 | **complexity metrics** | Low MI, high cognitive complexity, AI slop indicators |
|
|
332
|
-
| 5 | **TODO scanner** | TODO/FIXME annotations and tech debt markers |
|
|
390
|
+
| 5 | **TODO scanner** | TODO/FIXME annotations and tech debt markers (delta mode) |
|
|
333
391
|
| 6 | **dead code (Knip)** | Unused exports, files, dependencies |
|
|
334
392
|
| 7 | **duplicate code (jscpd)** | Copy-paste blocks with line/token counts |
|
|
335
393
|
| 8 | **type coverage** | Percentage typed vs `any`, low-coverage files |
|
|
336
|
-
| 9 | **circular deps (Madge)** | Import cycles and dependency chains |
|
|
394
|
+
| 9 | **circular deps (Madge)** | Import cycles and dependency chains (turn-end async) |
|
|
337
395
|
| 10 | **architectural rules** | Layer violations, file size limits, path rules |
|
|
338
396
|
|
|
397
|
+
**Turn-end findings** — Some expensive analysis (jscpd, Madge, TODO-delta) runs asynchronously at the end of each turn and surfaces findings via context injection. Results are cached and merged into the next context event.
|
|
398
|
+
|
|
339
399
|
**Output:**
|
|
340
400
|
- **Terminal:** Progress `[1/10] runner...` with timing, summary with findings per runner
|
|
341
401
|
- **JSON:** `.pi-lens/reviews/booboo-{timestamp}.json` (structured data for AI processing)
|
|
@@ -407,12 +467,13 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
|
|
|
407
467
|
|
|
408
468
|
| Tool | Install | What it does |
|
|
409
469
|
|------|---------|--------------|
|
|
410
|
-
| `@biomejs/biome` | `npm i -D @biomejs/biome` | Linting + formatting |
|
|
470
|
+
| `@biomejs/biome` | `npm i -D @biomejs/biome` | Linting + formatting + auto-fix |
|
|
471
|
+
| `eslint` | `npm i -D eslint` | Linting with project-specific rules (requires config file) |
|
|
411
472
|
| `oxlint` | `npm i -D oxlint` | Fast Rust-based JS/TS linting |
|
|
412
473
|
| `knip` | `npm i -D knip` | Dead code / unused exports |
|
|
413
474
|
| `jscpd` | `npm i -D jscpd` | Copy-paste detection |
|
|
414
475
|
| `type-coverage` | `npm i -D type-coverage` | TypeScript `any` coverage % |
|
|
415
|
-
| `@ast-grep/napi` | `npm i -D @ast-grep/napi` | Fast structural analysis (TS/JS
|
|
476
|
+
| `@ast-grep/napi` | `npm i -D @ast-grep/napi` | Fast structural analysis — 112 patterns (TS/JS/Python/Go/Rust security rules, slop detection) |
|
|
416
477
|
| `@ast-grep/cli` | `npm i -D @ast-grep/cli` | Structural pattern matching (all languages) |
|
|
417
478
|
| `typos-cli` | `cargo install typos-cli` | Spellcheck for Markdown |
|
|
418
479
|
|
|
@@ -428,6 +489,7 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
|
|
|
428
489
|
| Tool | Install | What it does |
|
|
429
490
|
|------|---------|--------------|
|
|
430
491
|
| `go` | [golang.org](https://golang.org) | Built-in `go vet` for static analysis |
|
|
492
|
+
| `golangci-lint` | [golangci-lint.run](https://golangci-lint.run) | Meta-linter (staticcheck, errcheck, gosimple, etc.) |
|
|
431
493
|
|
|
432
494
|
### Rust
|
|
433
495
|
|
|
@@ -435,6 +497,12 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
|
|
|
435
497
|
|------|---------|--------------|
|
|
436
498
|
| `rust` + `clippy` | [rustup.rs](https://rustup.rs) | Linting via `cargo clippy` |
|
|
437
499
|
|
|
500
|
+
### Ruby
|
|
501
|
+
|
|
502
|
+
| Tool | Install | What it does |
|
|
503
|
+
|------|---------|--------------|
|
|
504
|
+
| `rubocop` | `gem install rubocop` / Bundler | Ruby linting + formatting |
|
|
505
|
+
|
|
438
506
|
### Shell
|
|
439
507
|
|
|
440
508
|
| Tool | Install | What it does |
|
|
@@ -443,6 +511,19 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
|
|
|
443
511
|
|
|
444
512
|
---
|
|
445
513
|
|
|
514
|
+
## Security Hardening
|
|
515
|
+
|
|
516
|
+
pi-lens follows npm security best practices for tool installation:
|
|
517
|
+
|
|
518
|
+
| Measure | Implementation |
|
|
519
|
+
|---------|---------------|
|
|
520
|
+
| **Post-install scripts** | `--ignore-scripts` by default; only allowlisted packages (`@biomejs/biome`, `@ast-grep/napi`, `esbuild`) can run scripts for native binary downloads |
|
|
521
|
+
| **npx behavior** | `--no` flag prevents silent downloads; fails fast if package not cached |
|
|
522
|
+
| **Tool resolution** | Local `node_modules/.bin/` preferred over global over npx |
|
|
523
|
+
| **Global install safety** | `resolvePackagePath()` uses `import.meta.url` instead of `process.cwd()` to locate built-in rules/grammars when installed globally |
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
446
527
|
## Commands
|
|
447
528
|
|
|
448
529
|
| Command | Description |
|
|
@@ -467,22 +548,28 @@ pi-lens works out of the box for TypeScript/JavaScript. For full language suppor
|
|
|
467
548
|
| `--lens-lsp` | Use real Language Server Protocol servers instead of built-in type-checking |
|
|
468
549
|
| `--lens-verbose` | Enable detailed console logging |
|
|
469
550
|
| `--no-autoformat` | Disable automatic formatting (formatting is **enabled by default**) |
|
|
470
|
-
| `--no-autofix` | Disable all auto-fixing (Biome safe fixes + Ruff autofix **enabled by default**). Unsafe fixes
|
|
551
|
+
| `--no-autofix` | Disable all auto-fixing (Biome safe fixes + Ruff + ESLint autofix **enabled by default**). Unsafe fixes are never applied automatically. |
|
|
471
552
|
| `--no-autofix-biome` | Disable Biome auto-fix only |
|
|
472
553
|
| `--no-autofix-ruff` | Disable Ruff auto-fix only |
|
|
554
|
+
| `--no-autofix-eslint` | Disable ESLint auto-fix only |
|
|
555
|
+
| `--no-eslint` | Skip ESLint linting |
|
|
473
556
|
| `--no-oxlint` | Skip Oxlint linting |
|
|
474
557
|
| `--no-shellcheck` | Skip shellcheck for shell scripts |
|
|
475
558
|
| `--no-tests` | Disable automatic test running on file write |
|
|
476
559
|
| `--no-madge` | Skip circular dependency checks |
|
|
477
560
|
| `--no-ast-grep` | Skip ast-grep structural analysis |
|
|
561
|
+
| `--no-tree-sitter` | Skip tree-sitter structural analysis |
|
|
478
562
|
| `--no-biome` | Skip Biome linting |
|
|
563
|
+
| `--no-ruff` | Skip Ruff linting |
|
|
479
564
|
| `--no-lsp` | Skip TypeScript/Python type checking |
|
|
565
|
+
| `--no-similarity` | Skip pre-write structural similarity detection |
|
|
480
566
|
| `--error-debt` | Track test regressions across sessions |
|
|
481
567
|
|
|
482
568
|
**Recommended combinations:**
|
|
483
569
|
```bash
|
|
484
570
|
pi # Default: auto-format, auto-fix, built-in type-checking
|
|
485
571
|
pi --lens-lsp # LSP type-checking (31 languages)
|
|
572
|
+
pi --no-eslint # Skip ESLint on a Biome/OxLint project
|
|
486
573
|
```
|
|
487
574
|
|
|
488
575
|
---
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import * as fs from "node:fs";
|
|
13
13
|
import * as path from "node:path";
|
|
14
14
|
import { minimatch } from "minimatch";
|
|
15
|
+
import { resolvePackagePath } from "./package-root.js";
|
|
15
16
|
|
|
16
17
|
// --- Types ---
|
|
17
18
|
|
|
@@ -91,6 +92,8 @@ export class ArchitectClient {
|
|
|
91
92
|
// Try multiple possible locations for the default config
|
|
92
93
|
const possibleDefaultPaths = [
|
|
93
94
|
path.join(projectRoot, "default-architect.yaml"),
|
|
95
|
+
path.join(projectRoot, ".pi-lens", "default-architect.yaml"),
|
|
96
|
+
resolvePackagePath(import.meta.url, "default-architect.yaml"),
|
|
94
97
|
path.join(projectRoot, "..", "default-architect.yaml"),
|
|
95
98
|
path.join(process.cwd(), "default-architect.yaml"),
|
|
96
99
|
];
|
|
@@ -170,7 +173,7 @@ export class ArchitectClient {
|
|
|
170
173
|
|
|
171
174
|
for (const check of rule.must_not) {
|
|
172
175
|
// We use 'g' to find all occurrences and correctly report line numbers
|
|
173
|
-
const regex = new RegExp(check.pattern, "
|
|
176
|
+
const regex = new RegExp(check.pattern, "gim");
|
|
174
177
|
let match: RegExpExecArray | null;
|
|
175
178
|
|
|
176
179
|
// biome-ignore lint/suspicious/noAssignInExpressions: RegExp.exec iteration
|
|
@@ -286,7 +289,9 @@ export class ArchitectClient {
|
|
|
286
289
|
) {
|
|
287
290
|
// Extract everything after "pattern:" and unquote
|
|
288
291
|
const raw = trimmed.replace(/^-?\s*pattern:\s*/, "").trim();
|
|
289
|
-
|
|
292
|
+
let unquoted = raw.replace(/^["']|["']$/g, "");
|
|
293
|
+
// Single-quoted YAML: '' is an escaped single-quote
|
|
294
|
+
if (raw.startsWith("'")) unquoted = unquoted.split("''").join("'");
|
|
290
295
|
if (unquoted) {
|
|
291
296
|
violation = { pattern: unquoted, message: "" };
|
|
292
297
|
}
|