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,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session handoff — when the run should continue in a fresh pi session, and
|
|
3
|
+
* what the replacement is told.
|
|
4
|
+
*
|
|
5
|
+
* The thing being defended here is small and easy to get wrong: a handoff is
|
|
6
|
+
* only worth doing at a boundary, it must never fire twice for the same
|
|
7
|
+
* boundary, and it must never lose the brief. Everything else about a handoff
|
|
8
|
+
* — that pi really starts a new session, that the run's budgets carry across
|
|
9
|
+
* it — is proved in the `realpi` e2e scenario against a real pi process,
|
|
10
|
+
* because no unit test can see that.
|
|
11
|
+
*/
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import { mkdtempSync, rmSync, existsSync } from "node:fs";
|
|
14
|
+
import { tmpdir } from "node:os";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { clearHandoff, composeKickoff, defaultSessionPolicy, describeHandoff, hasPendingHandoff, peekHandoff, requestHandoff, shouldHandoff, takeHandoff, } from "../src/handoff.js";
|
|
17
|
+
import { defaultConfig } from "../src/core/config.js";
|
|
18
|
+
import { pendingSessionPath } from "../src/core/paths.js";
|
|
19
|
+
const tmp = () => mkdtempSync(join(tmpdir(), "handoff-test-"));
|
|
20
|
+
function config(session = {}) {
|
|
21
|
+
const c = defaultConfig();
|
|
22
|
+
c.session = { ...defaultSessionPolicy(), ...session };
|
|
23
|
+
return c;
|
|
24
|
+
}
|
|
25
|
+
const signals = (over = {}) => ({
|
|
26
|
+
config: config(),
|
|
27
|
+
fromPhase: "build",
|
|
28
|
+
toPhase: "build",
|
|
29
|
+
fromTask: "feature-001/task-001",
|
|
30
|
+
toTask: "feature-001/task-001",
|
|
31
|
+
contextRatio: null,
|
|
32
|
+
...over,
|
|
33
|
+
});
|
|
34
|
+
// ── when a handoff is due ──────────────────────────────────────────────────
|
|
35
|
+
{
|
|
36
|
+
assert.equal(shouldHandoff(signals()).handoff, false, "standing still is not a boundary");
|
|
37
|
+
const phase = shouldHandoff(signals({ toPhase: "verify" }));
|
|
38
|
+
assert.equal(phase.handoff, true);
|
|
39
|
+
assert.equal(phase.handoff && phase.reason, "phase");
|
|
40
|
+
assert.match(phase.handoff ? phase.detail : "", /BUILD → VERIFY/);
|
|
41
|
+
// Per-phase should ignore a task change; task (now default) should not.
|
|
42
|
+
assert.equal(shouldHandoff(signals({ config: config({ handoff: "phase" }), toTask: "feature-001/task-002" })).handoff, false, "per-phase policy ignores a task change");
|
|
43
|
+
assert.equal(shouldHandoff(signals({ toTask: "feature-001/task-002" })).handoff, true, "default is per-task now, so a task change does handoff");
|
|
44
|
+
const perTask = shouldHandoff(signals({ config: config({ handoff: "task" }), toTask: "feature-001/task-002" }));
|
|
45
|
+
assert.equal(perTask.handoff, true);
|
|
46
|
+
assert.equal(perTask.handoff && perTask.reason, "task");
|
|
47
|
+
assert.equal(shouldHandoff(signals({ config: config({ handoff: "off" }), toPhase: "verify" })).handoff, false, "off means off, even at a phase boundary");
|
|
48
|
+
console.log("✓ shouldHandoff fires at boundaries the policy names, and nowhere else");
|
|
49
|
+
}
|
|
50
|
+
// ── context pressure ───────────────────────────────────────────────────────
|
|
51
|
+
{
|
|
52
|
+
// The point of the context trigger is to get out *before* compaction, so it
|
|
53
|
+
// outranks everything: a handoff that arrives after the context filled up
|
|
54
|
+
// has arrived too late to be the thing that prevented it.
|
|
55
|
+
const pressed = shouldHandoff(signals({ contextRatio: 0.82 }));
|
|
56
|
+
assert.equal(pressed.handoff, true);
|
|
57
|
+
assert.equal(pressed.handoff && pressed.reason, "context");
|
|
58
|
+
assert.match(pressed.handoff ? pressed.detail : "", /82%/);
|
|
59
|
+
assert.equal(shouldHandoff(signals({ contextRatio: 0.5 })).handoff, false, "under the threshold, nothing happens");
|
|
60
|
+
assert.equal(shouldHandoff(signals({ config: config({ contextThreshold: 0 }), contextRatio: 0.99 })).handoff, false, "a zero threshold disables the trigger entirely");
|
|
61
|
+
// A misconfigured threshold must not silently become "never" or "always".
|
|
62
|
+
assert.equal(shouldHandoff(signals({ config: config({ contextThreshold: 5 }), contextRatio: 0.96 })).handoff, true, "a threshold above 1 is clamped rather than made unreachable");
|
|
63
|
+
assert.equal(shouldHandoff(signals({ config: config({ contextThreshold: -1 }), contextRatio: 0.1 })).handoff, false, "a negative threshold is treated as off, not as always-on");
|
|
64
|
+
assert.equal(shouldHandoff(signals({ contextRatio: null, toPhase: "verify" })).handoff, true, "an unknown context ratio does not stop a phase handoff");
|
|
65
|
+
console.log("✓ context pressure outranks the boundary rules, and bad thresholds are clamped");
|
|
66
|
+
}
|
|
67
|
+
// ── the pending handoff file ───────────────────────────────────────────────
|
|
68
|
+
{
|
|
69
|
+
const dir = tmp();
|
|
70
|
+
assert.equal(hasPendingHandoff(dir), false);
|
|
71
|
+
assert.equal(peekHandoff(dir), null);
|
|
72
|
+
assert.equal(takeHandoff(dir), null, "claiming nothing is not an error");
|
|
73
|
+
const pending = requestHandoff(dir, {
|
|
74
|
+
reason: "phase",
|
|
75
|
+
detail: "BUILD → VERIFY",
|
|
76
|
+
kickoff: "the whole brief",
|
|
77
|
+
carry: " 3/9 tasks done",
|
|
78
|
+
runId: "run-1",
|
|
79
|
+
});
|
|
80
|
+
assert.ok(pending.at, "a handoff is stamped");
|
|
81
|
+
assert.equal(hasPendingHandoff(dir), true);
|
|
82
|
+
assert.equal(peekHandoff(dir)?.kickoff, "the whole brief");
|
|
83
|
+
assert.equal(hasPendingHandoff(dir), true, "peeking does not consume it");
|
|
84
|
+
const taken = takeHandoff(dir);
|
|
85
|
+
assert.equal(taken?.runId, "run-1");
|
|
86
|
+
assert.equal(hasPendingHandoff(dir), false, "claiming consumes it");
|
|
87
|
+
assert.equal(takeHandoff(dir), null, "and a second claim finds nothing — a stale file must not loop the run through handoffs");
|
|
88
|
+
requestHandoff(dir, { reason: "manual", detail: "d", kickoff: "k", carry: null, runId: "r" });
|
|
89
|
+
clearHandoff(dir);
|
|
90
|
+
assert.equal(existsSync(pendingSessionPath(dir)), false);
|
|
91
|
+
assert.match(describeHandoff({ reason: "context", detail: "context 78% full", kickoff: "", carry: null, runId: "r", at: "" }), /context/);
|
|
92
|
+
rmSync(dir, { recursive: true, force: true });
|
|
93
|
+
console.log("✓ a pending handoff is written once, claimed once, and never twice");
|
|
94
|
+
}
|
|
95
|
+
// ── what the replacement session is told ───────────────────────────────────
|
|
96
|
+
{
|
|
97
|
+
const kickoff = composeKickoff("NEXT STEP · VERIFY\n…", "phase", "BUILD → VERIFY", " 3/9 tasks done");
|
|
98
|
+
assert.match(kickoff, /NEXT STEP · VERIFY/, "the brief is the point — it must survive");
|
|
99
|
+
assert.match(kickoff, /BUILD → VERIFY/, "and it says why this session exists");
|
|
100
|
+
assert.match(kickoff, /3\/9 tasks done/, "the carry note comes across");
|
|
101
|
+
assert.match(kickoff, /harness\//, "it points at where the state actually lives");
|
|
102
|
+
assert.match(kickoff, /Do not\s*\n?\s*go looking for the previous conversation/, "an agent that wakes up mid-run must be told not to go hunting for context");
|
|
103
|
+
for (const reason of ["phase", "task", "context", "goal-pass", "manual"]) {
|
|
104
|
+
const text = composeKickoff("BRIEF", reason, "detail", null);
|
|
105
|
+
assert.match(text, /BRIEF/);
|
|
106
|
+
assert.ok(text.split("\n").length > 3, `${reason} produced a kickoff with no explanation`);
|
|
107
|
+
}
|
|
108
|
+
console.log("✓ the kickoff carries the brief, the reason, and the note");
|
|
109
|
+
}
|
|
110
|
+
// -- full granularity (goal/phase/sprint/feature/task/subtask) ----------------
|
|
111
|
+
{
|
|
112
|
+
const sprint = shouldHandoff(signals({ config: config({ handoff: "sprint" }), fromSprint: "s-1", toSprint: "s-2" }));
|
|
113
|
+
assert.equal(sprint.handoff, true);
|
|
114
|
+
assert.equal(sprint.handoff && sprint.reason, "sprint");
|
|
115
|
+
assert.equal(shouldHandoff(signals({ config: config({ handoff: "phase" }), fromSprint: "s-1", toSprint: "s-2" })).handoff, false, "phase must not fire on sprint");
|
|
116
|
+
const feat = shouldHandoff(signals({ config: config({ handoff: "feature" }), fromFeature: "f-1", toFeature: "f-2" }));
|
|
117
|
+
assert.equal(feat.handoff, true);
|
|
118
|
+
assert.equal(feat.handoff && feat.reason, "feature");
|
|
119
|
+
const sub = shouldHandoff(signals({ config: config({ handoff: "subtask" }), fromSubtask: "t#s-1", toSubtask: "t#s-2" }));
|
|
120
|
+
assert.equal(sub.handoff, true);
|
|
121
|
+
assert.equal(sub.handoff && sub.reason, "subtask");
|
|
122
|
+
assert.equal(shouldHandoff(signals({ config: config({ handoff: "task" }), fromSubtask: "t#s-1", toSubtask: "t#s-2" })).handoff, false, "task must not fire on subtask");
|
|
123
|
+
// goal is an alias for off — never fires as a handoff reason in shouldHandoff
|
|
124
|
+
assert.equal(shouldHandoff(signals({ config: config({ handoff: "goal" }), fromGoal: "g1", toGoal: "g2" })).handoff, false);
|
|
125
|
+
console.log("✓ granularity hierarchy: sprint/feature/task/subtask fire only when configured fine enough");
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=handoff.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.test.js","sourceRoot":"","sources":["../../tests/handoff.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,aAAa,EACb,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,MAAM,GAAG,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;AAEvE,SAAS,MAAM,CAAC,UAAkC,EAAE;IAClD,MAAM,CAAC,GAAG,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,OAAO,GAAG,EAAE,GAAG,oBAAoB,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;IACtD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,OAAqD,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5E,MAAM,EAAE,MAAM,EAAE;IAChB,SAAS,EAAE,OAAgB;IAC3B,OAAO,EAAE,OAAgB;IACzB,QAAQ,EAAE,sBAAsB;IAChC,MAAM,EAAE,sBAAsB;IAC9B,YAAY,EAAE,IAAI;IAClB,GAAG,IAAI;CACR,CAAC,CAAC;AAEH,8EAA8E;AAC9E,CAAC;IACC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,kCAAkC,CAAC,CAAC;IAE1F,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAElE,wEAAwE;IACxE,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC,OAAO,EACxG,KAAK,EACL,wCAAwC,CACzC,CAAC;IACF,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC,OAAO,EAClE,IAAI,EACJ,wDAAwD,CACzD,CAAC;IAEF,MAAM,OAAO,GAAG,aAAa,CAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CACjF,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExD,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,EACzF,KAAK,EACL,yCAAyC,CAC1C,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,wEAAwE,CAAC,CAAC;AACxF,CAAC;AAED,8EAA8E;AAC9E,CAAC;IACC,4EAA4E;IAC5E,0EAA0E;IAC1E,0DAA0D;IAC1D,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAE3D,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,sCAAsC,CAAC,CAAC;IAEnH,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,EAC/F,KAAK,EACL,gDAAgD,CACjD,CAAC;IAEF,0EAA0E;IAC1E,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,EAC/F,IAAI,EACJ,6DAA6D,CAC9D,CAAC;IACF,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,EAC/F,KAAK,EACL,0DAA0D,CAC3D,CAAC;IAEF,MAAM,CAAC,KAAK,CACV,aAAa,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,EACzE,IAAI,EACJ,wDAAwD,CACzD,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;AAChG,CAAC;AAED,8EAA8E;AAC9E,CAAC;IACC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC;IAClB,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,kCAAkC,CAAC,CAAC;IAEzE,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE;QAClC,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,gBAAgB;QACxB,OAAO,EAAE,iBAAiB;QAC1B,KAAK,EAAE,kBAAkB;QACzB,KAAK,EAAE,OAAO;KACf,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,sBAAsB,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,6BAA6B,CAAC,CAAC;IAE1E,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,sBAAsB,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CACV,WAAW,CAAC,GAAG,CAAC,EAChB,IAAI,EACJ,wFAAwF,CACzF,CAAC;IAEF,cAAc,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9F,YAAY,CAAC,GAAG,CAAC,CAAC;IAClB,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEzD,MAAM,CAAC,KAAK,CACV,eAAe,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAChH,SAAS,CACV,CAAC;IACF,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;AACpF,CAAC;AAED,8EAA8E;AAC9E,CAAC;IACC,MAAM,OAAO,GAAG,cAAc,CAAC,uBAAuB,EAAE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IAEvG,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,oBAAoB,EAAE,0CAA0C,CAAC,CAAC;IACxF,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,gBAAgB,EAAE,qCAAqC,CAAC,CAAC;IAC/E,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,iBAAiB,EAAE,6BAA6B,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,6CAA6C,CAAC,CAAC;IAClF,MAAM,CAAC,KAAK,CACV,OAAO,EACP,yDAAyD,EACzD,2EAA2E,CAC5E,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAU,EAAE,CAAC;QAClF,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,MAAM,yCAAyC,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;AAC3E,CAAC;AAED,gFAAgF;AAChF,CAAC;IACC,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACrH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,IAAK,MAA6B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChF,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,CAAC;IAEnK,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACtH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACjC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,IAAK,IAA2B,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAE7E,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACzH,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,IAAK,GAA0B,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC3E,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,CAAC;IAExK,8EAA8E;IAC9E,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3H,OAAO,CAAC,GAAG,CAAC,4FAA4F,CAAC,CAAC;AAC5G,CAAC"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* You have to be able to start.
|
|
3
|
+
*
|
|
4
|
+
* This file exists because you couldn't. `pi install infinity-harness` put the
|
|
5
|
+
* extension in place, and then every single command answered:
|
|
6
|
+
*
|
|
7
|
+
* Warning: No harness in this project (harness/config.json not found).
|
|
8
|
+
*
|
|
9
|
+
* There was no command, tool, or documented procedure that created one. The
|
|
10
|
+
* package shipped, installed, loaded, passed its whole test suite, and could
|
|
11
|
+
* not be used.
|
|
12
|
+
*
|
|
13
|
+
* So: init makes a project the harness can actually run in, and these tests
|
|
14
|
+
* check that by running it — building a brief, running a gate — rather than by
|
|
15
|
+
* asserting that some files exist.
|
|
16
|
+
*/
|
|
17
|
+
import assert from "node:assert/strict";
|
|
18
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
|
|
19
|
+
import { tmpdir } from "node:os";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { detectStack, describeInit, initHarness, packagedDocsDir } from "../src/core/init.js";
|
|
22
|
+
import { isHarnessProject, loadConfig } from "../src/core/config.js";
|
|
23
|
+
import { loadFeatureList } from "../src/core/featureList.js";
|
|
24
|
+
import { buildBrief, renderBrief } from "../src/core/brief.js";
|
|
25
|
+
import { runChecks } from "../src/core/gates.js";
|
|
26
|
+
import { DEFAULT_ENABLED_PHASES } from "../src/core/types.js";
|
|
27
|
+
function tmpProject(files = {}) {
|
|
28
|
+
const dir = mkdtempSync(join(tmpdir(), "pi-init-"));
|
|
29
|
+
for (const [name, body] of Object.entries(files)) {
|
|
30
|
+
const full = join(dir, name);
|
|
31
|
+
mkdirSync(join(full, ".."), { recursive: true });
|
|
32
|
+
writeFileSync(full, body, "utf-8");
|
|
33
|
+
}
|
|
34
|
+
return dir;
|
|
35
|
+
}
|
|
36
|
+
// ── the whole point ────────────────────────────────────────────────────────
|
|
37
|
+
{
|
|
38
|
+
const dir = tmpProject();
|
|
39
|
+
assert.equal(isHarnessProject(dir), false, "a bare directory is not a harness project");
|
|
40
|
+
const result = initHarness(dir);
|
|
41
|
+
assert.ok(result.ok, result.error);
|
|
42
|
+
assert.equal(isHarnessProject(dir), true, "after init, it is");
|
|
43
|
+
// The three commands that used to dead-end all have something to read.
|
|
44
|
+
const { config, ok } = loadConfig(dir);
|
|
45
|
+
assert.ok(ok, "the config we just wrote is readable");
|
|
46
|
+
assert.equal(config.currentPhase, "define");
|
|
47
|
+
assert.equal(config.currentRole, "planner");
|
|
48
|
+
assert.deepEqual(config.phases.enabled, DEFAULT_ENABLED_PHASES);
|
|
49
|
+
const { list } = loadFeatureList(dir);
|
|
50
|
+
assert.deepEqual(list.features, [], "the plan starts empty, not absent");
|
|
51
|
+
const brief = await buildBrief(dir);
|
|
52
|
+
const text = renderBrief(brief, config);
|
|
53
|
+
assert.match(text, /NEXT STEP · DEFINE/);
|
|
54
|
+
assert.match(text, /THE LOOP/);
|
|
55
|
+
const gate = await runChecks(dir, "define", { record: false });
|
|
56
|
+
assert.ok(Array.isArray(gate.checks) && gate.checks.length > 0, "the gate runs and reports");
|
|
57
|
+
rmSync(dir, { recursive: true, force: true });
|
|
58
|
+
console.log("✓ init turns a bare directory into a project the harness can run");
|
|
59
|
+
}
|
|
60
|
+
// ── the gate stays unbribable ──────────────────────────────────────────────
|
|
61
|
+
// It would be easy to scaffold documents long enough to satisfy the review
|
|
62
|
+
// gate on the day they are created. That would mean REVIEW passes on
|
|
63
|
+
// boilerplate nobody wrote, which is the one thing this design cannot allow.
|
|
64
|
+
{
|
|
65
|
+
const dir = tmpProject();
|
|
66
|
+
initHarness(dir);
|
|
67
|
+
const gate = await runChecks(dir, "review", { record: false });
|
|
68
|
+
const docChecks = gate.checks.filter((c) => ["architecture-doc", "decisions-logged", "rubric-content"].includes(c.name));
|
|
69
|
+
assert.equal(docChecks.length, 3, "the review gate checks all three documents");
|
|
70
|
+
for (const check of docChecks) {
|
|
71
|
+
assert.equal(check.pass, false, `${check.name} passed on a starter template`);
|
|
72
|
+
assert.match(check.detail, /essentially empty/);
|
|
73
|
+
}
|
|
74
|
+
rmSync(dir, { recursive: true, force: true });
|
|
75
|
+
console.log("✓ the scaffolded documents do not satisfy the gate that demands them");
|
|
76
|
+
}
|
|
77
|
+
// ── it never destroys work ─────────────────────────────────────────────────
|
|
78
|
+
{
|
|
79
|
+
const dir = tmpProject();
|
|
80
|
+
initHarness(dir);
|
|
81
|
+
const arch = join(dir, "harness", "docs", "ARCHITECTURE.md");
|
|
82
|
+
writeFileSync(arch, "# Architecture\n\nReal content someone actually wrote.\n", "utf-8");
|
|
83
|
+
writeFileSync(join(dir, "harness", "features", "feature-list.json"), JSON.stringify({
|
|
84
|
+
version: "2.0", baseRevision: 7, goals: [], sprints: [],
|
|
85
|
+
features: [{ id: "feature-001", name: "Kept", passes: false, criteria: ["c"], tasks: [] }],
|
|
86
|
+
}));
|
|
87
|
+
const again = initHarness(dir, { force: true });
|
|
88
|
+
assert.ok(again.ok, again.error);
|
|
89
|
+
assert.match(readFileSync(arch, "utf-8"), /Real content someone actually wrote/);
|
|
90
|
+
assert.equal(loadFeatureList(dir).list.features.length, 1, "the existing plan survived");
|
|
91
|
+
assert.ok(again.kept.includes("harness/config.json"));
|
|
92
|
+
assert.ok(again.kept.includes("harness/features/feature-list.json"));
|
|
93
|
+
assert.equal(again.created.length, 0, "a complete harness needs nothing restored");
|
|
94
|
+
rmSync(dir, { recursive: true, force: true });
|
|
95
|
+
console.log("✓ re-running init never overwrites work that is already there");
|
|
96
|
+
}
|
|
97
|
+
// ...and restores only what is missing.
|
|
98
|
+
{
|
|
99
|
+
const dir = tmpProject();
|
|
100
|
+
initHarness(dir);
|
|
101
|
+
rmSync(join(dir, "harness", "evaluator-rubric.md"));
|
|
102
|
+
const again = initHarness(dir, { force: true });
|
|
103
|
+
assert.deepEqual(again.created, ["harness/evaluator-rubric.md"]);
|
|
104
|
+
console.log("✓ force restores exactly what is missing");
|
|
105
|
+
rmSync(dir, { recursive: true, force: true });
|
|
106
|
+
}
|
|
107
|
+
// ── refusing politely ──────────────────────────────────────────────────────
|
|
108
|
+
{
|
|
109
|
+
const dir = tmpProject();
|
|
110
|
+
initHarness(dir);
|
|
111
|
+
const again = initHarness(dir);
|
|
112
|
+
assert.equal(again.ok, false);
|
|
113
|
+
assert.match(again.error, /already has a harness/);
|
|
114
|
+
assert.match(again.error, /\/infinity:config/, "the refusal says what to do instead");
|
|
115
|
+
rmSync(dir, { recursive: true, force: true });
|
|
116
|
+
}
|
|
117
|
+
// ── stack detection ────────────────────────────────────────────────────────
|
|
118
|
+
{
|
|
119
|
+
const node = tmpProject({
|
|
120
|
+
"package.json": JSON.stringify({
|
|
121
|
+
name: "x",
|
|
122
|
+
scripts: { lint: "eslint .", test: "vitest run", build: "tsc", coverage: "vitest run --coverage" },
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
const d = detectStack(node);
|
|
126
|
+
assert.equal(d.id, "node");
|
|
127
|
+
assert.equal(d.commands.lint, "npm run lint");
|
|
128
|
+
assert.equal(d.commands.test, "npm run test");
|
|
129
|
+
assert.equal(d.commands.coverage, "npm run coverage");
|
|
130
|
+
assert.equal(d.commands.build, "npm run build");
|
|
131
|
+
rmSync(node, { recursive: true, force: true });
|
|
132
|
+
// The lockfile decides the runner — `npm run` in a pnpm project is a
|
|
133
|
+
// different resolution and sometimes a different result.
|
|
134
|
+
const pnpm = tmpProject({
|
|
135
|
+
"package.json": JSON.stringify({ scripts: { test: "vitest" } }),
|
|
136
|
+
"pnpm-lock.yaml": "lockfileVersion: 9",
|
|
137
|
+
});
|
|
138
|
+
assert.equal(detectStack(pnpm).commands.test, "pnpm run test");
|
|
139
|
+
rmSync(pnpm, { recursive: true, force: true });
|
|
140
|
+
// Scripts that do not exist are not invented.
|
|
141
|
+
const bare = tmpProject({ "package.json": JSON.stringify({ name: "x" }) });
|
|
142
|
+
assert.deepEqual(detectStack(bare).commands, { lint: null, test: null, coverage: null, build: null });
|
|
143
|
+
rmSync(bare, { recursive: true, force: true });
|
|
144
|
+
const rust = tmpProject({ "Cargo.toml": "[package]\nname = \"x\"\n" });
|
|
145
|
+
assert.equal(detectStack(rust).id, "rust");
|
|
146
|
+
assert.equal(detectStack(rust).commands.test, "cargo test");
|
|
147
|
+
rmSync(rust, { recursive: true, force: true });
|
|
148
|
+
const go = tmpProject({ "go.mod": "module x\n" });
|
|
149
|
+
assert.equal(detectStack(go).commands.test, "go test ./...");
|
|
150
|
+
rmSync(go, { recursive: true, force: true });
|
|
151
|
+
// Python only claims what the project shows evidence of.
|
|
152
|
+
const py = tmpProject({ "pyproject.toml": "[project]\nname = \"x\"\n" });
|
|
153
|
+
assert.equal(detectStack(py).id, "python");
|
|
154
|
+
assert.equal(detectStack(py).commands.test, null, "no tests dir, no pytest claim");
|
|
155
|
+
rmSync(py, { recursive: true, force: true });
|
|
156
|
+
const pyTested = tmpProject({
|
|
157
|
+
"pyproject.toml": "[tool.ruff]\nline-length = 100\n[tool.pytest.ini_options]\n",
|
|
158
|
+
"tests/test_x.py": "def test_x(): pass\n",
|
|
159
|
+
});
|
|
160
|
+
assert.equal(detectStack(pyTested).commands.test, "pytest");
|
|
161
|
+
assert.equal(detectStack(pyTested).commands.lint, "ruff check .");
|
|
162
|
+
rmSync(pyTested, { recursive: true, force: true });
|
|
163
|
+
const nothing = tmpProject();
|
|
164
|
+
assert.equal(detectStack(nothing).id, "unknown");
|
|
165
|
+
rmSync(nothing, { recursive: true, force: true });
|
|
166
|
+
console.log("✓ stack detection proposes only what the project shows evidence of");
|
|
167
|
+
}
|
|
168
|
+
// Detected commands reach the config, so the gate runs the right thing.
|
|
169
|
+
{
|
|
170
|
+
const dir = tmpProject({ "package.json": JSON.stringify({ scripts: { test: "jest", lint: "eslint ." } }) });
|
|
171
|
+
const r = initHarness(dir);
|
|
172
|
+
assert.equal(r.config.commands.test, "npm run test");
|
|
173
|
+
assert.equal(r.config.commands.lint, "npm run lint");
|
|
174
|
+
assert.equal(r.config.stack, "node");
|
|
175
|
+
assert.equal(loadConfig(dir).config.commands.test, "npm run test", "and they are persisted");
|
|
176
|
+
rmSync(dir, { recursive: true, force: true });
|
|
177
|
+
console.log("✓ what init detects is what the gate will run");
|
|
178
|
+
}
|
|
179
|
+
// ── phases ─────────────────────────────────────────────────────────────────
|
|
180
|
+
{
|
|
181
|
+
// Stored in pipeline order, not the order they were clicked.
|
|
182
|
+
const dir = tmpProject();
|
|
183
|
+
const r = initHarness(dir, { phases: ["ship", "build", "define"] });
|
|
184
|
+
assert.deepEqual(r.config.phases.enabled, ["define", "build", "ship"]);
|
|
185
|
+
assert.equal(r.config.currentPhase, "define", "the run starts at the first enabled phase");
|
|
186
|
+
rmSync(dir, { recursive: true, force: true });
|
|
187
|
+
// SIMPLIFY is opt-in, and opting in works.
|
|
188
|
+
const s = tmpProject();
|
|
189
|
+
const withSimplify = initHarness(s, { phases: [...DEFAULT_ENABLED_PHASES, "simplify"] });
|
|
190
|
+
assert.ok(withSimplify.config.phases.enabled.includes("simplify"));
|
|
191
|
+
assert.deepEqual(withSimplify.config.phases.enabled, ["define", "plan", "build", "verify", "simplify", "review", "ship"]);
|
|
192
|
+
rmSync(s, { recursive: true, force: true });
|
|
193
|
+
// Nonsense in, sane pipeline out — an empty pipeline is not a pipeline.
|
|
194
|
+
const junk = tmpProject();
|
|
195
|
+
const j = initHarness(junk, { phases: ["nope", "init"] });
|
|
196
|
+
assert.deepEqual(j.config.phases.enabled, DEFAULT_ENABLED_PHASES);
|
|
197
|
+
rmSync(junk, { recursive: true, force: true });
|
|
198
|
+
// A pipeline that starts at BUILD starts at BUILD.
|
|
199
|
+
const late = tmpProject();
|
|
200
|
+
const l = initHarness(late, { phases: ["build", "verify"] });
|
|
201
|
+
assert.equal(l.config.currentPhase, "build");
|
|
202
|
+
assert.equal(l.config.currentRole, "generator");
|
|
203
|
+
rmSync(late, { recursive: true, force: true });
|
|
204
|
+
console.log("✓ the pipeline is what you asked for, in the order it actually runs");
|
|
205
|
+
}
|
|
206
|
+
// ── the docs the brief points at ───────────────────────────────────────────
|
|
207
|
+
{
|
|
208
|
+
const dir = tmpProject();
|
|
209
|
+
initHarness(dir);
|
|
210
|
+
const packaged = packagedDocsDir();
|
|
211
|
+
assert.ok(existsSync(packaged), "the package ships the docs init copies");
|
|
212
|
+
for (const phase of DEFAULT_ENABLED_PHASES) {
|
|
213
|
+
assert.ok(existsSync(join(dir, "harness", "docs", "phases", `${phase}.md`)), `the ${phase} phase doc is missing — the brief points at it`);
|
|
214
|
+
}
|
|
215
|
+
for (const role of ["planner", "generator", "evaluator", "simplifier"]) {
|
|
216
|
+
assert.ok(existsSync(join(dir, "harness", "docs", "agents", `${role}.md`)), `${role}.md is missing`);
|
|
217
|
+
}
|
|
218
|
+
// Copied, not linked: a team's BUILD doc should be theirs to edit.
|
|
219
|
+
const doc = join(dir, "harness", "docs", "phases", "build.md");
|
|
220
|
+
writeFileSync(doc, "# Our BUILD\n", "utf-8");
|
|
221
|
+
assert.notEqual(readFileSync(join(packaged, "phases", "build.md"), "utf-8"), "# Our BUILD\n");
|
|
222
|
+
rmSync(dir, { recursive: true, force: true });
|
|
223
|
+
console.log("✓ the phase and role docs land in the project, as editable copies");
|
|
224
|
+
}
|
|
225
|
+
// ── run state does not get committed ───────────────────────────────────────
|
|
226
|
+
{
|
|
227
|
+
const dir = tmpProject();
|
|
228
|
+
initHarness(dir);
|
|
229
|
+
const ignore = readFileSync(join(dir, "harness", ".gitignore"), "utf-8");
|
|
230
|
+
for (const noisy of ["run-journal.jsonl", "STOP", "*.bak", "*.ilock"]) {
|
|
231
|
+
assert.ok(ignore.includes(noisy), `${noisy} should not be committed`);
|
|
232
|
+
}
|
|
233
|
+
assert.ok(!ignore.includes("config.json"), "the config IS worth committing");
|
|
234
|
+
assert.ok(!ignore.includes("feature-list"), "the plan IS worth committing");
|
|
235
|
+
rmSync(dir, { recursive: true, force: true });
|
|
236
|
+
console.log("✓ run state is ignored; the plan and config are not");
|
|
237
|
+
}
|
|
238
|
+
// ── what it tells the user ─────────────────────────────────────────────────
|
|
239
|
+
{
|
|
240
|
+
const dir = tmpProject({ "package.json": JSON.stringify({ scripts: { test: "vitest" } }) });
|
|
241
|
+
const text = describeInit(initHarness(dir));
|
|
242
|
+
assert.match(text, /Node/);
|
|
243
|
+
assert.match(text, /DEFINE/);
|
|
244
|
+
assert.match(text, /npm run test/);
|
|
245
|
+
assert.match(text, /say what you are building/, "with no goal it asks for one");
|
|
246
|
+
assert.doesNotMatch(text, /Goal {6}/, "and does not pretend to have one");
|
|
247
|
+
rmSync(dir, { recursive: true, force: true });
|
|
248
|
+
// With a goal from the wizard it must not tell the human to supply one they
|
|
249
|
+
// have already supplied.
|
|
250
|
+
const withGoal = tmpProject({ "package.json": JSON.stringify({ scripts: { test: "vitest" } }) });
|
|
251
|
+
const goalText = describeInit(initHarness(withGoal, { brief: "reconcile Stripe payouts" }));
|
|
252
|
+
assert.match(goalText, /Goal {6}reconcile Stripe payouts/);
|
|
253
|
+
assert.match(goalText, /\/infinity:run/, "it says what to do next");
|
|
254
|
+
assert.doesNotMatch(goalText, /say what you are building/);
|
|
255
|
+
rmSync(withGoal, { recursive: true, force: true });
|
|
256
|
+
const bare = tmpProject();
|
|
257
|
+
const bareText = describeInit(initHarness(bare));
|
|
258
|
+
assert.match(bareText, /none detected/);
|
|
259
|
+
assert.match(bareText, /\/infinity:config/, "and where to fix that");
|
|
260
|
+
rmSync(bare, { recursive: true, force: true });
|
|
261
|
+
console.log("✓ init reports what it found, what it did, and what to do next");
|
|
262
|
+
}
|
|
263
|
+
console.log("init.test.ts ✓");
|
|
264
|
+
//# sourceMappingURL=init.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../tests/init.test.ts"],"names":[],"mappings":"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"}
|