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
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Secrets scanner runner
|
|
3
|
-
*
|
|
4
|
-
* Scans file content for potential secret patterns before write.
|
|
5
|
-
* Works on all file types via regex matching.
|
|
6
|
-
*
|
|
7
|
-
* Patterns detected:
|
|
8
|
-
* - Stripe/OpenAI keys (sk-*)
|
|
9
|
-
* - GitHub tokens (ghp_*, gho_*, github_pat_*)
|
|
10
|
-
* - AWS keys (AKIA*)
|
|
11
|
-
* - Slack tokens (xoxp-*, xoxb-*)
|
|
12
|
-
* - Private keys (BEGIN PRIVATE KEY)
|
|
13
|
-
* - Generic API key patterns
|
|
14
|
-
*/
|
|
15
|
-
const SECRET_PATTERNS = [
|
|
16
|
-
{
|
|
17
|
-
pattern: /sk-[a-zA-Z0-9]{20,}/g,
|
|
18
|
-
name: "stripe-openai-key",
|
|
19
|
-
message: "Possible Stripe or OpenAI API key (sk-*)",
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
pattern: /ghp_[a-zA-Z0-9]{36}/g,
|
|
23
|
-
name: "github-personal-token",
|
|
24
|
-
message: "GitHub personal access token (ghp_*)",
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
pattern: /gho_[a-zA-Z0-9]{36}/g,
|
|
28
|
-
name: "github-oauth-token",
|
|
29
|
-
message: "GitHub OAuth token (gho_*)",
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
pattern: /github_pat_[a-zA-Z_]{82}/g,
|
|
33
|
-
name: "github-fine-grained-pat",
|
|
34
|
-
message: "GitHub fine-grained PAT (github_pat_*)",
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
pattern: /AKIA[0-9A-Z]{16}/g,
|
|
38
|
-
name: "aws-access-key",
|
|
39
|
-
message: "AWS access key ID (AKIA*)",
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
pattern: /xox[bp]-[a-zA-Z0-9]{10,}/g,
|
|
43
|
-
name: "slack-token",
|
|
44
|
-
message: "Slack token (xoxb-*/xoxp-*)",
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
pattern: /-----BEGIN\s+(RSA\s+)?PRIVATE KEY-----/g,
|
|
48
|
-
name: "private-key",
|
|
49
|
-
message: "Private key material detected",
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
pattern: /password\s*[:=]\s*["'][^"']{8,}["']/gi,
|
|
53
|
-
name: "hardcoded-password",
|
|
54
|
-
message: "Possible hardcoded password",
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
pattern: /(?:secret|api_?key|token)\s*[:=]\s*["'][a-zA-Z0-9]{20,}["']/gi,
|
|
58
|
-
name: "generic-api-secret",
|
|
59
|
-
message: "Possible hardcoded secret, API key, or token",
|
|
60
|
-
},
|
|
61
|
-
];
|
|
62
|
-
function scanContent(content) {
|
|
63
|
-
const findings = [];
|
|
64
|
-
const lines = content.split("\n");
|
|
65
|
-
for (let i = 0; i < lines.length; i++) {
|
|
66
|
-
const line = lines[i];
|
|
67
|
-
for (const secret of SECRET_PATTERNS) {
|
|
68
|
-
secret.pattern.lastIndex = 0; // Reset regex state
|
|
69
|
-
const match = secret.pattern.exec(line);
|
|
70
|
-
if (match) {
|
|
71
|
-
findings.push({
|
|
72
|
-
line: i + 1,
|
|
73
|
-
pattern: secret,
|
|
74
|
-
match: match[0].slice(0, 20) + "...",
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return findings;
|
|
80
|
-
}
|
|
81
|
-
async function run(ctx) {
|
|
82
|
-
const diagnostics = [];
|
|
83
|
-
// Get the content being written - check both full content and the diff
|
|
84
|
-
const content = ctx.content;
|
|
85
|
-
if (!content)
|
|
86
|
-
return { diagnostics };
|
|
87
|
-
const findings = scanContent(content);
|
|
88
|
-
for (const finding of findings) {
|
|
89
|
-
diagnostics.push({
|
|
90
|
-
id: `secrets-${finding.pattern.name}-${finding.line}`,
|
|
91
|
-
message: `${finding.pattern.message} at line ${finding.line}. Remove before committing.`,
|
|
92
|
-
filePath: ctx.filePath,
|
|
93
|
-
line: finding.line,
|
|
94
|
-
severity: "error",
|
|
95
|
-
semantic: "blocking", // Always blocking - secrets should never be committed
|
|
96
|
-
tool: "secrets",
|
|
97
|
-
rule: finding.pattern.name,
|
|
98
|
-
fixable: false,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
return { diagnostics };
|
|
102
|
-
}
|
|
103
|
-
const runner = {
|
|
104
|
-
id: "secrets",
|
|
105
|
-
appliesTo: ["*"], // All file types
|
|
106
|
-
priority: 0, // Run first - block before other checks
|
|
107
|
-
run,
|
|
108
|
-
};
|
|
109
|
-
export default runner;
|
package/commands/fix.js
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fix command for pi-lens
|
|
3
|
-
*
|
|
4
|
-
* Automated fix loop that scans for issues and generates fix plans.
|
|
5
|
-
* Supports --loop flag for automatic iteration via auto-loop engine.
|
|
6
|
-
*/
|
|
7
|
-
import * as childProcess from "node:child_process";
|
|
8
|
-
import * as nodeFs from "node:fs";
|
|
9
|
-
import * as path from "node:path";
|
|
10
|
-
import { createAutoLoop } from "../clients/auto-loop.js";
|
|
11
|
-
import { scanAll, } from "../clients/fix-scanners.js";
|
|
12
|
-
// --- Auto-loop singleton ---
|
|
13
|
-
let fixLoop = null;
|
|
14
|
-
function getFixLoop(pi) {
|
|
15
|
-
if (!fixLoop) {
|
|
16
|
-
fixLoop = createAutoLoop(pi, {
|
|
17
|
-
name: "fix",
|
|
18
|
-
maxIterations: 3,
|
|
19
|
-
command: "/lens-booboo-fix --loop",
|
|
20
|
-
exitPatterns: [
|
|
21
|
-
/✅ BOOBOO FIX LOOP COMPLETE/,
|
|
22
|
-
/⚠️ BOOBOO FIX LOOP STOPPED/,
|
|
23
|
-
/No more fixable issues/,
|
|
24
|
-
/Max iterations.*reached/,
|
|
25
|
-
],
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return fixLoop;
|
|
29
|
-
}
|
|
30
|
-
function loadSession(sessionFile) {
|
|
31
|
-
try {
|
|
32
|
-
const session = JSON.parse(nodeFs.readFileSync(sessionFile, "utf-8"));
|
|
33
|
-
return {
|
|
34
|
-
iteration: session.iteration || 0,
|
|
35
|
-
counts: session.counts || {},
|
|
36
|
-
falsePositives: session.falsePositives || [],
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return { iteration: 0, counts: {}, falsePositives: [] };
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function saveSession(sessionFile, session) {
|
|
44
|
-
nodeFs.mkdirSync(path.dirname(sessionFile), { recursive: true });
|
|
45
|
-
nodeFs.writeFileSync(sessionFile, JSON.stringify(session, null, 2), "utf-8");
|
|
46
|
-
}
|
|
47
|
-
function resetSession(sessionFile) {
|
|
48
|
-
try {
|
|
49
|
-
nodeFs.unlinkSync(sessionFile);
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// Ignore if doesn't exist
|
|
53
|
-
}
|
|
54
|
-
return { iteration: 0, counts: {}, falsePositives: [] };
|
|
55
|
-
}
|
|
56
|
-
// --- Issue ID helpers ---
|
|
57
|
-
const issueId = (type, file, line) => line !== undefined ? `${type}:${file}:${line}` : `${type}:${file}`;
|
|
58
|
-
const isFalsePositive = (id, session) => session.falsePositives.includes(id);
|
|
59
|
-
// --- Plan generation ---
|
|
60
|
-
function generatePlan(results, session, _isTsProject, prevCounts) {
|
|
61
|
-
const MAX_ITERATIONS = 3;
|
|
62
|
-
// Filter out false positives
|
|
63
|
-
const filteredDups = results.duplicates.filter((c) => !isFalsePositive(issueId("duplicate", c.fileA, c.startA), session));
|
|
64
|
-
const filteredDeadCode = results.deadCode.filter((i) => !isFalsePositive(issueId("dead_code", i.file ?? i.name), session));
|
|
65
|
-
const filteredBiome = results.biomeIssues.filter((i) => !isFalsePositive(issueId("biome", i.file, i.line), session));
|
|
66
|
-
const filteredSlop = results.slopFiles.filter((f) => !isFalsePositive(issueId("slop", f.file), session));
|
|
67
|
-
// Filter ast issues (exclude skip rules and false positives)
|
|
68
|
-
const agentTasks = results.astIssues.filter((i) => !isFalsePositive(issueId("ast", i.file, i.line), session));
|
|
69
|
-
const totalFixable = filteredDups.length +
|
|
70
|
-
filteredDeadCode.length +
|
|
71
|
-
agentTasks.length +
|
|
72
|
-
filteredBiome.length +
|
|
73
|
-
filteredSlop.length;
|
|
74
|
-
// Check for no progress
|
|
75
|
-
const prevTotal = Object.values(prevCounts).reduce((a, b) => a + b, 0);
|
|
76
|
-
const noProgress = session.iteration > 1 && prevTotal === totalFixable && totalFixable > 0;
|
|
77
|
-
// Completion/stopped messages
|
|
78
|
-
if (totalFixable === 0) {
|
|
79
|
-
const fpNote = session.falsePositives.length > 0
|
|
80
|
-
? `\n\n📝 ${session.falsePositives.length} item(s) marked as false positives.`
|
|
81
|
-
: "";
|
|
82
|
-
return `✅ BOOBOO FIX LOOP COMPLETE — No more fixable issues found after ${session.iteration} iteration(s).${fpNote}`;
|
|
83
|
-
}
|
|
84
|
-
if (noProgress) {
|
|
85
|
-
return `⚠️ BOOBOO FIX LOOP STOPPED — No progress after ${session.iteration} iteration(s).\n\nRemaining items may be false positives. Mark with: /lens-booboo-fix --false-positive "<type>:<file>:<line>"`;
|
|
86
|
-
}
|
|
87
|
-
// --- Write TSV plan file for agent to read ---
|
|
88
|
-
const reportDir = path.join(process.cwd(), ".pi-lens", "reports");
|
|
89
|
-
nodeFs.mkdirSync(reportDir, { recursive: true });
|
|
90
|
-
const reportPath = path.join(reportDir, "fix-plan.tsv");
|
|
91
|
-
const tsvRows = ["type\tfile\trule\tmessage"];
|
|
92
|
-
// Duplicates
|
|
93
|
-
for (const clone of filteredDups) {
|
|
94
|
-
tsvRows.push(`dup\t${clone.fileA}:${clone.startA}\tduplicate-code\t${clone.lines} lines duplicated with ${clone.fileB}:${clone.startB}`);
|
|
95
|
-
}
|
|
96
|
-
// Dead code
|
|
97
|
-
for (const issue of filteredDeadCode) {
|
|
98
|
-
tsvRows.push(`dead\t${issue.file || issue.name}\t${issue.type}\t${issue.name} is unused`);
|
|
99
|
-
}
|
|
100
|
-
// AST issues
|
|
101
|
-
for (const issue of agentTasks) {
|
|
102
|
-
tsvRows.push(`ast\t${issue.file}:${issue.line}\t${issue.rule}\t${issue.message}`);
|
|
103
|
-
}
|
|
104
|
-
// Biome
|
|
105
|
-
for (const issue of filteredBiome) {
|
|
106
|
-
tsvRows.push(`biome\t${issue.file}:${issue.line}\t${issue.rule}\t${issue.message}`);
|
|
107
|
-
}
|
|
108
|
-
// Slop
|
|
109
|
-
for (const { file, warnings } of filteredSlop) {
|
|
110
|
-
for (const w of warnings) {
|
|
111
|
-
tsvRows.push(`slop\t${file}\tcomplexity\t${w}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
nodeFs.writeFileSync(reportPath, tsvRows.join("\n"), "utf-8");
|
|
115
|
-
// --- Build actionable list for terminal (no TSV reading needed) ---
|
|
116
|
-
const lines = [];
|
|
117
|
-
lines.push(`📋 FIX PLAN — Iteration ${session.iteration}/${MAX_ITERATIONS} — ${totalFixable} issues:\n`);
|
|
118
|
-
// Duplicates
|
|
119
|
-
if (filteredDups.length > 0) {
|
|
120
|
-
for (const clone of filteredDups.slice(0, 10)) {
|
|
121
|
-
lines.push(`🔁 ${clone.fileA}:${clone.startA} — ${clone.lines} dup from ${clone.fileB}:${clone.startB}`);
|
|
122
|
-
}
|
|
123
|
-
if (filteredDups.length > 10)
|
|
124
|
-
lines.push(` ... +${filteredDups.length - 10} more`);
|
|
125
|
-
lines.push("");
|
|
126
|
-
}
|
|
127
|
-
// Dead code
|
|
128
|
-
if (filteredDeadCode.length > 0) {
|
|
129
|
-
for (const issue of filteredDeadCode.slice(0, 10)) {
|
|
130
|
-
lines.push(`🗑️ ${issue.file || issue.name} — ${issue.name} unused`);
|
|
131
|
-
}
|
|
132
|
-
if (filteredDeadCode.length > 10)
|
|
133
|
-
lines.push(` ... +${filteredDeadCode.length - 10} more`);
|
|
134
|
-
lines.push("");
|
|
135
|
-
}
|
|
136
|
-
// AST lint
|
|
137
|
-
if (agentTasks.length > 0) {
|
|
138
|
-
for (const issue of agentTasks.slice(0, 15)) {
|
|
139
|
-
lines.push(`🔨 ${issue.file}:${issue.line} — ${issue.rule}`);
|
|
140
|
-
}
|
|
141
|
-
if (agentTasks.length > 15)
|
|
142
|
-
lines.push(` ... +${agentTasks.length - 15} more`);
|
|
143
|
-
lines.push("");
|
|
144
|
-
}
|
|
145
|
-
// Biome
|
|
146
|
-
if (filteredBiome.length > 0) {
|
|
147
|
-
for (const issue of filteredBiome.slice(0, 10)) {
|
|
148
|
-
lines.push(`🟠 ${issue.file}:${issue.line} — ${issue.rule}`);
|
|
149
|
-
}
|
|
150
|
-
if (filteredBiome.length > 10)
|
|
151
|
-
lines.push(` ... +${filteredBiome.length - 10} more`);
|
|
152
|
-
lines.push("");
|
|
153
|
-
}
|
|
154
|
-
// AI Slop
|
|
155
|
-
if (filteredSlop.length > 0) {
|
|
156
|
-
for (const { file, warnings } of filteredSlop.slice(0, 5)) {
|
|
157
|
-
lines.push(`🤖 ${file} — ${warnings[0]}`);
|
|
158
|
-
}
|
|
159
|
-
if (filteredSlop.length > 5)
|
|
160
|
-
lines.push(` ... +${filteredSlop.length - 5} more`);
|
|
161
|
-
lines.push("");
|
|
162
|
-
}
|
|
163
|
-
lines.push("---");
|
|
164
|
-
lines.push("🚀 Fix items above, then run `/lens-booboo-fix --loop`");
|
|
165
|
-
lines.push('🚫 False positive: `/lens-booboo-fix --false-positive "type:file:line"`');
|
|
166
|
-
return lines.join("\n");
|
|
167
|
-
}
|
|
168
|
-
// --- Main handler ---
|
|
169
|
-
export async function handleFix(args, ctx, clients, pi, _ruleActions) {
|
|
170
|
-
const resetRequested = args.includes("--reset");
|
|
171
|
-
const loopMode = args.includes("--loop");
|
|
172
|
-
const fpMatch = args.match(/--false-positive\s+"([^"]+)"/);
|
|
173
|
-
const falsePositiveId = fpMatch?.[1];
|
|
174
|
-
// Clean args
|
|
175
|
-
const cleanArgs = args
|
|
176
|
-
.replace("--reset", "")
|
|
177
|
-
.replace("--loop", "")
|
|
178
|
-
.replace(/--false-positive\s+"[^"]+"/, "")
|
|
179
|
-
.trim();
|
|
180
|
-
const targetPath = cleanArgs || ctx.cwd || process.cwd();
|
|
181
|
-
const sessionFile = path.join(process.cwd(), ".pi-lens", "fix-session.json");
|
|
182
|
-
const configPath = path.join(typeof __dirname !== "undefined" ? __dirname : ".", "..", "rules", "ast-grep-rules", ".sgconfig.yml");
|
|
183
|
-
// Load session
|
|
184
|
-
let session = loadSession(sessionFile);
|
|
185
|
-
if (resetRequested) {
|
|
186
|
-
session = resetSession(sessionFile);
|
|
187
|
-
ctx.ui.notify("🔄 Fix session reset.", "info");
|
|
188
|
-
}
|
|
189
|
-
// Handle false positive marking
|
|
190
|
-
if (falsePositiveId) {
|
|
191
|
-
if (!session.falsePositives.includes(falsePositiveId)) {
|
|
192
|
-
session.falsePositives.push(falsePositiveId);
|
|
193
|
-
saveSession(sessionFile, session);
|
|
194
|
-
ctx.ui.notify(`✅ Marked as false positive: "${falsePositiveId}"`, "info");
|
|
195
|
-
}
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
// Start auto-loop if requested
|
|
199
|
-
const loop = getFixLoop(pi);
|
|
200
|
-
if (loopMode && !loop.getState().active) {
|
|
201
|
-
loop.start(ctx);
|
|
202
|
-
}
|
|
203
|
-
ctx.ui.notify("🔧 Running booboo fix loop...", "info");
|
|
204
|
-
const isTsProject = nodeFs.existsSync(path.join(targetPath, "tsconfig.json"));
|
|
205
|
-
// Auto-fix with Biome + Ruff
|
|
206
|
-
if (!pi.getFlag("no-biome") && clients.biome.isAvailable()) {
|
|
207
|
-
childProcess.spawnSync("npx", ["@biomejs/biome", "check", "--write", "--unsafe", targetPath], {
|
|
208
|
-
encoding: "utf-8",
|
|
209
|
-
timeout: 30000,
|
|
210
|
-
shell: true,
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
if (!pi.getFlag("no-ruff") && clients.ruff.isAvailable()) {
|
|
214
|
-
childProcess.spawnSync("ruff", ["check", "--fix", targetPath], {
|
|
215
|
-
encoding: "utf-8",
|
|
216
|
-
timeout: 15000,
|
|
217
|
-
shell: true,
|
|
218
|
-
});
|
|
219
|
-
childProcess.spawnSync("ruff", ["format", targetPath], {
|
|
220
|
-
encoding: "utf-8",
|
|
221
|
-
timeout: 15000,
|
|
222
|
-
shell: true,
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
// Run all scanners
|
|
226
|
-
const prevCounts = { ...session.counts };
|
|
227
|
-
session.iteration++;
|
|
228
|
-
const results = scanAll(clients, targetPath, isTsProject, configPath);
|
|
229
|
-
// Update session counts
|
|
230
|
-
session.counts = {
|
|
231
|
-
duplicates: results.duplicates.length,
|
|
232
|
-
dead_code: results.deadCode.length,
|
|
233
|
-
ast_issues: results.astIssues.length,
|
|
234
|
-
biome_issues: results.biomeIssues.length,
|
|
235
|
-
slop_files: results.slopFiles.length,
|
|
236
|
-
};
|
|
237
|
-
saveSession(sessionFile, session);
|
|
238
|
-
// Generate and send plan
|
|
239
|
-
const plan = generatePlan(results, session, isTsProject, prevCounts);
|
|
240
|
-
const planPath = path.join(process.cwd(), ".pi-lens", "fix-plan.md");
|
|
241
|
-
nodeFs.writeFileSync(planPath, `# Fix Plan — Iteration ${session.iteration}\n\n${plan}`, "utf-8");
|
|
242
|
-
ctx.ui.notify(`📄 Fix plan saved: ${planPath}`, "info");
|
|
243
|
-
pi.sendUserMessage(plan, { deliverAs: "followUp" });
|
|
244
|
-
}
|