@astrosheep/keiyaku 4.6.7 → 4.6.9

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 (336) hide show
  1. package/README.md +46 -16
  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/plugins/pi/keiyaku.ts +0 -5
  27. package/build/skills/keiyaku/SKILL.md +5 -6
  28. package/build/skills/keiyaku-akuma/SKILL.md +1 -1
  29. package/build/skills/keiyaku-akuma/references/automation.md +8 -8
  30. package/build/skills/keiyaku-babysit/SKILL.md +1 -1
  31. package/build/skills/keiyaku-bind/SKILL.md +9 -9
  32. package/build/skills/keiyaku-debt/SKILL.md +91 -0
  33. package/build/skills/keiyaku-workflow/SKILL.md +2 -2
  34. package/build/src/akuma/akuma-call.d.ts +2 -0
  35. package/build/src/akuma/akuma-call.js +8 -2
  36. package/build/src/akuma/akuma-instance.d.ts +14 -1
  37. package/build/src/akuma/akuma-instance.js +37 -7
  38. package/build/src/akuma/akuma-observe.d.ts +33 -8
  39. package/build/src/akuma/akuma-observe.js +89 -63
  40. package/build/src/akuma/akuma-owner.d.ts +14 -2
  41. package/build/src/akuma/akuma-owner.js +49 -35
  42. package/build/src/akuma/akuma-selection-execution.js +9 -1
  43. package/build/src/akuma/akuma-stream.d.ts +22 -0
  44. package/build/src/akuma/akuma-stream.js +116 -0
  45. package/build/src/akuma/akuma-wait.d.ts +1 -40
  46. package/build/src/akuma/akuma-wait.js +23 -84
  47. package/build/src/akuma/akuma.d.ts +52 -16
  48. package/build/src/akuma/akuma.js +10 -10
  49. package/build/src/akuma/allowed.d.ts +7 -12
  50. package/build/src/akuma/allowed.js +13 -4
  51. package/build/src/akuma/archetype.d.ts +7 -15
  52. package/build/src/akuma/archetype.js +36 -35
  53. package/build/src/akuma/body-supervisor.d.ts +5 -5
  54. package/build/src/akuma/body-supervisor.js +22 -20
  55. package/build/src/akuma/body.d.ts +5 -3
  56. package/build/src/akuma/body.js +57 -8
  57. package/build/src/akuma/call-request.d.ts +30 -32
  58. package/build/src/akuma/call-request.js +10 -3
  59. package/build/src/akuma/caller.d.ts +39 -0
  60. package/build/src/akuma/caller.js +36 -0
  61. package/build/src/akuma/dispatch-association.d.ts +0 -1
  62. package/build/src/akuma/dispatch-association.js +0 -3
  63. package/build/src/akuma/heart/activity-schema.d.ts +12 -0
  64. package/build/src/akuma/heart/activity-schema.js +6 -0
  65. package/build/src/akuma/heart/facts.d.ts +16 -12
  66. package/build/src/akuma/heart/facts.js +8 -0
  67. package/build/src/akuma/heart/index.d.ts +61 -9
  68. package/build/src/akuma/heart/index.js +89 -24
  69. package/build/src/akuma/heart/rows.d.ts +3 -3
  70. package/build/src/akuma/heart/rows.js +5 -3
  71. package/build/src/akuma/heart/soul.d.ts +10 -1
  72. package/build/src/akuma/heart/soul.js +34 -24
  73. package/build/src/akuma/heart/storage.d.ts +20 -0
  74. package/build/src/akuma/heart/storage.js +62 -3
  75. package/build/src/akuma/heart/timeline.d.ts +7 -0
  76. package/build/src/akuma/heart/timeline.js +10 -0
  77. package/build/src/akuma/identity.d.ts +0 -1
  78. package/build/src/akuma/identity.js +2 -5
  79. package/build/src/akuma/index.d.ts +6 -2
  80. package/build/src/akuma/index.js +1 -0
  81. package/build/src/akuma/nuke.js +6 -28
  82. package/build/src/akuma/projection.d.ts +25 -11
  83. package/build/src/akuma/projection.js +24 -7
  84. package/build/src/akuma/provider-recipe.d.ts +18 -6
  85. package/build/src/akuma/provider-recipe.js +24 -1
  86. package/build/src/akuma/provider.d.ts +31 -10
  87. package/build/src/akuma/provider.js +105 -14
  88. package/build/src/akuma/providers/acp/events.js +29 -19
  89. package/build/src/akuma/providers/acp/index.js +2 -3
  90. package/build/src/akuma/providers/claude/events.js +110 -69
  91. package/build/src/akuma/providers/claude/index.d.ts +2 -2
  92. package/build/src/akuma/providers/claude/index.js +4 -8
  93. package/build/src/akuma/providers/codex-app-server/events.js +17 -2
  94. package/build/src/akuma/providers/codex-app-server/index.js +17 -11
  95. package/build/src/akuma/providers/decode.d.ts +33 -0
  96. package/build/src/akuma/providers/decode.js +65 -0
  97. package/build/src/akuma/providers/execution-environment.d.ts +2 -1
  98. package/build/src/akuma/providers/execution-environment.js +3 -0
  99. package/build/src/akuma/providers/grok-build/index.js +16 -48
  100. package/build/src/akuma/providers/index.js +2 -0
  101. package/build/src/akuma/providers/lifecycle.d.ts +9 -0
  102. package/build/src/akuma/providers/lifecycle.js +10 -0
  103. package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
  104. package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
  105. package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
  106. package/build/src/akuma/providers/opencode-sdk/events.js +146 -296
  107. package/build/src/akuma/providers/opencode-sdk/index.js +270 -431
  108. package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
  109. package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
  110. package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
  111. package/build/src/akuma/providers/opencode-sdk/session.js +75 -84
  112. package/build/src/akuma/providers/paseo/events.d.ts +33 -0
  113. package/build/src/akuma/providers/paseo/events.js +204 -0
  114. package/build/src/akuma/providers/paseo/index.d.ts +9 -0
  115. package/build/src/akuma/providers/paseo/index.js +357 -0
  116. package/build/src/akuma/providers/pi/events.d.ts +2 -0
  117. package/build/src/akuma/providers/pi/events.js +36 -38
  118. package/build/src/akuma/providers/pi/index.js +21 -35
  119. package/build/src/akuma/publication.d.ts +2 -0
  120. package/build/src/akuma/publication.js +5 -0
  121. package/build/src/akuma/request-lifecycle.d.ts +4 -2
  122. package/build/src/akuma/request-lifecycle.js +27 -12
  123. package/build/src/akuma/request-rendezvous.js +38 -55
  124. package/build/src/akuma/request-serve.d.ts +1 -1
  125. package/build/src/akuma/request-serve.js +77 -113
  126. package/build/src/akuma/requests.d.ts +3 -1
  127. package/build/src/akuma/requests.js +32 -0
  128. package/build/src/akuma/selection-observation.d.ts +129 -53
  129. package/build/src/akuma/selection-observation.js +3 -9
  130. package/build/src/akuma/turn-drive.d.ts +3 -0
  131. package/build/src/akuma/turn-drive.js +28 -10
  132. package/build/src/akuma-body.js +12 -22
  133. package/build/src/cli/akuma-caller.d.ts +3 -0
  134. package/build/src/cli/akuma-caller.js +31 -0
  135. package/build/src/cli/commands/akuma-grammar.js +10 -16
  136. package/build/src/cli/commands/akuma.js +25 -55
  137. package/build/src/cli/commands/contract-grammar.d.ts +9 -7
  138. package/build/src/cli/commands/contract-grammar.js +40 -47
  139. package/build/src/cli/commands/contract-help.d.ts +17 -7
  140. package/build/src/cli/commands/contract-help.js +50 -11
  141. package/build/src/cli/commands/contract.js +34 -63
  142. package/build/src/cli/commands/debt-grammar.d.ts +19 -0
  143. package/build/src/cli/commands/debt-grammar.js +323 -0
  144. package/build/src/cli/commands/debt-query.d.ts +5 -0
  145. package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
  146. package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
  147. package/build/src/cli/commands/{task.js → debt.js} +87 -164
  148. package/build/src/cli/coordinates.d.ts +1 -1
  149. package/build/src/cli/coordinates.js +1 -1
  150. package/build/src/cli/parse.d.ts +5 -5
  151. package/build/src/cli/parse.js +17 -16
  152. package/build/src/cli/render/akuma-activity.d.ts +11 -83
  153. package/build/src/cli/render/akuma-activity.js +20 -382
  154. package/build/src/cli/render/catalog.d.ts +4 -7
  155. package/build/src/cli/render/catalog.js +5 -5
  156. package/build/src/cli/render/contract-history.js +3 -6
  157. package/build/src/cli/render/contract.js +17 -52
  158. package/build/src/cli/render/debt.d.ts +28 -0
  159. package/build/src/cli/render/{task.js → debt.js} +55 -133
  160. package/build/src/cli/render/kanshi.js +28 -28
  161. package/build/src/cli/render/marks.d.ts +5 -5
  162. package/build/src/cli/render/marks.js +4 -10
  163. package/build/src/cli/render/nuke.js +1 -1
  164. package/build/src/cli/render/receipt.js +3 -10
  165. package/build/src/cli/runtime.d.ts +1 -1
  166. package/build/src/cli/runtime.js +14 -20
  167. package/build/src/cli/scan.d.ts +1 -1
  168. package/build/src/cli/selectors.d.ts +3 -6
  169. package/build/src/cli/selectors.js +22 -53
  170. package/build/src/cli/usage.d.ts +1 -1
  171. package/build/src/cli/usage.js +4 -4
  172. package/build/src/contract-worktree.js +3 -3
  173. package/build/src/debt/board.d.ts +160 -0
  174. package/build/src/{task → debt}/board.js +89 -89
  175. package/build/src/debt/catalog.d.ts +11 -0
  176. package/build/src/debt/catalog.js +59 -0
  177. package/build/src/{task → debt}/context.d.ts +1 -1
  178. package/build/src/{task → debt}/context.js +1 -1
  179. package/build/src/{task → debt}/created-observation.d.ts +6 -10
  180. package/build/src/{task → debt}/created-observation.js +7 -7
  181. package/build/src/debt/document.d.ts +37 -0
  182. package/build/src/{task → debt}/document.js +37 -37
  183. package/build/src/debt/identity.d.ts +21 -0
  184. package/build/src/{task → debt}/identity.js +35 -35
  185. package/build/src/debt/index.d.ts +111 -0
  186. package/build/src/debt/index.js +203 -0
  187. package/build/src/{task → debt}/input.d.ts +8 -8
  188. package/build/src/{task → debt}/input.js +21 -21
  189. package/build/src/debt/lifecycle-operations.d.ts +6 -0
  190. package/build/src/{task → debt}/lifecycle-operations.js +27 -31
  191. package/build/src/debt/mutation-result.d.ts +981 -0
  192. package/build/src/debt/mutation-result.js +109 -0
  193. package/build/src/debt/mutation.d.ts +424 -0
  194. package/build/src/debt/mutation.js +223 -0
  195. package/build/src/debt/operation-types.d.ts +71 -0
  196. package/build/src/debt/operations.d.ts +28 -0
  197. package/build/src/{task → debt}/operations.js +59 -60
  198. package/build/src/debt/query.d.ts +76 -0
  199. package/build/src/{task → debt}/query.js +55 -55
  200. package/build/src/{task → debt}/store.d.ts +13 -13
  201. package/build/src/{task → debt}/store.js +58 -49
  202. package/build/src/debt/view.d.ts +4 -0
  203. package/build/src/debt/view.js +7 -0
  204. package/build/src/dispatch/index.d.ts +3 -3
  205. package/build/src/dispatch/index.js +1 -2
  206. package/build/src/git/observe.d.ts +6 -2
  207. package/build/src/git/observe.js +6 -2
  208. package/build/src/identity/coordinates.d.ts +1 -1
  209. package/build/src/index.d.ts +17 -17
  210. package/build/src/index.js +11 -11
  211. package/build/src/kanshi/index.d.ts +2 -2
  212. package/build/src/kanshi/read.js +54 -39
  213. package/build/src/kanshi/report.d.ts +7 -7
  214. package/build/src/kanshi/select.js +4 -4
  215. package/build/src/library/address.js +2 -4
  216. package/build/src/library/akuma-creation.d.ts +5 -1
  217. package/build/src/library/akuma-creation.js +27 -47
  218. package/build/src/library/akumas.d.ts +7 -7
  219. package/build/src/library/akumas.js +13 -9
  220. package/build/src/library/bind.d.ts +17 -17
  221. package/build/src/library/bind.js +16 -12
  222. package/build/src/library/contract-address.d.ts +9 -0
  223. package/build/src/library/contract-address.js +71 -0
  224. package/build/src/library/contract-composition.d.ts +4 -7
  225. package/build/src/library/contract-composition.js +6 -18
  226. package/build/src/library/contract-creation.d.ts +3 -5
  227. package/build/src/library/contract-creation.js +24 -22
  228. package/build/src/library/contract-execution.js +21 -26
  229. package/build/src/library/contract-outcomes.d.ts +2 -14
  230. package/build/src/library/contract-outcomes.js +2 -13
  231. package/build/src/library/contract-types.d.ts +38 -4
  232. package/build/src/library/delivery.d.ts +0 -2
  233. package/build/src/library/delivery.js +2 -5
  234. package/build/src/library/input.d.ts +2 -2
  235. package/build/src/library/input.js +5 -5
  236. package/build/src/library/invocation.js +2 -2
  237. package/build/src/library/keiyaku.d.ts +0 -5
  238. package/build/src/library/keiyaku.js +6 -12
  239. package/build/src/library/nuke.js +3 -3
  240. package/build/src/library/outcome.d.ts +626 -625
  241. package/build/src/library/outcome.js +13 -3
  242. package/build/src/library/reconcile.js +8 -16
  243. package/build/src/library/refusal.d.ts +2 -2
  244. package/build/src/library/repo.d.ts +3 -2
  245. package/build/src/library/repo.js +10 -5
  246. package/build/src/library/selection.d.ts +5 -8
  247. package/build/src/library/selection.js +22 -73
  248. package/build/src/plugin/akuma-signals.d.ts +2 -0
  249. package/build/src/plugin/akuma-signals.js +4 -0
  250. package/build/src/plugin/public.d.ts +32 -2
  251. package/build/src/plugin/runtime.js +5 -3
  252. package/build/src/protocol/amend.js +3 -2
  253. package/build/src/protocol/attempt.js +3 -8
  254. package/build/src/protocol/bind.d.ts +2 -2
  255. package/build/src/protocol/bind.js +1 -1
  256. package/build/src/protocol/deliver.js +3 -3
  257. package/build/src/protocol/operations.d.ts +1 -3
  258. package/build/src/protocol/operations.js +0 -8
  259. package/build/src/protocol/outcome.d.ts +1 -2
  260. package/build/src/protocol/outcome.js +1 -13
  261. package/build/src/protocol/placement.js +3 -10
  262. package/build/src/protocol/read/status.js +31 -70
  263. package/build/src/protocol/reintegrate.js +3 -10
  264. package/build/src/protocol/review.js +3 -3
  265. package/build/src/protocol/run.d.ts +5 -1
  266. package/build/src/protocol/run.js +3 -3
  267. package/build/src/runtime/proc/windows-launch.exe +0 -0
  268. package/build/src/settlement/fence.d.ts +3 -3
  269. package/build/src/settlement/fence.js +4 -4
  270. package/build/src/settlement/holder.d.ts +16 -16
  271. package/build/src/settlement/holder.js +69 -63
  272. package/build/src/settlement/settle.d.ts +5 -5
  273. package/build/src/settlement/settle.js +53 -53
  274. package/package.json +19 -9
  275. package/plugins/paseo/plugin/index.server.ts +17 -0
  276. package/plugins/paseo/plugin/paseo-plugin.json +4 -0
  277. package/plugins/paseo/plugin/server/attach.ts +52 -0
  278. package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
  279. package/plugins/paseo/plugin/server/message.ts +60 -0
  280. package/plugins/paseo/plugin/server/mirror.ts +193 -0
  281. package/plugins/paseo/plugin/server/model.ts +14 -0
  282. package/plugins/paseo/plugin/server/provider.ts +276 -0
  283. package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
  284. package/plugins/paseo/plugin/server/sdk.ts +289 -0
  285. package/plugins/paseo/plugin/server/stop.ts +26 -0
  286. package/plugins/paseo/plugin/server/transport.ts +35 -0
  287. package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
  288. package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
  289. package/plugins/paseo/plugin/tsconfig.json +6 -0
  290. package/plugins/pi/keiyaku.ts +57 -0
  291. package/skills/keiyaku/SKILL.md +43 -0
  292. package/skills/keiyaku-akuma/SKILL.md +130 -0
  293. package/skills/keiyaku-akuma/references/automation.md +269 -0
  294. package/skills/keiyaku-babysit/SKILL.md +65 -0
  295. package/skills/keiyaku-bind/SKILL.md +216 -0
  296. package/skills/keiyaku-bind/agents/openai.yaml +4 -0
  297. package/skills/keiyaku-debt/SKILL.md +91 -0
  298. package/skills/keiyaku-workflow/SKILL.md +129 -0
  299. package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
  300. package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
  301. package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
  302. package/build/skills/keiyaku-task/SKILL.md +0 -104
  303. package/build/src/cli/commands/amend.d.ts +0 -12
  304. package/build/src/cli/commands/amend.js +0 -10
  305. package/build/src/cli/commands/bind.d.ts +0 -11
  306. package/build/src/cli/commands/bind.js +0 -23
  307. package/build/src/cli/commands/task-grammar.d.ts +0 -19
  308. package/build/src/cli/commands/task-grammar.js +0 -384
  309. package/build/src/cli/commands/task-query.d.ts +0 -5
  310. package/build/src/cli/render/task.d.ts +0 -41
  311. package/build/src/dispatch/association.d.ts +0 -1
  312. package/build/src/dispatch/association.js +0 -1
  313. package/build/src/task/board.d.ts +0 -168
  314. package/build/src/task/catalog.d.ts +0 -11
  315. package/build/src/task/catalog.js +0 -59
  316. package/build/src/task/compose-language.d.ts +0 -57
  317. package/build/src/task/compose-language.js +0 -364
  318. package/build/src/task/compose-parser.d.ts +0 -32
  319. package/build/src/task/compose-parser.js +0 -180
  320. package/build/src/task/compose.d.ts +0 -16
  321. package/build/src/task/compose.js +0 -189
  322. package/build/src/task/document.d.ts +0 -39
  323. package/build/src/task/identity.d.ts +0 -21
  324. package/build/src/task/index.d.ts +0 -138
  325. package/build/src/task/index.js +0 -269
  326. package/build/src/task/lifecycle-operations.d.ts +0 -6
  327. package/build/src/task/mutation-result.d.ts +0 -1726
  328. package/build/src/task/mutation-result.js +0 -198
  329. package/build/src/task/mutation.d.ts +0 -590
  330. package/build/src/task/mutation.js +0 -262
  331. package/build/src/task/operation-types.d.ts +0 -71
  332. package/build/src/task/operations.d.ts +0 -28
  333. package/build/src/task/query.d.ts +0 -76
  334. package/build/src/task/view.d.ts +0 -4
  335. package/build/src/task/view.js +0 -7
  336. /package/build/src/{task → debt}/operation-types.js +0 -0
@@ -1,4 +1,5 @@
1
1
  import { noteEvent, otherToolCall, unknownEvent } from "../../provider.js";
2
+ import { nonblank, object, positiveLine, stringValue } from "../decode.js";
2
3
  export const EMPTY_ACP_EVENT_STATE = Object.freeze({
3
4
  answer: "",
4
5
  assistantMessageId: null,
@@ -27,20 +28,6 @@ function appendBlock(state, type, text, messageId) {
27
28
  },
28
29
  };
29
30
  }
30
- function nonblank(value) {
31
- return typeof value === "string" && value.trim().length > 0 ? value : undefined;
32
- }
33
- function object(value) {
34
- return value !== null && typeof value === "object" && !Array.isArray(value)
35
- ? value
36
- : undefined;
37
- }
38
- function positiveLine(value) {
39
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
40
- }
41
- function otherCall(name, input) {
42
- return otherToolCall(name, input);
43
- }
44
31
  function locationFact(locations) {
45
32
  if (locations === null || locations === undefined)
46
33
  return {};
@@ -53,11 +40,30 @@ function locationFact(locations) {
53
40
  }
54
41
  return {};
55
42
  }
43
+ /**
44
+ * The observed result text of one ACP tool update: its text content blocks in
45
+ * native order, otherwise a raw output that is itself a string. A raw output of
46
+ * any other shape is left absent rather than stringified.
47
+ */
48
+ function verifiedToolOutput(update) {
49
+ if (Array.isArray(update.content)) {
50
+ const blocks = update.content.flatMap((entry) => {
51
+ const value = object(entry);
52
+ if (value?.type !== "content")
53
+ return [];
54
+ const content = object(value.content);
55
+ return content?.type === "text" && typeof content.text === "string" ? [content.text] : [];
56
+ });
57
+ if (blocks.length > 0)
58
+ return blocks.join("");
59
+ }
60
+ return stringValue(update.rawOutput);
61
+ }
56
62
  function standardCall(update, name) {
57
63
  const location = locationFact(update.locations);
58
64
  if (update.kind === "read") {
59
65
  return location.path === undefined
60
- ? otherCall(name, update.rawInput)
66
+ ? otherToolCall(name, update.rawInput)
61
67
  : {
62
68
  kind: "read",
63
69
  path: location.path,
@@ -67,12 +73,12 @@ function standardCall(update, name) {
67
73
  const input = object(update.rawInput);
68
74
  if (update.kind === "execute") {
69
75
  const command = nonblank(input?.command);
70
- return command === undefined ? otherCall(name, update.rawInput) : { kind: "run", command };
76
+ return command === undefined ? otherToolCall(name, update.rawInput) : { kind: "run", command };
71
77
  }
72
78
  if (update.kind === "search") {
73
79
  const query = nonblank(input?.query);
74
80
  if (query === undefined)
75
- return otherCall(name, update.rawInput);
81
+ return otherToolCall(name, update.rawInput);
76
82
  const path = nonblank(input?.path);
77
83
  const glob = nonblank(input?.glob);
78
84
  const scope = input?.scope;
@@ -85,7 +91,7 @@ function standardCall(update, name) {
85
91
  ...(glob === undefined ? {} : { glob }),
86
92
  };
87
93
  }
88
- return otherCall(name, update.rawInput);
94
+ return otherToolCall(name, update.rawInput);
89
95
  }
90
96
  function strongest(previous, next) {
91
97
  if (previous === undefined || previous.kind === "other")
@@ -122,6 +128,7 @@ export function mapAcpUpdate(update, previous, interpret) {
122
128
  const observed = observeTool(update, previous.tools.get(update.toolCallId), interpret);
123
129
  const tools = new Map(previous.tools);
124
130
  if (update.status === "completed" || update.status === "failed") {
131
+ const output = verifiedToolOutput(update);
125
132
  tools.delete(update.toolCallId);
126
133
  return flushAcpEvents({ ...previous, tools }, [
127
134
  {
@@ -129,7 +136,10 @@ export function mapAcpUpdate(update, previous, interpret) {
129
136
  phase: "completed",
130
137
  id: update.toolCallId,
131
138
  ...observed,
132
- result: { status: update.status === "completed" ? "ok" : "error" },
139
+ result: {
140
+ status: update.status === "completed" ? "ok" : "error",
141
+ ...(output === undefined ? {} : { output }),
142
+ },
133
143
  },
134
144
  ]);
135
145
  }
@@ -1,4 +1,4 @@
1
- import { createProviderAttempt } from "../../provider.js";
1
+ import { providerLifecycle } from "../lifecycle.js";
2
2
  import { decodeAcpConfig } from "./config.js";
3
3
  import { startAcpSession } from "./core.js";
4
4
  export { decodeAcpConfig } from "./config.js";
@@ -63,7 +63,6 @@ export function createAcpProvider(execution, dependencies = {}) {
63
63
  };
64
64
  return {
65
65
  admitOptions: (options) => optionAdmission(options, config),
66
- start: (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody)),
67
- resume: (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody)),
66
+ ...providerLifecycle(drive),
68
67
  };
69
68
  }
@@ -1,4 +1,6 @@
1
- import { noteEvent, otherToolCall, unknownEvent } from "../../provider.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";
2
4
  export const CLAUDE_MESSAGE_DISPOSITIONS = {
3
5
  assistant: "assistant",
4
6
  auth_status: "auth",
@@ -42,20 +44,6 @@ export const CLAUDE_SYSTEM_DISPOSITIONS = {
42
44
  thinking_tokens: "drop",
43
45
  worker_shutting_down: "note",
44
46
  };
45
- function object(value) {
46
- return value !== null && typeof value === "object" && !Array.isArray(value)
47
- ? value
48
- : undefined;
49
- }
50
- function nonblank(value) {
51
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
52
- }
53
- function number(value) {
54
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
55
- }
56
- function positiveLine(value) {
57
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
58
- }
59
47
  function readRange(value) {
60
48
  const offset = positiveLine(value.offset);
61
49
  const limit = positiveLine(value.limit);
@@ -64,21 +52,10 @@ function readRange(value) {
64
52
  ...(limit === undefined ? {} : { limit }),
65
53
  };
66
54
  }
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
- }
78
55
  const CLAUDE_SYSTEM_NOTES = {
79
56
  api_retry: (message) => {
80
- const attempt = number(message.attempt);
81
- const maximum = number(message.max_retries);
57
+ const attempt = finiteNumber(message.attempt);
58
+ const maximum = finiteNumber(message.max_retries);
82
59
  return attempt === undefined || maximum === undefined
83
60
  ? "Retrying request"
84
61
  : `Retrying request ${attempt}/${maximum}`;
@@ -90,24 +67,24 @@ const CLAUDE_SYSTEM_NOTES = {
90
67
  const failed = Array.isArray(message.failed) ? message.failed.length : 0;
91
68
  return failed === 0 ? `Persisted ${files} files` : `Persisted ${files} files; ${failed} failed`;
92
69
  },
93
- informational: (message) => nonblank(message.content) ?? "Informational notice",
94
- mirror_error: (message) => `Transcript mirror warning: ${nonblank(message.error) ?? nonblank(message.message) ?? "unknown error"}`,
70
+ informational: (message) => trimmed(message.content) ?? "Informational notice",
71
+ mirror_error: (message) => `Transcript mirror warning: ${trimmed(message.error) ?? trimmed(message.message) ?? "unknown error"}`,
95
72
  model_refusal_fallback: () => "Model refusal; using fallback",
96
73
  model_refusal_no_fallback: () => "Model refusal; no fallback available",
97
- notification: (message) => nonblank(message.message) ?? nonblank(message.content) ?? "Notification",
98
- permission_denied: (message) => `Permission refused${nonblank(message.message) === undefined ? "" : `: ${nonblank(message.message)}`}`,
99
- plugin_install: (message) => `Plugin install ${nonblank(message.status) ?? "updated"}${nonblank(message.name) === undefined ? "" : `: ${nonblank(message.name)}`}`,
100
- status: (message) => `Status: ${nonblank(message.status) ?? "idle"}${nonblank(message.error) === undefined ? "" : ` (${nonblank(message.error)})`}`,
101
- task_notification: (message) => `Task ${nonblank(message.task_id) ?? "unknown"} ${nonblank(message.status) ?? "updated"}`,
102
- task_progress: (message) => nonblank(message.description) ?? `Task ${nonblank(message.task_id) ?? "unknown"} progressed`,
103
- task_started: (message) => nonblank(message.description) ?? `Task ${nonblank(message.task_id) ?? "unknown"} started`,
104
- task_updated: (message) => `Task ${nonblank(message.task_id) ?? "unknown"} updated`,
105
- worker_shutting_down: (message) => `Worker stopping: ${nonblank(message.reason) ?? "unknown reason"}`,
74
+ notification: (message) => trimmed(message.message) ?? trimmed(message.content) ?? "Notification",
75
+ permission_denied: (message) => `Permission refused${trimmed(message.message) === undefined ? "" : `: ${trimmed(message.message)}`}`,
76
+ plugin_install: (message) => `Plugin install ${trimmed(message.status) ?? "updated"}${trimmed(message.name) === undefined ? "" : `: ${trimmed(message.name)}`}`,
77
+ status: (message) => `Status: ${trimmed(message.status) ?? "idle"}${trimmed(message.error) === undefined ? "" : ` (${trimmed(message.error)})`}`,
78
+ task_notification: (message) => `Task ${trimmed(message.task_id) ?? "unknown"} ${trimmed(message.status) ?? "updated"}`,
79
+ task_progress: (message) => trimmed(message.description) ?? `Task ${trimmed(message.task_id) ?? "unknown"} progressed`,
80
+ task_started: (message) => trimmed(message.description) ?? `Task ${trimmed(message.task_id) ?? "unknown"} started`,
81
+ task_updated: (message) => `Task ${trimmed(message.task_id) ?? "unknown"} updated`,
82
+ worker_shutting_down: (message) => `Worker stopping: ${trimmed(message.reason) ?? "unknown reason"}`,
106
83
  };
107
84
  function runCall(name, value, input) {
108
85
  if (name !== "Bash")
109
86
  return undefined;
110
- const command = nonblank(value.command);
87
+ const command = trimmed(value.command);
111
88
  return command === undefined ? otherToolCall(name, input) : { kind: "run", command };
112
89
  }
113
90
  function readCall(name, path, value) {
@@ -115,19 +92,18 @@ function readCall(name, path, value) {
115
92
  }
116
93
  function searchCall(name, value) {
117
94
  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);
95
+ const query = trimmed(value.pattern) ?? trimmed(value.query);
124
96
  return query === undefined
125
97
  ? undefined
126
- : { kind: "search", query, scope: "files", ...(globPath === undefined ? {} : { path: globPath }) };
98
+ : searchToolCall(query, "content", { path: trimmed(value.path), glob: trimmed(value.glob) });
99
+ }
100
+ if (name === "Glob") {
101
+ const query = trimmed(value.pattern);
102
+ return query === undefined ? undefined : searchToolCall(query, "files", { path: trimmed(value.path) });
127
103
  }
128
104
  if (name === "WebSearch") {
129
- const query = nonblank(value.query);
130
- return query === undefined ? undefined : { kind: "search", query, scope: "web" };
105
+ const query = trimmed(value.query);
106
+ return query === undefined ? undefined : searchToolCall(query, "web");
131
107
  }
132
108
  return undefined;
133
109
  }
@@ -143,44 +119,83 @@ function fileChangeCall(name, path) {
143
119
  }
144
120
  function startedPath(name, value) {
145
121
  if (name === "NotebookEdit")
146
- return nonblank(value.notebook_path);
147
- return nonblank(value.file_path) ?? (name === "Read" ? nonblank(value.path) : undefined);
122
+ return trimmed(value.notebook_path);
123
+ return trimmed(value.file_path) ?? (name === "Read" ? trimmed(value.path) : undefined);
148
124
  }
149
125
  function nonnegativeInt(value) {
150
126
  return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
151
127
  }
152
- function fileChange(op, path, gitDiff) {
153
- const diff = object(gitDiff);
128
+ function fileChange(op, path, result) {
129
+ const diff = object(result.gitDiff);
154
130
  const added = nonnegativeInt(diff?.additions);
155
131
  const removed = nonnegativeInt(diff?.deletions);
156
- 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 };
157
138
  return {
158
139
  kind: "fileChange",
159
- changes: [{ op, path, ...(diffstat === undefined ? {} : { diffstat }) }],
140
+ changes: [
141
+ {
142
+ op,
143
+ path,
144
+ ...(diffstat === undefined ? {} : { diffstat }),
145
+ ...(patch === undefined ? {} : { patch }),
146
+ },
147
+ ],
160
148
  };
161
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
+ }
162
178
  function writeResult(result) {
163
179
  const value = object(result);
164
180
  if (value === undefined || (value.type !== "create" && value.type !== "update"))
165
181
  return undefined;
166
- const path = nonblank(value.filePath);
182
+ const path = trimmed(value.filePath);
167
183
  if (path === undefined)
168
184
  return undefined;
169
- const op = value.type === "create" ? "add" : "update";
170
- return fileChange(op, path, value.gitDiff);
185
+ return fileChange(value.type === "create" ? "add" : "update", path, value);
171
186
  }
172
187
  function editResult(result) {
173
188
  const value = object(result);
174
189
  if (value === undefined || value.type === "create" || value.type === "update")
175
190
  return undefined;
176
- const path = nonblank(value.filePath);
191
+ const path = trimmed(value.filePath);
177
192
  if (path === undefined)
178
193
  return undefined;
179
194
  const status = object(value.gitDiff)?.status;
180
- return fileChange(status === "added" ? "add" : "update", path, value.gitDiff);
195
+ return fileChange(status === "added" ? "add" : "update", path, value);
181
196
  }
182
197
  function notebookResult(result) {
183
- const path = nonblank(object(result)?.notebook_path);
198
+ const path = trimmed(object(result)?.notebook_path);
184
199
  return path === undefined ? undefined : { kind: "fileChange", changes: [{ op: "update", path }] };
185
200
  }
186
201
  function structuredFileChange(name, result) {
@@ -199,6 +214,11 @@ function toolCall(name, input) {
199
214
  return (readCall(name, path, value) ?? searchCall(name, value) ?? fileChangeCall(name, path) ?? otherToolCall(name, input));
200
215
  }
201
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));
202
222
  if (message.aborted === true)
203
223
  return;
204
224
  if (message.error !== undefined) {
@@ -232,7 +252,7 @@ function toolResultEvents(message, events, state) {
232
252
  const value = object(block);
233
253
  if (value?.type !== "tool_result")
234
254
  continue;
235
- const id = nonblank(value.tool_use_id);
255
+ const id = trimmed(value.tool_use_id);
236
256
  if (id === undefined)
237
257
  continue;
238
258
  const observed = state.tools.get(id);
@@ -241,30 +261,51 @@ function toolResultEvents(message, events, state) {
241
261
  state.tools.delete(id);
242
262
  const failed = value.is_error === true;
243
263
  const structured = failed ? undefined : structuredFileChange(observed.name, message.tool_use_result);
264
+ const output = observedTextContent(value.content);
244
265
  events.emit({
245
266
  type: "tool",
246
267
  phase: "completed",
247
268
  id,
248
269
  name: observed.name,
249
270
  call: structured ?? observed.call,
250
- result: { status: failed ? "error" : "ok" },
271
+ result: {
272
+ status: failed ? "error" : "ok",
273
+ ...(output === undefined ? {} : { output }),
274
+ },
251
275
  });
252
276
  }
253
277
  }
254
278
  function hookResponseNote(value) {
255
- const outcome = nonblank(value.outcome);
279
+ const outcome = trimmed(value.outcome);
256
280
  if (outcome !== "error" && outcome !== "cancelled")
257
281
  return undefined;
258
- const hook = nonblank(value.hook_name) ?? "unknown";
259
- const exitCode = number(value.exit_code);
282
+ const hook = trimmed(value.hook_name) ?? "unknown";
283
+ const exitCode = finiteNumber(value.exit_code);
260
284
  return `Hook ${hook} ${outcome}${exitCode === undefined ? "" : ` (exit ${exitCode})`}`;
261
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
+ }
262
300
  function emitSystemMessage(value, events) {
263
- const subtype = nonblank(value?.subtype) ?? "unknown";
301
+ const subtype = trimmed(value?.subtype) ?? "unknown";
264
302
  if (!Object.hasOwn(CLAUDE_SYSTEM_DISPOSITIONS, subtype)) {
265
303
  events.emit(unknownEvent(subtype));
266
304
  return;
267
305
  }
306
+ const evidence = systemModelEvidence(subtype, value);
307
+ if (evidence !== undefined)
308
+ events.emit(modelEvent(evidence));
268
309
  const systemDisposition = CLAUDE_SYSTEM_DISPOSITIONS[subtype];
269
310
  if (systemDisposition === "drop")
270
311
  return;
@@ -281,7 +322,7 @@ function emitSystemMessage(value, events) {
281
322
  }
282
323
  export function emitClaudeMessage(message, events, state) {
283
324
  const value = object(message) ?? {};
284
- const kind = nonblank(value.type) ?? "unknown";
325
+ const kind = trimmed(value.type) ?? "unknown";
285
326
  if (!Object.hasOwn(CLAUDE_MESSAGE_DISPOSITIONS, kind))
286
327
  return events.emit(unknownEvent(kind));
287
328
  const disposition = CLAUDE_MESSAGE_DISPOSITIONS[kind];
@@ -292,7 +333,7 @@ export function emitClaudeMessage(message, events, state) {
292
333
  toolResultEvents(message, events, state);
293
334
  }
294
335
  else if (disposition === "auth") {
295
- const error = nonblank(value.error);
336
+ const error = trimmed(value.error);
296
337
  if (error !== undefined)
297
338
  events.emit(noteEvent(`Authentication warning: ${error}`));
298
339
  }
@@ -2,13 +2,12 @@ import type { Options, Query, SDKUserMessage } from "@anthropic-ai/claude-agent-
2
2
  import { type ProviderAdapter, type Session } from "../../provider.js";
3
3
  import type { ProviderOptions } from "../../provider-recipe.js";
4
4
  import type { ResumeCoordinate } from "../../provider.js";
5
- export { CLAUDE_MESSAGE_DISPOSITIONS, CLAUDE_SYSTEM_DISPOSITIONS } from "./events.js";
6
5
  type ClaudeExecution = Readonly<{
7
6
  executable?: string;
8
7
  config?: Readonly<Record<string, unknown>>;
9
8
  env?: Readonly<Record<string, string>>;
10
9
  }>;
11
- export type ClaudeSdk = Readonly<{
10
+ type ClaudeSdk = Readonly<{
12
11
  query(input: Readonly<{
13
12
  prompt: string | AsyncIterable<SDKUserMessage>;
14
13
  options?: Options;
@@ -42,3 +41,4 @@ export declare const claudeProvider: Readonly<{
42
41
  }>;
43
42
  }>): import("../../provider.js").ProviderAttempt<Session>;
44
43
  }>;
44
+ export {};
@@ -1,10 +1,10 @@
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
+ import { providerLifecycle } from "../lifecycle.js";
5
6
  import { emitClaudeMessage } from "./events.js";
6
7
  import { claudeUserMessage, createClaudeInput, isClaudeTurnEnded } from "./input.js";
7
- export { CLAUDE_MESSAGE_DISPOSITIONS, CLAUDE_SYSTEM_DISPOSITIONS } from "./events.js";
8
8
  class ReceiptChannel {
9
9
  queued = [];
10
10
  waiters = [];
@@ -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),
@@ -364,8 +361,7 @@ export function createClaudeProvider(loadOrExecution = async () => (await import
364
361
  return {
365
362
  admitOptions: admitClaudeOptions,
366
363
  fork: (input) => createProviderAttempt(new AbortController().signal, async () => await forkClaude(load, selectedExecution, input)),
367
- start: (input) => createProviderAttempt(input.signal, async (custody) => await driveClaude(load, selectedExecution, { ...input, signal: custody.signal }, custody)),
368
- resume: (input) => createProviderAttempt(input.signal, async (custody) => await driveClaude(load, selectedExecution, { ...input, signal: custody.signal }, custody)),
364
+ ...providerLifecycle((input, custody) => driveClaude(load, selectedExecution, input, custody)),
369
365
  };
370
366
  }
371
367
  export const claudeProvider = createClaudeProvider(async () => (await import("@anthropic-ai/claude-agent-sdk")));
@@ -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,6 +1,7 @@
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
+ import { providerLifecycle } from "../lifecycle.js";
4
5
  import { codexNotificationResult, codexObject, codexText } from "./events.js";
5
6
  export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
6
7
  function diagnostic(error) {
@@ -29,6 +30,12 @@ function turnId(result) {
29
30
  throw new Error("codex app-server did not return a turn id");
30
31
  return id;
31
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
+ }
32
39
  async function steerTurn(server, state, tell) {
33
40
  if (state.settled)
34
41
  return { kind: "turn-ended" };
@@ -61,13 +68,15 @@ async function admitTurn(server, input, state, events, config) {
61
68
  : { developerInstructions: input.options.systemPrompt }),
62
69
  };
63
70
  if (input.session.kind === "fresh") {
64
- 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);
65
74
  }
66
75
  else {
67
- state.threadId = threadId(await server.request("thread/resume", {
68
- threadId: input.session.coordinate.sessionId,
69
- ...threadParams,
70
- }), 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);
71
80
  }
72
81
  events.emit({ type: "session", coordinate: { sessionId: state.threadId } });
73
82
  state.turnId = turnId(await server.request("turn/start", {
@@ -75,9 +84,7 @@ async function admitTurn(server, input, state, events, config) {
75
84
  input: [
76
85
  {
77
86
  type: "text",
78
- text: [input.body, ...input.launchTells.map((tell) => tell.text)]
79
- .filter((part) => part.length > 0)
80
- .join("\n\n"),
87
+ text: launchPrompt(input.body, input.launchTells),
81
88
  },
82
89
  ],
83
90
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
@@ -214,7 +221,6 @@ export function createCodexAppServerProvider(input = "codex") {
214
221
  };
215
222
  },
216
223
  fork: (input) => createProviderAttempt(new AbortController().signal, async (custody) => await forkCodex(execution, input, custody)),
217
- start: (input) => createProviderAttempt(input.signal, async (custody) => await startCodex(execution, { ...input, signal: custody.signal }, custody)),
218
- resume: (input) => createProviderAttempt(input.signal, async (custody) => await startCodex(execution, { ...input, signal: custody.signal }, custody)),
224
+ ...providerLifecycle((input, custody) => startCodex(execution, input, custody)),
219
225
  };
220
226
  }
@@ -0,0 +1,33 @@
1
+ import type { SearchScope, ToolCall } from "../provider.js";
2
+ /**
3
+ * Native payload decoders shared by provider event adaptation. Every adapter
4
+ * reads the same untrusted native shapes; these are the only places that decide
5
+ * what a present value means, so each keeps one exact predicate and return.
6
+ */
7
+ export declare function isRecord(value: unknown): value is Readonly<Record<string, unknown>>;
8
+ export declare function object(value: unknown): Readonly<Record<string, unknown>> | undefined;
9
+ /** A string with non-blank trim, returned as supplied. */
10
+ export declare function nonblank(value: unknown): string | undefined;
11
+ /** A string with non-blank trim, returned trimmed. */
12
+ export declare function trimmed(value: unknown): string | undefined;
13
+ /** A nonempty string, returned as supplied; internal whitespace stays content. */
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;
23
+ /** A one-based line number. */
24
+ export declare function positiveLine(value: unknown): number | undefined;
25
+ export declare function nonnegativeCount(value: unknown): number | undefined;
26
+ export declare function finiteNumber(value: unknown): number | undefined;
27
+ /** One neutral search call carrying only the bounds the native input supplied. */
28
+ export declare function searchToolCall(query: string, scope: SearchScope | undefined, bounds?: Readonly<{
29
+ path?: string | undefined;
30
+ glob?: string | undefined;
31
+ }>): Extract<ToolCall, {
32
+ kind: "search";
33
+ }>;