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,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinity-harness — replan: mid-BUILD plan amendment.
|
|
3
|
+
*
|
|
4
|
+
* `amendPlan` is the additive counterpart to `taskList.writeTaskList`: it adds
|
|
5
|
+
* sprints, features and tasks to the plan of record without asking the caller
|
|
6
|
+
* to resubmit everything, then re-validates the whole dependency graph and
|
|
7
|
+
* bumps `baseRevision`. A `maxReplansPerRun` budget keeps a stuck run from
|
|
8
|
+
* replanning forever, and every amendment is appended to
|
|
9
|
+
* `harness/replan.json`.
|
|
10
|
+
*
|
|
11
|
+
* Plan I/O, sidecar I/O, config reads, paths and locking all come from
|
|
12
|
+
* `core/`. This module used to carry private copies of each, and they had
|
|
13
|
+
* quietly drifted: the private plan loader did a raw `readFileSync` +
|
|
14
|
+
* `JSON.parse`, so it neither normalised status aliases (a stored "done" never
|
|
15
|
+
* compared equal to "complete", which `validateDeps` reads as an unresolved
|
|
16
|
+
* dependency) nor fell back to the `.bak` after a corrupt write, and its saver
|
|
17
|
+
* did a bare tmp+rename with no backup. The private lock helper wrapped
|
|
18
|
+
* `proper-lockfile` on `<path>.lock` while the plan writer takes
|
|
19
|
+
* `<path>.ilock`, so the two never actually excluded each other. One
|
|
20
|
+
* implementation of each now, in `core/`.
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
23
|
+
import { TASK_STATUSES } from "./core/types.js";
|
|
24
|
+
import { detectCycle, flattenTasks, loadFeatureList, saveFeatureList } from "./core/featureList.js";
|
|
25
|
+
import { fileExists, readJsonSafe, writeJsonAtomic } from "./core/fsx.js";
|
|
26
|
+
import { loadConfig } from "./core/config.js";
|
|
27
|
+
import { planPath, replanPath } from "./core/paths.js";
|
|
28
|
+
import { withLockSync } from "./core/lock.js";
|
|
29
|
+
/**
|
|
30
|
+
* Repo-relative label for the sidecar, kept for callers that display it.
|
|
31
|
+
* `core/paths.replanPath()` is what actually resolves the file.
|
|
32
|
+
*/
|
|
33
|
+
export const REPLAN_FILE = "harness/replan.json";
|
|
34
|
+
/** @deprecated The plan's location belongs to `core/paths.featureListPath()`. */
|
|
35
|
+
export const FEATURE_LIST = "harness/features/feature-list.json";
|
|
36
|
+
export const DEFAULT_MAX_REPLANS = 2;
|
|
37
|
+
function projectDirOf(p) {
|
|
38
|
+
return p ?? process.cwd();
|
|
39
|
+
}
|
|
40
|
+
/** Identity used for dependency resolution: the stable `key` when set, else the id. */
|
|
41
|
+
function taskKey(t) {
|
|
42
|
+
return t.key ?? t.id;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Load the plan through the core loader.
|
|
46
|
+
*
|
|
47
|
+
* Keeps the "missing file" error this module has always thrown: amending a
|
|
48
|
+
* project that was never planned is a caller mistake, not an empty plan to be
|
|
49
|
+
* seeded.
|
|
50
|
+
*/
|
|
51
|
+
function loadPlan(projectDir) {
|
|
52
|
+
const { list, path, existed } = loadFeatureList(projectDir);
|
|
53
|
+
if (!existed)
|
|
54
|
+
throw new Error("feature-list.json missing: " + path);
|
|
55
|
+
return list;
|
|
56
|
+
}
|
|
57
|
+
// ── validation ──────────────────────────────────────────────────────────────
|
|
58
|
+
/** The vocabulary lives in `core/types`; this only reports it. */
|
|
59
|
+
function validateStatus(status) {
|
|
60
|
+
if (!TASK_STATUSES.includes(status)) {
|
|
61
|
+
throw new Error(`invalid task status: ${status} (expected ${TASK_STATUSES.join("|")})`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Every dependency resolves, and nothing claims to be started or finished
|
|
66
|
+
* while something it depends on is not complete.
|
|
67
|
+
*/
|
|
68
|
+
function validateDeps(tasks) {
|
|
69
|
+
const byKey = new Map(tasks.map((t) => [t.key, t]));
|
|
70
|
+
for (const t of tasks) {
|
|
71
|
+
for (const dep of t.dependsOn ?? []) {
|
|
72
|
+
if (!byKey.has(dep))
|
|
73
|
+
throw new Error(`dependsOn references missing task ${dep} (from ${t.key})`);
|
|
74
|
+
}
|
|
75
|
+
if (t.status === "in_progress" || t.status === "complete") {
|
|
76
|
+
const unresolved = (t.dependsOn ?? []).filter((d) => byKey.get(d)?.status !== "complete");
|
|
77
|
+
if (unresolved.length > 0) {
|
|
78
|
+
throw new Error(`${t.key} cannot be ${t.status} while dependencies are unresolved: ${unresolved.join(", ")}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ── sidecar: harness/replan.json ────────────────────────────────────────────
|
|
84
|
+
/** Read the history, tolerating the bare-array, `{ history }` and single-entry shapes. */
|
|
85
|
+
function readReplanHistory(projectDir) {
|
|
86
|
+
const raw = readJsonSafe(replanPath(projectDir), null);
|
|
87
|
+
if (Array.isArray(raw))
|
|
88
|
+
return raw;
|
|
89
|
+
if (!raw || typeof raw !== "object")
|
|
90
|
+
return [];
|
|
91
|
+
const obj = raw;
|
|
92
|
+
if (Array.isArray(obj.history))
|
|
93
|
+
return obj.history;
|
|
94
|
+
return obj.reason ? [raw] : [];
|
|
95
|
+
}
|
|
96
|
+
/** Append an amendment. Locked, because it is a read-modify-write of the sidecar. */
|
|
97
|
+
function appendReplanHistory(projectDir, entry) {
|
|
98
|
+
const path = replanPath(projectDir);
|
|
99
|
+
withLockSync(path, () => {
|
|
100
|
+
const history = readReplanHistory(projectDir);
|
|
101
|
+
history.push(entry);
|
|
102
|
+
writeJsonAtomic(path, history);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function readMaxReplans(projectDir) {
|
|
106
|
+
const { config } = loadConfig(projectDir);
|
|
107
|
+
const lim = config.limits;
|
|
108
|
+
let hasLimitsFile = false;
|
|
109
|
+
try {
|
|
110
|
+
const p = `${projectDir}/harness/config.json`;
|
|
111
|
+
if (existsSync(p)) {
|
|
112
|
+
const raw = JSON.parse(readFileSync(p, "utf-8"));
|
|
113
|
+
if (raw && typeof raw.limits === "object")
|
|
114
|
+
hasLimitsFile = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch { }
|
|
118
|
+
const replan = config.replan;
|
|
119
|
+
const budgets = config.budgets;
|
|
120
|
+
if (hasLimitsFile && typeof lim?.maxReplansPerPhase === "number")
|
|
121
|
+
return lim.maxReplansPerPhase;
|
|
122
|
+
if (typeof replan?.maxReplans === "number")
|
|
123
|
+
return replan.maxReplans;
|
|
124
|
+
if (typeof replan?.maxReplansPerRun === "number")
|
|
125
|
+
return replan.maxReplansPerRun;
|
|
126
|
+
if (typeof budgets?.maxReplansPerRun === "number")
|
|
127
|
+
return budgets.maxReplansPerRun;
|
|
128
|
+
return DEFAULT_MAX_REPLANS;
|
|
129
|
+
}
|
|
130
|
+
// ── the amendment ───────────────────────────────────────────────────────────
|
|
131
|
+
/** Shape a submitted task into the stored form. One place, so the two add paths agree. */
|
|
132
|
+
function toStoredTask(t) {
|
|
133
|
+
const out = {
|
|
134
|
+
id: t.id,
|
|
135
|
+
key: t.key,
|
|
136
|
+
description: t.description,
|
|
137
|
+
status: (t.status ?? "pending"),
|
|
138
|
+
dependsOn: t.dependsOn ?? [],
|
|
139
|
+
subtasks: (t.subtasks ?? []),
|
|
140
|
+
difficulty: t.difficulty,
|
|
141
|
+
modelHint: t.modelHint,
|
|
142
|
+
acceptanceCriteria: t.acceptanceCriteria ?? [],
|
|
143
|
+
};
|
|
144
|
+
if (t.phase)
|
|
145
|
+
out.phase = t.phase;
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
export async function amendPlan(opts) {
|
|
149
|
+
const projectDir = projectDirOf(opts.projectDir);
|
|
150
|
+
const maxReplans = readMaxReplans(projectDir);
|
|
151
|
+
const priorCount = readReplanHistory(projectDir).length;
|
|
152
|
+
if (priorCount >= maxReplans) {
|
|
153
|
+
throw new Error(`maxReplansPerRun exceeded: ${priorCount} >= ${maxReplans}`);
|
|
154
|
+
}
|
|
155
|
+
// Read, amend, validate, bump, write — one atomic section. Adding to the
|
|
156
|
+
// plan is a read-apply-write over the same file every parallel worker edits.
|
|
157
|
+
const result = withLockSync(planPath(projectDir), () => {
|
|
158
|
+
const list = loadPlan(projectDir);
|
|
159
|
+
let addedSprints = 0;
|
|
160
|
+
let addedFeatures = 0;
|
|
161
|
+
let addedTasks = 0;
|
|
162
|
+
// `sprints` is optional on the type; loadFeatureList always normalises it
|
|
163
|
+
// to an array, so bind it once rather than asserting at each use.
|
|
164
|
+
const sprints = (list.sprints ??= []);
|
|
165
|
+
for (const s of opts.addSprints ?? []) {
|
|
166
|
+
if (!s.id || !s.name)
|
|
167
|
+
throw new Error("sprint requires id and name");
|
|
168
|
+
if (sprints.some((x) => x.id === s.id))
|
|
169
|
+
throw new Error(`duplicate sprint id: ${s.id}`);
|
|
170
|
+
sprints.push({
|
|
171
|
+
id: s.id,
|
|
172
|
+
name: s.name,
|
|
173
|
+
...(s.goalId ? { goalId: s.goalId } : {}),
|
|
174
|
+
...(s.difficulty ? { difficulty: s.difficulty } : {}),
|
|
175
|
+
});
|
|
176
|
+
addedSprints++;
|
|
177
|
+
}
|
|
178
|
+
for (const f of opts.addFeatures ?? []) {
|
|
179
|
+
if (!f.id || !f.name)
|
|
180
|
+
throw new Error("feature requires id and name");
|
|
181
|
+
if (list.features.some((x) => x.id === f.id))
|
|
182
|
+
throw new Error(`duplicate feature id: ${f.id}`);
|
|
183
|
+
const feature = {
|
|
184
|
+
id: f.id,
|
|
185
|
+
name: f.name,
|
|
186
|
+
description: f.description ?? "",
|
|
187
|
+
passes: f.passes ?? false,
|
|
188
|
+
sprintId: f.sprintId,
|
|
189
|
+
goalId: f.goalId,
|
|
190
|
+
difficulty: f.difficulty,
|
|
191
|
+
...(f.phase ? { phase: f.phase } : {}),
|
|
192
|
+
tasks: (f.tasks ?? []).map(toStoredTask),
|
|
193
|
+
};
|
|
194
|
+
list.features.push(feature);
|
|
195
|
+
addedFeatures++;
|
|
196
|
+
}
|
|
197
|
+
for (const at of opts.addTasks ?? []) {
|
|
198
|
+
const feature = list.features.find((x) => x.id === at.featureId);
|
|
199
|
+
if (!feature)
|
|
200
|
+
throw new Error(`feature not found for addTasks: ${at.featureId}`);
|
|
201
|
+
const t = at.task;
|
|
202
|
+
if (!t.id || !t.description)
|
|
203
|
+
throw new Error("task requires id and description");
|
|
204
|
+
const key = taskKey(t);
|
|
205
|
+
// Keys are the currency of `dependsOn`, so they are unique plan-wide;
|
|
206
|
+
// ids only have to be unique inside their feature.
|
|
207
|
+
const globalKeys = new Set(flattenTasks(list).map(taskKey));
|
|
208
|
+
if (globalKeys.has(key))
|
|
209
|
+
throw new Error(`duplicate task key: ${key}`);
|
|
210
|
+
if ((feature.tasks ?? []).some((x) => x.id === t.id)) {
|
|
211
|
+
throw new Error(`duplicate task id in feature ${at.featureId}: ${t.id}`);
|
|
212
|
+
}
|
|
213
|
+
if (t.status)
|
|
214
|
+
validateStatus(t.status);
|
|
215
|
+
feature.tasks = feature.tasks ?? [];
|
|
216
|
+
feature.tasks.push(toStoredTask(t));
|
|
217
|
+
addedTasks++;
|
|
218
|
+
}
|
|
219
|
+
// Re-validate the whole graph, not just what was added: an amendment can
|
|
220
|
+
// satisfy or break a dependency anywhere in the plan.
|
|
221
|
+
const all = flattenTasks(list);
|
|
222
|
+
const depView = all.map((t) => ({
|
|
223
|
+
key: taskKey(t),
|
|
224
|
+
dependsOn: t.dependsOn ?? [],
|
|
225
|
+
status: t.status ?? "pending",
|
|
226
|
+
}));
|
|
227
|
+
validateDeps(depView);
|
|
228
|
+
detectCycle(depView.map((t) => ({ compositeKey: t.key, dependsOn: t.dependsOn })));
|
|
229
|
+
const hasChange = addedSprints > 0 || addedFeatures > 0 || addedTasks > 0;
|
|
230
|
+
if (hasChange)
|
|
231
|
+
list.baseRevision += 1;
|
|
232
|
+
saveFeatureList(projectDir, list);
|
|
233
|
+
return {
|
|
234
|
+
baseRevision: list.baseRevision,
|
|
235
|
+
added: { sprints: addedSprints, features: addedFeatures, tasks: addedTasks },
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
appendReplanHistory(projectDir, {
|
|
239
|
+
timestamp: new Date().toISOString(),
|
|
240
|
+
reason: opts.reason ?? "amendPlan",
|
|
241
|
+
added: result.added,
|
|
242
|
+
baseRevision: result.baseRevision,
|
|
243
|
+
});
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
export function loadReplanHistory(projectDir) {
|
|
247
|
+
return readReplanHistory(projectDirOf(projectDir));
|
|
248
|
+
}
|
|
249
|
+
export async function clearReplanHistory(projectDir) {
|
|
250
|
+
const path = replanPath(projectDirOf(projectDir));
|
|
251
|
+
withLockSync(path, () => {
|
|
252
|
+
if (!fileExists(path))
|
|
253
|
+
return;
|
|
254
|
+
try {
|
|
255
|
+
unlinkSync(path);
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
/* already gone — the point is that it is not there afterwards */
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=replan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replan.js","sourceRoot":"","sources":["../../src/replan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* review — bounce guard for REVIEW fail -> rework
|
|
3
|
+
* Fresh-read each call from harness/config.json, respects allowBackward, maxBounces, bounceRequiresDelta + fileDelta
|
|
4
|
+
* Pure helper used by enforcer/unstuck; does not mutate feature-list.json itself
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
import { stripBom } from "./core/fsx.js";
|
|
9
|
+
function projectDirOf(pr) { return pr ? resolve(pr) : process.cwd(); }
|
|
10
|
+
function readConfig(projectDir) {
|
|
11
|
+
try {
|
|
12
|
+
const q = resolve(projectDir, "harness", "config.json");
|
|
13
|
+
if (!existsSync(q))
|
|
14
|
+
return null;
|
|
15
|
+
return JSON.parse(stripBom(readFileSync(q, "utf-8")));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function readBounceCount(projectDir) {
|
|
22
|
+
try {
|
|
23
|
+
const rp = resolve(projectDir, "harness", "rework.json");
|
|
24
|
+
if (!existsSync(rp))
|
|
25
|
+
return 0;
|
|
26
|
+
const raw = JSON.parse(stripBom(readFileSync(rp, "utf-8")));
|
|
27
|
+
if (Array.isArray(raw.history))
|
|
28
|
+
return raw.history.length;
|
|
29
|
+
if (raw.returnTask)
|
|
30
|
+
return 1;
|
|
31
|
+
if (Array.isArray(raw))
|
|
32
|
+
return raw.length;
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function shouldBounceToRework(opts) {
|
|
40
|
+
const projectDir = projectDirOf(opts.projectDir);
|
|
41
|
+
const cfg = readConfig(projectDir);
|
|
42
|
+
const allowBackward = cfg?.review?.allowBackward ?? true;
|
|
43
|
+
const maxBounces = typeof cfg?.review?.maxBounces === "number" ? cfg.review.maxBounces : 2;
|
|
44
|
+
const bounceRequiresDelta = cfg?.review?.bounceRequiresDelta ?? true;
|
|
45
|
+
const bounceCount = typeof opts.bounceCount === "number" ? opts.bounceCount : readBounceCount(projectDir);
|
|
46
|
+
if (!allowBackward)
|
|
47
|
+
return { shouldBounce: false, reason: "review.allowBackward false", maxBounces, bounceCount };
|
|
48
|
+
if (bounceCount >= maxBounces)
|
|
49
|
+
return { shouldBounce: false, reason: "maxBounces " + bounceCount + " >= " + maxBounces, maxBounces, bounceCount };
|
|
50
|
+
if (bounceRequiresDelta && !opts.fileDelta)
|
|
51
|
+
return { shouldBounce: false, reason: "bounceRequiresDelta true and no fileDelta", maxBounces, bounceCount };
|
|
52
|
+
return { shouldBounce: true, reason: "bounce eligible", maxBounces, bounceCount };
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinity-harness — rework: the backward edge, with return-to-origin.
|
|
3
|
+
*
|
|
4
|
+
* A task that fails late rarely fails alone: whatever depends on it is suspect
|
|
5
|
+
* too. `startRework` walks the `dependsOn` graph forward from the origin, flips
|
|
6
|
+
* the origin and everything it reaches within `maxImpactDepth` to "rework", and
|
|
7
|
+
* records where the pipeline must return to in `harness/rework.json`.
|
|
8
|
+
*
|
|
9
|
+
* Plan I/O, sidecar I/O, config reads, paths and locking all come from
|
|
10
|
+
* `core/`. This module used to carry private copies of each, and they had
|
|
11
|
+
* quietly drifted: the private plan loader did a raw `readFileSync` +
|
|
12
|
+
* `JSON.parse`, so it neither normalised status aliases (a task stored as
|
|
13
|
+
* "done" never compared equal to "complete") nor fell back to the `.bak` after
|
|
14
|
+
* a corrupt write, and its saver did a bare tmp+rename with no backup. The
|
|
15
|
+
* private lock helper wrapped `proper-lockfile` on `<path>.lock` while the
|
|
16
|
+
* plan writer takes `<path>.ilock`, so the two never actually excluded each
|
|
17
|
+
* other. One implementation of each now, in `core/`.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
20
|
+
import { flattenTasks, loadFeatureList, saveFeatureList } from "./core/featureList.js";
|
|
21
|
+
import { fileExists, readJsonSafe, writeJsonAtomic } from "./core/fsx.js";
|
|
22
|
+
import { loadConfig } from "./core/config.js";
|
|
23
|
+
import { planPath, reworkPath } from "./core/paths.js";
|
|
24
|
+
import { withLockSync } from "./core/lock.js";
|
|
25
|
+
/**
|
|
26
|
+
* Repo-relative label for the sidecar, kept for callers that display it.
|
|
27
|
+
* `core/paths.reworkPath()` is what actually resolves the file.
|
|
28
|
+
*/
|
|
29
|
+
export const REWORK_FILE = "harness/rework.json";
|
|
30
|
+
export const DEFAULT_MAX_REWORKS = 3;
|
|
31
|
+
export const DEFAULT_IMPACT_DEPTH = 3;
|
|
32
|
+
function projectDirOf(p) {
|
|
33
|
+
return p ?? process.cwd();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Identity used by the rework graph: the stable `key` when set, else the id.
|
|
37
|
+
*
|
|
38
|
+
* Deliberately *not* `flattenTasks`' `compositeKey`, which falls back to
|
|
39
|
+
* `featureId/id`. `dependsOn` entries in the plan are written in this
|
|
40
|
+
* spelling, and matching them is the whole job here.
|
|
41
|
+
*/
|
|
42
|
+
function taskKey(t) {
|
|
43
|
+
return t.key ?? t.id;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Load the plan through the core loader.
|
|
47
|
+
*
|
|
48
|
+
* Keeps the "missing file" error this module has always thrown: a rework
|
|
49
|
+
* against a project that was never planned is a caller mistake, not an empty
|
|
50
|
+
* plan to be seeded.
|
|
51
|
+
*/
|
|
52
|
+
function loadPlan(projectDir) {
|
|
53
|
+
const { list, path, existed } = loadFeatureList(projectDir);
|
|
54
|
+
if (!existed)
|
|
55
|
+
throw new Error("feature-list.json missing: " + path);
|
|
56
|
+
return list;
|
|
57
|
+
}
|
|
58
|
+
/** Breadth-first walk over the reverse-dependency edges, capped at `maxDepth`. */
|
|
59
|
+
export function computeImpact(allTasks, originKey, maxDepth) {
|
|
60
|
+
const impacted = [];
|
|
61
|
+
const visited = new Set([originKey]);
|
|
62
|
+
let frontier = [{ key: originKey, depth: 0 }];
|
|
63
|
+
while (frontier.length) {
|
|
64
|
+
const next = [];
|
|
65
|
+
for (const cur of frontier) {
|
|
66
|
+
if (cur.depth >= maxDepth)
|
|
67
|
+
continue;
|
|
68
|
+
for (const t of allTasks) {
|
|
69
|
+
const k = taskKey(t);
|
|
70
|
+
if (visited.has(k))
|
|
71
|
+
continue;
|
|
72
|
+
if ((t.dependsOn ?? []).includes(cur.key)) {
|
|
73
|
+
visited.add(k);
|
|
74
|
+
impacted.push(k);
|
|
75
|
+
next.push({ key: k, depth: cur.depth + 1 });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
frontier = next;
|
|
80
|
+
}
|
|
81
|
+
return impacted;
|
|
82
|
+
}
|
|
83
|
+
function readSidecar(projectDir) {
|
|
84
|
+
const raw = readJsonSafe(reworkPath(projectDir), null);
|
|
85
|
+
return raw && typeof raw === "object" ? raw : null;
|
|
86
|
+
}
|
|
87
|
+
function countPriorReworks(projectDir) {
|
|
88
|
+
const prev = readSidecar(projectDir);
|
|
89
|
+
if (!prev)
|
|
90
|
+
return 0;
|
|
91
|
+
if (Array.isArray(prev.history))
|
|
92
|
+
return prev.history.length;
|
|
93
|
+
return prev.returnTask ? 1 : 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Append a record, promoting a legacy single-record file to `{ history }`.
|
|
97
|
+
* Locked, because it is a read-modify-write of the sidecar.
|
|
98
|
+
*/
|
|
99
|
+
function appendReworkRecord(projectDir, record) {
|
|
100
|
+
const path = reworkPath(projectDir);
|
|
101
|
+
withLockSync(path, () => {
|
|
102
|
+
const prev = readSidecar(projectDir);
|
|
103
|
+
if (!prev) {
|
|
104
|
+
writeJsonAtomic(path, { ...record });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let history;
|
|
108
|
+
if (Array.isArray(prev.history)) {
|
|
109
|
+
history = [...prev.history];
|
|
110
|
+
}
|
|
111
|
+
else if (prev.returnTask) {
|
|
112
|
+
const { history: _legacy, ...rest } = prev;
|
|
113
|
+
history = [rest];
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
history = [];
|
|
117
|
+
}
|
|
118
|
+
history.push({ ...record });
|
|
119
|
+
writeJsonAtomic(path, { history });
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function readMaxReworks(projectDir) {
|
|
123
|
+
const { config } = loadConfig(projectDir);
|
|
124
|
+
const lim = config.limits;
|
|
125
|
+
// limits.maxReworkPerUnit wins only when writable: config actually has a limits file with it.
|
|
126
|
+
// Test configs write { rework: {maxReworks: 3} } onto a partial config that still has DEFAULT_LIMITS via merge — without this guard every test would see 2.
|
|
127
|
+
let hasLimitsFile = false;
|
|
128
|
+
try {
|
|
129
|
+
const p = `${projectDir}/harness/config.json`;
|
|
130
|
+
if (existsSync(p)) {
|
|
131
|
+
const raw = JSON.parse(readFileSync(p, "utf-8"));
|
|
132
|
+
if (raw && typeof raw.limits === "object")
|
|
133
|
+
hasLimitsFile = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch { }
|
|
137
|
+
const rework = config.rework;
|
|
138
|
+
const budgets = config.budgets;
|
|
139
|
+
if (hasLimitsFile && typeof lim?.maxReworkPerUnit === "number")
|
|
140
|
+
return lim.maxReworkPerUnit;
|
|
141
|
+
if (typeof rework?.maxReworks === "number")
|
|
142
|
+
return rework.maxReworks;
|
|
143
|
+
if (typeof budgets?.maxReworksPerRun === "number")
|
|
144
|
+
return budgets.maxReworksPerRun;
|
|
145
|
+
return DEFAULT_MAX_REWORKS;
|
|
146
|
+
}
|
|
147
|
+
// ── the backward edge ───────────────────────────────────────────────────────
|
|
148
|
+
/**
|
|
149
|
+
* Resolve which spelling of the origin the caller meant.
|
|
150
|
+
*
|
|
151
|
+
* Callers pass a bare id, a `key`, or a `featureId/taskId` composite more or
|
|
152
|
+
* less interchangeably; the plan stores one of them. First match wins, in
|
|
153
|
+
* order of specificity.
|
|
154
|
+
*/
|
|
155
|
+
function resolveOriginKey(tasks, opts) {
|
|
156
|
+
const explicitKey = opts.key ?? opts.taskId;
|
|
157
|
+
const byId = tasks.find((t) => t.id === opts.taskId);
|
|
158
|
+
const candidates = [
|
|
159
|
+
...(byId ? [taskKey(byId)] : []),
|
|
160
|
+
explicitKey,
|
|
161
|
+
`${opts.featureId}/${opts.taskId}`,
|
|
162
|
+
opts.taskId,
|
|
163
|
+
];
|
|
164
|
+
for (const cand of candidates) {
|
|
165
|
+
if (tasks.some((t) => taskKey(t) === cand))
|
|
166
|
+
return cand;
|
|
167
|
+
}
|
|
168
|
+
return explicitKey;
|
|
169
|
+
}
|
|
170
|
+
export async function startRework(opts) {
|
|
171
|
+
const projectDir = projectDirOf(opts.projectDir);
|
|
172
|
+
const maxDepth = opts.maxImpactDepth ?? DEFAULT_IMPACT_DEPTH;
|
|
173
|
+
const originKey = resolveOriginKey(flattenTasks(loadPlan(projectDir)), opts);
|
|
174
|
+
const maxReworks = readMaxReworks(projectDir);
|
|
175
|
+
const priorCount = countPriorReworks(projectDir);
|
|
176
|
+
if (priorCount >= maxReworks) {
|
|
177
|
+
throw new Error("maxReworksPerRun exceeded: " + priorCount + " >= " + maxReworks);
|
|
178
|
+
}
|
|
179
|
+
// Read, flip, bump, write — one atomic section. The status flip is a
|
|
180
|
+
// read-apply-write over the same file every parallel worker edits.
|
|
181
|
+
const result = withLockSync(planPath(projectDir), () => {
|
|
182
|
+
const list = loadPlan(projectDir);
|
|
183
|
+
const tasks = flattenTasks(list);
|
|
184
|
+
if (!tasks.some((t) => taskKey(t) === originKey)) {
|
|
185
|
+
throw new Error("origin task not found: " + originKey);
|
|
186
|
+
}
|
|
187
|
+
const impacted = computeImpact(tasks, originKey, maxDepth);
|
|
188
|
+
const toRework = new Set([originKey, ...impacted]);
|
|
189
|
+
// flattenTasks hands back copies, so the flip walks the stored tasks.
|
|
190
|
+
let changed = false;
|
|
191
|
+
for (const feature of list.features) {
|
|
192
|
+
for (const t of feature.tasks ?? []) {
|
|
193
|
+
if (toRework.has(taskKey(t)) && t.status !== "rework") {
|
|
194
|
+
t.status = "rework";
|
|
195
|
+
changed = true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (changed)
|
|
200
|
+
list.baseRevision += 1;
|
|
201
|
+
saveFeatureList(projectDir, list);
|
|
202
|
+
const record = {
|
|
203
|
+
runId: opts.runId ?? "run-" + Date.now(),
|
|
204
|
+
returnFeature: opts.featureId,
|
|
205
|
+
returnTask: opts.taskId,
|
|
206
|
+
impacted,
|
|
207
|
+
reason: opts.reason ?? "rework via startRework",
|
|
208
|
+
timestamp: new Date().toISOString(),
|
|
209
|
+
remainingBudgets: { reworks: maxReworks - priorCount - 1, replans: 2, bounces: 2 },
|
|
210
|
+
maxImpactDepth: maxDepth,
|
|
211
|
+
};
|
|
212
|
+
return { impacted, baseRevision: list.baseRevision, record };
|
|
213
|
+
});
|
|
214
|
+
appendReworkRecord(projectDir, result.record);
|
|
215
|
+
return { impacted: result.impacted, baseRevision: result.baseRevision, rework: result.record };
|
|
216
|
+
}
|
|
217
|
+
/** The most recent rework record, or null when there is none to return to. */
|
|
218
|
+
export function loadRework(projectDir) {
|
|
219
|
+
const prev = readSidecar(projectDirOf(projectDir));
|
|
220
|
+
if (!prev)
|
|
221
|
+
return null;
|
|
222
|
+
if (Array.isArray(prev.history)) {
|
|
223
|
+
const history = prev.history;
|
|
224
|
+
return history[history.length - 1] ?? null;
|
|
225
|
+
}
|
|
226
|
+
return prev;
|
|
227
|
+
}
|
|
228
|
+
export async function clearRework(projectDir) {
|
|
229
|
+
const path = reworkPath(projectDirOf(projectDir));
|
|
230
|
+
withLockSync(path, () => {
|
|
231
|
+
if (!fileExists(path))
|
|
232
|
+
return;
|
|
233
|
+
try {
|
|
234
|
+
unlinkSync(path);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
/* already gone — the point is that it is not there afterwards */
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=rework.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rework.js","sourceRoot":"","sources":["../../src/rework.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Re-export from core so both import paths work.
|
|
2
|
+
// Canonical type now lives in src/core/runState.ts (with baseModel/tiers/budget).
|
|
3
|
+
export { loadRunState, saveRunState, armRun, disarmRun, countSession, clearRunState, runIdFor, newRunState, parseBaseModelString, createUsageTotals, } from "./core/runState.js";
|
|
4
|
+
//# sourceMappingURL=runState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runState.js","sourceRoot":"","sources":["../../src/runState.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,kFAAkF;AAClF,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,SAAS,EACT,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,WAAW,EACX,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|