@tekyzinc/gsd-t 3.12.12 → 3.12.14
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 +103 -26
- package/README.md +76 -76
- package/bin/design-orchestrator.js +1 -1
- package/bin/gsd-t-unattended.cjs +15 -5
- package/bin/gsd-t-unattended.js +1 -1
- package/bin/gsd-t.js +114 -13
- package/bin/headless-auto-spawn.cjs +22 -3
- package/bin/headless-auto-spawn.js +12 -1
- package/bin/orchestrator.js +26 -0
- package/commands/gsd-t-backlog-promote.md +6 -6
- package/commands/gsd-t-complete-milestone.md +7 -7
- package/commands/gsd-t-design-audit.md +3 -3
- package/commands/gsd-t-design-build.md +1 -1
- package/commands/gsd-t-design-decompose.md +4 -4
- package/commands/gsd-t-execute.md +1 -1
- package/commands/gsd-t-feature.md +3 -3
- package/commands/gsd-t-gap-analysis.md +3 -3
- package/commands/gsd-t-health.md +3 -3
- package/commands/gsd-t-help.md +10 -10
- package/commands/gsd-t-impact.md +3 -3
- package/commands/gsd-t-init-scan-setup.md +5 -5
- package/commands/gsd-t-init.md +4 -4
- package/commands/gsd-t-log.md +1 -1
- package/commands/gsd-t-milestone.md +2 -2
- package/commands/gsd-t-pause.md +2 -2
- package/commands/gsd-t-prd.md +2 -2
- package/commands/gsd-t-project.md +1 -1
- package/commands/gsd-t-resume.md +4 -4
- package/commands/gsd-t-scan.md +3 -3
- package/commands/gsd-t-setup.md +2 -2
- package/commands/gsd-t-test-sync.md +1 -1
- package/commands/gsd-t-unattended-watch.md +5 -5
- package/commands/gsd-t-unattended.md +9 -9
- package/commands/gsd-t-wave.md +4 -4
- package/commands/gsd.md +17 -17
- package/docs/GSD-T-README.md +68 -68
- package/docs/architecture.md +8 -8
- package/docs/context-budget-recovery-plan.md +2 -2
- package/docs/infrastructure.md +7 -7
- package/docs/methodology.md +1 -1
- package/docs/neo4j-setup.md +2 -2
- package/docs/prd-gsd2-hybrid.md +1 -1
- package/docs/prd-harness-evolution.md +1 -1
- package/docs/requirements.md +2 -2
- package/docs/unattended-config.md +1 -1
- package/docs/unattended-windows-caveats.md +1 -1
- package/docs/workflows.md +1 -1
- package/package.json +1 -1
- package/scripts/context-meter/threshold.test.js +2 -2
- package/scripts/gsd-t-auto-route.js +1 -1
- package/scripts/gsd-t-context-meter.e2e.test.js +1 -1
- package/scripts/gsd-t-context-meter.test.js +1 -1
- package/scripts/gsd-t-design-review-server.js +11 -1
- package/scripts/gsd-t-event-writer.js +7 -4
- package/scripts/gsd-t-heartbeat.js +11 -1
- package/scripts/gsd-t-update-check.js +1 -1
- package/templates/CLAUDE-global.md +18 -163
- package/templates/stacks/_markdown.md +32 -0
- package/templates/stacks/design-to-code.md +1 -1
package/bin/gsd-t.js
CHANGED
|
@@ -1294,9 +1294,9 @@ function showInstallSummary(gsdtCount, utilCount) {
|
|
|
1294
1294
|
log(`${BOLD}Quick Start:${RESET}`);
|
|
1295
1295
|
log(` ${DIM}$${RESET} cd your-project`);
|
|
1296
1296
|
log(` ${DIM}$${RESET} claude`);
|
|
1297
|
-
log(` ${DIM}>${RESET} /
|
|
1298
|
-
log(` ${DIM}>${RESET} /
|
|
1299
|
-
log(` ${DIM}>${RESET} /
|
|
1297
|
+
log(` ${DIM}>${RESET} /gsd-t-init my-project`);
|
|
1298
|
+
log(` ${DIM}>${RESET} /gsd-t-milestone "First Feature"`);
|
|
1299
|
+
log(` ${DIM}>${RESET} /gsd-t-wave`);
|
|
1300
1300
|
log("");
|
|
1301
1301
|
log(`${BOLD}Other commands:${RESET}`);
|
|
1302
1302
|
log(` ${DIM}$${RESET} npx @tekyzinc/gsd-t status ${DIM}— check installation${RESET}`);
|
|
@@ -1344,7 +1344,7 @@ function initClaudeMd(projectDir, projectName, today) {
|
|
|
1344
1344
|
info("CLAUDE.md already contains GSD-T section — skipping");
|
|
1345
1345
|
} else {
|
|
1346
1346
|
warn("CLAUDE.md exists but doesn't reference GSD-T");
|
|
1347
|
-
info("Run /
|
|
1347
|
+
info("Run /gsd-t-init inside Claude Code to add GSD-T section");
|
|
1348
1348
|
}
|
|
1349
1349
|
} else { throw e; }
|
|
1350
1350
|
}
|
|
@@ -1513,8 +1513,8 @@ function showInitTree(projectDir) {
|
|
|
1513
1513
|
log(`${BOLD}Next steps:${RESET}`);
|
|
1514
1514
|
log(` 1. Edit CLAUDE.md — add project overview and tech stack`);
|
|
1515
1515
|
log(` 2. Start Claude Code: ${DIM}claude${RESET}`);
|
|
1516
|
-
log(` 3. Run: ${DIM}/
|
|
1517
|
-
log(` Or: ${DIM}/
|
|
1516
|
+
log(` 3. Run: ${DIM}/gsd-t-populate${RESET} ${DIM}(if existing codebase)${RESET}`);
|
|
1517
|
+
log(` Or: ${DIM}/gsd-t-project${RESET} ${DIM}(if new project)${RESET}`);
|
|
1518
1518
|
log("");
|
|
1519
1519
|
}
|
|
1520
1520
|
|
|
@@ -1687,7 +1687,7 @@ function showStatusProject() {
|
|
|
1687
1687
|
}
|
|
1688
1688
|
} else if (hasClaudeMd) {
|
|
1689
1689
|
info("CLAUDE.md found but no .gsd-t/ directory");
|
|
1690
|
-
info("Run /
|
|
1690
|
+
info("Run /gsd-t-init inside Claude Code to set up");
|
|
1691
1691
|
} else {
|
|
1692
1692
|
info("Not in a GSD-T project directory");
|
|
1693
1693
|
info(`Run 'npx @tekyzinc/gsd-t init' to set up this directory`);
|
|
@@ -1945,6 +1945,19 @@ function exportUniversalRulesForNpm() {
|
|
|
1945
1945
|
}
|
|
1946
1946
|
|
|
1947
1947
|
async function doUpdateAll() {
|
|
1948
|
+
// Step 1: Upgrade the globally-installed npm package FIRST. Without this,
|
|
1949
|
+
// `update-all` would only propagate command files — but the global `gsd-t`
|
|
1950
|
+
// binary itself could stay pinned to an older version (e.g., user stuck
|
|
1951
|
+
// on v3.11.11 while npm registry has v3.12.12). See CHANGELOG v3.12.13.
|
|
1952
|
+
// Guard with an env flag to prevent re-exec loops.
|
|
1953
|
+
if (!process.env.GSDT_POST_UPGRADE) {
|
|
1954
|
+
const upgraded = await upgradeGlobalBinary();
|
|
1955
|
+
if (upgraded.reexec) {
|
|
1956
|
+
reexecUpdateAll();
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1948
1961
|
await updateGlobalCommands();
|
|
1949
1962
|
heading("Updating registered projects...");
|
|
1950
1963
|
log("");
|
|
@@ -1969,6 +1982,65 @@ async function doUpdateAll() {
|
|
|
1969
1982
|
showUpdateAllSummary(projects.length, counts, playwrightMissing, swaggerMissing, syncCount);
|
|
1970
1983
|
}
|
|
1971
1984
|
|
|
1985
|
+
// Upgrade the globally-installed @tekyzinc/gsd-t to @latest. Returns
|
|
1986
|
+
// { upgraded: bool, reexec: bool, error?: string }.
|
|
1987
|
+
// - reexec=true when the on-disk version after `npm install -g` is newer than
|
|
1988
|
+
// the currently-running PKG_VERSION, meaning we need to hand off to the
|
|
1989
|
+
// freshly-installed binary so the new code drives propagation.
|
|
1990
|
+
// - reexec=false when already at latest, or when the install failed (we
|
|
1991
|
+
// continue with the current binary and still propagate command files).
|
|
1992
|
+
async function upgradeGlobalBinary() {
|
|
1993
|
+
heading("Upgrading global @tekyzinc/gsd-t to latest...");
|
|
1994
|
+
try {
|
|
1995
|
+
execFileSync("npm", ["install", "-g", "@tekyzinc/gsd-t@latest"], {
|
|
1996
|
+
stdio: "inherit",
|
|
1997
|
+
env: process.env,
|
|
1998
|
+
});
|
|
1999
|
+
} catch (e) {
|
|
2000
|
+
warn(`Global npm install failed: ${e.message || e}`);
|
|
2001
|
+
info("Continuing with current binary — command files will still be propagated.");
|
|
2002
|
+
return { upgraded: false, reexec: false, error: String(e.message || e) };
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
// Read the freshly-installed global package's version. If it's newer than
|
|
2006
|
+
// the currently-running process, signal a re-exec.
|
|
2007
|
+
let newVersion = null;
|
|
2008
|
+
try {
|
|
2009
|
+
const prefix = execFileSync("npm", ["prefix", "-g"], { encoding: "utf8" }).trim();
|
|
2010
|
+
const globalPkgJson = path.join(prefix, "lib", "node_modules", "@tekyzinc", "gsd-t", "package.json");
|
|
2011
|
+
if (fs.existsSync(globalPkgJson)) {
|
|
2012
|
+
newVersion = JSON.parse(fs.readFileSync(globalPkgJson, "utf8")).version;
|
|
2013
|
+
}
|
|
2014
|
+
} catch {
|
|
2015
|
+
// Best-effort; fall through.
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
if (newVersion && newVersion !== PKG_VERSION) {
|
|
2019
|
+
success(`Global binary upgraded: v${PKG_VERSION} → v${newVersion}`);
|
|
2020
|
+
info("Handing off to the newly-installed binary for propagation...");
|
|
2021
|
+
return { upgraded: true, reexec: true };
|
|
2022
|
+
}
|
|
2023
|
+
success(`Global binary already at latest (v${PKG_VERSION})`);
|
|
2024
|
+
return { upgraded: true, reexec: false };
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// Hand execution to the newly-installed global `gsd-t update-all`. Sets the
|
|
2028
|
+
// GSDT_POST_UPGRADE env flag so the child does not recurse into another
|
|
2029
|
+
// upgrade attempt.
|
|
2030
|
+
function reexecUpdateAll() {
|
|
2031
|
+
const env = Object.assign({}, process.env, { GSDT_POST_UPGRADE: "1" });
|
|
2032
|
+
try {
|
|
2033
|
+
execFileSync("gsd-t", ["update-all"], { stdio: "inherit", env });
|
|
2034
|
+
} catch (e) {
|
|
2035
|
+
// Surface the child's exit code; execFileSync throws with .status on
|
|
2036
|
+
// non-zero exit. Fall through to re-throw so the caller exits cleanly.
|
|
2037
|
+
if (e && typeof e.status === "number") {
|
|
2038
|
+
process.exit(e.status);
|
|
2039
|
+
}
|
|
2040
|
+
throw e;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
1972
2044
|
async function updateGlobalCommands() {
|
|
1973
2045
|
if (getInstalledVersion() !== PKG_VERSION) {
|
|
1974
2046
|
await doInstall({ update: true });
|
|
@@ -2671,8 +2743,10 @@ function appendHeadlessTokenLog(projectDir, entry) {
|
|
|
2671
2743
|
try {
|
|
2672
2744
|
const logPath = path.join(projectDir, ".gsd-t", "token-log.md");
|
|
2673
2745
|
const note = entry.exitCode === 0 ? "headless exec: ok" : `headless exec: exit ${entry.exitCode}`;
|
|
2746
|
+
// v3.12.14: prefer env-var model over hardcoded "unknown".
|
|
2747
|
+
const model = process.env.GSD_T_MODEL || "unknown";
|
|
2674
2748
|
const row =
|
|
2675
|
-
`| ${entry.dtStart} | ${entry.dtEnd} | ${entry.command} | headless |
|
|
2749
|
+
`| ${entry.dtStart} | ${entry.dtEnd} | ${entry.command} | headless | ${model} | ${entry.durationS}s | ${note} | - | - | unknown |\n`;
|
|
2676
2750
|
const gsdtDir = path.join(projectDir, ".gsd-t");
|
|
2677
2751
|
if (!fs.existsSync(gsdtDir)) fs.mkdirSync(gsdtDir, { recursive: true });
|
|
2678
2752
|
if (!fs.existsSync(logPath)) {
|
|
@@ -2718,7 +2792,7 @@ function parseHeadlessFlags(args) {
|
|
|
2718
2792
|
* Build the claude -p invocation string for a GSD-T command.
|
|
2719
2793
|
*
|
|
2720
2794
|
* Non-interactive `claude -p` mode requires the bare `/gsd-t-X` form — the
|
|
2721
|
-
* `/
|
|
2795
|
+
* `/gsd-t-X` namespace prefix is rejected as "Unknown command" even
|
|
2722
2796
|
* though interactive mode accepts both. Verified by M36 Phase 0 Spike A
|
|
2723
2797
|
* (2026-04-15). See .gsd-t/M36-spike-findings.md.
|
|
2724
2798
|
*/
|
|
@@ -2807,12 +2881,17 @@ function doHeadlessExec(command, cmdArgs, flags) {
|
|
|
2807
2881
|
let output = "";
|
|
2808
2882
|
let processExitCode = 0;
|
|
2809
2883
|
|
|
2810
|
-
// Inject command/phase env vars so worker
|
|
2811
|
-
// (
|
|
2884
|
+
// Inject command/phase/trace/model/project-dir env vars so worker
|
|
2885
|
+
// event-stream entries (writer CLI + heartbeat hook) are tagged in the
|
|
2886
|
+
// child's context (Fix 2, v3.12.12; trace/model/project-dir added v3.12.14
|
|
2887
|
+
// for the null-telemetry regression fix).
|
|
2812
2888
|
const workerEnv = Object.assign({}, process.env, {
|
|
2813
2889
|
GSD_T_COMMAND: `gsd-t-${command}`,
|
|
2814
2890
|
GSD_T_PHASE: process.env.GSD_T_PHASE || "execute",
|
|
2891
|
+
GSD_T_PROJECT_DIR: process.env.GSD_T_PROJECT_DIR || process.cwd(),
|
|
2815
2892
|
});
|
|
2893
|
+
if (process.env.GSD_T_TRACE_ID) workerEnv.GSD_T_TRACE_ID = process.env.GSD_T_TRACE_ID;
|
|
2894
|
+
if (process.env.GSD_T_MODEL) workerEnv.GSD_T_MODEL = process.env.GSD_T_MODEL;
|
|
2816
2895
|
|
|
2817
2896
|
try {
|
|
2818
2897
|
const result = execFileSync("claude", ["-p", "--dangerously-skip-permissions", prompt], {
|
|
@@ -3097,9 +3176,22 @@ function getEscalationModel(iteration) {
|
|
|
3097
3176
|
*/
|
|
3098
3177
|
function spawnClaudeSession(prompt, model) {
|
|
3099
3178
|
try {
|
|
3179
|
+
// v3.12.14: propagate GSD_T_* env vars so the worker's heartbeat hook +
|
|
3180
|
+
// event-writer entries are tagged with the parent command/phase/trace and
|
|
3181
|
+
// this session's model. Without these, tool_call events from the debug
|
|
3182
|
+
// worker appear as command=null/phase=null.
|
|
3183
|
+
const env = Object.assign({}, process.env, {
|
|
3184
|
+
GSD_T_COMMAND: process.env.GSD_T_COMMAND || "gsd-t-debug",
|
|
3185
|
+
GSD_T_PHASE: process.env.GSD_T_PHASE || "debug",
|
|
3186
|
+
GSD_T_MODEL: model || process.env.GSD_T_MODEL || null,
|
|
3187
|
+
GSD_T_PROJECT_DIR: process.env.GSD_T_PROJECT_DIR || process.cwd(),
|
|
3188
|
+
});
|
|
3189
|
+
if (env.GSD_T_MODEL === null) delete env.GSD_T_MODEL;
|
|
3190
|
+
if (process.env.GSD_T_TRACE_ID) env.GSD_T_TRACE_ID = process.env.GSD_T_TRACE_ID;
|
|
3100
3191
|
return execFileSync("claude", ["-p", prompt, "--model", model], {
|
|
3101
3192
|
encoding: "utf8", timeout: 300000,
|
|
3102
3193
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3194
|
+
env,
|
|
3103
3195
|
});
|
|
3104
3196
|
} catch (e) {
|
|
3105
3197
|
return (e.stdout || "") + (e.stderr || "") || null;
|
|
@@ -3136,8 +3228,17 @@ function runLedgerCompaction(projectDir, jsonMode) {
|
|
|
3136
3228
|
JSON.stringify(entries, null, 2);
|
|
3137
3229
|
let summary = "Compacted — see previous entries.";
|
|
3138
3230
|
try {
|
|
3231
|
+
// v3.12.14: propagate GSD_T_* env for telemetry tagging.
|
|
3232
|
+
const env = Object.assign({}, process.env, {
|
|
3233
|
+
GSD_T_COMMAND: process.env.GSD_T_COMMAND || "gsd-t-debug",
|
|
3234
|
+
GSD_T_PHASE: process.env.GSD_T_PHASE || "debug",
|
|
3235
|
+
GSD_T_MODEL: "haiku",
|
|
3236
|
+
GSD_T_PROJECT_DIR: process.env.GSD_T_PROJECT_DIR || projectDir,
|
|
3237
|
+
});
|
|
3238
|
+
if (process.env.GSD_T_TRACE_ID) env.GSD_T_TRACE_ID = process.env.GSD_T_TRACE_ID;
|
|
3139
3239
|
const out = execFileSync("claude", ["-p", compactPrompt, "--model", "haiku"], {
|
|
3140
3240
|
encoding: "utf8", timeout: 120000, stdio: ["pipe", "pipe", "pipe"],
|
|
3241
|
+
env,
|
|
3141
3242
|
});
|
|
3142
3243
|
summary = (out || "").trim() || summary;
|
|
3143
3244
|
} catch (e) {
|
|
@@ -3378,8 +3479,8 @@ function showHelp() {
|
|
|
3378
3479
|
log(` ${DIM}$${RESET} npx @tekyzinc/gsd-t init my-saas-app`);
|
|
3379
3480
|
log(` ${DIM}$${RESET} npx @tekyzinc/gsd-t update\n`);
|
|
3380
3481
|
log(`${BOLD}After installing, use in Claude Code:${RESET}`);
|
|
3381
|
-
log(` ${DIM}>${RESET} /
|
|
3382
|
-
log(` ${DIM}>${RESET} /
|
|
3482
|
+
log(` ${DIM}>${RESET} /gsd-t-project "Build a task management app"`);
|
|
3483
|
+
log(` ${DIM}>${RESET} /gsd-t-wave\n`);
|
|
3383
3484
|
log(`${DIM}Docs: https://github.com/Tekyz-Inc/get-stuff-done-teams${RESET}\n`);
|
|
3384
3485
|
}
|
|
3385
3486
|
|
|
@@ -135,12 +135,27 @@ function autoSpawnHeadless(opts) {
|
|
|
135
135
|
const gsdtCli = path.join(projectDir, "bin", "gsd-t.js");
|
|
136
136
|
const childArgs = [gsdtCli, "headless", stripGsdtPrefix(command), ...args, "--log"];
|
|
137
137
|
|
|
138
|
-
// Inject command/phase into worker env so event-stream entries
|
|
139
|
-
// (
|
|
138
|
+
// Inject command/phase/trace/model into worker env so event-stream entries
|
|
139
|
+
// (both the writer CLI and the heartbeat PostToolUse hook) are tagged in
|
|
140
|
+
// the child's context (Fix 2, v3.12.12; trace/model/project-dir added
|
|
141
|
+
// v3.12.14 to close the null-telemetry regression).
|
|
142
|
+
//
|
|
143
|
+
// GSD_T_PHASE defaults to "execute" for primary spawns.
|
|
144
|
+
// GSD_T_TRACE_ID / GSD_T_MODEL are inherited from parent env if set;
|
|
145
|
+
// parents (orchestrator, command files) should set them before spawning.
|
|
146
|
+
// GSD_T_PROJECT_DIR gives the writer a stable target when the child cwd
|
|
147
|
+
// drifts (e.g., temp dirs in subagents).
|
|
140
148
|
const workerEnv = Object.assign({}, process.env, {
|
|
141
149
|
GSD_T_COMMAND: command,
|
|
142
150
|
GSD_T_PHASE: process.env.GSD_T_PHASE || "execute",
|
|
151
|
+
GSD_T_PROJECT_DIR: process.env.GSD_T_PROJECT_DIR || projectDir,
|
|
143
152
|
});
|
|
153
|
+
if (process.env.GSD_T_TRACE_ID) {
|
|
154
|
+
workerEnv.GSD_T_TRACE_ID = process.env.GSD_T_TRACE_ID;
|
|
155
|
+
}
|
|
156
|
+
if (process.env.GSD_T_MODEL) {
|
|
157
|
+
workerEnv.GSD_T_MODEL = process.env.GSD_T_MODEL;
|
|
158
|
+
}
|
|
144
159
|
|
|
145
160
|
const child = spawn("node", childArgs, {
|
|
146
161
|
cwd: projectDir,
|
|
@@ -392,8 +407,12 @@ function appendTokenLog(projectDir, entry) {
|
|
|
392
407
|
try {
|
|
393
408
|
const logPath = path.join(projectDir, ".gsd-t", "token-log.md");
|
|
394
409
|
const note = entry.exitCode === 0 ? "headless spawn: ok" : `headless spawn: exit ${entry.exitCode}`;
|
|
410
|
+
// v3.12.14: prefer env-var model over the old hardcoded "unknown". The
|
|
411
|
+
// parent session should have set GSD_T_MODEL before invoking spawn; fall
|
|
412
|
+
// back to "unknown" if not (graceful).
|
|
413
|
+
const model = process.env.GSD_T_MODEL || "unknown";
|
|
395
414
|
const row =
|
|
396
|
-
`| ${entry.dtStart} | ${entry.dtEnd} | ${entry.command} | headless |
|
|
415
|
+
`| ${entry.dtStart} | ${entry.dtEnd} | ${entry.command} | headless | ${model} | ${entry.durationS}s | ${note} | - | - | unknown |\n`;
|
|
397
416
|
if (!fs.existsSync(logPath)) {
|
|
398
417
|
// Create with header
|
|
399
418
|
ensureDir(path.dirname(logPath));
|
|
@@ -135,11 +135,22 @@ function autoSpawnHeadless(opts) {
|
|
|
135
135
|
const gsdtCli = path.join(projectDir, "bin", "gsd-t.js");
|
|
136
136
|
const childArgs = [gsdtCli, "headless", stripGsdtPrefix(command), ...args, "--log"];
|
|
137
137
|
|
|
138
|
+
// v3.12.14 — env-var propagation for telemetry tagging (mirror of the
|
|
139
|
+
// authoritative .cjs variant). PRODUCTION consumers import the .cjs; this
|
|
140
|
+
// .js copy is retained only to keep the legacy test green.
|
|
141
|
+
const workerEnv = Object.assign({}, process.env, {
|
|
142
|
+
GSD_T_COMMAND: command,
|
|
143
|
+
GSD_T_PHASE: process.env.GSD_T_PHASE || "execute",
|
|
144
|
+
GSD_T_PROJECT_DIR: process.env.GSD_T_PROJECT_DIR || projectDir,
|
|
145
|
+
});
|
|
146
|
+
if (process.env.GSD_T_TRACE_ID) workerEnv.GSD_T_TRACE_ID = process.env.GSD_T_TRACE_ID;
|
|
147
|
+
if (process.env.GSD_T_MODEL) workerEnv.GSD_T_MODEL = process.env.GSD_T_MODEL;
|
|
148
|
+
|
|
138
149
|
const child = spawn("node", childArgs, {
|
|
139
150
|
cwd: projectDir,
|
|
140
151
|
detached: true,
|
|
141
152
|
stdio: ["ignore", logFd, logFd],
|
|
142
|
-
env:
|
|
153
|
+
env: workerEnv,
|
|
143
154
|
});
|
|
144
155
|
|
|
145
156
|
child.unref();
|
package/bin/orchestrator.js
CHANGED
|
@@ -82,6 +82,25 @@ function isPortInUse(port) {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Build the env block for orchestrator-spawned `claude -p` sessions.
|
|
87
|
+
* v3.12.14 — propagates GSD_T_COMMAND/PHASE/TRACE_ID/MODEL/PROJECT_DIR so the
|
|
88
|
+
* worker's heartbeat hook and event-writer entries are tagged. Accepts the
|
|
89
|
+
* opts object (for `label`) that callers already pass and defaults missing
|
|
90
|
+
* fields from the parent process env.
|
|
91
|
+
*/
|
|
92
|
+
function _buildOrchestratorEnv(opts, projectDir) {
|
|
93
|
+
opts = opts || {};
|
|
94
|
+
const env = Object.assign({}, process.env, {
|
|
95
|
+
GSD_T_COMMAND: process.env.GSD_T_COMMAND || "gsd-t-orchestrator",
|
|
96
|
+
GSD_T_PHASE: process.env.GSD_T_PHASE || opts.label || "orchestrator",
|
|
97
|
+
GSD_T_PROJECT_DIR: process.env.GSD_T_PROJECT_DIR || projectDir,
|
|
98
|
+
});
|
|
99
|
+
if (process.env.GSD_T_TRACE_ID) env.GSD_T_TRACE_ID = process.env.GSD_T_TRACE_ID;
|
|
100
|
+
if (process.env.GSD_T_MODEL) env.GSD_T_MODEL = process.env.GSD_T_MODEL;
|
|
101
|
+
return env;
|
|
102
|
+
}
|
|
103
|
+
|
|
85
104
|
// ─── Orchestrator Class ────────────────────────────────────────────────────
|
|
86
105
|
|
|
87
106
|
class Orchestrator {
|
|
@@ -212,11 +231,15 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
|
|
|
212
231
|
const signalFile = path.join(this.getReviewDir(projectDir), `_sync-done-${Date.now()}.json`);
|
|
213
232
|
let result = { output: "", exitCode: 1, duration: 0 };
|
|
214
233
|
|
|
234
|
+
// v3.12.14: propagate GSD_T_* env so the worker's heartbeat hook and
|
|
235
|
+
// event-writer entries are tagged. opts.label → phase/command hints.
|
|
236
|
+
const env = _buildOrchestratorEnv(opts, projectDir);
|
|
215
237
|
const child = execFile("claude", args, {
|
|
216
238
|
encoding: "utf8",
|
|
217
239
|
timeout: effectiveTimeout,
|
|
218
240
|
cwd: projectDir,
|
|
219
241
|
maxBuffer: 10 * 1024 * 1024,
|
|
242
|
+
env,
|
|
220
243
|
}, (err, stdout, stderr) => {
|
|
221
244
|
this.untrackChild(child.pid);
|
|
222
245
|
const raw = err ? ((err.stdout || "") + (err.stderr || "")) : (stdout || "");
|
|
@@ -264,12 +287,15 @@ ${BOLD}Phases:${RESET} ${this.wf.phases.join(" → ")}
|
|
|
264
287
|
);
|
|
265
288
|
}
|
|
266
289
|
|
|
290
|
+
// v3.12.14: propagate GSD_T_* env for telemetry tagging in the child.
|
|
291
|
+
const env = _buildOrchestratorEnv(opts, projectDir);
|
|
267
292
|
return new Promise((resolve) => {
|
|
268
293
|
const child = execFile("claude", args, {
|
|
269
294
|
encoding: "utf8",
|
|
270
295
|
timeout: timeout || 120_000,
|
|
271
296
|
cwd: projectDir,
|
|
272
297
|
maxBuffer: 10 * 1024 * 1024,
|
|
298
|
+
env,
|
|
273
299
|
}, (err, stdout, stderr) => {
|
|
274
300
|
this.untrackChild(child.pid);
|
|
275
301
|
const raw = err ? ((err.stdout || "") + (err.stderr || "")) : (stdout || "");
|
|
@@ -13,14 +13,14 @@ Parse $ARGUMENTS to extract:
|
|
|
13
13
|
- `<position>` — the entry number to promote
|
|
14
14
|
|
|
15
15
|
If no position is provided, show an error:
|
|
16
|
-
"Usage: `/
|
|
16
|
+
"Usage: `/gsd-t-backlog-promote <position>`"
|
|
17
17
|
|
|
18
18
|
## Step 2: Find and Display Entry
|
|
19
19
|
|
|
20
20
|
Find the entry at the specified position in `.gsd-t/backlog.md`.
|
|
21
21
|
|
|
22
22
|
If the position doesn't exist, show an error:
|
|
23
|
-
"No backlog entry at position {position}. Run `/
|
|
23
|
+
"No backlog entry at position {position}. Run `/gsd-t-backlog-list` to see available entries."
|
|
24
24
|
|
|
25
25
|
Display the entry to the user:
|
|
26
26
|
```
|
|
@@ -88,10 +88,10 @@ After classification is confirmed:
|
|
|
88
88
|
|
|
89
89
|
Based on the classification, present the command for the user to invoke:
|
|
90
90
|
|
|
91
|
-
- **Milestone**: "Run `/
|
|
92
|
-
- **Quick**: "Run `/
|
|
93
|
-
- **Debug**: "Run `/
|
|
94
|
-
- **Feature**: "Run `/
|
|
91
|
+
- **Milestone**: "Run `/gsd-t-milestone {refined description}`"
|
|
92
|
+
- **Quick**: "Run `/gsd-t-quick {refined description}`"
|
|
93
|
+
- **Debug**: "Run `/gsd-t-debug {refined description}`"
|
|
94
|
+
- **Feature**: "Run `/gsd-t-feature {refined description}`"
|
|
95
95
|
|
|
96
96
|
Display the full command with the refined description ready to copy.
|
|
97
97
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
You are finalizing a completed milestone. Your job is to archive the milestone documentation, create a git tag, and prepare for the next milestone.
|
|
4
4
|
|
|
5
5
|
This command is:
|
|
6
|
-
- **Auto-invoked** by `/
|
|
7
|
-
- **Auto-invoked** by `/
|
|
6
|
+
- **Auto-invoked** by `/gsd-t-verify` (Step 8) after all quality gates pass — at ALL autonomy levels
|
|
7
|
+
- **Auto-invoked** by `/gsd-t-wave` as part of the VERIFY+COMPLETE phase
|
|
8
8
|
- **Standalone** when user wants to manually close a milestone
|
|
9
9
|
|
|
10
10
|
## Step 1: Verify Completion
|
|
@@ -14,7 +14,7 @@ Read:
|
|
|
14
14
|
2. `.gsd-t/verify-report.md` — confirm all checks passed
|
|
15
15
|
|
|
16
16
|
If status is not VERIFIED:
|
|
17
|
-
"⚠️ Milestone not yet verified. Run `/
|
|
17
|
+
"⚠️ Milestone not yet verified. Run `/gsd-t-verify` first, or use `--force` to complete anyway."
|
|
18
18
|
|
|
19
19
|
If `--force` flag provided, proceed with warning in archive.
|
|
20
20
|
|
|
@@ -76,7 +76,7 @@ Refer to `.gsd-t/contracts/goal-backward-contract.md` for the full verification
|
|
|
76
76
|
{findings table}
|
|
77
77
|
|
|
78
78
|
Options:
|
|
79
|
-
1. Fix the findings and re-run /
|
|
79
|
+
1. Fix the findings and re-run /gsd-t-verify
|
|
80
80
|
2. Override with explicit acknowledgment: re-run this command with --force-goal-backward
|
|
81
81
|
|
|
82
82
|
Proceed with option 1 (recommended) or acknowledge to force completion?
|
|
@@ -493,8 +493,8 @@ Summary:
|
|
|
493
493
|
|
|
494
494
|
Next steps:
|
|
495
495
|
- Push tags: git push origin v{version}
|
|
496
|
-
- Start next milestone: /
|
|
497
|
-
- Or view roadmap: /
|
|
496
|
+
- Start next milestone: /gsd-t-milestone "{next name}"
|
|
497
|
+
- Or view roadmap: /gsd-t-status
|
|
498
498
|
```
|
|
499
499
|
|
|
500
500
|
## Step 13: Update Roadmap (if exists)
|
|
@@ -510,7 +510,7 @@ If `.gsd-t/roadmap.md` exists:
|
|
|
510
510
|
"Cannot complete — verification found issues. Address them first or use `--force`."
|
|
511
511
|
|
|
512
512
|
### If no milestone active:
|
|
513
|
-
"No active milestone to complete. Run `/
|
|
513
|
+
"No active milestone to complete. Run `/gsd-t-status` to see state."
|
|
514
514
|
|
|
515
515
|
### If git operations fail:
|
|
516
516
|
- Still create archive
|
|
@@ -400,7 +400,7 @@ If ANY CRITICAL or HIGH deviations were found, automatically prompt the fix work
|
|
|
400
400
|
The audit report at `.gsd-t/design-audit-{page-name}-{YYYY-MM-DD}.md`
|
|
401
401
|
has the exact Figma values for each deviation.
|
|
402
402
|
|
|
403
|
-
`/
|
|
403
|
+
`/gsd-t-quick fix all CRITICAL and HIGH deviations from .gsd-t/design-audit-{page-name}-{YYYY-MM-DD}.md — use the Figma values in the report as the source of truth`
|
|
404
404
|
|
|
405
405
|
───────────────────────────────────────────────────────────────
|
|
406
406
|
```
|
|
@@ -414,7 +414,7 @@ If ONLY MEDIUM or LOW deviations remain, show:
|
|
|
414
414
|
|
|
415
415
|
**{N} MEDIUM + {N} LOW deviations.** These are minor — fix if you want pixel-perfect.
|
|
416
416
|
|
|
417
|
-
`/
|
|
417
|
+
`/gsd-t-quick fix MEDIUM and LOW deviations from .gsd-t/design-audit-{page-name}-{YYYY-MM-DD}.md`
|
|
418
418
|
|
|
419
419
|
───────────────────────────────────────────────────────────────
|
|
420
420
|
```
|
|
@@ -427,7 +427,7 @@ After fixes are applied, **re-run the audit automatically** to verify. Loop unti
|
|
|
427
427
|
|
|
428
428
|
## Rules
|
|
429
429
|
|
|
430
|
-
- **You write ZERO code during the audit phase (Steps 1-5).** Report only. Code changes happen in Step 6 via `/
|
|
430
|
+
- **You write ZERO code during the audit phase (Steps 1-5).** Report only. Code changes happen in Step 6 via `/gsd-t-quick`.
|
|
431
431
|
- **You do NOT "look close" at anything.** Every property gets an exact value from Figma and an exact value from the build. They match or they don't.
|
|
432
432
|
- **You do NOT skip widgets.** Every widget in the Figma AND every widget in the build gets audited.
|
|
433
433
|
- **You MUST call `get_design_context` per widget node — NOT `get_screenshot`.** `get_design_context` returns structured code, component properties, and design tokens. `get_screenshot` returns only a visual image that you cannot extract exact values from. Using `get_screenshot` for widget extraction defeats the entire purpose of structured comparison — you end up eyeballing instead of measuring. The ONLY acceptable use of `get_screenshot` is for the built page (Step 2) where you need to see what was actually rendered. For Figma source data, ALWAYS use `get_design_context`.
|
|
@@ -40,7 +40,7 @@ Pass any of these as `$ARGUMENTS`:
|
|
|
40
40
|
## Prerequisites
|
|
41
41
|
|
|
42
42
|
- Design contracts must exist in `.gsd-t/contracts/design/` with an `INDEX.md`
|
|
43
|
-
- If no contracts exist, run `/
|
|
43
|
+
- If no contracts exist, run `/gsd-t-design-decompose` first
|
|
44
44
|
|
|
45
45
|
## Why a JS Orchestrator?
|
|
46
46
|
|
|
@@ -471,7 +471,7 @@ This domain owns the following design contracts:
|
|
|
471
471
|
- Pages: (none — pages owned by page-assembly domain)
|
|
472
472
|
```
|
|
473
473
|
|
|
474
|
-
If `.gsd-t/domains/` does NOT exist yet, suggest the user run `/
|
|
474
|
+
If `.gsd-t/domains/` does NOT exist yet, suggest the user run `/gsd-t-partition` next, with a note that design contracts should be partitioned into domains:
|
|
475
475
|
- **design-system domain** owns element contracts
|
|
476
476
|
- **widgets domain** owns widget contracts
|
|
477
477
|
- **pages domain** owns page assembly + routing
|
|
@@ -494,11 +494,11 @@ Display:
|
|
|
494
494
|
|
|
495
495
|
**Design Build** — build UI from contracts with tiered review gates (elements → widgets → pages)
|
|
496
496
|
|
|
497
|
-
`/
|
|
497
|
+
`/gsd-t-design-build`
|
|
498
498
|
|
|
499
499
|
**Also available:**
|
|
500
|
-
- `/
|
|
501
|
-
- `/
|
|
500
|
+
- `/gsd-t-partition` — if you need domain boundaries before building
|
|
501
|
+
- `/gsd-t-plan` — if you need task lists before building
|
|
502
502
|
|
|
503
503
|
───────────────────────────────────────────────────────────────
|
|
504
504
|
```
|
|
@@ -66,7 +66,7 @@ This calls `getSessionStatus()` (v2.0.0) which reads `.gsd-t/.context-meter-stat
|
|
|
66
66
|
|
|
67
67
|
Use the returned `threshold` as the gate signal for the rest of this run. The gate logic is in Step 3.5; do NOT skip it. If the Context Meter hook isn't installed (`.gsd-t/.context-meter-state.json` missing and doctor reports it), run `gsd-t doctor` to diagnose — the gate still works via the heuristic fallback but real-time readings give much better guardrails.
|
|
68
68
|
|
|
69
|
-
Why: every `/
|
|
69
|
+
Why: every `/gsd-t-execute` invocation is a fresh orchestrator session and needs a current reading of context utilization before spawning any subagents. The authoritative source is the Context Meter state file; the fallback keeps the gate functional on projects that haven't installed the hook yet.
|
|
70
70
|
|
|
71
71
|
## Step 1: Load State
|
|
72
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GSD-T: Feature — Add a Major Feature to an Existing Project
|
|
2
2
|
|
|
3
|
-
You are the lead agent planning a significant new feature for an existing codebase. Unlike `/
|
|
3
|
+
You are the lead agent planning a significant new feature for an existing codebase. Unlike `/gsd-t-project` (greenfield), this command respects and builds on what already exists — existing patterns, schema, auth, conventions, and contracts.
|
|
4
4
|
|
|
5
5
|
## Step 0.5: Scan Freshness Auto-Refresh
|
|
6
6
|
|
|
@@ -154,7 +154,7 @@ The feature may be a single milestone or multiple, depending on scope:
|
|
|
154
154
|
### Single Milestone (if feature is focused):
|
|
155
155
|
- 2-4 domains, < 15 tasks total
|
|
156
156
|
- Minimal impact on existing contracts
|
|
157
|
-
- Skip roadmap, go straight to: "Run `/
|
|
157
|
+
- Skip roadmap, go straight to: "Run `/gsd-t-partition` to begin"
|
|
158
158
|
|
|
159
159
|
### Multiple Milestones (if feature is complex):
|
|
160
160
|
Apply these sequencing rules:
|
|
@@ -267,7 +267,7 @@ Present:
|
|
|
267
267
|
4. Any conflicts with existing work
|
|
268
268
|
5. Recommended starting point
|
|
269
269
|
|
|
270
|
-
Ask: "Ready to start? Run `/
|
|
270
|
+
Ask: "Ready to start? Run `/gsd-t-partition` for Milestone {N}."
|
|
271
271
|
|
|
272
272
|
$ARGUMENTS
|
|
273
273
|
|
|
@@ -224,13 +224,13 @@ Show the recommended groupings and offer promotion paths:
|
|
|
224
224
|
## Recommended Next Steps
|
|
225
225
|
|
|
226
226
|
1. {Milestone name} — {N} gaps ({critical} critical, {high} high)
|
|
227
|
-
→ /
|
|
227
|
+
→ /gsd-t-milestone "{name}"
|
|
228
228
|
|
|
229
229
|
2. {Feature name} — {N} gaps
|
|
230
|
-
→ /
|
|
230
|
+
→ /gsd-t-feature "{name}"
|
|
231
231
|
|
|
232
232
|
3. Quick fixes — {N} items
|
|
233
|
-
→ /
|
|
233
|
+
→ /gsd-t-quick "{description}"
|
|
234
234
|
|
|
235
235
|
Promote any of these now, or review the gap analysis first?
|
|
236
236
|
```
|
package/commands/gsd-t-health.md
CHANGED
|
@@ -131,9 +131,9 @@ After repair, re-run the checks and report the final state.
|
|
|
131
131
|
## Step 6: Next Steps
|
|
132
132
|
|
|
133
133
|
If HEALTHY → "✅ GSD-T structure is healthy — all required files present."
|
|
134
|
-
If DEGRADED with --repair done → "✅ Repaired {N} missing files. Run /
|
|
135
|
-
If DEGRADED without --repair → "⚠ Run /
|
|
136
|
-
If BROKEN → "🔴 Project structure is broken. Run /
|
|
134
|
+
If DEGRADED with --repair done → "✅ Repaired {N} missing files. Run /gsd-t-health again to confirm."
|
|
135
|
+
If DEGRADED without --repair → "⚠ Run /gsd-t-health --repair to create {N} missing files."
|
|
136
|
+
If BROKEN → "🔴 Project structure is broken. Run /gsd-t-health --repair or /gsd-t-init to rebuild."
|
|
137
137
|
|
|
138
138
|
$ARGUMENTS
|
|
139
139
|
|
package/commands/gsd-t-help.md
CHANGED
|
@@ -84,8 +84,8 @@ BACKLOG Manual
|
|
|
84
84
|
backlog-settings Manage types, apps, categories, and defaults
|
|
85
85
|
|
|
86
86
|
───────────────────────────────────────────────────────────────────────────────
|
|
87
|
-
Type /
|
|
88
|
-
Example: /
|
|
87
|
+
Type /gsd-t-help {command} for detailed help on any command.
|
|
88
|
+
Example: /gsd-t-help impact
|
|
89
89
|
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
90
90
|
```
|
|
91
91
|
|
|
@@ -94,7 +94,7 @@ Example: /user:gsd-t-help impact
|
|
|
94
94
|
When user provides a command name, show detailed help:
|
|
95
95
|
|
|
96
96
|
```
|
|
97
|
-
/
|
|
97
|
+
/gsd-t-help {command}
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
### Command Details Format:
|
|
@@ -108,7 +108,7 @@ SUMMARY
|
|
|
108
108
|
{One-line description}
|
|
109
109
|
|
|
110
110
|
USAGE
|
|
111
|
-
/
|
|
111
|
+
/gsd-t-{command} [arguments]
|
|
112
112
|
|
|
113
113
|
WHEN TO USE
|
|
114
114
|
• {Use case 1}
|
|
@@ -131,8 +131,8 @@ FILES CREATED/UPDATED
|
|
|
131
131
|
• {file 2}
|
|
132
132
|
|
|
133
133
|
EXAMPLES
|
|
134
|
-
/
|
|
135
|
-
/
|
|
134
|
+
/gsd-t-{command}
|
|
135
|
+
/gsd-t-{command} "with argument"
|
|
136
136
|
|
|
137
137
|
RELATED COMMANDS
|
|
138
138
|
• {related 1} — {why related}
|
|
@@ -149,10 +149,10 @@ Use these when user asks for help on a specific command:
|
|
|
149
149
|
- **Summary**: Describe what you need in plain language — auto-routes to the right GSD-T command using semantic evaluation
|
|
150
150
|
- **Auto-invoked**: Yes — via UserPromptSubmit hook when prompt does not start with `/`
|
|
151
151
|
- **Files**: Reads `CLAUDE.md`, `.gsd-t/progress.md`, command summaries from `gsd-t-help`
|
|
152
|
-
- **How it works**: First checks if this is a continuation of an ongoing command (mid-task follow-up, status report, or acknowledgment) — if so, outputs `→ /gsd ──▶ continue /
|
|
152
|
+
- **How it works**: First checks if this is a continuation of an ongoing command (mid-task follow-up, status report, or acknowledgment) — if so, outputs `→ /gsd ──▶ continue /gsd-t-{last-command}` and resumes. For new requests, evaluates against every command's purpose and "Use when" criteria. Commands that match get shortlisted, best fit is selected. Shows runner-up when close.
|
|
153
153
|
- **Auto-route**: After `gsd-t install`, any plain text message (no leading `/`) is automatically routed through `/gsd`. Slash commands pass through unchanged. Binary detection — no heuristics.
|
|
154
154
|
- **Use when**: You don't want to remember which command to use — just describe what you want
|
|
155
|
-
- **Examples**: `/
|
|
155
|
+
- **Examples**: `/gsd Fix the login bug`, `/gsd Add dark mode`, `/gsd Scan for tech debt`
|
|
156
156
|
- **Auto-route examples**: `Fix the login bug` (no slash needed), `Add dark mode`, `Scan for tech debt`
|
|
157
157
|
|
|
158
158
|
### prd
|
|
@@ -228,7 +228,7 @@ Use these when user asks for help on a specific command:
|
|
|
228
228
|
- **Use when**: Ready to define specific implementation tasks
|
|
229
229
|
- **Note (M22)**: Tasks auto-split if estimated scope exceeds 70% context window — guarantees fresh dispatch works
|
|
230
230
|
- **Note (M26)**: Pre-mortem step now also reads rules.jsonl for historical failure patterns via getPreMortemRules
|
|
231
|
-
- **Note (M38)**: Conversational use cases (formerly `/
|
|
231
|
+
- **Note (M38)**: Conversational use cases (formerly `/gsd-t-prompt`, `/gsd-t-brainstorm`, `/gsd-t-discuss`) are now handled by the Smart Router's conversational mode — just describe what you want via `/gsd` or plain text.
|
|
232
232
|
|
|
233
233
|
### impact
|
|
234
234
|
- **Summary**: Analyze downstream effects of planned changes
|
|
@@ -433,7 +433,7 @@ Did you mean one of these?
|
|
|
433
433
|
• {closest match 1}
|
|
434
434
|
• {closest match 2}
|
|
435
435
|
|
|
436
|
-
Run /
|
|
436
|
+
Run /gsd-t-help for full command list.
|
|
437
437
|
```
|
|
438
438
|
|
|
439
439
|
$ARGUMENTS
|