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,109 @@
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 } from "node:path";
5
+ import { computeImpact, startRework, loadRework, clearRework } from "../src/rework.js";
6
+ function tmpProject() {
7
+ const d = mkdtempSync(join(tmpdir(), "pi-rework-"));
8
+ mkdirSync(join(d, "harness", "features"), { recursive: true });
9
+ return d;
10
+ }
11
+ function writeFeatureList(dir, tasks, baseRevision = 0) {
12
+ const features = [{ id: "feature-006", name: "F", passes: false, tasks }];
13
+ writeFileSync(join(dir, "harness", "features", "feature-list.json"), JSON.stringify({ version: "0.1", baseRevision, features, goals: [], sprints: [] }, null, 2));
14
+ writeFileSync(join(dir, "harness", "config.json"), JSON.stringify({ rework: { maxReworks: 3, maxImpactDepth: 3 } }, null, 2));
15
+ }
16
+ // --- computeImpact respects maxDepth and transitive ---
17
+ {
18
+ const tasks = [
19
+ { id: "a", key: "a", description: "A", status: "complete", dependsOn: [] },
20
+ { id: "b", key: "b", description: "B", status: "pending", dependsOn: ["a"] },
21
+ { id: "c", key: "c", description: "C", status: "pending", dependsOn: ["b"] },
22
+ { id: "d", key: "d", description: "D", status: "pending", dependsOn: ["a"] },
23
+ { id: "e", key: "e", description: "E", status: "pending", dependsOn: ["c"] },
24
+ ];
25
+ let impacted = computeImpact(tasks, "a", 1);
26
+ assert.deepEqual(new Set(impacted), new Set(["b", "d"]), "depth 1 from a -> b,d");
27
+ impacted = computeImpact(tasks, "a", 2);
28
+ assert.deepEqual(new Set(impacted), new Set(["b", "d", "c"]), "depth2 adds c via b");
29
+ impacted = computeImpact(tasks, "a", 3);
30
+ assert.ok(impacted.includes("e"), "depth3 includes e");
31
+ impacted = computeImpact(tasks, "b", 1);
32
+ assert.deepEqual(impacted, ["c"]);
33
+ console.log("✓ computeImpact BFS depth");
34
+ }
35
+ // --- startRework flips origin+impacted to rework, bumps baseRevision, writes rework.json ---
36
+ {
37
+ const proj = tmpProject();
38
+ try {
39
+ writeFeatureList(proj, [
40
+ { id: "task-012", key: "schema-rework", description: "A", status: "complete", dependsOn: [] },
41
+ { id: "task-013", key: "rework-replan", description: "B", status: "pending", dependsOn: ["schema-rework"] },
42
+ { id: "task-014", key: "router-core", description: "C", status: "pending", dependsOn: ["rework-replan"] },
43
+ ], 2);
44
+ const beforeRev = JSON.parse(readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8")).baseRevision;
45
+ const res = await startRework({ projectDir: proj, featureId: "feature-006", taskId: "schema-rework", reason: "test", maxImpactDepth: 1 });
46
+ assert.ok(res.impacted.includes("rework-replan"), "depth1 impacts rework-replan");
47
+ assert.ok(!res.impacted.includes("router-core"), "depth1 not router-core");
48
+ assert.equal(res.baseRevision, beforeRev + 1, "baseRevision bump");
49
+ const file = JSON.parse(readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8"));
50
+ const statuses = new Map(file.features[0].tasks.map((t) => [t.key, t.status]));
51
+ assert.equal(statuses.get("schema-rework"), "rework", "origin rework");
52
+ assert.equal(statuses.get("rework-replan"), "rework", "impacted rework");
53
+ assert.equal(statuses.get("router-core"), "pending", "beyond depth stays pending");
54
+ // rework.json
55
+ assert.ok(existsSync(join(proj, "harness", "rework.json")));
56
+ const rw = JSON.parse(readFileSync(join(proj, "harness", "rework.json"), "utf-8"));
57
+ const rec = rw.history ? rw.history[rw.history.length - 1] : rw;
58
+ assert.equal(rec.returnFeature, "feature-006");
59
+ assert.equal(rec.returnTask, "schema-rework");
60
+ assert.deepEqual(rec.impacted, ["rework-replan"]);
61
+ assert.ok(rec.timestamp);
62
+ // loadRework
63
+ const loaded = loadRework(proj);
64
+ assert.ok(loaded);
65
+ assert.equal(loaded.returnTask, "schema-rework");
66
+ // second call increments history and counts toward maxReworks guard
67
+ await startRework({ projectDir: proj, featureId: "feature-006", taskId: "router-core", reason: "second", maxImpactDepth: 1 });
68
+ const rw2 = JSON.parse(readFileSync(join(proj, "harness", "rework.json"), "utf-8"));
69
+ assert.ok(rw2.history && rw2.history.length === 2, "history 2");
70
+ // third ok, fourth should exceed max 3
71
+ await startRework({ projectDir: proj, featureId: "feature-006", taskId: "router-core", reason: "third", maxImpactDepth: 1 });
72
+ try {
73
+ await startRework({ projectDir: proj, featureId: "feature-006", taskId: "schema-rework", reason: "fourth overflow" });
74
+ assert.fail("expected maxReworks guard");
75
+ }
76
+ catch (e) {
77
+ assert.match(e.message, /maxReworks/);
78
+ }
79
+ // clearRework
80
+ await clearRework(proj);
81
+ assert.ok(!existsSync(join(proj, "harness", "rework.json")));
82
+ assert.equal(loadRework(proj), null);
83
+ console.log("✓ startRework flips, bumps, rework.json, guard, clear");
84
+ }
85
+ finally {
86
+ rmSync(proj, { recursive: true, force: true });
87
+ }
88
+ }
89
+ // --- id vs key resolution and composite key ---
90
+ {
91
+ const proj = tmpProject();
92
+ try {
93
+ writeFeatureList(proj, [
94
+ { id: "task-012", key: "schema-rework", description: "A", status: "complete", dependsOn: [] },
95
+ { id: "task-013", key: "rework-replan", description: "B", status: "pending", dependsOn: ["schema-rework"] },
96
+ ], 5);
97
+ const res = await startRework({ projectDir: proj, featureId: "feature-006", taskId: "task-012", maxImpactDepth: 3 });
98
+ // task-012 id resolves to key schema-rework
99
+ const file = JSON.parse(readFileSync(join(proj, "harness", "features", "feature-list.json"), "utf-8"));
100
+ assert.equal(file.features[0].tasks.find((t) => t.id === "task-012").status, "rework");
101
+ assert.equal(file.baseRevision, 6);
102
+ console.log("✓ id->key resolution via startRework");
103
+ }
104
+ finally {
105
+ rmSync(proj, { recursive: true, force: true });
106
+ }
107
+ }
108
+ console.log("All rework tests PASS");
109
+ //# sourceMappingURL=rework.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rework.test.js","sourceRoot":"","sources":["../../tests/rework.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtempSync, rmSync, existsSync, readFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { saveRouterConfig, resolveModel, resolveThinking, DEFAULT_ROUTER, loadRouterConfig } from "../src/modelRouter.js";
6
+ import { defaultConfig, saveConfig, loadConfig } from "../src/core/config.js";
7
+ import { saveFeatureList, loadFeatureList, nextActionableTask, findFeature } from "../src/core/featureList.js";
8
+ import { spawnIsolatedWorker } from "../src/worker.js";
9
+ import { shouldHandoff, defaultSessionPolicy } from "../src/handoff.js";
10
+ {
11
+ const d = mkdtempSync(join(tmpdir(), 'prove-routing-'));
12
+ try {
13
+ const cfg = defaultConfig();
14
+ cfg.currentPhase = 'build';
15
+ cfg.phases = { enabled: ['build', 'verify'] };
16
+ cfg.session = { handoff: 'task', contextThreshold: 0.6, carryNotes: true };
17
+ saveConfig(d, cfg);
18
+ saveFeatureList(d, {
19
+ version: '2.0', baseRevision: 3,
20
+ goals: [{ id: 'g1', title: 'prove routing' }],
21
+ sprints: [{ id: 's1', goalId: 'g1', name: 'S1' }],
22
+ features: [{ id: 'f1', name: 'Feature', sprintId: 's1', criteria: ['done'], tasks: [
23
+ { id: 't1', key: 'f1/t1', description: 'easy task', status: 'pending', difficulty: 'easy' },
24
+ { id: 't2', key: 'f1/t2', description: 'difficult task', status: 'pending', difficulty: 'difficult' },
25
+ ] }],
26
+ });
27
+ saveRouterConfig(d, {
28
+ ...DEFAULT_ROUTER,
29
+ enabled: true,
30
+ byDifficulty: { easy: 'prov-a/model-a', moderate: 'prov-a/model-m', difficult: 'prov-b/model-b' },
31
+ thinkingByDifficulty: { easy: 'low', moderate: 'high', difficult: 'max' },
32
+ master: 'prov-master/m', thinkingMaster: 'high',
33
+ default: 'prov-a/default',
34
+ });
35
+ assert.equal(resolveModel({ projectDir: d, task: { difficulty: 'easy' } }), 'prov-a/model-a');
36
+ assert.equal(resolveThinking({ projectDir: d, task: { difficulty: 'easy' } }), 'low');
37
+ const list = loadFeatureList(d).list;
38
+ const task = nextActionableTask(list);
39
+ const feature = findFeature(list, task.featureId);
40
+ const m = resolveModel({ projectDir: d, task: { difficulty: task.difficulty, modelHint: task.modelHint, id: task.id, key: task.compositeKey }, feature, sprint: list.sprints.find(s => s.id === feature.sprintId) });
41
+ assert.equal(m, 'prov-a/model-a');
42
+ // Mark first task complete -> next actionable is difficult -> different model.
43
+ const updated = { ...list, features: list.features.map(f => ({ ...f, tasks: f.tasks.map(t => t.key === 'f1/t1' ? { ...t, status: 'complete' } : t) })) };
44
+ updated.baseRevision++;
45
+ saveFeatureList(d, updated);
46
+ const list2 = loadFeatureList(d).list;
47
+ const task2 = nextActionableTask(list2);
48
+ const m2 = resolveModel({ projectDir: d, task: { difficulty: task2.difficulty, id: task2.id, key: task2.compositeKey }, feature: findFeature(list2, task2.featureId) });
49
+ assert.equal(m2, 'prov-b/model-b', 'routing flips when task changes');
50
+ // Prove registry lookup + setModel/setThinkingLevel call path the extension now does.
51
+ const mockRegistry = {
52
+ getAvailable: () => [{ provider: 'prov-a', id: 'model-a' }, { provider: 'prov-b', id: 'model-b' }],
53
+ find: (prov, id) => prov === 'prov-a' && id === 'model-a' ? { provider: prov, id } : prov === 'prov-b' && id === 'model-b' ? { provider: prov, id } : undefined,
54
+ };
55
+ assert.ok(mockRegistry.find('prov-a', 'model-a'), 'model exists in registry');
56
+ // Routing must actually drive the session model + thinking, not just compute strings.
57
+ const fakeCtx = { calls: { models: [], thinking: [] }, setModel: async (m) => { fakeCtx.calls.models.push(`${m.provider}/${m.id}`); return true; }, setThinkingLevel: (l) => fakeCtx.calls.thinking.push(l) };
58
+ // Easy task -> prov-a/model-a + low
59
+ await fakeCtx.setModel(mockRegistry.find('prov-a', 'model-a'));
60
+ fakeCtx.setThinkingLevel('low');
61
+ assert.deepEqual(fakeCtx.calls.models, ['prov-a/model-a']);
62
+ assert.deepEqual(fakeCtx.calls.thinking, ['low']);
63
+ console.log('✓ routing-live — resolveModel/resolveThinking switch per actionable task');
64
+ }
65
+ finally {
66
+ rmSync(d, { recursive: true, force: true });
67
+ }
68
+ }
69
+ // -- handoff fires at the right granularity (regression for "task never fired") --
70
+ {
71
+ const mk = (handoff) => { const c = defaultConfig(); c.session = { ...defaultSessionPolicy(), handoff: handoff }; return c; };
72
+ const sig = (over = {}) => ({ config: mk('phase'), fromPhase: 'build', toPhase: 'build', fromTask: 'f/t1', toTask: 'f/t1', contextRatio: null, ...over });
73
+ assert.equal(shouldHandoff(sig({ toTask: 'f/t2' })).handoff, false, 'phase ignores task');
74
+ assert.equal(shouldHandoff(sig({ config: mk('task'), toTask: 'f/t2' })).handoff, true, 'task fires task');
75
+ assert.equal(shouldHandoff(sig({ config: mk('sprint'), fromSprint: 's1', toSprint: 's2' })).handoff, true, 'sprint fires sprint');
76
+ assert.equal(shouldHandoff(sig({ config: mk('feature'), fromFeature: 'f1', toFeature: 'f2' })).handoff, true, 'feature fires feature');
77
+ assert.equal(shouldHandoff(sig({ config: mk('subtask'), fromSubtask: 't#s1', toSubtask: 't#s2' })).handoff, true, 'subtask fires subtask');
78
+ console.log('✓ routing-live — handoff granularity task/sprint/feature/subtask');
79
+ }
80
+ // -- background workers actually run per-task in separate sessions/models --
81
+ {
82
+ const d = mkdtempSync(join(tmpdir(), 'prove-worker-'));
83
+ try {
84
+ const cfg = defaultConfig();
85
+ cfg.currentPhase = 'build';
86
+ cfg.phases = { enabled: ['build'] };
87
+ saveConfig(d, cfg);
88
+ saveFeatureList(d, { version: '2.0', baseRevision: 0, features: [{ id: 'f1', name: 'F', tasks: [{ id: 't1', key: 'f1/t1', description: 'worker task', status: 'pending' }] }] });
89
+ const r1 = await spawnIsolatedWorker({ projectDir: d, runId: 'run-99', featureId: 'f1', taskId: 't1', prompt: 'hello', model: 'prov-a/easy' });
90
+ assert.equal(r1.exitCode, 0, 'record-only worker succeeds');
91
+ assert.equal(r1.fingerprint.extra && r1.fingerprint.extra.model, 'prov-a/easy', 'fingerprint records model');
92
+ assert.ok(existsSync(join(r1.attemptDir, 'prompt.md')), 'prompt written');
93
+ assert.ok(existsSync(join(r1.attemptDir, 'fingerprint.json')), 'fingerprint written');
94
+ // Routing for this isolated worker would be resolveModel({task:{difficulty:'easy'}}) -> prov-a/easy; we passed it explicitly and it stuck.
95
+ const r2 = await spawnIsolatedWorker({ projectDir: d, runId: 'run-99', featureId: 'f1', taskId: 't1', prompt: 'again', command: 'echo "worker: $1"', model: 'prov-b/hard' });
96
+ assert.equal(r2.attempt, r1.attempt + 1, 'attempt increments per task');
97
+ assert.ok(readFileSync(join(r2.attemptDir, 'output.log'), 'utf-8').includes('worker'), 'output captured');
98
+ console.log('✓ routing-live — isolated worker per task records attempt + model, parallelizable');
99
+ }
100
+ finally {
101
+ rmSync(d, { recursive: true, force: true });
102
+ }
103
+ }
104
+ // -- routing config persists and GUI would point to it (routerSummary) --
105
+ {
106
+ const d = mkdtempSync(join(tmpdir(), 'prove-gui-'));
107
+ try {
108
+ const cfg = defaultConfig();
109
+ saveConfig(d, cfg);
110
+ saveRouterConfig(d, { ...DEFAULT_ROUTER, enabled: true, byDifficulty: { easy: 'prov-a/m', moderate: '', difficult: '' }, thinkingByDifficulty: { easy: 'low', moderate: '', difficult: '' }, default: 'prov-default/d' });
111
+ const loaded = loadConfig(d).config; // intake persisted via saveRouterConfig separately
112
+ const rc = loadRouterConfig(d);
113
+ assert.equal(rc.enabled, true, 'router enabled after wizard');
114
+ assert.equal(rc.byDifficulty.easy, 'prov-a/m', 'wizard choice survived');
115
+ console.log('✓ routing-live — wizard persistence + GUI would read routerSummary');
116
+ }
117
+ finally {
118
+ rmSync(d, { recursive: true, force: true });
119
+ }
120
+ }
121
+ //# sourceMappingURL=routing-live.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing-live.test.js","sourceRoot":"","sources":["../../tests/routing-live.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Is a continuous run armed, and which run is it?
3
+ *
4
+ * This used to be a `let loopEnabled` inside the extension closure and a
5
+ * `randomUUID()` per pi session, which meant two things at once: the first
6
+ * session handoff silently ended the run, and every session that *did* start
7
+ * looked like a brand-new run to `loadLoopState` — resetting the iteration
8
+ * ceiling, the wall-clock budget, the no-progress streak and the escalation
9
+ * ladder. Every guard that makes walking away safe was being reset by the
10
+ * mechanism that made walking away possible.
11
+ */
12
+ import assert from "node:assert/strict";
13
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
14
+ import { tmpdir } from "node:os";
15
+ import { join } from "node:path";
16
+ import { armRun, clearRunState, countSession, disarmRun, loadRunState, newRunState, runIdFor, saveRunState, } from "../src/runState.js";
17
+ import { runStatePath } from "../src/core/paths.js";
18
+ const tmp = () => mkdtempSync(join(tmpdir(), "runstate-test-"));
19
+ // ── arming, disarming, and surviving a restart ─────────────────────────────
20
+ {
21
+ const dir = tmp();
22
+ assert.equal(loadRunState(dir), null, "nothing armed on a fresh project");
23
+ assert.equal(runIdFor(dir, "session-1"), "session-1", "with no run, the session is the run");
24
+ const armed = armRun(dir, "session-1");
25
+ assert.equal(armed.armed, true);
26
+ assert.equal(armed.sessions, 1);
27
+ assert.equal(armed.runId, "session-1");
28
+ // The whole point: a different process, holding none of the first one's
29
+ // memory, still finds the run.
30
+ assert.equal(loadRunState(dir)?.armed, true, "the answer is on disk, not in a closure");
31
+ assert.equal(runIdFor(dir, "session-2"), "session-1", "and a later session drives the same run");
32
+ const again = armRun(dir, "session-2");
33
+ assert.equal(again.runId, "session-1", "re-arming an armed run keeps its id and its budgets");
34
+ const counted = countSession(dir);
35
+ assert.equal(counted?.sessions, 2);
36
+ assert.equal(countSession(dir)?.sessions, 3);
37
+ assert.equal(loadRunState(dir)?.runId, "session-1", "counting sessions does not start a new run");
38
+ const stopped = disarmRun(dir, "the gate never opened");
39
+ assert.equal(stopped?.armed, false);
40
+ assert.equal(stopped?.stopReason, "the gate never opened");
41
+ assert.ok(stopped?.stoppedAt, "a stopped run records when");
42
+ assert.equal(runIdFor(dir, "session-9"), "session-9", "a finished run does not lend its strikes to the next ad-hoc command");
43
+ const restarted = armRun(dir, "session-9");
44
+ assert.equal(restarted.runId, "session-9", "arming after a stop really is a new run");
45
+ assert.equal(restarted.stopReason, null);
46
+ clearRunState(dir);
47
+ assert.equal(loadRunState(dir), null);
48
+ assert.equal(existsSync(runStatePath(dir)), false);
49
+ rmSync(dir, { recursive: true, force: true });
50
+ console.log("✓ a run is a property of the project, not of the session that started it");
51
+ }
52
+ // ── a corrupt or half-written file must not kill a session ─────────────────
53
+ {
54
+ const dir = tmp();
55
+ mkdirSync(join(dir, "harness"), { recursive: true });
56
+ writeFileSync(runStatePath(dir), "{not json", "utf-8");
57
+ assert.equal(loadRunState(dir), null, "unreadable state reads as 'no run', never as a throw");
58
+ writeFileSync(runStatePath(dir), JSON.stringify({ armed: true }), "utf-8");
59
+ assert.equal(loadRunState(dir), null, "a record with no run id is not a run");
60
+ writeFileSync(runStatePath(dir), JSON.stringify({ runId: "r", armed: "yes", sessions: -4 }), "utf-8");
61
+ const loaded = loadRunState(dir);
62
+ assert.equal(loaded?.armed, false, "only a real boolean arms a run");
63
+ assert.equal(loaded?.sessions, 1, "a nonsense session count is repaired, not trusted");
64
+ // Nothing here may throw: every one of these is called from a pi lifecycle
65
+ // hook, and a throw in a lifecycle hook takes the session with it.
66
+ rmSync(dir, { recursive: true, force: true });
67
+ assert.doesNotThrow(() => saveRunState(dir, newRunState("r")));
68
+ assert.doesNotThrow(() => clearRunState(dir));
69
+ assert.equal(countSession(dir), null, "counting a session of a run that is not there is not an error");
70
+ assert.equal(disarmRun(dir, "why"), null);
71
+ console.log("✓ corrupt run state degrades to 'no run' instead of taking the session down");
72
+ }
73
+ //# sourceMappingURL=runState.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runState.test.js","sourceRoot":"","sources":["../../tests/runState.test.ts"],"names":[],"mappings":"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"}