@astrosheep/keiyaku 4.0.1 → 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 (245) hide show
  1. package/README.md +137 -5
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -35
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +98 -58
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +152 -53
  9. package/build/src/akuma/abort.d.ts +2 -0
  10. package/build/src/akuma/abort.js +50 -0
  11. package/build/src/akuma/akuma.d.ts +23 -14
  12. package/build/src/akuma/akuma.js +120 -104
  13. package/build/src/akuma/archetype.d.ts +7 -6
  14. package/build/src/akuma/archetype.js +68 -41
  15. package/build/src/akuma/body.d.ts +3 -5
  16. package/build/src/akuma/body.js +408 -213
  17. package/build/src/akuma/heart/facts.d.ts +25 -34
  18. package/build/src/akuma/heart/facts.js +18 -7
  19. package/build/src/akuma/heart/index.d.ts +39 -42
  20. package/build/src/akuma/heart/index.js +134 -93
  21. package/build/src/akuma/heart/rows.d.ts +9 -31
  22. package/build/src/akuma/heart/rows.js +26 -44
  23. package/build/src/akuma/heart/schema.d.ts +1 -1
  24. package/build/src/akuma/heart/schema.js +7 -15
  25. package/build/src/akuma/heart/soul.d.ts +8 -0
  26. package/build/src/akuma/heart/soul.js +136 -0
  27. package/build/src/akuma/heart/storage.d.ts +28 -14
  28. package/build/src/akuma/heart/storage.js +86 -26
  29. package/build/src/akuma/identity.d.ts +2 -2
  30. package/build/src/akuma/identity.js +9 -9
  31. package/build/src/akuma/index.d.ts +6 -1
  32. package/build/src/akuma/index.js +6 -0
  33. package/build/src/akuma/projection.d.ts +117 -38
  34. package/build/src/akuma/projection.js +208 -97
  35. package/build/src/akuma/provider-recipe.d.ts +24 -0
  36. package/build/src/akuma/provider-recipe.js +100 -0
  37. package/build/src/akuma/provider.d.ts +12 -4
  38. package/build/src/akuma/provider.js +117 -70
  39. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  40. package/build/src/akuma/providers/acp/core.js +159 -0
  41. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  42. package/build/src/akuma/providers/acp/events.js +73 -0
  43. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  44. package/build/src/akuma/providers/acp/index.js +94 -0
  45. package/build/src/akuma/providers/claude/events.js +66 -13
  46. package/build/src/akuma/providers/claude/index.d.ts +2 -1
  47. package/build/src/akuma/providers/claude/index.js +35 -21
  48. package/build/src/akuma/providers/codex-app-server/events.js +4 -1
  49. package/build/src/akuma/providers/codex-app-server/index.d.ts +3 -3
  50. package/build/src/akuma/providers/codex-app-server/index.js +24 -31
  51. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  52. package/build/src/akuma/providers/grok-build/index.js +70 -0
  53. package/build/src/akuma/providers/index.d.ts +5 -3
  54. package/build/src/akuma/providers/index.js +24 -59
  55. package/build/src/akuma/providers/opencode-sdk/events.d.ts +40 -34
  56. package/build/src/akuma/providers/opencode-sdk/events.js +220 -101
  57. package/build/src/akuma/providers/opencode-sdk/index.d.ts +3 -2
  58. package/build/src/akuma/providers/opencode-sdk/index.js +233 -128
  59. package/build/src/akuma/providers/opencode-sdk/session.d.ts +11 -26
  60. package/build/src/akuma/providers/opencode-sdk/session.js +10 -9
  61. package/build/src/akuma/providers/pi/events.js +49 -11
  62. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  63. package/build/src/akuma/providers/pi/index.js +50 -21
  64. package/build/src/akuma/publication.d.ts +3 -3
  65. package/build/src/akuma/publication.js +28 -40
  66. package/build/src/akuma/requests.d.ts +9 -7
  67. package/build/src/akuma/requests.js +92 -65
  68. package/build/src/alias/index.d.ts +2 -2
  69. package/build/src/alias/index.js +10 -10
  70. package/build/src/body/decode.js +7 -1
  71. package/build/src/body/region.d.ts +2 -0
  72. package/build/src/body/region.js +77 -7
  73. package/build/src/cli/accepted.d.ts +17 -13
  74. package/build/src/cli/accepted.js +72 -34
  75. package/build/src/cli/actor.js +3 -3
  76. package/build/src/cli/commands/akuma-invoke.d.ts +4 -3
  77. package/build/src/cli/commands/akuma-invoke.js +14 -9
  78. package/build/src/cli/commands/akuma.d.ts +13 -3
  79. package/build/src/cli/commands/akuma.js +67 -34
  80. package/build/src/cli/commands/contract.d.ts +18 -5
  81. package/build/src/cli/commands/contract.js +9 -3
  82. package/build/src/cli/commands/task-invoke.d.ts +17 -4
  83. package/build/src/cli/commands/task-invoke.js +43 -20
  84. package/build/src/cli/commands/task-query.d.ts +5 -0
  85. package/build/src/cli/commands/task-query.js +247 -0
  86. package/build/src/cli/commands/task.d.ts +3 -1
  87. package/build/src/cli/commands/task.js +51 -13
  88. package/build/src/cli/coordinates.d.ts +18 -0
  89. package/build/src/cli/coordinates.js +120 -0
  90. package/build/src/cli/draft.d.ts +8 -0
  91. package/build/src/cli/draft.js +96 -0
  92. package/build/src/cli/invoke.d.ts +4 -3
  93. package/build/src/cli/invoke.js +160 -179
  94. package/build/src/cli/main.js +34 -6
  95. package/build/src/cli/parse.d.ts +9 -2
  96. package/build/src/cli/parse.js +29 -7
  97. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  98. package/build/src/cli/render/akuma-tool-command.js +144 -0
  99. package/build/src/cli/render/akuma-tool.d.ts +2 -2
  100. package/build/src/cli/render/akuma-tool.js +30 -4
  101. package/build/src/cli/render/akuma.d.ts +1 -0
  102. package/build/src/cli/render/akuma.js +211 -116
  103. package/build/src/cli/render/audit.d.ts +3 -0
  104. package/build/src/cli/render/audit.js +104 -0
  105. package/build/src/cli/render/contract.d.ts +3 -3
  106. package/build/src/cli/render/contract.js +192 -79
  107. package/build/src/cli/render/kanshi.js +263 -168
  108. package/build/src/cli/render/receipt.d.ts +19 -0
  109. package/build/src/cli/render/receipt.js +106 -0
  110. package/build/src/cli/render/refusal.d.ts +16 -2
  111. package/build/src/cli/render/refusal.js +88 -20
  112. package/build/src/cli/render/region.d.ts +2 -0
  113. package/build/src/cli/render/region.js +17 -0
  114. package/build/src/cli/render/task.d.ts +2 -1
  115. package/build/src/cli/render/task.js +223 -60
  116. package/build/src/cli/render/terminal.d.ts +7 -0
  117. package/build/src/cli/render/terminal.js +46 -0
  118. package/build/src/cli/render/text.js +6 -3
  119. package/build/src/cli/result.d.ts +115 -20
  120. package/build/src/cli/usage.d.ts +1 -0
  121. package/build/src/cli/usage.js +3 -0
  122. package/build/src/contract-worktree.d.ts +6 -5
  123. package/build/src/contract-worktree.js +95 -57
  124. package/build/src/coordination/durable-file.d.ts +4 -3
  125. package/build/src/coordination/durable-file.js +29 -25
  126. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  127. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  128. package/build/src/core/facts/fold.js +1 -6
  129. package/build/src/core/facts/gate.d.ts +1 -0
  130. package/build/src/core/facts/gate.js +1 -0
  131. package/build/src/core/verbs/amend.d.ts +1 -1
  132. package/build/src/core/verbs/amend.js +0 -11
  133. package/build/src/core/verbs/deliver.d.ts +1 -1
  134. package/build/src/core/verbs/deliver.js +1 -7
  135. package/build/src/core/verbs/placement.d.ts +1 -1
  136. package/build/src/core/verbs/placement.js +4 -1
  137. package/build/src/dispatch/index.d.ts +2 -2
  138. package/build/src/dispatch/index.js +17 -17
  139. package/build/src/git/admission.d.ts +1 -1
  140. package/build/src/git/admission.js +11 -11
  141. package/build/src/git/hooks.js +13 -13
  142. package/build/src/git/integration.d.ts +14 -15
  143. package/build/src/git/integration.js +80 -44
  144. package/build/src/git/observe.d.ts +5 -3
  145. package/build/src/git/observe.js +18 -12
  146. package/build/src/git/read-observation.js +9 -9
  147. package/build/src/git/reconcile.d.ts +2 -0
  148. package/build/src/git/reconcile.js +138 -95
  149. package/build/src/git/repository.d.ts +27 -19
  150. package/build/src/git/repository.js +155 -83
  151. package/build/src/git/scratch.d.ts +7 -3
  152. package/build/src/git/scratch.js +44 -37
  153. package/build/src/git/target-placement.d.ts +40 -4
  154. package/build/src/git/target-placement.js +221 -101
  155. package/build/src/git/tender.d.ts +6 -5
  156. package/build/src/git/tender.js +24 -43
  157. package/build/src/git/terminal-seal.d.ts +1 -1
  158. package/build/src/git/terminal-seal.js +7 -5
  159. package/build/src/git/workspace.d.ts +36 -4
  160. package/build/src/git/workspace.js +53 -18
  161. package/build/src/identity/selector.js +1 -1
  162. package/build/src/index.d.ts +3 -3
  163. package/build/src/index.js +1 -1
  164. package/build/src/kanshi/index.d.ts +2 -2
  165. package/build/src/kanshi/index.js +1 -1
  166. package/build/src/kanshi/read.d.ts +2 -1
  167. package/build/src/kanshi/read.js +118 -27
  168. package/build/src/kanshi/report.d.ts +50 -0
  169. package/build/src/kanshi/select.d.ts +5 -0
  170. package/build/src/kanshi/select.js +32 -0
  171. package/build/src/library/address.d.ts +12 -3
  172. package/build/src/library/address.js +77 -46
  173. package/build/src/library/akuma-creation.d.ts +6 -1
  174. package/build/src/library/akuma-creation.js +86 -13
  175. package/build/src/library/audit.d.ts +18 -0
  176. package/build/src/library/audit.js +44 -0
  177. package/build/src/library/bind.js +4 -4
  178. package/build/src/library/catalog.d.ts +1 -1
  179. package/build/src/library/catalog.js +5 -8
  180. package/build/src/library/contract.d.ts +5 -6
  181. package/build/src/library/contract.js +11 -35
  182. package/build/src/library/delivery.d.ts +2 -1
  183. package/build/src/library/fleet.d.ts +2 -2
  184. package/build/src/library/fleet.js +35 -71
  185. package/build/src/library/keiyaku.d.ts +3 -2
  186. package/build/src/library/keiyaku.js +1 -0
  187. package/build/src/library/mutation.d.ts +7 -6
  188. package/build/src/library/mutation.js +23 -25
  189. package/build/src/library/reconcile.d.ts +29 -0
  190. package/build/src/library/reconcile.js +179 -0
  191. package/build/src/library/region.d.ts +12 -0
  192. package/build/src/library/region.js +15 -1
  193. package/build/src/library/repo.d.ts +4 -16
  194. package/build/src/library/repo.js +13 -38
  195. package/build/src/protocol/attempt.js +6 -6
  196. package/build/src/protocol/bind.js +4 -4
  197. package/build/src/protocol/intent.d.ts +15 -2
  198. package/build/src/protocol/intent.js +21 -6
  199. package/build/src/protocol/operations.d.ts +73 -22
  200. package/build/src/protocol/operations.js +292 -88
  201. package/build/src/protocol/outcome.d.ts +9 -3
  202. package/build/src/protocol/outcome.js +3 -1
  203. package/build/src/protocol/placement.d.ts +15 -4
  204. package/build/src/protocol/placement.js +58 -25
  205. package/build/src/protocol/read/status.d.ts +8 -1
  206. package/build/src/protocol/read/status.js +61 -14
  207. package/build/src/runtime/proc/line-rpc.d.ts +3 -8
  208. package/build/src/runtime/proc/line-rpc.js +16 -43
  209. package/build/src/runtime/proc/run.d.ts +15 -29
  210. package/build/src/runtime/proc/run.js +113 -105
  211. package/build/src/runtime/proc/stdio.d.ts +18 -0
  212. package/build/src/runtime/proc/stdio.js +58 -0
  213. package/build/src/settings.d.ts +2 -2
  214. package/build/src/settings.js +8 -8
  215. package/build/src/settlement/fence.d.ts +0 -4
  216. package/build/src/settlement/fence.js +0 -9
  217. package/build/src/settlement/holder.d.ts +11 -1
  218. package/build/src/settlement/holder.js +25 -0
  219. package/build/src/settlement/settle.d.ts +1 -1
  220. package/build/src/settlement/settle.js +52 -89
  221. package/build/src/task/board.d.ts +3 -3
  222. package/build/src/task/board.js +6 -9
  223. package/build/src/task/compose.d.ts +1 -1
  224. package/build/src/task/compose.js +18 -10
  225. package/build/src/task/context.d.ts +3 -3
  226. package/build/src/task/context.js +14 -14
  227. package/build/src/task/document.d.ts +2 -1
  228. package/build/src/task/document.js +15 -5
  229. package/build/src/task/index.d.ts +19 -7
  230. package/build/src/task/index.js +42 -23
  231. package/build/src/task/operations.d.ts +15 -9
  232. package/build/src/task/operations.js +78 -48
  233. package/build/src/task/query.d.ts +67 -0
  234. package/build/src/task/query.js +279 -0
  235. package/build/src/task/store.d.ts +2 -2
  236. package/build/src/task/store.js +40 -25
  237. package/build/src/verification/execution.d.ts +4 -2
  238. package/build/src/verification/execution.js +9 -5
  239. package/build/src/workspace-place.d.ts +41 -0
  240. package/build/src/workspace-place.js +386 -0
  241. package/build/src/world.d.ts +13 -2
  242. package/build/src/world.js +81 -48
  243. package/package.json +3 -2
  244. package/build/src/protocol/read/audit.d.ts +0 -31
  245. package/build/src/protocol/read/audit.js +0 -55
@@ -53,6 +53,28 @@ function nonblank(value) {
53
53
  function number(value) {
54
54
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
55
55
  }
56
+ function positiveLine(value) {
57
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
58
+ }
59
+ function readRange(value) {
60
+ const offset = positiveLine(value.offset);
61
+ const limit = positiveLine(value.limit);
62
+ return {
63
+ ...(offset === undefined ? {} : { offset }),
64
+ ...(limit === undefined ? {} : { limit }),
65
+ };
66
+ }
67
+ function contentSearch(value, query) {
68
+ const path = nonblank(value.path);
69
+ const glob = nonblank(value.glob);
70
+ return {
71
+ kind: "search",
72
+ query,
73
+ scope: "content",
74
+ ...(path === undefined ? {} : { path }),
75
+ ...(glob === undefined ? {} : { glob }),
76
+ };
77
+ }
56
78
  const CLAUDE_SYSTEM_NOTES = {
57
79
  api_retry: (message) => {
58
80
  const attempt = number(message.attempt);
@@ -82,22 +104,53 @@ const CLAUDE_SYSTEM_NOTES = {
82
104
  task_updated: (message) => `Task ${nonblank(message.task_id) ?? "unknown"} updated`,
83
105
  worker_shutting_down: (message) => `Worker stopping: ${nonblank(message.reason) ?? "unknown reason"}`,
84
106
  };
85
- function toolCall(name, input) {
86
- const value = object(input) ?? {};
107
+ function runCall(name, value) {
108
+ if (name !== "Bash")
109
+ return undefined;
87
110
  const command = nonblank(value.command);
88
- if (command !== undefined)
89
- return { kind: "run", command };
90
- const path = nonblank(value.file_path) ?? nonblank(value.path);
91
- if (/^(?:read|view)/iu.test(name) && path !== undefined)
92
- return { kind: "read", path };
93
- const query = nonblank(value.query) ?? nonblank(value.pattern);
94
- if (/search|grep|glob/iu.test(name) && query !== undefined)
95
- return { kind: "search", query };
96
- if (/write/iu.test(name) && path !== undefined)
111
+ return command === undefined ? { kind: "other", display: name } : { kind: "run", command };
112
+ }
113
+ function readCall(name, path, value) {
114
+ return name === "Read" && path !== undefined ? { kind: "read", path, ...readRange(value) } : undefined;
115
+ }
116
+ function searchCall(name, value) {
117
+ if (name === "Grep") {
118
+ const query = nonblank(value.pattern) ?? nonblank(value.query);
119
+ return query === undefined ? undefined : contentSearch(value, query);
120
+ }
121
+ if (name === "Glob") {
122
+ const query = nonblank(value.pattern);
123
+ const globPath = nonblank(value.path);
124
+ return query === undefined
125
+ ? undefined
126
+ : { kind: "search", query, scope: "files", ...(globPath === undefined ? {} : { path: globPath }) };
127
+ }
128
+ if (name === "WebSearch") {
129
+ const query = nonblank(value.query);
130
+ return query === undefined ? undefined : { kind: "search", query, scope: "web" };
131
+ }
132
+ return undefined;
133
+ }
134
+ function fileChangeCall(name, path) {
135
+ if (path === undefined)
136
+ return undefined;
137
+ if (name === "Write")
97
138
  return { kind: "fileChange", changes: [{ op: "add", path }] };
98
- if (/edit|notebook/iu.test(name) && path !== undefined)
139
+ if (name === "Edit" || name === "NotebookEdit") {
99
140
  return { kind: "fileChange", changes: [{ op: "update", path }] };
100
- return { kind: "other", display: name };
141
+ }
142
+ return undefined;
143
+ }
144
+ function toolCall(name, input) {
145
+ const value = object(input) ?? {};
146
+ const run = runCall(name, value);
147
+ if (run !== undefined)
148
+ return run;
149
+ const path = nonblank(value.file_path) ?? (name === "Read" ? nonblank(value.path) : undefined);
150
+ return readCall(name, path, value)
151
+ ?? searchCall(name, value)
152
+ ?? fileChangeCall(name, path)
153
+ ?? { kind: "other", display: name };
101
154
  }
102
155
  function assistantEvents(message, events, state) {
103
156
  if (message.aborted === true)
@@ -1,5 +1,6 @@
1
1
  import type { Options, Query, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
2
- import { type ProviderAdapter, type ProviderOptions, type Session } from "../../provider.js";
2
+ import { type ProviderAdapter, type Session } from "../../provider.js";
3
+ import type { ProviderOptions } from "../../provider-recipe.js";
3
4
  import type { ResumeCoordinate } from "../../provider.js";
4
5
  export { CLAUDE_MESSAGE_DISPOSITIONS, CLAUDE_SYSTEM_DISPOSITIONS } from "./events.js";
5
6
  type ClaudeExecution = Readonly<{
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { abortable } from "../../abort.js";
2
3
  import { AgentEventChannel, } from "../../provider.js";
3
4
  import { emitClaudeMessage, } from "./events.js";
4
5
  import { claudeUserMessage, createClaudeInput, isClaudeTurnEnded } from "./input.js";
@@ -38,16 +39,16 @@ class ReceiptChannel {
38
39
  }
39
40
  function admitClaudeOptions(options) {
40
41
  if (options.network !== undefined) {
41
- return { kind: "refused", diagnostic: "Claude provider does not support the Archetype network option" };
42
+ return { kind: "refused", diagnostic: "Claude provider does not support the network option" };
42
43
  }
43
- return { kind: "admitted", options: Object.freeze({ ...options }) };
44
+ return {
45
+ kind: "admitted",
46
+ options: Object.freeze({ ...options }),
47
+ ...(options.readonly === undefined ? {} : { readonly: { enforcement: "native" } }),
48
+ };
44
49
  }
45
- function permissionMode(access) {
46
- if (access === "read")
47
- return "plan";
48
- if (access === "write")
49
- return "acceptEdits";
50
- return "bypassPermissions";
50
+ function permissionMode(readonly) {
51
+ return readonly === true ? "plan" : "bypassPermissions";
51
52
  }
52
53
  function claudeSessionId(coordinate) {
53
54
  if (!("sessionId" in coordinate) || coordinate.sessionId === undefined) {
@@ -56,14 +57,14 @@ function claudeSessionId(coordinate) {
56
57
  return coordinate.sessionId;
57
58
  }
58
59
  function claudeQueryOptions(input, execution, abortController) {
59
- const access = permissionMode(input.options.access);
60
+ const mode = permissionMode(input.options.readonly);
60
61
  return {
61
62
  cwd: input.cwd,
62
63
  abortController,
63
64
  ...(execution.executable === undefined ? {} : { pathToClaudeCodeExecutable: execution.executable }),
64
65
  ...(execution.env === undefined ? {} : { env: { ...process.env, ...execution.env } }),
65
- permissionMode: access,
66
- ...(access === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
66
+ permissionMode: mode,
67
+ ...(mode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
67
68
  settingSources: ["user", "project", "local"],
68
69
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
69
70
  ...(input.options.effort === undefined ? {} : { effort: input.options.effort }),
@@ -92,9 +93,11 @@ function launchText(input) {
92
93
  .filter((part) => part.length > 0).join("\n\n");
93
94
  }
94
95
  function successfulResult(message, historyId) {
95
- return historyId === undefined
96
- ? { kind: "failed", diagnostic: "Claude query succeeded without an assistant history id" }
97
- : { kind: "answered", answer: message.subtype === "success" ? message.result : "", historyId };
96
+ return {
97
+ kind: "answered",
98
+ answer: message.subtype === "success" ? message.result : "",
99
+ ...(historyId === undefined ? {} : { historyId }),
100
+ };
98
101
  }
99
102
  function finishClaudeInput(input, terminal) {
100
103
  if (terminal?.kind === "answered")
@@ -192,7 +195,10 @@ function observeClaudeQuery(context) {
192
195
  async function driveClaude(load, execution, drive) {
193
196
  if (drive.session.kind === "resume")
194
197
  claudeSessionId(drive.session.coordinate);
195
- const sdk = await load();
198
+ const signal = drive.signal ?? new AbortController().signal;
199
+ signal.throwIfAborted();
200
+ const sdk = await abortable(load(), signal);
201
+ signal.throwIfAborted();
196
202
  const events = new AgentEventChannel();
197
203
  const receipts = new ReceiptChannel();
198
204
  const input = createClaudeInput();
@@ -206,11 +212,23 @@ async function driveClaude(load, execution, drive) {
206
212
  prompt: input.iterable,
207
213
  options: claudeQueryOptions(drive, execution, abortController),
208
214
  });
215
+ const shutDown = (error) => {
216
+ abortController.abort(error);
217
+ input.fail(error);
218
+ query.close();
219
+ };
220
+ const abortSetup = () => shutDown(signal.reason);
221
+ signal.addEventListener("abort", abortSetup, { once: true });
209
222
  const observed = observeClaudeQuery({
210
223
  query, input, events, receipts, accepted,
211
224
  state: { get openSubmissions() { return openSubmissions; } },
212
225
  });
213
- await Promise.all([launchAcknowledged, observed.admission]);
226
+ try {
227
+ await Promise.all([launchAcknowledged, observed.admission]);
228
+ }
229
+ finally {
230
+ signal.removeEventListener("abort", abortSetup);
231
+ }
214
232
  return {
215
233
  admission: { fence: `claude:${run}:0` },
216
234
  events,
@@ -245,11 +263,7 @@ async function driveClaude(load, execution, drive) {
245
263
  });
246
264
  },
247
265
  async abort() {
248
- const error = new Error("Claude query aborted");
249
- abortController.abort(error);
250
- input.fail(error);
251
- query.close();
252
- await observed.completion;
266
+ shutDown(new Error("Claude query aborted"));
253
267
  },
254
268
  };
255
269
  }
@@ -186,7 +186,10 @@ function itemToolCall(item, kind) {
186
186
  return path === undefined ? { kind: "other", display: "image view" } : { kind: "read", path };
187
187
  }
188
188
  if (kind === "webSearch") {
189
- return { kind: "search", query: codexText(item.query) ?? "web search" };
189
+ const query = codexText(item.query);
190
+ return query === undefined
191
+ ? { kind: "other", display: "web search" }
192
+ : { kind: "search", query, scope: "web" };
190
193
  }
191
194
  if (kind === "fileChange") {
192
195
  const changes = itemChanges(item);
@@ -1,12 +1,12 @@
1
- import { type Session, type ProviderAdapter, type ProviderOptions } from "../../provider.js";
2
- import type { ProviderExecution } from "../../heart/index.js";
1
+ import { type Session, type ProviderAdapter } from "../../provider.js";
2
+ import type { ProviderExecution, ProviderOptions } from "../../provider-recipe.js";
3
3
  export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
4
4
  export declare function createCodexAppServerProvider(input?: string | ProviderExecution): ProviderAdapter;
5
5
  export declare const codexAppServerProvider: Readonly<{
6
6
  confinement(input: Readonly<{
7
7
  cwd: string;
8
8
  options: ProviderOptions;
9
- }>): import("../../heart/facts.js").Confinement;
9
+ }>): import("../../index.js").Confinement;
10
10
  admitOptions(options: ProviderOptions): import("../../provider.js").ProviderOptionAdmission;
11
11
  fork?(input: Readonly<{
12
12
  session: import("../../coordinate.js").ResumeCoordinate;
@@ -2,14 +2,6 @@ import { LineRpcProcess } from "../../../runtime/proc/line-rpc.js";
2
2
  import { AgentEventChannel, AKUMA_REQUESTS_ENV, } from "../../provider.js";
3
3
  import { codexNotificationResult, codexObject, codexText, } from "./events.js";
4
4
  export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
5
- const INTERRUPT_TIMEOUT_MS = 1_000;
6
- function interrupt(server, threadId, turnId) {
7
- const request = server.request("turn/interrupt", { threadId, turnId });
8
- return new Promise((resolve, reject) => {
9
- const timer = setTimeout(() => reject(new Error("codex app-server interrupt timed out")), INTERRUPT_TIMEOUT_MS);
10
- void request.then((value) => { clearTimeout(timer); resolve(value); }, (error) => { clearTimeout(timer); reject(error); });
11
- });
12
- }
13
5
  function diagnostic(error) {
14
6
  return error instanceof Error ? error.message : String(error);
15
7
  }
@@ -56,6 +48,9 @@ async function steerTurn(server, state, tell) {
56
48
  return { kind: "accepted", fence: `${accepted}:${tell.id}` };
57
49
  }
58
50
  function sandbox(cwd, options, requests) {
51
+ if (options.readonly === true) {
52
+ return { type: "readOnly", networkAccess: options.network === "enabled" };
53
+ }
59
54
  return {
60
55
  type: "workspaceWrite",
61
56
  writableRoots: [cwd, ...(requests === undefined ? [] : [requests.dir])],
@@ -115,26 +110,13 @@ async function forkCodex(execution, input) {
115
110
  await server.close();
116
111
  }
117
112
  }
118
- async function abortTurn(server, state, completion, settle) {
119
- if (state.settled) {
120
- await completion;
121
- return;
122
- }
123
- if (state.threadId !== undefined && state.turnId !== undefined) {
124
- try {
125
- await interrupt(server, state.threadId, state.turnId);
126
- await completion;
127
- }
128
- catch (error) {
129
- settle({ kind: "failed", diagnostic: diagnostic(error) });
130
- }
131
- }
132
- else {
133
- settle({ kind: "failed", diagnostic: "codex app-server aborted before turn admission" });
134
- }
135
- await completion;
113
+ async function abortTurn(server, state, settle) {
114
+ if (!state.settled)
115
+ settle({ kind: "failed", diagnostic: "codex app-server interrupted" });
116
+ await server.close(true);
136
117
  }
137
118
  async function startCodex(execution, input) {
119
+ const signal = input.signal ?? new AbortController().signal;
138
120
  if (input.session.kind === "resume" && !("sessionId" in input.session.coordinate))
139
121
  throw new Error("Codex app-server resume requires sessionId");
140
122
  const events = new AgentEventChannel();
@@ -177,19 +159,29 @@ async function startCodex(execution, input) {
177
159
  kind: "failed",
178
160
  diagnostic: `codex app-server made forbidden interactive request ${request.method}`,
179
161
  }));
162
+ const abortSetup = () => { void server.close(true); };
163
+ signal.addEventListener("abort", abortSetup, { once: true });
180
164
  try {
165
+ signal.throwIfAborted();
181
166
  await admitTurn(server, input, state, events, execution.config);
182
167
  }
183
168
  catch (error) {
169
+ if (signal.aborted) {
170
+ await server.close(true);
171
+ throw signal.reason;
172
+ }
184
173
  finish({ kind: "failed", diagnostic: diagnostic(error) });
185
174
  }
175
+ finally {
176
+ signal.removeEventListener("abort", abortSetup);
177
+ }
186
178
  if (state.turnId === undefined)
187
179
  throw new Error("codex app-server did not admit a turn");
188
180
  return {
189
181
  admission: { fence: state.turnId },
190
182
  events,
191
183
  completion,
192
- abort: () => abortTurn(server, state, completion, finish),
184
+ abort: () => abortTurn(server, state, finish),
193
185
  tell: (tell) => steerTurn(server, state, tell),
194
186
  };
195
187
  }
@@ -200,10 +192,11 @@ export function createCodexAppServerProvider(input = "codex") {
200
192
  return {
201
193
  confinement: ({ cwd }) => ({ kind: "declared", writableRoots: [cwd] }),
202
194
  admitOptions(options) {
203
- if (options.access !== undefined && options.access !== "write") {
204
- return { kind: "refused", diagnostic: "Codex app-server supports only access: write" };
205
- }
206
- 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
+ };
207
200
  },
208
201
  fork: (input) => forkCodex(execution, input),
209
202
  start: (input) => startCodex(execution, input),
@@ -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,75 +1,26 @@
1
+ import { decodeProviderRecipe } from "../provider-recipe.js";
2
+ import { createAcpProvider, decodeAcpConfig } from "./acp/index.js";
1
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";
3
6
  import { createOpencodeProvider } from "./opencode-sdk/index.js";
4
7
  import { createPiProvider } from "./pi/index.js";
5
8
  const PROVIDERS = {
6
9
  claude: claudeProvider,
7
10
  };
8
- function record(value) {
9
- return value !== null && typeof value === "object" && !Array.isArray(value)
10
- ? value : null;
11
- }
12
- function snapshot(value) {
13
- if (Array.isArray(value))
14
- return Object.freeze(value.map(snapshot));
15
- const object = record(value);
16
- if (object === null)
17
- return value;
18
- return Object.freeze(Object.fromEntries(Object.entries(object).map(([key, item]) => [key, snapshot(item)])));
19
- }
20
- function optionalText(value, field) {
21
- const selected = value[field];
22
- if (selected === undefined)
23
- return undefined;
24
- if (typeof selected !== "string" || selected.trim().length === 0) {
25
- throw new TypeError(`provider execution ${field} must be a nonblank string`);
26
- }
27
- return selected;
28
- }
29
- function providerKind(value) {
30
- return value === "claude-agent-sdk" || value === "codex-app-server" || value === "opencode-sdk" || value === "pi";
31
- }
32
- function providerConfig(value, kind) {
33
- const config = value.config === undefined ? undefined : record(value.config);
34
- if (config === null)
35
- throw new TypeError("provider execution config must be an object");
11
+ function providerConfig(execution) {
12
+ const { config, kind } = execution;
36
13
  if (kind === "claude-agent-sdk" && config !== undefined)
37
14
  throw new TypeError("provider execution config is unsupported by claude-agent-sdk");
38
15
  if (kind === "opencode-sdk" && config !== undefined)
39
16
  throw new TypeError("provider execution config is unsupported by opencode-sdk");
17
+ if (kind === "acp")
18
+ return decodeAcpConfig(config);
40
19
  return config;
41
20
  }
42
- export function decodeProviderExecution(input) {
43
- const value = record(input);
44
- if (value === null)
45
- throw new TypeError("provider execution must be an object");
46
- const allowed = ["config", "env", "executable", "kind", "name"];
47
- const unknown = Object.keys(value).find((key) => !allowed.includes(key));
48
- if (unknown !== undefined)
49
- throw new TypeError(`provider execution has unknown field ${unknown}`);
50
- if (typeof value.name !== "string" || value.name.trim().length === 0) {
51
- throw new TypeError("provider execution name must be a nonblank string");
52
- }
53
- if (!providerKind(value.kind)) {
54
- throw new TypeError("provider execution has unknown kind");
55
- }
56
- const executable = optionalText(value, "executable");
57
- const config = providerConfig(value, value.kind);
58
- const env = value.env === undefined ? undefined : record(value.env);
59
- if (env === null)
60
- throw new TypeError("provider execution env must be an object");
61
- if (env !== undefined && Object.values(env).some((item) => typeof item !== "string")) {
62
- throw new TypeError("provider execution env must contain only string values");
63
- }
64
- return Object.freeze({
65
- name: value.name,
66
- kind: value.kind,
67
- ...(executable === undefined ? {} : { executable }),
68
- ...(config === undefined ? {} : { config: snapshot(config) }),
69
- ...(env === undefined ? {} : { env: Object.freeze({ ...env }) }),
70
- });
71
- }
72
- export function providerNamed(execution) {
21
+ function adapterFor(execution) {
22
+ if (execution.kind === "acp")
23
+ return createAcpProvider(execution);
73
24
  if (execution.kind === "claude-agent-sdk") {
74
25
  return execution.executable === undefined && execution.env === undefined
75
26
  ? PROVIDERS.claude
@@ -77,9 +28,23 @@ export function providerNamed(execution) {
77
28
  }
78
29
  if (execution.kind === "codex-app-server")
79
30
  return createCodexAppServerProvider(execution);
31
+ if (execution.kind === "grok-build")
32
+ return createGrokBuildProvider(execution);
80
33
  if (execution.kind === "opencode-sdk")
81
34
  return createOpencodeProvider(execution);
82
35
  if (execution.kind === "pi")
83
36
  return createPiProvider(execution);
84
37
  throw new TypeError(`unknown Akuma provider kind ${execution.kind}`);
85
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
+ }
@@ -1,48 +1,54 @@
1
- import type { AgentEvent, ToolCall } from "../../provider.js";
1
+ import { type AgentEvent, type ToolCall } from "../../provider.js";
2
2
  type Emitter = {
3
3
  emit(event: AgentEvent): void;
4
4
  };
5
- type ToolState = Readonly<{
5
+ type ObservedTool = Readonly<{
6
6
  name: string;
7
7
  call: ToolCall;
8
8
  }>;
9
9
  type State = {
10
- tools: Map<string, ToolState>;
11
- answer: string[];
12
- seen: Set<string>;
10
+ sessionId?: string;
11
+ assistantParts: Set<string>;
12
+ reasoningParts: Set<string>;
13
+ tools: Map<string, ObservedTool>;
14
+ completedTools: Set<string>;
13
15
  failure?: string;
14
16
  };
15
17
  export declare const OPENCODE_EVENT_DISPOSITIONS: {
16
- readonly "session.next.agent.switched": "dropped";
17
- readonly "session.next.model.switched": "dropped";
18
- readonly "session.next.moved": "dropped";
19
- readonly "session.next.prompted": "dropped";
20
- readonly "session.next.prompt.admitted": "dropped";
21
- readonly "session.next.context.updated": "dropped";
22
- readonly "session.next.synthetic": "dropped";
23
- readonly "session.next.shell.started": "dropped";
24
- readonly "session.next.shell.ended": "dropped";
25
- readonly "session.next.step.started": "dropped";
26
- readonly "session.next.step.ended": "dropped";
27
- readonly "session.next.step.failed": "mapped";
28
- readonly "session.next.text.started": "dropped";
29
- readonly "session.next.text.ended": "mapped";
30
- readonly "session.next.tool.input.started": "dropped";
31
- readonly "session.next.tool.input.ended": "dropped";
32
- readonly "session.next.tool.called": "mapped";
33
- readonly "session.next.tool.progress": "dropped";
34
- readonly "session.next.tool.success": "mapped";
35
- readonly "session.next.tool.failed": "mapped";
36
- readonly "session.next.reasoning.started": "dropped";
37
- readonly "session.next.reasoning.ended": "mapped";
38
- readonly "session.next.retried": "mapped";
39
- readonly "session.next.compaction.started": "dropped";
40
- readonly "session.next.compaction.ended": "dropped";
41
- readonly "session.next.revert.staged": "dropped";
42
- readonly "session.next.revert.cleared": "dropped";
43
- readonly "session.next.revert.committed": "dropped";
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";
44
50
  };
45
51
  export declare function mapEvent(value: unknown, events: Emitter, state: State): void;
46
52
  export type EventState = State;
47
- export declare function createEventState(): State;
53
+ export declare function createEventState(sessionId?: string): State;
48
54
  export {};