@tekyzinc/gsd-t 2.72.10 → 2.73.11

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,20 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [2.73.11] - 2026-04-08
6
+
7
+ ### Changed (reviewer — Playwright-first visual inspection)
8
+ - **Playwright is now the PRIMARY reviewer method** — every contract-specified visual property is verified via `getComputedStyle()` in a real browser. Code review demoted to supplement for non-visual concerns (props, events, accessibility). CSS box math (cascade, specificity, flex/grid computation, relative units) can only be verified at render time, not from source code.
9
+
10
+ ## [2.73.10] - 2026-04-08
11
+
12
+ ### Added (orchestrator — parallel execution)
13
+ - **`--parallel N` flag** — runs N build+review items concurrently via async `spawnClaudeAsync()` and `_runWithConcurrency()`. Default: 1 (sequential). Recommended: 3. Reduces 15-element pipeline from ~30min to ~10min at 3x parallelism.
14
+ - **`--clean` artifact cleanup expanded** — now clears `auto-review/`, `build-logs/`, `queue/`, `feedback/`, `review-complete.json`, `orchestrator-state.json` on fresh start (not just build output).
15
+
16
+ ### Changed
17
+ - **Orchestrator `run()` is now async** — callers (`bin/gsd-t.js`, `bin/design-orchestrator.js`) updated with `.catch()` for proper error handling.
18
+
5
19
  ## [2.72.10] - 2026-04-08
6
20
 
7
21
  ### Added (orchestrator — per-item pipeline, stream-json, verbose, clean)
@@ -365,25 +365,39 @@ ${componentList}
365
365
  ${measurementContext}
366
366
  ## Review Process
367
367
 
368
- **Step 1 — Code review (do this FIRST for ALL components):**
369
- For each component, read the design contract file and the source file. Check that every contract-specified value (colors, sizes, spacing, border-radius, font, layout, chart type, etc.) is correctly implemented in the code. This is your primary review — most issues are catchable from code alone.
370
-
371
- **Step 2 Playwright spot-check (do this AFTER code review):**
372
- Use Playwright to render components at http://localhost:${ports.reviewPort}/ and verify:
373
- - Components render without errors and have correct dimensions
374
- - Chart types, orientations, and data structures are correct
375
- - Interactive elements respond correctly (hover, click, states)
376
-
377
- Focus Playwright on components where code review raised concerns or where visual behavior can't be verified from code alone (e.g., SVG rendering, computed layouts). You do NOT need to re-measure every CSS property — the orchestrator already ran Playwright measurements above.
368
+ **Step 1 — Playwright visual inspection (PRIMARY — do this FIRST):**
369
+ Every UI component is visual and MUST be visually inspected. For each component:
370
+ 1. Open http://localhost:${ports.reviewPort}/ in Playwright
371
+ 2. Navigate to / render the component using its selector
372
+ 3. For EVERY contract-specified visual property, use \`page.locator(selector).evaluate(el => getComputedStyle(el))\` to measure the actual computed value:
373
+ - **Box model**: width, height, padding, margin, gap, border-width, border-radius
374
+ - **Colors**: background-color, color, border-color (compare computed rgb/rgba values)
375
+ - **Typography**: font-family, font-size, font-weight, line-height, letter-spacing
376
+ - **Layout**: display, flex-direction, justify-content, align-items, grid-template-columns
377
+ - **Spacing**: gap, row-gap, column-gap, padding (all sides), margin (all sides)
378
+ - **Visual**: opacity, box-shadow, overflow, text-overflow
379
+ 4. Compare each measured value against the contract specification
380
+ 5. Check that the component renders without console errors
381
+ 6. For charts/SVGs: verify chart type, orientation, data structure, and proportions visually
382
+
383
+ Code review alone CANNOT verify CSS box math — cascade, specificity, flex/grid computation, relative units, and parent constraints all affect the final rendered result. Only computed styles from a running browser are authoritative.
384
+
385
+ **Step 2 — Code review (supplement for non-visual concerns):**
386
+ Read the source file to check:
387
+ - Prop interfaces match contract definitions
388
+ - Event handlers and interactivity are wired correctly
389
+ - Data binding and state management are correct
390
+ - Accessibility attributes (aria-*, role) are present
391
+ - Component structure matches contract hierarchy
378
392
 
379
393
  ## Output Format
380
394
 
381
- Output your findings between these markers. Each issue must have component, severity (critical/high/medium/low), and description with SPECIFIC contract vs. actual values:
395
+ Output your findings between these markers. Each issue must have component, severity (critical/high/medium/low), and description with SPECIFIC contract value vs. actual computed value:
382
396
 
383
397
  [REVIEW_ISSUES]
384
398
  [
385
399
  {"component": "ComponentName", "severity": "critical", "description": "Contract specifies donut chart but rendered as pie chart (no inner radius)"},
386
- {"component": "ComponentName", "severity": "high", "description": "Grid gap: contract 16px, actual 24px"}
400
+ {"component": "ComponentName", "severity": "high", "description": "Grid gap: contract 16px, computed 24px"}
387
401
  ]
388
402
  [/REVIEW_ISSUES]
389
403
 
@@ -395,9 +409,10 @@ If ALL components match their contracts, output:
395
409
  ## CRITICAL — Output Rules
396
410
  - Output MUST contain the [REVIEW_ISSUES] markers — the orchestrator parses your result from these markers. Without them, your review is lost.
397
411
  - You write ZERO code. You ONLY review.
412
+ - You MUST run Playwright for every component. Skipping visual inspection is a review failure.
398
413
  - Be HARSH. Your value is in catching what the builder missed.
399
- - NEVER say "looks close" or "appears to match" — give SPECIFIC values.
400
- - Every contract property must be verified. Missing verification = missed issue.
414
+ - NEVER say "looks close" or "appears to match" — give SPECIFIC computed values.
415
+ - Every contract property must be verified via computed style. Missing verification = missed issue.
401
416
  - Severity guide: critical = wrong component type, missing element, broken render. high = wrong dimensions, colors, layout. medium = spacing/padding off. low = minor visual difference.`;
402
417
  }
403
418
 
@@ -421,15 +436,30 @@ function buildSingleItemReviewPrompt(phase, item, measurements, projectDir, port
421
436
  ${measurementContext}
422
437
  ## Review Process
423
438
 
424
- 1. Read the design contract file note every specified property value
425
- 2. Read the source filecheck that every contract-specified value is implemented correctly
426
- 3. If needed, use Playwright to render at http://localhost:${ports.reviewPort}/ and verify visual behavior
439
+ **Step 1 — Playwright visual inspection (PRIMARY):**
440
+ This is a UI componentvisual inspection is mandatory, not optional.
441
+ 1. Read the design contract file note every specified visual property value
442
+ 2. Open http://localhost:${ports.reviewPort}/ in Playwright
443
+ 3. Render the component using its selector
444
+ 4. For EVERY contract-specified visual property, measure the actual computed value:
445
+ \`page.locator(selector).evaluate(el => getComputedStyle(el))\`
446
+ - Box model: width, height, padding, margin, gap, border-width, border-radius
447
+ - Colors: background-color, color, border-color (compare computed rgb/rgba)
448
+ - Typography: font-family, font-size, font-weight, line-height
449
+ - Layout: display, flex-direction, justify-content, align-items
450
+ 5. Compare each computed value against the contract specification
451
+ 6. For charts/SVGs: verify type, orientation, proportions visually
452
+
453
+ Code review alone cannot verify CSS — cascade, specificity, flex/grid, and relative units all affect computed output.
454
+
455
+ **Step 2 — Code review (non-visual concerns):**
456
+ Read the source file to check prop interfaces, event handlers, data binding, and accessibility attributes.
427
457
 
428
458
  ## Output Format
429
459
 
430
460
  [REVIEW_ISSUES]
431
461
  [
432
- {"component": "${item.componentName}", "severity": "high", "description": "Contract specifies X, code has Y"}
462
+ {"component": "${item.componentName}", "severity": "high", "description": "Contract specifies X, computed value is Y"}
433
463
  ]
434
464
  [/REVIEW_ISSUES]
435
465
 
@@ -439,8 +469,9 @@ If the component matches its contract, output:
439
469
  [/REVIEW_ISSUES]
440
470
 
441
471
  ## Rules
472
+ - You MUST run Playwright. Skipping visual inspection is a review failure.
442
473
  - You write ZERO code. You ONLY review.
443
- - Be HARSH — specific values only, no "looks close."
474
+ - Be HARSH — specific computed values only, no "looks close."
444
475
  - Output MUST contain [REVIEW_ISSUES] markers.`;
445
476
  }
446
477
 
@@ -485,6 +516,9 @@ ${BOLD}Options:${RESET}
485
516
  --review-port <N> Review server port (default: 3456)
486
517
  --timeout <sec> Claude timeout per tier in seconds (default: 600)
487
518
  --skip-measure Skip Playwright measurement (human-review only)
519
+ --clean Clear all stale artifacts before starting
520
+ --verbose, -v Show Claude's tool calls and prompts in terminal
521
+ --parallel <N> Run N items concurrently (default: 1 = sequential)
488
522
  --help Show this help
489
523
 
490
524
  ${BOLD}Pipeline:${RESET}
@@ -542,12 +576,12 @@ const designBuildWorkflow = {
542
576
 
543
577
  // ─── Entry Point ────────────────────────────────────────────────────────────
544
578
 
545
- function run(args) {
546
- new Orchestrator(designBuildWorkflow).run(args || []);
579
+ async function run(args) {
580
+ await new Orchestrator(designBuildWorkflow).run(args || []);
547
581
  }
548
582
 
549
583
  if (require.main === module) {
550
- run(process.argv.slice(2));
584
+ run(process.argv.slice(2)).catch(e => { console.error(e); process.exit(1); });
551
585
  }
552
586
 
553
587
  module.exports = { run, workflow: designBuildWorkflow };
package/bin/gsd-t.js CHANGED
@@ -2699,7 +2699,7 @@ if (require.main === module) {
2699
2699
  break;
2700
2700
  case "design-build": {
2701
2701
  const orchestrator = require("./design-orchestrator.js");
2702
- orchestrator.run(args.slice(1));
2702
+ orchestrator.run(args.slice(1)).catch(e => { console.error(e); process.exit(1); });
2703
2703
  break;
2704
2704
  }
2705
2705
  case "scan": {
@@ -25,7 +25,7 @@
25
25
 
26
26
  const fs = require("fs");
27
27
  const path = require("path");
28
- const { execFileSync, spawn: cpSpawn } = require("child_process");
28
+ const { execFileSync, execFile, spawn: cpSpawn } = require("child_process");
29
29
 
30
30
  // ─── ANSI Colors ────────────────────────────────────────────────────────────
31
31
 
@@ -136,6 +136,7 @@ class Orchestrator {
136
136
  case "--skip-measure": opts.skipMeasure = true; break;
137
137
  case "--clean": opts.clean = true; break;
138
138
  case "--verbose": case "-v": opts.verbose = true; break;
139
+ case "--parallel": opts.parallel = parseInt(argv[++i], 10) || 3; break;
139
140
  case "--help":
140
141
  case "-h":
141
142
  if (this.wf.showUsage) this.wf.showUsage();
@@ -162,7 +163,8 @@ ${BOLD}Options:${RESET}
162
163
  --review-port <N> Review server port (default: ${this.wf.defaults?.reviewPort || 3456})
163
164
  --timeout <sec> Claude timeout per phase in seconds (default: 600)
164
165
  --skip-measure Skip automated measurement (human-review only)
165
- --clean Delete previous build output before building each phase
166
+ --clean Clear all artifacts from previous runs + delete build output
167
+ --parallel <N> Run N items concurrently (default: 1, recommended: 3)
166
168
  --verbose, -v Show Claude's tool calls and prompts in terminal
167
169
  --help Show this help
168
170
 
@@ -237,6 +239,71 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
237
239
 
238
240
  // ─── Server Management ───────────────────────────────────────────────
239
241
 
242
+ /**
243
+ * Async Claude spawn — returns a Promise. Used for parallel execution.
244
+ */
245
+ spawnClaudeAsync(projectDir, prompt, timeout, opts = {}) {
246
+ const start = Date.now();
247
+ const verbose = this._verbose;
248
+
249
+ const args = ["-p", "--dangerously-skip-permissions", "--output-format", "stream-json"];
250
+ if (verbose) args.push("--verbose");
251
+ args.push(prompt);
252
+
253
+ if (verbose && opts.label) {
254
+ const logDir = path.join(this.getReviewDir(projectDir), "build-logs");
255
+ ensureDir(logDir);
256
+ fs.writeFileSync(
257
+ path.join(logDir, `${opts.label}-prompt.txt`),
258
+ `--- Prompt (${new Date().toISOString()}) ---\nTimeout: ${(timeout || 120_000) / 1000}s\nCWD: ${projectDir}\n\n${prompt}`
259
+ );
260
+ }
261
+
262
+ return new Promise((resolve) => {
263
+ const child = execFile("claude", args, {
264
+ encoding: "utf8",
265
+ timeout: timeout || 120_000,
266
+ cwd: projectDir,
267
+ maxBuffer: 10 * 1024 * 1024,
268
+ }, (err, stdout, stderr) => {
269
+ const raw = err ? ((err.stdout || "") + (err.stderr || "")) : (stdout || "");
270
+ const output = this._parseStreamJson(raw, false);
271
+ const exitCode = err ? (err.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ? 1 : (err.killed ? 143 : (err.code || 1))) : 0;
272
+ const duration = Math.round((Date.now() - start) / 1000);
273
+
274
+ if (verbose) {
275
+ dim(` ${opts.label || "claude"}: exit=${exitCode}, ${duration}s, ${output.length} chars`);
276
+ }
277
+
278
+ resolve({ output, exitCode, duration });
279
+ });
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Run tasks with concurrency limit. Returns results in same order as tasks.
285
+ * @param {Array<Function>} taskFns — array of () => Promise<result>
286
+ * @param {number} concurrency — max concurrent tasks
287
+ */
288
+ async _runWithConcurrency(taskFns, concurrency) {
289
+ const results = new Array(taskFns.length).fill(null);
290
+ let nextIdx = 0;
291
+
292
+ async function runNext() {
293
+ while (nextIdx < taskFns.length) {
294
+ const idx = nextIdx++;
295
+ results[idx] = await taskFns[idx]();
296
+ }
297
+ }
298
+
299
+ const workers = [];
300
+ for (let i = 0; i < Math.min(concurrency, taskFns.length); i++) {
301
+ workers.push(runNext());
302
+ }
303
+ await Promise.all(workers);
304
+ return results;
305
+ }
306
+
240
307
  _parseStreamJson(raw, verbose) {
241
308
  // stream-json format: one JSON object per line
242
309
  // We want assistant text content and tool use visibility
@@ -554,7 +621,7 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
554
621
 
555
622
  // ─── Main Pipeline ──────────────────────────────────────────────────
556
623
 
557
- run(argv) {
624
+ async run(argv) {
558
625
  const opts = this.wf.parseArgs
559
626
  ? this.wf.parseArgs(argv, this.parseBaseArgs.bind(this))
560
627
  : this.parseBaseArgs(argv || []);
@@ -597,6 +664,29 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
597
664
  }
598
665
  } else {
599
666
  state = this._createState();
667
+
668
+ // Clean all orchestrator artifacts on fresh start (not --resume)
669
+ if (opts.clean) {
670
+ const reviewDir = this.getReviewDir(projectDir);
671
+ const dirsToClean = ["auto-review", "build-logs", "queue", "feedback"];
672
+ let cleaned = 0;
673
+ for (const dir of dirsToClean) {
674
+ const full = path.join(reviewDir, dir);
675
+ if (fs.existsSync(full)) {
676
+ for (const f of fs.readdirSync(full)) {
677
+ try { fs.unlinkSync(path.join(full, f)); cleaned++; } catch { /* ignore */ }
678
+ }
679
+ }
680
+ }
681
+ // Remove signal and state files
682
+ for (const f of ["review-complete.json", "orchestrator-state.json", "shutdown.json"]) {
683
+ const full = path.join(reviewDir, f);
684
+ if (fs.existsSync(full)) {
685
+ try { fs.unlinkSync(full); cleaned++; } catch { /* ignore */ }
686
+ }
687
+ }
688
+ if (cleaned > 0) info(`--clean: removed ${cleaned} stale artifact(s)`);
689
+ }
600
690
  }
601
691
 
602
692
  // 4. Start servers
@@ -691,24 +781,30 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
691
781
  let measurements = {};
692
782
 
693
783
  // ── Per-item pipeline: build ONE → review ONE → fix if needed ──
694
- // Preferred when workflow provides single-item prompts.
695
- // Each Claude spawn reads 1 contract + 1 source = tiny context, fast completion.
784
+ // Each item is independent: 1 contract + 1 source = tiny context.
785
+ // With --parallel N, runs N items concurrently.
696
786
  if (this.wf.buildSingleItemPrompt && this.wf.buildSingleItemReviewPrompt) {
697
- log(`\n${CYAN} ⚙${RESET} Building and reviewing ${items.length} ${phase} one at a time...`);
787
+ const concurrency = opts.parallel || 1;
788
+ if (concurrency > 1) {
789
+ log(`\n${CYAN} ⚙${RESET} Building and reviewing ${items.length} ${phase} (${concurrency} parallel)...`);
790
+ } else {
791
+ log(`\n${CYAN} ⚙${RESET} Building and reviewing ${items.length} ${phase} one at a time...`);
792
+ }
698
793
 
699
- for (let idx = 0; idx < items.length; idx++) {
700
- const item = items[idx];
701
- heading(` [${idx + 1}/${items.length}] ${item.componentName}`);
794
+ // Each task: build review fix loop for one item
795
+ const processItem = async (item, idx) => {
796
+ const label = `[${idx + 1}/${items.length}] ${item.componentName}`;
797
+ log(`\n ${BOLD}${label}${RESET}`);
702
798
 
703
- // Build one item
799
+ // Build
704
800
  const buildPrompt = this.wf.buildSingleItemPrompt(phase, item, prevResults, projectDir);
705
801
  dim(` Building...`);
706
- const buildResult = this.spawnClaude(projectDir, buildPrompt, perItemTimeout, { label: `${phase}-build-${item.id}` });
802
+ const buildResult = await this.spawnClaudeAsync(projectDir, buildPrompt, perItemTimeout, { label: `${phase}-build-${item.id}` });
707
803
 
708
804
  if (buildResult.exitCode === 0) {
709
- success(` Built (${buildResult.duration}s)`);
805
+ success(` ${item.componentName}: built (${buildResult.duration}s)`);
710
806
  } else {
711
- warn(` Build exited with code ${buildResult.exitCode} (${buildResult.duration}s)`);
807
+ warn(` ${item.componentName}: build exit ${buildResult.exitCode} (${buildResult.duration}s)`);
712
808
  }
713
809
 
714
810
  fs.writeFileSync(
@@ -716,12 +812,12 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
716
812
  `Exit code: ${buildResult.exitCode}\nDuration: ${buildResult.duration}s\n\n--- OUTPUT ---\n${buildResult.output.slice(0, 5000)}`
717
813
  );
718
814
 
719
- // Review one item (up to maxAutoReviewCycles)
815
+ // Review cycles
720
816
  let itemClean = false;
721
817
  for (let cycle = 1; cycle <= maxAutoReviewCycles && !itemClean; cycle++) {
722
- dim(` Review cycle ${cycle}/${maxAutoReviewCycles}...`);
818
+ dim(` ${item.componentName}: review c${cycle}...`);
723
819
  const reviewPrompt = this.wf.buildSingleItemReviewPrompt(phase, item, {}, projectDir, { devPort, reviewPort });
724
- const reviewResult = this.spawnClaude(projectDir, reviewPrompt, perItemTimeout, { label: `${phase}-review-${item.id}-c${cycle}` });
820
+ const reviewResult = await this.spawnClaudeAsync(projectDir, reviewPrompt, perItemTimeout, { label: `${phase}-review-${item.id}-c${cycle}` });
725
821
 
726
822
  const isCrash = reviewResult.exitCode !== 0 && reviewResult.duration < 10;
727
823
  const isKilled = [143, 137].includes(reviewResult.exitCode);
@@ -730,7 +826,7 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
730
826
  let itemIssues = [];
731
827
  if (isCrash || isKilled || isEmptyFail) {
732
828
  const reason = isCrash ? "crashed" : isKilled ? "killed/timed out" : "failed with no output";
733
- warn(` Reviewer ${reason} (${reviewResult.duration}s)`);
829
+ warn(` ${item.componentName}: reviewer ${reason} (${reviewResult.duration}s)`);
734
830
  itemIssues = [{ component: item.componentName, severity: "critical", description: `Reviewer ${reason}` }];
735
831
  } else {
736
832
  itemIssues = this.wf.parseReviewResult
@@ -740,28 +836,34 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
740
836
 
741
837
  if (itemIssues.length === 0) {
742
838
  itemClean = true;
743
- success(` Clean (${reviewResult.duration}s)`);
839
+ success(` ${item.componentName}: clean (${reviewResult.duration}s)`);
744
840
  } else {
745
- warn(` ${itemIssues.length} issue(s) found`);
841
+ warn(` ${item.componentName}: ${itemIssues.length} issue(s)`);
746
842
  for (const issue of itemIssues) {
747
- dim(` ${issue.description || issue.reason || "issue"} [${issue.severity || "medium"}]`);
843
+ dim(` ${issue.description || "issue"} [${issue.severity || "medium"}]`);
748
844
  }
749
845
 
750
846
  if (cycle < maxAutoReviewCycles) {
751
- // Fix this one item
752
847
  const fixPrompt = this.wf.buildAutoFixPrompt
753
848
  ? this.wf.buildAutoFixPrompt(phase, itemIssues, [item], projectDir)
754
849
  : this._defaultAutoFixPrompt(phase, itemIssues);
755
- dim(` Fixing...`);
756
- const fixResult = this.spawnClaude(projectDir, fixPrompt, perItemTimeout, { label: `${phase}-fix-${item.id}-c${cycle}` });
757
- if (fixResult.exitCode === 0) success(` Fixed (${fixResult.duration}s)`);
758
- else warn(` Fix exited with code ${fixResult.exitCode}`);
850
+ dim(` ${item.componentName}: fixing...`);
851
+ const fixResult = await this.spawnClaudeAsync(projectDir, fixPrompt, perItemTimeout, { label: `${phase}-fix-${item.id}-c${cycle}` });
852
+ if (fixResult.exitCode === 0) success(` ${item.componentName}: fixed (${fixResult.duration}s)`);
853
+ else warn(` ${item.componentName}: fix exit ${fixResult.exitCode}`);
759
854
  }
760
855
  }
761
856
  }
762
857
 
763
- builtPaths.push(item.sourcePath || (this.wf.guessPaths ? this.wf.guessPaths(phase, item) : ""));
764
- }
858
+ return item.sourcePath || (this.wf.guessPaths ? this.wf.guessPaths(phase, item) : "");
859
+ };
860
+
861
+ // Run with concurrency
862
+ const taskFns = items.map((item, idx) => () => processItem(item, idx));
863
+ const startTime = Date.now();
864
+ builtPaths = await this._runWithConcurrency(taskFns, concurrency);
865
+ const totalSec = Math.round((Date.now() - startTime) / 1000);
866
+ success(`All ${items.length} ${phase} processed in ${totalSec}s (${concurrency}x parallel)`);
765
867
 
766
868
  // Measure ALL at once (one Playwright run after all items built)
767
869
  if (!skipMeasure && this.wf.measure) {
@@ -33,7 +33,8 @@ Pass any of these as `$ARGUMENTS`:
33
33
  | `--review-port <N>` | Review server port (default: 3456) |
34
34
  | `--timeout <sec>` | Claude timeout per tier in seconds (default: 600) |
35
35
  | `--skip-measure` | Skip Playwright measurement (human-review only) |
36
- | `--clean` | Delete previous build output before building each phase |
36
+ | `--clean` | Clear all stale artifacts + delete build output before each phase |
37
+ | `--parallel <N>` | Run N items concurrently (default: 1, recommended: 3) |
37
38
  | `--verbose`, `-v` | Show Claude's tool calls and prompts in terminal |
38
39
 
39
40
  ## Prerequisites
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "2.72.10",
3
+ "version": "2.73.11",
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",