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,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every name we tell someone to type is a name that exists.
|
|
3
|
+
*
|
|
4
|
+
* This file exists because the brief spent months ending with:
|
|
5
|
+
*
|
|
6
|
+
* THE LOOP
|
|
7
|
+
* 2. Run: harness validate
|
|
8
|
+
*
|
|
9
|
+
* `harness` is a command line that stopped existing when the CLI was ported
|
|
10
|
+
* into `src/`. Every brief — the text injected at session start, the thing the
|
|
11
|
+
* whole design rests on — closed by telling the model to run a command that
|
|
12
|
+
* would fail. Four shipped skills had the same disease, pointing at an
|
|
13
|
+
* `infinity-harness capability …` CLI this package never had.
|
|
14
|
+
*
|
|
15
|
+
* Nothing caught either one, because a wrong string in a template is invisible
|
|
16
|
+
* to a type checker and a passing test. So: extract the tools and commands the
|
|
17
|
+
* extension actually registers, then hold every document and every rendered
|
|
18
|
+
* brief to that list.
|
|
19
|
+
*/
|
|
20
|
+
import assert from "node:assert/strict";
|
|
21
|
+
import { execFileSync } from "node:child_process";
|
|
22
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
23
|
+
import { tmpdir } from "node:os";
|
|
24
|
+
import { dirname, join, resolve } from "node:path";
|
|
25
|
+
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { buildBrief, renderBrief } from "../src/core/brief.js";
|
|
27
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
28
|
+
/**
|
|
29
|
+
* The markdown this repository actually ships, from git rather than from a
|
|
30
|
+
* directory walk.
|
|
31
|
+
*
|
|
32
|
+
* A walk finds what the harness *wrote* as well as what we publish. Run the
|
|
33
|
+
* pipeline in this repo once and `harness/session-handoff.md` and
|
|
34
|
+
* `harness/.run-prompt.md` appear — git-ignored scratch, full of whatever
|
|
35
|
+
* commands were current when they were generated. Holding those to today's
|
|
36
|
+
* command list fails the suite for anyone who has actually used the tool, and
|
|
37
|
+
* says nothing about the package.
|
|
38
|
+
*/
|
|
39
|
+
function trackedMarkdown(...dirs) {
|
|
40
|
+
const listed = execFileSync("git", ["ls-files", "-z", "--", ...dirs], {
|
|
41
|
+
cwd: repoRoot,
|
|
42
|
+
encoding: "utf-8",
|
|
43
|
+
});
|
|
44
|
+
const files = listed
|
|
45
|
+
.split("\0")
|
|
46
|
+
.filter((f) => f.endsWith(".md"))
|
|
47
|
+
.map((f) => join(repoRoot, f));
|
|
48
|
+
assert.ok(files.length > 0, `git ls-files found no markdown under ${dirs.join(", ")}`);
|
|
49
|
+
return files;
|
|
50
|
+
}
|
|
51
|
+
const extensionSource = readFileSync(join(repoRoot, "extensions", "infinity-harness", "index.ts"), "utf-8");
|
|
52
|
+
// What the adapter actually hands to pi.
|
|
53
|
+
const TOOLS = new Set([...extensionSource.matchAll(/registerTool\(\{\s*\n\s*name:\s*"([a-z0-9_]+)"/g)].map((m) => m[1]));
|
|
54
|
+
const COMMANDS = new Set([...extensionSource.matchAll(/registerCommand\("([a-z0-9:_-]+)"/g)].map((m) => m[1]));
|
|
55
|
+
{
|
|
56
|
+
assert.ok(TOOLS.size >= 5, `expected the tool set, parsed ${TOOLS.size}: ${[...TOOLS]}`);
|
|
57
|
+
assert.ok(COMMANDS.size >= 9, `expected the command set, parsed ${COMMANDS.size}: ${[...COMMANDS]}`);
|
|
58
|
+
assert.ok(TOOLS.has("infinity_validate"));
|
|
59
|
+
assert.ok(COMMANDS.has("infinity:run"));
|
|
60
|
+
console.log(`✓ the extension registers ${TOOLS.size} tools and ${COMMANDS.size} commands`);
|
|
61
|
+
}
|
|
62
|
+
/** Every `infinity_x` / `/infinity:x` mentioned in a piece of text. */
|
|
63
|
+
function mentioned(text) {
|
|
64
|
+
return {
|
|
65
|
+
tools: [...new Set([...text.matchAll(/\binfinity_[a-z0-9_]+/g)].map((m) => m[0]))],
|
|
66
|
+
commands: [...new Set([...text.matchAll(/\/infinity:[a-z0-9-]+/g)].map((m) => m[0].slice(1)))],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function checkText(label, text) {
|
|
70
|
+
const { tools, commands } = mentioned(text);
|
|
71
|
+
const bad = [];
|
|
72
|
+
for (const tool of tools)
|
|
73
|
+
if (!TOOLS.has(tool))
|
|
74
|
+
bad.push(`${label}: no such tool ${tool}`);
|
|
75
|
+
for (const cmd of commands)
|
|
76
|
+
if (!COMMANDS.has(cmd))
|
|
77
|
+
bad.push(`${label}: no such command /${cmd}`);
|
|
78
|
+
return bad;
|
|
79
|
+
}
|
|
80
|
+
// ── the brief ──────────────────────────────────────────────────────────────
|
|
81
|
+
{
|
|
82
|
+
const dir = mkdtempSync(join(tmpdir(), "pi-surface-"));
|
|
83
|
+
mkdirSync(join(dir, "harness", "features"), { recursive: true });
|
|
84
|
+
const write = (phase, tasksDone) => {
|
|
85
|
+
writeFileSync(join(dir, "harness", "config.json"), JSON.stringify({ currentPhase: phase, phases: { enabled: ["define", "plan", "build", "verify", "review", "ship"] } }));
|
|
86
|
+
writeFileSync(join(dir, "harness", "features", "feature-list.json"), JSON.stringify({
|
|
87
|
+
revision: 1,
|
|
88
|
+
features: [
|
|
89
|
+
{
|
|
90
|
+
id: "feature-001",
|
|
91
|
+
name: "Checkout",
|
|
92
|
+
status: "in_progress",
|
|
93
|
+
criteria: ["it charges the right amount"],
|
|
94
|
+
tasks: [
|
|
95
|
+
{
|
|
96
|
+
id: 1,
|
|
97
|
+
description: "handle partial refunds across split tenders",
|
|
98
|
+
status: tasksDone ? "complete" : "pending",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
}));
|
|
104
|
+
};
|
|
105
|
+
const problems = [];
|
|
106
|
+
for (const phase of ["define", "plan", "build", "verify", "review", "ship"]) {
|
|
107
|
+
write(phase, false);
|
|
108
|
+
const brief = await buildBrief(dir);
|
|
109
|
+
const text = renderBrief(brief);
|
|
110
|
+
problems.push(...checkText(`brief(${phase})`, text));
|
|
111
|
+
// The whole point of the brief is that the model knows what to do next.
|
|
112
|
+
assert.match(text, /THE LOOP/, `brief(${phase}) lost its instructions`);
|
|
113
|
+
assert.ok(mentioned(text).tools.length > 0, `brief(${phase}) tells the model to act but names no tool`);
|
|
114
|
+
}
|
|
115
|
+
// The paused and complete briefs return early — they must still be clean.
|
|
116
|
+
write("ship", true);
|
|
117
|
+
const brief = await buildBrief(dir);
|
|
118
|
+
problems.push(...checkText("brief(complete)", renderBrief(brief)));
|
|
119
|
+
assert.deepEqual(problems, [], problems.join("\n"));
|
|
120
|
+
rmSync(dir, { recursive: true, force: true });
|
|
121
|
+
console.log("✓ every brief names tools and commands the extension registers");
|
|
122
|
+
}
|
|
123
|
+
// ── the documents ──────────────────────────────────────────────────────────
|
|
124
|
+
{
|
|
125
|
+
// CHANGELOG is deliberately absent: a changelog's job is to say what a
|
|
126
|
+
// release removed or renamed, so it has to be able to name things that no
|
|
127
|
+
// longer exist. Everything else here is instructions someone will follow.
|
|
128
|
+
const docs = [
|
|
129
|
+
join(repoRoot, "README.md"),
|
|
130
|
+
join(repoRoot, "AGENTS.md"),
|
|
131
|
+
...trackedMarkdown("harness/docs", "harness/skills"),
|
|
132
|
+
];
|
|
133
|
+
const problems = [];
|
|
134
|
+
for (const doc of docs) {
|
|
135
|
+
problems.push(...checkText(doc.slice(repoRoot.length + 1), readFileSync(doc, "utf-8")));
|
|
136
|
+
}
|
|
137
|
+
assert.deepEqual(problems, [], problems.join("\n"));
|
|
138
|
+
console.log(`✓ ${docs.length} shipped documents name only tools and commands that exist`);
|
|
139
|
+
}
|
|
140
|
+
// ── the CLI that isn't ─────────────────────────────────────────────────────
|
|
141
|
+
// This package ships no executable. It descends from one that did, and the
|
|
142
|
+
// instructions came with it: `infinity-harness capability add`, `contract
|
|
143
|
+
// propose`, `decision "..."`, `rollback list`, `checkpoint create`, `init`.
|
|
144
|
+
// Every one was a command-not-found waiting for whoever followed the document.
|
|
145
|
+
//
|
|
146
|
+
// A hardcoded list of banned verbs only ever catches the ones already found.
|
|
147
|
+
// So this looks at where the claim is made instead: inside a code fence or a
|
|
148
|
+
// code span, the package name followed by a word is a command line, and there
|
|
149
|
+
// is no command line. In prose — "infinity-harness drives the agent" — it is
|
|
150
|
+
// just the name.
|
|
151
|
+
{
|
|
152
|
+
const problems = [];
|
|
153
|
+
const CLI = /\b(?:infinity-harness|dev-harness|pi-harness)\s+([a-z][a-z-]*)/g;
|
|
154
|
+
/** Fenced blocks and inline spans — the places a command is written. */
|
|
155
|
+
function codeOnly(text) {
|
|
156
|
+
const parts = [];
|
|
157
|
+
for (const [, body] of text.matchAll(/```[a-z]*\n([\s\S]*?)```/g))
|
|
158
|
+
parts.push(body);
|
|
159
|
+
for (const [, body] of text.matchAll(/`([^`\n]+)`/g))
|
|
160
|
+
parts.push(body);
|
|
161
|
+
return parts.join("\n");
|
|
162
|
+
}
|
|
163
|
+
const check = (label, text) => {
|
|
164
|
+
for (const [hit, verb] of codeOnly(text).matchAll(CLI)) {
|
|
165
|
+
// `pi install npm:infinity-harness` is the one legitimate form.
|
|
166
|
+
if (/\b(?:pi|npm|npx|git)\b/.test(hit))
|
|
167
|
+
continue;
|
|
168
|
+
problems.push(`${label}: names a CLI that does not exist — "${verb}" in \`${hit.trim()}\``);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const files = [
|
|
172
|
+
join(repoRoot, "README.md"),
|
|
173
|
+
join(repoRoot, "AGENTS.md"),
|
|
174
|
+
...trackedMarkdown("harness"),
|
|
175
|
+
];
|
|
176
|
+
for (const file of files)
|
|
177
|
+
check(file.slice(repoRoot.length + 1), readFileSync(file, "utf-8"));
|
|
178
|
+
assert.deepEqual(problems, [], problems.join("\n"));
|
|
179
|
+
console.log("✓ nothing shipped tells anyone to run a command line this package does not have");
|
|
180
|
+
}
|
|
181
|
+
// ── the rename artefact ────────────────────────────────────────────────────
|
|
182
|
+
// A mechanical rename once turned "the `harness validate` command" into
|
|
183
|
+
// "`the infinity_validate tool`" in 36 places across 11 shipped documents —
|
|
184
|
+
// broken English in the very files the brief tells the agent to read, and in
|
|
185
|
+
// three of them a tool name that never existed.
|
|
186
|
+
{
|
|
187
|
+
const files = [
|
|
188
|
+
join(repoRoot, "README.md"),
|
|
189
|
+
join(repoRoot, "AGENTS.md"),
|
|
190
|
+
...trackedMarkdown("harness"),
|
|
191
|
+
];
|
|
192
|
+
const problems = [];
|
|
193
|
+
for (const file of files) {
|
|
194
|
+
const text = readFileSync(file, "utf-8");
|
|
195
|
+
for (const [hit] of text.matchAll(/`the (?:infinity|harness|pi)[a-z_:-]* (?:tool|command)`/g)) {
|
|
196
|
+
problems.push(`${file.slice(repoRoot.length + 1)}: ${hit}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
assert.deepEqual(problems, [], problems.join("\n"));
|
|
200
|
+
console.log("✓ no document carries the mechanical-rename artefact");
|
|
201
|
+
}
|
|
202
|
+
console.log("surface.test.ts ✓");
|
|
203
|
+
//# sourceMappingURL=surface.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.test.js","sourceRoot":"","sources":["../../tests/surface.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtempSync, rmSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { applyTaskList, writeTaskList, summarizeApply } from "../src/taskList.js";
|
|
6
|
+
import { ValidationError } from "../src/core/types.js";
|
|
7
|
+
function mkTask(id, status, extra = {}) {
|
|
8
|
+
return {
|
|
9
|
+
id,
|
|
10
|
+
key: id,
|
|
11
|
+
description: id.toUpperCase(),
|
|
12
|
+
status,
|
|
13
|
+
dependsOn: [],
|
|
14
|
+
subtasks: [],
|
|
15
|
+
...extra,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function listWith(tasks, baseRevision = 0) {
|
|
19
|
+
return {
|
|
20
|
+
version: "2.0",
|
|
21
|
+
baseRevision,
|
|
22
|
+
goals: [{ id: "goal-001", title: "G" }],
|
|
23
|
+
sprints: [{ id: "sprint-001", name: "S" }],
|
|
24
|
+
features: [{ id: "feature-001", name: "F", passes: false, tasks }],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function tmpProject() {
|
|
28
|
+
const d = mkdtempSync(join(tmpdir(), "pi-tasklist-"));
|
|
29
|
+
mkdirSync(join(d, "harness", "features"), { recursive: true });
|
|
30
|
+
return d;
|
|
31
|
+
}
|
|
32
|
+
function featureListFile(dir) {
|
|
33
|
+
return join(dir, "harness", "features", "feature-list.json");
|
|
34
|
+
}
|
|
35
|
+
function assertValidation(fn, match) {
|
|
36
|
+
try {
|
|
37
|
+
fn();
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
const err = e;
|
|
41
|
+
assert.ok(err instanceof ValidationError || err.name === "ValidationError", `expected ValidationError, got ${err?.name}: ${err?.message}`);
|
|
42
|
+
assert.match(err.message, match);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
assert.fail(`expected ValidationError matching ${match}`);
|
|
46
|
+
}
|
|
47
|
+
// ── baseRevision is the concurrency guard ───────────────────────────────────
|
|
48
|
+
{
|
|
49
|
+
const cur = listWith([mkTask("a", "pending")], 2);
|
|
50
|
+
const before = JSON.stringify(cur);
|
|
51
|
+
assertValidation(() => applyTaskList(cur, { baseRevision: 1, tasks: [{ key: "a", subject: "A", status: "complete" }] }), /stale baseRevision/);
|
|
52
|
+
assert.equal(JSON.stringify(cur), before, "a rejected apply must not mutate the input list");
|
|
53
|
+
const res = applyTaskList(cur, { baseRevision: 2, tasks: [{ key: "a", subject: "A", status: "complete" }] });
|
|
54
|
+
assert.equal(res.revision, 3, "a real change bumps the revision");
|
|
55
|
+
assert.equal(res.changed, true);
|
|
56
|
+
assert.equal(JSON.stringify(cur), before, "a successful apply is pure w.r.t. the input list");
|
|
57
|
+
// An omitted baseRevision opts out of the check entirely.
|
|
58
|
+
const noCheck = applyTaskList(cur, { tasks: [{ key: "a", subject: "A", status: "complete" }] });
|
|
59
|
+
assert.equal(noCheck.revision, 3);
|
|
60
|
+
// Resubmitting the same content is a no-op: the revision must not move.
|
|
61
|
+
const same = applyTaskList(res.list, { baseRevision: 3, tasks: [{ key: "a", subject: "A", status: "complete" }] });
|
|
62
|
+
assert.equal(same.changed, false);
|
|
63
|
+
assert.equal(same.revision, 3, "a no-op submission does not move the revision");
|
|
64
|
+
assert.deepEqual(same.change, { added: [], updated: [], removed: [], reordered: false });
|
|
65
|
+
console.log("✓ baseRevision guard, purity, and no-op detection");
|
|
66
|
+
}
|
|
67
|
+
// ── omission means deletion ────────────────────────────────────────────────
|
|
68
|
+
{
|
|
69
|
+
const cur = listWith([mkTask("a", "complete"), mkTask("b", "pending"), mkTask("c", "pending")], 0);
|
|
70
|
+
const res = applyTaskList(cur, {
|
|
71
|
+
tasks: [
|
|
72
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
73
|
+
{ key: "c", subject: "C", status: "pending" },
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
assert.equal(res.tasks.length, 2);
|
|
77
|
+
assert.deepEqual(res.change.removed, ["b"], "the omitted task is deleted");
|
|
78
|
+
assert.ok(!res.tasks.some((t) => t.compositeKey === "b"));
|
|
79
|
+
// Clearing the plan is legal and expressed the same way.
|
|
80
|
+
const cleared = applyTaskList(cur, { tasks: [] });
|
|
81
|
+
assert.equal(cleared.tasks.length, 0);
|
|
82
|
+
assert.equal(summarizeApply(cleared), `Plan cleared (revision ${cleared.revision}).`);
|
|
83
|
+
console.log("✓ omission = deletion");
|
|
84
|
+
}
|
|
85
|
+
// ── dangling vs satisfied dependencies ─────────────────────────────────────
|
|
86
|
+
{
|
|
87
|
+
// Deleting a task something still depends on is a planning error.
|
|
88
|
+
const pendingDep = listWith([mkTask("a", "pending"), mkTask("b", "pending", { dependsOn: ["a"] })]);
|
|
89
|
+
assertValidation(() => applyTaskList(pendingDep, { tasks: [{ key: "b", subject: "B", status: "pending", dependsOn: ["a"] }] }), /unknown task "a"/);
|
|
90
|
+
// Deleting a *completed* task is housekeeping: the dependency is satisfied,
|
|
91
|
+
// so it is pruned rather than treated as dangling.
|
|
92
|
+
const doneDep = listWith([mkTask("a", "complete"), mkTask("b", "complete", { dependsOn: ["a"] })]);
|
|
93
|
+
const pruned = applyTaskList(doneDep, {
|
|
94
|
+
tasks: [{ key: "b", subject: "B", status: "complete", dependsOn: ["a"] }],
|
|
95
|
+
});
|
|
96
|
+
assert.equal(pruned.tasks.length, 1);
|
|
97
|
+
assert.deepEqual(pruned.tasks[0].dependsOn, [], "dep on a deleted completed task is pruned");
|
|
98
|
+
console.log("✓ dangling deps rejected, satisfied deps pruned");
|
|
99
|
+
}
|
|
100
|
+
// ── cycles ─────────────────────────────────────────────────────────────────
|
|
101
|
+
{
|
|
102
|
+
const empty = listWith([]);
|
|
103
|
+
assertValidation(() => applyTaskList(empty, {
|
|
104
|
+
tasks: [
|
|
105
|
+
{ key: "a", subject: "A", status: "pending", dependsOn: ["b"] },
|
|
106
|
+
{ key: "b", subject: "B", status: "pending", dependsOn: ["a"] },
|
|
107
|
+
],
|
|
108
|
+
}), /dependency cycle/);
|
|
109
|
+
assertValidation(() => applyTaskList(empty, { tasks: [{ key: "a", subject: "A", status: "pending", dependsOn: ["a"] }] }), /dependency cycle/);
|
|
110
|
+
assertValidation(() => applyTaskList(empty, {
|
|
111
|
+
tasks: [
|
|
112
|
+
{ key: "a", subject: "A", status: "pending", dependsOn: ["c"] },
|
|
113
|
+
{ key: "b", subject: "B", status: "pending", dependsOn: ["a"] },
|
|
114
|
+
{ key: "c", subject: "C", status: "pending", dependsOn: ["b"] },
|
|
115
|
+
],
|
|
116
|
+
}), /dependency cycle/);
|
|
117
|
+
// A diamond is a DAG, not a cycle.
|
|
118
|
+
const dag = applyTaskList(empty, {
|
|
119
|
+
tasks: [
|
|
120
|
+
{ key: "a", subject: "A", status: "pending" },
|
|
121
|
+
{ key: "b", subject: "B", status: "pending", dependsOn: ["a"] },
|
|
122
|
+
{ key: "c", subject: "C", status: "pending", dependsOn: ["a"] },
|
|
123
|
+
{ key: "d", subject: "D", status: "pending", dependsOn: ["b", "c"] },
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
assert.equal(dag.tasks.length, 4);
|
|
127
|
+
console.log("✓ cycles rejected, DAG accepted");
|
|
128
|
+
}
|
|
129
|
+
// ── a task cannot start before its dependencies finish ─────────────────────
|
|
130
|
+
{
|
|
131
|
+
const cur = listWith([mkTask("a", "pending"), mkTask("b", "pending")]);
|
|
132
|
+
for (const status of ["in_progress", "complete"]) {
|
|
133
|
+
assertValidation(() => applyTaskList(cur, {
|
|
134
|
+
tasks: [
|
|
135
|
+
{ key: "a", subject: "A", status: "pending" },
|
|
136
|
+
{ key: "b", subject: "B", status, dependsOn: ["a"] },
|
|
137
|
+
],
|
|
138
|
+
}), /cannot be "(in_progress|complete)" while these are incomplete: a/);
|
|
139
|
+
}
|
|
140
|
+
const ok = applyTaskList(cur, {
|
|
141
|
+
tasks: [
|
|
142
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
143
|
+
{ key: "b", subject: "B", status: "in_progress", dependsOn: ["a"] },
|
|
144
|
+
],
|
|
145
|
+
});
|
|
146
|
+
assert.equal(ok.tasks.find((t) => t.compositeKey === "b")?.status, "in_progress");
|
|
147
|
+
console.log("✓ status/dependency consistency");
|
|
148
|
+
}
|
|
149
|
+
// ── input validation ───────────────────────────────────────────────────────
|
|
150
|
+
{
|
|
151
|
+
const cur = listWith([mkTask("a", "pending")]);
|
|
152
|
+
assertValidation(() => applyTaskList(cur, {
|
|
153
|
+
tasks: [
|
|
154
|
+
{ key: "a", subject: "A", status: "pending" },
|
|
155
|
+
{ key: "a", subject: "dup", status: "pending" },
|
|
156
|
+
],
|
|
157
|
+
}), /duplicated/);
|
|
158
|
+
assertValidation(() => applyTaskList(cur, { tasks: [{ key: "brand-new", status: "pending" }] }), /subject is required/);
|
|
159
|
+
assertValidation(() => applyTaskList(cur, { tasks: [{ key: "brand-new", subject: "N" }] }), /status is required/);
|
|
160
|
+
assertValidation(() => applyTaskList(cur, { tasks: [{ key: "", subject: "N", status: "pending" }] }), /non-empty/);
|
|
161
|
+
assertValidation(() => applyTaskList(cur, { tasks: [{ key: "bad key!", subject: "N", status: "pending" }] }), /not|must be/);
|
|
162
|
+
assertValidation(() => applyTaskList(cur, { tasks: [{ key: "a", subject: "A", status: "nonsense" }] }), /status is invalid/);
|
|
163
|
+
// Status aliases are accepted and normalised.
|
|
164
|
+
const aliased = applyTaskList(cur, { tasks: [{ key: "a", subject: "A", status: "done" }] });
|
|
165
|
+
assert.equal(aliased.tasks[0].status, "complete");
|
|
166
|
+
console.log("✓ input validation");
|
|
167
|
+
}
|
|
168
|
+
// ── unknown fields on a stored task survive an update ──────────────────────
|
|
169
|
+
{
|
|
170
|
+
const cur = listWith([
|
|
171
|
+
mkTask("a", "pending", {
|
|
172
|
+
difficulty: "difficult",
|
|
173
|
+
modelHint: "big-model",
|
|
174
|
+
criteria: ["it works"],
|
|
175
|
+
ownerNote: "written by a future version",
|
|
176
|
+
estimate: 42,
|
|
177
|
+
}),
|
|
178
|
+
]);
|
|
179
|
+
const res = applyTaskList(cur, { tasks: [{ key: "a", subject: "A", status: "in_progress" }] });
|
|
180
|
+
const t = res.tasks[0];
|
|
181
|
+
assert.equal(t.status, "in_progress");
|
|
182
|
+
assert.equal(t.difficulty, "difficult", "difficulty survives");
|
|
183
|
+
assert.equal(t.modelHint, "big-model", "modelHint survives");
|
|
184
|
+
assert.deepEqual(t.criteria, ["it works"], "criteria survive");
|
|
185
|
+
assert.equal(t.ownerNote, "written by a future version", "unknown field survives");
|
|
186
|
+
assert.equal(t.estimate, 42, "unknown numeric field survives");
|
|
187
|
+
// View-only fields from flattenTasks must never be persisted onto the task.
|
|
188
|
+
const stored = res.list.features[0].tasks[0];
|
|
189
|
+
for (const view of ["index", "compositeKey", "featureId", "featureName"]) {
|
|
190
|
+
assert.equal(view in stored, false, `${view} must not be persisted`);
|
|
191
|
+
}
|
|
192
|
+
console.log("✓ unknown fields survive a merge");
|
|
193
|
+
}
|
|
194
|
+
// ── composite keys route tasks to their feature ────────────────────────────
|
|
195
|
+
{
|
|
196
|
+
const cur = listWith([mkTask("a", "pending")]);
|
|
197
|
+
const res = applyTaskList(cur, {
|
|
198
|
+
tasks: [
|
|
199
|
+
{ key: "a", subject: "A", status: "pending" },
|
|
200
|
+
{ key: "feature-002/task-9", subject: "Elsewhere", status: "pending" },
|
|
201
|
+
],
|
|
202
|
+
});
|
|
203
|
+
assert.equal(res.list.features.length, 2, "an unseen feature id creates the feature");
|
|
204
|
+
const created = res.list.features.find((f) => f.id === "feature-002");
|
|
205
|
+
assert.ok(created);
|
|
206
|
+
assert.equal(created.tasks[0].id, "task-9");
|
|
207
|
+
assert.equal(res.tasks[1].compositeKey, "feature-002/task-9");
|
|
208
|
+
assert.equal(res.tasks[1].index, 2, "index is 1-based across the whole plan");
|
|
209
|
+
console.log("✓ composite keys create/route features");
|
|
210
|
+
}
|
|
211
|
+
// ── feature.passes is derived, never asserted by the agent ─────────────────
|
|
212
|
+
{
|
|
213
|
+
const cur = listWith([mkTask("a", "pending"), mkTask("b", "pending")]);
|
|
214
|
+
const half = applyTaskList(cur, {
|
|
215
|
+
tasks: [
|
|
216
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
217
|
+
{ key: "b", subject: "B", status: "pending" },
|
|
218
|
+
],
|
|
219
|
+
});
|
|
220
|
+
assert.equal(half.list.features[0].passes, false);
|
|
221
|
+
const all = applyTaskList(half.list, {
|
|
222
|
+
tasks: [
|
|
223
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
224
|
+
{ key: "b", subject: "B", status: "complete" },
|
|
225
|
+
],
|
|
226
|
+
});
|
|
227
|
+
assert.equal(all.list.features[0].passes, true, "feature passes once every task is complete");
|
|
228
|
+
console.log("✓ feature.passes derived from task statuses");
|
|
229
|
+
}
|
|
230
|
+
// ── writeTaskList: persistence, metadata, and the no-op path ───────────────
|
|
231
|
+
{
|
|
232
|
+
const dir = tmpProject();
|
|
233
|
+
try {
|
|
234
|
+
// No file on disk yet: the plan is seeded from empty.
|
|
235
|
+
const first = writeTaskList(dir, { tasks: [{ key: "a", subject: "A", status: "pending" }] });
|
|
236
|
+
assert.equal(first.revision, 1);
|
|
237
|
+
const onDisk = JSON.parse(readFileSync(featureListFile(dir), "utf-8"));
|
|
238
|
+
assert.equal(onDisk.baseRevision, 1);
|
|
239
|
+
assert.equal(onDisk.features[0].tasks.length, 1);
|
|
240
|
+
// Metadata the editor knows nothing about is carried through a write.
|
|
241
|
+
onDisk.goals = [{ id: "goal-001", title: "G" }];
|
|
242
|
+
onDisk.sprints = [{ id: "sprint-001", name: "S" }];
|
|
243
|
+
onDisk.features[0].criteria = ["ships"];
|
|
244
|
+
onDisk.features[0].tasks[0].ownerNote = "keep me";
|
|
245
|
+
writeFileSync(featureListFile(dir), JSON.stringify(onDisk, null, 2), "utf-8");
|
|
246
|
+
const second = writeTaskList(dir, {
|
|
247
|
+
baseRevision: 1,
|
|
248
|
+
tasks: [
|
|
249
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
250
|
+
{ key: "b", subject: "B", status: "pending", dependsOn: ["a"] },
|
|
251
|
+
],
|
|
252
|
+
});
|
|
253
|
+
assert.equal(second.revision, 2);
|
|
254
|
+
const after = JSON.parse(readFileSync(featureListFile(dir), "utf-8"));
|
|
255
|
+
assert.equal(after.baseRevision, 2);
|
|
256
|
+
assert.equal(after.goals.length, 1, "goals preserved through a write");
|
|
257
|
+
assert.equal(after.sprints.length, 1, "sprints preserved through a write");
|
|
258
|
+
assert.deepEqual(after.features[0].criteria, ["ships"], "feature criteria preserved");
|
|
259
|
+
assert.equal(after.features[0].tasks[0].ownerNote, "keep me", "unknown task field preserved on disk");
|
|
260
|
+
// A stale write is rejected and leaves the file untouched.
|
|
261
|
+
const before = readFileSync(featureListFile(dir), "utf-8");
|
|
262
|
+
assertValidation(() => writeTaskList(dir, { baseRevision: 0, tasks: [{ key: "a", subject: "A", status: "complete" }] }), /stale baseRevision/);
|
|
263
|
+
assert.equal(readFileSync(featureListFile(dir), "utf-8"), before, "file untouched after a rejected write");
|
|
264
|
+
// A no-op write does not move the revision on disk.
|
|
265
|
+
const noop = writeTaskList(dir, {
|
|
266
|
+
baseRevision: 2,
|
|
267
|
+
tasks: [
|
|
268
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
269
|
+
{ key: "b", subject: "B", status: "pending", dependsOn: ["a"] },
|
|
270
|
+
],
|
|
271
|
+
});
|
|
272
|
+
assert.equal(noop.changed, false);
|
|
273
|
+
assert.equal(JSON.parse(readFileSync(featureListFile(dir), "utf-8")).baseRevision, 2);
|
|
274
|
+
console.log("✓ writeTaskList persists, preserves metadata, rejects stale writes");
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
rmSync(dir, { recursive: true, force: true });
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// ── summarizeApply ─────────────────────────────────────────────────────────
|
|
281
|
+
{
|
|
282
|
+
const cur = listWith([mkTask("a", "pending"), mkTask("b", "pending")]);
|
|
283
|
+
const res = applyTaskList(cur, {
|
|
284
|
+
tasks: [
|
|
285
|
+
{ key: "a", subject: "A", status: "complete" },
|
|
286
|
+
{ key: "c", subject: "Cee", status: "pending" },
|
|
287
|
+
],
|
|
288
|
+
});
|
|
289
|
+
const text = summarizeApply(res);
|
|
290
|
+
assert.match(text, new RegExp(`Plan revision ${res.revision}`));
|
|
291
|
+
assert.match(text, /\+1/, "one added");
|
|
292
|
+
assert.match(text, /~1/, "one updated");
|
|
293
|
+
assert.match(text, /-1/, "one removed");
|
|
294
|
+
assert.match(text, /1\. \[complete\] a: A/);
|
|
295
|
+
assert.match(text, /2\. \[pending\] c: Cee/);
|
|
296
|
+
console.log("✓ summarizeApply");
|
|
297
|
+
}
|
|
298
|
+
console.log("All taskList tests PASS");
|
|
299
|
+
// ── feature metadata ───────────────────────────────────────────────────────
|
|
300
|
+
// Features are derived from task keys, which left no way to give one a name or
|
|
301
|
+
// its acceptance criteria — and the DEFINE gate requires criteria on every
|
|
302
|
+
// feature. The first gate in the pipeline was unpassable through the tools.
|
|
303
|
+
{
|
|
304
|
+
const dir = tmpProject();
|
|
305
|
+
// DEFINE: criteria exist before tasks do, so this submits no `tasks` field.
|
|
306
|
+
const defined = writeTaskList(dir, {
|
|
307
|
+
goal: "Ship the thing",
|
|
308
|
+
features: [{ id: "feature-001", name: "Checkout", criteria: ["it charges once", "it refunds"] }],
|
|
309
|
+
});
|
|
310
|
+
assert.ok(defined.changed, "writing criteria is a change");
|
|
311
|
+
assert.equal(defined.list.features[0].name, "Checkout");
|
|
312
|
+
assert.deepEqual(defined.list.features[0].criteria, ["it charges once", "it refunds"]);
|
|
313
|
+
assert.equal(defined.list.goals?.[0]?.title, "Ship the thing");
|
|
314
|
+
assert.deepEqual(defined.list.features[0].tasks, [], "a feature may exist before its tasks");
|
|
315
|
+
// PLAN: tasks arrive, and must not wipe the criteria written in DEFINE.
|
|
316
|
+
const planned = writeTaskList(dir, {
|
|
317
|
+
baseRevision: defined.revision,
|
|
318
|
+
tasks: [{ key: "feature-001/task-001", subject: "charge the card", status: "pending" }],
|
|
319
|
+
});
|
|
320
|
+
assert.deepEqual(planned.list.features[0].criteria, ["it charges once", "it refunds"]);
|
|
321
|
+
assert.equal(planned.list.features[0].name, "Checkout", "and the name survives too");
|
|
322
|
+
assert.equal(planned.list.features[0].tasks.length, 1);
|
|
323
|
+
// Omitting a feature leaves it alone — it is a merge, not a submission.
|
|
324
|
+
const more = writeTaskList(dir, {
|
|
325
|
+
baseRevision: planned.revision,
|
|
326
|
+
features: [{ id: "feature-002", name: "Refunds", criteria: ["money goes back"] }],
|
|
327
|
+
});
|
|
328
|
+
assert.equal(more.list.features.length, 2);
|
|
329
|
+
assert.equal(more.list.features[0].name, "Checkout", "feature-001 was not touched");
|
|
330
|
+
assert.equal(more.list.features[0].tasks.length, 1, "and kept its tasks");
|
|
331
|
+
// An unchanged resubmission does not move the revision.
|
|
332
|
+
const noop = writeTaskList(dir, {
|
|
333
|
+
baseRevision: more.revision,
|
|
334
|
+
features: [{ id: "feature-002", name: "Refunds", criteria: ["money goes back"] }],
|
|
335
|
+
});
|
|
336
|
+
assert.equal(noop.changed, false);
|
|
337
|
+
assert.equal(noop.revision, more.revision);
|
|
338
|
+
rmSync(dir, { recursive: true, force: true });
|
|
339
|
+
console.log("✓ features carry names and criteria, merged rather than resubmitted");
|
|
340
|
+
}
|
|
341
|
+
// Absent tasks means "leave them"; an empty array still means "delete them".
|
|
342
|
+
{
|
|
343
|
+
const dir = tmpProject();
|
|
344
|
+
const seeded = writeTaskList(dir, {
|
|
345
|
+
tasks: [
|
|
346
|
+
{ key: "feature-001/task-001", subject: "a", status: "pending" },
|
|
347
|
+
{ key: "feature-001/task-002", subject: "b", status: "pending" },
|
|
348
|
+
],
|
|
349
|
+
});
|
|
350
|
+
assert.equal(seeded.tasks.length, 2);
|
|
351
|
+
const metaOnly = writeTaskList(dir, {
|
|
352
|
+
baseRevision: seeded.revision,
|
|
353
|
+
features: [{ id: "feature-001", criteria: ["c"] }],
|
|
354
|
+
});
|
|
355
|
+
assert.equal(metaOnly.tasks.length, 2, "a metadata write must not delete the plan");
|
|
356
|
+
const emptied = writeTaskList(dir, { baseRevision: metaOnly.revision, tasks: [] });
|
|
357
|
+
assert.equal(emptied.tasks.length, 0, "an explicit empty list still clears it");
|
|
358
|
+
assert.deepEqual(emptied.list.features[0]?.criteria, ["c"], "without losing the criteria");
|
|
359
|
+
rmSync(dir, { recursive: true, force: true });
|
|
360
|
+
console.log("✓ omitting tasks is not the same as sending none");
|
|
361
|
+
}
|
|
362
|
+
// Bad input is refused with something the model can act on.
|
|
363
|
+
{
|
|
364
|
+
const dir = tmpProject();
|
|
365
|
+
assert.throws(() => writeTaskList(dir, {}), /nothing submitted/);
|
|
366
|
+
assert.throws(() => writeTaskList(dir, { features: [{ id: "feature-001", tasks: [] }] }), /top-level "tasks" array/);
|
|
367
|
+
assert.throws(() => writeTaskList(dir, { features: [{ id: "feature-001", criteria: ["ok", ""] }] }), /must be non-empty/);
|
|
368
|
+
assert.throws(() => writeTaskList(dir, { features: [{ id: "", criteria: ["x"] }] }), /features\[0\]\.id/);
|
|
369
|
+
assert.throws(() => writeTaskList(dir, { features: [{ id: "f", criteria: Array(41).fill("x") }] }), /at most 40/);
|
|
370
|
+
// Duplicates in one submission collapse rather than being stored twice.
|
|
371
|
+
const ok = writeTaskList(dir, { features: [{ id: "feature-001", criteria: ["same", "same"] }] });
|
|
372
|
+
assert.deepEqual(ok.list.features[0].criteria, ["same"]);
|
|
373
|
+
rmSync(dir, { recursive: true, force: true });
|
|
374
|
+
console.log("✓ malformed feature metadata is refused with a message that says the fix");
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=taskList.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taskList.test.js","sourceRoot":"","sources":["../../tests/taskList.test.ts"],"names":[],"mappings":"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"}
|