pi-lens 2.2.0 → 2.2.2
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
CHANGED
|
@@ -298,6 +298,11 @@ All notable changes to pi-lens will be documented in this file.
|
|
|
298
298
|
### Changed
|
|
299
299
|
- **Improved ast-grep tool descriptions**: Better pattern guidance to prevent overly broad searches.
|
|
300
300
|
|
|
301
|
+
## [2.2.1] - 2026-03-29
|
|
302
|
+
|
|
303
|
+
### Fixed
|
|
304
|
+
- **No auto-install**: Runners (biome, pyright) now use direct CLI commands instead of `npx`. If not installed, gracefully skip instead of attempting to download.
|
|
305
|
+
|
|
301
306
|
## [2.2.0] - 2026-03-29
|
|
302
307
|
|
|
303
308
|
### Added
|
package/README.md
CHANGED
|
@@ -16,6 +16,58 @@ pi install git:github.com/apmantza/pi-lens
|
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
+
## Dependent Tools
|
|
20
|
+
|
|
21
|
+
pi-lens works out of the box for TypeScript/JavaScript. For full language support, install these tools — **all are optional and gracefully skip if not installed**:
|
|
22
|
+
|
|
23
|
+
### JavaScript / TypeScript
|
|
24
|
+
|
|
25
|
+
| Tool | Install | What it does |
|
|
26
|
+
|------|---------|--------------|
|
|
27
|
+
| `@biomejs/biome` | `npm i -D @biomejs/biome` | Linting + formatting |
|
|
28
|
+
| `knip` | `npm i -D knip` | Dead code / unused exports |
|
|
29
|
+
| `jscpd` | `npm i -D jscpd` | Copy-paste detection |
|
|
30
|
+
| `type-coverage` | `npm i -D type-coverage` | TypeScript `any` coverage % |
|
|
31
|
+
|
|
32
|
+
### Python
|
|
33
|
+
|
|
34
|
+
| Tool | Install | What it does |
|
|
35
|
+
|------|---------|--------------|
|
|
36
|
+
| `ruff` | `pip install ruff` | Linting + formatting |
|
|
37
|
+
| `pyright` | `pip install pyright` | Type-checking (catches type errors) |
|
|
38
|
+
|
|
39
|
+
### Go
|
|
40
|
+
|
|
41
|
+
| Tool | Install | What it does |
|
|
42
|
+
|------|---------|--------------|
|
|
43
|
+
| `go` | [golang.org](https://golang.org) | Built-in `go vet` for static analysis |
|
|
44
|
+
|
|
45
|
+
### Rust
|
|
46
|
+
|
|
47
|
+
| Tool | Install | What it does |
|
|
48
|
+
|------|---------|--------------|
|
|
49
|
+
| `rust` + `clippy` | [rustup.rs](https://rustup.rs) | Linting via `cargo clippy` |
|
|
50
|
+
|
|
51
|
+
### All Languages
|
|
52
|
+
|
|
53
|
+
| Tool | Install | What it does |
|
|
54
|
+
|------|---------|--------------|
|
|
55
|
+
| `@ast-grep/cli` | `npm i -D @ast-grep/cli` | Structural pattern matching (80+ rules) |
|
|
56
|
+
|
|
57
|
+
**Example setup for a TypeScript + Python project:**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# TypeScript tooling
|
|
61
|
+
npm i -D @biomejs/biome knip jscpd type-coverage
|
|
62
|
+
|
|
63
|
+
# Python tooling
|
|
64
|
+
pip install ruff pyright
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
pi-lens automatically detects which tools are available and enables their runners accordingly.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
19
71
|
## What's New (v2.2)
|
|
20
72
|
|
|
21
73
|
### `/lens-rate` — Code Quality Scoring
|
|
@@ -384,21 +436,6 @@ Each rule includes a `message` and `note` that are shown in diagnostics, so the
|
|
|
384
436
|
|
|
385
437
|
---
|
|
386
438
|
|
|
387
|
-
## External dependencies summary
|
|
388
|
-
|
|
389
|
-
| Package | Install | Purpose |
|
|
390
|
-
|---|---|---|
|
|
391
|
-
| `@biomejs/biome` | `npm i -D @biomejs/biome` | JS/TS/CSS/JSON lint + format + autofix |
|
|
392
|
-
| `@ast-grep/cli` | `npm i -D @ast-grep/cli` | 60+ structural pattern rules |
|
|
393
|
-
| `knip` | `npm i -D knip` | Unused exports, types, unlisted deps |
|
|
394
|
-
| `jscpd` | `npm i -D jscpd` | Copy-paste / duplicate code detection |
|
|
395
|
-
| `type-coverage` | `npm i -D type-coverage` | TypeScript `any` coverage percentage |
|
|
396
|
-
| `madge` | `npm i -D madge` | Circular dependency detection |
|
|
397
|
-
| `ruff` | `pip install ruff` | Python lint + format + autofix |
|
|
398
|
-
| `pyright` | `npx pyright` (auto-installed) | Python type-checking |
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
439
|
## TypeScript LSP — tsconfig detection
|
|
403
440
|
|
|
404
441
|
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:
|
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Biome runner for dispatch system
|
|
3
|
+
*
|
|
4
|
+
* Requires: @biomejs/biome (npm install -D @biomejs/biome)
|
|
3
5
|
*/
|
|
4
6
|
import { spawnSync } from "node:child_process";
|
|
7
|
+
// Cache biome availability check
|
|
8
|
+
let biomeAvailable = null;
|
|
9
|
+
function isBiomeAvailable() {
|
|
10
|
+
if (biomeAvailable !== null)
|
|
11
|
+
return biomeAvailable;
|
|
12
|
+
// Check if biome CLI is available (do NOT auto-install via npx)
|
|
13
|
+
const check = spawnSync("biome", ["--version"], {
|
|
14
|
+
encoding: "utf-8",
|
|
15
|
+
timeout: 5000,
|
|
16
|
+
shell: true,
|
|
17
|
+
});
|
|
18
|
+
biomeAvailable = !check.error && check.status === 0;
|
|
19
|
+
return biomeAvailable;
|
|
20
|
+
}
|
|
5
21
|
const biomeRunner = {
|
|
6
22
|
id: "biome-lint",
|
|
7
23
|
appliesTo: ["jsts", "json"],
|
|
8
24
|
priority: 10,
|
|
9
25
|
enabledByDefault: true,
|
|
10
26
|
async run(ctx) {
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
encoding: "utf-8",
|
|
14
|
-
timeout: 5000,
|
|
15
|
-
shell: true,
|
|
16
|
-
});
|
|
17
|
-
if (check.error || check.status !== 0) {
|
|
27
|
+
// Skip if biome is not installed
|
|
28
|
+
if (!isBiomeAvailable()) {
|
|
18
29
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
19
30
|
}
|
|
20
|
-
// Run biome check
|
|
31
|
+
// Run biome check (use direct command, not npx)
|
|
21
32
|
const args = ctx.autofix
|
|
22
33
|
? ["check", "--write", ctx.filePath]
|
|
23
34
|
: ["check", ctx.filePath];
|
|
24
|
-
const result = spawnSync("
|
|
35
|
+
const result = spawnSync("biome", args, {
|
|
25
36
|
encoding: "utf-8",
|
|
26
37
|
timeout: 30000,
|
|
27
38
|
shell: true,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Biome runner for dispatch system
|
|
3
|
+
*
|
|
4
|
+
* Requires: @biomejs/biome (npm install -D @biomejs/biome)
|
|
3
5
|
*/
|
|
4
6
|
|
|
5
7
|
import { spawnSync } from "node:child_process";
|
|
@@ -10,6 +12,22 @@ import type {
|
|
|
10
12
|
RunnerResult,
|
|
11
13
|
} from "../types.js";
|
|
12
14
|
|
|
15
|
+
// Cache biome availability check
|
|
16
|
+
let biomeAvailable: boolean | null = null;
|
|
17
|
+
|
|
18
|
+
function isBiomeAvailable(): boolean {
|
|
19
|
+
if (biomeAvailable !== null) return biomeAvailable;
|
|
20
|
+
|
|
21
|
+
// Check if biome CLI is available (do NOT auto-install via npx)
|
|
22
|
+
const check = spawnSync("biome", ["--version"], {
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
timeout: 5000,
|
|
25
|
+
shell: true,
|
|
26
|
+
});
|
|
27
|
+
biomeAvailable = !check.error && check.status === 0;
|
|
28
|
+
return biomeAvailable;
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
const biomeRunner: RunnerDefinition = {
|
|
14
32
|
id: "biome-lint",
|
|
15
33
|
appliesTo: ["jsts", "json"],
|
|
@@ -17,23 +35,17 @@ const biomeRunner: RunnerDefinition = {
|
|
|
17
35
|
enabledByDefault: true,
|
|
18
36
|
|
|
19
37
|
async run(ctx: DispatchContext): Promise<RunnerResult> {
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
encoding: "utf-8",
|
|
23
|
-
timeout: 5000,
|
|
24
|
-
shell: true,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (check.error || check.status !== 0) {
|
|
38
|
+
// Skip if biome is not installed
|
|
39
|
+
if (!isBiomeAvailable()) {
|
|
28
40
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
29
41
|
}
|
|
30
42
|
|
|
31
|
-
// Run biome check
|
|
43
|
+
// Run biome check (use direct command, not npx)
|
|
32
44
|
const args = ctx.autofix
|
|
33
45
|
? ["check", "--write", ctx.filePath]
|
|
34
46
|
: ["check", ctx.filePath];
|
|
35
47
|
|
|
36
|
-
const result = spawnSync("
|
|
48
|
+
const result = spawnSync("biome", args, {
|
|
37
49
|
encoding: "utf-8",
|
|
38
50
|
timeout: 30000,
|
|
39
51
|
shell: true,
|
|
@@ -3,18 +3,38 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides real Python type-checking (not just linting).
|
|
5
5
|
* Catches type errors like: result: str = add(1, 2) # Type "int" not assignable to "str"
|
|
6
|
+
*
|
|
7
|
+
* Requires: pyright (pip install pyright or npm install -g pyright)
|
|
6
8
|
*/
|
|
7
9
|
import { spawnSync } from "node:child_process";
|
|
10
|
+
// Cache pyright availability check
|
|
11
|
+
let pyrightAvailable = null;
|
|
12
|
+
function isPyrightAvailable() {
|
|
13
|
+
if (pyrightAvailable !== null)
|
|
14
|
+
return pyrightAvailable;
|
|
15
|
+
// Check if pyright CLI is available (do NOT auto-install via npx)
|
|
16
|
+
const check = spawnSync("pyright", ["--version"], {
|
|
17
|
+
encoding: "utf-8",
|
|
18
|
+
timeout: 5000,
|
|
19
|
+
shell: true,
|
|
20
|
+
});
|
|
21
|
+
pyrightAvailable = !check.error && check.status === 0;
|
|
22
|
+
return pyrightAvailable;
|
|
23
|
+
}
|
|
8
24
|
const pyrightRunner = {
|
|
9
25
|
id: "pyright",
|
|
10
26
|
appliesTo: ["python"],
|
|
11
27
|
priority: 5, // Higher priority than ruff (10) - type errors are more important
|
|
12
28
|
enabledByDefault: true,
|
|
13
29
|
async run(ctx) {
|
|
14
|
-
//
|
|
15
|
-
|
|
30
|
+
// Skip if pyright is not installed
|
|
31
|
+
if (!isPyrightAvailable()) {
|
|
32
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
33
|
+
}
|
|
34
|
+
// Run pyright with JSON output (use direct command, not npx)
|
|
35
|
+
const result = spawnSync("pyright", ["--outputjson", ctx.filePath], {
|
|
16
36
|
encoding: "utf-8",
|
|
17
|
-
timeout: 60000,
|
|
37
|
+
timeout: 60000,
|
|
18
38
|
shell: true,
|
|
19
39
|
});
|
|
20
40
|
// Pyright returns non-zero when errors found, that's OK
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides real Python type-checking (not just linting).
|
|
5
5
|
* Catches type errors like: result: str = add(1, 2) # Type "int" not assignable to "str"
|
|
6
|
+
*
|
|
7
|
+
* Requires: pyright (pip install pyright or npm install -g pyright)
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import { spawnSync } from "node:child_process";
|
|
@@ -13,6 +15,22 @@ import type {
|
|
|
13
15
|
RunnerResult,
|
|
14
16
|
} from "../types.js";
|
|
15
17
|
|
|
18
|
+
// Cache pyright availability check
|
|
19
|
+
let pyrightAvailable: boolean | null = null;
|
|
20
|
+
|
|
21
|
+
function isPyrightAvailable(): boolean {
|
|
22
|
+
if (pyrightAvailable !== null) return pyrightAvailable;
|
|
23
|
+
|
|
24
|
+
// Check if pyright CLI is available (do NOT auto-install via npx)
|
|
25
|
+
const check = spawnSync("pyright", ["--version"], {
|
|
26
|
+
encoding: "utf-8",
|
|
27
|
+
timeout: 5000,
|
|
28
|
+
shell: true,
|
|
29
|
+
});
|
|
30
|
+
pyrightAvailable = !check.error && check.status === 0;
|
|
31
|
+
return pyrightAvailable;
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
const pyrightRunner: RunnerDefinition = {
|
|
17
35
|
id: "pyright",
|
|
18
36
|
appliesTo: ["python"],
|
|
@@ -20,10 +38,15 @@ const pyrightRunner: RunnerDefinition = {
|
|
|
20
38
|
enabledByDefault: true,
|
|
21
39
|
|
|
22
40
|
async run(ctx: DispatchContext): Promise<RunnerResult> {
|
|
23
|
-
//
|
|
24
|
-
|
|
41
|
+
// Skip if pyright is not installed
|
|
42
|
+
if (!isPyrightAvailable()) {
|
|
43
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Run pyright with JSON output (use direct command, not npx)
|
|
47
|
+
const result = spawnSync("pyright", ["--outputjson", ctx.filePath], {
|
|
25
48
|
encoding: "utf-8",
|
|
26
|
-
timeout: 60000,
|
|
49
|
+
timeout: 60000,
|
|
27
50
|
shell: true,
|
|
28
51
|
});
|
|
29
52
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lens",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Real-time code quality feedback for pi — TypeScript LSP, Biome, ast-grep, Ruff, complexity metrics, duplicate detection. Includes automated fix loop (/lens-booboo-fix) and interactive architectural refactoring (/lens-booboo-refactor) with browser-based interviews.",
|
|
6
6
|
"repository": {
|