@codespar/cli 0.14.0 → 0.16.0

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 (538) hide show
  1. package/README.md +44 -17
  2. package/dist/commands/audit-replay.js +267 -0
  3. package/dist/commands/audit-replay.js.map +1 -0
  4. package/dist/commands/init.js +28 -0
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/commands/login.js +2 -1
  7. package/dist/commands/login.js.map +1 -1
  8. package/dist/commands/mandate-verify.js +75 -27
  9. package/dist/commands/mandate-verify.js.map +1 -1
  10. package/dist/config.js +17 -1
  11. package/dist/config.js.map +1 -1
  12. package/dist/did.js +262 -41
  13. package/dist/did.js.map +1 -1
  14. package/dist/index.js +33 -7
  15. package/dist/index.js.map +1 -1
  16. package/dist/surface.js +4 -1
  17. package/dist/surface.js.map +1 -1
  18. package/package.json +1 -1
  19. package/templates/bills-agent/README.md +8 -5
  20. package/templates/bills-agent/agents/bills-agent/.env.example +3 -3
  21. package/templates/bills-agent/agents/bills-agent/AGENTS.md +1 -1
  22. package/templates/bills-agent/agents/bills-agent/CLAUDE.md +1 -1
  23. package/templates/bills-agent/agents/bills-agent/README.md +62 -22
  24. package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +1 -1
  25. package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -2
  26. package/templates/bills-agent/agents/bills-agent/package.json +14 -11
  27. package/templates/bills-agent/agents/bills-agent/src/kit.ts +193 -0
  28. package/templates/bills-agent/agents/bills-agent/test/adversarial.test.ts +8 -7
  29. package/templates/bills-agent/agents/bills-agent/test/check.test.ts +19 -2
  30. package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +72 -24
  31. package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -0
  32. package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +2 -0
  33. package/templates/bills-agent/agents/bills-agent/test/inspect.test.ts +124 -0
  34. package/templates/bills-agent/agents/bills-agent/test/provider.test.ts +25 -0
  35. package/templates/bills-agent/agents/bills-agent/test/scenarios.test.ts +10 -9
  36. package/templates/bills-agent/agents/bills-agent/tsconfig.json +0 -1
  37. package/templates/bills-agent/package.json +5 -2
  38. package/templates/bills-agent/packages/agent-core/README.md +2 -0
  39. package/templates/bills-agent/packages/agent-core/package.json +1 -1
  40. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +27 -6
  41. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +16 -0
  42. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +20 -7
  43. package/templates/bills-agent/packages/agent-core/src/approval.ts +16 -2
  44. package/templates/bills-agent/packages/agent-core/src/bundle.ts +50 -4
  45. package/templates/bills-agent/packages/agent-core/src/channels.ts +140 -0
  46. package/templates/bills-agent/packages/agent-core/src/check.ts +90 -8
  47. package/templates/bills-agent/packages/agent-core/src/clock.ts +42 -0
  48. package/templates/bills-agent/packages/agent-core/src/engine.ts +119 -18
  49. package/templates/bills-agent/packages/agent-core/src/hash.ts +13 -0
  50. package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
  51. package/templates/bills-agent/packages/agent-core/src/manifest.ts +1 -1
  52. package/templates/bills-agent/packages/agent-core/src/rail.ts +16 -2
  53. package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +401 -0
  54. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +3 -1
  55. package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +2 -0
  56. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +19 -2
  57. package/templates/bills-agent/packages/agent-core/src/types.ts +28 -0
  58. package/templates/bills-agent/packages/agent-core/test/approval.test.ts +36 -2
  59. package/templates/bills-agent/packages/agent-core/test/bundle.test.ts +85 -0
  60. package/templates/bills-agent/packages/agent-core/test/clock.test.ts +25 -0
  61. package/templates/bills-agent/packages/agent-core/test/engine.test.ts +73 -1
  62. package/templates/bills-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
  63. package/templates/bills-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
  64. package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
  65. package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
  66. package/templates/bills-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
  67. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +51 -0
  68. package/templates/bills-agent/packages/agent-runtime/README.md +68 -0
  69. package/templates/bills-agent/packages/agent-runtime/bin.mjs +32 -0
  70. package/templates/bills-agent/packages/agent-runtime/package.json +23 -0
  71. package/templates/bills-agent/{agents/bills-agent → packages/agent-runtime}/src/adversarial.ts +36 -44
  72. package/templates/bills-agent/packages/agent-runtime/src/agent.ts +68 -0
  73. package/templates/bills-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
  74. package/templates/bills-agent/packages/agent-runtime/src/channels/index.ts +72 -0
  75. package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
  76. package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +124 -0
  77. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
  78. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
  79. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
  80. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
  81. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
  82. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
  83. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
  84. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
  85. package/templates/bills-agent/packages/agent-runtime/src/cli.ts +98 -0
  86. package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +15 -0
  87. package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
  88. package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
  89. package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
  90. package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
  91. package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
  92. package/templates/bills-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
  93. package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
  94. package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
  95. package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
  96. package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +245 -0
  97. package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
  98. package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
  99. package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +83 -0
  100. package/templates/bills-agent/packages/agent-runtime/src/index.ts +12 -0
  101. package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +797 -0
  102. package/templates/bills-agent/packages/agent-runtime/src/kit.ts +206 -0
  103. package/templates/{collections-agent/agents/collections-agent → bills-agent/packages/agent-runtime}/src/poll.ts +22 -11
  104. package/templates/{collections-agent/agents/collections-agent → bills-agent/packages/agent-runtime}/src/scenarios.ts +50 -34
  105. package/templates/bills-agent/{agents/bills-agent → packages/agent-runtime}/src/setup.ts +88 -66
  106. package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +154 -0
  107. package/templates/{collections-agent/agents/collections-agent/channels/webhook/index.ts → bills-agent/packages/agent-runtime/src/webhook.ts} +1 -1
  108. package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
  109. package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
  110. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
  111. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
  112. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
  113. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
  114. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
  115. package/templates/bills-agent/packages/agent-runtime/tsconfig.json +9 -0
  116. package/templates/bills-agent/vitest.config.ts +1 -1
  117. package/templates/collections-agent/README.md +8 -5
  118. package/templates/collections-agent/agents/collections-agent/.env.example +14 -0
  119. package/templates/collections-agent/agents/collections-agent/AGENTS.md +6 -4
  120. package/templates/collections-agent/agents/collections-agent/CLAUDE.md +6 -4
  121. package/templates/collections-agent/agents/collections-agent/README.md +184 -16
  122. package/templates/collections-agent/agents/collections-agent/agent.yaml +3 -3
  123. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +111 -0
  124. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042.json +11 -0
  125. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1103.json +11 -0
  126. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +23 -0
  127. package/templates/collections-agent/agents/collections-agent/package.json +12 -10
  128. package/templates/collections-agent/agents/collections-agent/runbook.md +52 -1
  129. package/templates/collections-agent/agents/collections-agent/src/kit.ts +265 -0
  130. package/templates/collections-agent/agents/collections-agent/test/adversarial.test.ts +9 -8
  131. package/templates/collections-agent/agents/collections-agent/test/check.test.ts +43 -1
  132. package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +56 -18
  133. package/templates/collections-agent/agents/collections-agent/test/fixtures/agreed-1042-awaiting-payer.transcript.jsonl +4 -0
  134. package/templates/collections-agent/agents/collections-agent/test/scenarios.test.ts +11 -10
  135. package/templates/collections-agent/agents/collections-agent/test/webhook.test.ts +4 -7
  136. package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +271 -0
  137. package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +213 -0
  138. package/templates/collections-agent/agents/collections-agent/tsconfig.json +0 -1
  139. package/templates/collections-agent/package.json +3 -1
  140. package/templates/collections-agent/packages/agent-core/README.md +2 -0
  141. package/templates/collections-agent/packages/agent-core/package.json +1 -1
  142. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +27 -6
  143. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +16 -0
  144. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +20 -7
  145. package/templates/collections-agent/packages/agent-core/src/approval.ts +16 -2
  146. package/templates/collections-agent/packages/agent-core/src/bundle.ts +50 -4
  147. package/templates/collections-agent/packages/agent-core/src/channels.ts +140 -0
  148. package/templates/collections-agent/packages/agent-core/src/check.ts +90 -8
  149. package/templates/collections-agent/packages/agent-core/src/clock.ts +42 -0
  150. package/templates/collections-agent/packages/agent-core/src/engine.ts +119 -18
  151. package/templates/collections-agent/packages/agent-core/src/hash.ts +13 -0
  152. package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
  153. package/templates/collections-agent/packages/agent-core/src/manifest.ts +1 -1
  154. package/templates/collections-agent/packages/agent-core/src/rail.ts +16 -2
  155. package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +401 -0
  156. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +3 -1
  157. package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +2 -0
  158. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +19 -2
  159. package/templates/collections-agent/packages/agent-core/src/types.ts +28 -0
  160. package/templates/collections-agent/packages/agent-core/test/approval.test.ts +36 -2
  161. package/templates/collections-agent/packages/agent-core/test/bundle.test.ts +85 -0
  162. package/templates/collections-agent/packages/agent-core/test/clock.test.ts +25 -0
  163. package/templates/collections-agent/packages/agent-core/test/engine.test.ts +73 -1
  164. package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
  165. package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
  166. package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
  167. package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
  168. package/templates/collections-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
  169. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +51 -0
  170. package/templates/collections-agent/packages/agent-runtime/README.md +68 -0
  171. package/templates/collections-agent/packages/agent-runtime/bin.mjs +32 -0
  172. package/templates/collections-agent/packages/agent-runtime/package.json +23 -0
  173. package/templates/collections-agent/{agents/collections-agent → packages/agent-runtime}/src/adversarial.ts +29 -50
  174. package/templates/collections-agent/packages/agent-runtime/src/agent.ts +68 -0
  175. package/templates/collections-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
  176. package/templates/collections-agent/packages/agent-runtime/src/channels/index.ts +72 -0
  177. package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
  178. package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +124 -0
  179. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
  180. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
  181. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
  182. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
  183. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
  184. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
  185. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
  186. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
  187. package/templates/collections-agent/packages/agent-runtime/src/cli.ts +98 -0
  188. package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +15 -0
  189. package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
  190. package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
  191. package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
  192. package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
  193. package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
  194. package/templates/collections-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
  195. package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
  196. package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
  197. package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
  198. package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +245 -0
  199. package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
  200. package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
  201. package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +83 -0
  202. package/templates/collections-agent/packages/agent-runtime/src/index.ts +12 -0
  203. package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +797 -0
  204. package/templates/collections-agent/packages/agent-runtime/src/kit.ts +206 -0
  205. package/templates/collections-agent/packages/agent-runtime/src/poll.ts +105 -0
  206. package/templates/{bills-agent/agents/bills-agent → collections-agent/packages/agent-runtime}/src/scenarios.ts +98 -26
  207. package/templates/collections-agent/packages/agent-runtime/src/setup.ts +229 -0
  208. package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +154 -0
  209. package/templates/collections-agent/packages/agent-runtime/src/webhook.ts +131 -0
  210. package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
  211. package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
  212. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
  213. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
  214. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
  215. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
  216. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
  217. package/templates/collections-agent/packages/agent-runtime/tsconfig.json +9 -0
  218. package/templates/collections-agent/vitest.config.ts +1 -1
  219. package/templates/hello-agent/LICENSE +21 -0
  220. package/templates/hello-agent/README.md +23 -0
  221. package/templates/hello-agent/_gitignore +10 -0
  222. package/templates/hello-agent/agents/hello-agent/.env.example +5 -0
  223. package/templates/hello-agent/agents/hello-agent/AGENTS.md +15 -0
  224. package/templates/hello-agent/agents/hello-agent/CLAUDE.md +15 -0
  225. package/templates/hello-agent/agents/hello-agent/README.md +33 -0
  226. package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +19 -0
  227. package/templates/hello-agent/agents/hello-agent/agent.yaml +19 -0
  228. package/templates/hello-agent/agents/hello-agent/evals/adversarial/beneficiary-swap.json +6 -0
  229. package/templates/hello-agent/agents/hello-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
  230. package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.json +6 -0
  231. package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +2 -0
  232. package/templates/hello-agent/agents/hello-agent/evals/adversarial/false-authority.json +6 -0
  233. package/templates/hello-agent/agents/hello-agent/evals/adversarial/false-authority.transcript.jsonl +2 -0
  234. package/templates/hello-agent/agents/hello-agent/evals/adversarial/fractioning.json +6 -0
  235. package/templates/hello-agent/agents/hello-agent/evals/adversarial/fractioning.transcript.jsonl +2 -0
  236. package/templates/hello-agent/agents/hello-agent/evals/adversarial/model-total.json +6 -0
  237. package/templates/hello-agent/agents/hello-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
  238. package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.json +6 -0
  239. package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
  240. package/templates/hello-agent/agents/hello-agent/evals/adversarial/webhook-replay.json +6 -0
  241. package/templates/hello-agent/agents/hello-agent/evals/eval.yaml +7 -0
  242. package/templates/hello-agent/agents/hello-agent/guardrails.json +8 -0
  243. package/templates/hello-agent/agents/hello-agent/mandate.example.json +17 -0
  244. package/templates/hello-agent/agents/hello-agent/package.json +19 -0
  245. package/templates/hello-agent/agents/hello-agent/runbook.md +10 -0
  246. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +6 -0
  247. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +2 -0
  248. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +6 -0
  249. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
  250. package/templates/hello-agent/agents/hello-agent/src/bills.ts +23 -0
  251. package/templates/hello-agent/agents/hello-agent/src/kit.ts +33 -0
  252. package/templates/hello-agent/agents/hello-agent/tools.json +11 -0
  253. package/templates/hello-agent/agents/hello-agent/tsconfig.json +9 -0
  254. package/templates/hello-agent/package.json +30 -0
  255. package/templates/hello-agent/packages/agent-core/README.md +21 -0
  256. package/templates/hello-agent/packages/agent-core/package.json +24 -0
  257. package/templates/hello-agent/packages/agent-core/src/agent.ts +125 -0
  258. package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +175 -0
  259. package/templates/hello-agent/packages/agent-core/src/api/client.ts +53 -0
  260. package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
  261. package/templates/hello-agent/packages/agent-core/src/api/rail.ts +117 -0
  262. package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +58 -0
  263. package/templates/hello-agent/packages/agent-core/src/approval.ts +123 -0
  264. package/templates/hello-agent/packages/agent-core/src/bundle.ts +159 -0
  265. package/templates/hello-agent/packages/agent-core/src/channels.ts +140 -0
  266. package/templates/hello-agent/packages/agent-core/src/check.ts +253 -0
  267. package/templates/hello-agent/packages/agent-core/src/clock.ts +42 -0
  268. package/templates/hello-agent/packages/agent-core/src/engine.ts +885 -0
  269. package/templates/hello-agent/packages/agent-core/src/escalate.ts +85 -0
  270. package/templates/hello-agent/packages/agent-core/src/events.ts +40 -0
  271. package/templates/hello-agent/packages/agent-core/src/guardrails.ts +45 -0
  272. package/templates/hello-agent/packages/agent-core/src/hash.ts +62 -0
  273. package/templates/hello-agent/packages/agent-core/src/ids.ts +10 -0
  274. package/templates/hello-agent/packages/agent-core/src/index.ts +32 -0
  275. package/templates/hello-agent/packages/agent-core/src/mandate.ts +100 -0
  276. package/templates/hello-agent/packages/agent-core/src/manifest.ts +76 -0
  277. package/templates/hello-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
  278. package/templates/hello-agent/packages/agent-core/src/providers/replay.ts +63 -0
  279. package/templates/hello-agent/packages/agent-core/src/providers/types.ts +39 -0
  280. package/templates/hello-agent/packages/agent-core/src/rail.ts +101 -0
  281. package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +401 -0
  282. package/templates/hello-agent/packages/agent-core/src/revocation.ts +30 -0
  283. package/templates/hello-agent/packages/agent-core/src/secrets.ts +30 -0
  284. package/templates/hello-agent/packages/agent-core/src/state/store.ts +307 -0
  285. package/templates/hello-agent/packages/agent-core/src/state-machine.ts +148 -0
  286. package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
  287. package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
  288. package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +141 -0
  289. package/templates/hello-agent/packages/agent-core/src/tools.ts +55 -0
  290. package/templates/hello-agent/packages/agent-core/src/types.ts +134 -0
  291. package/templates/hello-agent/packages/agent-core/test/approval.test.ts +117 -0
  292. package/templates/hello-agent/packages/agent-core/test/bundle.test.ts +85 -0
  293. package/templates/hello-agent/packages/agent-core/test/clock.test.ts +25 -0
  294. package/templates/hello-agent/packages/agent-core/test/engine.test.ts +596 -0
  295. package/templates/hello-agent/packages/agent-core/test/escalate.test.ts +42 -0
  296. package/templates/hello-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
  297. package/templates/hello-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
  298. package/templates/hello-agent/packages/agent-core/test/helpers.ts +139 -0
  299. package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
  300. package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +45 -0
  301. package/templates/hello-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
  302. package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +316 -0
  303. package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +28 -0
  304. package/templates/hello-agent/packages/agent-core/test/state-machine.test.ts +67 -0
  305. package/templates/hello-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
  306. package/templates/hello-agent/packages/agent-core/tsconfig.json +10 -0
  307. package/templates/hello-agent/packages/agent-runtime/README.md +68 -0
  308. package/templates/hello-agent/packages/agent-runtime/bin.mjs +32 -0
  309. package/templates/hello-agent/packages/agent-runtime/package.json +23 -0
  310. package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +169 -0
  311. package/templates/hello-agent/packages/agent-runtime/src/agent.ts +68 -0
  312. package/templates/hello-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
  313. package/templates/hello-agent/packages/agent-runtime/src/channels/index.ts +72 -0
  314. package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
  315. package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +124 -0
  316. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
  317. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
  318. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
  319. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
  320. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
  321. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
  322. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
  323. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
  324. package/templates/hello-agent/packages/agent-runtime/src/cli.ts +98 -0
  325. package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +15 -0
  326. package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
  327. package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
  328. package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
  329. package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
  330. package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
  331. package/templates/hello-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
  332. package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
  333. package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
  334. package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
  335. package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +245 -0
  336. package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
  337. package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
  338. package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +83 -0
  339. package/templates/hello-agent/packages/agent-runtime/src/index.ts +12 -0
  340. package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +797 -0
  341. package/templates/hello-agent/packages/agent-runtime/src/kit.ts +206 -0
  342. package/templates/hello-agent/packages/agent-runtime/src/poll.ts +105 -0
  343. package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +268 -0
  344. package/templates/hello-agent/packages/agent-runtime/src/setup.ts +229 -0
  345. package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +154 -0
  346. package/templates/hello-agent/packages/agent-runtime/src/webhook.ts +131 -0
  347. package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
  348. package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
  349. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
  350. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
  351. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
  352. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
  353. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
  354. package/templates/hello-agent/packages/agent-runtime/tsconfig.json +9 -0
  355. package/templates/hello-agent/tsconfig.base.json +16 -0
  356. package/templates/hello-agent/vitest.config.ts +12 -0
  357. package/templates/kits.lock.json +60 -12
  358. package/templates/supplier-payments-agent/LICENSE +21 -0
  359. package/templates/supplier-payments-agent/README.md +23 -0
  360. package/templates/supplier-payments-agent/_gitignore +10 -0
  361. package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +7 -0
  362. package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +21 -0
  363. package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +21 -0
  364. package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +118 -0
  365. package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +29 -0
  366. package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +26 -0
  367. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/batch-tampering.json +12 -0
  368. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/batch-tampering.transcript.jsonl +3 -0
  369. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap-mandate.json +9 -0
  370. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap.json +10 -0
  371. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
  372. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.json +13 -0
  373. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
  374. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.json +9 -0
  375. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +3 -0
  376. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/fractioning.json +15 -0
  377. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/fractioning.transcript.jsonl +6 -0
  378. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/model-total.json +10 -0
  379. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
  380. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.json +9 -0
  381. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
  382. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/webhook-replay.json +9 -0
  383. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/eval.yaml +9 -0
  384. package/templates/supplier-payments-agent/agents/supplier-payments-agent/guardrails.json +15 -0
  385. package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +70 -0
  386. package/templates/supplier-payments-agent/agents/supplier-payments-agent/package.json +26 -0
  387. package/templates/supplier-payments-agent/agents/supplier-payments-agent/runbook.md +19 -0
  388. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.json +14 -0
  389. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +2 -0
  390. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.json +12 -0
  391. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +2 -0
  392. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.json +20 -0
  393. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +7 -0
  394. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.json +19 -0
  395. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +3 -0
  396. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.json +21 -0
  397. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +9 -0
  398. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +21 -0
  399. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +3 -0
  400. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.json +12 -0
  401. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
  402. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +176 -0
  403. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +345 -0
  404. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +118 -0
  405. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +76 -0
  406. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/adversarial.test.ts +53 -0
  407. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +384 -0
  408. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/check.test.ts +109 -0
  409. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/scenarios.test.ts +81 -0
  410. package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +53 -0
  411. package/templates/supplier-payments-agent/agents/supplier-payments-agent/tsconfig.json +9 -0
  412. package/templates/supplier-payments-agent/package.json +36 -0
  413. package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -0
  414. package/templates/supplier-payments-agent/packages/agent-core/package.json +24 -0
  415. package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +125 -0
  416. package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +175 -0
  417. package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +53 -0
  418. package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
  419. package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +117 -0
  420. package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +58 -0
  421. package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +123 -0
  422. package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +159 -0
  423. package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +140 -0
  424. package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +253 -0
  425. package/templates/supplier-payments-agent/packages/agent-core/src/clock.ts +42 -0
  426. package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +885 -0
  427. package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +85 -0
  428. package/templates/supplier-payments-agent/packages/agent-core/src/events.ts +40 -0
  429. package/templates/supplier-payments-agent/packages/agent-core/src/guardrails.ts +45 -0
  430. package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +62 -0
  431. package/templates/supplier-payments-agent/packages/agent-core/src/ids.ts +10 -0
  432. package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +32 -0
  433. package/templates/supplier-payments-agent/packages/agent-core/src/mandate.ts +100 -0
  434. package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +76 -0
  435. package/templates/supplier-payments-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
  436. package/templates/supplier-payments-agent/packages/agent-core/src/providers/replay.ts +63 -0
  437. package/templates/supplier-payments-agent/packages/agent-core/src/providers/types.ts +39 -0
  438. package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +101 -0
  439. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +401 -0
  440. package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +30 -0
  441. package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +30 -0
  442. package/templates/supplier-payments-agent/packages/agent-core/src/state/store.ts +307 -0
  443. package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +148 -0
  444. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
  445. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
  446. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +141 -0
  447. package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +55 -0
  448. package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +134 -0
  449. package/templates/supplier-payments-agent/packages/agent-core/test/approval.test.ts +117 -0
  450. package/templates/supplier-payments-agent/packages/agent-core/test/bundle.test.ts +85 -0
  451. package/templates/supplier-payments-agent/packages/agent-core/test/clock.test.ts +25 -0
  452. package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +596 -0
  453. package/templates/supplier-payments-agent/packages/agent-core/test/escalate.test.ts +42 -0
  454. package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
  455. package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
  456. package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +139 -0
  457. package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
  458. package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +45 -0
  459. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
  460. package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +316 -0
  461. package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +28 -0
  462. package/templates/supplier-payments-agent/packages/agent-core/test/state-machine.test.ts +67 -0
  463. package/templates/supplier-payments-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
  464. package/templates/supplier-payments-agent/packages/agent-core/tsconfig.json +10 -0
  465. package/templates/supplier-payments-agent/packages/agent-runtime/README.md +68 -0
  466. package/templates/supplier-payments-agent/packages/agent-runtime/bin.mjs +32 -0
  467. package/templates/supplier-payments-agent/packages/agent-runtime/package.json +23 -0
  468. package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +169 -0
  469. package/templates/supplier-payments-agent/packages/agent-runtime/src/agent.ts +68 -0
  470. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
  471. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/index.ts +72 -0
  472. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
  473. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +124 -0
  474. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
  475. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
  476. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
  477. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
  478. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
  479. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
  480. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
  481. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
  482. package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +98 -0
  483. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +15 -0
  484. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
  485. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
  486. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
  487. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
  488. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
  489. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
  490. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
  491. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
  492. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
  493. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +245 -0
  494. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
  495. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
  496. package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +83 -0
  497. package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +12 -0
  498. package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +797 -0
  499. package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +206 -0
  500. package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +105 -0
  501. package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +268 -0
  502. package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +229 -0
  503. package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +154 -0
  504. package/templates/supplier-payments-agent/packages/agent-runtime/src/webhook.ts +131 -0
  505. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
  506. package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
  507. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
  508. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
  509. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
  510. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
  511. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
  512. package/templates/supplier-payments-agent/packages/agent-runtime/tsconfig.json +9 -0
  513. package/templates/supplier-payments-agent/tsconfig.base.json +16 -0
  514. package/templates/supplier-payments-agent/vitest.config.ts +12 -0
  515. package/templates/bills-agent/agents/bills-agent/channels/terminal/index.ts +0 -108
  516. package/templates/bills-agent/agents/bills-agent/src/commands/approve.ts +0 -9
  517. package/templates/bills-agent/agents/bills-agent/src/commands/check.ts +0 -13
  518. package/templates/bills-agent/agents/bills-agent/src/commands/consent.ts +0 -26
  519. package/templates/bills-agent/agents/bills-agent/src/commands/decide.ts +0 -45
  520. package/templates/bills-agent/agents/bills-agent/src/commands/deny.ts +0 -7
  521. package/templates/bills-agent/agents/bills-agent/src/commands/eval.ts +0 -37
  522. package/templates/bills-agent/agents/bills-agent/src/commands/reconcile.ts +0 -38
  523. package/templates/bills-agent/agents/bills-agent/src/commands/rerun.ts +0 -65
  524. package/templates/bills-agent/agents/bills-agent/src/commands/resume.ts +0 -30
  525. package/templates/bills-agent/agents/bills-agent/src/main.ts +0 -185
  526. package/templates/collections-agent/agents/collections-agent/channels/terminal/index.ts +0 -178
  527. package/templates/collections-agent/agents/collections-agent/src/commands/approve.ts +0 -10
  528. package/templates/collections-agent/agents/collections-agent/src/commands/check.ts +0 -13
  529. package/templates/collections-agent/agents/collections-agent/src/commands/decide.ts +0 -48
  530. package/templates/collections-agent/agents/collections-agent/src/commands/deny.ts +0 -7
  531. package/templates/collections-agent/agents/collections-agent/src/commands/eval.ts +0 -39
  532. package/templates/collections-agent/agents/collections-agent/src/commands/poll.ts +0 -35
  533. package/templates/collections-agent/agents/collections-agent/src/commands/reconcile.ts +0 -38
  534. package/templates/collections-agent/agents/collections-agent/src/commands/rerun.ts +0 -55
  535. package/templates/collections-agent/agents/collections-agent/src/commands/resume.ts +0 -30
  536. package/templates/collections-agent/agents/collections-agent/src/commands/webhook.ts +0 -36
  537. package/templates/collections-agent/agents/collections-agent/src/main.ts +0 -193
  538. package/templates/collections-agent/agents/collections-agent/src/setup.ts +0 -250
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * `npm run check`: the manifest is the index, and the files it points to
3
3
  * must agree with it. Fails on a contradiction between `agent.yaml` and
4
- * `SYSTEM_PROMPT.md`, `tools.json` or `guardrails.json`, on `AGENTS.md`
5
- * and `CLAUDE.md` diverging, and on a missing `mcp`, `cli` or `schema`.
4
+ * `SYSTEM_PROMPT.md`, `tools.json`, `guardrails.json` or `channels/`, on
5
+ * `AGENTS.md` and `CLAUDE.md` diverging, and on a missing `mcp`, `cli` or
6
+ * `schema`.
6
7
  */
7
- import { existsSync, readFileSync } from "node:fs";
8
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
8
9
  import { join } from "node:path";
9
10
  import { parse as parseYaml } from "yaml";
11
+ import { ConversationScriptSchema, TemplateRegistrySchema, TEMPLATE_REGISTRY_FILE, templateArity } from "./channels.js";
10
12
  import { GuardrailsSchema } from "./guardrails.js";
11
13
  import { loadManifest, ManifestSchema, type LoadedManifest } from "./manifest.js";
12
14
  import { MandateSchema } from "./mandate.js";
@@ -58,6 +60,9 @@ export function checkAgent(agentDir: string): CheckReport {
58
60
 
59
61
  // tools.json
60
62
  let toolNames: string[] = [];
63
+ // Hoisted: the receipt-verification rule below needs it, and only a payment
64
+ // seals a receipt.
65
+ let hasPayment = false;
61
66
  const toolsPath = loaded.resolvePath(manifest.tools);
62
67
  if (!existsSync(toolsPath)) error("tools_missing", `${manifest.tools} does not exist`);
63
68
  else {
@@ -65,7 +70,7 @@ export function checkAgent(agentDir: string): CheckReport {
65
70
  if (!parsed.success) error("tools_invalid", parsed.error.message);
66
71
  else {
67
72
  toolNames = [...parsed.data.meta_tools, ...parsed.data.local_tools].map((t) => t.name);
68
- const hasPayment = parsed.data.meta_tools.some((t) => t.effect === "payment");
73
+ hasPayment = parsed.data.meta_tools.some((t) => t.effect === "payment");
69
74
  const declaresPixOut = manifest.maturity["pix-out"] !== undefined;
70
75
  if (declaresPixOut && !hasPayment) error("tools_contradict_manifest", "agent.yaml declares pix-out maturity but tools.json has no payment meta-tool");
71
76
  if (!declaresPixOut && hasPayment) error("tools_contradict_manifest", "tools.json has a payment meta-tool but agent.yaml declares no pix-out maturity");
@@ -92,6 +97,55 @@ export function checkAgent(agentDir: string): CheckReport {
92
97
  }
93
98
  }
94
99
 
100
+ // channels: the declaration and what the agent ships, checked BOTH ways.
101
+ //
102
+ // A channel is the runner's, but the conversations are the agent's, so
103
+ // `channels: [terminal, whatsapp]` is a claim about files. Declaring
104
+ // whatsapp without shipping a conversation gives a reader a channel that
105
+ // cannot be driven; shipping one without declaring it hides a surface the
106
+ // agent answers on. Both are errors, and a script that no longer parses is
107
+ // one too, because the simulator and this check read the same schema.
108
+ if (!manifest.channels.includes("terminal")) {
109
+ error("channels_terminal_missing", "agent.yaml must declare the terminal channel: `npm start` opens it and it needs no account");
110
+ }
111
+ // `templates.json` is the one file in there that is NOT a conversation: it
112
+ // is the local registry of the templates the agent declares it sends, which
113
+ // is what makes "this name was never registered here" a refusal the channel
114
+ // can make instead of a 400 from Meta. A conversation therefore cannot be
115
+ // called `templates`, and this is the only place that says so.
116
+ const whatsappDir = join(agentDir, "channels", "whatsapp");
117
+ const scripts = existsSync(whatsappDir) ? readdirSync(whatsappDir).filter((f) => f.endsWith(".json") && f !== TEMPLATE_REGISTRY_FILE).sort() : [];
118
+ if (manifest.channels.includes("whatsapp") && scripts.length === 0) {
119
+ error("channels_not_shipped", "agent.yaml declares the whatsapp channel but channels/whatsapp/ ships no conversation for the simulator to drive");
120
+ }
121
+ if (!manifest.channels.includes("whatsapp") && scripts.length > 0) {
122
+ error("channels_undeclared", `channels/whatsapp/ ships ${scripts.length} conversation(s) but agent.yaml does not declare the whatsapp channel`);
123
+ }
124
+ for (const file of scripts) {
125
+ const parsed = ConversationScriptSchema.safeParse(JSON.parse(readFileSync(join(whatsappDir, file), "utf8")));
126
+ if (!parsed.success) error("channels_script_invalid", `channels/whatsapp/${file}: ${parsed.error.message}`);
127
+ else if (parsed.data.name !== file.replace(/\.json$/, "")) error("channels_script_invalid", `channels/whatsapp/${file} declares name ${parsed.data.name}`);
128
+ }
129
+ const registryPath = join(whatsappDir, TEMPLATE_REGISTRY_FILE);
130
+ if (existsSync(registryPath)) {
131
+ const parsed = TemplateRegistrySchema.safeParse(JSON.parse(readFileSync(registryPath, "utf8")));
132
+ if (!parsed.success) error("channels_templates_invalid", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE}: ${parsed.error.message}`);
133
+ else {
134
+ // A body with no placeholder takes no variables, and one with `{{3}}`
135
+ // and no `{{2}}` cannot be filled: Meta numbers them from 1 without
136
+ // gaps, and a send that skips one is a 132000 nobody sees until the
137
+ // first real message goes out.
138
+ for (const template of parsed.data.templates) {
139
+ const arity = templateArity(template.body);
140
+ for (let n = 1; n <= arity; n += 1) {
141
+ if (!new RegExp(`\\{\\{\\s*${n}\\s*\\}\\}`).test(template.body)) {
142
+ error("channels_templates_invalid", `channels/whatsapp/${TEMPLATE_REGISTRY_FILE}: ${template.name} uses {{${arity}}} but never {{${n}}}; Meta numbers variables from 1 with no gaps`);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+
95
149
  // mandate.example.json
96
150
  const mandatePath = loaded.resolvePath(manifest.mandate_schema);
97
151
  if (!existsSync(mandatePath)) error("mandate_missing", `${manifest.mandate_schema} does not exist`);
@@ -139,7 +193,23 @@ export function checkAgent(agentDir: string): CheckReport {
139
193
  }
140
194
  }
141
195
 
142
- // Wording the README must not carry (section 6).
196
+ // Wording the docs must not carry UNQUALIFIED (section 6).
197
+ //
198
+ // Until ent#1633 the phrase was forbidden outright, because nothing in the
199
+ // product supported it. A receipt sealed since then carries an Ed25519
200
+ // signature over `codespar-receipt:v1:<id>:<chain>` that anybody can check
201
+ // against the published key set, so the claim is now true — of that, and of
202
+ // nothing else here. Every receipt sealed BEFORE the change carries no such
203
+ // signature and never will, and the approval artifact is still HMAC with a
204
+ // local development key.
205
+ //
206
+ // So the rule is no longer "never write it". It is two conditions, and an
207
+ // agent has to meet both. The agent must actually MINT a receipt that
208
+ // carries the seal — only a payment does, and `maturity` is where the agent
209
+ // says so — and the doc must NAME the mechanism, which is the word that
210
+ // tells a reader which of the two claims is being made.
211
+ const verificationMaturity = manifest.maturity["receipt-verification"];
212
+ const sealsVerifiableReceipts = hasPayment && verificationMaturity !== undefined && verificationMaturity !== "blocked";
143
213
  for (const file of ["README.md", "runbook.md", "SYSTEM_PROMPT.md"]) {
144
214
  const path = join(agentDir, file);
145
215
  if (!existsSync(path)) {
@@ -147,8 +217,12 @@ export function checkAgent(agentDir: string): CheckReport {
147
217
  continue;
148
218
  }
149
219
  const text = readFileSync(path, "utf8").toLowerCase();
150
- if (text.includes("verificável por terceiro") || text.includes("verifiable by a third party") || text.includes("third-party verifiable")) {
151
- error("doc_overclaims", `${file} claims third-party verifiability; the receipt is HMAC until Ed25519`);
220
+ const claims = text.includes("verificável por terceiro") || text.includes("verifiable by a third party") || text.includes("third-party verifiable");
221
+ if (!claims) continue;
222
+ if (!sealsVerifiableReceipts) {
223
+ error("doc_overclaims", `${file} claims third-party verifiability, and this agent seals nothing that carries it: only a payment receipt gets an Ed25519 signature, and agent.yaml declares receipt-verification as \`${verificationMaturity ?? "absent"}\``);
224
+ } else if (!text.includes("ed25519")) {
225
+ error("doc_overclaims", `${file} claims third-party verifiability without naming Ed25519; the receipt's asymmetric seal is the only thing here a third party can check, and receipts sealed before it — and the approval artifact — are HMAC`);
152
226
  }
153
227
  }
154
228
 
@@ -165,7 +239,15 @@ export function checkAgent(agentDir: string): CheckReport {
165
239
  if (!keys.includes("CODESPAR_API_KEY") || !keys.includes("ANTHROPIC_API_KEY")) error("env_example_incomplete", ".env.example must declare CODESPAR_API_KEY and ANTHROPIC_API_KEY");
166
240
  }
167
241
 
168
- if (manifest.maturity["receipt-verification"] === "live") warning("maturity_overclaims", "receipt-verification cannot be live before Ed25519");
242
+ // `receipt-verification` used to be a warning at `live`, because Ed25519 did
243
+ // not exist. It does (ent#1633), so what is left to check is the coherence
244
+ // the other maturity rules check: only a PAYMENT seals a receipt. A paid
245
+ // charge is reported by the API with no chain and no signature, so an agent
246
+ // that issues receivables and declares this capability beyond `blocked` is
247
+ // claiming a verification its records cannot carry.
248
+ if (verificationMaturity !== undefined && verificationMaturity !== "blocked" && !hasPayment) {
249
+ error("maturity_overclaims", "agent.yaml declares receipt-verification beyond `blocked` and tools.json has no payment meta-tool; only a payment seals a receipt, and a paid charge carries no signature to verify");
250
+ }
169
251
 
170
252
  return { ok: findings.every((f) => f.level !== "error"), agent: manifest.name, findings };
171
253
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A clock pinned to an instant the caller chose, for a run whose outcome must
3
+ * not depend on the hour it happens to execute at (the CI, a demo, a test).
4
+ * `ExecutionEngine`, the stubs, the status gate and the loop all take a
5
+ * `clock` dependency; this is the one the one-shot runner hands them when
6
+ * `--now` or `CODESPAR_AGENT_NOW` is set. The scenario runner freezes its own
7
+ * clock the same way.
8
+ *
9
+ * The clock advances one second per read so no two events share an instant,
10
+ * which is what the scenario runner does too.
11
+ */
12
+
13
+ export const FIXED_CLOCK_ENV = "CODESPAR_AGENT_NOW";
14
+
15
+ export class InvalidFixedClockError extends Error {
16
+ constructor(value: string, source: string) {
17
+ super(`${source} must be an ISO 8601 instant (e.g. 2026-09-23T14:00:00-03:00), got "${value}"`);
18
+ this.name = "InvalidFixedClockError";
19
+ }
20
+ }
21
+
22
+ /** A clock that starts at `iso` and ticks one second per read. Throws on a value `Date` cannot parse. */
23
+ export function fixedClock(iso: string, source = "--now"): () => Date {
24
+ const start = new Date(iso);
25
+ if (!/^\d{4}-\d{2}-\d{2}T/.test(iso.trim()) || Number.isNaN(start.getTime())) throw new InvalidFixedClockError(iso, source);
26
+ let current = start.getTime() - 1000;
27
+ return () => {
28
+ current += 1000;
29
+ return new Date(current);
30
+ };
31
+ }
32
+
33
+ /**
34
+ * The clock a command runs with: the `--now` flag, else `CODESPAR_AGENT_NOW`
35
+ * from the environment, else `undefined` (the wall clock, the caller's default).
36
+ */
37
+ export function resolveFixedClock(flag: string | undefined, env: NodeJS.ProcessEnv = process.env): (() => Date) | undefined {
38
+ if (flag !== undefined) return fixedClock(flag, "--now");
39
+ const fromEnv = env[FIXED_CLOCK_ENV];
40
+ if (fromEnv !== undefined && fromEnv.trim() !== "") return fixedClock(fromEnv, FIXED_CLOCK_ENV);
41
+ return undefined;
42
+ }
@@ -20,11 +20,11 @@ import { itemsHash, sha256Hex } from "./hash.js";
20
20
  import { newId } from "./ids.js";
21
21
  import { mandateExpired, payeeAllowed, resolveBeneficiary, windowCap, windowStart, type Mandate } from "./mandate.js";
22
22
  import type { Manifest } from "./manifest.js";
23
- import type { PaymentRail, RailPayment } from "./rail.js";
23
+ import type { PaymentRail, RailOutcome, RailPayment } from "./rail.js";
24
24
  import type { MandateStatusReport, MandateStatusSource } from "./revocation.js";
25
25
  import { isTerminal, transition, type Execution, type ExecutionState } from "./state-machine.js";
26
26
  import type { StateStore } from "./state/store.js";
27
- import type { Actor, ApprovalArtifact, ApprovalMode, ExecutionItem, ExecutionReason, ItemOutcome } from "./types.js";
27
+ import type { Actor, ApprovalArtifact, ApprovalMode, ExecutionBatch, ExecutionItem, ExecutionReason, ItemOutcome } from "./types.js";
28
28
 
29
29
  export interface ProposedItem {
30
30
  /** An alias from the mandate's named payees, or a raw payee key. */
@@ -54,6 +54,13 @@ export interface Proposal {
54
54
  items: ProposedItem[];
55
55
  /** What the model said the total was. Recorded; never used to pay. */
56
56
  claimed_total?: number;
57
+ /**
58
+ * The batch this proposal is one line of, when it is one. The kit computes
59
+ * it once over the whole ordered list before drafting any of it; the core
60
+ * stamps it on the execution and every artifact of that execution carries
61
+ * it. The core never invents one and never fills one in.
62
+ */
63
+ batch?: ExecutionBatch;
57
64
  }
58
65
 
59
66
  export type DraftResult =
@@ -119,6 +126,7 @@ export class ExecutionEngine {
119
126
 
120
127
  const items = proposal.items.map((p) => this.resolveItem(p));
121
128
  const total = items.reduce((sum, i) => sum + i.amount, 0);
129
+ if (proposal.batch) assertBatchBinding(proposal.batch);
122
130
  const id = newId("exe");
123
131
  const execution: Execution<"drafted"> = {
124
132
  id,
@@ -131,6 +139,7 @@ export class ExecutionEngine {
131
139
  currency: this.deps.mandate.currency,
132
140
  ...(proposal.claimed_total !== undefined ? { model_claimed_total: proposal.claimed_total } : {}),
133
141
  items_hash: itemsHash(items),
142
+ ...(proposal.batch ? { batch: proposal.batch } : {}),
134
143
  mandate: { id: this.deps.mandate.id, version: this.deps.mandate.version },
135
144
  idempotency_key: `idk_${sha256Hex(`${this.deps.runId}:${id}`).slice(0, 32)}`,
136
145
  blocking_reasons: [],
@@ -140,7 +149,7 @@ export class ExecutionEngine {
140
149
  updated_at: now.toISOString(),
141
150
  };
142
151
  this.deps.store.saveExecution(execution);
143
- this.record("execution.drafted", id, { items: execution.items, total, model_claimed_total: proposal.claimed_total ?? null, mode: this.deps.mode });
152
+ this.record("execution.drafted", id, { items: execution.items, total, model_claimed_total: proposal.claimed_total ?? null, mode: this.deps.mode, batch: execution.batch ?? null });
144
153
 
145
154
  return { ok: true, execution: await this.evaluateDraft(execution) };
146
155
  }
@@ -333,20 +342,26 @@ export class ExecutionEngine {
333
342
  */
334
343
  private async dispatch(execution: Execution<"executing">, payments: RailPayment[]): Promise<Execution> {
335
344
  const outcomes: ItemOutcome[] = [...execution.outcomes];
345
+ const unknown: string[] = [];
336
346
  this.deps.store.updateOutbox(execution.idempotency_key, "sent", undefined, this.clock().toISOString());
337
347
 
338
348
  for (const [index, payment] of payments.entries()) {
339
349
  if (outcomes.some((o) => o.index === index)) continue;
340
- this.record("rail.dispatch", execution.id, { attempt_id: payment.attempt_id, payee: payment.payee, amount: payment.amount_minor, rail: this.deps.rail.name });
350
+ // The dispatch line is the request. `idempotency_key` is what makes a retry the same payment, so the bundle names it next to the attempt.
351
+ this.record("rail.dispatch", execution.id, { attempt_id: payment.attempt_id, payee: payment.payee, amount: payment.amount_minor, rail: this.deps.rail.name, idempotency_key: execution.idempotency_key });
341
352
  const outcome = await this.deps.rail.pay(payment);
342
- this.record("rail.outcome", execution.id, { attempt_id: payment.attempt_id, status: outcome.status, ...(outcome.status === "failed" || outcome.status === "uncertain" ? { code: outcome.code } : {}) });
353
+ this.record("rail.outcome", execution.id, { attempt_id: payment.attempt_id, status: outcome.status, ...railAnswer(outcome) });
343
354
  if (outcome.status === "uncertain") {
344
355
  this.record("rail.uncertain", execution.id, { attempt_id: payment.attempt_id, code: outcome.code, message: outcome.message });
345
- return this.leaveUnresolved({ ...execution, outcomes }, `attempt ${payment.attempt_id}: ${outcome.code} — outcome unknown, kept for reconciliation`);
356
+ // No outcome is recorded because there is none. The siblings are still
357
+ // sent: an unknown answer about THIS payee says nothing about the next
358
+ // one, and the execution stays open until reconciliation settles it.
359
+ unknown.push(`attempt ${payment.attempt_id}: ${outcome.code} — outcome unknown, kept for reconciliation`);
360
+ continue;
346
361
  }
347
362
  if (outcome.status === "failed") {
348
363
  outcomes.push({ index, attempt_id: payment.attempt_id, status: "failed", code: outcome.code, error: `${outcome.code}: ${outcome.message}` });
349
- break;
364
+ continue;
350
365
  }
351
366
  if (outcome.status === "accepted") {
352
367
  // A receivable was issued; the payer decides the rest. Nothing settles here.
@@ -357,21 +372,29 @@ export class ExecutionEngine {
357
372
  outcomes.push({ index, attempt_id: payment.attempt_id, status: "settled", transaction_id: outcome.transaction_id, ...(outcome.receipt_id ? { receipt_id: outcome.receipt_id } : {}) });
358
373
  await this.ingestSettlement(execution, index, payment, outcome.receipt_id, PAYMENT_SUCCEEDED);
359
374
  }
360
- return this.close({ ...execution, outcomes }, payments.length);
375
+ return this.close({ ...execution, outcomes }, payments.length, unknown.join("; ") || undefined);
361
376
  }
362
377
 
363
378
  /**
364
379
  * Closes an `executing` execution from its recorded outcomes: stays while a
365
- * receivable is accepted and unpaid, failed if any attempt failed, settled
366
- * when every attempt settled, otherwise unresolved.
380
+ * receivable is accepted and unpaid, stays while any attempt has no outcome
381
+ * at all, failed if any attempt failed, settled when every attempt settled.
382
+ *
383
+ * The order matters. An execution does not close while one of its attempts
384
+ * is unknown, even when another one failed: "some of this moved and one of
385
+ * them we cannot see" is not a closed outcome, and closing it as `failed`
386
+ * would report a batch as finished while a payment may still be in flight.
367
387
  */
368
- private close(execution: Execution<"executing">, attempts: number): Execution {
388
+ private close(execution: Execution<"executing">, attempts: number, unknownDetail?: string): Execution {
369
389
  const at = this.clock().toISOString();
370
390
  const updated: Execution<"executing"> = { ...execution, updated_at: at };
371
391
  const accepted = execution.outcomes.filter((o) => o.status === "accepted");
372
392
  if (accepted.length > 0) {
373
393
  return this.leaveAwaiting(updated, `${accepted.length} receivable(s) issued and unpaid: ${accepted.map((o) => o.transaction_id ?? o.attempt_id).join(", ")}`);
374
394
  }
395
+ if (execution.outcomes.length < attempts) {
396
+ return this.leaveUnresolved(updated, unknownDetail ?? `${execution.outcomes.length} of ${attempts} attempt(s) have an outcome`);
397
+ }
375
398
  const failed = execution.outcomes.find((o) => o.status === "failed");
376
399
  if (failed) {
377
400
  this.deps.store.updateOutbox(execution.idempotency_key, "failed", execution.outcomes, at);
@@ -438,6 +461,7 @@ export class ExecutionEngine {
438
461
  }
439
462
  }
440
463
 
464
+
441
465
  /**
442
466
  * Fetches into the bundle the receipts of settled attempts the bundle does
443
467
  * not hold yet (a settlement that arrived by event names a receipt id and
@@ -480,7 +504,7 @@ export class ExecutionEngine {
480
504
  const prior = outcomes.find((o) => o.index === index);
481
505
  // Settled and failed are final. An accepted receivable is looked at again: its payer may have acted.
482
506
  if (prior && prior.status !== "accepted") continue;
483
- const seen = await this.deps.rail.lookup(payment.attempt_id, payment);
507
+ const seen = await this.deps.rail.lookup(payment.attempt_id, payment, prior?.transaction_id);
484
508
  const found = seen ? seen.status : "absent";
485
509
  const stored = this.deps.store.appendEvent({
486
510
  run_id: this.deps.runId,
@@ -494,8 +518,12 @@ export class ExecutionEngine {
494
518
  if (stored) this.deps.bundle.event({ ...stored, actor: this.agentActor });
495
519
  if (!seen || seen.status === "uncertain" || seen.status === "in_flight") {
496
520
  if (prior) continue; // the receivable is known to exist; the rail just did not answer this time
497
- unresolved = `attempt ${payment.attempt_id}: ${seen ? seen.status : "unknown to the rail"}; a human decides, nothing is re-sent`;
498
- break;
521
+ // One attempt the rail cannot answer for does not stop us learning
522
+ // about the others. A lookup moves no money, so there is nothing to
523
+ // be careful about here, and stopping would mean a later attempt's
524
+ // settlement is never recorded at all.
525
+ unresolved ??= `attempt ${payment.attempt_id}: ${seen ? seen.status : "unknown to the rail"}; a human decides, nothing is re-sent`;
526
+ continue;
499
527
  }
500
528
  const replace = (outcome: ItemOutcome) => {
501
529
  const at = outcomes.findIndex((o) => o.index === index);
@@ -509,7 +537,6 @@ export class ExecutionEngine {
509
537
  }
510
538
  if (seen.status === "failed") {
511
539
  replace({ index, attempt_id: payment.attempt_id, status: "failed", code: seen.code, error: `${seen.code}: ${seen.message}` });
512
- if (!prior) break;
513
540
  continue;
514
541
  }
515
542
  replace({ index, attempt_id: payment.attempt_id, status: "settled", transaction_id: seen.transaction_id, ...(seen.receipt_id ? { receipt_id: seen.receipt_id } : {}) });
@@ -643,6 +670,27 @@ export class ExecutionEngine {
643
670
  return true;
644
671
  }
645
672
 
673
+ /**
674
+ * A durable claim for work whose unit is bigger than one execution: a batch
675
+ * line, a scheduled instruction. `claimed` reads which execution covers a
676
+ * key, `claim` records it. Same cursor table as `markShown`, which is this
677
+ * with a boolean answer.
678
+ *
679
+ * It exists because a tool handler's only durable surface is this engine,
680
+ * and a batch that must not pay the same payee twice across runs has to
681
+ * remember which execution already covers each line. What a held claim
682
+ * MEANS is the kit's to decide: the engine records the pairing and reads
683
+ * nothing into it, because "settled, so skip" and "denied, so retry" are
684
+ * the batch's rules and not the state machine's.
685
+ */
686
+ claimed(key: string): string | undefined {
687
+ return this.deps.store.getCursor(`claim:${key}`);
688
+ }
689
+
690
+ claim(key: string, executionId: string): void {
691
+ this.deps.store.setCursor(`claim:${key}`, executionId);
692
+ }
693
+
646
694
  // ---- reads --------------------------------------------------------------
647
695
 
648
696
  get(executionId: string): Execution | undefined {
@@ -653,6 +701,22 @@ export class ExecutionEngine {
653
701
  return this.deps.store.listExecutions({ ...filter, mandate_id: this.deps.mandate.id });
654
702
  }
655
703
 
704
+ /**
705
+ * The items `draft()` would build from these proposals, resolved against
706
+ * the mandate and WITHOUT the validation that refuses one. It exists for a
707
+ * caller that must hash a whole list before it drafts any of it — a batch
708
+ * computing its `batch_hash` — and it does not throw on purpose: a line the
709
+ * core will refuse is still a line of the presented list, and dropping it
710
+ * from the hash would make a batch holding a broken line hash the same as
711
+ * the shorter batch without it, which is the hole `batch_hash` closes.
712
+ *
713
+ * It resolves nothing the draft will not resolve identically, which is what
714
+ * makes the hash computed here the hash the drafts below carry.
715
+ */
716
+ preview(items: readonly ProposedItem[]): ExecutionItem[] {
717
+ return items.map((p) => this.previewItem(p));
718
+ }
719
+
656
720
  // ---- helpers ------------------------------------------------------------
657
721
 
658
722
  /**
@@ -687,15 +751,19 @@ export class ExecutionEngine {
687
751
  }
688
752
 
689
753
  private resolveItem(proposed: ProposedItem): ExecutionItem {
690
- const known = resolveBeneficiary(this.deps.mandate, proposed.payee);
691
754
  const amount = Math.trunc(proposed.amount);
692
755
  if (!Number.isFinite(amount) || amount <= 0) throw new Error(`amount must be a positive integer in minor units, got ${proposed.amount}`);
693
756
  if (proposed.due_date !== undefined && !/^\d{4}-\d{2}-\d{2}$/.test(proposed.due_date)) throw new Error(`due_date must be YYYY-MM-DD, got ${proposed.due_date}`);
757
+ return this.previewItem(proposed);
758
+ }
759
+
760
+ private previewItem(proposed: ProposedItem): ExecutionItem {
761
+ const known = resolveBeneficiary(this.deps.mandate, proposed.payee);
694
762
  return {
695
763
  ...(known ? { alias: known.alias } : {}),
696
764
  beneficiary: known?.name ?? proposed.payee,
697
765
  payee: known?.payee ?? proposed.payee,
698
- amount,
766
+ amount: Math.trunc(proposed.amount),
699
767
  currency: this.deps.mandate.currency,
700
768
  ...(proposed.description ? { description: proposed.description } : {}),
701
769
  ...(proposed.due_date ? { due_date: proposed.due_date } : {}),
@@ -712,6 +780,7 @@ export class ExecutionEngine {
712
780
  beneficiary: item.beneficiary,
713
781
  purpose: this.deps.mandate.purpose,
714
782
  agent_id: this.deps.mandate.agent_id,
783
+ consumer_id: this.deps.mandate.consumer_id,
715
784
  ...(item.description ? { description: item.description } : {}),
716
785
  ...(item.due_date ? { due_date: item.due_date } : {}),
717
786
  actor: this.agentActor,
@@ -758,7 +827,7 @@ export class ExecutionEngine {
758
827
  private storeApproval(artifact: ApprovalArtifact): void {
759
828
  this.deps.store.saveApproval(artifact);
760
829
  this.deps.bundle.approval(artifact);
761
- this.record("approval.created", artifact.execution_id, { approval_id: artifact.approval_id, approver: artifact.approver, items_hash: artifact.items_hash, escalation: artifact.escalation ?? null });
830
+ this.record("approval.created", artifact.execution_id, { approval_id: artifact.approval_id, approver: artifact.approver, items_hash: artifact.items_hash, batch: artifact.batch ?? null, escalation: artifact.escalation ?? null });
762
831
  }
763
832
 
764
833
  private persist<S extends ExecutionState>(execution: Execution<S>): Execution<S> {
@@ -782,3 +851,35 @@ export class ExecutionEngine {
782
851
  return execution;
783
852
  }
784
853
  }
854
+
855
+ /**
856
+ * A batch binding is the kit's to compute and the core's to refuse when it
857
+ * cannot be true. `index` outside `count`, or a `count` of zero, would let a
858
+ * bundle say "line 5 of 3" and make the "N of M" an artifact reader sees
859
+ * meaningless, so it is rejected where the execution is minted rather than
860
+ * carried into the signature.
861
+ */
862
+ function assertBatchBinding(batch: ExecutionBatch): void {
863
+ if (!batch.ref.trim()) throw new Error("batch.ref must name the batch");
864
+ if (!batch.batch_hash.trim()) throw new Error("batch.batch_hash must be the hash of the presented lines");
865
+ if (!Number.isInteger(batch.count) || batch.count < 1) throw new Error(`batch.count must be a positive integer, got ${batch.count}`);
866
+ if (!Number.isInteger(batch.index) || batch.index < 0 || batch.index >= batch.count) {
867
+ throw new Error(`batch.index must be a position inside the batch (0..${batch.count - 1}), got ${batch.index}`);
868
+ }
869
+ }
870
+
871
+ /**
872
+ * What the rail answered about one attempt, as the bundle records it: the
873
+ * identifiers a reader follows the money by, and never `raw`, which carries
874
+ * whatever the provider chose to echo back.
875
+ */
876
+ function railAnswer(outcome: RailOutcome): Record<string, unknown> {
877
+ switch (outcome.status) {
878
+ case "accepted":
879
+ return { transaction_id: outcome.transaction_id, sandbox: outcome.sandbox };
880
+ case "settled":
881
+ return { transaction_id: outcome.transaction_id, receipt_id: outcome.receipt_id, money_moved: outcome.money_moved, sandbox: outcome.sandbox };
882
+ default:
883
+ return { code: outcome.code, message: outcome.message };
884
+ }
885
+ }
@@ -39,6 +39,19 @@ export function itemsHash(items: readonly ExecutionItem[]): string {
39
39
  return `sha256:${sha256Hex(canonicalJson(canonical))}`;
40
40
  }
41
41
 
42
+ /**
43
+ * The hash of a batch's ordered lines, bound into every artifact of that
44
+ * batch. It IS `itemsHash` over the whole list and deliberately not a second
45
+ * canonicalisation: the same fields decide the set that decide the line, so a
46
+ * reader who concatenates the batch's lines in order and hashes them gets the
47
+ * batch's hash back, and any line moved, re-priced, added or dropped changes
48
+ * it. Order is part of it — `index` names a position, and a position only
49
+ * means something in a list whose order is fixed.
50
+ */
51
+ export function batchHash(lines: readonly ExecutionItem[]): string {
52
+ return itemsHash(lines);
53
+ }
54
+
42
55
  export function hmacSha256Hex(key: Buffer, payload: string): string {
43
56
  return createHmac("sha256", key).update(payload).digest("hex");
44
57
  }
@@ -5,11 +5,14 @@ export * from "./ids.js";
5
5
  export * from "./approval.js";
6
6
  export * from "./manifest.js";
7
7
  export * from "./guardrails.js";
8
+ export * from "./channels.js";
8
9
  export * from "./mandate.js";
9
10
  export * from "./escalate.js";
11
+ export * from "./clock.js";
10
12
  export * from "./secrets.js";
11
13
  export * from "./revocation.js";
12
14
  export * from "./rail.js";
15
+ export * from "./receipt-verification.js";
13
16
  export * from "./tools.js";
14
17
  export * from "./bundle.js";
15
18
  export * from "./engine.js";
@@ -34,7 +34,7 @@ export const ManifestSchema = z
34
34
  default_approval: z.enum(["human", "mandate"]),
35
35
  escalate_above: EscalateAboveSchema.optional(),
36
36
  mcp: z.string().regex(PINNED_PACKAGE, "mcp must pin an exact version, e.g. @codespar/mcp@0.5.8"),
37
- cli: z.string().regex(PINNED_PACKAGE, "cli must pin an exact version, e.g. @codespar/cli@0.13.0"),
37
+ cli: z.string().regex(PINNED_PACKAGE, "cli must pin an exact version, e.g. @codespar/cli@0.14.0"),
38
38
  tools: z.string(),
39
39
  guardrails: z.string(),
40
40
  mandate_schema: z.string(),
@@ -15,6 +15,8 @@ export interface RailPayment {
15
15
  payee: string;
16
16
  purpose: string;
17
17
  agent_id: string;
18
+ /** The principal the agent acts for (the mandate's `consumer_id`). A receivable settles into THIS identity's account; `POST /v1/charges` needs it on the wire. */
19
+ consumer_id?: string;
18
20
  description?: string;
19
21
  /** Display name of the counterparty (a receivable's debtor). The rail that issues a charge needs it; a payout rail ignores it. */
20
22
  beneficiary?: string;
@@ -70,6 +72,14 @@ export interface RailReceipt {
70
72
  /** Null when the API seals nothing for this kind of record. */
71
73
  chain: string | null;
72
74
  receipt_sig: string | null;
75
+ /** The Ed25519 signature CodeSpar seals alongside the HMAC (base64url) and
76
+ * the published key that made it. Null on a receipt sealed before the API
77
+ * had the capability, on a record the API seals nothing for (a paid
78
+ * charge), and on the stub rail, which is not CodeSpar and must not look
79
+ * like it. Carried onto the bundle's copy so THAT copy is what a third
80
+ * party checks: `npm run verify runs/<run-id>/receipts/<id>.json`. */
81
+ receipt_sig_ed25519: string | null;
82
+ receipt_sig_kid: string | null;
73
83
  /** Section 4.5: the kit stamps the actor onto the local copy of every receipt. */
74
84
  actor: Actor;
75
85
  raw: unknown;
@@ -81,7 +91,11 @@ export type RailLookup = RailOutcome | { status: "in_flight" } | undefined;
81
91
  export interface PaymentRail {
82
92
  readonly name: "stub" | "codespar" | "stub-charge" | "codespar-charge";
83
93
  pay(payment: RailPayment): Promise<RailOutcome>;
84
- /** Answers the outcome of an attempt already presented, `in_flight` while the rail is still on it, or `undefined` when the rail never saw it. */
85
- lookup(attemptId: string, payment: RailPayment): Promise<RailLookup>;
94
+ /**
95
+ * Answers the outcome of an attempt already presented, `in_flight` while the rail is still on it, or `undefined` when the rail
96
+ * never saw it. `transactionId` is the rail's own id for the attempt when the core recorded one (an accepted receivable): a rail
97
+ * whose read is keyed on its id and not on the caller's key looks it up by that.
98
+ */
99
+ lookup(attemptId: string, payment: RailPayment, transactionId?: string): Promise<RailLookup>;
86
100
  receipt(receiptId: string, actor: Actor): Promise<RailReceipt | undefined>;
87
101
  }