@rsaglobaltech/specgate 0.22.3 → 0.24.0

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/packages/core/src/domain/DoneVerification.js +21 -2
  3. package/dist/packages/core/src/domain/DoneVerification.js.map +1 -1
  4. package/dist/packages/core/test/unit/done-verification.test.js +18 -0
  5. package/dist/packages/core/test/unit/done-verification.test.js.map +1 -1
  6. package/dist/scripts/cli/commands/harness/RunCommand.js +50 -5
  7. package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
  8. package/dist/scripts/cli/commands/quality/CheckCommand.js +6 -0
  9. package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
  10. package/dist/scripts/cli/commands/spec/DoneCommand.js +2 -1
  11. package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
  12. package/dist/scripts/cli/commands/spec/StudioCommand.js +31 -0
  13. package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
  14. package/dist/scripts/harness/events.js +57 -0
  15. package/dist/scripts/harness/events.js.map +1 -1
  16. package/dist/scripts/lib/harness-events.js +32 -1
  17. package/dist/scripts/lib/harness-events.js.map +1 -1
  18. package/dist/scripts/lib/harness-guard.js +186 -0
  19. package/dist/scripts/lib/harness-guard.js.map +1 -0
  20. package/dist/scripts/lib/in-flight.js +17 -4
  21. package/dist/scripts/lib/in-flight.js.map +1 -1
  22. package/dist/scripts/lib/live-detail.js +345 -0
  23. package/dist/scripts/lib/live-detail.js.map +1 -0
  24. package/dist/scripts/lib/live-model.js +158 -9
  25. package/dist/scripts/lib/live-model.js.map +1 -1
  26. package/dist/scripts/lib/live-page.js +599 -67
  27. package/dist/scripts/lib/live-page.js.map +1 -1
  28. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -9,6 +9,66 @@ The release process is in [`docs/release-process.md`](docs/release-process.md).
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.24.0] — 2026-10-26
13
+
14
+ A live view you can work from, and a harness that survives a night: what a twenty-requirement chain in a Next.js app ran into.
15
+
16
+ ### Added
17
+
18
+ - **A requirement opens into everything the project holds about it**
19
+ (REQ-180): clicking a requirement in `/live` shows its statement, its
20
+ scenarios with their steps, the spec file and line that define it, its
21
+ assumptions, the tests that name it, its feature, every attempt with the
22
+ stage it failed at, and the files the last attempt changed, each linked to
23
+ the editor.
24
+ - **The agent's session in the live view** (REQ-182):
25
+ `harness events --from claude` now records the model, the context of each message against the
26
+ model's window, and the session's tokens, cost and turns; `harness run`
27
+ keeps the run's queue and each attempt's prompt beside the events. The
28
+ sidebar is the run's work queue (now, needs attention, up next with an
29
+ estimate, finished recently), the summary adds tokens and cost, and an
30
+ Agent tab shows the selected attempt's session and the prompt it was given.
31
+
32
+ ### Changed
33
+
34
+ - **The live view groups by module and keeps its header in view** (REQ-181):
35
+ the header and summary stay put while the page scrolls; the centre is a
36
+ matrix by module, one segment per requirement, queued ones included; and a
37
+ Traceability view shows the matrix as it stands, filtered as you type.
38
+
39
+ ### Fixed
40
+
41
+ - **The harness no longer fills the disk** (REQ-184): the in-flight view
42
+ copied each worktree whole, `.next/cache` included, until a chain stopped
43
+ with ENOSPC. It now copies only what git keeps, and a requirement does not
44
+ start with less than 2 GB free (`SPECGATE_HARNESS_MIN_FREE_GB`).
45
+ - **Re-running delivered requirements works in the order asked** (REQ-185):
46
+ `--req` order is kept, and a branch whose own work is already merged is
47
+ recreated without `--force`.
48
+ - **One harness run per working copy** (REQ-186): a lock beside the events
49
+ refuses a second run; `check` warns while a run holds it; a post-merge
50
+ failure says it ran in the working copy.
51
+ - **`check` fills the test command's placeholders** (REQ-183): a test command
52
+ with `{req}` ran with the literal text. `check` runs it for the whole
53
+ project, with the placeholders empty; `apply` and `done` fill `{req}` with
54
+ the requirement they deliver.
55
+ - **The live view takes the last attempt that started**, not the highest
56
+ attempt number, so a new run's attempt 1 is not hidden by an earlier run's
57
+ attempt 3.
58
+
59
+ ## [0.23.0] — 2026-10-25
60
+
61
+ The live view, read like a CI run: watch the harness work through a run requirement by requirement, step by step.
62
+
63
+ ### Changed
64
+
65
+ - **The live view reads like a CI run** (REQ-179): `/live` listed every
66
+ requirement the same way, by id alone. It now has a sidebar of the run's
67
+ requirements by module, a summary of the run, its requirements as a graph of
68
+ jobs, and the selected one's steps (Agent, each gate stage, the stages still
69
+ to come) with the agent's stream as the log of the step in progress. Each
70
+ requirement shows its title from the specification. Light and dark.
71
+
12
72
  ## [0.22.3] — 2026-10-25
13
73
 
14
74
  What a first project from a brief tripped over, from statuses to the harness's first attempt: rehearsed on a Spanish brief with eight modules and a Next.js monorepo.
@@ -1,10 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NO_TEST_COMMAND_WARNING = void 0;
4
+ exports.gateTestCommand = gateTestCommand;
4
5
  exports.planDoneVerification = planDoneVerification;
5
6
  exports.planGateCheck = planGateCheck;
6
7
  exports.deliveryBlocker = deliveryBlocker;
7
8
  const TraceabilityFormat_1 = require("./TraceabilityFormat");
9
+ /**
10
+ * The test command as the gate outside the harness runs it (REQ-183): `{req}`
11
+ * is the requirement being delivered, or empty when the whole project is
12
+ * checked; `{scenario}` and `{feature_file}` are always empty, since no one
13
+ * scenario is meant. The harness fills them per requirement; `check` used to
14
+ * run them as written, and a command that named the requirement broke it.
15
+ */
16
+ function gateTestCommand(testCmd, reqId) {
17
+ return testCmd
18
+ .split("{req}")
19
+ .join(reqId || "")
20
+ .split("{scenario}")
21
+ .join("")
22
+ .split("{feature_file}")
23
+ .join("")
24
+ .replace(/[ \t]+$/gm, "")
25
+ .trim();
26
+ }
8
27
  /**
9
28
  * The checks `done` should run, in the order they should run.
10
29
  *
@@ -33,7 +52,7 @@ function planDoneVerification(projectDir, opts) {
33
52
  const archCmd = (opts.archCmd || "").trim();
34
53
  if (archCmd !== "")
35
54
  steps.push({ stage: "arch", argv: [archCmd] });
36
- const testCmd = (opts.testCmd || "").trim();
55
+ const testCmd = gateTestCommand((opts.testCmd || "").trim(), opts.reqId);
37
56
  if (testCmd !== "")
38
57
  steps.push({ stage: "tests", argv: [testCmd] });
39
58
  return { steps, testsUnverified: testCmd === "" };
@@ -51,7 +70,7 @@ function planGateCheck(projectDir, testCmd, archCmd) {
51
70
  const arch = (archCmd || "").trim();
52
71
  if (arch !== "")
53
72
  steps.push({ stage: "arch", argv: [arch] });
54
- const cmd = (testCmd || "").trim();
73
+ const cmd = gateTestCommand((testCmd || "").trim());
55
74
  if (cmd !== "")
56
75
  steps.push({ stage: "tests", argv: [cmd] });
57
76
  return { steps, testsUnverified: cmd === "" };
@@ -1 +1 @@
1
- {"version":3,"file":"DoneVerification.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/DoneVerification.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DoneVerification.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/DoneVerification.ts"],"names":[],"mappings":"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"}
@@ -84,4 +84,22 @@ const DoneVerification_1 = require("../../src/domain/DoneVerification");
84
84
  assert.match(DoneVerification_1.NO_TEST_COMMAND_WARNING.fix.join(" "), /`apply` and `check`/);
85
85
  assert.doesNotMatch(DoneVerification_1.NO_TEST_COMMAND_WARNING.fix.join(" "), /`done`/);
86
86
  });
87
+ // REQ-183 — the gate's placeholders outside the harness. `check` ran
88
+ // `node check.mjs {req}` with the literal text `{req}`, so a test command that
89
+ // names the requirement broke every `check` (fuhrerschein, S1).
90
+ (0, node_test_1.test)("REQ-183 SCN-183a: check runs the test command for the whole project, its placeholders empty", () => {
91
+ const plan = (0, DoneVerification_1.planGateCheck)("/p", "npm test && node e2e-names.mjs {req} {scenario} {feature_file}");
92
+ const tests = plan.steps.find((s) => s.stage === "tests");
93
+ assert.equal(tests?.argv[0], "npm test && node e2e-names.mjs");
94
+ });
95
+ (0, node_test_1.test)("REQ-183 SCN-183b: done and apply run it for the requirement they deliver", () => {
96
+ const plan = (0, DoneVerification_1.planDoneVerification)("/p", {
97
+ check: true,
98
+ strict: false,
99
+ reqId: "REQ-007",
100
+ testCmd: "npm test && node e2e-names.mjs {req}",
101
+ });
102
+ const tests = plan.steps.find((s) => s.stage === "tests");
103
+ assert.equal(tests?.argv[0], "npm test && node e2e-names.mjs REQ-007");
104
+ });
87
105
  //# sourceMappingURL=done-verification.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"done-verification.test.js","sourceRoot":"","sources":["../../../../../packages/core/test/unit/done-verification.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"done-verification.test.js","sourceRoot":"","sources":["../../../../../packages/core/test/unit/done-verification.test.ts"],"names":[],"mappings":"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"}
@@ -81,6 +81,7 @@ const prompt_1 = require("../../../harness/prompt");
81
81
  const init_1 = require("../../../harness/init");
82
82
  const in_flight_1 = require("../../../lib/in-flight");
83
83
  const harness_events_1 = require("../../../lib/harness-events");
84
+ const harness_guard_1 = require("../../../lib/harness-guard");
84
85
  const HarnessEvents_1 = require("../../../../packages/core/src/domain/HarnessEvents");
85
86
  /**
86
87
  * `read` against the project as it will be after its open changes are
@@ -990,6 +991,14 @@ function attemptRequirement(req, ctx) {
990
991
  const promptFile = path.join(os.tmpdir(), `specgate-harness-prompt-${req.requirement}-${crypto.randomBytes(4).toString("hex")}.md`);
991
992
  fs.writeFileSync(promptFile, prompt, "utf8");
992
993
  archivePrompt(worktreeDir, req.requirement, attempt, step, prompt);
994
+ // The live view shows what the agent was told and how big it was (REQ-182).
995
+ (0, harness_events_1.keepPrompt)(ctx.projectDir || worktreeDir, req.requirement, attempt, prompt);
996
+ event({
997
+ type: "prompt",
998
+ role: step.profile || (step.advisory ? "reviewer" : "agent"),
999
+ chars: prompt.length,
1000
+ lines: prompt.split("\n").length,
1001
+ });
993
1002
  // D1: a profile chosen by matching this requirement, when one matches.
994
1003
  // The role ladder still wins — `attempt_profiles` names a profile for
995
1004
  // *this step*, and a step that says which role it is has already
@@ -1667,15 +1676,32 @@ function processRequirement(req, ctx) {
1667
1676
  };
1668
1677
  }
1669
1678
  const worktreeDir = path.join(os.tmpdir(), `specgate-harness-${req.requirement}-${crypto.randomBytes(4).toString("hex")}`);
1679
+ // A full disk mid-copy ended a night's chain with ENOSPC (REQ-184): stop
1680
+ // before starting, with the reason, instead.
1681
+ const lowDisk = (0, harness_guard_1.lowDiskMessage)((0, harness_guard_1.freeBytes)(os.tmpdir()), (0, harness_guard_1.minFreeBytes)(), os.tmpdir());
1682
+ if (lowDisk) {
1683
+ return {
1684
+ requirement: req.requirement,
1685
+ category: req.category,
1686
+ result: "fail",
1687
+ attempts: 0,
1688
+ branch,
1689
+ error: `Not started: ${lowDisk}`,
1690
+ };
1691
+ }
1670
1692
  // Three ways to meet an existing branch, and until C3 there were only two:
1671
1693
  // skip it, or delete it with --force. After an interruption — a crash, a
1672
1694
  // Ctrl-C, a spend limit — neither is what anyone wants.
1673
1695
  let resuming = false;
1674
- if (branchExists(projectDir, branch)) {
1675
- if (ctx.resume) {
1696
+ const exists = branchExists(projectDir, branch);
1697
+ // A branch already merged into the base holds nothing to lose (REQ-185).
1698
+ const merged = exists && (0, harness_guard_1.branchMergedInto)(projectDir, branch, baseRef);
1699
+ const action = (0, harness_guard_1.existingBranchAction)({ exists, merged, resume: Boolean(ctx.resume), force });
1700
+ if (exists) {
1701
+ if (action === "resume") {
1676
1702
  resuming = true;
1677
1703
  }
1678
- else if (!force) {
1704
+ else if (action === "skip") {
1679
1705
  return {
1680
1706
  requirement: req.requirement,
1681
1707
  category: req.category,
@@ -1687,6 +1713,8 @@ function processRequirement(req, ctx) {
1687
1713
  };
1688
1714
  }
1689
1715
  else {
1716
+ if (merged && !force)
1717
+ info(`${req.requirement}: ${branch} is already merged — recreating it`);
1690
1718
  git(projectDir, ["branch", "-D", branch]);
1691
1719
  }
1692
1720
  }
@@ -2047,7 +2075,9 @@ async function runChain(pending, ctx, hintByReq) {
2047
2075
  result: "fail",
2048
2076
  error: `post-merge gate: ${gate.stage}\n${String(gate.output || "").slice(-4000)}`,
2049
2077
  });
2050
- warn(`${req.requirement}: green on ${branch}, red once merged — the merge was undone`);
2078
+ warn(`${req.requirement}: green on ${branch}, red once merged — the merge was undone. ` +
2079
+ `This gate runs in the working copy: tests or a server started there by hand ` +
2080
+ `while the harness runs can break it.`);
2051
2081
  stop(`the chain stopped at ${req.requirement}`);
2052
2082
  break;
2053
2083
  }
@@ -2393,7 +2423,8 @@ class RunCommand extends command_1.BaseCommand {
2393
2423
  });
2394
2424
  if (args.reqs.length > 0) {
2395
2425
  const wanted = new Set(args.reqs);
2396
- pending = pending.filter((r) => wanted.has(r.requirement));
2426
+ // In the order given (REQ-185): the plan's order reshuffled a chain silently.
2427
+ pending = (0, harness_guard_1.orderAsGiven)(pending.filter((r) => wanted.has(r.requirement)), args.reqs);
2397
2428
  const found = new Set(pending.map((r) => r.requirement));
2398
2429
  for (const want of args.reqs) {
2399
2430
  if (!found.has(want))
@@ -2497,6 +2528,20 @@ class RunCommand extends command_1.BaseCommand {
2497
2528
  strictArtifacts: args.strictArtifacts,
2498
2529
  verbose: args.verbose,
2499
2530
  };
2531
+ // One run per working copy (REQ-186): the post-merge gate runs in it.
2532
+ if (!process.env.SPECGATE_HARNESS_WORKER) {
2533
+ const release = (0, harness_guard_1.acquireRunLock)(projectDir, pending.map((r) => r.requirement));
2534
+ if (!release) {
2535
+ const holder = (0, harness_guard_1.runLockHolder)(projectDir);
2536
+ throw new Error(`Another harness run (pid ${holder ? holder.pid : "?"}) is working in this project` +
2537
+ (holder ? ` on ${holder.reqs.join(", ")}` : "") +
2538
+ `. Wait for it to finish: its post-merge gate runs in this working copy.`);
2539
+ }
2540
+ }
2541
+ // What the live view lists as up next (REQ-182).
2542
+ if (!process.env.SPECGATE_HARNESS_WORKER) {
2543
+ (0, harness_events_1.writeQueue)(projectDir, pending.map((r) => r.requirement));
2544
+ }
2500
2545
  const startedAt = new Date().toISOString();
2501
2546
  const results = args.chain
2502
2547
  ? await runChain(pending, ctx, hintByReq)