@astrosheep/keiyaku 4.1.0 → 4.1.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 (278) hide show
  1. package/README.md +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
  5. package/build/src/akuma/akuma-errors.d.ts +6 -0
  6. package/build/src/akuma/akuma-errors.js +9 -0
  7. package/build/src/akuma/akuma-handle.d.ts +39 -0
  8. package/build/src/akuma/akuma-handle.js +263 -0
  9. package/build/src/akuma/akuma-observe.d.ts +19 -0
  10. package/build/src/akuma/akuma-observe.js +74 -0
  11. package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
  12. package/build/src/akuma/akuma-product-symbols.js +1 -0
  13. package/build/src/akuma/akuma-product.d.ts +18 -0
  14. package/build/src/akuma/akuma-product.js +154 -0
  15. package/build/src/akuma/akuma.d.ts +37 -81
  16. package/build/src/akuma/akuma.js +39 -447
  17. package/build/src/akuma/allowed.d.ts +1 -0
  18. package/build/src/akuma/allowed.js +6 -0
  19. package/build/src/akuma/archetype.js +8 -5
  20. package/build/src/akuma/body-supervisor.d.ts +26 -0
  21. package/build/src/akuma/body-supervisor.js +89 -0
  22. package/build/src/akuma/body.d.ts +45 -4
  23. package/build/src/akuma/body.js +145 -35
  24. package/build/src/akuma/coordinate.js +17 -7
  25. package/build/src/akuma/heart/facts.js +1 -1
  26. package/build/src/akuma/heart/index.d.ts +1 -1
  27. package/build/src/akuma/heart/index.js +2 -4
  28. package/build/src/akuma/heart/request-authority.js +4 -4
  29. package/build/src/akuma/heart/request-rows.js +27 -16
  30. package/build/src/akuma/heart/rows.js +79 -41
  31. package/build/src/akuma/heart/soul.js +1 -1
  32. package/build/src/akuma/heart/storage.d.ts +1 -0
  33. package/build/src/akuma/heart/storage.js +76 -11
  34. package/build/src/akuma/heart/tells.js +35 -18
  35. package/build/src/akuma/heart/timeline.js +19 -11
  36. package/build/src/akuma/identity.d.ts +1 -0
  37. package/build/src/akuma/identity.js +1 -0
  38. package/build/src/akuma/index.d.ts +3 -3
  39. package/build/src/akuma/index.js +1 -1
  40. package/build/src/akuma/nuke.js +106 -14
  41. package/build/src/akuma/projection-read.d.ts +17 -0
  42. package/build/src/akuma/projection-read.js +135 -0
  43. package/build/src/akuma/projection.d.ts +1 -16
  44. package/build/src/akuma/projection.js +77 -154
  45. package/build/src/akuma/provider-recipe.js +11 -5
  46. package/build/src/akuma/provider.js +105 -62
  47. package/build/src/akuma/providers/acp/config.js +5 -6
  48. package/build/src/akuma/providers/acp/core.js +17 -10
  49. package/build/src/akuma/providers/acp/events.js +38 -29
  50. package/build/src/akuma/providers/acp/index.js +13 -9
  51. package/build/src/akuma/providers/claude/events.js +8 -12
  52. package/build/src/akuma/providers/claude/index.d.ts +1 -0
  53. package/build/src/akuma/providers/claude/index.js +55 -26
  54. package/build/src/akuma/providers/claude/input.js +6 -2
  55. package/build/src/akuma/providers/codex-app-server/events.js +61 -36
  56. package/build/src/akuma/providers/codex-app-server/index.js +25 -13
  57. package/build/src/akuma/providers/grok-build/index.js +22 -25
  58. package/build/src/akuma/providers/index.js +2 -18
  59. package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
  60. package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
  61. package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
  62. package/build/src/akuma/providers/pi/events.js +26 -19
  63. package/build/src/akuma/providers/pi/index.js +58 -40
  64. package/build/src/akuma/publication.js +9 -9
  65. package/build/src/akuma/request-execution.d.ts +6 -0
  66. package/build/src/akuma/request-execution.js +86 -0
  67. package/build/src/akuma/request-serve.d.ts +12 -1
  68. package/build/src/akuma/request-serve.js +19 -122
  69. package/build/src/akuma/request-wire.d.ts +2 -2
  70. package/build/src/akuma/request-wire.js +75 -102
  71. package/build/src/akuma/requests.js +2 -2
  72. package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
  73. package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
  74. package/build/src/akuma-body.js +6 -5
  75. package/build/src/body/amend.d.ts +4 -1
  76. package/build/src/body/amend.js +14 -6
  77. package/build/src/body/decode.js +2 -4
  78. package/build/src/body/envelope.js +2 -4
  79. package/build/src/body/region.d.ts +1 -2
  80. package/build/src/body/region.js +2 -70
  81. package/build/src/body/render.js +17 -12
  82. package/build/src/body/shape.js +1 -7
  83. package/build/src/cli/accepted.d.ts +1 -1
  84. package/build/src/cli/accepted.js +8 -1
  85. package/build/src/cli/commands/akuma-invoke.js +18 -6
  86. package/build/src/cli/commands/akuma.d.ts +0 -6
  87. package/build/src/cli/commands/akuma.js +11 -24
  88. package/build/src/cli/commands/amend.d.ts +2 -2
  89. package/build/src/cli/commands/amend.js +2 -4
  90. package/build/src/cli/commands/bind.d.ts +4 -4
  91. package/build/src/cli/commands/bind.js +16 -6
  92. package/build/src/cli/commands/contract-invoke.d.ts +25 -0
  93. package/build/src/cli/commands/contract-invoke.js +193 -0
  94. package/build/src/cli/commands/contract.d.ts +109 -10
  95. package/build/src/cli/commands/contract.js +339 -16
  96. package/build/src/cli/commands/install.d.ts +1 -1
  97. package/build/src/cli/commands/install.js +23 -15
  98. package/build/src/cli/commands/task-invoke.js +187 -67
  99. package/build/src/cli/commands/task-query.js +48 -24
  100. package/build/src/cli/commands/task.js +150 -38
  101. package/build/src/cli/coordinates.js +2 -4
  102. package/build/src/cli/invoke.js +92 -208
  103. package/build/src/cli/main.js +4 -2
  104. package/build/src/cli/parse.d.ts +3 -90
  105. package/build/src/cli/parse.js +27 -233
  106. package/build/src/cli/render/akuma-activity.d.ts +38 -0
  107. package/build/src/cli/render/akuma-activity.js +362 -0
  108. package/build/src/cli/render/akuma-tool-command.js +6 -7
  109. package/build/src/cli/render/akuma-tool.js +10 -8
  110. package/build/src/cli/render/akuma.d.ts +1 -1
  111. package/build/src/cli/render/akuma.js +61 -353
  112. package/build/src/cli/render/audit.js +5 -15
  113. package/build/src/cli/render/board.d.ts +1 -0
  114. package/build/src/cli/render/board.js +17 -0
  115. package/build/src/cli/render/catalog.js +81 -8
  116. package/build/src/cli/render/contract-history.d.ts +2 -0
  117. package/build/src/cli/render/contract-history.js +83 -0
  118. package/build/src/cli/render/contract-observation.d.ts +10 -0
  119. package/build/src/cli/render/contract-observation.js +58 -0
  120. package/build/src/cli/render/contract.d.ts +1 -2
  121. package/build/src/cli/render/contract.js +41 -142
  122. package/build/src/cli/render/kanshi.js +239 -215
  123. package/build/src/cli/render/receipt.js +2 -9
  124. package/build/src/cli/render/refusal.js +10 -15
  125. package/build/src/cli/render/region.js +22 -6
  126. package/build/src/cli/render/settings.js +4 -4
  127. package/build/src/cli/render/task.js +34 -14
  128. package/build/src/cli/render/terminal.js +16 -5
  129. package/build/src/cli/result.d.ts +3 -3
  130. package/build/src/cli/runtime.d.ts +6 -1
  131. package/build/src/cli/runtime.js +84 -63
  132. package/build/src/cli/selectors.js +2 -4
  133. package/build/src/cli/usage.js +6 -5
  134. package/build/src/contract-worktree.d.ts +1 -23
  135. package/build/src/contract-worktree.js +79 -155
  136. package/build/src/coordination/durable-file.js +7 -3
  137. package/build/src/coordination/sqlite-transaction-lock.js +29 -12
  138. package/build/src/core/facts/codec.js +7 -3
  139. package/build/src/core/facts/types.d.ts +1 -1
  140. package/build/src/core/subject.js +16 -9
  141. package/build/src/core/verbs/abandon.d.ts +1 -1
  142. package/build/src/core/verbs/abandon.js +1 -1
  143. package/build/src/core/verbs/amend.d.ts +1 -1
  144. package/build/src/core/verbs/amend.js +7 -7
  145. package/build/src/core/verbs/attestation.js +4 -1
  146. package/build/src/core/verbs/bind.d.ts +1 -1
  147. package/build/src/core/verbs/bind.js +1 -1
  148. package/build/src/core/verbs/placement.d.ts +1 -1
  149. package/build/src/core/verbs/placement.js +10 -8
  150. package/build/src/dispatch/index.js +8 -6
  151. package/build/src/duration.js +5 -1
  152. package/build/src/git/admission.js +5 -3
  153. package/build/src/git/hooks.d.ts +8 -0
  154. package/build/src/git/hooks.js +63 -14
  155. package/build/src/git/identity.js +1 -4
  156. package/build/src/git/integration.d.ts +2 -3
  157. package/build/src/git/integration.js +32 -39
  158. package/build/src/git/nuke.d.ts +1 -1
  159. package/build/src/git/nuke.js +110 -57
  160. package/build/src/git/observe.d.ts +13 -1
  161. package/build/src/git/observe.js +51 -44
  162. package/build/src/git/process.js +4 -2
  163. package/build/src/git/read-observation.js +10 -8
  164. package/build/src/git/reconcile.d.ts +22 -2
  165. package/build/src/git/reconcile.js +38 -274
  166. package/build/src/git/repository.d.ts +2 -0
  167. package/build/src/git/repository.js +13 -22
  168. package/build/src/git/scratch.d.ts +8 -5
  169. package/build/src/git/scratch.js +29 -2
  170. package/build/src/git/target-placement.d.ts +9 -10
  171. package/build/src/git/target-placement.js +59 -62
  172. package/build/src/git/tender.js +13 -46
  173. package/build/src/git/terminal-reconcile.d.ts +21 -0
  174. package/build/src/git/terminal-reconcile.js +278 -0
  175. package/build/src/git/terminal-seal.js +15 -12
  176. package/build/src/git/tree.js +5 -2
  177. package/build/src/git/workspace.d.ts +24 -2
  178. package/build/src/git/workspace.js +120 -16
  179. package/build/src/identity/coordinates.js +3 -1
  180. package/build/src/identity/selector.js +6 -3
  181. package/build/src/kanshi/fleet.d.ts +6 -0
  182. package/build/src/kanshi/fleet.js +27 -0
  183. package/build/src/kanshi/index.d.ts +1 -1
  184. package/build/src/kanshi/read.js +60 -48
  185. package/build/src/kanshi/report.d.ts +11 -23
  186. package/build/src/kanshi/select.js +25 -24
  187. package/build/src/library/address.d.ts +2 -1
  188. package/build/src/library/address.js +7 -8
  189. package/build/src/library/akuma-creation.js +20 -12
  190. package/build/src/library/audit.d.ts +0 -1
  191. package/build/src/library/audit.js +1 -2
  192. package/build/src/library/bind.d.ts +53 -5
  193. package/build/src/library/bind.js +98 -22
  194. package/build/src/library/catalog.d.ts +1 -0
  195. package/build/src/library/catalog.js +6 -3
  196. package/build/src/library/configuration.js +3 -1
  197. package/build/src/library/continuation.d.ts +15 -4
  198. package/build/src/library/continuation.js +24 -16
  199. package/build/src/library/contract-bind.d.ts +26 -0
  200. package/build/src/library/contract-bind.js +106 -0
  201. package/build/src/library/contract-operations.d.ts +77 -0
  202. package/build/src/library/contract-operations.js +130 -0
  203. package/build/src/library/contract-types.d.ts +95 -0
  204. package/build/src/library/contract-types.js +1 -0
  205. package/build/src/library/contract.d.ts +19 -154
  206. package/build/src/library/contract.js +46 -261
  207. package/build/src/library/fleet.d.ts +1 -1
  208. package/build/src/library/fleet.js +19 -11
  209. package/build/src/library/input.d.ts +2 -0
  210. package/build/src/library/input.js +14 -0
  211. package/build/src/library/keiyaku.d.ts +8 -7
  212. package/build/src/library/keiyaku.js +3 -3
  213. package/build/src/library/nuke.js +14 -5
  214. package/build/src/library/reconcile.d.ts +9 -4
  215. package/build/src/library/reconcile.js +30 -24
  216. package/build/src/library/refusal.d.ts +13 -5
  217. package/build/src/library/refusal.js +7 -0
  218. package/build/src/library/region.d.ts +8 -7
  219. package/build/src/library/region.js +31 -11
  220. package/build/src/library/repo.js +2 -2
  221. package/build/src/markdown/lex.js +9 -2
  222. package/build/src/markdown/parse.js +11 -7
  223. package/build/src/markdown/query.js +4 -2
  224. package/build/src/protocol/amend.js +3 -1
  225. package/build/src/protocol/attempt.d.ts +7 -3
  226. package/build/src/protocol/attempt.js +9 -5
  227. package/build/src/protocol/audit.d.ts +1 -1
  228. package/build/src/protocol/audit.js +4 -14
  229. package/build/src/protocol/bind.d.ts +19 -6
  230. package/build/src/protocol/bind.js +28 -13
  231. package/build/src/protocol/completion.d.ts +0 -1
  232. package/build/src/protocol/completion.js +1 -3
  233. package/build/src/protocol/deliver.d.ts +1 -3
  234. package/build/src/protocol/deliver.js +15 -39
  235. package/build/src/protocol/intent.d.ts +1 -0
  236. package/build/src/protocol/intent.js +9 -7
  237. package/build/src/protocol/operations.d.ts +3 -7
  238. package/build/src/protocol/operations.js +5 -3
  239. package/build/src/protocol/placement.d.ts +0 -1
  240. package/build/src/protocol/placement.js +6 -6
  241. package/build/src/protocol/read/observation.d.ts +11 -0
  242. package/build/src/protocol/read/observation.js +37 -0
  243. package/build/src/protocol/read/status.d.ts +23 -12
  244. package/build/src/protocol/read/status.js +90 -72
  245. package/build/src/protocol/reconcile.d.ts +1 -0
  246. package/build/src/protocol/reconcile.js +2 -3
  247. package/build/src/protocol/reintegrate.js +1 -1
  248. package/build/src/protocol/review.d.ts +0 -1
  249. package/build/src/protocol/review.js +15 -22
  250. package/build/src/protocol/run.d.ts +1 -0
  251. package/build/src/protocol/run.js +4 -5
  252. package/build/src/runtime/proc/launch.d.ts +33 -0
  253. package/build/src/runtime/proc/launch.js +98 -0
  254. package/build/src/runtime/proc/line-rpc.js +9 -3
  255. package/build/src/runtime/proc/run.d.ts +12 -6
  256. package/build/src/runtime/proc/run.js +78 -21
  257. package/build/src/runtime/proc/stdio.js +7 -10
  258. package/build/src/settings.js +6 -2
  259. package/build/src/settlement/holder.js +13 -10
  260. package/build/src/settlement/settle.js +39 -6
  261. package/build/src/task/board.js +12 -6
  262. package/build/src/task/compose.js +85 -22
  263. package/build/src/task/context.js +21 -8
  264. package/build/src/task/document.js +46 -10
  265. package/build/src/task/identity.js +5 -2
  266. package/build/src/task/index.d.ts +0 -1
  267. package/build/src/task/index.js +119 -34
  268. package/build/src/task/input.js +29 -7
  269. package/build/src/task/mutation.js +61 -19
  270. package/build/src/task/operations.d.ts +6 -1
  271. package/build/src/task/operations.js +83 -29
  272. package/build/src/task/query.js +55 -26
  273. package/build/src/task/store.d.ts +3 -1
  274. package/build/src/task/store.js +81 -17
  275. package/build/src/verification/execution.js +14 -11
  276. package/build/src/workspace-place.js +19 -7
  277. package/build/src/world.js +16 -6
  278. package/package.json +8 -3
@@ -5,7 +5,8 @@ import { createEventState, mapEvent } from "./events.js";
5
5
  import { coordinate, loadOpencode, OPENCODE_SDK_PROVIDER, parseModel } from "./session.js";
6
6
  function object(value) {
7
7
  return value !== null && typeof value === "object" && !Array.isArray(value)
8
- ? value : undefined;
8
+ ? value
9
+ : undefined;
9
10
  }
10
11
  function text(value) {
11
12
  return typeof value === "string" && value.trim().length > 0 ? value : undefined;
@@ -135,10 +136,7 @@ function nativeProgress(type, properties, busy) {
135
136
  function startsTurn(value, sessionId, messageID) {
136
137
  const event = object(value);
137
138
  const info = object(object(event?.properties)?.info);
138
- return event?.type === "message.updated"
139
- && info?.sessionID === sessionId
140
- && info.role === "user"
141
- && info.id === messageID;
139
+ return (event?.type === "message.updated" && info?.sessionID === sessionId && info.role === "user" && info.id === messageID);
142
140
  }
143
141
  async function observeTurn(input) {
144
142
  let active = false;
@@ -206,9 +204,7 @@ async function forceDisposeOpencode(abortController, close, finish) {
206
204
  async function drive(execution, input, loader) {
207
205
  admit(input.options);
208
206
  const signal = input.signal ?? new AbortController().signal;
209
- const resumeSessionId = input.session.kind === "resume"
210
- ? opencodeSessionId(input.session.coordinate)
211
- : undefined;
207
+ const resumeSessionId = input.session.kind === "resume" ? opencodeSessionId(input.session.coordinate) : undefined;
212
208
  const abortController = new AbortController();
213
209
  const abortSetup = () => abortController.abort(signal.reason);
214
210
  signal.addEventListener("abort", abortSetup, { once: true });
@@ -240,11 +236,20 @@ async function drive(execution, input, loader) {
240
236
  const messageID = `msg_${randomUUID().replaceAll("-", "")}`;
241
237
  const submissionState = { started: false };
242
238
  events.emit({ type: "session", coordinate: coordinate(sessionId) });
243
- const streamResult = await abortable(runtime.client.event.subscribe({ query: { directory: input.cwd } }), abortController.signal, async (late) => { await late.stream[Symbol.asyncIterator]().return?.(undefined); });
239
+ const streamResult = await abortable(runtime.client.event.subscribe({ query: { directory: input.cwd } }), abortController.signal, async (late) => {
240
+ await late.stream[Symbol.asyncIterator]().return?.(undefined);
241
+ });
244
242
  iterator = streamResult.stream[Symbol.asyncIterator]();
245
243
  const { completion, finish } = terminalSettlement(events, closeOnce);
246
244
  const observation = observeTurn({
247
- iterator, session, sessionId, cwd: input.cwd, messageID, events, state, submissionState,
245
+ iterator,
246
+ session,
247
+ sessionId,
248
+ cwd: input.cwd,
249
+ messageID,
250
+ events,
251
+ state,
252
+ submissionState,
248
253
  });
249
254
  submissionState.started = true;
250
255
  await abortable(session.promptAsync({
@@ -261,7 +266,9 @@ async function drive(execution, input, loader) {
261
266
  completion,
262
267
  abort: async () => {
263
268
  abortController.abort();
264
- void session.abort({ path: { id: sessionId }, query: { directory: input.cwd }, throwOnError: true }).catch(() => undefined);
269
+ void session
270
+ .abort({ path: { id: sessionId }, query: { directory: input.cwd }, throwOnError: true })
271
+ .catch(() => undefined);
265
272
  await finish({ kind: "failed", diagnostic: "OpenCode session interrupted" });
266
273
  },
267
274
  forceDispose: () => forceDisposeOpencode(abortController, closeOnce, finish),
@@ -288,12 +295,14 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
288
295
  return {
289
296
  kind: "admitted",
290
297
  options: Object.freeze({ ...options }),
291
- ...(options.readonly === undefined ? {} : {
292
- readonly: {
293
- enforcement: "none",
294
- diagnostic: "OpenCode V1 cannot remove task-surface mutation capabilities",
295
- },
296
- }),
298
+ ...(options.readonly === undefined
299
+ ? {}
300
+ : {
301
+ readonly: {
302
+ enforcement: "none",
303
+ diagnostic: "OpenCode V1 cannot remove task-surface mutation capabilities",
304
+ },
305
+ }),
297
306
  };
298
307
  },
299
308
  start: (input) => drive(execution, input, loader),
@@ -33,20 +33,29 @@ async function availablePort() {
33
33
  reject(new Error("OpenCode port unavailable"));
34
34
  return;
35
35
  }
36
- server.close((error) => error === undefined ? resolve(address.port) : reject(error));
36
+ server.close((error) => (error === undefined ? resolve(address.port) : reject(error)));
37
37
  });
38
38
  });
39
39
  }
40
40
  export async function loadOpencode(execution, cwd, signal, loader) {
41
41
  if (loader) {
42
42
  const loaded = await loader(cwd, execution);
43
- return { client: loaded.client, close: async () => { await loaded.close?.(); } };
43
+ return {
44
+ client: loaded.client,
45
+ close: async () => {
46
+ await loaded.close?.();
47
+ },
48
+ };
44
49
  }
45
50
  const port = await availablePort();
46
51
  const owned = await spawnDetachedProcess({
47
52
  argv: [execution.executable ?? "opencode", "serve", "--hostname", "127.0.0.1", "--port", String(port)],
48
53
  cwd,
49
- env: { ...process.env, ...execution.env },
54
+ env: {
55
+ ...process.env,
56
+ ...(execution.config === undefined ? {} : { OPENCODE_CONFIG_CONTENT: JSON.stringify(execution.config) }),
57
+ ...execution.env,
58
+ },
50
59
  log: `${cwd}/.opencode.log`,
51
60
  });
52
61
  const { createOpencodeClient } = await import("@opencode-ai/sdk");
@@ -58,6 +67,13 @@ export async function loadOpencode(execution, cwd, signal, loader) {
58
67
  await owned.terminate();
59
68
  throw error;
60
69
  }
61
- return { client, close: async () => { await owned.terminate(); } };
70
+ return {
71
+ client,
72
+ close: async () => {
73
+ await owned.terminate();
74
+ },
75
+ };
76
+ }
77
+ export function coordinate(sessionId) {
78
+ return { sessionId };
62
79
  }
63
- export function coordinate(sessionId) { return { sessionId }; }
@@ -23,25 +23,29 @@ export const PI_EVENT_DISPOSITIONS = {
23
23
  };
24
24
  function record(value) {
25
25
  return value !== null && typeof value === "object" && !Array.isArray(value)
26
- ? value : null;
26
+ ? value
27
+ : null;
27
28
  }
28
29
  function textContent(content) {
29
30
  if (typeof content === "string")
30
31
  return content;
31
32
  if (!Array.isArray(content))
32
33
  return "";
33
- return content.map((block) => {
34
+ return content
35
+ .map((block) => {
34
36
  const value = record(block);
35
37
  return value?.type === "text" && typeof value.text === "string" ? value.text : "";
36
- }).join("");
38
+ })
39
+ .join("");
37
40
  }
38
41
  function hasTextContent(content) {
39
42
  if (typeof content === "string")
40
43
  return true;
41
- return Array.isArray(content) && content.some((block) => {
42
- const value = record(block);
43
- return value?.type === "text" && typeof value.text === "string";
44
- });
44
+ return (Array.isArray(content) &&
45
+ content.some((block) => {
46
+ const value = record(block);
47
+ return value?.type === "text" && typeof value.text === "string";
48
+ }));
45
49
  }
46
50
  function positiveLine(value) {
47
51
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
@@ -50,9 +54,7 @@ function optionalText(value) {
50
54
  return typeof value === "string" && value.trim().length > 0 ? value : undefined;
51
55
  }
52
56
  function runCall(name, value) {
53
- return name === "bash" && typeof value.command === "string"
54
- ? { kind: "run", command: value.command }
55
- : undefined;
57
+ return name === "bash" && typeof value.command === "string" ? { kind: "run", command: value.command } : undefined;
56
58
  }
57
59
  function readCall(name, value) {
58
60
  if (name !== "read" || typeof value.path !== "string")
@@ -101,11 +103,10 @@ function refineEditCall(call, result) {
101
103
  }
102
104
  function toolCall(name, args) {
103
105
  const value = record(args) ?? {};
104
- return runCall(name, value)
105
- ?? readCall(name, value)
106
- ?? searchCall(name, value)
107
- ?? fileChangeCall(name, value)
108
- ?? { kind: "other", display: name };
106
+ return (runCall(name, value) ??
107
+ readCall(name, value) ??
108
+ searchCall(name, value) ??
109
+ fileChangeCall(name, value) ?? { kind: "other", display: name });
109
110
  }
110
111
  function translateNote(event) {
111
112
  if (event.type === "auto_retry_start")
@@ -122,11 +123,16 @@ function translateToolEnd(event, state) {
122
123
  state.tools.delete(event.toolCallId);
123
124
  const name = started?.name ?? event.toolName;
124
125
  const call = started?.call ?? { kind: "other", display: name };
125
- return [{
126
- type: "tool", phase: "completed", id: event.toolCallId, name,
126
+ return [
127
+ {
128
+ type: "tool",
129
+ phase: "completed",
130
+ id: event.toolCallId,
131
+ name,
127
132
  call: event.isError ? call : refineEditCall(call, event.result),
128
133
  result: { status: event.isError ? "error" : "ok" },
129
- }];
134
+ },
135
+ ];
130
136
  }
131
137
  function translateMessage(event, state) {
132
138
  const message = record(event.message);
@@ -174,7 +180,8 @@ export function piTerminalFailure(messages) {
174
180
  if (message.stopReason !== "error")
175
181
  return null;
176
182
  return typeof message.errorMessage === "string" && message.errorMessage.trim().length > 0
177
- ? message.errorMessage : "Pi provider ended with an error";
183
+ ? message.errorMessage
184
+ : "Pi provider ended with an error";
178
185
  }
179
186
  return null;
180
187
  }
@@ -3,7 +3,9 @@ import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
3
3
  import { piTerminalFailure, translatePiEvent } from "./events.js";
4
4
  const PI_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]);
5
5
  const MODEL_PATTERN = /^[^/\s]+\/[^\s]+$/u;
6
- function diagnostic(error) { return error instanceof Error ? error.message : String(error); }
6
+ function diagnostic(error) {
7
+ return error instanceof Error ? error.message : String(error);
8
+ }
7
9
  function admitPiOptions(options) {
8
10
  if (options.network !== undefined)
9
11
  return { kind: "refused", diagnostic: "Pi provider does not support the network option" };
@@ -29,27 +31,33 @@ async function piCreateOptions(sdk, input) {
29
31
  if (model === undefined)
30
32
  throw new Error(`Pi model '${input.options.model}' is unavailable`);
31
33
  }
32
- const resourceLoader = input.options.systemPrompt === undefined ? undefined : new sdk.DefaultResourceLoader({
33
- cwd: input.cwd,
34
- agentDir: sdk.getAgentDir(),
35
- ...(input.options.systemPromptMode === "append"
36
- ? { appendSystemPromptOverride: (base) => [...base, input.options.systemPrompt] }
37
- : { systemPromptOverride: () => input.options.systemPrompt }),
38
- });
34
+ const resourceLoader = input.options.systemPrompt === undefined
35
+ ? undefined
36
+ : new sdk.DefaultResourceLoader({
37
+ cwd: input.cwd,
38
+ agentDir: sdk.getAgentDir(),
39
+ ...(input.options.systemPromptMode === "append"
40
+ ? { appendSystemPromptOverride: (base) => [...base, input.options.systemPrompt] }
41
+ : { systemPromptOverride: () => input.options.systemPrompt }),
42
+ });
39
43
  await resourceLoader?.reload();
40
44
  const sessionManager = input.session.kind === "fresh"
41
45
  ? sdk.SessionManager.create(input.cwd)
42
46
  : "sessionFile" in input.session.coordinate
43
47
  ? sdk.SessionManager.open(input.session.coordinate.sessionFile)
44
- : (() => { throw new Error("Pi resume requires sessionFile"); })();
48
+ : (() => {
49
+ throw new Error("Pi resume requires sessionFile");
50
+ })();
45
51
  const customTools = input.requests === undefined || input.options.readonly === true
46
52
  ? undefined
47
- : [(await import("@earendil-works/pi-coding-agent")).createBashToolDefinition(input.cwd, {
53
+ : [
54
+ (await import("@earendil-works/pi-coding-agent")).createBashToolDefinition(input.cwd, {
48
55
  spawnHook: (context) => ({
49
56
  ...context,
50
57
  env: { ...context.env, [AKUMA_REQUESTS_ENV]: input.requests.dir },
51
58
  }),
52
- })];
59
+ }),
60
+ ];
53
61
  return {
54
62
  cwd: input.cwd,
55
63
  sessionManager,
@@ -60,8 +68,13 @@ async function piCreateOptions(sdk, input) {
60
68
  ...(customTools === undefined ? {} : { customTools }),
61
69
  };
62
70
  }
63
- async function createPiSession(sdk, input, signal) {
64
- const setup = piCreateOptions(sdk, input).then(async (options) => await sdk.createAgentSession(options));
71
+ async function createPiSession(sdk, execution, input, signal) {
72
+ const setup = piCreateOptions(sdk, input).then(async (options) => {
73
+ if (execution.config !== undefined) {
74
+ throw new TypeError("Pi provider config cannot be consumed by native CreateAgentSessionOptions");
75
+ }
76
+ return await sdk.createAgentSession(options);
77
+ });
65
78
  return await abortable(setup, signal, (created) => created.session.dispose());
66
79
  }
67
80
  function forceDisposePi(dispose, settle, setAborting) {
@@ -70,8 +83,8 @@ function forceDisposePi(dispose, settle, setAborting) {
70
83
  settle({ kind: "failed", diagnostic: "Pi session force-disposed" });
71
84
  return Promise.resolve();
72
85
  }
73
- async function drivePi(sdk, input, signal) {
74
- const created = await createPiSession(sdk, input, signal);
86
+ async function drivePi(sdk, execution, input, signal) {
87
+ const created = await createPiSession(sdk, execution, input, signal);
75
88
  const native = created.session;
76
89
  if (signal.aborted) {
77
90
  native.dispose();
@@ -112,7 +125,9 @@ async function drivePi(sdk, input, signal) {
112
125
  });
113
126
  events.emit({ type: "session", coordinate: { sessionFile: native.sessionFile, sessionId: native.sessionId } });
114
127
  let settleCompletion;
115
- const completion = new Promise((resolve) => { settleCompletion = resolve; });
128
+ const completion = new Promise((resolve) => {
129
+ settleCompletion = resolve;
130
+ });
116
131
  const settle = (result) => {
117
132
  if (settled)
118
133
  return;
@@ -123,24 +138,22 @@ async function drivePi(sdk, input, signal) {
123
138
  void (async () => {
124
139
  try {
125
140
  await native.prompt([input.body, ...input.launchTells.map((tell) => tell.text)].join("\n\n"));
126
- if (aborting) {
127
- settle({ kind: "failed", diagnostic: "Pi session aborted" });
128
- return;
129
- }
130
- if (terminalFailure !== null) {
131
- settle({ kind: "failed", diagnostic: terminalFailure });
132
- return;
141
+ let result;
142
+ if (aborting)
143
+ result = { kind: "failed", diagnostic: "Pi session aborted" };
144
+ else if (terminalFailure !== null)
145
+ result = { kind: "failed", diagnostic: terminalFailure };
146
+ else if (!state.assistantSeen)
147
+ result = { kind: "failed", diagnostic: "Pi completed without a native assistant answer" };
148
+ else {
149
+ const historyId = native.sessionManager.getLeafId();
150
+ result = {
151
+ kind: "answered",
152
+ answer: state.answer,
153
+ ...(historyId === null ? {} : { historyId }),
154
+ };
133
155
  }
134
- if (!state.assistantSeen) {
135
- settle({ kind: "failed", diagnostic: "Pi completed without a native assistant answer" });
136
- return;
137
- }
138
- const historyId = native.sessionManager.getLeafId();
139
- settle({
140
- kind: "answered",
141
- answer: state.answer,
142
- ...(historyId === null ? {} : { historyId }),
143
- });
156
+ settle(result);
144
157
  }
145
158
  catch (error) {
146
159
  settle(aborting
@@ -149,7 +162,9 @@ async function drivePi(sdk, input, signal) {
149
162
  }
150
163
  })();
151
164
  return {
152
- admission: { fence: native.sessionId }, events, completion,
165
+ admission: { fence: native.sessionId },
166
+ events,
167
+ completion,
153
168
  abort: () => {
154
169
  abortRequest ??= (async () => {
155
170
  if (settled)
@@ -158,12 +173,16 @@ async function drivePi(sdk, input, signal) {
158
173
  try {
159
174
  await native.abort();
160
175
  }
161
- catch { /* prompt settlement still proves local cleanup */ }
176
+ catch {
177
+ /* prompt settlement still proves local cleanup */
178
+ }
162
179
  settle({ kind: "failed", diagnostic: "Pi session aborted" });
163
180
  })();
164
181
  return abortRequest;
165
182
  },
166
- forceDispose: () => forceDisposePi(dispose, settle, () => { aborting = true; }),
183
+ forceDispose: () => forceDisposePi(dispose, settle, () => {
184
+ aborting = true;
185
+ }),
167
186
  };
168
187
  }
169
188
  function piSessionFile(coordinate) {
@@ -190,16 +209,15 @@ async function loadPiSdk() {
190
209
  };
191
210
  }
192
211
  export function createPiProvider(execution = { name: "pi", kind: "pi" }, load = loadPiSdk) {
193
- if (execution.executable !== undefined || execution.config !== undefined) {
194
- throw new TypeError("Pi provider does not support executable or config");
195
- }
212
+ if (execution.executable !== undefined)
213
+ throw new TypeError("Pi provider does not support executable");
196
214
  if (execution.env !== undefined && Object.keys(execution.env).length > 0) {
197
215
  throw new TypeError("env injection not supported for provider pi");
198
216
  }
199
217
  const drive = async (input) => {
200
218
  const signal = input.signal ?? new AbortController().signal;
201
219
  signal.throwIfAborted();
202
- return drivePi(await abortable(load(), signal), input, signal);
220
+ return drivePi(await abortable(load(), signal), execution, input, signal);
203
221
  };
204
222
  return {
205
223
  admitOptions: admitPiOptions,
@@ -1,7 +1,7 @@
1
- import { HeldAkumaLeash, initializeHeart, readHeart, readSeal, readSoul, } from "./heart/index.js";
2
- import { allocateAkumaDirectory, } from "./identity.js";
1
+ import { HeldAkumaLeash, initializeHeart, readHeart, readSeal, readSoul } from "./heart/index.js";
2
+ import { allocateAkumaDirectory } from "./identity.js";
3
3
  import { abortableDelay } from "./abort.js";
4
- const POLL_MS = 25;
4
+ const POLL_MS = 100;
5
5
  export const BIRTH_TIMEOUT_MS = 30_000;
6
6
  function diagnostic(error) {
7
7
  return error instanceof Error ? error.message : String(error);
@@ -22,9 +22,7 @@ async function settleTimedOutBirth(paths) {
22
22
  }
23
23
  if (result === "sealed") {
24
24
  const seal = await readSeal(paths);
25
- throw new Error(seal?.evidence === "call-timeout" || seal === null
26
- ? "Akuma body failed before birth"
27
- : seal.evidence);
25
+ throw new Error(seal?.evidence === "call-timeout" || seal === null ? "Akuma body failed before birth" : seal.evidence);
28
26
  }
29
27
  const soul = await readSoul(paths);
30
28
  if (soul === null)
@@ -57,7 +55,7 @@ async function awaitBirth(paths, signal) {
57
55
  if (settled !== null)
58
56
  return settled;
59
57
  }
60
- await abortableDelay(POLL_MS, signal);
58
+ await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())), signal);
61
59
  }
62
60
  }
63
61
  async function takeLeashUntil(paths, deadline) {
@@ -67,7 +65,7 @@ async function takeLeashUntil(paths, deadline) {
67
65
  return leash;
68
66
  if (performance.now() >= deadline)
69
67
  return null;
70
- await abortableDelay(POLL_MS);
68
+ await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
71
69
  }
72
70
  }
73
71
  async function awaitAsleepBirth(paths) {
@@ -98,7 +96,9 @@ async function sealLocalFailure(allocated, error) {
98
96
  leash.release();
99
97
  }
100
98
  }
101
- catch { /* the original local publication failure remains authoritative */ }
99
+ catch {
100
+ /* the original local publication failure remains authoritative */
101
+ }
102
102
  }
103
103
  export async function publishAkuma(input) {
104
104
  input.signal?.throwIfAborted();
@@ -0,0 +1,6 @@
1
+ import type { UpstreamRequestService } from "./heart/index.js";
2
+ import type { ServeInput, UpstreamFact } from "./request-serve.js";
3
+ export declare function executeRequest(input: ServeInput, request: UpstreamFact): Promise<Readonly<{
4
+ result: unknown;
5
+ service?: UpstreamRequestService;
6
+ }>>;
@@ -0,0 +1,86 @@
1
+ export async function executeRequest(input, request) {
2
+ if (input.upstream === undefined)
3
+ throw new Error("upstream execution port is unavailable");
4
+ if (request.action === "akuma.wait")
5
+ return {
6
+ result: await input.upstream.wait({
7
+ targets: request.targets,
8
+ completion: request.completion,
9
+ ...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
10
+ signal: input.signal,
11
+ }),
12
+ service: { action: request.action },
13
+ };
14
+ if (request.action === "akuma.tell")
15
+ return {
16
+ result: await input.upstream.tell({
17
+ target: request.target,
18
+ body: request.body,
19
+ tellId: request.id,
20
+ recordedAt: request.admittedAt,
21
+ signal: input.signal,
22
+ }),
23
+ service: { action: request.action, target: request.target, tellId: request.id },
24
+ };
25
+ if (request.action === "akuma.kill") {
26
+ const served = await input.upstream.kill({ targets: request.targets, signal: input.signal });
27
+ return { result: served.result, service: { action: request.action, results: served.service } };
28
+ }
29
+ if (request.action === "contract.deliver") {
30
+ const served = await input.upstream.deliver({
31
+ repoRoot: request.repoRoot,
32
+ contractId: request.contractId,
33
+ ...(request.message === undefined ? {} : { message: request.message }),
34
+ includeDirty: request.includeDirty,
35
+ materializeConflict: request.materializeConflict,
36
+ requester: request.requester,
37
+ signal: input.signal,
38
+ });
39
+ return {
40
+ result: served.result,
41
+ ...(served.deliveryFactId === undefined
42
+ ? {}
43
+ : {
44
+ service: {
45
+ action: request.action,
46
+ repoRoot: request.repoRoot,
47
+ contractId: request.contractId,
48
+ deliveryFactId: served.deliveryFactId,
49
+ },
50
+ }),
51
+ };
52
+ }
53
+ if (request.action === "contract.review") {
54
+ const served = await input.upstream.review({
55
+ repoRoot: request.repoRoot,
56
+ contractId: request.contractId,
57
+ verdict: request.verdict,
58
+ ...(request.summary === undefined ? {} : { summary: request.summary }),
59
+ requester: request.requester,
60
+ signal: input.signal,
61
+ });
62
+ return {
63
+ result: served.result,
64
+ ...(served.reviewFactId === undefined
65
+ ? {}
66
+ : {
67
+ service: {
68
+ action: request.action,
69
+ repoRoot: request.repoRoot,
70
+ contractId: request.contractId,
71
+ reviewFactId: served.reviewFactId,
72
+ },
73
+ }),
74
+ };
75
+ }
76
+ const task = request;
77
+ return {
78
+ result: await input.upstream.task({
79
+ world: task.world,
80
+ request: task.request,
81
+ requester: task.requester,
82
+ signal: input.signal,
83
+ }),
84
+ service: { action: task.action },
85
+ };
86
+ }
@@ -1,5 +1,6 @@
1
- import { type KillEvidence, type Soul } from "./heart/index.js";
1
+ import { type KillEvidence, type RequestFact, type Soul } from "./heart/index.js";
2
2
  import { type AkuId, type AkumaPaths } from "./identity.js";
3
+ import { type StructuralRequestClaim } from "./request-wire.js";
3
4
  import { type TaskMutationRequest } from "../task/mutation.js";
4
5
  export type RequestChildLaunch = Readonly<{
5
6
  paths: AkumaPaths;
@@ -67,6 +68,16 @@ type PumpInput = Readonly<{
67
68
  upstream?: UpstreamExecutionPort;
68
69
  signal: AbortSignal;
69
70
  }>;
71
+ export type ServeInput = Omit<PumpInput, "bodySequence"> & Readonly<{
72
+ directory: string;
73
+ claim: StructuralRequestClaim;
74
+ admissionOpen(): boolean;
75
+ }>;
76
+ export type UpstreamFact = Exclude<Extract<RequestFact, {
77
+ state: "admitted";
78
+ }>, Extract<RequestFact, {
79
+ action: "akuma.call";
80
+ }>>;
70
81
  export declare class BodyRequestPump {
71
82
  private readonly input;
72
83
  readonly directory: string;