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/rust-client.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
12
|
import * as path from "node:path";
|
|
13
|
+
import { safeSpawn } from "./safe-spawn.js";
|
|
13
14
|
|
|
14
15
|
// --- Types ---
|
|
15
16
|
|
|
@@ -85,10 +86,8 @@ export class RustClient {
|
|
|
85
86
|
return p;
|
|
86
87
|
}
|
|
87
88
|
} else {
|
|
88
|
-
const result =
|
|
89
|
-
encoding: "utf-8",
|
|
89
|
+
const result = safeSpawn(p, ["--version"], {
|
|
90
90
|
timeout: 3000,
|
|
91
|
-
shell: true,
|
|
92
91
|
});
|
|
93
92
|
if (!result.error && result.status === 0) {
|
|
94
93
|
this.cargoPath = p;
|
|
@@ -133,15 +132,12 @@ export class RustClient {
|
|
|
133
132
|
if (!fs.existsSync(absolutePath)) return [];
|
|
134
133
|
|
|
135
134
|
try {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
cargoCmd,
|
|
135
|
+
const result = safeSpawn(
|
|
136
|
+
cargoExe,
|
|
139
137
|
["check", "--message-format", "json"],
|
|
140
138
|
{
|
|
141
|
-
encoding: "utf-8",
|
|
142
139
|
timeout: 60000,
|
|
143
140
|
cwd,
|
|
144
|
-
shell: true,
|
|
145
141
|
},
|
|
146
142
|
);
|
|
147
143
|
|
|
@@ -160,14 +156,12 @@ export class RustClient {
|
|
|
160
156
|
if (!this.isAvailable()) return [];
|
|
161
157
|
|
|
162
158
|
try {
|
|
163
|
-
const result =
|
|
159
|
+
const result = safeSpawn(
|
|
164
160
|
"cargo",
|
|
165
161
|
["clippy", "--message-format", "json"],
|
|
166
162
|
{
|
|
167
|
-
encoding: "utf-8",
|
|
168
163
|
timeout: 60000,
|
|
169
164
|
cwd,
|
|
170
|
-
shell: true,
|
|
171
165
|
},
|
|
172
166
|
);
|
|
173
167
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe cross-platform spawn utilities
|
|
3
|
+
*
|
|
4
|
+
* Wraps child_process.spawnSync to handle Windows execution safely
|
|
5
|
+
* without triggering deprecation warnings.
|
|
6
|
+
*
|
|
7
|
+
* Strategy:
|
|
8
|
+
* - Unix: Use shell: false with normal args
|
|
9
|
+
* - Windows: Manually construct command string to avoid deprecation warning,
|
|
10
|
+
* then use shell: true with no args array
|
|
11
|
+
*/
|
|
12
|
+
import { spawnSync } from "node:child_process";
|
|
13
|
+
/**
|
|
14
|
+
* Escape an argument for Windows shell execution.
|
|
15
|
+
* Handles spaces, quotes, $variables, and special characters.
|
|
16
|
+
*/
|
|
17
|
+
function escapeWindowsArg(arg) {
|
|
18
|
+
// Check if this looks like an ast-grep pattern with meta-variables ($NAME)
|
|
19
|
+
// In Git Bash/MSYS2 on Windows, $VAR gets expanded by the shell
|
|
20
|
+
// We need to use single quotes to prevent expansion
|
|
21
|
+
if (arg.includes("$")) {
|
|
22
|
+
// Use single quotes for arguments with $variables
|
|
23
|
+
// Escape single quotes within the argument
|
|
24
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
25
|
+
}
|
|
26
|
+
// If no special characters, return as-is
|
|
27
|
+
if (!/[\s\"]/.test(arg))
|
|
28
|
+
return arg;
|
|
29
|
+
// Escape quotes by doubling them
|
|
30
|
+
return `"${arg.replace(/"/g, "\"\"")}"`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Construct a command string for Windows shell execution.
|
|
34
|
+
* This avoids the deprecation warning by not passing an args array.
|
|
35
|
+
*/
|
|
36
|
+
function buildWindowsCommand(command, args) {
|
|
37
|
+
const escapedArgs = args.map(escapeWindowsArg).join(" ");
|
|
38
|
+
return `${command} ${escapedArgs}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Safely spawn a process cross-platform without shell deprecation warnings.
|
|
42
|
+
*
|
|
43
|
+
* On Windows: Uses shell: true but constructs the command string manually
|
|
44
|
+
* to avoid the deprecation warning about unescaped args.
|
|
45
|
+
* On Unix: Uses shell: false for normal execution.
|
|
46
|
+
*/
|
|
47
|
+
export function safeSpawn(command, args, options) {
|
|
48
|
+
if (process.platform === "win32") {
|
|
49
|
+
// On Windows, construct the full command string and use shell: true
|
|
50
|
+
// without an args array. This avoids the deprecation warning.
|
|
51
|
+
const fullCommand = buildWindowsCommand(command, args);
|
|
52
|
+
const result = spawnSync(fullCommand, {
|
|
53
|
+
...options,
|
|
54
|
+
encoding: "utf-8",
|
|
55
|
+
shell: true,
|
|
56
|
+
windowsHide: true,
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
stdout: result.stdout?.toString() || "",
|
|
60
|
+
stderr: result.stderr?.toString() || "",
|
|
61
|
+
status: result.status,
|
|
62
|
+
error: result.error,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// On Unix, use shell: false (the default) with normal args
|
|
66
|
+
const result = spawnSync(command, args, {
|
|
67
|
+
...options,
|
|
68
|
+
encoding: "utf-8",
|
|
69
|
+
shell: false,
|
|
70
|
+
windowsHide: true,
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
stdout: result.stdout?.toString() || "",
|
|
74
|
+
stderr: result.stderr?.toString() || "",
|
|
75
|
+
status: result.status,
|
|
76
|
+
error: result.error,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if a command is available in PATH
|
|
81
|
+
*/
|
|
82
|
+
export function isCommandAvailable(command) {
|
|
83
|
+
const result = safeSpawn(process.platform === "win32" ? "where" : "which", [command], { timeout: 5000 });
|
|
84
|
+
return result.status === 0;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Find the full path to a command (npx, node, etc.)
|
|
88
|
+
*/
|
|
89
|
+
export function findCommand(command) {
|
|
90
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
91
|
+
const result = safeSpawn(finder, [command], { timeout: 5000 });
|
|
92
|
+
if (result.status !== 0)
|
|
93
|
+
return null;
|
|
94
|
+
// Take first line (first match)
|
|
95
|
+
return result.stdout.trim().split("\n")[0] || null;
|
|
96
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe cross-platform spawn utilities
|
|
3
|
+
*
|
|
4
|
+
* Wraps child_process.spawnSync to handle Windows execution safely
|
|
5
|
+
* without triggering deprecation warnings.
|
|
6
|
+
*
|
|
7
|
+
* Strategy:
|
|
8
|
+
* - Unix: Use shell: false with normal args
|
|
9
|
+
* - Windows: Manually construct command string to avoid deprecation warning,
|
|
10
|
+
* then use shell: true with no args array
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawnSync, type SpawnOptions } from "node:child_process";
|
|
14
|
+
|
|
15
|
+
export interface SpawnResult {
|
|
16
|
+
stdout: string;
|
|
17
|
+
stderr: string;
|
|
18
|
+
status: number | null;
|
|
19
|
+
error?: Error;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SafeSpawnOptions {
|
|
23
|
+
timeout?: number;
|
|
24
|
+
cwd?: string;
|
|
25
|
+
env?: NodeJS.ProcessEnv;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Escape an argument for Windows shell execution.
|
|
30
|
+
* Handles spaces, quotes, $variables, and special characters.
|
|
31
|
+
*/
|
|
32
|
+
function escapeWindowsArg(arg: string): string {
|
|
33
|
+
// Check if this looks like an ast-grep pattern with meta-variables ($NAME)
|
|
34
|
+
// In Git Bash/MSYS2 on Windows, $VAR gets expanded by the shell
|
|
35
|
+
// We need to use single quotes to prevent expansion
|
|
36
|
+
if (arg.includes("$")) {
|
|
37
|
+
// Use single quotes for arguments with $variables
|
|
38
|
+
// Escape single quotes within the argument
|
|
39
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If no special characters, return as-is
|
|
43
|
+
if (!/[\s\"]/.test(arg)) return arg;
|
|
44
|
+
|
|
45
|
+
// Escape quotes by doubling them
|
|
46
|
+
return `"${arg.replace(/"/g, "\"\"")}"`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Construct a command string for Windows shell execution.
|
|
51
|
+
* This avoids the deprecation warning by not passing an args array.
|
|
52
|
+
*/
|
|
53
|
+
function buildWindowsCommand(command: string, args: string[]): string {
|
|
54
|
+
const escapedArgs = args.map(escapeWindowsArg).join(" ");
|
|
55
|
+
return `${command} ${escapedArgs}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Safely spawn a process cross-platform without shell deprecation warnings.
|
|
60
|
+
*
|
|
61
|
+
* On Windows: Uses shell: true but constructs the command string manually
|
|
62
|
+
* to avoid the deprecation warning about unescaped args.
|
|
63
|
+
* On Unix: Uses shell: false for normal execution.
|
|
64
|
+
*/
|
|
65
|
+
export function safeSpawn(
|
|
66
|
+
command: string,
|
|
67
|
+
args: string[],
|
|
68
|
+
options?: SafeSpawnOptions,
|
|
69
|
+
): SpawnResult {
|
|
70
|
+
if (process.platform === "win32") {
|
|
71
|
+
// On Windows, construct the full command string and use shell: true
|
|
72
|
+
// without an args array. This avoids the deprecation warning.
|
|
73
|
+
const fullCommand = buildWindowsCommand(command, args);
|
|
74
|
+
const result = spawnSync(fullCommand, {
|
|
75
|
+
...(options as SpawnOptions),
|
|
76
|
+
encoding: "utf-8",
|
|
77
|
+
shell: true,
|
|
78
|
+
windowsHide: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
stdout: result.stdout?.toString() || "",
|
|
83
|
+
stderr: result.stderr?.toString() || "",
|
|
84
|
+
status: result.status,
|
|
85
|
+
error: result.error,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// On Unix, use shell: false (the default) with normal args
|
|
90
|
+
const result = spawnSync(command, args, {
|
|
91
|
+
...(options as SpawnOptions),
|
|
92
|
+
encoding: "utf-8",
|
|
93
|
+
shell: false,
|
|
94
|
+
windowsHide: true,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
stdout: result.stdout?.toString() || "",
|
|
99
|
+
stderr: result.stderr?.toString() || "",
|
|
100
|
+
status: result.status,
|
|
101
|
+
error: result.error,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Check if a command is available in PATH
|
|
107
|
+
*/
|
|
108
|
+
export function isCommandAvailable(command: string): boolean {
|
|
109
|
+
const result = safeSpawn(
|
|
110
|
+
process.platform === "win32" ? "where" : "which",
|
|
111
|
+
[command],
|
|
112
|
+
{ timeout: 5000 },
|
|
113
|
+
);
|
|
114
|
+
return result.status === 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Find the full path to a command (npx, node, etc.)
|
|
119
|
+
*/
|
|
120
|
+
export function findCommand(command: string): string | null {
|
|
121
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
122
|
+
const result = safeSpawn(finder, [command], { timeout: 5000 });
|
|
123
|
+
|
|
124
|
+
if (result.status !== 0) return null;
|
|
125
|
+
|
|
126
|
+
// Take first line (first match)
|
|
127
|
+
return result.stdout.trim().split("\n")[0] || null;
|
|
128
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared architectural debt scanning
|
|
2
|
+
* Shared architectural debt scanning.
|
|
3
3
|
* Scans ast-grep skip rules + complexity metrics + architect.yaml rules.
|
|
4
4
|
*/
|
|
5
|
-
import { spawnSync } from "node:child_process";
|
|
6
5
|
import * as fs from "node:fs";
|
|
7
6
|
import * as path from "node:path";
|
|
7
|
+
import { safeSpawn } from "./safe-spawn.js";
|
|
8
8
|
import { getSourceFiles, parseAstGrepJson } from "./scan-utils.js";
|
|
9
9
|
/**
|
|
10
10
|
* Scan for skip-category ast-grep violations grouped by absolute file path.
|
|
@@ -13,7 +13,7 @@ export function scanSkipViolations(astGrepClient, configPath, targetPath, isTsPr
|
|
|
13
13
|
const skipByFile = new Map();
|
|
14
14
|
if (!astGrepClient.isAvailable())
|
|
15
15
|
return skipByFile;
|
|
16
|
-
const sgResult =
|
|
16
|
+
const sgResult = safeSpawn("npx", [
|
|
17
17
|
"sg",
|
|
18
18
|
"scan",
|
|
19
19
|
"--config",
|
|
@@ -30,10 +30,7 @@ export function scanSkipViolations(astGrepClient, configPath, targetPath, isTsPr
|
|
|
30
30
|
...(isTsProject ? ["--globs", "!**/*.js"] : []),
|
|
31
31
|
targetPath,
|
|
32
32
|
], {
|
|
33
|
-
encoding: "utf-8",
|
|
34
33
|
timeout: 30000,
|
|
35
|
-
shell: true,
|
|
36
|
-
maxBuffer: 32 * 1024 * 1024,
|
|
37
34
|
});
|
|
38
35
|
const items = parseAstGrepJson(sgResult.stdout?.trim() ?? "");
|
|
39
36
|
for (const item of items) {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared architectural debt scanning
|
|
2
|
+
* Shared architectural debt scanning.
|
|
3
3
|
* Scans ast-grep skip rules + complexity metrics + architect.yaml rules.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
6
|
import * as fs from "node:fs";
|
|
8
7
|
import * as path from "node:path";
|
|
9
8
|
import type { ArchitectClient } from "./architect-client.js";
|
|
10
9
|
import type { AstGrepClient } from "./ast-grep-client.js";
|
|
11
10
|
import type { ComplexityClient } from "./complexity-client.js";
|
|
11
|
+
import { safeSpawn } from "./safe-spawn.js";
|
|
12
12
|
import { getSourceFiles, parseAstGrepJson } from "./scan-utils.js";
|
|
13
13
|
|
|
14
14
|
export type SkipIssue = { rule: string; line: number; note: string };
|
|
@@ -28,7 +28,7 @@ export function scanSkipViolations(
|
|
|
28
28
|
const skipByFile = new Map<string, SkipIssue[]>();
|
|
29
29
|
if (!astGrepClient.isAvailable()) return skipByFile;
|
|
30
30
|
|
|
31
|
-
const sgResult =
|
|
31
|
+
const sgResult = safeSpawn(
|
|
32
32
|
"npx",
|
|
33
33
|
[
|
|
34
34
|
"sg",
|
|
@@ -48,10 +48,7 @@ export function scanSkipViolations(
|
|
|
48
48
|
targetPath,
|
|
49
49
|
],
|
|
50
50
|
{
|
|
51
|
-
encoding: "utf-8",
|
|
52
51
|
timeout: 30000,
|
|
53
|
-
shell: true,
|
|
54
|
-
maxBuffer: 32 * 1024 * 1024,
|
|
55
52
|
},
|
|
56
53
|
);
|
|
57
54
|
|
package/clients/scan-utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { EXCLUDED_DIRS, isTestFile } from "./file-utils.js";
|
|
3
4
|
/**
|
|
4
5
|
* Common parsing logic for ast-grep JSON output (handles both array and NDJSON).
|
|
5
6
|
*/
|
|
@@ -30,7 +31,7 @@ export function parseAstGrepJson(raw) {
|
|
|
30
31
|
*/
|
|
31
32
|
export function shouldIgnoreFile(filePath, isTsProject) {
|
|
32
33
|
const relPath = filePath.replace(/\\/g, "/");
|
|
33
|
-
const
|
|
34
|
+
const _basename = path.basename(relPath);
|
|
34
35
|
// Ignore compiled JS in TS projects
|
|
35
36
|
const isJs = relPath.endsWith(".js") ||
|
|
36
37
|
relPath.endsWith(".mjs") ||
|
|
@@ -38,20 +39,11 @@ export function shouldIgnoreFile(filePath, isTsProject) {
|
|
|
38
39
|
if (isTsProject && isJs)
|
|
39
40
|
return true;
|
|
40
41
|
// Ignore test scripts and common test patterns
|
|
41
|
-
if (
|
|
42
|
-
basename.includes(".test.") ||
|
|
43
|
-
basename.includes(".spec.")) {
|
|
42
|
+
if (isTestFile(filePath))
|
|
44
43
|
return true;
|
|
45
|
-
}
|
|
46
44
|
// Ignore hidden directories and common build outputs
|
|
47
|
-
if (relPath.includes(
|
|
48
|
-
relPath.includes("/.git/") ||
|
|
49
|
-
relPath.includes("/dist/") ||
|
|
50
|
-
relPath.includes("/build/") ||
|
|
51
|
-
relPath.includes("/.next/") ||
|
|
52
|
-
relPath.includes("/.pi-lens/")) {
|
|
45
|
+
if (EXCLUDED_DIRS.some((d) => relPath.includes(`/${d}/`)))
|
|
53
46
|
return true;
|
|
54
|
-
}
|
|
55
47
|
return false;
|
|
56
48
|
}
|
|
57
49
|
/**
|
|
@@ -72,14 +64,7 @@ export function getSourceFiles(dir, isTsProject) {
|
|
|
72
64
|
for (const entry of entries) {
|
|
73
65
|
const full = path.join(d, entry.name);
|
|
74
66
|
if (entry.isDirectory()) {
|
|
75
|
-
if (
|
|
76
|
-
"node_modules",
|
|
77
|
-
".git",
|
|
78
|
-
"dist",
|
|
79
|
-
"build",
|
|
80
|
-
".next",
|
|
81
|
-
".pi-lens",
|
|
82
|
-
].includes(entry.name))
|
|
67
|
+
if (EXCLUDED_DIRS.includes(entry.name))
|
|
83
68
|
continue;
|
|
84
69
|
scan(full);
|
|
85
70
|
}
|
package/clients/scan-utils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { EXCLUDED_DIRS, isTestFile } from "./file-utils.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Common parsing logic for ast-grep JSON output (handles both array and NDJSON).
|
|
@@ -32,7 +33,7 @@ export function shouldIgnoreFile(
|
|
|
32
33
|
isTsProject: boolean,
|
|
33
34
|
): boolean {
|
|
34
35
|
const relPath = filePath.replace(/\\/g, "/");
|
|
35
|
-
const
|
|
36
|
+
const _basename = path.basename(relPath);
|
|
36
37
|
|
|
37
38
|
// Ignore compiled JS in TS projects
|
|
38
39
|
const isJs =
|
|
@@ -42,25 +43,10 @@ export function shouldIgnoreFile(
|
|
|
42
43
|
if (isTsProject && isJs) return true;
|
|
43
44
|
|
|
44
45
|
// Ignore test scripts and common test patterns
|
|
45
|
-
if (
|
|
46
|
-
basename.startsWith("test-") ||
|
|
47
|
-
basename.includes(".test.") ||
|
|
48
|
-
basename.includes(".spec.")
|
|
49
|
-
) {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
46
|
+
if (isTestFile(filePath)) return true;
|
|
52
47
|
|
|
53
48
|
// Ignore hidden directories and common build outputs
|
|
54
|
-
if (
|
|
55
|
-
relPath.includes("/node_modules/") ||
|
|
56
|
-
relPath.includes("/.git/") ||
|
|
57
|
-
relPath.includes("/dist/") ||
|
|
58
|
-
relPath.includes("/build/") ||
|
|
59
|
-
relPath.includes("/.next/") ||
|
|
60
|
-
relPath.includes("/.pi-lens/")
|
|
61
|
-
) {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
49
|
+
if (EXCLUDED_DIRS.some((d) => relPath.includes(`/${d}/`))) return true;
|
|
64
50
|
|
|
65
51
|
return false;
|
|
66
52
|
}
|
|
@@ -83,17 +69,7 @@ export function getSourceFiles(dir: string, isTsProject: boolean): string[] {
|
|
|
83
69
|
for (const entry of entries) {
|
|
84
70
|
const full = path.join(d, entry.name);
|
|
85
71
|
if (entry.isDirectory()) {
|
|
86
|
-
if (
|
|
87
|
-
[
|
|
88
|
-
"node_modules",
|
|
89
|
-
".git",
|
|
90
|
-
"dist",
|
|
91
|
-
"build",
|
|
92
|
-
".next",
|
|
93
|
-
".pi-lens",
|
|
94
|
-
].includes(entry.name)
|
|
95
|
-
)
|
|
96
|
-
continue;
|
|
72
|
+
if (EXCLUDED_DIRS.includes(entry.name)) continue;
|
|
97
73
|
scan(full);
|
|
98
74
|
} else if (/\.(ts|tsx|js|jsx|py|go|rs)$/.test(entry.name)) {
|
|
99
75
|
// Skip compiled JS if it's a TS project
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* - Private keys (BEGIN PRIVATE KEY)
|
|
13
13
|
* - Generic API key/password patterns
|
|
14
14
|
*/
|
|
15
|
+
import { isTestFile } from "./file-utils.js";
|
|
15
16
|
// Patterns ordered by specificity - first match wins per line
|
|
16
17
|
const SECRET_PATTERNS = [
|
|
17
18
|
// High-confidence: specific key prefixes
|
|
@@ -68,21 +69,6 @@ const SECRET_PATTERNS = [
|
|
|
68
69
|
message: "Possible secret in .env format",
|
|
69
70
|
},
|
|
70
71
|
];
|
|
71
|
-
/**
|
|
72
|
-
* Check if file path is a test file (should skip secrets scan)
|
|
73
|
-
*/
|
|
74
|
-
function isTestFile(filePath) {
|
|
75
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
76
|
-
return (normalized.includes(".test.") ||
|
|
77
|
-
normalized.includes(".spec.") ||
|
|
78
|
-
normalized.includes("/test/") ||
|
|
79
|
-
normalized.includes("/tests/") ||
|
|
80
|
-
normalized.includes("__tests__/") ||
|
|
81
|
-
normalized.includes("test-utils") ||
|
|
82
|
-
normalized.startsWith("test-") ||
|
|
83
|
-
normalized.includes(".fixture.") ||
|
|
84
|
-
normalized.includes(".mock."));
|
|
85
|
-
}
|
|
86
72
|
/**
|
|
87
73
|
* Scan content for potential secrets
|
|
88
74
|
* Returns findings with line numbers.
|
|
@@ -97,7 +83,7 @@ export function scanForSecrets(content, filePath) {
|
|
|
97
83
|
const lines = content.split("\n");
|
|
98
84
|
for (let i = 0; i < lines.length; i++) {
|
|
99
85
|
const line = lines[i];
|
|
100
|
-
let
|
|
86
|
+
let _matched = false;
|
|
101
87
|
for (const pattern of SECRET_PATTERNS) {
|
|
102
88
|
// Reset lastIndex before each test (important for global regex)
|
|
103
89
|
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
|
|
@@ -106,7 +92,7 @@ export function scanForSecrets(content, filePath) {
|
|
|
106
92
|
line: i + 1,
|
|
107
93
|
message: pattern.message,
|
|
108
94
|
});
|
|
109
|
-
|
|
95
|
+
_matched = true;
|
|
110
96
|
break; // One finding per line
|
|
111
97
|
}
|
|
112
98
|
}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* - Generic API key/password patterns
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { isTestFile } from "./file-utils.js";
|
|
17
|
+
|
|
16
18
|
interface SecretPattern {
|
|
17
19
|
pattern: RegExp;
|
|
18
20
|
name: string;
|
|
@@ -83,24 +85,6 @@ export interface SecretFinding {
|
|
|
83
85
|
message: string;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
/**
|
|
87
|
-
* Check if file path is a test file (should skip secrets scan)
|
|
88
|
-
*/
|
|
89
|
-
function isTestFile(filePath: string): boolean {
|
|
90
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
91
|
-
return (
|
|
92
|
-
normalized.includes(".test.") ||
|
|
93
|
-
normalized.includes(".spec.") ||
|
|
94
|
-
normalized.includes("/test/") ||
|
|
95
|
-
normalized.includes("/tests/") ||
|
|
96
|
-
normalized.includes("__tests__/") ||
|
|
97
|
-
normalized.includes("test-utils") ||
|
|
98
|
-
normalized.startsWith("test-") ||
|
|
99
|
-
normalized.includes(".fixture.") ||
|
|
100
|
-
normalized.includes(".mock.")
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
88
|
/**
|
|
105
89
|
* Scan content for potential secrets
|
|
106
90
|
* Returns findings with line numbers.
|
|
@@ -120,7 +104,7 @@ export function scanForSecrets(
|
|
|
120
104
|
|
|
121
105
|
for (let i = 0; i < lines.length; i++) {
|
|
122
106
|
const line = lines[i];
|
|
123
|
-
let
|
|
107
|
+
let _matched = false;
|
|
124
108
|
for (const pattern of SECRET_PATTERNS) {
|
|
125
109
|
// Reset lastIndex before each test (important for global regex)
|
|
126
110
|
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
|
|
@@ -129,7 +113,7 @@ export function scanForSecrets(
|
|
|
129
113
|
line: i + 1,
|
|
130
114
|
message: pattern.message,
|
|
131
115
|
});
|
|
132
|
-
|
|
116
|
+
_matched = true;
|
|
133
117
|
break; // One finding per line
|
|
134
118
|
}
|
|
135
119
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for Effect-TS concurrent runner execution.
|
|
5
|
+
*/
|
|
6
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
import { clearRunnerRegistry, listRunners, registerRunner, } from "../../dispatch/dispatcher.js";
|
|
8
|
+
import { dispatchLintWithEffect, dispatchWithEffect, } from "../effect-integration.js";
|
|
9
|
+
describe("Effect Integration", () => {
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
clearRunnerRegistry();
|
|
12
|
+
// Register a simple test runner
|
|
13
|
+
const testRunner = {
|
|
14
|
+
id: "test-runner",
|
|
15
|
+
appliesTo: ["jsts"],
|
|
16
|
+
priority: 10,
|
|
17
|
+
enabledByDefault: true,
|
|
18
|
+
async run(ctx) {
|
|
19
|
+
return {
|
|
20
|
+
status: "succeeded",
|
|
21
|
+
diagnostics: [{
|
|
22
|
+
id: "test:1",
|
|
23
|
+
message: "Test diagnostic",
|
|
24
|
+
filePath: ctx.filePath,
|
|
25
|
+
severity: "info",
|
|
26
|
+
semantic: "silent",
|
|
27
|
+
tool: "test-runner",
|
|
28
|
+
}],
|
|
29
|
+
semantic: "none",
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
registerRunner(testRunner);
|
|
34
|
+
});
|
|
35
|
+
it("should have runners registered", () => {
|
|
36
|
+
const runners = listRunners();
|
|
37
|
+
expect(runners.length).toBeGreaterThan(0);
|
|
38
|
+
expect(runners.some(r => r.id === "test-runner")).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it("should run effect integration with real runners", async () => {
|
|
41
|
+
const ctx = {
|
|
42
|
+
filePath: "test.ts",
|
|
43
|
+
cwd: "/test",
|
|
44
|
+
kind: "jsts",
|
|
45
|
+
pi: {
|
|
46
|
+
getFlag: vi.fn(() => false),
|
|
47
|
+
},
|
|
48
|
+
autofix: true,
|
|
49
|
+
deltaMode: false,
|
|
50
|
+
baselines: new Map(),
|
|
51
|
+
hasTool: vi.fn(() => Promise.resolve(false)),
|
|
52
|
+
log: vi.fn(),
|
|
53
|
+
};
|
|
54
|
+
// Get actual runners for jsts
|
|
55
|
+
const { getRunnersForKind } = await import("../../dispatch/dispatcher.js");
|
|
56
|
+
const runners = getRunnersForKind("jsts");
|
|
57
|
+
const group = {
|
|
58
|
+
runnerIds: runners.slice(0, 2).map(r => r.id), // Use first 2 runners
|
|
59
|
+
mode: "all",
|
|
60
|
+
};
|
|
61
|
+
const result = await dispatchWithEffect(ctx, [group]);
|
|
62
|
+
// Just verify it doesn't crash and returns valid result
|
|
63
|
+
expect(result).toBeDefined();
|
|
64
|
+
expect(typeof result.durationMs).toBe("number");
|
|
65
|
+
});
|
|
66
|
+
it("should handle --lens-effect flag path", async () => {
|
|
67
|
+
const mockPi = {
|
|
68
|
+
getFlag: vi.fn((flag) => flag === "lens-effect"),
|
|
69
|
+
readFile: vi.fn(),
|
|
70
|
+
writeFile: vi.fn(),
|
|
71
|
+
editFile: vi.fn(),
|
|
72
|
+
bash: vi.fn(),
|
|
73
|
+
ui: {
|
|
74
|
+
notify: vi.fn(),
|
|
75
|
+
progress: vi.fn(),
|
|
76
|
+
prompt: vi.fn(),
|
|
77
|
+
},
|
|
78
|
+
llm: {
|
|
79
|
+
stream: vi.fn(),
|
|
80
|
+
createMessage: vi.fn(),
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
const output = await dispatchLintWithEffect("test.ts", "/test", mockPi);
|
|
84
|
+
expect(typeof output).toBe("string");
|
|
85
|
+
});
|
|
86
|
+
});
|