@astrosheep/keiyaku 4.0.5 → 4.0.6

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 (153) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +10 -4
  8. package/build/src/akuma/akuma.d.ts +2 -0
  9. package/build/src/akuma/akuma.js +26 -3
  10. package/build/src/akuma/archetype.d.ts +3 -1
  11. package/build/src/akuma/archetype.js +11 -6
  12. package/build/src/akuma/body-turn.d.ts +64 -0
  13. package/build/src/akuma/body-turn.js +449 -0
  14. package/build/src/akuma/body.d.ts +3 -7
  15. package/build/src/akuma/body.js +9 -420
  16. package/build/src/akuma/heart/facts.d.ts +2 -0
  17. package/build/src/akuma/heart/facts.js +3 -1
  18. package/build/src/akuma/heart/index.js +12 -2
  19. package/build/src/akuma/heart/rows.js +4 -1
  20. package/build/src/akuma/heart/schema.d.ts +1 -1
  21. package/build/src/akuma/heart/schema.js +3 -2
  22. package/build/src/akuma/heart/timeline.d.ts +1 -0
  23. package/build/src/akuma/heart/timeline.js +19 -0
  24. package/build/src/akuma/nuke.d.ts +2 -0
  25. package/build/src/akuma/nuke.js +152 -0
  26. package/build/src/akuma/provider.d.ts +3 -1
  27. package/build/src/akuma/providers/acp/config.d.ts +8 -0
  28. package/build/src/akuma/providers/acp/config.js +37 -0
  29. package/build/src/akuma/providers/acp/core.js +6 -0
  30. package/build/src/akuma/providers/acp/index.d.ts +1 -8
  31. package/build/src/akuma/providers/acp/index.js +2 -37
  32. package/build/src/akuma/providers/claude/index.js +5 -0
  33. package/build/src/akuma/providers/codex-app-server/index.js +5 -0
  34. package/build/src/akuma/providers/grok-build/index.js +1 -1
  35. package/build/src/akuma/providers/index.d.ts +3 -2
  36. package/build/src/akuma/providers/index.js +36 -36
  37. package/build/src/akuma/providers/opencode-sdk/index.js +6 -0
  38. package/build/src/akuma/providers/opencode-sdk/session.d.ts +1 -1
  39. package/build/src/akuma/providers/opencode-sdk/session.js +1 -1
  40. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  41. package/build/src/akuma/providers/pi/index.js +27 -11
  42. package/build/src/akuma/request-serve.d.ts +1 -0
  43. package/build/src/akuma/request-serve.js +31 -31
  44. package/build/src/akuma/request-wire.d.ts +3 -2
  45. package/build/src/akuma/request-wire.js +5 -2
  46. package/build/src/akuma-body.js +15 -1
  47. package/build/src/alias/index.d.ts +1 -0
  48. package/build/src/alias/index.js +34 -1
  49. package/build/src/cli/accepted.js +4 -0
  50. package/build/src/cli/commands/akuma-invoke.js +1 -0
  51. package/build/src/cli/commands/akuma.d.ts +1 -0
  52. package/build/src/cli/commands/akuma.js +11 -8
  53. package/build/src/cli/commands/contract.d.ts +25 -14
  54. package/build/src/cli/commands/contract.js +23 -17
  55. package/build/src/cli/commands/install.d.ts +2 -2
  56. package/build/src/cli/commands/install.js +6 -6
  57. package/build/src/cli/commands/nuke.d.ts +10 -0
  58. package/build/src/cli/commands/nuke.js +20 -0
  59. package/build/src/cli/commands/task-invoke.d.ts +15 -0
  60. package/build/src/cli/commands/task-invoke.js +57 -26
  61. package/build/src/cli/commands/task-query.d.ts +2 -2
  62. package/build/src/cli/commands/task-query.js +1 -2
  63. package/build/src/cli/commands/task.js +22 -22
  64. package/build/src/cli/coordinates.d.ts +5 -2
  65. package/build/src/cli/coordinates.js +5 -52
  66. package/build/src/cli/invoke.d.ts +5 -4
  67. package/build/src/cli/invoke.js +89 -59
  68. package/build/src/cli/main.d.ts +0 -2
  69. package/build/src/cli/main.js +4 -140
  70. package/build/src/cli/parse.d.ts +15 -2
  71. package/build/src/cli/parse.js +73 -8
  72. package/build/src/cli/render/akuma.js +55 -40
  73. package/build/src/cli/render/contract.js +49 -48
  74. package/build/src/cli/render/kanshi.js +15 -5
  75. package/build/src/cli/render/nuke.d.ts +3 -0
  76. package/build/src/cli/render/nuke.js +8 -0
  77. package/build/src/cli/render/refusal.d.ts +2 -1
  78. package/build/src/cli/render/refusal.js +31 -0
  79. package/build/src/cli/render/text.js +6 -1
  80. package/build/src/cli/result.d.ts +21 -2
  81. package/build/src/cli/runtime.d.ts +2 -0
  82. package/build/src/cli/runtime.js +140 -0
  83. package/build/src/cli/usage.d.ts +0 -2
  84. package/build/src/cli/usage.js +0 -4
  85. package/build/src/contract-worktree.d.ts +28 -12
  86. package/build/src/contract-worktree.js +129 -63
  87. package/build/src/git/hooks.d.ts +2 -0
  88. package/build/src/git/hooks.js +34 -1
  89. package/build/src/git/integration.d.ts +4 -0
  90. package/build/src/git/integration.js +38 -0
  91. package/build/src/git/nuke.d.ts +2 -0
  92. package/build/src/git/nuke.js +97 -0
  93. package/build/src/git/process.d.ts +2 -0
  94. package/build/src/git/reconcile.d.ts +2 -0
  95. package/build/src/git/reconcile.js +33 -2
  96. package/build/src/git/repository.js +4 -1
  97. package/build/src/git/target-placement.d.ts +2 -1
  98. package/build/src/git/target-placement.js +6 -7
  99. package/build/src/git/tender.d.ts +1 -0
  100. package/build/src/git/tender.js +2 -2
  101. package/build/src/git/workspace.d.ts +3 -0
  102. package/build/src/kanshi/read.js +5 -1
  103. package/build/src/library/akuma-creation.d.ts +1 -0
  104. package/build/src/library/akuma-creation.js +8 -1
  105. package/build/src/library/audit.d.ts +1 -0
  106. package/build/src/library/audit.js +1 -0
  107. package/build/src/library/contract.d.ts +6 -4
  108. package/build/src/library/contract.js +56 -34
  109. package/build/src/library/delivery.d.ts +3 -1
  110. package/build/src/library/keiyaku.d.ts +5 -1
  111. package/build/src/library/keiyaku.js +2 -0
  112. package/build/src/library/mutation.d.ts +1 -0
  113. package/build/src/library/mutation.js +3 -0
  114. package/build/src/library/nuke.d.ts +14 -0
  115. package/build/src/library/nuke.js +54 -0
  116. package/build/src/library/reconcile.js +5 -2
  117. package/build/src/library/refusal.d.ts +10 -1
  118. package/build/src/library/repo.d.ts +1 -0
  119. package/build/src/library/repo.js +2 -0
  120. package/build/src/protocol/audit.js +12 -5
  121. package/build/src/protocol/completion.d.ts +11 -1
  122. package/build/src/protocol/completion.js +68 -15
  123. package/build/src/protocol/deliver.d.ts +14 -2
  124. package/build/src/protocol/deliver.js +107 -6
  125. package/build/src/protocol/intent.d.ts +1 -0
  126. package/build/src/protocol/intent.js +7 -1
  127. package/build/src/protocol/operations.d.ts +30 -3
  128. package/build/src/protocol/operations.js +2 -2
  129. package/build/src/protocol/placement.d.ts +9 -1
  130. package/build/src/protocol/placement.js +5 -4
  131. package/build/src/protocol/read/status.d.ts +16 -4
  132. package/build/src/protocol/read/status.js +54 -12
  133. package/build/src/protocol/review.d.ts +1 -0
  134. package/build/src/protocol/review.js +8 -0
  135. package/build/src/runtime/proc/run.js +9 -5
  136. package/build/src/settlement/fence.d.ts +2 -0
  137. package/build/src/settlement/fence.js +24 -0
  138. package/build/src/settlement/settle.js +1 -2
  139. package/build/src/task/compose.d.ts +1 -1
  140. package/build/src/task/compose.js +2 -7
  141. package/build/src/task/context.d.ts +14 -2
  142. package/build/src/task/context.js +30 -7
  143. package/build/src/task/index.d.ts +6 -5
  144. package/build/src/task/index.js +15 -18
  145. package/build/src/task/mutation.d.ts +7 -2
  146. package/build/src/task/mutation.js +14 -6
  147. package/build/src/task/operations.d.ts +12 -6
  148. package/build/src/task/operations.js +22 -46
  149. package/build/src/task/store.d.ts +1 -0
  150. package/build/src/task/store.js +91 -1
  151. package/build/src/workspace-place.d.ts +2 -0
  152. package/build/src/workspace-place.js +27 -1
  153. package/package.json +1 -1
@@ -0,0 +1,449 @@
1
+ import { abortableDelay } from "./abort.js";
2
+ import { appendActivity, beginTurn, breakBody, heartExists, readHeart, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
3
+ import { encodeAgentEvent, } from "./provider.js";
4
+ import { BodyRequestPump, } from "./request-serve.js";
5
+ const BODY_CONTROL_OBSERVATION_MS = 100;
6
+ export const CONTROL_RESPONSE_MS = 1_000;
7
+ export class BodySupervisor {
8
+ paths;
9
+ bodySequence;
10
+ leash;
11
+ signal;
12
+ controller = new AbortController();
13
+ finished = new AbortController();
14
+ observer;
15
+ waiter;
16
+ observation;
17
+ stopping;
18
+ constructor(paths, bodySequence, leash, observation) {
19
+ this.paths = paths;
20
+ this.bodySequence = bodySequence;
21
+ this.leash = leash;
22
+ this.signal = this.controller.signal;
23
+ this.observation = observation;
24
+ this.observer = this.observe();
25
+ }
26
+ static async open(paths, bodySequence, leash) {
27
+ return new BodySupervisor(paths, bodySequence, leash, await readHeart(paths));
28
+ }
29
+ get reason() { return this.stopping; }
30
+ current() { return this.observation; }
31
+ async recordHung(diagnostic, at) {
32
+ await this.leash.recordBodyHung(this.paths, { sequence: this.bodySequence, diagnostic, at });
33
+ }
34
+ async refresh() {
35
+ this.publish(await readHeart(this.paths));
36
+ return this.observation;
37
+ }
38
+ next(after) {
39
+ if (this.observation !== after)
40
+ return Promise.resolve(this.observation);
41
+ return new Promise((resolve) => { this.waiter = resolve; });
42
+ }
43
+ cancel(reason) {
44
+ if (this.stopping !== undefined)
45
+ return;
46
+ this.stopping = reason;
47
+ this.controller.abort(new Error(reason === "control"
48
+ ? "Akuma Body interrupted by durable control"
49
+ : "Akuma Heart disappeared"));
50
+ this.waiter?.(this.observation);
51
+ this.waiter = undefined;
52
+ }
53
+ async close() {
54
+ this.finished.abort();
55
+ await this.observer;
56
+ this.waiter = undefined;
57
+ }
58
+ publish(snapshot) {
59
+ this.observation = snapshot;
60
+ this.waiter?.(snapshot);
61
+ this.waiter = undefined;
62
+ }
63
+ async observe() {
64
+ for (;;) {
65
+ const snapshot = this.observation;
66
+ if (!await heartExists(this.paths))
67
+ return this.cancel("heart-gone");
68
+ if (snapshot.stop?.bodySequence === this.bodySequence || snapshot.pause?.bodySequence === this.bodySequence) {
69
+ return this.cancel("control");
70
+ }
71
+ try {
72
+ await abortableDelay(BODY_CONTROL_OBSERVATION_MS, this.finished.signal);
73
+ }
74
+ catch {
75
+ return;
76
+ }
77
+ try {
78
+ await this.refresh();
79
+ }
80
+ catch (error) {
81
+ if (await heartExists(this.paths))
82
+ throw error;
83
+ return this.cancel("heart-gone");
84
+ }
85
+ }
86
+ }
87
+ }
88
+ function serializeEffects() {
89
+ let tail = Promise.resolve();
90
+ let failed = false;
91
+ let failure;
92
+ const serialize = async (effect) => {
93
+ const result = tail.then(effect);
94
+ tail = result.then(() => undefined, (error) => {
95
+ if (!failed)
96
+ failure = error;
97
+ failed = true;
98
+ });
99
+ return await result;
100
+ };
101
+ serialize.drain = async () => {
102
+ await tail;
103
+ if (failed)
104
+ throw failure;
105
+ };
106
+ return serialize;
107
+ }
108
+ export async function turnRecipe(paths, soul) {
109
+ const latest = (await readHeart(paths)).latestSession;
110
+ const admitted = latest?.provider === soul.provider.name ? latest : undefined;
111
+ const session = admitted?.coordinate;
112
+ return {
113
+ cwd: admitted?.cwd ?? soul.cwd,
114
+ options: admitted?.options ?? soul.options,
115
+ ...(session === undefined ? {} : { session }),
116
+ };
117
+ }
118
+ async function failedTurnSetup(input, turnSequence, requests, cancelDrive, error) {
119
+ try {
120
+ await requests.close();
121
+ }
122
+ catch { /* Preserve the setup or pump failure. */ }
123
+ input.supervisor.signal.removeEventListener("abort", cancelDrive);
124
+ if (input.supervisor.signal.aborted) {
125
+ if (input.supervisor.reason === "heart-gone")
126
+ throw error;
127
+ return { kind: "stopped" };
128
+ }
129
+ return {
130
+ kind: "failed",
131
+ turnSequence,
132
+ diagnostic: error instanceof Error ? error.message : String(error),
133
+ };
134
+ }
135
+ async function writeProviderEvent(input, active, event) {
136
+ if (input.supervisor.signal.aborted)
137
+ return;
138
+ const at = input.now();
139
+ if (event.type === "session") {
140
+ await recordSession(input.paths, {
141
+ provider: input.soul.provider.name,
142
+ coordinate: event.coordinate,
143
+ cwd: active.cwd,
144
+ options: active.options,
145
+ admittedAt: at,
146
+ });
147
+ }
148
+ await appendActivity(input.paths, {
149
+ turnSequence: active.turnSequence,
150
+ event: encodeAgentEvent(event),
151
+ at,
152
+ });
153
+ }
154
+ async function startTurnDrive(input) {
155
+ const { cwd, options, session } = await turnRecipe(input.paths, input.soul);
156
+ if (session !== undefined && input.adapter.resume === undefined)
157
+ return { kind: "resume-unsupported" };
158
+ const turn = await beginTurn(input.paths, {
159
+ bodySequence: input.bodySequence,
160
+ startedAt: input.now(),
161
+ ...(input.call === undefined ? {} : { call: input.call }),
162
+ });
163
+ const requests = await BodyRequestPump.open({
164
+ paths: input.paths,
165
+ parent: input.soul,
166
+ bodySequence: input.bodySequence,
167
+ now: input.now,
168
+ spawn: input.runtimeSpawn,
169
+ ...(input.upstream === undefined ? {} : { upstream: input.upstream }),
170
+ signal: input.supervisor.signal,
171
+ });
172
+ const driveController = new AbortController();
173
+ const cancelDrive = () => {
174
+ if (!driveController.signal.aborted)
175
+ driveController.abort(input.supervisor.signal.reason);
176
+ };
177
+ input.supervisor.signal.addEventListener("abort", cancelDrive, { once: true });
178
+ if (input.supervisor.signal.aborted)
179
+ cancelDrive();
180
+ void requests.failure.catch((error) => {
181
+ if (!driveController.signal.aborted)
182
+ driveController.abort(error);
183
+ });
184
+ const driveInput = {
185
+ body: input.body,
186
+ launchTells: input.launchTells.map((tell) => ({ id: tell.id, text: tell.body })),
187
+ cwd,
188
+ options,
189
+ signal: driveController.signal,
190
+ requests: { dir: requests.directory },
191
+ };
192
+ const setup = session === undefined
193
+ ? input.adapter.start({ ...driveInput, session: { kind: "fresh" } })
194
+ : input.adapter.resume({ ...driveInput, session: { kind: "resume", coordinate: session } });
195
+ try {
196
+ const selected = await Promise.race([setup, requests.failure]);
197
+ if (input.supervisor.signal.aborted) {
198
+ try {
199
+ const retirement = await retireProviderCustody(input, turn.sequence, selected);
200
+ await requests.close();
201
+ if (retirement.kind === "hung")
202
+ return retirement;
203
+ }
204
+ finally {
205
+ input.supervisor.signal.removeEventListener("abort", cancelDrive);
206
+ }
207
+ return { kind: "stopped" };
208
+ }
209
+ if (input.launchTells.length > 0) {
210
+ await recordTellDeliveries(input.paths, input.launchTells.map((tell) => ({
211
+ tellId: tell.id,
212
+ route: "launch",
213
+ turnSequence: turn.sequence,
214
+ fence: selected.admission.fence,
215
+ deliveredAt: input.now(),
216
+ })));
217
+ }
218
+ void selected.completion.then(() => requests.stopAdmission());
219
+ return {
220
+ turnSequence: turn.sequence,
221
+ drive: selected,
222
+ requests,
223
+ cwd,
224
+ options,
225
+ releaseDriveSignal: () => input.supervisor.signal.removeEventListener("abort", cancelDrive),
226
+ ...(session === undefined ? {} : { resume: session }),
227
+ };
228
+ }
229
+ catch (error) {
230
+ return await failedTurnSetup(input, turn.sequence, requests, cancelDrive, error);
231
+ }
232
+ }
233
+ async function retireProviderCustody(input, turnSequence, drive) {
234
+ const dispose = async (operation) => await Promise.race([
235
+ operation().then(() => ({ kind: "retired" }), (error) => ({ kind: "held", error })),
236
+ abortableDelay(CONTROL_RESPONSE_MS).then(() => ({
237
+ kind: "held",
238
+ error: new Error(`provider custody remained live after ${CONTROL_RESPONSE_MS}ms`),
239
+ })),
240
+ ]);
241
+ let outcome = await dispose(drive.abort);
242
+ if (outcome.kind === "retired")
243
+ return outcome;
244
+ outcome = await dispose(drive.forceDispose);
245
+ if (outcome.kind === "retired")
246
+ return outcome;
247
+ if (await heartExists(input.paths)) {
248
+ const diagnostic = outcome.error instanceof Error ? outcome.error.message : String(outcome.error);
249
+ const at = input.now();
250
+ try {
251
+ await input.supervisor.recordHung(diagnostic, at);
252
+ await appendActivity(input.paths, {
253
+ turnSequence,
254
+ event: encodeAgentEvent({ type: "note", text: `Provider custody was not retired: ${diagnostic}` }),
255
+ at,
256
+ });
257
+ }
258
+ catch { /* Undisposed provider custody still owns the leash. */ }
259
+ }
260
+ await breakBody(input.paths, { sequence: input.bodySequence, end: "broke-off", at: input.now() });
261
+ return { kind: "hung" };
262
+ }
263
+ function pumpReceipts(writers) {
264
+ const { input, turnSequence, drive, writeWitness, mayWrite } = writers;
265
+ return (async () => {
266
+ if (drive.receipts === undefined)
267
+ return;
268
+ for await (const receipt of drive.receipts) {
269
+ if (!mayWrite())
270
+ return;
271
+ await writeWitness(async () => {
272
+ if (!mayWrite())
273
+ return;
274
+ await recordTellReceipt(input.paths, receipt.evidence === "exact"
275
+ ? { ...receipt, receivedAt: input.now() }
276
+ : { ...receipt, turnSequence, receivedAt: input.now() });
277
+ });
278
+ }
279
+ })();
280
+ }
281
+ function observeReceiptFailure(receiptPump) {
282
+ return receiptPump.then(() => new Promise(() => { }), (error) => Promise.reject(error));
283
+ }
284
+ async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
285
+ const { input, turnSequence, drive, writeWitness, mayWrite } = writers;
286
+ for (const tell of pending) {
287
+ if (attempted.has(tell.id))
288
+ continue;
289
+ attempted.add(tell.id);
290
+ const outcome = await writeWitness(async () => {
291
+ const submission = await tellLive({ id: tell.id, text: tell.body });
292
+ if (!mayWrite() || submission.kind === "turn-ended")
293
+ return "turn-ended";
294
+ await recordTellDeliveries(input.paths, [{
295
+ tellId: tell.id,
296
+ route: "live",
297
+ turnSequence,
298
+ fence: submission.fence,
299
+ receipt: drive.receipts === undefined ? "unavailable" : "required",
300
+ deliveredAt: input.now(),
301
+ }]);
302
+ return "accepted";
303
+ });
304
+ if (outcome === "turn-ended")
305
+ return outcome;
306
+ }
307
+ return "live";
308
+ }
309
+ async function stopActiveDrive(input, active) {
310
+ try {
311
+ const retirement = await retireProviderCustody(input, active.turnSequence, active.drive);
312
+ await active.requests.close();
313
+ return retirement;
314
+ }
315
+ finally {
316
+ active.releaseDriveSignal();
317
+ }
318
+ }
319
+ function hasUnattemptedTell(liveTells, tellPump, pending, attempted) {
320
+ return liveTells && tellPump === null && pending.some((tell) => !attempted.has(tell.id));
321
+ }
322
+ async function settleCompletion(result, session, active) {
323
+ try {
324
+ await active.requests.close();
325
+ return result.kind === "answered" ? { ...result, ...(session === undefined ? {} : { session }) } : result;
326
+ }
327
+ finally {
328
+ active.releaseDriveSignal();
329
+ }
330
+ }
331
+ async function consumeTurnDrive(input, active) {
332
+ const { turnSequence, drive, requests, resume } = active;
333
+ let heart = input.supervisor.current();
334
+ let turnSession = resume;
335
+ const attempted = new Set(input.launchTells.map((tell) => tell.id));
336
+ const writeWitness = serializeEffects();
337
+ let writesOpen = true;
338
+ const mayWrite = () => writesOpen && !input.supervisor.signal.aborted;
339
+ const writers = { input, turnSequence, drive, writeWitness, mayWrite };
340
+ const receiptFailure = observeReceiptFailure(pumpReceipts(writers));
341
+ const iterator = drive.events[Symbol.asyncIterator]();
342
+ let pending = iterator.next();
343
+ let liveTells = true;
344
+ let tellPump = null;
345
+ let tellObservation = null;
346
+ try {
347
+ for (;;) {
348
+ if (input.supervisor.signal.aborted) {
349
+ writesOpen = false;
350
+ const retirement = await stopActiveDrive(input, active);
351
+ return retirement.kind === "hung" ? retirement : { kind: "stopped" };
352
+ }
353
+ if (hasUnattemptedTell(liveTells, tellPump, heart.pending, attempted)) {
354
+ if (drive.tell === undefined) {
355
+ writesOpen = false;
356
+ const retirement = await stopActiveDrive(input, active);
357
+ return retirement.kind === "hung" ? retirement : { kind: "handoff" };
358
+ }
359
+ tellPump = submitPendingLiveTells(writers, heart.pending, attempted, drive.tell);
360
+ tellObservation = tellPump.then((result) => ({ kind: "tell", result }));
361
+ }
362
+ const next = await Promise.race([
363
+ pending.then((event) => ({ kind: "event", event })),
364
+ input.supervisor.next(heart).then((observation) => ({ kind: "heart", observation })),
365
+ ...(tellObservation === null ? [] : [tellObservation]),
366
+ receiptFailure,
367
+ requests.failure,
368
+ ]);
369
+ if (next.kind === "heart") {
370
+ heart = next.observation;
371
+ continue;
372
+ }
373
+ if (next.kind === "tell") {
374
+ tellPump = null;
375
+ tellObservation = null;
376
+ liveTells = next.result === "live";
377
+ continue;
378
+ }
379
+ if (next.event.done)
380
+ break;
381
+ await writeProviderEvent(input, active, next.event.value);
382
+ if (next.event.value.type === "session")
383
+ turnSession = next.event.value.coordinate;
384
+ pending = iterator.next();
385
+ }
386
+ const result = await drive.completion;
387
+ if (tellPump !== null)
388
+ await tellPump;
389
+ await writeWitness.drain();
390
+ writesOpen = false;
391
+ return await settleCompletion(result, turnSession, active);
392
+ }
393
+ catch (error) {
394
+ writesOpen = false;
395
+ if (input.supervisor.signal.aborted) {
396
+ const retirement = await stopActiveDrive(input, active);
397
+ return retirement.kind === "hung" ? retirement : { kind: "stopped" };
398
+ }
399
+ const retirement = await retireProviderCustody(input, turnSequence, drive);
400
+ try {
401
+ await requests.close();
402
+ }
403
+ catch { /* Preserve the first pump failure. */ }
404
+ active.releaseDriveSignal();
405
+ if (retirement.kind === "hung")
406
+ return retirement;
407
+ return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
408
+ }
409
+ }
410
+ export async function driveTurn(input) {
411
+ let active;
412
+ try {
413
+ const started = await startTurnDrive(input);
414
+ if ("kind" in started)
415
+ return started;
416
+ active = started;
417
+ }
418
+ catch (error) {
419
+ if (!await heartExists(input.paths)) {
420
+ input.supervisor.cancel("heart-gone");
421
+ return { kind: "stopped" };
422
+ }
423
+ throw error;
424
+ }
425
+ try {
426
+ const result = await consumeTurnDrive(input, active);
427
+ return result.kind === "stopped" || result.kind === "hung" || result.kind === "handoff"
428
+ ? result
429
+ : { ...result, turnSequence: active.turnSequence };
430
+ }
431
+ catch (error) {
432
+ if (await heartExists(input.paths)) {
433
+ try {
434
+ await active.requests.close();
435
+ }
436
+ finally {
437
+ active.releaseDriveSignal();
438
+ }
439
+ return {
440
+ kind: "failed",
441
+ diagnostic: error instanceof Error ? error.message : String(error),
442
+ turnSequence: active.turnSequence,
443
+ };
444
+ }
445
+ input.supervisor.cancel("heart-gone");
446
+ const retirement = await stopActiveDrive(input, active);
447
+ return retirement.kind === "hung" ? retirement : { kind: "stopped" };
448
+ }
449
+ }
@@ -1,8 +1,8 @@
1
1
  import { type SessionFact, type Soul } from "./heart/index.js";
2
2
  import type { AkumaPaths } from "./identity.js";
3
- import { type ProviderAdapter } from "./provider.js";
3
+ import type { ProviderAdapter } from "./provider.js";
4
4
  import { type UpstreamExecutionPort, type RequestChildLaunch } from "./request-serve.js";
5
- export declare const CONTROL_RESPONSE_MS = 1000;
5
+ export { CONTROL_RESPONSE_MS } from "./body-turn.js";
6
6
  export type BodyLaunch = Readonly<{
7
7
  paths: AkumaPaths;
8
8
  seed?: Omit<Soul, "createdAt">;
@@ -16,8 +16,4 @@ type BodyRuntime = Readonly<{
16
16
  }>;
17
17
  export declare function driveAkumaBody(launch: BodyLaunch, adapter?: ProviderAdapter, runtime?: BodyRuntime): Promise<void>;
18
18
  export declare function spawnAkumaBody(launch: BodyLaunch): Promise<void>;
19
- export declare function runAkumaBody(upstreamFor: (launch: BodyLaunch, configuration: Readonly<{
20
- home?: string;
21
- gitPath?: string;
22
- }>) => UpstreamExecutionPort): Promise<void>;
23
- export {};
19
+ export declare function runAkumaBody(launch: BodyLaunch, upstream: UpstreamExecutionPort): Promise<void>;