mirror of https://github.com/garrytan/gstack.git
fix(slop-diff): redirect slop-scan stdout to a file — piped output truncates at 8KB
slop-scan@0.3.0 emits its JSON report via async stdout writes and then calls process.exit(), so when stdout is a PIPE (spawnSync capture — this wrapper), the report is truncated at the first ~8KB chunk. A full-repo report is multi-MB, so both scans always failed JSON.parse and the /review and /ship integration silently reported 'slop-scan returned invalid JSON' (or, for the base scan, diffed against an empty baseline). File writes are synchronous, so redirecting the child's stdout to a temp file yields the complete report regardless of size. Repro: npx slop-scan scan . --json | wc -c → 8192 on any large repo, while a shell file-redirect of the same command yields the full report. Both scan sites now go through one runSlopScan() helper (fd-backed stdout, temp file cleaned up in finally). Behavior otherwise unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a3259400a3
commit
e2f894ddb4
|
|
@ -31,19 +31,49 @@ if (changedFiles.size === 0) {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run `npx slop-scan scan <target> --json` with stdout redirected to a temp
|
||||||
|
* FILE and return the report text.
|
||||||
|
*
|
||||||
|
* Why not capture the pipe: slop-scan@0.3.0 writes its report with async
|
||||||
|
* stdout writes and then calls process.exit(), so on a PIPED stdout the
|
||||||
|
* output is truncated at the first ~8KB chunk (a full-repo report is
|
||||||
|
* multi-MB). File writes are synchronous, so redirecting to a file yields
|
||||||
|
* the complete report regardless of size. Returns null when slop-scan is
|
||||||
|
* unavailable or produced no output.
|
||||||
|
*/
|
||||||
|
function runSlopScan(target: string): string | null {
|
||||||
|
const outFile = path.join(
|
||||||
|
os.tmpdir(),
|
||||||
|
`slop-scan-out-${process.pid}-${Date.now()}.json`,
|
||||||
|
);
|
||||||
|
const outFd = fs.openSync(outFile, "w");
|
||||||
|
try {
|
||||||
|
spawnSync("npx", ["slop-scan", "scan", target, "--json"], {
|
||||||
|
stdio: ["ignore", outFd, "pipe"],
|
||||||
|
timeout: 120000,
|
||||||
|
shell: process.platform === "win32",
|
||||||
|
});
|
||||||
|
fs.closeSync(outFd);
|
||||||
|
const raw = fs.readFileSync(outFile, "utf-8");
|
||||||
|
return raw.length > 0 ? raw : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(outFile, { force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Run slop-scan on HEAD
|
// 2. Run slop-scan on HEAD
|
||||||
const scanHead = spawnSync("npx", ["slop-scan", "scan", ".", "--json"], {
|
const scanHeadOut = runSlopScan(".");
|
||||||
encoding: "utf-8",
|
if (!scanHeadOut) {
|
||||||
timeout: 120000,
|
|
||||||
shell: process.platform === "win32",
|
|
||||||
});
|
|
||||||
if (!scanHead.stdout) {
|
|
||||||
console.log("slop-scan not available. Install: npm i -g slop-scan");
|
console.log("slop-scan not available. Install: npm i -g slop-scan");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
let headReport: any;
|
let headReport: any;
|
||||||
try {
|
try {
|
||||||
headReport = JSON.parse(scanHead.stdout);
|
headReport = JSON.parse(scanHeadOut);
|
||||||
} catch {
|
} catch {
|
||||||
console.log("slop-scan returned invalid JSON.");
|
console.log("slop-scan returned invalid JSON.");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
@ -86,19 +116,11 @@ if (mergeBase) {
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scanBase = spawnSync(
|
const scanBaseOut = runSlopScan(tmpWorktree);
|
||||||
"npx",
|
|
||||||
["slop-scan", "scan", tmpWorktree, "--json"],
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
timeout: 120000,
|
|
||||||
shell: process.platform === "win32",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (scanBase.stdout) {
|
if (scanBaseOut) {
|
||||||
try {
|
try {
|
||||||
const baseReport = JSON.parse(scanBase.stdout);
|
const baseReport = JSON.parse(scanBaseOut);
|
||||||
for (const f of baseReport.findings) {
|
for (const f of baseReport.findings) {
|
||||||
// Remap worktree paths back to repo-relative
|
// Remap worktree paths back to repo-relative
|
||||||
const realPath = f.path.replace(tmpWorktree + "/", "");
|
const realPath = f.path.replace(tmpWorktree + "/", "");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue