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.
- package/CHANGELOG.md +18 -0
- package/dist/extensions/infinity-harness/index.js +3614 -0
- package/dist/extensions/infinity-harness/index.js.map +1 -0
- package/dist/src/approval.js +154 -0
- package/dist/src/approval.js.map +1 -0
- package/dist/src/core/brief.js +309 -0
- package/dist/src/core/brief.js.map +1 -0
- package/dist/src/core/config.js +539 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/exec.js +106 -0
- package/dist/src/core/exec.js.map +1 -0
- package/dist/src/core/featureList.js +365 -0
- package/dist/src/core/featureList.js.map +1 -0
- package/dist/src/core/fsx.js +123 -0
- package/dist/src/core/fsx.js.map +1 -0
- package/dist/src/core/gates.js +490 -0
- package/dist/src/core/gates.js.map +1 -0
- package/dist/src/core/init.js +480 -0
- package/dist/src/core/init.js.map +1 -0
- package/dist/src/core/lock.js +183 -0
- package/dist/src/core/lock.js.map +1 -0
- package/dist/src/core/modelRouter.js +185 -0
- package/dist/src/core/modelRouter.js.map +1 -0
- package/dist/src/core/paths.js +129 -0
- package/dist/src/core/paths.js.map +1 -0
- package/dist/src/core/phases.js +254 -0
- package/dist/src/core/phases.js.map +1 -0
- package/dist/src/core/plan.js +15 -0
- package/dist/src/core/plan.js.map +1 -0
- package/dist/src/core/runState.js +126 -0
- package/dist/src/core/runState.js.map +1 -0
- package/dist/src/core/settings.js +877 -0
- package/dist/src/core/settings.js.map +1 -0
- package/dist/src/core/skills.js +319 -0
- package/dist/src/core/skills.js.map +1 -0
- package/dist/src/core/skillsAudit.js +194 -0
- package/dist/src/core/skillsAudit.js.map +1 -0
- package/dist/src/core/types.js +77 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/daemon/budget.js +85 -0
- package/dist/src/daemon/budget.js.map +1 -0
- package/dist/src/daemon/guard.js +122 -0
- package/dist/src/daemon/guard.js.map +1 -0
- package/dist/src/daemon/index.js +461 -0
- package/dist/src/daemon/index.js.map +1 -0
- package/dist/src/daemon/isolation.js +84 -0
- package/dist/src/daemon/isolation.js.map +1 -0
- package/dist/src/daemon/preflight.js +131 -0
- package/dist/src/daemon/preflight.js.map +1 -0
- package/dist/src/daemon/server.js +174 -0
- package/dist/src/daemon/server.js.map +1 -0
- package/dist/src/daemon/supervisorState.js +42 -0
- package/dist/src/daemon/supervisorState.js.map +1 -0
- package/dist/src/daemon/worker.js +239 -0
- package/dist/src/daemon/worker.js.map +1 -0
- package/dist/src/daemon/worktree.js +102 -0
- package/dist/src/daemon/worktree.js.map +1 -0
- package/dist/src/escalate.js +312 -0
- package/dist/src/escalate.js.map +1 -0
- package/dist/src/exec/piWorker.js +630 -0
- package/dist/src/exec/piWorker.js.map +1 -0
- package/dist/src/goal.js +317 -0
- package/dist/src/goal.js.map +1 -0
- package/dist/src/goalLoop.js +374 -0
- package/dist/src/goalLoop.js.map +1 -0
- package/dist/src/goalSpec.js +397 -0
- package/dist/src/goalSpec.js.map +1 -0
- package/dist/src/goalState.js +255 -0
- package/dist/src/goalState.js.map +1 -0
- package/dist/src/handoff.js +205 -0
- package/dist/src/handoff.js.map +1 -0
- package/dist/src/intake.js +203 -0
- package/dist/src/intake.js.map +1 -0
- package/dist/src/loop.js +592 -0
- package/dist/src/loop.js.map +1 -0
- package/dist/src/modelRouter.js +216 -0
- package/dist/src/modelRouter.js.map +1 -0
- package/dist/src/remote.js +246 -0
- package/dist/src/remote.js.map +1 -0
- package/dist/src/replan.js +262 -0
- package/dist/src/replan.js.map +1 -0
- package/dist/src/review.js +54 -0
- package/dist/src/review.js.map +1 -0
- package/dist/src/rework.js +241 -0
- package/dist/src/rework.js.map +1 -0
- package/dist/src/runState.js +4 -0
- package/dist/src/runState.js.map +1 -0
- package/dist/src/scheduler.js +270 -0
- package/dist/src/scheduler.js.map +1 -0
- package/dist/src/supervisor.js +787 -0
- package/dist/src/supervisor.js.map +1 -0
- package/dist/src/taskList.js +430 -0
- package/dist/src/taskList.js.map +1 -0
- package/dist/src/ui/config.js +268 -0
- package/dist/src/ui/config.js.map +1 -0
- package/dist/src/ui/dashboard.js +1288 -0
- package/dist/src/ui/dashboard.js.map +1 -0
- package/dist/src/ui/display.js +229 -0
- package/dist/src/ui/display.js.map +1 -0
- package/dist/src/ui/planTree.js +219 -0
- package/dist/src/ui/planTree.js.map +1 -0
- package/dist/src/ui/theme.js +298 -0
- package/dist/src/ui/theme.js.map +1 -0
- package/dist/src/ui/viewState.js +65 -0
- package/dist/src/ui/viewState.js.map +1 -0
- package/dist/src/ui/widget.js +721 -0
- package/dist/src/ui/widget.js.map +1 -0
- package/dist/src/ui/wizard.js +540 -0
- package/dist/src/ui/wizard.js.map +1 -0
- package/dist/src/unstuck.js +210 -0
- package/dist/src/unstuck.js.map +1 -0
- package/dist/src/worker.js +267 -0
- package/dist/src/worker.js.map +1 -0
- package/dist/src/workflow.js +250 -0
- package/dist/src/workflow.js.map +1 -0
- package/dist/tests/approval.test.js +144 -0
- package/dist/tests/approval.test.js.map +1 -0
- package/dist/tests/brief.test.js +271 -0
- package/dist/tests/brief.test.js.map +1 -0
- package/dist/tests/config.test.js +320 -0
- package/dist/tests/config.test.js.map +1 -0
- package/dist/tests/dashboard.test.js +277 -0
- package/dist/tests/dashboard.test.js.map +1 -0
- package/dist/tests/display.test.js +229 -0
- package/dist/tests/display.test.js.map +1 -0
- package/dist/tests/escalate.test.js +272 -0
- package/dist/tests/escalate.test.js.map +1 -0
- package/dist/tests/featureList.test.js +429 -0
- package/dist/tests/featureList.test.js.map +1 -0
- package/dist/tests/gates.test.js +333 -0
- package/dist/tests/gates.test.js.map +1 -0
- package/dist/tests/goal.test.js +229 -0
- package/dist/tests/goal.test.js.map +1 -0
- package/dist/tests/goalLoop.test.js +170 -0
- package/dist/tests/goalLoop.test.js.map +1 -0
- package/dist/tests/goalSpec.test.js +146 -0
- package/dist/tests/goalSpec.test.js.map +1 -0
- package/dist/tests/goalState.test.js +202 -0
- package/dist/tests/goalState.test.js.map +1 -0
- package/dist/tests/handoff.test.js +127 -0
- package/dist/tests/handoff.test.js.map +1 -0
- package/dist/tests/init.test.js +264 -0
- package/dist/tests/init.test.js.map +1 -0
- package/dist/tests/intake.test.js +288 -0
- package/dist/tests/intake.test.js.map +1 -0
- package/dist/tests/loop.test.js +453 -0
- package/dist/tests/loop.test.js.map +1 -0
- package/dist/tests/modelRouter.test.js +131 -0
- package/dist/tests/modelRouter.test.js.map +1 -0
- package/dist/tests/phases.test.js +244 -0
- package/dist/tests/phases.test.js.map +1 -0
- package/dist/tests/planTree.test.js +190 -0
- package/dist/tests/planTree.test.js.map +1 -0
- package/dist/tests/remote.test.js +380 -0
- package/dist/tests/remote.test.js.map +1 -0
- package/dist/tests/replan.test.js +113 -0
- package/dist/tests/replan.test.js.map +1 -0
- package/dist/tests/review.test.js +77 -0
- package/dist/tests/review.test.js.map +1 -0
- package/dist/tests/rework.test.js +109 -0
- package/dist/tests/rework.test.js.map +1 -0
- package/dist/tests/routing-live.test.js +121 -0
- package/dist/tests/routing-live.test.js.map +1 -0
- package/dist/tests/runState.test.js +73 -0
- package/dist/tests/runState.test.js.map +1 -0
- package/dist/tests/settings.test.js +311 -0
- package/dist/tests/settings.test.js.map +1 -0
- package/dist/tests/skills.test.js +387 -0
- package/dist/tests/skills.test.js.map +1 -0
- package/dist/tests/supervisor.test.js +437 -0
- package/dist/tests/supervisor.test.js.map +1 -0
- package/dist/tests/surface.test.js +203 -0
- package/dist/tests/surface.test.js.map +1 -0
- package/dist/tests/taskList.test.js +376 -0
- package/dist/tests/taskList.test.js.map +1 -0
- package/dist/tests/theme.test.js +149 -0
- package/dist/tests/theme.test.js.map +1 -0
- package/dist/tests/unstuck.test.js +268 -0
- package/dist/tests/unstuck.test.js.map +1 -0
- package/dist/tests/widget.test.js +424 -0
- package/dist/tests/widget.test.js.map +1 -0
- package/dist/tests/worker.test.js +306 -0
- package/dist/tests/worker.test.js.map +1 -0
- package/dist/tests/workflow.test.js +187 -0
- package/dist/tests/workflow.test.js.map +1 -0
- package/extensions/infinity-harness/index.ts +39 -12
- package/package.json +5 -2
- package/src/core/modelRouter.ts +23 -1
- package/src/daemon/index.ts +3 -3
- package/src/daemon/worker.ts +28 -5
- package/src/ui/config.ts +25 -1
- package/src/ui/wizard.ts +10 -5
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinity-harness — cross-process file locking.
|
|
3
|
+
*
|
|
4
|
+
* Parallel workers all write the same plan file. Without mutual exclusion,
|
|
5
|
+
* two writers that both read revision N both pass the `baseRevision` check and
|
|
6
|
+
* both write N+1 — one set of edits vanishes. `baseRevision` detects a stale
|
|
7
|
+
* *read*; it cannot serialise a read-modify-write. Only a lock can.
|
|
8
|
+
*
|
|
9
|
+
* Two flavours, deliberately:
|
|
10
|
+
*
|
|
11
|
+
* - `withLockSync` wraps the plan's read-apply-write in one atomic section.
|
|
12
|
+
* It is synchronous because the critical section is, and it **fails
|
|
13
|
+
* closed**: if the lock cannot be taken, the write is refused rather than
|
|
14
|
+
* racing. Losing an edit silently is worse than an error the caller can
|
|
15
|
+
* retry.
|
|
16
|
+
* - `withLock` is the async, best-effort variant for coarse advisory
|
|
17
|
+
* locking where proceeding un-locked is acceptable.
|
|
18
|
+
*
|
|
19
|
+
* Both hold the lock only for the duration of the work, never across a turn.
|
|
20
|
+
* An earlier version took a lock at the start of an agent turn with an
|
|
21
|
+
* 8-second staleness timeout, so every turn longer than 8 seconds left a lock
|
|
22
|
+
* another process was entitled to steal.
|
|
23
|
+
*/
|
|
24
|
+
import { dirname } from "node:path";
|
|
25
|
+
import { mkdirSync, rmdirSync, statSync, writeFileSync, unlinkSync, readdirSync } from "node:fs";
|
|
26
|
+
import { ensureDir, fileExists, writeTextAtomic } from "./fsx.js";
|
|
27
|
+
/** A lock held longer than this is assumed to belong to a dead process. */
|
|
28
|
+
export const STALE_MS = 30_000;
|
|
29
|
+
export const RETRIES = 12;
|
|
30
|
+
export const RETRY_MIN_MS = 20;
|
|
31
|
+
/** Total time `withLockSync` will wait before refusing. */
|
|
32
|
+
export const SYNC_LOCK_TIMEOUT_MS = 10_000;
|
|
33
|
+
export class LockTimeoutError extends Error {
|
|
34
|
+
name = "LockTimeoutError";
|
|
35
|
+
constructor(path, waitedMs) {
|
|
36
|
+
super(`could not lock ${path} after ${waitedMs}ms — another process is holding it. ` +
|
|
37
|
+
`Retry; if this persists, remove ${path}.ilock`);
|
|
38
|
+
Object.setPrototypeOf(this, LockTimeoutError.prototype);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// ── Synchronous lock ────────────────────────────────────────────────────────
|
|
42
|
+
/**
|
|
43
|
+
* Lock directory name.
|
|
44
|
+
*
|
|
45
|
+
* Deliberately NOT `<path>.lock` — that is exactly what `proper-lockfile`
|
|
46
|
+
* uses, and it is a directory there too. Sharing the name means a caller that
|
|
47
|
+
* wraps `withLock` around something that calls `withLockSync` deadlocks
|
|
48
|
+
* against itself: it holds the async lock, then blocks the event loop waiting
|
|
49
|
+
* for the same directory it already owns, until the timeout fires. Distinct
|
|
50
|
+
* names make nesting the two merely redundant instead of fatal.
|
|
51
|
+
*/
|
|
52
|
+
function lockDirFor(path) {
|
|
53
|
+
return `${path}.ilock`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Block the current thread for `ms`.
|
|
57
|
+
*
|
|
58
|
+
* `Atomics.wait` on a never-notified buffer is the only real synchronous sleep
|
|
59
|
+
* in Node. Busy-waiting on `Date.now()` would spin a core, and the critical
|
|
60
|
+
* sections here are short enough that blocking is the right trade.
|
|
61
|
+
*/
|
|
62
|
+
function sleepSync(ms) {
|
|
63
|
+
const shared = new Int32Array(new SharedArrayBuffer(4));
|
|
64
|
+
Atomics.wait(shared, 0, 0, ms);
|
|
65
|
+
}
|
|
66
|
+
function isStale(lockDir) {
|
|
67
|
+
try {
|
|
68
|
+
return Date.now() - statSync(lockDir).mtimeMs > STALE_MS;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Vanished between the EEXIST and the stat — treat as free.
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function breakStaleLock(lockDir) {
|
|
76
|
+
try {
|
|
77
|
+
for (const entry of readdirSync(lockDir)) {
|
|
78
|
+
try {
|
|
79
|
+
unlinkSync(`${lockDir}/${entry}`);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* best effort */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
rmdirSync(lockDir);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Another process broke it first, or it is no longer stale. Either way the
|
|
89
|
+
// next acquire attempt settles it.
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Run `fn` while holding an exclusive lock on `path`.
|
|
94
|
+
*
|
|
95
|
+
* `mkdir` is the primitive: it either creates the directory or fails with
|
|
96
|
+
* EEXIST, atomically, on every filesystem we care about — unlike a
|
|
97
|
+
* check-then-create on a lock *file*, which has the same race we are trying to
|
|
98
|
+
* close.
|
|
99
|
+
*
|
|
100
|
+
* @throws LockTimeoutError when the lock cannot be acquired in time.
|
|
101
|
+
*/
|
|
102
|
+
export function withLockSync(path, fn, timeoutMs = SYNC_LOCK_TIMEOUT_MS) {
|
|
103
|
+
const lockDir = lockDirFor(path);
|
|
104
|
+
ensureDir(dirname(path));
|
|
105
|
+
const deadline = Date.now() + timeoutMs;
|
|
106
|
+
let acquired = false;
|
|
107
|
+
let backoff = RETRY_MIN_MS;
|
|
108
|
+
while (!acquired) {
|
|
109
|
+
try {
|
|
110
|
+
mkdirSync(lockDir);
|
|
111
|
+
acquired = true;
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
if (e.code !== "EEXIST")
|
|
115
|
+
throw e;
|
|
116
|
+
if (isStale(lockDir)) {
|
|
117
|
+
breakStaleLock(lockDir);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (Date.now() >= deadline)
|
|
121
|
+
throw new LockTimeoutError(path, timeoutMs);
|
|
122
|
+
sleepSync(Math.min(backoff, 250));
|
|
123
|
+
backoff = Math.min(backoff * 2, 250);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
// Owner marker: purely diagnostic, so a stuck lock names a pid.
|
|
128
|
+
try {
|
|
129
|
+
writeFileSync(`${lockDir}/owner`, `${process.pid}\n`, "utf-8");
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
/* the directory is the lock; the marker is a nicety */
|
|
133
|
+
}
|
|
134
|
+
return fn();
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
breakStaleLock(lockDir);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// ── Asynchronous, best-effort lock ──────────────────────────────────────────
|
|
141
|
+
/**
|
|
142
|
+
* Run `fn` while holding an advisory lock on `path`.
|
|
143
|
+
*
|
|
144
|
+
* Best-effort by design: if the lock cannot be acquired, `fn` still runs and
|
|
145
|
+
* `locked` reports false. Use this only where an interleave is tolerable —
|
|
146
|
+
* never for a read-modify-write. Plan writes use `withLockSync`.
|
|
147
|
+
*/
|
|
148
|
+
export async function withLock(path, fn) {
|
|
149
|
+
const handle = await acquire(path);
|
|
150
|
+
try {
|
|
151
|
+
const value = await fn();
|
|
152
|
+
return { value, locked: handle !== null };
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
if (handle) {
|
|
156
|
+
try {
|
|
157
|
+
await handle.release();
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
/* the lock times out on its own */
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function acquire(path) {
|
|
166
|
+
try {
|
|
167
|
+
ensureDir(dirname(path));
|
|
168
|
+
// proper-lockfile refuses to lock a path that does not exist.
|
|
169
|
+
if (!fileExists(path))
|
|
170
|
+
writeTextAtomic(path, "");
|
|
171
|
+
const lockfile = await import("proper-lockfile");
|
|
172
|
+
const release = await lockfile.lock(path, {
|
|
173
|
+
retries: { retries: RETRIES, minTimeout: RETRY_MIN_MS, maxTimeout: 500, factor: 1.6 },
|
|
174
|
+
stale: STALE_MS,
|
|
175
|
+
realpath: false,
|
|
176
|
+
});
|
|
177
|
+
return { release: async () => release() };
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../../src/core/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAIlE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC/B,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,CAAC;AAC1B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAE3C,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACvB,IAAI,GAAG,kBAAkB,CAAC;IAC5C,YAAY,IAAY,EAAE,QAAgB;QACxC,KAAK,CACH,kBAAkB,IAAI,UAAU,QAAQ,sCAAsC;YAC5E,mCAAmC,IAAI,QAAQ,CAClD,CAAC;QACF,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,GAAG,IAAI,QAAQ,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,EAAU;IAC3B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,OAAO,CAAC,OAAe;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,GAAG,QAAQ,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAAe;IACrC,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC;gBACH,UAAU,CAAC,GAAG,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,iBAAiB;YACnB,CAAC;QACH,CAAC;QACD,SAAS,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,mCAAmC;IACrC,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAI,IAAY,EAAE,EAAW,EAAE,SAAS,GAAG,oBAAoB;IACzF,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAEzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,YAAY,CAAC;IAE3B,OAAO,CAAC,QAAQ,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAK,CAA2B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,CAAC,CAAC;YAC5D,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrB,cAAc,CAAC,OAAO,CAAC,CAAC;gBACxB,SAAS;YACX,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM,IAAI,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACxE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAClC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,gEAAgE;QAChE,IAAI,CAAC;YACH,aAAa,CAAC,GAAG,OAAO,QAAQ,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;QACD,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,cAAc,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,EAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;IAC5C,CAAC;YAAS,CAAC;QACT,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACzB,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAY;IACjC,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACzB,8DAA8D;QAC9D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE;YACxC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;YACrF,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinity-harness — modelRouter: which model for which unit (Core, pi-free).
|
|
3
|
+
*
|
|
4
|
+
* Pure decision: difficulty + tiers + baseModel -> asked {provider,id}.
|
|
5
|
+
* Never verifies — tier preflight + servedModel + budget live in the Daemon.
|
|
6
|
+
*
|
|
7
|
+
* Tiers live in `config.tiers` (A/B/C/D/X). Legacy `harness/model-router.json`
|
|
8
|
+
* is still migrated on read for one release (byDifficulty Master ladder).
|
|
9
|
+
*/
|
|
10
|
+
export function clampThinkingForProvider(provider, level, modelForCheck) {
|
|
11
|
+
if (!level)
|
|
12
|
+
return (level ?? "");
|
|
13
|
+
// If we have the actual model, use pi-default truth (getSupportedThinkingLevels semantics)
|
|
14
|
+
try {
|
|
15
|
+
const m = modelForCheck;
|
|
16
|
+
if (m && typeof m.reasoning === "boolean") {
|
|
17
|
+
if (m.reasoning === false)
|
|
18
|
+
return level === "off" || level === "" ? level : "off";
|
|
19
|
+
const map = m.thinkingLevelMap ?? {};
|
|
20
|
+
const all = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
21
|
+
const supported = all.filter(l => {
|
|
22
|
+
const v = map[l];
|
|
23
|
+
if (v === null)
|
|
24
|
+
return false;
|
|
25
|
+
if ((l === "xhigh" || l === "max") && v === undefined)
|
|
26
|
+
return false;
|
|
27
|
+
return true;
|
|
28
|
+
});
|
|
29
|
+
if (supported.includes(level))
|
|
30
|
+
return level;
|
|
31
|
+
// clamp to nearest supported (prefer lower)
|
|
32
|
+
const idx = all.indexOf(level);
|
|
33
|
+
for (let i = idx; i >= 0; i--)
|
|
34
|
+
if (supported.includes(all[i]))
|
|
35
|
+
return all[i];
|
|
36
|
+
for (let i = idx + 1; i < all.length; i++)
|
|
37
|
+
if (supported.includes(all[i]))
|
|
38
|
+
return all[i];
|
|
39
|
+
return supported[0] ?? "off";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch { }
|
|
43
|
+
// Fallback: old provider-string heuristic for when model not available (e.g. in config migration)
|
|
44
|
+
const pp = String(provider || "").toLowerCase();
|
|
45
|
+
const isLocal = pp === "lm-studio" || pp.startsWith("lm-studio/") || pp === "lmstudio";
|
|
46
|
+
if (!isLocal)
|
|
47
|
+
return level;
|
|
48
|
+
if (level === "xhigh" || level === "max" || level === "high")
|
|
49
|
+
return "medium";
|
|
50
|
+
return level;
|
|
51
|
+
}
|
|
52
|
+
const DIFF_TO_TIER = {
|
|
53
|
+
easy: "B",
|
|
54
|
+
moderate: "C",
|
|
55
|
+
difficult: "D",
|
|
56
|
+
};
|
|
57
|
+
function effectiveDifficultyForUnitFromTasks(tasks) {
|
|
58
|
+
const rank = { easy: 1, moderate: 2, difficult: 3 };
|
|
59
|
+
let best;
|
|
60
|
+
let bestRank = -1;
|
|
61
|
+
for (const t of tasks) {
|
|
62
|
+
const d = t.difficulty;
|
|
63
|
+
if (!d)
|
|
64
|
+
continue;
|
|
65
|
+
const r = rank[d] ?? -1;
|
|
66
|
+
if (r > bestRank) {
|
|
67
|
+
bestRank = r;
|
|
68
|
+
best = d;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return best;
|
|
72
|
+
}
|
|
73
|
+
function tiersOf(config) {
|
|
74
|
+
const t = config.tiers;
|
|
75
|
+
if (t && typeof t === "object")
|
|
76
|
+
return t;
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
function baseModelOf(runState) {
|
|
80
|
+
if (!runState?.baseModel)
|
|
81
|
+
return null;
|
|
82
|
+
const bm = runState.baseModel;
|
|
83
|
+
if (typeof bm === "string") {
|
|
84
|
+
const parts = String(bm).split("/");
|
|
85
|
+
if (parts.length >= 2)
|
|
86
|
+
return { provider: parts[0], id: parts.slice(1).join("/") };
|
|
87
|
+
return { provider: "anthropic", id: String(bm) };
|
|
88
|
+
}
|
|
89
|
+
if (typeof bm === "object" && bm !== null && typeof bm.provider === "string" && typeof bm.id === "string") {
|
|
90
|
+
return { provider: String(bm.provider), id: String(bm.id) };
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Resolve the asked model for one unit.
|
|
96
|
+
* Empty slot -> baseModel, never pi's default. Throws when no model can be resolved.
|
|
97
|
+
*/
|
|
98
|
+
export function routeModel(input) {
|
|
99
|
+
const tiers = input.tiers ?? (input.config ? tiersOf(input.config) : {});
|
|
100
|
+
const base = baseModelOf(input.runState ?? (input.baseModel ? { baseModel: input.baseModel } : null));
|
|
101
|
+
const diff = input.difficulty ?? undefined;
|
|
102
|
+
let tier = null;
|
|
103
|
+
if (diff && diff in DIFF_TO_TIER)
|
|
104
|
+
tier = DIFF_TO_TIER[diff];
|
|
105
|
+
if (!tier)
|
|
106
|
+
tier = "A"; // general work -> A
|
|
107
|
+
const spec = tiers[tier];
|
|
108
|
+
if (spec && spec.provider && spec.id)
|
|
109
|
+
return { provider: spec.provider, id: spec.id, tier: tier, askedTier: tier };
|
|
110
|
+
if (base)
|
|
111
|
+
return { provider: base.provider, id: base.id, tier: tier, askedTier: null };
|
|
112
|
+
throw new Error(`no model for tier ${tier}: tiers empty and no baseModel`);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Unit-level difficulty for handoff buckets.
|
|
116
|
+
* When handoff is coarser than `task`, the bucket's hardest difficulty wins.
|
|
117
|
+
*/
|
|
118
|
+
export function effectiveDifficultyForTask(plan, taskId, handoff) {
|
|
119
|
+
const needle = typeof taskId === "string" ? taskId : (taskId?.key ?? taskId?.compositeKey ?? taskId?.id ?? "");
|
|
120
|
+
const hh = (handoff ?? "task");
|
|
121
|
+
// Find the task and its feature
|
|
122
|
+
let target = null;
|
|
123
|
+
for (const f of plan.features ?? []) {
|
|
124
|
+
for (const t of f.tasks ?? []) {
|
|
125
|
+
const comp = t.key ?? `${f.id}/${t.id}`;
|
|
126
|
+
if (t.id === needle || t.key === needle || comp === needle) {
|
|
127
|
+
const featPhase = f.phase;
|
|
128
|
+
const taskPhase = t.phase;
|
|
129
|
+
const eff = taskPhase ?? featPhase ?? "build";
|
|
130
|
+
target = { task: t, featureId: f.id, effectivePhase: eff };
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (target)
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
if (!target) {
|
|
138
|
+
// Fallback: global hardest when target not found and handoff is coarse
|
|
139
|
+
if (hh === "off")
|
|
140
|
+
return effectiveDifficultyForUnitFromTasks((plan.features ?? []).flatMap(f => f.tasks ?? []));
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const own = target.task.difficulty;
|
|
144
|
+
if (hh === "task" || hh === "subtask" || hh === "off") {
|
|
145
|
+
if (hh === "off") {
|
|
146
|
+
const all = (plan.features ?? []).flatMap(f => f.tasks ?? []);
|
|
147
|
+
return effectiveDifficultyForUnitFromTasks(all) ?? own;
|
|
148
|
+
}
|
|
149
|
+
return own;
|
|
150
|
+
}
|
|
151
|
+
let bucket = [];
|
|
152
|
+
const all = (plan.features ?? []).flatMap(f => f.tasks ?? []);
|
|
153
|
+
if (hh === "phase") {
|
|
154
|
+
const phase = target.effectivePhase ?? "build";
|
|
155
|
+
for (const f of plan.features ?? []) {
|
|
156
|
+
const fp = f.phase;
|
|
157
|
+
for (const t of f.tasks ?? []) {
|
|
158
|
+
const tp = t.phase;
|
|
159
|
+
const eff = tp ?? fp ?? "build";
|
|
160
|
+
if (eff === phase)
|
|
161
|
+
bucket.push(t);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (hh === "feature") {
|
|
166
|
+
const feat = plan.features.find(f => f.id === target.featureId);
|
|
167
|
+
bucket = (feat?.tasks ?? []);
|
|
168
|
+
}
|
|
169
|
+
else if (hh === "sprint") {
|
|
170
|
+
const feat = plan.features.find(f => f.id === target.featureId);
|
|
171
|
+
const sid = feat?.sprintId;
|
|
172
|
+
if (!sid)
|
|
173
|
+
return own;
|
|
174
|
+
for (const f of plan.features ?? [])
|
|
175
|
+
if (f.sprintId === sid)
|
|
176
|
+
bucket.push(...(f.tasks ?? []));
|
|
177
|
+
}
|
|
178
|
+
else if (hh === "goal") {
|
|
179
|
+
// Simplify: goal = global hardest (goals span features via sprint)
|
|
180
|
+
const all2 = (plan.features ?? []).flatMap(f => f.tasks ?? []);
|
|
181
|
+
return effectiveDifficultyForUnitFromTasks(all2) ?? own;
|
|
182
|
+
}
|
|
183
|
+
return effectiveDifficultyForUnitFromTasks(bucket) ?? own;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=modelRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelRouter.js","sourceRoot":"","sources":["../../../src/core/modelRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinity-harness — path resolution.
|
|
3
|
+
*
|
|
4
|
+
* Every harness-managed file lives under `harness/` in the target project.
|
|
5
|
+
* Nothing outside this module hardcodes a harness path.
|
|
6
|
+
*/
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
export const HARNESS_DIRNAME = "harness";
|
|
10
|
+
/**
|
|
11
|
+
* Where things that belong to the *person* live, rather than to a project.
|
|
12
|
+
*
|
|
13
|
+
* A workflow someone designed and named is worth exactly as much on their next
|
|
14
|
+
* project as on this one, so it cannot live under `harness/`. This follows
|
|
15
|
+
* pi's own config directory, honouring the same override pi honours, so a
|
|
16
|
+
* sandboxed or rebranded install keeps everything in one place.
|
|
17
|
+
*/
|
|
18
|
+
export function userDir(env = process.env) {
|
|
19
|
+
const override = env.PI_CODING_AGENT_DIR;
|
|
20
|
+
if (override && override.trim())
|
|
21
|
+
return resolve(override.trim(), "infinity-harness");
|
|
22
|
+
return resolve(homedir(), ".pi", "agent", "infinity-harness");
|
|
23
|
+
}
|
|
24
|
+
/** The workflows this person has saved, reusable across every project. */
|
|
25
|
+
export function userWorkflowsPath(env) {
|
|
26
|
+
return resolve(userDir(env), "workflows.json");
|
|
27
|
+
}
|
|
28
|
+
/** The display templates this person has saved. */
|
|
29
|
+
export function userDisplayPath(env) {
|
|
30
|
+
return resolve(userDir(env), "displays.json");
|
|
31
|
+
}
|
|
32
|
+
export function harnessDir(targetDir) {
|
|
33
|
+
return resolve(targetDir, HARNESS_DIRNAME);
|
|
34
|
+
}
|
|
35
|
+
export function configPath(targetDir) {
|
|
36
|
+
return resolve(harnessDir(targetDir), "config.json");
|
|
37
|
+
}
|
|
38
|
+
export function featureListPath(targetDir) {
|
|
39
|
+
return resolve(harnessDir(targetDir), "features", "feature-list.json");
|
|
40
|
+
}
|
|
41
|
+
export function planPath(targetDir) {
|
|
42
|
+
return resolve(harnessDir(targetDir), "plan.json");
|
|
43
|
+
}
|
|
44
|
+
export function daemonPath(targetDir) {
|
|
45
|
+
return resolve(harnessDir(targetDir), "daemon.json");
|
|
46
|
+
}
|
|
47
|
+
export function supervisorPath(targetDir) {
|
|
48
|
+
return resolve(harnessDir(targetDir), "supervisor.json");
|
|
49
|
+
}
|
|
50
|
+
export function activityPath(targetDir) {
|
|
51
|
+
return resolve(harnessDir(targetDir), "activity.json");
|
|
52
|
+
}
|
|
53
|
+
export function sessionsDir(targetDir) {
|
|
54
|
+
return resolve(harnessDir(targetDir), "sessions");
|
|
55
|
+
}
|
|
56
|
+
export function progressPath(targetDir) {
|
|
57
|
+
return resolve(harnessDir(targetDir), "progress.md");
|
|
58
|
+
}
|
|
59
|
+
export function rubricPath(targetDir) {
|
|
60
|
+
return resolve(harnessDir(targetDir), "evaluator-rubric.md");
|
|
61
|
+
}
|
|
62
|
+
export function handoffPath(targetDir) {
|
|
63
|
+
return resolve(harnessDir(targetDir), "session-handoff.md");
|
|
64
|
+
}
|
|
65
|
+
export function contractPath(targetDir) {
|
|
66
|
+
return resolve(harnessDir(targetDir), "sprint-contract.md");
|
|
67
|
+
}
|
|
68
|
+
export function lessonsPath(targetDir) {
|
|
69
|
+
return resolve(harnessDir(targetDir), "lessons-decisions.md");
|
|
70
|
+
}
|
|
71
|
+
export function journalPath(targetDir) {
|
|
72
|
+
return resolve(harnessDir(targetDir), "run-journal.jsonl");
|
|
73
|
+
}
|
|
74
|
+
export function modelRouterPath(targetDir) {
|
|
75
|
+
return resolve(harnessDir(targetDir), "model-router.json");
|
|
76
|
+
}
|
|
77
|
+
export function reworkPath(targetDir) {
|
|
78
|
+
return resolve(harnessDir(targetDir), "rework.json");
|
|
79
|
+
}
|
|
80
|
+
export function replanPath(targetDir) {
|
|
81
|
+
return resolve(harnessDir(targetDir), "replan.json");
|
|
82
|
+
}
|
|
83
|
+
export function docsDir(targetDir) {
|
|
84
|
+
return resolve(harnessDir(targetDir), "docs");
|
|
85
|
+
}
|
|
86
|
+
export function architecturePath(targetDir) {
|
|
87
|
+
return resolve(docsDir(targetDir), "ARCHITECTURE.md");
|
|
88
|
+
}
|
|
89
|
+
export function decisionsPath(targetDir) {
|
|
90
|
+
return resolve(docsDir(targetDir), "DECISIONS.md");
|
|
91
|
+
}
|
|
92
|
+
export function researchPath(targetDir) {
|
|
93
|
+
return resolve(docsDir(targetDir), "RESEARCH.md");
|
|
94
|
+
}
|
|
95
|
+
export function constraintsPath(targetDir) {
|
|
96
|
+
return resolve(docsDir(targetDir), "CONSTRAINTS.md");
|
|
97
|
+
}
|
|
98
|
+
/** Whether a continuous run is armed, and which run it is. Survives sessions. */
|
|
99
|
+
export function runStatePath(targetDir) {
|
|
100
|
+
return resolve(harnessDir(targetDir), "run.json");
|
|
101
|
+
}
|
|
102
|
+
/** A handoff waiting to be picked up by the session that replaces this one. */
|
|
103
|
+
export function pendingSessionPath(targetDir) {
|
|
104
|
+
return resolve(harnessDir(targetDir), "next-session.json");
|
|
105
|
+
}
|
|
106
|
+
export function skillsDir(targetDir) {
|
|
107
|
+
return resolve(harnessDir(targetDir), "skills");
|
|
108
|
+
}
|
|
109
|
+
export function phaseDocPath(targetDir, phase) {
|
|
110
|
+
return resolve(docsDir(targetDir), "phases", `${phase}.md`);
|
|
111
|
+
}
|
|
112
|
+
export function agentDocPath(targetDir, role) {
|
|
113
|
+
return resolve(docsDir(targetDir), "agents", `${role}.md`);
|
|
114
|
+
}
|
|
115
|
+
/** Per-worker worktree root; git worktree per concurrent worker when isolation=worktree. */
|
|
116
|
+
export function worktreesDir(targetDir) {
|
|
117
|
+
return resolve(harnessDir(targetDir), "worktrees");
|
|
118
|
+
}
|
|
119
|
+
export function worktreePath(targetDir, branch) {
|
|
120
|
+
return resolve(worktreesDir(targetDir), branch.replace(/[^a-zA-Z0-9._-]/g, "-"));
|
|
121
|
+
}
|
|
122
|
+
/** Root for per-run worker isolation. Always inside the project, always ignorable. */
|
|
123
|
+
export function runRoot(targetDir) {
|
|
124
|
+
return resolve(targetDir, "tmp", "infinity-harness");
|
|
125
|
+
}
|
|
126
|
+
export function agentsPath(targetDir) {
|
|
127
|
+
return resolve(targetDir, "AGENTS.md");
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/core/paths.ts"],"names":[],"mappings":"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"}
|