@astrosheep/keiyaku 4.6.8 → 4.6.10

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 (253) hide show
  1. package/README.md +40 -14
  2. package/build/plugins/claude/.claude-plugin/plugin.json +1 -1
  3. package/build/plugins/claude/skills/keiyaku/SKILL.md +5 -6
  4. package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +1 -1
  5. package/build/plugins/claude/skills/keiyaku-akuma/references/automation.md +8 -8
  6. package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
  7. package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +9 -9
  8. package/build/plugins/claude/skills/keiyaku-debt/SKILL.md +91 -0
  9. package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +2 -2
  10. package/build/plugins/codex/.codex-plugin/plugin.json +1 -1
  11. package/build/plugins/codex/skills/keiyaku/SKILL.md +5 -6
  12. package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +1 -1
  13. package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +8 -8
  14. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
  15. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +9 -9
  16. package/build/plugins/codex/skills/keiyaku-debt/SKILL.md +91 -0
  17. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +2 -2
  18. package/build/plugins/opencode/index.js +1 -1
  19. package/build/plugins/opencode/skills/keiyaku/SKILL.md +5 -6
  20. package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +1 -1
  21. package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +8 -8
  22. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
  23. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +9 -9
  24. package/build/plugins/opencode/skills/keiyaku-debt/SKILL.md +91 -0
  25. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +2 -2
  26. package/build/skills/keiyaku/SKILL.md +5 -6
  27. package/build/skills/keiyaku-akuma/SKILL.md +1 -1
  28. package/build/skills/keiyaku-akuma/references/automation.md +8 -8
  29. package/build/skills/keiyaku-babysit/SKILL.md +1 -1
  30. package/build/skills/keiyaku-bind/SKILL.md +9 -9
  31. package/build/skills/keiyaku-debt/SKILL.md +91 -0
  32. package/build/skills/keiyaku-workflow/SKILL.md +2 -2
  33. package/build/src/akuma/akuma-instance.d.ts +2 -0
  34. package/build/src/akuma/akuma-instance.js +10 -0
  35. package/build/src/akuma/akuma-observe.d.ts +33 -8
  36. package/build/src/akuma/akuma-observe.js +88 -64
  37. package/build/src/akuma/akuma-owner.d.ts +11 -2
  38. package/build/src/akuma/akuma-owner.js +45 -35
  39. package/build/src/akuma/akuma-selection-execution.js +9 -1
  40. package/build/src/akuma/akuma-stream.d.ts +22 -0
  41. package/build/src/akuma/akuma-stream.js +116 -0
  42. package/build/src/akuma/akuma-wait.d.ts +1 -40
  43. package/build/src/akuma/akuma-wait.js +23 -84
  44. package/build/src/akuma/akuma.d.ts +17 -11
  45. package/build/src/akuma/akuma.js +2 -0
  46. package/build/src/akuma/allowed.d.ts +7 -12
  47. package/build/src/akuma/allowed.js +13 -4
  48. package/build/src/akuma/body-supervisor.d.ts +5 -5
  49. package/build/src/akuma/body-supervisor.js +22 -20
  50. package/build/src/akuma/body.js +28 -1
  51. package/build/src/akuma/call-request.d.ts +12 -22
  52. package/build/src/akuma/heart/activity-schema.d.ts +12 -0
  53. package/build/src/akuma/heart/activity-schema.js +6 -0
  54. package/build/src/akuma/heart/index.d.ts +59 -2
  55. package/build/src/akuma/heart/index.js +87 -8
  56. package/build/src/akuma/heart/rows.js +5 -3
  57. package/build/src/akuma/heart/soul.d.ts +9 -0
  58. package/build/src/akuma/heart/soul.js +29 -0
  59. package/build/src/akuma/heart/storage.d.ts +15 -0
  60. package/build/src/akuma/heart/storage.js +55 -0
  61. package/build/src/akuma/heart/timeline.d.ts +7 -0
  62. package/build/src/akuma/heart/timeline.js +10 -0
  63. package/build/src/akuma/index.d.ts +1 -0
  64. package/build/src/akuma/projection.d.ts +25 -0
  65. package/build/src/akuma/projection.js +24 -7
  66. package/build/src/akuma/provider-recipe.d.ts +11 -0
  67. package/build/src/akuma/provider-recipe.js +23 -0
  68. package/build/src/akuma/provider.d.ts +25 -0
  69. package/build/src/akuma/provider.js +99 -7
  70. package/build/src/akuma/providers/acp/events.js +25 -2
  71. package/build/src/akuma/providers/claude/events.js +76 -10
  72. package/build/src/akuma/providers/claude/index.js +2 -5
  73. package/build/src/akuma/providers/codex-app-server/events.js +17 -2
  74. package/build/src/akuma/providers/codex-app-server/index.js +15 -9
  75. package/build/src/akuma/providers/decode.d.ts +8 -0
  76. package/build/src/akuma/providers/decode.js +21 -0
  77. package/build/src/akuma/providers/grok-build/index.js +10 -26
  78. package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
  79. package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
  80. package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
  81. package/build/src/akuma/providers/opencode-sdk/events.js +147 -284
  82. package/build/src/akuma/providers/opencode-sdk/index.js +267 -421
  83. package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
  84. package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
  85. package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
  86. package/build/src/akuma/providers/opencode-sdk/session.js +75 -82
  87. package/build/src/akuma/providers/paseo/events.d.ts +8 -0
  88. package/build/src/akuma/providers/paseo/events.js +58 -11
  89. package/build/src/akuma/providers/paseo/index.js +11 -7
  90. package/build/src/akuma/providers/pi/events.d.ts +2 -0
  91. package/build/src/akuma/providers/pi/events.js +32 -24
  92. package/build/src/akuma/providers/pi/index.js +21 -35
  93. package/build/src/akuma/request-lifecycle.d.ts +1 -2
  94. package/build/src/akuma/request-lifecycle.js +2 -8
  95. package/build/src/akuma/request-rendezvous.js +38 -55
  96. package/build/src/akuma/request-serve.d.ts +1 -1
  97. package/build/src/akuma/request-serve.js +77 -113
  98. package/build/src/akuma/selection-observation.d.ts +57 -51
  99. package/build/src/akuma/selection-observation.js +3 -3
  100. package/build/src/akuma/turn-drive.d.ts +3 -0
  101. package/build/src/akuma/turn-drive.js +26 -5
  102. package/build/src/akuma-body.js +12 -22
  103. package/build/src/cli/akuma-caller.js +10 -0
  104. package/build/src/cli/commands/akuma-grammar.js +3 -4
  105. package/build/src/cli/commands/akuma.js +13 -51
  106. package/build/src/cli/commands/contract-grammar.d.ts +7 -6
  107. package/build/src/cli/commands/contract-grammar.js +27 -32
  108. package/build/src/cli/commands/contract-help.d.ts +16 -7
  109. package/build/src/cli/commands/contract-help.js +20 -11
  110. package/build/src/cli/commands/contract.js +11 -11
  111. package/build/src/cli/commands/debt-grammar.d.ts +19 -0
  112. package/build/src/cli/commands/debt-grammar.js +323 -0
  113. package/build/src/cli/commands/debt-query.d.ts +5 -0
  114. package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
  115. package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
  116. package/build/src/cli/commands/{task.js → debt.js} +83 -143
  117. package/build/src/cli/coordinates.d.ts +1 -1
  118. package/build/src/cli/coordinates.js +1 -1
  119. package/build/src/cli/parse.d.ts +4 -4
  120. package/build/src/cli/parse.js +17 -16
  121. package/build/src/cli/render/akuma-activity.d.ts +11 -83
  122. package/build/src/cli/render/akuma-activity.js +20 -382
  123. package/build/src/cli/render/catalog.d.ts +2 -2
  124. package/build/src/cli/render/catalog.js +5 -5
  125. package/build/src/cli/render/contract.js +2 -2
  126. package/build/src/cli/render/debt.d.ts +28 -0
  127. package/build/src/cli/render/{task.js → debt.js} +51 -112
  128. package/build/src/cli/render/kanshi.js +28 -28
  129. package/build/src/cli/render/marks.d.ts +5 -5
  130. package/build/src/cli/render/marks.js +4 -10
  131. package/build/src/cli/render/nuke.js +1 -1
  132. package/build/src/cli/runtime.js +3 -3
  133. package/build/src/cli/scan.d.ts +1 -1
  134. package/build/src/cli/usage.d.ts +1 -1
  135. package/build/src/cli/usage.js +4 -4
  136. package/build/src/contract-worktree.js +3 -3
  137. package/build/src/debt/board.d.ts +160 -0
  138. package/build/src/{task → debt}/board.js +89 -89
  139. package/build/src/debt/catalog.d.ts +11 -0
  140. package/build/src/debt/catalog.js +59 -0
  141. package/build/src/{task → debt}/context.d.ts +1 -1
  142. package/build/src/{task → debt}/context.js +1 -1
  143. package/build/src/{task → debt}/created-observation.d.ts +6 -10
  144. package/build/src/{task → debt}/created-observation.js +7 -7
  145. package/build/src/debt/document.d.ts +37 -0
  146. package/build/src/{task → debt}/document.js +37 -37
  147. package/build/src/debt/identity.d.ts +21 -0
  148. package/build/src/{task → debt}/identity.js +35 -35
  149. package/build/src/debt/index.d.ts +111 -0
  150. package/build/src/debt/index.js +203 -0
  151. package/build/src/{task → debt}/input.d.ts +8 -8
  152. package/build/src/{task → debt}/input.js +21 -21
  153. package/build/src/debt/lifecycle-operations.d.ts +6 -0
  154. package/build/src/{task → debt}/lifecycle-operations.js +27 -31
  155. package/build/src/debt/mutation-result.d.ts +981 -0
  156. package/build/src/debt/mutation-result.js +109 -0
  157. package/build/src/debt/mutation.d.ts +424 -0
  158. package/build/src/debt/mutation.js +223 -0
  159. package/build/src/debt/operation-types.d.ts +71 -0
  160. package/build/src/debt/operations.d.ts +28 -0
  161. package/build/src/{task → debt}/operations.js +59 -60
  162. package/build/src/debt/query.d.ts +76 -0
  163. package/build/src/{task → debt}/query.js +55 -55
  164. package/build/src/{task → debt}/store.d.ts +13 -13
  165. package/build/src/{task → debt}/store.js +58 -49
  166. package/build/src/debt/view.d.ts +4 -0
  167. package/build/src/debt/view.js +7 -0
  168. package/build/src/identity/coordinates.d.ts +1 -1
  169. package/build/src/index.d.ts +13 -13
  170. package/build/src/index.js +9 -9
  171. package/build/src/kanshi/index.d.ts +1 -1
  172. package/build/src/kanshi/read.js +33 -33
  173. package/build/src/kanshi/report.d.ts +7 -7
  174. package/build/src/kanshi/select.js +4 -4
  175. package/build/src/library/akumas.d.ts +2 -3
  176. package/build/src/library/bind.d.ts +3 -3
  177. package/build/src/library/bind.js +5 -5
  178. package/build/src/library/contract-creation.js +5 -5
  179. package/build/src/library/contract-execution.js +4 -4
  180. package/build/src/library/contract-types.d.ts +2 -2
  181. package/build/src/library/input.d.ts +2 -2
  182. package/build/src/library/input.js +5 -5
  183. package/build/src/library/invocation.js +2 -2
  184. package/build/src/library/nuke.js +3 -3
  185. package/build/src/library/outcome.d.ts +126 -126
  186. package/build/src/library/outcome.js +3 -3
  187. package/build/src/library/selection.d.ts +1 -4
  188. package/build/src/library/selection.js +11 -62
  189. package/build/src/plugin/public.d.ts +5 -0
  190. package/build/src/plugin/runtime.js +3 -1
  191. package/build/src/runtime/proc/windows-launch.exe +0 -0
  192. package/build/src/settlement/fence.d.ts +3 -3
  193. package/build/src/settlement/fence.js +4 -4
  194. package/build/src/settlement/holder.d.ts +16 -16
  195. package/build/src/settlement/holder.js +69 -63
  196. package/build/src/settlement/settle.d.ts +5 -5
  197. package/build/src/settlement/settle.js +53 -53
  198. package/package.json +12 -6
  199. package/plugins/paseo/plugin/index.server.ts +17 -0
  200. package/plugins/paseo/plugin/paseo-plugin.json +4 -0
  201. package/plugins/paseo/plugin/server/attach.ts +52 -0
  202. package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
  203. package/plugins/paseo/plugin/server/message.ts +60 -0
  204. package/plugins/paseo/plugin/server/mirror.ts +193 -0
  205. package/plugins/paseo/plugin/server/model.ts +14 -0
  206. package/plugins/paseo/plugin/server/provider.ts +276 -0
  207. package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
  208. package/plugins/paseo/plugin/server/sdk.ts +289 -0
  209. package/plugins/paseo/plugin/server/stop.ts +26 -0
  210. package/plugins/paseo/plugin/server/transport.ts +35 -0
  211. package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
  212. package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
  213. package/plugins/paseo/plugin/tsconfig.json +6 -0
  214. package/skills/keiyaku/SKILL.md +5 -6
  215. package/skills/keiyaku-akuma/SKILL.md +1 -1
  216. package/skills/keiyaku-akuma/references/automation.md +8 -8
  217. package/skills/keiyaku-babysit/SKILL.md +1 -1
  218. package/skills/keiyaku-bind/SKILL.md +9 -9
  219. package/skills/keiyaku-debt/SKILL.md +91 -0
  220. package/skills/keiyaku-workflow/SKILL.md +2 -2
  221. package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
  222. package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
  223. package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
  224. package/build/skills/keiyaku-task/SKILL.md +0 -104
  225. package/build/src/cli/commands/task-grammar.d.ts +0 -19
  226. package/build/src/cli/commands/task-grammar.js +0 -384
  227. package/build/src/cli/commands/task-query.d.ts +0 -5
  228. package/build/src/cli/render/task.d.ts +0 -39
  229. package/build/src/task/board.d.ts +0 -168
  230. package/build/src/task/catalog.d.ts +0 -11
  231. package/build/src/task/catalog.js +0 -59
  232. package/build/src/task/compose-language.d.ts +0 -57
  233. package/build/src/task/compose-language.js +0 -364
  234. package/build/src/task/compose-parser.d.ts +0 -32
  235. package/build/src/task/compose-parser.js +0 -180
  236. package/build/src/task/compose.d.ts +0 -16
  237. package/build/src/task/compose.js +0 -189
  238. package/build/src/task/document.d.ts +0 -39
  239. package/build/src/task/identity.d.ts +0 -21
  240. package/build/src/task/index.d.ts +0 -138
  241. package/build/src/task/index.js +0 -269
  242. package/build/src/task/lifecycle-operations.d.ts +0 -6
  243. package/build/src/task/mutation-result.d.ts +0 -1726
  244. package/build/src/task/mutation-result.js +0 -198
  245. package/build/src/task/mutation.d.ts +0 -590
  246. package/build/src/task/mutation.js +0 -262
  247. package/build/src/task/operation-types.d.ts +0 -71
  248. package/build/src/task/operations.d.ts +0 -28
  249. package/build/src/task/query.d.ts +0 -76
  250. package/build/src/task/view.d.ts +0 -4
  251. package/build/src/task/view.js +0 -7
  252. package/skills/keiyaku-task/SKILL.md +0 -104
  253. /package/build/src/{task → debt}/operation-types.js +0 -0
@@ -1,5 +1,6 @@
1
- import { noteEvent, otherToolCall, unknownEvent } from "../../provider.js";
2
- import { finiteNumber, object, positiveLine, searchToolCall, trimmed } from "../decode.js";
1
+ import { modelEvent, noteEvent, otherToolCall, unknownEvent, } from "../../provider.js";
2
+ import { finiteNumber, object, observedTextContent, positiveLine, searchToolCall, stringValue, trimmed, } from "../decode.js";
3
+ import { diffstatFromUnifiedPatch } from "../unified-patch.js";
3
4
  export const CLAUDE_MESSAGE_DISPOSITIONS = {
4
5
  assistant: "assistant",
5
6
  auth_status: "auth",
@@ -124,16 +125,56 @@ function startedPath(name, value) {
124
125
  function nonnegativeInt(value) {
125
126
  return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
126
127
  }
127
- function fileChange(op, path, gitDiff) {
128
- const diff = object(gitDiff);
128
+ function fileChange(op, path, result) {
129
+ const diff = object(result.gitDiff);
129
130
  const added = nonnegativeInt(diff?.additions);
130
131
  const removed = nonnegativeInt(diff?.deletions);
131
- const diffstat = added === undefined || removed === undefined ? undefined : { added, removed };
132
+ const patch = stringValue(diff?.patch) ?? structuredPatchText(path, result.structuredPatch);
133
+ const diffstat = added === undefined || removed === undefined
134
+ ? patch === undefined
135
+ ? undefined
136
+ : diffstatFromUnifiedPatch(patch)
137
+ : { added, removed };
132
138
  return {
133
139
  kind: "fileChange",
134
- changes: [{ op, path, ...(diffstat === undefined ? {} : { diffstat }) }],
140
+ changes: [
141
+ {
142
+ op,
143
+ path,
144
+ ...(diffstat === undefined ? {} : { diffstat }),
145
+ ...(patch === undefined ? {} : { patch }),
146
+ },
147
+ ],
135
148
  };
136
149
  }
150
+ /**
151
+ * Render the native hunk record as unified diff text when the provider supplied
152
+ * no patch of its own. Every figure comes from that record; nothing is
153
+ * reconstructed from the working tree or from proposed old and new strings.
154
+ */
155
+ function structuredPatchText(path, value) {
156
+ if (!Array.isArray(value) || value.length === 0)
157
+ return undefined;
158
+ const hunks = [];
159
+ for (const entry of value) {
160
+ const hunk = object(entry);
161
+ const oldStart = finiteNumber(hunk?.oldStart);
162
+ const oldLines = finiteNumber(hunk?.oldLines);
163
+ const newStart = finiteNumber(hunk?.newStart);
164
+ const newLines = finiteNumber(hunk?.newLines);
165
+ const lines = hunk?.lines;
166
+ if (oldStart === undefined ||
167
+ oldLines === undefined ||
168
+ newStart === undefined ||
169
+ newLines === undefined ||
170
+ !Array.isArray(lines) ||
171
+ lines.some((line) => typeof line !== "string")) {
172
+ return undefined;
173
+ }
174
+ hunks.push(`@@ -${oldStart},${oldLines} +${newStart},${newLines} @@`, ...lines);
175
+ }
176
+ return [`--- a/${path}`, `+++ b/${path}`, ...hunks].join("\n");
177
+ }
137
178
  function writeResult(result) {
138
179
  const value = object(result);
139
180
  if (value === undefined || (value.type !== "create" && value.type !== "update"))
@@ -141,8 +182,7 @@ function writeResult(result) {
141
182
  const path = trimmed(value.filePath);
142
183
  if (path === undefined)
143
184
  return undefined;
144
- const op = value.type === "create" ? "add" : "update";
145
- return fileChange(op, path, value.gitDiff);
185
+ return fileChange(value.type === "create" ? "add" : "update", path, value);
146
186
  }
147
187
  function editResult(result) {
148
188
  const value = object(result);
@@ -152,7 +192,7 @@ function editResult(result) {
152
192
  if (path === undefined)
153
193
  return undefined;
154
194
  const status = object(value.gitDiff)?.status;
155
- return fileChange(status === "added" ? "add" : "update", path, value.gitDiff);
195
+ return fileChange(status === "added" ? "add" : "update", path, value);
156
196
  }
157
197
  function notebookResult(result) {
158
198
  const path = trimmed(object(result)?.notebook_path);
@@ -174,6 +214,11 @@ function toolCall(name, input) {
174
214
  return (readCall(name, path, value) ?? searchCall(name, value) ?? fileChangeCall(name, path) ?? otherToolCall(name, input));
175
215
  }
176
216
  function assistantEvents(message, events, state) {
217
+ // Every complete response names the model that produced it; the native model
218
+ // identity is reported as-is.
219
+ const model = trimmed(object(message.message)?.model);
220
+ if (model !== undefined)
221
+ events.emit(modelEvent(model));
177
222
  if (message.aborted === true)
178
223
  return;
179
224
  if (message.error !== undefined) {
@@ -216,13 +261,17 @@ function toolResultEvents(message, events, state) {
216
261
  state.tools.delete(id);
217
262
  const failed = value.is_error === true;
218
263
  const structured = failed ? undefined : structuredFileChange(observed.name, message.tool_use_result);
264
+ const output = observedTextContent(value.content);
219
265
  events.emit({
220
266
  type: "tool",
221
267
  phase: "completed",
222
268
  id,
223
269
  name: observed.name,
224
270
  call: structured ?? observed.call,
225
- result: { status: failed ? "error" : "ok" },
271
+ result: {
272
+ status: failed ? "error" : "ok",
273
+ ...(output === undefined ? {} : { output }),
274
+ },
226
275
  });
227
276
  }
228
277
  }
@@ -234,12 +283,29 @@ function hookResponseNote(value) {
234
283
  const exitCode = finiteNumber(value.exit_code);
235
284
  return `Hook ${hook} ${outcome}${exitCode === undefined ? "" : ` (exit ${exitCode})`}`;
236
285
  }
286
+ /**
287
+ * Native system notices that prove which model the session is actually using.
288
+ * `init` reports the startup selection. A refusal fallback reports the model
289
+ * that serves the retried request; only a session-scoped fallback swaps the
290
+ * session model, and `local` leaves it unchanged. The two no-longer-emitted
291
+ * directions stay in the native enum and are never treated as evidence.
292
+ */
293
+ function systemModelEvidence(subtype, value) {
294
+ if (subtype === "init")
295
+ return trimmed(value.model);
296
+ if (subtype !== "model_refusal_fallback" || value.scope === "local")
297
+ return undefined;
298
+ return value.direction === "revert" || value.direction === "sticky" ? undefined : trimmed(value.fallback_model);
299
+ }
237
300
  function emitSystemMessage(value, events) {
238
301
  const subtype = trimmed(value?.subtype) ?? "unknown";
239
302
  if (!Object.hasOwn(CLAUDE_SYSTEM_DISPOSITIONS, subtype)) {
240
303
  events.emit(unknownEvent(subtype));
241
304
  return;
242
305
  }
306
+ const evidence = systemModelEvidence(subtype, value);
307
+ if (evidence !== undefined)
308
+ events.emit(modelEvent(evidence));
243
309
  const systemDisposition = CLAUDE_SYSTEM_DISPOSITIONS[subtype];
244
310
  if (systemDisposition === "drop")
245
311
  return;
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { abortable } from "../../abort.js";
3
- import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
3
+ import { AgentEventChannel, createProviderAttempt, launchPrompt, } from "../../provider.js";
4
4
  import { akumaExecutionEnvironment } from "../execution-environment.js";
5
5
  import { providerLifecycle } from "../lifecycle.js";
6
6
  import { emitClaudeMessage } from "./events.js";
@@ -98,9 +98,6 @@ async function forkClaude(load, execution, input) {
98
98
  throw new Error("Claude fork reused the source session id");
99
99
  return { session: { sessionId: forked.sessionId } };
100
100
  }
101
- function launchText(input) {
102
- return [input.body, ...input.launchTells.map((tell) => tell.text)].filter((part) => part.length > 0).join("\n\n");
103
- }
104
101
  function successfulResult(message, historyId) {
105
102
  return {
106
103
  kind: "answered",
@@ -292,7 +289,7 @@ async function driveClaude(load, execution, drive, custody) {
292
289
  const run = randomUUID();
293
290
  const accepted = [];
294
291
  const driveState = { submission: 0, openSubmissions: 0 };
295
- const launchAcknowledged = input.push(claudeUserMessage(launchText(drive)));
292
+ const launchAcknowledged = input.push(claudeUserMessage(launchPrompt(drive.body, drive.launchTells)));
296
293
  const query = sdk.query({
297
294
  prompt: input.iterable,
298
295
  options: claudeQueryOptions(drive, execution, abortController),
@@ -1,4 +1,5 @@
1
- import { noteEvent, unknownEvent, } from "../../provider.js";
1
+ import { modelEvent, noteEvent, unknownEvent, } from "../../provider.js";
2
+ import { stringValue } from "../decode.js";
2
3
  import { diffstatFromUnifiedPatch } from "../unified-patch.js";
3
4
  export const CODEX_NOTIFICATION_DISPOSITIONS = {
4
5
  "account/login/completed": "drop",
@@ -148,12 +149,14 @@ function itemChanges(item) {
148
149
  const op = fileChangeOp(change?.kind);
149
150
  if (path === undefined || op === undefined)
150
151
  return [];
151
- const diffstat = typeof change?.diff === "string" ? diffstatFromUnifiedPatch(change.diff) : undefined;
152
+ const patch = stringValue(change?.diff);
153
+ const diffstat = patch === undefined ? undefined : diffstatFromUnifiedPatch(patch);
152
154
  return [
153
155
  {
154
156
  op,
155
157
  path,
156
158
  ...(diffstat === undefined ? {} : { diffstat }),
159
+ ...(patch === undefined ? {} : { patch }),
157
160
  },
158
161
  ];
159
162
  });
@@ -195,10 +198,12 @@ function itemToolResult(item) {
195
198
  const status = codexText(item.status);
196
199
  const failed = error !== undefined || status === "failed" || status === "error";
197
200
  const detail = codexText(error?.message) ?? codexText(error?.additionalDetails);
201
+ const output = stringValue(item.aggregatedOutput);
198
202
  const exitCode = typeof item.exitCode === "number" && Number.isSafeInteger(item.exitCode) ? item.exitCode : undefined;
199
203
  return {
200
204
  status: failed || (exitCode !== undefined && exitCode !== 0) ? "error" : "ok",
201
205
  ...(detail === undefined ? {} : { message: detail }),
206
+ ...(output === undefined ? {} : { output }),
202
207
  ...(exitCode === undefined ? {} : { exitCode }),
203
208
  };
204
209
  }
@@ -318,6 +323,13 @@ function hookCompletionNote(params) {
318
323
  const diagnostic = codexText(run?.statusMessage) ?? codexText(issue?.text);
319
324
  return `Hook ${eventName} ${label}${diagnostic === undefined ? "" : `: ${diagnostic}`}`;
320
325
  }
326
+ /**
327
+ * A reroute names the model that now serves this thread, so it is runtime-model
328
+ * evidence as well as narration. Other notifications carry no model identity.
329
+ */
330
+ function notificationModel(method, params) {
331
+ return method === "model/rerouted" ? codexText(params.toModel) : undefined;
332
+ }
321
333
  function observeError(params, state, events) {
322
334
  const detail = turnError(params.error) ?? codexText(params.message) ?? "codex app-server error";
323
335
  state.error = detail;
@@ -348,6 +360,9 @@ export function codexNotificationResult(notification, state, events) {
348
360
  return undefined;
349
361
  }
350
362
  const disposition = CODEX_NOTIFICATION_DISPOSITIONS[method];
363
+ const rerouted = notificationModel(method, params);
364
+ if (rerouted !== undefined)
365
+ events.emit(modelEvent(rerouted));
351
366
  switch (disposition) {
352
367
  case "drop":
353
368
  return undefined;
@@ -1,5 +1,5 @@
1
1
  import { LineRpcProcess } from "../../../runtime/proc/line-rpc.js";
2
- import { AgentEventChannel, createProviderAttempt, } from "../../provider.js";
2
+ import { AgentEventChannel, createProviderAttempt, launchPrompt, modelEvent, } from "../../provider.js";
3
3
  import { akumaExecutionEnvironment } from "../execution-environment.js";
4
4
  import { providerLifecycle } from "../lifecycle.js";
5
5
  import { codexNotificationResult, codexObject, codexText } from "./events.js";
@@ -30,6 +30,12 @@ function turnId(result) {
30
30
  throw new Error("codex app-server did not return a turn id");
31
31
  return id;
32
32
  }
33
+ /** Thread admission answers with the model the server actually loaded. */
34
+ function emitAdmittedModel(result, events) {
35
+ const model = codexText(codexObject(result)?.model);
36
+ if (model !== undefined)
37
+ events.emit(modelEvent(model));
38
+ }
33
39
  async function steerTurn(server, state, tell) {
34
40
  if (state.settled)
35
41
  return { kind: "turn-ended" };
@@ -62,13 +68,15 @@ async function admitTurn(server, input, state, events, config) {
62
68
  : { developerInstructions: input.options.systemPrompt }),
63
69
  };
64
70
  if (input.session.kind === "fresh") {
65
- state.threadId = threadId(await server.request("thread/start", threadParams));
71
+ const admitted = await server.request("thread/start", threadParams);
72
+ state.threadId = threadId(admitted);
73
+ emitAdmittedModel(admitted, events);
66
74
  }
67
75
  else {
68
- state.threadId = threadId(await server.request("thread/resume", {
69
- threadId: input.session.coordinate.sessionId,
70
- ...threadParams,
71
- }), input.session.coordinate.sessionId);
76
+ const resumed = input.session.coordinate.sessionId;
77
+ const admitted = await server.request("thread/resume", { threadId: resumed, ...threadParams });
78
+ state.threadId = threadId(admitted, resumed);
79
+ emitAdmittedModel(admitted, events);
72
80
  }
73
81
  events.emit({ type: "session", coordinate: { sessionId: state.threadId } });
74
82
  state.turnId = turnId(await server.request("turn/start", {
@@ -76,9 +84,7 @@ async function admitTurn(server, input, state, events, config) {
76
84
  input: [
77
85
  {
78
86
  type: "text",
79
- text: [input.body, ...input.launchTells.map((tell) => tell.text)]
80
- .filter((part) => part.length > 0)
81
- .join("\n\n"),
87
+ text: launchPrompt(input.body, input.launchTells),
82
88
  },
83
89
  ],
84
90
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
@@ -12,6 +12,14 @@ export declare function nonblank(value: unknown): string | undefined;
12
12
  export declare function trimmed(value: unknown): string | undefined;
13
13
  /** A nonempty string, returned as supplied; internal whitespace stays content. */
14
14
  export declare function text(value: unknown): string | undefined;
15
+ /** Any string, including the empty one; absence stays absence. */
16
+ export declare function stringValue(value: unknown): string | undefined;
17
+ /**
18
+ * The observed text of one native result value: a plain string, or its text
19
+ * blocks joined in native order. A value carrying no text block observed no
20
+ * text, while a present empty string is observed and empty.
21
+ */
22
+ export declare function observedTextContent(content: unknown): string | undefined;
15
23
  /** A one-based line number. */
16
24
  export declare function positiveLine(value: unknown): number | undefined;
17
25
  export declare function nonnegativeCount(value: unknown): number | undefined;
@@ -22,6 +22,27 @@ export function trimmed(value) {
22
22
  export function text(value) {
23
23
  return typeof value === "string" && value.length > 0 ? value : undefined;
24
24
  }
25
+ /** Any string, including the empty one; absence stays absence. */
26
+ export function stringValue(value) {
27
+ return typeof value === "string" ? value : undefined;
28
+ }
29
+ /**
30
+ * The observed text of one native result value: a plain string, or its text
31
+ * blocks joined in native order. A value carrying no text block observed no
32
+ * text, while a present empty string is observed and empty.
33
+ */
34
+ export function observedTextContent(content) {
35
+ const single = stringValue(content);
36
+ if (single !== undefined)
37
+ return single;
38
+ if (!Array.isArray(content))
39
+ return undefined;
40
+ const blocks = content.flatMap((block) => {
41
+ const value = object(block);
42
+ return value?.type === "text" && typeof value.text === "string" ? [value.text] : [];
43
+ });
44
+ return blocks.length === 0 ? undefined : blocks.join("");
45
+ }
25
46
  /** A one-based line number. */
26
47
  export function positiveLine(value) {
27
48
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
@@ -1,3 +1,4 @@
1
+ import { tellRegistry } from "../../provider.js";
1
2
  import { nonblank, object, searchToolCall } from "../decode.js";
2
3
  import { providerLifecycle } from "../lifecycle.js";
3
4
  import { startAcpSession, } from "../acp/core.js";
@@ -94,18 +95,13 @@ function argv(execution, options) {
94
95
  values.push("stdio");
95
96
  return values;
96
97
  }
97
- function withInterject(live, pending) {
98
+ function withInterject(live, tells) {
98
99
  return {
99
100
  ...live.session,
100
101
  tell: (tell) => {
101
102
  if (!live.open())
102
103
  return Promise.resolve({ kind: "turn-ended" });
103
- const existing = pending.get(tell.id);
104
- if (existing !== undefined)
105
- throw new Error("Grok Build duplicate pending interjection id");
106
- const receipt = new Promise((resolve, reject) => {
107
- pending.set(tell.id, { resolve, reject });
108
- });
104
+ const receipt = tells.register(tell.id, tell.id);
109
105
  void live.agent
110
106
  .request(INTERJECT_METHOD, {
111
107
  sessionId: live.sessionId,
@@ -113,14 +109,10 @@ function withInterject(live, pending) {
113
109
  interjectionId: tell.id,
114
110
  })
115
111
  .then((response) => {
116
- if (response?.status !== "queued" && pending.has(tell.id)) {
117
- pending.get(tell.id)?.reject(new Error("Grok Build interject did not return queued"));
118
- pending.delete(tell.id);
112
+ if (response?.status !== "queued") {
113
+ tells.fail(tell.id, new Error("Grok Build interject did not return queued"));
119
114
  }
120
- }, (error) => {
121
- pending.get(tell.id)?.reject(error);
122
- pending.delete(tell.id);
123
- });
115
+ }, (error) => tells.fail(tell.id, error));
124
116
  return receipt;
125
117
  },
126
118
  };
@@ -129,7 +121,7 @@ export function createGrokBuildProvider(execution, dependencies = {}) {
129
121
  if (execution.executable === undefined)
130
122
  throw new TypeError("Grok Build provider execution requires executable");
131
123
  const drive = async (input, custody) => {
132
- const pending = new Map();
124
+ const tells = tellRegistry();
133
125
  let live;
134
126
  const launch = {
135
127
  argv: argv(execution, input.options),
@@ -142,23 +134,15 @@ export function createGrokBuildProvider(execution, dependencies = {}) {
142
134
  client.onNotification(INTERJECTION_METHOD, (value) => value, ({ params }) => {
143
135
  if (params.sessionId !== live?.sessionId)
144
136
  return;
145
- const waiter = pending.get(params.interjectionId);
146
- if (waiter === undefined)
147
- return;
148
- pending.delete(params.interjectionId);
149
- waiter.resolve({ kind: "accepted", fence: params.interjectionId });
137
+ tells.accept(params.interjectionId);
150
138
  });
151
139
  },
152
- onTerminal: () => {
153
- for (const waiter of pending.values())
154
- waiter.resolve({ kind: "turn-ended" });
155
- pending.clear();
156
- },
140
+ onTerminal: () => tells.end(),
157
141
  interpretTool: interpretGrokTool,
158
142
  freshSessionMeta: { ...(dependencies.freshSessionMeta ?? {}), ...(sessionMeta.freshSessionMeta ?? {}) },
159
143
  loadSessionMeta: { ...(dependencies.loadSessionMeta ?? {}), ...(sessionMeta.loadSessionMeta ?? {}) },
160
144
  }, custody);
161
- return withInterject(live, pending);
145
+ return withInterject(live, tells);
162
146
  };
163
147
  return {
164
148
  admitOptions: optionAdmission,
@@ -2,8 +2,8 @@ import type { AttemptCustody } from "../../provider.js";
2
2
  import type { OpencodeEventSubscriptionRequest } from "./session.js";
3
3
  /**
4
4
  * One adapter-private owner for every resource an OpenCode event subscription
5
- * creates: the native subscription, its fetch and reader, the pending read, and
6
- * the SDK's retry waiting. `closed` resolves only after those resources really
5
+ * creates: the native subscription, its fetch and reader, and the pending read.
6
+ * `closed` resolves only after those resources really
7
7
  * retired; a teardown rejection escapes through it, and an unprovable
8
8
  * retirement leaves it pending so existing custody reports the attempt hung.
9
9
  */
@@ -14,7 +14,7 @@ export type OwnedEventStream = Readonly<{
14
14
  next(): Promise<IteratorResult<unknown>>;
15
15
  /** Aborts the owned signal, settles any pending read, then awaits real iterator retirement. */
16
16
  retire(): Promise<void>;
17
- /** Resolves only when subscription, reader, and retry waiting actually ended. */
17
+ /** Resolves only when subscription and reader actually ended. */
18
18
  closed: Promise<void>;
19
19
  }>;
20
20
  export declare function ownEventStream(input: Readonly<{
@@ -1,25 +1,3 @@
1
- /**
2
- * A backoff sleep that resolves when the owned signal aborts and always clears
3
- * its timer. Cancellation before the sleep starts completes immediately, and a
4
- * simultaneous timeout and abort still settles once and drops the listener.
5
- */
6
- function cancellableSleep(signal) {
7
- return (milliseconds) => new Promise((resolve) => {
8
- if (signal.aborted) {
9
- resolve();
10
- return;
11
- }
12
- let timer;
13
- const finish = () => {
14
- if (timer !== undefined)
15
- clearTimeout(timer);
16
- signal.removeEventListener("abort", finish);
17
- resolve();
18
- };
19
- timer = setTimeout(finish, milliseconds);
20
- signal.addEventListener("abort", finish, { once: true });
21
- });
22
- }
23
1
  export function ownEventStream(input) {
24
2
  const controller = new AbortController();
25
3
  const follow = () => {
@@ -49,8 +27,8 @@ export function ownEventStream(input) {
49
27
  if (settling !== undefined)
50
28
  return settling;
51
29
  settling = (async () => {
52
- // Abort first: it interrupts the SDK's fetch, reader, and backoff and
53
- // settles a pending read, before iterator return can be waited on.
30
+ // Abort first: it interrupts the SDK's fetch and reader and settles a
31
+ // pending read before iterator return can be waited on.
54
32
  if (!controller.signal.aborted)
55
33
  controller.abort(new Error("OpenCode event stream retired"));
56
34
  input.signal.removeEventListener("abort", follow);
@@ -72,7 +50,6 @@ export function ownEventStream(input) {
72
50
  const subscription = await input.subscribe({
73
51
  directory: input.directory,
74
52
  signal: controller.signal,
75
- sleep: cancellableSleep(controller.signal),
76
53
  });
77
54
  iterator = subscription.stream[Symbol.asyncIterator]();
78
55
  })();
@@ -2,52 +2,16 @@ import { type AgentEvent, type ToolCall } from "../../provider.js";
2
2
  type Emitter = {
3
3
  emit(event: AgentEvent): void;
4
4
  };
5
- type ObservedTool = Readonly<{
6
- name: string;
7
- call: ToolCall;
8
- }>;
9
5
  type State = {
10
6
  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": "note";
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";
7
+ tools: Map<string, {
8
+ name: string;
9
+ call?: ToolCall;
10
+ }>;
11
+ completed: Set<string>;
50
12
  };
13
+ export declare function diagnostic(value: unknown): string;
14
+ /** Only complete native values enter narration. The caller enforces submission/step correlation. */
51
15
  export declare function mapEvent(value: unknown, events: Emitter, state: State): void;
52
16
  export declare function createEventState(sessionId?: string): State;
53
17
  export {};