wezard 2.6.1 → 2.6.3

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.
Files changed (73) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/config.example.jsonc +3 -1
  3. package/dist/daemon/answer-transfer.js +56 -0
  4. package/dist/daemon/answer-transfer.js.map +1 -0
  5. package/dist/daemon/approval.js +1 -1
  6. package/dist/daemon/approval.js.map +1 -1
  7. package/dist/daemon/cfg-sync.js +1 -1
  8. package/dist/daemon/cfg-sync.js.map +1 -1
  9. package/dist/daemon/chat-name.js +4 -4
  10. package/dist/daemon/chat-name.js.map +1 -1
  11. package/dist/daemon/config-api.js +2 -2
  12. package/dist/daemon/config-api.js.map +1 -1
  13. package/dist/daemon/image-input.js +34 -0
  14. package/dist/daemon/image-input.js.map +1 -0
  15. package/dist/daemon/inbound.js +4 -11
  16. package/dist/daemon/inbound.js.map +1 -1
  17. package/dist/daemon/index.js +880 -280
  18. package/dist/daemon/index.js.map +1 -1
  19. package/dist/daemon/jobs.js +32 -13
  20. package/dist/daemon/jobs.js.map +1 -1
  21. package/dist/daemon/last-response.js +16 -6
  22. package/dist/daemon/last-response.js.map +1 -1
  23. package/dist/daemon/message-format.js +40 -0
  24. package/dist/daemon/message-format.js.map +1 -0
  25. package/dist/daemon/mirror-bridge.js +673 -295
  26. package/dist/daemon/mirror-bridge.js.map +1 -1
  27. package/dist/daemon/pane-input.js +48 -0
  28. package/dist/daemon/pane-input.js.map +1 -0
  29. package/dist/daemon/peers.js +15 -14
  30. package/dist/daemon/peers.js.map +1 -1
  31. package/dist/daemon/pending-items.js +8 -0
  32. package/dist/daemon/pending-items.js.map +1 -1
  33. package/dist/daemon/receipts.js +346 -120
  34. package/dist/daemon/receipts.js.map +1 -1
  35. package/dist/daemon/scheduled-delivery.js +52 -0
  36. package/dist/daemon/scheduled-delivery.js.map +1 -0
  37. package/dist/daemon/spawn-tmux.js +7 -2
  38. package/dist/daemon/spawn-tmux.js.map +1 -1
  39. package/dist/daemon/steward-model.js +10 -10
  40. package/dist/daemon/steward-model.js.map +1 -1
  41. package/dist/daemon/tasks.js +83 -27
  42. package/dist/daemon/tasks.js.map +1 -1
  43. package/dist/daemon/tmux-buffer.js +44 -9
  44. package/dist/daemon/tmux-buffer.js.map +1 -1
  45. package/dist/daemon/weixin-cmd.js +2 -4
  46. package/dist/daemon/weixin-cmd.js.map +1 -1
  47. package/dist/daemon/wizard.js +2 -1
  48. package/dist/daemon/wizard.js.map +1 -1
  49. package/dist/daemon/workflow-nodes.js +217 -0
  50. package/dist/daemon/workflow-nodes.js.map +1 -0
  51. package/dist/daemon/workflow-plan-http.js +83 -0
  52. package/dist/daemon/workflow-plan-http.js.map +1 -0
  53. package/dist/daemon/workflow-plans.js +274 -0
  54. package/dist/daemon/workflow-plans.js.map +1 -0
  55. package/dist/mcp/server.js +27 -1
  56. package/dist/mcp/server.js.map +1 -1
  57. package/dist/shared/config.js +12 -10
  58. package/dist/shared/config.js.map +1 -1
  59. package/dist/shared/json-map-store.js +46 -9
  60. package/dist/shared/json-map-store.js.map +1 -1
  61. package/dist/shared/keyed-scheduler.js +51 -0
  62. package/dist/shared/keyed-scheduler.js.map +1 -0
  63. package/dist/shared/message-footer.js +34 -0
  64. package/dist/shared/message-footer.js.map +1 -0
  65. package/dist/shared/model-tiers.js +1 -2
  66. package/dist/shared/model-tiers.js.map +1 -1
  67. package/dist/shared/reminder.js +3 -0
  68. package/dist/shared/reminder.js.map +1 -1
  69. package/dist/shared/session-label.js +19 -1
  70. package/dist/shared/session-label.js.map +1 -1
  71. package/dist/shared/workflow-plan.js +36 -0
  72. package/dist/shared/workflow-plan.js.map +1 -0
  73. package/package.json +1 -1
@@ -0,0 +1,217 @@
1
+ // Opt-in execution history. Receipt completion and acceptance are separate facts.
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, openSync, fsyncSync, closeSync } from "node:fs";
4
+ import { dirname, isAbsolute, resolve } from "node:path";
5
+ import { parseClosing } from "./peers.js";
6
+ import { expandHome } from "../shared/paths.js";
7
+ export const resultDigest = (body) => createHash("sha256").update(body).digest("hex");
8
+ const fileDigest = (path) => createHash("sha256").update(readFileSync(path)).digest("hex");
9
+ const versionsMatch = (files) => files.every((f) => {
10
+ try {
11
+ return isAbsolute(f.path) && /^[a-f0-9]{64}$/.test(f.sha256) && fileDigest(f.path) === f.sha256 && (!f.snapshot || fileDigest(f.snapshot) === f.sha256);
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ });
17
+ export const createWorkflowNodes = (file) => {
18
+ const abs = resolve(expandHome(file));
19
+ // Corrupt/unwritable execution history must fail closed, unlike advisory stores.
20
+ let rows = existsSync(abs) ? JSON.parse(readFileSync(abs, "utf8")) : [];
21
+ if (!Array.isArray(rows) || rows.some((a) => ![a.id, a.node, a.owner, a.job, a.turn, a.to].every((s) => typeof s === "string" && s.length > 0)
22
+ || !Number.isFinite(a.at)
23
+ || (a.body !== undefined && typeof a.body !== "string")
24
+ || (a.digest !== undefined && (typeof a.digest !== "string" || typeof a.body !== "string" || a.digest !== resultDigest(a.body)))
25
+ || !["queued", "dispatching", "dispatch-unknown", "running", "needs-input", "errored", "terminal"].includes(a.execution)
26
+ || !["pending", "accepted", "rejected"].includes(a.acceptance)
27
+ || [a.stopped, a.exposed, a.canceled].some((v) => v !== undefined && typeof v !== "boolean")
28
+ || (a.status !== undefined && !["done", "need", "error", "timeout", "silent", "dead", "canceled"].includes(a.status))
29
+ || (a.acceptance === "accepted" && (a.execution !== "terminal" || a.status !== "done" || !a.body?.trim() || a.digest !== resultDigest(a.body)))
30
+ || (a.files !== undefined && (!Array.isArray(a.files) || a.files.some((f) => typeof f.path !== "string" || typeof f.sha256 !== "string" || (f.snapshot !== undefined && (typeof f.snapshot !== "string" || !isAbsolute(f.snapshot))))))
31
+ || (a.accountingVersion !== undefined && a.accountingVersion !== 1)
32
+ || (a.dispatches !== undefined && (!Array.isArray(a.dispatches) || a.dispatches.some((d) => typeof d.key !== "string" || !d.key || (d.tell && (d.tell.from !== a.owner || d.tell.to !== a.to || d.tell.turn !== a.turn)) || typeof d.text !== "string" || !Number.isFinite(d.at) || !["task", "ask"].includes(d.kind) || ([d.free, d.continuation].some((v) => v !== undefined && typeof v !== "boolean"))) || new Set(a.dispatches.map((d) => d.key)).size !== a.dispatches.length))
33
+ || (a.tell && (a.tell.from !== a.owner || a.tell.to !== a.to || a.tell.turn !== a.turn))))
34
+ throw new Error("invalid workflow node history");
35
+ if (new Set(rows.map((a) => a.id)).size !== rows.length || new Set(rows.map((a) => `${a.owner}\0${a.turn}`)).size !== rows.length)
36
+ throw new Error("duplicate workflow attempt identity");
37
+ const write = (next) => {
38
+ mkdirSync(dirname(abs), { recursive: true });
39
+ const tmp = `${abs}.${randomUUID()}.tmp`;
40
+ writeFileSync(tmp, JSON.stringify(next, null, 2), { mode: 0o600 });
41
+ const fd = openSync(tmp, "r");
42
+ try {
43
+ fsyncSync(fd);
44
+ }
45
+ finally {
46
+ closeSync(fd);
47
+ }
48
+ renameSync(tmp, abs);
49
+ const dir = openSync(dirname(abs), "r");
50
+ try {
51
+ fsyncSync(dir);
52
+ }
53
+ finally {
54
+ closeSync(dir);
55
+ }
56
+ rows = next;
57
+ };
58
+ const update = (id, change) => {
59
+ const old = rows.find((a) => a.id === id);
60
+ if (!old)
61
+ throw new Error("attempt not found");
62
+ const next = { ...old, ...change };
63
+ write(rows.map((a) => a.id === id ? next : a));
64
+ return structuredClone(next);
65
+ };
66
+ // A process death anywhere around injection leaves an uncertain attempt, never a retry.
67
+ if (rows.some((a) => a.execution === "dispatching"))
68
+ write(rows.map((a) => a.execution === "dispatching" ? { ...a, execution: "dispatch-unknown" } : a));
69
+ // First-slice records had optional file evidence and no snapshots. Keep their
70
+ // history, but require fresh validation rather than trusting an old accepted bit.
71
+ const legacy = rows.filter((a) => a.acceptance === "accepted" && (parseClosing(a.body ?? "").artifacts.some((f) => !(a.files ?? []).some((v) => v.path === f.path && v.snapshot))
72
+ || (a.files ?? []).some((f) => !f.snapshot)));
73
+ if (legacy.length)
74
+ write(rows.map((a) => legacy.some((b) => b.id === a.id) ? { ...a, acceptance: "pending", reason: "legacy file acceptance needs complete version evidence and snapshots" } : a));
75
+ const byTurn = (owner, turn) => rows.find((a) => a.owner === owner && a.turn === turn);
76
+ const begin = (owner, job, node, turn, to, queued) => {
77
+ const same = byTurn(owner, turn);
78
+ if (same) {
79
+ if (same.node !== node || same.job !== job || same.to !== to)
80
+ throw new Error("attempt identity mismatch");
81
+ if (!["queued", "running", "needs-input", "errored"].includes(same.execution))
82
+ throw new Error("attempt requires reconciliation before dispatch");
83
+ return structuredClone(same);
84
+ }
85
+ const prev = rows.filter((a) => a.owner === owner && a.job === job && a.node === node).at(-1);
86
+ if (prev && (!prev.stopped || prev.acceptance === "accepted"))
87
+ throw new Error("previous attempt may still execute; reconcile stopped before retry");
88
+ const busy = rows.find((a) => a.owner === owner && a.to === to && !["terminal", "queued"].includes(a.execution));
89
+ if (busy && !queued)
90
+ throw new Error("target already has a tracked execution");
91
+ const a = { id: `a${randomUUID()}`, node, owner, job, turn, to, at: Date.now(), execution: "queued", acceptance: "pending", accountingVersion: 1 };
92
+ write([...rows, a]);
93
+ return structuredClone(a);
94
+ };
95
+ return {
96
+ all: () => structuredClone(rows),
97
+ list: (owner, job) => structuredClone(rows.filter((a) => a.owner === owner && (!job || a.job === job))),
98
+ byTurn: (owner, turn) => { const a = byTurn(owner, turn); return a && structuredClone(a); },
99
+ begin,
100
+ cancel: (to, owner, job, turn, only = () => true) => {
101
+ const hit = rows.filter((a) => (!to || a.to === to) && (!owner || a.owner === owner) && (!job || a.job === job) && (!turn || a.turn === turn) && a.execution !== "terminal" && !a.canceled && only({ from: a.owner, turn: a.turn }));
102
+ if (hit.length)
103
+ write(rows.map((a) => hit.some((b) => b.id === a.id) ? { ...a, canceled: true, acceptance: "rejected", execution: a.exposed || a.execution === "dispatch-unknown" || ["running", "needs-input", "errored"].includes(a.execution) ? "dispatch-unknown" : "terminal", status: "canceled", stopped: !a.exposed && ["queued", "dispatching"].includes(a.execution), reason: "canceled; physical exposure requires stopped reconciliation" } : a));
104
+ return hit.length;
105
+ },
106
+ recordLeg: (id, data, reuse = false) => {
107
+ const a = rows.find((a) => a.id === id);
108
+ if (!a || a.canceled)
109
+ throw new Error("attempt not active");
110
+ const old = a.dispatches?.at(-1);
111
+ if (reuse && old) {
112
+ if (a.tell)
113
+ update(id, { tell: { ...a.tell, dispatchKey: old.key } });
114
+ return structuredClone(old);
115
+ }
116
+ const key = `${id}:${randomUUID()}`;
117
+ const leg = { ...data, key, ...(data.tell ? { tell: { ...data.tell, dispatchKey: key } } : {}) };
118
+ update(id, { accountingVersion: 1, dispatches: [...(a.dispatches ?? []), leg], ...(leg.tell ? { tell: leg.tell } : {}) });
119
+ return leg;
120
+ },
121
+ boundary: (id) => {
122
+ const a = rows.find((a) => a.id === id);
123
+ if (!a || a.canceled || a.execution !== "dispatching")
124
+ return false;
125
+ if (!a.exposed)
126
+ update(id, { exposed: true });
127
+ return true;
128
+ },
129
+ intent: (id, tell) => update(id, { execution: "dispatching", tell, status: undefined, body: undefined, digest: undefined, acceptance: "pending" }),
130
+ dispatched: (id, ok) => {
131
+ const a = rows.find((a) => a.id === id);
132
+ if (!a)
133
+ throw new Error("attempt not found");
134
+ return a.execution === "dispatching" ? update(id, { execution: ok ? "running" : "dispatch-unknown" }) : structuredClone(a);
135
+ },
136
+ outcome: (owner, turn, status, body) => {
137
+ const a = byTurn(owner, turn);
138
+ if (!a || a.execution === "terminal" || a.execution === "dispatch-unknown" || (["queued", "dispatching"].includes(a.execution) && status !== "canceled"))
139
+ return;
140
+ if (status === "canceled") {
141
+ const uncertain = !!a.exposed || ["running", "needs-input", "errored"].includes(a.execution);
142
+ update(a.id, { status, body, digest: resultDigest(body), canceled: true, acceptance: "rejected", execution: uncertain ? "dispatch-unknown" : "terminal", stopped: !uncertain });
143
+ return;
144
+ }
145
+ if (status === "done" && !body.trim()) {
146
+ update(a.id, { execution: "dispatch-unknown", acceptance: "pending", status: undefined, body: undefined, digest: undefined, reason: "receipt claimed without result body; reconcile from transcript" });
147
+ return;
148
+ }
149
+ update(a.id, { status, body, digest: resultDigest(body), acceptance: "pending", execution: status === "need" ? "needs-input" : status === "error" ? "errored" : "terminal" });
150
+ },
151
+ prereq: (owner, turn) => {
152
+ const a = byTurn(owner, turn);
153
+ if (!a)
154
+ return undefined;
155
+ const seen = { to: a.to, status: a.status ?? "canceled", body: a.body ?? "" };
156
+ if (a.canceled || a.acceptance === "rejected" || (a.execution === "terminal" && a.status !== "done"))
157
+ return { state: "failed", seen };
158
+ if (a.acceptance === "accepted")
159
+ return versionsMatch(a.files ?? []) ? { state: "done", seen } : { state: "failed", seen: { ...seen, status: "canceled", body: "accepted artifact version changed" } };
160
+ return { state: "pending" };
161
+ },
162
+ verdict: (owner, id, as, digest, reason, files = []) => {
163
+ const a = rows.find((a) => a.id === id && a.owner === owner);
164
+ if (!a)
165
+ throw new Error("attempt not found for owner");
166
+ if (!reason.trim())
167
+ throw new Error("evidence/reason required");
168
+ if (as === "sent") {
169
+ if (a.canceled || !["dispatch-unknown", "running"].includes(a.execution) || a.status || !a.tell)
170
+ throw new Error("only unknown dispatch can reconcile sent");
171
+ return update(id, { execution: "running", reason });
172
+ }
173
+ if (as === "stopped") {
174
+ if (a.acceptance === "accepted")
175
+ throw new Error("accepted attempt cannot be retried");
176
+ return update(id, { execution: "terminal", status: a.status ?? "canceled", stopped: true, acceptance: "rejected", reason });
177
+ }
178
+ if (a.execution !== "terminal" || a.status !== "done" || !a.digest || digest !== a.digest)
179
+ throw new Error("verdict requires terminal done and matching result digest");
180
+ if (a.acceptance !== "pending")
181
+ throw new Error("attempt already validated");
182
+ const declared = parseClosing(a.body ?? "").artifacts.map((f) => f.path);
183
+ if (as === "accepted" && declared.some((p) => !files.some((f) => f.path === p)))
184
+ throw new Error("every declared ARTIFACT requires files+sha256 evidence");
185
+ if (as === "accepted" && !versionsMatch(files))
186
+ throw new Error("artifact missing or sha256 mismatch");
187
+ const versions = as !== "accepted" ? files : files.map((f) => {
188
+ const data = readFileSync(f.path);
189
+ if (createHash("sha256").update(data).digest("hex") !== f.sha256)
190
+ throw new Error("artifact changed while snapshotting");
191
+ const snapshot = `${abs}.artifacts/${f.sha256}`;
192
+ mkdirSync(dirname(snapshot), { recursive: true });
193
+ if (!existsSync(snapshot))
194
+ writeFileSync(snapshot, data, { mode: 0o444, flag: "wx" });
195
+ if (fileDigest(snapshot) !== f.sha256)
196
+ throw new Error("snapshot corruption");
197
+ const fd = openSync(snapshot, "r");
198
+ try {
199
+ fsyncSync(fd);
200
+ }
201
+ finally {
202
+ closeSync(fd);
203
+ }
204
+ const parent = openSync(dirname(snapshot), "r");
205
+ try {
206
+ fsyncSync(parent);
207
+ }
208
+ finally {
209
+ closeSync(parent);
210
+ }
211
+ return { path: f.path, sha256: f.sha256, snapshot };
212
+ });
213
+ return update(id, { acceptance: as, reason, files: versions });
214
+ },
215
+ };
216
+ };
217
+ //# sourceMappingURL=workflow-nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-nodes.js","sourceRoot":"","sources":["../../daemon/workflow-nodes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { WorkflowPlanSchema } from "../shared/workflow-plan.js";
2
+ import { json } from "./http.js";
3
+ export const registerWorkflowPlanRoutes = (http, o) => {
4
+ const inputOf = (body) => {
5
+ if (!body || typeof body !== "object" || Array.isArray(body))
6
+ throw new Error("object required");
7
+ const { sessionId: _sid, tmuxPane: _pane, target: _target, ...input } = body;
8
+ return input;
9
+ };
10
+ http.register("POST /workflow/plans/create", async (req, res) => {
11
+ const { self, body } = await o.read(req);
12
+ if (!self) {
13
+ json(res, 400, { ok: false, reason: "cannot resolve caller" });
14
+ return;
15
+ }
16
+ let input;
17
+ try {
18
+ input = WorkflowPlanSchema.parse(inputOf(body));
19
+ }
20
+ catch (e) {
21
+ json(res, 400, { ok: false, reason: e.message });
22
+ return;
23
+ }
24
+ const existing = o.store.ofJob(input.job);
25
+ if (existing?.owner === self) {
26
+ json(res, 409, { ok: false, reason: "one immutable segment per job; existing plan unchanged", existingRun: existing.id, hint: "workflow_plan_status({run:existingRun}) recovers a lost create response; this request does not restart or update it" });
27
+ return;
28
+ }
29
+ const job = o.job(input.job);
30
+ if (!job || job.owner !== self || job.status !== "open") {
31
+ json(res, 409, { ok: false, reason: "plan requires your open job" });
32
+ return;
33
+ }
34
+ const origin = o.origin(self), denied = o.direction(self, job.id, origin);
35
+ if (denied) {
36
+ json(res, 409, { ok: false, reason: denied, gated: "direction" });
37
+ return;
38
+ }
39
+ try {
40
+ const run = o.store.create(self, input, origin, job, o.attempts(self, job.id), o.occupied(self, job.id));
41
+ o.runner.kick();
42
+ json(res, 200, { ok: true, run: o.runner.status(self, run.id), hint: "immutable segment; owner must explicitly accept every result via workflow_verdict. NEED/error/unknown require reconciliation, never automatic retry. Cancel blocks new work but does not kill executing panes." });
43
+ }
44
+ catch (e) {
45
+ json(res, 409, { ok: false, reason: e.message });
46
+ }
47
+ });
48
+ http.register("POST /workflow/plans/status", async (req, res) => {
49
+ const { self, body } = await o.read(req);
50
+ if (!self) {
51
+ json(res, 400, { ok: false, reason: "cannot resolve caller" });
52
+ return;
53
+ }
54
+ try {
55
+ const b = inputOf(body);
56
+ if (Object.keys(b).some((k) => k !== "run") || typeof b.run !== "string" || !b.run)
57
+ throw new Error("run required; unknown fields are not allowed");
58
+ const run = o.runner.status(self, b.run);
59
+ json(res, 200, { ok: true, run });
60
+ }
61
+ catch (e) {
62
+ json(res, 409, { ok: false, reason: e.message });
63
+ }
64
+ });
65
+ http.register("POST /workflow/plans/cancel", async (req, res) => {
66
+ const { self, body } = await o.read(req);
67
+ if (!self) {
68
+ json(res, 400, { ok: false, reason: "cannot resolve caller" });
69
+ return;
70
+ }
71
+ try {
72
+ const b = inputOf(body);
73
+ if (Object.keys(b).some((k) => !["run", "reason"].includes(k)) || typeof b.run !== "string" || typeof b.reason !== "string" || !b.reason.trim())
74
+ throw new Error("run and nonempty reason required; unknown fields are not allowed");
75
+ o.runner.cancel(self, b.run, b.reason.trim());
76
+ json(res, 200, { ok: true, run: o.runner.status(self, b.run) });
77
+ }
78
+ catch (e) {
79
+ json(res, 409, { ok: false, reason: e.message });
80
+ }
81
+ });
82
+ };
83
+ //# sourceMappingURL=workflow-plan-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-plan-http.js","sourceRoot":"","sources":["../../daemon/workflow-plan-http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,274 @@
1
+ import { baseOfKey, keyOf, normalizeTag } from "../shared/session-label.js";
2
+ import { randomUUID } from "node:crypto";
3
+ import { realpathSync, statSync } from "node:fs";
4
+ import { z } from "zod";
5
+ import { loadJsonMap } from "../shared/json-map-store.js";
6
+ import { WorkflowPlanSchema } from "../shared/workflow-plan.js";
7
+ const OriginSchema = z.object({
8
+ k: z.union([
9
+ z.object({ kind: z.literal("chat"), channel: z.string(), turn: z.string() }).strict(),
10
+ z.object({ kind: z.literal("peer"), from: z.string(), turn: z.string() }).strict(),
11
+ ]).optional(),
12
+ asker: z.object({ who: z.string(), chat: z.string() }).strict().optional(),
13
+ chain: z.array(z.string()),
14
+ }).strict();
15
+ const PhaseSchema = z.enum(["waiting", "spawning", "spawn-unknown", "spawned", "dispatching", "observing", "blocked"]);
16
+ const NodeStateSchema = z.object({
17
+ id: z.string(), turn: z.string().min(1), name: z.string().min(1), phase: PhaseSchema,
18
+ to: z.string().optional(), reason: z.string().optional(), birth: z.record(z.unknown()).optional(),
19
+ }).strict();
20
+ const RunSchema = z.object({
21
+ id: z.string().min(1), owner: z.string().min(1), plan: WorkflowPlanSchema,
22
+ origin: OriginSchema, at: z.number().finite(),
23
+ state: z.enum(["active", "completed", "failed", "canceled"]), reason: z.string().optional(),
24
+ nodes: z.array(NodeStateSchema),
25
+ }).strict();
26
+ export const loadWorkflowPlans = (file, prereq) => {
27
+ const db = loadJsonMap(file, undefined, { strict: true });
28
+ let healthy = true;
29
+ const all = () => structuredClone(Object.values(db.all()));
30
+ all().forEach((r) => {
31
+ RunSchema.parse(r);
32
+ if (r.nodes.length !== r.plan.nodes.length || r.nodes.some((n, i) => n.id !== r.plan.nodes[i]?.id)
33
+ || new Set(r.nodes.map((n) => n.turn)).size !== r.nodes.length
34
+ || new Set(r.nodes.map((n) => n.name)).size !== r.nodes.length
35
+ || r.nodes.some((n) => ["spawned", "dispatching", "observing"].includes(n.phase) && (!n.to || n.birth?.target !== n.to || n.birth?.name !== n.name)))
36
+ throw new Error("invalid workflow plan identities");
37
+ });
38
+ if (Object.entries(db.all()).some(([id, r]) => id !== r.id)
39
+ || new Set(all().flatMap((r) => r.nodes.map((n) => n.turn))).size !== all().reduce((sum, r) => sum + r.nodes.length, 0))
40
+ throw new Error("duplicate workflow plan run/turn identity");
41
+ if (new Set(all().map((r) => r.plan.job)).size !== all().length)
42
+ throw new Error("duplicate workflow plan job");
43
+ const write = (r) => {
44
+ try {
45
+ db.set(r.id, r);
46
+ }
47
+ catch (e) {
48
+ healthy = false;
49
+ throw e;
50
+ }
51
+ return structuredClone(r);
52
+ };
53
+ const get = (id) => { const r = db.get(id); return r && structuredClone(r); };
54
+ const change = (id, f) => {
55
+ const r = get(id);
56
+ if (!r)
57
+ throw new Error("workflow plan not found");
58
+ return write(f(r));
59
+ };
60
+ // A birth may exist even if its result was never committed. Do not create another.
61
+ all().filter((r) => r.nodes.some((n) => n.phase === "spawning")).forEach((r) => write({ ...r, nodes: r.nodes.map((n) => n.phase === "spawning" ? { ...n, phase: "spawn-unknown", reason: "spawn interrupted; reconcile executor by recorded name, then cancel this segment" } : n) }));
62
+ const ofJob = (job) => all().find((r) => r.plan.job === job);
63
+ // Reserve logical addresses before birth, and physical keys after reconciliation.
64
+ // Terminal runs retain their reservations: cancellation never frees a pane for
65
+ // untracked task injection or silently resurrects the segment.
66
+ const reservation = (target, name) => all().find((r) => r.nodes.some((n) => n.name === normalizeTag(name) || (!!target && (n.to === target || keyOf(baseOfKey(r.owner), n.name) === target))));
67
+ const owned = (owner, id) => {
68
+ const r = get(id);
69
+ if (!r || r.owner !== owner)
70
+ throw new Error("workflow plan not found for owner");
71
+ return r;
72
+ };
73
+ const permitted = (owner, job, p) => {
74
+ const r = ofJob(job);
75
+ return healthy && !!r && r.state === "active" && r.owner === owner && !!p && p.run === r.id
76
+ && r.nodes.some((n) => n.id === p.node && n.turn === p.turn) && p.alive();
77
+ };
78
+ return {
79
+ all, get, owned, ofJob, reservation, allowExternal: (target, name) => healthy && !reservation(target, name), healthy: () => healthy,
80
+ create: (owner, input, origin, job, attempts, occupied) => {
81
+ const plan = WorkflowPlanSchema.parse(input);
82
+ if (job.id !== plan.job || job.owner !== owner || job.status !== "open")
83
+ throw new Error("plan requires your open job");
84
+ if (ofJob(plan.job) || job.members.length || (job.turns ?? 0) || attempts.length || occupied)
85
+ throw new Error("plan requires a dedicated empty job; one immutable segment per job");
86
+ if (job.maxTurns && job.maxTurns < plan.nodes.length)
87
+ throw new Error("job budget cannot cover this plan");
88
+ if (!statSync(plan.cwd).isDirectory())
89
+ throw new Error("cwd must be a directory");
90
+ const id = `w${randomUUID().replace(/-/g, "")}`;
91
+ return write({ id, owner, plan: { ...plan, cwd: realpathSync(plan.cwd) }, origin: OriginSchema.parse(origin), at: Date.now(), state: "active",
92
+ nodes: plan.nodes.map((n, i) => ({ id: n.id, phase: "waiting", turn: `t${randomUUID().replace(/-/g, "")}`, name: `wf-${id.slice(1, 13)}-${i + 1}` })) });
93
+ },
94
+ node: (id, node, patch) => change(id, (r) => {
95
+ const old = r.nodes.find((n) => n.id === node);
96
+ if (!old)
97
+ throw new Error("plan node not found");
98
+ const moves = { waiting: ["spawning"], spawning: ["spawned", "spawn-unknown"], "spawn-unknown": [], spawned: ["dispatching"], dispatching: ["observing", "blocked"], observing: [], blocked: [] };
99
+ if (patch.phase && patch.phase !== old.phase && !moves[old.phase].includes(patch.phase))
100
+ throw new Error("illegal plan node transition");
101
+ const next = NodeStateSchema.parse({ ...old, ...patch });
102
+ if (["spawned", "dispatching", "observing"].includes(next.phase) && !next.to)
103
+ throw new Error("plan node requires executor identity");
104
+ return { ...r, nodes: r.nodes.map((n) => n.id === node ? next : n) };
105
+ }),
106
+ end: (id, state, reason) => change(id, (r) => r.state !== "active" ? r : { ...r, state, reason }),
107
+ allowSpawn: (owner, job, p, name, target) => {
108
+ const reserved = reservation(target, name);
109
+ const r = reserved ?? ofJob(job);
110
+ const node = p && r?.nodes.find((n) => n.id === p.node);
111
+ return !r || (r.plan.job === job && permitted(owner, job, p) && node?.phase === "spawning"
112
+ && (!name || normalizeTag(name) === node.name) && (!target || target === (node.to ?? keyOf(baseOfKey(r.owner), node.name))));
113
+ },
114
+ allowTell: (owner, job, node, target, re, p, name) => {
115
+ const r = reservation(target, name) ?? ofJob(job);
116
+ if (!r)
117
+ return true;
118
+ if (!healthy || r.state !== "active" || r.owner !== owner || r.plan.job !== job)
119
+ return false;
120
+ const n = r.nodes.find((n) => n.to === target && n.id === node);
121
+ const depsValid = (r.plan.nodes.find((x) => x.id === node)?.after ?? []).every((id) => prereq(owner, r.nodes.find((n) => n.id === id).turn)?.state === "done");
122
+ return !!n && depsValid && (p ? permitted(owner, job, p) && p.node === node && n.phase === "dispatching" : re === n.turn && n.phase === "observing");
123
+ },
124
+ };
125
+ };
126
+ export const createWorkflowPlanRunner = (store, d) => {
127
+ const locks = new Set();
128
+ const dirty = new Set();
129
+ let started = false;
130
+ const attemptOf = (r, n) => {
131
+ const a = d.attempt(r.owner, n.turn);
132
+ if (a && (a.node !== n.id || a.job !== r.plan.job || a.to !== n.to))
133
+ throw new Error("plan attempt identity mismatch");
134
+ return a;
135
+ };
136
+ const prereqOf = (r, n) => {
137
+ attemptOf(r, n);
138
+ return d.prereq(r.owner, n.turn);
139
+ };
140
+ const valid = (r, node) => (node.after ?? []).every((id) => {
141
+ const n = r.nodes.find((n) => n.id === id);
142
+ return prereqOf(r, n)?.state === "done";
143
+ });
144
+ const alive = (id, node) => {
145
+ const r = store.get(id);
146
+ return store.healthy() && started && !!r && r.state === "active" && d.job(r.plan.job)?.status === "open" && d.job(r.plan.job)?.owner === r.owner && valid(r, r.plan.nodes.find((n) => n.id === node));
147
+ };
148
+ const cancel = (owner, id, reason) => {
149
+ const old = store.owned(owner, id);
150
+ if (!["active", "canceled"].includes(old.state))
151
+ throw new Error("terminal workflow plan cannot be canceled or resumed");
152
+ const r = store.end(old.id, "canceled", reason);
153
+ d.cancel(r);
154
+ return r;
155
+ };
156
+ const advance = async (id) => {
157
+ if (!started || !store.healthy())
158
+ return;
159
+ if (locks.has(id)) {
160
+ dirty.add(id);
161
+ return;
162
+ }
163
+ locks.add(id);
164
+ try {
165
+ let r = store.get(id);
166
+ if (!r || r.state !== "active")
167
+ return;
168
+ const job = d.job(r.plan.job);
169
+ if (job?.status !== "open" || job.owner !== r.owner) {
170
+ cancel(r.owner, r.id, "job closed or unavailable");
171
+ return;
172
+ }
173
+ const failed = r.nodes.find((n) => prereqOf(r, n)?.state === "failed");
174
+ if (failed) {
175
+ store.end(id, "failed", `node ${failed.id} failed/rejected or artifact version changed`);
176
+ return;
177
+ }
178
+ if (r.nodes.every((n) => prereqOf(r, n)?.state === "done")) {
179
+ store.end(id, "completed", "all nodes explicitly accepted with valid versions");
180
+ return;
181
+ }
182
+ // Reconcile a crash between tell completion and writing the plan pointer.
183
+ for (const n of r.nodes.filter((n) => n.phase === "dispatching")) {
184
+ const a = attemptOf(r, n);
185
+ r = store.node(id, n.id, { phase: a ? "observing" : "blocked", ...(a ? {} : { reason: "dispatch intent has no attempt; no automatic replay" }) });
186
+ }
187
+ const pending = r.nodes.filter((n) => prereqOf(r, n)?.state !== "done");
188
+ if (pending.some((n) => !["waiting", "spawned"].includes(n.phase)))
189
+ return;
190
+ const state = pending.find((n) => valid(r, r.plan.nodes.find((x) => x.id === n.id)));
191
+ if (!state)
192
+ return;
193
+ const node = r.plan.nodes.find((n) => n.id === state.id);
194
+ if (job.maxTurns && (job.turns ?? 0) >= job.maxTurns) {
195
+ store.end(id, "failed", "job dispatch budget exhausted before spawn");
196
+ return;
197
+ }
198
+ const p = { run: id, node: node.id, turn: state.turn, origin: r.origin, alive: () => alive(id, node.id) };
199
+ if (state.phase === "waiting") {
200
+ r = store.node(id, node.id, { phase: "spawning" });
201
+ const born = await d.spawn(r, node, r.nodes.find((n) => n.id === node.id), p);
202
+ if (born.status !== 200 || typeof born.body.target !== "string" || !born.body.target || born.body.dispatched !== false
203
+ || born.body.inherited !== false || born.body.keepalive !== false || born.body.cwd !== r.plan.cwd || born.body.name !== state.name) {
204
+ store.node(id, node.id, { phase: "spawn-unknown", reason: String(born.body.reason ?? "executor creation unconfirmed"), birth: born.body });
205
+ return;
206
+ }
207
+ // Even after cancellation, retain the executor identity for operator cleanup.
208
+ r = store.node(id, node.id, { phase: "spawned", to: born.body.target, birth: born.body });
209
+ if (!p.alive())
210
+ return;
211
+ }
212
+ if (!p.alive())
213
+ return;
214
+ const current = store.get(id).nodes.find((n) => n.id === node.id);
215
+ r = store.node(id, node.id, { phase: "dispatching" });
216
+ const after = (node.after ?? []).map((dep) => r.nodes.find((n) => n.id === dep).turn);
217
+ const sent = await d.tell(r, node, current, after, p);
218
+ const a = attemptOf(r, current);
219
+ store.node(id, node.id, { phase: a ? "observing" : "blocked", ...(sent.status === 200 ? {} : { reason: String(sent.body.reason ?? "dispatch unconfirmed") }) });
220
+ // Completion/version failure can happen during transport before its response.
221
+ // Reconcile once after dropping the lock; never re-enter a dispatched node.
222
+ dirty.add(id);
223
+ }
224
+ catch (e) {
225
+ d.error(e);
226
+ const r = store.get(id);
227
+ if (store.healthy() && r?.state === "active") {
228
+ const n = r.nodes.find((n) => ["spawning", "dispatching"].includes(n.phase));
229
+ if (n) {
230
+ try {
231
+ store.node(id, n.id, { phase: n.phase === "spawning" ? "spawn-unknown" : d.attempt(r.owner, n.turn) ? "observing" : "blocked", reason: String(e) });
232
+ }
233
+ catch (failure) {
234
+ d.error(failure);
235
+ }
236
+ }
237
+ }
238
+ }
239
+ finally {
240
+ locks.delete(id);
241
+ if (dirty.delete(id))
242
+ queueMicrotask(() => { void advance(id); });
243
+ }
244
+ };
245
+ const kick = () => { if (started)
246
+ store.all().filter((r) => r.state === "active").forEach((r) => { void advance(r.id); }); };
247
+ const status = (owner, id) => {
248
+ const r = store.owned(owner, id);
249
+ const nodes = r.nodes.map((n) => {
250
+ const a = attemptOf(r, n), prereq = prereqOf(r, n);
251
+ const state = r.state === "canceled" ? "canceled" : prereq?.state === "failed" ? "failed"
252
+ : prereq?.state === "done" ? "succeeded" : a ? a.execution === "terminal" && a.status === "done" ? "validating" : a.execution
253
+ : n.phase === "waiting" ? r.state === "failed" ? "skipped" : valid(r, r.plan.nodes.find((x) => x.id === n.id)) ? "ready" : "pending" : n.phase;
254
+ return { ...n, state, ...(a ? { attempt: a } : {}), ...(r.state === "canceled" && a ? { physicalStopConfirmed: !!a.stopped } : {}) };
255
+ });
256
+ const versionsValid = r.nodes.every((n) => prereqOf(r, n)?.state === "done");
257
+ return { ...r, state: r.state === "completed" && !versionsValid ? "invalidated" : r.state, recordedState: r.state, nodes, versionsValid, storageHealthy: store.healthy() };
258
+ };
259
+ return { kick, status, cancel, start: () => {
260
+ // Cancellation is committed before touching other stores. Finish a partial
261
+ // cancellation after restart without reopening the run or replaying tasks.
262
+ store.all().filter((r) => r.state === "canceled").forEach((r) => { try {
263
+ d.cancel(r);
264
+ }
265
+ catch (e) {
266
+ d.error(e);
267
+ } });
268
+ started = true;
269
+ kick();
270
+ }, stop: () => { started = false; },
271
+ cancelJob: (owner, job) => { const r = store.ofJob(job); if (r?.owner === owner && r.state === "active")
272
+ cancel(owner, r.id, "job closed"); } };
273
+ };
274
+ //# sourceMappingURL=workflow-plans.js.map