@astrosheep/keiyaku 4.6.4 → 4.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +7 -0
  2. package/build/{integrations/marketplace → plugins}/.agents/plugins/marketplace.json +1 -1
  3. package/build/plugins/.claude-plugin/marketplace.json +5 -0
  4. package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/.claude-plugin/plugin.json +1 -1
  5. package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-akuma/SKILL.md +43 -8
  6. package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-bind/SKILL.md +7 -8
  7. package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-workflow/SKILL.md +3 -3
  8. package/build/{integrations/marketplace/plugins/keiyaku → plugins/codex}/.codex-plugin/plugin.json +1 -1
  9. package/build/plugins/codex/skills/keiyaku/SKILL.md +44 -0
  10. package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +130 -0
  11. package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +269 -0
  12. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +65 -0
  13. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +216 -0
  14. package/build/plugins/codex/skills/keiyaku-bind/agents/openai.yaml +4 -0
  15. package/build/plugins/codex/skills/keiyaku-task/SKILL.md +104 -0
  16. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +129 -0
  17. package/build/plugins/opencode/package.json +6 -0
  18. package/build/plugins/opencode/skills/keiyaku/SKILL.md +44 -0
  19. package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +130 -0
  20. package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +269 -0
  21. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +65 -0
  22. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +216 -0
  23. package/build/plugins/opencode/skills/keiyaku-bind/agents/openai.yaml +4 -0
  24. package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +104 -0
  25. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +129 -0
  26. package/build/skills/keiyaku/SKILL.md +44 -0
  27. package/build/skills/keiyaku-akuma/SKILL.md +130 -0
  28. package/build/skills/keiyaku-akuma/references/automation.md +269 -0
  29. package/build/skills/keiyaku-babysit/SKILL.md +65 -0
  30. package/build/skills/keiyaku-bind/SKILL.md +216 -0
  31. package/build/skills/keiyaku-bind/agents/openai.yaml +4 -0
  32. package/build/skills/keiyaku-task/SKILL.md +104 -0
  33. package/build/skills/keiyaku-workflow/SKILL.md +129 -0
  34. package/build/src/akuma/akuma-instance.js +7 -5
  35. package/build/src/akuma/akuma-observe.d.ts +22 -15
  36. package/build/src/akuma/akuma-observe.js +87 -16
  37. package/build/src/akuma/akuma-owner.d.ts +3 -2
  38. package/build/src/akuma/akuma-owner.js +28 -10
  39. package/build/src/akuma/akuma-selection-execution.d.ts +3 -1
  40. package/build/src/akuma/akuma-selection-execution.js +2 -1
  41. package/build/src/akuma/akuma-wait.d.ts +6 -4
  42. package/build/src/akuma/akuma-wait.js +78 -53
  43. package/build/src/akuma/akuma.d.ts +6 -4
  44. package/build/src/akuma/akuma.js +4 -0
  45. package/build/src/akuma/body.d.ts +1 -0
  46. package/build/src/akuma/body.js +12 -23
  47. package/build/src/akuma/call-initial-tell.d.ts +2 -2
  48. package/build/src/akuma/call-initial-tell.js +1 -1
  49. package/build/src/akuma/call-request.d.ts +2 -2
  50. package/build/src/akuma/heart/index.d.ts +7 -2
  51. package/build/src/akuma/heart/index.js +50 -5
  52. package/build/src/akuma/heart/tells.d.ts +33 -2
  53. package/build/src/akuma/heart/tells.js +24 -18
  54. package/build/src/akuma/heart/timeline.d.ts +23 -1
  55. package/build/src/akuma/heart/timeline.js +28 -21
  56. package/build/src/akuma/projection.d.ts +10 -10
  57. package/build/src/akuma/providers/pi/index.js +72 -39
  58. package/build/src/akuma/selection-observation.d.ts +20 -20
  59. package/build/src/akuma/selection-owner-port.d.ts +1 -1
  60. package/build/src/akuma/selection-owner-port.js +16 -5
  61. package/build/src/akuma/selection-request.d.ts +2 -0
  62. package/build/src/akuma/selection-request.js +2 -1
  63. package/build/src/akuma-body.js +5 -2
  64. package/build/src/alias/index.d.ts +0 -1
  65. package/build/src/alias/index.js +0 -4
  66. package/build/src/body/amend.d.ts +0 -4
  67. package/build/src/body/amend.js +0 -3
  68. package/build/src/body/region.d.ts +0 -1
  69. package/build/src/body/region.js +0 -3
  70. package/build/src/body/verification.d.ts +0 -1
  71. package/build/src/cli/commands/akuma-grammar.js +23 -66
  72. package/build/src/cli/commands/akuma.js +23 -42
  73. package/build/src/cli/commands/contract-grammar.d.ts +14 -1
  74. package/build/src/cli/commands/contract-grammar.js +54 -21
  75. package/build/src/cli/commands/contract-help.d.ts +9 -8
  76. package/build/src/cli/commands/contract-help.js +14 -7
  77. package/build/src/cli/commands/contract.js +57 -117
  78. package/build/src/cli/commands/install.d.ts +5 -5
  79. package/build/src/cli/commands/install.js +4 -7
  80. package/build/src/cli/commands/task-grammar.js +10 -66
  81. package/build/src/cli/commands/task.d.ts +0 -1
  82. package/build/src/cli/commands/task.js +34 -53
  83. package/build/src/cli/coordinates.d.ts +1 -2
  84. package/build/src/cli/coordinates.js +1 -4
  85. package/build/src/cli/parse.d.ts +2 -3
  86. package/build/src/cli/parse.js +24 -66
  87. package/build/src/cli/render/akuma.d.ts +3 -16
  88. package/build/src/cli/render/akuma.js +1 -13
  89. package/build/src/cli/render/audit.js +1 -1
  90. package/build/src/cli/render/contract.js +34 -32
  91. package/build/src/cli/render/kanshi-akuma.d.ts +8 -2
  92. package/build/src/cli/render/kanshi-akuma.js +14 -7
  93. package/build/src/cli/render/kanshi.d.ts +3 -1
  94. package/build/src/cli/render/kanshi.js +44 -32
  95. package/build/src/cli/render/receipt.js +6 -1
  96. package/build/src/cli/render/task.d.ts +1 -1
  97. package/build/src/cli/render/task.js +3 -27
  98. package/build/src/cli/render/terminal.d.ts +6 -2
  99. package/build/src/cli/render/terminal.js +8 -2
  100. package/build/src/cli/runtime.js +3 -16
  101. package/build/src/cli/scan.d.ts +26 -0
  102. package/build/src/cli/scan.js +82 -0
  103. package/build/src/cli/streams.d.ts +5 -0
  104. package/build/src/cli/streams.js +11 -0
  105. package/build/src/contract-worktree.js +38 -21
  106. package/build/src/core/facts/codec.d.ts +1 -2
  107. package/build/src/core/facts/codec.js +5 -11
  108. package/build/src/core/facts/types.d.ts +16 -2
  109. package/build/src/core/facts/types.js +15 -0
  110. package/build/src/core/verbs/abandon.js +3 -9
  111. package/build/src/core/verbs/amend.js +2 -9
  112. package/build/src/core/verbs/arc.js +6 -13
  113. package/build/src/core/verbs/attestation.js +2 -9
  114. package/build/src/core/verbs/bind.js +2 -9
  115. package/build/src/core/verbs/deliver.js +2 -9
  116. package/build/src/core/verbs/placement.d.ts +1 -1
  117. package/build/src/core/verbs/placement.js +2 -9
  118. package/build/src/core/verbs/reintegrate.d.ts +1 -1
  119. package/build/src/core/verbs/reintegrate.js +2 -9
  120. package/build/src/dispatch/index.d.ts +2 -2
  121. package/build/src/dispatch/index.js +33 -11
  122. package/build/src/git/hooks.d.ts +2 -4
  123. package/build/src/git/hooks.js +0 -12
  124. package/build/src/git/integration.d.ts +5 -3
  125. package/build/src/git/integration.js +36 -25
  126. package/build/src/git/nuke.js +4 -4
  127. package/build/src/git/observe.d.ts +4 -4
  128. package/build/src/git/observe.js +5 -5
  129. package/build/src/git/process.d.ts +1 -4
  130. package/build/src/git/process.js +1 -11
  131. package/build/src/git/read-observation.js +1 -1
  132. package/build/src/git/reconcile.d.ts +1 -1
  133. package/build/src/git/reconcile.js +15 -13
  134. package/build/src/git/repository.d.ts +2 -6
  135. package/build/src/git/repository.js +18 -31
  136. package/build/src/git/scratch.d.ts +6 -6
  137. package/build/src/git/scratch.js +110 -46
  138. package/build/src/git/target-placement.d.ts +5 -5
  139. package/build/src/git/target-placement.js +18 -33
  140. package/build/src/git/tender.d.ts +6 -2
  141. package/build/src/git/tender.js +19 -12
  142. package/build/src/git/terminal-reconcile.js +24 -13
  143. package/build/src/git/terminal-seal.d.ts +2 -5
  144. package/build/src/git/terminal-seal.js +5 -3
  145. package/build/src/git/workspace.d.ts +17 -13
  146. package/build/src/git/workspace.js +58 -41
  147. package/build/src/kanshi/index.d.ts +2 -2
  148. package/build/src/kanshi/index.js +1 -1
  149. package/build/src/kanshi/read.d.ts +8 -1
  150. package/build/src/kanshi/read.js +72 -7
  151. package/build/src/kanshi/report.d.ts +12 -0
  152. package/build/src/library/akuma-creation.d.ts +4 -4
  153. package/build/src/library/akuma-creation.js +21 -19
  154. package/build/src/library/bind.d.ts +1 -63
  155. package/build/src/library/bind.js +3 -9
  156. package/build/src/library/contract-creation.js +2 -30
  157. package/build/src/library/contract-execution.d.ts +0 -1
  158. package/build/src/library/contract-execution.js +9 -34
  159. package/build/src/library/contract-operations.d.ts +5 -1
  160. package/build/src/library/contract-operations.js +7 -3
  161. package/build/src/library/contract-types.d.ts +1 -1
  162. package/build/src/library/delivery.d.ts +91 -93
  163. package/build/src/library/delivery.js +2 -1
  164. package/build/src/library/input.d.ts +0 -2
  165. package/build/src/library/input.js +0 -4
  166. package/build/src/library/invocation.d.ts +0 -1
  167. package/build/src/library/invocation.js +3 -25
  168. package/build/src/library/outcome.d.ts +651 -602
  169. package/build/src/library/outcome.js +4 -4
  170. package/build/src/library/reconcile.d.ts +6 -0
  171. package/build/src/library/reconcile.js +31 -1
  172. package/build/src/library/repo.d.ts +0 -1
  173. package/build/src/library/selection.d.ts +1 -10
  174. package/build/src/library/selection.js +19 -17
  175. package/build/src/plugin/akuma-signals.d.ts +10 -11
  176. package/build/src/plugin/akuma-signals.js +36 -20
  177. package/build/src/plugin/public.d.ts +5 -0
  178. package/build/src/plugin/runtime.d.ts +1 -0
  179. package/build/src/plugin/runtime.js +34 -23
  180. package/build/src/protocol/abandon.d.ts +1 -1
  181. package/build/src/protocol/abandon.js +3 -10
  182. package/build/src/protocol/amend.js +2 -5
  183. package/build/src/protocol/arc.d.ts +1 -1
  184. package/build/src/protocol/arc.js +2 -9
  185. package/build/src/protocol/attempt.d.ts +3 -20
  186. package/build/src/protocol/attempt.js +6 -5
  187. package/build/src/protocol/audit.d.ts +1 -0
  188. package/build/src/protocol/audit.js +10 -11
  189. package/build/src/protocol/completion.d.ts +129 -55
  190. package/build/src/protocol/completion.js +62 -73
  191. package/build/src/protocol/deliver.d.ts +7 -5
  192. package/build/src/protocol/deliver.js +74 -44
  193. package/build/src/protocol/execution-observation.d.ts +2 -4
  194. package/build/src/protocol/execution-observation.js +3 -7
  195. package/build/src/protocol/intent.d.ts +1 -1
  196. package/build/src/protocol/intent.js +1 -0
  197. package/build/src/protocol/operations.d.ts +24 -12
  198. package/build/src/protocol/operations.js +36 -15
  199. package/build/src/protocol/placement.d.ts +2 -1
  200. package/build/src/protocol/placement.js +21 -5
  201. package/build/src/protocol/progress.d.ts +1 -1
  202. package/build/src/protocol/read/status.js +58 -41
  203. package/build/src/protocol/reintegrate.d.ts +1 -1
  204. package/build/src/protocol/reintegrate.js +10 -19
  205. package/build/src/protocol/review.d.ts +3 -28
  206. package/build/src/protocol/review.js +10 -37
  207. package/build/src/protocol/run.d.ts +19 -7
  208. package/build/src/protocol/run.js +19 -9
  209. package/build/src/runtime/proc/windows-launch.exe +0 -0
  210. package/build/src/settlement/holder.d.ts +2 -4
  211. package/build/src/settlement/holder.js +3 -6
  212. package/build/src/task/board.d.ts +6 -0
  213. package/build/src/task/board.js +30 -1
  214. package/build/src/task/catalog.js +1 -4
  215. package/build/src/task/compose.d.ts +0 -1
  216. package/build/src/task/compose.js +0 -1
  217. package/build/src/task/context.d.ts +0 -1
  218. package/build/src/task/context.js +0 -3
  219. package/build/src/task/created-observation.d.ts +5 -1
  220. package/build/src/task/created-observation.js +12 -5
  221. package/build/src/task/index.d.ts +1 -1
  222. package/build/src/task/index.js +7 -6
  223. package/build/src/task/input.d.ts +0 -6
  224. package/build/src/task/input.js +2 -14
  225. package/build/src/task/mutation.d.ts +3 -4
  226. package/build/src/task/mutation.js +11 -39
  227. package/build/src/task/operations.d.ts +2 -7
  228. package/build/src/task/operations.js +37 -49
  229. package/build/src/task/query.d.ts +0 -1
  230. package/build/src/task/query.js +1 -4
  231. package/build/src/task/store.d.ts +0 -2
  232. package/build/src/task/store.js +27 -11
  233. package/build/src/verification/declaration.js +3 -2
  234. package/build/src/verification/execution.d.ts +3 -2
  235. package/build/src/verification/execution.js +10 -6
  236. package/build/src/workspace-place.d.ts +0 -1
  237. package/build/src/workspace-place.js +0 -11
  238. package/package.json +13 -9
  239. package/build/integrations/marketplace/.claude-plugin/marketplace.json +0 -5
  240. package/build/integrations/marketplace/plugins/keiyaku/package.json +0 -17
  241. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku/SKILL.md +0 -0
  242. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-akuma/references/automation.md +0 -0
  243. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-babysit/SKILL.md +0 -0
  244. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-bind/agents/openai.yaml +0 -0
  245. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-task/SKILL.md +0 -0
  246. /package/build/{integrations/marketplace/plugins/keiyaku/opencode.js → plugins/opencode/index.js} +0 -0
  247. /package/build/{integrations → plugins}/pi/keiyaku.ts +0 -0
@@ -1,4 +1,4 @@
1
- import { readStatusFacts, readLifeSnapshot, HeldAkumaLeash, isHeartAbsent, life, lifeAt, probeLeash, readHeart, readSeal, readSoul, } from "./heart/index.js";
1
+ import { readStatusFacts, createStatusFactReader, readLifeSnapshot, HeldAkumaLeash, isHeartAbsent, life, lifeAt, probeLeash, readHeart, readSeal, readSoul, } from "./heart/index.js";
2
2
  import { pathsForAkuId } from "./identity.js";
3
3
  import { ordinarySnapshotBudget, projectTurns, selectHistory, selectSnapshot, } from "./projection.js";
4
4
  import { resolveProviderExecution } from "./providers/index.js";
@@ -59,21 +59,68 @@ async function bornObservation(paths, expected, read, snapshot) {
59
59
  claim?.release();
60
60
  }
61
61
  }
62
+ export async function observeOutcomeRows(id, rows, observer) {
63
+ if (observer === undefined)
64
+ return;
65
+ const historyIds = rows.flatMap((row) => (row.kind === "outcome" ? [row.outcome.historyId] : []));
66
+ if (historyIds.length > 0)
67
+ await observer(id, historyIds);
68
+ }
69
+ export async function observeStatusOutcome(status, observer) {
70
+ const snapshot = status.timeline;
71
+ if (snapshot.kind === "idle" && snapshot.outcome !== undefined)
72
+ await observer?.(status.id, [snapshot.outcome.outcome.historyId]);
73
+ }
74
+ function snapshotSelection(input) {
75
+ return {
76
+ aperture: input.aperture,
77
+ budget: ordinarySnapshotBudget(input.ordinaryBudget),
78
+ ...(input.admittedTellId === undefined ? {} : { admittedTellId: input.admittedTellId }),
79
+ };
80
+ }
81
+ /** Private to a live wait: retain only this member's current frontier and last selection. */
82
+ export function createLiveStatusReader(paths, expected) {
83
+ const reader = createStatusFactReader(paths);
84
+ let memo;
85
+ const clear = () => {
86
+ reader.clear();
87
+ memo = undefined;
88
+ };
89
+ return {
90
+ clear,
91
+ async read(input, signal) {
92
+ try {
93
+ return await bornLiveStatus(paths, expected, input, signal, async () => {
94
+ const facts = await reader.read(input, signal);
95
+ const ledger = memo?.facts === facts ? memo.ledger : projectTurns(facts);
96
+ const options = snapshotSelection(input);
97
+ const selected = memo?.ledger === ledger &&
98
+ memo.options.aperture === options.aperture &&
99
+ memo.options.admittedTellId === options.admittedTellId &&
100
+ memo.options.budget.tail === options.budget.tail &&
101
+ memo.options.budget.voice === options.budget.voice
102
+ ? memo.selected
103
+ : selectSnapshot(ledger, options);
104
+ memo = { facts, ledger, options, selected };
105
+ return { ledger, selected };
106
+ });
107
+ }
108
+ catch (error) {
109
+ clear();
110
+ throw error;
111
+ }
112
+ },
113
+ };
114
+ }
62
115
  /** Internal live companion for an observation loop; it is not a public result. */
63
- export async function bornLiveStatus(paths, expected, input) {
116
+ export async function bornLiveStatus(paths, expected, input, signal, readProjection) {
64
117
  if (input.ordinaryBudget !== undefined && (!Number.isSafeInteger(input.ordinaryBudget) || input.ordinaryBudget < 0))
65
118
  throw new TypeError("ordinary budget must be a nonnegative safe integer");
66
- const { snapshot, soul, currentLife } = await bornObservation(paths, expected, () => readLifeSnapshot(paths));
119
+ const { snapshot, soul, currentLife } = await bornObservation(paths, expected, () => readLifeSnapshot(paths, signal));
67
120
  const resumeUnsupported = currentLife === "stranded" &&
68
121
  snapshot.latestSession?.provider === soul.provider.name &&
69
122
  (await resolveProviderExecution(soul.provider)).adapter.resume === undefined;
70
- const facts = await readStatusFacts(paths, input);
71
- const ledger = projectTurns(facts);
72
- const selected = selectSnapshot(ledger, {
73
- aperture: input.aperture,
74
- budget: ordinarySnapshotBudget(input.ordinaryBudget),
75
- ...(input.admittedTellId === undefined ? {} : { admittedTellId: input.admittedTellId }),
76
- });
123
+ const { ledger, selected } = readProjection === undefined ? await readStatusProjection(paths, input, signal) : await readProjection();
77
124
  return {
78
125
  status: {
79
126
  id: soul.id,
@@ -87,12 +134,20 @@ export async function bornLiveStatus(paths, expected, input) {
87
134
  rows: ledger.rows,
88
135
  };
89
136
  }
137
+ async function readStatusProjection(paths, input, signal) {
138
+ const facts = await readStatusFacts(paths, input, signal);
139
+ const ledger = projectTurns(facts);
140
+ return {
141
+ ledger,
142
+ selected: selectSnapshot(ledger, snapshotSelection(input)),
143
+ };
144
+ }
90
145
  export async function bornStatus(paths, expected, input) {
91
146
  const { rows: _rows, ...status } = await bornLiveStatus(paths, expected, input);
92
147
  return status;
93
148
  }
94
- export async function readLiveStatus(worldPath, id, input) {
95
- return await bornLiveStatus(pathsForAkuId(worldPath, id), id, input);
149
+ export async function readLiveStatus(worldPath, id, input, signal) {
150
+ return await bornLiveStatus(pathsForAkuId(worldPath, id), id, input, signal);
96
151
  }
97
152
  function complete(life, pending) {
98
153
  return life !== "running" && !pending;
@@ -100,10 +155,26 @@ function complete(life, pending) {
100
155
  export function defaultWaitComplete(status) {
101
156
  return complete(status.life, status.timeline.entries.some((entry) => entry.kind === "row" && entry.row.kind === "tell" && entry.row.state === "pending"));
102
157
  }
103
- export async function readWaitComplete(worldPath, id) {
104
- const paths = pathsForAkuId(worldPath, id);
105
- const observed = await bornObservation(paths, id, () => readLifeSnapshot(paths));
106
- return complete(observed.currentLife, observed.snapshot.hasPendingTell);
158
+ /** Probe completion only; returned statuses still come from a full observation. */
159
+ export async function readWaitComplete(worldPath, ids, completion, signal) {
160
+ let completed = 0;
161
+ for (const id of ids) {
162
+ signal?.throwIfAborted();
163
+ try {
164
+ const paths = pathsForAkuId(worldPath, id);
165
+ const observed = await bornObservation(paths, id, () => readLifeSnapshot(paths, signal));
166
+ if (complete(observed.currentLife, observed.snapshot.hasPendingTell)) {
167
+ if (completion === "any")
168
+ return true;
169
+ completed += 1;
170
+ }
171
+ }
172
+ catch (error) {
173
+ if (ids.length === 1 || error instanceof AkumaNotBornError)
174
+ throw error;
175
+ }
176
+ }
177
+ return ids.length > 0 && completed === ids.length;
107
178
  }
108
179
  const OBSERVATION_POLL_MS = 100;
109
180
  /**
@@ -1,5 +1,5 @@
1
1
  import type { WorldRoot } from "../world.js";
2
- import { type LiveStatusObservation, type WaitReason } from "./akuma-observe.js";
2
+ import { type OutcomeObserver, type LiveStatusObservation, type WaitReason } from "./akuma-observe.js";
3
3
  import type { AkumaStatus } from "./akuma.js";
4
4
  import { type TellResult, type TellWakeRuntime } from "./body.js";
5
5
  import { type CallInitialTell, type CallInitialTellAdmission } from "./call-initial-tell.js";
@@ -68,7 +68,8 @@ export declare function killAkumaWithRecovery(paths: AkumaPaths, recover?: (path
68
68
  export declare class AkumaOwner {
69
69
  readonly id: AkuId;
70
70
  private readonly worldPath;
71
- constructor(id: AkuId, worldPath: WorldRoot);
71
+ private readonly outcomeObserved?;
72
+ constructor(id: AkuId, worldPath: WorldRoot, outcomeObserved?: OutcomeObserver | undefined);
72
73
  private get paths();
73
74
  private projectHistoryTurns;
74
75
  private exactHistory;
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { AkumaNotBornError, AkumaProviderError } from "./akuma-errors.js";
3
- import { bornLiveStatus, bornStatus, defaultWaitComplete, waitForObservation, } from "./akuma-observe.js";
3
+ import { bornLiveStatus, bornStatus, defaultWaitComplete, observeOutcomeRows, observeStatusOutcome, waitForObservation, } from "./akuma-observe.js";
4
4
  import { executeWaitAkuma } from "./akuma-wait.js";
5
5
  import { handoffPendingTells, spawnAkumaBody, wakeRecordedTell, } from "./body.js";
6
6
  import { admitCallInitialTell } from "./call-initial-tell.js";
@@ -88,9 +88,11 @@ export async function killAkumaWithRecovery(paths, recover, signal) {
88
88
  export class AkumaOwner {
89
89
  id;
90
90
  worldPath;
91
- constructor(id, worldPath) {
91
+ outcomeObserved;
92
+ constructor(id, worldPath, outcomeObserved) {
92
93
  this.id = id;
93
94
  this.worldPath = worldPath;
95
+ this.outcomeObserved = outcomeObserved;
94
96
  }
95
97
  get paths() {
96
98
  return pathsForAkuId(this.worldPath, this.id);
@@ -109,11 +111,17 @@ export class AkumaOwner {
109
111
  return selectExactHistory((await this.projectHistoryTurns()).rows, input.id);
110
112
  }
111
113
  async status() {
112
- return (await bornStatus(this.paths, this.id, { aperture: "monitoring" })).status;
114
+ const { status } = await bornStatus(this.paths, this.id, { aperture: "monitoring" });
115
+ await observeStatusOutcome(status, this.outcomeObserved);
116
+ return status;
113
117
  }
114
118
  async history(input = {}) {
115
- if (input.id !== undefined)
116
- return this.exactHistory(input);
119
+ if (input.id !== undefined) {
120
+ const exact = await this.exactHistory(input);
121
+ if (exact.kind === "exact")
122
+ await this.outcomeObserved?.(this.id, [exact.outcome.outcome.historyId]);
123
+ return exact;
124
+ }
117
125
  if (input.before !== undefined && input.since !== undefined) {
118
126
  throw new TypeError("Akuma history before and since are mutually exclusive");
119
127
  }
@@ -129,11 +137,13 @@ export class AkumaOwner {
129
137
  if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 5_000) {
130
138
  throw new TypeError("Akuma history limit must be a positive safe integer no greater than 5000");
131
139
  }
132
- return selectHistory(await this.projectHistoryTurns(), {
140
+ const history = selectHistory(await this.projectHistoryTurns(), {
133
141
  ...(input.before === undefined ? {} : { before: input.before }),
134
142
  ...(input.since === undefined ? {} : { since: input.since }),
135
143
  limit,
136
144
  });
145
+ await observeOutcomeRows(this.id, history.rows, this.outcomeObserved);
146
+ return history;
137
147
  }
138
148
  async waitReceipt(predicate = defaultWaitComplete, options = {}) {
139
149
  if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0)) {
@@ -143,6 +153,7 @@ export class AkumaOwner {
143
153
  path: this.worldPath,
144
154
  ids: [this.id],
145
155
  completion: "all",
156
+ ...(this.outcomeObserved === undefined ? {} : { outcomeObserved: this.outcomeObserved }),
146
157
  ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
147
158
  ...(options.signal === undefined ? {} : { signal: options.signal }),
148
159
  ...(predicate === defaultWaitComplete ? {} : { predicate }),
@@ -220,6 +231,8 @@ export class AkumaOwner {
220
231
  if (tell === null)
221
232
  throw new AkumaProviderError(`recorded Tell ${tellId} is missing from Heart`);
222
233
  const outcome = await this.boundTellOutcome(tell);
234
+ if (outcome.historyId !== undefined)
235
+ await this.outcomeObserved?.(this.id, [outcome.historyId]);
223
236
  if (options.observe !== undefined) {
224
237
  await options.observe(await bornLiveStatus(this.paths, this.id, { aperture: "monitoring", admittedTellId: tellId }));
225
238
  }
@@ -237,7 +250,11 @@ export class AkumaOwner {
237
250
  if (tell.binding === undefined)
238
251
  return { outcome: null, completedAt: null };
239
252
  const end = (await readTurn(this.paths, tell.binding.turnSequence))?.end;
240
- return { outcome: end?.outcome ?? null, completedAt: end?.completedAt ?? null };
253
+ return {
254
+ outcome: end?.outcome ?? null,
255
+ completedAt: end?.completedAt ?? null,
256
+ ...(end === undefined ? {} : { historyId: `turn/${tell.binding.turnSequence}` }),
257
+ };
241
258
  }
242
259
  async interrupt(body, options = {}) {
243
260
  const admitted = await this.admitInterrupt(body, options);
@@ -369,9 +386,10 @@ export class AkumaOwner {
369
386
  }
370
387
  async lastAnswer() {
371
388
  const turn = await readLastAnsweredTurn(this.paths);
372
- return turn?.end?.outcome.kind === "answered"
373
- ? { kind: "answer", answer: turn.end.outcome.answer }
374
- : { kind: "no-answer" };
389
+ if (turn?.end?.outcome.kind !== "answered")
390
+ return { kind: "no-answer" };
391
+ await this.outcomeObserved?.(this.id, [`turn/${turn.sequence}`]);
392
+ return { kind: "answer", answer: turn.end.outcome.answer };
375
393
  }
376
394
  }
377
395
  /* ---------------------------------------------------------------------------
@@ -1,5 +1,5 @@
1
1
  import type { WorldRoot } from "../world.js";
2
- import type { LiveStatusObservation } from "./akuma-observe.js";
2
+ import type { LiveStatusObservation, OutcomeObserver } from "./akuma-observe.js";
3
3
  import type { AkumaStatus } from "./akuma.js";
4
4
  import type { TellResult } from "./body.js";
5
5
  import type { Schema } from "./schema.js";
@@ -18,6 +18,7 @@ type TellExecutionInput = Readonly<{
18
18
  signal?: AbortSignal;
19
19
  interrupt?: boolean;
20
20
  onObserve?: AskObserver;
21
+ outcomeObserved?: OutcomeObserver;
21
22
  }>;
22
23
  export declare function executeTellAkuma(input: TellExecutionInput): Promise<AkumaTellResult>;
23
24
  export declare function decodeAskObservation<T>(observation: AkumaAskObservation, schema: Schema<T>): AkumaAskObservation<T>;
@@ -37,6 +38,7 @@ export declare function observeAdmittedAskAkuma(input: Readonly<{
37
38
  */
38
39
  receipt?: TellResult;
39
40
  onObserve?: AskObserver;
41
+ outcomeObserved?: OutcomeObserver;
40
42
  }>): Promise<AkumaAskResult>;
41
43
  export declare function executeAskAkuma(input: TellExecutionInput & Readonly<{
42
44
  timeoutMs?: number;
@@ -64,7 +64,7 @@ export function decodeAskObservation(observation, schema) {
64
64
  }
65
65
  }
66
66
  export async function observeAdmittedAskAkuma(input) {
67
- const owner = new AkumaOwner(input.id, input.path);
67
+ const owner = new AkumaOwner(input.id, input.path, input.outcomeObserved);
68
68
  const tell = input.receipt ?? (await owner.admittedReceipt(input.tellId));
69
69
  await input.onObserve?.admitted?.(tell, input.id);
70
70
  let settled;
@@ -118,6 +118,7 @@ export async function executeAskAkuma(input) {
118
118
  wake: admission.wake,
119
119
  ...(input.signal === undefined ? {} : { signal: input.signal }),
120
120
  ...(input.onObserve === undefined ? {} : { onObserve: input.onObserve }),
121
+ ...(input.outcomeObserved === undefined ? {} : { outcomeObserved: input.outcomeObserved }),
121
122
  });
122
123
  }
123
124
  export async function executeKillAkuma(input) {
@@ -1,6 +1,6 @@
1
1
  import type { AkumaAlias } from "../identity/selector.js";
2
2
  import type { WorldRoot } from "../world.js";
3
- import { type WaitReason } from "./akuma-observe.js";
3
+ import { type OutcomeObserver, type WaitReason } from "./akuma-observe.js";
4
4
  import type { AkumaStatus } from "./akuma.js";
5
5
  import type { DispatchAssociation } from "./dispatch-association.js";
6
6
  import type { ActivityRow } from "./projection.js";
@@ -33,6 +33,7 @@ type WaitExecutionInput = Readonly<{
33
33
  signal?: AbortSignal;
34
34
  /** Internal custom completion judge over the full final observation where supplied. */
35
35
  predicate?: (status: AkumaStatus) => boolean;
36
+ outcomeObserved?: OutcomeObserver;
36
37
  /** Resolves one Akuma's identity facts; consulted once per Akuma a viewer first sees. */
37
38
  identity?: (id: AkumaStatus["id"]) => Promise<WaitIdentityFacts>;
38
39
  /** The selected set in the caller's order; a viewer's head and scoreboard follow it. */
@@ -53,9 +54,10 @@ export type NativeWaitResult = Readonly<{
53
54
  * The one lower set-observation owner for Akuma wait completion. It serves the
54
55
  * standalone one-ID association-free face and the plural any/all face with one
55
56
  * ordered round algorithm, one shared ordinary-detail budget, transient
56
- * unreadable peers, and an honest final deadline edge. The default completion
57
- * probe is used only without live row callbacks and never with a custom
58
- * predicate; a live viewer always observes rounds.
57
+ * unreadable peers, and an honest final deadline edge. A silent observation —
58
+ * no live row callback and no custom judge — decides which running rounds to
59
+ * skip with the owner's lightweight completion probe over the selected set; a
60
+ * live viewer or a custom judge always observes full rounds.
59
61
  */
60
62
  export declare function executeWaitAkuma(input: WaitExecutionInput): Promise<NativeWaitResult>;
61
63
  export {};
@@ -1,10 +1,22 @@
1
1
  import { AkumaNotBornError } from "./akuma-errors.js";
2
- import { defaultWaitComplete, readLiveStatus, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
2
+ import { createLiveStatusReader, defaultWaitComplete, readLiveStatus, readWaitComplete, observeOutcomeRows, observeStatusOutcome, waitForObservation, } from "./akuma-observe.js";
3
+ import { pathsForAkuId } from "./identity.js";
3
4
  const SHARED_ORDINARY_BUDGET = 30;
4
- async function observeWaitRound(path, ids, signal) {
5
+ async function observeWaitRound(path, ids, signal, readers) {
6
+ const read = async (id, ordinaryBudget) => {
7
+ const options = { aperture: "monitoring", ...(ordinaryBudget === undefined ? {} : { ordinaryBudget }) };
8
+ if (readers === undefined)
9
+ return await readLiveStatus(path, id, options, signal);
10
+ let reader = readers.get(id);
11
+ if (reader === undefined) {
12
+ reader = createLiveStatusReader(pathsForAkuId(path, id), id);
13
+ readers.set(id, reader);
14
+ }
15
+ return await reader.read(options, signal);
16
+ };
5
17
  signal?.throwIfAborted();
6
18
  if (ids.length <= 1) {
7
- const observations = await Promise.all(ids.map(async (id) => await readLiveStatus(path, id, { aperture: "monitoring" })));
19
+ const observations = await Promise.all(ids.map(async (id) => await read(id)));
8
20
  return { observations, unobserved: [] };
9
21
  }
10
22
  let remaining = SHARED_ORDINARY_BUDGET;
@@ -13,11 +25,13 @@ async function observeWaitRound(path, ids, signal) {
13
25
  for (const id of ids) {
14
26
  signal?.throwIfAborted();
15
27
  try {
16
- const observed = await readLiveStatus(path, id, { aperture: "monitoring", ordinaryBudget: remaining });
28
+ const observed = await read(id, remaining);
17
29
  observations.push(observed);
18
30
  remaining -= observed.ordinarySelected;
19
31
  }
20
32
  catch (error) {
33
+ readers?.get(id)?.clear();
34
+ readers?.delete(id);
21
35
  if (error instanceof AkumaNotBornError)
22
36
  throw error;
23
37
  unobserved.push({ id, diagnostic: diagnostic(error) });
@@ -54,59 +68,70 @@ function selectionOrderedIds(ids, order) {
54
68
  * The one lower set-observation owner for Akuma wait completion. It serves the
55
69
  * standalone one-ID association-free face and the plural any/all face with one
56
70
  * ordered round algorithm, one shared ordinary-detail budget, transient
57
- * unreadable peers, and an honest final deadline edge. The default completion
58
- * probe is used only without live row callbacks and never with a custom
59
- * predicate; a live viewer always observes rounds.
71
+ * unreadable peers, and an honest final deadline edge. A silent observation —
72
+ * no live row callback and no custom judge — decides which running rounds to
73
+ * skip with the owner's lightweight completion probe over the selected set; a
74
+ * live viewer or a custom judge always observes full rounds.
60
75
  */
61
76
  export async function executeWaitAkuma(input) {
62
- // Identity facts are read once per observed Akuma, not once per 100ms round.
63
- const facts = new Map();
64
- if (input.onSelected !== undefined) {
65
- for (const id of input.ids) {
66
- input.signal?.throwIfAborted();
67
- const known = input.identity === undefined ? undefined : await input.identity(id);
68
- facts.set(id, known ?? { contract: { kind: "none" } });
69
- }
70
- const ordered = input.selectionOrder === undefined ? input.ids : selectionOrderedIds(input.ids, input.selectionOrder);
71
- input.onSelected(ordered.map((id) => ({ id, ...facts.get(id) })));
72
- }
73
- const observeRound = async (round) => {
74
- if (input.observe === undefined)
75
- return;
76
- const observed = [];
77
- for (const observation of round.observations) {
78
- input.signal?.throwIfAborted();
79
- const { status, rows } = observation;
80
- let known = facts.get(status.id);
81
- if (known === undefined && input.identity !== undefined) {
82
- known = await input.identity(status.id);
83
- facts.set(status.id, known);
84
- }
85
- if (known === undefined) {
86
- observed.push({ status, rows, contract: { kind: "none" } });
87
- continue;
77
+ const readers = input.observe === undefined ? undefined : new Map();
78
+ try {
79
+ // Identity facts are read once per observed Akuma, not once per 100ms round.
80
+ const facts = new Map();
81
+ if (input.onSelected !== undefined) {
82
+ for (const id of input.ids) {
83
+ input.signal?.throwIfAborted();
84
+ const known = input.identity === undefined ? undefined : await input.identity(id);
85
+ facts.set(id, known ?? { contract: { kind: "none" } });
88
86
  }
89
- observed.push({ status, rows, ...known });
87
+ const ordered = input.selectionOrder === undefined ? input.ids : selectionOrderedIds(input.ids, input.selectionOrder);
88
+ input.onSelected(ordered.map((id) => ({ id, ...facts.get(id) })));
90
89
  }
91
- input.observe(observed);
92
- };
93
- const live = input.observe !== undefined;
94
- const waited = await waitForObservation({
95
- ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
96
- ...(input.signal === undefined ? {} : { signal: input.signal }),
97
- ...(input.predicate === undefined && !live && input.ids.length === 1
98
- ? { probe: async () => await readWaitComplete(input.path, input.ids[0]) }
99
- : {}),
100
- observe: async () => await observeWaitRound(input.path, input.ids, input.signal),
101
- complete: (round) => roundComplete(round, input.completion, input.predicate),
102
- onObserve: async (round) => await observeRound(round),
103
- });
104
- return {
105
- mode: input.completion,
106
- reason: waited.reason,
107
- observations: waited.value.observations.map((observation) => observation.status),
108
- unobserved: waited.value.unobserved,
109
- };
90
+ const observeRound = async (round) => {
91
+ await Promise.all(round.observations.map(({ status, rows }) => input.observe === undefined
92
+ ? observeStatusOutcome(status, input.outcomeObserved)
93
+ : observeOutcomeRows(status.id, rows, input.outcomeObserved)));
94
+ if (input.observe === undefined)
95
+ return;
96
+ const observed = [];
97
+ for (const observation of round.observations) {
98
+ input.signal?.throwIfAborted();
99
+ const { status, rows } = observation;
100
+ let known = facts.get(status.id);
101
+ if (known === undefined && input.identity !== undefined) {
102
+ known = await input.identity(status.id);
103
+ facts.set(status.id, known);
104
+ }
105
+ if (known === undefined) {
106
+ observed.push({ status, rows, contract: { kind: "none" } });
107
+ continue;
108
+ }
109
+ observed.push({ status, rows, ...known });
110
+ }
111
+ input.observe(structuredClone(observed));
112
+ };
113
+ const waited = await waitForObservation({
114
+ ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
115
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
116
+ ...(input.predicate === undefined && input.observe === undefined
117
+ ? { probe: async () => await readWaitComplete(input.path, input.ids, input.completion, input.signal) }
118
+ : {}),
119
+ observe: async () => await observeWaitRound(input.path, input.ids, input.signal, readers),
120
+ complete: (round) => roundComplete(round, input.completion, input.predicate),
121
+ onObserve: async (round) => await observeRound(round),
122
+ });
123
+ return {
124
+ mode: input.completion,
125
+ reason: waited.reason,
126
+ observations: waited.value.observations.map((observation) => observation.status),
127
+ unobserved: waited.value.unobserved,
128
+ };
129
+ }
130
+ finally {
131
+ for (const reader of readers?.values() ?? [])
132
+ reader.clear();
133
+ readers?.clear();
134
+ }
110
135
  }
111
136
  function diagnostic(error) {
112
137
  return error instanceof Error ? error.message : String(error);
@@ -156,8 +156,8 @@ export declare const akumaStatusSchema: z.ZodObject<{
156
156
  }>;
157
157
  turnSequence: z.ZodNumber;
158
158
  receipt: z.ZodOptional<z.ZodEnum<{
159
- required: "required";
160
159
  unavailable: "unavailable";
160
+ required: "required";
161
161
  }>>;
162
162
  }, z.core.$strict>, z.ZodTransform<Readonly<{
163
163
  turnSequence: number;
@@ -168,7 +168,7 @@ export declare const akumaStatusSchema: z.ZodObject<{
168
168
  deliveredAt: string;
169
169
  route: "live" | "launch";
170
170
  turnSequence: number;
171
- receipt?: "required" | "unavailable" | undefined;
171
+ receipt?: "unavailable" | "required" | undefined;
172
172
  }>>>>;
173
173
  }, z.core.$strict>]>, z.ZodObject<{
174
174
  kind: z.ZodLiteral<"tool">;
@@ -363,8 +363,8 @@ export declare const akumaStatusSchema: z.ZodObject<{
363
363
  }>;
364
364
  turnSequence: z.ZodNumber;
365
365
  receipt: z.ZodOptional<z.ZodEnum<{
366
- required: "required";
367
366
  unavailable: "unavailable";
367
+ required: "required";
368
368
  }>>;
369
369
  }, z.core.$strict>, z.ZodTransform<Readonly<{
370
370
  turnSequence: number;
@@ -375,7 +375,7 @@ export declare const akumaStatusSchema: z.ZodObject<{
375
375
  deliveredAt: string;
376
376
  route: "live" | "launch";
377
377
  turnSequence: number;
378
- receipt?: "required" | "unavailable" | undefined;
378
+ receipt?: "unavailable" | "required" | undefined;
379
379
  }>>>>;
380
380
  }, z.core.$strict>]>, z.ZodObject<{
381
381
  kind: z.ZodLiteral<"tool">;
@@ -450,6 +450,8 @@ export declare function listAkumaArchetypes(path: WorldRoot, input?: Readonly<{
450
450
  * observed extent. World Alias context is attached by the upper composition.
451
451
  */
452
452
  export declare function readAkumaRoster(path: WorldRoot, input?: AkumaListInput): Promise<AkumaList>;
453
+ /** Internal recent observation with an aperture already validated by the composition. */
454
+ export declare function observeAkumaRoster(path: WorldRoot, limit: number, selected?: string): Promise<AkumaList>;
453
455
  /** The complete native roster for callers whose semantics require a frozen set. */
454
456
  export declare function readAkumaCompleteRoster(path: WorldRoot, input?: Readonly<{
455
457
  archetype?: string;
@@ -118,6 +118,10 @@ function rosterArchetype(input, allowLimit) {
118
118
  export async function readAkumaRoster(path, input = {}) {
119
119
  const selected = rosterArchetype(input, true);
120
120
  const limit = boundedListLimit(input.limit);
121
+ return observeAkumaRoster(path, limit, selected);
122
+ }
123
+ /** Internal recent observation with an aperture already validated by the composition. */
124
+ export async function observeAkumaRoster(path, limit, selected) {
121
125
  const observedAt = new Date().toISOString();
122
126
  const known = await knownAkuma(path, selected);
123
127
  const candidatesWithBounds = await boundedMap(known.rows, async (row) => ({
@@ -93,6 +93,7 @@ type BodyRuntime = Readonly<{
93
93
  world: WorldRoot;
94
94
  externalCommands: Readonly<Record<string, ErasedRequestCommand>>;
95
95
  }>;
96
+ export declare function recordPluginDiagnostic(paths: AkumaPaths, occurrence: string, error: unknown): Promise<void>;
96
97
  export declare function bodyProcessInput(launch: BodyLaunch, bodyModuleUrl?: string): Promise<{
97
98
  argv: string[];
98
99
  cwd: string;