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,306 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync, readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join, resolve } from "node:path";
5
+ import { hashLite, buildFingerprint, getWorkerRoot, getTaskRoot, getAttemptDir, getNextAttemptNumber, createWorkerRunDir, recordAttempt, createAndRecordAttempt, spawnIsolatedWorker, withFeatureListLock, withHarnessLocks, WORKER_ROOT_SEGMENT, PROMPT_FILE, OUTPUT_FILE, FINGERPRINT_FILE, } from "../src/worker.js";
6
+ function tmpProject() {
7
+ const d = mkdtempSync(join(tmpdir(), "pi-worker-"));
8
+ mkdirSync(join(d, "harness", "features"), { recursive: true });
9
+ return d;
10
+ }
11
+ // --- constants & hashLite ---
12
+ assert.equal(WORKER_ROOT_SEGMENT, "tmp/infinity-harness");
13
+ assert.equal(PROMPT_FILE, "prompt.md");
14
+ assert.equal(OUTPUT_FILE, "output.log");
15
+ assert.equal(FINGERPRINT_FILE, "fingerprint.json");
16
+ assert.equal(hashLite(""), 0);
17
+ {
18
+ const h1 = hashLite("hello");
19
+ const h2 = hashLite("hello");
20
+ assert.equal(h1, h2, "deterministic");
21
+ assert.notEqual(hashLite("hello"), hashLite("world"));
22
+ console.log("✓ hashLite deterministic");
23
+ }
24
+ // --- getWorkerRoot / getTaskRoot / getAttemptDir ---
25
+ {
26
+ const root = getWorkerRoot("/tmp/proj");
27
+ assert.equal(root, resolve("/tmp/proj", "tmp/infinity-harness"));
28
+ const taskRoot = getTaskRoot("/tmp/proj", "run-1", "feature-003", "task-005");
29
+ assert.ok(taskRoot.includes("run-1") && taskRoot.includes("feature-003") && taskRoot.includes("task-005"));
30
+ const attemptDir = getAttemptDir("/tmp/proj", "run-1", "feature-003", "task-005", 2);
31
+ assert.ok(attemptDir.endsWith("attempt-2"));
32
+ console.log("✓ worker dir helpers");
33
+ }
34
+ // --- createWorkerRunDir + getNextAttemptNumber increment ---
35
+ {
36
+ const proj = tmpProject();
37
+ try {
38
+ // first attempt
39
+ const d1 = createWorkerRunDir(proj, "run-xyz", "feature-003", "task-005");
40
+ assert.ok(existsSync(d1), "attempt-1 exists");
41
+ assert.ok(d1.endsWith("attempt-1"));
42
+ // second call without explicit attempt -> attempt-2
43
+ const d2 = createWorkerRunDir(proj, "run-xyz", "feature-003", "task-005");
44
+ assert.ok(d2.endsWith("attempt-2"));
45
+ assert.ok(existsSync(d2));
46
+ // explicit attempt
47
+ const d5 = createWorkerRunDir(proj, "run-xyz", "feature-003", "task-005", 5);
48
+ assert.ok(d5.endsWith("attempt-5"));
49
+ // getNextAttemptNumber should be 6 (max 5 +1)
50
+ const taskRoot = getTaskRoot(proj, "run-xyz", "feature-003", "task-005");
51
+ assert.equal(getNextAttemptNumber(taskRoot), 6);
52
+ console.log("✓ createWorkerRunDir increments");
53
+ }
54
+ finally {
55
+ rmSync(proj, { recursive: true, force: true });
56
+ }
57
+ }
58
+ // --- recordAttempt writes three files ---
59
+ {
60
+ const proj = tmpProject();
61
+ try {
62
+ const dir = createWorkerRunDir(proj, "run-a", "f-1", "t-1");
63
+ const fp = buildFingerprint({ projectDir: proj, runId: "run-a", featureId: "f-1", taskId: "t-1", attempt: 1, baseRevision: 2 });
64
+ const res = recordAttempt(dir, { prompt: "hello prompt", output: "hello output", fingerprint: fp });
65
+ assert.ok(existsSync(res.promptPath));
66
+ assert.ok(existsSync(res.outputPath));
67
+ assert.ok(existsSync(res.fingerprintPath));
68
+ assert.equal(readFileSync(res.promptPath, "utf-8"), "hello prompt");
69
+ assert.equal(readFileSync(res.outputPath, "utf-8"), "hello output");
70
+ const saved = JSON.parse(readFileSync(res.fingerprintPath, "utf-8"));
71
+ assert.equal(saved.runId, "run-a");
72
+ assert.equal(saved.baseRevision, 2);
73
+ assert.equal(saved.attempt, 1);
74
+ console.log("✓ recordAttempt writes prompt/output/fingerprint");
75
+ }
76
+ finally {
77
+ rmSync(proj, { recursive: true, force: true });
78
+ }
79
+ }
80
+ // --- createAndRecordAttempt convenience ---
81
+ {
82
+ const proj = tmpProject();
83
+ try {
84
+ const fp = buildFingerprint({ projectDir: proj, runId: "run-b", featureId: "feat-2", taskId: "task-006", attempt: 1, baseRevision: 0 });
85
+ const { attemptDir, attempt, fingerprint } = createAndRecordAttempt(proj, "run-b", "feat-2", "task-006", {
86
+ prompt: "p",
87
+ output: "o",
88
+ fingerprint: fp,
89
+ });
90
+ assert.equal(attempt, 1);
91
+ assert.ok(existsSync(join(attemptDir, "prompt.md")));
92
+ assert.equal(fingerprint.attempt, 1);
93
+ // second call increments
94
+ const r2 = createAndRecordAttempt(proj, "run-b", "feat-2", "task-006", { prompt: "p2", output: "o2", fingerprint: fp });
95
+ assert.equal(r2.attempt, 2);
96
+ console.log("✓ createAndRecordAttempt increments");
97
+ }
98
+ finally {
99
+ rmSync(proj, { recursive: true, force: true });
100
+ }
101
+ }
102
+ // --- buildFingerprint preserves baseRevision & featureListHash ---
103
+ {
104
+ const proj = tmpProject();
105
+ try {
106
+ // write feature-list with baseRevision 7 to test reading
107
+ writeFileSync(join(proj, "harness", "features", "feature-list.json"), JSON.stringify({ version: "0.1", baseRevision: 7, features: [] }, null, 2));
108
+ const fp = buildFingerprint({ projectDir: proj, runId: "run-c", featureId: "f", taskId: "t", attempt: 1 });
109
+ assert.equal(fp.baseRevision, 7, "reads baseRevision from file");
110
+ assert.ok(typeof fp.timestamp === "string" && fp.timestamp.includes("T"), "timestamp iso");
111
+ assert.ok(typeof fp.featureListHash === "number");
112
+ // explicit baseRevision overrides file
113
+ const fp2 = buildFingerprint({ projectDir: proj, runId: "run-c", featureId: "f", taskId: "t", attempt: 2, baseRevision: 42 });
114
+ assert.equal(fp2.baseRevision, 42);
115
+ console.log("✓ buildFingerprint preserves baseRevision");
116
+ }
117
+ finally {
118
+ rmSync(proj, { recursive: true, force: true });
119
+ }
120
+ }
121
+ // --- baseRevision preserved through file helpers (integration with taskList) ---
122
+ {
123
+ const proj = tmpProject();
124
+ try {
125
+ // Use the plan editor to create a file, then fingerprint should see its revision
126
+ const { writeTaskList } = await import("../src/taskList.js");
127
+ // initial file rev 0 -> create task
128
+ const r1 = writeTaskList(proj, { tasks: [{ key: "a", subject: "A", status: "pending" }] });
129
+ assert.equal(r1.revision, 1);
130
+ const fp = buildFingerprint({ projectDir: proj, runId: "run-d", featureId: "f", taskId: "t", attempt: 1 });
131
+ assert.equal(fp.baseRevision, 1);
132
+ // worker dir should not corrupt file
133
+ const dir = createWorkerRunDir(proj, "run-d", "f", "t");
134
+ const fp2 = buildFingerprint({ projectDir: proj, runId: "run-d", featureId: "f", taskId: "t", attempt: 1, baseRevision: 1 });
135
+ recordAttempt(dir, { prompt: "p", output: "done", fingerprint: fp2 });
136
+ // file still rev 1
137
+ const after = JSON.parse(readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8"));
138
+ assert.equal(after.baseRevision, 1, "worker attempt does not corrupt baseRevision");
139
+ console.log("✓ baseRevision preserved after worker record");
140
+ }
141
+ finally {
142
+ rmSync(proj, { recursive: true, force: true });
143
+ }
144
+ }
145
+ // --- proper-lockfile: concurrent workers do not corrupt baseRevision ---
146
+ {
147
+ const proj = tmpProject();
148
+ try {
149
+ const { writeTaskList } = await import("../src/taskList.js");
150
+ writeTaskList(proj, { tasks: [{ key: "a", subject: "A", status: "pending" }] });
151
+ // simulate two workers trying to update concurrently with lock
152
+ const worker = async (id) => {
153
+ return withFeatureListLock(proj, async () => {
154
+ // read, apply, write under lock
155
+ const before = JSON.parse(readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8"));
156
+ const rev = before.baseRevision;
157
+ // small delay to increase race window
158
+ await new Promise((r) => setTimeout(r, 10));
159
+ // try to apply with current rev; one will succeed, other may see stale if not re-read
160
+ // For this test, we just verify lock serializes: we do a simple file write under lock
161
+ const p = join(proj, "harness", "features", "feature-list.json");
162
+ const cur = JSON.parse(readFileSync(p, "utf-8"));
163
+ cur.baseRevision = cur.baseRevision + 1;
164
+ cur.features[0].tasks.push({ id: `c${id}`, key: `c${id}`, description: `C${id}`, status: "pending", dependsOn: [] });
165
+ writeFileSync(p, JSON.stringify(cur, null, 2));
166
+ return cur.baseRevision;
167
+ });
168
+ };
169
+ const [r1, r2] = await Promise.all([worker(1), worker(2)]);
170
+ const final = JSON.parse(readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8"));
171
+ // Both should have succeeded sequentially due to lock, final rev = initial 1 + 2 = 3
172
+ assert.equal(final.baseRevision, 3, `expected rev 3 after two locked writes, got ${final.baseRevision} r1=${r1} r2=${r2}`);
173
+ assert.equal(final.features[0].tasks.length, 3, "both tasks present");
174
+ console.log("✓ proper-lockfile concurrent writes serialized");
175
+ }
176
+ finally {
177
+ rmSync(proj, { recursive: true, force: true });
178
+ }
179
+ }
180
+ // --- withHarnessLocks also works (locks both files) ---
181
+ {
182
+ const proj = tmpProject();
183
+ try {
184
+ writeFileSync(join(proj, "harness", "config.json"), JSON.stringify({ phase: "build" }, null, 2));
185
+ writeFileSync(join(proj, "harness", "features", "feature-list.json"), JSON.stringify({ version: "0.1", baseRevision: 0, features: [] }, null, 2));
186
+ let ran = false;
187
+ await withHarnessLocks(proj, async () => {
188
+ ran = true;
189
+ assert.ok(existsSync(join(proj, "harness", "features", "feature-list.json")));
190
+ assert.ok(existsSync(join(proj, "harness", "config.json")));
191
+ });
192
+ assert.ok(ran);
193
+ console.log("✓ withHarnessLocks");
194
+ }
195
+ finally {
196
+ rmSync(proj, { recursive: true, force: true });
197
+ }
198
+ }
199
+ // --- spawnIsolatedWorker: no command just records ---
200
+ {
201
+ const proj = tmpProject();
202
+ try {
203
+ const res = await spawnIsolatedWorker({
204
+ projectDir: proj,
205
+ runId: "run-e",
206
+ featureId: "feature-003",
207
+ taskId: "task-005",
208
+ prompt: "do the thing",
209
+ });
210
+ assert.ok(existsSync(join(res.attemptDir, "prompt.md")));
211
+ assert.equal(readFileSync(join(res.attemptDir, "prompt.md"), "utf-8"), "do the thing");
212
+ assert.equal(res.exitCode, 0);
213
+ assert.equal(res.fingerprint.runId, "run-e");
214
+ assert.equal(res.attempt, 1);
215
+ // second spawn increments to 2
216
+ const res2 = await spawnIsolatedWorker({
217
+ projectDir: proj,
218
+ runId: "run-e",
219
+ featureId: "feature-003",
220
+ taskId: "task-005",
221
+ prompt: "second",
222
+ });
223
+ assert.equal(res2.attempt, 2);
224
+ assert.ok(res2.attemptDir.endsWith("attempt-2"));
225
+ console.log("✓ spawnIsolatedWorker no-command records");
226
+ }
227
+ finally {
228
+ rmSync(proj, { recursive: true, force: true });
229
+ }
230
+ }
231
+ // --- spawnIsolatedWorker with command writes output.log ---
232
+ {
233
+ const proj = tmpProject();
234
+ try {
235
+ const res = await spawnIsolatedWorker({
236
+ projectDir: proj,
237
+ runId: "run-f",
238
+ featureId: "feature-003",
239
+ taskId: "task-005",
240
+ prompt: "echo test",
241
+ command: "echo hello-worker",
242
+ timeoutMs: 5000,
243
+ });
244
+ assert.ok(existsSync(join(res.attemptDir, "output.log")));
245
+ const out = readFileSync(join(res.attemptDir, "output.log"), "utf-8");
246
+ assert.ok(out.includes("hello-worker"), `output should contain hello-worker, got ${out}`);
247
+ assert.equal(res.exitCode, 0);
248
+ console.log("✓ spawnIsolatedWorker with command writes output.log");
249
+ }
250
+ finally {
251
+ rmSync(proj, { recursive: true, force: true });
252
+ }
253
+ }
254
+ // --- fingerprint.json is valid JSON with required fields ---
255
+ {
256
+ const proj = tmpProject();
257
+ try {
258
+ const res = await spawnIsolatedWorker({
259
+ projectDir: proj,
260
+ runId: "run-g",
261
+ featureId: "feature-003",
262
+ taskId: "task-005",
263
+ prompt: "p",
264
+ command: "echo ok",
265
+ });
266
+ const fpPath = join(res.attemptDir, "fingerprint.json");
267
+ assert.ok(existsSync(fpPath));
268
+ const fp = JSON.parse(readFileSync(fpPath, "utf-8"));
269
+ assert.equal(fp.runId, "run-g");
270
+ assert.equal(fp.featureId, "feature-003");
271
+ assert.equal(fp.taskId, "task-005");
272
+ assert.equal(typeof fp.baseRevision, "number");
273
+ assert.ok(fp.timestamp);
274
+ // gitHead may be undefined in temp repo without git, thats ok
275
+ console.log("✓ fingerprint.json valid");
276
+ }
277
+ finally {
278
+ rmSync(proj, { recursive: true, force: true });
279
+ }
280
+ }
281
+ // --- tmp/infinity-harness isolation does not corrupt harness files ---
282
+ {
283
+ const proj = tmpProject();
284
+ try {
285
+ const { writeTaskList } = await import("../src/taskList.js");
286
+ writeTaskList(proj, { tasks: [{ key: "a", subject: "A", status: "pending" }] });
287
+ const before = readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8");
288
+ const res = await spawnIsolatedWorker({
289
+ projectDir: proj,
290
+ runId: "run-h",
291
+ featureId: "feature-003",
292
+ taskId: "task-005",
293
+ prompt: "isolated",
294
+ command: "echo isolated",
295
+ });
296
+ const after = readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8");
297
+ assert.equal(before, after, "feature-list.json untouched by isolated worker");
298
+ assert.ok(res.attemptDir.replace(/\\/g, "/").includes("tmp/infinity-harness"));
299
+ console.log("✓ tmp/infinity-harness isolated from harness files");
300
+ }
301
+ finally {
302
+ rmSync(proj, { recursive: true, force: true });
303
+ }
304
+ }
305
+ console.log("All worker tests PASS");
306
+ //# sourceMappingURL=worker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.test.js","sourceRoot":"","sources":["../../tests/worker.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Workflows: which phases run, and who signs each one.
3
+ *
4
+ * "copilot" and "autopilot" were a single switch, and a single switch is the
5
+ * wrong shape for the question — it cannot say "let it define and plan on its
6
+ * own but show me the review". The setting is a mode per phase; the two
7
+ * familiar words are two named points in that space.
8
+ *
9
+ * The two rules worth defending here: a saved workflow belongs to the *person*
10
+ * so it is there on their next project, and a built-in name cannot be taken,
11
+ * because "copilot" has to mean the same thing in every conversation about
12
+ * this tool.
13
+ */
14
+ import assert from "node:assert/strict";
15
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
16
+ import { tmpdir } from "node:os";
17
+ import { dirname, join } from "node:path";
18
+ import { BUILTIN_WORKFLOWS, SIGNABLE_PHASES, applyWorkflow, builtInWorkflow, deleteWorkflow, describeModes, findWorkflow, listWorkflows, loadSavedWorkflows, matchWorkflow, modeFor, modesOf, normalizeModes, normalizePhases, renderWorkflow, saveWorkflow, signedPhases, slugify, summarizeWorkflow, } from "../src/workflow.js";
19
+ import { defaultConfig, loadConfig, saveConfig } from "../src/core/config.js";
20
+ import { userWorkflowsPath } from "../src/core/paths.js";
21
+ function sandbox() {
22
+ const dir = mkdtempSync(join(tmpdir(), "workflow-store-"));
23
+ return { env: { PI_CODING_AGENT_DIR: dir }, clean: () => rmSync(dir, { recursive: true, force: true }) };
24
+ }
25
+ // ── the built-ins ──────────────────────────────────────────────────────────
26
+ {
27
+ const ids = BUILTIN_WORKFLOWS.map((w) => w.id);
28
+ assert.ok(ids.includes("copilot") && ids.includes("autopilot"), "the two familiar names survive");
29
+ assert.equal(new Set(ids).size, ids.length, "ids are unique");
30
+ const copilot = builtInWorkflow("copilot");
31
+ assert.deepEqual(signedPhasesOf(copilot), ["define", "plan"], "copilot signs the two thinking phases it runs");
32
+ const autopilot = builtInWorkflow("autopilot");
33
+ assert.deepEqual(signedPhasesOf(autopilot), [], "autopilot signs nothing");
34
+ const every = builtInWorkflow("every-gate");
35
+ assert.deepEqual(signedPhasesOf(every), every.phases, "every gate means every gate");
36
+ const spec = builtInWorkflow("spec-and-ship");
37
+ assert.deepEqual(signedPhasesOf(spec), ["define", "ship"], "the shape a single switch could not express: scope in, release out");
38
+ assert.equal(builtInWorkflow("nope"), null);
39
+ console.log("✓ the built-ins cover the shapes people ask for, including one no switch could");
40
+ }
41
+ function signedPhasesOf(w) {
42
+ return w.phases.filter((p) => w.modes[p] === "copilot");
43
+ }
44
+ // ── saving, reusing, deleting ──────────────────────────────────────────────
45
+ {
46
+ const box = sandbox();
47
+ assert.deepEqual(loadSavedWorkflows(box.env), [], "nothing saved to start with");
48
+ assert.equal(listWorkflows(box.env).length, BUILTIN_WORKFLOWS.length);
49
+ const saved = saveWorkflow({
50
+ name: "Client work",
51
+ phases: ["define", "plan", "build", "verify", "review", "ship"],
52
+ modes: { define: "copilot", review: "copilot", ship: "copilot" },
53
+ }, box.env);
54
+ assert.equal(saved.ok, true, saved.error ?? "");
55
+ assert.equal(saved.workflow?.id, "client-work");
56
+ assert.equal(saved.workflow?.builtIn, false);
57
+ assert.ok(saved.workflow?.savedAt, "a saved workflow is stamped");
58
+ assert.ok(saved.workflow.description.length > 0, "and describes itself if you did not");
59
+ // The point of saving: it is there next time, on any project.
60
+ assert.equal(findWorkflow("client-work", box.env)?.name, "Client work");
61
+ assert.equal(listWorkflows(box.env).length, BUILTIN_WORKFLOWS.length + 1);
62
+ assert.equal(listWorkflows(box.env)[0]?.builtIn, true, "built-ins come first in the menu");
63
+ // Saving the same name again is editing, not a duplicate.
64
+ const edited = saveWorkflow({ name: "Client work", phases: ["define", "plan", "build"], modes: { plan: "copilot" } }, box.env);
65
+ assert.equal(edited.ok, true);
66
+ assert.equal(loadSavedWorkflows(box.env).length, 1, "one entry, not two");
67
+ assert.equal(findWorkflow("client-work", box.env)?.modes.plan, "copilot");
68
+ assert.equal(deleteWorkflow("client-work", box.env).ok, true);
69
+ assert.equal(loadSavedWorkflows(box.env).length, 0);
70
+ box.clean();
71
+ console.log("✓ a saved workflow belongs to the person and is there on the next project");
72
+ }
73
+ // ── built-ins are read-only ────────────────────────────────────────────────
74
+ {
75
+ const box = sandbox();
76
+ for (const id of ["copilot", "autopilot", "Copilot", "AUTOPILOT", "auto pilot"]) {
77
+ const attempt = saveWorkflow({ name: id, phases: ["define"], modes: {} }, box.env);
78
+ if (builtInWorkflow(slugify(id))) {
79
+ assert.equal(attempt.ok, false, `"${id}" should be refused`);
80
+ assert.match(attempt.error ?? "", /built-in/i);
81
+ }
82
+ }
83
+ assert.equal(deleteWorkflow("copilot", box.env).ok, false, "and they cannot be deleted either");
84
+ assert.equal(saveWorkflow({ name: " ", phases: ["define"], modes: {} }, box.env).ok, false);
85
+ assert.equal(saveWorkflow({ name: "!!!", phases: ["define"], modes: {} }, box.env).ok, false);
86
+ box.clean();
87
+ console.log("✓ 'copilot' means the same thing everywhere — built-ins cannot be shadowed or deleted");
88
+ }
89
+ // ── a corrupt store degrades to the built-ins ──────────────────────────────
90
+ {
91
+ const box = sandbox();
92
+ const path = userWorkflowsPath(box.env);
93
+ mkdirSync(dirname(path), { recursive: true });
94
+ writeFileSync(path, "{not json", "utf-8");
95
+ assert.deepEqual(loadSavedWorkflows(box.env), [], "unreadable reads as none, never as a throw");
96
+ writeFileSync(path, JSON.stringify({ version: "1", workflows: [{ nonsense: true }] }), "utf-8");
97
+ assert.deepEqual(loadSavedWorkflows(box.env), [], "an entry with no id and no name is not a workflow");
98
+ writeFileSync(path, JSON.stringify({ version: "1", workflows: [{ id: "x", name: "X", phases: ["nope"], modes: { nope: "wat" } }] }), "utf-8");
99
+ const repaired = loadSavedWorkflows(box.env)[0];
100
+ assert.deepEqual(repaired.phases, normalizePhases(undefined), "a nonsense phase list falls back to the default");
101
+ assert.ok(Object.values(repaired.modes).every((m) => m === "copilot" || m === "autopilot"), "and a nonsense mode becomes a real one");
102
+ box.clean();
103
+ console.log("✓ a corrupt store leaves you with the built-ins rather than a broken session");
104
+ }
105
+ // ── applying one to a config ───────────────────────────────────────────────
106
+ {
107
+ const config = defaultConfig();
108
+ applyWorkflow(config, builtInWorkflow("research-first"));
109
+ assert.ok(config.phases.enabled.includes("research"), "the workflow's phases become the pipeline");
110
+ assert.equal(config.phases.enabled[0], "research", "in pipeline order");
111
+ assert.equal(config.phaseModes.research, "copilot");
112
+ assert.equal(config.phaseModes.build, "autopilot");
113
+ assert.deepEqual(config.workflow, { id: "research-first", name: "research first" });
114
+ assert.equal(modeFor(config, "define"), "copilot");
115
+ assert.equal(modeFor(config, "build"), "autopilot");
116
+ assert.equal(modeFor(config, null), "autopilot", "no phase is nothing to stop for");
117
+ assert.deepEqual(signedPhases(config), ["research", "define", "plan"]);
118
+ // Switching workflow replaces the modes rather than merging them.
119
+ applyWorkflow(config, builtInWorkflow("autopilot"));
120
+ assert.deepEqual(signedPhases(config), [], "the old copilot phases are gone, not left behind");
121
+ assert.ok(!config.phases.enabled.includes("research"), "and so is the phase it added");
122
+ console.log("✓ applying a workflow replaces the pipeline and the modes, cleanly");
123
+ }
124
+ // ── knowing when the settings have drifted ─────────────────────────────────
125
+ {
126
+ const box = sandbox();
127
+ const config = defaultConfig();
128
+ applyWorkflow(config, builtInWorkflow("copilot"));
129
+ assert.equal(matchWorkflow(config, box.env)?.id, "copilot");
130
+ assert.match(summarizeWorkflow(config, box.env), /^copilot ·/);
131
+ // One setting changed by hand, and it is no longer copilot. Saying so is the
132
+ // difference between a word that means something and a label.
133
+ config.phaseModes = { ...config.phaseModes, review: "copilot" };
134
+ assert.equal(matchWorkflow(config, box.env), null);
135
+ assert.match(summarizeWorkflow(config, box.env), /copilot \(edited\)/);
136
+ box.clean();
137
+ console.log("✓ a config edited off its preset says so instead of still claiming the name");
138
+ }
139
+ // ── an older config comes forward ──────────────────────────────────────────
140
+ {
141
+ const dir = mkdtempSync(join(tmpdir(), "workflow-migrate-"));
142
+ mkdirSync(join(dir, "harness"), { recursive: true });
143
+ // Exactly what 2.3 wrote: a three-phase `approvals` and no `phaseModes`.
144
+ const legacy = {
145
+ version: "2.0",
146
+ mode: "copilot",
147
+ phases: { enabled: ["define", "plan", "build", "verify", "review", "ship"] },
148
+ approvals: { research: false, define: true, plan: true },
149
+ gates: {},
150
+ git: {},
151
+ maxRetries: 10,
152
+ };
153
+ writeFileSync(join(dir, "harness", "config.json"), JSON.stringify(legacy), "utf-8");
154
+ const { config, ok } = loadConfig(dir);
155
+ assert.equal(ok, true);
156
+ assert.deepEqual(signedPhases(config), ["define", "plan"], "a project mid-run keeps the approvals it was configured with");
157
+ assert.equal(config.phaseModes.build, "autopilot");
158
+ assert.equal(config.workflow?.id, "copilot", "and is labelled with the workflow it amounts to");
159
+ // A 2.3 config that approved nothing lands on autopilot, not on a mystery.
160
+ writeFileSync(join(dir, "harness", "config.json"), JSON.stringify({ ...legacy, approvals: { research: false, define: false, plan: false } }), "utf-8");
161
+ assert.deepEqual(signedPhases(loadConfig(dir).config), []);
162
+ assert.equal(loadConfig(dir).config.workflow?.id, "autopilot");
163
+ // And the migration does not clobber a config that already has modes.
164
+ const modern = defaultConfig();
165
+ applyWorkflow(modern, builtInWorkflow("spec-and-ship"));
166
+ saveConfig(dir, modern);
167
+ assert.deepEqual(signedPhases(loadConfig(dir).config), ["define", "ship"]);
168
+ rmSync(dir, { recursive: true, force: true });
169
+ console.log("✓ a 2.3 config keeps its approvals without anyone editing JSON");
170
+ }
171
+ // ── describing ─────────────────────────────────────────────────────────────
172
+ {
173
+ assert.match(describeModes(["define", "build"], { define: "copilot", build: "autopilot" }), /DEFINE/);
174
+ assert.match(describeModes(["define"], { define: "autopilot" }), /without stopping/);
175
+ assert.match(describeModes(["define"], { define: "copilot" }), /every phase/);
176
+ const rendered = renderWorkflow(builtInWorkflow("copilot"));
177
+ assert.match(rendered, /\[define\]/, "a phase that stops is bracketed");
178
+ assert.match(rendered, /brackets/, "and the notation is explained rather than assumed");
179
+ assert.deepEqual(modesOf(defaultConfig()).init, undefined, "INIT is not a phase with a mode");
180
+ assert.ok(!SIGNABLE_PHASES.includes("init"));
181
+ assert.deepEqual(normalizeModes({ define: "copilot" }, ["define", "build"]), {
182
+ define: "copilot",
183
+ build: "autopilot",
184
+ });
185
+ console.log("✓ a workflow can be read at a glance, and unset phases default to autopilot");
186
+ }
187
+ //# sourceMappingURL=workflow.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.test.js","sourceRoot":"","sources":["../../tests/workflow.test.ts"],"names":[],"mappings":"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"}
@@ -540,6 +540,27 @@ export default function (pi: ExtensionAPI): void {
540
540
  * would produce a tier that fails at the first task rather than at setup.
541
541
  */
542
542
  const availableModels = (ctx: ExtensionContext): ModelChoice[] => {
543
+ // Helper: get pi-default thinking levels for a model (the truth — not our THINKING_LEVELS)
544
+ const supportedOf = (m: unknown): readonly string[] | null => {
545
+ try {
546
+ const mod = m as { reasoning?: boolean; thinkingLevelMap?: Record<string, string | null> };
547
+ if (!mod) return null;
548
+ // pi-ai getSupportedThinkingLevels: reasoning false => ["off"]
549
+ if (mod.reasoning === false) return ["off"] as const;
550
+ if (mod.reasoning === true) {
551
+ const map = mod.thinkingLevelMap ?? {};
552
+ const all: readonly string[] = ["off","minimal","low","medium","high","xhigh","max"];
553
+ const supported = all.filter(l => {
554
+ const v = (map as Record<string, string | null | undefined>)[l];
555
+ if (v === null) return false;
556
+ if ((l === "xhigh" || l === "max") && v === undefined) return false;
557
+ return true;
558
+ });
559
+ return supported.length ? supported : (["off"] as const);
560
+ }
561
+ return null;
562
+ } catch { return null; }
563
+ };
543
564
  try {
544
565
  const scoped = ctx.scopedModels ?? [];
545
566
  const models =
@@ -558,7 +579,8 @@ export default function (pi: ExtensionAPI): void {
558
579
  if (m.name && m.name !== m.id) bits.push(`· ${m.name}`);
559
580
  if (m.contextWindow) bits.push(`· ${Math.round(m.contextWindow / 1000)}k ctx`);
560
581
  if (m.reasoning) bits.push("· reasoning");
561
- out.push({ ref, label: bits.join(" ") });
582
+ const levels = supportedOf(m);
583
+ out.push({ ref, label: bits.join(" "), ...(levels ? { supportedThinkingLevels: levels } : {}) } as unknown as ModelChoice & { supportedThinkingLevels?: readonly string[] });
562
584
  }
563
585
  out.sort((a, b) => a.ref.localeCompare(b.ref));
564
586
  return out;
@@ -2030,14 +2052,16 @@ export default function (pi: ExtensionAPI): void {
2030
2052
  const { spawn: _sp } = await import("node:child_process");
2031
2053
  const { existsSync: _ex, openSync: _op, closeSync: _cl } = await import("node:fs");
2032
2054
  const { resolve: _re } = await import("node:path");
2033
- // B: daemon lives in the *installed package*, not in the target project.
2034
- // Prefer the package's own dist (works in published installs), then the
2035
- // target's dist/src (works in dev checkouts where the harness lives under extensions/).
2055
+ // Daemon lives in the *installed package*, not the target project.
2056
+ // Prefer the package's own dist (works in every install, including Node 26 where
2057
+ // stripping .ts under node_modules is ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING).
2058
+ // The .ts src entries are kept only for unpacked dev checkouts without a build.
2036
2059
  let pkgDir: string | null = null;
2037
2060
  try { pkgDir = _re(dirname(fileURLToPath(import.meta.url)), "../.."); } catch {}
2038
- const pkgDist = pkgDir ? _re(pkgDir, "dist/daemon/index.js") : null;
2039
- const pkgSrc = pkgDir ? _re(pkgDir, "src/daemon/index.ts") : null;
2040
- const cands = [pkgDist, _re(dir, "dist/daemon/index.js"), pkgSrc, _re(dir, "src/daemon/index.ts")].filter(Boolean) as string[];
2061
+ const pkgJs = pkgDir ? _re(pkgDir, "dist/src/daemon/index.js") : null;
2062
+ const pkgTs = pkgDir ? _re(pkgDir, "src/daemon/index.ts") : null;
2063
+ const altJs = pkgDir ? _re(pkgDir, "dist/daemon/index.js") : null;
2064
+ const cands = [pkgJs, altJs, _re(dir, "dist/daemon/index.js"), _re(dir, "dist/src/daemon/index.js"), pkgTs, _re(dir, "src/daemon/index.ts")].filter(Boolean) as string[];
2041
2065
  let entry: string | null = null;
2042
2066
  for (const c of cands) if (_ex(c)) { entry = c; break; }
2043
2067
  if (!entry) return { spawned: false };
@@ -2900,15 +2924,18 @@ export default function (pi: ExtensionAPI): void {
2900
2924
  const { existsSync, openSync, closeSync } = await import("node:fs");
2901
2925
  const { resolve: _resolve } = await import("node:path");
2902
2926
  // Daemon entry must exist; when not built (dev) fall back to supervisor.
2903
- // B: same as init path above package dist first, then project
2927
+ // Package dist first Node 26 bans stripping .ts under node_modules.
2904
2928
  let _pkgDir: string | null = null;
2905
2929
  try { _pkgDir = dirname(fileURLToPath(import.meta.url)); _pkgDir = _resolve(_pkgDir, "../.."); } catch {}
2906
- const _pkgDist = _pkgDir ? _resolve(_pkgDir, "dist/daemon/index.js") : null;
2907
- const _pkgSrc = _pkgDir ? _resolve(_pkgDir, "src/daemon/index.ts") : null;
2930
+ const _pkgJs = _pkgDir ? _resolve(_pkgDir, "dist/src/daemon/index.js") : null;
2931
+ const _altJs = _pkgDir ? _resolve(_pkgDir, "dist/daemon/index.js") : null;
2932
+ const _pkgTs = _pkgDir ? _resolve(_pkgDir, "src/daemon/index.ts") : null;
2908
2933
  const candidates = [
2909
- _pkgDist,
2934
+ _pkgJs,
2935
+ _altJs,
2936
+ _resolve(dir, "dist/src/daemon/index.js"),
2910
2937
  _resolve(dir, "dist/daemon/index.js"),
2911
- _pkgSrc,
2938
+ _pkgTs,
2912
2939
  _resolve(dir, "src/daemon/index.ts"),
2913
2940
  ].filter(Boolean) as string[];
2914
2941
  let entry: string | null = null;