@iowarp/clio-coder 0.3.6 → 0.3.7

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 (258) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +16 -5
  3. package/dist/{acp-2BEHC4DL.js → acp-SK4MD6MM.js} +10 -10
  4. package/dist/{agents-LNNFTM53.js → agents-2FN2K6ME.js} +30 -25
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-KXXFI2VS.js → auth-QIYZWM5I.js} +13 -13
  7. package/dist/{chunk-KHSFENX2.js → chunk-3HAPLH5M.js} +10 -10
  8. package/dist/{chunk-24I7BN55.js → chunk-465YSENW.js} +2 -2
  9. package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
  10. package/dist/{chunk-CYQKWTG3.js → chunk-4DWFMQDR.js} +4 -4
  11. package/dist/{chunk-E2ER4LJF.js → chunk-5C3AQNDW.js} +25 -1
  12. package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
  13. package/dist/{chunk-43AOLP7E.js → chunk-5FR74PWO.js} +2 -1
  14. package/dist/{chunk-K7T3E2SR.js → chunk-5UJ6ECTS.js} +10 -9
  15. package/dist/{chunk-6US73PDB.js → chunk-6M7VS3J3.js} +5 -5
  16. package/dist/{chunk-CJUB2JJ2.js → chunk-6TUKSZVF.js} +5 -5
  17. package/dist/{chunk-5JGRAMKL.js → chunk-AB4XIIVB.js} +8 -6
  18. package/dist/{chunk-R46L2BIR.js → chunk-BMWK7ZIZ.js} +14 -20
  19. package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
  20. package/dist/{chunk-XXQNGV4M.js → chunk-CEYBNUGC.js} +243 -63
  21. package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
  22. package/dist/chunk-DJNLUABN.js +843 -0
  23. package/dist/{chunk-RY3LY4J5.js → chunk-DMD2AGVS.js} +5 -4
  24. package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
  25. package/dist/chunk-DQA7QLMD.js +123 -0
  26. package/dist/chunk-DR52UMZW.js +21 -0
  27. package/dist/{chunk-XF5N4U5A.js → chunk-EBEFWSGL.js} +6 -5
  28. package/dist/{chunk-EYPA3EGJ.js → chunk-EELBMBT6.js} +120 -13
  29. package/dist/{chunk-CKXWIANG.js → chunk-EOOQZZDE.js} +16 -14
  30. package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
  31. package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
  32. package/dist/chunk-GWS3VEIW.js +195 -0
  33. package/dist/{chunk-LYF7OHWH.js → chunk-J7PIKKWC.js} +8 -463
  34. package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
  35. package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
  36. package/dist/{chunk-6XXKFVSN.js → chunk-JTSEDYVQ.js} +7 -7
  37. package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
  38. package/dist/chunk-KZ2H5X4G.js +1026 -0
  39. package/dist/{chunk-QNQHSOLF.js → chunk-LADCF22A.js} +12 -12
  40. package/dist/chunk-M4AKACEO.js +382 -0
  41. package/dist/{chunk-XYDYPRZI.js → chunk-MXI6J5JF.js} +7 -7
  42. package/dist/{chunk-G7MUEIGA.js → chunk-OB5HIGJY.js} +1 -1
  43. package/dist/{chunk-EKY57CSP.js → chunk-OBMAI2DP.js} +61 -767
  44. package/dist/chunk-PD3MESLB.js +242 -0
  45. package/dist/{chunk-ZRGEBJ4T.js → chunk-QCTRSGHQ.js} +21 -21
  46. package/dist/chunk-RVG5JXAL.js +41 -0
  47. package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
  48. package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
  49. package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
  50. package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
  51. package/dist/chunk-UND3GU2L.js +103 -0
  52. package/dist/{chunk-QM3F2GKX.js → chunk-UUANF5CR.js} +2247 -2096
  53. package/dist/chunk-UVDSQ6LW.js +472 -0
  54. package/dist/{chunk-DJVECN66.js → chunk-VQNODYQ4.js} +14 -14
  55. package/dist/{chunk-3BPUFZDL.js → chunk-VREKEFLL.js} +3 -3
  56. package/dist/{chunk-PBTHKCPN.js → chunk-WJHBC77E.js} +6 -6
  57. package/dist/{chunk-XE2VEJHX.js → chunk-X2KV5FXT.js} +2 -2
  58. package/dist/{chunk-ZXF4XRKW.js → chunk-XEGB6BCN.js} +157 -7
  59. package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
  60. package/dist/{verifiers-NCBTHHN2.js → chunk-YTYFXUI3.js} +65 -322
  61. package/dist/{chunk-OH3TOQTB.js → chunk-ZGH7FGS5.js} +13 -7
  62. package/dist/cli/index.js +32 -30
  63. package/dist/{clio-M2KGYUFZ.js → clio-WBVQEBKO.js} +7 -7
  64. package/dist/{code-nav-GQNL7XA6.js → code-nav-FGGFIE7L.js} +3 -3
  65. package/dist/{components-5TTYYX6G.js → components-F7OEATSO.js} +4 -4
  66. package/dist/{config-XUUYQIWO.js → config-TRBL3RCF.js} +34 -29
  67. package/dist/{configure-IHJ7YOMV.js → configure-OLCVPHNM.js} +15 -15
  68. package/dist/{context-74JLXAWD.js → context-MJIJ6GOX.js} +11 -11
  69. package/dist/{context-ZQ7SIFJV.js → context-WFPKQSM6.js} +19 -3
  70. package/dist/{context-75MIWW3U.js → context-XEWE3MOJ.js} +31 -26
  71. package/dist/{context-clear-GYKWNUML.js → context-clear-KNOS2JPB.js} +31 -26
  72. package/dist/{context-working-set-UX5KEP4J.js → context-working-set-EUXAZI6N.js} +8 -8
  73. package/dist/{dispatch-runner-GIJBHNFL.js → dispatch-runner-B7MTOVKL.js} +313 -53
  74. package/dist/{docs-6FZSCG5B.js → docs-FLJTIDSE.js} +4 -4
  75. package/dist/{doctor-SVJ5BZCW.js → doctor-RN4YKO2X.js} +14 -14
  76. package/dist/{eval-CG6LLBLD.js → eval-RUBJVSNQ.js} +8 -7
  77. package/dist/{evidence-ZYFIEN42.js → evidence-JZNBUOQZ.js} +30 -25
  78. package/dist/{evolve-QGEXEMDW.js → evolve-FJVC4KKI.js} +30 -25
  79. package/dist/{extensions-ADGNCJJD.js → extensions-IQL36S7K.js} +4 -4
  80. package/dist/{fleet-S5R4ZOQY.js → fleet-BDKYJFCP.js} +214 -360
  81. package/dist/fleet-commands-ZFIWZSB3.js +70 -0
  82. package/dist/fleet-graph-Y6HPXIVF.js +125 -0
  83. package/dist/fleet-new-RDVJLHHH.js +48 -0
  84. package/dist/fleet-validate-BIYREGIK.js +79 -0
  85. package/dist/{init-5DRU55YR.js → init-LQUB5COQ.js} +44 -37
  86. package/dist/library-NJAHIGG4.js +217 -0
  87. package/dist/{memory-7YKKR6UC.js → memory-OG6HOYKM.js} +31 -26
  88. package/dist/{models-ZPOLRU2C.js → models-5ZG5XY7J.js} +21 -20
  89. package/dist/{monitor-US5F5YGZ.js → monitor-TJ7AMTGB.js} +49 -30
  90. package/dist/{orchestrator-E2AL4T5N.js → orchestrator-WZYB54DM.js} +3827 -581
  91. package/dist/{paths-E7KYAQWE.js → paths-XUC7GS6E.js} +4 -4
  92. package/dist/{reset-KZ652EK6.js → reset-PXQT45IY.js} +7 -7
  93. package/dist/{run-SRNBKDWD.js → run-FQ74YF62.js} +53 -45
  94. package/dist/{share-CGZE33UP.js → share-FW7SVCL3.js} +33 -9
  95. package/dist/{skills-S2X4DLY5.js → skills-7E7IRB3R.js} +24 -8
  96. package/dist/{skills-eval-W2GGIC4R.js → skills-eval-LI75W6OK.js} +34 -27
  97. package/dist/{targets-54SWINWB.js → targets-4CIFKCTW.js} +23 -22
  98. package/dist/{terminal-lease-SAIF2OGY.js → terminal-lease-WUZY7ZV5.js} +4 -4
  99. package/dist/{uninstall-BVLWXKBT.js → uninstall-7FV7IP4E.js} +4 -4
  100. package/dist/{upgrade-JKAR27XC.js → upgrade-K2HVIVMQ.js} +20 -19
  101. package/dist/{usage-MSAWCLX4.js → usage-GTZELZQX.js} +116 -49
  102. package/dist/verifiers-RLAHT27O.js +336 -0
  103. package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
  104. package/dist/{wiki-generate-GUSOQ6ZP.js → wiki-generate-ASIFASCN.js} +45 -37
  105. package/dist/worker/entry.js +38 -35
  106. package/docs/README.md +3 -2
  107. package/docs/acp.md +1 -1
  108. package/docs/alcf-provider.md +1 -1
  109. package/docs/architecture.md +2 -2
  110. package/docs/artifact-versions.md +10 -6
  111. package/docs/built-in-agents.md +26 -2
  112. package/docs/capacity-and-scheduling.md +1 -1
  113. package/docs/commands-and-modes.md +82 -2
  114. package/docs/configuration-and-targets.md +79 -2
  115. package/docs/context-engine.md +1 -1
  116. package/docs/development-pipeline.md +1 -1
  117. package/docs/dispatch-architecture-rationale.md +1 -1
  118. package/docs/documentation-coverage.md +3 -3
  119. package/docs/documentation-guide.md +3 -3
  120. package/docs/eval-runner.md +1 -1
  121. package/docs/evals-internal.md +1 -1
  122. package/docs/evidence-and-memory.md +5 -5
  123. package/docs/evolution.md +1 -1
  124. package/docs/exit-codes-and-output.md +4 -1
  125. package/docs/extensions-and-sharing.md +6 -2
  126. package/docs/fleet-demo-runbook.md +2 -2
  127. package/docs/fleet-dispatch.md +197 -10
  128. package/docs/git-commit-provenance.md +2 -2
  129. package/docs/glossary.md +1 -1
  130. package/docs/installation-and-lifecycle.md +2 -2
  131. package/docs/middleware-and-components.md +2 -1
  132. package/docs/model-catalog.md +1 -1
  133. package/docs/observability.md +55 -8
  134. package/docs/proactive-memory.md +1 -1
  135. package/docs/prompt-envelope-and-tools.md +1 -1
  136. package/docs/provider-adapter-cookbook.md +1 -1
  137. package/docs/release-cut-checklist.md +79 -64
  138. package/docs/resource-library.md +59 -0
  139. package/docs/safety-model.md +2 -2
  140. package/docs/scientific-validation.md +3 -3
  141. package/docs/session-lifecycle.md +37 -1
  142. package/docs/skills-marketplace.md +16 -3
  143. package/docs/tool-usage.md +14 -7
  144. package/docs/trace-store.md +1 -1
  145. package/docs/troubleshooting.md +1 -1
  146. package/docs/tui-design.md +1 -1
  147. package/docs/worker-dispatch-mechanics.md +3 -3
  148. package/package.json +1 -1
  149. package/src/cli/fleet-commands.ts +37 -0
  150. package/src/cli/fleet-graph.ts +102 -0
  151. package/src/cli/fleet-new.ts +36 -0
  152. package/src/cli/fleet-preflight.ts +121 -0
  153. package/src/cli/fleet-validate.ts +30 -0
  154. package/src/cli/fleet.ts +173 -335
  155. package/src/cli/index.ts +3 -1
  156. package/src/cli/library.ts +190 -0
  157. package/src/cli/share.ts +13 -1
  158. package/src/cli/usage.ts +111 -19
  159. package/src/core/bus-events.ts +4 -0
  160. package/src/core/commit-attribution.ts +4 -4
  161. package/src/core/config.ts +130 -0
  162. package/src/core/defaults.ts +81 -0
  163. package/src/domains/agents/builtins/architect.md +1 -0
  164. package/src/domains/agents/builtins/oracle.md +33 -0
  165. package/src/domains/agents/catalog.ts +13 -1
  166. package/src/domains/agents/fleet-contract.ts +278 -16
  167. package/src/domains/agents/index.ts +14 -0
  168. package/src/domains/agents/result-contract.ts +235 -1
  169. package/src/domains/config/classify.ts +4 -0
  170. package/src/domains/dispatch/active-route-planner.ts +14 -0
  171. package/src/domains/dispatch/backoff.ts +2 -1
  172. package/src/domains/dispatch/capability-match.ts +1 -0
  173. package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
  174. package/src/domains/dispatch/contract.ts +34 -0
  175. package/src/domains/dispatch/delegation-plan.ts +167 -0
  176. package/src/domains/dispatch/execution-plan.ts +76 -5
  177. package/src/domains/dispatch/execution-role.ts +3 -1
  178. package/src/domains/dispatch/execution-scheduler.ts +183 -67
  179. package/src/domains/dispatch/extension.ts +258 -9
  180. package/src/domains/dispatch/fleet-gate.ts +14 -0
  181. package/src/domains/dispatch/fleet-plan.ts +63 -3
  182. package/src/domains/dispatch/fleet-run.ts +737 -0
  183. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  184. package/src/domains/dispatch/host-verification.ts +178 -0
  185. package/src/domains/dispatch/index.ts +38 -0
  186. package/src/domains/dispatch/intent.ts +159 -0
  187. package/src/domains/dispatch/receipt-integrity.ts +8 -4
  188. package/src/domains/dispatch/state.ts +36 -3
  189. package/src/domains/dispatch/types.ts +51 -6
  190. package/src/domains/dispatch/validation.ts +66 -6
  191. package/src/domains/evidence/trust-status.ts +10 -1
  192. package/src/domains/middleware/index.ts +15 -0
  193. package/src/domains/middleware/watchdog.ts +281 -0
  194. package/src/domains/observability/contract.ts +3 -1
  195. package/src/domains/observability/cost.ts +12 -1
  196. package/src/domains/observability/extension.ts +2 -2
  197. package/src/domains/observability/index.ts +10 -0
  198. package/src/domains/observability/out-of-turn-usage.ts +223 -0
  199. package/src/domains/resources/index.ts +20 -0
  200. package/src/domains/resources/library.ts +326 -0
  201. package/src/domains/resources/skills/marketplace.ts +37 -12
  202. package/src/domains/session/handoff.ts +629 -0
  203. package/src/domains/share/archive.ts +67 -2
  204. package/src/entry/orchestrator.ts +37 -0
  205. package/src/interactive/bus-notices.ts +26 -0
  206. package/src/interactive/chat-loop.ts +235 -1
  207. package/src/interactive/chat-renderer.ts +22 -0
  208. package/src/interactive/cost-overlay.ts +31 -3
  209. package/src/interactive/council-dispatch.ts +30 -0
  210. package/src/interactive/council-grid.ts +213 -0
  211. package/src/interactive/council.ts +99 -0
  212. package/src/interactive/dispatch-board.ts +260 -16
  213. package/src/interactive/fleet-run-preview.ts +307 -0
  214. package/src/interactive/footer/notifications.ts +219 -0
  215. package/src/interactive/handoff-round.ts +56 -0
  216. package/src/interactive/interactive-application.ts +43 -1
  217. package/src/interactive/interactive-event-projection.ts +9 -1
  218. package/src/interactive/interactive-slash-runtime.ts +52 -2
  219. package/src/interactive/interactive-subscriptions.ts +14 -2
  220. package/src/interactive/oracle.ts +179 -0
  221. package/src/interactive/overlay-ask-user-lifecycle.ts +6 -0
  222. package/src/interactive/overlay-general-openers.ts +190 -1
  223. package/src/interactive/overlay-key-routing.ts +17 -1
  224. package/src/interactive/overlay-lifecycle.ts +41 -1
  225. package/src/interactive/overlay-permission-lifecycle.ts +10 -0
  226. package/src/interactive/overlay-resource-openers.ts +11 -3
  227. package/src/interactive/overlay-session-lifecycle.ts +234 -2
  228. package/src/interactive/overlays/fleet-run-approval.ts +208 -0
  229. package/src/interactive/overlays/handoff-review.ts +185 -0
  230. package/src/interactive/overlays/library-install-confirm.ts +151 -0
  231. package/src/interactive/overlays/list-overlay.ts +168 -2
  232. package/src/interactive/overlays/settings.ts +101 -4
  233. package/src/interactive/overlays/side-question.ts +139 -0
  234. package/src/interactive/overlays/skills-hub.ts +401 -15
  235. package/src/interactive/side-question.ts +171 -0
  236. package/src/interactive/slash-commands.ts +432 -5
  237. package/src/interactive/slash-spec.ts +19 -6
  238. package/src/interactive/theme/tokens.ts +30 -0
  239. package/src/interactive/turn-middleware.ts +15 -1
  240. package/src/interactive/watchdog-run.ts +75 -0
  241. package/src/interactive/worker-share.ts +56 -1
  242. package/src/interactive/worker-stream.ts +7 -0
  243. package/src/tools/bootstrap.ts +3 -0
  244. package/src/tools/compete-worktrees.ts +13 -79
  245. package/src/tools/dispatch-admission.ts +242 -8
  246. package/src/tools/dispatch-arguments.ts +57 -1
  247. package/src/tools/dispatch-plan.ts +136 -6
  248. package/src/tools/dispatch-runner.ts +319 -13
  249. package/src/tools/dispatch-types.ts +20 -1
  250. package/src/tools/dispatch.ts +72 -2
  251. package/src/tools/monitor.ts +16 -0
  252. package/src/tools/profiles.ts +18 -4
  253. package/src/tools/task-worktree.ts +238 -0
  254. package/src/tools/verify/authoring.ts +61 -1
  255. package/src/tools/verify/scripts.ts +62 -0
  256. package/src/tools/worker-evidence.ts +2 -1
  257. package/src/worker/spec-contract.ts +1 -0
  258. package/dist/chunk-HC4CLZ2Y.js +0 -68
@@ -0,0 +1,167 @@
1
+ import { createHash } from "node:crypto";
2
+ import { normalizeWriteBoundary } from "../agents/write-boundary.js";
3
+
4
+ export type DelegationTaskMode = "sequential" | "parallel";
5
+
6
+ export interface DelegationPlanTask {
7
+ id: string;
8
+ agent: string;
9
+ description: string;
10
+ depends_on: ReadonlyArray<string>;
11
+ writes: ReadonlyArray<string>;
12
+ mode?: DelegationTaskMode;
13
+ }
14
+
15
+ export interface DelegationPlan {
16
+ tasks: ReadonlyArray<DelegationPlanTask>;
17
+ }
18
+
19
+ export type DelegationPlanReason =
20
+ | "delegation_plan_malformed"
21
+ | "delegation_plan_over_max_tasks"
22
+ | "delegation_plan_duplicate_id"
23
+ | "delegation_plan_roster_violation"
24
+ | "delegation_plan_dependency_unknown"
25
+ | "delegation_plan_dependency_cycle"
26
+ | "delegation_plan_writes_outside_boundary";
27
+
28
+ export type DelegationPlanValidation =
29
+ | { ok: true; plan: DelegationPlan; hash: string }
30
+ | { ok: false; reason: DelegationPlanReason; detail: string };
31
+
32
+ export interface ValidateDelegationPlanInput {
33
+ value: unknown;
34
+ roster: ReadonlyArray<string>;
35
+ maxTasks: number;
36
+ writes: ReadonlyArray<string>;
37
+ }
38
+
39
+ export const DELEGATION_PROPOSAL_BRIEFING_MAX_BYTES = 12_000;
40
+
41
+ export function buildDelegationProposalBriefing(proposals: ReadonlyArray<{ agent: string; output: string }>): string {
42
+ const value = proposals.map((proposal) => `PROPOSAL ${proposal.agent}\n${proposal.output}`).join("\n\n");
43
+ if (Buffer.byteLength(value, "utf8") <= DELEGATION_PROPOSAL_BRIEFING_MAX_BYTES) return value;
44
+ const suffix = "\n[truncated]";
45
+ const source = Buffer.from(value, "utf8");
46
+ let end = DELEGATION_PROPOSAL_BRIEFING_MAX_BYTES - Buffer.byteLength(suffix, "utf8");
47
+ while (end > 0) {
48
+ const byte = source[end];
49
+ if (byte === undefined || (byte & 0xc0) !== 0x80) break;
50
+ end -= 1;
51
+ }
52
+ return `${source.subarray(0, end).toString("utf8")}${suffix}`;
53
+ }
54
+
55
+ const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
56
+
57
+ function insideBoundary(path: string, boundary: ReadonlyArray<string>): boolean {
58
+ return boundary.some((root) => (root.endsWith("/") ? path.startsWith(root) : path === root));
59
+ }
60
+
61
+ function malformed(detail: string): DelegationPlanValidation {
62
+ return { ok: false, reason: "delegation_plan_malformed", detail };
63
+ }
64
+
65
+ export function validateDelegationPlan(input: ValidateDelegationPlanInput): DelegationPlanValidation {
66
+ if (input.value === null || typeof input.value !== "object" || Array.isArray(input.value)) {
67
+ return malformed("delegation plan must be an object");
68
+ }
69
+ const record = input.value as Record<string, unknown>;
70
+ if (Object.keys(record).some((key) => key !== "tasks") || !Array.isArray(record.tasks)) {
71
+ return malformed("delegation plan must carry only tasks[]");
72
+ }
73
+ if (record.tasks.length === 0) return malformed("delegation plan must carry at least one task");
74
+ if (record.tasks.length > input.maxTasks) {
75
+ return {
76
+ ok: false,
77
+ reason: "delegation_plan_over_max_tasks",
78
+ detail: `delegation plan returned ${record.tasks.length} tasks, above maxTasks ${input.maxTasks}`,
79
+ };
80
+ }
81
+ const roster = new Set(input.roster);
82
+ const ids = new Set<string>();
83
+ const tasks: DelegationPlanTask[] = [];
84
+ for (const raw of record.tasks) {
85
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return malformed("every task must be an object");
86
+ const task = raw as Record<string, unknown>;
87
+ if (
88
+ Object.keys(task).some((key) => !["id", "agent", "description", "depends_on", "writes", "mode"].includes(key)) ||
89
+ typeof task.id !== "string" ||
90
+ !ID_RE.test(task.id) ||
91
+ typeof task.agent !== "string" ||
92
+ task.agent.length === 0 ||
93
+ typeof task.description !== "string" ||
94
+ task.description.trim().length === 0 ||
95
+ !Array.isArray(task.depends_on) ||
96
+ task.depends_on.some((value) => typeof value !== "string" || value.length === 0) ||
97
+ !Array.isArray(task.writes) ||
98
+ task.writes.some((value) => typeof value !== "string" || value.length === 0) ||
99
+ (task.mode !== undefined && task.mode !== "sequential" && task.mode !== "parallel")
100
+ ) {
101
+ return malformed("each task requires id, agent, description, depends_on[], writes[], and an optional valid mode");
102
+ }
103
+ if (ids.has(task.id)) {
104
+ return { ok: false, reason: "delegation_plan_duplicate_id", detail: `duplicate task id '${task.id}'` };
105
+ }
106
+ if (!roster.has(task.agent)) {
107
+ return {
108
+ ok: false,
109
+ reason: "delegation_plan_roster_violation",
110
+ detail: `task '${task.id}' names agent '${task.agent}' outside the roster`,
111
+ };
112
+ }
113
+ let writes: ReadonlyArray<string>;
114
+ try {
115
+ writes = normalizeWriteBoundary(task.writes as string[]);
116
+ } catch (error) {
117
+ return malformed(`task '${task.id}' has invalid writes: ${error instanceof Error ? error.message : String(error)}`);
118
+ }
119
+ const outside = writes.find((path) => !insideBoundary(path, input.writes));
120
+ if (outside !== undefined) {
121
+ return {
122
+ ok: false,
123
+ reason: "delegation_plan_writes_outside_boundary",
124
+ detail: `task '${task.id}' writes '${outside}' outside the plan step boundary`,
125
+ };
126
+ }
127
+ ids.add(task.id);
128
+ tasks.push({
129
+ id: task.id,
130
+ agent: task.agent,
131
+ description: task.description,
132
+ depends_on: [...(task.depends_on as string[])],
133
+ writes,
134
+ ...(task.mode !== undefined ? { mode: task.mode as DelegationTaskMode } : {}),
135
+ });
136
+ }
137
+ for (const task of tasks) {
138
+ const unknown = task.depends_on.find((dependency) => !ids.has(dependency));
139
+ if (unknown !== undefined) {
140
+ return {
141
+ ok: false,
142
+ reason: "delegation_plan_dependency_unknown",
143
+ detail: `task '${task.id}' depends on unknown task '${unknown}'`,
144
+ };
145
+ }
146
+ }
147
+ const remaining = new Set(ids);
148
+ const completed = new Set<string>();
149
+ while (remaining.size > 0) {
150
+ const ready = tasks.filter(
151
+ (task) => remaining.has(task.id) && task.depends_on.every((dependency) => completed.has(dependency)),
152
+ );
153
+ if (ready.length === 0) {
154
+ return {
155
+ ok: false,
156
+ reason: "delegation_plan_dependency_cycle",
157
+ detail: `delegation plan dependency cycle includes ${[...remaining].sort().join(", ")}`,
158
+ };
159
+ }
160
+ for (const task of ready) {
161
+ remaining.delete(task.id);
162
+ completed.add(task.id);
163
+ }
164
+ }
165
+ const plan = { tasks } satisfies DelegationPlan;
166
+ return { ok: true, plan, hash: createHash("sha256").update(JSON.stringify(plan)).digest("hex") };
167
+ }
@@ -3,7 +3,7 @@ import type { ResultContract } from "../agents/result-contract.js";
3
3
  import type { AgentAutomationAuthority } from "../agents/spec.js";
4
4
  import type { ExecutionRole } from "./execution-role.js";
5
5
 
6
- export type ExecutionPlanTopology = "parallel" | "sequential" | "pipeline" | "review" | "compete" | "fleet";
6
+ export type ExecutionPlanTopology = "parallel" | "sequential" | "pipeline" | "review" | "compete" | "council" | "fleet";
7
7
  export type ExecutionPlanScope = "readonly" | "workspace";
8
8
  export type ExecutionPlanFailurePolicy = "stop" | "continue";
9
9
 
@@ -56,6 +56,19 @@ export interface ExecutionPlanAgentStep {
56
56
  * contract declares no boundary at all and is therefore not enforced.
57
57
  */
58
58
  writes?: ReadonlyArray<string>;
59
+ /** Exact per-step route defaults from a version 5 fleet contract. */
60
+ target?: string;
61
+ profile?: string;
62
+ /** Version 5 gate authoring and baseline execution facts. */
63
+ gate?: { path: string; commandId: string };
64
+ /** Version 5 dynamic planning facts. */
65
+ plan?: {
66
+ roster: ReadonlyArray<string>;
67
+ maxTasks: number;
68
+ proposals: boolean;
69
+ };
70
+ /** The plan step that admitted this dynamically authored task. */
71
+ planParentId?: string;
59
72
  }
60
73
 
61
74
  /**
@@ -85,6 +98,8 @@ export interface ExecutionPlanCodeStep {
85
98
  commitFrom?: ReadonlyArray<string>;
86
99
  /** Declared write boundary; see `ExecutionPlanAgentStep.writes`. */
87
100
  writes?: ReadonlyArray<string>;
101
+ /** A gate check executes a declared gate file through this command. */
102
+ gate?: { gateId: string; path: string };
88
103
  }
89
104
 
90
105
  export type ExecutionPlanStep = ExecutionPlanAgentStep | ExecutionPlanCodeStep;
@@ -106,6 +121,8 @@ export interface ExecutionPlan {
106
121
  topology: ExecutionPlanTopology;
107
122
  rootTask: string;
108
123
  maxWorkers: number;
124
+ /** Serialize writer admission when set. The only supported value in this cut is one. */
125
+ writers?: 1;
109
126
  onFailure: ExecutionPlanFailurePolicy;
110
127
  steps: ReadonlyArray<ExecutionPlanStep>;
111
128
  loops: ReadonlyArray<ExecutionPlanLoop>;
@@ -240,6 +257,7 @@ function checkLoops(steps: ReadonlyArray<ExecutionPlanStep>, loops: ReadonlyArra
240
257
  function checkWriteBoundaryWaves(
241
258
  steps: ReadonlyArray<ExecutionPlanStep>,
242
259
  waves: ReadonlyArray<ReadonlyArray<string>>,
260
+ writerLimit?: 1,
243
261
  ): void {
244
262
  const byId = new Map(steps.map((step) => [step.id, step]));
245
263
  for (const [index, wave] of waves.entries()) {
@@ -250,7 +268,7 @@ function checkWriteBoundaryWaves(
250
268
  const declared = members.filter((step) => step.writes !== undefined);
251
269
  if (declared.length === 0) continue;
252
270
  const undeclared = members.filter((step) => step.writes === undefined);
253
- if (undeclared.length > 0) {
271
+ if (undeclared.length > 0 && writerLimit !== 1) {
254
272
  throw new Error(
255
273
  `execution plan: wave ${index} mixes boundary-enforced steps (${declared
256
274
  .map((step) => step.id)
@@ -260,7 +278,7 @@ function checkWriteBoundaryWaves(
260
278
  );
261
279
  }
262
280
  const writers = declared.filter((step) => (step.writes?.length ?? 0) > 0);
263
- if (writers.length > 1) {
281
+ if (writers.length > 1 && writerLimit !== 1) {
264
282
  throw new Error(
265
283
  `execution plan: wave ${index} schedules ${writers.length} steps that may write (${writers
266
284
  .map((step) => step.id)
@@ -273,6 +291,9 @@ function checkWriteBoundaryWaves(
273
291
  }
274
292
 
275
293
  export function compileExecutionPlan(input: ExecutionPlanInput): ExecutionPlan {
294
+ if (input.writers !== undefined && input.writers !== 1) {
295
+ throw new Error("execution plan: writers must be 1 when present");
296
+ }
276
297
  const steps = canonicalSteps(input.steps);
277
298
  const loops = (input.loops ?? []).map((loop) => ({
278
299
  ...loop,
@@ -281,12 +302,13 @@ export function compileExecutionPlan(input: ExecutionPlanInput): ExecutionPlan {
281
302
  }));
282
303
  checkLoops(steps, loops);
283
304
  const waves = executionPlanWaves(steps, input.maxWorkers);
284
- checkWriteBoundaryWaves(steps, waves);
305
+ checkWriteBoundaryWaves(steps, waves, input.writers);
285
306
  const canonical = {
286
307
  version: 4 as const,
287
308
  topology: input.topology,
288
309
  rootTask: input.rootTask,
289
310
  maxWorkers: input.maxWorkers,
311
+ ...(input.writers === 1 ? { writers: 1 as const } : {}),
290
312
  onFailure: input.onFailure,
291
313
  steps,
292
314
  loops,
@@ -309,6 +331,55 @@ export function executionPlanAncestors(plan: ExecutionPlan, stepId: string): Rea
309
331
  return ancestors;
310
332
  }
311
333
 
334
+ /** Recompile a plan with coordinator-validated dynamic agent tasks. */
335
+ export function spliceExecutionPlan(
336
+ plan: ExecutionPlan,
337
+ parentId: string,
338
+ tasks: ReadonlyArray<{
339
+ id: string;
340
+ agentId: string;
341
+ task: string;
342
+ dependencies: ReadonlyArray<string>;
343
+ writes: ReadonlyArray<string>;
344
+ target?: string;
345
+ profile?: string;
346
+ requestedAuthority: AgentAutomationAuthority;
347
+ approvedAuthority: AgentAutomationAuthority | null;
348
+ expectedResultContract: ResultContract["kind"];
349
+ executionRole: ExecutionRole;
350
+ }>,
351
+ ): ExecutionPlan {
352
+ const parent = plan.steps.find((step) => step.id === parentId);
353
+ if (parent?.kind !== "agent" || parent.plan === undefined) {
354
+ throw new Error(`execution plan: '${parentId}' is not a plan step`);
355
+ }
356
+ const inserted: ExecutionPlanStepInput[] = tasks.map((task) => ({
357
+ kind: "agent",
358
+ id: task.id,
359
+ agentId: task.agentId,
360
+ executionRole: task.executionRole,
361
+ scope: task.writes.length > 0 ? "workspace" : "readonly",
362
+ expectedResultContract: task.expectedResultContract,
363
+ requestedAuthority: task.requestedAuthority,
364
+ approvedAuthority: task.approvedAuthority,
365
+ dependencies: [parentId, ...task.dependencies],
366
+ task: task.task,
367
+ writes: [...task.writes],
368
+ ...(task.target !== undefined ? { target: task.target } : {}),
369
+ ...(task.profile !== undefined ? { profile: task.profile } : {}),
370
+ planParentId: parentId,
371
+ }));
372
+ return compileExecutionPlan({
373
+ topology: plan.topology,
374
+ rootTask: plan.rootTask,
375
+ maxWorkers: plan.maxWorkers,
376
+ ...(plan.writers === 1 ? { writers: 1 as const } : {}),
377
+ onFailure: plan.onFailure,
378
+ steps: [...plan.steps, ...inserted],
379
+ loops: plan.loops,
380
+ });
381
+ }
382
+
312
383
  /** A linear step declares no dependencies; the compiler chains them by position. */
313
384
  export type ExecutionPlanLinearStepInput =
314
385
  | (Omit<ExecutionPlanAgentStep, "kind" | "dependencies"> & { kind?: "agent" })
@@ -317,7 +388,7 @@ export type ExecutionPlanLinearStepInput =
317
388
  export function compileLinearExecutionPlan(
318
389
  input: Omit<ExecutionPlanInput, "steps"> & { steps: ReadonlyArray<ExecutionPlanLinearStepInput> },
319
390
  ): ExecutionPlan {
320
- const parallel = input.topology === "parallel" || input.topology === "compete";
391
+ const parallel = input.topology === "parallel" || input.topology === "compete" || input.topology === "council";
321
392
  return compileExecutionPlan({
322
393
  ...input,
323
394
  steps: input.steps.map((step, index): ExecutionPlanStepInput => {
@@ -47,7 +47,7 @@ export function isExecutionRole(value: unknown): value is ExecutionRole {
47
47
  * statistics belong to: every compete candidate occupies a distinct `candidate`
48
48
  * position but they are all ordinary `builder` routes.
49
49
  */
50
- export type GateTopologyRole = "builder" | "reviewer" | "candidate" | "judge";
50
+ export type GateTopologyRole = "builder" | "reviewer" | "candidate" | "judge" | "member" | "synthesis";
51
51
 
52
52
  /**
53
53
  * Facts the role is derived from. `capabilityClass` and `resultContractKind`
@@ -86,6 +86,8 @@ export function deriveExecutionRole(input: ExecutionRoleInput): ExecutionRole {
86
86
  if (input.attempt > 0) return "recovery";
87
87
  if (input.gateRole === "reviewer") return "reviewer";
88
88
  if (input.gateRole === "judge") return "judge";
89
+ if (input.gateRole === "synthesis") return "judge";
90
+ if (input.gateRole === "member") return "researcher";
89
91
  if (input.gateRole === "builder" || input.gateRole === "candidate") return "builder";
90
92
  if (input.resultContractKind === "verifier-report") return "verifier";
91
93
  if (input.capabilityClass === "read-only") return "researcher";