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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
const scanHead = spawnSync("npx", ["slop-scan", "scan", ".", "--json"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 120000,
|
||||
shell: process.platform === "win32",
|
||||
});
|
||||
if (!scanHead.stdout) {
|
||||
const scanHeadOut = runSlopScan(".");
|
||||
if (!scanHeadOut) {
|
||||
console.log("slop-scan not available. Install: npm i -g slop-scan");
|
||||
process.exit(0);
|
||||
}
|
||||
let headReport: any;
|
||||
try {
|
||||
headReport = JSON.parse(scanHead.stdout);
|
||||
headReport = JSON.parse(scanHeadOut);
|
||||
} catch {
|
||||
console.log("slop-scan returned invalid JSON.");
|
||||
process.exit(0);
|
||||
|
|
@ -86,19 +116,11 @@ if (mergeBase) {
|
|||
} catch {}
|
||||
}
|
||||
|
||||
const scanBase = spawnSync(
|
||||
"npx",
|
||||
["slop-scan", "scan", tmpWorktree, "--json"],
|
||||
{
|
||||
encoding: "utf-8",
|
||||
timeout: 120000,
|
||||
shell: process.platform === "win32",
|
||||
},
|
||||
);
|
||||
const scanBaseOut = runSlopScan(tmpWorktree);
|
||||
|
||||
if (scanBase.stdout) {
|
||||
if (scanBaseOut) {
|
||||
try {
|
||||
const baseReport = JSON.parse(scanBase.stdout);
|
||||
const baseReport = JSON.parse(scanBaseOut);
|
||||
for (const f of baseReport.findings) {
|
||||
// Remap worktree paths back to repo-relative
|
||||
const realPath = f.path.replace(tmpWorktree + "/", "");
|
||||
|
|
|
|||
Loading…
Reference in New Issue