claude-crap 0.1.2 → 0.2.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 +35 -0
- package/README.md +43 -23
- package/dist/index.js +79 -1
- package/dist/index.js.map +1 -1
- package/dist/scanner/auto-scan.d.ts +57 -0
- package/dist/scanner/auto-scan.d.ts.map +1 -0
- package/dist/scanner/auto-scan.js +138 -0
- package/dist/scanner/auto-scan.js.map +1 -0
- package/dist/scanner/detector.d.ts +53 -0
- package/dist/scanner/detector.d.ts.map +1 -0
- package/dist/scanner/detector.js +173 -0
- package/dist/scanner/detector.js.map +1 -0
- package/dist/scanner/index.d.ts +22 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +22 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/runner.d.ts +59 -0
- package/dist/scanner/runner.d.ts.map +1 -0
- package/dist/scanner/runner.js +159 -0
- package/dist/scanner/runner.js.map +1 -0
- package/dist/schemas/tool-schemas.d.ts +11 -0
- package/dist/schemas/tool-schemas.d.ts.map +1 -1
- package/dist/schemas/tool-schemas.js +11 -0
- package/dist/schemas/tool-schemas.js.map +1 -1
- package/package.json +5 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/bundle/mcp-server.mjs +452 -0
- package/plugin/bundle/mcp-server.mjs.map +4 -4
- package/plugin/package.json +1 -1
- package/src/index.ts +98 -0
- package/src/scanner/auto-scan.ts +212 -0
- package/src/scanner/detector.ts +224 -0
- package/src/scanner/index.ts +22 -0
- package/src/scanner/runner.ts +212 -0
- package/src/schemas/tool-schemas.ts +13 -0
- package/src/tests/auto-scan.test.ts +137 -0
- package/src/tests/integration/mcp-server.integration.test.ts +2 -1
- package/src/tests/scanner-detector.test.ts +181 -0
- package/src/tests/scanner-runner.test.ts +63 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-detect which scanners are available in the current workspace.
|
|
3
|
+
*
|
|
4
|
+
* For each of the four supported scanners (ESLint, Semgrep, Bandit,
|
|
5
|
+
* Stryker) the detector probes three signal layers in order:
|
|
6
|
+
*
|
|
7
|
+
* 1. Config file existence (fastest — a single `fs.stat`)
|
|
8
|
+
* 2. Package.json dependency (for JS-ecosystem scanners)
|
|
9
|
+
* 3. Binary availability via `which` (slowest — spawns a child process)
|
|
10
|
+
*
|
|
11
|
+
* Detection short-circuits on the first hit, so a project that has an
|
|
12
|
+
* `eslint.config.mjs` will never shell out to `which eslint`.
|
|
13
|
+
*
|
|
14
|
+
* The module is side-effect-free beyond filesystem reads and one
|
|
15
|
+
* `child_process.execFile` per binary probe.
|
|
16
|
+
*
|
|
17
|
+
* @module scanner/detector
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
const SCANNER_SIGNALS = {
|
|
23
|
+
eslint: {
|
|
24
|
+
configFiles: [
|
|
25
|
+
"eslint.config.js",
|
|
26
|
+
"eslint.config.mjs",
|
|
27
|
+
"eslint.config.cjs",
|
|
28
|
+
"eslint.config.ts",
|
|
29
|
+
"eslint.config.mts",
|
|
30
|
+
"eslint.config.cts",
|
|
31
|
+
".eslintrc.js",
|
|
32
|
+
".eslintrc.cjs",
|
|
33
|
+
".eslintrc.yaml",
|
|
34
|
+
".eslintrc.yml",
|
|
35
|
+
".eslintrc.json",
|
|
36
|
+
],
|
|
37
|
+
packageJsonKeys: ["eslint"],
|
|
38
|
+
binaryNames: ["eslint"],
|
|
39
|
+
},
|
|
40
|
+
semgrep: {
|
|
41
|
+
configFiles: [
|
|
42
|
+
".semgrep.yml",
|
|
43
|
+
".semgrep.yaml",
|
|
44
|
+
".semgrep.json",
|
|
45
|
+
],
|
|
46
|
+
packageJsonKeys: [],
|
|
47
|
+
binaryNames: ["semgrep"],
|
|
48
|
+
},
|
|
49
|
+
bandit: {
|
|
50
|
+
configFiles: [
|
|
51
|
+
".bandit",
|
|
52
|
+
"bandit.yaml",
|
|
53
|
+
"bandit.yml",
|
|
54
|
+
],
|
|
55
|
+
packageJsonKeys: [],
|
|
56
|
+
binaryNames: ["bandit"],
|
|
57
|
+
},
|
|
58
|
+
stryker: {
|
|
59
|
+
configFiles: [
|
|
60
|
+
"stryker.conf.js",
|
|
61
|
+
"stryker.conf.mjs",
|
|
62
|
+
"stryker.conf.cjs",
|
|
63
|
+
"stryker.conf.json",
|
|
64
|
+
".strykerrc",
|
|
65
|
+
".strykerrc.json",
|
|
66
|
+
],
|
|
67
|
+
packageJsonKeys: ["@stryker-mutator/core"],
|
|
68
|
+
binaryNames: ["stryker"],
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
// ── Probes ──────────────────────────────────────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* Check if any of the scanner's config files exist in the workspace.
|
|
74
|
+
*/
|
|
75
|
+
function probeConfigFiles(workspaceRoot, scanner) {
|
|
76
|
+
const signals = SCANNER_SIGNALS[scanner];
|
|
77
|
+
for (const file of signals.configFiles) {
|
|
78
|
+
const fullPath = join(workspaceRoot, file);
|
|
79
|
+
if (existsSync(fullPath)) {
|
|
80
|
+
return { found: true, path: fullPath };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { found: false };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if the scanner appears in package.json deps or devDeps.
|
|
87
|
+
*/
|
|
88
|
+
function probePackageJson(workspaceRoot, scanner) {
|
|
89
|
+
const signals = SCANNER_SIGNALS[scanner];
|
|
90
|
+
if (signals.packageJsonKeys.length === 0)
|
|
91
|
+
return false;
|
|
92
|
+
const pkgPath = join(workspaceRoot, "package.json");
|
|
93
|
+
if (!existsSync(pkgPath))
|
|
94
|
+
return false;
|
|
95
|
+
try {
|
|
96
|
+
const raw = readFileSync(pkgPath, "utf-8");
|
|
97
|
+
const pkg = JSON.parse(raw);
|
|
98
|
+
const deps = {
|
|
99
|
+
...(typeof pkg.dependencies === "object" && pkg.dependencies !== null
|
|
100
|
+
? pkg.dependencies
|
|
101
|
+
: {}),
|
|
102
|
+
...(typeof pkg.devDependencies === "object" && pkg.devDependencies !== null
|
|
103
|
+
? pkg.devDependencies
|
|
104
|
+
: {}),
|
|
105
|
+
};
|
|
106
|
+
return signals.packageJsonKeys.some((key) => key in deps);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if a binary is available on PATH via `which`.
|
|
114
|
+
*/
|
|
115
|
+
function probeBinary(binaryName) {
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
execFile("which", [binaryName], { timeout: 5_000 }, (err) => {
|
|
118
|
+
resolve(err === null);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// ── Public API ──────────────────────────────────────────────────────
|
|
123
|
+
/**
|
|
124
|
+
* Detect which of the four supported scanners are available in the
|
|
125
|
+
* given workspace. Probes config files, package.json, and binary
|
|
126
|
+
* availability in order, short-circuiting on first match.
|
|
127
|
+
*
|
|
128
|
+
* @param workspaceRoot Absolute path to the project root.
|
|
129
|
+
* @returns One {@link ScannerDetection} per known scanner.
|
|
130
|
+
*/
|
|
131
|
+
export async function detectScanners(workspaceRoot) {
|
|
132
|
+
const scanners = ["eslint", "semgrep", "bandit", "stryker"];
|
|
133
|
+
const results = await Promise.all(scanners.map(async (scanner) => {
|
|
134
|
+
// 1. Config file probe (fastest)
|
|
135
|
+
const configProbe = probeConfigFiles(workspaceRoot, scanner);
|
|
136
|
+
if (configProbe.found && configProbe.path) {
|
|
137
|
+
return {
|
|
138
|
+
scanner,
|
|
139
|
+
available: true,
|
|
140
|
+
reason: `config file found: ${configProbe.path.replace(workspaceRoot + "/", "")}`,
|
|
141
|
+
configPath: configProbe.path,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// 2. Package.json probe
|
|
145
|
+
if (probePackageJson(workspaceRoot, scanner)) {
|
|
146
|
+
return {
|
|
147
|
+
scanner,
|
|
148
|
+
available: true,
|
|
149
|
+
reason: `found in package.json dependencies`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// 3. Binary probe (slowest)
|
|
153
|
+
const signals = SCANNER_SIGNALS[scanner];
|
|
154
|
+
for (const bin of signals.binaryNames) {
|
|
155
|
+
if (await probeBinary(bin)) {
|
|
156
|
+
return {
|
|
157
|
+
scanner,
|
|
158
|
+
available: true,
|
|
159
|
+
reason: `binary "${bin}" found on PATH`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
scanner,
|
|
165
|
+
available: false,
|
|
166
|
+
reason: "no config file, package.json entry, or binary found",
|
|
167
|
+
};
|
|
168
|
+
}));
|
|
169
|
+
return results;
|
|
170
|
+
}
|
|
171
|
+
// Exported for testing
|
|
172
|
+
export { SCANNER_SIGNALS };
|
|
173
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/scanner/detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public SDK entry point for the scanner auto-detection and execution
|
|
3
|
+
* pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { autoScan, detectScanners } from "claude-crap/scanner";
|
|
9
|
+
*
|
|
10
|
+
* // Full pipeline: detect → run → ingest
|
|
11
|
+
* const result = await autoScan(workspaceRoot, sarifStore, logger);
|
|
12
|
+
*
|
|
13
|
+
* // Detection only (no execution)
|
|
14
|
+
* const detections = await detectScanners(workspaceRoot);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module scanner
|
|
18
|
+
*/
|
|
19
|
+
export { detectScanners, type ScannerDetection } from "./detector.js";
|
|
20
|
+
export { runScanner, type ScannerRunResult } from "./runner.js";
|
|
21
|
+
export { autoScan, type AutoScanResult, type ScannerResult } from "./auto-scan.js";
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public SDK entry point for the scanner auto-detection and execution
|
|
3
|
+
* pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { autoScan, detectScanners } from "claude-crap/scanner";
|
|
9
|
+
*
|
|
10
|
+
* // Full pipeline: detect → run → ingest
|
|
11
|
+
* const result = await autoScan(workspaceRoot, sarifStore, logger);
|
|
12
|
+
*
|
|
13
|
+
* // Detection only (no execution)
|
|
14
|
+
* const detections = await detectScanners(workspaceRoot);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module scanner
|
|
18
|
+
*/
|
|
19
|
+
export { detectScanners } from "./detector.js";
|
|
20
|
+
export { runScanner } from "./runner.js";
|
|
21
|
+
export { autoScan } from "./auto-scan.js";
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,cAAc,EAAyB,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,UAAU,EAAyB,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,QAAQ,EAA2C,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute a single scanner CLI and capture its raw output.
|
|
3
|
+
*
|
|
4
|
+
* Each scanner has a fixed invocation that produces the format its
|
|
5
|
+
* adapter expects:
|
|
6
|
+
*
|
|
7
|
+
* - ESLint → `npx eslint -f json .` (JSON array)
|
|
8
|
+
* - Semgrep → `semgrep --sarif --quiet .` (SARIF 2.1.0)
|
|
9
|
+
* - Bandit → `bandit -f json -r . -q` (JSON object)
|
|
10
|
+
* - Stryker → `npx stryker run` then read `reports/mutation/mutation.json`
|
|
11
|
+
*
|
|
12
|
+
* ESLint and Bandit exit non-zero when findings exist — that is
|
|
13
|
+
* expected, not an error. The runner captures stdout regardless of
|
|
14
|
+
* exit code for those scanners.
|
|
15
|
+
*
|
|
16
|
+
* Stryker is special: it writes to a file instead of stdout, so we
|
|
17
|
+
* read the output file after the process exits.
|
|
18
|
+
*
|
|
19
|
+
* @module scanner/runner
|
|
20
|
+
*/
|
|
21
|
+
import type { KnownScanner } from "../adapters/common.js";
|
|
22
|
+
/**
|
|
23
|
+
* Result of executing a single scanner.
|
|
24
|
+
*/
|
|
25
|
+
export interface ScannerRunResult {
|
|
26
|
+
/** Which scanner was executed. */
|
|
27
|
+
scanner: KnownScanner;
|
|
28
|
+
/** Whether execution completed and produced parseable output. */
|
|
29
|
+
success: boolean;
|
|
30
|
+
/** The scanner's raw output (stdout or file contents). */
|
|
31
|
+
rawOutput: string;
|
|
32
|
+
/** Error message when `success` is false. */
|
|
33
|
+
error?: string;
|
|
34
|
+
/** Wall-clock execution time in milliseconds. */
|
|
35
|
+
durationMs: number;
|
|
36
|
+
}
|
|
37
|
+
interface ScannerCommand {
|
|
38
|
+
/** Binary or npx command. */
|
|
39
|
+
command: string;
|
|
40
|
+
/** CLI arguments. */
|
|
41
|
+
args: string[];
|
|
42
|
+
/** Maximum execution time in ms. */
|
|
43
|
+
timeoutMs: number;
|
|
44
|
+
/** If true, non-zero exit is expected when findings exist. */
|
|
45
|
+
nonZeroIsNormal: boolean;
|
|
46
|
+
/** If set, read output from this file instead of stdout. */
|
|
47
|
+
outputFile?: string;
|
|
48
|
+
}
|
|
49
|
+
declare function getScannerCommand(scanner: KnownScanner, workspaceRoot: string): ScannerCommand;
|
|
50
|
+
/**
|
|
51
|
+
* Execute a scanner CLI and return its raw output.
|
|
52
|
+
*
|
|
53
|
+
* @param scanner Which scanner to run.
|
|
54
|
+
* @param workspaceRoot Absolute path to the project root (used as cwd).
|
|
55
|
+
* @returns A {@link ScannerRunResult} with stdout or file output.
|
|
56
|
+
*/
|
|
57
|
+
export declare function runScanner(scanner: KnownScanner, workspaceRoot: string): Promise<ScannerRunResult>;
|
|
58
|
+
export { getScannerCommand, type ScannerCommand };
|
|
59
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/scanner/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,UAAU,cAAc;IACtB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,eAAe,EAAE,OAAO,CAAC;IACzB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,iBAAS,iBAAiB,CACxB,OAAO,EAAE,YAAY,EACrB,aAAa,EAAE,MAAM,GACpB,cAAc,CAgChB;AAID;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,YAAY,EACrB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,CAAC,CAoG3B;AAGD,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute a single scanner CLI and capture its raw output.
|
|
3
|
+
*
|
|
4
|
+
* Each scanner has a fixed invocation that produces the format its
|
|
5
|
+
* adapter expects:
|
|
6
|
+
*
|
|
7
|
+
* - ESLint → `npx eslint -f json .` (JSON array)
|
|
8
|
+
* - Semgrep → `semgrep --sarif --quiet .` (SARIF 2.1.0)
|
|
9
|
+
* - Bandit → `bandit -f json -r . -q` (JSON object)
|
|
10
|
+
* - Stryker → `npx stryker run` then read `reports/mutation/mutation.json`
|
|
11
|
+
*
|
|
12
|
+
* ESLint and Bandit exit non-zero when findings exist — that is
|
|
13
|
+
* expected, not an error. The runner captures stdout regardless of
|
|
14
|
+
* exit code for those scanners.
|
|
15
|
+
*
|
|
16
|
+
* Stryker is special: it writes to a file instead of stdout, so we
|
|
17
|
+
* read the output file after the process exits.
|
|
18
|
+
*
|
|
19
|
+
* @module scanner/runner
|
|
20
|
+
*/
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
function getScannerCommand(scanner, workspaceRoot) {
|
|
25
|
+
switch (scanner) {
|
|
26
|
+
case "eslint":
|
|
27
|
+
return {
|
|
28
|
+
command: "npx",
|
|
29
|
+
args: ["eslint", "-f", "json", "."],
|
|
30
|
+
timeoutMs: 120_000,
|
|
31
|
+
nonZeroIsNormal: true,
|
|
32
|
+
};
|
|
33
|
+
case "semgrep":
|
|
34
|
+
return {
|
|
35
|
+
command: "semgrep",
|
|
36
|
+
args: ["--sarif", "--quiet", "."],
|
|
37
|
+
timeoutMs: 120_000,
|
|
38
|
+
nonZeroIsNormal: false,
|
|
39
|
+
};
|
|
40
|
+
case "bandit":
|
|
41
|
+
return {
|
|
42
|
+
command: "bandit",
|
|
43
|
+
args: ["-f", "json", "-r", ".", "-q"],
|
|
44
|
+
timeoutMs: 120_000,
|
|
45
|
+
nonZeroIsNormal: true,
|
|
46
|
+
};
|
|
47
|
+
case "stryker":
|
|
48
|
+
return {
|
|
49
|
+
command: "npx",
|
|
50
|
+
args: ["stryker", "run"],
|
|
51
|
+
timeoutMs: 300_000,
|
|
52
|
+
nonZeroIsNormal: false,
|
|
53
|
+
outputFile: join(workspaceRoot, "reports", "mutation", "mutation.json"),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ── Public API ──────────────────────────────────────────────────────
|
|
58
|
+
/**
|
|
59
|
+
* Execute a scanner CLI and return its raw output.
|
|
60
|
+
*
|
|
61
|
+
* @param scanner Which scanner to run.
|
|
62
|
+
* @param workspaceRoot Absolute path to the project root (used as cwd).
|
|
63
|
+
* @returns A {@link ScannerRunResult} with stdout or file output.
|
|
64
|
+
*/
|
|
65
|
+
export function runScanner(scanner, workspaceRoot) {
|
|
66
|
+
const start = Date.now();
|
|
67
|
+
const cmd = getScannerCommand(scanner, workspaceRoot);
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
execFile(cmd.command, cmd.args, {
|
|
70
|
+
cwd: workspaceRoot,
|
|
71
|
+
timeout: cmd.timeoutMs,
|
|
72
|
+
maxBuffer: 50 * 1024 * 1024, // 50 MB — large codebases produce verbose output
|
|
73
|
+
env: { ...process.env, FORCE_COLOR: "0" }, // suppress ANSI in output
|
|
74
|
+
}, (err, stdout, stderr) => {
|
|
75
|
+
const durationMs = Date.now() - start;
|
|
76
|
+
// For scanners where non-zero exit means "findings exist",
|
|
77
|
+
// we still have valid output in stdout.
|
|
78
|
+
if (err && !cmd.nonZeroIsNormal) {
|
|
79
|
+
// Stryker: check if the output file was written despite the error
|
|
80
|
+
if (cmd.outputFile && existsSync(cmd.outputFile)) {
|
|
81
|
+
try {
|
|
82
|
+
const fileOutput = readFileSync(cmd.outputFile, "utf-8");
|
|
83
|
+
resolve({
|
|
84
|
+
scanner,
|
|
85
|
+
success: true,
|
|
86
|
+
rawOutput: fileOutput,
|
|
87
|
+
durationMs,
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Fall through to error path
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
resolve({
|
|
96
|
+
scanner,
|
|
97
|
+
success: false,
|
|
98
|
+
rawOutput: "",
|
|
99
|
+
error: stderr || err.message,
|
|
100
|
+
durationMs,
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// For file-based output (Stryker), read from file
|
|
105
|
+
if (cmd.outputFile) {
|
|
106
|
+
if (existsSync(cmd.outputFile)) {
|
|
107
|
+
try {
|
|
108
|
+
const fileOutput = readFileSync(cmd.outputFile, "utf-8");
|
|
109
|
+
resolve({
|
|
110
|
+
scanner,
|
|
111
|
+
success: true,
|
|
112
|
+
rawOutput: fileOutput,
|
|
113
|
+
durationMs,
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
catch (readErr) {
|
|
118
|
+
resolve({
|
|
119
|
+
scanner,
|
|
120
|
+
success: false,
|
|
121
|
+
rawOutput: "",
|
|
122
|
+
error: `Failed to read output file: ${readErr.message}`,
|
|
123
|
+
durationMs,
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
resolve({
|
|
129
|
+
scanner,
|
|
130
|
+
success: false,
|
|
131
|
+
rawOutput: "",
|
|
132
|
+
error: `Scanner completed but output file not found: ${cmd.outputFile}`,
|
|
133
|
+
durationMs,
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Stdout-based output
|
|
138
|
+
const output = stdout.trim();
|
|
139
|
+
if (!output) {
|
|
140
|
+
resolve({
|
|
141
|
+
scanner,
|
|
142
|
+
success: true,
|
|
143
|
+
rawOutput: "[]", // ESLint returns empty when no files match
|
|
144
|
+
durationMs,
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
resolve({
|
|
149
|
+
scanner,
|
|
150
|
+
success: true,
|
|
151
|
+
rawOutput: output,
|
|
152
|
+
durationMs,
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Exported for testing
|
|
158
|
+
export { getScannerCommand };
|
|
159
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/scanner/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -182,6 +182,17 @@ export declare const ingestScannerOutputSchema: {
|
|
|
182
182
|
* from an external scanner, deduplicates against the internal store, and
|
|
183
183
|
* normalizes the output into claude-crap's canonical format.
|
|
184
184
|
*/
|
|
185
|
+
/**
|
|
186
|
+
* Schema for the `auto_scan` tool. Auto-detects available scanners
|
|
187
|
+
* in the workspace, runs them, and ingests findings into the SARIF store.
|
|
188
|
+
*/
|
|
189
|
+
export declare const autoScanSchema: {
|
|
190
|
+
readonly type: "object";
|
|
191
|
+
readonly description: "Auto-detect available scanners (ESLint, Semgrep, Bandit, Stryker) in the workspace, execute them, and ingest findings into the SARIF store. Returns detection results, per-scanner execution stats, and total findings ingested. Call this to populate findings without manual scanner invocation.";
|
|
192
|
+
readonly properties: {};
|
|
193
|
+
readonly required: readonly [];
|
|
194
|
+
readonly additionalProperties: false;
|
|
195
|
+
};
|
|
185
196
|
export declare const ingestSarifSchema: {
|
|
186
197
|
readonly type: "object";
|
|
187
198
|
readonly description: "Ingest a raw SARIF 2.1.0 report produced by an external scanner (Semgrep, ESLint, Bandit, Stryker, etc.), deduplicate it against the internal store, and return the normalized document. The agent should call this once per scanner invocation, not once per finding.";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-schemas.d.ts","sourceRoot":"","sources":["../../src/schemas/tool-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCpB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;CAyBnB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAuBvB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;CAcrB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CAgB3B,CAAC;AAEX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;CAkB5B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBpB,CAAC"}
|
|
1
|
+
{"version":3,"file":"tool-schemas.d.ts","sourceRoot":"","sources":["../../src/schemas/tool-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCpB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;CAyBnB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAuBvB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;CAcrB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CAgB3B,CAAC;AAEX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;CAkB5B,CAAC;AAEX;;;;GAIG;AACH;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;CAOjB,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBpB,CAAC"}
|
|
@@ -182,6 +182,17 @@ export const ingestScannerOutputSchema = {
|
|
|
182
182
|
* from an external scanner, deduplicates against the internal store, and
|
|
183
183
|
* normalizes the output into claude-crap's canonical format.
|
|
184
184
|
*/
|
|
185
|
+
/**
|
|
186
|
+
* Schema for the `auto_scan` tool. Auto-detects available scanners
|
|
187
|
+
* in the workspace, runs them, and ingests findings into the SARIF store.
|
|
188
|
+
*/
|
|
189
|
+
export const autoScanSchema = {
|
|
190
|
+
type: "object",
|
|
191
|
+
description: "Auto-detect available scanners (ESLint, Semgrep, Bandit, Stryker) in the workspace, execute them, and ingest findings into the SARIF store. Returns detection results, per-scanner execution stats, and total findings ingested. Call this to populate findings without manual scanner invocation.",
|
|
192
|
+
properties: {},
|
|
193
|
+
required: [],
|
|
194
|
+
additionalProperties: false,
|
|
195
|
+
};
|
|
185
196
|
export const ingestSarifSchema = {
|
|
186
197
|
type: "object",
|
|
187
198
|
description: "Ingest a raw SARIF 2.1.0 report produced by an external scanner (Semgrep, ESLint, Bandit, Stryker, etc.), deduplicate it against the internal store, and return the normalized document. The agent should call this once per scanner invocation, not once per finding.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-schemas.js","sourceRoot":"","sources":["../../src/schemas/tool-schemas.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tool-schemas.js","sourceRoot":"","sources":["../../src/schemas/tool-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,2EAA2E;AAC3E,0EAA0E;AAC1E,wCAAwC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,sQAAsQ;IACxQ,UAAU,EAAE;QACV,oBAAoB,EAAE;YACpB,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,+EAA+E;SAC7F;QACD,eAAe,EAAE;YACf,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,GAAG;YACZ,WAAW,EAAE,mEAAmE;SACjF;QACD,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,gCAAgC;YACzC,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,GAAG;YACd,WAAW,EAAE,mFAAmF;SACjG;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,oFAAoF;SAClG;KACF;IACD,QAAQ,EAAE,CAAC,sBAAsB,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,CAAC;IACjF,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,0PAA0P;IAC5P,UAAU,EAAE;QACV,kBAAkB,EAAE;YAClB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,UAAU;YACnB,WAAW,EAAE,0FAA0F;SACxG;QACD,gBAAgB,EAAE;YAChB,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,WAAW;YACpB,WAAW,EAAE,iEAAiE;SAC/E;QACD,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC;YACnC,WAAW,EAAE,4CAA4C;SAC1D;KACF;IACD,QAAQ,EAAE,CAAC,oBAAoB,EAAE,kBAAkB,EAAE,OAAO,CAAC;IAC7D,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,wPAAwP;IAC1P,UAAU,EAAE;QACV,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,IAAI;YACf,sEAAsE;YACtE,sEAAsE;YACtE,gDAAgD;YAChD,OAAO,EAAE,mBAAmB;YAC5B,WAAW,EAAE,+FAA+F;SAC7G;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC;YAC9D,WAAW,EAAE,4EAA4E;SAC1F;KACF;IACD,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;IAClC,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,qTAAqT;IACvT,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC;YAClC,WAAW,EACT,iKAAiK;SACpK;KACF;IACD,QAAQ,EAAE,EAAE;IACZ,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,wRAAwR;IAC1R,UAAU,EAAE;QACV,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,mBAAmB;YAC5B,WAAW,EACT,+FAA+F;SAClG;KACF;IACD,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,4TAA4T;IAC9T,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;YAChD,WAAW,EAAE,sCAAsC;SACpD;QACD,SAAS,EAAE;YACT,WAAW,EACT,mIAAmI;YACrI,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;SACnE;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC;IAClC,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;;GAIG;AACH;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,oSAAoS;IACtS,UAAU,EAAE,EAAE;IACd,QAAQ,EAAE,EAAE;IACZ,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,wQAAwQ;IAC1Q,UAAU,EAAE;QACV,aAAa,EAAE;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,6DAA6D;YAC1E,UAAU,EAAE;gBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;gBAC5C,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3B,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE;aACrC;YACD,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;SAC9B;QACD,UAAU,EAAE;YACV,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,wBAAwB;YACjC,WAAW,EAAE,8FAA8F;SAC5G;KACF;IACD,QAAQ,EAAE,CAAC,eAAe,EAAE,YAAY,CAAC;IACzC,oBAAoB,EAAE,KAAK;CACnB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-crap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Deterministic QA plugin for Claude Code — CRAP index, Technical Debt Ratio, tree-sitter AST, SARIF 2.1.0, hooks, and a local Vue dashboard.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -55,6 +55,10 @@
|
|
|
55
55
|
"types": "./dist/tools/index.d.ts",
|
|
56
56
|
"import": "./dist/tools/index.js"
|
|
57
57
|
},
|
|
58
|
+
"./scanner": {
|
|
59
|
+
"types": "./dist/scanner/index.d.ts",
|
|
60
|
+
"import": "./dist/scanner/index.js"
|
|
61
|
+
},
|
|
58
62
|
"./adapters": {
|
|
59
63
|
"types": "./dist/adapters/index.d.ts",
|
|
60
64
|
"import": "./dist/adapters/index.js"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://code.claude.com/schemas/plugin.json",
|
|
3
3
|
"name": "claude-crap",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "Deterministic Quality Assurance plugin for Claude Code. Wraps every Write / Edit / Bash tool call with a PreToolUse gatekeeper, a PostToolUse verifier, and a Stop quality gate backed by CRAP index, Technical Debt Ratio, tree-sitter AST metrics, and SARIF 2.1.0 reports. Forbids the agent from writing functional code before a test safety net exists.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Alan Hernandez",
|