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,216 @@
1
+ /**
2
+ * modelRouter — difficulty tiers + MASTER ladder, fresh-read each call, optional via harness/model-router.json v1
3
+ * Priority: task.modelHint > byDifficulty[difficulty] > byFeature > bySprint > byPhase > byRole > default
4
+ * Ladder: easy -> moderate -> difficult -> MASTER (MASTER never directly assigned)
5
+ */
6
+ import { existsSync, readFileSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+ import { writeJsonAtomic, stripBom } from "./core/fsx.js";
9
+ export const ROUTER_FILE = "harness/model-router.json";
10
+ export const ROUTER_VERSION = 1;
11
+ export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
12
+ export function isThinkingLevel(v) {
13
+ return typeof v === "string" && THINKING_LEVELS.includes(v);
14
+ }
15
+ /**
16
+ * Router defaults.
17
+ *
18
+ * Every model slot is empty on purpose. An empty string means "whatever model
19
+ * pi is already configured with", so installing the harness never silently
20
+ * redirects work to some vendor's model that the user did not choose. Routing
21
+ * only takes effect once someone fills in harness/model-router.json and sets
22
+ * `enabled: true`.
23
+ */
24
+ export const DEFAULT_ROUTER = {
25
+ version: 1,
26
+ enabled: false,
27
+ default: "",
28
+ byDifficulty: {
29
+ easy: "",
30
+ moderate: "",
31
+ difficult: "",
32
+ },
33
+ master: "",
34
+ byPhase: {},
35
+ byRole: {},
36
+ byFeature: {},
37
+ bySprint: {},
38
+ byTask: {},
39
+ consultation: { enabled: true, maxPerTask: 1, oneStepOnly: true, requireExhaustion: true },
40
+ budgets: { maxReworksPerRun: 3, maxReplansPerRun: 2, maxReviewBounces: 2 },
41
+ thinkingByDifficulty: { easy: "", moderate: "", difficult: "" },
42
+ thinkingMaster: "",
43
+ thinkingDefault: "",
44
+ };
45
+ export const DIFFICULTY_LADDER = ["easy", "moderate", "difficult"];
46
+ function routerPath(projectDir = process.cwd()) { return resolve(projectDir, ROUTER_FILE); }
47
+ /**
48
+ * Persist the router config.
49
+ *
50
+ * Written atomically and read fresh on every resolution, so an edit made from
51
+ * the config TUI takes effect on the next task without restarting the session.
52
+ */
53
+ export function saveRouterConfig(projectDir, cfg) {
54
+ writeJsonAtomic(routerPath(projectDir), cfg);
55
+ }
56
+ function normalizeThinking(v) {
57
+ return typeof v === "string" && THINKING_LEVELS.includes(v) ? v : "";
58
+ }
59
+ export function loadRouterConfig(projectDir) {
60
+ const p = routerPath(projectDir);
61
+ if (!existsSync(p))
62
+ return { ...DEFAULT_ROUTER, byDifficulty: { ...DEFAULT_ROUTER.byDifficulty }, byPhase: {}, byRole: {}, byFeature: {}, bySprint: {}, byTask: {}, consultation: { ...DEFAULT_ROUTER.consultation }, budgets: { ...DEFAULT_ROUTER.budgets }, thinkingByDifficulty: { ...DEFAULT_ROUTER.thinkingByDifficulty }, thinkingMaster: DEFAULT_ROUTER.thinkingMaster, thinkingDefault: DEFAULT_ROUTER.thinkingDefault };
63
+ try {
64
+ const raw = JSON.parse(stripBom(readFileSync(p, "utf-8")));
65
+ // merge with defaults to ensure fields
66
+ const cfg = {
67
+ version: typeof raw.version === "number" ? raw.version : 1,
68
+ enabled: typeof raw.enabled === "boolean" ? raw.enabled : false,
69
+ default: typeof raw.default === "string" && raw.default ? raw.default : DEFAULT_ROUTER.default,
70
+ byDifficulty: raw.byDifficulty ?? { ...DEFAULT_ROUTER.byDifficulty },
71
+ master: typeof raw.master === "string" ? raw.master : DEFAULT_ROUTER.master,
72
+ byPhase: raw.byPhase ?? {},
73
+ byRole: raw.byRole ?? {},
74
+ byFeature: raw.byFeature ?? {},
75
+ bySprint: raw.bySprint ?? {},
76
+ byTask: raw.byTask ?? {},
77
+ consultation: raw.consultation ?? { ...DEFAULT_ROUTER.consultation },
78
+ budgets: raw.budgets ?? { ...DEFAULT_ROUTER.budgets },
79
+ thinkingByDifficulty: (() => {
80
+ const cur = raw.thinkingByDifficulty;
81
+ if (!cur || typeof cur !== "object")
82
+ return { ...DEFAULT_ROUTER.thinkingByDifficulty };
83
+ const out = {};
84
+ for (const k of DIFFICULTY_LADDER)
85
+ out[k] = normalizeThinking(cur[k]);
86
+ return out;
87
+ })(),
88
+ thinkingMaster: normalizeThinking(raw.thinkingMaster),
89
+ thinkingDefault: normalizeThinking(raw.thinkingDefault),
90
+ };
91
+ if (!cfg.byDifficulty)
92
+ cfg.byDifficulty = { ...DEFAULT_ROUTER.byDifficulty };
93
+ if (!cfg.thinkingByDifficulty)
94
+ cfg.thinkingByDifficulty = { ...DEFAULT_ROUTER.thinkingByDifficulty };
95
+ return cfg;
96
+ }
97
+ catch {
98
+ return { ...DEFAULT_ROUTER };
99
+ }
100
+ }
101
+ export function resolveModel(opts = {}) {
102
+ const cfg = loadRouterConfig(opts.projectDir);
103
+ if (!cfg.enabled)
104
+ return cfg.default;
105
+ // 1. task.modelHint (explicit override)
106
+ const hint = opts.modelHint ?? opts.task?.modelHint;
107
+ if (hint && hint.trim())
108
+ return hint.trim();
109
+ // 2. byTask exact key
110
+ const taskKey = opts.task?.key ?? opts.task?.id;
111
+ if (taskKey && cfg.byTask && cfg.byTask[taskKey])
112
+ return cfg.byTask[taskKey];
113
+ // 3. byDifficulty[difficulty]
114
+ const difficulty = opts.difficulty ?? opts.task?.difficulty ?? opts.feature?.difficulty ?? opts.sprint?.difficulty;
115
+ if (difficulty && cfg.byDifficulty && cfg.byDifficulty[difficulty]) {
116
+ return cfg.byDifficulty[difficulty];
117
+ }
118
+ // 4. byFeature
119
+ const featureId = opts.feature?.id;
120
+ if (featureId && cfg.byFeature && cfg.byFeature[featureId])
121
+ return cfg.byFeature[featureId];
122
+ // 5. bySprint
123
+ const sprintId = opts.sprint?.id;
124
+ if (sprintId && cfg.bySprint && cfg.bySprint[sprintId])
125
+ return cfg.bySprint[sprintId];
126
+ // 6. byPhase
127
+ if (opts.phase && cfg.byPhase && cfg.byPhase[opts.phase])
128
+ return cfg.byPhase[opts.phase];
129
+ // 7. byRole
130
+ if (opts.role && cfg.byRole && cfg.byRole[opts.role])
131
+ return cfg.byRole[opts.role];
132
+ return cfg.default;
133
+ }
134
+ /**
135
+ * One-step ladder: easy -> moderate -> difficult -> MASTER
136
+ * MASTER never assigned, only via consultNext after exhaustion.
137
+ * Returns next model or null if at top/budget exhausted.
138
+ */
139
+ export function consultNextWithThinking(currentDifficulty, opts = {}) {
140
+ const model = consultNext(currentDifficulty, opts);
141
+ let thinking = "";
142
+ if (model) {
143
+ const idx = DIFFICULTY_LADDER.indexOf(currentDifficulty);
144
+ const nextDiff = idx >= 0 && idx < DIFFICULTY_LADDER.length - 1 ? DIFFICULTY_LADDER[idx + 1] : (idx === DIFFICULTY_LADDER.length - 1 ? null : null);
145
+ thinking = resolveThinkingForConsult(nextDiff, opts.projectDir) ?? "";
146
+ }
147
+ return { model, thinking };
148
+ }
149
+ export function consultNext(currentDifficulty, opts = {}) {
150
+ const cfg = loadRouterConfig(opts.projectDir);
151
+ if (!cfg.consultation?.enabled)
152
+ return null;
153
+ const maxPerTask = cfg.consultation.maxPerTask ?? 1;
154
+ if ((opts.consultedCount ?? 0) >= maxPerTask)
155
+ return null;
156
+ // oneStepOnly: only one step per call
157
+ if (!currentDifficulty) {
158
+ // from no difficulty -> easy? Actually consult is after exhaustion of current ladder rung
159
+ // If no difficulty, next is byDifficulty easy, else if easy -> moderate etc.
160
+ return null;
161
+ }
162
+ const idx = DIFFICULTY_LADDER.indexOf(currentDifficulty);
163
+ if (idx === -1) {
164
+ // unknown difficulty: check if current is byDifficulty value? Try to infer
165
+ return null;
166
+ }
167
+ if (idx < DIFFICULTY_LADDER.length - 1) {
168
+ const nextDiff = DIFFICULTY_LADDER[idx + 1];
169
+ const nextModel = cfg.byDifficulty?.[nextDiff] ?? DEFAULT_ROUTER.byDifficulty[nextDiff];
170
+ return nextModel ?? null;
171
+ }
172
+ // at difficult -> MASTER
173
+ if (idx === DIFFICULTY_LADDER.length - 1) {
174
+ return cfg.master ?? DEFAULT_ROUTER.master ?? null;
175
+ }
176
+ return null;
177
+ }
178
+ export function resolveThinking(opts = {}) {
179
+ const cfg = loadRouterConfig(opts.projectDir);
180
+ // Thinking is orthogonal to routing-enabled; when disabled, fall through to default/inherit.
181
+ const difficulty = opts.difficulty ?? opts.task?.difficulty ?? opts.feature?.difficulty ?? opts.sprint?.difficulty;
182
+ if (difficulty && cfg.thinkingByDifficulty && cfg.thinkingByDifficulty[difficulty]) {
183
+ const v = cfg.thinkingByDifficulty[difficulty];
184
+ if (v)
185
+ return v;
186
+ }
187
+ // Master thinking only via consultation path; here just check difficulty default fallback
188
+ if (cfg.thinkingDefault)
189
+ return cfg.thinkingDefault;
190
+ return "";
191
+ }
192
+ export function resolveThinkingForConsult(nextDifficulty, projectDir) {
193
+ const cfg = loadRouterConfig(projectDir);
194
+ if (!nextDifficulty)
195
+ return cfg.thinkingMaster ?? "";
196
+ const v = cfg.thinkingByDifficulty?.[nextDifficulty];
197
+ if (v)
198
+ return v;
199
+ return "";
200
+ }
201
+ /** For widget/remote read-only exposure */
202
+ export function routerSummary(projectDir) {
203
+ const cfg = loadRouterConfig(projectDir);
204
+ return {
205
+ enabled: cfg.enabled,
206
+ default: cfg.default,
207
+ byDifficulty: { ...(cfg.byDifficulty ?? {}) },
208
+ thinkingByDifficulty: { ...(cfg.thinkingByDifficulty ?? {}) },
209
+ master: cfg.master ?? DEFAULT_ROUTER.master,
210
+ thinkingMaster: (cfg.thinkingMaster ?? ""),
211
+ thinkingDefault: (cfg.thinkingDefault ?? ""),
212
+ budgets: cfg.budgets,
213
+ consultation: cfg.consultation,
214
+ };
215
+ }
216
+ //# sourceMappingURL=modelRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelRouter.js","sourceRoot":"","sources":["../../src/modelRouter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,CAAC,MAAM,WAAW,GAAG,2BAA2B,CAAC;AACvD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAIhC,MAAM,CAAC,MAAM,eAAe,GAA6B,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAU,CAAC;AAE9H,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC;AAqBD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,EAAE;IACX,YAAY,EAAE;QACZ,IAAI,EAAE,EAAE;QACR,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,EAAE;KACd;IACD,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,EAAE;IACV,SAAS,EAAE,EAAE;IACb,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;IAC1F,OAAO,EAAE,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE;IAC1E,oBAAoB,EAAE,EAAE,IAAI,EAAE,EAAwB,EAAE,QAAQ,EAAE,EAAwB,EAAE,SAAS,EAAE,EAAwB,EAAiD;IAChL,cAAc,EAAE,EAAwB;IACxC,eAAe,EAAE,EAAwB;CAC1C,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAA6C,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAE7G,SAAS,UAAU,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,IAAY,OAAO,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AAEpG;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,GAAiB;IACpE,eAAe,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAU;IACnC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;AACjH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAmB;IAClD,MAAM,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,YAAY,EAAE,EAAE,GAAG,cAAc,CAAC,YAAa,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,GAAG,cAAc,CAAC,YAAa,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,cAAc,CAAC,OAAQ,EAAE,EAAE,oBAAoB,EAAE,EAAE,GAAI,cAAc,CAAC,oBAA2D,EAAE,EAAE,cAAc,EAAE,cAAc,CAAC,cAAc,EAAE,eAAe,EAAE,cAAc,CAAC,eAAe,EAAE,CAAC;IAC5c,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3D,uCAAuC;QACvC,MAAM,GAAG,GAAiB;YACxB,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1D,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;YAC/D,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO;YAC9F,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,EAAE,GAAG,cAAc,CAAC,YAAa,EAAE;YACrE,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM;YAC3E,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE;YAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;YACxB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE;YAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;YACxB,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,EAAE,GAAG,cAAc,CAAC,YAAa,EAAE;YACrE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,GAAG,cAAc,CAAC,OAAQ,EAAE;YACtD,oBAAoB,EAAE,CAAC,GAAG,EAAE;gBAC1B,MAAM,GAAG,GAAG,GAAG,CAAC,oBAAoB,CAAC;gBACrC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;oBAAE,OAAO,EAAE,GAAI,cAAc,CAAC,oBAA2D,EAAE,CAAC;gBAC/H,MAAM,GAAG,GAAuC,EAAE,CAAC;gBACnD,KAAK,MAAM,CAAC,IAAI,iBAAiB;oBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAE,GAA+B,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnG,OAAO,GAAG,CAAC;YACb,CAAC,CAAC,EAAE;YACJ,cAAc,EAAE,iBAAiB,CAAC,GAAG,CAAC,cAAc,CAAC;YACrD,eAAe,EAAE,iBAAiB,CAAC,GAAG,CAAC,eAAe,CAAC;SACxD,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,YAAY;YAAE,GAAG,CAAC,YAAY,GAAG,EAAE,GAAG,cAAc,CAAC,YAAa,EAAE,CAAC;QAC9E,IAAI,CAAC,GAAG,CAAC,oBAAoB;YAAE,GAAG,CAAC,oBAAoB,GAAG,EAAE,GAAI,cAAc,CAAC,oBAA2D,EAAE,CAAC;QAC7I,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;AACH,CAAC;AAcD,MAAM,UAAU,YAAY,CAAC,OAAoB,EAAE;IACjD,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IACrC,wCAAwC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;IACpD,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5C,sBAAsB;IACtB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;IAChD,IAAI,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7E,8BAA8B;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;IACnH,IAAI,UAAU,IAAI,GAAG,CAAC,YAAY,IAAK,GAAG,CAAC,YAAuC,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/F,OAAQ,GAAG,CAAC,YAAuC,CAAC,UAAU,CAAC,CAAC;IAClE,CAAC;IACD,eAAe;IACf,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;IACnC,IAAI,SAAS,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5F,cAAc;IACd,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACjC,IAAI,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtF,aAAa;IACb,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzF,YAAY;IACZ,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnF,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,iBAA4C,EAC5C,OAAyD,EAAE;IAE3D,MAAM,KAAK,GAAG,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,QAAQ,GAAuB,EAAE,CAAC;IACtC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,iBAAwB,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,GAAG,CAAC,CAAW,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9J,QAAQ,GAAG,yBAAyB,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,iBAA4C,EAC5C,OAAyD,EAAE;IAE3D,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,UAAU,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC,IAAI,UAAU;QAAE,OAAO,IAAI,CAAC;IAC1D,sCAAsC;IACtC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,0FAA0F;QAC1F,6EAA6E;QAC7E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,iBAAwB,CAAC,CAAC;IAChE,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,2EAA2E;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,GAAG,GAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,IAAI,cAAc,CAAC,YAAa,CAAC,QAAQ,CAAC,CAAC;QACzF,OAAO,SAAS,IAAI,IAAI,CAAC;IAC3B,CAAC;IACD,yBAAyB;IACzB,IAAI,GAAG,KAAK,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,GAAG,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,IAAI,IAAI,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAoB,EAAE;IACpD,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9C,6FAA6F;IAC7F,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;IACnH,IAAI,UAAU,IAAI,GAAG,CAAC,oBAAoB,IAAK,GAAG,CAAC,oBAA2D,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3H,MAAM,CAAC,GAAI,GAAG,CAAC,oBAA2D,CAAC,UAAU,CAAC,CAAC;QACvF,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAClB,CAAC;IACD,0FAA0F;IAC1F,IAAI,GAAG,CAAC,eAAe;QAAE,OAAO,GAAG,CAAC,eAAe,CAAC;IACpD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,cAA6B,EAAE,UAAmB;IAC1F,MAAM,GAAG,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,CAAC,cAAc;QAAE,OAAO,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;IACrD,MAAM,CAAC,GAAG,GAAG,CAAC,oBAAoB,EAAE,CAAC,cAAwB,CAAmC,CAAC;IACjG,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAChB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,aAAa,CAAC,UAAmB;IAC/C,MAAM,GAAG,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,YAAY,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,EAA4B;QACvE,oBAAoB,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAwC;QACnG,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,cAAc,CAAC,MAAO;QAC5C,cAAc,EAAE,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAuB;QAChE,eAAe,EAAE,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAuB;QAClE,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,YAAY,EAAE,GAAG,CAAC,YAAY;KAC/B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,246 @@
1
+ /**
2
+ * infinity-harness — the read-only dashboard server.
3
+ *
4
+ * A developer running the harness unattended wants to glance at progress
5
+ * without attaching to the terminal session. This serves that view over plain
6
+ * HTTP on loopback.
7
+ *
8
+ * Two properties are non-negotiable:
9
+ *
10
+ * - **Read-only.** Nothing here writes, and nothing bumps `baseRevision`.
11
+ * Opening the dashboard must never perturb the run it is observing.
12
+ * - **Loopback by default.** The page exposes source paths, task text and
13
+ * gate output. Binding it to a public interface would leak the project.
14
+ * A non-loopback host has to be asked for explicitly.
15
+ */
16
+ import { createServer } from "node:http";
17
+ import { resolve } from "node:path";
18
+ import { loadFeatureList, computeProgress } from "./core/featureList.js";
19
+ import { loadConfig } from "./core/config.js";
20
+ import { modelRouterPath, reworkPath } from "./core/paths.js";
21
+ import { readJsonSafe } from "./core/fsx.js";
22
+ import { loadRunState } from "./runState.js";
23
+ import { normalizeDisplay } from "./ui/display.js";
24
+ import { supervisorStatePath, activityPath } from "./supervisor.js";
25
+ import { renderDashboard, escapeHtml } from "./ui/dashboard.js";
26
+ import { executionPolicyOf } from "./scheduler.js";
27
+ export { escapeHtml };
28
+ /**
29
+ * Snapshot everything the dashboard needs, from disk, without mutating a thing.
30
+ *
31
+ * The gate is *not* run here — running lint and tests because someone opened a
32
+ * web page would be a surprising and expensive side effect. The last recorded
33
+ * verdict from `gateHistory` is reported instead, which is what the human
34
+ * actually wants: what the harness last decided.
35
+ */
36
+ export function buildRemoteState(projectDir) {
37
+ const dir = projectDir ? resolve(projectDir) : process.cwd();
38
+ const { list } = loadFeatureList(dir);
39
+ const { config } = loadConfig(dir);
40
+ const lastGate = [...(config.gateHistory ?? [])].reverse()[0] ?? null;
41
+ const gate = lastGate
42
+ ? {
43
+ phase: lastGate.phase,
44
+ overall: lastGate.result === "pass",
45
+ failures: lastGate.result === "pass" ? [] : ["see terminal for detail"],
46
+ checks: [
47
+ {
48
+ name: `last recorded gate (${lastGate.timestamp})`,
49
+ pass: lastGate.result === "pass",
50
+ detail: lastGate.result === "pass"
51
+ ? `passed on ${lastGate.phase}`
52
+ : `failed on ${lastGate.phase} — run validate for the per-check breakdown`,
53
+ },
54
+ ],
55
+ ...(lastGate.feature ? { feature: lastGate.feature } : {}),
56
+ ...(lastGate.task ? { task: lastGate.task } : {}),
57
+ }
58
+ : null;
59
+ return {
60
+ baseRevision: list.baseRevision,
61
+ phase: config.currentPhase,
62
+ enabledPhases: config.phases?.enabled ?? null,
63
+ paused: Boolean(config.paused),
64
+ features: list.features ?? [],
65
+ goals: list.goals ?? [],
66
+ list,
67
+ progress: computeProgress(list),
68
+ gate,
69
+ retries: { task: config.taskRetryCount ?? 0, max: config.maxRetries ?? 10 },
70
+ timestamp: new Date().toISOString(),
71
+ router: readJsonSafe(modelRouterPath(dir), null),
72
+ rework: readJsonSafe(reworkPath(dir), null),
73
+ awaitingApproval: config.awaitingApproval ?? null,
74
+ sessions: loadRunState(dir)?.sessions ?? null,
75
+ execution: (() => { try {
76
+ return executionPolicyOf(config);
77
+ }
78
+ catch {
79
+ return null;
80
+ } })(),
81
+ engine: (() => { try {
82
+ return executionPolicyOf(config).engine;
83
+ }
84
+ catch {
85
+ return null;
86
+ } })(),
87
+ // The supervisor's own state is the truth about what is running. This used
88
+ // to scan the attempt-directory tree, which reported every attempt ever
89
+ // made as a live worker.
90
+ supervisor: readJsonSafe(supervisorStatePath(dir), null),
91
+ workers: (() => {
92
+ const sup = readJsonSafe(supervisorStatePath(dir), null);
93
+ const live = sup?.worker ? [sup.worker] : [];
94
+ const past = Array.isArray(sup?.history) ? sup.history.slice(-3).reverse() : [];
95
+ return [...live, ...past];
96
+ })(),
97
+ activity: (() => {
98
+ const raw = readJsonSafe(activityPath(dir), null);
99
+ return Array.isArray(raw?.lines) ? raw.lines.slice(-60) : [];
100
+ })(),
101
+ goalPass: typeof config.goalPass === "number" && typeof config.goalMaxPasses === "number"
102
+ ? { current: config.goalPass, max: config.goalMaxPasses }
103
+ : null,
104
+ sprints: list.sprints ?? [],
105
+ display: normalizeDisplay(config.display),
106
+ };
107
+ }
108
+ function toDashboardState(s) {
109
+ return {
110
+ list: s.list,
111
+ phase: s.phase,
112
+ enabledPhases: s.enabledPhases,
113
+ paused: s.paused,
114
+ gate: s.gate,
115
+ baseRevision: s.baseRevision,
116
+ timestamp: s.timestamp,
117
+ retries: s.retries,
118
+ router: s.router,
119
+ rework: s.rework,
120
+ awaitingApproval: s.awaitingApproval,
121
+ sessions: s.sessions,
122
+ goalPass: s.goalPass,
123
+ display: s.display,
124
+ engine: s.engine,
125
+ workers: s.workers ?? [],
126
+ activity: s.activity ?? [],
127
+ };
128
+ }
129
+ export function buildHtml(state) {
130
+ return renderDashboard(toDashboardState(state));
131
+ }
132
+ /** JSON payload for `/api/harness`. Excludes the full list to stay compact. */
133
+ export function buildApiPayload(state) {
134
+ return {
135
+ baseRevision: state.baseRevision,
136
+ phase: state.phase,
137
+ paused: state.paused,
138
+ progress: state.progress,
139
+ retries: state.retries,
140
+ timestamp: state.timestamp,
141
+ gate: state.gate,
142
+ router: state.router,
143
+ rework: state.rework,
144
+ awaitingApproval: state.awaitingApproval,
145
+ sessions: state.sessions,
146
+ engine: state.engine,
147
+ workers: state.workers,
148
+ activity: state.activity,
149
+ goalPass: state.goalPass,
150
+ sprints: state.sprints,
151
+ display: state.display,
152
+ features: state.features.map((f) => ({
153
+ id: f.id,
154
+ name: f.name,
155
+ passes: f.passes ?? false,
156
+ tasks: (f.tasks ?? []).map((t) => ({
157
+ id: t.id,
158
+ key: t.key ?? t.id,
159
+ description: t.description,
160
+ status: t.status,
161
+ dependsOn: t.dependsOn ?? [],
162
+ subtasks: t.subtasks ?? [],
163
+ })),
164
+ })),
165
+ goals: state.goals,
166
+ };
167
+ }
168
+ const LOOPBACK = new Set(["127.0.0.1", "::1", "localhost"]);
169
+ export async function createRemoteServer(opts) {
170
+ const projectDir = opts?.projectDir ? resolve(opts.projectDir) : process.cwd();
171
+ const host = opts?.host ?? "127.0.0.1";
172
+ const port = opts?.port ?? 0;
173
+ if (!LOOPBACK.has(host) && process.env.INFINITY_HARNESS_ALLOW_REMOTE !== "1") {
174
+ throw new Error(`refusing to bind the dashboard to ${host}: it exposes project source and task text. ` +
175
+ `Set INFINITY_HARNESS_ALLOW_REMOTE=1 if you really mean to.`);
176
+ }
177
+ const server = createServer((req, res) => {
178
+ // Read-only surface: anything that is not a GET is refused outright.
179
+ if (req.method !== "GET" && req.method !== "HEAD") {
180
+ res.writeHead(405, { "content-type": "text/plain; charset=utf-8", allow: "GET, HEAD" });
181
+ res.end("method not allowed");
182
+ return;
183
+ }
184
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
185
+ const noStore = { "cache-control": "no-store" };
186
+ try {
187
+ if (url.pathname === "/api/health") {
188
+ res.writeHead(200, { "content-type": "application/json; charset=utf-8", ...noStore });
189
+ res.end(JSON.stringify({ ok: true, timestamp: new Date().toISOString() }));
190
+ return;
191
+ }
192
+ if (url.pathname === "/api/harness") {
193
+ const payload = buildApiPayload(buildRemoteState(projectDir));
194
+ res.writeHead(200, { "content-type": "application/json; charset=utf-8", ...noStore });
195
+ res.end(JSON.stringify(payload, null, 2));
196
+ return;
197
+ }
198
+ if (url.pathname === "/") {
199
+ const html = buildHtml(buildRemoteState(projectDir));
200
+ res.writeHead(200, {
201
+ "content-type": "text/html; charset=utf-8",
202
+ // The page renders untrusted model output; a tight CSP means an
203
+ // escaping slip cannot become script execution.
204
+ "content-security-policy": "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src 'self'; img-src data:",
205
+ "x-content-type-options": "nosniff",
206
+ ...noStore,
207
+ });
208
+ res.end(html);
209
+ return;
210
+ }
211
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8", ...noStore });
212
+ res.end("not found");
213
+ }
214
+ catch (e) {
215
+ res.writeHead(500, { "content-type": "text/plain; charset=utf-8", ...noStore });
216
+ res.end(`dashboard error: ${e instanceof Error ? e.message : String(e)}`);
217
+ }
218
+ });
219
+ await new Promise((res, rej) => {
220
+ server.once("error", rej);
221
+ server.listen(port, host, () => {
222
+ server.removeListener("error", rej);
223
+ res();
224
+ });
225
+ });
226
+ const addr = server.address();
227
+ const shownHost = addr.address === "::1" ? "[::1]" : addr.address;
228
+ let closed = false;
229
+ return {
230
+ url: `http://${shownHost}:${addr.port}`,
231
+ host: addr.address,
232
+ port: addr.port,
233
+ close: async () => {
234
+ if (closed)
235
+ return;
236
+ closed = true;
237
+ await new Promise((res) => {
238
+ server.close(() => res());
239
+ // Idle keep-alive sockets would otherwise hold the server open past
240
+ // session shutdown, leaking a port for the life of the process.
241
+ server.closeAllConnections?.();
242
+ });
243
+ },
244
+ };
245
+ }
246
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/remote.ts"],"names":[],"mappings":"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"}