pi-lens 3.2.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +4 -10
- package/clients/__tests__/file-time.test.js +216 -0
- package/clients/__tests__/format-service.test.js +245 -0
- package/clients/__tests__/formatters.test.js +271 -0
- package/clients/agent-behavior-client.test.js +94 -0
- package/clients/biome-client.test.js +144 -0
- package/clients/cache-manager.test.js +197 -0
- package/clients/complexity-client.test.js +234 -0
- package/clients/dependency-checker.test.js +60 -0
- package/clients/dispatch/__tests__/autofix-integration.test.js +245 -0
- package/clients/dispatch/__tests__/runner-registration.test.js +234 -0
- package/clients/dispatch/__tests__/runner-registration.test.ts +2 -2
- package/clients/dispatch/dispatcher.edge.test.js +82 -0
- package/clients/dispatch/dispatcher.format.test.js +46 -0
- package/clients/dispatch/dispatcher.inline.test.js +74 -0
- package/clients/dispatch/dispatcher.test.js +116 -0
- package/clients/dispatch/runners/architect.test.js +138 -0
- package/clients/dispatch/runners/ast-grep-napi.test.js +106 -0
- package/clients/dispatch/runners/lsp.js +42 -5
- package/clients/dispatch/runners/oxlint.test.js +230 -0
- package/clients/dispatch/runners/pyright.test.js +98 -0
- package/clients/dispatch/runners/python-slop.test.js +203 -0
- package/clients/dispatch/runners/scan_codebase.test.js +89 -0
- package/clients/dispatch/runners/shellcheck.test.js +98 -0
- package/clients/dispatch/runners/spellcheck.test.js +158 -0
- package/clients/dispatch/utils/format-utils.js +1 -6
- package/clients/dispatch/utils/format-utils.ts +1 -6
- package/clients/dogfood.test.js +201 -0
- package/clients/file-kinds.test.js +169 -0
- package/clients/formatters.js +1 -1
- package/clients/go-client.test.js +127 -0
- package/clients/jscpd-client.test.js +127 -0
- package/clients/knip-client.test.js +112 -0
- package/clients/lsp/__tests__/client.test.js +310 -0
- package/clients/lsp/__tests__/client.test.ts +1 -46
- package/clients/lsp/__tests__/config.test.js +167 -0
- package/clients/lsp/__tests__/error-recovery.test.js +213 -0
- package/clients/lsp/__tests__/integration.test.js +127 -0
- package/clients/lsp/__tests__/launch.test.js +313 -0
- package/clients/lsp/__tests__/server.test.js +259 -0
- package/clients/lsp/__tests__/service.test.js +435 -0
- package/clients/lsp/client.js +32 -44
- package/clients/lsp/client.ts +36 -45
- package/clients/lsp/launch.js +11 -6
- package/clients/lsp/launch.ts +11 -6
- package/clients/lsp/server.js +27 -2
- package/clients/metrics-client.test.js +141 -0
- package/clients/ruff-client.test.js +132 -0
- package/clients/rust-client.test.js +108 -0
- package/clients/sanitize.test.js +177 -0
- package/clients/secrets-scanner.test.js +100 -0
- package/clients/test-runner-client.test.js +192 -0
- package/clients/todo-scanner.test.js +301 -0
- package/clients/type-coverage-client.test.js +105 -0
- package/clients/typescript-client.codefix.test.js +157 -0
- package/clients/typescript-client.test.js +105 -0
- package/commands/rate.test.js +119 -0
- package/index.ts +66 -72
- package/package.json +1 -1
- package/clients/bus/bus.js +0 -191
- package/clients/bus/bus.ts +0 -251
- package/clients/bus/events.js +0 -214
- package/clients/bus/events.ts +0 -279
- package/clients/bus/index.js +0 -8
- package/clients/bus/index.ts +0 -9
- package/clients/bus/integration.js +0 -158
- package/clients/bus/integration.ts +0 -227
- package/clients/dispatch/bus-dispatcher.js +0 -178
- package/clients/dispatch/bus-dispatcher.ts +0 -258
- package/clients/services/__tests__/effect-integration.test.ts +0 -111
- package/clients/services/effect-integration.js +0 -198
- package/clients/services/effect-integration.ts +0 -276
- package/clients/services/index.js +0 -7
- package/clients/services/index.ts +0 -8
- package/clients/services/runner-service.js +0 -134
- package/clients/services/runner-service.ts +0 -225
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { DiagnosticFound, FileModified, ReportReady, RunnerCompleted, RunnerStarted, } from "../bus/events.js";
|
|
2
|
-
import { formatDiagnostics } from "./utils/format-utils.js";
|
|
3
|
-
// Import runners to register them
|
|
4
|
-
import "./runners/index.js";
|
|
5
|
-
// --- Core Functions ---
|
|
6
|
-
async function runRunner(ctx, runner, defaultSemantic) {
|
|
7
|
-
const startTime = Date.now();
|
|
8
|
-
// Publish runner started event
|
|
9
|
-
RunnerStarted.publish({
|
|
10
|
-
runnerId: runner.id,
|
|
11
|
-
filePath: ctx.filePath,
|
|
12
|
-
timestamp: startTime,
|
|
13
|
-
});
|
|
14
|
-
try {
|
|
15
|
-
// Check when() condition async-safely (sync filter in caller can't await Promises)
|
|
16
|
-
if (runner.when && !(await runner.when(ctx))) {
|
|
17
|
-
return {
|
|
18
|
-
status: "skipped",
|
|
19
|
-
diagnostics: [],
|
|
20
|
-
semantic: defaultSemantic,
|
|
21
|
-
durationMs: Date.now() - startTime,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
const result = await runner.run(ctx);
|
|
25
|
-
const durationMs = Date.now() - startTime;
|
|
26
|
-
// Publish diagnostic found event
|
|
27
|
-
if (result.diagnostics.length > 0) {
|
|
28
|
-
DiagnosticFound.publish({
|
|
29
|
-
runnerId: runner.id,
|
|
30
|
-
filePath: ctx.filePath,
|
|
31
|
-
diagnostics: result.diagnostics,
|
|
32
|
-
durationMs,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
// Publish runner completed event
|
|
36
|
-
// Map "succeeded" to "completed" for the event status
|
|
37
|
-
const eventStatus = result.status === "succeeded" ? "completed" : result.status;
|
|
38
|
-
RunnerCompleted.publish({
|
|
39
|
-
runnerId: runner.id,
|
|
40
|
-
filePath: ctx.filePath,
|
|
41
|
-
status: eventStatus,
|
|
42
|
-
durationMs,
|
|
43
|
-
diagnosticCount: result.diagnostics.length,
|
|
44
|
-
});
|
|
45
|
-
return {
|
|
46
|
-
...result,
|
|
47
|
-
semantic: result.semantic ?? defaultSemantic,
|
|
48
|
-
durationMs,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
const durationMs = Date.now() - startTime;
|
|
53
|
-
ctx.log?.(`Runner ${runner.id} failed: ${error}`);
|
|
54
|
-
RunnerCompleted.publish({
|
|
55
|
-
runnerId: runner.id,
|
|
56
|
-
filePath: ctx.filePath,
|
|
57
|
-
status: "failed",
|
|
58
|
-
durationMs,
|
|
59
|
-
diagnosticCount: 0,
|
|
60
|
-
});
|
|
61
|
-
return {
|
|
62
|
-
status: "failed",
|
|
63
|
-
diagnostics: [],
|
|
64
|
-
semantic: defaultSemantic,
|
|
65
|
-
durationMs,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// --- Concurrent Dispatch (new feature) ---
|
|
70
|
-
export async function dispatchConcurrent(ctx, groups) {
|
|
71
|
-
const startTime = Date.now();
|
|
72
|
-
const allDiagnostics = [];
|
|
73
|
-
const runnerResults = [];
|
|
74
|
-
let stopped = false;
|
|
75
|
-
for (const group of groups) {
|
|
76
|
-
if (stopped && ctx.pi.getFlag("stop-on-error")) {
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
// Get applicable runners
|
|
80
|
-
const { getRunner } = await import("./dispatcher.js");
|
|
81
|
-
const runnerIds = group.filterKinds
|
|
82
|
-
? group.runnerIds.filter((id) => {
|
|
83
|
-
const runner = getRunner(id);
|
|
84
|
-
return runner && ctx.kind && group.filterKinds?.includes(ctx.kind);
|
|
85
|
-
})
|
|
86
|
-
: group.runnerIds;
|
|
87
|
-
// Note: when() is async — must be awaited. Filter it out here synchronously
|
|
88
|
-
// (runners without when always run; runners with when are checked inside runRunner).
|
|
89
|
-
const runners = runnerIds
|
|
90
|
-
.map((id) => getRunner(id))
|
|
91
|
-
.filter((r) => r !== undefined);
|
|
92
|
-
const semantic = group.semantic ?? "warning";
|
|
93
|
-
if (group.mode === "all") {
|
|
94
|
-
// Run all runners concurrently
|
|
95
|
-
const results = await Promise.all(runners.map((runner) => runRunner(ctx, runner, semantic)));
|
|
96
|
-
for (const result of results) {
|
|
97
|
-
runnerResults.push({
|
|
98
|
-
runnerId: runners[results.indexOf(result)].id,
|
|
99
|
-
status: result.status === "succeeded" ? "completed" : result.status,
|
|
100
|
-
durationMs: result.durationMs,
|
|
101
|
-
diagnosticCount: result.diagnostics.length,
|
|
102
|
-
});
|
|
103
|
-
allDiagnostics.push(...result.diagnostics);
|
|
104
|
-
if (semantic === "blocking" && result.diagnostics.length > 0) {
|
|
105
|
-
stopped = true;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else if (group.mode === "fallback") {
|
|
110
|
-
// Run sequentially until first success
|
|
111
|
-
for (const runner of runners) {
|
|
112
|
-
const result = await runRunner(ctx, runner, semantic);
|
|
113
|
-
runnerResults.push({
|
|
114
|
-
runnerId: runner.id,
|
|
115
|
-
status: result.status === "succeeded" ? "completed" : result.status,
|
|
116
|
-
durationMs: result.durationMs,
|
|
117
|
-
diagnosticCount: result.diagnostics.length,
|
|
118
|
-
});
|
|
119
|
-
allDiagnostics.push(...result.diagnostics);
|
|
120
|
-
if (result.diagnostics.length === 0 || result.semantic === "fixed") {
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
// Categorize results
|
|
127
|
-
const blockers = allDiagnostics.filter((d) => d.semantic === "blocking");
|
|
128
|
-
const warnings = allDiagnostics.filter((d) => d.semantic === "warning" || d.semantic === "none");
|
|
129
|
-
const fixedItems = allDiagnostics.filter((d) => d.semantic === "fixed");
|
|
130
|
-
const silentItems = allDiagnostics.filter((d) => d.semantic === "silent");
|
|
131
|
-
// Format output
|
|
132
|
-
let output = formatDiagnostics(blockers, "blocking");
|
|
133
|
-
output += formatDiagnostics(fixedItems, "fixed");
|
|
134
|
-
const durationMs = Date.now() - startTime;
|
|
135
|
-
// Publish report ready event
|
|
136
|
-
ReportReady.publish({
|
|
137
|
-
filePath: ctx.filePath,
|
|
138
|
-
report: {
|
|
139
|
-
blockers,
|
|
140
|
-
warnings,
|
|
141
|
-
fixed: fixedItems,
|
|
142
|
-
silent: silentItems,
|
|
143
|
-
},
|
|
144
|
-
durationMs,
|
|
145
|
-
});
|
|
146
|
-
return {
|
|
147
|
-
diagnostics: allDiagnostics,
|
|
148
|
-
blockers,
|
|
149
|
-
warnings,
|
|
150
|
-
fixed: fixedItems,
|
|
151
|
-
silent: silentItems,
|
|
152
|
-
output,
|
|
153
|
-
hasBlockers: blockers.length > 0,
|
|
154
|
-
durationMs,
|
|
155
|
-
runnerResults,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
// --- Simple Integration Helper ---
|
|
159
|
-
export async function dispatchLintWithBus(filePath, cwd, pi) {
|
|
160
|
-
const { createDispatchContext } = await import("./dispatcher.js");
|
|
161
|
-
const { getRunnersForKind } = await import("./dispatcher.js");
|
|
162
|
-
const { TOOL_PLANS } = await import("./plan.js");
|
|
163
|
-
// Publish file modified event to trigger any background processing
|
|
164
|
-
FileModified.publish({
|
|
165
|
-
filePath,
|
|
166
|
-
changeType: "external",
|
|
167
|
-
});
|
|
168
|
-
// blockingOnly=true: post-write dispatch only reports blocking errors (same as standard dispatchLint)
|
|
169
|
-
const ctx = createDispatchContext(filePath, cwd, pi, undefined, true);
|
|
170
|
-
const kind = ctx.kind;
|
|
171
|
-
if (!kind)
|
|
172
|
-
return "";
|
|
173
|
-
const plan = TOOL_PLANS[kind];
|
|
174
|
-
if (!plan)
|
|
175
|
-
return "";
|
|
176
|
-
const result = await dispatchConcurrent(ctx, plan.groups);
|
|
177
|
-
return result.output;
|
|
178
|
-
}
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Diagnostic,
|
|
3
|
-
DiagnosticFound,
|
|
4
|
-
FileModified,
|
|
5
|
-
type OutputSemantic,
|
|
6
|
-
ReportReady,
|
|
7
|
-
RunnerCompleted,
|
|
8
|
-
RunnerStarted,
|
|
9
|
-
} from "../bus/events.js";
|
|
10
|
-
import { formatDiagnostics } from "./utils/format-utils.js";
|
|
11
|
-
// Import runners to register them
|
|
12
|
-
import "./runners/index.js";
|
|
13
|
-
|
|
14
|
-
import type {
|
|
15
|
-
DispatchContext,
|
|
16
|
-
RunnerDefinition,
|
|
17
|
-
RunnerGroup,
|
|
18
|
-
RunnerResult,
|
|
19
|
-
} from "./types.js";
|
|
20
|
-
|
|
21
|
-
// --- Enhanced Dispatch Result ---
|
|
22
|
-
|
|
23
|
-
export interface BusDispatchResult {
|
|
24
|
-
diagnostics: Diagnostic[];
|
|
25
|
-
blockers: Diagnostic[];
|
|
26
|
-
warnings: Diagnostic[];
|
|
27
|
-
fixed: Diagnostic[];
|
|
28
|
-
silent: Diagnostic[];
|
|
29
|
-
output: string;
|
|
30
|
-
hasBlockers: boolean;
|
|
31
|
-
durationMs: number;
|
|
32
|
-
runnerResults: Array<{
|
|
33
|
-
runnerId: string;
|
|
34
|
-
status: "succeeded" | "failed" | "skipped" | "completed";
|
|
35
|
-
durationMs: number;
|
|
36
|
-
diagnosticCount: number;
|
|
37
|
-
}>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// --- Core Functions ---
|
|
41
|
-
|
|
42
|
-
async function runRunner(
|
|
43
|
-
ctx: DispatchContext,
|
|
44
|
-
runner: RunnerDefinition,
|
|
45
|
-
defaultSemantic: OutputSemantic,
|
|
46
|
-
): Promise<RunnerResult & { durationMs: number }> {
|
|
47
|
-
const startTime = Date.now();
|
|
48
|
-
|
|
49
|
-
// Publish runner started event
|
|
50
|
-
RunnerStarted.publish({
|
|
51
|
-
runnerId: runner.id,
|
|
52
|
-
filePath: ctx.filePath,
|
|
53
|
-
timestamp: startTime,
|
|
54
|
-
});
|
|
55
|
-
|
|
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
|
-
}
|
|
66
|
-
const result = await runner.run(ctx);
|
|
67
|
-
const durationMs = Date.now() - startTime;
|
|
68
|
-
|
|
69
|
-
// Publish diagnostic found event
|
|
70
|
-
if (result.diagnostics.length > 0) {
|
|
71
|
-
DiagnosticFound.publish({
|
|
72
|
-
runnerId: runner.id,
|
|
73
|
-
filePath: ctx.filePath,
|
|
74
|
-
diagnostics: result.diagnostics,
|
|
75
|
-
durationMs,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Publish runner completed event
|
|
80
|
-
// Map "succeeded" to "completed" for the event status
|
|
81
|
-
const eventStatus =
|
|
82
|
-
result.status === "succeeded" ? "completed" : result.status;
|
|
83
|
-
RunnerCompleted.publish({
|
|
84
|
-
runnerId: runner.id,
|
|
85
|
-
filePath: ctx.filePath,
|
|
86
|
-
status: eventStatus,
|
|
87
|
-
durationMs,
|
|
88
|
-
diagnosticCount: result.diagnostics.length,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
...result,
|
|
93
|
-
semantic: result.semantic ?? defaultSemantic,
|
|
94
|
-
durationMs,
|
|
95
|
-
};
|
|
96
|
-
} catch (error) {
|
|
97
|
-
const durationMs = Date.now() - startTime;
|
|
98
|
-
ctx.log?.(`Runner ${runner.id} failed: ${error}`);
|
|
99
|
-
|
|
100
|
-
RunnerCompleted.publish({
|
|
101
|
-
runnerId: runner.id,
|
|
102
|
-
filePath: ctx.filePath,
|
|
103
|
-
status: "failed",
|
|
104
|
-
durationMs,
|
|
105
|
-
diagnosticCount: 0,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
status: "failed",
|
|
110
|
-
diagnostics: [],
|
|
111
|
-
semantic: defaultSemantic,
|
|
112
|
-
durationMs,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// --- Concurrent Dispatch (new feature) ---
|
|
118
|
-
|
|
119
|
-
export async function dispatchConcurrent(
|
|
120
|
-
ctx: DispatchContext,
|
|
121
|
-
groups: RunnerGroup[],
|
|
122
|
-
): Promise<BusDispatchResult> {
|
|
123
|
-
const startTime = Date.now();
|
|
124
|
-
const allDiagnostics: Diagnostic[] = [];
|
|
125
|
-
const runnerResults: BusDispatchResult["runnerResults"] = [];
|
|
126
|
-
let stopped = false;
|
|
127
|
-
|
|
128
|
-
for (const group of groups) {
|
|
129
|
-
if (stopped && ctx.pi.getFlag("stop-on-error")) {
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Get applicable runners
|
|
134
|
-
const { getRunner } = await import("./dispatcher.js");
|
|
135
|
-
const runnerIds = group.filterKinds
|
|
136
|
-
? group.runnerIds.filter((id) => {
|
|
137
|
-
const runner = getRunner(id);
|
|
138
|
-
return runner && ctx.kind && group.filterKinds?.includes(ctx.kind);
|
|
139
|
-
})
|
|
140
|
-
: group.runnerIds;
|
|
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).
|
|
144
|
-
const runners = runnerIds
|
|
145
|
-
.map((id) => getRunner(id))
|
|
146
|
-
.filter((r): r is RunnerDefinition => r !== undefined);
|
|
147
|
-
|
|
148
|
-
const semantic = group.semantic ?? "warning";
|
|
149
|
-
|
|
150
|
-
if (group.mode === "all") {
|
|
151
|
-
// Run all runners concurrently
|
|
152
|
-
const results = await Promise.all(
|
|
153
|
-
runners.map((runner) => runRunner(ctx, runner, semantic)),
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
for (const result of results) {
|
|
157
|
-
runnerResults.push({
|
|
158
|
-
runnerId: runners[results.indexOf(result)].id,
|
|
159
|
-
status: result.status === "succeeded" ? "completed" : result.status,
|
|
160
|
-
durationMs: result.durationMs,
|
|
161
|
-
diagnosticCount: result.diagnostics.length,
|
|
162
|
-
});
|
|
163
|
-
allDiagnostics.push(...result.diagnostics);
|
|
164
|
-
|
|
165
|
-
if (semantic === "blocking" && result.diagnostics.length > 0) {
|
|
166
|
-
stopped = true;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
} else if (group.mode === "fallback") {
|
|
170
|
-
// Run sequentially until first success
|
|
171
|
-
for (const runner of runners) {
|
|
172
|
-
const result = await runRunner(ctx, runner, semantic);
|
|
173
|
-
runnerResults.push({
|
|
174
|
-
runnerId: runner.id,
|
|
175
|
-
status: result.status === "succeeded" ? "completed" : result.status,
|
|
176
|
-
durationMs: result.durationMs,
|
|
177
|
-
diagnosticCount: result.diagnostics.length,
|
|
178
|
-
});
|
|
179
|
-
allDiagnostics.push(...result.diagnostics);
|
|
180
|
-
|
|
181
|
-
if (result.diagnostics.length === 0 || result.semantic === "fixed") {
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Categorize results
|
|
189
|
-
const blockers = allDiagnostics.filter((d) => d.semantic === "blocking");
|
|
190
|
-
const warnings = allDiagnostics.filter(
|
|
191
|
-
(d) => d.semantic === "warning" || d.semantic === "none",
|
|
192
|
-
);
|
|
193
|
-
const fixedItems = allDiagnostics.filter((d) => d.semantic === "fixed");
|
|
194
|
-
const silentItems = allDiagnostics.filter((d) => d.semantic === "silent");
|
|
195
|
-
|
|
196
|
-
// Format output
|
|
197
|
-
let output = formatDiagnostics(blockers, "blocking");
|
|
198
|
-
output += formatDiagnostics(fixedItems, "fixed");
|
|
199
|
-
|
|
200
|
-
const durationMs = Date.now() - startTime;
|
|
201
|
-
|
|
202
|
-
// Publish report ready event
|
|
203
|
-
ReportReady.publish({
|
|
204
|
-
filePath: ctx.filePath,
|
|
205
|
-
report: {
|
|
206
|
-
blockers,
|
|
207
|
-
warnings,
|
|
208
|
-
fixed: fixedItems,
|
|
209
|
-
silent: silentItems,
|
|
210
|
-
},
|
|
211
|
-
durationMs,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
diagnostics: allDiagnostics,
|
|
216
|
-
blockers,
|
|
217
|
-
warnings,
|
|
218
|
-
fixed: fixedItems,
|
|
219
|
-
silent: silentItems,
|
|
220
|
-
output,
|
|
221
|
-
hasBlockers: blockers.length > 0,
|
|
222
|
-
durationMs,
|
|
223
|
-
runnerResults,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// --- Simple Integration Helper ---
|
|
228
|
-
|
|
229
|
-
export async function dispatchLintWithBus(
|
|
230
|
-
filePath: string,
|
|
231
|
-
cwd: string,
|
|
232
|
-
pi: {
|
|
233
|
-
getFlag(flag: string): string | boolean | undefined;
|
|
234
|
-
log?: (msg: string) => void;
|
|
235
|
-
},
|
|
236
|
-
): Promise<string> {
|
|
237
|
-
const { createDispatchContext } = await import("./dispatcher.js");
|
|
238
|
-
const { getRunnersForKind } = await import("./dispatcher.js");
|
|
239
|
-
const { TOOL_PLANS } = await import("./plan.js");
|
|
240
|
-
|
|
241
|
-
// Publish file modified event to trigger any background processing
|
|
242
|
-
FileModified.publish({
|
|
243
|
-
filePath,
|
|
244
|
-
changeType: "external",
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// blockingOnly=true: post-write dispatch only reports blocking errors (same as standard dispatchLint)
|
|
248
|
-
const ctx = createDispatchContext(filePath, cwd, pi, undefined, true);
|
|
249
|
-
|
|
250
|
-
const kind = ctx.kind;
|
|
251
|
-
if (!kind) return "";
|
|
252
|
-
|
|
253
|
-
const plan = TOOL_PLANS[kind];
|
|
254
|
-
if (!plan) return "";
|
|
255
|
-
|
|
256
|
-
const result = await dispatchConcurrent(ctx, plan.groups);
|
|
257
|
-
return result.output;
|
|
258
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Effect Integration Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for Effect-TS concurrent runner execution.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
8
|
-
import type {
|
|
9
|
-
DispatchContext,
|
|
10
|
-
RunnerDefinition,
|
|
11
|
-
RunnerGroup,
|
|
12
|
-
RunnerResult,
|
|
13
|
-
} from "../../dispatch/types.js";
|
|
14
|
-
import {
|
|
15
|
-
clearRunnerRegistry,
|
|
16
|
-
getRunner,
|
|
17
|
-
listRunners,
|
|
18
|
-
registerRunner,
|
|
19
|
-
} from "../../dispatch/dispatcher.js";
|
|
20
|
-
import {
|
|
21
|
-
dispatchLintWithEffect,
|
|
22
|
-
dispatchWithEffect,
|
|
23
|
-
type EffectDispatchResult,
|
|
24
|
-
} from "../effect-integration.js";
|
|
25
|
-
|
|
26
|
-
describe("Effect Integration", () => {
|
|
27
|
-
beforeEach(async () => {
|
|
28
|
-
clearRunnerRegistry();
|
|
29
|
-
// Register a simple test runner
|
|
30
|
-
const testRunner: RunnerDefinition = {
|
|
31
|
-
id: "test-runner",
|
|
32
|
-
appliesTo: ["jsts"],
|
|
33
|
-
priority: 10,
|
|
34
|
-
enabledByDefault: true,
|
|
35
|
-
async run(ctx) {
|
|
36
|
-
return {
|
|
37
|
-
status: "succeeded",
|
|
38
|
-
diagnostics: [{
|
|
39
|
-
id: "test:1",
|
|
40
|
-
message: "Test diagnostic",
|
|
41
|
-
filePath: ctx.filePath,
|
|
42
|
-
severity: "info",
|
|
43
|
-
semantic: "silent",
|
|
44
|
-
tool: "test-runner",
|
|
45
|
-
}],
|
|
46
|
-
semantic: "none",
|
|
47
|
-
};
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
registerRunner(testRunner);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("should have runners registered", () => {
|
|
54
|
-
const runners = listRunners();
|
|
55
|
-
expect(runners.length).toBeGreaterThan(0);
|
|
56
|
-
expect(runners.some(r => r.id === "test-runner")).toBe(true);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("should run effect integration with real runners", async () => {
|
|
60
|
-
const ctx: DispatchContext = {
|
|
61
|
-
filePath: "test.ts",
|
|
62
|
-
cwd: "/test",
|
|
63
|
-
kind: "jsts",
|
|
64
|
-
pi: {
|
|
65
|
-
getFlag: vi.fn(() => false),
|
|
66
|
-
},
|
|
67
|
-
autofix: true,
|
|
68
|
-
deltaMode: false,
|
|
69
|
-
baselines: new Map(),
|
|
70
|
-
hasTool: vi.fn(() => Promise.resolve(false)),
|
|
71
|
-
log: vi.fn(),
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Get actual runners for jsts
|
|
75
|
-
const { getRunnersForKind } = await import("../../dispatch/dispatcher.js");
|
|
76
|
-
const runners = getRunnersForKind("jsts");
|
|
77
|
-
|
|
78
|
-
const group: RunnerGroup = {
|
|
79
|
-
runnerIds: runners.slice(0, 2).map(r => r.id), // Use first 2 runners
|
|
80
|
-
mode: "all",
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const result = await dispatchWithEffect(ctx, [group]);
|
|
84
|
-
|
|
85
|
-
// Just verify it doesn't crash and returns valid result
|
|
86
|
-
expect(result).toBeDefined();
|
|
87
|
-
expect(typeof result.durationMs).toBe("number");
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("should handle --lens-effect flag path", async () => {
|
|
91
|
-
const mockPi = {
|
|
92
|
-
getFlag: vi.fn((flag: string) => flag === "lens-effect"),
|
|
93
|
-
readFile: vi.fn(),
|
|
94
|
-
writeFile: vi.fn(),
|
|
95
|
-
editFile: vi.fn(),
|
|
96
|
-
bash: vi.fn(),
|
|
97
|
-
ui: {
|
|
98
|
-
notify: vi.fn(),
|
|
99
|
-
progress: vi.fn(),
|
|
100
|
-
prompt: vi.fn(),
|
|
101
|
-
},
|
|
102
|
-
llm: {
|
|
103
|
-
stream: vi.fn(),
|
|
104
|
-
createMessage: vi.fn(),
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const output = await dispatchLintWithEffect("test.ts", "/test", mockPi);
|
|
109
|
-
expect(typeof output).toBe("string");
|
|
110
|
-
});
|
|
111
|
-
});
|