pi-lens 3.1.2 → 3.2.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 (154) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +16 -12
  3. package/clients/ast-grep-client.js +8 -1
  4. package/clients/ast-grep-client.ts +9 -1
  5. package/clients/biome-client.js +51 -38
  6. package/clients/biome-client.ts +60 -58
  7. package/clients/dependency-checker.js +30 -1
  8. package/clients/dependency-checker.ts +35 -1
  9. package/clients/dispatch/__tests__/runner-registration.test.ts +286 -282
  10. package/clients/dispatch/bus-dispatcher.js +15 -14
  11. package/clients/dispatch/bus-dispatcher.ts +32 -25
  12. package/clients/dispatch/dispatcher.js +18 -25
  13. package/clients/dispatch/dispatcher.test.ts +2 -1
  14. package/clients/dispatch/dispatcher.ts +17 -28
  15. package/clients/dispatch/plan.js +77 -32
  16. package/clients/dispatch/plan.ts +78 -32
  17. package/clients/dispatch/runners/ast-grep-napi.js +36 -376
  18. package/clients/dispatch/runners/ast-grep-napi.ts +60 -433
  19. package/clients/dispatch/runners/index.js +8 -4
  20. package/clients/dispatch/runners/index.ts +8 -4
  21. package/clients/dispatch/runners/lsp.js +65 -0
  22. package/clients/dispatch/runners/lsp.ts +125 -0
  23. package/clients/dispatch/runners/oxlint.js +2 -2
  24. package/clients/dispatch/runners/oxlint.ts +2 -2
  25. package/clients/dispatch/runners/pyright.js +24 -8
  26. package/clients/dispatch/runners/pyright.ts +28 -14
  27. package/clients/dispatch/runners/rust-clippy.js +2 -2
  28. package/clients/dispatch/runners/rust-clippy.ts +2 -4
  29. package/clients/dispatch/runners/tree-sitter.js +14 -2
  30. package/clients/dispatch/runners/tree-sitter.ts +15 -2
  31. package/clients/dispatch/runners/ts-lsp.js +3 -3
  32. package/clients/dispatch/runners/ts-lsp.ts +8 -5
  33. package/clients/dispatch/runners/yaml-rule-parser.js +292 -0
  34. package/clients/dispatch/runners/yaml-rule-parser.ts +338 -0
  35. package/clients/dispatch/types.js +3 -0
  36. package/clients/dispatch/types.ts +3 -0
  37. package/clients/formatters.js +67 -14
  38. package/clients/formatters.ts +68 -15
  39. package/clients/installer/index.js +78 -10
  40. package/clients/installer/index.ts +519 -426
  41. package/clients/jscpd-client.js +28 -0
  42. package/clients/jscpd-client.ts +41 -3
  43. package/clients/knip-client.js +30 -1
  44. package/clients/knip-client.ts +34 -2
  45. package/clients/lsp/__tests__/client.test.ts +64 -41
  46. package/clients/lsp/__tests__/config.test.ts +25 -17
  47. package/clients/lsp/__tests__/launch.test.ts +108 -43
  48. package/clients/lsp/__tests__/service.test.ts +76 -48
  49. package/clients/lsp/client.js +87 -2
  50. package/clients/lsp/client.ts +150 -6
  51. package/clients/lsp/config.js +8 -11
  52. package/clients/lsp/config.ts +24 -21
  53. package/clients/lsp/index.js +69 -0
  54. package/clients/lsp/index.ts +82 -0
  55. package/clients/lsp/interactive-install.js +19 -8
  56. package/clients/lsp/interactive-install.ts +52 -27
  57. package/clients/lsp/launch.js +182 -32
  58. package/clients/lsp/launch.ts +241 -38
  59. package/clients/lsp/path-utils.js +3 -46
  60. package/clients/lsp/path-utils.ts +11 -51
  61. package/clients/lsp/server.js +93 -71
  62. package/clients/lsp/server.ts +173 -131
  63. package/clients/path-utils.js +142 -0
  64. package/clients/path-utils.ts +153 -0
  65. package/clients/ruff-client.js +33 -4
  66. package/clients/ruff-client.ts +44 -13
  67. package/clients/safe-spawn.js +3 -1
  68. package/clients/safe-spawn.ts +3 -1
  69. package/clients/services/effect-integration.js +11 -7
  70. package/clients/services/effect-integration.ts +34 -26
  71. package/clients/sg-runner.js +51 -9
  72. package/clients/sg-runner.ts +58 -15
  73. package/clients/tree-sitter-client.js +12 -0
  74. package/clients/tree-sitter-client.ts +12 -0
  75. package/clients/typescript-client.js +6 -2
  76. package/clients/typescript-client.ts +9 -2
  77. package/commands/booboo.js +2 -4
  78. package/commands/booboo.ts +2 -4
  79. package/index.ts +377 -93
  80. package/package.json +2 -1
  81. package/rules/tree-sitter-queries/tsx/no-nested-links.yml +45 -0
  82. package/rules/tree-sitter-queries/typescript/constructor-super.yml +55 -0
  83. package/rules/tree-sitter-queries/typescript/debugger.yml +1 -1
  84. package/rules/tree-sitter-queries/typescript/no-dupe-class-members.yml +47 -0
  85. package/tsconfig.json +1 -1
  86. package/clients/__tests__/file-time.test.js +0 -216
  87. package/clients/__tests__/format-service.test.js +0 -245
  88. package/clients/__tests__/formatters.test.js +0 -271
  89. package/clients/agent-behavior-client.test.js +0 -94
  90. package/clients/ast-grep-client.test.js +0 -129
  91. package/clients/ast-grep-client.test.ts +0 -155
  92. package/clients/biome-client.test.js +0 -144
  93. package/clients/cache-manager.test.js +0 -197
  94. package/clients/complexity-client.test.js +0 -234
  95. package/clients/dependency-checker.test.js +0 -60
  96. package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
  97. package/clients/dispatch/__tests__/runner-registration.test.js +0 -236
  98. package/clients/dispatch/dispatcher.edge.test.js +0 -82
  99. package/clients/dispatch/dispatcher.format.test.js +0 -46
  100. package/clients/dispatch/dispatcher.inline.test.js +0 -74
  101. package/clients/dispatch/dispatcher.test.js +0 -115
  102. package/clients/dispatch/runners/architect.test.js +0 -138
  103. package/clients/dispatch/runners/ast-grep-napi.test.js +0 -106
  104. package/clients/dispatch/runners/oxlint.test.js +0 -230
  105. package/clients/dispatch/runners/pyright.test.js +0 -98
  106. package/clients/dispatch/runners/python-slop.test.js +0 -203
  107. package/clients/dispatch/runners/scan_codebase.test.js +0 -89
  108. package/clients/dispatch/runners/shellcheck.test.js +0 -98
  109. package/clients/dispatch/runners/spellcheck.test.js +0 -158
  110. package/clients/dispatch/runners/ts-slop.test.js +0 -180
  111. package/clients/dispatch/runners/ts-slop.test.ts +0 -230
  112. package/clients/dogfood.test.js +0 -201
  113. package/clients/file-kinds.test.js +0 -169
  114. package/clients/go-client.test.js +0 -127
  115. package/clients/jscpd-client.test.js +0 -127
  116. package/clients/knip-client.test.js +0 -112
  117. package/clients/lsp/__tests__/client.test.js +0 -325
  118. package/clients/lsp/__tests__/config.test.js +0 -166
  119. package/clients/lsp/__tests__/error-recovery.test.js +0 -213
  120. package/clients/lsp/__tests__/integration.test.js +0 -127
  121. package/clients/lsp/__tests__/launch.test.js +0 -260
  122. package/clients/lsp/__tests__/server.test.js +0 -259
  123. package/clients/lsp/__tests__/service.test.js +0 -417
  124. package/clients/metrics-client.test.js +0 -141
  125. package/clients/ruff-client.test.js +0 -132
  126. package/clients/rust-client.test.js +0 -108
  127. package/clients/sanitize.test.js +0 -177
  128. package/clients/secrets-scanner.test.js +0 -100
  129. package/clients/services/__tests__/effect-integration.test.js +0 -86
  130. package/clients/test-runner-client.test.js +0 -192
  131. package/clients/todo-scanner.test.js +0 -301
  132. package/clients/type-coverage-client.test.js +0 -105
  133. package/clients/typescript-client.codefix.test.js +0 -157
  134. package/clients/typescript-client.test.js +0 -105
  135. package/commands/clients/ast-grep-client.js +0 -250
  136. package/commands/clients/ast-grep-parser.js +0 -86
  137. package/commands/clients/ast-grep-rule-manager.js +0 -91
  138. package/commands/clients/ast-grep-types.js +0 -9
  139. package/commands/clients/biome-client.js +0 -380
  140. package/commands/clients/complexity-client.js +0 -667
  141. package/commands/clients/file-kinds.js +0 -177
  142. package/commands/clients/file-utils.js +0 -40
  143. package/commands/clients/jscpd-client.js +0 -169
  144. package/commands/clients/knip-client.js +0 -211
  145. package/commands/clients/ruff-client.js +0 -297
  146. package/commands/clients/safe-spawn.js +0 -88
  147. package/commands/clients/scan-utils.js +0 -83
  148. package/commands/clients/sg-runner.js +0 -190
  149. package/commands/clients/types.js +0 -11
  150. package/commands/clients/typescript-client.js +0 -505
  151. package/commands/rate.test.js +0 -119
  152. package/rules/ast-grep-rules/rules/no-dangerously-set-inner-html.yml +0 -13
  153. package/rules/ast-grep-rules/rules/no-debugger.yml +0 -12
  154. package/rules/ast-grep-rules/rules/no-eval.yml +0 -13
@@ -1,30 +1,22 @@
1
- /**
2
- * Bus-Integrated Dispatcher for pi-lens
3
- *
4
- * Bridges the declarative dispatch system with the event bus.
5
- *
6
- * Changes from original dispatcher:
7
- * - Publishes events for each runner lifecycle phase
8
- * - Supports concurrent execution with progress tracking
9
- * - Integrates with DiagnosticAggregator for results
10
- */
11
-
12
1
  import {
2
+ type Diagnostic,
13
3
  DiagnosticFound,
14
- RunnerStarted,
15
- RunnerCompleted,
16
- AutoFixApplied,
17
4
  FileModified,
18
- ReportReady,
19
- type Diagnostic,
20
5
  type OutputSemantic,
6
+ ReportReady,
7
+ RunnerCompleted,
8
+ RunnerStarted,
21
9
  } from "../bus/events.js";
22
- import { publish } from "../bus/bus.js";
23
- import { formatDiagnostic, formatDiagnostics, EMOJI } from "./utils/format-utils.js";
10
+ import { formatDiagnostics } from "./utils/format-utils.js";
24
11
  // Import runners to register them
25
12
  import "./runners/index.js";
26
13
 
27
- import type { DispatchContext, RunnerDefinition, RunnerResult, RunnerGroup } from "./types.js";
14
+ import type {
15
+ DispatchContext,
16
+ RunnerDefinition,
17
+ RunnerGroup,
18
+ RunnerResult,
19
+ } from "./types.js";
28
20
 
29
21
  // --- Enhanced Dispatch Result ---
30
22
 
@@ -53,7 +45,7 @@ async function runRunner(
53
45
  defaultSemantic: OutputSemantic,
54
46
  ): Promise<RunnerResult & { durationMs: number }> {
55
47
  const startTime = Date.now();
56
-
48
+
57
49
  // Publish runner started event
58
50
  RunnerStarted.publish({
59
51
  runnerId: runner.id,
@@ -62,6 +54,15 @@ async function runRunner(
62
54
  });
63
55
 
64
56
  try {
57
+ // Check when() condition async-safely (sync filter in caller can't await Promises)
58
+ if (runner.when && !(await runner.when(ctx))) {
59
+ return {
60
+ status: "skipped",
61
+ diagnostics: [],
62
+ semantic: defaultSemantic,
63
+ durationMs: Date.now() - startTime,
64
+ };
65
+ }
65
66
  const result = await runner.run(ctx);
66
67
  const durationMs = Date.now() - startTime;
67
68
 
@@ -77,7 +78,8 @@ async function runRunner(
77
78
 
78
79
  // Publish runner completed event
79
80
  // Map "succeeded" to "completed" for the event status
80
- const eventStatus = result.status === "succeeded" ? "completed" : result.status;
81
+ const eventStatus =
82
+ result.status === "succeeded" ? "completed" : result.status;
81
83
  RunnerCompleted.publish({
82
84
  runnerId: runner.id,
83
85
  filePath: ctx.filePath,
@@ -137,10 +139,11 @@ export async function dispatchConcurrent(
137
139
  })
138
140
  : group.runnerIds;
139
141
 
142
+ // Note: when() is async — must be awaited. Filter it out here synchronously
143
+ // (runners without when always run; runners with when are checked inside runRunner).
140
144
  const runners = runnerIds
141
145
  .map((id) => getRunner(id))
142
- .filter((r): r is RunnerDefinition => r !== undefined)
143
- .filter((r) => (r.when ? r.when(ctx) : true));
146
+ .filter((r): r is RunnerDefinition => r !== undefined);
144
147
 
145
148
  const semantic = group.semantic ?? "warning";
146
149
 
@@ -226,7 +229,10 @@ export async function dispatchConcurrent(
226
229
  export async function dispatchLintWithBus(
227
230
  filePath: string,
228
231
  cwd: string,
229
- pi: { getFlag(flag: string): string | boolean | undefined; log?: (msg: string) => void },
232
+ pi: {
233
+ getFlag(flag: string): string | boolean | undefined;
234
+ log?: (msg: string) => void;
235
+ },
230
236
  ): Promise<string> {
231
237
  const { createDispatchContext } = await import("./dispatcher.js");
232
238
  const { getRunnersForKind } = await import("./dispatcher.js");
@@ -238,7 +244,8 @@ export async function dispatchLintWithBus(
238
244
  changeType: "external",
239
245
  });
240
246
 
241
- const ctx = createDispatchContext(filePath, cwd, pi);
247
+ // blockingOnly=true: post-write dispatch only reports blocking errors (same as standard dispatchLint)
248
+ const ctx = createDispatchContext(filePath, cwd, pi, undefined, true);
242
249
 
243
250
  const kind = ctx.kind;
244
251
  if (!kind) return "";
@@ -16,6 +16,7 @@
16
16
  import { detectFileKind } from "../file-kinds.js";
17
17
  import { isTestFile } from "../file-utils.js";
18
18
  import { logLatency } from "../latency-logger.js";
19
+ import { normalizeMapKey } from "../path-utils.js";
19
20
  import { safeSpawn } from "../safe-spawn.js";
20
21
  import { formatDiagnostics } from "./utils/format-utils.js";
21
22
  // --- In-Memory Baseline Store ---
@@ -24,10 +25,10 @@ export function createBaselineStore() {
24
25
  const baselines = new Map();
25
26
  return {
26
27
  get(filePath) {
27
- return baselines.get(filePath);
28
+ return baselines.get(normalizeMapKey(filePath));
28
29
  },
29
30
  set(filePath, diagnostics) {
30
- baselines.set(filePath, diagnostics);
31
+ baselines.set(normalizeMapKey(filePath), diagnostics);
31
32
  },
32
33
  clear() {
33
34
  baselines.clear();
@@ -37,10 +38,8 @@ export function createBaselineStore() {
37
38
  // --- Runner Registry ---
38
39
  const globalRegistry = new Map();
39
40
  export function registerRunner(runner) {
40
- if (globalRegistry.has(runner.id)) {
41
- console.error(`[dispatch] Duplicate runner: ${runner.id}`);
42
- return;
43
- }
41
+ if (globalRegistry.has(runner.id))
42
+ return; // Already registered, skip silently
44
43
  globalRegistry.set(runner.id, runner);
45
44
  }
46
45
  export function getRunner(id) {
@@ -91,9 +90,11 @@ function checkToolAvailability(command) {
91
90
  }
92
91
  // --- Dispatch Context Factory ---
93
92
  export function createDispatchContext(filePath, cwd, pi, baselines, blockingOnly) {
94
- const kind = detectFileKind(filePath);
93
+ // Normalize path for consistent Map key usage on Windows
94
+ const normalizedFilePath = normalizeMapKey(filePath);
95
+ const kind = detectFileKind(normalizedFilePath);
95
96
  return {
96
- filePath,
97
+ filePath: normalizedFilePath,
97
98
  cwd,
98
99
  kind,
99
100
  pi,
@@ -168,12 +169,17 @@ export async function dispatchForFile(ctx, groups) {
168
169
  let stopped = false;
169
170
  const runnerLatencies = [];
170
171
  // Debug logging goes to latency log only (not console - avoid noise)
172
+ const allRunnerIds = groups.flatMap((g) => g.runnerIds);
171
173
  logLatency({
172
174
  type: "phase",
173
175
  filePath: ctx.filePath,
174
176
  phase: "dispatch_start",
175
177
  durationMs: 0,
176
- metadata: { groupCount: groups.length, kind: ctx.kind },
178
+ metadata: {
179
+ groupCount: groups.length,
180
+ kind: ctx.kind,
181
+ runners: allRunnerIds.join(","),
182
+ },
177
183
  });
178
184
  for (const group of groups) {
179
185
  if (stopped && ctx.pi.getFlag("stop-on-error")) {
@@ -256,10 +262,6 @@ export async function dispatchForFile(ctx, groups) {
256
262
  diagnosticCount: result.diagnostics.length,
257
263
  semantic: result.semantic ?? semantic,
258
264
  });
259
- // Log slow runners immediately for real-time debugging
260
- if (duration > 500) {
261
- ctx.log(`⚠️ SLOW RUNNER: ${runnerId} took ${duration}ms (${result.status}, ${result.diagnostics.length} issues)`);
262
- }
263
265
  // Apply delta mode filtering
264
266
  let diagnostics = result.diagnostics;
265
267
  if (ctx.deltaMode && result.semantic !== "silent") {
@@ -312,18 +314,9 @@ export async function dispatchForFile(ctx, groups) {
312
314
  if (latencyReports.length > 100) {
313
315
  latencyReports.shift();
314
316
  }
315
- // Log each runner as separate entry for detailed analysis
316
- for (const runner of runnerLatencies) {
317
- logLatency({
318
- type: "runner",
319
- filePath: ctx.filePath,
320
- runnerId: runner.runnerId,
321
- durationMs: runner.durationMs,
322
- status: runner.status,
323
- diagnosticCount: runner.diagnosticCount,
324
- semantic: runner.semantic,
325
- });
326
- }
317
+ // Runner latencies already logged immediately after execution (line ~329)
318
+ // The runnerLatencies array is stored in latencyReport for aggregate analysis
319
+ // No need to log again here - would create duplicates in the log
327
320
  // Log summary to latency log only (not console - avoid noise)
328
321
  logLatency({
329
322
  type: "tool_result",
@@ -97,7 +97,8 @@ describe("Dispatch Context", () => {
97
97
 
98
98
  const ctx = createDispatchContext("test.ts", "/project", mockPi);
99
99
 
100
- expect(ctx.filePath).toBe("test.ts");
100
+ // Path is normalized to absolute path (Windows compatibility)
101
+ expect(ctx.filePath).toContain("test.ts");
101
102
  expect(ctx.cwd).toBe("/project");
102
103
  expect(ctx.autofix).toBe(false);
103
104
  expect(ctx.deltaMode).toBe(true);
@@ -18,6 +18,7 @@ import type { FileKind } from "../file-kinds.js";
18
18
  import { detectFileKind } from "../file-kinds.js";
19
19
  import { isTestFile } from "../file-utils.js";
20
20
  import { logLatency } from "../latency-logger.js";
21
+ import { normalizeMapKey } from "../path-utils.js";
21
22
  import { safeSpawn } from "../safe-spawn.js";
22
23
  import type {
23
24
  BaselineStore,
@@ -40,10 +41,10 @@ export function createBaselineStore(): BaselineStore {
40
41
 
41
42
  return {
42
43
  get(filePath) {
43
- return baselines.get(filePath);
44
+ return baselines.get(normalizeMapKey(filePath));
44
45
  },
45
46
  set(filePath, diagnostics) {
46
- baselines.set(filePath, diagnostics);
47
+ baselines.set(normalizeMapKey(filePath), diagnostics);
47
48
  },
48
49
  clear() {
49
50
  baselines.clear();
@@ -56,10 +57,7 @@ export function createBaselineStore(): BaselineStore {
56
57
  const globalRegistry = new Map<string, RunnerDefinition>();
57
58
 
58
59
  export function registerRunner(runner: RunnerDefinition): void {
59
- if (globalRegistry.has(runner.id)) {
60
- console.error(`[dispatch] Duplicate runner: ${runner.id}`);
61
- return;
62
- }
60
+ if (globalRegistry.has(runner.id)) return; // Already registered, skip silently
63
61
  globalRegistry.set(runner.id, runner);
64
62
  }
65
63
 
@@ -127,10 +125,12 @@ export function createDispatchContext(
127
125
  baselines?: BaselineStore,
128
126
  blockingOnly?: boolean,
129
127
  ): DispatchContext {
130
- const kind = detectFileKind(filePath);
128
+ // Normalize path for consistent Map key usage on Windows
129
+ const normalizedFilePath = normalizeMapKey(filePath);
130
+ const kind = detectFileKind(normalizedFilePath);
131
131
 
132
132
  return {
133
- filePath,
133
+ filePath: normalizedFilePath,
134
134
  cwd,
135
135
  kind,
136
136
  pi,
@@ -267,12 +267,17 @@ export async function dispatchForFile(
267
267
  const runnerLatencies: RunnerLatency[] = [];
268
268
 
269
269
  // Debug logging goes to latency log only (not console - avoid noise)
270
+ const allRunnerIds = groups.flatMap((g) => g.runnerIds);
270
271
  logLatency({
271
272
  type: "phase",
272
273
  filePath: ctx.filePath,
273
274
  phase: "dispatch_start",
274
275
  durationMs: 0,
275
- metadata: { groupCount: groups.length, kind: ctx.kind },
276
+ metadata: {
277
+ groupCount: groups.length,
278
+ kind: ctx.kind,
279
+ runners: allRunnerIds.join(","),
280
+ },
276
281
  });
277
282
 
278
283
  for (const group of groups) {
@@ -364,13 +369,6 @@ export async function dispatchForFile(
364
369
  semantic: result.semantic ?? semantic,
365
370
  });
366
371
 
367
- // Log slow runners immediately for real-time debugging
368
- if (duration > 500) {
369
- ctx.log(
370
- `⚠️ SLOW RUNNER: ${runnerId} took ${duration}ms (${result.status}, ${result.diagnostics.length} issues)`,
371
- );
372
- }
373
-
374
372
  // Apply delta mode filtering
375
373
  let diagnostics = result.diagnostics;
376
374
  if (ctx.deltaMode && result.semantic !== "silent") {
@@ -437,18 +435,9 @@ export async function dispatchForFile(
437
435
  latencyReports.shift();
438
436
  }
439
437
 
440
- // Log each runner as separate entry for detailed analysis
441
- for (const runner of runnerLatencies) {
442
- logLatency({
443
- type: "runner",
444
- filePath: ctx.filePath,
445
- runnerId: runner.runnerId,
446
- durationMs: runner.durationMs,
447
- status: runner.status,
448
- diagnosticCount: runner.diagnosticCount,
449
- semantic: runner.semantic,
450
- });
451
- }
438
+ // Runner latencies already logged immediately after execution (line ~329)
439
+ // The runnerLatencies array is stored in latencyReport for aggregate analysis
440
+ // No need to log again here - would create duplicates in the log
452
441
 
453
442
  // Log summary to latency log only (not console - avoid noise)
454
443
  logLatency({
@@ -11,6 +11,13 @@
11
11
  */
12
12
  /**
13
13
  * Tool plans organized by purpose
14
+ *
15
+ * CORE PRINCIPLE: File write only runs BLOCKING tools
16
+ * - Type checking (LSP) - blocking errors
17
+ * - Security/correctness lint - blocking errors
18
+ * - Auto-format/auto-fix handled by direct calls in index.ts (not here)
19
+ *
20
+ * Warning-only tools run on /lens-booboo command only
14
21
  */
15
22
  export const TOOL_PLANS = {
16
23
  /**
@@ -19,17 +26,18 @@ export const TOOL_PLANS = {
19
26
  jsts: {
20
27
  name: "JavaScript/TypeScript Linting",
21
28
  groups: [
22
- // TypeScript LSP always runs first - blocks on errors
23
- { mode: "all", runnerIds: ["ts-lsp"], filterKinds: ["jsts"] },
24
- // Then biome or oxlint for fast linting (user preference)
25
- { mode: "fallback", runnerIds: ["biome-lint", "oxlint"] },
26
- // Fast structural analysis via NAPI (replaces CLI - 100x faster)
27
- { mode: "all", runnerIds: ["ast-grep-napi"] },
28
- // Type safety checks
29
- { mode: "fallback", runnerIds: ["type-safety"] },
29
+ // LSP type checking (unified for all languages) - priority 4, blocking errors
30
+ { mode: "all", runnerIds: ["lsp"], filterKinds: ["jsts"] },
31
+ // Tree-sitter native structural analysis (blocking rules: constructor-super, dangerouslySetInnerHTML, etc.)
32
+ { mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["jsts"] },
33
+ // AST structural analysis (blocking: no-dupe-keys, no-hardcoded-secrets, jwt-no-verify, etc.)
34
+ // DISABLED in post-write - ast-grep-napi can crash. Runs via /lens-booboo only.
35
+ // { mode: "all", runnerIds: ["ast-grep-napi"], filterKinds: ["jsts"] },
36
+ // Type safety checks (has some blocking errors)
37
+ { mode: "fallback", runnerIds: ["type-safety"], filterKinds: ["jsts"] },
30
38
  // Note: ast-grep CLI kept for ast_grep_search/ast_grep_replace tools only
31
- // Architectural rules
32
- { mode: "fallback", runnerIds: ["architect"] },
39
+ // Note: biome, oxlint handled by direct auto-fix calls in index.ts (not in dispatch)
40
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
33
41
  ],
34
42
  },
35
43
  /**
@@ -38,10 +46,13 @@ export const TOOL_PLANS = {
38
46
  python: {
39
47
  name: "Python Linting",
40
48
  groups: [
41
- // Ruff handles both formatting and linting
42
- { mode: "fallback", runnerIds: ["ruff-lint"] },
43
- // Architectural rules
44
- { mode: "fallback", runnerIds: ["architect"] },
49
+ // Pyright type checking (standard mode - no LSP flag needed)
50
+ // Provides Python type errors in standard pi mode
51
+ { mode: "all", runnerIds: ["pyright"], filterKinds: ["python"] },
52
+ // LSP type checking (unified) - when --lens-lsp enabled
53
+ { mode: "all", runnerIds: ["lsp"], filterKinds: ["python"] },
54
+ // Note: ruff handled by direct auto-fix calls in index.ts (not in dispatch)
55
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
45
56
  ],
46
57
  },
47
58
  /**
@@ -50,10 +61,11 @@ export const TOOL_PLANS = {
50
61
  go: {
51
62
  name: "Go Linting",
52
63
  groups: [
53
- // Go vet
54
- { mode: "fallback", runnerIds: ["go-vet"] },
55
- // Architectural rules
56
- { mode: "fallback", runnerIds: ["architect"] },
64
+ // LSP type checking (gopls)
65
+ { mode: "all", runnerIds: ["lsp"], filterKinds: ["go"] },
66
+ // Go vet for additional checks (warning only, but low cost)
67
+ { mode: "fallback", runnerIds: ["go-vet"], filterKinds: ["go"] },
68
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
57
69
  ],
58
70
  },
59
71
  /**
@@ -62,10 +74,11 @@ export const TOOL_PLANS = {
62
74
  rust: {
63
75
  name: "Rust Linting",
64
76
  groups: [
65
- // Cargo clippy
66
- { mode: "fallback", runnerIds: ["rust-clippy"] },
67
- // Architectural rules
68
- { mode: "fallback", runnerIds: ["architect"] },
77
+ // LSP type checking (rust-analyzer)
78
+ { mode: "all", runnerIds: ["lsp"], filterKinds: ["rust"] },
79
+ // Cargo clippy for additional checks
80
+ { mode: "fallback", runnerIds: ["rust-clippy"], filterKinds: ["rust"] },
81
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
69
82
  ],
70
83
  },
71
84
  /**
@@ -74,8 +87,7 @@ export const TOOL_PLANS = {
74
87
  cxx: {
75
88
  name: "C/C++ Linting",
76
89
  groups: [
77
- // Architectural rules
78
- { mode: "fallback", runnerIds: ["architect"] },
90
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
79
91
  ],
80
92
  },
81
93
  /**
@@ -84,8 +96,8 @@ export const TOOL_PLANS = {
84
96
  json: {
85
97
  name: "JSON Processing",
86
98
  groups: [
87
- // Biome handles JSON well
88
- { mode: "fallback", runnerIds: ["biome-lint"] },
99
+ // Note: Biome handles JSON formatting via direct call in index.ts
100
+ // No additional linting needed for JSON
89
101
  ],
90
102
  },
91
103
  /**
@@ -94,7 +106,7 @@ export const TOOL_PLANS = {
94
106
  markdown: {
95
107
  name: "Markdown Processing",
96
108
  groups: [
97
- // Spellcheck for typos
109
+ // Spellcheck for typos (warning only, but useful)
98
110
  { mode: "fallback", runnerIds: ["spellcheck"] },
99
111
  ],
100
112
  },
@@ -104,10 +116,9 @@ export const TOOL_PLANS = {
104
116
  shell: {
105
117
  name: "Shell Script Linting",
106
118
  groups: [
107
- // Shellcheck for bash/sh/zsh linting
119
+ // Shellcheck for bash/sh/zsh linting (has blocking errors for syntax)
108
120
  { mode: "fallback", runnerIds: ["shellcheck"] },
109
- // Architectural rules
110
- { mode: "fallback", runnerIds: ["architect"] },
121
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
111
122
  ],
112
123
  },
113
124
  /**
@@ -116,8 +127,7 @@ export const TOOL_PLANS = {
116
127
  cmake: {
117
128
  name: "CMake Processing",
118
129
  groups: [
119
- // Architectural rules
120
- { mode: "fallback", runnerIds: ["architect"] },
130
+ // Architectural rules (guidance only, not blocking) - runs via /lens-booboo only
121
131
  ],
122
132
  },
123
133
  };
@@ -133,3 +143,38 @@ export function getToolPlan(kind) {
133
143
  export function getAllToolPlans() {
134
144
  return TOOL_PLANS;
135
145
  }
146
+ /**
147
+ * Full lint plan for /lens-booboo command (includes warning-only tools)
148
+ * This includes ALL runners for comprehensive analysis
149
+ */
150
+ export const FULL_LINT_PLANS = {
151
+ ...TOOL_PLANS,
152
+ // Override jsts to include warning-only tools
153
+ jsts: {
154
+ name: "JavaScript/TypeScript Full Lint",
155
+ groups: [
156
+ { mode: "all", runnerIds: ["lsp"], filterKinds: ["jsts"] },
157
+ { mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["jsts"] },
158
+ { mode: "all", runnerIds: ["ast-grep-napi"], filterKinds: ["jsts"] },
159
+ // Warning-only tools (for full lint, not file write)
160
+ {
161
+ mode: "fallback",
162
+ runnerIds: ["biome-lint", "oxlint"],
163
+ filterKinds: ["jsts"],
164
+ },
165
+ { mode: "fallback", runnerIds: ["type-safety"], filterKinds: ["jsts"] },
166
+ { mode: "fallback", runnerIds: ["architect"], filterKinds: ["jsts"] },
167
+ ],
168
+ },
169
+ // Override python to include warning-only tools
170
+ python: {
171
+ name: "Python Full Lint",
172
+ groups: [
173
+ { mode: "all", runnerIds: ["lsp"], filterKinds: ["python"] },
174
+ // Warning-only tools
175
+ { mode: "fallback", runnerIds: ["ruff-lint"], filterKinds: ["python"] },
176
+ { mode: "fallback", runnerIds: ["python-slop"], filterKinds: ["python"] },
177
+ { mode: "fallback", runnerIds: ["architect"], filterKinds: ["python"] },
178
+ ],
179
+ },
180
+ };