@astrosheep/keiyaku 4.0.0 → 4.0.1

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 (241) hide show
  1. package/README.md +2 -9
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +11 -3
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +9 -6
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +94 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +162 -45
  12. package/build/src/akuma/akuma.d.ts +33 -25
  13. package/build/src/akuma/akuma.js +93 -61
  14. package/build/src/akuma/archetype.d.ts +8 -0
  15. package/build/src/akuma/archetype.js +28 -9
  16. package/build/src/akuma/body.js +196 -84
  17. package/build/src/akuma/coordinate.d.ts +9 -0
  18. package/build/src/akuma/coordinate.js +22 -0
  19. package/build/src/akuma/heart/facts.d.ts +67 -15
  20. package/build/src/akuma/heart/facts.js +3 -3
  21. package/build/src/akuma/heart/index.d.ts +41 -29
  22. package/build/src/akuma/heart/index.js +72 -193
  23. package/build/src/akuma/heart/rows.d.ts +30 -53
  24. package/build/src/akuma/heart/rows.js +91 -111
  25. package/build/src/akuma/heart/schema.d.ts +1 -1
  26. package/build/src/akuma/heart/schema.js +55 -8
  27. package/build/src/akuma/heart/storage.d.ts +33 -0
  28. package/build/src/akuma/heart/storage.js +164 -0
  29. package/build/src/akuma/heart/tells.d.ts +12 -0
  30. package/build/src/akuma/heart/tells.js +79 -0
  31. package/build/src/akuma/heart/timeline.d.ts +15 -0
  32. package/build/src/akuma/heart/timeline.js +86 -0
  33. package/build/src/akuma/index.d.ts +4 -2
  34. package/build/src/akuma/index.js +1 -1
  35. package/build/src/akuma/projection.d.ts +97 -0
  36. package/build/src/akuma/projection.js +145 -0
  37. package/build/src/akuma/provider.d.ts +57 -11
  38. package/build/src/akuma/provider.js +57 -37
  39. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  40. package/build/src/akuma/providers/claude/events.js +185 -0
  41. package/build/src/akuma/providers/claude/index.d.ts +46 -0
  42. package/build/src/akuma/providers/claude/index.js +265 -0
  43. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  44. package/build/src/akuma/providers/claude/input.js +109 -0
  45. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  46. package/build/src/akuma/providers/codex-app-server/events.js +12 -12
  47. package/build/src/akuma/providers/codex-app-server/index.d.ts +13 -11
  48. package/build/src/akuma/providers/codex-app-server/index.js +73 -22
  49. package/build/src/akuma/providers/index.js +22 -8
  50. package/build/src/akuma/providers/opencode-sdk/events.d.ts +48 -0
  51. package/build/src/akuma/providers/opencode-sdk/events.js +116 -0
  52. package/build/src/akuma/providers/opencode-sdk/index.d.ts +32 -0
  53. package/build/src/akuma/providers/opencode-sdk/index.js +203 -0
  54. package/build/src/akuma/providers/opencode-sdk/session.d.ts +41 -0
  55. package/build/src/akuma/providers/opencode-sdk/session.js +62 -0
  56. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  57. package/build/src/akuma/providers/pi/events.js +128 -0
  58. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  59. package/build/src/akuma/providers/pi/index.js +162 -0
  60. package/build/src/akuma/requests.d.ts +1 -0
  61. package/build/src/akuma/requests.js +5 -2
  62. package/build/src/alias/index.d.ts +4 -3
  63. package/build/src/alias/index.js +2 -3
  64. package/build/src/body/render.js +2 -1
  65. package/build/src/body/shape.js +7 -1
  66. package/build/src/body/verification.js +19 -4
  67. package/build/src/cli/accepted.d.ts +2 -0
  68. package/build/src/cli/accepted.js +2 -1
  69. package/build/src/cli/commands/akuma-invoke.d.ts +42 -18
  70. package/build/src/cli/commands/akuma-invoke.js +94 -50
  71. package/build/src/cli/commands/akuma.d.ts +15 -7
  72. package/build/src/cli/commands/akuma.js +94 -56
  73. package/build/src/cli/commands/contract.d.ts +142 -0
  74. package/build/src/cli/commands/contract.js +14 -0
  75. package/build/src/cli/commands/install.js +2 -0
  76. package/build/src/cli/commands/task-invoke.d.ts +3 -1
  77. package/build/src/cli/commands/task-invoke.js +27 -2
  78. package/build/src/cli/commands/task.js +2 -2
  79. package/build/src/cli/invoke.d.ts +6 -1
  80. package/build/src/cli/invoke.js +241 -43
  81. package/build/src/cli/main.js +20 -1
  82. package/build/src/cli/parse.d.ts +13 -116
  83. package/build/src/cli/parse.js +51 -78
  84. package/build/src/cli/render/akuma-tool.d.ts +2 -0
  85. package/build/src/cli/render/akuma-tool.js +6 -2
  86. package/build/src/cli/render/akuma.d.ts +2 -1
  87. package/build/src/cli/render/akuma.js +157 -217
  88. package/build/src/cli/render/catalog.d.ts +2 -0
  89. package/build/src/cli/render/catalog.js +16 -0
  90. package/build/src/cli/render/contract.d.ts +1 -1
  91. package/build/src/cli/render/contract.js +38 -5
  92. package/build/src/cli/render/kanshi.js +53 -5
  93. package/build/src/cli/render/refusal.js +17 -0
  94. package/build/src/cli/render/terminal.d.ts +13 -0
  95. package/build/src/cli/render/terminal.js +75 -0
  96. package/build/src/cli/render/text.js +5 -0
  97. package/build/src/cli/result.d.ts +15 -3
  98. package/build/src/contract-worktree.d.ts +43 -0
  99. package/build/src/contract-worktree.js +213 -0
  100. package/build/src/coordination/durable-file.d.ts +3 -0
  101. package/build/src/coordination/durable-file.js +44 -1
  102. package/build/src/core/facts/codec.js +23 -4
  103. package/build/src/core/facts/eligibility.d.ts +1 -10
  104. package/build/src/core/facts/eligibility.js +0 -49
  105. package/build/src/core/facts/observation.d.ts +3 -0
  106. package/build/src/core/facts/observation.js +12 -0
  107. package/build/src/core/facts/types.d.ts +10 -3
  108. package/build/src/core/subject.js +2 -2
  109. package/build/src/core/verbs/amend.js +12 -16
  110. package/build/src/core/verbs/bind.js +2 -16
  111. package/build/src/core/verbs/deliver.js +20 -4
  112. package/build/src/core/verbs/placement.js +3 -8
  113. package/build/src/dispatch/index.d.ts +3 -1
  114. package/build/src/dispatch/index.js +14 -5
  115. package/build/src/duration.d.ts +10 -0
  116. package/build/src/duration.js +22 -0
  117. package/build/src/git/admission.d.ts +2 -2
  118. package/build/src/git/admission.js +26 -16
  119. package/build/src/git/hooks.d.ts +15 -0
  120. package/build/src/git/hooks.js +57 -5
  121. package/build/src/git/identity.d.ts +5 -1
  122. package/build/src/git/identity.js +23 -4
  123. package/build/src/git/integration.d.ts +49 -0
  124. package/build/src/git/integration.js +214 -0
  125. package/build/src/git/observe.d.ts +25 -13
  126. package/build/src/git/observe.js +175 -72
  127. package/build/src/git/read-observation.d.ts +41 -0
  128. package/build/src/git/read-observation.js +361 -0
  129. package/build/src/git/reconcile.d.ts +15 -5
  130. package/build/src/git/reconcile.js +238 -85
  131. package/build/src/git/repository.d.ts +19 -4
  132. package/build/src/git/repository.js +77 -43
  133. package/build/src/git/scratch.d.ts +13 -0
  134. package/build/src/git/scratch.js +66 -0
  135. package/build/src/git/target-placement.d.ts +56 -0
  136. package/build/src/git/target-placement.js +255 -0
  137. package/build/src/git/tender.d.ts +48 -0
  138. package/build/src/git/tender.js +82 -0
  139. package/build/src/git/terminal-seal.d.ts +24 -0
  140. package/build/src/git/terminal-seal.js +87 -0
  141. package/build/src/git/tree.d.ts +2 -2
  142. package/build/src/git/tree.js +4 -0
  143. package/build/src/git/workspace.d.ts +21 -0
  144. package/build/src/git/workspace.js +104 -0
  145. package/build/src/identity/selector.d.ts +6 -0
  146. package/build/src/identity/selector.js +19 -0
  147. package/build/src/index.d.ts +4 -2
  148. package/build/src/index.js +2 -1
  149. package/build/src/kanshi/index.d.ts +1 -1
  150. package/build/src/kanshi/read.d.ts +5 -2
  151. package/build/src/kanshi/read.js +154 -45
  152. package/build/src/kanshi/report.d.ts +31 -6
  153. package/build/src/kanshi/select.js +1 -1
  154. package/build/src/library/address.d.ts +48 -0
  155. package/build/src/library/address.js +134 -0
  156. package/build/src/library/akuma-creation.d.ts +10 -6
  157. package/build/src/library/akuma-creation.js +12 -11
  158. package/build/src/library/bind.d.ts +21 -0
  159. package/build/src/library/bind.js +56 -0
  160. package/build/src/library/catalog.d.ts +58 -0
  161. package/build/src/library/catalog.js +72 -0
  162. package/build/src/library/configuration.d.ts +6 -15
  163. package/build/src/library/configuration.js +14 -17
  164. package/build/src/library/contract.d.ts +21 -46
  165. package/build/src/library/contract.js +193 -183
  166. package/build/src/library/delivery.d.ts +23 -0
  167. package/build/src/library/delivery.js +21 -0
  168. package/build/src/library/fleet.d.ts +65 -0
  169. package/build/src/library/fleet.js +189 -0
  170. package/build/src/library/input.d.ts +3 -0
  171. package/build/src/library/input.js +19 -0
  172. package/build/src/library/keiyaku.d.ts +16 -2
  173. package/build/src/library/keiyaku.js +11 -1
  174. package/build/src/library/mutation.d.ts +38 -0
  175. package/build/src/library/mutation.js +39 -0
  176. package/build/src/library/refusal.d.ts +21 -0
  177. package/build/src/library/refusal.js +29 -0
  178. package/build/src/library/region.d.ts +2 -1
  179. package/build/src/library/region.js +3 -3
  180. package/build/src/library/repo.d.ts +4 -1
  181. package/build/src/library/repo.js +31 -16
  182. package/build/src/protocol/attempt.d.ts +16 -3
  183. package/build/src/protocol/attempt.js +39 -8
  184. package/build/src/protocol/bind.d.ts +9 -2
  185. package/build/src/protocol/bind.js +47 -39
  186. package/build/src/protocol/intent.d.ts +42 -18
  187. package/build/src/protocol/intent.js +36 -75
  188. package/build/src/protocol/operations.d.ts +93 -35
  189. package/build/src/protocol/operations.js +235 -123
  190. package/build/src/protocol/outcome.d.ts +7 -2
  191. package/build/src/protocol/outcome.js +9 -3
  192. package/build/src/protocol/placement.d.ts +30 -0
  193. package/build/src/protocol/placement.js +114 -0
  194. package/build/src/protocol/read/audit.d.ts +9 -3
  195. package/build/src/protocol/read/audit.js +25 -9
  196. package/build/src/protocol/read/documents.d.ts +2 -2
  197. package/build/src/protocol/read/documents.js +4 -4
  198. package/build/src/protocol/read/status.d.ts +11 -5
  199. package/build/src/protocol/read/status.js +28 -15
  200. package/build/src/protocol/run.d.ts +49 -7
  201. package/build/src/protocol/run.js +53 -25
  202. package/build/src/runtime/proc/line-rpc.d.ts +1 -0
  203. package/build/src/runtime/proc/line-rpc.js +21 -0
  204. package/build/src/runtime/proc/run.d.ts +18 -2
  205. package/build/src/runtime/proc/run.js +34 -8
  206. package/build/src/settings.d.ts +6 -0
  207. package/build/src/settings.js +29 -14
  208. package/build/src/settlement/fence.d.ts +9 -0
  209. package/build/src/settlement/fence.js +23 -0
  210. package/build/src/settlement/holder.d.ts +25 -4
  211. package/build/src/settlement/holder.js +102 -28
  212. package/build/src/settlement/settle.d.ts +8 -0
  213. package/build/src/settlement/settle.js +102 -28
  214. package/build/src/task/board.d.ts +20 -2
  215. package/build/src/task/board.js +11 -1
  216. package/build/src/task/compose.d.ts +2 -2
  217. package/build/src/task/compose.js +2 -2
  218. package/build/src/task/context.js +2 -7
  219. package/build/src/task/index.d.ts +9 -9
  220. package/build/src/task/index.js +15 -12
  221. package/build/src/task/operations.d.ts +31 -12
  222. package/build/src/task/operations.js +8 -4
  223. package/build/src/task/store.d.ts +4 -6
  224. package/build/src/task/store.js +3 -3
  225. package/build/src/verification/declaration.d.ts +1 -0
  226. package/build/src/verification/execution.d.ts +49 -0
  227. package/build/src/verification/execution.js +104 -0
  228. package/build/src/world.d.ts +13 -0
  229. package/build/src/world.js +103 -0
  230. package/package.json +7 -4
  231. package/build/src/akuma/activity.d.ts +0 -66
  232. package/build/src/akuma/activity.js +0 -139
  233. package/build/src/akuma/providers/claude.js +0 -305
  234. package/build/src/context-root.d.ts +0 -4
  235. package/build/src/context-root.js +0 -15
  236. package/build/src/git/delivery.d.ts +0 -20
  237. package/build/src/git/delivery.js +0 -109
  238. package/build/src/git/verification.d.ts +0 -14
  239. package/build/src/git/verification.js +0 -56
  240. package/build/src/verification/producer.d.ts +0 -23
  241. package/build/src/verification/producer.js +0 -54
@@ -1,13 +1,28 @@
1
1
  import { fileURLToPath } from "node:url";
2
- import { HeldAkumaLeash, advanceTell, appendActivity, breakBody, clearAbandonedControl, finishBodyIfIdle, heartExists, pauseRequested, readHeart, recordBody, recordSession, recordTurn, stopRequested, } from "./heart/index.js";
2
+ import { HeldAkumaLeash, appendActivity, beginTurn, breakBody, endTurn, finishBodyIfIdle, heartExists, pauseRequested, readHeart, recordBody, recordSession, recordTellDeliveries, recordTellReceipt, stopRequested, } from "./heart/index.js";
3
3
  import { encodeAgentEvent } from "./provider.js";
4
4
  import { providerNamed } from "./providers/index.js";
5
- import { BodyRequestPump, settleBodyRequests, } from "./requests.js";
5
+ import { BodyRequestPump, clearBodyRequestTransport, settleBodyRequests, } from "./requests.js";
6
6
  import { currentProcessCollar, probeProcessTree, putDownProcessTree, spawnDetachedProcess, } from "../runtime/proc/run.js";
7
7
  const LEASH_RETRY_MS = 25;
8
8
  function wait(milliseconds) {
9
9
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
10
10
  }
11
+ function serializeEffects() {
12
+ let tail = Promise.resolve();
13
+ return async (effect) => {
14
+ const before = tail;
15
+ let release;
16
+ tail = new Promise((resolve) => { release = resolve; });
17
+ await before;
18
+ try {
19
+ return await effect();
20
+ }
21
+ finally {
22
+ release();
23
+ }
24
+ };
25
+ }
11
26
  function missing(error) {
12
27
  return error.code === "ENOENT";
13
28
  }
@@ -50,6 +65,13 @@ async function settlePredecessor(paths) {
50
65
  }
51
66
  async function startTurnDrive(input) {
52
67
  const { cwd, options, session } = turnRecipe(input.paths, input.soul);
68
+ if (session !== undefined && input.adapter.resume === undefined)
69
+ return { kind: "resume-unsupported" };
70
+ const turn = beginTurn(input.paths, {
71
+ bodySequence: input.bodySequence,
72
+ startedAt: input.now(),
73
+ ...(input.call === undefined ? {} : { call: input.call }),
74
+ });
53
75
  const requests = input.soul.confinement.kind === "declared"
54
76
  ? new BodyRequestPump({
55
77
  paths: input.paths,
@@ -60,94 +82,181 @@ async function startTurnDrive(input) {
60
82
  })
61
83
  : null;
62
84
  try {
63
- const drive = await input.adapter.start({
64
- prompt: input.prompt,
85
+ const driveInput = {
86
+ body: input.body,
87
+ launchTells: input.launchTells.map((tell) => ({ id: tell.id, text: tell.body })),
65
88
  cwd,
66
89
  options,
67
- ...(session === undefined ? {} : { session }),
68
90
  ...(requests === null ? {} : { requests: { dir: requests.directory } }),
69
- });
91
+ };
92
+ const selected = session === undefined
93
+ ? await input.adapter.start({ ...driveInput, session: { kind: "fresh" } })
94
+ : await input.adapter.resume({ ...driveInput, session: { kind: "resume", coordinate: session } });
95
+ if (input.launchTells.length > 0) {
96
+ recordTellDeliveries(input.paths, input.launchTells.map((tell) => ({
97
+ tellId: tell.id,
98
+ route: "launch",
99
+ turnSequence: turn.sequence,
100
+ fence: selected.admission.fence,
101
+ deliveredAt: input.now(),
102
+ })));
103
+ }
70
104
  if (requests !== null)
71
- void drive.completion.then(() => requests.stopAdmission());
72
- return { drive, requests, cwd, options, ...(session === undefined ? {} : { session }) };
105
+ void selected.completion.then(() => requests.stopAdmission());
106
+ return { turnSequence: turn.sequence, drive: selected, requests, cwd, options,
107
+ ...(session === undefined ? {} : { resume: session }) };
73
108
  }
74
109
  catch (error) {
75
110
  if (requests !== null)
76
111
  await requests.close();
77
- throw error;
112
+ const diagnostic = error instanceof Error ? error.message : String(error);
113
+ endTurn(input.paths, {
114
+ turnSequence: turn.sequence,
115
+ outcome: { kind: "failed", diagnostic },
116
+ completedAt: input.now(),
117
+ });
118
+ return { kind: "start-failed", turnSequence: turn.sequence, diagnostic };
78
119
  }
79
120
  }
121
+ function pumpReceipts(input, turnSequence, drive, writeWitness) {
122
+ return (async () => {
123
+ if (drive.receipts === undefined)
124
+ return;
125
+ for await (const receipt of drive.receipts) {
126
+ await writeWitness(() => recordTellReceipt(input.paths, receipt.evidence === "exact"
127
+ ? { ...receipt, receivedAt: input.now() }
128
+ : { ...receipt, turnSequence, receivedAt: input.now() }));
129
+ }
130
+ })();
131
+ }
132
+ async function submitPendingLiveTells(input, turnSequence, drive, attempted, writeWitness) {
133
+ if (drive.tell === undefined)
134
+ return "live";
135
+ for (const tell of readHeart(input.paths).pending) {
136
+ if (attempted.has(tell.id))
137
+ continue;
138
+ attempted.add(tell.id);
139
+ const outcome = await writeWitness(async () => {
140
+ const submission = await drive.tell({ id: tell.id, text: tell.body });
141
+ if (submission.kind === "turn-ended")
142
+ return "turn-ended";
143
+ recordTellDeliveries(input.paths, [{
144
+ tellId: tell.id,
145
+ route: "live",
146
+ turnSequence,
147
+ fence: submission.fence,
148
+ receipt: drive.receipts === undefined ? "unavailable" : "required",
149
+ deliveredAt: input.now(),
150
+ }]);
151
+ return "accepted";
152
+ });
153
+ if (outcome === "turn-ended")
154
+ return "turn-ended";
155
+ }
156
+ return "live";
157
+ }
80
158
  async function consumeTurnDrive(input, active) {
81
- const { drive, requests, cwd, options, session } = active;
82
- let turnSession = session;
83
- let entered = false;
159
+ const { turnSequence, drive, requests, cwd, options, resume } = active;
160
+ let turnSession = resume;
161
+ const attempted = new Set(input.launchTells.map((tell) => tell.id));
162
+ const writeWitness = serializeEffects();
163
+ const receiptPump = pumpReceipts(input, turnSequence, drive, writeWitness);
164
+ const receiptFailure = receiptPump.then(() => new Promise(() => { }), (error) => Promise.reject(error));
84
165
  const iterator = drive.events[Symbol.asyncIterator]();
85
166
  let pending = iterator.next();
86
- for (;;) {
87
- if (stopRequested(input.paths) || pauseRequested(input.paths)) {
88
- const draining = requests?.close();
89
- try {
90
- await drive.abort();
167
+ let liveTells = true;
168
+ try {
169
+ for (;;) {
170
+ if (stopRequested(input.paths, input.bodySequence) || pauseRequested(input.paths)) {
171
+ const draining = requests?.close();
172
+ try {
173
+ await drive.abort();
174
+ }
175
+ finally {
176
+ await draining;
177
+ await receiptPump;
178
+ }
179
+ return { kind: "stopped" };
91
180
  }
92
- finally {
93
- await draining;
181
+ if (liveTells) {
182
+ liveTells = await submitPendingLiveTells(input, turnSequence, drive, attempted, writeWitness) === "live";
94
183
  }
95
- return { kind: "stopped" };
96
- }
97
- const next = await Promise.race([
98
- pending,
99
- wait(LEASH_RETRY_MS).then(() => null),
100
- ...(requests === null ? [] : [requests.failure]),
101
- ]);
102
- if (next === null)
103
- continue;
104
- if (next.done)
105
- break;
106
- const event = next.value;
107
- const at = input.now();
108
- if (event.type === "session") {
109
- turnSession = event.coordinate;
110
- recordSession(input.paths, {
111
- provider: input.soul.provider.name,
112
- coordinate: event.coordinate,
113
- cwd,
114
- options,
115
- admittedAt: at,
184
+ const next = await Promise.race([
185
+ pending,
186
+ wait(LEASH_RETRY_MS).then(() => null),
187
+ receiptFailure,
188
+ ...(requests === null ? [] : [requests.failure]),
189
+ ]);
190
+ if (next === null)
191
+ continue;
192
+ if (next.done)
193
+ break;
194
+ const event = next.value;
195
+ const at = input.now();
196
+ if (event.type === "session") {
197
+ turnSession = event.coordinate;
198
+ recordSession(input.paths, {
199
+ provider: input.soul.provider.name,
200
+ coordinate: event.coordinate,
201
+ cwd,
202
+ options,
203
+ admittedAt: at,
204
+ });
205
+ }
206
+ appendActivity(input.paths, {
207
+ turnSequence,
208
+ event: encodeAgentEvent(event),
209
+ at,
116
210
  });
211
+ pending = iterator.next();
117
212
  }
118
- appendActivity(input.paths, {
119
- bodySequence: input.bodySequence,
120
- event: encodeAgentEvent(event),
121
- at,
122
- });
123
- if (!entered && input.tellId !== undefined) {
124
- entered = true;
125
- advanceTell(input.paths, input.tellId, "seen");
126
- advanceTell(input.paths, input.tellId, "consumed");
127
- }
128
- pending = iterator.next();
213
+ const result = await drive.completion;
214
+ await receiptPump;
215
+ if (requests !== null)
216
+ await requests.close();
217
+ return result.kind === "answered"
218
+ ? { ...result, ...(turnSession === undefined ? {} : { session: turnSession }) }
219
+ : result;
129
220
  }
130
- const result = await drive.completion;
131
- if (requests !== null)
132
- await requests.close();
133
- if (!entered && result.kind === "answered" && input.tellId !== undefined) {
134
- advanceTell(input.paths, input.tellId, "seen");
135
- advanceTell(input.paths, input.tellId, "consumed");
221
+ catch (error) {
222
+ const draining = requests?.close();
223
+ try {
224
+ await drive.abort();
225
+ }
226
+ catch { /* the pump failure owns the turn result */ }
227
+ try {
228
+ await receiptPump;
229
+ }
230
+ catch { /* preserve the first pump failure */ }
231
+ try {
232
+ await draining;
233
+ }
234
+ catch { /* preserve the first pump failure */ }
235
+ return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
136
236
  }
137
- return result.kind === "answered"
138
- ? { ...result, ...(turnSession === undefined ? {} : { session: turnSession }) }
139
- : result;
140
237
  }
141
238
  async function driveTurn(input) {
142
- const active = await startTurnDrive(input);
239
+ let active;
240
+ try {
241
+ const started = await startTurnDrive(input);
242
+ if ("kind" in started)
243
+ return started;
244
+ active = started;
245
+ }
246
+ catch (error) {
247
+ if (!heartExists(input.paths))
248
+ return { kind: "heart-gone" };
249
+ throw error;
250
+ }
143
251
  try {
144
- return await consumeTurnDrive(input, active);
252
+ return { ...await consumeTurnDrive(input, active), turnSequence: active.turnSequence };
145
253
  }
146
254
  catch (error) {
147
255
  const draining = active.requests?.close();
148
256
  if (heartExists(input.paths)) {
149
257
  await draining;
150
- throw error;
258
+ return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error),
259
+ turnSequence: active.turnSequence };
151
260
  }
152
261
  try {
153
262
  await active.drive.abort();
@@ -162,10 +271,8 @@ async function driveTurn(input) {
162
271
  }
163
272
  function bornSoul(launch, leash, now) {
164
273
  const before = readHeart(launch.paths);
165
- if (before.death !== null)
166
- return null;
167
274
  if (before.soul !== null) {
168
- clearAbandonedControl(launch.paths);
275
+ leash.clearPause(launch.paths);
169
276
  return before.soul;
170
277
  }
171
278
  if (launch.seed === undefined)
@@ -190,9 +297,9 @@ function launchCwd(launch) {
190
297
  ? snapshot.latestSession.cwd
191
298
  : soul.cwd;
192
299
  }
193
- function persistTurn(paths, bodySequence, result, completedAt) {
194
- recordTurn(paths, {
195
- bodySequence,
300
+ function persistTurn(paths, turnSequence, result, completedAt) {
301
+ endTurn(paths, {
302
+ turnSequence,
196
303
  outcome: result.kind === "answered" && result.session !== undefined
197
304
  ? { kind: "answered", historyId: result.historyId, session: result.session, answer: result.answer }
198
305
  : result.kind === "answered"
@@ -213,11 +320,14 @@ function defaultRuntime() {
213
320
  function childSpawner(runtime) {
214
321
  return runtime.spawnChild ?? spawnAkumaBody;
215
322
  }
216
- async function beginBody(paths, soul, runtime) {
323
+ async function beginBody(paths, soul, leash, runtime) {
217
324
  if (!await settlePredecessor(paths))
218
325
  return null;
326
+ leash.settleStop(paths);
219
327
  const body = recordBody(paths, { collar: runtime.collar, leashTakenAt: runtime.now() });
220
- if (await settleBodyRequests(paths, soul, runtime.now) === "settled")
328
+ const requests = await settleBodyRequests(paths, soul, runtime.now);
329
+ clearBodyRequestTransport(paths);
330
+ if (requests === "settled")
221
331
  return body;
222
332
  breakBody(paths, { sequence: body.sequence, end: "broke-off", at: runtime.now() });
223
333
  return null;
@@ -231,34 +341,28 @@ export async function driveAkumaBody(launch, adapter, runtime = defaultRuntime()
231
341
  if (soul === null)
232
342
  return;
233
343
  const selected = adapter ?? providerNamed(soul.provider);
234
- const body = await beginBody(launch.paths, soul, runtime);
344
+ const body = await beginBody(launch.paths, soul, leash, runtime);
235
345
  if (body === null)
236
346
  return;
237
347
  let initial = launch.initialBody;
238
348
  for (;;) {
239
349
  const snapshot = readHeart(launch.paths);
240
- if (snapshot.death !== null) {
241
- breakBody(launch.paths, { sequence: body.sequence, end: "put-down", at: runtime.now() });
242
- return;
243
- }
244
- const tell = initial === undefined ? snapshot.pending[0] : undefined;
245
- const prompt = initial ?? tell?.body;
246
- if (prompt === undefined) {
350
+ const launchTells = snapshot.pending;
351
+ if (initial === undefined && launchTells.length === 0) {
247
352
  const finished = finishBodyIfIdle(launch.paths, { sequence: body.sequence, at: runtime.now() });
248
353
  if (finished.kind === "finished")
249
354
  return;
250
355
  continue;
251
356
  }
252
- if (tell !== undefined)
253
- advanceTell(launch.paths, tell.id, "delivered");
254
357
  const result = await driveTurn({
255
358
  paths: launch.paths,
256
359
  soul,
257
360
  adapter: selected,
258
361
  bodySequence: body.sequence,
259
362
  runtimeSpawn: childSpawner(runtime),
260
- prompt,
261
- ...(tell === undefined ? {} : { tellId: tell.id }),
363
+ body: initial ?? "",
364
+ ...(initial === undefined ? {} : { call: initial }),
365
+ launchTells,
262
366
  now: runtime.now,
263
367
  });
264
368
  if (result.kind === "heart-gone") {
@@ -269,7 +373,15 @@ export async function driveAkumaBody(launch, adapter, runtime = defaultRuntime()
269
373
  breakBody(launch.paths, { sequence: body.sequence, end: "put-down", at: runtime.now() });
270
374
  return;
271
375
  }
272
- if (persistTurn(launch.paths, body.sequence, result, runtime.now()) === "failed") {
376
+ if (result.kind === "resume-unsupported") {
377
+ breakBody(launch.paths, { sequence: body.sequence, end: "broke-off", at: runtime.now() });
378
+ return;
379
+ }
380
+ if (result.kind === "start-failed") {
381
+ breakBody(launch.paths, { sequence: body.sequence, end: "broke-off", at: runtime.now() });
382
+ return;
383
+ }
384
+ if (persistTurn(launch.paths, result.turnSequence, result, runtime.now()) === "failed") {
273
385
  breakBody(launch.paths, { sequence: body.sequence, end: "broke-off", at: runtime.now() });
274
386
  return;
275
387
  }
@@ -0,0 +1,9 @@
1
+ export type ResumeCoordinate = Readonly<{
2
+ sessionId: string;
3
+ sessionFile?: never;
4
+ }> | Readonly<{
5
+ sessionFile: string;
6
+ sessionId?: string;
7
+ }>;
8
+ export declare function decodeResumeCoordinate(value: unknown): ResumeCoordinate | null;
9
+ export declare function encodeResumeCoordinate(coordinate: ResumeCoordinate): unknown;
@@ -0,0 +1,22 @@
1
+ function record(value) {
2
+ return value !== null && typeof value === "object" && !Array.isArray(value)
3
+ ? value : null;
4
+ }
5
+ export function decodeResumeCoordinate(value) {
6
+ const coordinate = record(value);
7
+ if (coordinate === null)
8
+ return null;
9
+ const keys = Object.keys(coordinate);
10
+ if (typeof coordinate.sessionFile === "string" && coordinate.sessionFile.trim().length > 0
11
+ && (coordinate.sessionId === undefined || (typeof coordinate.sessionId === "string" && coordinate.sessionId.trim().length > 0))
12
+ && keys.every((key) => key === "sessionFile" || key === "sessionId")) {
13
+ return { sessionFile: coordinate.sessionFile, ...(coordinate.sessionId === undefined ? {} : { sessionId: coordinate.sessionId }) };
14
+ }
15
+ return typeof coordinate.sessionId === "string" && coordinate.sessionId.trim().length > 0 && keys.length === 1
16
+ ? { sessionId: coordinate.sessionId } : null;
17
+ }
18
+ export function encodeResumeCoordinate(coordinate) {
19
+ return "sessionFile" in coordinate
20
+ ? { sessionFile: coordinate.sessionFile, ...(coordinate.sessionId === undefined ? {} : { sessionId: coordinate.sessionId }) }
21
+ : { sessionId: coordinate.sessionId };
22
+ }
@@ -1,4 +1,6 @@
1
1
  import type { AkuId } from "../identity.js";
2
+ import type { ResumeCoordinate } from "../coordinate.js";
3
+ export type { ResumeCoordinate } from "../coordinate.js";
2
4
  export type Confinement = Readonly<{
3
5
  kind: "unconfined";
4
6
  }> | Readonly<{
@@ -14,7 +16,7 @@ export type ProviderOptions = Readonly<{
14
16
  }>;
15
17
  export type ProviderExecution = Readonly<{
16
18
  name: string;
17
- kind: "claude-agent-sdk" | "codex-app-server";
19
+ kind: "claude-agent-sdk" | "codex-app-server" | "opencode-sdk" | "pi";
18
20
  executable?: string;
19
21
  config?: Readonly<Record<string, unknown>>;
20
22
  env?: Readonly<Record<string, string>>;
@@ -23,7 +25,7 @@ export type AkumaOrigin = Readonly<{
23
25
  kind: "direct";
24
26
  }> | Readonly<{
25
27
  kind: "request";
26
- parentId: AkuId;
28
+ parent: AkuId;
27
29
  requestId: string;
28
30
  }> | Readonly<{
29
31
  kind: "fork";
@@ -55,9 +57,6 @@ export type BodyFact = Readonly<{
55
57
  end?: BodyEnd;
56
58
  endedAt?: string;
57
59
  }>;
58
- export type ResumeCoordinate = Readonly<{
59
- sessionId: string;
60
- }>;
61
60
  export type SessionFact = Readonly<{
62
61
  sequence: number;
63
62
  provider: string;
@@ -82,19 +81,66 @@ export type TurnOutcome = Readonly<{
82
81
  kind: "failed";
83
82
  diagnostic: string;
84
83
  }>;
85
- export type TurnFact = Readonly<{
84
+ export type TurnStartFact = Readonly<{
85
+ kind: "turn-start";
86
86
  sequence: number;
87
87
  bodySequence: number;
88
+ startedAt: string;
89
+ }>;
90
+ export type TurnEndFact = Readonly<{
91
+ kind: "turn-end";
92
+ sequence: number;
93
+ turnSequence: number;
88
94
  outcome: TurnOutcome;
89
95
  completedAt: string;
90
96
  }>;
91
- export type TellState = "recorded" | "delivered" | "seen" | "consumed" | "voided-by-death";
97
+ export type TurnFact = TurnStartFact & Readonly<{
98
+ end?: TurnEndFact;
99
+ }>;
100
+ export type CallFact = Readonly<{
101
+ kind: "call";
102
+ sequence: number;
103
+ turnSequence: number;
104
+ body: string;
105
+ at: string;
106
+ }>;
107
+ export type TellDelivery = Readonly<{
108
+ turnSequence: number;
109
+ route: "launch" | "live";
110
+ receipt?: "unavailable" | "required";
111
+ deliveredAt: string;
112
+ }>;
92
113
  export type TellFact = Readonly<{
114
+ kind: "tell";
115
+ sequence: number;
93
116
  id: string;
94
117
  body: string;
95
- state: TellState;
96
118
  recordedAt: string;
97
- }>;
119
+ state: "pending" | "told";
120
+ deliveries: readonly TellDelivery[];
121
+ }>;
122
+ export type TellDeliveryInput = Readonly<{
123
+ tellId: string;
124
+ turnSequence: number;
125
+ fence: string;
126
+ deliveredAt: string;
127
+ }> & (Readonly<{
128
+ route: "launch";
129
+ }> | Readonly<{
130
+ route: "live";
131
+ receipt: "unavailable" | "required";
132
+ }>);
133
+ export type TellReceiptInput = Readonly<{
134
+ kind: string;
135
+ receivedAt: string;
136
+ }> & (Readonly<{
137
+ evidence: "exact";
138
+ tellId: string;
139
+ }> | Readonly<{
140
+ evidence: "fence";
141
+ turnSequence: number;
142
+ fence: string;
143
+ }>);
98
144
  export type RequestInput = Readonly<{
99
145
  id: string;
100
146
  archetype: string;
@@ -120,11 +166,17 @@ export type RequestFact = RequestInput & Readonly<{
120
166
  state: "voided";
121
167
  evidence: string;
122
168
  }>);
123
- export type KillEvidence = "killed" | "already-dead" | "alive-after-sigkill" | "unavailable";
124
- export type DeathFact = Readonly<{
125
- evidence: KillEvidence;
169
+ export type KillEvidence = "killed" | "already-killed" | "alive-after-sigkill" | "unavailable";
170
+ export type KillFact = Readonly<{
171
+ sequence: number;
172
+ bodySequence: number;
173
+ evidence: "killed";
126
174
  at: string;
127
175
  }>;
176
+ export type StopFact = Readonly<{
177
+ bodySequence: number;
178
+ requestedAt: string;
179
+ }>;
128
180
  export type SealFact = Readonly<{
129
181
  evidence: string;
130
182
  at: string;
@@ -139,12 +191,12 @@ export type CollarProbe = Readonly<{
139
191
  kind: "unverifiable";
140
192
  diagnostic: string;
141
193
  }>;
142
- export type AkumaLife = "running" | "asleep" | "stranded" | "headless" | "dead";
194
+ export type AkumaLife = "running" | "asleep" | "stranded" | "headless" | "killed";
143
195
  export type HeartSnapshot = Readonly<{
144
196
  soul: Soul | null;
145
197
  latestBody: BodyFact | null;
146
198
  latestSession: SessionFact | null;
147
199
  pending: readonly TellFact[];
148
- death: DeathFact | null;
200
+ latestKill: KillFact | null;
149
201
  }>;
150
- export declare function life(leashProbe: LeashProbe, collarProbe: CollarProbe, deathRow: DeathFact | null): AkumaLife;
202
+ export declare function life(leashProbe: LeashProbe, collarProbe: CollarProbe, latestBody: BodyFact | null, latestKill: KillFact | null): AkumaLife;
@@ -1,9 +1,9 @@
1
- export function life(leashProbe, collarProbe, deathRow) {
2
- if (deathRow !== null)
3
- return "dead";
1
+ export function life(leashProbe, collarProbe, latestBody, latestKill) {
4
2
  if (leashProbe === "held")
5
3
  return "running";
6
4
  if (collarProbe.kind !== "gone")
7
5
  return "headless";
6
+ if (latestBody !== null && latestKill?.bodySequence === latestBody.sequence)
7
+ return "killed";
8
8
  return collarProbe.end === "exited" ? "asleep" : "stranded";
9
9
  }