@astrosheep/keiyaku 4.6.6 → 4.6.8

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 (217) hide show
  1. package/README.md +11 -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/codex}/.codex-plugin/plugin.json +1 -1
  6. package/build/plugins/codex/skills/keiyaku/SKILL.md +44 -0
  7. package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +130 -0
  8. package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +269 -0
  9. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +65 -0
  10. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +216 -0
  11. package/build/plugins/codex/skills/keiyaku-bind/agents/openai.yaml +4 -0
  12. package/build/plugins/codex/skills/keiyaku-task/SKILL.md +104 -0
  13. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +129 -0
  14. package/build/plugins/opencode/package.json +6 -0
  15. package/build/plugins/opencode/skills/keiyaku/SKILL.md +44 -0
  16. package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +130 -0
  17. package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +269 -0
  18. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +65 -0
  19. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +216 -0
  20. package/build/plugins/opencode/skills/keiyaku-bind/agents/openai.yaml +4 -0
  21. package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +104 -0
  22. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +129 -0
  23. package/build/{integrations → plugins}/pi/keiyaku.ts +0 -5
  24. package/build/skills/keiyaku/SKILL.md +44 -0
  25. package/build/skills/keiyaku-akuma/SKILL.md +130 -0
  26. package/build/skills/keiyaku-akuma/references/automation.md +269 -0
  27. package/build/skills/keiyaku-babysit/SKILL.md +65 -0
  28. package/build/skills/keiyaku-bind/SKILL.md +216 -0
  29. package/build/skills/keiyaku-bind/agents/openai.yaml +4 -0
  30. package/build/skills/keiyaku-task/SKILL.md +104 -0
  31. package/build/skills/keiyaku-workflow/SKILL.md +129 -0
  32. package/build/src/akuma/akuma-call.d.ts +2 -0
  33. package/build/src/akuma/akuma-call.js +8 -2
  34. package/build/src/akuma/akuma-instance.d.ts +12 -1
  35. package/build/src/akuma/akuma-instance.js +31 -9
  36. package/build/src/akuma/akuma-observe.d.ts +4 -0
  37. package/build/src/akuma/akuma-observe.js +14 -0
  38. package/build/src/akuma/akuma-owner.d.ts +6 -2
  39. package/build/src/akuma/akuma-owner.js +32 -10
  40. package/build/src/akuma/akuma-selection-execution.d.ts +3 -1
  41. package/build/src/akuma/akuma-selection-execution.js +2 -1
  42. package/build/src/akuma/akuma-wait.d.ts +2 -1
  43. package/build/src/akuma/akuma-wait.js +4 -1
  44. package/build/src/akuma/akuma.d.ts +35 -5
  45. package/build/src/akuma/akuma.js +8 -10
  46. package/build/src/akuma/archetype.d.ts +7 -15
  47. package/build/src/akuma/archetype.js +36 -35
  48. package/build/src/akuma/body.d.ts +6 -3
  49. package/build/src/akuma/body.js +41 -30
  50. package/build/src/akuma/call-request.d.ts +18 -10
  51. package/build/src/akuma/call-request.js +10 -3
  52. package/build/src/akuma/caller.d.ts +39 -0
  53. package/build/src/akuma/caller.js +36 -0
  54. package/build/src/akuma/dispatch-association.d.ts +0 -1
  55. package/build/src/akuma/dispatch-association.js +0 -3
  56. package/build/src/akuma/heart/facts.d.ts +16 -12
  57. package/build/src/akuma/heart/facts.js +8 -0
  58. package/build/src/akuma/heart/index.d.ts +2 -7
  59. package/build/src/akuma/heart/index.js +3 -17
  60. package/build/src/akuma/heart/rows.d.ts +3 -3
  61. package/build/src/akuma/heart/soul.d.ts +1 -1
  62. package/build/src/akuma/heart/soul.js +5 -24
  63. package/build/src/akuma/heart/storage.d.ts +5 -0
  64. package/build/src/akuma/heart/storage.js +7 -3
  65. package/build/src/akuma/identity.d.ts +0 -1
  66. package/build/src/akuma/identity.js +2 -5
  67. package/build/src/akuma/index.d.ts +5 -2
  68. package/build/src/akuma/index.js +1 -0
  69. package/build/src/akuma/nuke.js +6 -28
  70. package/build/src/akuma/projection.d.ts +0 -11
  71. package/build/src/akuma/provider-recipe.d.ts +7 -6
  72. package/build/src/akuma/provider-recipe.js +1 -1
  73. package/build/src/akuma/provider.d.ts +6 -10
  74. package/build/src/akuma/provider.js +6 -7
  75. package/build/src/akuma/providers/acp/events.js +5 -18
  76. package/build/src/akuma/providers/acp/index.js +2 -3
  77. package/build/src/akuma/providers/claude/events.js +35 -60
  78. package/build/src/akuma/providers/claude/index.d.ts +2 -2
  79. package/build/src/akuma/providers/claude/index.js +2 -3
  80. package/build/src/akuma/providers/codex-app-server/index.js +2 -2
  81. package/build/src/akuma/providers/decode.d.ts +25 -0
  82. package/build/src/akuma/providers/decode.js +44 -0
  83. package/build/src/akuma/providers/execution-environment.d.ts +2 -1
  84. package/build/src/akuma/providers/execution-environment.js +3 -0
  85. package/build/src/akuma/providers/grok-build/index.js +6 -22
  86. package/build/src/akuma/providers/index.js +2 -0
  87. package/build/src/akuma/providers/lifecycle.d.ts +9 -0
  88. package/build/src/akuma/providers/lifecycle.js +10 -0
  89. package/build/src/akuma/providers/opencode-sdk/events.js +1 -14
  90. package/build/src/akuma/providers/opencode-sdk/index.js +10 -17
  91. package/build/src/akuma/providers/opencode-sdk/session.js +1 -3
  92. package/build/src/akuma/providers/paseo/events.d.ts +25 -0
  93. package/build/src/akuma/providers/paseo/events.js +157 -0
  94. package/build/src/akuma/providers/paseo/index.d.ts +9 -0
  95. package/build/src/akuma/providers/paseo/index.js +353 -0
  96. package/build/src/akuma/providers/pi/events.js +5 -15
  97. package/build/src/akuma/publication.d.ts +2 -0
  98. package/build/src/akuma/publication.js +5 -0
  99. package/build/src/akuma/request-lifecycle.d.ts +3 -0
  100. package/build/src/akuma/request-lifecycle.js +25 -4
  101. package/build/src/akuma/requests.d.ts +3 -1
  102. package/build/src/akuma/requests.js +32 -0
  103. package/build/src/akuma/selection-observation.d.ts +72 -2
  104. package/build/src/akuma/selection-observation.js +0 -6
  105. package/build/src/akuma/selection-owner-port.d.ts +1 -1
  106. package/build/src/akuma/selection-owner-port.js +16 -5
  107. package/build/src/akuma/selection-request.d.ts +2 -0
  108. package/build/src/akuma/selection-request.js +2 -1
  109. package/build/src/akuma/turn-drive.js +2 -5
  110. package/build/src/akuma-body.js +4 -2
  111. package/build/src/cli/akuma-caller.d.ts +3 -0
  112. package/build/src/cli/akuma-caller.js +21 -0
  113. package/build/src/cli/commands/akuma-grammar.js +7 -12
  114. package/build/src/cli/commands/akuma.js +18 -16
  115. package/build/src/cli/commands/contract-grammar.d.ts +2 -1
  116. package/build/src/cli/commands/contract-grammar.js +13 -15
  117. package/build/src/cli/commands/contract-help.d.ts +2 -1
  118. package/build/src/cli/commands/contract-help.js +31 -1
  119. package/build/src/cli/commands/contract.js +24 -53
  120. package/build/src/cli/commands/install.js +3 -3
  121. package/build/src/cli/commands/task.js +18 -35
  122. package/build/src/cli/parse.d.ts +2 -2
  123. package/build/src/cli/render/catalog.d.ts +2 -5
  124. package/build/src/cli/render/contract-history.js +3 -6
  125. package/build/src/cli/render/contract.js +15 -50
  126. package/build/src/cli/render/receipt.js +3 -10
  127. package/build/src/cli/render/task.d.ts +4 -6
  128. package/build/src/cli/render/task.js +9 -26
  129. package/build/src/cli/runtime.d.ts +1 -1
  130. package/build/src/cli/runtime.js +11 -17
  131. package/build/src/cli/selectors.d.ts +3 -6
  132. package/build/src/cli/selectors.js +22 -53
  133. package/build/src/dispatch/index.d.ts +3 -3
  134. package/build/src/dispatch/index.js +1 -2
  135. package/build/src/git/observe.d.ts +6 -2
  136. package/build/src/git/observe.js +6 -2
  137. package/build/src/index.d.ts +6 -6
  138. package/build/src/index.js +2 -2
  139. package/build/src/kanshi/index.d.ts +1 -1
  140. package/build/src/kanshi/read.js +21 -6
  141. package/build/src/library/address.js +2 -4
  142. package/build/src/library/akuma-creation.d.ts +5 -1
  143. package/build/src/library/akuma-creation.js +33 -51
  144. package/build/src/library/akumas.d.ts +5 -4
  145. package/build/src/library/akumas.js +13 -9
  146. package/build/src/library/bind.d.ts +14 -14
  147. package/build/src/library/bind.js +11 -7
  148. package/build/src/library/contract-address.d.ts +9 -0
  149. package/build/src/library/contract-address.js +71 -0
  150. package/build/src/library/contract-composition.d.ts +4 -7
  151. package/build/src/library/contract-composition.js +6 -18
  152. package/build/src/library/contract-creation.d.ts +3 -5
  153. package/build/src/library/contract-creation.js +19 -17
  154. package/build/src/library/contract-execution.js +18 -23
  155. package/build/src/library/contract-outcomes.d.ts +2 -14
  156. package/build/src/library/contract-outcomes.js +2 -13
  157. package/build/src/library/contract-types.d.ts +36 -2
  158. package/build/src/library/delivery.d.ts +0 -2
  159. package/build/src/library/delivery.js +2 -5
  160. package/build/src/library/keiyaku.d.ts +0 -5
  161. package/build/src/library/keiyaku.js +6 -12
  162. package/build/src/library/outcome.d.ts +500 -499
  163. package/build/src/library/outcome.js +10 -0
  164. package/build/src/library/reconcile.js +8 -16
  165. package/build/src/library/refusal.d.ts +2 -2
  166. package/build/src/library/repo.d.ts +3 -2
  167. package/build/src/library/repo.js +10 -5
  168. package/build/src/library/selection.d.ts +4 -4
  169. package/build/src/library/selection.js +12 -9
  170. package/build/src/plugin/akuma-signals.d.ts +12 -11
  171. package/build/src/plugin/akuma-signals.js +40 -20
  172. package/build/src/plugin/public.d.ts +32 -2
  173. package/build/src/plugin/runtime.d.ts +1 -0
  174. package/build/src/plugin/runtime.js +35 -24
  175. package/build/src/protocol/amend.js +3 -2
  176. package/build/src/protocol/attempt.js +3 -8
  177. package/build/src/protocol/bind.d.ts +2 -2
  178. package/build/src/protocol/bind.js +1 -1
  179. package/build/src/protocol/deliver.js +3 -3
  180. package/build/src/protocol/operations.d.ts +1 -3
  181. package/build/src/protocol/operations.js +0 -8
  182. package/build/src/protocol/outcome.d.ts +1 -2
  183. package/build/src/protocol/outcome.js +1 -13
  184. package/build/src/protocol/placement.js +3 -10
  185. package/build/src/protocol/read/status.js +31 -70
  186. package/build/src/protocol/reintegrate.js +3 -10
  187. package/build/src/protocol/review.js +3 -3
  188. package/build/src/protocol/run.d.ts +5 -1
  189. package/build/src/protocol/run.js +3 -3
  190. package/build/src/runtime/proc/windows-launch.exe +0 -0
  191. package/package.json +12 -8
  192. package/plugins/pi/keiyaku.ts +57 -0
  193. package/skills/keiyaku/SKILL.md +44 -0
  194. package/skills/keiyaku-akuma/SKILL.md +130 -0
  195. package/skills/keiyaku-akuma/references/automation.md +269 -0
  196. package/skills/keiyaku-babysit/SKILL.md +65 -0
  197. package/skills/keiyaku-bind/SKILL.md +216 -0
  198. package/skills/keiyaku-bind/agents/openai.yaml +4 -0
  199. package/skills/keiyaku-task/SKILL.md +104 -0
  200. package/skills/keiyaku-workflow/SKILL.md +129 -0
  201. package/build/integrations/marketplace/.claude-plugin/marketplace.json +0 -5
  202. package/build/integrations/marketplace/plugins/keiyaku/package.json +0 -17
  203. package/build/src/cli/commands/amend.d.ts +0 -12
  204. package/build/src/cli/commands/amend.js +0 -10
  205. package/build/src/cli/commands/bind.d.ts +0 -11
  206. package/build/src/cli/commands/bind.js +0 -23
  207. package/build/src/dispatch/association.d.ts +0 -1
  208. package/build/src/dispatch/association.js +0 -1
  209. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku/SKILL.md +0 -0
  210. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-akuma/SKILL.md +0 -0
  211. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-akuma/references/automation.md +0 -0
  212. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-babysit/SKILL.md +0 -0
  213. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-bind/SKILL.md +0 -0
  214. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-bind/agents/openai.yaml +0 -0
  215. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-task/SKILL.md +0 -0
  216. /package/build/{integrations/marketplace/plugins/keiyaku → plugins/claude}/skills/keiyaku-workflow/SKILL.md +0 -0
  217. /package/build/{integrations/marketplace/plugins/keiyaku/opencode.js → plugins/opencode/index.js} +0 -0
@@ -1,3 +1,4 @@
1
+ import { projectAkumaBirth } from "./caller.js";
1
2
  import { readStatusFacts, createStatusFactReader, readLifeSnapshot, HeldAkumaLeash, isHeartAbsent, life, lifeAt, probeLeash, readHeart, readSeal, readSoul, } from "./heart/index.js";
2
3
  import { pathsForAkuId } from "./identity.js";
3
4
  import { ordinarySnapshotBudget, projectTurns, selectHistory, selectSnapshot, } from "./projection.js";
@@ -59,6 +60,18 @@ async function bornObservation(paths, expected, read, snapshot) {
59
60
  claim?.release();
60
61
  }
61
62
  }
63
+ export async function observeOutcomeRows(id, rows, observer) {
64
+ if (observer === undefined)
65
+ return;
66
+ const historyIds = rows.flatMap((row) => (row.kind === "outcome" ? [row.outcome.historyId] : []));
67
+ if (historyIds.length > 0)
68
+ await observer(id, historyIds);
69
+ }
70
+ export async function observeStatusOutcome(status, observer) {
71
+ const snapshot = status.timeline;
72
+ if (snapshot.kind === "idle" && snapshot.outcome !== undefined)
73
+ await observer?.(status.id, [snapshot.outcome.outcome.historyId]);
74
+ }
62
75
  function snapshotSelection(input) {
63
76
  return {
64
77
  aperture: input.aperture,
@@ -112,6 +125,7 @@ export async function bornLiveStatus(paths, expected, input, signal, readProject
112
125
  return {
113
126
  status: {
114
127
  id: soul.id,
128
+ birth: projectAkumaBirth(soul),
115
129
  life: currentLife,
116
130
  cwd: soul.cwd,
117
131
  allowed: soul.allowed,
@@ -1,5 +1,6 @@
1
+ import { type AkumaCaller } from "./caller.js";
1
2
  import type { WorldRoot } from "../world.js";
2
- import { type LiveStatusObservation, type WaitReason } from "./akuma-observe.js";
3
+ import { type OutcomeObserver, type LiveStatusObservation, type WaitReason } from "./akuma-observe.js";
3
4
  import type { AkumaStatus } from "./akuma.js";
4
5
  import { type TellResult, type TellWakeRuntime } from "./body.js";
5
6
  import { type CallInitialTell, type CallInitialTellAdmission } from "./call-initial-tell.js";
@@ -68,7 +69,8 @@ export declare function killAkumaWithRecovery(paths: AkumaPaths, recover?: (path
68
69
  export declare class AkumaOwner {
69
70
  readonly id: AkuId;
70
71
  private readonly worldPath;
71
- constructor(id: AkuId, worldPath: WorldRoot);
72
+ private readonly outcomeObserved?;
73
+ constructor(id: AkuId, worldPath: WorldRoot, outcomeObserved?: OutcomeObserver | undefined);
72
74
  private get paths();
73
75
  private projectHistoryTurns;
74
76
  private exactHistory;
@@ -146,6 +148,8 @@ export declare class AkumaOwner {
146
148
  }>): Promise<InterruptAdmission>;
147
149
  fork(input: Readonly<{
148
150
  at: string;
151
+ caller?: AkumaCaller;
152
+ initiator?: string;
149
153
  }>): Promise<ForkReceipt>;
150
154
  kill(options?: Readonly<{
151
155
  signal?: AbortSignal;
@@ -1,6 +1,7 @@
1
+ import { decodeAkumaCaller } from "./caller.js";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { AkumaNotBornError, AkumaProviderError } from "./akuma-errors.js";
3
- import { bornLiveStatus, bornStatus, defaultWaitComplete, waitForObservation, } from "./akuma-observe.js";
4
+ import { bornLiveStatus, bornStatus, defaultWaitComplete, observeOutcomeRows, observeStatusOutcome, waitForObservation, } from "./akuma-observe.js";
4
5
  import { executeWaitAkuma } from "./akuma-wait.js";
5
6
  import { handoffPendingTells, spawnAkumaBody, wakeRecordedTell, } from "./body.js";
6
7
  import { admitCallInitialTell } from "./call-initial-tell.js";
@@ -88,9 +89,11 @@ export async function killAkumaWithRecovery(paths, recover, signal) {
88
89
  export class AkumaOwner {
89
90
  id;
90
91
  worldPath;
91
- constructor(id, worldPath) {
92
+ outcomeObserved;
93
+ constructor(id, worldPath, outcomeObserved) {
92
94
  this.id = id;
93
95
  this.worldPath = worldPath;
96
+ this.outcomeObserved = outcomeObserved;
94
97
  }
95
98
  get paths() {
96
99
  return pathsForAkuId(this.worldPath, this.id);
@@ -109,11 +112,17 @@ export class AkumaOwner {
109
112
  return selectExactHistory((await this.projectHistoryTurns()).rows, input.id);
110
113
  }
111
114
  async status() {
112
- return (await bornStatus(this.paths, this.id, { aperture: "monitoring" })).status;
115
+ const { status } = await bornStatus(this.paths, this.id, { aperture: "monitoring" });
116
+ await observeStatusOutcome(status, this.outcomeObserved);
117
+ return status;
113
118
  }
114
119
  async history(input = {}) {
115
- if (input.id !== undefined)
116
- return this.exactHistory(input);
120
+ if (input.id !== undefined) {
121
+ const exact = await this.exactHistory(input);
122
+ if (exact.kind === "exact")
123
+ await this.outcomeObserved?.(this.id, [exact.outcome.outcome.historyId]);
124
+ return exact;
125
+ }
117
126
  if (input.before !== undefined && input.since !== undefined) {
118
127
  throw new TypeError("Akuma history before and since are mutually exclusive");
119
128
  }
@@ -129,11 +138,13 @@ export class AkumaOwner {
129
138
  if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 5_000) {
130
139
  throw new TypeError("Akuma history limit must be a positive safe integer no greater than 5000");
131
140
  }
132
- return selectHistory(await this.projectHistoryTurns(), {
141
+ const history = selectHistory(await this.projectHistoryTurns(), {
133
142
  ...(input.before === undefined ? {} : { before: input.before }),
134
143
  ...(input.since === undefined ? {} : { since: input.since }),
135
144
  limit,
136
145
  });
146
+ await observeOutcomeRows(this.id, history.rows, this.outcomeObserved);
147
+ return history;
137
148
  }
138
149
  async waitReceipt(predicate = defaultWaitComplete, options = {}) {
139
150
  if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0)) {
@@ -143,6 +154,7 @@ export class AkumaOwner {
143
154
  path: this.worldPath,
144
155
  ids: [this.id],
145
156
  completion: "all",
157
+ ...(this.outcomeObserved === undefined ? {} : { outcomeObserved: this.outcomeObserved }),
146
158
  ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
147
159
  ...(options.signal === undefined ? {} : { signal: options.signal }),
148
160
  ...(predicate === defaultWaitComplete ? {} : { predicate }),
@@ -220,6 +232,8 @@ export class AkumaOwner {
220
232
  if (tell === null)
221
233
  throw new AkumaProviderError(`recorded Tell ${tellId} is missing from Heart`);
222
234
  const outcome = await this.boundTellOutcome(tell);
235
+ if (outcome.historyId !== undefined)
236
+ await this.outcomeObserved?.(this.id, [outcome.historyId]);
223
237
  if (options.observe !== undefined) {
224
238
  await options.observe(await bornLiveStatus(this.paths, this.id, { aperture: "monitoring", admittedTellId: tellId }));
225
239
  }
@@ -237,7 +251,11 @@ export class AkumaOwner {
237
251
  if (tell.binding === undefined)
238
252
  return { outcome: null, completedAt: null };
239
253
  const end = (await readTurn(this.paths, tell.binding.turnSequence))?.end;
240
- return { outcome: end?.outcome ?? null, completedAt: end?.completedAt ?? null };
254
+ return {
255
+ outcome: end?.outcome ?? null,
256
+ completedAt: end?.completedAt ?? null,
257
+ ...(end === undefined ? {} : { historyId: `turn/${tell.binding.turnSequence}` }),
258
+ };
241
259
  }
242
260
  async interrupt(body, options = {}) {
243
261
  const admitted = await this.admitInterrupt(body, options);
@@ -302,6 +320,7 @@ export class AkumaOwner {
302
320
  };
303
321
  }
304
322
  async fork(input) {
323
+ const caller = decodeAkumaCaller(input.caller);
305
324
  const source = await readSoul(this.paths);
306
325
  if (source === null)
307
326
  throw new AkumaNotBornError(this.id);
@@ -349,8 +368,10 @@ export class AkumaOwner {
349
368
  allowed: source.allowed,
350
369
  cwd: source.cwd,
351
370
  origin: { kind: "fork", parent: this.id, at: input.at },
371
+ ...(caller === undefined ? {} : { caller }),
352
372
  },
353
373
  birthSession,
374
+ ...(input.initiator === undefined ? {} : { birthInitiator: input.initiator }),
354
375
  });
355
376
  },
356
377
  });
@@ -369,9 +390,10 @@ export class AkumaOwner {
369
390
  }
370
391
  async lastAnswer() {
371
392
  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" };
393
+ if (turn?.end?.outcome.kind !== "answered")
394
+ return { kind: "no-answer" };
395
+ await this.outcomeObserved?.(this.id, [`turn/${turn.sequence}`]);
396
+ return { kind: "answer", answer: turn.end.outcome.answer };
375
397
  }
376
398
  }
377
399
  /* ---------------------------------------------------------------------------
@@ -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. */
@@ -1,5 +1,5 @@
1
1
  import { AkumaNotBornError } from "./akuma-errors.js";
2
- import { createLiveStatusReader, defaultWaitComplete, readLiveStatus, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
2
+ import { createLiveStatusReader, defaultWaitComplete, readLiveStatus, readWaitComplete, observeOutcomeRows, observeStatusOutcome, waitForObservation, } from "./akuma-observe.js";
3
3
  import { pathsForAkuId } from "./identity.js";
4
4
  const SHARED_ORDINARY_BUDGET = 30;
5
5
  async function observeWaitRound(path, ids, signal, readers) {
@@ -88,6 +88,9 @@ export async function executeWaitAkuma(input) {
88
88
  input.onSelected(ordered.map((id) => ({ id, ...facts.get(id) })));
89
89
  }
90
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)));
91
94
  if (input.observe === undefined)
92
95
  return;
93
96
  const observed = [];
@@ -3,7 +3,7 @@ import { type BoundedList } from "../bounded-list.js";
3
3
  import type { AkumaAlias } from "../identity/selector.js";
4
4
  import type { WorldRoot } from "../world.js";
5
5
  import type { AkumaLife } from "./heart/index.js";
6
- import { type AkuId } from "./identity.js";
6
+ import { type AkuId, type AkumaPaths } from "./identity.js";
7
7
  export type AkumaListRow = Readonly<{
8
8
  id: AkuId;
9
9
  archetype: string;
@@ -34,6 +34,30 @@ export type AkumaListInput = Readonly<{
34
34
  }>;
35
35
  export declare const akumaStatusSchema: z.ZodObject<{
36
36
  id: z.ZodPipe<z.ZodString, z.ZodTransform<AkuId, string>>;
37
+ birth: z.ZodObject<{
38
+ origin: z.ZodDiscriminatedUnion<[z.ZodObject<{
39
+ kind: z.ZodLiteral<"direct">;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ kind: z.ZodLiteral<"request">;
42
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<AkuId, string>>;
43
+ requestId: z.ZodString;
44
+ }, z.core.$strip>, z.ZodObject<{
45
+ kind: z.ZodLiteral<"fork">;
46
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<AkuId, string>>;
47
+ at: z.ZodString;
48
+ }, z.core.$strip>], "kind">;
49
+ caller: z.ZodUnion<readonly [z.ZodDiscriminatedUnion<[z.ZodObject<{
50
+ kind: z.ZodLiteral<"akuma">;
51
+ world: z.ZodCustom<WorldRoot, WorldRoot>;
52
+ akuId: z.ZodPipe<z.ZodString, z.ZodTransform<AkuId, string>>;
53
+ }, z.core.$strict>, z.ZodObject<{
54
+ kind: z.ZodLiteral<"external">;
55
+ integration: z.ZodString;
56
+ id: z.ZodString;
57
+ }, z.core.$strict>], "kind">, z.ZodObject<{
58
+ kind: z.ZodLiteral<"unknown">;
59
+ }, z.core.$strict>]>;
60
+ }, z.core.$strict>;
37
61
  life: z.ZodEnum<{
38
62
  killed: "killed";
39
63
  hung: "hung";
@@ -441,10 +465,16 @@ export declare const akumaStatusSchema: z.ZodObject<{
441
465
  strandedReason: z.ZodOptional<z.ZodLiteral<"resume-unsupported">>;
442
466
  }, z.core.$strict>;
443
467
  export type AkumaStatus = z.infer<typeof akumaStatusSchema>;
444
- export declare function parseAkumaStatus(value: unknown): AkumaStatus;
445
- export declare function listAkumaArchetypes(path: WorldRoot, input?: Readonly<{
446
- home?: string;
447
- }>): Promise<readonly string[]>;
468
+ /** One recognized Akuma directory under this World's run root. */
469
+ export type KnownAkuma = Readonly<{
470
+ id: AkuId;
471
+ paths: AkumaPaths;
472
+ }>;
473
+ /** Enumerate the recognized Akuma directories under this World's run root. */
474
+ export declare function knownAkuma(path: WorldRoot, selected?: string): Promise<Readonly<{
475
+ runRoot: string;
476
+ rows: readonly KnownAkuma[];
477
+ }>>;
448
478
  /**
449
479
  * The bounded recent-activity roster: native membership, semantic order and
450
480
  * observed extent. World Alias context is attached by the upper composition.
@@ -1,16 +1,18 @@
1
+ import { akumaBirthSchema } from "./caller.js";
1
2
  import { readdir, stat } from "node:fs/promises";
2
3
  import { z } from "zod";
3
4
  import { boundedListLimit, projectBoundedList } from "../bounded-list.js";
4
5
  import { rosterListRow } from "./akuma-observe.js";
5
6
  import { AkumaOwner } from "./akuma-owner.js";
6
7
  import { allowedActionsSchema } from "./allowed.js";
7
- import { listArchetypes as readArchetypes } from "./archetype.js";
8
- import { akuIdFromDirectoryName, akumaIdSchema, akumaPaths, akumaRunRoot, archetypeName, } from "./identity.js";
8
+ import { akuIdFromDirectoryName, akumaIdSchema, akumaPaths, akumaRunRoot, } from "./identity.js";
9
+ import { validateAkumaName } from "../identity/normalize.js";
9
10
  import { activitySnapshotSchema } from "./projection.js";
10
11
  import { PAGE_POOL_SIZE, boundedMap } from "./read-pool.js";
11
12
  export const akumaStatusSchema = z
12
13
  .object({
13
14
  id: akumaIdSchema,
15
+ birth: akumaBirthSchema,
14
16
  life: z.enum(["running", "asleep", "stranded", "hung", "untidy", "killed"]),
15
17
  cwd: z.string().optional(),
16
18
  allowed: allowedActionsSchema,
@@ -18,12 +20,6 @@ export const akumaStatusSchema = z
18
20
  strandedReason: z.literal("resume-unsupported").optional(),
19
21
  })
20
22
  .strict();
21
- export function parseAkumaStatus(value) {
22
- return akumaStatusSchema.parse(value);
23
- }
24
- export async function listAkumaArchetypes(path, input = {}) {
25
- return readArchetypes({ project: path, ...(input.home === undefined ? {} : { home: input.home }) });
26
- }
27
23
  function activityAt(row) {
28
24
  if (!("lifeAt" in row))
29
25
  return null;
@@ -59,7 +55,8 @@ async function mtimeBound(paths) {
59
55
  };
60
56
  return Math.max(await read(paths.heart), await read(`${paths.heart}-wal`));
61
57
  }
62
- async function knownAkuma(path, selected) {
58
+ /** Enumerate the recognized Akuma directories under this World's run root. */
59
+ export async function knownAkuma(path, selected) {
63
60
  const runRoot = akumaRunRoot(path);
64
61
  let names;
65
62
  try {
@@ -80,6 +77,7 @@ async function knownAkuma(path, selected) {
80
77
  physical = akuIdFromDirectoryName(name);
81
78
  }
82
79
  catch {
80
+ // The run root can contain bytes not produced by Keiyaku. Preserve them.
83
81
  continue;
84
82
  }
85
83
  if (selected !== undefined && physical.archetype !== selected)
@@ -109,7 +107,7 @@ function rosterArchetype(input, allowLimit) {
109
107
  const unknown = Object.keys(input).find((key) => !allowed.includes(key));
110
108
  if (unknown !== undefined)
111
109
  throw new TypeError(`Akuma list input has unknown field: ${unknown}`);
112
- return input.archetype === undefined ? undefined : archetypeName(input.archetype);
110
+ return input.archetype === undefined ? undefined : validateAkumaName(input.archetype);
113
111
  }
114
112
  /**
115
113
  * The bounded recent-activity roster: native membership, semantic order and
@@ -1,6 +1,5 @@
1
1
  import { type BoundedList } from "../bounded-list.js";
2
2
  import type { Settings } from "../settings.js";
3
- import type { ProviderAdapter } from "./provider.js";
4
3
  import { type ProviderExecution, type ProviderOptions } from "./provider-recipe.js";
5
4
  import { type AllowedActions } from "./allowed.js";
6
5
  type DecodedArchetype = Readonly<{
@@ -17,11 +16,12 @@ export type ArchetypeCatalogRow = Readonly<{
17
16
  model?: string;
18
17
  description?: string;
19
18
  }>;
20
- type ArchetypeDefinition = DecodedArchetype & Readonly<{
21
- adapter: ProviderAdapter;
22
- }>;
23
- type AdmittedArchetype = Omit<ArchetypeDefinition, "provider"> & Readonly<{
24
- provider: ProviderExecution;
19
+ export type ArchetypeCatalog = BoundedList<ArchetypeCatalogRow>;
20
+ /** One closed catalogue request: omitted project means no project scope, never ambient discovery. */
21
+ export type ArchetypeCatalogInput = Readonly<{
22
+ project?: string;
23
+ home?: string;
24
+ limit?: number;
25
25
  }>;
26
26
  /** One loaded archetype whose provider owner has decoded its execution but not yet admitted its options. */
27
27
  type PreparedArchetype = Omit<DecodedArchetype, "provider"> & Readonly<{
@@ -39,9 +39,7 @@ type ArchetypeCoordinates = Readonly<{
39
39
  home?: string;
40
40
  }>;
41
41
  export declare function listArchetypes(input?: ArchetypeCoordinates): Promise<readonly string[]>;
42
- export declare function listArchetypeDefinitions(input?: ArchetypeCoordinates & Readonly<{
43
- limit?: number;
44
- }>): Promise<BoundedList<ArchetypeCatalogRow>>;
42
+ export declare function listArchetypeDefinitions(input?: ArchetypeCatalogInput): Promise<ArchetypeCatalog>;
45
43
  /** Resolve one archetype and decode its provider execution, leaving option admission to the caller. */
46
44
  export declare function loadPreparedArchetype(input: Readonly<{
47
45
  name: string;
@@ -49,10 +47,4 @@ export declare function loadPreparedArchetype(input: Readonly<{
49
47
  home?: string;
50
48
  settings: Settings;
51
49
  }>): Promise<PreparedArchetype>;
52
- export declare function loadArchetype(input: Readonly<{
53
- name: string;
54
- project?: string;
55
- home?: string;
56
- settings: Settings;
57
- }>): Promise<AdmittedArchetype>;
58
50
  export {};
@@ -1,11 +1,10 @@
1
1
  import { readFile, readdir } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
- import { join } from "node:path";
3
+ import { isAbsolute, join } from "node:path";
4
4
  import { parseDocument } from "yaml";
5
5
  import { boundedListLimit } from "../bounded-list.js";
6
- import { archetypeName } from "./identity.js";
6
+ import { validateAkumaName } from "../identity/normalize.js";
7
7
  import { decodeProviderOptions, decodeProviderRecipe, } from "./provider-recipe.js";
8
- import { resolveProviderExecution } from "./providers/index.js";
9
8
  import { DEFAULT_ALLOWED_ACTIONS, decodeAllowedActions } from "./allowed.js";
10
9
  export class AkumaArchetypeError extends Error {
11
10
  archetype;
@@ -37,7 +36,7 @@ async function pathsInDirectory(directory) {
37
36
  return [];
38
37
  const name = entry.name.slice(0, -3);
39
38
  try {
40
- return [{ name: archetypeName(name), path: join(directory, entry.name) }];
39
+ return [{ name: validateAkumaName(name), path: join(directory, entry.name) }];
41
40
  }
42
41
  catch {
43
42
  return [];
@@ -127,7 +126,7 @@ function parseArchetypeFrontmatter(markdown) {
127
126
  function decodeArchetypeFields(values) {
128
127
  const provider = archetypeField(values, "provider");
129
128
  const baseValue = archetypeField(values, "base");
130
- const base = baseValue === undefined ? undefined : archetypeName(baseValue);
129
+ const base = baseValue === undefined ? undefined : validateAkumaName(baseValue);
131
130
  const model = archetypeField(values, "model");
132
131
  const effort = archetypeField(values, "effort");
133
132
  const network = archetypeEnum(values, "network", ["disabled", "enabled"]);
@@ -237,14 +236,41 @@ async function resolveArchetype(name, input, source, chain = []) {
237
236
  const missingChain = chain.length === 0 ? chain : [...chain, name];
238
237
  throw archetypeError(name, searched, "was not found", missingChain, chain.length === 0 ? "use `keiyaku ls aku/` to list available Akuma" : undefined);
239
238
  }
239
+ function catalogueCoordinate(value, field) {
240
+ if (value === undefined)
241
+ return undefined;
242
+ if (typeof value !== "string" || value.trim().length === 0) {
243
+ throw new TypeError(`Akuma catalogue ${field} must be a nonblank string`);
244
+ }
245
+ if (!isAbsolute(value))
246
+ throw new TypeError(`Akuma catalogue ${field} must be absolute: ${value}`);
247
+ return value;
248
+ }
249
+ /** Malformed caller input fails here, before any filesystem observation. */
250
+ function catalogueInput(value) {
251
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
252
+ throw new TypeError("Akuma catalogue input must be an object");
253
+ }
254
+ const input = value;
255
+ const unknown = Object.keys(input).find((key) => !["project", "home", "limit"].includes(key));
256
+ if (unknown !== undefined)
257
+ throw new TypeError(`Akuma catalogue input has unknown field: ${unknown}`);
258
+ const project = catalogueCoordinate(input.project, "project");
259
+ const home = catalogueCoordinate(input.home, "home");
260
+ return {
261
+ ...(project === undefined ? {} : { project }),
262
+ ...(home === undefined ? {} : { home }),
263
+ ...(input.limit === undefined ? {} : { limit: boundedListLimit(input.limit) }),
264
+ };
265
+ }
240
266
  export async function listArchetypeDefinitions(input = {}) {
241
267
  // Reads still run concurrently, but the reported failure is the first invalid
242
268
  // definition in catalog byte order, not whichever read happened to finish first.
243
- const limit = input.limit === undefined ? undefined : boundedListLimit(input.limit);
244
- const all = await archetypePaths(input);
269
+ const { limit, ...coordinates } = catalogueInput(input);
270
+ const all = await archetypePaths(coordinates);
245
271
  const settled = await Promise.allSettled(all.map(async ({ name, path }) => {
246
272
  try {
247
- return await resolveArchetype(name, input, undefined);
273
+ return await resolveArchetype(name, coordinates, undefined);
248
274
  }
249
275
  catch (error) {
250
276
  if (error instanceof AkumaArchetypeError)
@@ -307,6 +333,7 @@ const BUILTIN_EXECUTIONS = {
307
333
  executable: "kimi",
308
334
  config: { argvBefore: ["acp"], argvAfter: [], modelConfigId: "model", effortConfigId: "thinking" },
309
335
  },
336
+ paseo: { kind: "paseo" },
310
337
  pi: { kind: "pi" },
311
338
  "grok-build": {
312
339
  kind: "grok-build",
@@ -325,32 +352,9 @@ function providerExecution(settings, name) {
325
352
  return decodeProviderRecipe({ name, ...builtin });
326
353
  throw new TypeError(`unknown provider ${name}`);
327
354
  }
328
- async function admitArchetype(archetype) {
329
- let selected;
330
- try {
331
- selected = await resolveProviderExecution(archetype.provider);
332
- }
333
- catch (error) {
334
- if (error instanceof TypeError)
335
- throw new AkumaArchetypeError(archetype.name, [archetype.path], `uses ${error.message}`);
336
- throw error;
337
- }
338
- const execution = selected.execution;
339
- const adapter = selected.adapter;
340
- const admission = adapter.admitOptions(archetype.options);
341
- if (admission.kind === "refused") {
342
- throw new AkumaArchetypeError(archetype.name, [archetype.path], `is unsupported: ${admission.diagnostic}`);
343
- }
344
- return Object.freeze({
345
- ...archetype,
346
- provider: execution,
347
- adapter,
348
- options: admission.options,
349
- });
350
- }
351
355
  /** Resolve one archetype and decode its provider execution, leaving option admission to the caller. */
352
356
  export async function loadPreparedArchetype(input) {
353
- const name = archetypeName(input.name);
357
+ const name = validateAkumaName(input.name);
354
358
  const definition = await resolveArchetype(name, input, undefined);
355
359
  let provider;
356
360
  try {
@@ -363,6 +367,3 @@ export async function loadPreparedArchetype(input) {
363
367
  }
364
368
  return Object.freeze({ ...definition, provider });
365
369
  }
366
- export async function loadArchetype(input) {
367
- return await admitArchetype(await loadPreparedArchetype(input));
368
- }
@@ -25,6 +25,7 @@ export declare const bodyLaunchSchema: z.ZodObject<{
25
25
  options: import("./provider-recipe.js").ProviderOptions;
26
26
  cwd: string;
27
27
  origin: import("./heart/facts.js").AkumaOrigin;
28
+ caller?: import("./caller.js").AkumaCaller;
28
29
  allowed: import("./allowed.js").AllowedActions;
29
30
  createdAt: string;
30
31
  }>, "createdAt">, unknown>>>;
@@ -55,11 +56,11 @@ export declare const bodyLaunchSchema: z.ZodObject<{
55
56
  }>>;
56
57
  systemPrompt: z.ZodOptional<z.ZodString>;
57
58
  systemPromptMode: z.ZodOptional<z.ZodEnum<{
58
- append: "append";
59
59
  replace: "replace";
60
+ append: "append";
60
61
  }>>;
61
62
  }, z.core.$strip>, z.ZodTransform<Readonly<{
62
- systemPromptMode?: "append" | "replace";
63
+ systemPromptMode?: "replace" | "append";
63
64
  systemPrompt?: string;
64
65
  network?: "disabled" | "enabled";
65
66
  effort?: string;
@@ -69,12 +70,13 @@ export declare const bodyLaunchSchema: z.ZodObject<{
69
70
  effort?: string | undefined;
70
71
  network?: "disabled" | "enabled" | undefined;
71
72
  systemPrompt?: string | undefined;
72
- systemPromptMode?: "append" | "replace" | undefined;
73
+ systemPromptMode?: "replace" | "append" | undefined;
73
74
  }>>;
74
75
  admittedAt: z.ZodString;
75
76
  }, z.core.$strict>>;
76
77
  initialBody: z.ZodOptional<z.ZodString>;
77
78
  initiator: z.ZodOptional<z.ZodString>;
79
+ birthInitiator: z.ZodOptional<z.ZodString>;
78
80
  initialSchemaJson: z.ZodOptional<z.ZodString>;
79
81
  refuseIfHeld: z.ZodOptional<z.ZodBoolean>;
80
82
  completion: z.ZodOptional<z.ZodObject<{
@@ -93,6 +95,7 @@ type BodyRuntime = Readonly<{
93
95
  world: WorldRoot;
94
96
  externalCommands: Readonly<Record<string, ErasedRequestCommand>>;
95
97
  }>;
98
+ export declare function recordPluginDiagnostic(paths: AkumaPaths, occurrence: string, error: unknown): Promise<void>;
96
99
  export declare function bodyProcessInput(launch: BodyLaunch, bodyModuleUrl?: string): Promise<{
97
100
  argv: string[];
98
101
  cwd: string;