@tekyzinc/gsd-t 3.29.10 → 4.0.12
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 +176 -0
- package/bin/gsd-t-parallel.cjs +64 -13
- package/bin/gsd-t-test-data-adapters/file-json-array.cjs +27 -3
- package/bin/gsd-t-test-data-adapters/localstorage-key-prefix.cjs +6 -1
- package/bin/gsd-t-test-data-adapters/sqlite-table-where.cjs +16 -1
- package/bin/gsd-t-test-data-ledger.cjs +1 -0
- package/bin/gsd-t.js +48 -376
- package/bin/journey-coverage.cjs +6 -3
- package/bin/parallel-cli.cjs +13 -1
- package/commands/gsd-t-debug.md +47 -533
- package/commands/gsd-t-design-decompose.md +24 -497
- package/commands/gsd-t-doc-ripple.md +23 -139
- package/commands/gsd-t-execute.md +41 -958
- package/commands/gsd-t-help.md +0 -2
- package/commands/gsd-t-impact.md +26 -295
- package/commands/gsd-t-integrate.md +44 -369
- package/commands/gsd-t-milestone.md +25 -124
- package/commands/gsd-t-partition.md +28 -539
- package/commands/gsd-t-plan.md +26 -472
- package/commands/gsd-t-prd.md +25 -311
- package/commands/gsd-t-quick.md +1 -1
- package/commands/gsd-t-resume.md +0 -33
- package/commands/gsd-t-verify.md +52 -569
- package/commands/gsd-t-wave.md +41 -430
- package/package.json +1 -1
- package/scripts/gsd-t-calibration-hook.js +3 -1
- package/scripts/hooks/pre-commit-journey-coverage +0 -2
- package/scripts/hooks/pre-commit-playwright-gate +0 -2
- package/templates/CLAUDE-global.md +43 -173
- package/templates/CLAUDE-project.md +118 -104
- package/templates/prompts/design-verify-subagent.md +3 -0
- package/templates/prompts/qa-subagent.md +3 -0
- package/templates/prompts/red-team-subagent.md +5 -2
- package/templates/workflows/_lib.js +176 -0
- package/templates/workflows/gsd-t-debug.workflow.js +86 -0
- package/templates/workflows/gsd-t-execute.workflow.js +206 -0
- package/templates/workflows/gsd-t-integrate.workflow.js +71 -0
- package/templates/workflows/gsd-t-phase.workflow.js +94 -0
- package/templates/workflows/gsd-t-quick.workflow.js +72 -0
- package/templates/workflows/gsd-t-verify.workflow.js +348 -0
- package/templates/workflows/gsd-t-wave.workflow.js +43 -0
- package/bin/check-headless-sessions.js +0 -140
- package/bin/context-budget-audit.cjs +0 -447
- package/bin/context-meter-config.cjs +0 -101
- package/bin/context-meter-config.test.cjs +0 -101
- package/bin/event-stream.cjs +0 -205
- package/bin/gsd-t-benchmark-orchestrator.js +0 -437
- package/bin/gsd-t-capture-lint.cjs +0 -440
- package/bin/gsd-t-economics.cjs +0 -315
- package/bin/gsd-t-in-session-usage.cjs +0 -213
- package/bin/gsd-t-orchestrator-config.cjs +0 -161
- package/bin/gsd-t-orchestrator-queue.cjs +0 -180
- package/bin/gsd-t-orchestrator-recover.cjs +0 -231
- package/bin/gsd-t-orchestrator-worker.cjs +0 -219
- package/bin/gsd-t-orchestrator.js +0 -535
- package/bin/gsd-t-parallel-probe.cjs +0 -132
- package/bin/gsd-t-ratelimit-probe-worker.cjs +0 -237
- package/bin/gsd-t-ratelimit-probe.cjs +0 -648
- package/bin/gsd-t-report-tokens.cjs +0 -549
- package/bin/gsd-t-stream-feed-client.cjs +0 -151
- package/bin/gsd-t-token-backfill.cjs +0 -366
- package/bin/gsd-t-token-capture.cjs +0 -321
- package/bin/gsd-t-token-dashboard.cjs +0 -353
- package/bin/gsd-t-token-regenerate-log.cjs +0 -129
- package/bin/gsd-t-tool-attribution.cjs +0 -377
- package/bin/gsd-t-tool-cost.cjs +0 -195
- package/bin/gsd-t-transcript-tee.cjs +0 -246
- package/bin/gsd-t-unattended-heartbeat.cjs +0 -188
- package/bin/gsd-t-unattended-platform.cjs +0 -551
- package/bin/gsd-t-unattended-platform.js +0 -381
- package/bin/gsd-t-unattended-safety.cjs +0 -773
- package/bin/gsd-t-unattended-safety.js +0 -788
- package/bin/gsd-t-unattended.cjs +0 -2109
- package/bin/gsd-t-unattended.js +0 -1367
- package/bin/gsd-t-worker-dispatch.cjs +0 -211
- package/bin/handoff-lock.cjs +0 -249
- package/bin/handoff-lock.js +0 -249
- package/bin/headless-auto-spawn.cjs +0 -711
- package/bin/headless-auto-spawn.js +0 -373
- package/bin/headless-exit-codes.cjs +0 -67
- package/bin/live-activity-report.cjs +0 -615
- package/bin/log-tail.cjs +0 -81
- package/bin/m44-proof-measure.cjs +0 -285
- package/bin/m46-iter-proof.cjs +0 -149
- package/bin/m46-worker-proof.cjs +0 -201
- package/bin/m55-substrate-proof.cjs +0 -134
- package/bin/metrics-rollup.js +0 -200
- package/bin/model-windows.cjs +0 -99
- package/bin/model-windows.test.cjs +0 -75
- package/bin/parallelism-report.cjs +0 -535
- package/bin/runway-estimator.cjs +0 -242
- package/bin/spawn-plan-derive.cjs +0 -163
- package/bin/spawn-plan-status-updater.cjs +0 -292
- package/bin/spawn-plan-writer.cjs +0 -204
- package/bin/supervisor-pid-fingerprint.cjs +0 -126
- package/bin/token-budget.cjs +0 -265
- package/bin/unattended-watch-format.cjs +0 -178
- package/bin/watch-progress.js +0 -155
- package/commands/gsd-t-unattended-stop.md +0 -85
- package/commands/gsd-t-unattended-watch.md +0 -465
- package/commands/gsd-t-unattended.md +0 -476
- package/commands/gsd-t-visualize.md +0 -116
- package/scripts/gsd-t-context-meter.e2e.test.js +0 -364
- package/scripts/gsd-t-context-meter.js +0 -341
- package/scripts/gsd-t-context-meter.test.js +0 -471
- package/scripts/gsd-t-dashboard-server.js +0 -1203
- package/scripts/gsd-t-post-commit-spawn-plan.sh +0 -86
- package/scripts/gsd-t-transcript.html +0 -1821
- package/scripts/hooks/gsd-t-conversation-capture.js +0 -439
- package/scripts/hooks/gsd-t-in-session-usage-hook.js +0 -84
- package/scripts/spawn-plan-fmt-tokens.cjs +0 -80
- package/templates/hooks/post-commit-spawn-plan.sh +0 -85
package/bin/gsd-t.js
CHANGED
|
@@ -34,12 +34,6 @@ try {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// Shared headless exit-code helper — lives in its own file so non-entry
|
|
38
|
-
// modules (e.g. bin/gsd-t-unattended.cjs) can require it without pulling
|
|
39
|
-
// in the full CLI. See commentary near the original declaration site and
|
|
40
|
-
// in headless-exit-codes.cjs itself.
|
|
41
|
-
const { mapHeadlessExitCode } = require(path.join(__dirname, "headless-exit-codes.cjs"));
|
|
42
|
-
|
|
43
37
|
// ─── Configuration ───────────────────────────────────────────────────────────
|
|
44
38
|
|
|
45
39
|
const CLAUDE_DIR = path.join(os.homedir(), ".claude");
|
|
@@ -1152,7 +1146,7 @@ function configureFigmaMcp() {
|
|
|
1152
1146
|
|
|
1153
1147
|
// ─── Utility Scripts ─────────────────────────────────────────────────────────
|
|
1154
1148
|
|
|
1155
|
-
const UTILITY_SCRIPTS = ["gsd-t-tools.js", "gsd-t-statusline.js", "gsd-t-event-writer.js"
|
|
1149
|
+
const UTILITY_SCRIPTS = ["gsd-t-tools.js", "gsd-t-statusline.js", "gsd-t-event-writer.js"];
|
|
1156
1150
|
|
|
1157
1151
|
function installUtilityScripts() {
|
|
1158
1152
|
ensureDir(SCRIPTS_DIR);
|
|
@@ -1760,17 +1754,11 @@ async function doInit(projectName) {
|
|
|
1760
1754
|
initGsdtDir(projectDir, projectName, today);
|
|
1761
1755
|
copyBinToolsToProject(projectDir, projectName);
|
|
1762
1756
|
|
|
1763
|
-
//
|
|
1764
|
-
//
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
const cmHook = configureContextMeterHooks(SETTINGS_JSON);
|
|
1769
|
-
if (cmHook.installed) {
|
|
1770
|
-
if (cmHook.action === "added") success("Context meter PostToolUse hook added");
|
|
1771
|
-
else if (cmHook.action === "updated") success("Context meter hook command refreshed");
|
|
1772
|
-
else info("Context meter hook already configured");
|
|
1773
|
-
}
|
|
1757
|
+
// M61 D1: Context Meter retired (token-budget.cjs + scripts/gsd-t-context-meter.js
|
|
1758
|
+
// deleted). Native /context replaces it. No longer provisioned at install —
|
|
1759
|
+
// installContextMeter / configureContextMeterHooks would register a PostToolUse
|
|
1760
|
+
// hook pointing at a deleted script. Both functions remain defined but unused
|
|
1761
|
+
// (cleaned in M65 follow-up).
|
|
1774
1762
|
|
|
1775
1763
|
if (registerProject(projectDir)) success("Registered in ~/.claude/.gsd-t-projects");
|
|
1776
1764
|
|
|
@@ -2474,12 +2462,7 @@ function updateSingleProject(projectDir, counts) {
|
|
|
2474
2462
|
// a new tool only requires appending to this array. Use .cjs extension so they
|
|
2475
2463
|
// always run as CommonJS regardless of the project's package.json "type" field.
|
|
2476
2464
|
const PROJECT_BIN_TOOLS = [
|
|
2477
|
-
"archive-progress.cjs",
|
|
2478
|
-
"context-meter-config.cjs", "token-budget.cjs",
|
|
2479
|
-
"gsd-t-token-capture.cjs",
|
|
2480
|
-
"gsd-t-unattended.cjs", "gsd-t-unattended-platform.cjs", "gsd-t-unattended-safety.cjs",
|
|
2481
|
-
"handoff-lock.cjs", "headless-auto-spawn.cjs",
|
|
2482
|
-
"headless-exit-codes.cjs",
|
|
2465
|
+
"archive-progress.cjs",
|
|
2483
2466
|
// M55 — preflight + parallel-cli + brief + verify-gate libraries copied to project bin/
|
|
2484
2467
|
// so per-project workflows can `require('./bin/cli-preflight.cjs')` etc. without
|
|
2485
2468
|
// depending on the globally-installed gsd-t CLI being on PATH.
|
|
@@ -3147,7 +3130,11 @@ async function doDoctor(opts) {
|
|
|
3147
3130
|
issues += checkDoctorInstallation();
|
|
3148
3131
|
issues += await checkDoctorProject(opts);
|
|
3149
3132
|
issues += checkDoctorCgc();
|
|
3150
|
-
|
|
3133
|
+
// M61 D1: Context Meter retired (token-budget.cjs + context-meter hook deleted).
|
|
3134
|
+
// checkDoctorContextMeter would emit phantom errors for the deleted subsystem
|
|
3135
|
+
// and tell the user to reinstall it. Native /context replaces the meter.
|
|
3136
|
+
// M61 D4: dashboard orphan check left for the deleted dashboard-server is also
|
|
3137
|
+
// dead, but harmless (ps string-match, no require) — deferred.
|
|
3151
3138
|
issues += checkDoctorDashboardOrphans(opts);
|
|
3152
3139
|
// M50 D2: opt-in install of the playwright-gate pre-commit hook.
|
|
3153
3140
|
if (opts && opts.installHooks) {
|
|
@@ -3508,11 +3495,43 @@ function buildHeadlessCmd(command, cmdArgs) {
|
|
|
3508
3495
|
* Map claude output + process exit code to a GSD-T headless exit code.
|
|
3509
3496
|
* Exit codes: 0=success, 1=verify-fail, 2=context-budget-exceeded, 3=error,
|
|
3510
3497
|
* 4=blocked-needs-human, 5=command-dispatch-failed
|
|
3498
|
+
*
|
|
3499
|
+
* Inlined from the former bin/headless-exit-codes.cjs (M65) — that file existed
|
|
3500
|
+
* to decouple the exit-code map from the CLI so the unattended supervisor could
|
|
3501
|
+
* require it without pulling in gsd-t.js. The supervisor was retired in M61 D2,
|
|
3502
|
+
* so the only remaining requirer is this file; the helper now lives inline.
|
|
3503
|
+
*
|
|
3504
|
+
* Match terminal markers, not narration. A bare "tests failed" substring
|
|
3505
|
+
* appears in healthy output ("0 tests failed", "no tests failed", quoted in
|
|
3506
|
+
* prose). Require a non-zero count prefix or a structured terminal marker.
|
|
3507
|
+
* Bug history: M45 worker output contained "tests failed" 6× in narration,
|
|
3508
|
+
* mapping exit 0 → 1 and halting a successful run — keep these regexes anchored.
|
|
3511
3509
|
*/
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3510
|
+
const HEADLESS_NONZERO_FAILURE_COUNT_RE =
|
|
3511
|
+
/(?:^|\b)([1-9]\d*)\s+(?:tests?|specs?|assertions?|examples?|suites?)\s+failed\b/i;
|
|
3512
|
+
const HEADLESS_STRUCTURED_FAIL_RE = /^FAIL[:\s]/m;
|
|
3513
|
+
const HEADLESS_JEST_SUMMARY_FAIL_RE = /^Tests:\s+\d+\s+failed/im;
|
|
3514
|
+
const HEADLESS_VERIFICATION_FAILED_RE =
|
|
3515
|
+
/(?:^|[.!?]\s+)(?:verification|verify|quality gate)\s+failed\b/im;
|
|
3516
|
+
const HEADLESS_CONTEXT_BUDGET_RE =
|
|
3517
|
+
/(?:^|[.!?]\s+)(?:context budget exceeded|context window exceeded|budget exceeded|token limit)\b/im;
|
|
3518
|
+
const HEADLESS_BLOCKED_HUMAN_RE =
|
|
3519
|
+
/\bblocked\b[\s\S]{0,80}?\b(?:needs? human|human input|human approval)\b/i;
|
|
3520
|
+
|
|
3521
|
+
function mapHeadlessExitCode(processExitCode, output) {
|
|
3522
|
+
if (processExitCode !== 0 && processExitCode !== null) return 3;
|
|
3523
|
+
const raw = output || "";
|
|
3524
|
+
if (/^unknown command:/im.test(raw)) return 5;
|
|
3525
|
+
if (HEADLESS_CONTEXT_BUDGET_RE.test(raw)) return 2;
|
|
3526
|
+
if (HEADLESS_BLOCKED_HUMAN_RE.test(raw)) return 4;
|
|
3527
|
+
if (
|
|
3528
|
+
HEADLESS_VERIFICATION_FAILED_RE.test(raw) ||
|
|
3529
|
+
HEADLESS_NONZERO_FAILURE_COUNT_RE.test(raw) ||
|
|
3530
|
+
HEADLESS_STRUCTURED_FAIL_RE.test(raw) ||
|
|
3531
|
+
HEADLESS_JEST_SUMMARY_FAIL_RE.test(raw)
|
|
3532
|
+
) return 1;
|
|
3533
|
+
return 0;
|
|
3534
|
+
}
|
|
3516
3535
|
|
|
3517
3536
|
/**
|
|
3518
3537
|
* Generate a headless log file path.
|
|
@@ -4151,121 +4170,6 @@ function doMetrics(_args) {
|
|
|
4151
4170
|
log(`${DIM}metrics removed in v3.12 — context meter is no longer telemetry-instrumented${RESET}`);
|
|
4152
4171
|
}
|
|
4153
4172
|
|
|
4154
|
-
function doStreamFeed(args) {
|
|
4155
|
-
const sub = args[0];
|
|
4156
|
-
const projectDir = process.cwd();
|
|
4157
|
-
const pidFile = path.join(projectDir, ".gsd-t", "stream-feed", ".server.pid");
|
|
4158
|
-
const portFile = path.join(projectDir, ".gsd-t", "stream-feed", ".server.port");
|
|
4159
|
-
|
|
4160
|
-
function readPid() {
|
|
4161
|
-
try { return parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10); }
|
|
4162
|
-
catch { return null; }
|
|
4163
|
-
}
|
|
4164
|
-
function readPort() {
|
|
4165
|
-
try { return parseInt(fs.readFileSync(portFile, "utf8").trim(), 10); }
|
|
4166
|
-
catch { return null; }
|
|
4167
|
-
}
|
|
4168
|
-
function isAlive(pid) {
|
|
4169
|
-
if (!pid) return false;
|
|
4170
|
-
try { process.kill(pid, 0); return true; } catch { return false; }
|
|
4171
|
-
}
|
|
4172
|
-
|
|
4173
|
-
if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
|
|
4174
|
-
log(`\n${BOLD}gsd-t stream-feed${RESET} — Localhost stream-json watcher (M40 D4)\n`);
|
|
4175
|
-
log(`${BOLD}Usage:${RESET}`);
|
|
4176
|
-
log(` gsd-t stream-feed ${CYAN}start${RESET} [--port N]`);
|
|
4177
|
-
log(` gsd-t stream-feed ${CYAN}status${RESET}`);
|
|
4178
|
-
log(` gsd-t stream-feed ${CYAN}stop${RESET}`);
|
|
4179
|
-
log(`\nDefault port: 7842. Env override: GSD_T_STREAM_FEED_PORT.`);
|
|
4180
|
-
return;
|
|
4181
|
-
}
|
|
4182
|
-
|
|
4183
|
-
if (sub === "start") {
|
|
4184
|
-
const existing = readPid();
|
|
4185
|
-
if (isAlive(existing)) {
|
|
4186
|
-
log(`${YELLOW}stream-feed-server already running${RESET} (pid ${existing}, port ${readPort() || "?"})`);
|
|
4187
|
-
return;
|
|
4188
|
-
}
|
|
4189
|
-
let port = null;
|
|
4190
|
-
for (let i = 1; i < args.length; i++) {
|
|
4191
|
-
if (args[i] === "--port") port = Number(args[++i]);
|
|
4192
|
-
}
|
|
4193
|
-
const { spawn } = require("child_process");
|
|
4194
|
-
const serverScript = path.join(__dirname, "..", "scripts", "gsd-t-stream-feed-server.js");
|
|
4195
|
-
const forward = ["--project-dir", projectDir];
|
|
4196
|
-
if (port) forward.push("--port", String(port));
|
|
4197
|
-
const feedDir = path.join(projectDir, ".gsd-t", "stream-feed");
|
|
4198
|
-
try { fs.mkdirSync(feedDir, { recursive: true }); } catch { /* exists */ }
|
|
4199
|
-
const out = fs.openSync(path.join(feedDir, "server.log"), "a");
|
|
4200
|
-
const err = fs.openSync(path.join(feedDir, "server.log"), "a");
|
|
4201
|
-
const child = spawn(process.execPath, [serverScript, ...forward], {
|
|
4202
|
-
detached: true, stdio: ["ignore", out, err], cwd: projectDir,
|
|
4203
|
-
});
|
|
4204
|
-
child.unref();
|
|
4205
|
-
try { fs.writeFileSync(pidFile, String(child.pid)); } catch { /* noop */ }
|
|
4206
|
-
try { fs.writeFileSync(portFile, String(port || process.env.GSD_T_STREAM_FEED_PORT || 7842)); } catch { /* noop */ }
|
|
4207
|
-
log(`${GREEN}✓${RESET} stream-feed-server started (pid ${child.pid}, port ${port || 7842})`);
|
|
4208
|
-
log(` log: .gsd-t/stream-feed/server.log`);
|
|
4209
|
-
return;
|
|
4210
|
-
}
|
|
4211
|
-
|
|
4212
|
-
if (sub === "status") {
|
|
4213
|
-
const pid = readPid();
|
|
4214
|
-
const port = readPort();
|
|
4215
|
-
if (!isAlive(pid)) {
|
|
4216
|
-
log(`${DIM}stream-feed-server not running${RESET}`);
|
|
4217
|
-
return;
|
|
4218
|
-
}
|
|
4219
|
-
log(`${GREEN}●${RESET} stream-feed-server running`);
|
|
4220
|
-
log(` pid: ${pid}`);
|
|
4221
|
-
log(` port: ${port || 7842}`);
|
|
4222
|
-
// Try to fetch live stats
|
|
4223
|
-
try {
|
|
4224
|
-
const http = require("http");
|
|
4225
|
-
const done = { v: false };
|
|
4226
|
-
const req = http.get({ host: "127.0.0.1", port: port || 7842, path: "/status", timeout: 1000 }, (res) => {
|
|
4227
|
-
let body = "";
|
|
4228
|
-
res.on("data", (c) => body += c);
|
|
4229
|
-
res.on("end", () => {
|
|
4230
|
-
try {
|
|
4231
|
-
const j = JSON.parse(body);
|
|
4232
|
-
log(` frames today: ${j.framesToday}`);
|
|
4233
|
-
log(` clients: ${j.clients}`);
|
|
4234
|
-
log(` stats: ingested=${j.stats.framesIngested} broadcast=${j.stats.framesBroadcast} kicked=${j.stats.kicked}`);
|
|
4235
|
-
} catch { /* noop */ }
|
|
4236
|
-
done.v = true;
|
|
4237
|
-
});
|
|
4238
|
-
});
|
|
4239
|
-
req.on("error", () => { done.v = true; });
|
|
4240
|
-
req.on("timeout", () => { req.destroy(); done.v = true; });
|
|
4241
|
-
} catch { /* noop */ }
|
|
4242
|
-
return;
|
|
4243
|
-
}
|
|
4244
|
-
|
|
4245
|
-
if (sub === "stop") {
|
|
4246
|
-
const pid = readPid();
|
|
4247
|
-
if (!isAlive(pid)) {
|
|
4248
|
-
log(`${DIM}stream-feed-server not running${RESET}`);
|
|
4249
|
-
try { fs.unlinkSync(pidFile); } catch { /* noop */ }
|
|
4250
|
-
try { fs.unlinkSync(portFile); } catch { /* noop */ }
|
|
4251
|
-
return;
|
|
4252
|
-
}
|
|
4253
|
-
try { process.kill(pid, "SIGTERM"); } catch { /* noop */ }
|
|
4254
|
-
log(`${GREEN}✓${RESET} stream-feed-server stopped (pid ${pid})`);
|
|
4255
|
-
// Clean up stale PID files after a short wait
|
|
4256
|
-
setTimeout(() => {
|
|
4257
|
-
if (!isAlive(pid)) {
|
|
4258
|
-
try { fs.unlinkSync(pidFile); } catch { /* noop */ }
|
|
4259
|
-
try { fs.unlinkSync(portFile); } catch { /* noop */ }
|
|
4260
|
-
}
|
|
4261
|
-
}, 500);
|
|
4262
|
-
return;
|
|
4263
|
-
}
|
|
4264
|
-
|
|
4265
|
-
error(`Unknown stream-feed subcommand: ${sub}`);
|
|
4266
|
-
log(`Try: gsd-t stream-feed --help`);
|
|
4267
|
-
process.exit(1);
|
|
4268
|
-
}
|
|
4269
4173
|
|
|
4270
4174
|
function showHelp() {
|
|
4271
4175
|
log(`\n${BOLD}GSD-T${RESET} — Contract-Driven Development for Claude Code\n`);
|
|
@@ -4282,12 +4186,7 @@ function showHelp() {
|
|
|
4282
4186
|
log(` ${CYAN}changelog${RESET} Open changelog in the browser`);
|
|
4283
4187
|
log(` ${CYAN}graph${RESET} Code graph operations (index, status, query)`);
|
|
4284
4188
|
log(` ${CYAN}headless${RESET} Non-interactive execution via claude -p + fast state queries`);
|
|
4285
|
-
log(` ${CYAN}orchestrate${RESET} External task orchestrator — one claude -p spawn per task (M40)`);
|
|
4286
|
-
log(` ${CYAN}benchmark-orchestrator${RESET} M40 speed gate — compares orchestrator vs in-session wall-clock`);
|
|
4287
|
-
log(` ${CYAN}stream-feed${RESET} Localhost stream-json watcher (start|status|stop) — M40 D4`);
|
|
4288
4189
|
log(` ${CYAN}design-build${RESET} Deterministic design→code pipeline (elements → widgets → pages)`);
|
|
4289
|
-
log(` ${CYAN}tool-cost${RESET} Per-tool token/cost attribution (M43 D2) — group-by tool|command|domain`);
|
|
4290
|
-
log(` ${CYAN}report tokens${RESET} Generate token-usage optimization report (Run → Iter → CW → Turn → Tool)`);
|
|
4291
4190
|
log(` ${CYAN}help${RESET} Show this help\n`);
|
|
4292
4191
|
log(`${BOLD}Examples:${RESET}`);
|
|
4293
4192
|
log(` ${DIM}$${RESET} npx @tekyzinc/gsd-t install`);
|
|
@@ -4495,22 +4394,6 @@ if (require.main === module) {
|
|
|
4495
4394
|
case "headless":
|
|
4496
4395
|
doHeadless(args.slice(1));
|
|
4497
4396
|
break;
|
|
4498
|
-
case "unattended": {
|
|
4499
|
-
const { spawnSync } = require("child_process");
|
|
4500
|
-
const cjs = path.join(__dirname, "gsd-t-unattended.cjs");
|
|
4501
|
-
const res = spawnSync(process.execPath, [cjs, ...args.slice(1)], {
|
|
4502
|
-
stdio: "inherit",
|
|
4503
|
-
});
|
|
4504
|
-
process.exit(res.status == null ? 1 : res.status);
|
|
4505
|
-
}
|
|
4506
|
-
case "orchestrate": {
|
|
4507
|
-
const { spawnSync } = require("child_process");
|
|
4508
|
-
const js = path.join(__dirname, "gsd-t-orchestrator.js");
|
|
4509
|
-
const res = spawnSync(process.execPath, [js, ...args.slice(1)], {
|
|
4510
|
-
stdio: "inherit",
|
|
4511
|
-
});
|
|
4512
|
-
process.exit(res.status == null ? 1 : res.status);
|
|
4513
|
-
}
|
|
4514
4397
|
case "parallel": {
|
|
4515
4398
|
// M44 D2 — `gsd-t parallel` wraps M40 orchestrator with task-level
|
|
4516
4399
|
// parallelism + mode-aware gating math. Extends, does not replace.
|
|
@@ -4518,14 +4401,6 @@ if (require.main === module) {
|
|
|
4518
4401
|
const code = runParallelCli(args.slice(1), process.env);
|
|
4519
4402
|
process.exit(code);
|
|
4520
4403
|
}
|
|
4521
|
-
case "benchmark-orchestrator": {
|
|
4522
|
-
const { spawnSync } = require("child_process");
|
|
4523
|
-
const js = path.join(__dirname, "gsd-t-benchmark-orchestrator.js");
|
|
4524
|
-
const res = spawnSync(process.execPath, [js, ...args.slice(1)], {
|
|
4525
|
-
stdio: "inherit",
|
|
4526
|
-
});
|
|
4527
|
-
process.exit(res.status == null ? 1 : res.status);
|
|
4528
|
-
}
|
|
4529
4404
|
case "preflight": {
|
|
4530
4405
|
// M55 D5 — `gsd-t preflight` thin dispatcher to bin/cli-preflight.cjs.
|
|
4531
4406
|
const { spawnSync } = require("child_process");
|
|
@@ -4589,212 +4464,9 @@ if (require.main === module) {
|
|
|
4589
4464
|
});
|
|
4590
4465
|
process.exit(res.status == null ? 1 : res.status);
|
|
4591
4466
|
}
|
|
4592
|
-
case "stream-feed": {
|
|
4593
|
-
doStreamFeed(args.slice(1));
|
|
4594
|
-
break;
|
|
4595
|
-
}
|
|
4596
4467
|
case "metrics":
|
|
4597
4468
|
doMetrics(args.slice(1));
|
|
4598
4469
|
break;
|
|
4599
|
-
case "backfill-tokens": {
|
|
4600
|
-
const bfOpts = { projectDir: process.cwd(), since: null, patchLog: false, dryRun: false };
|
|
4601
|
-
for (let i = 1; i < args.length; i++) {
|
|
4602
|
-
const a = args[i];
|
|
4603
|
-
if (a === '--since' && args[i+1]) { bfOpts.since = args[++i]; }
|
|
4604
|
-
else if (a.startsWith('--since=')) { bfOpts.since = a.slice(8); }
|
|
4605
|
-
else if (a === '--patch-log') { bfOpts.patchLog = true; }
|
|
4606
|
-
else if (a === '--dry-run') { bfOpts.dryRun = true; }
|
|
4607
|
-
else if (a === '--project-dir' && args[i+1]) { bfOpts.projectDir = args[++i]; }
|
|
4608
|
-
else if (a.startsWith('--project-dir=')) { bfOpts.projectDir = a.slice(14); }
|
|
4609
|
-
else if (a === '--help' || a === '-h') {
|
|
4610
|
-
log('Usage: gsd-t backfill-tokens [--since YYYY-MM-DD] [--patch-log] [--dry-run] [--project-dir PATH]');
|
|
4611
|
-
process.exit(0);
|
|
4612
|
-
}
|
|
4613
|
-
else {
|
|
4614
|
-
error(`backfill-tokens: unknown arg: ${a}`);
|
|
4615
|
-
process.exit(2);
|
|
4616
|
-
}
|
|
4617
|
-
}
|
|
4618
|
-
const backfill = require(path.join(__dirname, 'gsd-t-token-backfill.cjs'));
|
|
4619
|
-
backfill.main(bfOpts)
|
|
4620
|
-
.then(({ exitCode }) => process.exit(exitCode || 0))
|
|
4621
|
-
.catch((e) => { error(e.message || String(e)); process.exit(3); });
|
|
4622
|
-
break;
|
|
4623
|
-
}
|
|
4624
|
-
case "capture-lint": {
|
|
4625
|
-
const clOpts = { projectDir: process.cwd(), mode: 'staged' };
|
|
4626
|
-
let checkStreamJson = false;
|
|
4627
|
-
for (let i = 1; i < args.length; i++) {
|
|
4628
|
-
const a = args[i];
|
|
4629
|
-
if (a === '--staged') { clOpts.mode = 'staged'; }
|
|
4630
|
-
else if (a === '--all') { clOpts.mode = 'all'; }
|
|
4631
|
-
else if (a === '--check-stream-json') { checkStreamJson = true; }
|
|
4632
|
-
else if (a === '--project-dir' && args[i+1]) { clOpts.projectDir = args[++i]; }
|
|
4633
|
-
else if (a.startsWith('--project-dir=')) { clOpts.projectDir = a.slice(14); }
|
|
4634
|
-
else if (a === '--help' || a === '-h') {
|
|
4635
|
-
log('Usage: gsd-t capture-lint [--staged] [--all] [--check-stream-json] [--project-dir PATH]');
|
|
4636
|
-
log('');
|
|
4637
|
-
log('Default mode (M41 D5): rejects bare Task() / claude -p / spawn() calls');
|
|
4638
|
-
log(' missing the captureSpawn / recordSpawnRow wrapper.');
|
|
4639
|
-
log('');
|
|
4640
|
-
log('--check-stream-json (M56 D5): rejects claude -p / spawn(claude, ...) invocations');
|
|
4641
|
-
log(' missing --output-format stream-json --verbose flag pair.');
|
|
4642
|
-
log(' Allowlist via marker comment: GSD-T-LINT: skip stream-json (reason: …)');
|
|
4643
|
-
process.exit(0);
|
|
4644
|
-
}
|
|
4645
|
-
else {
|
|
4646
|
-
error(`capture-lint: unknown arg: ${a}`);
|
|
4647
|
-
process.exit(2);
|
|
4648
|
-
}
|
|
4649
|
-
}
|
|
4650
|
-
try {
|
|
4651
|
-
const linter = require(path.join(__dirname, 'gsd-t-capture-lint.cjs'));
|
|
4652
|
-
const res = checkStreamJson ? linter.mainStreamJson(clOpts) : linter.main(clOpts);
|
|
4653
|
-
if (res.error) {
|
|
4654
|
-
error(`capture-lint: ${res.error}`);
|
|
4655
|
-
process.exit(2);
|
|
4656
|
-
}
|
|
4657
|
-
for (const v of res.violations) {
|
|
4658
|
-
log(`${v.file}:${v.line}: ${v.message}`);
|
|
4659
|
-
}
|
|
4660
|
-
const modeLabel = checkStreamJson ? 'stream-json' : 'capture';
|
|
4661
|
-
if (res.violations.length === 0) {
|
|
4662
|
-
log(`${modeLabel}-lint: ${res.files.length} file(s) checked — clean`);
|
|
4663
|
-
} else {
|
|
4664
|
-
log(`${modeLabel}-lint: ${res.violations.length} violation(s) across ${res.files.length} file(s)`);
|
|
4665
|
-
}
|
|
4666
|
-
process.exit(res.exitCode);
|
|
4667
|
-
} catch (e) {
|
|
4668
|
-
error(e.message || String(e));
|
|
4669
|
-
process.exit(2);
|
|
4670
|
-
}
|
|
4671
|
-
break;
|
|
4672
|
-
}
|
|
4673
|
-
case "tokens": {
|
|
4674
|
-
const tkOpts = { projectDir: process.cwd(), since: null, milestone: null, format: 'table', regenerateLog: false, showToolCosts: false };
|
|
4675
|
-
for (let i = 1; i < args.length; i++) {
|
|
4676
|
-
const a = args[i];
|
|
4677
|
-
if (a === '--since' && args[i+1]) { tkOpts.since = args[++i]; }
|
|
4678
|
-
else if (a.startsWith('--since=')) { tkOpts.since = a.slice(8); }
|
|
4679
|
-
else if (a === '--milestone' && args[i+1]) { tkOpts.milestone = args[++i]; }
|
|
4680
|
-
else if (a.startsWith('--milestone=')) { tkOpts.milestone = a.slice(12); }
|
|
4681
|
-
else if (a === '--format' && args[i+1]) { tkOpts.format = args[++i]; }
|
|
4682
|
-
else if (a.startsWith('--format=')) { tkOpts.format = a.slice(9); }
|
|
4683
|
-
else if (a === '--project-dir' && args[i+1]) { tkOpts.projectDir = args[++i]; }
|
|
4684
|
-
else if (a.startsWith('--project-dir=')) { tkOpts.projectDir = a.slice(14); }
|
|
4685
|
-
else if (a === '--regenerate-log') { tkOpts.regenerateLog = true; }
|
|
4686
|
-
else if (a === '--show-tool-costs') { tkOpts.showToolCosts = true; }
|
|
4687
|
-
else if (a === '--help' || a === '-h') {
|
|
4688
|
-
log('Usage: gsd-t tokens [--since YYYY-MM-DD] [--milestone Mxx] [--format table|json] [--show-tool-costs]');
|
|
4689
|
-
log(' gsd-t tokens --regenerate-log (rewrite .gsd-t/token-log.md from token-usage.jsonl)');
|
|
4690
|
-
process.exit(0);
|
|
4691
|
-
}
|
|
4692
|
-
else {
|
|
4693
|
-
error(`tokens: unknown arg: ${a}`);
|
|
4694
|
-
process.exit(2);
|
|
4695
|
-
}
|
|
4696
|
-
}
|
|
4697
|
-
if (tkOpts.regenerateLog) {
|
|
4698
|
-
try {
|
|
4699
|
-
const regen = require(path.join(__dirname, 'gsd-t-token-regenerate-log.cjs'));
|
|
4700
|
-
const res = regen.regenerateLog({ projectDir: tkOpts.projectDir });
|
|
4701
|
-
log(`Regenerated ${res.wrote} (${res.rowCount} row${res.rowCount === 1 ? '' : 's'})`);
|
|
4702
|
-
process.exit(0);
|
|
4703
|
-
} catch (e) {
|
|
4704
|
-
error(e.message || String(e));
|
|
4705
|
-
process.exit(3);
|
|
4706
|
-
}
|
|
4707
|
-
break;
|
|
4708
|
-
}
|
|
4709
|
-
if (tkOpts.format !== 'table' && tkOpts.format !== 'json') {
|
|
4710
|
-
error(`tokens: --format must be 'table' or 'json' (got: ${tkOpts.format})`);
|
|
4711
|
-
process.exit(2);
|
|
4712
|
-
}
|
|
4713
|
-
const dashboard = require(path.join(__dirname, 'gsd-t-token-dashboard.cjs'));
|
|
4714
|
-
dashboard.aggregate(tkOpts)
|
|
4715
|
-
.then((agg) => {
|
|
4716
|
-
const baseOut = tkOpts.format === 'json' ? dashboard.renderJson(agg) : dashboard.renderTable(agg);
|
|
4717
|
-
let out = baseOut;
|
|
4718
|
-
if (tkOpts.showToolCosts) {
|
|
4719
|
-
try {
|
|
4720
|
-
out = out + '\n' + dashboard.renderToolCostsSection({
|
|
4721
|
-
projectDir: tkOpts.projectDir,
|
|
4722
|
-
since: tkOpts.since,
|
|
4723
|
-
milestone: tkOpts.milestone,
|
|
4724
|
-
format: tkOpts.format,
|
|
4725
|
-
});
|
|
4726
|
-
} catch (e) {
|
|
4727
|
-
// Non-fatal: tool-cost section failure doesn't break primary output.
|
|
4728
|
-
out = out + '\n── Top 10 tools by cost ──\n (tool-cost section unavailable: ' + (e.message || String(e)) + ')';
|
|
4729
|
-
}
|
|
4730
|
-
}
|
|
4731
|
-
log(out);
|
|
4732
|
-
process.exit(0);
|
|
4733
|
-
})
|
|
4734
|
-
.catch((e) => { error(e.message || String(e)); process.exit(3); });
|
|
4735
|
-
break;
|
|
4736
|
-
}
|
|
4737
|
-
case "design-build": {
|
|
4738
|
-
const orchestrator = require("./design-orchestrator.js");
|
|
4739
|
-
orchestrator.run(args.slice(1)).catch(e => { console.error(e); process.exit(1); });
|
|
4740
|
-
break;
|
|
4741
|
-
}
|
|
4742
|
-
case "tool-cost": {
|
|
4743
|
-
const toolCost = require(path.join(__dirname, 'gsd-t-tool-cost.cjs'));
|
|
4744
|
-
process.exit(toolCost.run(args.slice(1)));
|
|
4745
|
-
break;
|
|
4746
|
-
}
|
|
4747
|
-
case "report": {
|
|
4748
|
-
// Nested dispatch: `gsd-t report tokens [--date YYYY-MM-DD] [--out PATH]`
|
|
4749
|
-
const sub = args[1];
|
|
4750
|
-
if (!sub || sub === '--help' || sub === '-h') {
|
|
4751
|
-
log('Usage: gsd-t report tokens [--date YYYY-MM-DD] [--out PATH]');
|
|
4752
|
-
log('');
|
|
4753
|
-
log('Subcommands:');
|
|
4754
|
-
log(' tokens Generate token-usage optimization report (Run → Iter → CW → Turn → Tool).');
|
|
4755
|
-
process.exit(sub ? 0 : 2);
|
|
4756
|
-
break;
|
|
4757
|
-
}
|
|
4758
|
-
if (sub !== 'tokens') {
|
|
4759
|
-
error(`report: unknown subcommand: ${sub}`);
|
|
4760
|
-
log('Usage: gsd-t report tokens [--date YYYY-MM-DD] [--out PATH]');
|
|
4761
|
-
process.exit(2);
|
|
4762
|
-
break;
|
|
4763
|
-
}
|
|
4764
|
-
const rOpts = { projectDir: process.cwd(), date: null, outPath: null };
|
|
4765
|
-
for (let i = 2; i < args.length; i++) {
|
|
4766
|
-
const a = args[i];
|
|
4767
|
-
if (a === '--date' && args[i+1]) { rOpts.date = args[++i]; }
|
|
4768
|
-
else if (a.startsWith('--date=')) { rOpts.date = a.slice(7); }
|
|
4769
|
-
else if (a === '--out' && args[i+1]) { rOpts.outPath = args[++i]; }
|
|
4770
|
-
else if (a.startsWith('--out=')) { rOpts.outPath = a.slice(6); }
|
|
4771
|
-
else if (a === '--project-dir' && args[i+1]) { rOpts.projectDir = args[++i]; }
|
|
4772
|
-
else if (a.startsWith('--project-dir=')) { rOpts.projectDir = a.slice(14); }
|
|
4773
|
-
else if (a === '--help' || a === '-h') {
|
|
4774
|
-
log('Usage: gsd-t report tokens [--date YYYY-MM-DD] [--out PATH]');
|
|
4775
|
-
log(' --date YYYY-MM-DD Date stamp in output filename (default: today UTC)');
|
|
4776
|
-
log(' --out PATH Output path (default: .gsd-t/reports/token-usage-{DATE}.md)');
|
|
4777
|
-
process.exit(0);
|
|
4778
|
-
}
|
|
4779
|
-
else {
|
|
4780
|
-
error(`report tokens: unknown arg: ${a}`);
|
|
4781
|
-
process.exit(2);
|
|
4782
|
-
}
|
|
4783
|
-
}
|
|
4784
|
-
try {
|
|
4785
|
-
const rep = require(path.join(__dirname, 'gsd-t-report-tokens.cjs'));
|
|
4786
|
-
const res = rep.generateReport(rOpts);
|
|
4787
|
-
log(`Wrote ${res.path}`);
|
|
4788
|
-
const s = res.summary;
|
|
4789
|
-
log(` ${s.cws} CW(s) · ${s.turns} turn rows · ${s.compactions} compactions · ${s.sessions} session(s)`);
|
|
4790
|
-
log(` ${s.compactionEndedCWs}/${s.cws} CW${s.cws === 1 ? '' : 's'} ended by compaction · top tool: ${s.topTool || '—'}`);
|
|
4791
|
-
process.exit(0);
|
|
4792
|
-
} catch (e) {
|
|
4793
|
-
error(e.message || String(e));
|
|
4794
|
-
process.exit(3);
|
|
4795
|
-
}
|
|
4796
|
-
break;
|
|
4797
|
-
}
|
|
4798
4470
|
case "scan": {
|
|
4799
4471
|
const exportFlag = args.find(a => a.startsWith('--export='));
|
|
4800
4472
|
const exportFormat = exportFlag ? exportFlag.split('=')[1] : null;
|
package/bin/journey-coverage.cjs
CHANGED
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
+
// M61 D4 retired the specific viewer HTML + dashboard server. The detector's
|
|
7
|
+
// HTML-listener scanning stays general-purpose: any `scripts/*.html` is a
|
|
8
|
+
// viewer-source surface (so a future viewer is covered automatically), plus
|
|
9
|
+
// the live journey specs. The retired files simply no longer exist to scan —
|
|
10
|
+
// `gsd-t check-coverage` returns 0 listeners until a new HTML surface appears.
|
|
6
11
|
const VIEWER_FILE_PATTERNS = [
|
|
7
|
-
/^scripts
|
|
8
|
-
/^scripts\/gsd-t-dashboard-server\.js$/,
|
|
9
|
-
/^bin\/gsd-t-dashboard.*\.cjs$/,
|
|
12
|
+
/^scripts\/.*\.html$/,
|
|
10
13
|
/^e2e\/journeys\/.*\.spec\.ts$/,
|
|
11
14
|
];
|
|
12
15
|
|
package/bin/parallel-cli.cjs
CHANGED
|
@@ -26,7 +26,19 @@ const { spawn } = require('child_process');
|
|
|
26
26
|
const fs = require('fs');
|
|
27
27
|
const path = require('path');
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
// M61 D3: gsd-t-token-capture retired. captureSpawn was a wrapper that
|
|
30
|
+
// parsed result.usage and wrote a token-log row, returning
|
|
31
|
+
// `{ result, usage, rowWritten }`. Native /usage replaces the token-log.
|
|
32
|
+
// Stub preserves the RETURN SHAPE (callers read `wrapped.result`) — only the
|
|
33
|
+
// token-log side-effect is dropped. Returning the bare spawn result would
|
|
34
|
+
// make every parallel-CLI worker read `wrapped.result === undefined` and
|
|
35
|
+
// report ok:false regardless of real outcome (M61 post-audit CRITICAL fix).
|
|
36
|
+
const captureSpawn = async (opts) => {
|
|
37
|
+
if (typeof opts.spawnFn === 'function') {
|
|
38
|
+
return { result: await opts.spawnFn(), usage: null, rowWritten: false };
|
|
39
|
+
}
|
|
40
|
+
return { result: null, usage: null, rowWritten: false };
|
|
41
|
+
};
|
|
30
42
|
const { attachTee, VALID_ID_RE } = require('./parallel-cli-tee.cjs');
|
|
31
43
|
|
|
32
44
|
const SCHEMA_VERSION = '1.0.0';
|