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.
- package/CHANGELOG.md +198 -0
- package/README.md +709 -519
- package/clients/__tests__/file-time.test.js +216 -0
- package/clients/__tests__/file-time.test.ts +276 -0
- package/clients/__tests__/format-service.test.js +245 -0
- package/clients/__tests__/format-service.test.ts +339 -0
- package/clients/__tests__/formatters.test.js +271 -0
- package/clients/__tests__/formatters.test.ts +401 -0
- package/clients/amain-types.js +164 -0
- package/clients/amain-types.ts +165 -0
- package/clients/architect-client.js +56 -12
- package/clients/architect-client.ts +81 -16
- package/clients/ast-grep-client.js +2 -2
- package/clients/ast-grep-client.ts +14 -39
- package/clients/ast-grep-parser.ts +1 -1
- package/clients/ast-grep-rule-manager.js +8 -0
- package/clients/ast-grep-rule-manager.ts +10 -1
- package/clients/ast-grep-types.js +9 -0
- package/clients/ast-grep-types.ts +106 -0
- package/clients/auto-loop.js +10 -0
- package/clients/auto-loop.ts +14 -1
- package/clients/biome-client.js +81 -19
- package/clients/biome-client.ts +103 -22
- package/clients/bus/bus.js +191 -0
- package/clients/bus/bus.ts +251 -0
- package/clients/bus/events.js +214 -0
- package/clients/bus/events.ts +279 -0
- package/clients/bus/index.js +8 -0
- package/clients/bus/index.ts +9 -0
- package/clients/bus/integration.js +158 -0
- package/clients/bus/integration.ts +214 -0
- package/clients/complexity-client.js +13 -7
- package/clients/complexity-client.ts +13 -7
- package/clients/config-validator.js +465 -0
- package/clients/config-validator.ts +558 -0
- package/clients/dependency-checker.js +4 -10
- package/clients/dependency-checker.ts +4 -10
- package/clients/dispatch/__tests__/autofix-integration.test.js +245 -0
- package/clients/dispatch/__tests__/autofix-integration.test.ts +300 -0
- package/clients/dispatch/__tests__/runner-registration.test.js +236 -0
- package/clients/dispatch/__tests__/runner-registration.test.ts +282 -0
- package/clients/dispatch/bus-dispatcher.js +177 -0
- package/clients/dispatch/bus-dispatcher.ts +251 -0
- package/clients/dispatch/dispatcher.edge.test.js +82 -0
- package/clients/dispatch/dispatcher.edge.test.ts +100 -0
- package/clients/dispatch/dispatcher.format.test.js +46 -0
- package/clients/dispatch/dispatcher.format.test.ts +58 -0
- package/clients/dispatch/dispatcher.inline.test.js +74 -0
- package/clients/dispatch/dispatcher.inline.test.ts +93 -0
- package/clients/dispatch/dispatcher.js +19 -53
- package/clients/dispatch/dispatcher.ts +20 -67
- package/clients/dispatch/plan.js +9 -4
- package/clients/dispatch/plan.ts +9 -4
- package/clients/dispatch/runners/architect.js +21 -7
- package/clients/dispatch/runners/architect.test.js +138 -0
- package/clients/dispatch/runners/architect.test.ts +162 -0
- package/clients/dispatch/runners/architect.ts +22 -7
- package/clients/dispatch/runners/ast-grep-napi.js +462 -0
- package/clients/dispatch/runners/ast-grep-napi.test.js +111 -0
- package/clients/dispatch/runners/ast-grep-napi.test.ts +133 -0
- package/clients/dispatch/runners/ast-grep-napi.ts +506 -0
- package/clients/dispatch/runners/ast-grep.js +62 -19
- package/clients/dispatch/runners/ast-grep.ts +70 -18
- package/clients/dispatch/runners/biome.js +29 -53
- package/clients/dispatch/runners/biome.ts +29 -63
- package/clients/dispatch/runners/config-validation.js +67 -0
- package/clients/dispatch/runners/config-validation.ts +82 -0
- package/clients/dispatch/runners/go-vet.js +4 -28
- package/clients/dispatch/runners/go-vet.ts +4 -32
- package/clients/dispatch/runners/index.js +30 -10
- package/clients/dispatch/runners/index.ts +30 -10
- package/clients/dispatch/runners/oxlint.js +141 -0
- package/clients/dispatch/runners/oxlint.test.js +230 -0
- package/clients/dispatch/runners/oxlint.test.ts +303 -0
- package/clients/dispatch/runners/oxlint.ts +175 -0
- package/clients/dispatch/runners/pyright.js +40 -70
- package/clients/dispatch/runners/pyright.test.js +16 -2
- package/clients/dispatch/runners/pyright.test.ts +14 -2
- package/clients/dispatch/runners/pyright.ts +48 -91
- package/clients/dispatch/runners/python-slop.js +97 -0
- package/clients/dispatch/runners/python-slop.test.js +203 -0
- package/clients/dispatch/runners/python-slop.test.ts +298 -0
- package/clients/dispatch/runners/python-slop.ts +124 -0
- package/clients/dispatch/runners/ruff.js +18 -71
- package/clients/dispatch/runners/ruff.ts +19 -79
- package/clients/dispatch/runners/rust-clippy.js +28 -32
- package/clients/dispatch/runners/rust-clippy.ts +29 -31
- package/clients/dispatch/runners/scan_codebase.test.js +89 -0
- package/clients/dispatch/runners/scan_codebase.test.ts +105 -0
- package/clients/dispatch/runners/shellcheck.js +147 -0
- package/clients/dispatch/runners/shellcheck.test.js +98 -0
- package/clients/dispatch/runners/shellcheck.test.ts +129 -0
- package/clients/dispatch/runners/shellcheck.ts +188 -0
- package/clients/dispatch/runners/similarity.js +230 -0
- package/clients/dispatch/runners/similarity.ts +339 -0
- package/clients/dispatch/runners/spellcheck.js +106 -0
- package/clients/dispatch/runners/spellcheck.test.js +158 -0
- package/clients/dispatch/runners/spellcheck.test.ts +214 -0
- package/clients/dispatch/runners/spellcheck.ts +136 -0
- package/clients/dispatch/runners/tree-sitter.js +107 -0
- package/clients/dispatch/runners/tree-sitter.ts +135 -0
- package/clients/dispatch/runners/ts-lsp.js +104 -33
- package/clients/dispatch/runners/ts-lsp.ts +120 -38
- package/clients/dispatch/runners/ts-slop.js +113 -0
- package/clients/dispatch/runners/ts-slop.test.js +180 -0
- package/clients/dispatch/runners/ts-slop.test.ts +230 -0
- package/clients/dispatch/runners/ts-slop.ts +142 -0
- package/clients/dispatch/runners/utils/diagnostic-parsers.js +134 -0
- package/clients/dispatch/runners/utils/diagnostic-parsers.ts +186 -0
- package/clients/dispatch/runners/utils/runner-helpers.js +115 -0
- package/clients/dispatch/runners/utils/runner-helpers.ts +167 -0
- package/clients/dispatch/runners/utils.js +2 -4
- package/clients/dispatch/runners/utils.ts +2 -4
- package/clients/dispatch/types.ts +1 -1
- package/clients/dispatch/utils/format-utils.js +49 -0
- package/clients/dispatch/utils/format-utils.ts +60 -0
- package/clients/dogfood.test.js +201 -0
- package/clients/dogfood.test.ts +269 -0
- package/clients/file-time.js +152 -0
- package/clients/file-time.ts +208 -0
- package/clients/file-utils.js +40 -0
- package/clients/file-utils.ts +44 -0
- package/clients/fix-scanners.js +10 -20
- package/clients/fix-scanners.ts +10 -22
- package/clients/format-service.js +172 -0
- package/clients/format-service.ts +254 -0
- package/clients/formatters.js +435 -0
- package/clients/formatters.ts +508 -0
- package/clients/go-client.js +5 -14
- package/clients/go-client.ts +5 -13
- package/clients/installer/index.js +356 -0
- package/clients/installer/index.ts +426 -0
- package/clients/jscpd-client.js +11 -9
- package/clients/jscpd-client.ts +12 -8
- package/clients/knip-client.js +3 -7
- package/clients/knip-client.ts +3 -6
- package/clients/lsp/__tests__/client.test.js +325 -0
- package/clients/lsp/__tests__/client.test.ts +434 -0
- package/clients/lsp/__tests__/config.test.js +166 -0
- package/clients/lsp/__tests__/config.test.ts +209 -0
- package/clients/lsp/__tests__/error-recovery.test.js +213 -0
- package/clients/lsp/__tests__/error-recovery.test.ts +279 -0
- package/clients/lsp/__tests__/integration.test.js +127 -0
- package/clients/lsp/__tests__/integration.test.ts +160 -0
- package/clients/lsp/__tests__/launch.test.js +260 -0
- package/clients/lsp/__tests__/launch.test.ts +329 -0
- package/clients/lsp/__tests__/server.test.js +259 -0
- package/clients/lsp/__tests__/server.test.ts +332 -0
- package/clients/lsp/__tests__/service.test.js +417 -0
- package/clients/lsp/__tests__/service.test.ts +499 -0
- package/clients/lsp/client.js +235 -0
- package/clients/lsp/client.ts +328 -0
- package/clients/lsp/config.js +115 -0
- package/clients/lsp/config.ts +149 -0
- package/clients/lsp/index.js +222 -0
- package/clients/lsp/index.ts +280 -0
- package/clients/lsp/installer/index.js +391 -0
- package/clients/lsp/interactive-install.js +210 -0
- package/clients/lsp/interactive-install.ts +251 -0
- package/clients/lsp/language.js +170 -0
- package/clients/lsp/language.ts +216 -0
- package/clients/lsp/launch.js +174 -0
- package/clients/lsp/launch.ts +240 -0
- package/clients/lsp/lsp/launch.js +116 -0
- package/clients/lsp/lsp/server.js +532 -0
- package/clients/lsp/lsp-index.js +10 -0
- package/clients/lsp/lsp-index.ts +11 -0
- package/clients/lsp/path-utils.js +48 -0
- package/clients/lsp/path-utils.ts +52 -0
- package/clients/lsp/server.js +615 -0
- package/clients/lsp/server.ts +800 -0
- package/clients/lsp/test-py-spawn/requirements.txt +1 -0
- package/clients/lsp/test-py-spawn/test.py +3 -0
- package/clients/lsp/test-py-svc/requirements.txt +1 -0
- package/clients/lsp/test-py-svc/test.py +3 -0
- package/clients/lsp/test-python-project/requirements.txt +1 -0
- package/clients/lsp/test-python-project/test.py +5 -0
- package/clients/metrics-history.js +2 -2
- package/clients/metrics-history.ts +2 -2
- package/clients/production-readiness.js +522 -0
- package/clients/production-readiness.ts +556 -0
- package/clients/project-index.js +255 -0
- package/clients/project-index.ts +383 -0
- package/clients/project-metadata.js +531 -0
- package/clients/project-metadata.ts +624 -0
- package/clients/ruff-client.js +56 -16
- package/clients/ruff-client.ts +72 -15
- package/clients/runner-tracker.js +152 -0
- package/clients/runner-tracker.ts +213 -0
- package/clients/rust-client.js +4 -11
- package/clients/rust-client.ts +5 -11
- package/clients/safe-spawn.js +96 -0
- package/clients/safe-spawn.ts +128 -0
- package/clients/scan-architectural-debt.js +3 -6
- package/clients/scan-architectural-debt.ts +3 -6
- package/clients/scan-utils.js +5 -20
- package/clients/scan-utils.ts +5 -29
- package/clients/secrets-scanner.js +3 -17
- package/clients/secrets-scanner.ts +4 -20
- package/clients/services/__tests__/effect-integration.test.js +86 -0
- package/clients/services/__tests__/effect-integration.test.ts +111 -0
- package/clients/services/effect-integration.js +194 -0
- package/clients/services/effect-integration.ts +268 -0
- package/clients/services/index.js +7 -0
- package/clients/services/index.ts +8 -0
- package/clients/services/runner-service.js +105 -0
- package/clients/services/runner-service.ts +179 -0
- package/clients/sg-runner.js +87 -13
- package/clients/sg-runner.ts +97 -13
- package/clients/state-matrix.js +160 -0
- package/clients/state-matrix.ts +202 -0
- package/clients/subprocess-client.js +10 -9
- package/clients/subprocess-client.ts +10 -8
- package/clients/test-runner-client.js +3 -7
- package/clients/test-runner-client.ts +3 -6
- package/clients/tool-availability.js +4 -10
- package/clients/tool-availability.ts +4 -9
- package/clients/tree-sitter-client.js +564 -0
- package/clients/tree-sitter-client.ts +797 -0
- package/clients/tree-sitter-query-loader.js +355 -0
- package/clients/tree-sitter-query-loader.ts +425 -0
- package/clients/type-coverage-client.js +3 -7
- package/clients/type-coverage-client.ts +3 -6
- package/clients/typescript-client.codefix.test.js +157 -0
- package/clients/typescript-client.codefix.test.ts +186 -0
- package/clients/typescript-client.js +43 -0
- package/clients/typescript-client.ts +98 -0
- package/commands/booboo.js +799 -219
- package/commands/booboo.ts +1004 -225
- package/commands/clients/ast-grep-client.js +250 -0
- package/commands/clients/ast-grep-parser.js +86 -0
- package/commands/clients/ast-grep-rule-manager.js +91 -0
- package/commands/clients/ast-grep-types.js +9 -0
- package/commands/clients/biome-client.js +380 -0
- package/commands/clients/complexity-client.js +667 -0
- package/commands/clients/file-kinds.js +177 -0
- package/commands/clients/file-utils.js +40 -0
- package/commands/clients/jscpd-client.js +169 -0
- package/commands/clients/knip-client.js +211 -0
- package/commands/clients/ruff-client.js +297 -0
- package/commands/clients/safe-spawn.js +88 -0
- package/commands/clients/scan-utils.js +83 -0
- package/commands/clients/sg-runner.js +190 -0
- package/commands/clients/types.js +11 -0
- package/commands/clients/typescript-client.js +505 -0
- package/commands/fix-from-booboo.js +398 -0
- package/commands/fix-from-booboo.ts +485 -0
- package/commands/fix-simplified.js +618 -0
- package/commands/fix-simplified.ts +768 -0
- package/commands/rate.js +10 -14
- package/commands/rate.ts +9 -16
- package/default-architect.yaml +59 -15
- package/index.ts +342 -429
- package/package.json +16 -3
- package/rules/ast-grep-rules/rules/empty-catch.yml +38 -13
- package/rules/ast-grep-rules/rules/no-array-constructor.yml +1 -0
- package/rules/ast-grep-rules/rules/no-debugger.yml +2 -0
- package/rules/python-slop-rules/.sgconfig.yml +4 -0
- package/rules/python-slop-rules/rules/slop-rules.yml +647 -0
- package/rules/tree-sitter-queries/python/bare-except.yml +54 -0
- package/rules/tree-sitter-queries/python/eval-exec.yml +50 -0
- package/rules/tree-sitter-queries/python/is-vs-equals.yml +60 -0
- package/rules/tree-sitter-queries/python/mutable-default-arg.yml +57 -0
- package/rules/tree-sitter-queries/python/unreachable-except.yml +60 -0
- package/rules/tree-sitter-queries/python/wildcard-import.yml +46 -0
- package/rules/tree-sitter-queries/tsx/dangerously-set-inner-html.yml +63 -0
- package/rules/tree-sitter-queries/typescript/await-in-loop.yml +56 -0
- package/rules/tree-sitter-queries/typescript/console-statement.yml +47 -0
- package/rules/tree-sitter-queries/typescript/debugger.yml +47 -0
- package/rules/tree-sitter-queries/typescript/deep-nesting.yml +117 -0
- package/rules/tree-sitter-queries/typescript/deep-promise-chain.yml +73 -0
- package/rules/tree-sitter-queries/typescript/empty-catch.yml +64 -0
- package/rules/tree-sitter-queries/typescript/eval.yml +48 -0
- package/rules/tree-sitter-queries/typescript/hardcoded-secrets.yml +78 -0
- package/rules/tree-sitter-queries/typescript/long-parameter-list.yml +62 -0
- package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +49 -0
- package/rules/tree-sitter-queries/typescript/nested-ternary.yml +45 -0
- package/rules/ts-slop-rules/.sgconfig.yml +4 -0
- package/rules/ts-slop-rules/rules/in-correct-optional-input-type.yml +10 -0
- package/rules/ts-slop-rules/rules/jwt-no-verify.yml +13 -0
- package/rules/ts-slop-rules/rules/no-architecture-violation.yml +10 -0
- package/rules/ts-slop-rules/rules/no-case-declarations.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dangerously-set-inner-html.yml +10 -0
- package/rules/ts-slop-rules/rules/no-debugger.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dupe-args.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dupe-class-members.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dupe-keys.yml +10 -0
- package/rules/ts-slop-rules/rules/no-eval.yml +13 -0
- package/rules/ts-slop-rules/rules/no-hardcoded-secrets.yml +12 -0
- package/rules/ts-slop-rules/rules/no-implied-eval.yml +12 -0
- package/rules/ts-slop-rules/rules/no-inner-html.yml +13 -0
- package/rules/ts-slop-rules/rules/no-javascript-url.yml +10 -0
- package/rules/ts-slop-rules/rules/no-mutable-default.yml +10 -0
- package/rules/ts-slop-rules/rules/no-nested-links.yml +12 -0
- package/rules/ts-slop-rules/rules/no-new-symbol.yml +10 -0
- package/rules/ts-slop-rules/rules/no-new-wrappers.yml +13 -0
- package/rules/ts-slop-rules/rules/no-open-redirect.yml +16 -0
- package/rules/ts-slop-rules/rules/slop-rules.yml +455 -0
- package/rules/ts-slop-rules/rules/weak-rsa-key.yml +12 -0
- package/skills/ast-grep/SKILL.md +182 -0
- package/clients/dispatch/runners/secrets.js +0 -109
- package/commands/fix.js +0 -244
- package/commands/fix.ts +0 -373
- package/rules/ast-grep-rules/rules/no-lonely-if.yml +0 -13
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runner Registration Verification Tests
|
|
3
|
+
*
|
|
4
|
+
* Ensures all runners are properly registered and unique.
|
|
5
|
+
* Catches issues like missing runner imports.
|
|
6
|
+
*/
|
|
7
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
8
|
+
import { clearRunnerRegistry, getRunner, getRunnersForKind, listRunners, } from "../dispatcher.js";
|
|
9
|
+
describe("Runner Registration", () => {
|
|
10
|
+
let allRunners;
|
|
11
|
+
beforeAll(async () => {
|
|
12
|
+
// Clear any existing registrations for clean slate
|
|
13
|
+
clearRunnerRegistry();
|
|
14
|
+
// Import runners to trigger registration
|
|
15
|
+
// This is the critical import that was missing in the effect-integration bug
|
|
16
|
+
await import("../runners/index.js");
|
|
17
|
+
// Get all registered runners
|
|
18
|
+
allRunners = listRunners();
|
|
19
|
+
});
|
|
20
|
+
describe("Basic Registration", () => {
|
|
21
|
+
it("should have runners registered", () => {
|
|
22
|
+
expect(allRunners.length).toBeGreaterThan(0);
|
|
23
|
+
});
|
|
24
|
+
it("should have unique runner IDs", () => {
|
|
25
|
+
const ids = allRunners.map((r) => r.id);
|
|
26
|
+
const uniqueIds = new Set(ids);
|
|
27
|
+
// All IDs should be unique
|
|
28
|
+
expect(uniqueIds.size).toBe(ids.length);
|
|
29
|
+
});
|
|
30
|
+
it("should be able to retrieve any registered runner by ID", () => {
|
|
31
|
+
for (const runner of allRunners) {
|
|
32
|
+
// Skip disabled runners (those with no appliesTo)
|
|
33
|
+
if (!(runner.appliesTo?.length ?? 0))
|
|
34
|
+
continue;
|
|
35
|
+
const retrieved = getRunner(runner.id);
|
|
36
|
+
expect(retrieved).toBeDefined();
|
|
37
|
+
expect(retrieved?.id).toBe(runner.id);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it("should return undefined for unknown runner IDs", () => {
|
|
41
|
+
const unknown = getRunner("definitely-not-a-real-runner-id");
|
|
42
|
+
expect(unknown).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("Runner Properties", () => {
|
|
46
|
+
it("should have valid appliesTo for all runners", () => {
|
|
47
|
+
const validKinds = [
|
|
48
|
+
"jsts",
|
|
49
|
+
"python",
|
|
50
|
+
"rust",
|
|
51
|
+
"go",
|
|
52
|
+
"shell",
|
|
53
|
+
"json",
|
|
54
|
+
"markdown",
|
|
55
|
+
"cmake",
|
|
56
|
+
"cxx",
|
|
57
|
+
];
|
|
58
|
+
for (const runner of allRunners) {
|
|
59
|
+
// Skip disabled runners (those with no appliesTo)
|
|
60
|
+
if (!(runner.appliesTo?.length ?? 0))
|
|
61
|
+
continue;
|
|
62
|
+
// Each runner should have at least one appliesTo
|
|
63
|
+
if (!(runner.appliesTo?.length ?? 0)) {
|
|
64
|
+
console.error(`Runner ${runner.id} has no appliesTo`);
|
|
65
|
+
}
|
|
66
|
+
expect(runner.appliesTo?.length ?? 0, `Runner ${runner.id} should have appliesTo`).toBeGreaterThan(0);
|
|
67
|
+
// All appliesTo should be valid kinds
|
|
68
|
+
for (const kind of runner.appliesTo) {
|
|
69
|
+
expect(validKinds).toContain(kind);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
it("should have priority defined", () => {
|
|
74
|
+
for (const runner of allRunners) {
|
|
75
|
+
// Skip disabled runners (those with no appliesTo)
|
|
76
|
+
if (!(runner.appliesTo?.length ?? 0))
|
|
77
|
+
continue;
|
|
78
|
+
// Priority should be a number (or undefined, which defaults to 100)
|
|
79
|
+
if (runner.priority !== undefined) {
|
|
80
|
+
expect(typeof runner.priority).toBe("number");
|
|
81
|
+
expect(runner.priority).toBeGreaterThanOrEqual(0);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
it("should have enabledByDefault boolean", () => {
|
|
86
|
+
for (const runner of allRunners) {
|
|
87
|
+
// Skip disabled runners (those with no appliesTo)
|
|
88
|
+
if (!(runner.appliesTo?.length ?? 0))
|
|
89
|
+
continue;
|
|
90
|
+
expect(typeof runner.enabledByDefault).toBe("boolean");
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
it("should have a run function", () => {
|
|
94
|
+
for (const runner of allRunners) {
|
|
95
|
+
// Skip disabled runners (those with no appliesTo)
|
|
96
|
+
if (!(runner.appliesTo?.length ?? 0))
|
|
97
|
+
continue;
|
|
98
|
+
expect(typeof runner.run).toBe("function");
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe("Expected Runners", () => {
|
|
103
|
+
const expectedRunners = [
|
|
104
|
+
"ts-lsp",
|
|
105
|
+
"ts-slop",
|
|
106
|
+
"pyright",
|
|
107
|
+
"python-slop",
|
|
108
|
+
"biome-lint",
|
|
109
|
+
"oxlint",
|
|
110
|
+
"ruff-lint",
|
|
111
|
+
"shellcheck",
|
|
112
|
+
"spellcheck",
|
|
113
|
+
"ast-grep",
|
|
114
|
+
"ast-grep-napi",
|
|
115
|
+
"architect",
|
|
116
|
+
"ast-grep-napi",
|
|
117
|
+
"config-validation",
|
|
118
|
+
];
|
|
119
|
+
it("should have all expected critical runners", () => {
|
|
120
|
+
const registeredIds = allRunners.map((r) => r.id);
|
|
121
|
+
for (const expectedId of expectedRunners) {
|
|
122
|
+
expect(registeredIds).toContain(expectedId);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
it("should have TypeScript-related runners", () => {
|
|
126
|
+
const tsRunners = getRunnersForKind("jsts");
|
|
127
|
+
const tsIds = tsRunners.map((r) => r.id);
|
|
128
|
+
// Should have at least ts-lsp
|
|
129
|
+
expect(tsIds).toContain("ts-lsp");
|
|
130
|
+
// Should have ts-slop
|
|
131
|
+
expect(tsIds).toContain("ts-slop");
|
|
132
|
+
});
|
|
133
|
+
it("should have Python-related runners", () => {
|
|
134
|
+
const pyRunners = getRunnersForKind("python");
|
|
135
|
+
const pyIds = pyRunners.map((r) => r.id);
|
|
136
|
+
// Should have pyright
|
|
137
|
+
expect(pyIds).toContain("pyright");
|
|
138
|
+
// Should have python-slop
|
|
139
|
+
expect(pyIds).toContain("python-slop");
|
|
140
|
+
});
|
|
141
|
+
it("should have lint runners", () => {
|
|
142
|
+
const jstsRunners = getRunnersForKind("jsts");
|
|
143
|
+
const lintIds = ["biome-lint", "oxlint", "ts-slop"];
|
|
144
|
+
for (const lintId of lintIds) {
|
|
145
|
+
// At least one should be present
|
|
146
|
+
const hasLintRunner = jstsRunners.some((r) => r.id === lintId);
|
|
147
|
+
if (hasLintRunner) {
|
|
148
|
+
// Found at least one
|
|
149
|
+
expect(hasLintRunner).toBe(true);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
it("should have format runners", () => {
|
|
155
|
+
const jstsRunners = getRunnersForKind("jsts");
|
|
156
|
+
const formatIds = ["biome-lint"];
|
|
157
|
+
for (const formatId of formatIds) {
|
|
158
|
+
const hasFormatRunner = jstsRunners.some((r) => r.id === formatId);
|
|
159
|
+
if (hasFormatRunner) {
|
|
160
|
+
expect(hasFormatRunner).toBe(true);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe("Runner Import Verification", () => {
|
|
167
|
+
it("should load runner index without errors", async () => {
|
|
168
|
+
// This catches the bug where runners weren't imported
|
|
169
|
+
// in effect-integration.ts and bus-dispatcher.ts
|
|
170
|
+
expect(async () => {
|
|
171
|
+
await import("../runners/index.js");
|
|
172
|
+
}).not.toThrow();
|
|
173
|
+
});
|
|
174
|
+
it("should have runners available after import", async () => {
|
|
175
|
+
// Clear and re-import to verify fresh load
|
|
176
|
+
const initialCount = listRunners().length;
|
|
177
|
+
// Import again - should not duplicate due to id check
|
|
178
|
+
await import("../runners/index.js");
|
|
179
|
+
const finalCount = listRunners().length;
|
|
180
|
+
// Should be same count (no duplicates)
|
|
181
|
+
expect(finalCount).toBe(initialCount);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe("Runner Condition Functions", () => {
|
|
185
|
+
it("should handle runners with when conditions", () => {
|
|
186
|
+
const runnersWithWhen = allRunners.filter((r) => r.when !== undefined);
|
|
187
|
+
for (const runner of runnersWithWhen) {
|
|
188
|
+
// when should be a function
|
|
189
|
+
expect(typeof runner.when).toBe("function");
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
it("should evaluate when conditions correctly", async () => {
|
|
193
|
+
// Find a runner with a when condition (e.g., autofix runners)
|
|
194
|
+
const conditionalRunner = allRunners.find((r) => r.when !== undefined);
|
|
195
|
+
if (conditionalRunner) {
|
|
196
|
+
// Create mock contexts
|
|
197
|
+
const ctxWithAutofix = {
|
|
198
|
+
autofix: true,
|
|
199
|
+
filePath: "test.ts",
|
|
200
|
+
cwd: "/test",
|
|
201
|
+
kind: "jsts",
|
|
202
|
+
pi: { getFlag: () => false },
|
|
203
|
+
deltaMode: false,
|
|
204
|
+
baselines: new Map(),
|
|
205
|
+
hasTool: async () => false,
|
|
206
|
+
log: () => { },
|
|
207
|
+
};
|
|
208
|
+
const ctxWithoutAutofix = {
|
|
209
|
+
...ctxWithAutofix,
|
|
210
|
+
autofix: false,
|
|
211
|
+
};
|
|
212
|
+
// Evaluate condition
|
|
213
|
+
const shouldRunWith = await conditionalRunner.when?.(ctxWithAutofix);
|
|
214
|
+
const shouldRunWithout = await conditionalRunner.when?.(ctxWithoutAutofix);
|
|
215
|
+
// Results should be boolean
|
|
216
|
+
expect(typeof shouldRunWith).toBe("boolean");
|
|
217
|
+
expect(typeof shouldRunWithout).toBe("boolean");
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
describe("Priority Ordering", () => {
|
|
222
|
+
it("should return runners sorted by priority", () => {
|
|
223
|
+
const kinds = ["jsts", "python", "rust", "go"];
|
|
224
|
+
for (const kind of kinds) {
|
|
225
|
+
const runners = getRunnersForKind(kind);
|
|
226
|
+
if (runners.length > 1) {
|
|
227
|
+
const priorities = runners.map((r) => r.priority ?? 100);
|
|
228
|
+
// Should be sorted ascending
|
|
229
|
+
for (let i = 1; i < priorities.length; i++) {
|
|
230
|
+
expect(priorities[i - 1]).toBeLessThanOrEqual(priorities[i]);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runner Registration Verification Tests
|
|
3
|
+
*
|
|
4
|
+
* Ensures all runners are properly registered and unique.
|
|
5
|
+
* Catches issues like missing runner imports.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
9
|
+
import type { FileKind } from "../../file-kinds.js";
|
|
10
|
+
import {
|
|
11
|
+
clearRunnerRegistry,
|
|
12
|
+
getRunner,
|
|
13
|
+
getRunnersForKind,
|
|
14
|
+
listRunners,
|
|
15
|
+
} from "../dispatcher.js";
|
|
16
|
+
import type { RunnerDefinition } from "../types.js";
|
|
17
|
+
|
|
18
|
+
describe("Runner Registration", () => {
|
|
19
|
+
let allRunners: RunnerDefinition[];
|
|
20
|
+
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
// Clear any existing registrations for clean slate
|
|
23
|
+
clearRunnerRegistry();
|
|
24
|
+
|
|
25
|
+
// Import runners to trigger registration
|
|
26
|
+
// This is the critical import that was missing in the effect-integration bug
|
|
27
|
+
await import("../runners/index.js");
|
|
28
|
+
|
|
29
|
+
// Get all registered runners
|
|
30
|
+
allRunners = listRunners();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("Basic Registration", () => {
|
|
34
|
+
it("should have runners registered", () => {
|
|
35
|
+
expect(allRunners.length).toBeGreaterThan(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should have unique runner IDs", () => {
|
|
39
|
+
const ids = allRunners.map((r) => r.id);
|
|
40
|
+
const uniqueIds = new Set(ids);
|
|
41
|
+
|
|
42
|
+
// All IDs should be unique
|
|
43
|
+
expect(uniqueIds.size).toBe(ids.length);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should be able to retrieve any registered runner by ID", () => {
|
|
47
|
+
for (const runner of allRunners) {
|
|
48
|
+
// Skip disabled runners (those with no appliesTo)
|
|
49
|
+
if (!(runner.appliesTo?.length ?? 0)) continue;
|
|
50
|
+
const retrieved = getRunner(runner.id);
|
|
51
|
+
expect(retrieved).toBeDefined();
|
|
52
|
+
expect(retrieved?.id).toBe(runner.id);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should return undefined for unknown runner IDs", () => {
|
|
57
|
+
const unknown = getRunner("definitely-not-a-real-runner-id");
|
|
58
|
+
expect(unknown).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("Runner Properties", () => {
|
|
63
|
+
it("should have valid appliesTo for all runners", () => {
|
|
64
|
+
const validKinds: FileKind[] = [
|
|
65
|
+
"jsts",
|
|
66
|
+
"python",
|
|
67
|
+
"rust",
|
|
68
|
+
"go",
|
|
69
|
+
"shell",
|
|
70
|
+
"json",
|
|
71
|
+
"markdown",
|
|
72
|
+
"cmake",
|
|
73
|
+
"cxx",
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
for (const runner of allRunners) {
|
|
77
|
+
// Skip disabled runners (those with no appliesTo)
|
|
78
|
+
if (!(runner.appliesTo?.length ?? 0)) continue;
|
|
79
|
+
// Each runner should have at least one appliesTo
|
|
80
|
+
if (!(runner.appliesTo?.length ?? 0)) { console.error(`Runner ${runner.id} has no appliesTo`); } expect(runner.appliesTo?.length ?? 0, `Runner ${runner.id} should have appliesTo`).toBeGreaterThan(0);
|
|
81
|
+
|
|
82
|
+
// All appliesTo should be valid kinds
|
|
83
|
+
for (const kind of runner.appliesTo) {
|
|
84
|
+
expect(validKinds).toContain(kind);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should have priority defined", () => {
|
|
90
|
+
for (const runner of allRunners) {
|
|
91
|
+
// Skip disabled runners (those with no appliesTo)
|
|
92
|
+
if (!(runner.appliesTo?.length ?? 0)) continue;
|
|
93
|
+
// Priority should be a number (or undefined, which defaults to 100)
|
|
94
|
+
if (runner.priority !== undefined) {
|
|
95
|
+
expect(typeof runner.priority).toBe("number");
|
|
96
|
+
expect(runner.priority).toBeGreaterThanOrEqual(0);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should have enabledByDefault boolean", () => {
|
|
102
|
+
for (const runner of allRunners) {
|
|
103
|
+
// Skip disabled runners (those with no appliesTo)
|
|
104
|
+
if (!(runner.appliesTo?.length ?? 0)) continue;
|
|
105
|
+
expect(typeof runner.enabledByDefault).toBe("boolean");
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should have a run function", () => {
|
|
110
|
+
for (const runner of allRunners) {
|
|
111
|
+
// Skip disabled runners (those with no appliesTo)
|
|
112
|
+
if (!(runner.appliesTo?.length ?? 0)) continue;
|
|
113
|
+
expect(typeof runner.run).toBe("function");
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("Expected Runners", () => {
|
|
119
|
+
const expectedRunners = [
|
|
120
|
+
"ts-lsp",
|
|
121
|
+
"ts-slop",
|
|
122
|
+
"pyright",
|
|
123
|
+
"python-slop",
|
|
124
|
+
"biome-lint",
|
|
125
|
+
|
|
126
|
+
"oxlint",
|
|
127
|
+
"ruff-lint",
|
|
128
|
+
"shellcheck",
|
|
129
|
+
"spellcheck",
|
|
130
|
+
"ast-grep",
|
|
131
|
+
"ast-grep-napi",
|
|
132
|
+
"architect",
|
|
133
|
+
"ast-grep-napi",
|
|
134
|
+
"config-validation",
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
it("should have all expected critical runners", () => {
|
|
138
|
+
const registeredIds = allRunners.map((r) => r.id);
|
|
139
|
+
|
|
140
|
+
for (const expectedId of expectedRunners) {
|
|
141
|
+
expect(registeredIds).toContain(expectedId);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should have TypeScript-related runners", () => {
|
|
146
|
+
const tsRunners = getRunnersForKind("jsts");
|
|
147
|
+
const tsIds = tsRunners.map((r) => r.id);
|
|
148
|
+
|
|
149
|
+
// Should have at least ts-lsp
|
|
150
|
+
expect(tsIds).toContain("ts-lsp");
|
|
151
|
+
|
|
152
|
+
// Should have ts-slop
|
|
153
|
+
expect(tsIds).toContain("ts-slop");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("should have Python-related runners", () => {
|
|
157
|
+
const pyRunners = getRunnersForKind("python");
|
|
158
|
+
const pyIds = pyRunners.map((r) => r.id);
|
|
159
|
+
|
|
160
|
+
// Should have pyright
|
|
161
|
+
expect(pyIds).toContain("pyright");
|
|
162
|
+
|
|
163
|
+
// Should have python-slop
|
|
164
|
+
expect(pyIds).toContain("python-slop");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should have lint runners", () => {
|
|
168
|
+
const jstsRunners = getRunnersForKind("jsts");
|
|
169
|
+
const lintIds = ["biome-lint", "oxlint", "ts-slop"];
|
|
170
|
+
|
|
171
|
+
for (const lintId of lintIds) {
|
|
172
|
+
// At least one should be present
|
|
173
|
+
const hasLintRunner = jstsRunners.some((r) => r.id === lintId);
|
|
174
|
+
if (hasLintRunner) {
|
|
175
|
+
// Found at least one
|
|
176
|
+
expect(hasLintRunner).toBe(true);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should have format runners", () => {
|
|
183
|
+
const jstsRunners = getRunnersForKind("jsts");
|
|
184
|
+
const formatIds = ["biome-lint"];
|
|
185
|
+
|
|
186
|
+
for (const formatId of formatIds) {
|
|
187
|
+
const hasFormatRunner = jstsRunners.some((r) => r.id === formatId);
|
|
188
|
+
if (hasFormatRunner) {
|
|
189
|
+
expect(hasFormatRunner).toBe(true);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("Runner Import Verification", () => {
|
|
197
|
+
it("should load runner index without errors", async () => {
|
|
198
|
+
// This catches the bug where runners weren't imported
|
|
199
|
+
// in effect-integration.ts and bus-dispatcher.ts
|
|
200
|
+
expect(async () => {
|
|
201
|
+
await import("../runners/index.js");
|
|
202
|
+
}).not.toThrow();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should have runners available after import", async () => {
|
|
206
|
+
// Clear and re-import to verify fresh load
|
|
207
|
+
const initialCount = listRunners().length;
|
|
208
|
+
|
|
209
|
+
// Import again - should not duplicate due to id check
|
|
210
|
+
await import("../runners/index.js");
|
|
211
|
+
|
|
212
|
+
const finalCount = listRunners().length;
|
|
213
|
+
|
|
214
|
+
// Should be same count (no duplicates)
|
|
215
|
+
expect(finalCount).toBe(initialCount);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe("Runner Condition Functions", () => {
|
|
220
|
+
it("should handle runners with when conditions", () => {
|
|
221
|
+
const runnersWithWhen = allRunners.filter((r) => r.when !== undefined);
|
|
222
|
+
|
|
223
|
+
for (const runner of runnersWithWhen) {
|
|
224
|
+
// when should be a function
|
|
225
|
+
expect(typeof runner.when).toBe("function");
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("should evaluate when conditions correctly", async () => {
|
|
230
|
+
// Find a runner with a when condition (e.g., autofix runners)
|
|
231
|
+
const conditionalRunner = allRunners.find((r) => r.when !== undefined);
|
|
232
|
+
|
|
233
|
+
if (conditionalRunner) {
|
|
234
|
+
// Create mock contexts
|
|
235
|
+
const ctxWithAutofix = {
|
|
236
|
+
autofix: true,
|
|
237
|
+
filePath: "test.ts",
|
|
238
|
+
cwd: "/test",
|
|
239
|
+
kind: "jsts" as FileKind,
|
|
240
|
+
pi: { getFlag: () => false },
|
|
241
|
+
deltaMode: false,
|
|
242
|
+
baselines: new Map(),
|
|
243
|
+
hasTool: async () => false,
|
|
244
|
+
log: () => {},
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const ctxWithoutAutofix = {
|
|
248
|
+
...ctxWithAutofix,
|
|
249
|
+
autofix: false,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// Evaluate condition
|
|
253
|
+
const shouldRunWith = await conditionalRunner.when?.(ctxWithAutofix);
|
|
254
|
+
const shouldRunWithout =
|
|
255
|
+
await conditionalRunner.when?.(ctxWithoutAutofix);
|
|
256
|
+
|
|
257
|
+
// Results should be boolean
|
|
258
|
+
expect(typeof shouldRunWith).toBe("boolean");
|
|
259
|
+
expect(typeof shouldRunWithout).toBe("boolean");
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe("Priority Ordering", () => {
|
|
265
|
+
it("should return runners sorted by priority", () => {
|
|
266
|
+
const kinds: FileKind[] = ["jsts", "python", "rust", "go"];
|
|
267
|
+
|
|
268
|
+
for (const kind of kinds) {
|
|
269
|
+
const runners = getRunnersForKind(kind);
|
|
270
|
+
|
|
271
|
+
if (runners.length > 1) {
|
|
272
|
+
const priorities = runners.map((r) => r.priority ?? 100);
|
|
273
|
+
|
|
274
|
+
// Should be sorted ascending
|
|
275
|
+
for (let i = 1; i < priorities.length; i++) {
|
|
276
|
+
expect(priorities[i - 1]).toBeLessThanOrEqual(priorities[i]);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
import { DiagnosticFound, RunnerStarted, RunnerCompleted, FileModified, ReportReady, } from "../bus/events.js";
|
|
12
|
+
import { formatDiagnostics } from "./utils/format-utils.js";
|
|
13
|
+
// Import runners to register them
|
|
14
|
+
import "./runners/index.js";
|
|
15
|
+
// --- Core Functions ---
|
|
16
|
+
async function runRunner(ctx, runner, defaultSemantic) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
// Publish runner started event
|
|
19
|
+
RunnerStarted.publish({
|
|
20
|
+
runnerId: runner.id,
|
|
21
|
+
filePath: ctx.filePath,
|
|
22
|
+
timestamp: startTime,
|
|
23
|
+
});
|
|
24
|
+
try {
|
|
25
|
+
const result = await runner.run(ctx);
|
|
26
|
+
const durationMs = Date.now() - startTime;
|
|
27
|
+
// Publish diagnostic found event
|
|
28
|
+
if (result.diagnostics.length > 0) {
|
|
29
|
+
DiagnosticFound.publish({
|
|
30
|
+
runnerId: runner.id,
|
|
31
|
+
filePath: ctx.filePath,
|
|
32
|
+
diagnostics: result.diagnostics,
|
|
33
|
+
durationMs,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Publish runner completed event
|
|
37
|
+
// Map "succeeded" to "completed" for the event status
|
|
38
|
+
const eventStatus = result.status === "succeeded" ? "completed" : result.status;
|
|
39
|
+
RunnerCompleted.publish({
|
|
40
|
+
runnerId: runner.id,
|
|
41
|
+
filePath: ctx.filePath,
|
|
42
|
+
status: eventStatus,
|
|
43
|
+
durationMs,
|
|
44
|
+
diagnosticCount: result.diagnostics.length,
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
...result,
|
|
48
|
+
semantic: result.semantic ?? defaultSemantic,
|
|
49
|
+
durationMs,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const durationMs = Date.now() - startTime;
|
|
54
|
+
ctx.log?.(`Runner ${runner.id} failed: ${error}`);
|
|
55
|
+
RunnerCompleted.publish({
|
|
56
|
+
runnerId: runner.id,
|
|
57
|
+
filePath: ctx.filePath,
|
|
58
|
+
status: "failed",
|
|
59
|
+
durationMs,
|
|
60
|
+
diagnosticCount: 0,
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
status: "failed",
|
|
64
|
+
diagnostics: [],
|
|
65
|
+
semantic: defaultSemantic,
|
|
66
|
+
durationMs,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// --- Concurrent Dispatch (new feature) ---
|
|
71
|
+
export async function dispatchConcurrent(ctx, groups) {
|
|
72
|
+
const startTime = Date.now();
|
|
73
|
+
const allDiagnostics = [];
|
|
74
|
+
const runnerResults = [];
|
|
75
|
+
let stopped = false;
|
|
76
|
+
for (const group of groups) {
|
|
77
|
+
if (stopped && ctx.pi.getFlag("stop-on-error")) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
// Get applicable runners
|
|
81
|
+
const { getRunner } = await import("./dispatcher.js");
|
|
82
|
+
const runnerIds = group.filterKinds
|
|
83
|
+
? group.runnerIds.filter((id) => {
|
|
84
|
+
const runner = getRunner(id);
|
|
85
|
+
return runner && ctx.kind && group.filterKinds?.includes(ctx.kind);
|
|
86
|
+
})
|
|
87
|
+
: group.runnerIds;
|
|
88
|
+
const runners = runnerIds
|
|
89
|
+
.map((id) => getRunner(id))
|
|
90
|
+
.filter((r) => r !== undefined)
|
|
91
|
+
.filter((r) => (r.when ? r.when(ctx) : true));
|
|
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
|
+
const ctx = createDispatchContext(filePath, cwd, pi);
|
|
169
|
+
const kind = ctx.kind;
|
|
170
|
+
if (!kind)
|
|
171
|
+
return "";
|
|
172
|
+
const plan = TOOL_PLANS[kind];
|
|
173
|
+
if (!plan)
|
|
174
|
+
return "";
|
|
175
|
+
const result = await dispatchConcurrent(ctx, plan.groups);
|
|
176
|
+
return result.output;
|
|
177
|
+
}
|