pi-lens 2.0.0 → 2.0.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 +18 -0
- package/README.md +14 -15
- package/index.ts +41 -34
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to pi-lens will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.0.1] - 2026-03-25
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **ast-grep in `/lens-booboo` was silently dropping all results** — newer ast-grep versions exit `0` with `--json` even when issues are found; fixed the exit code check.
|
|
9
|
+
- **Renamed "Design Smells" to "ast-grep"** in booboo report — the scan runs all 65 rules (security, correctness, style, design), not just design smells.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **Stronger real-time feedback messages** — all messages now use severity emoji and imperative language:
|
|
13
|
+
- `🔴 Fix N TypeScript error(s) — these must be resolved`
|
|
14
|
+
- `🧹 Remove N unused import(s) — they are dead code`
|
|
15
|
+
- `🔴 You introduced N new structural violation(s) — fix before moving on`
|
|
16
|
+
- `🟠 You introduced N new Biome violation(s) — fix before moving on`
|
|
17
|
+
- `🟡 Complexity issues — refactor when you get a chance`
|
|
18
|
+
- `🟠 This file has N duplicate block(s) — extract to shared utilities`
|
|
19
|
+
- `🔴 Do not redefine — N function(s) already exist elsewhere`
|
|
20
|
+
- **Biome fix command is now a real bash command** — `npx @biomejs/biome check --write <file>` instead of `/lens-format` (which is a pi UI command, not runnable from agent tools).
|
|
21
|
+
- **Complexity warnings skip test files in real-time** — same exclusion as lens-booboo.
|
|
22
|
+
|
|
5
23
|
## [2.0.0] - 2026-03-25
|
|
6
24
|
|
|
7
25
|
### Added
|
package/README.md
CHANGED
|
@@ -24,30 +24,29 @@ Real-time code quality feedback for [pi](https://github.com/mariozechner/pi-codi
|
|
|
24
24
|
ast-grep and Biome run in **delta mode** — only violations *introduced by the current edit* are shown. Pre-existing issues are silent. Fixed violations are acknowledged.
|
|
25
25
|
|
|
26
26
|
```
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
🔴 Fix 2 TypeScript error(s) — these must be resolved:
|
|
28
|
+
L10: Type 'string' is not assignable to type 'number'
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
no-var: Use 'const' or 'let' instead of 'var' (L23)
|
|
30
|
+
🔴 You introduced 1 new structural violation(s) — fix before moving on:
|
|
31
|
+
no-var: Use 'const' or 'let' instead of 'var' (L23)
|
|
32
32
|
→ var has function scope and can lead to unexpected hoisting behavior.
|
|
33
|
-
(18 total)
|
|
33
|
+
(18 total remaining)
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
✅ ast-grep: fixed no-console-log (-1)
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
🟠 You introduced 1 new Biome violation(s) — fix before moving on:
|
|
38
38
|
L23:5 [style/useConst] This let declares a variable that is only assigned once.
|
|
39
|
-
|
|
40
|
-
(4 total)
|
|
39
|
+
→ Auto-fixable: `npx @biomejs/biome check --write utils.ts`
|
|
40
|
+
(4 total remaining)
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
15 lines
|
|
44
|
-
→ Extract duplicated code to a shared utility function
|
|
42
|
+
🟠 This file has 1 duplicate block(s) — extract to shared utilities:
|
|
43
|
+
15 lines duplicated with helpers.ts:20
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
🔴 Do not redefine — 1 function(s) already exist elsewhere:
|
|
47
46
|
formatDate (already in helpers.ts)
|
|
48
|
-
→ Import the existing function instead
|
|
47
|
+
→ Import the existing function instead
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
🟡 Complexity issues — refactor when you get a chance:
|
|
51
50
|
⚠ Maintainability dropped to 55 — extract logic into helper functions
|
|
52
51
|
⚠ AI-style comments (6) — remove hand-holding comments
|
|
53
52
|
⚠ Many try/catch blocks (7) — consolidate error handling
|
package/index.ts
CHANGED
|
@@ -254,7 +254,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
254
254
|
});
|
|
255
255
|
|
|
256
256
|
const output = result.stdout || result.stderr || "";
|
|
257
|
-
if (output.trim() && result.status
|
|
257
|
+
if (output.trim() && result.status !== undefined) {
|
|
258
258
|
let issues: Array<{line: number; rule: string; message: string}> = [];
|
|
259
259
|
const lines = output.split("\n").filter((l: string) => l.trim());
|
|
260
260
|
|
|
@@ -279,7 +279,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
279
279
|
|
|
280
280
|
if (issues.length > 0) {
|
|
281
281
|
// UI summary (truncated)
|
|
282
|
-
let report = `[
|
|
282
|
+
let report = `[ast-grep] ${issues.length} issue(s) found:\n`;
|
|
283
283
|
for (const issue of issues.slice(0, 20)) {
|
|
284
284
|
report += ` L${issue.line}: ${issue.rule} — ${issue.message}\n`;
|
|
285
285
|
}
|
|
@@ -289,7 +289,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
289
289
|
parts.push(report);
|
|
290
290
|
|
|
291
291
|
// Full report for file
|
|
292
|
-
let fullSection = `##
|
|
292
|
+
let fullSection = `## ast-grep (Structural Issues)\n\n**${issues.length} issue(s) found**\n\n`;
|
|
293
293
|
fullSection += "| Line | Rule | Message |\n|------|------|--------|\n";
|
|
294
294
|
for (const issue of issues) {
|
|
295
295
|
fullSection += `| ${issue.line} | ${issue.rule} | ${issue.message} |\n`;
|
|
@@ -1103,18 +1103,26 @@ export default function (pi: ExtensionAPI) {
|
|
|
1103
1103
|
const otherDiags = diags.filter(d => d.code !== 6133 && d.code !== 6196);
|
|
1104
1104
|
|
|
1105
1105
|
if (unusedImports.length > 0) {
|
|
1106
|
-
lspOutput += `\n\n
|
|
1106
|
+
lspOutput += `\n\n🧹 Remove ${unusedImports.length} unused import(s) — they are dead code:\n`;
|
|
1107
1107
|
for (const d of unusedImports.slice(0, 10)) {
|
|
1108
1108
|
lspOutput += ` L${d.range.start.line + 1}: ${d.message}\n`;
|
|
1109
1109
|
}
|
|
1110
|
-
lspOutput += ` → Remove unused imports to reduce noise\n`;
|
|
1111
1110
|
}
|
|
1112
1111
|
|
|
1113
1112
|
if (otherDiags.length > 0) {
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
lspOutput +=
|
|
1113
|
+
const errors = otherDiags.filter(d => d.severity !== 2);
|
|
1114
|
+
const warnings = otherDiags.filter(d => d.severity === 2);
|
|
1115
|
+
if (errors.length > 0) {
|
|
1116
|
+
lspOutput += `\n\n🔴 Fix ${errors.length} TypeScript error(s) — these must be resolved:\n`;
|
|
1117
|
+
for (const d of errors.slice(0, 10)) {
|
|
1118
|
+
lspOutput += ` L${d.range.start.line + 1}: ${d.message}\n`;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (warnings.length > 0) {
|
|
1122
|
+
lspOutput += `\n\n🟡 ${warnings.length} TypeScript warning(s) — address before moving on:\n`;
|
|
1123
|
+
for (const d of warnings.slice(0, 10)) {
|
|
1124
|
+
lspOutput += ` L${d.range.start.line + 1}: ${d.message}\n`;
|
|
1125
|
+
}
|
|
1118
1126
|
}
|
|
1119
1127
|
}
|
|
1120
1128
|
}
|
|
@@ -1157,10 +1165,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
1157
1165
|
}
|
|
1158
1166
|
} else {
|
|
1159
1167
|
if (diags.length > 0)
|
|
1160
|
-
lspOutput += `\n\n${ruffClient.formatDiagnostics(diags)}`;
|
|
1168
|
+
lspOutput += `\n\n🟠 Fix ${diags.length} Ruff issue(s):\n${ruffClient.formatDiagnostics(diags)}`;
|
|
1161
1169
|
if (fmtReport) lspOutput += `\n\n${fmtReport}`;
|
|
1162
1170
|
if (fixable.length > 0 || hasFormatIssues) {
|
|
1163
|
-
lspOutput += `\n
|
|
1171
|
+
lspOutput += `\n → Enable --autofix-ruff to auto-fix ${fixable.length} of these on every write`;
|
|
1164
1172
|
}
|
|
1165
1173
|
}
|
|
1166
1174
|
}
|
|
@@ -1195,17 +1203,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
1195
1203
|
}
|
|
1196
1204
|
|
|
1197
1205
|
if (newViolations.length > 0) {
|
|
1198
|
-
|
|
1206
|
+
const hasFixable = newViolations.some(v => v.fix);
|
|
1207
|
+
lspOutput += `\n\n🔴 You introduced ${newViolations.length} new structural violation(s) — fix before moving on:\n`;
|
|
1199
1208
|
lspOutput += astGrepClient.formatDiagnostics(newViolations);
|
|
1209
|
+
if (hasFixable) lspOutput += `\n Some are fixable — check the → hints above`;
|
|
1200
1210
|
}
|
|
1201
1211
|
if (fixedRules.length > 0) {
|
|
1202
|
-
lspOutput += `\n\n
|
|
1212
|
+
lspOutput += `\n\n✅ ast-grep: fixed ${fixedRules.join(", ")}`;
|
|
1203
1213
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
// no change — show nothing
|
|
1207
|
-
} else if (after.length > 0) {
|
|
1208
|
-
lspOutput += `\n (${after.length} total)`;
|
|
1214
|
+
if (after.length > 0 && newViolations.length > 0) {
|
|
1215
|
+
lspOutput += `\n (${after.length} total remaining)`;
|
|
1209
1216
|
}
|
|
1210
1217
|
}
|
|
1211
1218
|
|
|
@@ -1253,17 +1260,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
1253
1260
|
} else {
|
|
1254
1261
|
if (newDiags.length > 0) {
|
|
1255
1262
|
const fixable = newDiags.filter((d) => d.fixable);
|
|
1256
|
-
lspOutput += `\n\n
|
|
1263
|
+
lspOutput += `\n\n🟠 You introduced ${newDiags.length} new Biome violation(s) — fix before moving on:\n`;
|
|
1257
1264
|
lspOutput += biomeClient.formatDiagnostics(newDiags, filePath);
|
|
1258
|
-
if (fixable.length > 0) lspOutput += `\n
|
|
1265
|
+
if (fixable.length > 0) lspOutput += `\n → Auto-fixable: \`npx @biomejs/biome check --write ${path.basename(filePath)}\``;
|
|
1259
1266
|
}
|
|
1260
1267
|
if (fixedRules.length > 0) {
|
|
1261
|
-
lspOutput += `\n\n
|
|
1268
|
+
lspOutput += `\n\n✅ Biome: fixed ${fixedRules.join(", ")}`;
|
|
1262
1269
|
}
|
|
1263
|
-
if (after.length > 0 && newDiags.length
|
|
1264
|
-
|
|
1265
|
-
} else if (after.length > 0) {
|
|
1266
|
-
lspOutput += `\n (${after.length} total)`;
|
|
1270
|
+
if (after.length > 0 && newDiags.length > 0) {
|
|
1271
|
+
lspOutput += `\n (${after.length} total remaining)`;
|
|
1267
1272
|
}
|
|
1268
1273
|
}
|
|
1269
1274
|
}
|
|
@@ -1291,11 +1296,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
1291
1296
|
if (metrics) {
|
|
1292
1297
|
const warnings = complexityClient.checkThresholds(metrics);
|
|
1293
1298
|
if (warnings.length > 0) {
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
warningReport
|
|
1299
|
+
const isTestFile = /\.(test|spec)\.[jt]sx?$/.test(filePath);
|
|
1300
|
+
if (!isTestFile) {
|
|
1301
|
+
let warningReport = `🟡 Complexity issues — refactor when you get a chance:\n`;
|
|
1302
|
+
for (const w of warnings) {
|
|
1303
|
+
warningReport += ` ⚠ ${w}\n`;
|
|
1304
|
+
}
|
|
1305
|
+
lspOutput += `\n\n${warningReport}`;
|
|
1297
1306
|
}
|
|
1298
|
-
lspOutput += `\n\n${warningReport}`;
|
|
1299
1307
|
}
|
|
1300
1308
|
}
|
|
1301
1309
|
}
|
|
@@ -1335,17 +1343,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
1335
1343
|
);
|
|
1336
1344
|
if (fileClones.length > 0) {
|
|
1337
1345
|
dbg(` jscpd: ${fileClones.length} duplicate(s) involving ${filePath}`);
|
|
1338
|
-
let dupReport =
|
|
1346
|
+
let dupReport = `🟠 This file has ${fileClones.length} duplicate block(s) — extract to shared utilities:\n`;
|
|
1339
1347
|
for (const clone of fileClones.slice(0, 3)) {
|
|
1340
1348
|
const other = path.resolve(clone.fileA) === path.resolve(filePath)
|
|
1341
1349
|
? `${path.basename(clone.fileB)}:${clone.startB}`
|
|
1342
1350
|
: `${path.basename(clone.fileA)}:${clone.startA}`;
|
|
1343
|
-
dupReport += ` ${clone.lines} lines
|
|
1351
|
+
dupReport += ` ${clone.lines} lines duplicated with ${other}\n`;
|
|
1344
1352
|
}
|
|
1345
1353
|
if (fileClones.length > 3) {
|
|
1346
1354
|
dupReport += ` ... and ${fileClones.length - 3} more\n`;
|
|
1347
1355
|
}
|
|
1348
|
-
dupReport += ` → Extract duplicated code to a shared utility function\n`;
|
|
1349
1356
|
lspOutput += `\n\n${dupReport}`;
|
|
1350
1357
|
}
|
|
1351
1358
|
}
|
|
@@ -1365,11 +1372,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
1365
1372
|
}
|
|
1366
1373
|
if (dupes.length > 0) {
|
|
1367
1374
|
dbg(` duplicate exports: ${dupes.length} found`);
|
|
1368
|
-
let exportReport =
|
|
1375
|
+
let exportReport = `🔴 Do not redefine — ${dupes.length} function(s) already exist elsewhere:\n`;
|
|
1369
1376
|
for (const dupe of dupes.slice(0, 5)) {
|
|
1370
1377
|
exportReport += ` ${dupe}\n`;
|
|
1371
1378
|
}
|
|
1372
|
-
exportReport += ` → Import the existing function instead
|
|
1379
|
+
exportReport += ` → Import the existing function instead\n`;
|
|
1373
1380
|
lspOutput += `\n\n${exportReport}`;
|
|
1374
1381
|
}
|
|
1375
1382
|
// Update cache with new exports
|
package/package.json
CHANGED