@codespar/cli 0.17.0 → 0.18.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 (480) hide show
  1. package/README.md +1 -0
  2. package/package.json +1 -1
  3. package/templates/bills-agent/README.md +1 -1
  4. package/templates/bills-agent/agents/bills-agent/AGENTS.md +1 -1
  5. package/templates/bills-agent/agents/bills-agent/CLAUDE.md +1 -1
  6. package/templates/bills-agent/agents/bills-agent/README.md +6 -5
  7. package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +5 -4
  8. package/templates/bills-agent/packages/agent-core/README.md +14 -1
  9. package/templates/bills-agent/packages/agent-core/package.json +1 -1
  10. package/templates/bills-agent/packages/agent-core/src/agent.ts +39 -1
  11. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  12. package/templates/bills-agent/packages/agent-core/src/api/client.ts +28 -5
  13. package/templates/bills-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  14. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +62 -26
  15. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  16. package/templates/bills-agent/packages/agent-core/src/approval.ts +14 -2
  17. package/templates/bills-agent/packages/agent-core/src/bundle.ts +35 -3
  18. package/templates/bills-agent/packages/agent-core/src/channels.ts +49 -3
  19. package/templates/bills-agent/packages/agent-core/src/check.ts +25 -2
  20. package/templates/bills-agent/packages/agent-core/src/engine.ts +235 -46
  21. package/templates/bills-agent/packages/agent-core/src/hash.ts +57 -1
  22. package/templates/bills-agent/packages/agent-core/src/index.ts +2 -0
  23. package/templates/bills-agent/packages/agent-core/src/quote.ts +50 -0
  24. package/templates/bills-agent/packages/agent-core/src/rail.ts +89 -4
  25. package/templates/bills-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  26. package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  27. package/templates/bills-agent/packages/agent-core/src/revocation.ts +1 -1
  28. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +10 -1
  29. package/templates/bills-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  30. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  31. package/templates/bills-agent/packages/agent-core/src/tools.ts +17 -6
  32. package/templates/bills-agent/packages/agent-core/src/types.ts +54 -1
  33. package/templates/bills-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  34. package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  35. package/templates/bills-agent/packages/agent-core/test/composition.test.ts +204 -0
  36. package/templates/bills-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  37. package/templates/bills-agent/packages/agent-core/test/helpers.ts +4 -1
  38. package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  39. package/templates/bills-agent/packages/agent-core/test/quote.test.ts +198 -0
  40. package/templates/bills-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  41. package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  42. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +103 -3
  43. package/templates/bills-agent/packages/agent-runtime/README.md +12 -0
  44. package/templates/bills-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  45. package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  46. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  47. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  48. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  49. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  50. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  51. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  52. package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  53. package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  54. package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  55. package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  56. package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  57. package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  58. package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  59. package/templates/bills-agent/packages/agent-runtime/src/index.ts +1 -0
  60. package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +5 -1
  61. package/templates/bills-agent/packages/agent-runtime/src/kit.ts +25 -2
  62. package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  63. package/templates/bills-agent/packages/agent-runtime/src/setup.ts +13 -3
  64. package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +127 -18
  65. package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  66. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  67. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  68. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  69. package/templates/checkout-agent/LICENSE +21 -0
  70. package/templates/checkout-agent/README.md +28 -0
  71. package/templates/checkout-agent/_gitignore +10 -0
  72. package/templates/checkout-agent/agents/checkout-agent/.env.example +5 -0
  73. package/templates/checkout-agent/agents/checkout-agent/AGENTS.md +20 -0
  74. package/templates/checkout-agent/agents/checkout-agent/CLAUDE.md +20 -0
  75. package/templates/checkout-agent/agents/checkout-agent/README.md +94 -0
  76. package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +36 -0
  77. package/templates/checkout-agent/agents/checkout-agent/agent.yaml +30 -0
  78. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +28 -0
  79. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-beatriz.json +11 -0
  80. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina-retomada.json +10 -0
  81. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina.json +11 -0
  82. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +49 -0
  83. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +12 -0
  84. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +11 -0
  85. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +5 -0
  86. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +13 -0
  87. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.transcript.jsonl +4 -0
  88. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.json +26 -0
  89. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
  90. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.json +11 -0
  91. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.transcript.jsonl +5 -0
  92. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.json +12 -0
  93. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +5 -0
  94. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.json +13 -0
  95. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.transcript.jsonl +5 -0
  96. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +15 -0
  97. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +7 -0
  98. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +12 -0
  99. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.transcript.jsonl +5 -0
  100. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.json +13 -0
  101. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +4 -0
  102. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.json +16 -0
  103. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.transcript.jsonl +9 -0
  104. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.json +15 -0
  105. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +8 -0
  106. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/webhook-replay.json +11 -0
  107. package/templates/checkout-agent/agents/checkout-agent/evals/eval.yaml +11 -0
  108. package/templates/checkout-agent/agents/checkout-agent/guardrails.json +25 -0
  109. package/templates/checkout-agent/agents/checkout-agent/mandate.example.json +28 -0
  110. package/templates/checkout-agent/agents/checkout-agent/package.json +33 -0
  111. package/templates/checkout-agent/agents/checkout-agent/runbook.md +19 -0
  112. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.json +42 -0
  113. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +4 -0
  114. package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.json +32 -0
  115. package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.transcript.jsonl +4 -0
  116. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.json +61 -0
  117. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +9 -0
  118. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +61 -0
  119. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +9 -0
  120. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +36 -0
  121. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +6 -0
  122. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.json +23 -0
  123. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +4 -0
  124. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.json +72 -0
  125. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +9 -0
  126. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.json +15 -0
  127. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +6 -0
  128. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.json +23 -0
  129. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +3 -0
  130. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.json +42 -0
  131. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +12 -0
  132. package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.json +14 -0
  133. package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.transcript.jsonl +9 -0
  134. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +34 -0
  135. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +7 -0
  136. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.json +33 -0
  137. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +4 -0
  138. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.json +32 -0
  139. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +4 -0
  140. package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +92 -0
  141. package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +338 -0
  142. package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +179 -0
  143. package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +374 -0
  144. package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +220 -0
  145. package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +297 -0
  146. package/templates/checkout-agent/agents/checkout-agent/test/adversarial.test.ts +117 -0
  147. package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +67 -0
  148. package/templates/checkout-agent/agents/checkout-agent/test/cli.test.ts +169 -0
  149. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +5 -0
  150. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +6 -0
  151. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +2 -0
  152. package/templates/checkout-agent/agents/checkout-agent/test/nfse.test.ts +170 -0
  153. package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +138 -0
  154. package/templates/checkout-agent/agents/checkout-agent/test/scenarios.test.ts +113 -0
  155. package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +171 -0
  156. package/templates/checkout-agent/agents/checkout-agent/tools.json +68 -0
  157. package/templates/checkout-agent/agents/checkout-agent/tsconfig.json +10 -0
  158. package/templates/checkout-agent/package.json +38 -0
  159. package/templates/checkout-agent/packages/agent-core/README.md +34 -0
  160. package/templates/checkout-agent/packages/agent-core/package.json +24 -0
  161. package/templates/checkout-agent/packages/agent-core/src/agent.ts +163 -0
  162. package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +195 -0
  163. package/templates/checkout-agent/packages/agent-core/src/api/client.ts +76 -0
  164. package/templates/checkout-agent/packages/agent-core/src/api/mandate-status.ts +74 -0
  165. package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +153 -0
  166. package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +43 -0
  167. package/templates/checkout-agent/packages/agent-core/src/approval.ts +135 -0
  168. package/templates/checkout-agent/packages/agent-core/src/bundle.ts +191 -0
  169. package/templates/checkout-agent/packages/agent-core/src/channels.ts +186 -0
  170. package/templates/checkout-agent/packages/agent-core/src/check.ts +276 -0
  171. package/templates/checkout-agent/packages/agent-core/src/clock.ts +42 -0
  172. package/templates/checkout-agent/packages/agent-core/src/engine.ts +1074 -0
  173. package/templates/checkout-agent/packages/agent-core/src/escalate.ts +85 -0
  174. package/templates/checkout-agent/packages/agent-core/src/events.ts +40 -0
  175. package/templates/checkout-agent/packages/agent-core/src/guardrails.ts +45 -0
  176. package/templates/checkout-agent/packages/agent-core/src/hash.ts +118 -0
  177. package/templates/checkout-agent/packages/agent-core/src/ids.ts +10 -0
  178. package/templates/checkout-agent/packages/agent-core/src/index.ts +34 -0
  179. package/templates/checkout-agent/packages/agent-core/src/mandate.ts +100 -0
  180. package/templates/checkout-agent/packages/agent-core/src/manifest.ts +76 -0
  181. package/templates/checkout-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
  182. package/templates/checkout-agent/packages/agent-core/src/providers/replay.ts +63 -0
  183. package/templates/checkout-agent/packages/agent-core/src/providers/types.ts +39 -0
  184. package/templates/checkout-agent/packages/agent-core/src/quote.ts +50 -0
  185. package/templates/checkout-agent/packages/agent-core/src/rail.ts +186 -0
  186. package/templates/checkout-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  187. package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +577 -0
  188. package/templates/checkout-agent/packages/agent-core/src/revocation.ts +30 -0
  189. package/templates/checkout-agent/packages/agent-core/src/secrets.ts +30 -0
  190. package/templates/checkout-agent/packages/agent-core/src/state/store.ts +307 -0
  191. package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +157 -0
  192. package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
  193. package/templates/checkout-agent/packages/agent-core/src/stubs/mandate-status.ts +58 -0
  194. package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +209 -0
  195. package/templates/checkout-agent/packages/agent-core/src/tools.ts +66 -0
  196. package/templates/checkout-agent/packages/agent-core/src/types.ts +187 -0
  197. package/templates/checkout-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  198. package/templates/checkout-agent/packages/agent-core/test/approval.test.ts +117 -0
  199. package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  200. package/templates/checkout-agent/packages/agent-core/test/bundle.test.ts +85 -0
  201. package/templates/checkout-agent/packages/agent-core/test/clock.test.ts +25 -0
  202. package/templates/checkout-agent/packages/agent-core/test/composition.test.ts +204 -0
  203. package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +596 -0
  204. package/templates/checkout-agent/packages/agent-core/test/escalate.test.ts +42 -0
  205. package/templates/checkout-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  206. package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
  207. package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
  208. package/templates/checkout-agent/packages/agent-core/test/helpers.ts +142 -0
  209. package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +229 -0
  210. package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +45 -0
  211. package/templates/checkout-agent/packages/agent-core/test/quote.test.ts +198 -0
  212. package/templates/checkout-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  213. package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  214. package/templates/checkout-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
  215. package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +416 -0
  216. package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +28 -0
  217. package/templates/checkout-agent/packages/agent-core/test/state-machine.test.ts +67 -0
  218. package/templates/checkout-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
  219. package/templates/checkout-agent/packages/agent-core/tsconfig.json +10 -0
  220. package/templates/checkout-agent/packages/agent-runtime/README.md +80 -0
  221. package/templates/checkout-agent/packages/agent-runtime/bin.mjs +32 -0
  222. package/templates/checkout-agent/packages/agent-runtime/package.json +23 -0
  223. package/templates/checkout-agent/packages/agent-runtime/src/adversarial.ts +199 -0
  224. package/templates/checkout-agent/packages/agent-runtime/src/agent.ts +68 -0
  225. package/templates/checkout-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
  226. package/templates/checkout-agent/packages/agent-runtime/src/channels/index.ts +72 -0
  227. package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
  228. package/templates/checkout-agent/packages/agent-runtime/src/channels/types.ts +173 -0
  229. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +459 -0
  230. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +216 -0
  231. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
  232. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +350 -0
  233. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +180 -0
  234. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
  235. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +120 -0
  236. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +127 -0
  237. package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +98 -0
  238. package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +15 -0
  239. package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
  240. package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
  241. package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
  242. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +367 -0
  243. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +145 -0
  244. package/templates/checkout-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
  245. package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
  246. package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +49 -0
  247. package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +134 -0
  248. package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +248 -0
  249. package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +330 -0
  250. package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +40 -0
  251. package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +83 -0
  252. package/templates/checkout-agent/packages/agent-runtime/src/index.ts +13 -0
  253. package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +801 -0
  254. package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +229 -0
  255. package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +105 -0
  256. package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +274 -0
  257. package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +239 -0
  258. package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +263 -0
  259. package/templates/checkout-agent/packages/agent-runtime/src/webhook.ts +131 -0
  260. package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
  261. package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +329 -0
  262. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +277 -0
  263. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
  264. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
  265. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +167 -0
  266. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  267. package/templates/checkout-agent/packages/agent-runtime/tsconfig.json +9 -0
  268. package/templates/checkout-agent/scripts/whatsapp-emulator.mjs +84 -0
  269. package/templates/checkout-agent/tsconfig.base.json +16 -0
  270. package/templates/checkout-agent/vitest.config.ts +12 -0
  271. package/templates/collections-agent/README.md +6 -1
  272. package/templates/collections-agent/agents/collections-agent/README.md +12 -8
  273. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +8 -0
  274. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042-retomada.json +10 -0
  275. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +27 -1
  276. package/templates/collections-agent/agents/collections-agent/src/kit.ts +2 -0
  277. package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +12 -2
  278. package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +55 -0
  279. package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +2 -0
  280. package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +12 -6
  281. package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +148 -0
  282. package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +5 -0
  283. package/templates/collections-agent/package.json +1 -0
  284. package/templates/collections-agent/packages/agent-core/README.md +14 -1
  285. package/templates/collections-agent/packages/agent-core/package.json +1 -1
  286. package/templates/collections-agent/packages/agent-core/src/agent.ts +39 -1
  287. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  288. package/templates/collections-agent/packages/agent-core/src/api/client.ts +28 -5
  289. package/templates/collections-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  290. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +62 -26
  291. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  292. package/templates/collections-agent/packages/agent-core/src/approval.ts +14 -2
  293. package/templates/collections-agent/packages/agent-core/src/bundle.ts +35 -3
  294. package/templates/collections-agent/packages/agent-core/src/channels.ts +49 -3
  295. package/templates/collections-agent/packages/agent-core/src/check.ts +25 -2
  296. package/templates/collections-agent/packages/agent-core/src/engine.ts +235 -46
  297. package/templates/collections-agent/packages/agent-core/src/hash.ts +57 -1
  298. package/templates/collections-agent/packages/agent-core/src/index.ts +2 -0
  299. package/templates/collections-agent/packages/agent-core/src/quote.ts +50 -0
  300. package/templates/collections-agent/packages/agent-core/src/rail.ts +89 -4
  301. package/templates/collections-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  302. package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  303. package/templates/collections-agent/packages/agent-core/src/revocation.ts +1 -1
  304. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +10 -1
  305. package/templates/collections-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  306. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  307. package/templates/collections-agent/packages/agent-core/src/tools.ts +17 -6
  308. package/templates/collections-agent/packages/agent-core/src/types.ts +54 -1
  309. package/templates/collections-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  310. package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  311. package/templates/collections-agent/packages/agent-core/test/composition.test.ts +204 -0
  312. package/templates/collections-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  313. package/templates/collections-agent/packages/agent-core/test/helpers.ts +4 -1
  314. package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  315. package/templates/collections-agent/packages/agent-core/test/quote.test.ts +198 -0
  316. package/templates/collections-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  317. package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  318. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +103 -3
  319. package/templates/collections-agent/packages/agent-runtime/README.md +12 -0
  320. package/templates/collections-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  321. package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  322. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  323. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  324. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  325. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  326. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  327. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  328. package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  329. package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  330. package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  331. package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  332. package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  333. package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  334. package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  335. package/templates/collections-agent/packages/agent-runtime/src/index.ts +1 -0
  336. package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +5 -1
  337. package/templates/collections-agent/packages/agent-runtime/src/kit.ts +25 -2
  338. package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  339. package/templates/collections-agent/packages/agent-runtime/src/setup.ts +13 -3
  340. package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +127 -18
  341. package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  342. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  343. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  344. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  345. package/templates/collections-agent/scripts/whatsapp-emulator.mjs +84 -0
  346. package/templates/hello-agent/README.md +1 -1
  347. package/templates/hello-agent/packages/agent-core/README.md +14 -1
  348. package/templates/hello-agent/packages/agent-core/package.json +1 -1
  349. package/templates/hello-agent/packages/agent-core/src/agent.ts +39 -1
  350. package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  351. package/templates/hello-agent/packages/agent-core/src/api/client.ts +28 -5
  352. package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  353. package/templates/hello-agent/packages/agent-core/src/api/rail.ts +62 -26
  354. package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  355. package/templates/hello-agent/packages/agent-core/src/approval.ts +14 -2
  356. package/templates/hello-agent/packages/agent-core/src/bundle.ts +35 -3
  357. package/templates/hello-agent/packages/agent-core/src/channels.ts +49 -3
  358. package/templates/hello-agent/packages/agent-core/src/check.ts +25 -2
  359. package/templates/hello-agent/packages/agent-core/src/engine.ts +235 -46
  360. package/templates/hello-agent/packages/agent-core/src/hash.ts +57 -1
  361. package/templates/hello-agent/packages/agent-core/src/index.ts +2 -0
  362. package/templates/hello-agent/packages/agent-core/src/quote.ts +50 -0
  363. package/templates/hello-agent/packages/agent-core/src/rail.ts +89 -4
  364. package/templates/hello-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  365. package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  366. package/templates/hello-agent/packages/agent-core/src/revocation.ts +1 -1
  367. package/templates/hello-agent/packages/agent-core/src/state-machine.ts +10 -1
  368. package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  369. package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  370. package/templates/hello-agent/packages/agent-core/src/tools.ts +17 -6
  371. package/templates/hello-agent/packages/agent-core/src/types.ts +54 -1
  372. package/templates/hello-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  373. package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  374. package/templates/hello-agent/packages/agent-core/test/composition.test.ts +204 -0
  375. package/templates/hello-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  376. package/templates/hello-agent/packages/agent-core/test/helpers.ts +4 -1
  377. package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  378. package/templates/hello-agent/packages/agent-core/test/quote.test.ts +198 -0
  379. package/templates/hello-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  380. package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  381. package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +103 -3
  382. package/templates/hello-agent/packages/agent-runtime/README.md +12 -0
  383. package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  384. package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  385. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  386. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  387. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  388. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  389. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  390. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  391. package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  392. package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  393. package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  394. package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  395. package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  396. package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  397. package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  398. package/templates/hello-agent/packages/agent-runtime/src/index.ts +1 -0
  399. package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +5 -1
  400. package/templates/hello-agent/packages/agent-runtime/src/kit.ts +25 -2
  401. package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  402. package/templates/hello-agent/packages/agent-runtime/src/setup.ts +13 -3
  403. package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +127 -18
  404. package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  405. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  406. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  407. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  408. package/templates/kits.lock.json +29 -6
  409. package/templates/supplier-payments-agent/README.md +1 -1
  410. package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +1 -1
  411. package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +1 -1
  412. package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +11 -9
  413. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +1 -1
  414. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +67 -20
  415. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +504 -5
  416. package/templates/supplier-payments-agent/packages/agent-core/README.md +14 -1
  417. package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
  418. package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +39 -1
  419. package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
  420. package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +28 -5
  421. package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
  422. package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +62 -26
  423. package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
  424. package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +14 -2
  425. package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +35 -3
  426. package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +49 -3
  427. package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -2
  428. package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +235 -46
  429. package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +57 -1
  430. package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +2 -0
  431. package/templates/supplier-payments-agent/packages/agent-core/src/quote.ts +50 -0
  432. package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +89 -4
  433. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-chain.ts +270 -0
  434. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +194 -18
  435. package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +1 -1
  436. package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +10 -1
  437. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
  438. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +100 -32
  439. package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +17 -6
  440. package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +54 -1
  441. package/templates/supplier-payments-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
  442. package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
  443. package/templates/supplier-payments-agent/packages/agent-core/test/composition.test.ts +204 -0
  444. package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
  445. package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +4 -1
  446. package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
  447. package/templates/supplier-payments-agent/packages/agent-core/test/quote.test.ts +198 -0
  448. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
  449. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
  450. package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +103 -3
  451. package/templates/supplier-payments-agent/packages/agent-runtime/README.md +12 -0
  452. package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +32 -2
  453. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +53 -4
  454. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
  455. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
  456. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
  457. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
  458. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
  459. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
  460. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
  461. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
  462. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
  463. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
  464. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +6 -3
  465. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
  466. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
  467. package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +1 -0
  468. package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +5 -1
  469. package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +25 -2
  470. package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +8 -2
  471. package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +13 -3
  472. package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +127 -18
  473. package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
  474. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
  475. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
  476. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
  477. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
  478. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
  479. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
  480. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Everything about this agent the shared runner cannot know: the cart the
3
+ * conversation builds (in state.db), the price and discount envelope the core
4
+ * runs as its `policyExtension`, the bolepix rail and its sandbox payer, the
5
+ * tool handlers, the words the customer and the attendant read, and what a
6
+ * one-shot prints as JSON. The runner (`@codespar/agent-runtime`) owns the
7
+ * rest.
8
+ *
9
+ * Ordering and issuing are two moments (`executeOnApproval: false`): the
10
+ * attendant, or the policy, confirms the order, and the charge goes out when
11
+ * the customer asks for it, through the last gate.
12
+ *
13
+ * There is no consent step: the sales policy is the MERCHANT's own and no API
14
+ * surface signs it (checkout §3.3), so the example file is the policy in both
15
+ * rails.
16
+ */
17
+ import { relative } from "node:path";
18
+ import qrcode from "qrcode-terminal";
19
+ import {
20
+ CodeSparChargeRail,
21
+ NotATestKeyError,
22
+ StubChargeRail,
23
+ createCodeSparClient,
24
+ isTestKey,
25
+ loadMandate,
26
+ paySandboxCharge,
27
+ type Execution,
28
+ type StubChargeRailOptions,
29
+ } from "@codespar/agent-core";
30
+ import { defineAgent, envName, type AgentKit, type Setup } from "@codespar/agent-runtime";
31
+ import { formatBRL, formatDate } from "./catalog.js";
32
+ import { checkOrder, loadEnvelope, priceCart, localDate } from "./pricing.js";
33
+ import { claimOrder, CartBook, makeCartHandlers, type Cart } from "./modules/storefront-cart.js";
34
+ import { followCart, makeChargeHandlers, orderProposal } from "./modules/bolepix-receivables.js";
35
+ import { CodeSparInvoiceRail, followSale, InvoiceBook, resumeInvoices, StubInvoiceRail, type InvoiceDeps, type InvoiceRail, type StubIssuerBehaviour } from "./modules/nfse-invoice.js";
36
+
37
+ function cartOf(setup: Setup, execution: Execution): Cart | undefined {
38
+ return execution.composition ? new CartBook(setup.store).get(execution.composition.ref) : undefined;
39
+ }
40
+
41
+ const invoiceRails = new WeakMap<Setup, InvoiceRail>();
42
+
43
+ /**
44
+ * The issuer the NFS-e goes to: `codespar_invoice` through the API with a
45
+ * test key, the stub issuer otherwise. `CHECKOUT_STUB_ISSUER` scripts the
46
+ * stub from a test process (issues | refuses | times_out | unsent_once | unsent).
47
+ */
48
+ function invoiceRail(s: Setup): InvoiceRail {
49
+ let rail = invoiceRails.get(s);
50
+ if (!rail) {
51
+ const scripted = process.env[envName(s.agent, "STUB_ISSUER")] as StubIssuerBehaviour | undefined;
52
+ rail = s.api ? new CodeSparInvoiceRail(s.api) : new StubInvoiceRail(s.store, scripted);
53
+ invoiceRails.set(s, rail);
54
+ }
55
+ return rail;
56
+ }
57
+
58
+ function invoiceDeps(s: Setup, say: (line: string) => void): InvoiceDeps {
59
+ const carts = new CartBook(s.store);
60
+ return { store: s.store, engine: s.engine, rail: invoiceRail(s), cart: (ref) => carts.get(ref), say };
61
+ }
62
+
63
+ /**
64
+ * A cart and its order placed outside a conversation: the velocity window's
65
+ * history (`warmUp`) and the webhook case. Same book, same proposal, same
66
+ * gates as a conversation's.
67
+ */
68
+ async function placeOrder(s: Setup, customer: string, lines: Array<{ sku: string; quantity: number }>): Promise<Execution> {
69
+ const book = new CartBook(s.store);
70
+ const now = s.engine.clock();
71
+ const priced = priceCart({ lines }, loadEnvelope(s.guardrails), localDate(now, s.guardrails.timezone));
72
+ const runId = s.runId;
73
+ const cartId = book.nextId(runId);
74
+ const cart: Cart = { ...priced, cart_id: cartId, ref: `${runId}/${cartId}`, run_id: runId, version: 1, currency: "BRL", order_discount_pct: 0, updated_at: now.toISOString() };
75
+ book.save(cart);
76
+ const draft = await s.engine.draft(orderProposal(cart, customer, { timezone: s.guardrails.timezone, clock: s.engine.clock }));
77
+ if (!draft.ok) throw new Error(`refused: ${draft.reason}`);
78
+ claimOrder(s.engine, cart, draft.execution.id);
79
+ return draft.execution;
80
+ }
81
+
82
+ const kit: AgentKit = {
83
+ settlement: "await-payer",
84
+ scenarioRail: "requested",
85
+ executeOnApproval: false,
86
+
87
+ labels: {
88
+ defaultUser: "usr_atendente",
89
+ evalUser: "usr_atendente",
90
+ mandateWord: "politica",
91
+ receiptWord: "pedido",
92
+ intro: 'Voce e o cliente. Diga o que quer ("oi, sou a Marina, quero o pacote de dez aulas e uma avaliacao inicial"). Ctrl+D ou "sair" encerra.',
93
+ prompt: "cliente> ",
94
+ approveQuestion: " [atendente] Confirmar este pedido? [s/N] ",
95
+ uncertainDispatch: " desfecho desconhecido no trilho; rode `npm run resume` para reconciliar (nunca repita a emissao)",
96
+ missingReceiptKind: "record_missing_locally",
97
+ missingReceiptDetail: (receiptId, runId) => `paid charge ${receiptId} is not in runs/${runId}/receipts`,
98
+ stillExecuting: (e) => `${e.id}: still executing (${e.reason}) — ${e.detail}; nothing was re-issued; \`npm run poll\` keeps looking`,
99
+ waitingForPayer: (round) => ` aguardando o pagamento... (${round} consultas)`,
100
+ },
101
+
102
+ usage: () => `checkout-agent
103
+ npm start interactive terminal (you are the customer; the attendant answers the approval question)
104
+ npm start -- --input "oi, sou a Marina, quero o pacote de dez aulas e uma avaliacao inicial" one turn (add --approve/--deny, --json)
105
+ npm start -- --scenario <name> run a scenario pack (see scenarios/)
106
+ npm run approve -- <execution-id> the attendant confirms an order left awaiting (it is issued when the customer asks)
107
+ npm start -- --channel whatsapp --conversation <name> the conversation channel (needs npm run whatsapp:emulator at the repo root)
108
+ npm start -- --channel whatsapp --conversation <name> --scripted the same, with the customer's turns replayed from channels/whatsapp/
109
+ npm run poll -- --channel whatsapp --conversation <name> back to a conversation whose payment landed after the run ended
110
+ options: --mode human|mandate --provider anthropic|replay --transcript <file> --rail stub|api --user <id>
111
+ --wait <seconds> --simulate-payer --payer pays|expires|never (stub only) --json
112
+ --now <ISO 8601> pin the run to that instant (service hours, the due date, timestamps); env CODESPAR_AGENT_NOW is the same thing`,
113
+
114
+ buildRail: (ctx) => {
115
+ const mandate = ctx.mandate ?? loadMandate(ctx.manifest.resolvePath(ctx.manifest.manifest.mandate_schema));
116
+ if (ctx.kind === "api") {
117
+ if (!isTestKey(ctx.env["CODESPAR_API_KEY"])) throw new NotATestKeyError();
118
+ const client = createCodeSparClient({ apiKey: ctx.env["CODESPAR_API_KEY"], baseUrl: ctx.env["CODESPAR_API_URL"], projectId: ctx.env["CODESPAR_PROJECT_ID"] });
119
+ return {
120
+ rail: new CodeSparChargeRail(client),
121
+ mandate,
122
+ api: client,
123
+ pollIntervalMs: 3000,
124
+ payer: {
125
+ kind: "api" as const,
126
+ async pay(chargeId: string) {
127
+ const result = await paySandboxCharge(client, chargeId);
128
+ if (!result.ok) return { ok: false as const, detail: `${result.failure.code}: ${result.failure.message}` };
129
+ const s = result.state;
130
+ return { ok: true as const, detail: `sandbox payer: ${s.charge_id} ${s.status} (${s.payment}, ${s.paid_minor} of ${s.quoted_minor}), simulated=${s.simulated}, settled_against=${s.settled_against}, money_moved=${s.money_moved}${s.idempotent_replay ? ", replay" : ""}` };
131
+ },
132
+ behave() {
133
+ /* the API's payer is a route, not a fixture; a scenario that needs "expires" declares rails: [stub] */
134
+ },
135
+ },
136
+ };
137
+ }
138
+ // CHECKOUT_KILL_AFTER_DISPATCH=1 simulates a crash right after the issuer accepted the charge and before the outcome was recorded.
139
+ const killAfterDispatch = ctx.envVar("KILL_AFTER_DISPATCH") === "1" ? { afterDispatch: () => process.exit(137) } : {};
140
+ // CHECKOUT_STUB_PAYER=pays|expires|never: what the fixture payer does, from a test process.
141
+ const behaviour = ctx.envVar("STUB_PAYER");
142
+ const fixture: Pick<StubChargeRailOptions, "payer"> = behaviour === "pays" || behaviour === "expires" || behaviour === "never" ? { payer: behaviour } : {};
143
+ const stub = new StubChargeRail(ctx.store, { ...(ctx.now ? { clock: ctx.now } : {}), ...killAfterDispatch, ...fixture, ...(ctx.stubRail ?? {}) });
144
+ return {
145
+ rail: stub,
146
+ mandate,
147
+ pollIntervalMs: 0,
148
+ payer: {
149
+ kind: "stub" as const,
150
+ async pay(_chargeId: string, attemptId: string) {
151
+ stub.decide(attemptId, "pays");
152
+ return { ok: true as const, detail: "stub payer: will pay at the next look" };
153
+ },
154
+ behave: (b) => stub.setPayer(b),
155
+ decideFor: (attemptId, b) => stub.decide(attemptId, b),
156
+ },
157
+ };
158
+ },
159
+
160
+ handlers: (setup) => {
161
+ const envelope = loadEnvelope(setup.guardrails);
162
+ const book = new CartBook(setup.store);
163
+ // On a channel that binds a conversation, the customer is the one it is bound to: read at call time, because the channel binds after setup.
164
+ const orderDeps = { book, runId: setup.runId, timezone: setup.guardrails.timezone, clock: setup.engine.clock, boundCustomer: () => setup.conversation?.subject };
165
+ return {
166
+ ...makeCartHandlers({ ...orderDeps, envelope, onReplaced: (cart, engine) => void followCart(cart, engine, orderDeps) }),
167
+ ...makeChargeHandlers(orderDeps),
168
+ };
169
+ },
170
+
171
+ policyExtension: ({ guardrails, store }) => {
172
+ const envelope = loadEnvelope(guardrails);
173
+ const book = new CartBook(store);
174
+ return (execution, ctx) => checkOrder(execution, execution.composition ? book.get(execution.composition.ref) : undefined, envelope, ctx.now, ctx.guardrails.timezone);
175
+ },
176
+
177
+ describeExecution: (execution, setup) => {
178
+ const lines: string[] = [];
179
+ const cart = cartOf(setup, execution);
180
+ lines.push(` pedido ${execution.id}: ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}`);
181
+ lines.push(` cliente ${execution.items[0]?.beneficiary ?? "?"}${cart ? `, carrinho ${cart.cart_id} v${cart.version}` : ""}`);
182
+ for (const l of cart?.line_items ?? []) lines.push(` - ${l.quantity}x ${l.name}: ${formatBRL(l.totals.find((t) => t.type === "total")!.amount)}${l.discount_pct ? ` (desconto ${l.discount_pct}%)` : ""}`);
183
+ for (const d of cart?.order_discounts ?? []) lines.push(` - ${d.kind === "coupon" ? `cupom ${d.ref.replace("coupon:", "")}` : "desconto no pedido"}: ${formatBRL(-d.amount)}`);
184
+ lines.push(` total (calculado pelo core): ${formatBRL(execution.total)}${execution.items[0]?.due_date ? `, vence ${formatDate(execution.items[0].due_date)}` : ""}`);
185
+ if (execution.composition) lines.push(` cart_hash ${execution.composition.composition_hash.slice(0, 19)}… (${execution.composition.line_count} linha(s))`);
186
+ if (execution.escalation) lines.push(` escalado por: ${execution.escalation.trigger} — ${execution.escalation.detail}`);
187
+ if (execution.blocking_reasons.length) lines.push(` bloqueado: ${execution.blocking_reasons.join(", ")} — a politica nao autoriza; nao ha o que aprovar`);
188
+ if (execution.detail && execution.state !== "awaiting_approval") lines.push(` ${execution.detail}`);
189
+ for (const outcome of execution.outcomes) {
190
+ if (outcome.transaction_id) lines.push(` cobranca: ${outcome.transaction_id} — ${outcome.status}${outcome.code ? ` (${outcome.code})` : ""}`);
191
+ if (outcome.receipt_id) lines.push(` pedido pago: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
192
+ }
193
+ const invoice = new InvoiceBook(setup.store).of(execution.id);
194
+ if (invoice) lines.push(` NFS-e ${invoice.id}: ${invoice.state}${invoice.reason ? ` (${invoice.reason}, ${invoice.code})` : ""}${invoice.document ? ` — documento ${invoice.document.id}` : ""}`);
195
+ return lines;
196
+ },
197
+
198
+ oneShotPayload: ({ setup: s, reply, toolCalls, executions, startedAt }) => {
199
+ const book = new CartBook(s.store);
200
+ return {
201
+ run_id: s.runId,
202
+ agent: `${s.manifest.manifest.name}@${s.manifest.manifest.version}`,
203
+ mode: s.mode,
204
+ rail: s.railKind,
205
+ policy_id: s.mandate.id,
206
+ actor: s.engine.agentActor,
207
+ reply,
208
+ tool_calls: toolCalls,
209
+ carts: book.idsOf(s.runId).map((id) => book.byId(s.runId, id)!).map((c) => ({ cart_id: c.cart_id, version: c.version, cart_hash: c.cart_hash, total_minor: c.total, validation_issues: c.validation_issues.map((i) => i.code) })),
210
+ executions: executions.map((e) => {
211
+ const cart = cartOf(s, e);
212
+ const outcome = e.outcomes[0];
213
+ return {
214
+ id: e.id,
215
+ state: e.state,
216
+ reason: e.reason ?? null,
217
+ escalation: e.escalation ?? null,
218
+ cart_id: cart?.cart_id ?? null,
219
+ cart_hash: e.composition?.composition_hash ?? null,
220
+ total_minor: e.total,
221
+ due_date: e.items[0]?.due_date ?? null,
222
+ approval_id: e.approval_id ?? null,
223
+ charge_id: outcome?.transaction_id ?? null,
224
+ payable: outcome?.instrument?.payable ?? null,
225
+ pix_copy_paste: outcome?.instrument?.pix_copy_paste ?? null,
226
+ receipt_ids: e.outcomes.filter((o) => o.receipt_id).map((o) => o.receipt_id),
227
+ };
228
+ }),
229
+ invoices: executions.map((e) => new InvoiceBook(s.store).of(e.id)).filter((r) => r !== undefined).map((r) => ({ id: r.id, sale_execution_id: r.sale_execution_id, state: r.state, reason: r.reason ?? null, code: r.code ?? null, document_id: r.document?.id ?? null, attempts: r.attempts })),
230
+ receipts: s.bundle.listReceipts().map((f) => relative(process.cwd(), `${s.bundle.dir}/receipts/${f}`)),
231
+ bundle_dir: relative(process.cwd(), s.bundle.dir),
232
+ seconds: Math.round(((Date.now() - startedAt) / 1000) * 10) / 10,
233
+ };
234
+ },
235
+
236
+ /** What the customer reads when the charge is payable: the QR as an image, the copy-and-paste under it, the bank line if any. */
237
+ presentInstrument: (execution, _instalment, chargeId, instrument, tell) => {
238
+ tell("");
239
+ tell(`Pedido de ${formatBRL(execution.total)}${instrument.due_date ? `, vence ${formatDate(instrument.due_date)}` : ""} — cobranca ${chargeId}`);
240
+ if (instrument.pix_copy_paste) {
241
+ qrcode.generate(instrument.pix_copy_paste, { small: true }, (qr: string) => {
242
+ for (const line of qr.split("\n")) tell(line);
243
+ });
244
+ tell("Pix copia e cola:");
245
+ tell(instrument.pix_copy_paste);
246
+ }
247
+ if (instrument.boleto_bank_line) {
248
+ tell("Ou pelo boleto, linha digitavel:");
249
+ tell(instrument.boleto_bank_line);
250
+ }
251
+ tell("");
252
+ },
253
+
254
+ /** One message per outcome, and only for an outcome: an order confirmed, or sent back to the attendant, is not one. */
255
+ announceOutcome: (execution, setup, tell) => {
256
+ if (!["settled", "failed", "denied", "expired"].includes(execution.state)) return false;
257
+ if (!setup.engine.markTold(execution.id, execution.state)) return false;
258
+ let text: string;
259
+ if (execution.state === "settled") text = `Recebemos, pedido confirmado! Obrigado. (${execution.outcomes.map((o) => o.transaction_id).filter(Boolean).join(", ")})`;
260
+ else if (execution.reason === "charge_expired") text = "A cobranca venceu sem pagamento. Se quiser, emito uma nova para o mesmo pedido.";
261
+ else if (execution.reason === "charge_cancelled") text = "A cobranca foi cancelada. Nada foi pago.";
262
+ else if (execution.reason === "charge_reference_ambiguous") text = "A cobranca deste pedido ja foi emitida e estamos conferindo a situacao dela. Nao pague de novo; te aviso assim que estiver conferida.";
263
+ else if (execution.state === "failed") text = `Nao consegui emitir a cobranca (${execution.reason ?? "falha no trilho"}). Nada foi cobrado.`;
264
+ else if (execution.state === "denied") text = `Nao consigo fechar o pedido nesses termos (${execution.reason ?? "recusado"}).`;
265
+ else text = `O pedido expirou sem confirmacao (${execution.reason ?? execution.state}).`;
266
+ tell(text);
267
+ setup.engine.note("message.debtor", execution.id, { state: execution.state, reason: execution.reason ?? null, text });
268
+ return true;
269
+ },
270
+
271
+ /** Checkout §4: a paid order opens its NFS-e, an execution of its own that never moves the sale. */
272
+ followUp: async (execution, setup, say) => {
273
+ await followSale(execution, invoiceDeps(setup, say));
274
+ },
275
+ resumeFollowUps: async (setup, say) => {
276
+ for (const r of await resumeInvoices(invoiceDeps(setup, say))) say(`${r.id}: NFS-e of ${r.sale_execution_id} -> ${r.state}${r.reason ? ` (${r.reason}, ${r.code})` : ""}`);
277
+ },
278
+
279
+ /**
280
+ * The same outcome as `announceOutcome`, as a template this agent declares
281
+ * in `channels/whatsapp/templates.json`: what a poll sends once the 24-hour
282
+ * window has shut, which for a sale is the ordinary case of a customer who
283
+ * ordered at night and paid in the morning. A denial or an expired approval
284
+ * is answered inside the turn that produced it, so it has no template, and
285
+ * the poll reports it rather than sending approximate copy.
286
+ */
287
+ outcomeTemplate: (execution) => {
288
+ const total = formatBRL(execution.total);
289
+ if (execution.state === "settled") return { template: "pedido_confirmado", variables: [total] };
290
+ if (execution.reason === "charge_expired") return { template: "pedido_cobranca_vencida", variables: [total] };
291
+ if (execution.reason === "charge_cancelled") return { template: "pedido_cobranca_cancelada", variables: [total] };
292
+ return undefined;
293
+ },
294
+
295
+ /** Orders already paid by the same customer under this policy, so the velocity window has history. */
296
+ warmUp: async (s, aliases, approver) => {
297
+ const warm = new Set<string>();
298
+ for (const alias of aliases) {
299
+ let e = await placeOrder(s, alias, [{ sku: "aula-avulsa", quantity: 1 }]);
300
+ if (e.state === "awaiting_approval") e = s.engine.approve(e.id, approver);
301
+ if (e.state === "approved") e = await s.engine.execute(e.id);
302
+ for (let i = 0; i < 2 && e.state === "executing"; i += 1) e = await s.engine.reconcile(e.id);
303
+ if (e.state !== "settled") throw new Error(`warm-up for ${alias} ended ${e.state} (${e.reason})`);
304
+ warm.add(e.id);
305
+ }
306
+ return warm;
307
+ },
308
+
309
+ /** Webhook duplicated or out of order: the same `commerce.charge.paid` twice, `paid` before `created`, `expired` after `paid`. One settled, one message. */
310
+ runEventsCase: async (s, tell) => {
311
+ s.payer!.behave("never");
312
+ let execution = await placeOrder(s, "marina", [{ sku: "aula-avulsa", quantity: 2 }]);
313
+ if (execution.state === "awaiting_approval") execution = s.engine.approve(execution.id, { id: "usr_atendente", channel: "terminal" });
314
+ execution = await s.engine.execute(execution.id);
315
+ const chargeId = execution.outcomes[0]!.transaction_id!;
316
+ const apply = (event_id: string, type: string) => {
317
+ s.engine.ingestExternalEvent({ event_id, type, transaction_id: chargeId });
318
+ kit.announceOutcome!(s.engine.get(execution.id)!, s, tell);
319
+ };
320
+ apply("evt_paid_1", "commerce.charge.paid");
321
+ apply("evt_paid_1", "commerce.charge.paid");
322
+ apply("evt_created_late", "commerce.charge.created");
323
+ apply("evt_paid_2", "commerce.charge.paid");
324
+ apply("evt_expired_late", "commerce.charge.expired");
325
+ },
326
+
327
+ // The payer's behaviour is part of the recording: a charge that expired in the original run expires in the rerun.
328
+ rerunPlan: (events) => {
329
+ const expired = events.some((e) => e["type"] === "execution.transition" && (e["payload"] as { reason?: string }).reason === "charge_expired");
330
+ return { stubRail: { payer: expired ? "expires" : "pays" }, simulatePayer: !expired };
331
+ },
332
+ rerunComparesOutcomes: false,
333
+
334
+ evalScenarioLine: (check) =>
335
+ `${check.ok ? "ok " : "FAIL"} scenario/${check.run.scenario} [${check.mode}] — states ${JSON.stringify(check.run.executions.map((e) => e.state))}, ${check.run.charges_issued} charge(s), ${check.run.receipts} paid order(s), ${check.run.debtor_messages} message(s)${check.failures.length ? ` — ${check.failures.join("; ")}` : ""}`,
336
+ };
337
+
338
+ export const agent = defineAgent(import.meta.url, kit);
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Module `bolepix-receivables`, the sales version: the `codespar_charge`
3
+ * handler. A copy of the collections-agent's module in its bones (agents do
4
+ * not import each other's modules, OPEN_QUESTIONS §39f) and different in what
5
+ * it charges: an ORDER, one cobranca com vencimento whose amount is the
6
+ * cart's total as the code priced it, due today (checkout decision 1).
7
+ *
8
+ * Three actions, because ordering and issuing are two moments of a sale:
9
+ *
10
+ * - `create` turns the cart into an order: ONE execution, one item (the
11
+ * customer, the cart's total, today's due date) and the cart's composition
12
+ * bound to it. The code checks it at every gate; in `approval: human` the
13
+ * attendant confirms it, in `approval: mandate` the policy does. Nothing is
14
+ * issued.
15
+ * - `issue` hands the approved order to `engine.execute`, which runs the last
16
+ * gate: a cart changed since the approval sends the order back to a person
17
+ * (`items_hash_mismatch`). Only then does the rail call `POST /v1/charges`,
18
+ * with the customer's name and document from the policy and the attempt id
19
+ * as `idempotency_key`, so asking twice returns the same charge.
20
+ * - `status` reads.
21
+ *
22
+ * No input carries an amount. `total_minor` is recorded and, with
23
+ * `model_total_mismatch: refuse`, refuses a total the model got wrong.
24
+ */
25
+ import type { Execution, ExecutionEngine, Proposal, ToolHandler } from "@codespar/agent-core";
26
+ import { MERCHANT, formatBRL, formatDate } from "../catalog.js";
27
+ import { localDate } from "../pricing.js";
28
+ import { claimOrder, currentCart, orderOf, resolveCart, type Cart, type CartBook } from "./storefront-cart.js";
29
+
30
+ interface ChargeInput {
31
+ action?: unknown;
32
+ cart_id?: unknown;
33
+ customer?: unknown;
34
+ payment?: unknown;
35
+ total_minor?: unknown;
36
+ execution_id?: unknown;
37
+ }
38
+
39
+ export interface OrderDeps {
40
+ book: CartBook;
41
+ runId: string;
42
+ timezone: string;
43
+ clock: () => Date;
44
+ /** The customer a channel's conversation is bound to, when one is: an order in this conversation is theirs. */
45
+ boundCustomer?: () => string | undefined;
46
+ }
47
+
48
+ const OPEN = new Set(["awaiting_approval", "approved"]);
49
+
50
+ /** The proposal an order is: the customer, the cart's total due today, and the cart's composition. */
51
+ export function orderProposal(cart: Cart, customer: string, deps: Pick<OrderDeps, "timezone" | "clock">, claimedTotal?: number): Proposal {
52
+ return {
53
+ items: [{ payee: customer, amount: cart.total, due_date: localDate(deps.clock(), deps.timezone), description: `${MERCHANT.name} - pedido ${cart.cart_id}` }],
54
+ composition: { ref: cart.ref, composition_hash: cart.cart_hash, line_count: cart.composition.length },
55
+ ...(claimedTotal !== undefined ? { claimed_total: claimedTotal } : {}),
56
+ };
57
+ }
58
+
59
+ /**
60
+ * A cart replaced while its order is open: the order follows the cart
61
+ * (`restate`), and the gates judge it on what it says now. An APPROVED order
62
+ * keeps the artifact of the old cart, which is exactly what the last gate
63
+ * compares. A cart left empty or with pending issues is not an order anyone
64
+ * can issue; the order is left as it was and every gate refuses it, because
65
+ * the policy compares the order with the CURRENT cart.
66
+ */
67
+ export function followCart(cart: Cart, engine: ExecutionEngine, deps: Pick<OrderDeps, "timezone" | "clock">): Execution | undefined {
68
+ const order = orderOf(engine, cart);
69
+ if (!order || !OPEN.has(order.state)) return undefined;
70
+ if (order.composition?.composition_hash === cart.cart_hash) return order;
71
+ if (cart.line_items.length === 0 || cart.validation_issues.length > 0) return order;
72
+ const customer = order.items[0]!.alias ?? order.items[0]!.payee;
73
+ return engine.restate(order.id, orderProposal(cart, customer, deps));
74
+ }
75
+
76
+ export function makeChargeHandlers(deps: OrderDeps): Record<string, ToolHandler> {
77
+ const findOrder = (engine: ExecutionEngine, input: ChargeInput): { order: Execution | undefined; cart: Cart | undefined } => {
78
+ if (typeof input.execution_id === "string" && input.execution_id) {
79
+ const order = engine.get(input.execution_id);
80
+ if (!order) throw new Error(`no order ${input.execution_id} in this state`);
81
+ return { order, cart: order.composition ? deps.book.get(order.composition.ref) : undefined };
82
+ }
83
+ const cart = resolveCart(engine, deps, input.cart_id);
84
+ return { order: cart ? orderOf(engine, cart) : undefined, cart };
85
+ };
86
+
87
+ const codesparCharge: ToolHandler = async (raw, ctx) => {
88
+ const input = raw as ChargeInput;
89
+ const action = input.action ?? "create";
90
+ if (input.payment !== undefined && input.payment !== "bolepix") throw new Error(`codespar_charge: payment ${String(input.payment)} is not offered; the order is charged by bolepix (Pix or boleto on one charge)`);
91
+
92
+ if (action === "status") {
93
+ const { order, cart } = findOrder(ctx.engine, input);
94
+ if (!order) return { found: false, message: cart ? `o carrinho ${cart.cart_id} ainda nao virou pedido` : "nenhum pedido nesta conversa" };
95
+ return { found: true, ...describe(order, cart) };
96
+ }
97
+
98
+ if (action === "issue") {
99
+ const { order, cart } = findOrder(ctx.engine, input);
100
+ if (!order) throw new Error("codespar_charge: no order to issue; create the order from the cart first (action=create)");
101
+ if (order.state !== "approved") return { ...describe(order, cart), message: messageFor(order) };
102
+ // The cart may have moved since the order was approved; the order follows it, and the last gate compares.
103
+ if (cart) followCart(cart, ctx.engine, deps);
104
+ const executed = await ctx.engine.execute(order.id);
105
+ const handled = await ctx.onExecution(executed);
106
+ return describe(handled, cart ?? undefined);
107
+ }
108
+
109
+ if (action !== "create") throw new Error(`codespar_charge: unsupported action ${String(action)}; this agent creates an order, issues its charge and reads it`);
110
+ const cart = input.cart_id === undefined ? (currentCart(ctx.engine, deps) ?? deps.book.latest(deps.runId)) : resolveCart(ctx.engine, deps, input.cart_id);
111
+ if (!cart || cart.line_items.length === 0) throw new Error("codespar_charge: cart_empty — the cart has no lines; nothing is ordered");
112
+ if (cart.validation_issues.length > 0) {
113
+ throw new Error(`codespar_charge: the cart has pending validation_issues (${cart.validation_issues.map((i) => i.code).join(", ")}); replace the cart without them (cart_update) before ordering. Nothing was ordered.`);
114
+ }
115
+ if (typeof input.customer !== "string" || !input.customer.trim()) throw new Error("codespar_charge: customer must be the alias of the customer you are talking to (their first name, lowercase)");
116
+ const customer = input.customer.trim().toLowerCase();
117
+ // The contact binding is what identifies the customer on a channel. A charge in anybody else's name — even another
118
+ // customer of the store, whom the policy would allow — is refused before an order exists.
119
+ const bound = deps.boundCustomer?.();
120
+ if (bound && customer !== bound) throw new Error(`codespar_charge: this conversation is with ${bound}; an order here is charged to ${bound} and to nobody else. Nothing was ordered.`);
121
+
122
+ const existing = orderOf(ctx.engine, cart);
123
+ if (existing && (OPEN.has(existing.state) || existing.state === "executing" || existing.state === "settled")) {
124
+ if (OPEN.has(existing.state)) followCart(cart, ctx.engine, deps);
125
+ const current = ctx.engine.get(existing.id)!;
126
+ return { ...describe(current, cart), message: `este carrinho ja e o pedido ${current.id}; nada novo foi criado` };
127
+ }
128
+
129
+ const claimed = typeof input.total_minor === "number" ? input.total_minor : undefined;
130
+ const draft = await ctx.engine.draft(orderProposal(cart, customer, deps, claimed));
131
+ if (!draft.ok) return { status: "refused", reason: draft.reason, message: draft.message, issued: false, paid: false };
132
+ claimOrder(ctx.engine, cart, draft.execution.id);
133
+ const decided = await ctx.onExecution(draft.execution);
134
+ return { ...describe(decided, cart), message: messageFor(decided) };
135
+ };
136
+
137
+ return { codespar_charge: codesparCharge };
138
+ }
139
+
140
+ function messageFor(order: Execution): string {
141
+ switch (order.state) {
142
+ case "approved":
143
+ return "pedido confirmado; a cobranca sai quando o cliente pedir (action=issue)";
144
+ case "awaiting_approval":
145
+ return order.reason === "items_hash_mismatch" ? "o carrinho mudou depois da confirmacao; o pedido voltou para o atendente" : "aguardando o atendente confirmar o pedido";
146
+ case "executing":
147
+ return order.reason === "awaiting_settlement" ? "cobranca emitida; aguardando o pagamento" : "desfecho da emissao desconhecido; nada sera reemitido";
148
+ case "settled":
149
+ return "pago";
150
+ default:
151
+ return `${order.state}${order.reason ? ` (${order.reason})` : ""}`;
152
+ }
153
+ }
154
+
155
+ export function describe(order: Execution, cart: Cart | undefined) {
156
+ const outcome = order.outcomes[0];
157
+ return {
158
+ status: order.state,
159
+ execution_id: order.id,
160
+ cart_id: cart?.cart_id ?? order.composition?.ref ?? null,
161
+ customer: order.items[0]?.alias ?? null,
162
+ total_minor: order.total,
163
+ total: formatBRL(order.total),
164
+ due_date: order.items[0]?.due_date ? formatDate(order.items[0].due_date) : null,
165
+ ...(order.reason ? { reason: order.reason, detail: order.detail } : {}),
166
+ ...(order.escalation ? { escalated_by: order.escalation.trigger } : {}),
167
+ charge: outcome
168
+ ? {
169
+ charge_id: outcome.transaction_id ?? null,
170
+ status: outcome.status,
171
+ ...(outcome.instrument ? { payable: outcome.instrument.payable, pix_copy_paste: outcome.instrument.pix_copy_paste, boleto_bank_line: outcome.instrument.boleto_bank_line } : {}),
172
+ ...(outcome.code ? { code: outcome.code } : {}),
173
+ }
174
+ : null,
175
+ issued: order.reason === "charge_reference_ambiguous" ? order.state === "failed" : order.outcomes.length > 0 && order.outcomes.every((o) => o.status !== "failed"),
176
+ paid: order.state === "settled",
177
+ expired: order.state === "failed" && order.reason === "charge_expired",
178
+ };
179
+ }