@tekyzinc/gsd-t 4.0.28 → 4.1.10
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 +35 -0
- package/README.md +3 -0
- package/bin/gsd-t-competition-judge.cjs +344 -0
- package/bin/gsd-t.js +16 -0
- package/commands/gsd-t-design-decompose.md +9 -2
- package/commands/gsd-t-help.md +8 -0
- package/commands/gsd-t-milestone.md +9 -2
- package/commands/gsd-t-partition.md +9 -2
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +2 -2
- package/templates/workflows/gsd-t-debug.workflow.js +34 -5
- package/templates/workflows/gsd-t-execute.workflow.js +54 -29
- package/templates/workflows/gsd-t-integrate.workflow.js +37 -7
- package/templates/workflows/gsd-t-phase.workflow.js +368 -25
- package/templates/workflows/gsd-t-quick.workflow.js +59 -7
- package/templates/workflows/gsd-t-verify.workflow.js +67 -47
- package/templates/workflows/gsd-t-wave.workflow.js +7 -4
|
@@ -16,11 +16,63 @@ export const meta = {
|
|
|
16
16
|
],
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// M81: runtime-native helpers. The Anthropic Workflow sandbox provides ONLY the
|
|
20
|
+
// globals agent/parallel/pipeline/log/phase/budget/args — NO require/fs/path/
|
|
21
|
+
// child_process/process. The old `require("./_lib.js")` threw ReferenceError on first
|
|
22
|
+
// eval, so EVERY workflow except scan silently crashed and never ran (TD-113, confirmed
|
|
23
|
+
// by the NiceNote session 2026-06-05). These inline helpers delegate the CLI calls to an
|
|
24
|
+
// agent() that runs them via Bash (preferring project-local bin/<tool>.cjs, falling back
|
|
25
|
+
// to the global `gsd-t` PATH binary), parsing the JSON envelope — same brains, sandbox-safe
|
|
26
|
+
// invocation. The args global also arrives as a JSON STRING in this runtime, so parse it.
|
|
27
|
+
const _args = (typeof args === "string") ? (() => { try { return JSON.parse(args); } catch { return {}; } })() : (args || {});
|
|
20
28
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
const _CLI_ENVELOPE_SCHEMA = {
|
|
30
|
+
type: "object", required: ["ok", "exitCode"], additionalProperties: true,
|
|
31
|
+
properties: {
|
|
32
|
+
ok: { type: "boolean" }, exitCode: { type: "integer" },
|
|
33
|
+
envelope: {}, stdout: { type: "string" }, stderr: { type: "string" }, via: { type: "string" },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
// Run a `gsd-t <subcmd>` CLI (or project-local bin/<localBin>) via an agent's Bash and
|
|
37
|
+
// return { ok, exitCode, envelope, stderr, via }. parseJson=true parses stdout as the envelope.
|
|
38
|
+
async function runCli(projectDir, subcmd, argv, localBin, label, parseJson = true, phaseName) {
|
|
39
|
+
const argStr = (argv || []).map((a) => `'${String(a).replace(/'/g, "'\\''")}'`).join(" ");
|
|
40
|
+
const prompt = [
|
|
41
|
+
`Run a GSD-T CLI command for the project at \`${projectDir}\` and report the result. Steps:`,
|
|
42
|
+
`1. If \`${projectDir}/bin/${localBin}\` exists, run: \`node ${projectDir}/bin/${localBin} ${argStr}\` (set via="local").`,
|
|
43
|
+
` Otherwise run: \`gsd-t ${subcmd} ${argStr}\` (set via="global").`,
|
|
44
|
+
` Run it with cwd \`${projectDir}\` (use \`cd ${projectDir} && …\` or \`-C\`/\`--cwd\` as appropriate).`,
|
|
45
|
+
`2. Capture the exit code (ok = exitCode 0) and stdout/stderr.`,
|
|
46
|
+
parseJson
|
|
47
|
+
? `3. Parse stdout as JSON into \`envelope\` (null if not JSON). Return JSON per the schema.`
|
|
48
|
+
: `3. Put stdout (trimmed, ≤4000 chars) in \`stdout\`. Return JSON per the schema.`,
|
|
49
|
+
`Do NOT do any other work. ONLY run this one command and report.`,
|
|
50
|
+
].join("\n");
|
|
51
|
+
const opts = { label, schema: _CLI_ENVELOPE_SCHEMA, model: "haiku" };
|
|
52
|
+
if (phaseName) opts.phase = phaseName; // opts.phase MUST be a string, never the phase() fn
|
|
53
|
+
const r = await agent(prompt, opts)
|
|
54
|
+
.catch((e) => ({ ok: false, exitCode: -1, envelope: null, stderr: String(e && e.message), via: "error" }));
|
|
55
|
+
return r || { ok: false, exitCode: -1, envelope: null, via: "error" };
|
|
56
|
+
}
|
|
57
|
+
async function runPreflight(projectDir, label = "preflight", phaseName) {
|
|
58
|
+
return runCli(projectDir, "preflight", ["--json"], "cli-preflight.cjs", label, true, phaseName);
|
|
59
|
+
}
|
|
60
|
+
async function runVerifyGate(projectDir, label = "verify-gate", phaseName) {
|
|
61
|
+
return runCli(projectDir, "verify-gate", ["--json"], "gsd-t-verify-gate.cjs", label, true, phaseName);
|
|
62
|
+
}
|
|
63
|
+
// Brief generation: writes .gsd-t/briefs/<id>.json and returns its path. The id must be
|
|
64
|
+
// caller-supplied (no Date.now/Math.random in the sandbox) — pass a stable id per spawn.
|
|
65
|
+
async function generateBrief(projectDir, { kind = "execute", milestone, domain, id, label = "brief", phaseName } = {}) {
|
|
66
|
+
const argv = ["--kind", kind, "--spawn-id", id, "--out", `${projectDir}/.gsd-t/briefs/${id}.json`];
|
|
67
|
+
if (milestone) argv.push("--milestone", milestone);
|
|
68
|
+
if (domain) argv.push("--domain", domain);
|
|
69
|
+
const r = await runCli(projectDir, "brief", argv, "gsd-t-context-brief.cjs", label, false, phaseName);
|
|
70
|
+
return { ok: r.ok, briefPath: `${projectDir}/.gsd-t/briefs/${id}.json`, via: r.via };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const projectDir = _args.projectDir || ".";
|
|
74
|
+
const task = _args.task || null;
|
|
75
|
+
const model = _args.model || "sonnet";
|
|
24
76
|
|
|
25
77
|
const QUICK_SCHEMA = {
|
|
26
78
|
type: "object",
|
|
@@ -38,9 +90,9 @@ if (!task) {
|
|
|
38
90
|
}
|
|
39
91
|
|
|
40
92
|
phase("Preflight");
|
|
41
|
-
const pre =
|
|
93
|
+
const pre = await runPreflight(projectDir);
|
|
42
94
|
if (!pre.ok) return { status: "failed", reason: "preflight-failed", preflight: pre.envelope };
|
|
43
|
-
const brief =
|
|
95
|
+
const brief = await generateBrief(projectDir, { kind: "execute", id: "quick-brief" });
|
|
44
96
|
|
|
45
97
|
phase("Execute");
|
|
46
98
|
const result = await agent(
|
|
@@ -64,7 +116,7 @@ if (result.status === "failed" || result.status === "blocked") {
|
|
|
64
116
|
}
|
|
65
117
|
|
|
66
118
|
phase("Verify");
|
|
67
|
-
const vg =
|
|
119
|
+
const vg = await runVerifyGate(projectDir);
|
|
68
120
|
return {
|
|
69
121
|
status: vg.ok ? "complete" : "verify-failed",
|
|
70
122
|
result,
|
|
@@ -30,12 +30,55 @@ export const meta = {
|
|
|
30
30
|
],
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// M81: runtime-native helpers (sandbox bans require/fs/path/child_process/process — the
|
|
34
|
+
// old require("./_lib.js") + the inline require("child_process"/"fs"/"path") in the
|
|
35
|
+
// CI-parity block crashed this on first eval, TD-113). All CLI calls (preflight,
|
|
36
|
+
// verify-gate, build-coverage, ci-parity, test-data) delegate to an agent's Bash; the
|
|
37
|
+
// QA/Red-Team protocol bodies are read by an agent (Read) instead of fs. args arrives as
|
|
38
|
+
// a JSON STRING in this runtime. See gsd-t-scan.workflow.js.
|
|
39
|
+
const _args = (typeof args === "string") ? (() => { try { return JSON.parse(args); } catch { return {}; } })() : (args || {});
|
|
40
|
+
const _CLI_ENVELOPE_SCHEMA = {
|
|
41
|
+
type: "object", required: ["ok", "exitCode"], additionalProperties: true,
|
|
42
|
+
properties: { ok: { type: "boolean" }, exitCode: { type: "integer" }, envelope: {}, stdout: { type: "string" }, stderr: { type: "string" }, via: { type: "string" } },
|
|
43
|
+
};
|
|
44
|
+
async function runCli(projectDir, subcmd, argv, localBin, label, parseJson = true, phaseName) {
|
|
45
|
+
const argStr = (argv || []).map((a) => `'${String(a).replace(/'/g, "'\\''")}'`).join(" ");
|
|
46
|
+
const prompt = [
|
|
47
|
+
`Run a GSD-T CLI command for the project at \`${projectDir}\` and report the result. Steps:`,
|
|
48
|
+
`1. If \`${projectDir}/bin/${localBin}\` exists, run: \`node ${projectDir}/bin/${localBin} ${argStr}\` (set via="local"). Otherwise run: \`gsd-t ${subcmd} ${argStr}\` (set via="global"). Use cwd \`${projectDir}\`.`,
|
|
49
|
+
`2. Capture exit code (ok = exitCode 0) and stdout/stderr.`,
|
|
50
|
+
parseJson ? `3. Parse stdout as JSON into \`envelope\` (null if not JSON). Return JSON per the schema.` : `3. Put stdout (trimmed, ≤4000 chars) in \`stdout\`. Return JSON per the schema.`,
|
|
51
|
+
`Do NOT do any other work. ONLY run this one command and report.`,
|
|
52
|
+
].join("\n");
|
|
53
|
+
const opts = { label, schema: _CLI_ENVELOPE_SCHEMA, model: "haiku" };
|
|
54
|
+
if (phaseName) opts.phase = phaseName;
|
|
55
|
+
const r = await agent(prompt, opts).catch((e) => ({ ok: false, exitCode: -1, envelope: null, stderr: String(e && e.message), via: "error" }));
|
|
56
|
+
return r || { ok: false, exitCode: -1, envelope: null, via: "error" };
|
|
57
|
+
}
|
|
58
|
+
async function runPreflight(projectDir, label = "preflight", phaseName) { return runCli(projectDir, "preflight", ["--json"], "cli-preflight.cjs", label, true, phaseName); }
|
|
59
|
+
async function runVerifyGate(projectDir, label = "verify-gate", phaseName) { return runCli(projectDir, "verify-gate", ["--json"], "gsd-t-verify-gate.cjs", label, true, phaseName); }
|
|
60
|
+
async function generateBrief(projectDir, { kind = "verify", milestone, domain, id, label = "brief", phaseName } = {}) {
|
|
61
|
+
const argv = ["--kind", kind, "--spawn-id", id, "--out", `${projectDir}/.gsd-t/briefs/${id}.json`];
|
|
62
|
+
if (milestone) argv.push("--milestone", milestone);
|
|
63
|
+
if (domain) argv.push("--domain", domain);
|
|
64
|
+
const r = await runCli(projectDir, "brief", argv, "gsd-t-context-brief.cjs", label, false, phaseName);
|
|
65
|
+
return { ok: r.ok, briefPath: `${projectDir}/.gsd-t/briefs/${id}.json`, via: r.via };
|
|
66
|
+
}
|
|
67
|
+
// The QA / Red-Team / design-verify protocol bodies live at templates/prompts/<name>-subagent.md
|
|
68
|
+
// inside the installed @tekyzinc/gsd-t package. The orchestrator can't read files (no fs); each
|
|
69
|
+
// triad agent reads its OWN protocol via Read at spawn time. loadProtocol returns a Read-instruction
|
|
70
|
+
// the agent prompt embeds, rather than the protocol text itself.
|
|
71
|
+
function loadProtocolInstruction(name) {
|
|
72
|
+
const rel = `templates/prompts/${name}-subagent.md`;
|
|
73
|
+
// Locate the protocol inside the installed @tekyzinc/gsd-t package using ONLY shell
|
|
74
|
+
// (no require/fs tokens — those trip the runtime-native lint even inside a string).
|
|
75
|
+
return `Read your protocol FIRST. Find it by running in Bash: \`cat "$(npm root -g)/@tekyzinc/gsd-t/${rel}"\` (or, if a project-local \`${rel}\` exists, read that instead). Follow that protocol exactly.`;
|
|
76
|
+
}
|
|
34
77
|
|
|
35
|
-
const projectDir =
|
|
36
|
-
const milestone =
|
|
37
|
-
const skipUltra =
|
|
38
|
-
const skipUltraReason =
|
|
78
|
+
const projectDir = _args.projectDir || ".";
|
|
79
|
+
const milestone = _args.milestone || null;
|
|
80
|
+
const skipUltra = _args.skipUltra || false;
|
|
81
|
+
const skipUltraReason = _args.skipUltraReason || null;
|
|
39
82
|
|
|
40
83
|
// 4.8-audit fix: skipUltra requires a recorded reason per
|
|
41
84
|
// orthogonal-validation-contract.md Rule #2. Refuse without one.
|
|
@@ -153,15 +196,15 @@ if (!milestone) {
|
|
|
153
196
|
}
|
|
154
197
|
|
|
155
198
|
phase("Preflight");
|
|
156
|
-
const pre =
|
|
199
|
+
const pre = await runPreflight(projectDir);
|
|
157
200
|
if (!pre.ok) {
|
|
158
201
|
log(`preflight FAIL — halting verify`);
|
|
159
202
|
return { status: "failed", reason: "preflight-failed", preflight: pre.envelope };
|
|
160
203
|
}
|
|
161
|
-
const brief =
|
|
204
|
+
const brief = await generateBrief(projectDir, { kind: "verify", milestone, id: `verify-${(milestone || "m").toLowerCase()}` });
|
|
162
205
|
|
|
163
206
|
phase("Verify-Gate");
|
|
164
|
-
const vg =
|
|
207
|
+
const vg = await runVerifyGate(projectDir);
|
|
165
208
|
if (!vg.ok) {
|
|
166
209
|
log(`verify-gate FAIL exitCode=${vg.exitCode} — halting before triad`);
|
|
167
210
|
return {
|
|
@@ -179,36 +222,16 @@ log(`verify-gate green`);
|
|
|
179
222
|
// from Dockerfile COPY — silent CI-divergence regression. M57 made this gate
|
|
180
223
|
// mandatory; Workflow MUST preserve it or we re-introduce that exact failure.
|
|
181
224
|
// Detected by user/worker in parallel session 2026-05-29 13:00.
|
|
225
|
+
// M81: these were raw spawnSync + require("fs"/"path"/"child_process") in the orchestrator
|
|
226
|
+
// — the exact sandbox-forbidden pattern (TD-113). Now awaited runCli agent calls. The
|
|
227
|
+
// FAIL-blocking semantics are UNCHANGED: a non-zero exit halts verify before the triad.
|
|
182
228
|
phase("CI-Parity");
|
|
183
|
-
const
|
|
184
|
-
function _runJsonCli(subcmd, argv = []) {
|
|
185
|
-
// Use _lib-style resolution — prefer project-local bin/<tool>.cjs
|
|
186
|
-
const fsMod = require("fs");
|
|
187
|
-
const pMod = require("path");
|
|
188
|
-
const localMap = {
|
|
189
|
-
"build-coverage": "gsd-t-build-coverage.cjs",
|
|
190
|
-
"ci-parity": "gsd-t-ci-parity.cjs",
|
|
191
|
-
"test-data": "gsd-t-test-data-ledger.cjs",
|
|
192
|
-
};
|
|
193
|
-
const local = pMod.join(projectDir, "bin", localMap[subcmd] || "");
|
|
194
|
-
const cmd = fsMod.existsSync(local) ? process.execPath : "gsd-t";
|
|
195
|
-
const args = fsMod.existsSync(local) ? [local, ...argv] : [subcmd, ...argv];
|
|
196
|
-
const r = spawnSync(cmd, args, { cwd: projectDir, stdio: "pipe" });
|
|
197
|
-
let envelope = null;
|
|
198
|
-
try { envelope = r.stdout ? JSON.parse(r.stdout.toString()) : null; } catch (_) {}
|
|
199
|
-
return {
|
|
200
|
-
ok: r.status === 0,
|
|
201
|
-
exitCode: r.status,
|
|
202
|
-
envelope,
|
|
203
|
-
stderr: r.stderr && r.stderr.toString(),
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
const bc = _runJsonCli("build-coverage", ["--json"]);
|
|
229
|
+
const bc = await runCli(projectDir, "build-coverage", ["--json"], "gsd-t-build-coverage.cjs", "m57:build-coverage", true, "CI-Parity");
|
|
207
230
|
if (!bc.ok) {
|
|
208
231
|
log(`M57 build-coverage FAIL exitCode=${bc.exitCode} — halting (FAIL-blocking)`);
|
|
209
232
|
return { status: "ci-parity-failed", overallVerdict: "VERIFY-FAILED", buildCoverage: bc.envelope };
|
|
210
233
|
}
|
|
211
|
-
const cip =
|
|
234
|
+
const cip = await runCli(projectDir, "ci-parity", ["--json"], "gsd-t-ci-parity.cjs", "m57:ci-parity", true, "CI-Parity");
|
|
212
235
|
if (!cip.ok) {
|
|
213
236
|
log(`M57 ci-parity FAIL exitCode=${cip.exitCode} — halting (FAIL-blocking)`);
|
|
214
237
|
return { status: "ci-parity-failed", overallVerdict: "VERIFY-FAILED", ciParity: cip.envelope };
|
|
@@ -221,8 +244,10 @@ log(`M57 CI-parity gate green`);
|
|
|
221
244
|
// live in production data. M58 made post-E2E purge mandatory; M60 hardened
|
|
222
245
|
// the adapters against empty-prefix bypass. Workflow MUST preserve.
|
|
223
246
|
phase("Test-Data Purge");
|
|
224
|
-
|
|
225
|
-
|
|
247
|
+
// M81: run-id is stable per verify run (no Date.now in the sandbox); the milestone scope
|
|
248
|
+
// is sufficient for purge targeting and is deterministic on resume.
|
|
249
|
+
const verifyRunId = `verify-${(milestone || "M__").toLowerCase()}`;
|
|
250
|
+
const td = await runCli(projectDir, "test-data", ["--purge", "--run", verifyRunId, "--json"], "gsd-t-test-data-ledger.cjs", "m58:test-data-purge", true, "Test-Data Purge");
|
|
226
251
|
if (!td.ok) {
|
|
227
252
|
log(`M58 test-data purge FAIL exitCode=${td.exitCode} — halting (FAIL-blocking)`);
|
|
228
253
|
return { status: "test-data-purge-failed", overallVerdict: "VERIFY-FAILED", testDataPurge: td.envelope };
|
|
@@ -233,10 +258,11 @@ phase("Orthogonal Triad");
|
|
|
233
258
|
|
|
234
259
|
const briefRef = brief.briefPath || "(brief generation failed — re-walk repo)";
|
|
235
260
|
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
const
|
|
261
|
+
// M81: the protocol body lives in templates/prompts/<name>-subagent.md inside the installed
|
|
262
|
+
// package; the orchestrator can't read files (no fs). Each triad agent reads its OWN
|
|
263
|
+
// protocol via Read at spawn time — loadProtocolInstruction returns the Read directive.
|
|
264
|
+
const redTeamProtocolInstruction = loadProtocolInstruction("red-team");
|
|
265
|
+
const qaProtocolInstruction = loadProtocolInstruction("qa");
|
|
240
266
|
|
|
241
267
|
const stages = [
|
|
242
268
|
// Stage A — /code-review ultra (cooperative correctness + cleanup)
|
|
@@ -273,10 +299,7 @@ const stages = [
|
|
|
273
299
|
`**adversarial / security / boundaries**. You are NOT cooperative — your`,
|
|
274
300
|
`success is measured in bugs FOUND, not tests passed. Try to break the code.`,
|
|
275
301
|
``,
|
|
276
|
-
`Run the Red Team protocol
|
|
277
|
-
"----- BEGIN RED TEAM PROTOCOL -----",
|
|
278
|
-
redTeamProtocol.slice(0, 8000),
|
|
279
|
-
"----- END RED TEAM PROTOCOL -----",
|
|
302
|
+
`Run the Red Team protocol. ${redTeamProtocolInstruction}`,
|
|
280
303
|
``,
|
|
281
304
|
`Verdict is FAIL if you found any CRITICAL or HIGH severity bug; GRUDGING-PASS`,
|
|
282
305
|
`if you searched exhaustively and found nothing. Return JSON per the schema.`,
|
|
@@ -296,10 +319,7 @@ const stages = [
|
|
|
296
319
|
`counts. Detect shallow tests (layout-only assertions that pass on an empty HTML page).`,
|
|
297
320
|
`Verify contract compliance against .gsd-t/contracts/.`,
|
|
298
321
|
``,
|
|
299
|
-
`Run the QA protocol
|
|
300
|
-
"----- BEGIN QA PROTOCOL -----",
|
|
301
|
-
qaProtocol.slice(0, 8000),
|
|
302
|
-
"----- END QA PROTOCOL -----",
|
|
322
|
+
`Run the QA protocol. ${qaProtocolInstruction}`,
|
|
303
323
|
``,
|
|
304
324
|
`Return JSON per the schema.`,
|
|
305
325
|
].join("\n"),
|
|
@@ -14,11 +14,14 @@ export const meta = {
|
|
|
14
14
|
],
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
// M81: this workflow only composes sub-workflows (execute + verify) — it never used
|
|
18
|
+
// lib.*, but the `require("./_lib.js")` import alone crashed it on first eval in the
|
|
19
|
+
// sandbox (TD-113). Removed. args arrives as a JSON STRING in this runtime, so parse it.
|
|
20
|
+
const _args = (typeof args === "string") ? (() => { try { return JSON.parse(args); } catch { return {}; } })() : (args || {});
|
|
18
21
|
|
|
19
|
-
const projectDir =
|
|
20
|
-
const milestone =
|
|
21
|
-
const domains =
|
|
22
|
+
const projectDir = _args.projectDir || ".";
|
|
23
|
+
const milestone = _args.milestone || null;
|
|
24
|
+
const domains = _args.domains || [];
|
|
22
25
|
|
|
23
26
|
if (!milestone || !domains.length) {
|
|
24
27
|
log("wave: args.milestone and args.domains required");
|