@astrosheep/keiyaku 4.0.1 → 4.0.2

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 (245) hide show
  1. package/README.md +137 -5
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -35
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +98 -58
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +152 -53
  9. package/build/src/akuma/abort.d.ts +2 -0
  10. package/build/src/akuma/abort.js +50 -0
  11. package/build/src/akuma/akuma.d.ts +23 -14
  12. package/build/src/akuma/akuma.js +120 -104
  13. package/build/src/akuma/archetype.d.ts +7 -6
  14. package/build/src/akuma/archetype.js +68 -41
  15. package/build/src/akuma/body.d.ts +3 -5
  16. package/build/src/akuma/body.js +408 -213
  17. package/build/src/akuma/heart/facts.d.ts +25 -34
  18. package/build/src/akuma/heart/facts.js +18 -7
  19. package/build/src/akuma/heart/index.d.ts +39 -42
  20. package/build/src/akuma/heart/index.js +134 -93
  21. package/build/src/akuma/heart/rows.d.ts +9 -31
  22. package/build/src/akuma/heart/rows.js +26 -44
  23. package/build/src/akuma/heart/schema.d.ts +1 -1
  24. package/build/src/akuma/heart/schema.js +7 -15
  25. package/build/src/akuma/heart/soul.d.ts +8 -0
  26. package/build/src/akuma/heart/soul.js +136 -0
  27. package/build/src/akuma/heart/storage.d.ts +28 -14
  28. package/build/src/akuma/heart/storage.js +86 -26
  29. package/build/src/akuma/identity.d.ts +2 -2
  30. package/build/src/akuma/identity.js +9 -9
  31. package/build/src/akuma/index.d.ts +6 -1
  32. package/build/src/akuma/index.js +6 -0
  33. package/build/src/akuma/projection.d.ts +117 -38
  34. package/build/src/akuma/projection.js +208 -97
  35. package/build/src/akuma/provider-recipe.d.ts +24 -0
  36. package/build/src/akuma/provider-recipe.js +100 -0
  37. package/build/src/akuma/provider.d.ts +12 -4
  38. package/build/src/akuma/provider.js +117 -70
  39. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  40. package/build/src/akuma/providers/acp/core.js +159 -0
  41. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  42. package/build/src/akuma/providers/acp/events.js +73 -0
  43. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  44. package/build/src/akuma/providers/acp/index.js +94 -0
  45. package/build/src/akuma/providers/claude/events.js +66 -13
  46. package/build/src/akuma/providers/claude/index.d.ts +2 -1
  47. package/build/src/akuma/providers/claude/index.js +35 -21
  48. package/build/src/akuma/providers/codex-app-server/events.js +4 -1
  49. package/build/src/akuma/providers/codex-app-server/index.d.ts +3 -3
  50. package/build/src/akuma/providers/codex-app-server/index.js +24 -31
  51. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  52. package/build/src/akuma/providers/grok-build/index.js +70 -0
  53. package/build/src/akuma/providers/index.d.ts +5 -3
  54. package/build/src/akuma/providers/index.js +24 -59
  55. package/build/src/akuma/providers/opencode-sdk/events.d.ts +40 -34
  56. package/build/src/akuma/providers/opencode-sdk/events.js +220 -101
  57. package/build/src/akuma/providers/opencode-sdk/index.d.ts +3 -2
  58. package/build/src/akuma/providers/opencode-sdk/index.js +233 -128
  59. package/build/src/akuma/providers/opencode-sdk/session.d.ts +11 -26
  60. package/build/src/akuma/providers/opencode-sdk/session.js +10 -9
  61. package/build/src/akuma/providers/pi/events.js +49 -11
  62. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  63. package/build/src/akuma/providers/pi/index.js +50 -21
  64. package/build/src/akuma/publication.d.ts +3 -3
  65. package/build/src/akuma/publication.js +28 -40
  66. package/build/src/akuma/requests.d.ts +9 -7
  67. package/build/src/akuma/requests.js +92 -65
  68. package/build/src/alias/index.d.ts +2 -2
  69. package/build/src/alias/index.js +10 -10
  70. package/build/src/body/decode.js +7 -1
  71. package/build/src/body/region.d.ts +2 -0
  72. package/build/src/body/region.js +77 -7
  73. package/build/src/cli/accepted.d.ts +17 -13
  74. package/build/src/cli/accepted.js +72 -34
  75. package/build/src/cli/actor.js +3 -3
  76. package/build/src/cli/commands/akuma-invoke.d.ts +4 -3
  77. package/build/src/cli/commands/akuma-invoke.js +14 -9
  78. package/build/src/cli/commands/akuma.d.ts +13 -3
  79. package/build/src/cli/commands/akuma.js +67 -34
  80. package/build/src/cli/commands/contract.d.ts +18 -5
  81. package/build/src/cli/commands/contract.js +9 -3
  82. package/build/src/cli/commands/task-invoke.d.ts +17 -4
  83. package/build/src/cli/commands/task-invoke.js +43 -20
  84. package/build/src/cli/commands/task-query.d.ts +5 -0
  85. package/build/src/cli/commands/task-query.js +247 -0
  86. package/build/src/cli/commands/task.d.ts +3 -1
  87. package/build/src/cli/commands/task.js +51 -13
  88. package/build/src/cli/coordinates.d.ts +18 -0
  89. package/build/src/cli/coordinates.js +120 -0
  90. package/build/src/cli/draft.d.ts +8 -0
  91. package/build/src/cli/draft.js +96 -0
  92. package/build/src/cli/invoke.d.ts +4 -3
  93. package/build/src/cli/invoke.js +160 -179
  94. package/build/src/cli/main.js +34 -6
  95. package/build/src/cli/parse.d.ts +9 -2
  96. package/build/src/cli/parse.js +29 -7
  97. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  98. package/build/src/cli/render/akuma-tool-command.js +144 -0
  99. package/build/src/cli/render/akuma-tool.d.ts +2 -2
  100. package/build/src/cli/render/akuma-tool.js +30 -4
  101. package/build/src/cli/render/akuma.d.ts +1 -0
  102. package/build/src/cli/render/akuma.js +211 -116
  103. package/build/src/cli/render/audit.d.ts +3 -0
  104. package/build/src/cli/render/audit.js +104 -0
  105. package/build/src/cli/render/contract.d.ts +3 -3
  106. package/build/src/cli/render/contract.js +192 -79
  107. package/build/src/cli/render/kanshi.js +263 -168
  108. package/build/src/cli/render/receipt.d.ts +19 -0
  109. package/build/src/cli/render/receipt.js +106 -0
  110. package/build/src/cli/render/refusal.d.ts +16 -2
  111. package/build/src/cli/render/refusal.js +88 -20
  112. package/build/src/cli/render/region.d.ts +2 -0
  113. package/build/src/cli/render/region.js +17 -0
  114. package/build/src/cli/render/task.d.ts +2 -1
  115. package/build/src/cli/render/task.js +223 -60
  116. package/build/src/cli/render/terminal.d.ts +7 -0
  117. package/build/src/cli/render/terminal.js +46 -0
  118. package/build/src/cli/render/text.js +6 -3
  119. package/build/src/cli/result.d.ts +115 -20
  120. package/build/src/cli/usage.d.ts +1 -0
  121. package/build/src/cli/usage.js +3 -0
  122. package/build/src/contract-worktree.d.ts +6 -5
  123. package/build/src/contract-worktree.js +95 -57
  124. package/build/src/coordination/durable-file.d.ts +4 -3
  125. package/build/src/coordination/durable-file.js +29 -25
  126. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  127. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  128. package/build/src/core/facts/fold.js +1 -6
  129. package/build/src/core/facts/gate.d.ts +1 -0
  130. package/build/src/core/facts/gate.js +1 -0
  131. package/build/src/core/verbs/amend.d.ts +1 -1
  132. package/build/src/core/verbs/amend.js +0 -11
  133. package/build/src/core/verbs/deliver.d.ts +1 -1
  134. package/build/src/core/verbs/deliver.js +1 -7
  135. package/build/src/core/verbs/placement.d.ts +1 -1
  136. package/build/src/core/verbs/placement.js +4 -1
  137. package/build/src/dispatch/index.d.ts +2 -2
  138. package/build/src/dispatch/index.js +17 -17
  139. package/build/src/git/admission.d.ts +1 -1
  140. package/build/src/git/admission.js +11 -11
  141. package/build/src/git/hooks.js +13 -13
  142. package/build/src/git/integration.d.ts +14 -15
  143. package/build/src/git/integration.js +80 -44
  144. package/build/src/git/observe.d.ts +5 -3
  145. package/build/src/git/observe.js +18 -12
  146. package/build/src/git/read-observation.js +9 -9
  147. package/build/src/git/reconcile.d.ts +2 -0
  148. package/build/src/git/reconcile.js +138 -95
  149. package/build/src/git/repository.d.ts +27 -19
  150. package/build/src/git/repository.js +155 -83
  151. package/build/src/git/scratch.d.ts +7 -3
  152. package/build/src/git/scratch.js +44 -37
  153. package/build/src/git/target-placement.d.ts +40 -4
  154. package/build/src/git/target-placement.js +221 -101
  155. package/build/src/git/tender.d.ts +6 -5
  156. package/build/src/git/tender.js +24 -43
  157. package/build/src/git/terminal-seal.d.ts +1 -1
  158. package/build/src/git/terminal-seal.js +7 -5
  159. package/build/src/git/workspace.d.ts +36 -4
  160. package/build/src/git/workspace.js +53 -18
  161. package/build/src/identity/selector.js +1 -1
  162. package/build/src/index.d.ts +3 -3
  163. package/build/src/index.js +1 -1
  164. package/build/src/kanshi/index.d.ts +2 -2
  165. package/build/src/kanshi/index.js +1 -1
  166. package/build/src/kanshi/read.d.ts +2 -1
  167. package/build/src/kanshi/read.js +118 -27
  168. package/build/src/kanshi/report.d.ts +50 -0
  169. package/build/src/kanshi/select.d.ts +5 -0
  170. package/build/src/kanshi/select.js +32 -0
  171. package/build/src/library/address.d.ts +12 -3
  172. package/build/src/library/address.js +77 -46
  173. package/build/src/library/akuma-creation.d.ts +6 -1
  174. package/build/src/library/akuma-creation.js +86 -13
  175. package/build/src/library/audit.d.ts +18 -0
  176. package/build/src/library/audit.js +44 -0
  177. package/build/src/library/bind.js +4 -4
  178. package/build/src/library/catalog.d.ts +1 -1
  179. package/build/src/library/catalog.js +5 -8
  180. package/build/src/library/contract.d.ts +5 -6
  181. package/build/src/library/contract.js +11 -35
  182. package/build/src/library/delivery.d.ts +2 -1
  183. package/build/src/library/fleet.d.ts +2 -2
  184. package/build/src/library/fleet.js +35 -71
  185. package/build/src/library/keiyaku.d.ts +3 -2
  186. package/build/src/library/keiyaku.js +1 -0
  187. package/build/src/library/mutation.d.ts +7 -6
  188. package/build/src/library/mutation.js +23 -25
  189. package/build/src/library/reconcile.d.ts +29 -0
  190. package/build/src/library/reconcile.js +179 -0
  191. package/build/src/library/region.d.ts +12 -0
  192. package/build/src/library/region.js +15 -1
  193. package/build/src/library/repo.d.ts +4 -16
  194. package/build/src/library/repo.js +13 -38
  195. package/build/src/protocol/attempt.js +6 -6
  196. package/build/src/protocol/bind.js +4 -4
  197. package/build/src/protocol/intent.d.ts +15 -2
  198. package/build/src/protocol/intent.js +21 -6
  199. package/build/src/protocol/operations.d.ts +73 -22
  200. package/build/src/protocol/operations.js +292 -88
  201. package/build/src/protocol/outcome.d.ts +9 -3
  202. package/build/src/protocol/outcome.js +3 -1
  203. package/build/src/protocol/placement.d.ts +15 -4
  204. package/build/src/protocol/placement.js +58 -25
  205. package/build/src/protocol/read/status.d.ts +8 -1
  206. package/build/src/protocol/read/status.js +61 -14
  207. package/build/src/runtime/proc/line-rpc.d.ts +3 -8
  208. package/build/src/runtime/proc/line-rpc.js +16 -43
  209. package/build/src/runtime/proc/run.d.ts +15 -29
  210. package/build/src/runtime/proc/run.js +113 -105
  211. package/build/src/runtime/proc/stdio.d.ts +18 -0
  212. package/build/src/runtime/proc/stdio.js +58 -0
  213. package/build/src/settings.d.ts +2 -2
  214. package/build/src/settings.js +8 -8
  215. package/build/src/settlement/fence.d.ts +0 -4
  216. package/build/src/settlement/fence.js +0 -9
  217. package/build/src/settlement/holder.d.ts +11 -1
  218. package/build/src/settlement/holder.js +25 -0
  219. package/build/src/settlement/settle.d.ts +1 -1
  220. package/build/src/settlement/settle.js +52 -89
  221. package/build/src/task/board.d.ts +3 -3
  222. package/build/src/task/board.js +6 -9
  223. package/build/src/task/compose.d.ts +1 -1
  224. package/build/src/task/compose.js +18 -10
  225. package/build/src/task/context.d.ts +3 -3
  226. package/build/src/task/context.js +14 -14
  227. package/build/src/task/document.d.ts +2 -1
  228. package/build/src/task/document.js +15 -5
  229. package/build/src/task/index.d.ts +19 -7
  230. package/build/src/task/index.js +42 -23
  231. package/build/src/task/operations.d.ts +15 -9
  232. package/build/src/task/operations.js +78 -48
  233. package/build/src/task/query.d.ts +67 -0
  234. package/build/src/task/query.js +279 -0
  235. package/build/src/task/store.d.ts +2 -2
  236. package/build/src/task/store.js +40 -25
  237. package/build/src/verification/execution.d.ts +4 -2
  238. package/build/src/verification/execution.js +9 -5
  239. package/build/src/workspace-place.d.ts +41 -0
  240. package/build/src/workspace-place.js +386 -0
  241. package/build/src/world.d.ts +13 -2
  242. package/build/src/world.js +81 -48
  243. package/package.json +3 -2
  244. package/build/src/protocol/read/audit.d.ts +0 -31
  245. package/build/src/protocol/read/audit.js +0 -55
@@ -1,18 +1,16 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { readdirSync } from "node:fs";
2
+ import { readdir } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
- import { spawnAkumaBody } from "./body.js";
5
- import { HeldAkumaLeash, activitySlice, life, probeLeash, readHeart, readLastAnsweredTurn, readForkPoint, readKill, readSeal, readSoul, recordTell, requestPause, requestStop, } from "./heart/index.js";
4
+ import { CONTROL_RESPONSE_MS, spawnAkumaBody } from "./body.js";
5
+ import { HeldAkumaLeash, activitySlice, life, lifeAt, probeLeash, readHeart, readLastAnsweredTurn, readForkPoint, readKill, readSeal, readSoul, recordTell, requestPause, requestStop, } from "./heart/index.js";
6
6
  import { akuIdFromDirectoryName, akumaPaths, akumaRunRoot, parseAkuId, pathsForAkuId, archetypeName, } from "./identity.js";
7
- import { projectActivityHistory, selectActivitySnapshot, } from "./projection.js";
7
+ import { ordinarySelectedCount, ordinarySnapshotBudget, projectTurns, selectActivitySnapshot, selectHistory, selectSnapshot, } from "./projection.js";
8
8
  import { listArchetypes as readArchetypes, loadArchetype } from "./archetype.js";
9
9
  import { publishAkuma } from "./publication.js";
10
- import { providerNamed } from "./providers/index.js";
10
+ import { resolveProviderExecution } from "./providers/index.js";
11
11
  import { injectedBodyRequests, requestBodyCall } from "./requests.js";
12
- import { probeProcessTree, putDownProcessTree } from "../runtime/proc/run.js";
13
12
  import { settings as readSettings } from "../settings.js";
14
13
  const POLL_MS = 25;
15
- const KILL_GRACE_MS = 1_000;
16
14
  export class AkumaNotBornError extends Error {
17
15
  id;
18
16
  kind = "akuma-not-born";
@@ -27,7 +25,7 @@ function wait(milliseconds) {
27
25
  }
28
26
  async function takeLeashUntil(paths, deadline) {
29
27
  for (;;) {
30
- const leash = HeldAkumaLeash.try(paths);
28
+ const leash = await HeldAkumaLeash.try(paths);
31
29
  if (leash !== null)
32
30
  return leash;
33
31
  if (performance.now() >= deadline)
@@ -35,9 +33,9 @@ async function takeLeashUntil(paths, deadline) {
35
33
  await wait(POLL_MS);
36
34
  }
37
35
  }
38
- function recordTellBody(paths, akuma, body) {
36
+ async function recordTellBody(paths, akuma, body) {
39
37
  const id = randomUUID();
40
- const admitted = recordTell(paths, { kind: "tell", id, body, recordedAt: new Date().toISOString() });
38
+ const admitted = await recordTell(paths, { kind: "tell", id, body, recordedAt: new Date().toISOString() });
41
39
  if (admitted.kind === "not-born")
42
40
  throw new AkumaNotBornError(akuma);
43
41
  return { kind: "recorded", tellId: admitted.tell.id };
@@ -54,56 +52,57 @@ async function wakeTell(paths, tellId) {
54
52
  };
55
53
  }
56
54
  }
57
- function collarProbe(snapshot) {
58
- if (snapshot.latestBody === null)
59
- return { kind: "gone", end: null };
60
- const probe = probeProcessTree(snapshot.latestBody.collar);
61
- if (probe.kind === "gone")
62
- return { kind: "gone", end: snapshot.latestBody.end ?? null };
63
- return probe;
64
- }
65
- function bornListRow(paths, expected, snapshot = readHeart(paths)) {
55
+ async function bornListRow(paths, expected, snapshot) {
56
+ snapshot ??= await readHeart(paths);
66
57
  if (snapshot.soul === null)
67
58
  throw new AkumaNotBornError(expected);
68
59
  if (snapshot.soul.id !== expected)
69
60
  throw new Error("Akuma soul does not match its coordinate");
70
- const collar = collarProbe(snapshot);
61
+ const currentLife = life({
62
+ leash: await probeLeash(paths),
63
+ body: snapshot.latestBody,
64
+ kill: snapshot.latestKill,
65
+ });
71
66
  return {
72
67
  id: snapshot.soul.id,
73
68
  archetype: snapshot.soul.archetype,
74
69
  ...(snapshot.soul.description === undefined ? {} : { description: snapshot.soul.description }),
75
- life: life(probeLeash(paths), collar, snapshot.latestBody, snapshot.latestKill),
76
- collar,
70
+ life: currentLife,
71
+ lifeAt: lifeAt(currentLife, snapshot.latestBody, snapshot.latestKill, snapshot.soul.createdAt),
77
72
  confinement: snapshot.soul.confinement,
78
73
  pending: snapshot.pending.map((tell) => tell.id),
79
74
  };
80
75
  }
81
- function bornStatus(paths, expected, profile = "status") {
82
- const snapshot = readHeart(paths);
76
+ async function bornStatus(paths, expected, budget) {
77
+ const snapshot = await readHeart(paths);
83
78
  if (snapshot.soul === null)
84
79
  throw new AkumaNotBornError(expected);
85
- const current = bornListRow(paths, expected, snapshot);
80
+ const current = await bornListRow(paths, expected, snapshot);
86
81
  const resumeUnsupported = current.life === "stranded"
87
82
  && snapshot.latestSession?.provider === snapshot.soul.provider.name
88
- && providerNamed(snapshot.soul.provider).resume === undefined;
83
+ && resolveProviderExecution(snapshot.soul.provider).adapter.resume === undefined;
84
+ const slice = await activitySlice(paths, { limit: Number.MAX_SAFE_INTEGER });
89
85
  return {
90
86
  id: current.id,
91
87
  life: current.life,
92
- collar: current.collar,
88
+ ...(snapshot.soul.readonly === undefined ? {} : { readonly: snapshot.soul.readonly }),
93
89
  ...(resumeUnsupported ? { strandedReason: "resume-unsupported" } : {}),
94
- timeline: (() => {
95
- const slice = activitySlice(paths, { limit: Number.MAX_SAFE_INTEGER });
96
- return selectActivitySnapshot(slice.rows, {
97
- lowestRetained: slice.lowestRetained,
98
- highest: slice.highest,
99
- profile,
100
- });
101
- })(),
90
+ timeline: budget === undefined
91
+ ? selectActivitySnapshot(slice.rows)
92
+ : selectSnapshot(projectTurns(slice.rows), budget),
102
93
  };
103
94
  }
104
- /** Package-internal compact observation for action feedback. */
105
- export function readActionFeedbackStatus(worldPath, id) {
106
- return bornStatus(pathsForAkuId(worldPath, id), id, "feedback");
95
+ /** Package-internal action observation; it uses the same snapshot selector as status. */
96
+ export async function readActionFeedbackStatus(worldPath, id) {
97
+ return await bornStatus(pathsForAkuId(worldPath, id), id);
98
+ }
99
+ /** Package-internal budgeted observation; Fleet allocates, Akuma still selects. */
100
+ export async function readBudgetedStatus(worldPath, id, input) {
101
+ if (!Number.isSafeInteger(input.ordinaryBudget) || input.ordinaryBudget < 0) {
102
+ throw new TypeError("ordinary budget must be a nonnegative safe integer");
103
+ }
104
+ const status = await bornStatus(pathsForAkuId(worldPath, id), id, ordinarySnapshotBudget(input.ordinaryBudget));
105
+ return { status, ordinarySelected: ordinarySelectedCount(status.timeline) };
107
106
  }
108
107
  function diagnostic(error) {
109
108
  return error instanceof Error ? error.message : String(error);
@@ -118,10 +117,10 @@ export class AkumaHandle {
118
117
  get paths() {
119
118
  return pathsForAkuId(this.worldPath, this.id);
120
119
  }
121
- status() {
122
- return bornStatus(this.paths, this.id);
120
+ async status() {
121
+ return await bornStatus(this.paths, this.id);
123
122
  }
124
- history(input = {}) {
123
+ async history(input = {}) {
125
124
  if (input.before !== undefined && input.since !== undefined) {
126
125
  throw new TypeError("Akuma history before and since are mutually exclusive");
127
126
  }
@@ -134,12 +133,15 @@ export class AkumaHandle {
134
133
  if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 5_000) {
135
134
  throw new TypeError("Akuma history limit must be a positive safe integer no greater than 5000");
136
135
  }
137
- const slice = activitySlice(this.paths, {
136
+ const slice = await activitySlice(this.paths, {
138
137
  ...(input.before === undefined ? {} : { before: input.before }),
139
138
  ...(input.since === undefined ? {} : { since: input.since }),
140
139
  limit: 5_000,
141
140
  });
142
- return projectActivityHistory(slice, {
141
+ return selectHistory(projectTurns(slice.rows, {
142
+ lowestRetained: slice.lowestRetained,
143
+ highest: slice.highest,
144
+ }), {
143
145
  ...(input.before === undefined ? {} : { before: input.before }),
144
146
  ...(input.since === undefined ? {} : { since: input.since }),
145
147
  limit,
@@ -152,46 +154,49 @@ export class AkumaHandle {
152
154
  }
153
155
  const deadline = options.timeoutMs === undefined ? undefined : performance.now() + options.timeoutMs;
154
156
  for (;;) {
155
- const status = this.status();
157
+ const status = await this.status();
156
158
  if (predicate(status) || (deadline !== undefined && performance.now() >= deadline))
157
159
  return status;
158
160
  await wait(deadline === undefined ? POLL_MS : Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
159
161
  }
160
162
  }
161
163
  async tell(body) {
162
- const recorded = recordTellBody(this.paths, this.id, body);
164
+ const recorded = await recordTellBody(this.paths, this.id, body);
163
165
  return await wakeTell(this.paths, recorded.tellId);
164
166
  }
165
167
  async interrupt(body) {
166
- if (requestPause(this.paths, new Date().toISOString()).kind === "not-born") {
168
+ const request = await requestPause(this.paths, new Date().toISOString());
169
+ if (request.kind === "not-born") {
167
170
  throw new AkumaNotBornError(this.id);
168
171
  }
169
172
  let putDown = "was-idle";
170
- let leash = HeldAkumaLeash.try(this.paths);
173
+ let leash = await HeldAkumaLeash.try(this.paths);
171
174
  if (leash === null) {
172
- leash = await takeLeashUntil(this.paths, performance.now() + KILL_GRACE_MS);
175
+ leash = await takeLeashUntil(this.paths, performance.now() + CONTROL_RESPONSE_MS);
173
176
  putDown = "self-aborted";
174
177
  }
175
178
  if (leash === null) {
176
- const current = readHeart(this.paths).latestBody;
177
- if (current === null)
178
- return { kind: "unstoppable", evidence: "no-collar" };
179
- if (probeProcessTree(current.collar).kind === "unverifiable") {
180
- return { kind: "unstoppable", evidence: "collar-unverifiable" };
179
+ const body = (await readHeart(this.paths)).latestBody;
180
+ return { kind: "unavailable", evidence: body?.sequence === request.body.sequence && body.hung !== undefined
181
+ ? "hung"
182
+ : "unavailable" };
183
+ }
184
+ const settledBody = (await readHeart(this.paths)).latestBody;
185
+ if (settledBody?.sequence !== request.body.sequence || settledBody.end === undefined) {
186
+ try {
187
+ await leash.clearPause(this.paths);
181
188
  }
182
- const evidence = await putDownProcessTree(current.collar);
183
- if (evidence === "unavailable" || evidence === "alive-after-sigkill") {
184
- return { kind: "unstoppable", evidence };
189
+ finally {
190
+ leash.release();
185
191
  }
186
- leash = await takeLeashUntil(this.paths, performance.now() + KILL_GRACE_MS);
187
- if (leash === null)
188
- return { kind: "unstoppable", evidence: "leash-held-after-put-down" };
189
- putDown = "collar";
192
+ return { kind: "unavailable", evidence: "untidy" };
190
193
  }
194
+ if (request.body.end !== undefined || settledBody.end !== "put-down")
195
+ putDown = "was-idle";
191
196
  let recorded;
192
197
  try {
193
198
  const id = randomUUID();
194
- const admitted = leash.recordInterruptTell(this.paths, {
199
+ const admitted = await leash.recordInterruptTell(this.paths, {
195
200
  kind: "tell",
196
201
  id,
197
202
  body,
@@ -207,15 +212,15 @@ export class AkumaHandle {
207
212
  return { kind: "interrupted", putDown, tell: await wakeTell(this.paths, recorded.tellId) };
208
213
  }
209
214
  async fork(input) {
210
- const source = readSoul(this.paths);
215
+ const source = await readSoul(this.paths);
211
216
  if (source === null)
212
217
  throw new AkumaNotBornError(this.id);
213
218
  if (source.id !== this.id)
214
219
  throw new Error("Akuma soul does not match its coordinate");
215
- const adapter = providerNamed(source.provider);
220
+ const adapter = resolveProviderExecution(source.provider).adapter;
216
221
  if (adapter.fork === undefined)
217
222
  return { kind: "provider-cannot-fork", provider: source.provider.name };
218
- const point = readForkPoint(this.paths, input.at);
223
+ const point = await readForkPoint(this.paths, input.at);
219
224
  if (point === null)
220
225
  return { kind: "unknown-history", at: input.at };
221
226
  if (point.provider !== source.provider.name)
@@ -248,6 +253,7 @@ export class AkumaHandle {
248
253
  ...(source.description === undefined ? {} : { description: source.description }),
249
254
  provider: source.provider,
250
255
  options: source.options,
256
+ ...(source.readonly === undefined ? {} : { readonly: source.readonly }),
251
257
  cwd: source.cwd,
252
258
  origin: { kind: "fork", parent: this.id, at: input.at },
253
259
  confinement: source.confinement,
@@ -263,28 +269,31 @@ export class AkumaHandle {
263
269
  }
264
270
  async kill() {
265
271
  const at = new Date().toISOString();
266
- const request = requestStop(this.paths, at);
267
- if (request.kind === "already-killed")
268
- return "already-killed";
272
+ const request = await requestStop(this.paths, at);
273
+ if (request.kind !== "requested")
274
+ return request.kind;
269
275
  const target = request.body;
270
- const graceDeadline = performance.now() + KILL_GRACE_MS;
271
- while (probeLeash(this.paths) === "held" && performance.now() < graceDeadline)
272
- await wait(POLL_MS);
273
- if (readKill(this.paths, target.sequence) !== null)
276
+ const graceDeadline = performance.now() + CONTROL_RESPONSE_MS;
277
+ const leash = await takeLeashUntil(this.paths, graceDeadline);
278
+ if (await readKill(this.paths, target.sequence) !== null) {
279
+ leash?.release();
274
280
  return "killed";
275
- const targetProbe = probeProcessTree(target.collar);
276
- if (targetProbe.kind === "unverifiable")
277
- return "unavailable";
278
- if (targetProbe.kind === "alive") {
279
- const evidence = await putDownProcessTree(target.collar);
280
- if (evidence === "unavailable" || evidence === "alive-after-sigkill")
281
- return evidence;
282
281
  }
283
- const leash = await takeLeashUntil(this.paths, performance.now() + KILL_GRACE_MS);
284
- if (leash === null)
285
- return readKill(this.paths, target.sequence) === null ? "unavailable" : "killed";
282
+ if (leash === null) {
283
+ if (await readKill(this.paths, target.sequence) !== null)
284
+ return "killed";
285
+ const body = (await readHeart(this.paths)).latestBody;
286
+ return body?.sequence === target.sequence && body.hung !== undefined ? "hung" : "unavailable";
287
+ }
286
288
  try {
287
- const settled = leash.settleStop(this.paths, target.sequence);
289
+ const settledBody = (await readHeart(this.paths)).latestBody;
290
+ if (settledBody?.sequence !== target.sequence)
291
+ return await readKill(this.paths, target.sequence) === null ? "unavailable" : "killed";
292
+ if (settledBody.end !== "put-down") {
293
+ await leash.clearStop(this.paths);
294
+ return "untidy";
295
+ }
296
+ const settled = await leash.settleStop(this.paths, target.sequence);
288
297
  if (settled === null)
289
298
  return "unavailable";
290
299
  return "killed";
@@ -293,8 +302,8 @@ export class AkumaHandle {
293
302
  leash.release();
294
303
  }
295
304
  }
296
- lastAnswer() {
297
- const turn = readLastAnsweredTurn(this.paths);
305
+ async lastAnswer() {
306
+ const turn = await readLastAnsweredTurn(this.paths);
298
307
  return turn?.end?.outcome.kind === "answered"
299
308
  ? { kind: "answer", answer: turn.end.outcome.answer }
300
309
  : { kind: "no-answer" };
@@ -312,24 +321,25 @@ export class Akuma {
312
321
  throw new TypeError("Akuma.of root must be a WorldRoot");
313
322
  return new Akuma(root, settings);
314
323
  }
315
- settings() {
316
- return this.configuredSettings ?? readSettings({ root: this.path });
324
+ async settings() {
325
+ return this.configuredSettings ?? await readSettings({ root: this.path });
317
326
  }
318
327
  of(input) {
319
328
  return new AkumaHandle(parseAkuId(input.id).id, this.path);
320
329
  }
321
- listArchetypes() {
322
- return readArchetypes({ settings: this.settings() });
330
+ async listArchetypes() {
331
+ return readArchetypes({ settings: await this.settings() });
323
332
  }
324
333
  async call(input) {
325
334
  const name = archetypeName(input.archetype);
326
- const archetype = loadArchetype({ name, settings: this.settings() });
335
+ const archetype = await loadArchetype({ name, settings: await this.settings() });
327
336
  const provider = archetype.adapter;
328
337
  const cwd = resolve(input.cwd ?? this.path);
329
338
  const recipe = Object.freeze({
330
339
  ...(archetype.description === undefined ? {} : { description: archetype.description }),
331
340
  provider: archetype.provider,
332
341
  options: archetype.options,
342
+ ...(archetype.readonly === undefined ? {} : { readonly: archetype.readonly }),
333
343
  confinement: provider.confinement({ cwd, options: archetype.options }),
334
344
  });
335
345
  const requests = injectedBodyRequests();
@@ -356,6 +366,7 @@ export class Akuma {
356
366
  ...(archetype.description === undefined ? {} : { description: archetype.description }),
357
367
  provider: archetype.provider,
358
368
  options: archetype.options,
369
+ ...(archetype.readonly === undefined ? {} : { readonly: archetype.readonly }),
359
370
  cwd,
360
371
  origin: { kind: "direct" },
361
372
  confinement: recipe.confinement,
@@ -365,7 +376,7 @@ export class Akuma {
365
376
  });
366
377
  return new AkumaHandle(published.id, this.path);
367
378
  }
368
- list(input = {}) {
379
+ async list(input = {}) {
369
380
  if (typeof input !== "object" || input === null || Array.isArray(input)) {
370
381
  throw new TypeError("Akuma list input must be an object");
371
382
  }
@@ -376,7 +387,7 @@ export class Akuma {
376
387
  const runRoot = akumaRunRoot(this.path);
377
388
  let names;
378
389
  try {
379
- names = readdirSync(runRoot, { withFileTypes: true })
390
+ names = (await readdir(runRoot, { withFileTypes: true }))
380
391
  .filter((entry) => entry.isDirectory())
381
392
  .map((entry) => entry.name)
382
393
  .sort();
@@ -386,26 +397,31 @@ export class Akuma {
386
397
  return { rows: [], searched: [runRoot] };
387
398
  throw error;
388
399
  }
389
- const rows = names.flatMap((name) => {
400
+ const rows = [];
401
+ for (const name of names) {
390
402
  try {
391
403
  const physical = akuIdFromDirectoryName(name);
392
404
  if (selected !== undefined && physical.archetype !== selected)
393
- return [];
405
+ continue;
394
406
  const paths = akumaPaths({ runRoot, archetype: physical.archetype, suffix: physical.suffix });
395
- const snapshot = readHeart(paths);
396
- if (snapshot.soul !== null)
397
- return [bornListRow(paths, physical.id, snapshot)];
398
- if (probeLeash(paths) === "held")
399
- return [{ id: physical.id, life: "unborn" }];
400
- const seal = readSeal(paths);
401
- return seal === null
402
- ? [{ id: physical.id, life: "unborn" }]
403
- : [{ id: physical.id, life: "stillborn", seal }];
407
+ const snapshot = await readHeart(paths);
408
+ if (snapshot.soul !== null) {
409
+ rows.push(await bornListRow(paths, physical.id, snapshot));
410
+ continue;
411
+ }
412
+ if (await probeLeash(paths) === "held") {
413
+ rows.push({ id: physical.id, life: "unborn" });
414
+ continue;
415
+ }
416
+ const seal = await readSeal(paths);
417
+ rows.push(seal === null
418
+ ? { id: physical.id, life: "unborn" }
419
+ : { id: physical.id, life: "stillborn", seal });
404
420
  }
405
421
  catch {
406
- return [];
422
+ continue;
407
423
  }
408
- });
424
+ }
409
425
  return {
410
426
  rows,
411
427
  searched: [runRoot],
@@ -1,6 +1,6 @@
1
1
  import type { Settings } from "../settings.js";
2
- import { type ProviderAdapter, type ProviderOptions } from "./provider.js";
3
- import type { ProviderExecution } from "./heart/index.js";
2
+ import type { ProviderAdapter } from "./provider.js";
3
+ import { type ProviderExecution, type ProviderOptions, type ReadonlyRestraint } from "./provider-recipe.js";
4
4
  type DecodedArchetype = Readonly<{
5
5
  name: string;
6
6
  path: string;
@@ -18,22 +18,23 @@ type ArchetypeDefinition = DecodedArchetype & Readonly<{
18
18
  }>;
19
19
  type AdmittedArchetype = Omit<ArchetypeDefinition, "provider"> & Readonly<{
20
20
  provider: ProviderExecution;
21
+ readonly?: ReadonlyRestraint;
21
22
  }>;
22
23
  export declare class AkumaArchetypeError extends Error {
23
24
  readonly archetype: string;
24
25
  readonly searched: readonly string[];
25
26
  readonly reason: string;
26
27
  readonly kind = "akuma-archetype";
27
- constructor(archetype: string, searched: readonly string[], reason: string);
28
+ constructor(archetype: string, searched: readonly string[], reason: string, guidance?: string);
28
29
  }
29
30
  export declare function listArchetypes(input: Readonly<{
30
31
  settings: Settings;
31
- }>): readonly string[];
32
+ }>): Promise<readonly string[]>;
32
33
  export declare function listArchetypeDefinitions(input: Readonly<{
33
34
  settings: Settings;
34
- }>): readonly ArchetypeCatalogRow[];
35
+ }>): Promise<readonly ArchetypeCatalogRow[]>;
35
36
  export declare function loadArchetype(input: Readonly<{
36
37
  name: string;
37
38
  settings: Settings;
38
- }>): AdmittedArchetype;
39
+ }>): Promise<AdmittedArchetype>;
39
40
  export {};