@astrosheep/keiyaku 4.0.0 → 4.0.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 (308) hide show
  1. package/README.md +133 -8
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +13 -5
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -32
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +134 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +262 -46
  12. package/build/src/akuma/abort.d.ts +2 -0
  13. package/build/src/akuma/abort.js +50 -0
  14. package/build/src/akuma/akuma.d.ts +50 -33
  15. package/build/src/akuma/akuma.js +175 -127
  16. package/build/src/akuma/archetype.d.ts +14 -5
  17. package/build/src/akuma/archetype.js +85 -39
  18. package/build/src/akuma/body.d.ts +3 -5
  19. package/build/src/akuma/body.js +490 -183
  20. package/build/src/akuma/coordinate.d.ts +9 -0
  21. package/build/src/akuma/coordinate.js +22 -0
  22. package/build/src/akuma/heart/facts.d.ts +88 -45
  23. package/build/src/akuma/heart/facts.js +19 -8
  24. package/build/src/akuma/heart/index.d.ts +64 -55
  25. package/build/src/akuma/heart/index.js +172 -252
  26. package/build/src/akuma/heart/rows.d.ts +38 -83
  27. package/build/src/akuma/heart/rows.js +117 -155
  28. package/build/src/akuma/heart/schema.d.ts +1 -1
  29. package/build/src/akuma/heart/schema.js +61 -22
  30. package/build/src/akuma/heart/soul.d.ts +8 -0
  31. package/build/src/akuma/heart/soul.js +136 -0
  32. package/build/src/akuma/heart/storage.d.ts +47 -0
  33. package/build/src/akuma/heart/storage.js +224 -0
  34. package/build/src/akuma/heart/tells.d.ts +12 -0
  35. package/build/src/akuma/heart/tells.js +79 -0
  36. package/build/src/akuma/heart/timeline.d.ts +15 -0
  37. package/build/src/akuma/heart/timeline.js +86 -0
  38. package/build/src/akuma/identity.d.ts +2 -2
  39. package/build/src/akuma/identity.js +9 -9
  40. package/build/src/akuma/index.d.ts +10 -3
  41. package/build/src/akuma/index.js +7 -1
  42. package/build/src/akuma/projection.d.ts +176 -0
  43. package/build/src/akuma/projection.js +256 -0
  44. package/build/src/akuma/provider-recipe.d.ts +24 -0
  45. package/build/src/akuma/provider-recipe.js +100 -0
  46. package/build/src/akuma/provider.d.ts +67 -13
  47. package/build/src/akuma/provider.js +172 -105
  48. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  49. package/build/src/akuma/providers/acp/core.js +159 -0
  50. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  51. package/build/src/akuma/providers/acp/events.js +73 -0
  52. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  53. package/build/src/akuma/providers/acp/index.js +94 -0
  54. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  55. package/build/src/akuma/providers/claude/events.js +238 -0
  56. package/build/src/akuma/providers/claude/index.d.ts +47 -0
  57. package/build/src/akuma/providers/claude/index.js +279 -0
  58. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  59. package/build/src/akuma/providers/claude/input.js +109 -0
  60. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  61. package/build/src/akuma/providers/codex-app-server/events.js +15 -12
  62. package/build/src/akuma/providers/codex-app-server/index.d.ts +15 -13
  63. package/build/src/akuma/providers/codex-app-server/index.js +77 -33
  64. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  65. package/build/src/akuma/providers/grok-build/index.js +70 -0
  66. package/build/src/akuma/providers/index.d.ts +5 -3
  67. package/build/src/akuma/providers/index.js +35 -56
  68. package/build/src/akuma/providers/opencode-sdk/events.d.ts +54 -0
  69. package/build/src/akuma/providers/opencode-sdk/events.js +235 -0
  70. package/build/src/akuma/providers/opencode-sdk/index.d.ts +33 -0
  71. package/build/src/akuma/providers/opencode-sdk/index.js +308 -0
  72. package/build/src/akuma/providers/opencode-sdk/session.d.ts +26 -0
  73. package/build/src/akuma/providers/opencode-sdk/session.js +63 -0
  74. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  75. package/build/src/akuma/providers/pi/events.js +166 -0
  76. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  77. package/build/src/akuma/providers/pi/index.js +191 -0
  78. package/build/src/akuma/publication.d.ts +3 -3
  79. package/build/src/akuma/publication.js +28 -40
  80. package/build/src/akuma/requests.d.ts +9 -6
  81. package/build/src/akuma/requests.js +95 -65
  82. package/build/src/alias/index.d.ts +4 -3
  83. package/build/src/alias/index.js +12 -13
  84. package/build/src/body/decode.js +7 -1
  85. package/build/src/body/region.d.ts +2 -0
  86. package/build/src/body/region.js +77 -7
  87. package/build/src/body/render.js +2 -1
  88. package/build/src/body/shape.js +7 -1
  89. package/build/src/body/verification.js +19 -4
  90. package/build/src/cli/accepted.d.ts +18 -12
  91. package/build/src/cli/accepted.js +73 -34
  92. package/build/src/cli/actor.js +3 -3
  93. package/build/src/cli/commands/akuma-invoke.d.ts +44 -19
  94. package/build/src/cli/commands/akuma-invoke.js +101 -52
  95. package/build/src/cli/commands/akuma.d.ts +27 -9
  96. package/build/src/cli/commands/akuma.js +151 -80
  97. package/build/src/cli/commands/contract.d.ts +155 -0
  98. package/build/src/cli/commands/contract.js +20 -0
  99. package/build/src/cli/commands/install.js +2 -0
  100. package/build/src/cli/commands/task-invoke.d.ts +19 -4
  101. package/build/src/cli/commands/task-invoke.js +65 -17
  102. package/build/src/cli/commands/task-query.d.ts +5 -0
  103. package/build/src/cli/commands/task-query.js +247 -0
  104. package/build/src/cli/commands/task.d.ts +3 -1
  105. package/build/src/cli/commands/task.js +52 -14
  106. package/build/src/cli/coordinates.d.ts +18 -0
  107. package/build/src/cli/coordinates.js +120 -0
  108. package/build/src/cli/draft.d.ts +8 -0
  109. package/build/src/cli/draft.js +96 -0
  110. package/build/src/cli/invoke.d.ts +9 -3
  111. package/build/src/cli/invoke.js +287 -108
  112. package/build/src/cli/main.js +54 -7
  113. package/build/src/cli/parse.d.ts +21 -117
  114. package/build/src/cli/parse.js +79 -84
  115. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  116. package/build/src/cli/render/akuma-tool-command.js +144 -0
  117. package/build/src/cli/render/akuma-tool.d.ts +4 -2
  118. package/build/src/cli/render/akuma-tool.js +35 -5
  119. package/build/src/cli/render/akuma.d.ts +3 -1
  120. package/build/src/cli/render/akuma.js +247 -212
  121. package/build/src/cli/render/audit.d.ts +3 -0
  122. package/build/src/cli/render/audit.js +104 -0
  123. package/build/src/cli/render/catalog.d.ts +2 -0
  124. package/build/src/cli/render/catalog.js +16 -0
  125. package/build/src/cli/render/contract.d.ts +3 -3
  126. package/build/src/cli/render/contract.js +200 -54
  127. package/build/src/cli/render/kanshi.js +272 -129
  128. package/build/src/cli/render/receipt.d.ts +19 -0
  129. package/build/src/cli/render/receipt.js +106 -0
  130. package/build/src/cli/render/refusal.d.ts +16 -2
  131. package/build/src/cli/render/refusal.js +88 -3
  132. package/build/src/cli/render/region.d.ts +2 -0
  133. package/build/src/cli/render/region.js +17 -0
  134. package/build/src/cli/render/task.d.ts +2 -1
  135. package/build/src/cli/render/task.js +223 -60
  136. package/build/src/cli/render/terminal.d.ts +20 -0
  137. package/build/src/cli/render/terminal.js +121 -0
  138. package/build/src/cli/render/text.js +11 -3
  139. package/build/src/cli/result.d.ts +126 -19
  140. package/build/src/cli/usage.d.ts +1 -0
  141. package/build/src/cli/usage.js +3 -0
  142. package/build/src/contract-worktree.d.ts +44 -0
  143. package/build/src/contract-worktree.js +251 -0
  144. package/build/src/coordination/durable-file.d.ts +5 -1
  145. package/build/src/coordination/durable-file.js +57 -10
  146. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  147. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  148. package/build/src/core/facts/codec.js +23 -4
  149. package/build/src/core/facts/eligibility.d.ts +1 -10
  150. package/build/src/core/facts/eligibility.js +0 -49
  151. package/build/src/core/facts/fold.js +1 -6
  152. package/build/src/core/facts/gate.d.ts +1 -0
  153. package/build/src/core/facts/gate.js +1 -0
  154. package/build/src/core/facts/observation.d.ts +3 -0
  155. package/build/src/core/facts/observation.js +12 -0
  156. package/build/src/core/facts/types.d.ts +10 -3
  157. package/build/src/core/subject.js +2 -2
  158. package/build/src/core/verbs/amend.d.ts +1 -1
  159. package/build/src/core/verbs/amend.js +3 -18
  160. package/build/src/core/verbs/bind.js +2 -16
  161. package/build/src/core/verbs/deliver.d.ts +1 -1
  162. package/build/src/core/verbs/deliver.js +14 -4
  163. package/build/src/core/verbs/placement.d.ts +1 -1
  164. package/build/src/core/verbs/placement.js +7 -9
  165. package/build/src/dispatch/index.d.ts +5 -3
  166. package/build/src/dispatch/index.js +30 -21
  167. package/build/src/duration.d.ts +10 -0
  168. package/build/src/duration.js +22 -0
  169. package/build/src/git/admission.d.ts +2 -2
  170. package/build/src/git/admission.js +33 -23
  171. package/build/src/git/hooks.d.ts +15 -0
  172. package/build/src/git/hooks.js +70 -18
  173. package/build/src/git/identity.d.ts +5 -1
  174. package/build/src/git/identity.js +23 -4
  175. package/build/src/git/integration.d.ts +48 -0
  176. package/build/src/git/integration.js +250 -0
  177. package/build/src/git/observe.d.ts +29 -15
  178. package/build/src/git/observe.js +185 -76
  179. package/build/src/git/read-observation.d.ts +41 -0
  180. package/build/src/git/read-observation.js +361 -0
  181. package/build/src/git/reconcile.d.ts +17 -5
  182. package/build/src/git/reconcile.js +305 -109
  183. package/build/src/git/repository.d.ts +41 -18
  184. package/build/src/git/repository.js +220 -114
  185. package/build/src/git/scratch.d.ts +17 -0
  186. package/build/src/git/scratch.js +73 -0
  187. package/build/src/git/target-placement.d.ts +92 -0
  188. package/build/src/git/target-placement.js +375 -0
  189. package/build/src/git/tender.d.ts +49 -0
  190. package/build/src/git/tender.js +63 -0
  191. package/build/src/git/terminal-seal.d.ts +24 -0
  192. package/build/src/git/terminal-seal.js +89 -0
  193. package/build/src/git/tree.d.ts +2 -2
  194. package/build/src/git/tree.js +4 -0
  195. package/build/src/git/workspace.d.ts +53 -0
  196. package/build/src/git/workspace.js +139 -0
  197. package/build/src/identity/selector.d.ts +6 -0
  198. package/build/src/identity/selector.js +19 -0
  199. package/build/src/index.d.ts +4 -2
  200. package/build/src/index.js +2 -1
  201. package/build/src/kanshi/index.d.ts +2 -2
  202. package/build/src/kanshi/index.js +1 -1
  203. package/build/src/kanshi/read.d.ts +7 -3
  204. package/build/src/kanshi/read.js +245 -45
  205. package/build/src/kanshi/report.d.ts +81 -6
  206. package/build/src/kanshi/select.d.ts +5 -0
  207. package/build/src/kanshi/select.js +33 -1
  208. package/build/src/library/address.d.ts +57 -0
  209. package/build/src/library/address.js +165 -0
  210. package/build/src/library/akuma-creation.d.ts +16 -7
  211. package/build/src/library/akuma-creation.js +96 -22
  212. package/build/src/library/audit.d.ts +18 -0
  213. package/build/src/library/audit.js +44 -0
  214. package/build/src/library/bind.d.ts +21 -0
  215. package/build/src/library/bind.js +56 -0
  216. package/build/src/library/catalog.d.ts +58 -0
  217. package/build/src/library/catalog.js +69 -0
  218. package/build/src/library/configuration.d.ts +6 -15
  219. package/build/src/library/configuration.js +14 -17
  220. package/build/src/library/contract.d.ts +23 -49
  221. package/build/src/library/contract.js +171 -185
  222. package/build/src/library/delivery.d.ts +24 -0
  223. package/build/src/library/delivery.js +21 -0
  224. package/build/src/library/fleet.d.ts +65 -0
  225. package/build/src/library/fleet.js +153 -0
  226. package/build/src/library/input.d.ts +3 -0
  227. package/build/src/library/input.js +19 -0
  228. package/build/src/library/keiyaku.d.ts +18 -3
  229. package/build/src/library/keiyaku.js +12 -1
  230. package/build/src/library/mutation.d.ts +39 -0
  231. package/build/src/library/mutation.js +37 -0
  232. package/build/src/library/reconcile.d.ts +29 -0
  233. package/build/src/library/reconcile.js +179 -0
  234. package/build/src/library/refusal.d.ts +21 -0
  235. package/build/src/library/refusal.js +29 -0
  236. package/build/src/library/region.d.ts +14 -1
  237. package/build/src/library/region.js +18 -4
  238. package/build/src/library/repo.d.ts +4 -13
  239. package/build/src/library/repo.js +14 -24
  240. package/build/src/protocol/attempt.d.ts +16 -3
  241. package/build/src/protocol/attempt.js +41 -10
  242. package/build/src/protocol/bind.d.ts +9 -2
  243. package/build/src/protocol/bind.js +48 -40
  244. package/build/src/protocol/intent.d.ts +57 -20
  245. package/build/src/protocol/intent.js +55 -79
  246. package/build/src/protocol/operations.d.ts +152 -43
  247. package/build/src/protocol/operations.js +482 -166
  248. package/build/src/protocol/outcome.d.ts +14 -3
  249. package/build/src/protocol/outcome.js +11 -3
  250. package/build/src/protocol/placement.d.ts +41 -0
  251. package/build/src/protocol/placement.js +147 -0
  252. package/build/src/protocol/read/documents.d.ts +2 -2
  253. package/build/src/protocol/read/documents.js +4 -4
  254. package/build/src/protocol/read/status.d.ts +18 -5
  255. package/build/src/protocol/read/status.js +73 -13
  256. package/build/src/protocol/run.d.ts +49 -7
  257. package/build/src/protocol/run.js +53 -25
  258. package/build/src/runtime/proc/line-rpc.d.ts +4 -8
  259. package/build/src/runtime/proc/line-rpc.js +22 -28
  260. package/build/src/runtime/proc/run.d.ts +23 -21
  261. package/build/src/runtime/proc/run.js +123 -89
  262. package/build/src/runtime/proc/stdio.d.ts +18 -0
  263. package/build/src/runtime/proc/stdio.js +58 -0
  264. package/build/src/settings.d.ts +7 -1
  265. package/build/src/settings.js +32 -17
  266. package/build/src/settlement/fence.d.ts +5 -0
  267. package/build/src/settlement/fence.js +14 -0
  268. package/build/src/settlement/holder.d.ts +35 -4
  269. package/build/src/settlement/holder.js +127 -28
  270. package/build/src/settlement/settle.d.ts +9 -1
  271. package/build/src/settlement/settle.js +74 -37
  272. package/build/src/task/board.d.ts +23 -5
  273. package/build/src/task/board.js +17 -10
  274. package/build/src/task/compose.d.ts +2 -2
  275. package/build/src/task/compose.js +18 -10
  276. package/build/src/task/context.d.ts +3 -3
  277. package/build/src/task/context.js +15 -20
  278. package/build/src/task/document.d.ts +2 -1
  279. package/build/src/task/document.js +15 -5
  280. package/build/src/task/index.d.ts +27 -15
  281. package/build/src/task/index.js +57 -35
  282. package/build/src/task/operations.d.ts +38 -13
  283. package/build/src/task/operations.js +80 -46
  284. package/build/src/task/query.d.ts +67 -0
  285. package/build/src/task/query.js +279 -0
  286. package/build/src/task/store.d.ts +5 -7
  287. package/build/src/task/store.js +43 -28
  288. package/build/src/verification/declaration.d.ts +1 -0
  289. package/build/src/verification/execution.d.ts +51 -0
  290. package/build/src/verification/execution.js +108 -0
  291. package/build/src/workspace-place.d.ts +41 -0
  292. package/build/src/workspace-place.js +386 -0
  293. package/build/src/world.d.ts +24 -0
  294. package/build/src/world.js +136 -0
  295. package/package.json +8 -4
  296. package/build/src/akuma/activity.d.ts +0 -66
  297. package/build/src/akuma/activity.js +0 -139
  298. package/build/src/akuma/providers/claude.js +0 -305
  299. package/build/src/context-root.d.ts +0 -4
  300. package/build/src/context-root.js +0 -15
  301. package/build/src/git/delivery.d.ts +0 -20
  302. package/build/src/git/delivery.js +0 -109
  303. package/build/src/git/verification.d.ts +0 -14
  304. package/build/src/git/verification.js +0 -56
  305. package/build/src/protocol/read/audit.d.ts +0 -25
  306. package/build/src/protocol/read/audit.js +0 -39
  307. package/build/src/verification/producer.d.ts +0 -23
  308. package/build/src/verification/producer.js +0 -54
@@ -28,7 +28,29 @@ function turnId(result) {
28
28
  throw new Error("codex app-server did not return a turn id");
29
29
  return id;
30
30
  }
31
+ async function steerTurn(server, state, tell) {
32
+ if (state.settled)
33
+ return { kind: "turn-ended" };
34
+ if (state.threadId === undefined || state.turnId === undefined)
35
+ throw new Error("codex app-server turn is not admitted");
36
+ const request = server.request("turn/steer", {
37
+ threadId: state.threadId,
38
+ expectedTurnId: state.turnId,
39
+ input: [{ type: "text", text: tell.text }],
40
+ clientUserMessageId: tell.id,
41
+ });
42
+ const response = codexObject(await request);
43
+ const accepted = codexText(response?.turnId);
44
+ if (accepted === undefined)
45
+ throw new Error("codex app-server steer did not return a turn id");
46
+ if (accepted !== state.turnId)
47
+ throw new Error("codex app-server steer acknowledged a different turn");
48
+ return { kind: "accepted", fence: `${accepted}:${tell.id}` };
49
+ }
31
50
  function sandbox(cwd, options, requests) {
51
+ if (options.readonly === true) {
52
+ return { type: "readOnly", networkAccess: options.network === "enabled" };
53
+ }
32
54
  return {
33
55
  type: "workspaceWrite",
34
56
  writableRoots: [cwd, ...(requests === undefined ? [] : [requests.dir])],
@@ -46,16 +68,20 @@ async function admitTurn(server, input, state, events, config) {
46
68
  ...(input.options.systemPrompt === undefined || input.options.systemPrompt.length === 0
47
69
  ? {} : { developerInstructions: input.options.systemPrompt }),
48
70
  };
49
- state.threadId = input.session === undefined
50
- ? threadId(await server.request("thread/start", threadParams))
51
- : threadId(await server.request("thread/resume", {
52
- threadId: input.session.sessionId,
71
+ if (input.session.kind === "fresh") {
72
+ state.threadId = threadId(await server.request("thread/start", threadParams));
73
+ }
74
+ else {
75
+ state.threadId = threadId(await server.request("thread/resume", {
76
+ threadId: input.session.coordinate.sessionId,
53
77
  ...threadParams,
54
- }), input.session.sessionId);
78
+ }), input.session.coordinate.sessionId);
79
+ }
55
80
  events.emit({ type: "session", coordinate: { sessionId: state.threadId } });
56
81
  state.turnId = turnId(await server.request("turn/start", {
57
82
  threadId: state.threadId,
58
- input: [{ type: "text", text: input.prompt }],
83
+ input: [{ type: "text", text: [input.body, ...input.launchTells.map((tell) => tell.text)]
84
+ .filter((part) => part.length > 0).join("\n\n") }],
59
85
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
60
86
  ...(input.options.effort === undefined ? {} : { effort: input.options.effort }),
61
87
  approvalPolicy: "never",
@@ -63,6 +89,8 @@ async function admitTurn(server, input, state, events, config) {
63
89
  }));
64
90
  }
65
91
  async function forkCodex(execution, input) {
92
+ if (!("sessionId" in input.session))
93
+ throw new Error("Codex app-server fork requires sessionId");
66
94
  const server = new LineRpcProcess({
67
95
  argv: [execution.executable ?? "codex", "app-server", "--listen", "stdio://"],
68
96
  cwd: input.cwd,
@@ -82,22 +110,15 @@ async function forkCodex(execution, input) {
82
110
  await server.close();
83
111
  }
84
112
  }
85
- async function abortTurn(server, state, completion, finish) {
86
- if (!state.settled && state.threadId !== undefined && state.turnId !== undefined) {
87
- try {
88
- await server.request("turn/interrupt", { threadId: state.threadId, turnId: state.turnId });
89
- await completion;
90
- }
91
- catch (error) {
92
- finish({ kind: "failed", diagnostic: diagnostic(error) });
93
- }
94
- }
95
- else if (!state.settled) {
96
- finish({ kind: "failed", diagnostic: "codex app-server aborted before turn admission" });
97
- }
113
+ async function abortTurn(server, state, settle) {
114
+ if (!state.settled)
115
+ settle({ kind: "failed", diagnostic: "codex app-server interrupted" });
98
116
  await server.close(true);
99
117
  }
100
118
  async function startCodex(execution, input) {
119
+ const signal = input.signal ?? new AbortController().signal;
120
+ if (input.session.kind === "resume" && !("sessionId" in input.session.coordinate))
121
+ throw new Error("Codex app-server resume requires sessionId");
101
122
  const events = new AgentEventChannel();
102
123
  const server = new LineRpcProcess({
103
124
  argv: [execution.executable ?? "codex", "app-server", "--listen", "stdio://"],
@@ -108,16 +129,28 @@ async function startCodex(execution, input) {
108
129
  ...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
109
130
  } }),
110
131
  });
111
- const state = { answers: [], settled: false, tools: new Map() };
132
+ const state = { settled: false, tools: new Map() };
112
133
  let settle;
113
134
  const completion = new Promise((resolve) => { settle = resolve; });
135
+ let terminal;
114
136
  const finish = (result) => {
115
- if (state.settled)
137
+ if (terminal !== undefined)
116
138
  return;
139
+ terminal = result;
117
140
  state.settled = true;
118
- events.end();
119
- void server.close().then(() => settle(result), (error) => settle({ kind: "failed", diagnostic: `codex app-server cleanup failed: ${diagnostic(error)}` }));
141
+ void server.endInputAndDrain().then(() => {
142
+ events.end();
143
+ settle(result);
144
+ }, () => {
145
+ events.end();
146
+ settle(result);
147
+ });
120
148
  };
149
+ server.onNotification((notification) => {
150
+ const result = codexNotificationResult(notification, state, events);
151
+ if (result !== undefined)
152
+ finish(result);
153
+ });
121
154
  server.onExit(({ code, signal, stderr }) => finish({
122
155
  kind: "failed",
123
156
  diagnostic: stderr || `codex app-server exited before completion (${code ?? signal ?? "unknown"})`,
@@ -126,21 +159,30 @@ async function startCodex(execution, input) {
126
159
  kind: "failed",
127
160
  diagnostic: `codex app-server made forbidden interactive request ${request.method}`,
128
161
  }));
129
- server.onNotification((notification) => {
130
- const result = codexNotificationResult(notification, state, events);
131
- if (result !== undefined)
132
- finish(result);
133
- });
162
+ const abortSetup = () => { void server.close(true); };
163
+ signal.addEventListener("abort", abortSetup, { once: true });
134
164
  try {
165
+ signal.throwIfAborted();
135
166
  await admitTurn(server, input, state, events, execution.config);
136
167
  }
137
168
  catch (error) {
169
+ if (signal.aborted) {
170
+ await server.close(true);
171
+ throw signal.reason;
172
+ }
138
173
  finish({ kind: "failed", diagnostic: diagnostic(error) });
139
174
  }
175
+ finally {
176
+ signal.removeEventListener("abort", abortSetup);
177
+ }
178
+ if (state.turnId === undefined)
179
+ throw new Error("codex app-server did not admit a turn");
140
180
  return {
181
+ admission: { fence: state.turnId },
141
182
  events,
142
183
  completion,
143
- abort: () => abortTurn(server, state, completion, finish),
184
+ abort: () => abortTurn(server, state, finish),
185
+ tell: (tell) => steerTurn(server, state, tell),
144
186
  };
145
187
  }
146
188
  export function createCodexAppServerProvider(input = "codex") {
@@ -150,13 +192,15 @@ export function createCodexAppServerProvider(input = "codex") {
150
192
  return {
151
193
  confinement: ({ cwd }) => ({ kind: "declared", writableRoots: [cwd] }),
152
194
  admitOptions(options) {
153
- if (options.access !== undefined && options.access !== "write") {
154
- return { kind: "refused", diagnostic: "Codex app-server supports only access: write" };
155
- }
156
- return { kind: "admitted", options: Object.freeze({ ...options }) };
195
+ return {
196
+ kind: "admitted",
197
+ options: Object.freeze({ ...options }),
198
+ ...(options.readonly === undefined ? {} : { readonly: { enforcement: "native" } }),
199
+ };
157
200
  },
158
201
  fork: (input) => forkCodex(execution, input),
159
202
  start: (input) => startCodex(execution, input),
203
+ resume: (input) => startCodex(execution, input),
160
204
  };
161
205
  }
162
206
  export const codexAppServerProvider = createCodexAppServerProvider();
@@ -0,0 +1,4 @@
1
+ import type { ProviderAdapter } from "../../provider.js";
2
+ import type { ProviderExecution } from "../../provider-recipe.js";
3
+ import { type AcpDependencies } from "../acp/core.js";
4
+ export declare function createGrokBuildProvider(execution: ProviderExecution, dependencies?: AcpDependencies): ProviderAdapter;
@@ -0,0 +1,70 @@
1
+ import { startAcpSession } from "../acp/core.js";
2
+ const INTERJECT_METHOD = "x.ai/interject";
3
+ function optionAdmission(options) {
4
+ if (options.network !== undefined) {
5
+ return { kind: "refused", diagnostic: "Grok Build does not support the network option" };
6
+ }
7
+ if (options.systemPrompt !== undefined && options.systemPrompt.length > 0) {
8
+ return { kind: "refused", diagnostic: "Grok Build does not support the systemPrompt option" };
9
+ }
10
+ return {
11
+ kind: "admitted",
12
+ options,
13
+ ...(options.readonly === undefined ? {} : {
14
+ readonly: {
15
+ enforcement: "none",
16
+ diagnostic: "Grok Build cannot remove task-surface mutation capabilities",
17
+ },
18
+ }),
19
+ };
20
+ }
21
+ function argv(execution, options) {
22
+ if (execution.executable === undefined)
23
+ throw new Error("Grok Build provider execution requires executable");
24
+ const values = [execution.executable, "agent", "--always-approve"];
25
+ if (options.model !== undefined)
26
+ values.push("--model", options.model);
27
+ if (options.effort !== undefined)
28
+ values.push("--reasoning-effort", options.effort);
29
+ values.push("stdio");
30
+ return values;
31
+ }
32
+ function withInterject(live) {
33
+ return {
34
+ ...live.session,
35
+ tell: async (tell) => {
36
+ if (!live.open())
37
+ return { kind: "turn-ended" };
38
+ const response = await live.agent.request(INTERJECT_METHOD, {
39
+ sessionId: live.sessionId,
40
+ text: tell.text,
41
+ interjectionId: tell.id,
42
+ });
43
+ if (!live.open())
44
+ return { kind: "turn-ended" };
45
+ if (response === null || typeof response !== "object" || response.status !== "queued") {
46
+ throw new Error("Grok Build interject did not return queued");
47
+ }
48
+ return { kind: "accepted", fence: tell.id };
49
+ },
50
+ };
51
+ }
52
+ export function createGrokBuildProvider(execution, dependencies = {}) {
53
+ if (execution.executable === undefined)
54
+ throw new TypeError("Grok Build provider execution requires executable");
55
+ if (execution.config !== undefined)
56
+ throw new TypeError("Grok Build provider does not support execution config");
57
+ const drive = async (input) => {
58
+ const launch = {
59
+ argv: argv(execution, input.options),
60
+ ...(execution.env === undefined ? {} : { env: execution.env }),
61
+ };
62
+ return withInterject(await startAcpSession(launch, input, dependencies));
63
+ };
64
+ return {
65
+ confinement: () => ({ kind: "unconfined" }),
66
+ admitOptions: optionAdmission,
67
+ start: async (input) => await drive(input),
68
+ resume: async (input) => await drive(input),
69
+ };
70
+ }
@@ -1,4 +1,6 @@
1
1
  import type { ProviderAdapter } from "../provider.js";
2
- import type { ProviderExecution } from "../heart/index.js";
3
- export declare function decodeProviderExecution(input: unknown): ProviderExecution;
4
- export declare function providerNamed(execution: ProviderExecution): ProviderAdapter;
2
+ import { type ProviderExecution } from "../provider-recipe.js";
3
+ export declare function resolveProviderExecution(input: unknown): Readonly<{
4
+ execution: ProviderExecution;
5
+ adapter: ProviderAdapter;
6
+ }>;
@@ -1,65 +1,26 @@
1
- import { claudeProvider, createClaudeProvider } from "./claude.js";
1
+ import { decodeProviderRecipe } from "../provider-recipe.js";
2
+ import { createAcpProvider, decodeAcpConfig } from "./acp/index.js";
3
+ import { claudeProvider, createClaudeProvider } from "./claude/index.js";
2
4
  import { createCodexAppServerProvider } from "./codex-app-server/index.js";
5
+ import { createGrokBuildProvider } from "./grok-build/index.js";
6
+ import { createOpencodeProvider } from "./opencode-sdk/index.js";
7
+ import { createPiProvider } from "./pi/index.js";
3
8
  const PROVIDERS = {
4
9
  claude: claudeProvider,
5
10
  };
6
- function record(value) {
7
- return value !== null && typeof value === "object" && !Array.isArray(value)
8
- ? value : null;
9
- }
10
- function snapshot(value) {
11
- if (Array.isArray(value))
12
- return Object.freeze(value.map(snapshot));
13
- const object = record(value);
14
- if (object === null)
15
- return value;
16
- return Object.freeze(Object.fromEntries(Object.entries(object).map(([key, item]) => [key, snapshot(item)])));
17
- }
18
- function optionalText(value, field) {
19
- const selected = value[field];
20
- if (selected === undefined)
21
- return undefined;
22
- if (typeof selected !== "string" || selected.trim().length === 0) {
23
- throw new TypeError(`provider execution ${field} must be a nonblank string`);
24
- }
25
- return selected;
26
- }
27
- export function decodeProviderExecution(input) {
28
- const value = record(input);
29
- if (value === null)
30
- throw new TypeError("provider execution must be an object");
31
- const allowed = ["config", "env", "executable", "kind", "name"];
32
- const unknown = Object.keys(value).find((key) => !allowed.includes(key));
33
- if (unknown !== undefined)
34
- throw new TypeError(`provider execution has unknown field ${unknown}`);
35
- if (typeof value.name !== "string" || value.name.trim().length === 0) {
36
- throw new TypeError("provider execution name must be a nonblank string");
37
- }
38
- if (value.kind !== "claude-agent-sdk" && value.kind !== "codex-app-server") {
39
- throw new TypeError("provider execution has unknown kind");
40
- }
41
- const executable = optionalText(value, "executable");
42
- const config = value.config === undefined ? undefined : record(value.config);
43
- if (config === null)
44
- throw new TypeError("provider execution config must be an object");
45
- if (value.kind === "claude-agent-sdk" && config !== undefined) {
11
+ function providerConfig(execution) {
12
+ const { config, kind } = execution;
13
+ if (kind === "claude-agent-sdk" && config !== undefined)
46
14
  throw new TypeError("provider execution config is unsupported by claude-agent-sdk");
47
- }
48
- const env = value.env === undefined ? undefined : record(value.env);
49
- if (env === null)
50
- throw new TypeError("provider execution env must be an object");
51
- if (env !== undefined && Object.values(env).some((item) => typeof item !== "string")) {
52
- throw new TypeError("provider execution env must contain only string values");
53
- }
54
- return Object.freeze({
55
- name: value.name,
56
- kind: value.kind,
57
- ...(executable === undefined ? {} : { executable }),
58
- ...(config === undefined ? {} : { config: snapshot(config) }),
59
- ...(env === undefined ? {} : { env: Object.freeze({ ...env }) }),
60
- });
15
+ if (kind === "opencode-sdk" && config !== undefined)
16
+ throw new TypeError("provider execution config is unsupported by opencode-sdk");
17
+ if (kind === "acp")
18
+ return decodeAcpConfig(config);
19
+ return config;
61
20
  }
62
- export function providerNamed(execution) {
21
+ function adapterFor(execution) {
22
+ if (execution.kind === "acp")
23
+ return createAcpProvider(execution);
63
24
  if (execution.kind === "claude-agent-sdk") {
64
25
  return execution.executable === undefined && execution.env === undefined
65
26
  ? PROVIDERS.claude
@@ -67,5 +28,23 @@ export function providerNamed(execution) {
67
28
  }
68
29
  if (execution.kind === "codex-app-server")
69
30
  return createCodexAppServerProvider(execution);
31
+ if (execution.kind === "grok-build")
32
+ return createGrokBuildProvider(execution);
33
+ if (execution.kind === "opencode-sdk")
34
+ return createOpencodeProvider(execution);
35
+ if (execution.kind === "pi")
36
+ return createPiProvider(execution);
70
37
  throw new TypeError(`unknown Akuma provider kind ${execution.kind}`);
71
38
  }
39
+ export function resolveProviderExecution(input) {
40
+ const decoded = decodeProviderRecipe(input);
41
+ const config = providerConfig(decoded);
42
+ const execution = Object.freeze({
43
+ name: decoded.name,
44
+ kind: decoded.kind,
45
+ ...(decoded.executable === undefined ? {} : { executable: decoded.executable }),
46
+ ...(config === undefined ? {} : { config }),
47
+ ...(decoded.env === undefined ? {} : { env: decoded.env }),
48
+ });
49
+ return Object.freeze({ execution, adapter: adapterFor(execution) });
50
+ }
@@ -0,0 +1,54 @@
1
+ import { type AgentEvent, type ToolCall } from "../../provider.js";
2
+ type Emitter = {
3
+ emit(event: AgentEvent): void;
4
+ };
5
+ type ObservedTool = Readonly<{
6
+ name: string;
7
+ call: ToolCall;
8
+ }>;
9
+ type State = {
10
+ sessionId?: string;
11
+ assistantParts: Set<string>;
12
+ reasoningParts: Set<string>;
13
+ tools: Map<string, ObservedTool>;
14
+ completedTools: Set<string>;
15
+ failure?: string;
16
+ };
17
+ export declare const OPENCODE_EVENT_DISPOSITIONS: {
18
+ readonly "server.instance.disposed": "dropped";
19
+ readonly "installation.updated": "dropped";
20
+ readonly "installation.update-available": "dropped";
21
+ readonly "lsp.client.diagnostics": "dropped";
22
+ readonly "lsp.updated": "dropped";
23
+ readonly "message.updated": "mapped";
24
+ readonly "message.removed": "dropped";
25
+ readonly "message.part.updated": "mapped";
26
+ readonly "message.part.removed": "dropped";
27
+ readonly "permission.updated": "dropped";
28
+ readonly "permission.replied": "dropped";
29
+ readonly "session.status": "dropped";
30
+ readonly "session.idle": "dropped";
31
+ readonly "session.compacted": "dropped";
32
+ readonly "file.edited": "dropped";
33
+ readonly "todo.updated": "mapped";
34
+ readonly "command.executed": "dropped";
35
+ readonly "session.created": "dropped";
36
+ readonly "session.updated": "dropped";
37
+ readonly "session.deleted": "dropped";
38
+ readonly "session.diff": "dropped";
39
+ readonly "session.error": "mapped";
40
+ readonly "file.watcher.updated": "dropped";
41
+ readonly "vcs.branch.updated": "dropped";
42
+ readonly "tui.prompt.append": "dropped";
43
+ readonly "tui.command.execute": "dropped";
44
+ readonly "tui.toast.show": "dropped";
45
+ readonly "pty.created": "dropped";
46
+ readonly "pty.updated": "dropped";
47
+ readonly "pty.exited": "dropped";
48
+ readonly "pty.deleted": "dropped";
49
+ readonly "server.connected": "dropped";
50
+ };
51
+ export declare function mapEvent(value: unknown, events: Emitter, state: State): void;
52
+ export type EventState = State;
53
+ export declare function createEventState(sessionId?: string): State;
54
+ export {};
@@ -0,0 +1,235 @@
1
+ import { noteEvent } from "../../provider.js";
2
+ export const OPENCODE_EVENT_DISPOSITIONS = {
3
+ "server.instance.disposed": "dropped",
4
+ "installation.updated": "dropped",
5
+ "installation.update-available": "dropped",
6
+ "lsp.client.diagnostics": "dropped",
7
+ "lsp.updated": "dropped",
8
+ "message.updated": "mapped",
9
+ "message.removed": "dropped",
10
+ "message.part.updated": "mapped",
11
+ "message.part.removed": "dropped",
12
+ "permission.updated": "dropped",
13
+ "permission.replied": "dropped",
14
+ "session.status": "dropped",
15
+ "session.idle": "dropped",
16
+ "session.compacted": "dropped",
17
+ "file.edited": "dropped",
18
+ "todo.updated": "mapped",
19
+ "command.executed": "dropped",
20
+ "session.created": "dropped",
21
+ "session.updated": "dropped",
22
+ "session.deleted": "dropped",
23
+ "session.diff": "dropped",
24
+ "session.error": "mapped",
25
+ "file.watcher.updated": "dropped",
26
+ "vcs.branch.updated": "dropped",
27
+ "tui.prompt.append": "dropped",
28
+ "tui.command.execute": "dropped",
29
+ "tui.toast.show": "dropped",
30
+ "pty.created": "dropped",
31
+ "pty.updated": "dropped",
32
+ "pty.exited": "dropped",
33
+ "pty.deleted": "dropped",
34
+ "server.connected": "dropped",
35
+ };
36
+ // OpenCode may emit these server-side metadata events before the generated
37
+ // SDK union catches up. They are all non-narrative and therefore remain drop
38
+ // dispositions; genuinely new execution events still use the unknown arm.
39
+ const RUNTIME_DROPPED_EVENT_KINDS = new Set([
40
+ "plugin.added",
41
+ "catalog.updated",
42
+ "reference.updated",
43
+ "integration.updated",
44
+ "server.heartbeat",
45
+ "message.part.delta",
46
+ ]);
47
+ function object(value) {
48
+ return value !== null && typeof value === "object" && !Array.isArray(value)
49
+ ? value : undefined;
50
+ }
51
+ function text(value) {
52
+ return typeof value === "string" && value.length > 0 ? value : undefined;
53
+ }
54
+ function diagnostic(value) {
55
+ const data = object(value);
56
+ const nested = object(data?.data);
57
+ return text(nested?.message) ?? text(data?.message) ?? "OpenCode session failed";
58
+ }
59
+ function positiveLine(value) {
60
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
61
+ }
62
+ function runCall(name, value) {
63
+ return name === "bash" || name === "shell"
64
+ ? { kind: "run", command: text(value?.command) ?? name }
65
+ : undefined;
66
+ }
67
+ function readCall(name, value) {
68
+ if (name !== "read")
69
+ return undefined;
70
+ const path = text(value?.filePath) ?? text(value?.path);
71
+ if (path === undefined)
72
+ return undefined;
73
+ const offset = positiveLine(value?.offset);
74
+ const limit = positiveLine(value?.limit);
75
+ return {
76
+ kind: "read",
77
+ path,
78
+ ...(offset === undefined ? {} : { offset }),
79
+ ...(limit === undefined ? {} : { limit }),
80
+ };
81
+ }
82
+ function searchCall(name, value) {
83
+ if (name !== "grep" && name !== "glob" && name !== "search")
84
+ return undefined;
85
+ const query = text(value?.pattern) ?? text(value?.query);
86
+ if (query === undefined)
87
+ return undefined;
88
+ const path = text(value?.path) ?? text(value?.filePath);
89
+ const glob = text(value?.glob);
90
+ const scope = name === "glob" ? "files" : "content";
91
+ return {
92
+ kind: "search",
93
+ query,
94
+ scope,
95
+ ...(path === undefined ? {} : { path }),
96
+ ...(scope === "content" && glob !== undefined ? { glob } : {}),
97
+ };
98
+ }
99
+ function callFor(name, input) {
100
+ const value = object(input);
101
+ const lower = name.toLowerCase();
102
+ if (lower === "bash" || lower === "shell")
103
+ return runCall(lower, value);
104
+ if (lower === "read")
105
+ return readCall(lower, value);
106
+ if (lower === "grep" || lower === "glob" || lower === "search")
107
+ return searchCall(lower, value);
108
+ return { kind: "other", display: name };
109
+ }
110
+ function belongs(part, state) {
111
+ return state.sessionId === undefined || part.sessionID === state.sessionId;
112
+ }
113
+ function mapTextPart(part, events, state, thought) {
114
+ const id = text(part.id);
115
+ const time = object(part.time);
116
+ const content = text(part.text);
117
+ const seen = thought ? state.reasoningParts : state.assistantParts;
118
+ if (!belongs(part, state) || id === undefined || content === undefined || time?.end === undefined || seen.has(id))
119
+ return;
120
+ seen.add(id);
121
+ if (thought)
122
+ events.emit({ type: "thought", text: content });
123
+ else
124
+ events.emit({ type: "assistant", text: content });
125
+ }
126
+ function resultFor(state, failed) {
127
+ const exit = object(state.metadata)?.exit;
128
+ const exitCode = typeof exit === "number" && Number.isInteger(exit) ? exit : undefined;
129
+ if (failed) {
130
+ return { status: "error", message: text(state.error) ?? "OpenCode tool failed", ...(exitCode === undefined ? {} : { exitCode }) };
131
+ }
132
+ return { status: exitCode !== undefined && exitCode !== 0 ? "error" : "ok", ...(exitCode === undefined ? {} : { exitCode }) };
133
+ }
134
+ function mapToolPart(part, events, state) {
135
+ if (!belongs(part, state))
136
+ return;
137
+ const id = text(part.callID);
138
+ const name = text(part.tool);
139
+ const toolState = object(part.state);
140
+ if (id === undefined || name === undefined || toolState === undefined)
141
+ return;
142
+ if ((toolState.status === "pending" || toolState.status === "running")
143
+ && !state.tools.has(id) && !state.completedTools.has(id)) {
144
+ const call = callFor(name, toolState.input);
145
+ if (call === undefined)
146
+ return;
147
+ const observed = { name, call };
148
+ state.tools.set(id, observed);
149
+ events.emit({ type: "tool", phase: "started", id, ...observed });
150
+ return;
151
+ }
152
+ if ((toolState.status !== "completed" && toolState.status !== "error") || state.completedTools.has(id))
153
+ return;
154
+ const started = state.tools.get(id);
155
+ const call = started?.call ?? callFor(name, toolState.input);
156
+ if (call === undefined)
157
+ return;
158
+ const observed = started ?? { name, call };
159
+ if (!state.tools.has(id)) {
160
+ state.tools.set(id, observed);
161
+ events.emit({ type: "tool", phase: "started", id, ...observed });
162
+ }
163
+ state.completedTools.add(id);
164
+ events.emit({
165
+ type: "tool",
166
+ phase: "completed",
167
+ id,
168
+ ...observed,
169
+ result: resultFor(toolState, toolState.status === "error"),
170
+ });
171
+ }
172
+ function mapPart(part, events, state) {
173
+ if (part.type === "text")
174
+ return mapTextPart(part, events, state, false);
175
+ if (part.type === "reasoning")
176
+ return mapTextPart(part, events, state, true);
177
+ if (part.type === "tool")
178
+ mapToolPart(part, events, state);
179
+ }
180
+ function mapSessionError(properties, events, state) {
181
+ if (state.sessionId !== undefined && properties.sessionID !== state.sessionId)
182
+ return;
183
+ state.failure = diagnostic(properties.error);
184
+ events.emit(noteEvent(state.failure));
185
+ }
186
+ function mapTodo(properties, events, state) {
187
+ if (properties.sessionID !== state.sessionId || !Array.isArray(properties.todos))
188
+ return;
189
+ const summary = properties.todos.flatMap((value) => {
190
+ const todo = object(value);
191
+ const content = text(todo?.content);
192
+ return content === undefined ? [] : [`${text(todo?.status) ?? "todo"}: ${content}`];
193
+ }).join("; ");
194
+ if (summary.length > 0)
195
+ events.emit(noteEvent(summary));
196
+ }
197
+ function ignoredEvent(type) {
198
+ return typeof type === "string"
199
+ && (OPENCODE_EVENT_DISPOSITIONS[type] === "dropped" || RUNTIME_DROPPED_EVENT_KINDS.has(type));
200
+ }
201
+ export function mapEvent(value, events, state) {
202
+ const event = object(value);
203
+ if (event === undefined)
204
+ return;
205
+ const properties = object(event.properties) ?? {};
206
+ if (event.type === "message.part.updated") {
207
+ const part = object(properties.part);
208
+ if (part !== undefined)
209
+ mapPart(part, events, state);
210
+ return;
211
+ }
212
+ if (event.type === "message.updated") {
213
+ const info = object(properties.info);
214
+ if (info !== undefined && info.sessionID === state.sessionId && info.role === "assistant" && info.error !== undefined) {
215
+ state.failure = diagnostic(info.error);
216
+ }
217
+ return;
218
+ }
219
+ if (event.type === "session.error")
220
+ return mapSessionError(properties, events, state);
221
+ if (event.type === "todo.updated")
222
+ return mapTodo(properties, events, state);
223
+ if (ignoredEvent(event.type))
224
+ return;
225
+ events.emit({ type: "unknown", kind: typeof event.type === "string" ? event.type : "unknown" });
226
+ }
227
+ export function createEventState(sessionId) {
228
+ return {
229
+ ...(sessionId === undefined ? {} : { sessionId }),
230
+ assistantParts: new Set(),
231
+ reasoningParts: new Set(),
232
+ tools: new Map(),
233
+ completedTools: new Set(),
234
+ };
235
+ }