@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
@@ -8,14 +8,13 @@ import { mkdtempSync } from "node:fs";
8
8
  import { tmpdir } from "node:os";
9
9
  import { join } from "node:path";
10
10
  import { describe, expect, it } from "vitest";
11
- import { announceOutcome } from "../channels/terminal/index.js";
12
- import { createWebhookHandler, verifySignature } from "../channels/webhook/index.js";
13
- import { RUNS_DIR, setup } from "../src/setup.js";
11
+ import { announceOutcome, createWebhookHandler, setup, verifySignature } from "@codespar/agent-runtime";
12
+ import { agent } from "../src/kit.js";
14
13
 
15
14
  function issued(mode: "human" | "mandate" = "mandate") {
16
15
  let clock = new Date("2026-09-23T18:00:00Z");
17
- const s = setup({ mode, rail: "stub", provider: "replay", transcript: "unused", stateDir: mkdtempSync(join(tmpdir(), "collections-webhook-")), runsDir: mkdtempSync(join(tmpdir(), "collections-webhook-runs-")), now: () => (clock = new Date(clock.getTime() + 1000)), say: () => undefined });
18
- s.payer.behave("never");
16
+ const s = setup(agent, { mode, rail: "stub", provider: "replay", transcript: "unused", stateDir: mkdtempSync(join(tmpdir(), "collections-webhook-")), runsDir: mkdtempSync(join(tmpdir(), "collections-webhook-runs-")), now: () => (clock = new Date(clock.getTime() + 1000)), say: () => undefined });
17
+ s.payer!.behave("never");
19
18
  return s;
20
19
  }
21
20
 
@@ -96,5 +95,3 @@ describe("channels/webhook", () => {
96
95
  }
97
96
  });
98
97
  });
99
-
100
- void RUNS_DIR;
@@ -0,0 +1,271 @@
1
+ /**
2
+ * The case the channel could not run before: agreed on Tuesday, paid on
3
+ * Friday.
4
+ *
5
+ * Every case that converses runs TWO processes over ONE state directory,
6
+ * because that is the shape in production — the run that agreed the terms has
7
+ * exited by the time the money lands, and what carries the cycle across is
8
+ * the record it left. Between them the CONVERSATION's clock moves
9
+ * (`POST /_sim/clock`), which is a different thing from the AGENT's clock
10
+ * (`--now`, #16): one is where the person's last message sits, the other is
11
+ * what the guardrails and the window comparison read.
12
+ *
13
+ * What is asserted is which CARRIER the confirmation went out on and that the
14
+ * cycle closed, never the wording. Read the template assertions precisely:
15
+ * the emulator prices the 24-hour window and does not enforce it
16
+ * (docs/OPEN_QUESTIONS.md §46a), so what passes here is OUR choice of
17
+ * carrier, made by the session window, and not the provider refusing the
18
+ * alternative.
19
+ *
20
+ * The conversing cases SKIP without the emulator, like the rest of the
21
+ * channel suite; `npm run whatsapp:gate` fails rather than skipping, so the
22
+ * thing that matters never hides behind one. The cases that need no
23
+ * conversation at all — the no-op, the flag that belongs to another channel —
24
+ * run everywhere.
25
+ */
26
+ import { spawnSync } from "node:child_process";
27
+ import { existsSync, mkdtempSync, readFileSync, readdirSync } from "node:fs";
28
+ import { tmpdir } from "node:os";
29
+ import { isAbsolute, join, resolve } from "node:path";
30
+ import { DatabaseSync } from "node:sqlite";
31
+ import { describe, expect, it } from "vitest";
32
+
33
+ const AGENT_DIR = resolve(import.meta.dirname, "..");
34
+ const NODE = process.execPath;
35
+ const BIN = resolve(AGENT_DIR, "../../packages/agent-runtime/bin.mjs");
36
+ const EMULATOR = process.env["WHATSAPP_SIM_URL"] ?? "http://127.0.0.1:4290";
37
+
38
+ /** Tuesday, inside the collection hours the guardrails declare. */
39
+ const TUESDAY = "2026-09-23T14:00:00-03:00";
40
+ const ADVANCE_HOURS = 26;
41
+ /** The same instant plus the advance: 16:00 in Sao Paulo, still inside 08:00-20:00. */
42
+ const AFTER_WINDOW = new Date(new Date(TUESDAY).getTime() + ADVANCE_HOURS * 3600_000).toISOString();
43
+ /**
44
+ * The recording where the charge is issued and NOBODY has paid yet. The
45
+ * shipped happy-path one closes with "quitado" because its payer paid inside
46
+ * the turn; here that would be a lie, and it is the lie this whole command
47
+ * exists to stop telling.
48
+ */
49
+ const AGREED = "test/fixtures/agreed-1042-awaiting-payer.transcript.jsonl";
50
+
51
+ interface ChannelLine {
52
+ direction: "in" | "out";
53
+ kind: string;
54
+ text?: string;
55
+ message_id: string;
56
+ provider_timestamp?: number;
57
+ refused?: { rule: string };
58
+ }
59
+
60
+ interface Polled {
61
+ id: string;
62
+ state: string;
63
+ reason: string | null;
64
+ timed_out: boolean;
65
+ session_open: boolean;
66
+ delivery: { told: boolean; carrier?: string; template?: string; reason?: string };
67
+ }
68
+
69
+ interface PollPayload {
70
+ polled: Polled[];
71
+ conversation: string;
72
+ channel: { backend: string; session_open: boolean; messages_out: number; refused: Array<{ rule: string }>; log: string } | null;
73
+ }
74
+
75
+ function scratch(label: string) {
76
+ const stateDir = mkdtempSync(join(tmpdir(), `collections-wa-poll-${label}-`));
77
+ return { COLLECTIONS_STATE_DIR: stateDir, COLLECTIONS_RUNS_DIR: join(stateDir, "runs") };
78
+ }
79
+
80
+ function agent(args: string[], env: Record<string, string>) {
81
+ const result = spawnSync(NODE, [BIN, ...args], {
82
+ cwd: AGENT_DIR,
83
+ env: {
84
+ ...process.env,
85
+ ANTHROPIC_API_KEY: "",
86
+ CODESPAR_API_KEY: "",
87
+ // A developer's own Meta credentials must not change what this suite does.
88
+ WHATSAPP_PHONE_NUMBER_ID: "",
89
+ WHATSAPP_ACCESS_TOKEN: "",
90
+ WHATSAPP_VERIFY_TOKEN: "",
91
+ WHATSAPP_APP_SECRET: "",
92
+ ...env,
93
+ },
94
+ encoding: "utf8",
95
+ timeout: 90_000,
96
+ });
97
+ return { code: result.status, stdout: result.stdout, stderr: result.stderr };
98
+ }
99
+
100
+ /** Tuesday: the debtor agrees, the bolepix is issued, and the fixture payer is told to sit on it. */
101
+ function agree(env: Record<string, string>) {
102
+ return agent(
103
+ ["start", "--channel", "whatsapp", "--conversation", "acordo-1042", "--scripted", "--mode", "mandate", "--transcript", AGREED, "--now", TUESDAY, "--json"],
104
+ { ...env, COLLECTIONS_STUB_PAYER: "never" },
105
+ );
106
+ }
107
+
108
+ function poll(env: Record<string, string>, extra: string[] = []) {
109
+ const out = agent(["poll", "--channel", "whatsapp", "--conversation", "acordo-1042", "--json", ...extra], env);
110
+ const lines = out.stdout.split("\n").filter(Boolean);
111
+ expect(lines).toHaveLength(1);
112
+ return { ...out, payload: JSON.parse(lines[0]!) as PollPayload };
113
+ }
114
+
115
+ async function advanceConversationClock(hours: number) {
116
+ const response = await fetch(`${EMULATOR}/_sim/clock`, {
117
+ method: "POST",
118
+ headers: { "content-type": "application/json" },
119
+ body: JSON.stringify({ advance_hours: hours }),
120
+ signal: AbortSignal.timeout(5000),
121
+ });
122
+ expect(response.ok).toBe(true);
123
+ }
124
+
125
+ function conversationOf(logPath: string): ChannelLine[] {
126
+ const path = isAbsolute(logPath) ? logPath : join(AGENT_DIR, logPath);
127
+ expect(existsSync(path)).toBe(true);
128
+ return readFileSync(path, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l) as ChannelLine);
129
+ }
130
+
131
+ function countEvents(env: Record<string, string>, type: string): number {
132
+ const db = new DatabaseSync(join(env["COLLECTIONS_STATE_DIR"]!, "state.db"));
133
+ try {
134
+ return (db.prepare("SELECT COUNT(*) AS n FROM events WHERE type = ?").get(type) as { n: number }).n;
135
+ } finally {
136
+ db.close();
137
+ }
138
+ }
139
+
140
+ const emulatorUp = await (async () => {
141
+ try {
142
+ return (await fetch(`${EMULATOR}/health`, { signal: AbortSignal.timeout(2000) })).ok;
143
+ } catch {
144
+ return false;
145
+ }
146
+ })();
147
+ if (!emulatorUp) process.stderr.write(`[whatsapp] no emulator at ${EMULATOR}; the poll's conversing cases are skipped. Start it with \`npm run whatsapp:emulator\`.\n`);
148
+
149
+ describe.skipIf(!emulatorUp)("a charge paid after the 24-hour window closed", () => {
150
+ it("confirms by template, closes the cycle, and leaves one conversation rather than two", async () => {
151
+ const env = scratch("template");
152
+
153
+ const agreed = agree(env);
154
+ // Nobody has paid: the execution is still open and that is why the process exits 3.
155
+ expect(agreed.code).toBe(3);
156
+ const opened = JSON.parse(agreed.stdout.split("\n").filter(Boolean).pop()!) as { executions: Array<{ state: string; reason: string }>; channel: { log: string } };
157
+ expect(opened.executions[0]).toMatchObject({ state: "executing", reason: "awaiting_settlement" });
158
+ const before = conversationOf(opened.channel.log);
159
+ // The person's own message carries the provider's clock, which is the only
160
+ // thing the window can be counted from once this process is gone.
161
+ expect(before.filter((l) => l.direction === "in").every((l) => typeof l.provider_timestamp === "number")).toBe(true);
162
+ expect(before.some((l) => l.direction === "out" && /quitad/i.test(l.text ?? ""))).toBe(false);
163
+
164
+ await advanceConversationClock(ADVANCE_HOURS);
165
+
166
+ const polled = poll(env, ["--simulate-payer", "--now", AFTER_WINDOW]);
167
+ expect(polled.code).toBe(0);
168
+ expect(polled.payload.polled).toHaveLength(1);
169
+ expect(polled.payload.polled[0]).toMatchObject({
170
+ state: "settled",
171
+ timed_out: false,
172
+ session_open: false,
173
+ delivery: { told: true, carrier: "template", template: "acordo_quitado" },
174
+ });
175
+ expect(polled.payload.channel?.refused).toEqual([]);
176
+ // One message, and only one, went out with the window shut.
177
+ expect(polled.payload.channel?.messages_out).toBe(1);
178
+
179
+ // The confirmation was appended to the bundle of the run that opened the
180
+ // conversation, so it sits under the QR it confirms instead of in a second folder.
181
+ const after = conversationOf(polled.payload.channel!.log);
182
+ expect(after.slice(0, before.length)).toEqual(before);
183
+ const last = after[after.length - 1]!;
184
+ expect(last.kind).toBe("template");
185
+ expect(last.text).toContain("acordo_quitado");
186
+ expect(last.refused).toBeUndefined();
187
+ // It went through the provider's own surface, not around it.
188
+ expect(last.message_id).toMatch(/^wamid\./);
189
+
190
+ expect(countEvents(env, "message.debtor")).toBe(1);
191
+ expect(countEvents(env, "commerce.charge.paid")).toBe(1);
192
+ const runs = env["COLLECTIONS_RUNS_DIR"]!;
193
+ const receipts = readdirSync(runs).flatMap((d) => (existsSync(join(runs, d, "receipts")) ? readdirSync(join(runs, d, "receipts")) : []));
194
+ expect(receipts).toHaveLength(1);
195
+ });
196
+
197
+ it("polled twice, tells the person once: the cursor that says so is in state.db, not in the process", async () => {
198
+ const env = scratch("twice");
199
+ expect(agree(env).code).toBe(3);
200
+ await advanceConversationClock(ADVANCE_HOURS);
201
+
202
+ const first = poll(env, ["--simulate-payer", "--now", AFTER_WINDOW]);
203
+ expect(first.payload.polled[0]!.delivery.told).toBe(true);
204
+
205
+ // The execution is terminal, so there is nothing left waiting for a payer
206
+ // and the second poll never opens the channel at all.
207
+ const second = poll(env, ["--simulate-payer", "--now", AFTER_WINDOW]);
208
+ expect(second.code).toBe(0);
209
+ expect(second.payload.polled).toEqual([]);
210
+ expect(second.payload.channel).toBeNull();
211
+ expect(countEvents(env, "message.debtor")).toBe(1);
212
+ });
213
+
214
+ it("writes freely while the window is still open: the carrier follows the rule, not the command", async () => {
215
+ const env = scratch("open");
216
+ expect(agree(env).code).toBe(3);
217
+ // No clock move: the person wrote minutes ago.
218
+ const polled = poll(env, ["--simulate-payer", "--now", "2026-09-23T15:30:00-03:00"]);
219
+ expect(polled.code).toBe(0);
220
+ expect(polled.payload.polled[0]).toMatchObject({ state: "settled", session_open: true, delivery: { told: true, carrier: "text" } });
221
+ const last = conversationOf(polled.payload.channel!.log).at(-1)!;
222
+ expect(last.kind).toBe("text");
223
+ expect(last.text).toMatch(/quitad/i);
224
+ });
225
+
226
+ it("a charge that expired gets the expiry template and not the paid one", async () => {
227
+ const env = scratch("expired");
228
+ expect(agree(env).code).toBe(3);
229
+ await advanceConversationClock(ADVANCE_HOURS);
230
+
231
+ // No `--simulate-payer`: nobody paid, and that is the point. `--payer
232
+ // expires` rewrites the fate of the receivable this state already holds.
233
+ const polled = poll(env, ["--payer", "expires", "--now", AFTER_WINDOW]);
234
+ expect(polled.payload.polled[0]).toMatchObject({
235
+ state: "failed",
236
+ reason: "charge_expired",
237
+ session_open: false,
238
+ delivery: { told: true, carrier: "template", template: "acordo_cobranca_vencida" },
239
+ });
240
+ const last = conversationOf(polled.payload.channel!.log).at(-1)!;
241
+ expect(last.text).toContain("acordo_cobranca_vencida");
242
+ expect(last.text).not.toContain("acordo_quitado");
243
+ // Nothing was paid, so nothing was sealed.
244
+ const runs = env["COLLECTIONS_RUNS_DIR"]!;
245
+ expect(readdirSync(runs).flatMap((d) => (existsSync(join(runs, d, "receipts")) ? readdirSync(join(runs, d, "receipts")) : []))).toHaveLength(0);
246
+ });
247
+ });
248
+
249
+ describe("what the poll refuses to be asked, with no emulator in sight", () => {
250
+ it("nothing waiting for a payer is a clean no-op, not an error: a cron that fails on an empty queue gets turned off", () => {
251
+ const env = scratch("noop");
252
+ const out = poll(env, ["--now", TUESDAY]);
253
+ expect(out.code).toBe(0);
254
+ expect(out.payload).toEqual({ polled: [], conversation: "acordo-1042", channel: null });
255
+ // The channel was never opened, so a machine with no emulator running
256
+ // still gets a clean answer.
257
+ expect(out.stderr).not.toContain("emulator backend");
258
+ });
259
+
260
+ it("refuses --conversation on the terminal channel rather than quietly ignoring it", () => {
261
+ const out = agent(["poll", "--conversation", "acordo-1042", "--json"], scratch("flag"));
262
+ expect(out.code).toBe(2);
263
+ expect(out.stderr).toContain("belong to --channel whatsapp");
264
+ });
265
+
266
+ it("refuses a flag it does not know, so a typo is not a silently different run", () => {
267
+ const out = agent(["poll", "--chanel", "whatsapp"], scratch("typo"));
268
+ expect(out.code).toBe(2);
269
+ expect(out.stderr).toContain("unknown argument --chanel");
270
+ });
271
+ });
@@ -0,0 +1,213 @@
1
+ /**
2
+ * The collections-agent on the channel it was written for.
3
+ *
4
+ * Every case here runs a real process: no key of either kind, and the
5
+ * WHATSAPP_* variables explicitly blanked, so a machine that happens to have
6
+ * Meta credentials in its shell runs the same test as the CI.
7
+ *
8
+ * The cases that actually converse need `dyvit-wa-sim` listening — the local
9
+ * Cloud API emulator the channel's `simulator` backend talks to — and SKIP
10
+ * when it is not, so `npm test` is green on a machine that never started it.
11
+ * The CI starts it, and `npm run whatsapp:gate` fails rather than skipping, so
12
+ * the thing that matters never hides behind a skip. The cases that check what
13
+ * the channel REFUSES to be asked need no emulator: those refusals happen
14
+ * before anything is opened, and they run everywhere.
15
+ *
16
+ * What is asserted is the final state and the shape of the conversation, never
17
+ * the wording — the copy-and-paste as its own message, the operator's question
18
+ * nowhere near the debtor, nothing at all outside the collection hours.
19
+ */
20
+ import { spawnSync } from "node:child_process";
21
+ import { existsSync, mkdtempSync, readFileSync } from "node:fs";
22
+ import { tmpdir } from "node:os";
23
+ import { isAbsolute, join, resolve } from "node:path";
24
+ import { describe, expect, it } from "vitest";
25
+
26
+ const AGENT_DIR = resolve(import.meta.dirname, "..");
27
+ const NODE = process.execPath;
28
+ const BIN = resolve(AGENT_DIR, "../../packages/agent-runtime/bin.mjs");
29
+
30
+ interface ChannelLine {
31
+ direction: "in" | "out";
32
+ kind: string;
33
+ text?: string;
34
+ contact: string;
35
+ state: string;
36
+ message_id: string;
37
+ refused?: { rule: string };
38
+ }
39
+
40
+ interface Payload {
41
+ executions: Array<{ state: string; charges: Array<{ charge_id: string | null }> }>;
42
+ receipts: string[];
43
+ channel: { backend: string; conversation: string; turns: number; messages_in: number; messages_out: number; refused: Array<{ rule: string }>; log: string };
44
+ }
45
+
46
+ function run(args: string[], extra: Record<string, string> = {}) {
47
+ const stateDir = mkdtempSync(join(tmpdir(), "collections-wa-"));
48
+ const result = spawnSync(NODE, [BIN, "start", ...args], {
49
+ cwd: AGENT_DIR,
50
+ env: {
51
+ ...process.env,
52
+ ANTHROPIC_API_KEY: "",
53
+ CODESPAR_API_KEY: "",
54
+ // A developer's own Meta credentials must not change what this suite does.
55
+ WHATSAPP_PHONE_NUMBER_ID: "",
56
+ WHATSAPP_ACCESS_TOKEN: "",
57
+ WHATSAPP_VERIFY_TOKEN: "",
58
+ WHATSAPP_APP_SECRET: "",
59
+ COLLECTIONS_STATE_DIR: stateDir,
60
+ COLLECTIONS_RUNS_DIR: join(stateDir, "runs"),
61
+ ...extra,
62
+ },
63
+ encoding: "utf8",
64
+ timeout: 90_000,
65
+ });
66
+ return { code: result.status, stdout: result.stdout, stderr: result.stderr };
67
+ }
68
+
69
+ function payloadOf(stdout: string): Payload {
70
+ const lines = stdout.split("\n").filter(Boolean);
71
+ expect(lines).toHaveLength(1);
72
+ return JSON.parse(lines[0]!) as Payload;
73
+ }
74
+
75
+ function conversationOf(payload: Payload): ChannelLine[] {
76
+ const path = isAbsolute(payload.channel.log) ? payload.channel.log : join(AGENT_DIR, payload.channel.log);
77
+ expect(existsSync(path)).toBe(true);
78
+ return readFileSync(path, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l) as ChannelLine);
79
+ }
80
+
81
+ const EMULATOR = process.env["WHATSAPP_SIM_URL"] ?? "http://127.0.0.1:4290";
82
+ /** Probed at module level: `describe.skipIf` is read when the file is collected, before any hook runs. */
83
+ const emulatorUp = await (async () => {
84
+ try {
85
+ return (await fetch(`${EMULATOR}/health`, { signal: AbortSignal.timeout(2000) })).ok;
86
+ } catch {
87
+ return false;
88
+ }
89
+ })();
90
+ if (!emulatorUp) process.stderr.write(`[whatsapp] no emulator at ${EMULATOR}; the conversing cases are skipped. Start it with \`npm run whatsapp:emulator\`.\n`);
91
+
92
+ const INSIDE_HOURS = ["--now", "2026-09-23T14:00:00-03:00"];
93
+ const AFTER_HOURS = ["--now", "2026-09-23T22:30:00-03:00"];
94
+ const SCRIPTED = ["--channel", "whatsapp", "--conversation", "acordo-1042", "--scripted", "--simulate-payer", "--json"];
95
+
96
+ describe.skipIf(!emulatorUp)("the cycle closes over the WhatsApp channel", () => {
97
+ it("settles in mandate mode with nobody at a keyboard, and sends the QR with the copy-and-paste under it", () => {
98
+ const out = run([...SCRIPTED, "--mode", "mandate", ...INSIDE_HOURS]);
99
+ expect(out.code).toBe(0);
100
+ const payload = payloadOf(out.stdout);
101
+ expect(payload.executions.map((e) => e.state)).toEqual(["settled"]);
102
+ expect(payload.executions[0]!.charges).toHaveLength(1);
103
+ expect(payload.receipts).toHaveLength(1);
104
+ expect(payload.channel.backend).toBe("emulator");
105
+ // The one expected refusal: neither backend can upload the QR image.
106
+ expect(payload.channel.refused.map((r) => r.rule)).toEqual(["media_upload_unimplemented"]);
107
+
108
+ const conversation = conversationOf(payload);
109
+ const outbound = conversation.filter((l) => l.direction === "out");
110
+ const qr = outbound.findIndex((l) => l.kind === "media");
111
+ expect(qr).toBeGreaterThanOrEqual(0);
112
+ expect(outbound[qr + 1]!.kind).toBe("instrument");
113
+ expect(outbound[qr + 1]!.text).toMatch(/^00020126/);
114
+ expect(conversation.filter((l) => l.direction === "in")).toHaveLength(2);
115
+ // Every delivered message carries a provider id: it went through the Cloud API surface, not around it.
116
+ for (const line of outbound.filter((l) => !l.refused)) expect(line.message_id).toMatch(/^wamid\./);
117
+ });
118
+
119
+ it("settles in human mode too, and the operator's question never reaches the debtor", () => {
120
+ const out = run([...SCRIPTED, "--mode", "human", "--approve", ...INSIDE_HOURS]);
121
+ expect(out.code).toBe(0);
122
+ const payload = payloadOf(out.stdout);
123
+ expect(payload.executions.map((e) => e.state)).toEqual(["settled"]);
124
+ // The question is the operator's and is on the console; nothing like it is in the conversation.
125
+ for (const line of conversationOf(payload)) expect(line.text ?? "").not.toMatch(/operador|Aprovar a emissao/i);
126
+ });
127
+
128
+ it("writes the conversation into the bundle with the contact masked", () => {
129
+ const out = run([...SCRIPTED, "--mode", "mandate", ...INSIDE_HOURS]);
130
+ const conversation = conversationOf(payloadOf(out.stdout));
131
+ expect(conversation.length).toBeGreaterThan(0);
132
+ for (const line of conversation) {
133
+ expect(line.contact).not.toContain("987654321");
134
+ expect(line.contact).toContain("****");
135
+ }
136
+ });
137
+
138
+ it("tells the person once when the charge expires, and writes no record", () => {
139
+ const out = run(["--channel", "whatsapp", "--conversation", "acordo-1103", "--scripted", "--mode", "mandate", "--payer", "expires", "--json", ...INSIDE_HOURS]);
140
+ const payload = payloadOf(out.stdout);
141
+ expect(payload.executions.map((e) => e.state)).toEqual(["failed"]);
142
+ expect(payload.receipts).toEqual([]);
143
+ expect(payload.channel.conversation).toBe("acordo-1103");
144
+ // The QR still went out: it was payable, nobody paid it.
145
+ const outbound = conversationOf(payload).filter((l) => l.direction === "out");
146
+ expect(outbound.some((l) => l.kind === "media")).toBe(true);
147
+ // The kit's one-per-outcome message, sent once however many looks carried the event.
148
+ // The model's own reply also says the charge expired, which is the terminal's behaviour too.
149
+ expect(outbound.filter((l) => String(l.text ?? "").startsWith("A cobranca venceu sem pagamento"))).toHaveLength(1);
150
+ });
151
+
152
+ it("refuses to say anything at all outside the collection hours, and issues nothing", () => {
153
+ const out = run([...SCRIPTED, "--mode", "mandate", ...AFTER_HOURS]);
154
+ const payload = payloadOf(out.stdout);
155
+ expect(payload.channel.messages_out).toBe(0);
156
+ // The emulator would have accepted every one of them: the collection hours are OUR rule, not WhatsApp's.
157
+ expect(payload.channel.refused.map((r) => r.rule)).toContain("collection_hours");
158
+ expect(payload.executions.flatMap((e) => e.charges)).toEqual([]);
159
+ expect(payload.receipts).toEqual([]);
160
+ });
161
+ });
162
+
163
+ describe("what the channel refuses to be asked", () => {
164
+ it("refuses the cloud-api backend by naming every credential this repo does not ship", () => {
165
+ const out = run(["--channel", "whatsapp", "--conversation", "acordo-1042", "--scripted", "--backend", "cloud-api", "--mode", "mandate", ...INSIDE_HOURS]);
166
+ expect(out.code).toBe(1);
167
+ for (const name of ["WHATSAPP_PHONE_NUMBER_ID", "WHATSAPP_ACCESS_TOKEN", "WHATSAPP_VERIFY_TOKEN", "WHATSAPP_APP_SECRET"]) {
168
+ expect(out.stderr).toContain(name);
169
+ }
170
+ expect(out.stderr).toContain("emulator");
171
+ });
172
+
173
+ it("refuses --input on a channel: a conversation takes its turns from the conversation", () => {
174
+ const out = run(["--channel", "whatsapp", "--input", "oi", "--json"]);
175
+ expect(out.code).toBe(2);
176
+ expect(out.stderr).toContain("--input");
177
+ });
178
+
179
+ it("refuses the channel flags on the terminal", () => {
180
+ expect(run(["--backend", "simulator", "--input", "oi"]).code).toBe(2);
181
+ expect(run(["--conversation", "acordo-1042", "--input", "oi"]).code).toBe(2);
182
+ });
183
+
184
+ it("refuses a scripted human-mode run rather than waiting on a keyboard nobody is at", () => {
185
+ const out = run(["--channel", "whatsapp", "--conversation", "acordo-1042", "--scripted", "--mode", "human", "--json", ...INSIDE_HOURS]);
186
+ expect(out.code).toBe(2);
187
+ expect(out.stderr).toContain("--approve");
188
+ });
189
+
190
+ it("asks which conversation when the agent ships more than one: which debtor is not a default", () => {
191
+ const out = run(["--channel", "whatsapp", "--scripted", "--json", ...INSIDE_HOURS]);
192
+ expect(out.code).toBe(2);
193
+ expect(out.stderr).toContain("--conversation is required");
194
+ expect(out.stderr).toContain("acordo-1103");
195
+ });
196
+
197
+ it("refuses a conversation the agent does not ship", () => {
198
+ const out = run(["--channel", "whatsapp", "--scripted", "--conversation", "acordo-9999", "--json", ...INSIDE_HOURS]);
199
+ expect(out.code).toBe(2);
200
+ expect(out.stderr).toContain("acordo-1042");
201
+ });
202
+ });
203
+
204
+ describe("the terminal is untouched", () => {
205
+ it("still runs the same one-shot with no channel flag", () => {
206
+ const out = run(["--input", "fechado, pago à vista", "--transcript", "test/fixtures/accept-1042.transcript.jsonl", "--approve", "--simulate-payer", "--json", ...INSIDE_HOURS]);
207
+ expect(out.code).toBe(0);
208
+ const payload = JSON.parse(out.stdout.split("\n").filter(Boolean)[0]!) as Payload & { channel?: unknown };
209
+ expect(payload.executions.map((e) => e.state)).toEqual(["settled"]);
210
+ // No channel key: a terminal run is not a channel run, and its JSON shape did not change.
211
+ expect(payload.channel).toBeUndefined();
212
+ });
213
+ });
@@ -5,7 +5,6 @@
5
5
  },
6
6
  "include": [
7
7
  "src/**/*.ts",
8
- "channels/**/*.ts",
9
8
  "test/**/*.ts"
10
9
  ]
11
10
  }
@@ -7,16 +7,18 @@
7
7
  "type": "module",
8
8
  "workspaces": [
9
9
  "packages/agent-core",
10
+ "packages/agent-runtime",
10
11
  "agents/collections-agent"
11
12
  ],
12
13
  "scripts": {
13
14
  "start": "npm start --workspace=agents/collections-agent --",
14
15
  "check": "npm run check --workspaces --if-present --",
15
16
  "test": "vitest run --pool=forks --maxWorkers=1",
16
- "typecheck": "tsc --noEmit -p packages/agent-core/tsconfig.json && tsc --noEmit -p agents/collections-agent/tsconfig.json",
17
+ "typecheck": "tsc --noEmit -p packages/agent-core/tsconfig.json && tsc --noEmit -p packages/agent-runtime/tsconfig.json && tsc --noEmit -p agents/collections-agent/tsconfig.json",
17
18
  "approve": "npm run approve --workspace=agents/collections-agent --",
18
19
  "deny": "npm run deny --workspace=agents/collections-agent --",
19
20
  "eval": "npm run eval --workspace=agents/collections-agent --",
21
+ "inspect": "npm run inspect --workspace=agents/collections-agent --",
20
22
  "poll": "npm run poll --workspace=agents/collections-agent --",
21
23
  "reconcile": "npm run reconcile --workspace=agents/collections-agent --",
22
24
  "rerun": "npm run rerun --workspace=agents/collections-agent --",
@@ -2,6 +2,8 @@
2
2
 
3
3
  The primitives every CodeSpar starter-kit agent inherits (spec v5.1.1, section 4): the execution state machine, the approval artifact, the `agent.yaml` manifest, `escalate_above`, `actor`, local state in SQLite, the proof bundle, the rail contract and the two providers.
4
4
 
5
+ This package is the decisions. The RUNNER around them — the terminal channel, `codespar-agent start|consent|approve|deny|resume|rerun|reconcile|poll|webhook|check|eval`, the setup that wires this package to an agent directory, and the scenario and adversarial runners — is [`@codespar/agent-runtime`](../agent-runtime), which depends on this one and is what an agent's `package.json` scripts call (#13). Nothing here knows an agent's name.
6
+
5
7
  ## The state machine, and what the types do and do not prove
6
8
 
7
9
  `transition(execution, to, input)` accepts only a `to` that the table in `state-machine.ts` lists for `execution.state`. On a **narrowed** value (`Execution<"drafted">`, `Execution<"executing">`, ...) a transition outside the table is a compile error, and `test/transitions.type-test.ts` keeps that true with `@ts-expect-error` lines that `tsc` refuses to leave unused. An **un-narrowed** `Execution` (the union, which is what a row read back from SQLite is) compiles for any target; the engine narrows with casts at its call sites. So the guard that always holds is the runtime one: `transition()` throws `IllegalTransitionError` on any pair the table does not list, whatever the static type said. The type test proves the table is closed; the runtime check enforces it.
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@anthropic-ai/sdk": "0.128.0",
20
- "@codespar/sdk": "0.16.4",
20
+ "@codespar/sdk": "0.16.6",
21
21
  "yaml": "2.9.1",
22
22
  "zod": "3.25.76"
23
23
  }
@@ -79,10 +79,12 @@ export class CodeSparChargeRail implements PaymentRail {
79
79
 
80
80
  async pay(payment: RailPayment): Promise<RailOutcome> {
81
81
  if (!payment.due_date) return { status: "failed", code: "due_date_required", message: "a receivable needs a due_date; the immediate Pix charge cannot be read back or replayed" };
82
+ if (!payment.consumer_id) return { status: "failed", code: "consumer_id_required", message: "a receivable settles into the principal's account; the policy names no consumer_id" };
82
83
  let view: ChargeView;
83
84
  try {
84
85
  view = (await this.api.post("/v1/charges", {
85
86
  body: {
87
+ consumer_id: payment.consumer_id,
86
88
  amount: payment.amount_minor / 100,
87
89
  currency: payment.currency,
88
90
  method: "boleto",
@@ -108,15 +110,32 @@ export class CodeSparChargeRail implements PaymentRail {
108
110
  return outcome.status === "in_flight" ? { status: "uncertain", code: "issuance_unconfirmed", message: "the create answered no readable state" } : outcome;
109
111
  }
110
112
 
111
- async lookup(attemptId: string, _payment: RailPayment): Promise<RailLookup> {
113
+ /**
114
+ * By the charge id when the create handed one back; by our idempotency key only when it did not (the create's answer was lost).
115
+ * The route's doc says the read accepts the caller's key as the id; on staging (2026-09-23) it answered `charge_not_found` for
116
+ * the key and the charge for the id, so the id comes first and the key is the fallback, not the other way round.
117
+ */
118
+ async lookup(attemptId: string, _payment: RailPayment, transactionId?: string): Promise<RailLookup> {
119
+ const byId = transactionId ? await this.read(transactionId) : { kind: "missing" as const };
120
+ if (byId.kind === "view") return outcomeOf(byId.view);
121
+ if (byId.kind === "in_flight") return { status: "in_flight" };
122
+ if (byId.kind === "uncertain") return byId.outcome;
123
+ const byKey = await this.read(attemptId);
124
+ if (byKey.kind === "view") return outcomeOf(byKey.view);
125
+ if (byKey.kind === "in_flight") return { status: "in_flight" };
126
+ if (byKey.kind === "uncertain") return byKey.outcome;
127
+ return undefined;
128
+ }
129
+
130
+ private async read(chargeRef: string): Promise<{ kind: "view"; view: ChargeView } | { kind: "missing" } | { kind: "in_flight" } | { kind: "uncertain"; outcome: Extract<RailOutcome, { status: "uncertain" }> }> {
112
131
  try {
113
- const view = (await this.api.get("/v1/charges/{chargeId}", { path: { chargeId: attemptId } })) as ChargeView;
114
- return outcomeOf(view);
132
+ const view = (await this.api.get("/v1/charges/{chargeId}", { path: { chargeId: chargeRef } })) as ChargeView;
133
+ return { kind: "view", view };
115
134
  } catch (err) {
116
135
  const failure = describeApiError(err);
117
- if (failure.status === 404) return undefined;
118
- if (failure.status === 409) return { status: "in_flight" };
119
- return { status: "uncertain", code: failure.code, message: failure.message };
136
+ if (failure.status === 404) return { kind: "missing" };
137
+ if (failure.status === 409) return { kind: "in_flight" };
138
+ return { kind: "uncertain", outcome: { status: "uncertain", code: failure.code, message: failure.message } };
120
139
  }
121
140
  }
122
141
 
@@ -133,6 +152,8 @@ export class CodeSparChargeRail implements PaymentRail {
133
152
  payment: { amount_minor: view.amount_minor, payee: null, attempt_id: chargeId, money_moved: false, sandbox: true, at: raw.settled_at ?? new Date().toISOString() },
134
153
  chain: null,
135
154
  receipt_sig: null,
155
+ receipt_sig_ed25519: null,
156
+ receipt_sig_kid: null,
136
157
  actor,
137
158
  raw: view,
138
159
  };
@@ -18,6 +18,16 @@ import type { PaymentRail, RailLookup, RailOutcome, RailPayment, RailReceipt } f
18
18
  import type { Actor } from "../types.js";
19
19
  import { describeApiError, isUncertain } from "./client.js";
20
20
 
21
+ /** The asymmetric seal as the API serves it, or nulls when this deployment
22
+ * does not serve one. Never throws on a shape it does not recognise: a
23
+ * receipt is evidence of a payment that already happened, and refusing to
24
+ * record it over an unexpected field would trade the record for the proof. */
25
+ function readEd25519Seal(body: unknown): { receipt_sig_ed25519: string | null; receipt_sig_kid: string | null } {
26
+ const r = body as { receipt_sig_ed25519?: unknown; receipt_sig_kid?: unknown };
27
+ const str = (v: unknown): string | null => (typeof v === "string" && v.length > 0 ? v : null);
28
+ return { receipt_sig_ed25519: str(r.receipt_sig_ed25519), receipt_sig_kid: str(r.receipt_sig_kid) };
29
+ }
30
+
21
31
  export class CodeSparRail implements PaymentRail {
22
32
  readonly name = "codespar" as const;
23
33
 
@@ -89,6 +99,12 @@ export class CodeSparRail implements PaymentRail {
89
99
  },
90
100
  chain: r.chain,
91
101
  receipt_sig: r.receipt_sig,
102
+ // ent#1633 landed after `@codespar/sdk@0.16.6` was generated, so the
103
+ // typed response does not carry these two yet. Read off the body
104
+ // defensively rather than pinning a new SDK for two nullable strings:
105
+ // a deployment that predates the change answers null, which is the
106
+ // same answer the columns hold and reads as `unsigned`.
107
+ ...readEd25519Seal(r),
92
108
  actor,
93
109
  raw: r,
94
110
  };