@astrosheep/keiyaku 4.5.11 → 4.5.13

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 (272) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +135 -377
  2. package/build/integrations/pi/keiyaku.ts +11 -116
  3. package/build/src/akuma/akuma-errors.d.ts +1 -0
  4. package/build/src/akuma/akuma-errors.js +1 -0
  5. package/build/src/akuma/akuma-handle.d.ts +1 -0
  6. package/build/src/akuma/akuma-handle.js +6 -7
  7. package/build/src/akuma/akuma-product.d.ts +6 -8
  8. package/build/src/akuma/akuma-product.js +141 -57
  9. package/build/src/akuma/akuma.d.ts +5 -7
  10. package/build/src/akuma/akuma.js +1 -22
  11. package/build/src/akuma/archetype.d.ts +6 -5
  12. package/build/src/akuma/archetype.js +137 -38
  13. package/build/src/akuma/body.d.ts +5 -5
  14. package/build/src/akuma/body.js +223 -63
  15. package/build/src/akuma/call-input.d.ts +4 -0
  16. package/build/src/akuma/call-input.js +21 -0
  17. package/build/src/akuma/call-request.d.ts +5 -8
  18. package/build/src/akuma/call-request.js +28 -73
  19. package/build/src/akuma/fleet-execution.d.ts +26 -0
  20. package/build/src/akuma/fleet-execution.js +109 -0
  21. package/build/src/{library/fleet-result.d.ts → akuma/fleet-observation.d.ts} +13 -57
  22. package/build/src/{library/fleet-result.js → akuma/fleet-observation.js} +4 -25
  23. package/build/src/akuma/fleet-request.d.ts +122 -0
  24. package/build/src/akuma/fleet-request.js +168 -0
  25. package/build/src/akuma/heart/facts.d.ts +23 -0
  26. package/build/src/akuma/heart/facts.js +7 -0
  27. package/build/src/akuma/heart/index.d.ts +43 -4
  28. package/build/src/akuma/heart/index.js +107 -7
  29. package/build/src/akuma/heart/request-authority.d.ts +2 -0
  30. package/build/src/akuma/heart/request-authority.js +28 -3
  31. package/build/src/akuma/heart/request-rows.d.ts +2 -0
  32. package/build/src/akuma/heart/request-rows.js +24 -5
  33. package/build/src/akuma/heart/rows.d.ts +4 -1
  34. package/build/src/akuma/heart/rows.js +46 -19
  35. package/build/src/akuma/heart/schema.d.ts +1 -1
  36. package/build/src/akuma/heart/schema.js +28 -6
  37. package/build/src/akuma/heart/storage.d.ts +1 -1
  38. package/build/src/akuma/heart/tells.d.ts +29 -0
  39. package/build/src/akuma/heart/tells.js +136 -5
  40. package/build/src/akuma/heart/timeline.js +9 -3
  41. package/build/src/akuma/projection-read.js +36 -3
  42. package/build/src/akuma/projection.js +3 -4
  43. package/build/src/akuma/provider.d.ts +4 -0
  44. package/build/src/akuma/provider.js +56 -3
  45. package/build/src/akuma/providers/claude/index.js +3 -0
  46. package/build/src/akuma/providers/codex-app-server/index.js +14 -12
  47. package/build/src/akuma/providers/pi/index.js +7 -1
  48. package/build/src/akuma/publication.js +65 -49
  49. package/build/src/akuma/request-lifecycle.d.ts +5 -4
  50. package/build/src/akuma/request-lifecycle.js +29 -16
  51. package/build/src/akuma/request-rendezvous.d.ts +15 -12
  52. package/build/src/akuma/request-rendezvous.js +80 -51
  53. package/build/src/akuma/request-serve.d.ts +1 -2
  54. package/build/src/akuma/request-serve.js +94 -39
  55. package/build/src/akuma/request-wire.d.ts +57 -26
  56. package/build/src/akuma/request-wire.js +64 -25
  57. package/build/src/akuma/turn-drive.d.ts +5 -4
  58. package/build/src/akuma/turn-drive.js +27 -11
  59. package/build/src/akuma-body.d.ts +4 -6
  60. package/build/src/akuma-body.js +19 -17
  61. package/build/src/bounded-list.d.ts +8 -0
  62. package/build/src/bounded-list.js +14 -0
  63. package/build/src/cli/accepted.d.ts +1 -1
  64. package/build/src/cli/accepted.js +1 -0
  65. package/build/src/cli/commands/akuma-invoke.js +1 -25
  66. package/build/src/cli/commands/contract-help.d.ts +5 -2
  67. package/build/src/cli/commands/contract-help.js +62 -12
  68. package/build/src/cli/commands/contract-invoke.d.ts +5 -0
  69. package/build/src/cli/commands/contract-invoke.js +26 -1
  70. package/build/src/cli/commands/contract.js +50 -18
  71. package/build/src/cli/commands/task-invoke.js +10 -2
  72. package/build/src/cli/commands/task-query.js +3 -4
  73. package/build/src/cli/coordinates.d.ts +13 -0
  74. package/build/src/cli/coordinates.js +38 -24
  75. package/build/src/cli/draft.d.ts +1 -1
  76. package/build/src/cli/invoke.js +14 -1
  77. package/build/src/cli/render/akuma-activity.d.ts +0 -1
  78. package/build/src/cli/render/akuma-activity.js +5 -38
  79. package/build/src/cli/render/akuma.js +4 -1
  80. package/build/src/cli/render/audit.js +4 -1
  81. package/build/src/cli/render/catalog.js +13 -39
  82. package/build/src/cli/render/contract.js +4 -14
  83. package/build/src/cli/render/kanshi-akuma.js +3 -8
  84. package/build/src/cli/render/kanshi.js +8 -34
  85. package/build/src/cli/render/nuke.js +7 -3
  86. package/build/src/cli/render/receipt.d.ts +1 -0
  87. package/build/src/cli/render/receipt.js +8 -0
  88. package/build/src/cli/render/refusal.js +4 -3
  89. package/build/src/cli/render/task.js +4 -37
  90. package/build/src/cli/render/terminal.d.ts +2 -6
  91. package/build/src/cli/render/terminal.js +4 -9
  92. package/build/src/cli/result.d.ts +2 -1
  93. package/build/src/contract-guidance.js +13 -3
  94. package/build/src/contract-worktree.d.ts +1 -0
  95. package/build/src/contract-worktree.js +26 -2
  96. package/build/src/core/facts/codec.d.ts +2 -1
  97. package/build/src/core/facts/codec.js +3 -0
  98. package/build/src/core/facts/gate.d.ts +2 -1
  99. package/build/src/core/facts/gate.js +63 -0
  100. package/build/src/core/verbs/abandon.d.ts +2 -1
  101. package/build/src/core/verbs/abandon.js +16 -0
  102. package/build/src/core/verbs/amend.d.ts +2 -1
  103. package/build/src/core/verbs/amend.js +20 -0
  104. package/build/src/core/verbs/arc.d.ts +2 -1
  105. package/build/src/core/verbs/arc.js +16 -0
  106. package/build/src/core/verbs/attestation.d.ts +2 -1
  107. package/build/src/core/verbs/attestation.js +16 -0
  108. package/build/src/core/verbs/bind.d.ts +2 -1
  109. package/build/src/core/verbs/bind.js +16 -0
  110. package/build/src/core/verbs/deliver.d.ts +2 -1
  111. package/build/src/core/verbs/deliver.js +16 -0
  112. package/build/src/core/verbs/placement.d.ts +2 -1
  113. package/build/src/core/verbs/placement.js +58 -1
  114. package/build/src/dispatch/association.d.ts +13 -0
  115. package/build/src/dispatch/association.js +20 -0
  116. package/build/src/dispatch/index.d.ts +6 -0
  117. package/build/src/dispatch/index.js +27 -3
  118. package/build/src/git/hooks.d.ts +9 -1
  119. package/build/src/git/hooks.js +79 -1
  120. package/build/src/git/nuke.d.ts +2 -1
  121. package/build/src/git/nuke.js +6 -11
  122. package/build/src/git/private-state-seat.d.ts +26 -1
  123. package/build/src/git/private-state-seat.js +78 -13
  124. package/build/src/git/process.d.ts +2 -0
  125. package/build/src/git/reconcile.d.ts +1 -2
  126. package/build/src/git/reconcile.js +0 -6
  127. package/build/src/git/repository.d.ts +0 -2
  128. package/build/src/git/repository.js +27 -25
  129. package/build/src/git/result-codec.d.ts +29 -0
  130. package/build/src/git/result-codec.js +306 -0
  131. package/build/src/git/target-placement.js +2 -8
  132. package/build/src/git/workspace.d.ts +2 -0
  133. package/build/src/git/workspace.js +4 -0
  134. package/build/src/index.d.ts +1 -0
  135. package/build/src/kanshi/fleet.js +1 -1
  136. package/build/src/kanshi/read.js +55 -28
  137. package/build/src/kanshi/report.d.ts +4 -3
  138. package/build/src/kanshi/select.js +14 -1
  139. package/build/src/library/address.d.ts +1 -0
  140. package/build/src/library/address.js +4 -7
  141. package/build/src/library/akuma-creation.d.ts +5 -3
  142. package/build/src/library/akuma-creation.js +90 -33
  143. package/build/src/library/audit.js +2 -1
  144. package/build/src/library/catalog.d.ts +10 -2
  145. package/build/src/library/catalog.js +65 -25
  146. package/build/src/library/composition.d.ts +1 -0
  147. package/build/src/library/composition.js +1 -0
  148. package/build/src/library/configuration.d.ts +4 -21
  149. package/build/src/library/configuration.js +2 -158
  150. package/build/src/library/continuation.d.ts +20 -1
  151. package/build/src/library/continuation.js +36 -0
  152. package/build/src/library/contract-bind.d.ts +1 -0
  153. package/build/src/library/contract-bind.js +16 -5
  154. package/build/src/library/contract-forwarding.d.ts +2 -2
  155. package/build/src/library/contract-forwarding.js +18 -4
  156. package/build/src/library/contract-handle.js +4 -3
  157. package/build/src/library/contract-operations.d.ts +5 -9
  158. package/build/src/library/contract-operations.js +34 -47
  159. package/build/src/library/contract.d.ts +11 -2
  160. package/build/src/library/contract.js +21 -1
  161. package/build/src/library/delivery.d.ts +4 -1
  162. package/build/src/library/delivery.js +47 -0
  163. package/build/src/library/fleet.d.ts +4 -136
  164. package/build/src/library/fleet.js +31 -315
  165. package/build/src/library/keiyaku.d.ts +7 -3
  166. package/build/src/library/keiyaku.js +1 -0
  167. package/build/src/library/mutation.d.ts +431 -3
  168. package/build/src/library/mutation.js +192 -19
  169. package/build/src/library/nuke.d.ts +7 -1
  170. package/build/src/library/nuke.js +18 -4
  171. package/build/src/library/reconcile.d.ts +14 -0
  172. package/build/src/library/reconcile.js +22 -8
  173. package/build/src/library/refusal.d.ts +9 -1
  174. package/build/src/library/refusal.js +76 -0
  175. package/build/src/library/region.d.ts +0 -8
  176. package/build/src/library/region.js +1 -29
  177. package/build/src/library/result-codec.d.ts +2 -0
  178. package/build/src/library/result-codec.js +12 -0
  179. package/build/src/markdown/lex.js +9 -2
  180. package/build/src/markdown/types.d.ts +2 -1
  181. package/build/src/markdown/types.js +3 -1
  182. package/build/src/plugin/akuma-signals.d.ts +12 -0
  183. package/build/src/plugin/akuma-signals.js +14 -0
  184. package/build/src/plugin/public.d.ts +51 -0
  185. package/build/src/plugin/public.js +1 -0
  186. package/build/src/plugin/runtime.d.ts +14 -0
  187. package/build/src/plugin/runtime.js +357 -0
  188. package/build/src/protocol/amend.js +3 -3
  189. package/build/src/protocol/attempt.d.ts +2 -1
  190. package/build/src/protocol/attempt.js +1 -1
  191. package/build/src/protocol/audit.d.ts +1 -1
  192. package/build/src/protocol/audit.js +1 -1
  193. package/build/src/protocol/bind.d.ts +3 -1
  194. package/build/src/protocol/bind.js +26 -0
  195. package/build/src/protocol/completion.js +0 -1
  196. package/build/src/protocol/deliver.d.ts +1 -1
  197. package/build/src/protocol/deliver.js +136 -57
  198. package/build/src/protocol/intent.d.ts +0 -1
  199. package/build/src/protocol/intent.js +0 -1
  200. package/build/src/protocol/operations.d.ts +9 -2
  201. package/build/src/protocol/operations.js +16 -1
  202. package/build/src/protocol/outcome.d.ts +3 -0
  203. package/build/src/protocol/outcome.js +17 -1
  204. package/build/src/protocol/placement.js +10 -3
  205. package/build/src/protocol/read/status.d.ts +8 -0
  206. package/build/src/protocol/read/status.js +49 -0
  207. package/build/src/protocol/reintegrate.js +10 -3
  208. package/build/src/protocol/result-codec.d.ts +22 -0
  209. package/build/src/protocol/result-codec.js +442 -0
  210. package/build/src/protocol/review.d.ts +1 -1
  211. package/build/src/protocol/review.js +81 -46
  212. package/build/src/protocol/run.d.ts +22 -2
  213. package/build/src/protocol/run.js +119 -29
  214. package/build/src/runtime/proc/lifecycle.js +1 -1
  215. package/build/src/runtime/proc/line-rpc.d.ts +7 -1
  216. package/build/src/runtime/proc/line-rpc.js +49 -9
  217. package/build/src/runtime/proc/run.d.ts +0 -1
  218. package/build/src/runtime/proc/run.js +1 -11
  219. package/build/src/runtime/proc/termination.d.ts +1 -0
  220. package/build/src/runtime/proc/termination.js +63 -18
  221. package/build/src/runtime/proc/windows-launch.exe +0 -0
  222. package/build/src/settings.d.ts +10 -0
  223. package/build/src/settings.js +88 -2
  224. package/build/src/settlement/result-codec.d.ts +2 -0
  225. package/build/src/settlement/result-codec.js +56 -0
  226. package/build/src/settlement/settle.d.ts +5 -12
  227. package/build/src/settlement/settle.js +60 -55
  228. package/build/src/task/board.d.ts +3 -0
  229. package/build/src/task/board.js +22 -4
  230. package/build/src/task/catalog.d.ts +13 -2
  231. package/build/src/task/catalog.js +59 -5
  232. package/build/src/task/compose.d.ts +4 -2
  233. package/build/src/task/compose.js +56 -30
  234. package/build/src/task/created-observation.d.ts +39 -0
  235. package/build/src/task/created-observation.js +26 -0
  236. package/build/src/task/identity.d.ts +6 -0
  237. package/build/src/task/identity.js +48 -7
  238. package/build/src/task/index.d.ts +4 -3
  239. package/build/src/task/index.js +19 -16
  240. package/build/src/task/input.d.ts +3 -1
  241. package/build/src/task/input.js +7 -4
  242. package/build/src/task/lifecycle-operations.d.ts +6 -0
  243. package/build/src/task/lifecycle-operations.js +116 -0
  244. package/build/src/task/mutation-result.d.ts +762 -20
  245. package/build/src/task/mutation-result.js +34 -9
  246. package/build/src/task/mutation.d.ts +4 -9
  247. package/build/src/task/mutation.js +17 -52
  248. package/build/src/task/operation-types.d.ts +114 -0
  249. package/build/src/task/operation-types.js +1 -0
  250. package/build/src/task/operations.d.ts +6 -113
  251. package/build/src/task/operations.js +75 -117
  252. package/build/src/task/query.d.ts +8 -11
  253. package/build/src/task/query.js +7 -14
  254. package/build/src/task/store.d.ts +11 -1
  255. package/build/src/task/store.js +169 -55
  256. package/build/src/task/view.d.ts +4 -0
  257. package/build/src/task/view.js +7 -0
  258. package/build/src/verification/declaration.d.ts +1 -0
  259. package/build/src/verification/declaration.js +18 -1
  260. package/build/src/verification/execution.d.ts +0 -1
  261. package/build/src/verification/execution.js +5 -5
  262. package/build/src/world.d.ts +0 -2
  263. package/build/src/world.js +3 -7
  264. package/package.json +17 -5
  265. package/build/src/cli/square-edge.d.ts +0 -7
  266. package/build/src/cli/square-edge.js +0 -159
  267. package/build/src/git/ref-migration.d.ts +0 -22
  268. package/build/src/git/ref-migration.js +0 -55
  269. package/build/src/library/contract-forwarding-reconciliation-result.d.ts +0 -102
  270. package/build/src/library/contract-forwarding-reconciliation-result.js +0 -92
  271. package/build/src/library/contract-forwarding-result.d.ts +0 -4270
  272. package/build/src/library/contract-forwarding-result.js +0 -521
@@ -2,6 +2,7 @@ import { HeldAkumaLeash, initializeHeart, readHeart, readSeal, readSoul } from "
2
2
  import { allocateAkumaDirectory } from "./identity.js";
3
3
  import { abortableDelay } from "./abort.js";
4
4
  const POLL_MS = 100;
5
+ const CUSTODY_HANDOFF_MS = 1_000;
5
6
  export const BIRTH_TIMEOUT_MS = 30_000;
6
7
  function diagnostic(error) {
7
8
  return error instanceof Error ? error.message : String(error);
@@ -43,24 +44,6 @@ async function observedBirthFailure(paths) {
43
44
  function preAdmissionDiagnostic(exit) {
44
45
  return exit.code === null ? `pre-admission signal ${exit.signal ?? "unknown"}` : `pre-admission exit ${exit.code}`;
45
46
  }
46
- async function sealObservedExit(paths, exit) {
47
- const evidence = preAdmissionDiagnostic(exit);
48
- try {
49
- const leash = await HeldAkumaLeash.try(paths);
50
- if (leash !== null) {
51
- try {
52
- await leash.sealIfUnborn(paths, { evidence, at: new Date().toISOString() });
53
- }
54
- finally {
55
- leash.release();
56
- }
57
- }
58
- }
59
- catch {
60
- /* Parent evidence remains authoritative when best-effort sealing fails. */
61
- }
62
- throw new Error(evidence);
63
- }
64
47
  async function observeSettledExit(owned) {
65
48
  if (owned === undefined)
66
49
  return { kind: "pending" };
@@ -73,6 +56,21 @@ async function observeSettledExit(owned) {
73
56
  return { kind: "exit-error", error };
74
57
  }
75
58
  }
59
+ async function observeExitWithin(owned, milliseconds) {
60
+ return await Promise.race([
61
+ owned.exited.then((exit) => ({ kind: "exited", exit }), (error) => ({ kind: "exit-error", error })),
62
+ abortableDelay(milliseconds).then(() => ({ kind: "timeout" })),
63
+ ]);
64
+ }
65
+ async function attemptTermination(owned, force = false) {
66
+ const outcome = await Promise.race([
67
+ Promise.resolve()
68
+ .then(() => owned.terminate(force))
69
+ .then(() => ({ kind: "terminated" }), (error) => ({ kind: "error", error })),
70
+ abortableDelay(CUSTODY_HANDOFF_MS).then(() => ({ kind: "timeout" })),
71
+ ]);
72
+ return outcome.kind === "error" ? outcome.error : undefined;
73
+ }
76
74
  async function awaitBirth(paths, owned, signal) {
77
75
  const deadline = performance.now() + BIRTH_TIMEOUT_MS;
78
76
  for (;;) {
@@ -84,7 +82,7 @@ async function awaitBirth(paths, owned, signal) {
84
82
  if (failure !== null) {
85
83
  const settled = await observeSettledExit(owned);
86
84
  if (settled.kind === "exited")
87
- await sealObservedExit(paths, settled.exit);
85
+ throw new Error(preAdmissionDiagnostic(settled.exit));
88
86
  if (settled.kind === "exit-error")
89
87
  throw new Error(diagnostic(settled.error));
90
88
  throw new Error(failure);
@@ -94,7 +92,7 @@ async function awaitBirth(paths, owned, signal) {
94
92
  if (settled !== null)
95
93
  return settled;
96
94
  if (owned !== undefined)
97
- await owned.terminate(true);
95
+ await attemptTermination(owned, true);
98
96
  throw new Error("Akuma birth timed out before Soul admission");
99
97
  }
100
98
  if (owned === undefined) {
@@ -111,8 +109,7 @@ async function awaitBirth(paths, owned, signal) {
111
109
  const settledSoul = await readSoul(paths);
112
110
  if (settledSoul !== null)
113
111
  return settledSoul;
114
- await sealObservedExit(paths, outcome.exit);
115
- continue;
112
+ throw new Error(preAdmissionDiagnostic(outcome.exit));
116
113
  }
117
114
  throw new Error(diagnostic(outcome.error));
118
115
  }
@@ -127,14 +124,6 @@ async function takeLeashUntil(paths, deadline) {
127
124
  await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
128
125
  }
129
126
  }
130
- async function takeLeash(paths) {
131
- for (;;) {
132
- const leash = await HeldAkumaLeash.try(paths);
133
- if (leash !== null)
134
- return leash;
135
- await abortableDelay(POLL_MS);
136
- }
137
- }
138
127
  async function allocatedSoul(allocated) {
139
128
  const soul = await readSoul(allocated.paths);
140
129
  if (soul === null)
@@ -143,30 +132,54 @@ async function allocatedSoul(allocated) {
143
132
  throw new Error("Akuma birth returned a different identity");
144
133
  return soul;
145
134
  }
146
- async function awaitConfirmation(result) {
147
- try {
148
- await result;
149
- }
150
- catch {
151
- await new Promise(() => { });
152
- }
135
+ function settlementEvidence(primary, terminationError, exitError) {
136
+ const reason = primary === undefined || primary === null ? "" : diagnostic(primary).trim();
137
+ if (reason.length > 0)
138
+ return reason;
139
+ const details = [terminationError, exitError]
140
+ .filter((error) => error !== undefined)
141
+ .map((error) => diagnostic(error).trim())
142
+ .filter((detail) => detail.length > 0);
143
+ return details[0] ?? "Akuma publication failed";
153
144
  }
154
- async function settleCancelledLaunch(allocated, owned, cancellation) {
145
+ async function settleLaunch(allocated, owned, failure) {
155
146
  if ((await readSoul(allocated.paths)) !== null) {
156
147
  await allocatedSoul(allocated);
148
+ const settled = await observeExitWithin(owned, CUSTODY_HANDOFF_MS);
149
+ if (settled.kind === "timeout") {
150
+ const leash = await HeldAkumaLeash.try(allocated.paths);
151
+ if (leash === null)
152
+ return "handoff";
153
+ leash.release();
154
+ }
155
+ if (settled.kind === "exit-error")
156
+ throw failure;
157
157
  return "born";
158
158
  }
159
- await awaitConfirmation(owned.terminate());
160
- await awaitConfirmation(owned.exited);
159
+ let terminationError;
160
+ let exitError;
161
+ let outcome;
162
+ const preAdmissionExit = diagnostic(failure).startsWith("pre-admission ");
163
+ const settled = preAdmissionExit ? await observeSettledExit(owned) : { kind: "pending" };
164
+ if (settled.kind !== "exited") {
165
+ terminationError = await attemptTermination(owned);
166
+ const exit = await observeSettledExit(owned);
167
+ if (exit.kind === "exit-error")
168
+ exitError = exit.error;
169
+ }
170
+ else {
171
+ /* An already-settled pre-admission exit needs no second termination request. */
172
+ }
161
173
  if ((await readSoul(allocated.paths)) !== null) {
162
174
  await allocatedSoul(allocated);
163
175
  return "born";
164
176
  }
165
- const leash = await takeLeash(allocated.paths);
166
- let outcome;
177
+ const leash = await HeldAkumaLeash.try(allocated.paths);
178
+ if (leash === null)
179
+ return "handoff";
167
180
  try {
168
181
  outcome = await leash.sealIfUnborn(allocated.paths, {
169
- evidence: diagnostic(cancellation),
182
+ evidence: settlementEvidence(failure, terminationError, exitError),
170
183
  at: new Date().toISOString(),
171
184
  });
172
185
  }
@@ -242,19 +255,22 @@ export async function launchAkuma(input) {
242
255
  return allocated;
243
256
  }
244
257
  catch (error) {
245
- if (owned !== undefined && input.signal?.aborted && error === input.signal.reason) {
246
- const outcome = await settleCancelledLaunch(allocated, owned, error);
247
- if (outcome === "born") {
258
+ if (owned !== undefined) {
259
+ let outcome;
260
+ try {
261
+ outcome = await settleLaunch(allocated, owned, error);
262
+ }
263
+ finally {
264
+ owned.release();
265
+ }
266
+ if (outcome === "born" && input.signal?.aborted && error === input.signal.reason) {
248
267
  if (input.awaitAsleep === true)
249
268
  await awaitAsleepBirth(allocated.paths);
250
- owned.release();
251
269
  return allocated;
252
270
  }
253
- owned.release();
254
271
  throw error;
255
272
  }
256
273
  await sealLocalFailure(allocated, error);
257
- owned?.release();
258
274
  throw error;
259
275
  }
260
276
  }
@@ -1,13 +1,11 @@
1
- import { type Soul } from "./heart/index.js";
1
+ import { type RequestFact, type Soul } from "./heart/index.js";
2
2
  import { type AkumaPaths } from "./identity.js";
3
3
  import { type RequestEnvelope } from "./request-wire.js";
4
4
  export type PumpInput = Readonly<{
5
5
  paths: AkumaPaths;
6
- parent: Soul;
6
+ allowed: readonly string[];
7
7
  bodySequence: number;
8
8
  now(): string;
9
- spawn(launch: unknown): Promise<unknown>;
10
- upstream?: unknown;
11
9
  signal: AbortSignal;
12
10
  }>;
13
11
  type ServeClaim = (input: PumpInput & Readonly<{
@@ -35,5 +33,8 @@ export declare class BodyRequestPump {
35
33
  stopAdmission(): void;
36
34
  }
37
35
  export declare function clearBodyRequestTransport(paths: AkumaPaths): Promise<void>;
36
+ export declare function settleReserved(paths: AkumaPaths, parent: Soul, request: Extract<RequestFact, {
37
+ state: "reserved";
38
+ }>, now: () => string, signal?: AbortSignal): Promise<boolean>;
38
39
  export declare function settleBodyRequests(paths: AkumaPaths, parent: Soul, now: () => string, signal?: AbortSignal): Promise<"settled" | "pending">;
39
40
  export {};
@@ -1,7 +1,7 @@
1
1
  import { access, mkdir, readFile, readdir, rm } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { abortableDelay } from "./abort.js";
4
- import { HeldAkumaLeash, readNonterminalRequests, readSoul, serveRequest, voidRequest, } from "./heart/index.js";
4
+ import { HeldAkumaLeash, readNonterminalRequests, readSoul, serveRequest, unproveRequest, voidRequest, } from "./heart/index.js";
5
5
  import { pathsForAkuId, worldRootForAkumaPaths } from "./identity.js";
6
6
  import { BIRTH_TIMEOUT_MS } from "./publication.js";
7
7
  import { decodeEnvelope } from "./request-wire.js";
@@ -77,6 +77,8 @@ export class BodyRequestPump {
77
77
  }
78
78
  async close() {
79
79
  this.stopAdmission();
80
+ if (!this.executionSignal.signal.aborted)
81
+ this.executionSignal.abort(new Error("Body request pump closed"));
80
82
  try {
81
83
  await this.running;
82
84
  }
@@ -112,14 +114,34 @@ async function settleReservedSoul(paths, parent, request, soul) {
112
114
  ? serveRequest(paths, request.id, request.child)
113
115
  : voidRequest(paths, request.id, "reserved child origin does not match the request"));
114
116
  }
115
- async function settleReserved(paths, parent, request, now, signal) {
117
+ async function settleReservedWithLeash(paths, parent, request, leash, now) {
118
+ const childPaths = pathsForAkuId(worldRootForAkumaPaths(paths), request.child);
119
+ try {
120
+ const settled = await readSoul(childPaths);
121
+ if (settled !== null) {
122
+ await settleReservedSoul(paths, parent, request, settled);
123
+ return;
124
+ }
125
+ const outcome = await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
126
+ if (outcome === "sealed") {
127
+ await voidRequest(paths, request.id, "reserved child was sealed unborn");
128
+ return;
129
+ }
130
+ const born = await readSoul(childPaths);
131
+ if (born !== null)
132
+ await settleReservedSoul(paths, parent, request, born);
133
+ }
134
+ finally {
135
+ leash.release();
136
+ }
137
+ }
138
+ export async function settleReserved(paths, parent, request, now, signal) {
116
139
  const childPaths = pathsForAkuId(worldRootForAkumaPaths(paths), request.child);
117
140
  const deadline = performance.now() + BIRTH_TIMEOUT_MS;
118
141
  for (;;) {
119
142
  signal?.throwIfAborted();
120
143
  if (!(await access(childPaths.directory).then(() => true, () => false))) {
121
- await voidRequest(paths, request.id, "reserved child directory is absent");
122
- return true;
144
+ return false;
123
145
  }
124
146
  const soul = await readSoul(childPaths);
125
147
  if (soul !== null) {
@@ -128,18 +150,7 @@ async function settleReserved(paths, parent, request, now, signal) {
128
150
  }
129
151
  const leash = await HeldAkumaLeash.try(childPaths);
130
152
  if (leash !== null) {
131
- try {
132
- const settled = await readSoul(childPaths);
133
- if (settled !== null)
134
- await settleReservedSoul(paths, parent, request, settled);
135
- else {
136
- await leash.sealIfUnborn(childPaths, { evidence: "request settlement", at: now() });
137
- await voidRequest(paths, request.id, "reserved child was sealed unborn");
138
- }
139
- }
140
- finally {
141
- leash.release();
142
- }
153
+ await settleReservedWithLeash(paths, parent, request, leash, now);
143
154
  return true;
144
155
  }
145
156
  if (performance.now() >= deadline)
@@ -155,6 +166,8 @@ export async function settleBodyRequests(paths, parent, now, signal) {
155
166
  await voidRequest(paths, request.id, "body died before serving the request");
156
167
  else if (request.state === "reserved" && !(await settleReserved(paths, parent, request, now, signal)))
157
168
  pending = true;
169
+ else if (request.state === "begun")
170
+ await unproveRequest(paths, request.id, "body died after service request began");
158
171
  }
159
172
  return pending ? "pending" : "settled";
160
173
  }
@@ -1,19 +1,13 @@
1
- import { type RequestCommand } from "./request-wire.js";
1
+ import { type RequestProtocol } from "./request-wire.js";
2
2
  export declare class AkumaBodyRequestError extends Error {
3
3
  readonly action: string;
4
- readonly outcome: "refused" | "voided";
4
+ readonly outcome: "refused" | "voided" | "unproven" | "unknown";
5
5
  readonly diagnostic: string;
6
+ readonly requestId: string;
6
7
  readonly kind = "akuma-body-request";
7
- constructor(action: string, outcome: "refused" | "voided", diagnostic: string);
8
+ constructor(action: string, outcome: "refused" | "voided" | "unproven" | "unknown", diagnostic: string, requestId: string);
8
9
  }
9
- /** Generic rendezvous only: operation owners supply their own request and result codecs. */
10
- export declare function requestBodyCommand<Input, Output, Service, Reference = Service>(input: Readonly<{
11
- directory: string;
12
- id?: string;
13
- command: RequestCommand<Input, Output, Service, Reference>;
14
- value: Input;
15
- signal?: AbortSignal;
16
- }>): Promise<Readonly<{
10
+ type RequestResponse<Output, Reference> = Readonly<{
17
11
  kind: "returned";
18
12
  result: Output;
19
13
  requestId: string;
@@ -23,4 +17,13 @@ export declare function requestBodyCommand<Input, Output, Service, Reference = S
23
17
  reference: Reference;
24
18
  requestId: string;
25
19
  action: string;
26
- }>>;
20
+ }>;
21
+ /** Generic rendezvous only: operation owners supply their own request and result codecs. */
22
+ export declare function requestBodyCommand<Input, Output, Reference>(input: Readonly<{
23
+ directory: string;
24
+ id?: string;
25
+ command: RequestProtocol<Input, Output, Reference>;
26
+ value: Input;
27
+ signal?: AbortSignal;
28
+ }>): Promise<RequestResponse<Output, Reference>>;
29
+ export {};
@@ -7,20 +7,25 @@ export class AkumaBodyRequestError extends Error {
7
7
  action;
8
8
  outcome;
9
9
  diagnostic;
10
+ requestId;
10
11
  kind = "akuma-body-request";
11
- constructor(action, outcome, diagnostic) {
12
- super(`${action} ${outcome === "voided" ? "failed" : "refused"}: ${diagnostic}`);
12
+ constructor(action, outcome, diagnostic, requestId) {
13
+ super(`${action} ${outcome === "refused" ? "refused" : outcome}: ${diagnostic}`);
13
14
  this.action = action;
14
15
  this.outcome = outcome;
15
16
  this.diagnostic = diagnostic;
17
+ this.requestId = requestId;
16
18
  this.name = "AkumaBodyRequestError";
17
19
  }
18
20
  }
19
- function throwVoidedRequestFailure(action, evidence, failure, decodeFailure) {
21
+ function throwVoidedRequestFailure(action, evidence, failure, decodeFailure, requestId) {
20
22
  const ownerFailure = decodeVoidedOwnerFailure(failure, decodeFailure);
21
23
  if (ownerFailure !== null)
22
- throw ownerFailure;
23
- throw new AkumaBodyRequestError(action, "voided", evidence);
24
+ throw withRequestMetadata(ownerFailure, requestId, action);
25
+ throw new AkumaBodyRequestError(action, "voided", evidence, requestId);
26
+ }
27
+ function throwUnprovenRequestFailure(action, evidence, requestId) {
28
+ throw new AkumaBodyRequestError(action, "unproven", evidence, requestId);
24
29
  }
25
30
  function decodeVoidedOwnerFailure(failure, decodeFailure) {
26
31
  if (failure === undefined || decodeFailure === undefined)
@@ -39,62 +44,86 @@ function withRequestMetadata(response, id, action) {
39
44
  });
40
45
  return response;
41
46
  }
47
+ async function readRequestReceipt(input, path, id) {
48
+ try {
49
+ const receipt = decodeReceiptEnvelope(await readFile(path, "utf8"), id, input.command.action);
50
+ if (receipt === null)
51
+ throw new Error(`Akuma body request ${id} has an invalid receipt`);
52
+ if (receipt.state === "refused") {
53
+ throw new AkumaBodyRequestError(receipt.action, "refused", receipt.diagnostic, receipt.id);
54
+ }
55
+ if (receipt.state === "voided") {
56
+ throwVoidedRequestFailure(receipt.action, receipt.evidence, receipt.failure, input.command.decodeFailure, receipt.id);
57
+ }
58
+ if (receipt.state === "unproven")
59
+ throwUnprovenRequestFailure(receipt.action, receipt.evidence, receipt.id);
60
+ if ("reference" in receipt) {
61
+ let reference;
62
+ try {
63
+ reference = input.command.decodeReference(receipt.reference);
64
+ }
65
+ catch (error) {
66
+ const diagnostic = error instanceof Error ? error.message : String(error);
67
+ throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid durable reference: ${diagnostic}`);
68
+ }
69
+ return withRequestMetadata({ kind: "reference", reference }, id, input.command.action);
70
+ }
71
+ if (receipt.outcome.kind === "failed") {
72
+ const failure = receipt.outcome.failure;
73
+ throw new Error(failure.kind === "failed" ? failure.diagnostic : `Akuma ${failure.id} was not born`);
74
+ }
75
+ let result;
76
+ try {
77
+ result = input.command.decodeResult(receipt.outcome.result);
78
+ }
79
+ catch (error) {
80
+ const diagnostic = error instanceof Error ? error.message : String(error);
81
+ throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid live result: ${diagnostic}`);
82
+ }
83
+ return withRequestMetadata({ kind: "returned", result }, id, input.command.action);
84
+ }
85
+ catch (error) {
86
+ if (error.code === "ENOENT")
87
+ return undefined;
88
+ throw error;
89
+ }
90
+ }
42
91
  /** Generic rendezvous only: operation owners supply their own request and result codecs. */
43
92
  export async function requestBodyCommand(input) {
44
93
  const id = input.id ?? randomUUID();
45
94
  input.signal?.throwIfAborted();
46
95
  const transportId = randomUUID();
47
- await atomicJson(requestPath(input.directory, transportId), {
48
- id,
49
- action: input.command.action,
50
- payload: input.command.encodeRequest(input.value),
51
- });
96
+ const payload = input.command.encodeRequest(input.value);
97
+ try {
98
+ await atomicJson(requestPath(input.directory, transportId), {
99
+ id,
100
+ action: input.command.action,
101
+ payload,
102
+ }, input.signal);
103
+ }
104
+ catch (error) {
105
+ if (error.code !== "ENOENT")
106
+ throw error;
107
+ if (input.signal?.aborted)
108
+ input.signal.throwIfAborted();
109
+ throw new AkumaBodyRequestError(input.command.action, "unknown", "parent request channel closed before request publication", id);
110
+ }
52
111
  const path = receiptPath(input.directory, transportId);
53
112
  for (;;) {
113
+ const response = await readRequestReceipt(input, path, id);
114
+ if (response !== undefined)
115
+ return response;
116
+ if (!(await access(input.directory).then(() => true, () => false))) {
117
+ throw new AkumaBodyRequestError(input.command.action, "unknown", "parent request channel closed before a receipt", id);
118
+ }
54
119
  try {
55
- const receipt = decodeReceiptEnvelope(await readFile(path, "utf8"), id, input.command.action);
56
- if (receipt === null)
57
- throw new Error(`Akuma body request ${id} has an invalid receipt`);
58
- if (receipt.state === "refused")
59
- throw new AkumaBodyRequestError(receipt.action, "refused", receipt.diagnostic);
60
- if (receipt.state === "voided") {
61
- throwVoidedRequestFailure(receipt.action, receipt.evidence, receipt.failure, input.command.decodeFailure);
62
- }
63
- if ("reference" in receipt) {
64
- let reference;
65
- try {
66
- reference = input.command.decodeReference(receipt.reference);
67
- }
68
- catch (error) {
69
- const diagnostic = error instanceof Error ? error.message : String(error);
70
- throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid durable reference: ${diagnostic}`);
71
- }
72
- return withRequestMetadata({
73
- kind: "reference",
74
- reference,
75
- }, id, input.command.action);
76
- }
77
- if (receipt.outcome.kind === "failed") {
78
- const failure = receipt.outcome.failure;
79
- throw new Error(failure.kind === "failed" ? failure.diagnostic : `Akuma ${failure.id} was not born`);
80
- }
81
- let result;
82
- try {
83
- result = input.command.decodeResult(receipt.outcome.result);
84
- }
85
- catch (error) {
86
- const diagnostic = error instanceof Error ? error.message : String(error);
87
- throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid live result: ${diagnostic}`);
88
- }
89
- return withRequestMetadata({ kind: "returned", result }, id, input.command.action);
120
+ await abortableDelay(POLL_MS, input.signal);
90
121
  }
91
122
  catch (error) {
92
- if (error.code !== "ENOENT")
93
- throw error;
94
- }
95
- if (!(await access(input.directory).then(() => true, () => false))) {
96
- throw new AkumaBodyRequestError(input.command.action, "voided", "parent request channel closed before a receipt");
123
+ if (input.signal?.aborted) {
124
+ throw new AkumaBodyRequestError(input.command.action, "unknown", "request was cancelled after publication and before a receipt", id);
125
+ }
126
+ throw error;
97
127
  }
98
- await abortableDelay(POLL_MS, input.signal);
99
128
  }
100
129
  }
@@ -1,8 +1,7 @@
1
1
  import { type ErasedRequestCommand, type RequestEnvelope } from "./request-wire.js";
2
2
  import { BodyRequestPump as LifecycleBodyRequestPump, type PumpInput as LifecyclePumpInput } from "./request-lifecycle.js";
3
3
  export { clearBodyRequestTransport, settleBodyRequests } from "./request-lifecycle.js";
4
- type PumpInput = Omit<LifecyclePumpInput, "upstream"> & Readonly<{
5
- upstream?: unknown;
4
+ type PumpInput = LifecyclePumpInput & Readonly<{
6
5
  commands: Readonly<Record<string, ErasedRequestCommand>>;
7
6
  }>;
8
7
  export type ServeInput = Omit<PumpInput, "bodySequence"> & Readonly<{