infinity-harness 2.8.9 → 2.8.11

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 (192) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/extensions/infinity-harness/index.js +3614 -0
  3. package/dist/extensions/infinity-harness/index.js.map +1 -0
  4. package/dist/src/approval.js +154 -0
  5. package/dist/src/approval.js.map +1 -0
  6. package/dist/src/core/brief.js +309 -0
  7. package/dist/src/core/brief.js.map +1 -0
  8. package/dist/src/core/config.js +539 -0
  9. package/dist/src/core/config.js.map +1 -0
  10. package/dist/src/core/exec.js +106 -0
  11. package/dist/src/core/exec.js.map +1 -0
  12. package/dist/src/core/featureList.js +365 -0
  13. package/dist/src/core/featureList.js.map +1 -0
  14. package/dist/src/core/fsx.js +123 -0
  15. package/dist/src/core/fsx.js.map +1 -0
  16. package/dist/src/core/gates.js +490 -0
  17. package/dist/src/core/gates.js.map +1 -0
  18. package/dist/src/core/init.js +480 -0
  19. package/dist/src/core/init.js.map +1 -0
  20. package/dist/src/core/lock.js +183 -0
  21. package/dist/src/core/lock.js.map +1 -0
  22. package/dist/src/core/modelRouter.js +185 -0
  23. package/dist/src/core/modelRouter.js.map +1 -0
  24. package/dist/src/core/paths.js +129 -0
  25. package/dist/src/core/paths.js.map +1 -0
  26. package/dist/src/core/phases.js +254 -0
  27. package/dist/src/core/phases.js.map +1 -0
  28. package/dist/src/core/plan.js +15 -0
  29. package/dist/src/core/plan.js.map +1 -0
  30. package/dist/src/core/runState.js +126 -0
  31. package/dist/src/core/runState.js.map +1 -0
  32. package/dist/src/core/settings.js +877 -0
  33. package/dist/src/core/settings.js.map +1 -0
  34. package/dist/src/core/skills.js +319 -0
  35. package/dist/src/core/skills.js.map +1 -0
  36. package/dist/src/core/skillsAudit.js +194 -0
  37. package/dist/src/core/skillsAudit.js.map +1 -0
  38. package/dist/src/core/types.js +77 -0
  39. package/dist/src/core/types.js.map +1 -0
  40. package/dist/src/daemon/budget.js +85 -0
  41. package/dist/src/daemon/budget.js.map +1 -0
  42. package/dist/src/daemon/guard.js +122 -0
  43. package/dist/src/daemon/guard.js.map +1 -0
  44. package/dist/src/daemon/index.js +461 -0
  45. package/dist/src/daemon/index.js.map +1 -0
  46. package/dist/src/daemon/isolation.js +84 -0
  47. package/dist/src/daemon/isolation.js.map +1 -0
  48. package/dist/src/daemon/preflight.js +131 -0
  49. package/dist/src/daemon/preflight.js.map +1 -0
  50. package/dist/src/daemon/server.js +174 -0
  51. package/dist/src/daemon/server.js.map +1 -0
  52. package/dist/src/daemon/supervisorState.js +42 -0
  53. package/dist/src/daemon/supervisorState.js.map +1 -0
  54. package/dist/src/daemon/worker.js +239 -0
  55. package/dist/src/daemon/worker.js.map +1 -0
  56. package/dist/src/daemon/worktree.js +102 -0
  57. package/dist/src/daemon/worktree.js.map +1 -0
  58. package/dist/src/escalate.js +312 -0
  59. package/dist/src/escalate.js.map +1 -0
  60. package/dist/src/exec/piWorker.js +630 -0
  61. package/dist/src/exec/piWorker.js.map +1 -0
  62. package/dist/src/goal.js +317 -0
  63. package/dist/src/goal.js.map +1 -0
  64. package/dist/src/goalLoop.js +374 -0
  65. package/dist/src/goalLoop.js.map +1 -0
  66. package/dist/src/goalSpec.js +397 -0
  67. package/dist/src/goalSpec.js.map +1 -0
  68. package/dist/src/goalState.js +255 -0
  69. package/dist/src/goalState.js.map +1 -0
  70. package/dist/src/handoff.js +205 -0
  71. package/dist/src/handoff.js.map +1 -0
  72. package/dist/src/intake.js +203 -0
  73. package/dist/src/intake.js.map +1 -0
  74. package/dist/src/loop.js +592 -0
  75. package/dist/src/loop.js.map +1 -0
  76. package/dist/src/modelRouter.js +216 -0
  77. package/dist/src/modelRouter.js.map +1 -0
  78. package/dist/src/remote.js +246 -0
  79. package/dist/src/remote.js.map +1 -0
  80. package/dist/src/replan.js +262 -0
  81. package/dist/src/replan.js.map +1 -0
  82. package/dist/src/review.js +54 -0
  83. package/dist/src/review.js.map +1 -0
  84. package/dist/src/rework.js +241 -0
  85. package/dist/src/rework.js.map +1 -0
  86. package/dist/src/runState.js +4 -0
  87. package/dist/src/runState.js.map +1 -0
  88. package/dist/src/scheduler.js +270 -0
  89. package/dist/src/scheduler.js.map +1 -0
  90. package/dist/src/supervisor.js +787 -0
  91. package/dist/src/supervisor.js.map +1 -0
  92. package/dist/src/taskList.js +430 -0
  93. package/dist/src/taskList.js.map +1 -0
  94. package/dist/src/ui/config.js +268 -0
  95. package/dist/src/ui/config.js.map +1 -0
  96. package/dist/src/ui/dashboard.js +1288 -0
  97. package/dist/src/ui/dashboard.js.map +1 -0
  98. package/dist/src/ui/display.js +229 -0
  99. package/dist/src/ui/display.js.map +1 -0
  100. package/dist/src/ui/planTree.js +219 -0
  101. package/dist/src/ui/planTree.js.map +1 -0
  102. package/dist/src/ui/theme.js +298 -0
  103. package/dist/src/ui/theme.js.map +1 -0
  104. package/dist/src/ui/viewState.js +65 -0
  105. package/dist/src/ui/viewState.js.map +1 -0
  106. package/dist/src/ui/widget.js +721 -0
  107. package/dist/src/ui/widget.js.map +1 -0
  108. package/dist/src/ui/wizard.js +540 -0
  109. package/dist/src/ui/wizard.js.map +1 -0
  110. package/dist/src/unstuck.js +210 -0
  111. package/dist/src/unstuck.js.map +1 -0
  112. package/dist/src/worker.js +267 -0
  113. package/dist/src/worker.js.map +1 -0
  114. package/dist/src/workflow.js +250 -0
  115. package/dist/src/workflow.js.map +1 -0
  116. package/dist/tests/approval.test.js +144 -0
  117. package/dist/tests/approval.test.js.map +1 -0
  118. package/dist/tests/brief.test.js +271 -0
  119. package/dist/tests/brief.test.js.map +1 -0
  120. package/dist/tests/config.test.js +320 -0
  121. package/dist/tests/config.test.js.map +1 -0
  122. package/dist/tests/dashboard.test.js +277 -0
  123. package/dist/tests/dashboard.test.js.map +1 -0
  124. package/dist/tests/display.test.js +229 -0
  125. package/dist/tests/display.test.js.map +1 -0
  126. package/dist/tests/escalate.test.js +272 -0
  127. package/dist/tests/escalate.test.js.map +1 -0
  128. package/dist/tests/featureList.test.js +429 -0
  129. package/dist/tests/featureList.test.js.map +1 -0
  130. package/dist/tests/gates.test.js +333 -0
  131. package/dist/tests/gates.test.js.map +1 -0
  132. package/dist/tests/goal.test.js +229 -0
  133. package/dist/tests/goal.test.js.map +1 -0
  134. package/dist/tests/goalLoop.test.js +170 -0
  135. package/dist/tests/goalLoop.test.js.map +1 -0
  136. package/dist/tests/goalSpec.test.js +146 -0
  137. package/dist/tests/goalSpec.test.js.map +1 -0
  138. package/dist/tests/goalState.test.js +202 -0
  139. package/dist/tests/goalState.test.js.map +1 -0
  140. package/dist/tests/handoff.test.js +127 -0
  141. package/dist/tests/handoff.test.js.map +1 -0
  142. package/dist/tests/init.test.js +264 -0
  143. package/dist/tests/init.test.js.map +1 -0
  144. package/dist/tests/intake.test.js +288 -0
  145. package/dist/tests/intake.test.js.map +1 -0
  146. package/dist/tests/loop.test.js +453 -0
  147. package/dist/tests/loop.test.js.map +1 -0
  148. package/dist/tests/modelRouter.test.js +131 -0
  149. package/dist/tests/modelRouter.test.js.map +1 -0
  150. package/dist/tests/phases.test.js +244 -0
  151. package/dist/tests/phases.test.js.map +1 -0
  152. package/dist/tests/planTree.test.js +190 -0
  153. package/dist/tests/planTree.test.js.map +1 -0
  154. package/dist/tests/remote.test.js +380 -0
  155. package/dist/tests/remote.test.js.map +1 -0
  156. package/dist/tests/replan.test.js +113 -0
  157. package/dist/tests/replan.test.js.map +1 -0
  158. package/dist/tests/review.test.js +77 -0
  159. package/dist/tests/review.test.js.map +1 -0
  160. package/dist/tests/rework.test.js +109 -0
  161. package/dist/tests/rework.test.js.map +1 -0
  162. package/dist/tests/routing-live.test.js +121 -0
  163. package/dist/tests/routing-live.test.js.map +1 -0
  164. package/dist/tests/runState.test.js +73 -0
  165. package/dist/tests/runState.test.js.map +1 -0
  166. package/dist/tests/settings.test.js +311 -0
  167. package/dist/tests/settings.test.js.map +1 -0
  168. package/dist/tests/skills.test.js +387 -0
  169. package/dist/tests/skills.test.js.map +1 -0
  170. package/dist/tests/supervisor.test.js +437 -0
  171. package/dist/tests/supervisor.test.js.map +1 -0
  172. package/dist/tests/surface.test.js +203 -0
  173. package/dist/tests/surface.test.js.map +1 -0
  174. package/dist/tests/taskList.test.js +376 -0
  175. package/dist/tests/taskList.test.js.map +1 -0
  176. package/dist/tests/theme.test.js +149 -0
  177. package/dist/tests/theme.test.js.map +1 -0
  178. package/dist/tests/unstuck.test.js +268 -0
  179. package/dist/tests/unstuck.test.js.map +1 -0
  180. package/dist/tests/widget.test.js +424 -0
  181. package/dist/tests/widget.test.js.map +1 -0
  182. package/dist/tests/worker.test.js +306 -0
  183. package/dist/tests/worker.test.js.map +1 -0
  184. package/dist/tests/workflow.test.js +187 -0
  185. package/dist/tests/workflow.test.js.map +1 -0
  186. package/extensions/infinity-harness/index.ts +39 -12
  187. package/package.json +5 -2
  188. package/src/core/modelRouter.ts +23 -1
  189. package/src/daemon/index.ts +3 -3
  190. package/src/daemon/worker.ts +28 -5
  191. package/src/ui/config.ts +25 -1
  192. package/src/ui/wizard.ts +10 -5
@@ -0,0 +1,453 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync, mkdirSync, writeFileSync, readFileSync, existsSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { DEFAULT_MAX_ITERATIONS, DEFAULT_MAX_WALL_CLOCK_MS, DEFAULT_NO_PROGRESS_LIMIT, budgetFrom, decideNext, describeDecision, fingerprint, loadLoopState, loopStatePath, newLoopState, saveLoopState, stopFilePath, } from "../src/loop.js";
6
+ import { defaultConfig, loadConfig } from "../src/core/config.js";
7
+ function mkTask(id, status) {
8
+ return { id, description: `Do ${id}`, status, dependsOn: [], subtasks: [] };
9
+ }
10
+ function plan(tasks, baseRevision = 1) {
11
+ return {
12
+ version: "2.0",
13
+ baseRevision,
14
+ goals: [{ id: "goal-001", title: "Ship it" }],
15
+ sprints: [],
16
+ features: [{ id: "feature-001", name: "F", criteria: ["works"], tasks }],
17
+ };
18
+ }
19
+ function tmpProject(mutate = () => { }, list = plan([mkTask("task-1", "pending")])) {
20
+ const d = mkdtempSync(join(tmpdir(), "pi-loop-"));
21
+ mkdirSync(join(d, "harness", "features"), { recursive: true });
22
+ const c = defaultConfig();
23
+ c.currentPhase = "build";
24
+ mutate(c);
25
+ writeFileSync(join(d, "harness", "config.json"), JSON.stringify(c, null, 2), "utf-8");
26
+ if (list)
27
+ writeFileSync(join(d, "harness", "features", "feature-list.json"), JSON.stringify(list, null, 2), "utf-8");
28
+ return d;
29
+ }
30
+ function writePlan(dir, list) {
31
+ writeFileSync(join(dir, "harness", "features", "feature-list.json"), JSON.stringify(list, null, 2), "utf-8");
32
+ }
33
+ const RUN = "run-under-test";
34
+ // ── paths and state bookkeeping ────────────────────────────────────────────
35
+ {
36
+ const dir = tmpProject();
37
+ try {
38
+ assert.equal(loopStatePath(dir), join(dir, "harness", "loop-state.json"));
39
+ assert.equal(stopFilePath(dir), join(dir, "harness", "STOP"));
40
+ const now = new Date("2026-01-01T00:00:00.000Z");
41
+ const fresh = newLoopState(RUN, now);
42
+ assert.deepEqual(fresh, {
43
+ runId: RUN,
44
+ startedAt: "2026-01-01T00:00:00.000Z",
45
+ iterations: 0,
46
+ lastFingerprint: null,
47
+ noProgressStreak: 0,
48
+ lastPhase: null,
49
+ lastDecision: null,
50
+ stoppedAt: null,
51
+ stopReason: null,
52
+ escalation: { consultedCount: 0, masterUsed: false, lastUnstuckAt: null, fingerprints: [], tried: [] },
53
+ perLevelEscalation: {},
54
+ escalations: [],
55
+ });
56
+ // Nothing on disk yet: a fresh state is synthesised.
57
+ assert.deepEqual(loadLoopState(dir, RUN, now), fresh);
58
+ const used = { ...fresh, iterations: 12, noProgressStreak: 2, lastFingerprint: "abc" };
59
+ saveLoopState(dir, used);
60
+ assert.deepEqual(loadLoopState(dir, RUN, now), used, "state round-trips through disk");
61
+ // A different run must not inherit the previous run's budget.
62
+ const other = loadLoopState(dir, "some-other-run", now);
63
+ assert.equal(other.iterations, 0);
64
+ assert.equal(other.runId, "some-other-run");
65
+ // A corrupt state file is not worth aborting a run over.
66
+ writeFileSync(loopStatePath(dir), "{ not json", "utf-8");
67
+ assert.equal(loadLoopState(dir, RUN, now).iterations, 0, "a corrupt loop state restarts the budget");
68
+ console.log("✓ loop state paths, defaults and persistence");
69
+ }
70
+ finally {
71
+ rmSync(dir, { recursive: true, force: true });
72
+ }
73
+ }
74
+ // ── budgetFrom ─────────────────────────────────────────────────────────────
75
+ {
76
+ assert.deepEqual(budgetFrom(defaultConfig()), {
77
+ maxIterations: DEFAULT_MAX_ITERATIONS,
78
+ maxWallClockMs: DEFAULT_MAX_WALL_CLOCK_MS,
79
+ noProgressLimit: DEFAULT_NO_PROGRESS_LIMIT,
80
+ });
81
+ const c = defaultConfig();
82
+ c.loop = { maxIterations: 7, maxWallClockMs: 60_000, noProgressLimit: 2 };
83
+ assert.deepEqual(budgetFrom(c), { maxIterations: 7, maxWallClockMs: 60_000, noProgressLimit: 2 });
84
+ // Nonsense never silently disables a guard.
85
+ for (const bad of [0, -1, "10", null, Number.NaN, Number.POSITIVE_INFINITY]) {
86
+ const junk = defaultConfig();
87
+ // Deliberately ill-typed: this is what a hand-edited config can contain.
88
+ junk.loop = { maxIterations: bad, maxWallClockMs: bad, noProgressLimit: bad };
89
+ assert.deepEqual(budgetFrom(junk), {
90
+ maxIterations: DEFAULT_MAX_ITERATIONS,
91
+ maxWallClockMs: DEFAULT_MAX_WALL_CLOCK_MS,
92
+ noProgressLimit: DEFAULT_NO_PROGRESS_LIMIT,
93
+ }, `${JSON.stringify(bad)} falls back to the default budget`);
94
+ }
95
+ console.log("✓ budgetFrom defaults and validation");
96
+ }
97
+ // ── fingerprint ────────────────────────────────────────────────────────────
98
+ {
99
+ const dir = tmpProject();
100
+ try {
101
+ const a = await fingerprint(dir);
102
+ assert.match(a, /^[0-9a-f]{16}$/, "a short stable hex digest");
103
+ assert.equal(await fingerprint(dir), a, "an unchanged tree fingerprints the same");
104
+ // The plan revision is part of the fingerprint: a task edit leaves no file
105
+ // trace in the working tree, but it is still progress.
106
+ writePlan(dir, plan([mkTask("task-1", "pending")], 2));
107
+ const b = await fingerprint(dir);
108
+ assert.notEqual(b, a, "a changed baseRevision changes the fingerprint");
109
+ // So is the shape of the plan itself.
110
+ writePlan(dir, plan([mkTask("task-1", "in_progress")], 2));
111
+ const c = await fingerprint(dir);
112
+ assert.notEqual(c, b, "a changed task status changes the fingerprint");
113
+ writePlan(dir, plan([mkTask("task-1", "pending")], 2));
114
+ assert.equal(await fingerprint(dir), b, "reverting the change reverts the fingerprint");
115
+ console.log("✓ fingerprint tracks the plan revision and task statuses");
116
+ }
117
+ finally {
118
+ rmSync(dir, { recursive: true, force: true });
119
+ }
120
+ }
121
+ // ── human brakes: the stop file wins over everything ───────────────────────
122
+ {
123
+ const dir = tmpProject();
124
+ try {
125
+ writeFileSync(stopFilePath(dir), "", "utf-8");
126
+ const { decision, state } = await decideNext({ targetDir: dir, runId: RUN });
127
+ assert.equal(decision.action, "stop");
128
+ assert.equal(decision.reason, "stop-file");
129
+ assert.match(decision.detail, /harness\/STOP exists — delete it to resume/);
130
+ assert.equal(state.stopReason, "stop-file");
131
+ assert.ok(state.stoppedAt, "the stop is timestamped");
132
+ // The stop is persisted so the next process sees why the run ended.
133
+ const persisted = JSON.parse(readFileSync(loopStatePath(dir), "utf-8"));
134
+ assert.equal(persisted.stopReason, "stop-file");
135
+ assert.equal(persisted.lastDecision, "stop");
136
+ console.log("✓ the stop file stops the loop");
137
+ }
138
+ finally {
139
+ rmSync(dir, { recursive: true, force: true });
140
+ }
141
+ }
142
+ // ── the stop file is checked before the config is even read ────────────────
143
+ {
144
+ const dir = mkdtempSync(join(tmpdir(), "pi-loop-bare-"));
145
+ try {
146
+ mkdirSync(join(dir, "harness"), { recursive: true });
147
+ writeFileSync(stopFilePath(dir), "", "utf-8");
148
+ const { decision } = await decideNext({ targetDir: dir, runId: RUN });
149
+ assert.equal(decision.reason, "stop-file", "a human brake outranks every other condition");
150
+ }
151
+ finally {
152
+ rmSync(dir, { recursive: true, force: true });
153
+ }
154
+ // …and with no stop file, a project with no config stops rather than guessing.
155
+ const bare = mkdtempSync(join(tmpdir(), "pi-loop-noconfig-"));
156
+ try {
157
+ const { decision } = await decideNext({ targetDir: bare, runId: RUN });
158
+ assert.equal(decision.action, "stop");
159
+ assert.equal(decision.reason, "no-config");
160
+ assert.match(decision.detail, /config.json is missing or unreadable/);
161
+ }
162
+ finally {
163
+ rmSync(bare, { recursive: true, force: true });
164
+ }
165
+ // A corrupt config is the same story: stop, do not run blind.
166
+ const corrupt = mkdtempSync(join(tmpdir(), "pi-loop-corrupt-"));
167
+ try {
168
+ mkdirSync(join(corrupt, "harness"), { recursive: true });
169
+ writeFileSync(join(corrupt, "harness", "config.json"), "{ broken", "utf-8");
170
+ const { decision } = await decideNext({ targetDir: corrupt, runId: RUN });
171
+ assert.equal(decision.action, "stop");
172
+ assert.equal(decision.reason, "no-config");
173
+ }
174
+ finally {
175
+ rmSync(corrupt, { recursive: true, force: true });
176
+ }
177
+ console.log("✓ missing or unreadable config stops the loop");
178
+ }
179
+ // ── paused waits rather than stops ─────────────────────────────────────────
180
+ {
181
+ const dir = tmpProject((c) => {
182
+ c.paused = true;
183
+ });
184
+ try {
185
+ const { decision, state } = await decideNext({ targetDir: dir, runId: RUN });
186
+ assert.equal(decision.action, "wait", "a pause is resumable, so it is a wait and not a stop");
187
+ assert.equal(decision.reason, "paused");
188
+ assert.match(decision.detail, /paused/i);
189
+ assert.equal(state.stopReason, null, "waiting does not end the run");
190
+ assert.equal(state.stoppedAt, null);
191
+ console.log("✓ paused waits");
192
+ }
193
+ finally {
194
+ rmSync(dir, { recursive: true, force: true });
195
+ }
196
+ }
197
+ // ── terminal: the pipeline finished ────────────────────────────────────────
198
+ {
199
+ const dir = tmpProject((c) => {
200
+ c.currentPhase = "ship";
201
+ }, plan([mkTask("task-1", "complete"), mkTask("task-2", "complete")]));
202
+ try {
203
+ const { decision } = await decideNext({ targetDir: dir, runId: RUN });
204
+ assert.equal(decision.action, "stop");
205
+ assert.equal(decision.reason, "complete");
206
+ assert.match(decision.detail, /Pipeline complete: 2\/2 tasks across 1 feature\(s\)/);
207
+ console.log("✓ a finished pipeline stops");
208
+ }
209
+ finally {
210
+ rmSync(dir, { recursive: true, force: true });
211
+ }
212
+ }
213
+ // ── the retry budget ends the run ──────────────────────────────────────────
214
+ {
215
+ const dir = tmpProject((c) => {
216
+ c.maxRetries = 5;
217
+ c.taskRetryCount = 5;
218
+ });
219
+ try {
220
+ const { decision } = await decideNext({ targetDir: dir, runId: RUN });
221
+ assert.equal(decision.action, "stop");
222
+ assert.equal(decision.reason, "retry-budget");
223
+ assert.match(decision.detail, /The task retry budget is exhausted/);
224
+ assert.match(decision.detail, /A human needs to look at this/);
225
+ console.log("✓ an exhausted retry budget stops the loop");
226
+ }
227
+ finally {
228
+ rmSync(dir, { recursive: true, force: true });
229
+ }
230
+ }
231
+ // ── the iteration ceiling ends the run ─────────────────────────────────────
232
+ {
233
+ const dir = tmpProject((c) => {
234
+ c.loop = { ...c.loop, maxIterations: 10 };
235
+ });
236
+ try {
237
+ saveLoopState(dir, { ...newLoopState(RUN), iterations: 10 });
238
+ const { decision, state } = await decideNext({ targetDir: dir, runId: RUN });
239
+ assert.equal(decision.action, "stop");
240
+ assert.equal(decision.reason, "max-iterations");
241
+ assert.match(decision.detail, /Reached the 10-iteration ceiling/);
242
+ assert.equal(state.iterations, 11, "the iteration that tripped the ceiling is still counted");
243
+ // One under the ceiling, the loop keeps going.
244
+ saveLoopState(dir, { ...newLoopState(RUN), iterations: 8 });
245
+ const under = await decideNext({ targetDir: dir, runId: RUN });
246
+ assert.notEqual(under.decision.reason, "max-iterations", "9 of 10 is not the ceiling");
247
+ console.log("✓ the iteration ceiling stops the loop");
248
+ }
249
+ finally {
250
+ rmSync(dir, { recursive: true, force: true });
251
+ }
252
+ }
253
+ // ── the wall-clock budget ends the run ─────────────────────────────────────
254
+ {
255
+ const dir = tmpProject();
256
+ try {
257
+ const old = newLoopState(RUN, new Date(Date.now() - 48 * 60 * 60 * 1000));
258
+ saveLoopState(dir, old);
259
+ const { decision } = await decideNext({ targetDir: dir, runId: RUN });
260
+ assert.equal(decision.action, "stop");
261
+ assert.equal(decision.reason, "max-wall-clock");
262
+ assert.match(decision.detail, /Run exceeded its 24.0h wall-clock budget/);
263
+ // A run that started an hour ago is well inside the default budget.
264
+ saveLoopState(dir, newLoopState(RUN, new Date(Date.now() - 60 * 60 * 1000)));
265
+ const fresh = await decideNext({ targetDir: dir, runId: RUN });
266
+ assert.notEqual(fresh.decision.reason, "max-wall-clock");
267
+ // A shorter configured budget bites sooner.
268
+ const cfg = loadConfig(dir).config;
269
+ cfg.loop = { ...cfg.loop, maxWallClockMs: 30 * 60 * 1000 };
270
+ writeFileSync(join(dir, "harness", "config.json"), JSON.stringify(cfg, null, 2), "utf-8");
271
+ saveLoopState(dir, newLoopState(RUN, new Date(Date.now() - 60 * 60 * 1000)));
272
+ const tight = await decideNext({ targetDir: dir, runId: RUN });
273
+ assert.equal(tight.decision.reason, "max-wall-clock");
274
+ assert.match(tight.decision.detail, /0.5h wall-clock budget/);
275
+ console.log("✓ the wall-clock budget stops the loop");
276
+ }
277
+ finally {
278
+ rmSync(dir, { recursive: true, force: true });
279
+ }
280
+ }
281
+ // ── no phase yet ───────────────────────────────────────────────────────────
282
+ {
283
+ const dir = tmpProject((c) => {
284
+ c.currentPhase = null;
285
+ });
286
+ try {
287
+ const { decision } = await decideNext({ targetDir: dir, runId: RUN });
288
+ assert.equal(decision.action, "wait");
289
+ assert.equal(decision.reason, "not-started");
290
+ assert.match(decision.detail, /Initialise the harness before running the loop/);
291
+ console.log("✓ an un-started harness waits");
292
+ }
293
+ finally {
294
+ rmSync(dir, { recursive: true, force: true });
295
+ }
296
+ }
297
+ // ── no-progress detection ──────────────────────────────────────────────────
298
+ //
299
+ // `skipEscalation` throughout: this block is about the base loop's stall
300
+ // detection, and the escalation ladder deliberately interrupts a stall to try
301
+ // something different. Both behaviours matter, so they are tested apart —
302
+ // escalate.test.ts covers what happens when the ladder is left switched on.
303
+ {
304
+ // The gate cannot pass and the tree never changes: the agent is spinning.
305
+ const dir = tmpProject((c) => {
306
+ c.commands.test = "exit 1";
307
+ c.loop = { ...c.loop, noProgressLimit: 3 };
308
+ });
309
+ try {
310
+ // The first failing iteration establishes the baseline: there is nothing
311
+ // to compare against yet, so it cannot count as a stall.
312
+ const first = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
313
+ assert.equal(first.decision.action, "continue", "the first failure is just a failure");
314
+ assert.equal(first.decision.reason, "gate failed");
315
+ assert.match(first.decision.message, /BUILD gate did not pass/);
316
+ assert.match(first.decision.message, /x tests:/, "the failing check is named");
317
+ assert.equal(first.state.noProgressStreak, 0, "no baseline yet, so no stall yet");
318
+ assert.ok(first.state.lastFingerprint, "the tree is fingerprinted for next time");
319
+ const second = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
320
+ assert.equal(second.decision.action, "continue");
321
+ assert.equal(second.state.noProgressStreak, 1, "first confirmed no-change observation");
322
+ assert.equal(second.state.lastFingerprint, first.state.lastFingerprint, "the tree really is unchanged");
323
+ const third = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
324
+ assert.equal(third.decision.action, "continue");
325
+ assert.equal(third.state.noProgressStreak, 2, "the streak grows while nothing changes");
326
+ const fourth = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
327
+ assert.equal(fourth.decision.action, "stop", "spinning is not working");
328
+ assert.equal(fourth.decision.reason, "no-progress");
329
+ const detail = fourth.decision.detail;
330
+ assert.match(detail, /failed 3 times in a row with no change to the working tree/);
331
+ assert.match(detail, /looping without making progress: tests/, "the reason the gate failed is carried through");
332
+ assert.match(detail, /Stopping so a human can intervene/);
333
+ assert.equal(fourth.state.stopReason, "no-progress");
334
+ // Each failing iteration charges a phase retry, so a configured phase
335
+ // budget bounds the run even when the tree does keep changing.
336
+ assert.ok(loadConfig(dir).config.phaseRetryCount >= 2, "failing iterations burn phase retries");
337
+ console.log("✓ no-progress detection stops a spinning loop");
338
+ }
339
+ finally {
340
+ rmSync(dir, { recursive: true, force: true });
341
+ }
342
+ }
343
+ // ── real progress resets the streak ────────────────────────────────────────
344
+ {
345
+ const dir = tmpProject((c) => {
346
+ c.commands.test = "exit 1";
347
+ c.loop = { ...c.loop, noProgressLimit: 3 };
348
+ });
349
+ try {
350
+ const one = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
351
+ assert.equal(one.state.noProgressStreak, 0, "baseline iteration");
352
+ const two = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
353
+ assert.equal(two.state.noProgressStreak, 1);
354
+ // The agent actually changed something between iterations.
355
+ writePlan(dir, plan([mkTask("task-1", "pending")], 99));
356
+ const three = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
357
+ assert.equal(three.decision.action, "continue", "a moving tree is not a stuck loop");
358
+ assert.equal(three.state.noProgressStreak, 0, "progress resets the streak");
359
+ assert.notEqual(three.state.lastFingerprint, two.state.lastFingerprint);
360
+ // …and the streak starts climbing again once it stalls.
361
+ const four = await decideNext({ targetDir: dir, runId: RUN, skipEscalation: true });
362
+ assert.equal(four.state.noProgressStreak, 1);
363
+ console.log("✓ a change to the tree resets the no-progress streak");
364
+ }
365
+ finally {
366
+ rmSync(dir, { recursive: true, force: true });
367
+ }
368
+ }
369
+ // ── a passing gate advances the phase ──────────────────────────────────────
370
+ {
371
+ const dir = tmpProject((c) => {
372
+ c.currentPhase = "build";
373
+ }, plan([mkTask("task-1", "complete")]));
374
+ try {
375
+ const { decision, state } = await decideNext({ targetDir: dir, runId: RUN });
376
+ assert.equal(decision.action, "advanced", JSON.stringify(decision));
377
+ assert.equal(decision.toPhase, "verify");
378
+ assert.match(decision.reason, /gate passed on build/);
379
+ assert.match(decision.message, /NEXT STEP · VERIFY/, "the next brief comes with it");
380
+ assert.equal(loadConfig(dir).config.currentPhase, "verify", "the advance is persisted");
381
+ assert.equal(state.noProgressStreak, 0);
382
+ // A new phase starts with no baseline: the first failure of the *next*
383
+ // phase must not be read as a stall against a fingerprint taken before
384
+ // the agent was asked to do anything.
385
+ assert.equal(state.lastFingerprint, null);
386
+ // Passing the gate on the final phase is the end of the run.
387
+ const cfg = loadConfig(dir).config;
388
+ cfg.currentPhase = "ship";
389
+ writeFileSync(join(dir, "harness", "config.json"), JSON.stringify(cfg, null, 2), "utf-8");
390
+ // On the final phase with every task done, the terminal check fires before
391
+ // the gate is ever run — that ordering is what stops a finished run from
392
+ // burning another lint/test cycle.
393
+ const done = await decideNext({ targetDir: dir, runId: RUN });
394
+ assert.equal(done.decision.action, "stop");
395
+ assert.equal(done.decision.reason, "complete");
396
+ console.log("✓ a passing gate advances the phase and issues the next brief");
397
+ }
398
+ finally {
399
+ rmSync(dir, { recursive: true, force: true });
400
+ }
401
+ }
402
+ // ── skipGate hands the decision to the caller's verdict ──
403
+ // (escalation off: this is about the guards, not the ladder)──────────────────
404
+ {
405
+ const dir = tmpProject((c) => {
406
+ c.loop = { ...c.loop, noProgressLimit: 2 };
407
+ });
408
+ try {
409
+ const first = await decideNext({ targetDir: dir, runId: RUN, skipGate: true, skipEscalation: true });
410
+ assert.equal(first.decision.action, "continue");
411
+ assert.match(first.decision.message, /\(gate not run\)/);
412
+ assert.equal(first.state.noProgressStreak, 0, "baseline iteration");
413
+ const second = await decideNext({ targetDir: dir, runId: RUN, skipGate: true, skipEscalation: true });
414
+ assert.equal(second.decision.action, "continue");
415
+ assert.equal(second.state.noProgressStreak, 1);
416
+ const third = await decideNext({ targetDir: dir, runId: RUN, skipGate: true, skipEscalation: true });
417
+ assert.equal(third.decision.action, "stop", "the no-progress guard still applies without a gate");
418
+ assert.equal(third.decision.reason, "no-progress");
419
+ assert.ok(!third.decision.detail.includes("undefined"));
420
+ assert.equal(loadConfig(dir).config.gateHistory.length, 0, "skipping the gate records no verdict");
421
+ console.log("✓ skipGate skips the gate but not the guards");
422
+ }
423
+ finally {
424
+ rmSync(dir, { recursive: true, force: true });
425
+ }
426
+ }
427
+ // ── describeDecision ───────────────────────────────────────────────────────
428
+ {
429
+ assert.equal(describeDecision({ action: "continue", message: "m", reason: "gate failed" }), "continuing — gate failed");
430
+ assert.equal(describeDecision({ action: "advanced", toPhase: "verify", message: "m", reason: "r" }), "advanced to verify");
431
+ assert.equal(describeDecision({ action: "wait", reason: "paused", detail: "it is paused" }), "waiting — it is paused");
432
+ assert.equal(describeDecision({ action: "stop", reason: "stop-file", detail: "STOP exists" }), "stopped — STOP exists");
433
+ console.log("✓ describeDecision");
434
+ }
435
+ // ── every decision leaves the loop state readable on disk ──────────────────
436
+ {
437
+ const dir = tmpProject();
438
+ try {
439
+ await decideNext({ targetDir: dir, runId: RUN });
440
+ assert.ok(existsSync(loopStatePath(dir)));
441
+ const state = JSON.parse(readFileSync(loopStatePath(dir), "utf-8"));
442
+ assert.equal(state.runId, RUN);
443
+ assert.equal(state.iterations, 1);
444
+ assert.equal(state.lastPhase, "build", "the state remembers where the run was");
445
+ assert.ok(state.lastDecision);
446
+ console.log("✓ every decision persists the loop state");
447
+ }
448
+ finally {
449
+ rmSync(dir, { recursive: true, force: true });
450
+ }
451
+ }
452
+ console.log("All loop tests PASS");
453
+ //# sourceMappingURL=loop.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.test.js","sourceRoot":"","sources":["../../tests/loop.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { loadRouterConfig, resolveModel, consultNext, DEFAULT_ROUTER } from "../src/modelRouter.js";
6
+ function tmpProject() {
7
+ const d = mkdtempSync(join(tmpdir(), "pi-router-"));
8
+ mkdirSync(join(d, "harness"), { recursive: true });
9
+ return d;
10
+ }
11
+ // --- defaults: disabled returns default regardless of difficulty ---
12
+ {
13
+ const proj = tmpProject();
14
+ try {
15
+ // no file -> disabled default
16
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "difficult" } }), DEFAULT_ROUTER.default);
17
+ // write enabled false with byDifficulty
18
+ writeFileSync(join(proj, "harness", "model-router.json"), JSON.stringify({ version: 1, enabled: false, default: "def", byDifficulty: { easy: "E", moderate: "M", difficult: "D" }, master: "MASTER" }));
19
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "easy" } }), "def");
20
+ console.log("✓ disabled returns default");
21
+ }
22
+ finally {
23
+ rmSync(proj, { recursive: true, force: true });
24
+ }
25
+ }
26
+ // --- enabled priority chain: modelHint > byDifficulty > byFeature > bySprint > byPhase > byRole > default ---
27
+ {
28
+ const proj = tmpProject();
29
+ try {
30
+ writeFileSync(join(proj, "harness", "model-router.json"), JSON.stringify({
31
+ version: 1, enabled: true, default: "DEF",
32
+ byDifficulty: { easy: "EASY", moderate: "MOD", difficult: "DIFF" },
33
+ master: "MASTER",
34
+ byFeature: { "feature-007": "FEAT" },
35
+ bySprint: { "sprint-006": "SPRINT" },
36
+ byPhase: { "build": "PHASE" },
37
+ byRole: { "generator": "ROLE" },
38
+ byTask: { "task-014": "TASKHINT" }
39
+ }));
40
+ // byTask exact
41
+ assert.equal(resolveModel({ projectDir: proj, task: { id: "task-014", key: "task-014" } }), "TASKHINT");
42
+ // modelHint top
43
+ assert.equal(resolveModel({ projectDir: proj, task: { modelHint: "OVERRIDE", difficulty: "easy", id: "task-014" } }), "OVERRIDE");
44
+ // byDifficulty
45
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "moderate" } }), "MOD");
46
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "difficult" }, feature: { id: "feature-007" } }), "DIFF", "difficulty before feature");
47
+ // byFeature
48
+ assert.equal(resolveModel({ projectDir: proj, feature: { id: "feature-007" } }), "FEAT");
49
+ // bySprint
50
+ assert.equal(resolveModel({ projectDir: proj, sprint: { id: "sprint-006" } }), "SPRINT");
51
+ // byPhase
52
+ assert.equal(resolveModel({ projectDir: proj, phase: "build" }), "PHASE");
53
+ // byRole
54
+ assert.equal(resolveModel({ projectDir: proj, role: "generator" }), "ROLE");
55
+ // default fallback
56
+ assert.equal(resolveModel({ projectDir: proj }), "DEF");
57
+ // inheritance: feature difficulty -> byDifficulty if task no difficulty
58
+ assert.equal(resolveModel({ projectDir: proj, task: {}, feature: { difficulty: "easy" } }), "EASY");
59
+ console.log("✓ priority chain");
60
+ }
61
+ finally {
62
+ rmSync(proj, { recursive: true, force: true });
63
+ }
64
+ }
65
+ // --- ladder: MASTER never assigned ---
66
+ {
67
+ const proj = tmpProject();
68
+ try {
69
+ writeFileSync(join(proj, "harness", "model-router.json"), JSON.stringify({
70
+ version: 1, enabled: true, default: "DEF",
71
+ byDifficulty: { easy: "E", moderate: "M", difficult: "D" },
72
+ master: "MASTER",
73
+ consultation: { enabled: true, maxPerTask: 1, oneStepOnly: true, requireExhaustion: true }
74
+ }));
75
+ // resolveModel never returns MASTER even for difficult (it returns D)
76
+ assert.notEqual(resolveModel({ projectDir: proj, task: { difficulty: "difficult" } }), "MASTER");
77
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "difficult" } }), "D");
78
+ // consultNext steps one rung
79
+ assert.equal(consultNext("easy", { projectDir: proj }), "M");
80
+ assert.equal(consultNext("moderate", { projectDir: proj }), "D");
81
+ assert.equal(consultNext("difficult", { projectDir: proj }), "MASTER");
82
+ // oneStepOnly: second consult exceeds maxPerTask 1 -> null
83
+ assert.equal(consultNext("easy", { projectDir: proj, consultedCount: 1 }), null);
84
+ assert.equal(consultNext("difficult", { projectDir: proj, consultedCount: 1 }), null);
85
+ // unknown difficulty -> null
86
+ assert.equal(consultNext("unknown", { projectDir: proj }), null);
87
+ assert.equal(consultNext(null, { projectDir: proj }), null);
88
+ console.log("✓ ladder MASTER never assigned, one-step");
89
+ }
90
+ finally {
91
+ rmSync(proj, { recursive: true, force: true });
92
+ }
93
+ }
94
+ // --- fresh read each call (toggle disabled->enabled) ---
95
+ {
96
+ const proj = tmpProject();
97
+ try {
98
+ writeFileSync(join(proj, "harness", "model-router.json"), JSON.stringify({ version: 1, enabled: false, default: "DEF", byDifficulty: { easy: "E" } }));
99
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "easy" } }), "DEF");
100
+ writeFileSync(join(proj, "harness", "model-router.json"), JSON.stringify({ version: 1, enabled: true, default: "DEF", byDifficulty: { easy: "E" } }));
101
+ assert.equal(resolveModel({ projectDir: proj, task: { difficulty: "easy" } }), "E");
102
+ console.log("✓ fresh read toggle");
103
+ }
104
+ finally {
105
+ rmSync(proj, { recursive: true, force: true });
106
+ }
107
+ }
108
+ // --- loadRouterConfig merges defaults ---
109
+ {
110
+ const proj = tmpProject();
111
+ try {
112
+ writeFileSync(join(proj, "harness", "model-router.json"), JSON.stringify({ version: 1, enabled: true }));
113
+ const cfg = loadRouterConfig(proj);
114
+ assert.equal(cfg.version, 1);
115
+ assert.equal(cfg.enabled, true);
116
+ // Model slots default to "" — meaning "use whatever model pi is already
117
+ // configured with". Installing the harness must never silently redirect
118
+ // work to a model the user did not choose.
119
+ assert.equal(cfg.default, "", "default model slot is empty, not a vendor id");
120
+ assert.equal(cfg.master, "", "master slot is empty, not a vendor id");
121
+ assert.ok(cfg.byDifficulty, "difficulty map is present");
122
+ assert.equal(cfg.byDifficulty.easy, "");
123
+ assert.ok(cfg.budgets);
124
+ console.log("✓ load merges defaults");
125
+ }
126
+ finally {
127
+ rmSync(proj, { recursive: true, force: true });
128
+ }
129
+ }
130
+ console.log("All modelRouter tests PASS");
131
+ //# sourceMappingURL=modelRouter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelRouter.test.js","sourceRoot":"","sources":["../../tests/modelRouter.test.ts"],"names":[],"mappings":"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"}