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
package/clients/biome-client.ts
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* Docs: https://biomejs.dev/
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { spawnSync } from "node:child_process";
|
|
12
11
|
import * as fs from "node:fs";
|
|
13
12
|
import * as path from "node:path";
|
|
14
13
|
import { isFileKind } from "./file-kinds.js";
|
|
14
|
+
import { safeSpawn } from "./safe-spawn.js";
|
|
15
15
|
|
|
16
16
|
// --- Types ---
|
|
17
17
|
|
|
@@ -57,10 +57,8 @@ export class BiomeClient {
|
|
|
57
57
|
if (this.biomeAvailable !== null) return this.biomeAvailable;
|
|
58
58
|
|
|
59
59
|
// Try npx biome first (works without global install)
|
|
60
|
-
const result =
|
|
61
|
-
encoding: "utf-8",
|
|
60
|
+
const result = safeSpawn("npx", ["@biomejs/biome", "--version"], {
|
|
62
61
|
timeout: 10000,
|
|
63
|
-
shell: true,
|
|
64
62
|
});
|
|
65
63
|
|
|
66
64
|
this.biomeAvailable = !result.error && result.status === 0;
|
|
@@ -105,7 +103,7 @@ export class BiomeClient {
|
|
|
105
103
|
if (!absolutePath) return [];
|
|
106
104
|
|
|
107
105
|
try {
|
|
108
|
-
const result =
|
|
106
|
+
const result = safeSpawn(
|
|
109
107
|
"npx",
|
|
110
108
|
[
|
|
111
109
|
"@biomejs/biome",
|
|
@@ -115,9 +113,7 @@ export class BiomeClient {
|
|
|
115
113
|
absolutePath,
|
|
116
114
|
],
|
|
117
115
|
{
|
|
118
|
-
encoding: "utf-8",
|
|
119
116
|
timeout: 15000,
|
|
120
|
-
shell: true,
|
|
121
117
|
},
|
|
122
118
|
);
|
|
123
119
|
|
|
@@ -126,8 +122,10 @@ export class BiomeClient {
|
|
|
126
122
|
if (!output.trim()) return [];
|
|
127
123
|
|
|
128
124
|
return this.parseDiagnostics(output, absolutePath);
|
|
129
|
-
} catch (err
|
|
130
|
-
this.log(
|
|
125
|
+
} catch (err) {
|
|
126
|
+
this.log(
|
|
127
|
+
`Check error: ${err instanceof Error ? err.message : String(err)}`,
|
|
128
|
+
);
|
|
131
129
|
return [];
|
|
132
130
|
}
|
|
133
131
|
}
|
|
@@ -151,13 +149,11 @@ export class BiomeClient {
|
|
|
151
149
|
const content = fs.readFileSync(absolutePath, "utf-8");
|
|
152
150
|
|
|
153
151
|
try {
|
|
154
|
-
const result =
|
|
152
|
+
const result = safeSpawn(
|
|
155
153
|
"npx",
|
|
156
154
|
["@biomejs/biome", "format", "--write", absolutePath],
|
|
157
155
|
{
|
|
158
|
-
encoding: "utf-8",
|
|
159
156
|
timeout: 15000,
|
|
160
|
-
shell: true,
|
|
161
157
|
},
|
|
162
158
|
);
|
|
163
159
|
|
|
@@ -174,8 +170,12 @@ export class BiomeClient {
|
|
|
174
170
|
}
|
|
175
171
|
|
|
176
172
|
return { success: true, changed };
|
|
177
|
-
} catch (err
|
|
178
|
-
return {
|
|
173
|
+
} catch (err) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
changed: false,
|
|
177
|
+
error: err instanceof Error ? err.message : String(err),
|
|
178
|
+
};
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
@@ -205,7 +205,7 @@ export class BiomeClient {
|
|
|
205
205
|
const fixableCount = beforeDiags.filter((d) => d.fixable).length;
|
|
206
206
|
|
|
207
207
|
// Apply fixes
|
|
208
|
-
const result =
|
|
208
|
+
const result = safeSpawn(
|
|
209
209
|
"npx",
|
|
210
210
|
[
|
|
211
211
|
"@biomejs/biome",
|
|
@@ -215,9 +215,7 @@ export class BiomeClient {
|
|
|
215
215
|
absolutePath,
|
|
216
216
|
],
|
|
217
217
|
{
|
|
218
|
-
encoding: "utf-8",
|
|
219
218
|
timeout: 15000,
|
|
220
|
-
shell: true,
|
|
221
219
|
},
|
|
222
220
|
);
|
|
223
221
|
|
|
@@ -240,8 +238,93 @@ export class BiomeClient {
|
|
|
240
238
|
}
|
|
241
239
|
|
|
242
240
|
return { success: true, changed, fixed: fixableCount };
|
|
243
|
-
} catch (err
|
|
244
|
-
return {
|
|
241
|
+
} catch (err) {
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
changed: false,
|
|
245
|
+
fixed: 0,
|
|
246
|
+
error: err instanceof Error ? err.message : String(err),
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Fix multiple files at once (much faster than file-by-file)
|
|
253
|
+
*/
|
|
254
|
+
fixFiles(filePaths: string[]): {
|
|
255
|
+
success: boolean;
|
|
256
|
+
fixed: number;
|
|
257
|
+
changed: number;
|
|
258
|
+
error?: string;
|
|
259
|
+
} {
|
|
260
|
+
if (!this.isAvailable()) {
|
|
261
|
+
return {
|
|
262
|
+
success: false,
|
|
263
|
+
fixed: 0,
|
|
264
|
+
changed: 0,
|
|
265
|
+
error: "Biome not available",
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Filter to existing files
|
|
270
|
+
const validFiles = filePaths
|
|
271
|
+
.map(f => path.resolve(f))
|
|
272
|
+
.filter(f => fs.existsSync(f));
|
|
273
|
+
|
|
274
|
+
if (validFiles.length === 0) {
|
|
275
|
+
return { success: true, fixed: 0, changed: 0 };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
// Count fixable issues before fixing
|
|
280
|
+
let totalFixable = 0;
|
|
281
|
+
for (const file of validFiles) {
|
|
282
|
+
const diags = this.checkFile(file);
|
|
283
|
+
totalFixable += diags.filter(d => d.fixable).length;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Run biome once on all files - much faster than npx per file
|
|
287
|
+
const result = safeSpawn(
|
|
288
|
+
"npx",
|
|
289
|
+
[
|
|
290
|
+
"@biomejs/biome",
|
|
291
|
+
"check",
|
|
292
|
+
"--write",
|
|
293
|
+
"--unsafe",
|
|
294
|
+
...validFiles,
|
|
295
|
+
],
|
|
296
|
+
{
|
|
297
|
+
timeout: 60000, // Longer timeout for batch
|
|
298
|
+
},
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
if (result.error) {
|
|
302
|
+
return {
|
|
303
|
+
success: false,
|
|
304
|
+
fixed: 0,
|
|
305
|
+
changed: 0,
|
|
306
|
+
error: result.error.message,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Count how many files actually changed
|
|
311
|
+
let changedCount = 0;
|
|
312
|
+
for (const file of validFiles) {
|
|
313
|
+
// We don't know exactly which files changed without re-reading,
|
|
314
|
+
// so we report total files processed
|
|
315
|
+
changedCount++;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
this.log(`Fixed ${totalFixable} issue(s) in ${validFiles.length} file(s)`);
|
|
319
|
+
|
|
320
|
+
return { success: true, fixed: totalFixable, changed: changedCount };
|
|
321
|
+
} catch (err) {
|
|
322
|
+
return {
|
|
323
|
+
success: false,
|
|
324
|
+
fixed: 0,
|
|
325
|
+
changed: 0,
|
|
326
|
+
error: err instanceof Error ? err.message : String(err),
|
|
327
|
+
};
|
|
245
328
|
}
|
|
246
329
|
}
|
|
247
330
|
|
|
@@ -291,13 +374,11 @@ export class BiomeClient {
|
|
|
291
374
|
|
|
292
375
|
try {
|
|
293
376
|
// Get formatted output without writing
|
|
294
|
-
const result =
|
|
377
|
+
const result = safeSpawn(
|
|
295
378
|
"npx",
|
|
296
379
|
["@biomejs/biome", "format", absolutePath],
|
|
297
380
|
{
|
|
298
|
-
encoding: "utf-8",
|
|
299
381
|
timeout: 15000,
|
|
300
|
-
shell: true,
|
|
301
382
|
},
|
|
302
383
|
);
|
|
303
384
|
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Bus for pi-lens
|
|
3
|
+
*
|
|
4
|
+
* Decoupled pub/sub system for diagnostic events.
|
|
5
|
+
* Enables loose coupling between diagnostic producers (runners, LSP clients)
|
|
6
|
+
* and consumers (UI, aggregators, history trackers).
|
|
7
|
+
*/
|
|
8
|
+
// --- Internal State ---
|
|
9
|
+
const subscribers = new Map();
|
|
10
|
+
const globalMiddleware = [];
|
|
11
|
+
let eventCount = 0;
|
|
12
|
+
let isDebugEnabled = false;
|
|
13
|
+
// --- Core Functions ---
|
|
14
|
+
function debug(type, event) {
|
|
15
|
+
if (!isDebugEnabled)
|
|
16
|
+
return;
|
|
17
|
+
const timestamp = new Date(event.timestamp).toISOString();
|
|
18
|
+
console.error(`[bus] [${timestamp}] ${type}: ${event.type}`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Publish an event to all subscribers
|
|
22
|
+
*/
|
|
23
|
+
export function publish(event) {
|
|
24
|
+
eventCount++;
|
|
25
|
+
debug("publish", event);
|
|
26
|
+
// Run through middleware
|
|
27
|
+
let currentEvent = event;
|
|
28
|
+
for (const mw of globalMiddleware) {
|
|
29
|
+
currentEvent = mw(currentEvent);
|
|
30
|
+
if (!currentEvent)
|
|
31
|
+
return; // Middleware cancelled the event
|
|
32
|
+
}
|
|
33
|
+
const handlers = subscribers.get(event.type);
|
|
34
|
+
if (!handlers || handlers.size === 0)
|
|
35
|
+
return;
|
|
36
|
+
// Notify all subscribers (fire-and-forget for async handlers)
|
|
37
|
+
for (const handler of handlers) {
|
|
38
|
+
try {
|
|
39
|
+
const result = handler(currentEvent);
|
|
40
|
+
if (result instanceof Promise) {
|
|
41
|
+
result.catch((err) => {
|
|
42
|
+
console.error(`[bus] async handler error for ${event.type}:`, err);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.error(`[bus] handler error for ${event.type}:`, err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to a specific event type
|
|
53
|
+
* @returns Unsubscribe function
|
|
54
|
+
*/
|
|
55
|
+
export function subscribe(eventType, handler) {
|
|
56
|
+
if (!subscribers.has(eventType)) {
|
|
57
|
+
subscribers.set(eventType, new Set());
|
|
58
|
+
}
|
|
59
|
+
const handlers = subscribers.get(eventType);
|
|
60
|
+
handlers.add(handler);
|
|
61
|
+
debug("subscribe", { type: eventType, properties: {}, timestamp: Date.now() });
|
|
62
|
+
// Return unsubscribe function
|
|
63
|
+
return () => {
|
|
64
|
+
handlers.delete(handler);
|
|
65
|
+
if (handlers.size === 0) {
|
|
66
|
+
subscribers.delete(eventType);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Subscribe to an event type and automatically unsubscribe after first match
|
|
72
|
+
*/
|
|
73
|
+
export function once(eventType, predicate) {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
const unsubscribe = subscribe(eventType, (event) => {
|
|
76
|
+
if (!predicate || predicate(event)) {
|
|
77
|
+
unsubscribe();
|
|
78
|
+
resolve(event);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wait for an event with timeout
|
|
85
|
+
*/
|
|
86
|
+
export function waitFor(eventType, timeoutMs, predicate) {
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
const timer = setTimeout(() => {
|
|
89
|
+
unsubscribe();
|
|
90
|
+
resolve(undefined);
|
|
91
|
+
}, timeoutMs);
|
|
92
|
+
const unsubscribe = subscribe(eventType, (event) => {
|
|
93
|
+
if (!predicate || predicate(event)) {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
unsubscribe();
|
|
96
|
+
resolve(event);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// --- Middleware ---
|
|
102
|
+
export function addMiddleware(mw) {
|
|
103
|
+
globalMiddleware.push(mw);
|
|
104
|
+
return () => {
|
|
105
|
+
const idx = globalMiddleware.indexOf(mw);
|
|
106
|
+
if (idx !== -1)
|
|
107
|
+
globalMiddleware.splice(idx, 1);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// --- Utilities ---
|
|
111
|
+
export function enableDebug(enabled = true) {
|
|
112
|
+
isDebugEnabled = enabled;
|
|
113
|
+
}
|
|
114
|
+
export function getStats() {
|
|
115
|
+
return {
|
|
116
|
+
subscriberCount: Array.from(subscribers.values()).reduce((sum, set) => sum + set.size, 0),
|
|
117
|
+
eventTypes: Array.from(subscribers.keys()),
|
|
118
|
+
totalEvents: eventCount,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export function clearAllSubscribers() {
|
|
122
|
+
subscribers.clear();
|
|
123
|
+
}
|
|
124
|
+
export var BusEvent;
|
|
125
|
+
(function (BusEvent) {
|
|
126
|
+
/**
|
|
127
|
+
* Define a typed event type with Zod schema validation
|
|
128
|
+
*/
|
|
129
|
+
function define(type, _schema) {
|
|
130
|
+
return {
|
|
131
|
+
type,
|
|
132
|
+
create(properties) {
|
|
133
|
+
return {
|
|
134
|
+
type,
|
|
135
|
+
properties,
|
|
136
|
+
timestamp: Date.now(),
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
subscribe(handler) {
|
|
140
|
+
return subscribe(type, handler);
|
|
141
|
+
},
|
|
142
|
+
publish(properties) {
|
|
143
|
+
publish({
|
|
144
|
+
type,
|
|
145
|
+
properties,
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
BusEvent.define = define;
|
|
152
|
+
/**
|
|
153
|
+
* Create a simple event type without schema (for internal use)
|
|
154
|
+
*/
|
|
155
|
+
function defineSimple(type) {
|
|
156
|
+
return {
|
|
157
|
+
type,
|
|
158
|
+
create(properties) {
|
|
159
|
+
return {
|
|
160
|
+
type,
|
|
161
|
+
properties,
|
|
162
|
+
timestamp: Date.now(),
|
|
163
|
+
};
|
|
164
|
+
},
|
|
165
|
+
subscribe(handler) {
|
|
166
|
+
return subscribe(type, handler);
|
|
167
|
+
},
|
|
168
|
+
publish(properties) {
|
|
169
|
+
publish({
|
|
170
|
+
type,
|
|
171
|
+
properties,
|
|
172
|
+
timestamp: Date.now(),
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
BusEvent.defineSimple = defineSimple;
|
|
178
|
+
/**
|
|
179
|
+
* Create a raw event (helper)
|
|
180
|
+
*/
|
|
181
|
+
function create(type, properties) {
|
|
182
|
+
return {
|
|
183
|
+
type,
|
|
184
|
+
properties,
|
|
185
|
+
timestamp: Date.now(),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
BusEvent.create = create;
|
|
189
|
+
})(BusEvent || (BusEvent = {}));
|
|
190
|
+
// --- Re-export for convenience ---
|
|
191
|
+
export { subscribe as on, publish as emit };
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Bus for pi-lens
|
|
3
|
+
*
|
|
4
|
+
* Decoupled pub/sub system for diagnostic events.
|
|
5
|
+
* Enables loose coupling between diagnostic producers (runners, LSP clients)
|
|
6
|
+
* and consumers (UI, aggregators, history trackers).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { z } from "zod";
|
|
10
|
+
|
|
11
|
+
// --- Types ---
|
|
12
|
+
|
|
13
|
+
export interface BusEvent<T = unknown> {
|
|
14
|
+
type: string;
|
|
15
|
+
properties: T;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type EventHandler<T> = (event: BusEvent<T>) => void | Promise<void>;
|
|
20
|
+
|
|
21
|
+
// --- Internal State ---
|
|
22
|
+
|
|
23
|
+
const subscribers = new Map<string, Set<EventHandler<unknown>>>();
|
|
24
|
+
const globalMiddleware: Array<(event: BusEvent) => BusEvent | undefined> = [];
|
|
25
|
+
|
|
26
|
+
let eventCount = 0;
|
|
27
|
+
let isDebugEnabled = false;
|
|
28
|
+
|
|
29
|
+
// --- Core Functions ---
|
|
30
|
+
|
|
31
|
+
function debug(type: string, event: BusEvent) {
|
|
32
|
+
if (!isDebugEnabled) return;
|
|
33
|
+
const timestamp = new Date(event.timestamp).toISOString();
|
|
34
|
+
console.error(`[bus] [${timestamp}] ${type}: ${event.type}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Publish an event to all subscribers
|
|
39
|
+
*/
|
|
40
|
+
export function publish<T>(event: BusEvent<T>): void {
|
|
41
|
+
eventCount++;
|
|
42
|
+
debug("publish", event as BusEvent<unknown>);
|
|
43
|
+
|
|
44
|
+
// Run through middleware
|
|
45
|
+
let currentEvent: BusEvent | undefined = event as BusEvent;
|
|
46
|
+
for (const mw of globalMiddleware) {
|
|
47
|
+
currentEvent = mw(currentEvent);
|
|
48
|
+
if (!currentEvent) return; // Middleware cancelled the event
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const handlers = subscribers.get(event.type);
|
|
52
|
+
if (!handlers || handlers.size === 0) return;
|
|
53
|
+
|
|
54
|
+
// Notify all subscribers (fire-and-forget for async handlers)
|
|
55
|
+
for (const handler of handlers) {
|
|
56
|
+
try {
|
|
57
|
+
const result = handler(currentEvent as BusEvent<unknown>);
|
|
58
|
+
if (result instanceof Promise) {
|
|
59
|
+
result.catch((err) => {
|
|
60
|
+
console.error(`[bus] async handler error for ${event.type}:`, err);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(`[bus] handler error for ${event.type}:`, err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Subscribe to a specific event type
|
|
71
|
+
* @returns Unsubscribe function
|
|
72
|
+
*/
|
|
73
|
+
export function subscribe<T>(
|
|
74
|
+
eventType: string,
|
|
75
|
+
handler: EventHandler<T>,
|
|
76
|
+
): () => void {
|
|
77
|
+
if (!subscribers.has(eventType)) {
|
|
78
|
+
subscribers.set(eventType, new Set());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const handlers = subscribers.get(eventType)!;
|
|
82
|
+
handlers.add(handler as EventHandler<unknown>);
|
|
83
|
+
|
|
84
|
+
debug("subscribe", { type: eventType, properties: {}, timestamp: Date.now() });
|
|
85
|
+
|
|
86
|
+
// Return unsubscribe function
|
|
87
|
+
return () => {
|
|
88
|
+
handlers.delete(handler as EventHandler<unknown>);
|
|
89
|
+
if (handlers.size === 0) {
|
|
90
|
+
subscribers.delete(eventType);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Subscribe to an event type and automatically unsubscribe after first match
|
|
97
|
+
*/
|
|
98
|
+
export function once<T>(
|
|
99
|
+
eventType: string,
|
|
100
|
+
predicate?: (event: BusEvent<T>) => boolean,
|
|
101
|
+
): Promise<BusEvent<T>> {
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
const unsubscribe = subscribe<T>(eventType, (event) => {
|
|
104
|
+
if (!predicate || predicate(event)) {
|
|
105
|
+
unsubscribe();
|
|
106
|
+
resolve(event);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Wait for an event with timeout
|
|
114
|
+
*/
|
|
115
|
+
export function waitFor<T>(
|
|
116
|
+
eventType: string,
|
|
117
|
+
timeoutMs: number,
|
|
118
|
+
predicate?: (event: BusEvent<T>) => boolean,
|
|
119
|
+
): Promise<BusEvent<T> | undefined> {
|
|
120
|
+
return new Promise((resolve) => {
|
|
121
|
+
const timer = setTimeout(() => {
|
|
122
|
+
unsubscribe();
|
|
123
|
+
resolve(undefined);
|
|
124
|
+
}, timeoutMs);
|
|
125
|
+
|
|
126
|
+
const unsubscribe = subscribe<T>(eventType, (event) => {
|
|
127
|
+
if (!predicate || predicate(event)) {
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
unsubscribe();
|
|
130
|
+
resolve(event);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// --- Middleware ---
|
|
137
|
+
|
|
138
|
+
export function addMiddleware(
|
|
139
|
+
mw: (event: BusEvent) => BusEvent | undefined,
|
|
140
|
+
): () => void {
|
|
141
|
+
globalMiddleware.push(mw);
|
|
142
|
+
return () => {
|
|
143
|
+
const idx = globalMiddleware.indexOf(mw);
|
|
144
|
+
if (idx !== -1) globalMiddleware.splice(idx, 1);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- Utilities ---
|
|
149
|
+
|
|
150
|
+
export function enableDebug(enabled = true): void {
|
|
151
|
+
isDebugEnabled = enabled;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function getStats(): {
|
|
155
|
+
subscriberCount: number;
|
|
156
|
+
eventTypes: string[];
|
|
157
|
+
totalEvents: number;
|
|
158
|
+
} {
|
|
159
|
+
return {
|
|
160
|
+
subscriberCount: Array.from(subscribers.values()).reduce(
|
|
161
|
+
(sum, set) => sum + set.size,
|
|
162
|
+
0,
|
|
163
|
+
),
|
|
164
|
+
eventTypes: Array.from(subscribers.keys()),
|
|
165
|
+
totalEvents: eventCount,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function clearAllSubscribers(): void {
|
|
170
|
+
subscribers.clear();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// --- Event Factory ---
|
|
174
|
+
|
|
175
|
+
export interface EventDefinition<T> {
|
|
176
|
+
type: string;
|
|
177
|
+
create(properties: T): BusEvent<T>;
|
|
178
|
+
subscribe(handler: EventHandler<T>): () => void;
|
|
179
|
+
publish(properties: T): void;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export namespace BusEvent {
|
|
183
|
+
/**
|
|
184
|
+
* Define a typed event type with Zod schema validation
|
|
185
|
+
*/
|
|
186
|
+
export function define<T>(
|
|
187
|
+
type: string,
|
|
188
|
+
_schema: z.ZodType<T>,
|
|
189
|
+
): EventDefinition<T> {
|
|
190
|
+
return {
|
|
191
|
+
type,
|
|
192
|
+
create(properties): BusEvent<T> {
|
|
193
|
+
return {
|
|
194
|
+
type,
|
|
195
|
+
properties,
|
|
196
|
+
timestamp: Date.now(),
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
subscribe(handler: EventHandler<T>): () => void {
|
|
200
|
+
return subscribe(type, handler);
|
|
201
|
+
},
|
|
202
|
+
publish(properties: T): void {
|
|
203
|
+
publish({
|
|
204
|
+
type,
|
|
205
|
+
properties,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Create a simple event type without schema (for internal use)
|
|
214
|
+
*/
|
|
215
|
+
export function defineSimple<T>(type: string): EventDefinition<T> {
|
|
216
|
+
return {
|
|
217
|
+
type,
|
|
218
|
+
create(properties: T): BusEvent<T> {
|
|
219
|
+
return {
|
|
220
|
+
type,
|
|
221
|
+
properties,
|
|
222
|
+
timestamp: Date.now(),
|
|
223
|
+
};
|
|
224
|
+
},
|
|
225
|
+
subscribe(handler: EventHandler<T>): () => void {
|
|
226
|
+
return subscribe(type, handler);
|
|
227
|
+
},
|
|
228
|
+
publish(properties: T): void {
|
|
229
|
+
publish({
|
|
230
|
+
type,
|
|
231
|
+
properties,
|
|
232
|
+
timestamp: Date.now(),
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Create a raw event (helper)
|
|
240
|
+
*/
|
|
241
|
+
export function create<T>(type: string, properties: T): BusEvent<T> {
|
|
242
|
+
return {
|
|
243
|
+
type,
|
|
244
|
+
properties,
|
|
245
|
+
timestamp: Date.now(),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --- Re-export for convenience ---
|
|
251
|
+
export { subscribe as on, publish as emit };
|