@tekyzinc/gsd-t 2.71.18 → 2.71.20

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 CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [2.71.20] - 2026-04-08
6
+
7
+ ### Fixed (orchestrator — reviewer crash false-pass + Ctrl+C + build logging)
8
+ - **Reviewer crash no longer treated as "pass"** — if the reviewer exits with non-zero code in under 10s, it's a crash, not a clean review. Retried on next cycle. Previously, empty output from a crashed reviewer was parsed as "0 issues = pass."
9
+ - **Ctrl+C now works** — replaced `Atomics.wait` with `sleep` command for synchronous polling. `Atomics.wait` blocks the event loop completely, preventing SIGINT.
10
+ - **Build output logging** — builder output written to `.gsd-t/design-review/build-logs/{phase}-build.log` for debugging.
11
+
5
12
  ## [2.71.18] - 2026-04-08
6
13
 
7
14
  ### Fixed (orchestrator — Claude permissions and timeouts)
@@ -52,10 +52,12 @@ function ensureDir(dir) {
52
52
  }
53
53
 
54
54
  function syncSleep(ms) {
55
+ // Use sleep command instead of Atomics.wait — Atomics blocks the event loop
56
+ // completely, preventing SIGINT (Ctrl+C) from being handled
55
57
  try {
56
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
58
+ execFileSync("sleep", [String(ms / 1000)], { stdio: "pipe" });
57
59
  } catch {
58
- try { execFileSync("sleep", [String(ms / 1000)], { stdio: "pipe" }); } catch { /* ignore */ }
60
+ // sleep interrupted by signal that's fine
59
61
  }
60
62
  }
61
63
 
@@ -569,6 +571,14 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
569
571
  warn(`Claude exited with code ${buildResult.exitCode} after ${buildResult.duration}s`);
570
572
  }
571
573
 
574
+ // Log build output for debugging
575
+ const buildLogDir = path.join(this.getReviewDir(projectDir), "build-logs");
576
+ ensureDir(buildLogDir);
577
+ fs.writeFileSync(
578
+ path.join(buildLogDir, `${phase}-build.log`),
579
+ `Exit code: ${buildResult.exitCode}\nDuration: ${buildResult.duration}s\nPrompt length: ${prompt.length}\n\n--- OUTPUT ---\n${buildResult.output.slice(0, 20000)}`
580
+ );
581
+
572
582
  // 6c. Collect built paths
573
583
  const builtPaths = items.map(item =>
574
584
  item.sourcePath || (this.wf.guessPaths ? this.wf.guessPaths(phase, item) : "")
@@ -599,14 +609,22 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
599
609
  const reviewResult = this.spawnClaude(projectDir, reviewPrompt, reviewTimeout);
600
610
 
601
611
  // Parse reviewer output for issues
602
- const issues = this.wf.parseReviewResult
603
- ? this.wf.parseReviewResult(reviewResult.output, phase)
604
- : this._parseDefaultReviewResult(reviewResult.output);
612
+ let issues;
605
613
 
606
- if (reviewResult.exitCode === 0) {
607
- success(`Reviewer finished in ${reviewResult.duration}s`);
614
+ // Treat reviewer crash (non-zero exit, very short duration) as a failed review, not a pass
615
+ if (reviewResult.exitCode !== 0 && reviewResult.duration < 10) {
616
+ warn(`Reviewer crashed (code ${reviewResult.exitCode}, ${reviewResult.duration}s) — treating as review failure, will retry`);
617
+ issues = [{ component: "ALL", severity: "critical", description: `Reviewer crashed with exit code ${reviewResult.exitCode} — review not performed` }];
608
618
  } else {
609
- warn(`Reviewer exited with code ${reviewResult.exitCode} after ${reviewResult.duration}s`);
619
+ issues = this.wf.parseReviewResult
620
+ ? this.wf.parseReviewResult(reviewResult.output, phase)
621
+ : this._parseDefaultReviewResult(reviewResult.output);
622
+
623
+ if (reviewResult.exitCode === 0) {
624
+ success(`Reviewer finished in ${reviewResult.duration}s`);
625
+ } else {
626
+ warn(`Reviewer exited with code ${reviewResult.exitCode} after ${reviewResult.duration}s`);
627
+ }
610
628
  }
611
629
 
612
630
  // Write review report
@@ -614,7 +632,7 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
614
632
  ensureDir(reportDir);
615
633
  fs.writeFileSync(
616
634
  path.join(reportDir, `${phase}-cycle-${autoReviewCycle}.json`),
617
- JSON.stringify({ cycle: autoReviewCycle, issues, output: reviewResult.output.slice(0, 5000) }, null, 2)
635
+ JSON.stringify({ cycle: autoReviewCycle, issues, exitCode: reviewResult.exitCode, duration: reviewResult.duration, output: reviewResult.output.slice(0, 5000) }, null, 2)
618
636
  );
619
637
 
620
638
  if (issues.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "2.71.18",
3
+ "version": "2.71.20",
4
4
  "description": "GSD-T: Contract-Driven Development for Claude Code — 56 slash commands with headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",