zelari-code 1.42.0 → 1.43.0
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/dist/cli/main.bundled.js +1096 -680
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/runHeadless.js +15 -0
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/toolRegistry.js +16 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/planTaskTools.js +236 -0
- package/dist/cli/tools/planTaskTools.js.map +1 -0
- package/dist/cli/workspace/planStore.js +213 -0
- package/dist/cli/workspace/planStore.js.map +1 -0
- package/dist/cli/workspace/planStore.test.js +295 -0
- package/dist/cli/workspace/planStore.test.js.map +1 -0
- package/dist/cli/workspace/stubs.js +14 -4
- package/dist/cli/workspace/stubs.js.map +1 -1
- package/dist/cli/workspace/workspaceSummary.js +7 -1
- package/dist/cli/workspace/workspaceSummary.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workspace/planStore.ts — Durable workspace task store (ADR-0018, slice 3a).
|
|
3
|
+
*
|
|
4
|
+
* Canonical, versioned view of `.zelari/plan.json`, shared by the agent-loop
|
|
5
|
+
* `task_*` tools (src/cli/tools/planTaskTools.ts) and the council stubs
|
|
6
|
+
* (createPlan/createTask/updateTask — src/cli/workspace/stubs.ts).
|
|
7
|
+
*
|
|
8
|
+
* Contract (docs/decisions/0018-workspace-task-store-plan-json.md):
|
|
9
|
+
* - Envelope v1: root carries `schemaVersion`, `counter`, `tasks`; every
|
|
10
|
+
* other root field (`phases`, `milestones`, council metadata, …) is
|
|
11
|
+
* preserved verbatim in pass-through. Unknown fields on a task are kept
|
|
12
|
+
* unless explicitly overwritten.
|
|
13
|
+
* - Status: `pending | in_progress | completed | cancelled | blocked`.
|
|
14
|
+
* Legacy council `done` is normalized to `completed` on read; `task_*`
|
|
15
|
+
* writes use the v1 vocabulary. Council readers were patched to accept
|
|
16
|
+
* both (workspaceSummary.ts).
|
|
17
|
+
* - Ids: `t<N>` sequential via the persisted `counter` — never collides
|
|
18
|
+
* with council ids (`<phaseId>-<slug>-<N>`).
|
|
19
|
+
* - Concurrency: same in-process keyed mutex as the council stubs
|
|
20
|
+
* (`workspaceMutex`, key `<root>:plan`) + atomic tmp+rename write, with a
|
|
21
|
+
* `plan.json.bak` backup before rewriting an existing file. Cross-process
|
|
22
|
+
* races (two CLIs on the same cwd) remain best-effort until a lock file
|
|
23
|
+
* lands (ADR-0018 hardening, out of scope for 3a).
|
|
24
|
+
*
|
|
25
|
+
* @since v1.43.0
|
|
26
|
+
*/
|
|
27
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
|
|
28
|
+
import { dirname, join } from 'node:path';
|
|
29
|
+
import { resolveWorkspaceRoot } from './paths.js';
|
|
30
|
+
import { Storage, workspaceMutex } from './storage.js';
|
|
31
|
+
export const PLAN_SCHEMA_VERSION = 1;
|
|
32
|
+
export const PLAN_MAX_TASKS = 100;
|
|
33
|
+
export const PLAN_TITLE_MAX = 200;
|
|
34
|
+
export const PLAN_NOTES_MAX = 2000;
|
|
35
|
+
export const PLAN_TAG_MAX = 64;
|
|
36
|
+
export const PLAN_TASK_STATUSES = [
|
|
37
|
+
'pending',
|
|
38
|
+
'in_progress',
|
|
39
|
+
'completed',
|
|
40
|
+
'cancelled',
|
|
41
|
+
'blocked',
|
|
42
|
+
];
|
|
43
|
+
/** Typed store error — corrupt file never gets overwritten silently. */
|
|
44
|
+
export class PlanStoreError extends Error {
|
|
45
|
+
code;
|
|
46
|
+
constructor(message, code) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.name = 'PlanStoreError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Resolved plan.json path for a project root (creates nothing). */
|
|
53
|
+
export function planJsonPathFor(projectRoot = process.cwd()) {
|
|
54
|
+
return join(resolveWorkspaceRoot(projectRoot), 'plan.json');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read-modify-write the plan store under the shared workspace mutex.
|
|
58
|
+
* Corrupt JSON → PlanStoreError('PLAN_CORRUPT') and the file is left intact.
|
|
59
|
+
*/
|
|
60
|
+
export async function withPlanStore(projectRoot, fn) {
|
|
61
|
+
const rootDir = resolveWorkspaceRoot(projectRoot);
|
|
62
|
+
return workspaceMutex.run(`${rootDir}:plan`, () => {
|
|
63
|
+
const handle = loadHandle(rootDir);
|
|
64
|
+
const out = fn(handle);
|
|
65
|
+
saveHandle(rootDir, handle);
|
|
66
|
+
return out;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Allocate the next `t<N>` id (increments the persisted counter). */
|
|
70
|
+
export function nextPlanTaskId(store) {
|
|
71
|
+
const maxExisting = store.tasks.reduce((max, t) => {
|
|
72
|
+
const m = /^t(\d+)$/.exec(t.id);
|
|
73
|
+
return m ? Math.max(max, parseInt(m[1], 10)) : max;
|
|
74
|
+
}, 0);
|
|
75
|
+
store.counter = Math.max(store.counter, maxExisting) + 1;
|
|
76
|
+
return `t${store.counter}`;
|
|
77
|
+
}
|
|
78
|
+
/** Write/refresh the per-task artifact the workspace summary links to. */
|
|
79
|
+
export function writePlanTaskArtifact(rootDir, task) {
|
|
80
|
+
const path = join(rootDir, 'plan-tasks', `${task.id}.md`);
|
|
81
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
82
|
+
const meta = {
|
|
83
|
+
kind: 'task',
|
|
84
|
+
id: task.id,
|
|
85
|
+
name: task.title,
|
|
86
|
+
phaseId: task.phaseId,
|
|
87
|
+
status: task.status,
|
|
88
|
+
priority: task.priority ?? 'medium',
|
|
89
|
+
updatedAt: task.updatedAt,
|
|
90
|
+
};
|
|
91
|
+
const body = [
|
|
92
|
+
`# Task ${task.id}: ${task.title}`,
|
|
93
|
+
'',
|
|
94
|
+
`- Status: **${task.status}**`,
|
|
95
|
+
`- Priority: ${task.priority ?? 'medium'}`,
|
|
96
|
+
task.phaseId ? `- Phase: ${task.phaseId}` : null,
|
|
97
|
+
task.agent ? `- Agent: ${task.agent}` : null,
|
|
98
|
+
'',
|
|
99
|
+
task.notes?.trim() ? task.notes.trim() : '_(no notes)_',
|
|
100
|
+
'',
|
|
101
|
+
]
|
|
102
|
+
.filter((l) => l !== null)
|
|
103
|
+
.join('\n');
|
|
104
|
+
new Storage().write(path, meta, body);
|
|
105
|
+
}
|
|
106
|
+
// ── internals ─────────────────────────────────────────────────────────
|
|
107
|
+
function loadHandle(rootDir) {
|
|
108
|
+
const jsonPath = join(rootDir, 'plan.json');
|
|
109
|
+
if (!existsSync(jsonPath)) {
|
|
110
|
+
return { rootDir, tasks: [], counter: 0, rootFields: {} };
|
|
111
|
+
}
|
|
112
|
+
let parsed;
|
|
113
|
+
try {
|
|
114
|
+
const raw = JSON.parse(readFileSync(jsonPath, 'utf8'));
|
|
115
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
116
|
+
throw new Error('root is not a JSON object');
|
|
117
|
+
}
|
|
118
|
+
parsed = raw;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
throw new PlanStoreError(`PLAN_CORRUPT: ${jsonPath} is not valid JSON — refusing to overwrite a ` +
|
|
122
|
+
`possibly hand-edited or crashed write. Fix or remove the file (a ` +
|
|
123
|
+
`.bak may exist), then retry.`, 'PLAN_CORRUPT');
|
|
124
|
+
}
|
|
125
|
+
const { tasks: rawTasks, counter, schemaVersion: _schemaVersion, ...rootFields } = parsed;
|
|
126
|
+
const tasks = (Array.isArray(rawTasks) ? rawTasks : [])
|
|
127
|
+
.map(normalizeTask)
|
|
128
|
+
.filter((t) => typeof t.id === 'string' && t.id.length > 0);
|
|
129
|
+
const numericCounter = typeof counter === 'number' && Number.isFinite(counter) && counter >= 0
|
|
130
|
+
? Math.floor(counter)
|
|
131
|
+
: 0;
|
|
132
|
+
return { rootDir, tasks, counter: numericCounter, rootFields };
|
|
133
|
+
}
|
|
134
|
+
function saveHandle(rootDir, handle) {
|
|
135
|
+
if (handle.tasks.length > PLAN_MAX_TASKS) {
|
|
136
|
+
throw new PlanStoreError(`PLAN_TOO_MANY_TASKS: plan.json would exceed ${PLAN_MAX_TASKS} tasks ` +
|
|
137
|
+
`(${handle.tasks.length}) — cancel or complete tasks first.`, 'PLAN_TOO_MANY_TASKS');
|
|
138
|
+
}
|
|
139
|
+
const jsonPath = join(rootDir, 'plan.json');
|
|
140
|
+
mkdirSync(rootDir, { recursive: true });
|
|
141
|
+
if (existsSync(jsonPath)) {
|
|
142
|
+
copyFileSync(jsonPath, `${jsonPath}.bak`);
|
|
143
|
+
}
|
|
144
|
+
const file = {
|
|
145
|
+
...handle.rootFields,
|
|
146
|
+
schemaVersion: PLAN_SCHEMA_VERSION,
|
|
147
|
+
counter: handle.counter,
|
|
148
|
+
tasks: handle.tasks,
|
|
149
|
+
};
|
|
150
|
+
const tmp = `${jsonPath}.tmp-${process.pid}`;
|
|
151
|
+
writeFileSync(tmp, JSON.stringify(file, null, 2) + '\n', 'utf8');
|
|
152
|
+
renameSync(tmp, jsonPath);
|
|
153
|
+
}
|
|
154
|
+
/** Normalize a raw task record (council or v1) into the contract shape. */
|
|
155
|
+
function normalizeTask(raw) {
|
|
156
|
+
const t = (raw !== null && typeof raw === 'object'
|
|
157
|
+
? { ...raw }
|
|
158
|
+
: {});
|
|
159
|
+
if (typeof t.id === 'string') {
|
|
160
|
+
t.id = t.id.trim().slice(0, 64);
|
|
161
|
+
}
|
|
162
|
+
const titleSource = firstString(t.title) ??
|
|
163
|
+
firstString(t.name) ??
|
|
164
|
+
firstString(t.description) ??
|
|
165
|
+
'';
|
|
166
|
+
t.title = titleSource.slice(0, PLAN_TITLE_MAX);
|
|
167
|
+
// Council readers (buildPlanSummary) render `name` — keep the alias in
|
|
168
|
+
// sync so t<N> tasks display correctly there too.
|
|
169
|
+
if (t.title && !firstString(t.name)) {
|
|
170
|
+
t.name = t.title;
|
|
171
|
+
}
|
|
172
|
+
t.status = normalizeStatus(t.status);
|
|
173
|
+
if (typeof t.notes === 'string') {
|
|
174
|
+
t.notes = t.notes.slice(0, PLAN_NOTES_MAX);
|
|
175
|
+
}
|
|
176
|
+
if (typeof t.phaseId === 'string') {
|
|
177
|
+
t.phaseId = t.phaseId.slice(0, PLAN_TAG_MAX);
|
|
178
|
+
}
|
|
179
|
+
if (typeof t.agent === 'string') {
|
|
180
|
+
t.agent = t.agent.slice(0, PLAN_TAG_MAX);
|
|
181
|
+
}
|
|
182
|
+
return t;
|
|
183
|
+
}
|
|
184
|
+
function normalizeStatus(raw) {
|
|
185
|
+
const s = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
|
|
186
|
+
switch (s) {
|
|
187
|
+
case 'in_progress':
|
|
188
|
+
case 'in-progress':
|
|
189
|
+
case 'doing':
|
|
190
|
+
case 'started':
|
|
191
|
+
case 'active':
|
|
192
|
+
return 'in_progress';
|
|
193
|
+
case 'completed':
|
|
194
|
+
case 'complete':
|
|
195
|
+
case 'done':
|
|
196
|
+
case 'finished':
|
|
197
|
+
return 'completed';
|
|
198
|
+
case 'cancelled':
|
|
199
|
+
case 'canceled':
|
|
200
|
+
case 'closed':
|
|
201
|
+
return 'cancelled';
|
|
202
|
+
case 'blocked':
|
|
203
|
+
case 'on-hold':
|
|
204
|
+
case 'on hold':
|
|
205
|
+
return 'blocked';
|
|
206
|
+
default:
|
|
207
|
+
return 'pending';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function firstString(v) {
|
|
211
|
+
return typeof v === 'string' && v.trim().length > 0 ? v : null;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=planStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planStore.js","sourceRoot":"","sources":["../../../src/cli/workspace/planStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* planStore + planTaskTools tests — ADR-0018 slice 3a acceptance.
|
|
3
|
+
*
|
|
4
|
+
* Covers: v1 envelope persistence, coexistence with council plan tasks
|
|
5
|
+
* (normalization done→completed, name→title alias, no id collisions, root
|
|
6
|
+
* pass-through), caps, corrupt-file safety, .bak backup, and the council
|
|
7
|
+
* writePlan round-trip preserving the v1 root fields.
|
|
8
|
+
*
|
|
9
|
+
* @since v1.43.0
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
12
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { createPlanTaskTools } from '../tools/planTaskTools.js';
|
|
16
|
+
import { createWorkspaceContext, createWorkspaceStubs } from './stubs.js';
|
|
17
|
+
let dir;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
dir = mkdtempSync(join(tmpdir(), 'zelari-plan-'));
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
rmSync(dir, { recursive: true, force: true });
|
|
23
|
+
});
|
|
24
|
+
function planPath() {
|
|
25
|
+
return join(dir, '.zelari', 'plan.json');
|
|
26
|
+
}
|
|
27
|
+
function readPlanJson() {
|
|
28
|
+
return JSON.parse(readFileSync(planPath(), 'utf8'));
|
|
29
|
+
}
|
|
30
|
+
function seedPlanJson(content) {
|
|
31
|
+
mkdirSync(join(dir, '.zelari'), { recursive: true });
|
|
32
|
+
writeFileSync(planPath(), JSON.stringify(content), 'utf8');
|
|
33
|
+
}
|
|
34
|
+
function toolCtx() {
|
|
35
|
+
return {
|
|
36
|
+
signal: new AbortController().signal,
|
|
37
|
+
cwd: dir,
|
|
38
|
+
audit: () => { },
|
|
39
|
+
sessionId: 'plan-store-test',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function makeTools(onTaskEvent) {
|
|
43
|
+
const tools = createPlanTaskTools({ projectRoot: dir, onTaskEvent });
|
|
44
|
+
return {
|
|
45
|
+
create: tools[0],
|
|
46
|
+
update: tools[1],
|
|
47
|
+
list: tools[2],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
describe('planStore / task_* tools (ADR-0018 3a)', () => {
|
|
51
|
+
it('task_create persists the v1 envelope and the per-task artifact', async () => {
|
|
52
|
+
const { create } = makeTools();
|
|
53
|
+
const res = await create.execute({ title: 'Extract RunCoordinator' }, toolCtx());
|
|
54
|
+
expect(res.ok).toBe(true);
|
|
55
|
+
if (!res.ok)
|
|
56
|
+
return;
|
|
57
|
+
expect(res.value.id).toBe('t1');
|
|
58
|
+
expect(res.value.task.status).toBe('pending');
|
|
59
|
+
const file = readPlanJson();
|
|
60
|
+
expect(file.schemaVersion).toBe(1);
|
|
61
|
+
expect(file.counter).toBe(1);
|
|
62
|
+
expect(file.tasks[0].id).toBe('t1');
|
|
63
|
+
expect(file.tasks[0].title).toBe('Extract RunCoordinator');
|
|
64
|
+
expect(file.tasks[0].name).toBe('Extract RunCoordinator'); // council alias
|
|
65
|
+
expect(existsSync(join(dir, '.zelari', 'plan-tasks', 't1.md'))).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('coexists with council tasks: normalization, no id collision, root pass-through', async () => {
|
|
68
|
+
seedPlanJson({
|
|
69
|
+
phases: [{ kind: 'phase', id: 'p1', name: 'P1', order: 1 }],
|
|
70
|
+
tasks: [
|
|
71
|
+
{
|
|
72
|
+
kind: 'task',
|
|
73
|
+
id: 'p1-foo-1',
|
|
74
|
+
name: 'Council task',
|
|
75
|
+
phaseId: 'p1',
|
|
76
|
+
status: 'done',
|
|
77
|
+
priority: 'high',
|
|
78
|
+
description: 'council extra field',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
milestones: [],
|
|
82
|
+
xCouncilMeta: 'keep-me',
|
|
83
|
+
});
|
|
84
|
+
const { create, list } = makeTools();
|
|
85
|
+
const l1 = await list.execute({}, toolCtx());
|
|
86
|
+
expect(l1.ok).toBe(true);
|
|
87
|
+
if (!l1.ok)
|
|
88
|
+
return;
|
|
89
|
+
expect(l1.value.tasks).toHaveLength(1);
|
|
90
|
+
expect(l1.value.tasks[0].title).toBe('Council task'); // name → title
|
|
91
|
+
expect(l1.value.tasks[0].status).toBe('completed'); // done → completed
|
|
92
|
+
expect(l1.value.done).toBe(1);
|
|
93
|
+
expect(l1.value.total).toBe(1);
|
|
94
|
+
const res = await create.execute({ title: 'Agent task', phaseId: 'p1' }, toolCtx());
|
|
95
|
+
expect(res.ok).toBe(true);
|
|
96
|
+
if (!res.ok)
|
|
97
|
+
return;
|
|
98
|
+
expect(res.value.id).toBe('t1'); // counter starts fresh, no collision with p1-foo-1
|
|
99
|
+
const file = readPlanJson();
|
|
100
|
+
expect(file.xCouncilMeta).toBe('keep-me'); // unknown root field preserved
|
|
101
|
+
expect(file.phases).toHaveLength(1);
|
|
102
|
+
const council = file.tasks.find((t) => t.id === 'p1-foo-1');
|
|
103
|
+
expect(council.name).toBe('Council task');
|
|
104
|
+
expect(council.description).toBe('council extra field'); // task pass-through
|
|
105
|
+
expect(council.status).toBe('completed'); // normalized on rewrite
|
|
106
|
+
});
|
|
107
|
+
it('task_update applies fields, appendNote, and errors PLAN_TASK_NOT_FOUND', async () => {
|
|
108
|
+
const { create, update } = makeTools();
|
|
109
|
+
const created = await create.execute({ title: 'Fix auth refresh' }, toolCtx());
|
|
110
|
+
expect(created.ok).toBe(true);
|
|
111
|
+
const up = await update.execute({ id: 't1', status: 'in_progress', priority: 'high' }, toolCtx());
|
|
112
|
+
expect(up.ok).toBe(true);
|
|
113
|
+
if (!up.ok)
|
|
114
|
+
return;
|
|
115
|
+
expect(up.value.task.status).toBe('in_progress');
|
|
116
|
+
expect(up.value.task.priority).toBe('high');
|
|
117
|
+
const up2 = await update.execute({ id: 't1', appendNote: 'wip on refresh token' }, toolCtx());
|
|
118
|
+
expect(up2.ok).toBe(true);
|
|
119
|
+
const up3 = await update.execute({ id: 't1', appendNote: 'second note' }, toolCtx());
|
|
120
|
+
expect(up3.ok).toBe(true);
|
|
121
|
+
if (!up3.ok)
|
|
122
|
+
return;
|
|
123
|
+
expect(String(up3.value.task.notes)).toContain('wip on refresh token');
|
|
124
|
+
expect(String(up3.value.task.notes)).toContain('second note');
|
|
125
|
+
const nf = await update.execute({ id: 't9', status: 'pending' }, toolCtx());
|
|
126
|
+
expect(nf.ok).toBe(false);
|
|
127
|
+
if (nf.ok)
|
|
128
|
+
return;
|
|
129
|
+
expect(nf.error).toContain('PLAN_TASK_NOT_FOUND');
|
|
130
|
+
});
|
|
131
|
+
it('task_list filters by status and phaseId', async () => {
|
|
132
|
+
const { create, update, list } = makeTools();
|
|
133
|
+
await create.execute({ title: 'A', phaseId: 'p1' }, toolCtx());
|
|
134
|
+
await create.execute({ title: 'B', phaseId: 'p2' }, toolCtx());
|
|
135
|
+
await update.execute({ id: 't1', status: 'completed' }, toolCtx());
|
|
136
|
+
const byStatus = await list.execute({ status: 'completed' }, toolCtx());
|
|
137
|
+
expect(byStatus.ok && byStatus.value.tasks.map((t) => t.id)).toEqual(['t1']);
|
|
138
|
+
const byPhase = await list.execute({ phaseId: 'p2' }, toolCtx());
|
|
139
|
+
expect(byPhase.ok && byPhase.value.tasks.map((t) => t.id)).toEqual(['t2']);
|
|
140
|
+
const all = await list.execute({}, toolCtx());
|
|
141
|
+
expect(all.ok && all.value.total).toBe(2);
|
|
142
|
+
expect(all.ok && all.value.done).toBe(1);
|
|
143
|
+
});
|
|
144
|
+
it('defensive caps: oversized title is truncated, 101st task rejected', async () => {
|
|
145
|
+
const { create } = makeTools();
|
|
146
|
+
// Bypassing zod (registry validates; execute is called directly here) —
|
|
147
|
+
// the store must still enforce the cap defensively.
|
|
148
|
+
const res = await create.execute({ title: 'x'.repeat(250) }, toolCtx());
|
|
149
|
+
expect(res.ok).toBe(true);
|
|
150
|
+
if (!res.ok)
|
|
151
|
+
return;
|
|
152
|
+
expect(res.value.task.title.length).toBe(200);
|
|
153
|
+
const tasks = Array.from({ length: 100 }, (_, i) => ({
|
|
154
|
+
kind: 'task',
|
|
155
|
+
id: `t${i + 1}`,
|
|
156
|
+
name: `bulk ${i + 1}`,
|
|
157
|
+
phaseId: 'p0',
|
|
158
|
+
status: 'pending',
|
|
159
|
+
}));
|
|
160
|
+
seedPlanJson({
|
|
161
|
+
schemaVersion: 1,
|
|
162
|
+
counter: 100,
|
|
163
|
+
tasks,
|
|
164
|
+
phases: [],
|
|
165
|
+
milestones: [],
|
|
166
|
+
});
|
|
167
|
+
const over = await create.execute({ title: 'one too many' }, toolCtx());
|
|
168
|
+
expect(over.ok).toBe(false);
|
|
169
|
+
if (over.ok)
|
|
170
|
+
return;
|
|
171
|
+
expect(over.error).toContain('PLAN_TOO_MANY_TASKS');
|
|
172
|
+
});
|
|
173
|
+
it('corrupt plan.json → PLAN_CORRUPT error and the file is left untouched', async () => {
|
|
174
|
+
mkdirSync(join(dir, '.zelari'), { recursive: true });
|
|
175
|
+
writeFileSync(planPath(), '{ broken json', 'utf8');
|
|
176
|
+
const { create, list } = makeTools();
|
|
177
|
+
const res = await create.execute({ title: 'X' }, toolCtx());
|
|
178
|
+
expect(res.ok).toBe(false);
|
|
179
|
+
if (res.ok)
|
|
180
|
+
return;
|
|
181
|
+
expect(res.error).toContain('PLAN_CORRUPT');
|
|
182
|
+
const ls = await list.execute({}, toolCtx());
|
|
183
|
+
expect(ls.ok).toBe(false);
|
|
184
|
+
expect(readFileSync(planPath(), 'utf8')).toBe('{ broken json'); // not overwritten
|
|
185
|
+
});
|
|
186
|
+
it('a second write keeps a .bak of the previous state', async () => {
|
|
187
|
+
const { create } = makeTools();
|
|
188
|
+
await create.execute({ title: 'first' }, toolCtx());
|
|
189
|
+
await create.execute({ title: 'second' }, toolCtx());
|
|
190
|
+
const bak = JSON.parse(readFileSync(`${planPath()}.bak`, 'utf8'));
|
|
191
|
+
expect(bak.tasks[0].title).toBe('first');
|
|
192
|
+
const cur = readPlanJson();
|
|
193
|
+
expect(cur.tasks).toHaveLength(2);
|
|
194
|
+
expect(cur.counter).toBe(2);
|
|
195
|
+
});
|
|
196
|
+
it('council writePlan round-trip preserves schemaVersion/counter (stub interop)', async () => {
|
|
197
|
+
seedPlanJson({
|
|
198
|
+
schemaVersion: 1,
|
|
199
|
+
counter: 3,
|
|
200
|
+
phases: [{ kind: 'phase', id: 'p1', name: 'P1', order: 1 }],
|
|
201
|
+
tasks: [
|
|
202
|
+
{
|
|
203
|
+
kind: 'task',
|
|
204
|
+
id: 't1',
|
|
205
|
+
name: 'Agent task',
|
|
206
|
+
title: 'Agent task',
|
|
207
|
+
phaseId: 'p1',
|
|
208
|
+
status: 'pending',
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
milestones: [],
|
|
212
|
+
});
|
|
213
|
+
const wsCtx = createWorkspaceContext(dir);
|
|
214
|
+
const updateTask = createWorkspaceStubs(wsCtx).find((s) => s.name === 'updateTask');
|
|
215
|
+
expect(updateTask).toBeTruthy();
|
|
216
|
+
const out = await updateTask.execute({ taskId: 't1', status: 'done' }, wsCtx);
|
|
217
|
+
expect(String(out)).toContain('t1');
|
|
218
|
+
const file = readPlanJson();
|
|
219
|
+
expect(file.schemaVersion).toBe(1); // ADR-0018 pass-through root fields
|
|
220
|
+
expect(file.counter).toBe(3);
|
|
221
|
+
expect(file.tasks[0].status).toBe('done'); // council writer vocabulary
|
|
222
|
+
expect(file.phases).toHaveLength(1);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
describe('task_* first-class events (ADR-0018 3b)', () => {
|
|
226
|
+
it('task_create emits task_update with the created payload', async () => {
|
|
227
|
+
const events = [];
|
|
228
|
+
const { create } = makeTools((e) => events.push(e));
|
|
229
|
+
const res = await create.execute({ title: 'Event slice', priority: 'high', phaseId: 'p9' }, toolCtx());
|
|
230
|
+
expect(res.ok).toBe(true);
|
|
231
|
+
expect(events).toEqual([
|
|
232
|
+
{
|
|
233
|
+
type: 'task_update',
|
|
234
|
+
source: 'workspace_plan',
|
|
235
|
+
task: {
|
|
236
|
+
id: 't1',
|
|
237
|
+
title: 'Event slice',
|
|
238
|
+
status: 'pending',
|
|
239
|
+
phaseId: 'p9',
|
|
240
|
+
priority: 'high',
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
]);
|
|
244
|
+
});
|
|
245
|
+
it('task_update emits task_update with the mutated status', async () => {
|
|
246
|
+
const events = [];
|
|
247
|
+
const { create, update } = makeTools((e) => events.push(e));
|
|
248
|
+
await create.execute({ title: 'A' }, toolCtx());
|
|
249
|
+
const res = await update.execute({ id: 't1', status: 'in_progress' }, toolCtx());
|
|
250
|
+
expect(res.ok).toBe(true);
|
|
251
|
+
const last = events[events.length - 1];
|
|
252
|
+
expect(last.type).toBe('task_update');
|
|
253
|
+
if (last.type !== 'task_update')
|
|
254
|
+
return;
|
|
255
|
+
expect(last.task.id).toBe('t1');
|
|
256
|
+
expect(last.task.status).toBe('in_progress');
|
|
257
|
+
});
|
|
258
|
+
it('task_list emits a FULL snapshot regardless of filters', async () => {
|
|
259
|
+
const events = [];
|
|
260
|
+
const { create, update, list } = makeTools((e) => events.push(e));
|
|
261
|
+
await create.execute({ title: 'One' }, toolCtx());
|
|
262
|
+
await create.execute({ title: 'Two' }, toolCtx());
|
|
263
|
+
await update.execute({ id: 't1', status: 'completed' }, toolCtx());
|
|
264
|
+
const res = await list.execute({ status: 'pending' }, toolCtx());
|
|
265
|
+
expect(res.ok).toBe(true);
|
|
266
|
+
if (!res.ok)
|
|
267
|
+
return;
|
|
268
|
+
expect(res.value.tasks).toHaveLength(1); // filtered view for the agent
|
|
269
|
+
const snap = events.find((e) => e.type === 'task_snapshot');
|
|
270
|
+
expect(snap).toBeDefined();
|
|
271
|
+
if (!snap || snap.type !== 'task_snapshot')
|
|
272
|
+
return;
|
|
273
|
+
expect(snap.tasks).toHaveLength(2); // full view for frontends
|
|
274
|
+
expect(snap.tasks.map((t) => `${t.id}:${t.status}`).sort()).toEqual([
|
|
275
|
+
't1:completed',
|
|
276
|
+
't2:pending',
|
|
277
|
+
]);
|
|
278
|
+
});
|
|
279
|
+
it('no events on tool errors; a throwing sink never breaks the tool', async () => {
|
|
280
|
+
const events = [];
|
|
281
|
+
const ok = makeTools((e) => events.push(e));
|
|
282
|
+
const bad = makeTools(() => {
|
|
283
|
+
throw new Error('sink exploded');
|
|
284
|
+
});
|
|
285
|
+
const missing = await ok.update.execute({ id: 'nope', status: 'pending' }, toolCtx());
|
|
286
|
+
expect(missing.ok).toBe(false);
|
|
287
|
+
expect(events).toHaveLength(0);
|
|
288
|
+
const res = await bad.create.execute({ title: 'Still works' }, toolCtx());
|
|
289
|
+
expect(res.ok).toBe(true);
|
|
290
|
+
if (!res.ok)
|
|
291
|
+
return;
|
|
292
|
+
expect(res.value.id).toBe('t1');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
//# sourceMappingURL=planStore.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planStore.test.js","sourceRoot":"","sources":["../../../src/cli/workspace/planStore.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,10 +46,14 @@ function readPlan(ctx) {
|
|
|
46
46
|
if (existsSync(jsonPath)) {
|
|
47
47
|
try {
|
|
48
48
|
const parsed = JSON.parse(readFileSync(jsonPath, "utf8"));
|
|
49
|
+
// ADR-0018: keep unknown root fields (schemaVersion/counter/…) so the
|
|
50
|
+
// next writePlan round-trips them for the task_* tool store.
|
|
51
|
+
const { phases, tasks, milestones, ...root } = parsed;
|
|
49
52
|
return {
|
|
50
|
-
phases: Array.isArray(
|
|
51
|
-
tasks: Array.isArray(
|
|
52
|
-
milestones: Array.isArray(
|
|
53
|
+
phases: Array.isArray(phases) ? phases : [],
|
|
54
|
+
tasks: Array.isArray(tasks) ? tasks : [],
|
|
55
|
+
milestones: Array.isArray(milestones) ? milestones : [],
|
|
56
|
+
root,
|
|
53
57
|
};
|
|
54
58
|
}
|
|
55
59
|
catch {
|
|
@@ -79,7 +83,13 @@ function writePlan(ctx, summary) {
|
|
|
79
83
|
const jsonPath = planJsonPath(ctx);
|
|
80
84
|
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
81
85
|
const tmp = jsonPath + ".tmp-" + process.pid;
|
|
82
|
-
|
|
86
|
+
// ADR-0018: spread pass-through root fields first; canonical arrays win.
|
|
87
|
+
writeFileSync(tmp, JSON.stringify({
|
|
88
|
+
...(summary.root ?? {}),
|
|
89
|
+
phases: summary.phases,
|
|
90
|
+
tasks: summary.tasks,
|
|
91
|
+
milestones: summary.milestones,
|
|
92
|
+
}, null, 2), "utf8");
|
|
83
93
|
renameSync(tmp, jsonPath);
|
|
84
94
|
const mdPath = workspaceFile(ctx.rootDir, "plan");
|
|
85
95
|
const summaryMeta = {
|