pi-lens 2.2.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/CHANGELOG.md +198 -0
  2. package/README.md +709 -519
  3. package/clients/__tests__/file-time.test.js +216 -0
  4. package/clients/__tests__/file-time.test.ts +276 -0
  5. package/clients/__tests__/format-service.test.js +245 -0
  6. package/clients/__tests__/format-service.test.ts +339 -0
  7. package/clients/__tests__/formatters.test.js +271 -0
  8. package/clients/__tests__/formatters.test.ts +401 -0
  9. package/clients/amain-types.js +164 -0
  10. package/clients/amain-types.ts +165 -0
  11. package/clients/architect-client.js +56 -12
  12. package/clients/architect-client.ts +81 -16
  13. package/clients/ast-grep-client.js +2 -2
  14. package/clients/ast-grep-client.ts +14 -39
  15. package/clients/ast-grep-parser.ts +1 -1
  16. package/clients/ast-grep-rule-manager.js +8 -0
  17. package/clients/ast-grep-rule-manager.ts +10 -1
  18. package/clients/ast-grep-types.js +9 -0
  19. package/clients/ast-grep-types.ts +106 -0
  20. package/clients/auto-loop.js +10 -0
  21. package/clients/auto-loop.ts +14 -1
  22. package/clients/biome-client.js +81 -19
  23. package/clients/biome-client.ts +103 -22
  24. package/clients/bus/bus.js +191 -0
  25. package/clients/bus/bus.ts +251 -0
  26. package/clients/bus/events.js +214 -0
  27. package/clients/bus/events.ts +279 -0
  28. package/clients/bus/index.js +8 -0
  29. package/clients/bus/index.ts +9 -0
  30. package/clients/bus/integration.js +158 -0
  31. package/clients/bus/integration.ts +214 -0
  32. package/clients/complexity-client.js +13 -7
  33. package/clients/complexity-client.ts +13 -7
  34. package/clients/config-validator.js +465 -0
  35. package/clients/config-validator.ts +558 -0
  36. package/clients/dependency-checker.js +4 -10
  37. package/clients/dependency-checker.ts +4 -10
  38. package/clients/dispatch/__tests__/autofix-integration.test.js +245 -0
  39. package/clients/dispatch/__tests__/autofix-integration.test.ts +300 -0
  40. package/clients/dispatch/__tests__/runner-registration.test.js +236 -0
  41. package/clients/dispatch/__tests__/runner-registration.test.ts +282 -0
  42. package/clients/dispatch/bus-dispatcher.js +177 -0
  43. package/clients/dispatch/bus-dispatcher.ts +251 -0
  44. package/clients/dispatch/dispatcher.edge.test.js +82 -0
  45. package/clients/dispatch/dispatcher.edge.test.ts +100 -0
  46. package/clients/dispatch/dispatcher.format.test.js +46 -0
  47. package/clients/dispatch/dispatcher.format.test.ts +58 -0
  48. package/clients/dispatch/dispatcher.inline.test.js +74 -0
  49. package/clients/dispatch/dispatcher.inline.test.ts +93 -0
  50. package/clients/dispatch/dispatcher.js +19 -53
  51. package/clients/dispatch/dispatcher.ts +20 -67
  52. package/clients/dispatch/plan.js +9 -4
  53. package/clients/dispatch/plan.ts +9 -4
  54. package/clients/dispatch/runners/architect.js +21 -7
  55. package/clients/dispatch/runners/architect.test.js +138 -0
  56. package/clients/dispatch/runners/architect.test.ts +162 -0
  57. package/clients/dispatch/runners/architect.ts +22 -7
  58. package/clients/dispatch/runners/ast-grep-napi.js +462 -0
  59. package/clients/dispatch/runners/ast-grep-napi.test.js +111 -0
  60. package/clients/dispatch/runners/ast-grep-napi.test.ts +133 -0
  61. package/clients/dispatch/runners/ast-grep-napi.ts +506 -0
  62. package/clients/dispatch/runners/ast-grep.js +62 -19
  63. package/clients/dispatch/runners/ast-grep.ts +70 -18
  64. package/clients/dispatch/runners/biome.js +29 -53
  65. package/clients/dispatch/runners/biome.ts +29 -63
  66. package/clients/dispatch/runners/config-validation.js +67 -0
  67. package/clients/dispatch/runners/config-validation.ts +82 -0
  68. package/clients/dispatch/runners/go-vet.js +4 -28
  69. package/clients/dispatch/runners/go-vet.ts +4 -32
  70. package/clients/dispatch/runners/index.js +30 -10
  71. package/clients/dispatch/runners/index.ts +30 -10
  72. package/clients/dispatch/runners/oxlint.js +141 -0
  73. package/clients/dispatch/runners/oxlint.test.js +230 -0
  74. package/clients/dispatch/runners/oxlint.test.ts +303 -0
  75. package/clients/dispatch/runners/oxlint.ts +175 -0
  76. package/clients/dispatch/runners/pyright.js +40 -70
  77. package/clients/dispatch/runners/pyright.test.js +16 -2
  78. package/clients/dispatch/runners/pyright.test.ts +14 -2
  79. package/clients/dispatch/runners/pyright.ts +48 -91
  80. package/clients/dispatch/runners/python-slop.js +97 -0
  81. package/clients/dispatch/runners/python-slop.test.js +203 -0
  82. package/clients/dispatch/runners/python-slop.test.ts +298 -0
  83. package/clients/dispatch/runners/python-slop.ts +124 -0
  84. package/clients/dispatch/runners/ruff.js +18 -71
  85. package/clients/dispatch/runners/ruff.ts +19 -79
  86. package/clients/dispatch/runners/rust-clippy.js +28 -32
  87. package/clients/dispatch/runners/rust-clippy.ts +29 -31
  88. package/clients/dispatch/runners/scan_codebase.test.js +89 -0
  89. package/clients/dispatch/runners/scan_codebase.test.ts +105 -0
  90. package/clients/dispatch/runners/shellcheck.js +147 -0
  91. package/clients/dispatch/runners/shellcheck.test.js +98 -0
  92. package/clients/dispatch/runners/shellcheck.test.ts +129 -0
  93. package/clients/dispatch/runners/shellcheck.ts +188 -0
  94. package/clients/dispatch/runners/similarity.js +230 -0
  95. package/clients/dispatch/runners/similarity.ts +339 -0
  96. package/clients/dispatch/runners/spellcheck.js +106 -0
  97. package/clients/dispatch/runners/spellcheck.test.js +158 -0
  98. package/clients/dispatch/runners/spellcheck.test.ts +214 -0
  99. package/clients/dispatch/runners/spellcheck.ts +136 -0
  100. package/clients/dispatch/runners/tree-sitter.js +107 -0
  101. package/clients/dispatch/runners/tree-sitter.ts +135 -0
  102. package/clients/dispatch/runners/ts-lsp.js +104 -33
  103. package/clients/dispatch/runners/ts-lsp.ts +120 -38
  104. package/clients/dispatch/runners/ts-slop.js +113 -0
  105. package/clients/dispatch/runners/ts-slop.test.js +180 -0
  106. package/clients/dispatch/runners/ts-slop.test.ts +230 -0
  107. package/clients/dispatch/runners/ts-slop.ts +142 -0
  108. package/clients/dispatch/runners/utils/diagnostic-parsers.js +134 -0
  109. package/clients/dispatch/runners/utils/diagnostic-parsers.ts +186 -0
  110. package/clients/dispatch/runners/utils/runner-helpers.js +115 -0
  111. package/clients/dispatch/runners/utils/runner-helpers.ts +167 -0
  112. package/clients/dispatch/runners/utils.js +2 -4
  113. package/clients/dispatch/runners/utils.ts +2 -4
  114. package/clients/dispatch/types.ts +1 -1
  115. package/clients/dispatch/utils/format-utils.js +49 -0
  116. package/clients/dispatch/utils/format-utils.ts +60 -0
  117. package/clients/dogfood.test.js +201 -0
  118. package/clients/dogfood.test.ts +269 -0
  119. package/clients/file-time.js +152 -0
  120. package/clients/file-time.ts +208 -0
  121. package/clients/file-utils.js +40 -0
  122. package/clients/file-utils.ts +44 -0
  123. package/clients/fix-scanners.js +10 -20
  124. package/clients/fix-scanners.ts +10 -22
  125. package/clients/format-service.js +172 -0
  126. package/clients/format-service.ts +254 -0
  127. package/clients/formatters.js +435 -0
  128. package/clients/formatters.ts +508 -0
  129. package/clients/go-client.js +5 -14
  130. package/clients/go-client.ts +5 -13
  131. package/clients/installer/index.js +356 -0
  132. package/clients/installer/index.ts +426 -0
  133. package/clients/jscpd-client.js +11 -9
  134. package/clients/jscpd-client.ts +12 -8
  135. package/clients/knip-client.js +3 -7
  136. package/clients/knip-client.ts +3 -6
  137. package/clients/lsp/__tests__/client.test.js +325 -0
  138. package/clients/lsp/__tests__/client.test.ts +434 -0
  139. package/clients/lsp/__tests__/config.test.js +166 -0
  140. package/clients/lsp/__tests__/config.test.ts +209 -0
  141. package/clients/lsp/__tests__/error-recovery.test.js +213 -0
  142. package/clients/lsp/__tests__/error-recovery.test.ts +279 -0
  143. package/clients/lsp/__tests__/integration.test.js +127 -0
  144. package/clients/lsp/__tests__/integration.test.ts +160 -0
  145. package/clients/lsp/__tests__/launch.test.js +260 -0
  146. package/clients/lsp/__tests__/launch.test.ts +329 -0
  147. package/clients/lsp/__tests__/server.test.js +259 -0
  148. package/clients/lsp/__tests__/server.test.ts +332 -0
  149. package/clients/lsp/__tests__/service.test.js +417 -0
  150. package/clients/lsp/__tests__/service.test.ts +499 -0
  151. package/clients/lsp/client.js +235 -0
  152. package/clients/lsp/client.ts +328 -0
  153. package/clients/lsp/config.js +115 -0
  154. package/clients/lsp/config.ts +149 -0
  155. package/clients/lsp/index.js +222 -0
  156. package/clients/lsp/index.ts +280 -0
  157. package/clients/lsp/installer/index.js +391 -0
  158. package/clients/lsp/interactive-install.js +210 -0
  159. package/clients/lsp/interactive-install.ts +251 -0
  160. package/clients/lsp/language.js +170 -0
  161. package/clients/lsp/language.ts +216 -0
  162. package/clients/lsp/launch.js +174 -0
  163. package/clients/lsp/launch.ts +240 -0
  164. package/clients/lsp/lsp/launch.js +116 -0
  165. package/clients/lsp/lsp/server.js +532 -0
  166. package/clients/lsp/lsp-index.js +10 -0
  167. package/clients/lsp/lsp-index.ts +11 -0
  168. package/clients/lsp/path-utils.js +48 -0
  169. package/clients/lsp/path-utils.ts +52 -0
  170. package/clients/lsp/server.js +615 -0
  171. package/clients/lsp/server.ts +800 -0
  172. package/clients/lsp/test-py-spawn/requirements.txt +1 -0
  173. package/clients/lsp/test-py-spawn/test.py +3 -0
  174. package/clients/lsp/test-py-svc/requirements.txt +1 -0
  175. package/clients/lsp/test-py-svc/test.py +3 -0
  176. package/clients/lsp/test-python-project/requirements.txt +1 -0
  177. package/clients/lsp/test-python-project/test.py +5 -0
  178. package/clients/metrics-history.js +2 -2
  179. package/clients/metrics-history.ts +2 -2
  180. package/clients/production-readiness.js +522 -0
  181. package/clients/production-readiness.ts +556 -0
  182. package/clients/project-index.js +255 -0
  183. package/clients/project-index.ts +383 -0
  184. package/clients/project-metadata.js +531 -0
  185. package/clients/project-metadata.ts +624 -0
  186. package/clients/ruff-client.js +56 -16
  187. package/clients/ruff-client.ts +72 -15
  188. package/clients/runner-tracker.js +152 -0
  189. package/clients/runner-tracker.ts +213 -0
  190. package/clients/rust-client.js +4 -11
  191. package/clients/rust-client.ts +5 -11
  192. package/clients/safe-spawn.js +96 -0
  193. package/clients/safe-spawn.ts +128 -0
  194. package/clients/scan-architectural-debt.js +3 -6
  195. package/clients/scan-architectural-debt.ts +3 -6
  196. package/clients/scan-utils.js +5 -20
  197. package/clients/scan-utils.ts +5 -29
  198. package/clients/secrets-scanner.js +3 -17
  199. package/clients/secrets-scanner.ts +4 -20
  200. package/clients/services/__tests__/effect-integration.test.js +86 -0
  201. package/clients/services/__tests__/effect-integration.test.ts +111 -0
  202. package/clients/services/effect-integration.js +194 -0
  203. package/clients/services/effect-integration.ts +268 -0
  204. package/clients/services/index.js +7 -0
  205. package/clients/services/index.ts +8 -0
  206. package/clients/services/runner-service.js +105 -0
  207. package/clients/services/runner-service.ts +179 -0
  208. package/clients/sg-runner.js +87 -13
  209. package/clients/sg-runner.ts +97 -13
  210. package/clients/state-matrix.js +160 -0
  211. package/clients/state-matrix.ts +202 -0
  212. package/clients/subprocess-client.js +10 -9
  213. package/clients/subprocess-client.ts +10 -8
  214. package/clients/test-runner-client.js +3 -7
  215. package/clients/test-runner-client.ts +3 -6
  216. package/clients/tool-availability.js +4 -10
  217. package/clients/tool-availability.ts +4 -9
  218. package/clients/tree-sitter-client.js +564 -0
  219. package/clients/tree-sitter-client.ts +797 -0
  220. package/clients/tree-sitter-query-loader.js +355 -0
  221. package/clients/tree-sitter-query-loader.ts +425 -0
  222. package/clients/type-coverage-client.js +3 -7
  223. package/clients/type-coverage-client.ts +3 -6
  224. package/clients/typescript-client.codefix.test.js +157 -0
  225. package/clients/typescript-client.codefix.test.ts +186 -0
  226. package/clients/typescript-client.js +43 -0
  227. package/clients/typescript-client.ts +98 -0
  228. package/commands/booboo.js +799 -219
  229. package/commands/booboo.ts +1004 -225
  230. package/commands/clients/ast-grep-client.js +250 -0
  231. package/commands/clients/ast-grep-parser.js +86 -0
  232. package/commands/clients/ast-grep-rule-manager.js +91 -0
  233. package/commands/clients/ast-grep-types.js +9 -0
  234. package/commands/clients/biome-client.js +380 -0
  235. package/commands/clients/complexity-client.js +667 -0
  236. package/commands/clients/file-kinds.js +177 -0
  237. package/commands/clients/file-utils.js +40 -0
  238. package/commands/clients/jscpd-client.js +169 -0
  239. package/commands/clients/knip-client.js +211 -0
  240. package/commands/clients/ruff-client.js +297 -0
  241. package/commands/clients/safe-spawn.js +88 -0
  242. package/commands/clients/scan-utils.js +83 -0
  243. package/commands/clients/sg-runner.js +190 -0
  244. package/commands/clients/types.js +11 -0
  245. package/commands/clients/typescript-client.js +505 -0
  246. package/commands/fix-from-booboo.js +398 -0
  247. package/commands/fix-from-booboo.ts +485 -0
  248. package/commands/fix-simplified.js +618 -0
  249. package/commands/fix-simplified.ts +768 -0
  250. package/commands/rate.js +10 -14
  251. package/commands/rate.ts +9 -16
  252. package/default-architect.yaml +59 -15
  253. package/index.ts +342 -429
  254. package/package.json +16 -3
  255. package/rules/ast-grep-rules/rules/empty-catch.yml +38 -13
  256. package/rules/ast-grep-rules/rules/no-array-constructor.yml +1 -0
  257. package/rules/ast-grep-rules/rules/no-debugger.yml +2 -0
  258. package/rules/python-slop-rules/.sgconfig.yml +4 -0
  259. package/rules/python-slop-rules/rules/slop-rules.yml +647 -0
  260. package/rules/tree-sitter-queries/python/bare-except.yml +54 -0
  261. package/rules/tree-sitter-queries/python/eval-exec.yml +50 -0
  262. package/rules/tree-sitter-queries/python/is-vs-equals.yml +60 -0
  263. package/rules/tree-sitter-queries/python/mutable-default-arg.yml +57 -0
  264. package/rules/tree-sitter-queries/python/unreachable-except.yml +60 -0
  265. package/rules/tree-sitter-queries/python/wildcard-import.yml +46 -0
  266. package/rules/tree-sitter-queries/tsx/dangerously-set-inner-html.yml +63 -0
  267. package/rules/tree-sitter-queries/typescript/await-in-loop.yml +56 -0
  268. package/rules/tree-sitter-queries/typescript/console-statement.yml +47 -0
  269. package/rules/tree-sitter-queries/typescript/debugger.yml +47 -0
  270. package/rules/tree-sitter-queries/typescript/deep-nesting.yml +117 -0
  271. package/rules/tree-sitter-queries/typescript/deep-promise-chain.yml +73 -0
  272. package/rules/tree-sitter-queries/typescript/empty-catch.yml +64 -0
  273. package/rules/tree-sitter-queries/typescript/eval.yml +48 -0
  274. package/rules/tree-sitter-queries/typescript/hardcoded-secrets.yml +78 -0
  275. package/rules/tree-sitter-queries/typescript/long-parameter-list.yml +62 -0
  276. package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +49 -0
  277. package/rules/tree-sitter-queries/typescript/nested-ternary.yml +45 -0
  278. package/rules/ts-slop-rules/.sgconfig.yml +4 -0
  279. package/rules/ts-slop-rules/rules/in-correct-optional-input-type.yml +10 -0
  280. package/rules/ts-slop-rules/rules/jwt-no-verify.yml +13 -0
  281. package/rules/ts-slop-rules/rules/no-architecture-violation.yml +10 -0
  282. package/rules/ts-slop-rules/rules/no-case-declarations.yml +10 -0
  283. package/rules/ts-slop-rules/rules/no-dangerously-set-inner-html.yml +10 -0
  284. package/rules/ts-slop-rules/rules/no-debugger.yml +10 -0
  285. package/rules/ts-slop-rules/rules/no-dupe-args.yml +10 -0
  286. package/rules/ts-slop-rules/rules/no-dupe-class-members.yml +10 -0
  287. package/rules/ts-slop-rules/rules/no-dupe-keys.yml +10 -0
  288. package/rules/ts-slop-rules/rules/no-eval.yml +13 -0
  289. package/rules/ts-slop-rules/rules/no-hardcoded-secrets.yml +12 -0
  290. package/rules/ts-slop-rules/rules/no-implied-eval.yml +12 -0
  291. package/rules/ts-slop-rules/rules/no-inner-html.yml +13 -0
  292. package/rules/ts-slop-rules/rules/no-javascript-url.yml +10 -0
  293. package/rules/ts-slop-rules/rules/no-mutable-default.yml +10 -0
  294. package/rules/ts-slop-rules/rules/no-nested-links.yml +12 -0
  295. package/rules/ts-slop-rules/rules/no-new-symbol.yml +10 -0
  296. package/rules/ts-slop-rules/rules/no-new-wrappers.yml +13 -0
  297. package/rules/ts-slop-rules/rules/no-open-redirect.yml +16 -0
  298. package/rules/ts-slop-rules/rules/slop-rules.yml +455 -0
  299. package/rules/ts-slop-rules/rules/weak-rsa-key.yml +12 -0
  300. package/skills/ast-grep/SKILL.md +182 -0
  301. package/clients/dispatch/runners/secrets.js +0 -109
  302. package/commands/fix.js +0 -244
  303. package/commands/fix.ts +0 -373
  304. package/rules/ast-grep-rules/rules/no-lonely-if.yml +0 -13
package/commands/fix.ts DELETED
@@ -1,373 +0,0 @@
1
- /**
2
- * Fix command for pi-lens
3
- *
4
- * Automated fix loop that scans for issues and generates fix plans.
5
- * Supports --loop flag for automatic iteration via auto-loop engine.
6
- */
7
-
8
- import * as childProcess from "node:child_process";
9
- import * as nodeFs from "node:fs";
10
- import * as path from "node:path";
11
- import type {
12
- ExtensionAPI,
13
- ExtensionContext,
14
- } from "@mariozechner/pi-coding-agent";
15
- import type { AstGrepClient } from "../clients/ast-grep-client.js";
16
- import { createAutoLoop } from "../clients/auto-loop.js";
17
- import type { BiomeClient } from "../clients/biome-client.js";
18
- import type { ComplexityClient } from "../clients/complexity-client.js";
19
- import {
20
- type AstIssue,
21
- type FixScanResults,
22
- scanAll,
23
- } from "../clients/fix-scanners.js";
24
- import type { JscpdClient } from "../clients/jscpd-client.js";
25
- import type { KnipClient } from "../clients/knip-client.js";
26
- import type { RuffClient } from "../clients/ruff-client.js";
27
-
28
- // --- Auto-loop singleton ---
29
- let fixLoop: ReturnType<typeof createAutoLoop> | null = null;
30
-
31
- function getFixLoop(pi: ExtensionAPI) {
32
- if (!fixLoop) {
33
- fixLoop = createAutoLoop(pi, {
34
- name: "fix",
35
- maxIterations: 3,
36
- command: "/lens-booboo-fix --loop",
37
- exitPatterns: [
38
- /✅ BOOBOO FIX LOOP COMPLETE/,
39
- /⚠️ BOOBOO FIX LOOP STOPPED/,
40
- /No more fixable issues/,
41
- /Max iterations.*reached/,
42
- ],
43
- });
44
- }
45
- return fixLoop;
46
- }
47
-
48
- // --- Session management ---
49
- interface FixSession {
50
- iteration: number;
51
- counts: Record<string, number>;
52
- falsePositives: string[];
53
- }
54
-
55
- function loadSession(sessionFile: string): FixSession {
56
- try {
57
- const session = JSON.parse(nodeFs.readFileSync(sessionFile, "utf-8"));
58
- return {
59
- iteration: session.iteration || 0,
60
- counts: session.counts || {},
61
- falsePositives: session.falsePositives || [],
62
- };
63
- } catch {
64
- return { iteration: 0, counts: {}, falsePositives: [] };
65
- }
66
- }
67
-
68
- function saveSession(sessionFile: string, session: FixSession): void {
69
- nodeFs.mkdirSync(path.dirname(sessionFile), { recursive: true });
70
- nodeFs.writeFileSync(sessionFile, JSON.stringify(session, null, 2), "utf-8");
71
- }
72
-
73
- function resetSession(sessionFile: string): FixSession {
74
- try {
75
- nodeFs.unlinkSync(sessionFile);
76
- } catch {
77
- // Ignore if doesn't exist
78
- }
79
- return { iteration: 0, counts: {}, falsePositives: [] };
80
- }
81
-
82
- // --- Issue ID helpers ---
83
- const issueId = (type: string, file: string, line?: number): string =>
84
- line !== undefined ? `${type}:${file}:${line}` : `${type}:${file}`;
85
-
86
- const isFalsePositive = (id: string, session: FixSession): boolean =>
87
- session.falsePositives.includes(id);
88
-
89
- // --- Plan generation ---
90
- function generatePlan(
91
- results: FixScanResults,
92
- session: FixSession,
93
- _isTsProject: boolean,
94
- prevCounts: Record<string, number>,
95
- ): string {
96
- const MAX_ITERATIONS = 3;
97
-
98
- // Filter out false positives
99
- const filteredDups = results.duplicates.filter(
100
- (c) => !isFalsePositive(issueId("duplicate", c.fileA, c.startA), session),
101
- );
102
- const filteredDeadCode = results.deadCode.filter(
103
- (i) => !isFalsePositive(issueId("dead_code", i.file ?? i.name), session),
104
- );
105
- const filteredBiome = results.biomeIssues.filter(
106
- (i) => !isFalsePositive(issueId("biome", i.file, i.line), session),
107
- );
108
- const filteredSlop = results.slopFiles.filter(
109
- (f) => !isFalsePositive(issueId("slop", f.file), session),
110
- );
111
-
112
- // Filter ast issues (exclude skip rules and false positives)
113
- const agentTasks = results.astIssues.filter(
114
- (i) => !isFalsePositive(issueId("ast", i.file, i.line), session),
115
- );
116
-
117
- const totalFixable =
118
- filteredDups.length +
119
- filteredDeadCode.length +
120
- agentTasks.length +
121
- filteredBiome.length +
122
- filteredSlop.length;
123
-
124
- // Check for no progress
125
- const prevTotal = Object.values(prevCounts).reduce((a, b) => a + b, 0);
126
- const noProgress =
127
- session.iteration > 1 && prevTotal === totalFixable && totalFixable > 0;
128
-
129
- // Completion/stopped messages
130
- if (totalFixable === 0) {
131
- const fpNote =
132
- session.falsePositives.length > 0
133
- ? `\n\n📝 ${session.falsePositives.length} item(s) marked as false positives.`
134
- : "";
135
- return `✅ BOOBOO FIX LOOP COMPLETE — No more fixable issues found after ${session.iteration} iteration(s).${fpNote}`;
136
- }
137
-
138
- if (noProgress) {
139
- return `⚠️ BOOBOO FIX LOOP STOPPED — No progress after ${session.iteration} iteration(s).\n\nRemaining items may be false positives. Mark with: /lens-booboo-fix --false-positive "<type>:<file>:<line>"`;
140
- }
141
-
142
- // --- Write TSV plan file for agent to read ---
143
- const reportDir = path.join(process.cwd(), ".pi-lens", "reports");
144
- nodeFs.mkdirSync(reportDir, { recursive: true });
145
- const reportPath = path.join(reportDir, "fix-plan.tsv");
146
-
147
- const tsvRows: string[] = ["type\tfile\trule\tmessage"];
148
-
149
- // Duplicates
150
- for (const clone of filteredDups) {
151
- tsvRows.push(
152
- `dup\t${clone.fileA}:${clone.startA}\tduplicate-code\t${clone.lines} lines duplicated with ${clone.fileB}:${clone.startB}`,
153
- );
154
- }
155
-
156
- // Dead code
157
- for (const issue of filteredDeadCode) {
158
- tsvRows.push(
159
- `dead\t${issue.file || issue.name}\t${issue.type}\t${issue.name} is unused`,
160
- );
161
- }
162
-
163
- // AST issues
164
- for (const issue of agentTasks) {
165
- tsvRows.push(
166
- `ast\t${issue.file}:${issue.line}\t${issue.rule}\t${issue.message}`,
167
- );
168
- }
169
-
170
- // Biome
171
- for (const issue of filteredBiome) {
172
- tsvRows.push(
173
- `biome\t${issue.file}:${issue.line}\t${issue.rule}\t${issue.message}`,
174
- );
175
- }
176
-
177
- // Slop
178
- for (const { file, warnings } of filteredSlop) {
179
- for (const w of warnings) {
180
- tsvRows.push(`slop\t${file}\tcomplexity\t${w}`);
181
- }
182
- }
183
-
184
- nodeFs.writeFileSync(reportPath, tsvRows.join("\n"), "utf-8");
185
-
186
- // --- Build actionable list for terminal (no TSV reading needed) ---
187
- const lines: string[] = [];
188
- lines.push(
189
- `📋 FIX PLAN — Iteration ${session.iteration}/${MAX_ITERATIONS} — ${totalFixable} issues:\n`,
190
- );
191
-
192
- // Duplicates
193
- if (filteredDups.length > 0) {
194
- for (const clone of filteredDups.slice(0, 10)) {
195
- lines.push(
196
- `🔁 ${clone.fileA}:${clone.startA} — ${clone.lines} dup from ${clone.fileB}:${clone.startB}`,
197
- );
198
- }
199
- if (filteredDups.length > 10)
200
- lines.push(` ... +${filteredDups.length - 10} more`);
201
- lines.push("");
202
- }
203
-
204
- // Dead code
205
- if (filteredDeadCode.length > 0) {
206
- for (const issue of filteredDeadCode.slice(0, 10)) {
207
- lines.push(`🗑️ ${issue.file || issue.name} — ${issue.name} unused`);
208
- }
209
- if (filteredDeadCode.length > 10)
210
- lines.push(` ... +${filteredDeadCode.length - 10} more`);
211
- lines.push("");
212
- }
213
-
214
- // AST lint
215
- if (agentTasks.length > 0) {
216
- for (const issue of agentTasks.slice(0, 15)) {
217
- lines.push(`🔨 ${issue.file}:${issue.line} — ${issue.rule}`);
218
- }
219
- if (agentTasks.length > 15)
220
- lines.push(` ... +${agentTasks.length - 15} more`);
221
- lines.push("");
222
- }
223
-
224
- // Biome
225
- if (filteredBiome.length > 0) {
226
- for (const issue of filteredBiome.slice(0, 10)) {
227
- lines.push(`🟠 ${issue.file}:${issue.line} — ${issue.rule}`);
228
- }
229
- if (filteredBiome.length > 10)
230
- lines.push(` ... +${filteredBiome.length - 10} more`);
231
- lines.push("");
232
- }
233
-
234
- // AI Slop
235
- if (filteredSlop.length > 0) {
236
- for (const { file, warnings } of filteredSlop.slice(0, 5)) {
237
- lines.push(`🤖 ${file} — ${warnings[0]}`);
238
- }
239
- if (filteredSlop.length > 5)
240
- lines.push(` ... +${filteredSlop.length - 5} more`);
241
- lines.push("");
242
- }
243
-
244
- lines.push("---");
245
- lines.push("🚀 Fix items above, then run `/lens-booboo-fix --loop`");
246
- lines.push(
247
- '🚫 False positive: `/lens-booboo-fix --false-positive "type:file:line"`',
248
- );
249
-
250
- return lines.join("\n");
251
- }
252
-
253
- // --- Main handler ---
254
- export async function handleFix(
255
- args: string,
256
- ctx: ExtensionContext,
257
- clients: {
258
- tsClient: any;
259
- astGrep: AstGrepClient;
260
- ruff: RuffClient;
261
- biome: BiomeClient;
262
- knip: KnipClient;
263
- jscpd: JscpdClient;
264
- complexity: ComplexityClient;
265
- },
266
- pi: ExtensionAPI,
267
- _ruleActions: Record<string, { type: string; note: string }>,
268
- ) {
269
- const resetRequested = args.includes("--reset");
270
- const loopMode = args.includes("--loop");
271
- const fpMatch = args.match(/--false-positive\s+"([^"]+)"/);
272
- const falsePositiveId = fpMatch?.[1];
273
-
274
- // Clean args
275
- const cleanArgs = args
276
- .replace("--reset", "")
277
- .replace("--loop", "")
278
- .replace(/--false-positive\s+"[^"]+"/, "")
279
- .trim();
280
- const targetPath = cleanArgs || ctx.cwd || process.cwd();
281
-
282
- const sessionFile = path.join(process.cwd(), ".pi-lens", "fix-session.json");
283
- const configPath = path.join(
284
- typeof __dirname !== "undefined" ? __dirname : ".",
285
- "..",
286
- "rules",
287
- "ast-grep-rules",
288
- ".sgconfig.yml",
289
- );
290
-
291
- // Load session
292
- let session = loadSession(sessionFile);
293
- if (resetRequested) {
294
- session = resetSession(sessionFile);
295
- ctx.ui.notify("🔄 Fix session reset.", "info");
296
- }
297
-
298
- // Handle false positive marking
299
- if (falsePositiveId) {
300
- if (!session.falsePositives.includes(falsePositiveId)) {
301
- session.falsePositives.push(falsePositiveId);
302
- saveSession(sessionFile, session);
303
- ctx.ui.notify(
304
- `✅ Marked as false positive: "${falsePositiveId}"`,
305
- "info",
306
- );
307
- }
308
- return;
309
- }
310
-
311
- // Start auto-loop if requested
312
- const loop = getFixLoop(pi);
313
- if (loopMode && !loop.getState().active) {
314
- loop.start(ctx);
315
- }
316
-
317
- ctx.ui.notify("🔧 Running booboo fix loop...", "info");
318
-
319
- const isTsProject = nodeFs.existsSync(path.join(targetPath, "tsconfig.json"));
320
-
321
- // Auto-fix with Biome + Ruff
322
- if (!pi.getFlag("no-biome") && clients.biome.isAvailable()) {
323
- childProcess.spawnSync(
324
- "npx",
325
- ["@biomejs/biome", "check", "--write", "--unsafe", targetPath],
326
- {
327
- encoding: "utf-8",
328
- timeout: 30000,
329
- shell: true,
330
- },
331
- );
332
- }
333
- if (!pi.getFlag("no-ruff") && clients.ruff.isAvailable()) {
334
- childProcess.spawnSync("ruff", ["check", "--fix", targetPath], {
335
- encoding: "utf-8",
336
- timeout: 15000,
337
- shell: true,
338
- });
339
- childProcess.spawnSync("ruff", ["format", targetPath], {
340
- encoding: "utf-8",
341
- timeout: 15000,
342
- shell: true,
343
- });
344
- }
345
-
346
- // Run all scanners
347
- const prevCounts = { ...session.counts };
348
- session.iteration++;
349
-
350
- const results = scanAll(clients, targetPath, isTsProject, configPath);
351
-
352
- // Update session counts
353
- session.counts = {
354
- duplicates: results.duplicates.length,
355
- dead_code: results.deadCode.length,
356
- ast_issues: results.astIssues.length,
357
- biome_issues: results.biomeIssues.length,
358
- slop_files: results.slopFiles.length,
359
- };
360
- saveSession(sessionFile, session);
361
-
362
- // Generate and send plan
363
- const plan = generatePlan(results, session, isTsProject, prevCounts);
364
- const planPath = path.join(process.cwd(), ".pi-lens", "fix-plan.md");
365
- nodeFs.writeFileSync(
366
- planPath,
367
- `# Fix Plan — Iteration ${session.iteration}\n\n${plan}`,
368
- "utf-8",
369
- );
370
-
371
- ctx.ui.notify(`📄 Fix plan saved: ${planPath}`, "info");
372
- pi.sendUserMessage(plan, { deliverAs: "followUp" });
373
- }
@@ -1,13 +0,0 @@
1
- id: no-lonely-if
2
- language: TypeScript
3
- message: "Unexpected lonely 'if' — combine with the enclosing 'else' clause"
4
- severity: warning
5
- note: |
6
- An 'if' statement as the sole statement in an 'else' block can be
7
- combined into an 'else if' for better readability.
8
- rule:
9
- all:
10
- - pattern: if ($$$COND) { $$$BODY }
11
- - inside:
12
- kind: else_clause
13
- stopBy: end