@astrosheep/keiyaku 4.1.0 → 4.1.1

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 (241) 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.d.ts +17 -14
  6. package/build/src/akuma/akuma.js +122 -114
  7. package/build/src/akuma/allowed.d.ts +1 -0
  8. package/build/src/akuma/allowed.js +6 -0
  9. package/build/src/akuma/archetype.js +8 -5
  10. package/build/src/akuma/body-turn.js +27 -15
  11. package/build/src/akuma/body.d.ts +44 -3
  12. package/build/src/akuma/body.js +142 -33
  13. package/build/src/akuma/coordinate.js +17 -7
  14. package/build/src/akuma/heart/facts.js +1 -1
  15. package/build/src/akuma/heart/index.d.ts +1 -1
  16. package/build/src/akuma/heart/index.js +2 -4
  17. package/build/src/akuma/heart/request-authority.js +4 -4
  18. package/build/src/akuma/heart/request-rows.js +27 -16
  19. package/build/src/akuma/heart/rows.js +79 -41
  20. package/build/src/akuma/heart/soul.js +1 -1
  21. package/build/src/akuma/heart/storage.d.ts +1 -0
  22. package/build/src/akuma/heart/storage.js +76 -11
  23. package/build/src/akuma/heart/tells.js +35 -18
  24. package/build/src/akuma/heart/timeline.js +19 -11
  25. package/build/src/akuma/identity.d.ts +1 -0
  26. package/build/src/akuma/identity.js +1 -0
  27. package/build/src/akuma/index.d.ts +3 -3
  28. package/build/src/akuma/index.js +1 -1
  29. package/build/src/akuma/nuke.js +106 -14
  30. package/build/src/akuma/projection.d.ts +11 -9
  31. package/build/src/akuma/projection.js +110 -53
  32. package/build/src/akuma/provider-recipe.js +11 -5
  33. package/build/src/akuma/provider.js +105 -62
  34. package/build/src/akuma/providers/acp/config.js +5 -6
  35. package/build/src/akuma/providers/acp/core.js +17 -10
  36. package/build/src/akuma/providers/acp/events.js +38 -29
  37. package/build/src/akuma/providers/acp/index.js +13 -9
  38. package/build/src/akuma/providers/claude/events.js +8 -12
  39. package/build/src/akuma/providers/claude/index.d.ts +1 -0
  40. package/build/src/akuma/providers/claude/index.js +55 -26
  41. package/build/src/akuma/providers/claude/input.js +6 -2
  42. package/build/src/akuma/providers/codex-app-server/events.js +61 -36
  43. package/build/src/akuma/providers/codex-app-server/index.js +25 -13
  44. package/build/src/akuma/providers/grok-build/index.js +22 -25
  45. package/build/src/akuma/providers/index.js +2 -18
  46. package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
  47. package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
  48. package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
  49. package/build/src/akuma/providers/pi/events.js +26 -19
  50. package/build/src/akuma/providers/pi/index.js +58 -40
  51. package/build/src/akuma/publication.js +9 -9
  52. package/build/src/akuma/request-serve.js +37 -40
  53. package/build/src/akuma/request-wire.d.ts +2 -2
  54. package/build/src/akuma/request-wire.js +75 -102
  55. package/build/src/akuma/requests.js +2 -2
  56. package/build/src/akuma-body.js +6 -5
  57. package/build/src/body/amend.d.ts +4 -1
  58. package/build/src/body/amend.js +14 -6
  59. package/build/src/body/decode.js +2 -4
  60. package/build/src/body/envelope.js +2 -4
  61. package/build/src/body/region.d.ts +1 -2
  62. package/build/src/body/region.js +2 -70
  63. package/build/src/body/render.js +17 -12
  64. package/build/src/body/shape.js +1 -7
  65. package/build/src/cli/accepted.d.ts +1 -1
  66. package/build/src/cli/accepted.js +8 -1
  67. package/build/src/cli/commands/akuma-invoke.js +18 -6
  68. package/build/src/cli/commands/akuma.js +10 -13
  69. package/build/src/cli/commands/amend.d.ts +2 -2
  70. package/build/src/cli/commands/amend.js +2 -4
  71. package/build/src/cli/commands/bind.d.ts +4 -4
  72. package/build/src/cli/commands/bind.js +16 -6
  73. package/build/src/cli/commands/contract.d.ts +97 -10
  74. package/build/src/cli/commands/contract.js +110 -16
  75. package/build/src/cli/commands/install.d.ts +1 -1
  76. package/build/src/cli/commands/install.js +23 -15
  77. package/build/src/cli/commands/task-invoke.js +187 -67
  78. package/build/src/cli/commands/task-query.js +48 -24
  79. package/build/src/cli/commands/task.js +150 -38
  80. package/build/src/cli/coordinates.js +2 -4
  81. package/build/src/cli/invoke.js +88 -44
  82. package/build/src/cli/main.js +4 -2
  83. package/build/src/cli/parse.d.ts +2 -89
  84. package/build/src/cli/parse.js +86 -78
  85. package/build/src/cli/render/akuma-tool-command.js +6 -7
  86. package/build/src/cli/render/akuma-tool.js +10 -8
  87. package/build/src/cli/render/akuma.js +125 -60
  88. package/build/src/cli/render/audit.js +5 -15
  89. package/build/src/cli/render/board.d.ts +1 -0
  90. package/build/src/cli/render/board.js +17 -0
  91. package/build/src/cli/render/catalog.js +81 -8
  92. package/build/src/cli/render/contract-observation.d.ts +10 -0
  93. package/build/src/cli/render/contract-observation.js +58 -0
  94. package/build/src/cli/render/contract.js +42 -61
  95. package/build/src/cli/render/kanshi.js +239 -215
  96. package/build/src/cli/render/receipt.js +2 -9
  97. package/build/src/cli/render/refusal.js +10 -15
  98. package/build/src/cli/render/region.js +22 -6
  99. package/build/src/cli/render/settings.js +4 -4
  100. package/build/src/cli/render/task.js +34 -14
  101. package/build/src/cli/render/terminal.js +16 -5
  102. package/build/src/cli/result.d.ts +3 -3
  103. package/build/src/cli/runtime.d.ts +6 -1
  104. package/build/src/cli/runtime.js +84 -63
  105. package/build/src/cli/selectors.js +2 -4
  106. package/build/src/cli/usage.js +6 -5
  107. package/build/src/contract-worktree.d.ts +1 -23
  108. package/build/src/contract-worktree.js +79 -155
  109. package/build/src/coordination/durable-file.js +7 -3
  110. package/build/src/coordination/sqlite-transaction-lock.js +29 -12
  111. package/build/src/core/facts/codec.js +7 -3
  112. package/build/src/core/facts/types.d.ts +1 -1
  113. package/build/src/core/subject.js +16 -9
  114. package/build/src/core/verbs/abandon.d.ts +1 -1
  115. package/build/src/core/verbs/abandon.js +1 -1
  116. package/build/src/core/verbs/amend.d.ts +1 -1
  117. package/build/src/core/verbs/amend.js +7 -7
  118. package/build/src/core/verbs/attestation.js +4 -1
  119. package/build/src/core/verbs/bind.d.ts +1 -1
  120. package/build/src/core/verbs/bind.js +1 -1
  121. package/build/src/core/verbs/placement.d.ts +1 -1
  122. package/build/src/core/verbs/placement.js +10 -8
  123. package/build/src/dispatch/index.js +8 -6
  124. package/build/src/duration.js +5 -1
  125. package/build/src/git/admission.js +5 -3
  126. package/build/src/git/hooks.d.ts +8 -0
  127. package/build/src/git/hooks.js +63 -14
  128. package/build/src/git/identity.js +1 -4
  129. package/build/src/git/integration.d.ts +2 -3
  130. package/build/src/git/integration.js +32 -39
  131. package/build/src/git/nuke.d.ts +1 -1
  132. package/build/src/git/nuke.js +110 -57
  133. package/build/src/git/observe.d.ts +13 -1
  134. package/build/src/git/observe.js +51 -44
  135. package/build/src/git/process.js +4 -2
  136. package/build/src/git/read-observation.js +10 -8
  137. package/build/src/git/reconcile.d.ts +14 -1
  138. package/build/src/git/reconcile.js +121 -69
  139. package/build/src/git/repository.d.ts +2 -0
  140. package/build/src/git/repository.js +13 -22
  141. package/build/src/git/target-placement.d.ts +9 -10
  142. package/build/src/git/target-placement.js +59 -62
  143. package/build/src/git/tender.js +13 -46
  144. package/build/src/git/terminal-seal.js +15 -12
  145. package/build/src/git/tree.js +5 -2
  146. package/build/src/git/workspace.d.ts +24 -2
  147. package/build/src/git/workspace.js +120 -16
  148. package/build/src/identity/coordinates.js +3 -1
  149. package/build/src/identity/selector.js +6 -3
  150. package/build/src/kanshi/fleet.d.ts +6 -0
  151. package/build/src/kanshi/fleet.js +27 -0
  152. package/build/src/kanshi/index.d.ts +1 -1
  153. package/build/src/kanshi/read.js +60 -48
  154. package/build/src/kanshi/report.d.ts +11 -23
  155. package/build/src/kanshi/select.js +25 -24
  156. package/build/src/library/address.d.ts +2 -1
  157. package/build/src/library/address.js +7 -8
  158. package/build/src/library/akuma-creation.js +20 -12
  159. package/build/src/library/audit.d.ts +0 -1
  160. package/build/src/library/audit.js +1 -2
  161. package/build/src/library/bind.d.ts +53 -5
  162. package/build/src/library/bind.js +98 -22
  163. package/build/src/library/catalog.d.ts +1 -0
  164. package/build/src/library/catalog.js +6 -3
  165. package/build/src/library/configuration.js +3 -1
  166. package/build/src/library/continuation.d.ts +15 -4
  167. package/build/src/library/continuation.js +24 -16
  168. package/build/src/library/contract.d.ts +33 -43
  169. package/build/src/library/contract.js +138 -140
  170. package/build/src/library/fleet.d.ts +1 -1
  171. package/build/src/library/fleet.js +19 -11
  172. package/build/src/library/input.d.ts +2 -0
  173. package/build/src/library/input.js +14 -0
  174. package/build/src/library/keiyaku.d.ts +8 -7
  175. package/build/src/library/keiyaku.js +3 -3
  176. package/build/src/library/nuke.js +14 -5
  177. package/build/src/library/reconcile.d.ts +9 -4
  178. package/build/src/library/reconcile.js +30 -24
  179. package/build/src/library/refusal.d.ts +13 -5
  180. package/build/src/library/refusal.js +7 -0
  181. package/build/src/library/region.d.ts +8 -7
  182. package/build/src/library/region.js +31 -11
  183. package/build/src/library/repo.js +2 -2
  184. package/build/src/markdown/lex.js +9 -2
  185. package/build/src/markdown/parse.js +11 -7
  186. package/build/src/markdown/query.js +4 -2
  187. package/build/src/protocol/amend.js +3 -1
  188. package/build/src/protocol/attempt.d.ts +7 -3
  189. package/build/src/protocol/attempt.js +9 -5
  190. package/build/src/protocol/audit.d.ts +1 -1
  191. package/build/src/protocol/audit.js +4 -14
  192. package/build/src/protocol/bind.d.ts +19 -6
  193. package/build/src/protocol/bind.js +28 -13
  194. package/build/src/protocol/completion.d.ts +0 -1
  195. package/build/src/protocol/completion.js +1 -3
  196. package/build/src/protocol/deliver.d.ts +1 -3
  197. package/build/src/protocol/deliver.js +15 -39
  198. package/build/src/protocol/intent.d.ts +1 -0
  199. package/build/src/protocol/intent.js +9 -7
  200. package/build/src/protocol/operations.d.ts +3 -7
  201. package/build/src/protocol/operations.js +5 -3
  202. package/build/src/protocol/placement.d.ts +0 -1
  203. package/build/src/protocol/placement.js +6 -6
  204. package/build/src/protocol/read/observation.d.ts +11 -0
  205. package/build/src/protocol/read/observation.js +37 -0
  206. package/build/src/protocol/read/status.d.ts +23 -12
  207. package/build/src/protocol/read/status.js +90 -72
  208. package/build/src/protocol/reconcile.d.ts +1 -0
  209. package/build/src/protocol/reconcile.js +2 -3
  210. package/build/src/protocol/reintegrate.js +1 -1
  211. package/build/src/protocol/review.d.ts +0 -1
  212. package/build/src/protocol/review.js +15 -22
  213. package/build/src/protocol/run.d.ts +1 -0
  214. package/build/src/protocol/run.js +4 -5
  215. package/build/src/runtime/proc/launch.d.ts +33 -0
  216. package/build/src/runtime/proc/launch.js +98 -0
  217. package/build/src/runtime/proc/line-rpc.js +9 -3
  218. package/build/src/runtime/proc/run.d.ts +12 -6
  219. package/build/src/runtime/proc/run.js +78 -21
  220. package/build/src/runtime/proc/stdio.js +7 -10
  221. package/build/src/settings.js +6 -2
  222. package/build/src/settlement/holder.js +13 -10
  223. package/build/src/settlement/settle.js +39 -6
  224. package/build/src/task/board.js +12 -6
  225. package/build/src/task/compose.js +85 -22
  226. package/build/src/task/context.js +21 -8
  227. package/build/src/task/document.js +46 -10
  228. package/build/src/task/identity.js +5 -2
  229. package/build/src/task/index.d.ts +0 -1
  230. package/build/src/task/index.js +119 -34
  231. package/build/src/task/input.js +29 -7
  232. package/build/src/task/mutation.js +61 -19
  233. package/build/src/task/operations.d.ts +6 -1
  234. package/build/src/task/operations.js +83 -29
  235. package/build/src/task/query.js +55 -26
  236. package/build/src/task/store.d.ts +3 -1
  237. package/build/src/task/store.js +81 -17
  238. package/build/src/verification/execution.js +14 -11
  239. package/build/src/workspace-place.js +19 -7
  240. package/build/src/world.js +16 -6
  241. 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();
@@ -2,11 +2,11 @@ import { access, mkdir, readFile, readdir, rm } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { abortableDelay } from "./abort.js";
4
4
  import { HeldAkumaLeash, admitRequest, readNonterminalRequests, readRequest, readSoul, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, voidRequest, } from "./heart/index.js";
5
- import { pathsForAkuId, worldRootForAkumaPaths, } from "./identity.js";
5
+ import { pathsForAkuId, worldRootForAkumaPaths } from "./identity.js";
6
6
  import { BIRTH_TIMEOUT_MS, publishAkuma } from "./publication.js";
7
7
  import { atomicJson, canonicalAkuId, decodeClaim, decodeRecipe, receiptPath, } from "./request-wire.js";
8
8
  import { isTaskMutationAction } from "../task/mutation.js";
9
- const POLL_MS = 25;
9
+ const POLL_MS = 100;
10
10
  function diagnostic(error) {
11
11
  return error instanceof Error ? error.message : String(error);
12
12
  }
@@ -123,14 +123,10 @@ async function serveCall(input) {
123
123
  seed: {
124
124
  id: allocated.id,
125
125
  archetype: allocated.archetype,
126
- ...(request.recipe.description === undefined
127
- ? {}
128
- : { description: request.recipe.description }),
126
+ ...(request.recipe.description === undefined ? {} : { description: request.recipe.description }),
129
127
  provider: request.recipe.provider,
130
128
  options: request.recipe.options,
131
- ...(request.recipe.readonly === undefined
132
- ? {}
133
- : { readonly: request.recipe.readonly }),
129
+ ...(request.recipe.readonly === undefined ? {} : { readonly: request.recipe.readonly }),
134
130
  allowed: request.recipe.allowed,
135
131
  cwd: request.cwd ?? input.parent.cwd,
136
132
  origin: {
@@ -149,9 +145,10 @@ async function serveCall(input) {
149
145
  const current = await readRequest(input.paths, request.id);
150
146
  if (current === null)
151
147
  throw error;
152
- fact = current.state === "admitted" || current.state === "reserved"
153
- ? await voidRequest(input.paths, request.id, diagnostic(error))
154
- : current;
148
+ fact =
149
+ current.state === "admitted" || current.state === "reserved"
150
+ ? await voidRequest(input.paths, request.id, diagnostic(error))
151
+ : current;
155
152
  }
156
153
  await projectReceipt(input.directory, fact);
157
154
  }
@@ -228,14 +225,16 @@ async function executeDeliver(input, request) {
228
225
  });
229
226
  return {
230
227
  result: served.result,
231
- ...(served.deliveryFactId === undefined ? {} : {
232
- service: {
233
- action: request.action,
234
- repoRoot: request.repoRoot,
235
- contractId: request.contractId,
236
- deliveryFactId: served.deliveryFactId,
237
- },
238
- }),
228
+ ...(served.deliveryFactId === undefined
229
+ ? {}
230
+ : {
231
+ service: {
232
+ action: request.action,
233
+ repoRoot: request.repoRoot,
234
+ contractId: request.contractId,
235
+ deliveryFactId: served.deliveryFactId,
236
+ },
237
+ }),
239
238
  };
240
239
  }
241
240
  async function executeReview(input, request) {
@@ -251,14 +250,16 @@ async function executeReview(input, request) {
251
250
  });
252
251
  return {
253
252
  result: served.result,
254
- ...(served.reviewFactId === undefined ? {} : {
255
- service: {
256
- action: request.action,
257
- repoRoot: request.repoRoot,
258
- contractId: request.contractId,
259
- reviewFactId: served.reviewFactId,
260
- },
261
- }),
253
+ ...(served.reviewFactId === undefined
254
+ ? {}
255
+ : {
256
+ service: {
257
+ action: request.action,
258
+ repoRoot: request.repoRoot,
259
+ contractId: request.contractId,
260
+ reviewFactId: served.reviewFactId,
261
+ },
262
+ }),
262
263
  };
263
264
  }
264
265
  function pendingService(request) {
@@ -313,9 +314,10 @@ async function serveUpstream(input) {
313
314
  await projectReceipt(input.directory, fact);
314
315
  return;
315
316
  }
316
- fact = service === undefined
317
- ? await voidRequest(input.paths, request.id, "body completed without a durable Contract fact reference")
318
- : await serveUpstreamRequest(input.paths, request.id, service);
317
+ fact =
318
+ service === undefined
319
+ ? await voidRequest(input.paths, request.id, "body completed without a durable Contract fact reference")
320
+ : await serveUpstreamRequest(input.paths, request.id, service);
319
321
  await projectReceipt(input.directory, fact, outcome);
320
322
  }
321
323
  async function serve(input) {
@@ -325,9 +327,7 @@ async function serve(input) {
325
327
  }
326
328
  async function requestFiles(directory) {
327
329
  try {
328
- return (await readdir(directory))
329
- .filter((name) => name.endsWith(".request.json"))
330
- .sort();
330
+ return (await readdir(directory)).filter((name) => name.endsWith(".request.json")).sort();
331
331
  }
332
332
  catch (error) {
333
333
  if (error.code === "ENOENT")
@@ -421,9 +421,7 @@ export async function clearBodyRequestTransport(paths) {
421
421
  await rm(join(paths.directory, "requests"), { recursive: true, force: true });
422
422
  }
423
423
  function matchingRequestOrigin(soul, parent, id) {
424
- return soul.origin.kind === "request"
425
- && soul.origin.parent === parent
426
- && soul.origin.requestId === id;
424
+ return soul.origin.kind === "request" && soul.origin.parent === parent && soul.origin.requestId === id;
427
425
  }
428
426
  async function settleReservedSoul(paths, parent, request, soul) {
429
427
  await (matchingRequestOrigin(soul, parent.id, request.id)
@@ -435,7 +433,7 @@ async function settleReserved(paths, parent, request, now, signal) {
435
433
  const deadline = performance.now() + BIRTH_TIMEOUT_MS;
436
434
  for (;;) {
437
435
  signal?.throwIfAborted();
438
- if (!await access(childPaths.directory).then(() => true, () => false)) {
436
+ if (!(await access(childPaths.directory).then(() => true, () => false))) {
439
437
  await voidRequest(paths, request.id, "reserved child directory is absent");
440
438
  return true;
441
439
  }
@@ -466,7 +464,7 @@ async function settleReserved(paths, parent, request, now, signal) {
466
464
  }
467
465
  if (performance.now() >= deadline)
468
466
  return false;
469
- await abortableDelay(POLL_MS, signal);
467
+ await abortableDelay(Math.min(POLL_MS, Math.max(0, deadline - performance.now())), signal);
470
468
  }
471
469
  }
472
470
  export async function settleBodyRequests(paths, parent, now, signal) {
@@ -476,8 +474,7 @@ export async function settleBodyRequests(paths, parent, now, signal) {
476
474
  if (request.state === "admitted") {
477
475
  await voidRequest(paths, request.id, "body died before serving the request");
478
476
  }
479
- else if (request.state === "reserved"
480
- && !await settleReserved(paths, parent, request, now, signal))
477
+ else if (request.state === "reserved" && !(await settleReserved(paths, parent, request, now, signal)))
481
478
  pending = true;
482
479
  }
483
480
  return pending ? "pending" : "settled";
@@ -60,9 +60,9 @@ export type TaskRequestClaim = Readonly<{
60
60
  request: TaskMutationRequest;
61
61
  }>;
62
62
  export type RequestClaim = CallRequestClaim | WaitRequestClaim | TellRequestClaim | KillRequestClaim | DeliverRequestClaim | ReviewRequestClaim | TaskRequestClaim;
63
- export type StructuralRequestClaim = Omit<CallRequestClaim, "recipe"> & Readonly<{
63
+ export type StructuralRequestClaim = (Omit<CallRequestClaim, "recipe"> & Readonly<{
64
64
  recipe: unknown;
65
- }> | Exclude<RequestClaim, CallRequestClaim>;
65
+ }>) | Exclude<RequestClaim, CallRequestClaim>;
66
66
  export type UpstreamRequestFailure = Readonly<{
67
67
  kind: "akuma-not-born";
68
68
  id: AkuId;