@astrosheep/keiyaku 4.0.6 → 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 (251) 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 +12 -2
  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.d.ts +2 -0
  33. package/build/src/akuma/provider-recipe.js +21 -5
  34. package/build/src/akuma/provider.js +105 -62
  35. package/build/src/akuma/providers/acp/config.d.ts +2 -0
  36. package/build/src/akuma/providers/acp/config.js +13 -6
  37. package/build/src/akuma/providers/acp/core.d.ts +5 -2
  38. package/build/src/akuma/providers/acp/core.js +45 -25
  39. package/build/src/akuma/providers/acp/events.js +38 -29
  40. package/build/src/akuma/providers/acp/index.js +18 -8
  41. package/build/src/akuma/providers/claude/events.js +8 -12
  42. package/build/src/akuma/providers/claude/index.d.ts +2 -1
  43. package/build/src/akuma/providers/claude/index.js +59 -26
  44. package/build/src/akuma/providers/claude/input.js +6 -2
  45. package/build/src/akuma/providers/codex-app-server/events.js +61 -36
  46. package/build/src/akuma/providers/codex-app-server/index.js +29 -14
  47. package/build/src/akuma/providers/grok-build/index.js +28 -17
  48. package/build/src/akuma/providers/index.js +3 -19
  49. package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
  50. package/build/src/akuma/providers/opencode-sdk/index.js +29 -17
  51. package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
  52. package/build/src/akuma/providers/pi/events.js +26 -19
  53. package/build/src/akuma/providers/pi/index.js +58 -38
  54. package/build/src/akuma/publication.js +9 -9
  55. package/build/src/akuma/request-serve.js +37 -40
  56. package/build/src/akuma/request-wire.d.ts +2 -2
  57. package/build/src/akuma/request-wire.js +75 -102
  58. package/build/src/akuma/requests.js +2 -2
  59. package/build/src/akuma-body.js +6 -5
  60. package/build/src/body/amend.d.ts +4 -1
  61. package/build/src/body/amend.js +14 -15
  62. package/build/src/body/decode.js +2 -4
  63. package/build/src/body/envelope.js +2 -4
  64. package/build/src/body/region.d.ts +1 -2
  65. package/build/src/body/region.js +4 -72
  66. package/build/src/body/render.js +17 -12
  67. package/build/src/body/shape.js +1 -7
  68. package/build/src/cli/accepted.d.ts +1 -1
  69. package/build/src/cli/accepted.js +10 -1
  70. package/build/src/cli/commands/akuma-invoke.js +18 -6
  71. package/build/src/cli/commands/akuma.js +10 -13
  72. package/build/src/cli/commands/amend.d.ts +2 -2
  73. package/build/src/cli/commands/amend.js +2 -4
  74. package/build/src/cli/commands/bind.d.ts +4 -4
  75. package/build/src/cli/commands/bind.js +16 -6
  76. package/build/src/cli/commands/contract.d.ts +99 -10
  77. package/build/src/cli/commands/contract.js +128 -24
  78. package/build/src/cli/commands/install.d.ts +1 -1
  79. package/build/src/cli/commands/install.js +23 -15
  80. package/build/src/cli/commands/task-invoke.d.ts +4 -1
  81. package/build/src/cli/commands/task-invoke.js +191 -68
  82. package/build/src/cli/commands/task-query.js +48 -24
  83. package/build/src/cli/commands/task.js +150 -30
  84. package/build/src/cli/coordinates.js +2 -4
  85. package/build/src/cli/invoke.js +88 -44
  86. package/build/src/cli/main.js +4 -2
  87. package/build/src/cli/parse.d.ts +2 -89
  88. package/build/src/cli/parse.js +87 -79
  89. package/build/src/cli/render/akuma-tool-command.js +6 -7
  90. package/build/src/cli/render/akuma-tool.js +10 -8
  91. package/build/src/cli/render/akuma.js +149 -53
  92. package/build/src/cli/render/audit.js +5 -15
  93. package/build/src/cli/render/board.d.ts +1 -0
  94. package/build/src/cli/render/board.js +17 -0
  95. package/build/src/cli/render/catalog.js +84 -7
  96. package/build/src/cli/render/contract-observation.d.ts +10 -0
  97. package/build/src/cli/render/contract-observation.js +58 -0
  98. package/build/src/cli/render/contract.js +57 -54
  99. package/build/src/cli/render/kanshi.js +281 -209
  100. package/build/src/cli/render/receipt.d.ts +1 -0
  101. package/build/src/cli/render/receipt.js +20 -23
  102. package/build/src/cli/render/refusal.js +16 -15
  103. package/build/src/cli/render/region.js +22 -6
  104. package/build/src/cli/render/settings.js +4 -4
  105. package/build/src/cli/render/task.js +93 -21
  106. package/build/src/cli/render/terminal.js +16 -5
  107. package/build/src/cli/result.d.ts +11 -4
  108. package/build/src/cli/runtime.d.ts +6 -1
  109. package/build/src/cli/runtime.js +84 -63
  110. package/build/src/cli/selectors.js +2 -4
  111. package/build/src/cli/usage.js +6 -5
  112. package/build/src/contract-worktree.d.ts +1 -25
  113. package/build/src/contract-worktree.js +87 -174
  114. package/build/src/coordination/durable-file.js +7 -3
  115. package/build/src/coordination/sqlite-transaction-lock.js +29 -12
  116. package/build/src/core/facts/codec.js +7 -3
  117. package/build/src/core/facts/types.d.ts +1 -1
  118. package/build/src/core/subject.js +16 -9
  119. package/build/src/core/verbs/abandon.d.ts +1 -1
  120. package/build/src/core/verbs/abandon.js +1 -1
  121. package/build/src/core/verbs/amend.d.ts +1 -1
  122. package/build/src/core/verbs/amend.js +7 -7
  123. package/build/src/core/verbs/attestation.js +4 -1
  124. package/build/src/core/verbs/bind.d.ts +1 -1
  125. package/build/src/core/verbs/bind.js +1 -1
  126. package/build/src/core/verbs/placement.d.ts +1 -1
  127. package/build/src/core/verbs/placement.js +10 -8
  128. package/build/src/dispatch/index.js +8 -6
  129. package/build/src/duration.js +5 -1
  130. package/build/src/git/admission.js +5 -3
  131. package/build/src/git/hooks.d.ts +8 -0
  132. package/build/src/git/hooks.js +63 -14
  133. package/build/src/git/identity.js +1 -4
  134. package/build/src/git/integration.d.ts +2 -3
  135. package/build/src/git/integration.js +32 -39
  136. package/build/src/git/nuke.d.ts +1 -1
  137. package/build/src/git/nuke.js +110 -62
  138. package/build/src/git/observe.d.ts +13 -1
  139. package/build/src/git/observe.js +51 -44
  140. package/build/src/git/process.js +4 -2
  141. package/build/src/git/read-observation.js +10 -8
  142. package/build/src/git/reconcile.d.ts +14 -3
  143. package/build/src/git/reconcile.js +123 -102
  144. package/build/src/git/repository.d.ts +2 -0
  145. package/build/src/git/repository.js +13 -22
  146. package/build/src/git/target-placement.d.ts +9 -10
  147. package/build/src/git/target-placement.js +59 -62
  148. package/build/src/git/tender.d.ts +13 -2
  149. package/build/src/git/tender.js +28 -22
  150. package/build/src/git/terminal-seal.js +15 -12
  151. package/build/src/git/tree.js +5 -2
  152. package/build/src/git/workspace.d.ts +24 -2
  153. package/build/src/git/workspace.js +120 -16
  154. package/build/src/identity/coordinates.js +3 -1
  155. package/build/src/identity/selector.js +6 -3
  156. package/build/src/kanshi/fleet.d.ts +6 -0
  157. package/build/src/kanshi/fleet.js +27 -0
  158. package/build/src/kanshi/index.d.ts +1 -1
  159. package/build/src/kanshi/read.js +77 -45
  160. package/build/src/kanshi/report.d.ts +13 -24
  161. package/build/src/kanshi/select.js +25 -24
  162. package/build/src/library/address.d.ts +2 -1
  163. package/build/src/library/address.js +7 -8
  164. package/build/src/library/akuma-creation.js +20 -12
  165. package/build/src/library/audit.d.ts +0 -1
  166. package/build/src/library/audit.js +1 -2
  167. package/build/src/library/bind.d.ts +53 -5
  168. package/build/src/library/bind.js +98 -22
  169. package/build/src/library/catalog.d.ts +1 -0
  170. package/build/src/library/catalog.js +6 -3
  171. package/build/src/library/configuration.js +3 -1
  172. package/build/src/library/continuation.d.ts +37 -0
  173. package/build/src/library/continuation.js +86 -0
  174. package/build/src/library/contract.d.ts +39 -45
  175. package/build/src/library/contract.js +141 -118
  176. package/build/src/library/delivery.d.ts +18 -13
  177. package/build/src/library/fleet.d.ts +1 -1
  178. package/build/src/library/fleet.js +19 -11
  179. package/build/src/library/input.d.ts +2 -0
  180. package/build/src/library/input.js +14 -0
  181. package/build/src/library/keiyaku.d.ts +8 -7
  182. package/build/src/library/keiyaku.js +3 -3
  183. package/build/src/library/mutation.js +11 -4
  184. package/build/src/library/nuke.js +14 -5
  185. package/build/src/library/reconcile.d.ts +9 -4
  186. package/build/src/library/reconcile.js +30 -24
  187. package/build/src/library/refusal.d.ts +13 -5
  188. package/build/src/library/refusal.js +7 -0
  189. package/build/src/library/region.d.ts +8 -7
  190. package/build/src/library/region.js +31 -11
  191. package/build/src/library/repo.js +2 -2
  192. package/build/src/markdown/lex.js +9 -2
  193. package/build/src/markdown/parse.js +11 -7
  194. package/build/src/markdown/query.js +4 -2
  195. package/build/src/protocol/amend.js +3 -1
  196. package/build/src/protocol/attempt.d.ts +7 -3
  197. package/build/src/protocol/attempt.js +9 -5
  198. package/build/src/protocol/audit.d.ts +1 -1
  199. package/build/src/protocol/audit.js +4 -14
  200. package/build/src/protocol/bind.d.ts +19 -6
  201. package/build/src/protocol/bind.js +28 -13
  202. package/build/src/protocol/completion.d.ts +0 -1
  203. package/build/src/protocol/completion.js +1 -3
  204. package/build/src/protocol/deliver.d.ts +12 -4
  205. package/build/src/protocol/deliver.js +60 -51
  206. package/build/src/protocol/intent.d.ts +1 -0
  207. package/build/src/protocol/intent.js +9 -7
  208. package/build/src/protocol/operations.d.ts +10 -9
  209. package/build/src/protocol/operations.js +5 -3
  210. package/build/src/protocol/placement.d.ts +0 -1
  211. package/build/src/protocol/placement.js +6 -6
  212. package/build/src/protocol/read/observation.d.ts +11 -0
  213. package/build/src/protocol/read/observation.js +37 -0
  214. package/build/src/protocol/read/status.d.ts +23 -12
  215. package/build/src/protocol/read/status.js +90 -72
  216. package/build/src/protocol/reconcile.d.ts +1 -0
  217. package/build/src/protocol/reconcile.js +2 -3
  218. package/build/src/protocol/reintegrate.js +1 -1
  219. package/build/src/protocol/review.d.ts +0 -1
  220. package/build/src/protocol/review.js +15 -22
  221. package/build/src/protocol/run.d.ts +1 -0
  222. package/build/src/protocol/run.js +4 -5
  223. package/build/src/runtime/proc/launch.d.ts +33 -0
  224. package/build/src/runtime/proc/launch.js +98 -0
  225. package/build/src/runtime/proc/line-rpc.js +9 -3
  226. package/build/src/runtime/proc/run.d.ts +12 -6
  227. package/build/src/runtime/proc/run.js +78 -21
  228. package/build/src/runtime/proc/stdio.js +7 -10
  229. package/build/src/settings.js +6 -2
  230. package/build/src/settlement/fence.d.ts +0 -2
  231. package/build/src/settlement/fence.js +0 -24
  232. package/build/src/settlement/holder.js +13 -10
  233. package/build/src/settlement/settle.js +39 -6
  234. package/build/src/task/board.d.ts +21 -2
  235. package/build/src/task/board.js +35 -16
  236. package/build/src/task/compose.js +85 -22
  237. package/build/src/task/context.js +21 -8
  238. package/build/src/task/document.js +46 -10
  239. package/build/src/task/identity.js +19 -6
  240. package/build/src/task/index.js +118 -27
  241. package/build/src/task/input.js +29 -7
  242. package/build/src/task/mutation.js +61 -19
  243. package/build/src/task/operations.d.ts +8 -2
  244. package/build/src/task/operations.js +97 -32
  245. package/build/src/task/query.js +57 -28
  246. package/build/src/task/store.d.ts +5 -1
  247. package/build/src/task/store.js +88 -95
  248. package/build/src/verification/execution.js +14 -11
  249. package/build/src/workspace-place.js +19 -7
  250. package/build/src/world.js +16 -6
  251. package/package.json +8 -3
@@ -46,7 +46,8 @@ const RUNTIME_DROPPED_EVENT_KINDS = new Set([
46
46
  ]);
47
47
  function object(value) {
48
48
  return value !== null && typeof value === "object" && !Array.isArray(value)
49
- ? value : undefined;
49
+ ? value
50
+ : undefined;
50
51
  }
51
52
  function text(value) {
52
53
  return typeof value === "string" && value.length > 0 ? value : undefined;
@@ -83,8 +84,7 @@ function editCall(input, metadata) {
83
84
  }
84
85
  function writeCall(input, metadata) {
85
86
  const path = text(metadata?.filepath) ?? text(input?.filePath);
86
- const op = metadata?.exists === false ? "add"
87
- : metadata?.exists === true ? "update" : undefined;
87
+ const op = metadata?.exists === false ? "add" : metadata?.exists === true ? "update" : undefined;
88
88
  return path === undefined || op === undefined ? undefined : fileChange([change(op, path, undefined)]);
89
89
  }
90
90
  function applyPatchFile(value) {
@@ -92,10 +92,13 @@ function applyPatchFile(value) {
92
92
  if (file === undefined)
93
93
  return undefined;
94
94
  const type = file.type;
95
- const op = type === "add" ? "add"
96
- : type === "delete" ? "delete"
95
+ const op = type === "add"
96
+ ? "add"
97
+ : type === "delete"
98
+ ? "delete"
97
99
  : type === "update" || type === "modify" || type === "move"
98
- ? "update" : undefined;
100
+ ? "update"
101
+ : undefined;
99
102
  const path = type === "move" ? text(file.movePath) : text(file.filePath);
100
103
  return op === undefined || path === undefined ? undefined : change(op, path, diffstat(file));
101
104
  }
@@ -115,9 +118,7 @@ function strongerCall(previous, next) {
115
118
  return next;
116
119
  }
117
120
  function runCall(name, value) {
118
- return name === "bash" || name === "shell"
119
- ? { kind: "run", command: text(value?.command) ?? name }
120
- : undefined;
121
+ return name === "bash" || name === "shell" ? { kind: "run", command: text(value?.command) ?? name } : undefined;
121
122
  }
122
123
  function readCall(name, value) {
123
124
  if (name !== "read")
@@ -189,9 +190,16 @@ function resultFor(state, failed) {
189
190
  const exit = object(state.metadata)?.exit;
190
191
  const exitCode = typeof exit === "number" && Number.isInteger(exit) ? exit : undefined;
191
192
  if (failed) {
192
- return { status: "error", message: text(state.error) ?? "OpenCode tool failed", ...(exitCode === undefined ? {} : { exitCode }) };
193
+ return {
194
+ status: "error",
195
+ message: text(state.error) ?? "OpenCode tool failed",
196
+ ...(exitCode === undefined ? {} : { exitCode }),
197
+ };
193
198
  }
194
- return { status: exitCode !== undefined && exitCode !== 0 ? "error" : "ok", ...(exitCode === undefined ? {} : { exitCode }) };
199
+ return {
200
+ status: exitCode !== undefined && exitCode !== 0 ? "error" : "ok",
201
+ ...(exitCode === undefined ? {} : { exitCode }),
202
+ };
195
203
  }
196
204
  function mapToolPart(part, events, state) {
197
205
  if (!belongs(part, state))
@@ -202,8 +210,9 @@ function mapToolPart(part, events, state) {
202
210
  if (id === undefined || name === undefined || toolState === undefined)
203
211
  return;
204
212
  const next = callFor(name, toolState.input, toolState.metadata);
205
- if ((toolState.status === "pending" || toolState.status === "running")
206
- && !state.tools.has(id) && !state.completedTools.has(id)) {
213
+ if ((toolState.status === "pending" || toolState.status === "running") &&
214
+ !state.tools.has(id) &&
215
+ !state.completedTools.has(id)) {
207
216
  if (next === undefined)
208
217
  return;
209
218
  const observed = { name, call: next };
@@ -251,17 +260,19 @@ function mapSessionError(properties, events, state) {
251
260
  function mapTodo(properties, events, state) {
252
261
  if (properties.sessionID !== state.sessionId || !Array.isArray(properties.todos))
253
262
  return;
254
- const summary = properties.todos.flatMap((value) => {
263
+ const summary = properties.todos
264
+ .flatMap((value) => {
255
265
  const todo = object(value);
256
266
  const content = text(todo?.content);
257
267
  return content === undefined ? [] : [`${text(todo?.status) ?? "todo"}: ${content}`];
258
- }).join("; ");
268
+ })
269
+ .join("; ");
259
270
  if (summary.length > 0)
260
271
  events.emit(noteEvent(summary));
261
272
  }
262
273
  function ignoredEvent(type) {
263
- return typeof type === "string"
264
- && (OPENCODE_EVENT_DISPOSITIONS[type] === "dropped" || RUNTIME_DROPPED_EVENT_KINDS.has(type));
274
+ return (typeof type === "string" &&
275
+ (OPENCODE_EVENT_DISPOSITIONS[type] === "dropped" || RUNTIME_DROPPED_EVENT_KINDS.has(type)));
265
276
  }
266
277
  export function mapEvent(value, events, state) {
267
278
  const event = object(value);
@@ -276,7 +287,10 @@ export function mapEvent(value, events, state) {
276
287
  }
277
288
  if (event.type === "message.updated") {
278
289
  const info = object(properties.info);
279
- if (info !== undefined && info.sessionID === state.sessionId && info.role === "assistant" && info.error !== undefined) {
290
+ if (info !== undefined &&
291
+ info.sessionID === state.sessionId &&
292
+ info.role === "assistant" &&
293
+ info.error !== undefined) {
280
294
  state.failure = diagnostic(info.error);
281
295
  }
282
296
  return;
@@ -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;
@@ -24,6 +25,9 @@ function opencodeSessionId(coordinateValue) {
24
25
  function admit(options) {
25
26
  if (options.network !== undefined)
26
27
  throw new Error("OpenCode does not support explicit network");
28
+ if (options.systemPromptMode === "replace") {
29
+ throw new Error("OpenCode V1 does not support replacing the native system prompt");
30
+ }
27
31
  if (options.model !== undefined)
28
32
  parseModel(options.model);
29
33
  }
@@ -132,10 +136,7 @@ function nativeProgress(type, properties, busy) {
132
136
  function startsTurn(value, sessionId, messageID) {
133
137
  const event = object(value);
134
138
  const info = object(object(event?.properties)?.info);
135
- return event?.type === "message.updated"
136
- && info?.sessionID === sessionId
137
- && info.role === "user"
138
- && info.id === messageID;
139
+ return (event?.type === "message.updated" && info?.sessionID === sessionId && info.role === "user" && info.id === messageID);
139
140
  }
140
141
  async function observeTurn(input) {
141
142
  let active = false;
@@ -203,9 +204,7 @@ async function forceDisposeOpencode(abortController, close, finish) {
203
204
  async function drive(execution, input, loader) {
204
205
  admit(input.options);
205
206
  const signal = input.signal ?? new AbortController().signal;
206
- const resumeSessionId = input.session.kind === "resume"
207
- ? opencodeSessionId(input.session.coordinate)
208
- : undefined;
207
+ const resumeSessionId = input.session.kind === "resume" ? opencodeSessionId(input.session.coordinate) : undefined;
209
208
  const abortController = new AbortController();
210
209
  const abortSetup = () => abortController.abort(signal.reason);
211
210
  signal.addEventListener("abort", abortSetup, { once: true });
@@ -237,11 +236,20 @@ async function drive(execution, input, loader) {
237
236
  const messageID = `msg_${randomUUID().replaceAll("-", "")}`;
238
237
  const submissionState = { started: false };
239
238
  events.emit({ type: "session", coordinate: coordinate(sessionId) });
240
- 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
+ });
241
242
  iterator = streamResult.stream[Symbol.asyncIterator]();
242
243
  const { completion, finish } = terminalSettlement(events, closeOnce);
243
244
  const observation = observeTurn({
244
- 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,
245
253
  });
246
254
  submissionState.started = true;
247
255
  await abortable(session.promptAsync({
@@ -258,7 +266,9 @@ async function drive(execution, input, loader) {
258
266
  completion,
259
267
  abort: async () => {
260
268
  abortController.abort();
261
- 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);
262
272
  await finish({ kind: "failed", diagnostic: "OpenCode session interrupted" });
263
273
  },
264
274
  forceDispose: () => forceDisposeOpencode(abortController, closeOnce, finish),
@@ -285,12 +295,14 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
285
295
  return {
286
296
  kind: "admitted",
287
297
  options: Object.freeze({ ...options }),
288
- ...(options.readonly === undefined ? {} : {
289
- readonly: {
290
- enforcement: "none",
291
- diagnostic: "OpenCode V1 cannot remove task-surface mutation capabilities",
292
- },
293
- }),
298
+ ...(options.readonly === undefined
299
+ ? {}
300
+ : {
301
+ readonly: {
302
+ enforcement: "none",
303
+ diagnostic: "OpenCode V1 cannot remove task-surface mutation capabilities",
304
+ },
305
+ }),
294
306
  };
295
307
  },
296
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,25 +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
- systemPromptOverride: () => input.options.systemPrompt,
36
- });
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
+ });
37
43
  await resourceLoader?.reload();
38
44
  const sessionManager = input.session.kind === "fresh"
39
45
  ? sdk.SessionManager.create(input.cwd)
40
46
  : "sessionFile" in input.session.coordinate
41
47
  ? sdk.SessionManager.open(input.session.coordinate.sessionFile)
42
- : (() => { throw new Error("Pi resume requires sessionFile"); })();
48
+ : (() => {
49
+ throw new Error("Pi resume requires sessionFile");
50
+ })();
43
51
  const customTools = input.requests === undefined || input.options.readonly === true
44
52
  ? undefined
45
- : [(await import("@earendil-works/pi-coding-agent")).createBashToolDefinition(input.cwd, {
53
+ : [
54
+ (await import("@earendil-works/pi-coding-agent")).createBashToolDefinition(input.cwd, {
46
55
  spawnHook: (context) => ({
47
56
  ...context,
48
57
  env: { ...context.env, [AKUMA_REQUESTS_ENV]: input.requests.dir },
49
58
  }),
50
- })];
59
+ }),
60
+ ];
51
61
  return {
52
62
  cwd: input.cwd,
53
63
  sessionManager,
@@ -58,8 +68,13 @@ async function piCreateOptions(sdk, input) {
58
68
  ...(customTools === undefined ? {} : { customTools }),
59
69
  };
60
70
  }
61
- async function createPiSession(sdk, input, signal) {
62
- 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
+ });
63
78
  return await abortable(setup, signal, (created) => created.session.dispose());
64
79
  }
65
80
  function forceDisposePi(dispose, settle, setAborting) {
@@ -68,8 +83,8 @@ function forceDisposePi(dispose, settle, setAborting) {
68
83
  settle({ kind: "failed", diagnostic: "Pi session force-disposed" });
69
84
  return Promise.resolve();
70
85
  }
71
- async function drivePi(sdk, input, signal) {
72
- const created = await createPiSession(sdk, input, signal);
86
+ async function drivePi(sdk, execution, input, signal) {
87
+ const created = await createPiSession(sdk, execution, input, signal);
73
88
  const native = created.session;
74
89
  if (signal.aborted) {
75
90
  native.dispose();
@@ -110,7 +125,9 @@ async function drivePi(sdk, input, signal) {
110
125
  });
111
126
  events.emit({ type: "session", coordinate: { sessionFile: native.sessionFile, sessionId: native.sessionId } });
112
127
  let settleCompletion;
113
- const completion = new Promise((resolve) => { settleCompletion = resolve; });
128
+ const completion = new Promise((resolve) => {
129
+ settleCompletion = resolve;
130
+ });
114
131
  const settle = (result) => {
115
132
  if (settled)
116
133
  return;
@@ -121,24 +138,22 @@ async function drivePi(sdk, input, signal) {
121
138
  void (async () => {
122
139
  try {
123
140
  await native.prompt([input.body, ...input.launchTells.map((tell) => tell.text)].join("\n\n"));
124
- if (aborting) {
125
- settle({ kind: "failed", diagnostic: "Pi session aborted" });
126
- return;
127
- }
128
- if (terminalFailure !== null) {
129
- settle({ kind: "failed", diagnostic: terminalFailure });
130
- 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
+ };
131
155
  }
132
- if (!state.assistantSeen) {
133
- settle({ kind: "failed", diagnostic: "Pi completed without a native assistant answer" });
134
- return;
135
- }
136
- const historyId = native.sessionManager.getLeafId();
137
- settle({
138
- kind: "answered",
139
- answer: state.answer,
140
- ...(historyId === null ? {} : { historyId }),
141
- });
156
+ settle(result);
142
157
  }
143
158
  catch (error) {
144
159
  settle(aborting
@@ -147,7 +162,9 @@ async function drivePi(sdk, input, signal) {
147
162
  }
148
163
  })();
149
164
  return {
150
- admission: { fence: native.sessionId }, events, completion,
165
+ admission: { fence: native.sessionId },
166
+ events,
167
+ completion,
151
168
  abort: () => {
152
169
  abortRequest ??= (async () => {
153
170
  if (settled)
@@ -156,12 +173,16 @@ async function drivePi(sdk, input, signal) {
156
173
  try {
157
174
  await native.abort();
158
175
  }
159
- catch { /* prompt settlement still proves local cleanup */ }
176
+ catch {
177
+ /* prompt settlement still proves local cleanup */
178
+ }
160
179
  settle({ kind: "failed", diagnostic: "Pi session aborted" });
161
180
  })();
162
181
  return abortRequest;
163
182
  },
164
- forceDispose: () => forceDisposePi(dispose, settle, () => { aborting = true; }),
183
+ forceDispose: () => forceDisposePi(dispose, settle, () => {
184
+ aborting = true;
185
+ }),
165
186
  };
166
187
  }
167
188
  function piSessionFile(coordinate) {
@@ -188,16 +209,15 @@ async function loadPiSdk() {
188
209
  };
189
210
  }
190
211
  export function createPiProvider(execution = { name: "pi", kind: "pi" }, load = loadPiSdk) {
191
- if (execution.executable !== undefined || execution.config !== undefined) {
192
- throw new TypeError("Pi provider does not support executable or config");
193
- }
212
+ if (execution.executable !== undefined)
213
+ throw new TypeError("Pi provider does not support executable");
194
214
  if (execution.env !== undefined && Object.keys(execution.env).length > 0) {
195
215
  throw new TypeError("env injection not supported for provider pi");
196
216
  }
197
217
  const drive = async (input) => {
198
218
  const signal = input.signal ?? new AbortController().signal;
199
219
  signal.throwIfAborted();
200
- return drivePi(await abortable(load(), signal), input, signal);
220
+ return drivePi(await abortable(load(), signal), execution, input, signal);
201
221
  };
202
222
  return {
203
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();