pi-lens 3.6.3 → 3.6.4

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 (206) hide show
  1. package/package.json +3 -3
  2. package/tsconfig.json +1 -1
  3. package/clients/__tests__/file-time.test.js +0 -216
  4. package/clients/__tests__/file-time.test.ts +0 -276
  5. package/clients/__tests__/format-service.test.js +0 -245
  6. package/clients/__tests__/format-service.test.ts +0 -339
  7. package/clients/__tests__/formatters.test.js +0 -271
  8. package/clients/__tests__/formatters.test.ts +0 -401
  9. package/clients/agent-behavior-client.js +0 -110
  10. package/clients/agent-behavior-client.test.js +0 -94
  11. package/clients/agent-behavior-client.test.ts +0 -116
  12. package/clients/amain-types.js +0 -164
  13. package/clients/architect-client.js +0 -291
  14. package/clients/ast-grep-client.js +0 -253
  15. package/clients/ast-grep-parser.js +0 -84
  16. package/clients/ast-grep-rule-manager.js +0 -89
  17. package/clients/ast-grep-types.js +0 -9
  18. package/clients/auto-loop.js +0 -131
  19. package/clients/biome-client.js +0 -420
  20. package/clients/biome-client.test.js +0 -144
  21. package/clients/biome-client.test.ts +0 -163
  22. package/clients/cache/rule-cache.js +0 -72
  23. package/clients/cache-manager.js +0 -245
  24. package/clients/cache-manager.test.js +0 -197
  25. package/clients/cache-manager.test.ts +0 -299
  26. package/clients/complexity-client.js +0 -675
  27. package/clients/complexity-client.test.js +0 -234
  28. package/clients/complexity-client.test.ts +0 -255
  29. package/clients/config-validator.js +0 -465
  30. package/clients/dependency-checker.js +0 -325
  31. package/clients/dependency-checker.test.js +0 -60
  32. package/clients/dependency-checker.test.ts +0 -71
  33. package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
  34. package/clients/dispatch/__tests__/autofix-integration.test.ts +0 -300
  35. package/clients/dispatch/__tests__/runner-registration.test.js +0 -234
  36. package/clients/dispatch/__tests__/runner-registration.test.ts +0 -286
  37. package/clients/dispatch/debug.log +0 -1
  38. package/clients/dispatch/dispatcher.edge.test.js +0 -82
  39. package/clients/dispatch/dispatcher.edge.test.ts +0 -100
  40. package/clients/dispatch/dispatcher.format.test.js +0 -46
  41. package/clients/dispatch/dispatcher.format.test.ts +0 -58
  42. package/clients/dispatch/dispatcher.inline.test.js +0 -74
  43. package/clients/dispatch/dispatcher.inline.test.ts +0 -93
  44. package/clients/dispatch/dispatcher.js +0 -381
  45. package/clients/dispatch/dispatcher.test.js +0 -116
  46. package/clients/dispatch/dispatcher.test.ts +0 -149
  47. package/clients/dispatch/integration.js +0 -108
  48. package/clients/dispatch/plan.js +0 -183
  49. package/clients/dispatch/runners/architect.js +0 -83
  50. package/clients/dispatch/runners/architect.test.js +0 -138
  51. package/clients/dispatch/runners/architect.test.ts +0 -162
  52. package/clients/dispatch/runners/ast-grep-napi.js +0 -405
  53. package/clients/dispatch/runners/ast-grep-napi.test.js +0 -107
  54. package/clients/dispatch/runners/ast-grep-napi.test.ts +0 -129
  55. package/clients/dispatch/runners/ast-grep.js +0 -157
  56. package/clients/dispatch/runners/biome.js +0 -55
  57. package/clients/dispatch/runners/config-validation.js +0 -67
  58. package/clients/dispatch/runners/go-vet.js +0 -48
  59. package/clients/dispatch/runners/index.js +0 -47
  60. package/clients/dispatch/runners/lsp.js +0 -102
  61. package/clients/dispatch/runners/oxlint.js +0 -67
  62. package/clients/dispatch/runners/oxlint.test.js +0 -230
  63. package/clients/dispatch/runners/oxlint.test.ts +0 -303
  64. package/clients/dispatch/runners/pyright.js +0 -100
  65. package/clients/dispatch/runners/pyright.test.js +0 -98
  66. package/clients/dispatch/runners/pyright.test.ts +0 -121
  67. package/clients/dispatch/runners/python-slop.js +0 -97
  68. package/clients/dispatch/runners/python-slop.test.js +0 -203
  69. package/clients/dispatch/runners/python-slop.test.ts +0 -298
  70. package/clients/dispatch/runners/ruff.js +0 -48
  71. package/clients/dispatch/runners/rust-clippy.js +0 -102
  72. package/clients/dispatch/runners/scan_codebase.test.js +0 -89
  73. package/clients/dispatch/runners/scan_codebase.test.ts +0 -105
  74. package/clients/dispatch/runners/shellcheck.js +0 -147
  75. package/clients/dispatch/runners/shellcheck.test.js +0 -98
  76. package/clients/dispatch/runners/shellcheck.test.ts +0 -129
  77. package/clients/dispatch/runners/similarity.js +0 -230
  78. package/clients/dispatch/runners/spellcheck.js +0 -106
  79. package/clients/dispatch/runners/spellcheck.test.js +0 -158
  80. package/clients/dispatch/runners/spellcheck.test.ts +0 -214
  81. package/clients/dispatch/runners/tree-sitter.js +0 -246
  82. package/clients/dispatch/runners/ts-lsp.js +0 -125
  83. package/clients/dispatch/runners/ts-slop.js +0 -113
  84. package/clients/dispatch/runners/type-safety.js +0 -142
  85. package/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -134
  86. package/clients/dispatch/runners/utils/runner-helpers.js +0 -115
  87. package/clients/dispatch/runners/utils.js +0 -51
  88. package/clients/dispatch/runners/yaml-rule-parser.js +0 -360
  89. package/clients/dispatch/types.js +0 -16
  90. package/clients/dispatch/utils/format-utils.js +0 -44
  91. package/clients/dogfood.test.js +0 -201
  92. package/clients/dogfood.test.ts +0 -269
  93. package/clients/file-kinds.js +0 -177
  94. package/clients/file-kinds.test.js +0 -169
  95. package/clients/file-kinds.test.ts +0 -210
  96. package/clients/file-time.js +0 -152
  97. package/clients/file-utils.js +0 -40
  98. package/clients/fix-scanners.js +0 -204
  99. package/clients/format-service.js +0 -184
  100. package/clients/formatters.js +0 -488
  101. package/clients/go-client.js +0 -203
  102. package/clients/go-client.test.js +0 -127
  103. package/clients/go-client.test.ts +0 -143
  104. package/clients/installer/index.js +0 -403
  105. package/clients/interviewer-templates.js +0 -75
  106. package/clients/interviewer.js +0 -173
  107. package/clients/jscpd-client.js +0 -196
  108. package/clients/jscpd-client.test.js +0 -127
  109. package/clients/jscpd-client.test.ts +0 -145
  110. package/clients/knip-client.js +0 -239
  111. package/clients/knip-client.test.js +0 -112
  112. package/clients/knip-client.test.ts +0 -128
  113. package/clients/latency-logger.js +0 -40
  114. package/clients/lsp/__tests__/client.test.js +0 -310
  115. package/clients/lsp/__tests__/client.test.ts +0 -412
  116. package/clients/lsp/__tests__/config.test.js +0 -167
  117. package/clients/lsp/__tests__/config.test.ts +0 -217
  118. package/clients/lsp/__tests__/error-recovery.test.js +0 -213
  119. package/clients/lsp/__tests__/error-recovery.test.ts +0 -279
  120. package/clients/lsp/__tests__/integration.test.js +0 -127
  121. package/clients/lsp/__tests__/integration.test.ts +0 -160
  122. package/clients/lsp/__tests__/launch.test.js +0 -313
  123. package/clients/lsp/__tests__/launch.test.ts +0 -394
  124. package/clients/lsp/__tests__/server.test.js +0 -259
  125. package/clients/lsp/__tests__/server.test.ts +0 -332
  126. package/clients/lsp/__tests__/service.test.js +0 -438
  127. package/clients/lsp/__tests__/service.test.ts +0 -530
  128. package/clients/lsp/client.js +0 -350
  129. package/clients/lsp/config.js +0 -112
  130. package/clients/lsp/index.js +0 -318
  131. package/clients/lsp/installer/index.js +0 -391
  132. package/clients/lsp/interactive-install.js +0 -221
  133. package/clients/lsp/language.js +0 -170
  134. package/clients/lsp/launch.js +0 -329
  135. package/clients/lsp/lsp/launch.js +0 -116
  136. package/clients/lsp/lsp/server.js +0 -532
  137. package/clients/lsp/lsp-index.js +0 -10
  138. package/clients/lsp/path-utils.js +0 -5
  139. package/clients/lsp/server.js +0 -725
  140. package/clients/lsp/test-py-spawn/requirements.txt +0 -1
  141. package/clients/lsp/test-py-spawn/test.py +0 -3
  142. package/clients/lsp/test-py-svc/requirements.txt +0 -1
  143. package/clients/lsp/test-py-svc/test.py +0 -3
  144. package/clients/lsp/test-python-project/requirements.txt +0 -1
  145. package/clients/lsp/test-python-project/test.py +0 -5
  146. package/clients/metrics-client.js +0 -107
  147. package/clients/metrics-client.test.js +0 -128
  148. package/clients/metrics-client.test.ts +0 -163
  149. package/clients/metrics-history.js +0 -367
  150. package/clients/path-utils.js +0 -142
  151. package/clients/pipeline.js +0 -272
  152. package/clients/production-readiness.js +0 -522
  153. package/clients/project-index.js +0 -255
  154. package/clients/project-metadata.js +0 -531
  155. package/clients/ruff-client.js +0 -325
  156. package/clients/ruff-client.test.js +0 -132
  157. package/clients/ruff-client.test.ts +0 -153
  158. package/clients/rules-scanner.js +0 -97
  159. package/clients/runner-tracker.js +0 -152
  160. package/clients/rust-client.js +0 -205
  161. package/clients/rust-client.test.js +0 -108
  162. package/clients/rust-client.test.ts +0 -130
  163. package/clients/safe-spawn-async.js +0 -163
  164. package/clients/safe-spawn.js +0 -241
  165. package/clients/sanitize.js +0 -291
  166. package/clients/sanitize.test.js +0 -177
  167. package/clients/sanitize.test.ts +0 -223
  168. package/clients/scan-architectural-debt.js +0 -167
  169. package/clients/scan-utils.js +0 -83
  170. package/clients/secrets-scanner.js +0 -119
  171. package/clients/secrets-scanner.test.js +0 -100
  172. package/clients/secrets-scanner.test.ts +0 -113
  173. package/clients/sg-runner.js +0 -292
  174. package/clients/state-matrix.js +0 -160
  175. package/clients/subprocess-client.js +0 -65
  176. package/clients/symbol-types.js +0 -5
  177. package/clients/test-runner-client.js +0 -523
  178. package/clients/test-runner-client.test.js +0 -192
  179. package/clients/test-runner-client.test.ts +0 -253
  180. package/clients/test-utils.js +0 -27
  181. package/clients/test-utils.ts +0 -36
  182. package/clients/todo-scanner.js +0 -200
  183. package/clients/todo-scanner.test.js +0 -301
  184. package/clients/todo-scanner.test.ts +0 -352
  185. package/clients/tool-availability.js +0 -207
  186. package/clients/tree-sitter-client.js +0 -601
  187. package/clients/tree-sitter-query-loader.js +0 -355
  188. package/clients/tree-sitter-symbol-extractor.js +0 -289
  189. package/clients/ts-service.js +0 -129
  190. package/clients/type-coverage-client.js +0 -127
  191. package/clients/type-coverage-client.test.js +0 -105
  192. package/clients/type-coverage-client.test.ts +0 -125
  193. package/clients/type-safety-client.js +0 -138
  194. package/clients/types.js +0 -11
  195. package/clients/typescript-client.codefix.test.js +0 -157
  196. package/clients/typescript-client.codefix.test.ts +0 -186
  197. package/clients/typescript-client.js +0 -509
  198. package/clients/typescript-client.test.js +0 -105
  199. package/clients/typescript-client.test.ts +0 -126
  200. package/commands/booboo.js +0 -1007
  201. package/commands/fix-from-booboo.js +0 -398
  202. package/commands/fix-simplified.js +0 -618
  203. package/commands/rate.js +0 -281
  204. package/commands/rate.test.js +0 -119
  205. package/commands/rate.test.ts +0 -131
  206. package/commands/refactor.js +0 -130
@@ -1,381 +0,0 @@
1
- /**
2
- * Declarative Tool Dispatcher for pi-lens
3
- *
4
- * Redesigned to handle the full complexity of pi-lens's tool_result handler:
5
- * - Multiple tools with different semantics (blocking, warning, silent)
6
- * - Delta mode (baseline tracking)
7
- * - Autofix handling
8
- * - Output aggregation and formatting
9
- *
10
- * Key abstractions:
11
- * - RunnerDefinition: A tool that can be run
12
- * - Diagnostic: Structured issue representation
13
- * - OutputSemantic: How to display (blocking, warning, silent, etc.)
14
- * - BaselineStore: Track pre-existing issues for delta mode
15
- */
16
- import { detectFileKind } from "../file-kinds.js";
17
- import { isTestFile } from "../file-utils.js";
18
- import { logLatency } from "../latency-logger.js";
19
- import { normalizeMapKey } from "../path-utils.js";
20
- import { safeSpawn } from "../safe-spawn.js";
21
- import { formatDiagnostics } from "./utils/format-utils.js";
22
- // --- In-Memory Baseline Store ---
23
- // DEBUG TEST EDIT - Testing dispatch logging
24
- export function createBaselineStore() {
25
- const baselines = new Map();
26
- return {
27
- get(filePath) {
28
- return baselines.get(normalizeMapKey(filePath));
29
- },
30
- set(filePath, diagnostics) {
31
- baselines.set(normalizeMapKey(filePath), diagnostics);
32
- },
33
- clear() {
34
- baselines.clear();
35
- },
36
- };
37
- }
38
- // --- Runner Registry ---
39
- const globalRegistry = new Map();
40
- export function registerRunner(runner) {
41
- if (globalRegistry.has(runner.id))
42
- return; // Already registered, skip silently
43
- globalRegistry.set(runner.id, runner);
44
- }
45
- export function getRunner(id) {
46
- return globalRegistry.get(id);
47
- }
48
- export function getRunnersForKind(kind, filePath) {
49
- if (!kind)
50
- return [];
51
- const runners = [];
52
- const isTest = filePath ? isTestFile(filePath) : false;
53
- for (const runner of globalRegistry.values()) {
54
- // Skip runners that shouldn't run on test files
55
- if (isTest && runner.skipTestFiles)
56
- continue;
57
- if (runner.appliesTo.includes(kind) || runner.appliesTo.length === 0) {
58
- runners.push(runner);
59
- }
60
- }
61
- return runners.sort((a, b) => a.priority - b.priority);
62
- }
63
- export function listRunners() {
64
- return Array.from(globalRegistry.values());
65
- }
66
- /**
67
- * Clear all registered runners. Used primarily for testing.
68
- */
69
- export function clearRunnerRegistry() {
70
- globalRegistry.clear();
71
- }
72
- // --- Tool Availability Cache ---
73
- const toolCache = new Map();
74
- function checkToolAvailability(command) {
75
- if (toolCache.has(command)) {
76
- return toolCache.get(command);
77
- }
78
- try {
79
- const result = safeSpawn(command, ["--version"], {
80
- timeout: 5000,
81
- });
82
- const available = result.status === 0;
83
- toolCache.set(command, available);
84
- return available;
85
- }
86
- catch {
87
- toolCache.set(command, false);
88
- return false;
89
- }
90
- }
91
- // --- Dispatch Context Factory ---
92
- export function createDispatchContext(filePath, cwd, pi, baselines, blockingOnly) {
93
- // Normalize path for consistent Map key usage on Windows
94
- const normalizedFilePath = normalizeMapKey(filePath);
95
- const kind = detectFileKind(normalizedFilePath);
96
- return {
97
- filePath: normalizedFilePath,
98
- cwd,
99
- kind,
100
- pi,
101
- autofix: !!(pi.getFlag("autofix-biome") || pi.getFlag("autofix-ruff")),
102
- deltaMode: !pi.getFlag("no-delta"),
103
- baselines: baselines ?? createBaselineStore(),
104
- blockingOnly,
105
- async hasTool(command) {
106
- return checkToolAvailability(command);
107
- },
108
- log(message) {
109
- console.error(`[dispatch] ${message}`);
110
- },
111
- };
112
- }
113
- // --- Delta Mode Logic ---
114
- /**
115
- * Filter diagnostics to only show NEW issues (delta mode)
116
- */
117
- function filterDelta(after, before, keyFn) {
118
- const beforeSet = new Set((before ?? []).map(keyFn));
119
- const afterSet = new Set(after.map(keyFn));
120
- const fixed = (before ?? []).filter((d) => !afterSet.has(keyFn(d)));
121
- const newItems = after.filter((d) => !beforeSet.has(keyFn(d)));
122
- return { new: newItems, fixed };
123
- }
124
- const latencyReports = [];
125
- export function getLatencyReports() {
126
- return [...latencyReports];
127
- }
128
- export function clearLatencyReports() {
129
- latencyReports.length = 0;
130
- }
131
- export function formatLatencyReport(report) {
132
- const lines = [];
133
- lines.push(`\n═══════════════════════════════════════════════════════════════`);
134
- lines.push(`📊 DISPATCH LATENCY REPORT: ${report.filePath.split("/").pop()}`);
135
- lines.push(` Kind: ${report.fileKind || "unknown"} | Total: ${report.totalDurationMs}ms`);
136
- lines.push(`───────────────────────────────────────────────────────────────`);
137
- lines.push(`Runner Duration Status Issues Semantic`);
138
- lines.push(`───────────────────────────────────────────────────────────────`);
139
- for (const r of report.runners) {
140
- const name = r.runnerId.padEnd(30);
141
- const dur = `${r.durationMs}ms`.padStart(8);
142
- const status = r.status.padStart(9);
143
- const issues = String(r.diagnosticCount).padStart(6);
144
- const sem = r.semantic.padStart(8);
145
- const slowMarker = r.durationMs > 500 ? " 🔥" : r.durationMs > 100 ? " ⚡" : "";
146
- lines.push(`${name}${dur}${status}${issues}${sem}${slowMarker}`);
147
- }
148
- lines.push(`───────────────────────────────────────────────────────────────`);
149
- lines.push(`Total: ${report.runners.length} runners | Stopped early: ${report.stoppedEarly}`);
150
- lines.push(`Diagnostics: ${report.totalDiagnostics} (${report.blockers} blockers, ${report.warnings} warnings)`);
151
- // Show top 3 slowest
152
- const sorted = [...report.runners].sort((a, b) => b.durationMs - a.durationMs);
153
- if (sorted.length > 0 && sorted[0].durationMs > 100) {
154
- lines.push(`\n🐌 Slowest runners:`);
155
- for (const r of sorted.slice(0, 3)) {
156
- if (r.durationMs > 50) {
157
- lines.push(` ${r.runnerId}: ${r.durationMs}ms (${r.status})`);
158
- }
159
- }
160
- }
161
- lines.push(`═══════════════════════════════════════════════════════════════`);
162
- return lines.join("\n");
163
- }
164
- // --- Main Dispatch Function ---
165
- export async function dispatchForFile(ctx, groups) {
166
- const _overallStart = Date.now();
167
- const allDiagnostics = [];
168
- const _fixed = [];
169
- let stopped = false;
170
- const runnerLatencies = [];
171
- // Debug logging goes to latency log only (not console - avoid noise)
172
- const allRunnerIds = groups.flatMap((g) => g.runnerIds);
173
- logLatency({
174
- type: "phase",
175
- filePath: ctx.filePath,
176
- phase: "dispatch_start",
177
- durationMs: 0,
178
- metadata: {
179
- groupCount: groups.length,
180
- kind: ctx.kind,
181
- runners: allRunnerIds.join(","),
182
- },
183
- });
184
- for (const group of groups) {
185
- if (stopped && ctx.pi.getFlag("stop-on-error")) {
186
- break;
187
- }
188
- // Filter runners by kind if specified
189
- const runnerIds = group.filterKinds
190
- ? group.runnerIds.filter((id) => {
191
- const runner = getRunner(id);
192
- return runner && ctx.kind && group.filterKinds?.includes(ctx.kind);
193
- })
194
- : group.runnerIds;
195
- const semantic = group.semantic ?? "warning";
196
- for (const runnerId of runnerIds) {
197
- const runnerStart = Date.now();
198
- const runner = getRunner(runnerId);
199
- if (!runner) {
200
- runnerLatencies.push({
201
- runnerId,
202
- startTime: runnerStart,
203
- endTime: Date.now(),
204
- durationMs: 0,
205
- status: "skipped",
206
- diagnosticCount: 0,
207
- semantic: "unknown",
208
- });
209
- logLatency({
210
- type: "runner",
211
- filePath: ctx.filePath,
212
- runnerId,
213
- durationMs: 0,
214
- status: "not_registered",
215
- diagnosticCount: 0,
216
- semantic: "unknown",
217
- });
218
- continue;
219
- }
220
- // Check preconditions
221
- if (runner.when && !(await runner.when(ctx))) {
222
- runnerLatencies.push({
223
- runnerId,
224
- startTime: runnerStart,
225
- endTime: Date.now(),
226
- durationMs: Date.now() - runnerStart,
227
- status: "when_skipped",
228
- diagnosticCount: 0,
229
- semantic: runner.id,
230
- });
231
- logLatency({
232
- type: "runner",
233
- filePath: ctx.filePath,
234
- runnerId,
235
- durationMs: 0,
236
- status: "when_skipped",
237
- diagnosticCount: 0,
238
- semantic: "when_condition",
239
- });
240
- continue;
241
- }
242
- const result = await runRunner(ctx, runner, semantic);
243
- const runnerEnd = Date.now();
244
- const duration = runnerEnd - runnerStart;
245
- // Track latency for this runner
246
- runnerLatencies.push({
247
- runnerId,
248
- startTime: runnerStart,
249
- endTime: runnerEnd,
250
- durationMs: duration,
251
- status: result.status,
252
- diagnosticCount: result.diagnostics.length,
253
- semantic: result.semantic ?? semantic,
254
- });
255
- // IMMEDIATE LOG: Each runner result (for debugging)
256
- logLatency({
257
- type: "runner",
258
- filePath: ctx.filePath,
259
- runnerId,
260
- durationMs: duration,
261
- status: result.status,
262
- diagnosticCount: result.diagnostics.length,
263
- semantic: result.semantic ?? semantic,
264
- });
265
- // Apply delta mode filtering
266
- let diagnostics = result.diagnostics;
267
- if (ctx.deltaMode && result.semantic !== "silent") {
268
- const before = ctx.baselines.get(ctx.filePath);
269
- if (before) {
270
- const filtered = filterDelta(diagnostics, before, (d) => d.id);
271
- diagnostics = filtered.new;
272
- // TODO: Track fixed diagnostics
273
- }
274
- // Update baseline
275
- ctx.baselines.set(ctx.filePath, [...allDiagnostics, ...diagnostics]);
276
- }
277
- allDiagnostics.push(...diagnostics);
278
- // Check for blockers - use result semantic (not group default) and check individual diagnostics
279
- const resultSemantic = result.semantic ?? semantic;
280
- if (resultSemantic === "blocking" && diagnostics.length > 0) {
281
- stopped = true;
282
- }
283
- // Also check if any individual diagnostic is blocking
284
- if (diagnostics.some((d) => d.semantic === "blocking")) {
285
- stopped = true;
286
- }
287
- }
288
- }
289
- // Categorize results
290
- const blockers = allDiagnostics.filter((d) => d.semantic === "blocking");
291
- const warnings = allDiagnostics.filter((d) => d.semantic === "warning" || d.semantic === "none");
292
- const fixedItems = allDiagnostics.filter((d) => d.semantic === "fixed");
293
- // Format output — only blocking issues shown inline
294
- // Warnings tracked but not shown (noise) — surfaced via /lens-booboo
295
- let output = formatDiagnostics(blockers, "blocking");
296
- output += formatDiagnostics(fixedItems, "fixed");
297
- // Generate and store latency report
298
- const overallEnd = Date.now();
299
- const latencyReport = {
300
- filePath: ctx.filePath,
301
- fileKind: ctx.kind,
302
- overallStartMs: _overallStart,
303
- overallEndMs: overallEnd,
304
- totalDurationMs: overallEnd - _overallStart,
305
- runners: runnerLatencies,
306
- stoppedEarly: stopped,
307
- totalDiagnostics: allDiagnostics.length,
308
- blockers: blockers.length,
309
- warnings: warnings.length,
310
- };
311
- // Store for later analysis
312
- latencyReports.push(latencyReport);
313
- // Keep only last 100 reports to prevent memory bloat
314
- if (latencyReports.length > 100) {
315
- latencyReports.shift();
316
- }
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
320
- // Log summary to latency log only (not console - avoid noise)
321
- logLatency({
322
- type: "tool_result",
323
- filePath: ctx.filePath,
324
- durationMs: latencyReport.totalDurationMs,
325
- result: "dispatch_complete",
326
- metadata: {
327
- runners: runnerLatencies.map((r) => ({
328
- id: r.runnerId,
329
- duration: r.durationMs,
330
- status: r.status,
331
- })),
332
- totalDiagnostics: allDiagnostics.length,
333
- blockers: blockers.length,
334
- },
335
- });
336
- return {
337
- diagnostics: allDiagnostics,
338
- blockers,
339
- warnings,
340
- fixed: fixedItems,
341
- output,
342
- hasBlockers: blockers.length > 0,
343
- };
344
- }
345
- // --- Run Single Runner ---
346
- async function runRunner(ctx, runner, defaultSemantic) {
347
- try {
348
- const result = await runner.run(ctx);
349
- return {
350
- ...result,
351
- semantic: result.semantic ?? defaultSemantic,
352
- };
353
- }
354
- catch (error) {
355
- ctx.log(`Runner ${runner.id} failed: ${error}`);
356
- return {
357
- status: "failed",
358
- diagnostics: [],
359
- semantic: defaultSemantic,
360
- };
361
- }
362
- }
363
- // --- Simple Integration Helper ---
364
- export async function dispatchLint(filePath, cwd, pi, baselines) {
365
- // By default, only run BLOCKING rules for fast feedback on file write
366
- const ctx = createDispatchContext(filePath, cwd, pi, baselines, true);
367
- // Get runners for this file kind
368
- const runners = getRunnersForKind(ctx.kind);
369
- if (runners.length === 0) {
370
- return "";
371
- }
372
- // Create groups from registered runners (all in fallback mode)
373
- const groups = [
374
- {
375
- mode: "fallback",
376
- runnerIds: runners.map((r) => r.id),
377
- },
378
- ];
379
- const result = await dispatchForFile(ctx, groups);
380
- return result.output;
381
- }
@@ -1,116 +0,0 @@
1
- /**
2
- * Tests for declarative dispatch system
3
- */
4
- import { beforeEach, describe, expect, it } from "vitest";
5
- import { createDispatchContext, getRunner, getRunnersForKind, listRunners, registerRunner, } from "./dispatcher.js";
6
- // --- Test Runners ---
7
- const testRunner1 = {
8
- id: "test-runner-1",
9
- appliesTo: ["jsts", "python"],
10
- priority: 10,
11
- enabledByDefault: true,
12
- async run() {
13
- return { status: "succeeded", diagnostics: [], semantic: "none" };
14
- },
15
- };
16
- const testRunner2 = {
17
- id: "test-runner-2",
18
- appliesTo: ["python"],
19
- priority: 20,
20
- enabledByDefault: true,
21
- async run() {
22
- return { status: "succeeded", diagnostics: [], semantic: "none" };
23
- },
24
- };
25
- const testRunnerWithCondition = {
26
- id: "test-runner-conditional",
27
- appliesTo: ["jsts"],
28
- priority: 5,
29
- enabledByDefault: false,
30
- when: async (ctx) => ctx.autofix,
31
- async run() {
32
- return { status: "succeeded", diagnostics: [], semantic: "none" };
33
- },
34
- };
35
- // --- Tests ---
36
- describe("Runner Registry", () => {
37
- beforeEach(() => {
38
- // Note: In a real test suite, we'd reset the registry between tests
39
- registerRunner(testRunner1);
40
- registerRunner(testRunner2);
41
- registerRunner(testRunnerWithCondition);
42
- });
43
- it("should register a runner", () => {
44
- const runner = getRunner("test-runner-1");
45
- expect(runner).toBeDefined();
46
- expect(runner?.id).toBe("test-runner-1");
47
- });
48
- it("should return undefined for unknown runner", () => {
49
- const runner = getRunner("unknown-runner");
50
- expect(runner).toBeUndefined();
51
- });
52
- it("should get runners for a specific kind", () => {
53
- const jstsRunners = getRunnersForKind("jsts");
54
- expect(jstsRunners.length).toBeGreaterThan(0);
55
- expect(jstsRunners.some((r) => r.id === "test-runner-1")).toBe(true);
56
- });
57
- it("should return runners sorted by priority", () => {
58
- const jstsRunners = getRunnersForKind("jsts");
59
- const priorities = jstsRunners.map((r) => r.priority ?? 100);
60
- for (let i = 1; i < priorities.length; i++) {
61
- expect(priorities[i - 1]).toBeLessThanOrEqual(priorities[i]);
62
- }
63
- });
64
- it("should list all registered runners", () => {
65
- const all = listRunners();
66
- expect(all.length).toBeGreaterThanOrEqual(3);
67
- });
68
- it("should reject duplicate registrations", () => {
69
- // This should log an error but not throw
70
- expect(() => registerRunner(testRunner1)).not.toThrow();
71
- });
72
- });
73
- describe("Dispatch Context", () => {
74
- it("should create a dispatch context", () => {
75
- const mockPi = { getFlag: (flag) => flag === "autofix" };
76
- const ctx = createDispatchContext("test.ts", "/project", mockPi);
77
- // Path is normalized to absolute path (Windows compatibility)
78
- expect(ctx.filePath).toContain("test.ts");
79
- expect(ctx.cwd).toBe("/project");
80
- expect(ctx.autofix).toBe(false);
81
- expect(ctx.deltaMode).toBe(true);
82
- });
83
- it("should detect file kind", () => {
84
- const mockPi = { getFlag: () => false };
85
- const ctxTs = createDispatchContext("test.ts", "/project", mockPi);
86
- expect(ctxTs.kind).toBe("jsts");
87
- const ctxPy = createDispatchContext("test.py", "/project", mockPi);
88
- expect(ctxPy.kind).toBe("python");
89
- const ctxGo = createDispatchContext("test.go", "/project", mockPi);
90
- expect(ctxGo.kind).toBe("go");
91
- });
92
- it("should respect autofix flag", () => {
93
- const mockPiNoFix = { getFlag: (_f) => false };
94
- const ctx1 = createDispatchContext("test.ts", "/project", mockPiNoFix);
95
- expect(ctx1.autofix).toBe(false);
96
- const mockPiWithFix = { getFlag: (f) => f === "autofix-biome" };
97
- const ctx2 = createDispatchContext("test.ts", "/project", mockPiWithFix);
98
- expect(ctx2.autofix).toBe(true);
99
- });
100
- });
101
- describe("Conditional Runners", () => {
102
- beforeEach(() => {
103
- registerRunner(testRunnerWithCondition);
104
- });
105
- it("should respect when condition", async () => {
106
- const runner = getRunner("test-runner-conditional");
107
- expect(runner).toBeDefined();
108
- const mockPiNoFix = { getFlag: () => false };
109
- const ctxNoFix = createDispatchContext("test.ts", "/project", mockPiNoFix);
110
- // When autofix is false, the condition should return false
111
- if (runner?.when) {
112
- const shouldRun = await runner.when(ctxNoFix);
113
- expect(shouldRun).toBe(false);
114
- }
115
- });
116
- });
@@ -1,149 +0,0 @@
1
- /**
2
- * Tests for declarative dispatch system
3
- */
4
-
5
- import { beforeEach, describe, expect, it } from "vitest";
6
- import {
7
- createDispatchContext,
8
- getRunner,
9
- getRunnersForKind,
10
- listRunners,
11
- registerRunner,
12
- } from "./dispatcher.js";
13
- import type { RunnerDefinition, RunnerResult } from "./types.js";
14
-
15
- // --- Test Runners ---
16
-
17
- const testRunner1: RunnerDefinition = {
18
- id: "test-runner-1",
19
- appliesTo: ["jsts", "python"],
20
- priority: 10,
21
- enabledByDefault: true,
22
- async run(): Promise<RunnerResult> {
23
- return { status: "succeeded", diagnostics: [], semantic: "none" };
24
- },
25
- };
26
-
27
- const testRunner2: RunnerDefinition = {
28
- id: "test-runner-2",
29
- appliesTo: ["python"],
30
- priority: 20,
31
- enabledByDefault: true,
32
- async run(): Promise<RunnerResult> {
33
- return { status: "succeeded", diagnostics: [], semantic: "none" };
34
- },
35
- };
36
-
37
- const testRunnerWithCondition: RunnerDefinition = {
38
- id: "test-runner-conditional",
39
- appliesTo: ["jsts"],
40
- priority: 5,
41
- enabledByDefault: false,
42
- when: async (ctx) => ctx.autofix,
43
- async run(): Promise<RunnerResult> {
44
- return { status: "succeeded", diagnostics: [], semantic: "none" };
45
- },
46
- };
47
-
48
- // --- Tests ---
49
-
50
- describe("Runner Registry", () => {
51
- beforeEach(() => {
52
- // Note: In a real test suite, we'd reset the registry between tests
53
- registerRunner(testRunner1);
54
- registerRunner(testRunner2);
55
- registerRunner(testRunnerWithCondition);
56
- });
57
-
58
- it("should register a runner", () => {
59
- const runner = getRunner("test-runner-1");
60
- expect(runner).toBeDefined();
61
- expect(runner?.id).toBe("test-runner-1");
62
- });
63
-
64
- it("should return undefined for unknown runner", () => {
65
- const runner = getRunner("unknown-runner");
66
- expect(runner).toBeUndefined();
67
- });
68
-
69
- it("should get runners for a specific kind", () => {
70
- const jstsRunners = getRunnersForKind("jsts");
71
- expect(jstsRunners.length).toBeGreaterThan(0);
72
- expect(jstsRunners.some((r) => r.id === "test-runner-1")).toBe(true);
73
- });
74
-
75
- it("should return runners sorted by priority", () => {
76
- const jstsRunners = getRunnersForKind("jsts");
77
- const priorities = jstsRunners.map((r) => r.priority ?? 100);
78
- for (let i = 1; i < priorities.length; i++) {
79
- expect(priorities[i - 1]).toBeLessThanOrEqual(priorities[i]);
80
- }
81
- });
82
-
83
- it("should list all registered runners", () => {
84
- const all = listRunners();
85
- expect(all.length).toBeGreaterThanOrEqual(3);
86
- });
87
-
88
- it("should reject duplicate registrations", () => {
89
- // This should log an error but not throw
90
- expect(() => registerRunner(testRunner1)).not.toThrow();
91
- });
92
- });
93
-
94
- describe("Dispatch Context", () => {
95
- it("should create a dispatch context", () => {
96
- const mockPi = { getFlag: (flag: string) => flag === "autofix" };
97
-
98
- const ctx = createDispatchContext("test.ts", "/project", mockPi);
99
-
100
- // Path is normalized to absolute path (Windows compatibility)
101
- expect(ctx.filePath).toContain("test.ts");
102
- expect(ctx.cwd).toBe("/project");
103
- expect(ctx.autofix).toBe(false);
104
- expect(ctx.deltaMode).toBe(true);
105
- });
106
-
107
- it("should detect file kind", () => {
108
- const mockPi = { getFlag: () => false };
109
-
110
- const ctxTs = createDispatchContext("test.ts", "/project", mockPi);
111
- expect(ctxTs.kind).toBe("jsts");
112
-
113
- const ctxPy = createDispatchContext("test.py", "/project", mockPi);
114
- expect(ctxPy.kind).toBe("python");
115
-
116
- const ctxGo = createDispatchContext("test.go", "/project", mockPi);
117
- expect(ctxGo.kind).toBe("go");
118
- });
119
-
120
- it("should respect autofix flag", () => {
121
- const mockPiNoFix = { getFlag: (_f: string) => false };
122
- const ctx1 = createDispatchContext("test.ts", "/project", mockPiNoFix);
123
- expect(ctx1.autofix).toBe(false);
124
-
125
- const mockPiWithFix = { getFlag: (f: string) => f === "autofix-biome" };
126
- const ctx2 = createDispatchContext("test.ts", "/project", mockPiWithFix);
127
- expect(ctx2.autofix).toBe(true);
128
- });
129
- });
130
-
131
- describe("Conditional Runners", () => {
132
- beforeEach(() => {
133
- registerRunner(testRunnerWithCondition);
134
- });
135
-
136
- it("should respect when condition", async () => {
137
- const runner = getRunner("test-runner-conditional");
138
- expect(runner).toBeDefined();
139
-
140
- const mockPiNoFix = { getFlag: () => false };
141
- const ctxNoFix = createDispatchContext("test.ts", "/project", mockPiNoFix);
142
-
143
- // When autofix is false, the condition should return false
144
- if (runner?.when) {
145
- const shouldRun = await runner.when(ctxNoFix);
146
- expect(shouldRun).toBe(false);
147
- }
148
- });
149
- });