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
|
@@ -13,7 +13,13 @@ import * as fs from "node:fs";
|
|
|
13
13
|
import * as path from "node:path";
|
|
14
14
|
import { AstGrepParser } from "./ast-grep-parser.js";
|
|
15
15
|
import { AstGrepRuleManager } from "./ast-grep-rule-manager.js";
|
|
16
|
-
import
|
|
16
|
+
import type {
|
|
17
|
+
AstGrepDiagnostic,
|
|
18
|
+
AstGrepMatch,
|
|
19
|
+
RuleDescription,
|
|
20
|
+
SgMatch,
|
|
21
|
+
} from "./ast-grep-types.js";
|
|
22
|
+
import { SgRunner } from "./sg-runner.js";
|
|
17
23
|
|
|
18
24
|
const _getExtensionDir = () => {
|
|
19
25
|
if (typeof __dirname !== "undefined") {
|
|
@@ -22,39 +28,6 @@ const _getExtensionDir = () => {
|
|
|
22
28
|
return ".";
|
|
23
29
|
};
|
|
24
30
|
|
|
25
|
-
// --- Types ---
|
|
26
|
-
|
|
27
|
-
export interface RuleDescription {
|
|
28
|
-
id: string;
|
|
29
|
-
message: string;
|
|
30
|
-
note?: string;
|
|
31
|
-
severity: "error" | "warning" | "info" | "hint";
|
|
32
|
-
grade?: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface AstGrepMatch {
|
|
36
|
-
file: string;
|
|
37
|
-
range: {
|
|
38
|
-
start: { line: number; column: number };
|
|
39
|
-
end: { line: number; column: number };
|
|
40
|
-
};
|
|
41
|
-
text: string;
|
|
42
|
-
replacement?: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface AstGrepDiagnostic {
|
|
46
|
-
line: number;
|
|
47
|
-
column: number;
|
|
48
|
-
endLine: number;
|
|
49
|
-
endColumn: number;
|
|
50
|
-
severity: "error" | "warning" | "info" | "hint";
|
|
51
|
-
message: string;
|
|
52
|
-
rule: string;
|
|
53
|
-
ruleDescription?: RuleDescription;
|
|
54
|
-
file: string;
|
|
55
|
-
fix?: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
31
|
// --- Client ---
|
|
59
32
|
|
|
60
33
|
export class AstGrepClient {
|
|
@@ -140,7 +113,7 @@ export class AstGrepClient {
|
|
|
140
113
|
ruleId: string,
|
|
141
114
|
ruleYaml: string,
|
|
142
115
|
timeout = 30000,
|
|
143
|
-
):
|
|
116
|
+
): AstGrepMatch[] {
|
|
144
117
|
if (!this.isAvailable()) return [];
|
|
145
118
|
return this.runner.tempScan(dir, ruleId, ruleYaml, timeout);
|
|
146
119
|
}
|
|
@@ -171,7 +144,7 @@ message: found
|
|
|
171
144
|
return this.groupSimilarFunctions(matches);
|
|
172
145
|
}
|
|
173
146
|
|
|
174
|
-
private groupSimilarFunctions(matches:
|
|
147
|
+
private groupSimilarFunctions(matches: AstGrepMatch[]): Array<{
|
|
175
148
|
pattern: string;
|
|
176
149
|
functions: Array<{ name: string; file: string; line: number }>;
|
|
177
150
|
}> {
|
|
@@ -289,7 +262,7 @@ message: found
|
|
|
289
262
|
{
|
|
290
263
|
encoding: "utf-8",
|
|
291
264
|
timeout: 15000,
|
|
292
|
-
shell:
|
|
265
|
+
shell: process.platform === "win32",
|
|
293
266
|
},
|
|
294
267
|
);
|
|
295
268
|
|
|
@@ -302,8 +275,10 @@ message: found
|
|
|
302
275
|
(sev) => this.mapSeverity(sev),
|
|
303
276
|
);
|
|
304
277
|
return parser.parseOutput(output, absolutePath);
|
|
305
|
-
} catch (err
|
|
306
|
-
this.log(
|
|
278
|
+
} catch (err) {
|
|
279
|
+
this.log(
|
|
280
|
+
`Scan error: ${err instanceof Error ? err.message : String(err)}`,
|
|
281
|
+
);
|
|
307
282
|
return [];
|
|
308
283
|
}
|
|
309
284
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import type { AstGrepDiagnostic, RuleDescription } from "./ast-grep-
|
|
2
|
+
import type { AstGrepDiagnostic, RuleDescription } from "./ast-grep-types.js";
|
|
3
3
|
|
|
4
4
|
// New ast-grep JSON format
|
|
5
5
|
export interface AstGrepJsonDiagnostic {
|
|
@@ -63,6 +63,14 @@ export class AstGrepRuleManager {
|
|
|
63
63
|
const gradeMatch = content.match(/Grade\s+(\d+\.\d+)/i);
|
|
64
64
|
if (gradeMatch)
|
|
65
65
|
result.grade = parseFloat(gradeMatch[1]);
|
|
66
|
+
const fixMatch = content.match(/^fix:\s*\|?([\s\S]*?)(?=^\w|^rule:|Z)/m);
|
|
67
|
+
if (fixMatch) {
|
|
68
|
+
result.fix = fixMatch[1]
|
|
69
|
+
.split("\n")
|
|
70
|
+
.map((line) => line.replace(/^\s*\|?\s*/, ""))
|
|
71
|
+
.filter((line) => line.length > 0)
|
|
72
|
+
.join("\n");
|
|
73
|
+
}
|
|
66
74
|
if (result.id && result.message) {
|
|
67
75
|
return result;
|
|
68
76
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { RuleDescription } from "./ast-grep-
|
|
3
|
+
import type { RuleDescription } from "./ast-grep-types.js";
|
|
4
4
|
|
|
5
5
|
export class AstGrepRuleManager {
|
|
6
6
|
private ruleDescriptions: Map<string, RuleDescription> | null = null;
|
|
@@ -79,6 +79,15 @@ export class AstGrepRuleManager {
|
|
|
79
79
|
const gradeMatch = content.match(/Grade\s+(\d+\.\d+)/i);
|
|
80
80
|
if (gradeMatch) result.grade = parseFloat(gradeMatch[1]);
|
|
81
81
|
|
|
82
|
+
const fixMatch = content.match(/^fix:\s*\|?([\s\S]*?)(?=^\w|^rule:|Z)/m);
|
|
83
|
+
if (fixMatch) {
|
|
84
|
+
result.fix = fixMatch[1]
|
|
85
|
+
.split("\n")
|
|
86
|
+
.map((line) => line.replace(/^\s*\|?\s*/, ""))
|
|
87
|
+
.filter((line) => line.length > 0)
|
|
88
|
+
.join("\n");
|
|
89
|
+
}
|
|
90
|
+
|
|
82
91
|
if (result.id && result.message) {
|
|
83
92
|
return result as RuleDescription;
|
|
84
93
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for ast-grep client, parser, and rule manager.
|
|
3
|
+
*
|
|
4
|
+
* Extracted to prevent circular dependencies between:
|
|
5
|
+
* - ast-grep-client.ts
|
|
6
|
+
* - ast-grep-parser.ts
|
|
7
|
+
* - ast-grep-rule-manager.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// RULE DESCRIPTIONS
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
export interface RuleDescription {
|
|
15
|
+
id: string;
|
|
16
|
+
message: string;
|
|
17
|
+
note?: string;
|
|
18
|
+
fix?: string; // Suggested fix from rule
|
|
19
|
+
severity: "error" | "warning" | "info" | "hint";
|
|
20
|
+
grade?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// MATCHES (from sg-runner)
|
|
25
|
+
// =============================================================================
|
|
26
|
+
|
|
27
|
+
export interface SgMatch {
|
|
28
|
+
file: string;
|
|
29
|
+
range: {
|
|
30
|
+
start: { line: number; column: number };
|
|
31
|
+
end: { line: number; column: number };
|
|
32
|
+
};
|
|
33
|
+
text: string;
|
|
34
|
+
replacement?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SgResult {
|
|
38
|
+
matches: SgMatch[];
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// DIAGNOSTICS
|
|
44
|
+
// =============================================================================
|
|
45
|
+
|
|
46
|
+
export interface AstGrepMatch {
|
|
47
|
+
file: string;
|
|
48
|
+
range: {
|
|
49
|
+
start: { line: number; column: number };
|
|
50
|
+
end: { line: number; column: number };
|
|
51
|
+
};
|
|
52
|
+
text: string;
|
|
53
|
+
replacement?: string;
|
|
54
|
+
labels?: Array<{
|
|
55
|
+
range: {
|
|
56
|
+
start: { line: number; column: number };
|
|
57
|
+
end: { line: number; column: number };
|
|
58
|
+
};
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface AstGrepDiagnostic {
|
|
63
|
+
line: number;
|
|
64
|
+
column: number;
|
|
65
|
+
endLine: number;
|
|
66
|
+
endColumn: number;
|
|
67
|
+
severity: "error" | "warning" | "info" | "hint";
|
|
68
|
+
message: string;
|
|
69
|
+
rule: string;
|
|
70
|
+
ruleDescription?: RuleDescription;
|
|
71
|
+
file: string;
|
|
72
|
+
fix?: string;
|
|
73
|
+
note?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// JSON FORMAT (ast-grep CLI output)
|
|
78
|
+
// =============================================================================
|
|
79
|
+
|
|
80
|
+
export interface AstGrepJsonDiagnostic {
|
|
81
|
+
ruleId: string;
|
|
82
|
+
severity: string;
|
|
83
|
+
message: string;
|
|
84
|
+
note?: string;
|
|
85
|
+
labels: Array<{
|
|
86
|
+
text: string;
|
|
87
|
+
range: {
|
|
88
|
+
start: { line: number; column: number };
|
|
89
|
+
end: { line: number; column: number };
|
|
90
|
+
};
|
|
91
|
+
file?: string;
|
|
92
|
+
style: string;
|
|
93
|
+
}>;
|
|
94
|
+
// Legacy format support
|
|
95
|
+
Message?: { text: string };
|
|
96
|
+
Severity?: string;
|
|
97
|
+
spans?: Array<{
|
|
98
|
+
context: string;
|
|
99
|
+
range: {
|
|
100
|
+
start: { line: number; column: number };
|
|
101
|
+
end: { line: number; column: number };
|
|
102
|
+
};
|
|
103
|
+
file: string;
|
|
104
|
+
}>;
|
|
105
|
+
name?: string;
|
|
106
|
+
}
|
package/clients/auto-loop.js
CHANGED
|
@@ -99,6 +99,15 @@ export function createAutoLoop(pi, config) {
|
|
|
99
99
|
complete(ctx, "completed - no more work");
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
+
// Check if agent is waiting for manual fixes (indicated in the prompt)
|
|
103
|
+
// If the last message says "When done, run..." we should NOT auto-continue
|
|
104
|
+
const awaitingManualFix = textContent.includes("When done, run");
|
|
105
|
+
if (awaitingManualFix) {
|
|
106
|
+
console.error("[auto-loop] Paused - awaiting agent manual fixes");
|
|
107
|
+
updateStatus(ctx);
|
|
108
|
+
// Don't send followUp - wait for agent to manually continue
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
102
111
|
// Check max iterations
|
|
103
112
|
state.iteration++;
|
|
104
113
|
if (state.iteration >= state.maxIterations) {
|
|
@@ -108,6 +117,7 @@ export function createAutoLoop(pi, config) {
|
|
|
108
117
|
// Continue to next iteration - send command as follow-up
|
|
109
118
|
updateStatus(ctx);
|
|
110
119
|
const continueMsg = config.continuePrompt || `Run ${config.command} to continue.`;
|
|
120
|
+
console.error(`[auto-loop] Triggering iteration ${state.iteration + 1}/${state.maxIterations}: ${config.command}`);
|
|
111
121
|
pi.sendUserMessage(`🔄 Auto-loop (${state.iteration + 1}/${state.maxIterations}): ${continueMsg}`, { deliverAs: "followUp" });
|
|
112
122
|
});
|
|
113
123
|
return {
|
package/clients/auto-loop.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface LoopConfig {
|
|
|
20
20
|
name: string;
|
|
21
21
|
/** Maximum iterations before stopping */
|
|
22
22
|
maxIterations: number;
|
|
23
|
-
/** Command to run for each iteration
|
|
23
|
+
/** Command to run for each iteration */
|
|
24
24
|
command: string;
|
|
25
25
|
/** Patterns that indicate the loop should exit (e.g., "no more fixable issues") */
|
|
26
26
|
exitPatterns: RegExp[];
|
|
@@ -159,6 +159,16 @@ export function createAutoLoop(
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
// Check if agent is waiting for manual fixes (indicated in the prompt)
|
|
163
|
+
// If the last message says "When done, run..." we should NOT auto-continue
|
|
164
|
+
const awaitingManualFix = textContent.includes("When done, run");
|
|
165
|
+
if (awaitingManualFix) {
|
|
166
|
+
console.error("[auto-loop] Paused - awaiting agent manual fixes");
|
|
167
|
+
updateStatus(ctx);
|
|
168
|
+
// Don't send followUp - wait for agent to manually continue
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
162
172
|
// Check max iterations
|
|
163
173
|
state.iteration++;
|
|
164
174
|
if (state.iteration >= state.maxIterations) {
|
|
@@ -170,6 +180,9 @@ export function createAutoLoop(
|
|
|
170
180
|
updateStatus(ctx);
|
|
171
181
|
const continueMsg =
|
|
172
182
|
config.continuePrompt || `Run ${config.command} to continue.`;
|
|
183
|
+
console.error(
|
|
184
|
+
`[auto-loop] Triggering iteration ${state.iteration + 1}/${state.maxIterations}: ${config.command}`,
|
|
185
|
+
);
|
|
173
186
|
pi.sendUserMessage(
|
|
174
187
|
`🔄 Auto-loop (${state.iteration + 1}/${state.maxIterations}): ${continueMsg}`,
|
|
175
188
|
{ deliverAs: "followUp" },
|
package/clients/biome-client.js
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* Requires: npm install @biomejs/biome (or npx @biomejs/biome)
|
|
8
8
|
* Docs: https://biomejs.dev/
|
|
9
9
|
*/
|
|
10
|
-
import { spawnSync } from "node:child_process";
|
|
11
10
|
import * as fs from "node:fs";
|
|
12
11
|
import * as path from "node:path";
|
|
13
12
|
import { isFileKind } from "./file-kinds.js";
|
|
13
|
+
import { safeSpawn } from "./safe-spawn.js";
|
|
14
14
|
// --- Client ---
|
|
15
15
|
export class BiomeClient {
|
|
16
16
|
constructor(verbose = false) {
|
|
@@ -26,10 +26,8 @@ export class BiomeClient {
|
|
|
26
26
|
if (this.biomeAvailable !== null)
|
|
27
27
|
return this.biomeAvailable;
|
|
28
28
|
// Try npx biome first (works without global install)
|
|
29
|
-
const result =
|
|
30
|
-
encoding: "utf-8",
|
|
29
|
+
const result = safeSpawn("npx", ["@biomejs/biome", "--version"], {
|
|
31
30
|
timeout: 10000,
|
|
32
|
-
shell: true,
|
|
33
31
|
});
|
|
34
32
|
this.biomeAvailable = !result.error && result.status === 0;
|
|
35
33
|
if (this.biomeAvailable) {
|
|
@@ -67,16 +65,14 @@ export class BiomeClient {
|
|
|
67
65
|
if (!absolutePath)
|
|
68
66
|
return [];
|
|
69
67
|
try {
|
|
70
|
-
const result =
|
|
68
|
+
const result = safeSpawn("npx", [
|
|
71
69
|
"@biomejs/biome",
|
|
72
70
|
"check",
|
|
73
71
|
"--reporter=json",
|
|
74
72
|
"--max-diagnostics=50",
|
|
75
73
|
absolutePath,
|
|
76
74
|
], {
|
|
77
|
-
encoding: "utf-8",
|
|
78
75
|
timeout: 15000,
|
|
79
|
-
shell: true,
|
|
80
76
|
});
|
|
81
77
|
// Biome exits 0 on success, 1 on issues found
|
|
82
78
|
const output = result.stdout || "";
|
|
@@ -85,7 +81,7 @@ export class BiomeClient {
|
|
|
85
81
|
return this.parseDiagnostics(output, absolutePath);
|
|
86
82
|
}
|
|
87
83
|
catch (err) {
|
|
88
|
-
this.log(`Check error: ${err.message}`);
|
|
84
|
+
this.log(`Check error: ${err instanceof Error ? err.message : String(err)}`);
|
|
89
85
|
return [];
|
|
90
86
|
}
|
|
91
87
|
}
|
|
@@ -102,10 +98,8 @@ export class BiomeClient {
|
|
|
102
98
|
};
|
|
103
99
|
const content = fs.readFileSync(absolutePath, "utf-8");
|
|
104
100
|
try {
|
|
105
|
-
const result =
|
|
106
|
-
encoding: "utf-8",
|
|
101
|
+
const result = safeSpawn("npx", ["@biomejs/biome", "format", "--write", absolutePath], {
|
|
107
102
|
timeout: 15000,
|
|
108
|
-
shell: true,
|
|
109
103
|
});
|
|
110
104
|
if (result.error) {
|
|
111
105
|
return { success: false, changed: false, error: result.error.message };
|
|
@@ -119,7 +113,11 @@ export class BiomeClient {
|
|
|
119
113
|
return { success: true, changed };
|
|
120
114
|
}
|
|
121
115
|
catch (err) {
|
|
122
|
-
return {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
changed: false,
|
|
119
|
+
error: err instanceof Error ? err.message : String(err),
|
|
120
|
+
};
|
|
123
121
|
}
|
|
124
122
|
}
|
|
125
123
|
/**
|
|
@@ -140,16 +138,14 @@ export class BiomeClient {
|
|
|
140
138
|
const beforeDiags = this.checkFile(filePath);
|
|
141
139
|
const fixableCount = beforeDiags.filter((d) => d.fixable).length;
|
|
142
140
|
// Apply fixes
|
|
143
|
-
const result =
|
|
141
|
+
const result = safeSpawn("npx", [
|
|
144
142
|
"@biomejs/biome",
|
|
145
143
|
"check",
|
|
146
144
|
"--write",
|
|
147
145
|
"--unsafe", // Apply unsafe fixes too
|
|
148
146
|
absolutePath,
|
|
149
147
|
], {
|
|
150
|
-
encoding: "utf-8",
|
|
151
148
|
timeout: 15000,
|
|
152
|
-
shell: true,
|
|
153
149
|
});
|
|
154
150
|
if (result.error) {
|
|
155
151
|
return {
|
|
@@ -167,7 +163,75 @@ export class BiomeClient {
|
|
|
167
163
|
return { success: true, changed, fixed: fixableCount };
|
|
168
164
|
}
|
|
169
165
|
catch (err) {
|
|
170
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
success: false,
|
|
168
|
+
changed: false,
|
|
169
|
+
fixed: 0,
|
|
170
|
+
error: err instanceof Error ? err.message : String(err),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Fix multiple files at once (much faster than file-by-file)
|
|
176
|
+
*/
|
|
177
|
+
fixFiles(filePaths) {
|
|
178
|
+
if (!this.isAvailable()) {
|
|
179
|
+
return {
|
|
180
|
+
success: false,
|
|
181
|
+
fixed: 0,
|
|
182
|
+
changed: 0,
|
|
183
|
+
error: "Biome not available",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// Filter to existing files
|
|
187
|
+
const validFiles = filePaths
|
|
188
|
+
.map(f => path.resolve(f))
|
|
189
|
+
.filter(f => fs.existsSync(f));
|
|
190
|
+
if (validFiles.length === 0) {
|
|
191
|
+
return { success: true, fixed: 0, changed: 0 };
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
// Count fixable issues before fixing
|
|
195
|
+
let totalFixable = 0;
|
|
196
|
+
for (const file of validFiles) {
|
|
197
|
+
const diags = this.checkFile(file);
|
|
198
|
+
totalFixable += diags.filter(d => d.fixable).length;
|
|
199
|
+
}
|
|
200
|
+
// Run biome once on all files - much faster than npx per file
|
|
201
|
+
const result = safeSpawn("npx", [
|
|
202
|
+
"@biomejs/biome",
|
|
203
|
+
"check",
|
|
204
|
+
"--write",
|
|
205
|
+
"--unsafe",
|
|
206
|
+
...validFiles,
|
|
207
|
+
], {
|
|
208
|
+
timeout: 60000, // Longer timeout for batch
|
|
209
|
+
});
|
|
210
|
+
if (result.error) {
|
|
211
|
+
return {
|
|
212
|
+
success: false,
|
|
213
|
+
fixed: 0,
|
|
214
|
+
changed: 0,
|
|
215
|
+
error: result.error.message,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
// Count how many files actually changed
|
|
219
|
+
let changedCount = 0;
|
|
220
|
+
for (const file of validFiles) {
|
|
221
|
+
// We don't know exactly which files changed without re-reading,
|
|
222
|
+
// so we report total files processed
|
|
223
|
+
changedCount++;
|
|
224
|
+
}
|
|
225
|
+
this.log(`Fixed ${totalFixable} issue(s) in ${validFiles.length} file(s)`);
|
|
226
|
+
return { success: true, fixed: totalFixable, changed: changedCount };
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
return {
|
|
230
|
+
success: false,
|
|
231
|
+
fixed: 0,
|
|
232
|
+
changed: 0,
|
|
233
|
+
error: err instanceof Error ? err.message : String(err),
|
|
234
|
+
};
|
|
171
235
|
}
|
|
172
236
|
}
|
|
173
237
|
/**
|
|
@@ -213,10 +277,8 @@ export class BiomeClient {
|
|
|
213
277
|
const content = fs.readFileSync(absolutePath, "utf-8");
|
|
214
278
|
try {
|
|
215
279
|
// Get formatted output without writing
|
|
216
|
-
const result =
|
|
217
|
-
encoding: "utf-8",
|
|
280
|
+
const result = safeSpawn("npx", ["@biomejs/biome", "format", absolutePath], {
|
|
218
281
|
timeout: 15000,
|
|
219
|
-
shell: true,
|
|
220
282
|
});
|
|
221
283
|
if (result.error || !result.stdout)
|
|
222
284
|
return "";
|