@jaybeeuu/agent-cortex 2.0.0 → 2.2.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 (183) hide show
  1. package/CHANGELOG.md +437 -0
  2. package/README.md +46 -15
  3. package/agents/README.md +22 -10
  4. package/agents/plan/agent.md +2 -2
  5. package/agents/ralph/agent.md +128 -91
  6. package/agents/ralph/claude/frontmatter.json +3 -3
  7. package/agents/ralph/claude/wake.md +46 -0
  8. package/agents/ralph/pi/{polling.md → wake.md} +35 -20
  9. package/agents/ralph-plan/agent.md +23 -11
  10. package/bin/agent-cortex.mjs +66 -4
  11. package/bin/installers/claude.mjs +262 -77
  12. package/bin/installers/pi.mjs +200 -24
  13. package/extensions/agent-guardrails/README.md +1 -1
  14. package/extensions/agent-guardrails/guardrails.ts +1 -1
  15. package/extensions/agent-guardrails/index.ts +1 -1
  16. package/extensions/agent-modes/discover.test.ts +2 -2
  17. package/extensions/output-style/README.md +58 -0
  18. package/extensions/output-style/index.ts +23 -0
  19. package/extensions/output-style/output-style.md +43 -0
  20. package/extensions/output-style/output-style.test.ts +50 -0
  21. package/extensions/output-style/output-style.ts +32 -0
  22. package/extensions/output-style/package.json +19 -0
  23. package/hooks/claude/scripts/notify.mjs +8 -1
  24. package/lib/cli.mjs +91 -2
  25. package/package.json +29 -4
  26. package/scripts/check-changeset.mjs +4 -0
  27. package/scripts/check-no-sync.mjs +5 -1
  28. package/scripts/check-skill-frontmatter.mjs +21 -0
  29. package/scripts/lib/compose-agent.mjs +69 -9
  30. package/scripts/lib/fs.mjs +10 -2
  31. package/scripts/lib/migrate.mjs +736 -0
  32. package/scripts/lib/release-gates.mjs +21 -1
  33. package/scripts/lib/skill-frontmatter.mjs +152 -0
  34. package/scripts/lib/skill-links.mjs +52 -0
  35. package/scripts/lib/verify-worker-tree.mjs +25 -0
  36. package/scripts/resolve-publish-command.mjs +4 -0
  37. package/skills/engineering/design-an-interface/SKILL.md +3 -3
  38. package/skills/engineering/grill-with-docs/SKILL.md +3 -5
  39. package/skills/engineering/improve-codebase-architecture/SKILL.md +5 -4
  40. package/skills/engineering/tdd/SKILL.md +5 -7
  41. package/skills/engineering/technical-direction/SKILL.md +5 -5
  42. package/skills/planning/classify-bead/REFERENCE.md +3 -3
  43. package/skills/planning/classify-bead/SKILL.md +14 -9
  44. package/skills/planning/classify-bead/scripts/classify-bead.mjs +5 -4
  45. package/skills/planning/create-task/REFERENCE.md +52 -3
  46. package/skills/planning/create-task/SKILL.md +70 -26
  47. package/skills/planning/create-task/scripts/{create-chores.ts → create-chores.mjs} +48 -23
  48. package/skills/planning/flesh-out-idea/REFERENCE.md +116 -0
  49. package/skills/planning/flesh-out-idea/SKILL.md +146 -0
  50. package/skills/planning/prd-to-tasks/REFERENCE.md +54 -5
  51. package/skills/planning/prd-to-tasks/SKILL.md +22 -16
  52. package/skills/planning/record-idea/FORMAT.md +66 -17
  53. package/skills/planning/record-idea/SKILL.md +48 -24
  54. package/skills/planning/request-refactor-plan/SKILL.md +4 -4
  55. package/skills/planning/spec-to-tickets/SKILL.md +5 -5
  56. package/skills/planning/write-a-prd/SKILL.md +8 -9
  57. package/skills/planning/write-a-ticket/SKILL.md +4 -6
  58. package/skills/productivity/bd-tool/SKILL.md +15 -10
  59. package/skills/productivity/grill-me/SKILL.md +5 -0
  60. package/skills/productivity/init-beads/SKILL.md +3 -3
  61. package/skills/productivity/migration/REFERENCE.md +227 -0
  62. package/skills/productivity/migration/SKILL.md +188 -0
  63. package/skills/productivity/validate-agent-dir/scripts/{validate-agent-dir.ts → validate-agent-dir.mjs} +49 -28
  64. package/skills/productivity/write-a-skill/SKILL.md +5 -5
  65. package/skills/review/maintain-agent-docs/SKILL.md +5 -7
  66. package/skills/review/refactor-skill/SKILL.md +4 -3
  67. package/skills/review/review-security/SKILL.md +3 -5
  68. package/skills/style/style-code/SKILL.md +5 -10
  69. package/skills/style/style-comms/SKILL.md +5 -7
  70. package/skills/style/style-documentation/SKILL.md +5 -6
  71. package/skills/style/style-tests/SKILL.md +5 -7
  72. package/skills/workflow/git-workflow/SKILL.md +28 -4
  73. package/skills/workflow/hitl-collab/SKILL.md +4 -6
  74. package/skills/workflow/plan/SKILL.md +41 -30
  75. package/skills/workflow/ralph/REFERENCE.md +209 -55
  76. package/skills/workflow/ralph/SKILL.md +89 -50
  77. package/skills/workflow/ralph/scripts/pending-gates.mjs +134 -0
  78. package/skills/workflow/run-pipeline-stage/SKILL.md +72 -71
  79. package/skills/workflow/run-pipeline-stage/playbooks/code.md +11 -0
  80. package/skills/workflow/run-pipeline-stage/playbooks/document.md +12 -0
  81. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +12 -0
  82. package/skills/workflow/run-pipeline-stage/playbooks/review.md +11 -0
  83. package/skills/workflow/run-pipeline-stage/playbooks/verify.md +13 -0
  84. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +73 -1
  85. package/token-map.README.md +9 -4
  86. package/token-map.json +13 -6
  87. package/.agents/skills/style-versioning/SKILL.md +0 -172
  88. package/.changeset/README.md +0 -8
  89. package/.changeset/config.json +0 -11
  90. package/.github/workflows/ci.yml +0 -302
  91. package/.junie/guidelines.md +0 -87
  92. package/.junie/mcp/mcp.json +0 -10
  93. package/AGENTS.md +0 -151
  94. package/agents/ralph/claude/polling.md +0 -31
  95. package/agents-native/ralph.md +0 -193
  96. package/docs/claude-hooks.md +0 -128
  97. package/docs/commit-signing.md +0 -231
  98. package/docs/ideas/auto-model-selection.md +0 -75
  99. package/docs/ideas/ban-content-assertion-tests.md +0 -75
  100. package/docs/ideas/bead-progress-notes-for-session-resumption.md +0 -75
  101. package/docs/ideas/classify-beads-via-deterministic-script-with-agent-fallback.md +0 -70
  102. package/docs/ideas/ctx-alias-version-and-update-commands.md +0 -65
  103. package/docs/ideas/ctx-feedback-command-for-capturing-ideas-from-any-machine.md +0 -67
  104. package/docs/ideas/dedicated-review-tests-skill.md +0 -71
  105. package/docs/ideas/deployment-beads-for-post-merge-pipelines.md +0 -36
  106. package/docs/ideas/design-and-delivery-as-separate-bead-trees/design-and-delivery-as-separate-bead-trees.md +0 -99
  107. package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +0 -42
  108. package/docs/ideas/extension-manifests.md +0 -121
  109. package/docs/ideas/improve-pi-system-prompt.md +0 -37
  110. package/docs/ideas/map-every-cortex-tool-to-a-real-pi-equivalent.md +0 -95
  111. package/docs/ideas/model-selector.md +0 -40
  112. package/docs/ideas/pi-task-memory.md +0 -34
  113. package/docs/ideas/qa-extension.md +0 -43
  114. package/docs/ideas/record-idea-implementation-questions.md +0 -68
  115. package/docs/ideas/record-ideas-as-beads.md +0 -115
  116. package/docs/ideas/self-flushing-session.md +0 -72
  117. package/docs/ideas/state-in-beads-not-md.md +0 -69
  118. package/docs/ideas/subagent-visibility.md +0 -72
  119. package/docs/ideas/task-session-context.local.md +0 -95
  120. package/docs/ideas/task-session-context.md +0 -89
  121. package/docs/ideas/test-data-creation-helpers.md +0 -92
  122. package/docs/ideas/test-planning-stage-bead-in-feature-planning.md +0 -68
  123. package/docs/ideas/unified-ci-pipeline.md +0 -28
  124. package/docs/ideas/unify-the-ticket-and-task-decomposition-workflows.md +0 -71
  125. package/docs/ideas/worktree-housekeeping-for-closed-beads.md +0 -39
  126. package/docs/inspirations.md +0 -33
  127. package/docs/research/disable-model-invocation.md +0 -82
  128. package/docs/research/gas-city-research.md +0 -256
  129. package/docs/research/skill-design-research.md +0 -286
  130. package/docs/research/skill-improvements-analysis.md +0 -117
  131. package/docs/research/skill-patterns-research.md +0 -24
  132. package/docs/skills/skill-anatomy.md +0 -197
  133. package/docs/technical-direction/harness-config.md +0 -177
  134. package/docs/technical-direction/migration-execution-labels.md +0 -177
  135. package/docs/user-preferences.md +0 -17
  136. package/extensions/agent-guardrails/tsconfig.json +0 -12
  137. package/extensions/agent-modes/tsconfig.json +0 -12
  138. package/extensions/session-start/tsconfig.json +0 -12
  139. package/extensions/skill-stats/pnpm-lock.yaml +0 -329
  140. package/extensions/skill-stats/tsconfig.json +0 -12
  141. package/extensions/subagent/agents/planner.md +0 -37
  142. package/extensions/subagent/agents/reviewer.md +0 -35
  143. package/extensions/subagent/agents/scout.md +0 -50
  144. package/extensions/subagent/agents/worker.md +0 -24
  145. package/extensions/subagent/prompts/implement-and-review.md +0 -10
  146. package/extensions/subagent/prompts/implement.md +0 -10
  147. package/extensions/subagent/prompts/scout-and-plan.md +0 -9
  148. package/extensions/subagent/tsconfig.json +0 -12
  149. package/pi/keybindings.json +0 -3
  150. package/pi/settings.json +0 -34
  151. package/pnpm-workspace.yaml +0 -14
  152. package/skills/planning/create-task/scripts/package.json +0 -14
  153. package/skills/planning/create-task/scripts/pnpm-lock.yaml +0 -342
  154. package/skills/planning/create-task/scripts/tsconfig.json +0 -12
  155. package/skills/planning/record-idea/scripts/new-idea.sh +0 -89
  156. package/skills/productivity/validate-agent-dir/scripts/package.json +0 -15
  157. package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +0 -329
  158. package/skills/productivity/validate-agent-dir/scripts/pnpm-workspace.yaml +0 -2
  159. package/skills/productivity/validate-agent-dir/scripts/tsconfig.json +0 -19
  160. package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.test.ts +0 -317
  161. package/skills/workflow/run-pipeline-stage/REFERENCE.md +0 -22
  162. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +0 -682
  163. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +0 -588
  164. package/skills/workflow/run-pipeline-stage/scripts/package.json +0 -15
  165. package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +0 -342
  166. package/skills/workflow/run-pipeline-stage/scripts/pnpm-workspace.yaml +0 -2
  167. package/skills/workflow/run-pipeline-stage/scripts/tsconfig.json +0 -12
  168. package/test/classify-bead.test.mjs +0 -277
  169. package/test/claude-installer.test.mjs +0 -308
  170. package/test/cli.test.mjs +0 -314
  171. package/test/create-chores.test.mjs +0 -85
  172. package/test/fake-bd.test.mjs +0 -72
  173. package/test/fs.test.mjs +0 -76
  174. package/test/helpers/fake-bd.mjs +0 -87
  175. package/test/helpers/fake-claude.mjs +0 -152
  176. package/test/helpers/fake-pi.mjs +0 -132
  177. package/test/installer.test.mjs +0 -664
  178. package/test/notify-hook.test.mjs +0 -63
  179. package/test/pi-installer.test.mjs +0 -785
  180. package/test/pi-register.test.mjs +0 -342
  181. package/test/pi-sweep.test.mjs +0 -619
  182. package/test/release-gates.test.mjs +0 -190
  183. package/test/verify-worker-tree.test.mjs +0 -120
@@ -1,190 +0,0 @@
1
- // Behaviour tests for the release gates that keep `main` from re-publishing a
2
- // version: the inverted PR changeset gate and the no-publish release gate.
3
- // The decision logic is pure; the two CLI adapters are exercised through their
4
- // process boundary because that is the contract CI depends on.
5
-
6
- import { describe, it } from "node:test";
7
- import assert from "node:assert/strict";
8
- import { spawn } from "node:child_process";
9
- import { fileURLToPath } from "node:url";
10
- import {
11
- PUBLISH_COMMAND,
12
- NO_PUBLISH_COMMAND,
13
- evaluateChangesetGate,
14
- parseNameStatus,
15
- resolvePublishCommand,
16
- } from "../scripts/lib/release-gates.mjs";
17
-
18
- const CHECK_CHANGESET = fileURLToPath(new URL("../scripts/check-changeset.mjs", import.meta.url));
19
- const RESOLVE_PUBLISH = fileURLToPath(
20
- new URL("../scripts/resolve-publish-command.mjs", import.meta.url),
21
- );
22
-
23
- function runScript(script, { args = [], env = {}, stdin = "" } = {}) {
24
- return new Promise((resolve, reject) => {
25
- const child = spawn(process.execPath, [script, ...args], {
26
- env: { ...process.env, ...env },
27
- });
28
- let stdout = "";
29
- let stderr = "";
30
- child.stdout.on("data", (chunk) => {
31
- stdout += chunk;
32
- });
33
- child.stderr.on("data", (chunk) => {
34
- stderr += chunk;
35
- });
36
- child.on("error", reject);
37
- child.on("close", (code) => resolve({ code, stdout, stderr }));
38
- child.stdin.end(stdin);
39
- });
40
- }
41
-
42
- describe("parseNameStatus", () => {
43
- it("parses added and modified paths from git diff --name-status output", () => {
44
- const changes = parseNameStatus("M\tpackage.json\nA\t.changeset/fix-release.md\n");
45
-
46
- assert.deepEqual(changes, [
47
- { status: "M", path: "package.json" },
48
- { status: "A", path: ".changeset/fix-release.md" },
49
- ]);
50
- });
51
-
52
- it("uses the new path for a rename", () => {
53
- const changes = parseNameStatus("R087\t.changeset/old.md\t.changeset/new.md\n");
54
-
55
- assert.deepEqual(changes, [{ status: "R", path: ".changeset/new.md" }]);
56
- });
57
-
58
- it("returns no changes for empty output", () => {
59
- assert.deepEqual(parseNameStatus(""), []);
60
- });
61
- });
62
-
63
- describe("evaluateChangesetGate", () => {
64
- it("passes a PR that adds a changeset", () => {
65
- const result = evaluateChangesetGate({
66
- changes: [{ status: "A", path: ".changeset/fix-release.md" }],
67
- labels: [],
68
- headRef: "fix/release-gate",
69
- actor: "jaybeeuu",
70
- });
71
-
72
- assert.deepEqual(result, { ok: true, reason: "changeset-added" });
73
- });
74
-
75
- it("fails a CI-only change that adds no changeset", () => {
76
- const result = evaluateChangesetGate({
77
- changes: [{ status: "M", path: ".github/workflows/ci.yml" }],
78
- labels: [],
79
- headRef: "chore/bump-pnpm",
80
- actor: "jaybeeuu",
81
- });
82
-
83
- assert.equal(result.ok, false);
84
- assert.equal(result.reason, "missing-changeset");
85
- });
86
-
87
- it("fails a PR that only modifies an existing changeset", () => {
88
- const result = evaluateChangesetGate({
89
- changes: [{ status: "M", path: ".changeset/pending.md" }],
90
- labels: [],
91
- headRef: "chore/edit-changeset",
92
- actor: "jaybeeuu",
93
- });
94
-
95
- assert.equal(result.ok, false);
96
- });
97
-
98
- it("fails a PR that only adds the changeset README", () => {
99
- const result = evaluateChangesetGate({
100
- changes: [{ status: "A", path: ".changeset/README.md" }],
101
- labels: [],
102
- headRef: "docs/changesets",
103
- actor: "jaybeeuu",
104
- });
105
-
106
- assert.equal(result.ok, false);
107
- });
108
-
109
- it("passes an unlabelled-change PR carrying the no-publish label", () => {
110
- const result = evaluateChangesetGate({
111
- changes: [{ status: "M", path: ".github/workflows/ci.yml" }],
112
- labels: ["no-publish"],
113
- headRef: "chore/bump-pnpm",
114
- actor: "jaybeeuu",
115
- });
116
-
117
- assert.deepEqual(result, { ok: true, reason: "no-publish-label" });
118
- });
119
-
120
- it("passes the Version Packages PR by head branch", () => {
121
- const result = evaluateChangesetGate({
122
- changes: [{ status: "M", path: "package.json" }],
123
- labels: [],
124
- headRef: "changeset-release/main",
125
- actor: "jaybeeuu",
126
- });
127
-
128
- assert.deepEqual(result, { ok: true, reason: "version-packages-pr" });
129
- });
130
-
131
- it("passes a PR opened by the GitHub Actions bot", () => {
132
- const result = evaluateChangesetGate({
133
- changes: [{ status: "M", path: "package.json" }],
134
- labels: [],
135
- headRef: "automation/some-branch",
136
- actor: "github-actions[bot]",
137
- });
138
-
139
- assert.deepEqual(result, { ok: true, reason: "version-packages-pr" });
140
- });
141
- });
142
-
143
- describe("resolvePublishCommand", () => {
144
- it("publishes by default when the merged PR has no labels", () => {
145
- assert.equal(resolvePublishCommand([]), PUBLISH_COMMAND);
146
- });
147
-
148
- it("publishes when the merged PR carries unrelated labels", () => {
149
- assert.equal(resolvePublishCommand(["bug", "priority:p2"]), PUBLISH_COMMAND);
150
- });
151
-
152
- it("refuses to publish when the merged PR carries the no-publish label", () => {
153
- assert.equal(resolvePublishCommand(["bug", "no-publish"]), NO_PUBLISH_COMMAND);
154
- });
155
-
156
- it("matches the label exactly, not as a substring", () => {
157
- assert.equal(resolvePublishCommand(["no-publish-ci"]), PUBLISH_COMMAND);
158
- });
159
- });
160
-
161
- describe("check-changeset CLI", () => {
162
- it("exits 0 for a no-publish PR with no diff", async () => {
163
- const { code } = await runScript(CHECK_CHANGESET, {
164
- env: { PR_LABELS: '["no-publish"]', PR_HEAD_REF: "chore/bump-pnpm", PR_ACTOR: "jaybeeuu" },
165
- });
166
-
167
- assert.equal(code, 0);
168
- });
169
-
170
- it("exits 1 and explains the no-publish escape hatch for a changeset-less PR", async () => {
171
- const { code, stderr } = await runScript(CHECK_CHANGESET, {
172
- stdin: "M\tpackage.json\n",
173
- env: { PR_LABELS: "[]", PR_HEAD_REF: "chore/bump-pnpm", PR_ACTOR: "jaybeeuu" },
174
- });
175
-
176
- assert.equal(code, 1);
177
- assert.match(stderr, /no-publish/);
178
- });
179
- });
180
-
181
- describe("resolve-publish-command CLI", () => {
182
- it("prints the noop command for a no-publish label set", async () => {
183
- const { code, stdout } = await runScript(RESOLVE_PUBLISH, {
184
- args: ['["no-publish"]'],
185
- });
186
-
187
- assert.equal(code, 0);
188
- assert.equal(stdout.trim(), NO_PUBLISH_COMMAND);
189
- });
190
- });
@@ -1,120 +0,0 @@
1
- // Integration tests for scripts/lib/verify-worker-tree.mjs. The module exists to
2
- // tell a worker that delivered from one that only said it did, so each case runs
3
- // a real git repository and asserts the verdict — no mocking of git, because git
4
- // is the thing whose state the verdict is about.
5
-
6
- import { describe, it } from "node:test";
7
- import assert from "node:assert/strict";
8
- import { execFile } from "node:child_process";
9
- import { mkdtemp, writeFile, rm } from "node:fs/promises";
10
- import { tmpdir } from "node:os";
11
- import { join } from "node:path";
12
- import { promisify } from "node:util";
13
-
14
- import { verifyWorkerTree } from "../scripts/lib/verify-worker-tree.mjs";
15
-
16
- const execFileAsync = promisify(execFile);
17
-
18
- /** Run a git command in `cwd`. */
19
- async function git(cwd, args) {
20
- await execFileAsync("git", args, { cwd });
21
- }
22
-
23
- /** A repository with one base commit; returns its directory and that commit. */
24
- async function createRepo() {
25
- const dir = await mkdtemp(join(tmpdir(), "verify-worker-tree-"));
26
- await git(dir, ["init", "--quiet"]);
27
- await git(dir, ["config", "user.email", "t@example.com"]);
28
- await git(dir, ["config", "user.name", "T"]);
29
- // A developer's global config may enable commit signing; the fixture must not
30
- // depend on a secret key being present.
31
- await git(dir, ["config", "commit.gpgsign", "false"]);
32
- await writeFile(join(dir, "README.md"), "base\n");
33
- await git(dir, ["add", "-A"]);
34
- await git(dir, ["commit", "-m", "base"]);
35
- const { stdout } = await execFileAsync("git", ["rev-parse", "HEAD"], { cwd: dir });
36
- return { dir, base: stdout.trim() };
37
- }
38
-
39
- /** Commit a file in the repo, as a delivering worker would. */
40
- async function commitWork(dir) {
41
- await writeFile(join(dir, "worker-output.txt"), "delivered\n");
42
- await git(dir, ["add", "-A"]);
43
- await git(dir, ["commit", "-m", "worker: deliver"]);
44
- }
45
-
46
- describe("verifyWorkerTree", () => {
47
- it("passes a worker that committed and left a clean tree", async () => {
48
- const { dir, base } = await createRepo();
49
- try {
50
- await commitWork(dir);
51
-
52
- const verdict = await verifyWorkerTree({ worktree: dir, base });
53
-
54
- assert.deepEqual(verdict, { ok: true, reasons: [], commitsAhead: 1 });
55
- } finally {
56
- await rm(dir, { recursive: true, force: true });
57
- }
58
- });
59
-
60
- it("fails a worker that reported success but left its work uncommitted", async () => {
61
- const { dir, base } = await createRepo();
62
- try {
63
- await writeFile(join(dir, "left-behind.txt"), "uncommitted\n");
64
-
65
- const verdict = await verifyWorkerTree({ worktree: dir, base });
66
-
67
- assert.equal(verdict.ok, false);
68
- assert.equal(verdict.reasons[0], "worktree is dirty: 1 uncommitted path(s)");
69
- assert.equal(verdict.commitsAhead, 0);
70
- } finally {
71
- await rm(dir, { recursive: true, force: true });
72
- }
73
- });
74
-
75
- it("fails a worker that left a clean tree with nothing committed", async () => {
76
- const { dir, base } = await createRepo();
77
- try {
78
- const verdict = await verifyWorkerTree({ worktree: dir, base });
79
-
80
- assert.equal(verdict.ok, false);
81
- assert.equal(verdict.reasons.length, 1);
82
- assert.match(verdict.reasons[0], /^no commit ahead of base [0-9a-f]{7}$/);
83
- } finally {
84
- await rm(dir, { recursive: true, force: true });
85
- }
86
- });
87
-
88
- it("reports a dirty tree and a missing commit together", async () => {
89
- const { dir, base } = await createRepo();
90
- try {
91
- await writeFile(join(dir, "partial.txt"), "half done\n");
92
-
93
- const verdict = await verifyWorkerTree({ worktree: dir, base });
94
-
95
- assert.equal(verdict.ok, false);
96
- assert.equal(verdict.reasons.length, 2);
97
- assert.equal(verdict.reasons[0], "worktree is dirty: 1 uncommitted path(s)");
98
- assert.match(verdict.reasons[1], /^no commit ahead of base [0-9a-f]{7}$/);
99
- } finally {
100
- await rm(dir, { recursive: true, force: true });
101
- }
102
- });
103
-
104
- it("counts every commit the worker made, not just the last", async () => {
105
- const { dir, base } = await createRepo();
106
- try {
107
- await commitWork(dir);
108
- await writeFile(join(dir, "second.txt"), "more\n");
109
- await git(dir, ["add", "-A"]);
110
- await git(dir, ["commit", "-m", "worker: second"]);
111
-
112
- const verdict = await verifyWorkerTree({ worktree: dir, base });
113
-
114
- assert.equal(verdict.ok, true);
115
- assert.equal(verdict.commitsAhead, 2);
116
- } finally {
117
- await rm(dir, { recursive: true, force: true });
118
- }
119
- });
120
- });