@codespar/cli 0.18.1 → 0.20.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 (558) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/login.js +52 -12
  3. package/dist/commands/login.js.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/surface.js +31 -13
  7. package/dist/surface.js.map +1 -1
  8. package/package.json +1 -1
  9. package/templates/bills-agent/README.md +2 -2
  10. package/templates/bills-agent/agents/bills-agent/.env.example +2 -2
  11. package/templates/bills-agent/agents/bills-agent/README.md +25 -18
  12. package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +13 -3
  13. package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -1
  14. package/templates/bills-agent/agents/bills-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  15. package/templates/bills-agent/agents/bills-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
  16. package/templates/bills-agent/agents/bills-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  17. package/templates/bills-agent/agents/bills-agent/mandate.example.json +1 -1
  18. package/templates/bills-agent/agents/bills-agent/runbook.md +1 -1
  19. package/templates/bills-agent/agents/bills-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  20. package/templates/bills-agent/agents/bills-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
  21. package/templates/bills-agent/agents/bills-agent/scenarios/escalated-above-threshold.transcript.jsonl +4 -4
  22. package/templates/bills-agent/agents/bills-agent/scenarios/happy-path.transcript.jsonl +1 -1
  23. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.json +1 -1
  24. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.transcript.jsonl +4 -4
  25. package/templates/bills-agent/agents/bills-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  26. package/templates/bills-agent/agents/bills-agent/src/bills.ts +1 -1
  27. package/templates/bills-agent/agents/bills-agent/src/kit.ts +15 -28
  28. package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +42 -15
  29. package/templates/bills-agent/agents/bills-agent/src/modules/pix-out.ts +21 -3
  30. package/templates/bills-agent/agents/bills-agent/src/strings.ts +68 -0
  31. package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +130 -2
  32. package/templates/bills-agent/agents/bills-agent/test/consent-money.test.ts +25 -0
  33. package/templates/bills-agent/agents/bills-agent/test/dates-and-approval.test.ts +98 -0
  34. package/templates/bills-agent/agents/bills-agent/test/eval-runs.test.ts +81 -0
  35. package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -2
  36. package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +1 -1
  37. package/templates/bills-agent/agents/bills-agent/test/locale.test.ts +161 -0
  38. package/templates/bills-agent/agents/bills-agent/test/mandate-state.test.ts +108 -0
  39. package/templates/bills-agent/agents/bills-agent/test/refused-before-draft.test.ts +81 -0
  40. package/templates/bills-agent/agents/bills-agent/test/replay.test.ts +76 -0
  41. package/templates/bills-agent/agents/bills-agent/test/reply-and-outcome.test.ts +84 -0
  42. package/templates/bills-agent/agents/bills-agent/test/reply-language.test.ts +95 -0
  43. package/templates/bills-agent/agents/bills-agent/test/rerun-and-missing-transcript.test.ts +120 -0
  44. package/templates/bills-agent/agents/bills-agent/test/rerun-world-events.test.ts +55 -0
  45. package/templates/bills-agent/agents/bills-agent/tools.json +1 -1
  46. package/templates/bills-agent/packages/agent-core/README.md +21 -2
  47. package/templates/bills-agent/packages/agent-core/package.json +1 -1
  48. package/templates/bills-agent/packages/agent-core/src/agent.ts +33 -6
  49. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  50. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +11 -5
  51. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  52. package/templates/bills-agent/packages/agent-core/src/bundle.ts +2 -0
  53. package/templates/bills-agent/packages/agent-core/src/channels.ts +18 -8
  54. package/templates/bills-agent/packages/agent-core/src/check.ts +25 -3
  55. package/templates/bills-agent/packages/agent-core/src/engine.ts +90 -9
  56. package/templates/bills-agent/packages/agent-core/src/escalate.ts +10 -0
  57. package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
  58. package/templates/bills-agent/packages/agent-core/src/language.ts +52 -0
  59. package/templates/bills-agent/packages/agent-core/src/locale.ts +88 -0
  60. package/templates/bills-agent/packages/agent-core/src/manifest.ts +4 -1
  61. package/templates/bills-agent/packages/agent-core/src/rail.ts +29 -1
  62. package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  63. package/templates/bills-agent/packages/agent-core/src/secrets.ts +53 -8
  64. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +14 -0
  65. package/templates/bills-agent/packages/agent-core/src/strings.ts +175 -0
  66. package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  67. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  68. package/templates/bills-agent/packages/agent-core/src/types.ts +15 -2
  69. package/templates/bills-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  70. package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  71. package/templates/bills-agent/packages/agent-core/test/engine.test.ts +23 -0
  72. package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
  73. package/templates/bills-agent/packages/agent-core/test/language.test.ts +40 -0
  74. package/templates/bills-agent/packages/agent-core/test/locale.test.ts +137 -0
  75. package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  76. package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
  77. package/templates/bills-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  78. package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  79. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +49 -0
  80. package/templates/bills-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  81. package/templates/bills-agent/packages/agent-core/test/secrets.test.ts +40 -1
  82. package/templates/bills-agent/packages/agent-runtime/README.md +31 -4
  83. package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  84. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  85. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  86. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  87. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  88. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  89. package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  90. package/templates/bills-agent/packages/agent-runtime/src/cli.ts +30 -4
  91. package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  92. package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  93. package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  94. package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  95. package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  96. package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  97. package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  98. package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  99. package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  100. package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  101. package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  102. package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  103. package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  104. package/templates/bills-agent/packages/agent-runtime/src/env.ts +64 -0
  105. package/templates/bills-agent/packages/agent-runtime/src/index.ts +2 -0
  106. package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +81 -10
  107. package/templates/bills-agent/packages/agent-runtime/src/kit.ts +34 -12
  108. package/templates/bills-agent/packages/agent-runtime/src/outcome.ts +118 -0
  109. package/templates/bills-agent/packages/agent-runtime/src/poll.ts +7 -7
  110. package/templates/bills-agent/packages/agent-runtime/src/runs.ts +51 -0
  111. package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  112. package/templates/bills-agent/packages/agent-runtime/src/setup.ts +75 -5
  113. package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +71 -33
  114. package/templates/bills-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  115. package/templates/bills-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  116. package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  117. package/templates/bills-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  118. package/templates/bills-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  119. package/templates/bills-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  120. package/templates/bills-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  121. package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  122. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  123. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  124. package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  125. package/templates/checkout-agent/README.md +2 -2
  126. package/templates/checkout-agent/agents/checkout-agent/.env.example +6 -4
  127. package/templates/checkout-agent/agents/checkout-agent/README.md +16 -8
  128. package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +17 -7
  129. package/templates/checkout-agent/agents/checkout-agent/agent.yaml +4 -3
  130. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +2 -2
  131. package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +48 -4
  132. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +1 -1
  133. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +1 -1
  134. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +1 -1
  135. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +1 -1
  136. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  137. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +1 -1
  138. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +1 -1
  139. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +1 -1
  140. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +1 -1
  141. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  142. package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +1 -1
  143. package/templates/checkout-agent/agents/checkout-agent/package.json +1 -1
  144. package/templates/checkout-agent/agents/checkout-agent/runbook.md +4 -4
  145. package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  146. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +2 -2
  147. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +2 -2
  148. package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +2 -2
  149. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +1 -1
  150. package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +2 -2
  151. package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +1 -1
  152. package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +1 -1
  153. package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +2 -2
  154. package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +1 -1
  155. package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +3 -3
  156. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +1 -1
  157. package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +2 -2
  158. package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +1 -1
  159. package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  160. package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +7 -7
  161. package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +47 -43
  162. package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +20 -12
  163. package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +4 -4
  164. package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +9 -6
  165. package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +44 -41
  166. package/templates/checkout-agent/agents/checkout-agent/src/strings.ts +179 -0
  167. package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +4 -1
  168. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +1 -1
  169. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +2 -2
  170. package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +1 -1
  171. package/templates/checkout-agent/agents/checkout-agent/test/payable-instrument.test.ts +58 -0
  172. package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +2 -2
  173. package/templates/checkout-agent/agents/checkout-agent/test/rerun-unpaid.test.ts +47 -0
  174. package/templates/checkout-agent/agents/checkout-agent/test/scenario-reach-and-seconds.test.ts +55 -0
  175. package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +26 -10
  176. package/templates/checkout-agent/agents/checkout-agent/tools.json +1 -1
  177. package/templates/checkout-agent/packages/agent-core/README.md +21 -2
  178. package/templates/checkout-agent/packages/agent-core/package.json +1 -1
  179. package/templates/checkout-agent/packages/agent-core/src/agent.ts +33 -6
  180. package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  181. package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +11 -5
  182. package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  183. package/templates/checkout-agent/packages/agent-core/src/bundle.ts +2 -0
  184. package/templates/checkout-agent/packages/agent-core/src/channels.ts +18 -8
  185. package/templates/checkout-agent/packages/agent-core/src/check.ts +25 -3
  186. package/templates/checkout-agent/packages/agent-core/src/engine.ts +90 -9
  187. package/templates/checkout-agent/packages/agent-core/src/escalate.ts +10 -0
  188. package/templates/checkout-agent/packages/agent-core/src/index.ts +3 -0
  189. package/templates/checkout-agent/packages/agent-core/src/language.ts +52 -0
  190. package/templates/checkout-agent/packages/agent-core/src/locale.ts +88 -0
  191. package/templates/checkout-agent/packages/agent-core/src/manifest.ts +4 -1
  192. package/templates/checkout-agent/packages/agent-core/src/rail.ts +29 -1
  193. package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  194. package/templates/checkout-agent/packages/agent-core/src/secrets.ts +53 -8
  195. package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +14 -0
  196. package/templates/checkout-agent/packages/agent-core/src/strings.ts +175 -0
  197. package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  198. package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  199. package/templates/checkout-agent/packages/agent-core/src/types.ts +15 -2
  200. package/templates/checkout-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  201. package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  202. package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +23 -0
  203. package/templates/checkout-agent/packages/agent-core/test/helpers.ts +1 -1
  204. package/templates/checkout-agent/packages/agent-core/test/language.test.ts +40 -0
  205. package/templates/checkout-agent/packages/agent-core/test/locale.test.ts +137 -0
  206. package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  207. package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +2 -2
  208. package/templates/checkout-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  209. package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  210. package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +49 -0
  211. package/templates/checkout-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  212. package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +40 -1
  213. package/templates/checkout-agent/packages/agent-runtime/README.md +31 -4
  214. package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  215. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  216. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  217. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  218. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  219. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  220. package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  221. package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +30 -4
  222. package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  223. package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  224. package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  225. package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  226. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  227. package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  228. package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  229. package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  230. package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  231. package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  232. package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  233. package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  234. package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  235. package/templates/checkout-agent/packages/agent-runtime/src/env.ts +64 -0
  236. package/templates/checkout-agent/packages/agent-runtime/src/index.ts +2 -0
  237. package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +81 -10
  238. package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +34 -12
  239. package/templates/checkout-agent/packages/agent-runtime/src/outcome.ts +118 -0
  240. package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +7 -7
  241. package/templates/checkout-agent/packages/agent-runtime/src/runs.ts +51 -0
  242. package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  243. package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +75 -5
  244. package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +71 -33
  245. package/templates/checkout-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  246. package/templates/checkout-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  247. package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  248. package/templates/checkout-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  249. package/templates/checkout-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  250. package/templates/checkout-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  251. package/templates/checkout-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  252. package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  253. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  254. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  255. package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  256. package/templates/collections-agent/README.md +2 -2
  257. package/templates/collections-agent/agents/collections-agent/.env.example +6 -3
  258. package/templates/collections-agent/agents/collections-agent/README.md +14 -9
  259. package/templates/collections-agent/agents/collections-agent/SYSTEM_PROMPT.md +16 -5
  260. package/templates/collections-agent/agents/collections-agent/agent.yaml +4 -3
  261. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +21 -4
  262. package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +49 -5
  263. package/templates/collections-agent/agents/collections-agent/mandate.example.json +1 -1
  264. package/templates/collections-agent/agents/collections-agent/runbook.md +3 -3
  265. package/templates/collections-agent/agents/collections-agent/src/agreements.ts +1 -1
  266. package/templates/collections-agent/agents/collections-agent/src/envelope.ts +15 -13
  267. package/templates/collections-agent/agents/collections-agent/src/kit.ts +38 -35
  268. package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +16 -8
  269. package/templates/collections-agent/agents/collections-agent/src/strings.ts +91 -0
  270. package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +2 -2
  271. package/templates/collections-agent/agents/collections-agent/test/check.test.ts +4 -1
  272. package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +1 -1
  273. package/templates/collections-agent/agents/collections-agent/test/envelope.test.ts +2 -2
  274. package/templates/collections-agent/agents/collections-agent/test/fixtures/accept-1103.transcript.jsonl +1 -1
  275. package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +1 -1
  276. package/templates/collections-agent/agents/collections-agent/test/payable-instrument.test.ts +56 -0
  277. package/templates/collections-agent/agents/collections-agent/test/rerun-clock.test.ts +54 -0
  278. package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +69 -2
  279. package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +16 -3
  280. package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +16 -4
  281. package/templates/collections-agent/agents/collections-agent/tools.json +2 -2
  282. package/templates/collections-agent/packages/agent-core/README.md +21 -2
  283. package/templates/collections-agent/packages/agent-core/package.json +1 -1
  284. package/templates/collections-agent/packages/agent-core/src/agent.ts +33 -6
  285. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  286. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +11 -5
  287. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  288. package/templates/collections-agent/packages/agent-core/src/bundle.ts +2 -0
  289. package/templates/collections-agent/packages/agent-core/src/channels.ts +18 -8
  290. package/templates/collections-agent/packages/agent-core/src/check.ts +25 -3
  291. package/templates/collections-agent/packages/agent-core/src/engine.ts +90 -9
  292. package/templates/collections-agent/packages/agent-core/src/escalate.ts +10 -0
  293. package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
  294. package/templates/collections-agent/packages/agent-core/src/language.ts +52 -0
  295. package/templates/collections-agent/packages/agent-core/src/locale.ts +88 -0
  296. package/templates/collections-agent/packages/agent-core/src/manifest.ts +4 -1
  297. package/templates/collections-agent/packages/agent-core/src/rail.ts +29 -1
  298. package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  299. package/templates/collections-agent/packages/agent-core/src/secrets.ts +53 -8
  300. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +14 -0
  301. package/templates/collections-agent/packages/agent-core/src/strings.ts +175 -0
  302. package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  303. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  304. package/templates/collections-agent/packages/agent-core/src/types.ts +15 -2
  305. package/templates/collections-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  306. package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  307. package/templates/collections-agent/packages/agent-core/test/engine.test.ts +23 -0
  308. package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
  309. package/templates/collections-agent/packages/agent-core/test/language.test.ts +40 -0
  310. package/templates/collections-agent/packages/agent-core/test/locale.test.ts +137 -0
  311. package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  312. package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
  313. package/templates/collections-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  314. package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  315. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +49 -0
  316. package/templates/collections-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  317. package/templates/collections-agent/packages/agent-core/test/secrets.test.ts +40 -1
  318. package/templates/collections-agent/packages/agent-runtime/README.md +31 -4
  319. package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  320. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  321. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  322. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  323. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  324. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  325. package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  326. package/templates/collections-agent/packages/agent-runtime/src/cli.ts +30 -4
  327. package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  328. package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  329. package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  330. package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  331. package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  332. package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  333. package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  334. package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  335. package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  336. package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  337. package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  338. package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  339. package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  340. package/templates/collections-agent/packages/agent-runtime/src/env.ts +64 -0
  341. package/templates/collections-agent/packages/agent-runtime/src/index.ts +2 -0
  342. package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +81 -10
  343. package/templates/collections-agent/packages/agent-runtime/src/kit.ts +34 -12
  344. package/templates/collections-agent/packages/agent-runtime/src/outcome.ts +118 -0
  345. package/templates/collections-agent/packages/agent-runtime/src/poll.ts +7 -7
  346. package/templates/collections-agent/packages/agent-runtime/src/runs.ts +51 -0
  347. package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  348. package/templates/collections-agent/packages/agent-runtime/src/setup.ts +75 -5
  349. package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +71 -33
  350. package/templates/collections-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  351. package/templates/collections-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  352. package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  353. package/templates/collections-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  354. package/templates/collections-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  355. package/templates/collections-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  356. package/templates/collections-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  357. package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  358. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  359. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  360. package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  361. package/templates/hello-agent/README.md +2 -2
  362. package/templates/hello-agent/agents/hello-agent/README.md +6 -0
  363. package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +27 -13
  364. package/templates/hello-agent/agents/hello-agent/agent.yaml +2 -1
  365. package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  366. package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  367. package/templates/hello-agent/agents/hello-agent/mandate.example.json +1 -1
  368. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +1 -1
  369. package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +1 -1
  370. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +1 -1
  371. package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  372. package/templates/hello-agent/agents/hello-agent/src/bills.ts +9 -5
  373. package/templates/hello-agent/agents/hello-agent/src/kit.ts +4 -1
  374. package/templates/hello-agent/agents/hello-agent/tools.json +1 -1
  375. package/templates/hello-agent/packages/agent-core/README.md +21 -2
  376. package/templates/hello-agent/packages/agent-core/package.json +1 -1
  377. package/templates/hello-agent/packages/agent-core/src/agent.ts +33 -6
  378. package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  379. package/templates/hello-agent/packages/agent-core/src/api/rail.ts +11 -5
  380. package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  381. package/templates/hello-agent/packages/agent-core/src/bundle.ts +2 -0
  382. package/templates/hello-agent/packages/agent-core/src/channels.ts +18 -8
  383. package/templates/hello-agent/packages/agent-core/src/check.ts +25 -3
  384. package/templates/hello-agent/packages/agent-core/src/engine.ts +90 -9
  385. package/templates/hello-agent/packages/agent-core/src/escalate.ts +10 -0
  386. package/templates/hello-agent/packages/agent-core/src/index.ts +3 -0
  387. package/templates/hello-agent/packages/agent-core/src/language.ts +52 -0
  388. package/templates/hello-agent/packages/agent-core/src/locale.ts +88 -0
  389. package/templates/hello-agent/packages/agent-core/src/manifest.ts +4 -1
  390. package/templates/hello-agent/packages/agent-core/src/rail.ts +29 -1
  391. package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  392. package/templates/hello-agent/packages/agent-core/src/secrets.ts +53 -8
  393. package/templates/hello-agent/packages/agent-core/src/state-machine.ts +14 -0
  394. package/templates/hello-agent/packages/agent-core/src/strings.ts +175 -0
  395. package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  396. package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  397. package/templates/hello-agent/packages/agent-core/src/types.ts +15 -2
  398. package/templates/hello-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  399. package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  400. package/templates/hello-agent/packages/agent-core/test/engine.test.ts +23 -0
  401. package/templates/hello-agent/packages/agent-core/test/helpers.ts +1 -1
  402. package/templates/hello-agent/packages/agent-core/test/language.test.ts +40 -0
  403. package/templates/hello-agent/packages/agent-core/test/locale.test.ts +137 -0
  404. package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  405. package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +2 -2
  406. package/templates/hello-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  407. package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  408. package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +49 -0
  409. package/templates/hello-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  410. package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +40 -1
  411. package/templates/hello-agent/packages/agent-runtime/README.md +31 -4
  412. package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  413. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  414. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  415. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  416. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  417. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  418. package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  419. package/templates/hello-agent/packages/agent-runtime/src/cli.ts +30 -4
  420. package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  421. package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  422. package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  423. package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  424. package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  425. package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  426. package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  427. package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  428. package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  429. package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  430. package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  431. package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  432. package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  433. package/templates/hello-agent/packages/agent-runtime/src/env.ts +64 -0
  434. package/templates/hello-agent/packages/agent-runtime/src/index.ts +2 -0
  435. package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +81 -10
  436. package/templates/hello-agent/packages/agent-runtime/src/kit.ts +34 -12
  437. package/templates/hello-agent/packages/agent-runtime/src/outcome.ts +118 -0
  438. package/templates/hello-agent/packages/agent-runtime/src/poll.ts +7 -7
  439. package/templates/hello-agent/packages/agent-runtime/src/runs.ts +51 -0
  440. package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  441. package/templates/hello-agent/packages/agent-runtime/src/setup.ts +75 -5
  442. package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +71 -33
  443. package/templates/hello-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  444. package/templates/hello-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  445. package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  446. package/templates/hello-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  447. package/templates/hello-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  448. package/templates/hello-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  449. package/templates/hello-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  450. package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  451. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  452. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  453. package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
  454. package/templates/kits.lock.json +12 -12
  455. package/templates/supplier-payments-agent/README.md +2 -2
  456. package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +2 -2
  457. package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +12 -7
  458. package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +14 -3
  459. package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +2 -1
  460. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +1 -1
  461. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +1 -1
  462. package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +1 -1
  463. package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +3 -3
  464. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +1 -1
  465. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +1 -1
  466. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +5 -5
  467. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +1 -1
  468. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +5 -5
  469. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +1 -1
  470. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +1 -1
  471. package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +1 -1
  472. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +37 -26
  473. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +41 -14
  474. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +12 -3
  475. package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +8 -8
  476. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +75 -10
  477. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/locale.test.ts +101 -0
  478. package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/run-outcome.test.ts +127 -0
  479. package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +1 -1
  480. package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -2
  481. package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
  482. package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +33 -6
  483. package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +15 -1
  484. package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +11 -5
  485. package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +36 -0
  486. package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +2 -0
  487. package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +18 -8
  488. package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -3
  489. package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +90 -9
  490. package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +10 -0
  491. package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +3 -0
  492. package/templates/supplier-payments-agent/packages/agent-core/src/language.ts +52 -0
  493. package/templates/supplier-payments-agent/packages/agent-core/src/locale.ts +88 -0
  494. package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +4 -1
  495. package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +29 -1
  496. package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +30 -2
  497. package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +53 -8
  498. package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +14 -0
  499. package/templates/supplier-payments-agent/packages/agent-core/src/strings.ts +175 -0
  500. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +15 -2
  501. package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +7 -4
  502. package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +15 -2
  503. package/templates/supplier-payments-agent/packages/agent-core/test/actor-on-the-wire.test.ts +144 -0
  504. package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +2 -2
  505. package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +23 -0
  506. package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +1 -1
  507. package/templates/supplier-payments-agent/packages/agent-core/test/language.test.ts +40 -0
  508. package/templates/supplier-payments-agent/packages/agent-core/test/locale.test.ts +137 -0
  509. package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +2 -2
  510. package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +2 -2
  511. package/templates/supplier-payments-agent/packages/agent-core/test/rail-errors.test.ts +74 -0
  512. package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +32 -0
  513. package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +49 -0
  514. package/templates/supplier-payments-agent/packages/agent-core/test/recorded-turns.ts +29 -0
  515. package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +40 -1
  516. package/templates/supplier-payments-agent/packages/agent-runtime/README.md +31 -4
  517. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +4 -2
  518. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +11 -5
  519. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +43 -21
  520. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +3 -0
  521. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +8 -12
  522. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -4
  523. package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +12 -9
  524. package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +30 -4
  525. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +18 -2
  526. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +13 -4
  527. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +7 -2
  528. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +11 -13
  529. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +32 -24
  530. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +12 -5
  531. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +83 -10
  532. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +2 -1
  533. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +10 -5
  534. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +48 -17
  535. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +37 -12
  536. package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +11 -3
  537. package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +52 -22
  538. package/templates/supplier-payments-agent/packages/agent-runtime/src/env.ts +64 -0
  539. package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +2 -0
  540. package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +81 -10
  541. package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +34 -12
  542. package/templates/supplier-payments-agent/packages/agent-runtime/src/outcome.ts +118 -0
  543. package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +7 -7
  544. package/templates/supplier-payments-agent/packages/agent-runtime/src/runs.ts +51 -0
  545. package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +55 -8
  546. package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +75 -5
  547. package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +71 -33
  548. package/templates/supplier-payments-agent/packages/agent-runtime/test/env-names.test.ts +56 -0
  549. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect-mandate-status.test.ts +80 -0
  550. package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +63 -2
  551. package/templates/supplier-payments-agent/packages/agent-runtime/test/outcome.test.ts +72 -0
  552. package/templates/supplier-payments-agent/packages/agent-runtime/test/poll-payer.test.ts +64 -0
  553. package/templates/supplier-payments-agent/packages/agent-runtime/test/rerun-not-replayed.test.ts +46 -0
  554. package/templates/supplier-payments-agent/packages/agent-runtime/test/transition-line.test.ts +29 -0
  555. package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +99 -6
  556. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +8 -0
  557. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +77 -0
  558. package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +27 -1
@@ -18,12 +18,17 @@
18
18
  * party, payee unmasked; checked with no credential at all — or a copy from a
19
19
  * run's `runs/<run-id>/receipts/`, which masks the payee and carries none of
20
20
  * the links. A copy reaches check 2 only with `--from-api`: the tenant's
21
- * `CODESPAR_API_KEY` (the environment, or the `.env` of the agent the copy
22
- * sits in) reads the receipt from the API, in memory, and nothing unmasked is
21
+ * `CODESPAR_API_KEY`, against the deployment `CODESPAR_API_URL` names (each
22
+ * from the environment, or else from the `.env` of the agent the copy sits
23
+ * in), reads the receipt from the API, in memory, and nothing unmasked is
23
24
  * written anywhere. Without it a copy answers `signature_only`, which is the
24
25
  * truth about what a masked copy can prove. The approval artifact of a copy
25
26
  * is the one its `approval_id` names in the run's own `approval.json`.
26
27
  *
28
+ * Of the read, the output carries only `sealed_payment` (`sandbox`,
29
+ * `money_moved`) off a body that bound. The tenant's read still carries
30
+ * `mandate.sig`, a spend credential, and it is never printed.
31
+ *
27
32
  * It is the one command here that does NOT need an agent — `cli.ts`
28
33
  * dispatches it before it looks for an `agent.yaml` — because the file it
29
34
  * reads has usually been copied off the machine that produced it.
@@ -40,6 +45,7 @@ import { stderr, stdout } from "node:process";
40
45
  import {
41
46
  DEFAULT_BASE_URL,
42
47
  DEFAULT_RECEIPT_KEYS_URL,
48
+ NotATestKeyError,
43
49
  VERDICT_EXIT_CODES,
44
50
  copyDisagreesWithRead,
45
51
  createCodeSparClient,
@@ -55,7 +61,8 @@ import {
55
61
  type ReceiptVerification,
56
62
  } from "@codespar/agent-core";
57
63
  import { findAgentDir } from "../agent.js";
58
- import { readDotEnv } from "../setup.js";
64
+ import { readAgentEnv } from "../env.js";
65
+ import { envFileOf } from "../setup.js";
59
66
 
60
67
  const USAGE =
61
68
  "usage: npm run verify <receipt-file> [--json] [--keys <key-set.json> | --url <https://.../.well-known/codespar-receipt-keys.json>] [--approval <approval.json> [--approval-id <apr_...>]] [--from-api]";
@@ -109,7 +116,7 @@ export async function verify(argv: string[]): Promise<number> {
109
116
  say(`the key set is public and needs no credential; its default is ${DEFAULT_RECEIPT_KEYS_URL}`);
110
117
  say("--keys reads a saved copy of that document instead, so the check runs with no network at all");
111
118
  say("the receipt file is the API's read (GET /v1/consumers/receipts/{id}), whose body is recomputed against the signed chain, or a run's copy, which proves the signature only");
112
- say("--from-api reads a run's copy from the API with CODESPAR_API_KEY (in memory, nothing written), so its body and its approval are checked too; the key set then defaults to that deployment's");
119
+ say("--from-api reads a run's copy from the API with CODESPAR_API_KEY (in memory, nothing written), so its body and its approval are checked too; the key set then defaults to that deployment's. CODESPAR_API_KEY and CODESPAR_API_URL come from the environment, or else from the .env of the agent the copy sits in; the CodeSpar CLI's name CODESPAR_BASE_URL is read too, and the two must agree");
113
120
  say("--approval holds a v4 receipt's sealed approval link against an approval artifact (a run's copy uses its own approval.json)");
114
121
  return 0;
115
122
  } else if (a.startsWith("-")) {
@@ -139,6 +146,20 @@ export async function verify(argv: string[]): Promise<number> {
139
146
  const receipt = readJson(args.receiptFile, say);
140
147
  if (receipt === undefined) return 2;
141
148
 
149
+ // Before the deployment is chosen, not only before the key is read: a
150
+ // staging key in that `.env` sits next to the staging URL, and a read sent
151
+ // to production with it is a 401 (#66). Only `--from-api` touches it; the
152
+ // other paths are the verifier who holds nothing.
153
+ const agentDir = args.fromApi ? findAgentDir(dirname(resolve(args.receiptFile))) : undefined;
154
+ // `--from-api` is also the one path that reads the deployment and the project, so it is the one that reconciles the CLI's names for them; a check against `--keys` or the default key set holds no opinion on either. Two names that disagree are a usage error (2), never 1: 1 means the receipt does not verify.
155
+ if (args.fromApi) {
156
+ const disagreement = readAgentEnv(agentDir);
157
+ if (disagreement) {
158
+ say(`${disagreement.message}\n${USAGE}`);
159
+ return 2;
160
+ }
161
+ }
162
+
142
163
  // The read and the key set must come from ONE deployment: the recipe that
143
164
  // binds the body is the key document's, and a staging read checked under
144
165
  // production's document is the §47 trap again.
@@ -161,14 +182,14 @@ export async function verify(argv: string[]): Promise<number> {
161
182
  if (keysDocument === undefined) return 2;
162
183
  }
163
184
 
164
- const report = await check(receipt, args, apiBase, approval, keysDocument);
185
+ const report = await check(receipt, args, apiBase, agentDir, approval, keysDocument);
165
186
  if (args.json) stdout.write(JSON.stringify(report) + "\n");
166
187
  else stdout.write(render(report));
167
188
  say(report.message);
168
189
  return VERDICT_EXIT_CODES[report.verdict];
169
190
  }
170
191
 
171
- async function check(receipt: unknown, args: Args, apiBase: string, approval: ApprovalClaim | undefined, keysDocument: unknown): Promise<ReceiptVerification> {
192
+ async function check(receipt: unknown, args: Args, apiBase: string, agentDir: string | undefined, approval: ApprovalClaim | undefined, keysDocument: unknown): Promise<ReceiptVerification> {
172
193
  // Answered before the network is touched, as before: an unsigned or
173
194
  // malformed file needs no key set, and fetching one to check a signature
174
195
  // that is not there would turn an offline answer into an outage.
@@ -202,7 +223,7 @@ async function check(receipt: unknown, args: Args, apiBase: string, approval: Ap
202
223
  return signatureOnly(signature, "read_required", "this is a run's copy, which masks the payee and carries none of the chain's links. Recompute from the API's read: run this again with --from-api (the tenant's key, read-only, nothing written), or verify the read itself");
203
224
  }
204
225
 
205
- const read = await readFromApi(signed.fields.receipt_id, args.receiptFile!, apiBase);
226
+ const read = await readFromApi(signed.fields.receipt_id, apiBase, agentDir);
206
227
  if (!read.ok) return signatureOnly(signature, "read_unavailable", `the API's read of it could not be fetched (${read.detail}), so nothing is proved and nothing is disproved about the body`);
207
228
  const differs = copyDisagreesWithRead(receipt as Record<string, unknown>, read.body);
208
229
  if (differs.includes("chain")) {
@@ -229,18 +250,18 @@ function unreachable(receiptId: string, label: string, message: string): Receipt
229
250
  /**
230
251
  * The receipt as the API reads it, for a copy, with the tenant's key. The key
231
252
  * is the environment's, or the `.env` of the agent the copy sits in — the
232
- * same place `npm start` reads it from — and only a `csk_test_` key is
233
- * accepted, like everywhere else in this repository.
253
+ * same place `npm start` reads it from, loaded by `verify` before it chose
254
+ * `apiBase` — and only a `csk_test_` key is accepted, like everywhere else in
255
+ * this repository.
234
256
  */
235
- async function readFromApi(receiptId: string, receiptFile: string, apiBase: string): Promise<{ ok: true; body: Record<string, unknown> } | { ok: false; detail: string }> {
236
- const agentDir = findAgentDir(dirname(resolve(receiptFile)));
237
- if (agentDir) readDotEnv(agentDir);
257
+ async function readFromApi(receiptId: string, apiBase: string, agentDir: string | undefined): Promise<{ ok: true; body: Record<string, unknown> } | { ok: false; detail: string }> {
238
258
  try {
239
259
  const api = createCodeSparClient({ apiKey: process.env["CODESPAR_API_KEY"], baseUrl: apiBase, projectId: process.env["CODESPAR_PROJECT_ID"], timeoutMs: 15_000 });
240
260
  const body: unknown = await api.get("/v1/consumers/receipts/{id}", { path: { id: receiptId } });
241
261
  if (!isReceiptRead(body)) return { ok: false, detail: "the API answered something that is not a receipt read" };
242
262
  return { ok: true, body };
243
263
  } catch (err) {
264
+ if (err instanceof NotATestKeyError) return { ok: false, detail: new NotATestKeyError(err.problem, agentDir ? envFileOf(agentDir) : undefined).message };
244
265
  const failure = describeApiError(err);
245
266
  return { ok: false, detail: `${failure.code}: ${failure.message}` };
246
267
  }
@@ -325,6 +346,10 @@ function render(report: ReceiptVerification): string {
325
346
  lines.push(` approval ${a.status}: sealed ${a.sealed.items_hash}${a.sealed.batch_hash ? ` batch ${a.sealed.batch_hash}` : ""}`);
326
347
  if (a.artifact) lines.push(` artifact ${a.artifact.approval_id} ${a.artifact.items_hash}${a.artifact.batch_hash ? ` batch ${a.artifact.batch_hash}` : ""}`);
327
348
  }
349
+ if (report.sealed_payment) {
350
+ const shown = (v: boolean | null) => (v === null ? "not sealed" : String(v));
351
+ lines.push(` payment sandbox ${shown(report.sealed_payment.sandbox)}, money_moved ${shown(report.sealed_payment.money_moved)}`);
352
+ }
328
353
  lines.push(` reason ${report.reason}`);
329
354
  return lines.join("\n") + "\n";
330
355
  }
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { stderr, stdout } from "node:process";
9
9
  import { envName, type Agent } from "../agent.js";
10
- import { setup } from "../setup.js";
10
+ import { inLocaleOf, localeFlag, setup } from "../setup.js";
11
11
  import { announceOutcome, followUp } from "../terminal.js";
12
12
  import { startWebhookServer } from "../webhook.js";
13
13
 
@@ -15,14 +15,22 @@ export async function webhook(agent: Agent, argv: string[]): Promise<number> {
15
15
  const port = Number(argv.includes("--port") ? argv[argv.indexOf("--port") + 1] : process.env[envName(agent, "WEBHOOK_PORT")] ?? "8787");
16
16
  const secret = argv.includes("--secret") ? argv[argv.indexOf("--secret") + 1] : process.env[envName(agent, "TRIGGER_SECRET")];
17
17
  const say = (l: string) => stderr.write(l + "\n");
18
- const s = setup(agent, { say, runId: `run_webhook_${Date.now().toString(36)}` });
18
+ let locale;
19
+ try {
20
+ locale = localeFlag(argv);
21
+ } catch (err) {
22
+ say(err instanceof Error ? err.message : String(err));
23
+ return 2;
24
+ }
25
+ const s = setup(agent, { say, runId: `run_webhook_${Date.now().toString(36)}`, locale });
19
26
  const server = startWebhookServer(
20
27
  port,
21
28
  {
22
29
  engine: s.engine,
23
30
  secret,
24
31
  onClosed: async (execution) => {
25
- announceOutcome(execution, s, (l) => void stdout.write(l + "\n"));
32
+ // Told in the locale of the run that issued the charge, whatever this receiver's own is.
33
+ announceOutcome(execution, inLocaleOf(s, execution), (l) => void stdout.write(l + "\n"));
26
34
  await followUp(execution, s, say);
27
35
  },
28
36
  },
@@ -3,9 +3,32 @@
3
3
  * example mandate, the generic console words, and no tools. A read-only agent
4
4
  * spreads this and adds its handlers; a payer or a collector replaces the rail.
5
5
  */
6
- import { StubRail, loadMandate, type Execution } from "@codespar/agent-core";
6
+ import { StubRail, formatBRL, isReplayedSettlement, loadMandate, railErrorOf, type Execution, type LocaleTable } from "@codespar/agent-core";
7
7
  import { relative } from "node:path";
8
- import type { AgentKit } from "./kit.js";
8
+ import type { AgentKit, KitStrings } from "./kit.js";
9
+ import type { Setup } from "./setup.js";
10
+
11
+ /**
12
+ * The lines a payment execution reads as on the console, in the run's locale:
13
+ * the default kit's, and the bills and supplier agents', which pay the same
14
+ * way and describe it the same way.
15
+ */
16
+ export function describePayment(execution: Execution, setup: Setup): string[] {
17
+ const text = setup.coreStrings;
18
+ const words = setup.strings;
19
+ const lines: string[] = [];
20
+ lines.push(` ${text.execution} ${execution.id}: ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}`);
21
+ for (const item of execution.items) lines.push(` - ${item.beneficiary}: ${formatBRL(item.amount, setup.locale)}${item.description ? ` — ${item.description}` : ""}`);
22
+ lines.push(` ${text.totalByCore}: ${formatBRL(execution.total, setup.locale)}`);
23
+ if (execution.escalation) lines.push(` ${text.escalatedBy}: ${execution.escalation.trigger} — ${execution.escalation.detail}`);
24
+ if (execution.blocking_reasons.length) lines.push(` ${text.blocked(execution.blocking_reasons.join(", "), words.notAuthorized)}`);
25
+ if (execution.detail && execution.state !== "awaiting_approval") lines.push(` ${execution.detail}`);
26
+ if (isReplayedSettlement(execution)) lines.push(` ${text.replayedSettlement}`);
27
+ for (const outcome of execution.outcomes) {
28
+ if (outcome.receipt_id) lines.push(` ${words.receiptWord}: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
29
+ }
30
+ return lines;
31
+ }
9
32
 
10
33
  export function formatMinor(minor: number): string {
11
34
  const sign = minor < 0 ? "-" : "";
@@ -13,28 +36,45 @@ export function formatMinor(minor: number): string {
13
36
  return `${sign}R$ ${Math.floor(abs / 100).toLocaleString("pt-BR")},${String(abs % 100).padStart(2, "0")}`;
14
37
  }
15
38
 
39
+ export const DEFAULT_STRINGS: LocaleTable<KitStrings> = {
40
+ "pt-BR": {
41
+ mandateWord: "mandato",
42
+ receiptWord: "recibo",
43
+ intro: 'Diga o que precisa. Ctrl+D ou "sair" encerra.',
44
+ prompt: "> ",
45
+ approveQuestion: " Aprovar? [s/N] ",
46
+ uncertainDispatch: " desfecho desconhecido no trilho; rode `npm run resume` para reconciliar (nunca repita a operação)",
47
+ notAuthorized: "o mandato não autoriza",
48
+ },
49
+ en: {
50
+ mandateWord: "mandate",
51
+ receiptWord: "receipt",
52
+ intro: 'Say what you need. Ctrl+D or "exit" ends.',
53
+ prompt: "> ",
54
+ approveQuestion: " Approve? [y/N] ",
55
+ uncertainDispatch: " outcome unknown on the rail; run `npm run resume` to reconcile (never repeat the operation)",
56
+ notAuthorized: "the mandate does not authorize it",
57
+ },
58
+ };
59
+
16
60
  export const defaultKit: AgentKit = {
17
61
  settlement: "immediate",
18
62
  scenarioRail: "stub",
19
63
  labels: {
20
64
  defaultUser: "usr_terminal",
21
65
  evalUser: "usr_demo_titular",
22
- mandateWord: "mandato",
23
- receiptWord: "recibo",
24
- intro: 'Diga o que precisa. Ctrl+D ou "sair" encerra.',
25
- prompt: "> ",
26
- approveQuestion: " Aprovar? [s/N] ",
27
- uncertainDispatch: " desfecho desconhecido no trilho; rode `npm run resume` para reconciliar (nunca repita a operacao)",
28
66
  missingReceiptKind: "receipt_missing_locally",
29
67
  missingReceiptDetail: (receiptId, runId) => `receipt ${receiptId} is not in runs/${runId}/receipts`,
30
68
  stillExecuting: (e) => `${e.id}: still executing — ${e.detail}; nothing was re-sent`,
31
69
  },
70
+ strings: DEFAULT_STRINGS,
32
71
  usage: (manifest) => `${manifest.manifest.name}
33
72
  npm start interactive terminal
34
73
  npm start -- --input "..." one turn (add --approve/--deny to decide, --json for machine output)
35
74
  npm start -- --scenario <name> run a scenario pack (see scenarios/)
36
75
  options: --mode human|mandate --provider anthropic|replay --transcript <file> --rail stub|api --user <id> --json
37
- --now <ISO 8601> pin the run to that instant; env CODESPAR_AGENT_NOW is the same thing`,
76
+ --now <ISO 8601> pin the run to that instant; env CODESPAR_AGENT_NOW is the same thing
77
+ --locale pt-BR|en the language of what the code prints; default: agent.yaml \`locale\`, else pt-BR`,
38
78
  buildRail: (ctx) => {
39
79
  // A read-only agent has no rail to reach: the stub answers offline, whatever key the environment carries.
40
80
  const killAfterDispatch = ctx.envVar("KILL_AFTER_DISPATCH") === "1" ? { afterDispatch: () => process.exit(137) } : {};
@@ -45,19 +85,7 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
45
85
  };
46
86
  },
47
87
  handlers: () => ({}),
48
- describeExecution: (execution, setup) => {
49
- const lines: string[] = [];
50
- lines.push(` execucao ${execution.id}: ${execution.state}${execution.reason ? ` (${execution.reason})` : ""}`);
51
- for (const item of execution.items) lines.push(` - ${item.beneficiary}: ${formatMinor(item.amount)}${item.description ? ` — ${item.description}` : ""}`);
52
- lines.push(` total (calculado pelo core): ${formatMinor(execution.total)}`);
53
- if (execution.escalation) lines.push(` escalado por: ${execution.escalation.trigger} — ${execution.escalation.detail}`);
54
- if (execution.blocking_reasons.length) lines.push(` bloqueado: ${execution.blocking_reasons.join(", ")} — o mandato nao autoriza; nao ha o que aprovar`);
55
- if (execution.detail && execution.state !== "awaiting_approval") lines.push(` ${execution.detail}`);
56
- for (const outcome of execution.outcomes) {
57
- if (outcome.receipt_id) lines.push(` recibo: ${relative(process.cwd(), `${setup.bundle.dir}/receipts/${outcome.receipt_id}.json`)}`);
58
- }
59
- return lines;
60
- },
88
+ describeExecution: (execution, setup) => describePayment(execution, setup),
61
89
  oneShotPayload: ({ setup: s, reply, toolCalls, executions }) => ({
62
90
  run_id: s.runId,
63
91
  agent: `${s.manifest.manifest.name}@${s.manifest.manifest.version}`,
@@ -71,11 +99,13 @@ options: --mode human|mandate --provider anthropic|replay --transcript <file>
71
99
  id: e.id,
72
100
  state: e.state,
73
101
  reason: e.reason ?? null,
102
+ rail_error: railErrorOf(e),
74
103
  escalation: e.escalation ?? null,
75
104
  total_minor: e.total,
76
105
  items: e.items.map((i) => ({ beneficiary: i.beneficiary, amount_minor: i.amount })),
77
106
  approval_id: e.approval_id ?? null,
78
107
  receipt_ids: e.outcomes.filter((o) => o.receipt_id).map((o) => o.receipt_id),
108
+ replayed: isReplayedSettlement(e),
79
109
  })),
80
110
  receipts: s.bundle.listReceipts().map((f) => relative(process.cwd(), `${s.bundle.dir}/receipts/${f}`)),
81
111
  bundle_dir: relative(process.cwd(), s.bundle.dir),
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Two names for the same two settings. The kit reads `CODESPAR_API_URL` and
3
+ * `CODESPAR_PROJECT_ID`; the CodeSpar CLI (`@codespar/cli`) reads
4
+ * `CODESPAR_BASE_URL` and `CODESPAR_PROJECT`. A shell prepared for one of them
5
+ * left the other on its default, production, with nothing said: a staging key
6
+ * then meets the wrong deployment.
7
+ *
8
+ * The kit takes the CLI's names as aliases of its own, and a command that
9
+ * talks to the API refuses to start when the two disagree. Only the
10
+ * environment and the agent's `.env` are read: the CLI's own config file
11
+ * (`~/.codespar/config.json`, what `codespar login` writes) is not.
12
+ */
13
+ import { readDotEnv } from "./setup.js";
14
+
15
+ const PAIRS: ReadonlyArray<{ kit: string; cli: string; same: (a: string, b: string) => boolean }> = [
16
+ { kit: "CODESPAR_API_URL", cli: "CODESPAR_BASE_URL", same: (a, b) => a.replace(/\/+$/, "") === b.replace(/\/+$/, "") },
17
+ { kit: "CODESPAR_PROJECT_ID", cli: "CODESPAR_PROJECT", same: (a, b) => a === b },
18
+ ];
19
+
20
+ export class EnvNamesDisagreeError extends Error {
21
+ constructor(kit: string, kitValue: string, cli: string, cliValue: string) {
22
+ super(`${kit}=${kitValue} and ${cli}=${cliValue} disagree. The kit reads ${kit} and the CodeSpar CLI reads ${cli}; they must name the same thing. Set one of them, or both to the same value.`);
23
+ this.name = "EnvNamesDisagreeError";
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Makes the two names of each pair say one thing: whichever is set fills the
29
+ * other, and two that are set and differ throw. Both are left set, so a later
30
+ * reader of either name, and a later `.env`, finds the pair already decided.
31
+ * An empty value counts as unset, as it does in the CLI.
32
+ */
33
+ export function reconcileEnvNames(env: NodeJS.ProcessEnv = process.env): void {
34
+ for (const { kit, cli, same } of PAIRS) {
35
+ const kitValue = env[kit]?.trim() || undefined;
36
+ const cliValue = env[cli]?.trim() || undefined;
37
+ if (kitValue && cliValue && !same(kitValue, cliValue)) throw new EnvNamesDisagreeError(kit, kitValue, cli, cliValue);
38
+ const value = kitValue ?? cliValue;
39
+ if (value !== undefined) env[kit] = env[cli] = value;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * The agent's `.env` under the rule `readDotEnv` already has, extended to the
45
+ * aliases: what the shell exported wins, and the file fills only what is
46
+ * unset. The shell is reconciled first, so a name it set under either spelling
47
+ * closes the pair before the file is read; then the file's own names are.
48
+ *
49
+ * It returns the disagreement instead of throwing it: only a command that is
50
+ * about to use the URL or the project should stop on it.
51
+ */
52
+ export function readAgentEnv(agentDir: string | undefined): EnvNamesDisagreeError | undefined {
53
+ try {
54
+ reconcileEnvNames();
55
+ if (agentDir) readDotEnv(agentDir);
56
+ reconcileEnvNames();
57
+ return undefined;
58
+ } catch (err) {
59
+ if (!(err instanceof EnvNamesDisagreeError)) throw err;
60
+ // The shell disagreed with itself before the file was read: the file is still owed, for the key it may hold.
61
+ if (agentDir) readDotEnv(agentDir);
62
+ return err;
63
+ }
64
+ }
@@ -2,6 +2,7 @@ export * from "./agent.js";
2
2
  export * from "./kit.js";
3
3
  export * from "./default-kit.js";
4
4
  export * from "./setup.js";
5
+ export * from "./runs.js";
5
6
  export * from "./terminal.js";
6
7
  export * from "./channels/index.js";
7
8
  export * from "./poll.js";
@@ -10,4 +11,5 @@ export * from "./scenarios.js";
10
11
  export * from "./adversarial.js";
11
12
  export * from "./inspect.js";
12
13
  export { main } from "./cli.js";
14
+ export { checkStrings } from "./commands/check.js";
13
15
  export { pollWhatsApp, type PollWhatsAppOptions } from "./commands/poll-whatsapp.js";
@@ -57,6 +57,8 @@ export interface InspectAttempt {
57
57
  receipt_id: string | null;
58
58
  money_moved: boolean | null;
59
59
  sandbox: boolean | null;
60
+ /** The rail answered from its record of an earlier presentation: the payment it names was not made by this call. */
61
+ idempotent_replay: boolean;
60
62
  } | null;
61
63
  /** The attempt's outcome as last known, from the call, a later look or a settlement event. */
62
64
  status: string | null;
@@ -71,6 +73,13 @@ export interface InspectAttempt {
71
73
  export interface InspectExecution {
72
74
  execution_id: string;
73
75
  final_state: string;
76
+ /**
77
+ * Settled, and every attempt that settled was answered at dispatch as a
78
+ * replay: the money moved, and this run did not move it. An attempt closed
79
+ * by a later look is never counted as one, because a look re-presents an
80
+ * attempt this run already sent and cannot say whose payment it reads.
81
+ */
82
+ replayed: boolean;
74
83
  mode: string | null;
75
84
  proposed_at: string | null;
76
85
  items: InspectItem[];
@@ -108,6 +117,8 @@ export interface InspectReceipt {
108
117
  money_moved: boolean | null;
109
118
  sandbox: boolean | null;
110
119
  at: string | null;
120
+ /** Every attempt naming this receipt got it back as a replay: the receipt of an earlier payment, read back by this run. */
121
+ replayed: boolean;
111
122
  }
112
123
 
113
124
  /**
@@ -128,7 +139,7 @@ export interface InspectBatch {
128
139
  /** Lines the list held when it was presented. */
129
140
  count: number;
130
141
  /** The lines this bundle holds an execution for, by their position in the list. */
131
- lines: Array<{ index: number; execution_id: string; final_state: string; attested: boolean }>;
142
+ lines: Array<{ index: number; execution_id: string; final_state: string; replayed: boolean; attested: boolean }>;
132
143
  /** How many of the lines carry an approval artifact. The "3" of "3 of 4". */
133
144
  attested: number;
134
145
  /** Positions of the presented list this bundle holds no execution for at all. */
@@ -149,7 +160,10 @@ export interface InspectReport {
149
160
  mandate: {
150
161
  id: string;
151
162
  version: number;
163
+ /** The status in `mandate.snapshot.json`: what the local copy said when the run started. */
152
164
  status: string;
165
+ /** What the status source answered at a gate of this run, when that is the last word the run has on the mandate; null when no gate refused for it, or when a payment executed after the refusal. */
166
+ status_seen: MandateStatusSeen | null;
153
167
  expires_at: string;
154
168
  currency: string;
155
169
  per_tx_cap_minor: number;
@@ -309,6 +323,7 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
309
323
  const executions = new Map<string, InspectExecution>();
310
324
  const attemptsBy = new Map<string, Map<string, InspectAttempt>>();
311
325
  const runEvents: InspectReport["run_events"] = [];
326
+ let statusSeen: MandateStatusSeen | null = null;
312
327
 
313
328
  const executionOf = (id: string): InspectExecution => {
314
329
  const existing = executions.get(id);
@@ -316,6 +331,7 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
316
331
  const fresh: InspectExecution = {
317
332
  execution_id: id,
318
333
  final_state: "unknown",
334
+ replayed: false,
319
335
  mode: null,
320
336
  proposed_at: null,
321
337
  items: [],
@@ -340,6 +356,7 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
340
356
  const p = payload(event);
341
357
 
342
358
  if (!executionId) {
359
+ if (type === "execution.refused_before_draft") statusSeen = mandateStatusSeen(str(p["reason"]), str(p["detail"]), at) ?? statusSeen;
343
360
  const detail = str(p["detail"]) ?? str(p["reason"]) ?? str(event["reason"]) ?? str(event["tool"]) ?? str(event["message"]) ?? "";
344
361
  const tool = str(event["tool"]);
345
362
  runEvents.push({ at, type, detail: redact(tool ? `${tool}: ${detail || String(event["reason"] ?? "")}` : detail) ?? "" });
@@ -363,6 +380,8 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
363
380
  const to = str(p["to"]) ?? "unknown";
364
381
  execution.transitions.push({ at: str(p["at"]) ?? at, from: str(p["from"]), to, actor: actorLabel(p["actor"] ?? event["actor"]), reason: str(p["reason"]), detail: redact(str(p["detail"])) });
365
382
  execution.final_state = to;
383
+ // A gate that let a payment through read `active` after whatever an earlier gate saw (a mandate paused and resumed).
384
+ statusSeen = to === "executing" ? null : (mandateStatusSeen(str(p["reason"]), str(p["detail"]), str(p["at"]) ?? at) ?? statusSeen);
366
385
  break;
367
386
  }
368
387
  case "approval.created":
@@ -392,6 +411,7 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
392
411
  receipt_id: str(p["receipt_id"]),
393
412
  money_moved: bool(p["money_moved"]),
394
413
  sandbox: bool(p["sandbox"]),
414
+ idempotent_replay: p["idempotent_replay"] === true,
395
415
  };
396
416
  attempt.status = attempt.answer.status;
397
417
  attempt.transaction_id = attempt.answer.transaction_id ?? attempt.transaction_id;
@@ -465,6 +485,15 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
465
485
  }
466
486
 
467
487
  for (const [id, attempts] of attemptsBy) executionOf(id).attempts = [...attempts.values()];
488
+ for (const execution of executions.values()) {
489
+ const settled = execution.attempts.filter((a) => a.status === "settled");
490
+ execution.replayed = execution.final_state === "settled" && settled.length > 0 && settled.every((a) => a.answer?.idempotent_replay === true);
491
+ }
492
+ const replayedReceipts = new Set<string>();
493
+ const paidReceipts = new Set<string>();
494
+ for (const execution of executions.values()) {
495
+ for (const a of execution.attempts) if (a.receipt_id) (a.answer?.idempotent_replay ? replayedReceipts : paidReceipts).add(a.receipt_id);
496
+ }
468
497
 
469
498
  const receipts: InspectReceipt[] = bundle.listReceipts().map((file) => {
470
499
  const raw = bundle.readReceipt(file) ?? {};
@@ -478,8 +507,10 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
478
507
  money_moved: bool(payment["money_moved"]),
479
508
  sandbox: bool(payment["sandbox"]),
480
509
  at: str(payment["at"]),
510
+ replayed: false,
481
511
  };
482
512
  });
513
+ for (const receipt of receipts) receipt.replayed = replayedReceipts.has(receipt.receipt_id) && !paidReceipts.has(receipt.receipt_id);
483
514
 
484
515
  const transcript = bundle.readTranscript();
485
516
  const toolCalls = transcript.filter((l) => l.kind === "tool_call");
@@ -501,6 +532,7 @@ export function assembleTimeline(bundle: ProofBundle): InspectReport {
501
532
  id: str(snapshot["id"]) ?? "unknown",
502
533
  version: num(snapshot["version"]) ?? 0,
503
534
  status: str(snapshot["status"]) ?? "unknown",
535
+ status_seen: statusSeen,
504
536
  expires_at: str(snapshot["expires_at"]) ?? "unknown",
505
537
  currency,
506
538
  per_tx_cap_minor: num(snapshot["per_tx_cap_minor"]) ?? 0,
@@ -538,7 +570,7 @@ function assembleBatches(executions: InspectExecution[]): InspectBatch[] {
538
570
  if (!binding) continue;
539
571
  const key = `${binding.ref}\u0000${binding.batch_hash}`;
540
572
  const entry = batches.get(key) ?? { ref: binding.ref, batch_hash: binding.batch_hash, count: binding.count, lines: [], attested: 0, missing: [] };
541
- entry.lines.push({ index: binding.index, execution_id: execution.execution_id, final_state: execution.final_state, attested: execution.approval !== null });
573
+ entry.lines.push({ index: binding.index, execution_id: execution.execution_id, final_state: execution.final_state, replayed: execution.replayed, attested: execution.approval !== null });
542
574
  batches.set(key, entry);
543
575
  }
544
576
  for (const entry of batches.values()) {
@@ -597,7 +629,9 @@ function executionLines(execution: InspectExecution): Array<{ at: string; label:
597
629
  if (answer) {
598
630
  const bits = [answer.transaction_id ? `tx ${answer.transaction_id}` : "", answer.receipt_id ? `receipt ${answer.receipt_id}` : "", answer.money_moved !== null ? `money_moved ${answer.money_moved}` : "", answer.sandbox ? "sandbox" : ""].filter(Boolean);
599
631
  const why = [answer.code, answer.message].filter(Boolean).join(": ");
600
- lines.push({ at: answer.at, label: "rail says", text: `${answer.status}${why ? ` ${why}` : ""}`, wrapped: bits.length ? [bits.join(" · ")] : [] });
632
+ const wrapped = bits.length ? [bits.join(" · ")] : [];
633
+ if (answer.idempotent_replay) wrapped.push(REPLAY_NOTE);
634
+ lines.push({ at: answer.at, label: "rail says", text: `${answer.status}${answer.idempotent_replay ? " (replayed)" : ""}${why ? ` ${why}` : ""}`, wrapped });
601
635
  }
602
636
  for (const i of a.instrument) lines.push({ at: i.at, label: "instrument", text: `${a.attempt_id} ${i.status}${i.payable ? ", payable" : ", not payable yet"}${i.due_date ? `, due ${i.due_date}` : ""}`, wrapped: [] });
603
637
  for (const r of a.reconciles) lines.push({ at: r.at, label: "look again", text: `${a.attempt_id} the rail says ${r.found}`, wrapped: [] });
@@ -616,6 +650,8 @@ function executionLines(execution: InspectExecution): Array<{ at: string; label:
616
650
  */
617
651
  export function batchSummary(batch: InspectBatch): string {
618
652
  const bits = [`${batch.attested} of ${batch.count} line(s) attested`];
653
+ const replayed = batch.lines.filter((l) => l.replayed).length;
654
+ if (replayed) bits.push(`${replayed} replayed, paid before and not by this run`);
619
655
  if (batch.lines.length !== batch.attested) bits.push(`${batch.lines.length} with an execution`);
620
656
  if (batch.missing.length) bits.push(`no execution for line(s) ${batch.missing.map((i) => i + 1).join(", ")}`);
621
657
  return bits.join(" · ");
@@ -628,14 +664,48 @@ export function batchLineRows(batch: InspectBatch): string[] {
628
664
  const line = byIndex.get(i);
629
665
  const where = `line ${i + 1} of ${batch.count}`;
630
666
  if (!line) return `${where} — no execution in this bundle: approved as part of this list, and nothing here says it ran`;
631
- return `${where} ${line.execution_id} ${line.final_state} ${line.attested ? "approval artifact present" : "no approval artifact"}`;
667
+ return `${where} ${line.execution_id} ${line.final_state}${line.replayed ? " (replayed)" : ""} ${line.attested ? "approval artifact present" : "no approval artifact"}`;
632
668
  });
633
669
  }
634
670
 
671
+ /** The mandate's status as a gate of the run saw it, and who answered. */
672
+ export interface MandateStatusSeen {
673
+ status: "revoked" | "paused" | "expired";
674
+ /** `api` or `stub`: the status source that answered. Null when the refusal names none: the run's own clock passed `expires_at`, or the bundle predates the source on the detail. */
675
+ source: "api" | "stub" | null;
676
+ at: string;
677
+ }
678
+
679
+ const SEEN_BY_REASON: Record<string, MandateStatusSeen["status"]> = { mandate_revoked: "revoked", mandate_paused: "paused", mandate_expired: "expired" };
680
+
681
+ /** A refusal the mandate gate recorded (`mandateGate` in the core): the reason is the status, and the detail ends with the source that answered. */
682
+ function mandateStatusSeen(reason: string | null, detail: string | null, at: string): MandateStatusSeen | undefined {
683
+ const status = reason ? SEEN_BY_REASON[reason] : undefined;
684
+ if (!status) return undefined;
685
+ const source = /\(source: (api|stub)\)/.exec(detail ?? "")?.[1] as "api" | "stub" | undefined;
686
+ return { status, source: source ?? null, at };
687
+ }
688
+
689
+ /**
690
+ * The header's word for the mandate. The snapshot is the local copy at the
691
+ * start of the run, and it goes on saying `active` under a mandate the API
692
+ * answered was revoked; where a gate of the run heard otherwise, the header
693
+ * says what it heard, from whom, and what the snapshot had said.
694
+ */
695
+ function mandateStatusLabel(m: NonNullable<InspectReport["mandate"]>): string {
696
+ const seen = m.status_seen;
697
+ if (!seen || seen.status === m.status) return m.status;
698
+ const by = seen.source ? `source: ${seen.source}` : seen.status === "expired" ? "by the run's clock" : "source not recorded";
699
+ return `${seen.status} (${by}, ${clock(seen.at)}; ${m.status} in the snapshot at the start of the run)`;
700
+ }
701
+
702
+ /** What a replayed answer means, in the one sentence both renderings print under it. */
703
+ export const REPLAY_NOTE = "idempotent_replay: the rail answered with an earlier payment of this attempt; this run moved no money for it";
704
+
635
705
  /** `execution exe_x — settled` gains ` · folha-2026-10 line 2 of 3` when it is one line of a batch. */
636
706
  function executionHeading(execution: InspectExecution): string {
637
707
  const b = execution.batch;
638
- return `execution ${execution.execution_id} — ${execution.final_state}${b ? ` · ${b.ref} line ${b.index + 1} of ${b.count}` : ""}`;
708
+ return `execution ${execution.execution_id} — ${execution.final_state}${execution.replayed ? " (replayed, not paid by this run)" : ""}${b ? ` · ${b.ref} line ${b.index + 1} of ${b.count}` : ""}`;
639
709
  }
640
710
 
641
711
  export function renderText(report: InspectReport): string {
@@ -646,7 +716,7 @@ export function renderText(report: InspectReport): string {
646
716
  const m = report.mandate;
647
717
  if (m) {
648
718
  const caps = [`per payment ${formatMinor(m.per_tx_cap_minor)}`, m.periodic_cap ? `per ${m.periodic_cap.window} ${formatMinor(m.periodic_cap.cap_minor)}` : "", `lifetime ${formatMinor(m.cap_minor)}`].filter(Boolean);
649
- out.push(` mandate ${m.status}, expires ${m.expires_at} · ${caps.join(" · ")}`);
719
+ out.push(` mandate ${mandateStatusLabel(m)}, expires ${m.expires_at} · ${caps.join(" · ")}`);
650
720
  if (m.beneficiaries.length) out.push(` named payees: ${m.beneficiaries.map((b) => `${b.name} <${b.payee}>`).join(", ")}`);
651
721
  }
652
722
 
@@ -675,7 +745,7 @@ export function renderText(report: InspectReport): string {
675
745
  out.push("");
676
746
  out.push(`receipts (${report.receipts.length})`);
677
747
  for (const receipt of report.receipts) {
678
- const bits = [receipt.state ?? "?", receipt.amount_minor !== null ? formatMinor(receipt.amount_minor) : "", receipt.payee ?? "", receipt.sandbox ? "sandbox" : "", receipt.money_moved === false ? "no money moved" : ""].filter(Boolean);
748
+ const bits = [receipt.state ?? "?", receipt.amount_minor !== null ? formatMinor(receipt.amount_minor) : "", receipt.payee ?? "", receipt.sandbox ? "sandbox" : "", receipt.money_moved === false ? "no money moved" : "", receipt.replayed ? "read back from a replay, not paid by this run" : ""].filter(Boolean);
679
749
  out.push(` ${receipt.receipt_id} ${bits.join(" ")}`);
680
750
  out.push(` ${receipt.file}`);
681
751
  }
@@ -708,7 +778,7 @@ export function renderHtml(report: InspectReport): string {
708
778
  `<h1>${esc(r.run_id)}</h1>`,
709
779
  `<p class="lede">${esc(r.agent ?? "unknown agent")} · mode <b>${esc(r.mode ?? "?")}</b> · rail <b>${esc(r.rail ?? "?")}</b> · mandate <b>${esc(r.mandate_id ?? "?")}</b>${r.mandate_version !== null ? ` v${r.mandate_version}` : ""}${r.started_at ? ` · started ${esc(r.started_at)}` : ""}</p>`,
710
780
  m
711
- ? `<p class="lede">mandate ${esc(m.status)}, expires ${esc(m.expires_at)} · per payment ${esc(formatMinor(m.per_tx_cap_minor))}${m.periodic_cap ? ` · per ${esc(m.periodic_cap.window)} ${esc(formatMinor(m.periodic_cap.cap_minor))}` : ""} · lifetime ${esc(formatMinor(m.cap_minor))}</p>`
781
+ ? `<p class="lede">mandate ${esc(mandateStatusLabel(m))}, expires ${esc(m.expires_at)} · per payment ${esc(formatMinor(m.per_tx_cap_minor))}${m.periodic_cap ? ` · per ${esc(m.periodic_cap.window)} ${esc(formatMinor(m.periodic_cap.cap_minor))}` : ""} · lifetime ${esc(formatMinor(m.cap_minor))}</p>`
712
782
  : "",
713
783
  m && m.beneficiaries.length ? `<p class="lede">named payees: ${m.beneficiaries.map((b) => `${esc(b.name)} <code>${esc(b.payee)}</code>`).join(", ")}</p>` : "",
714
784
  ].join("\n");
@@ -734,7 +804,8 @@ export function renderHtml(report: InspectReport): string {
734
804
  .join("\n");
735
805
  const b = execution.batch;
736
806
  const where = b ? `<span class="state">${esc(`${b.ref} line ${b.index + 1} of ${b.count}`)}</span>` : "";
737
- return `<section><h2>execution ${esc(execution.execution_id)} <span class="state state-${esc(execution.final_state)}">${esc(execution.final_state)}</span> ${where}</h2><table>${rows}</table></section>`;
807
+ const replayed = execution.replayed ? ` <span class="state">replayed, not paid by this run</span>` : "";
808
+ return `<section><h2>execution ${esc(execution.execution_id)} <span class="state state-${esc(execution.final_state)}">${esc(execution.final_state)}</span>${replayed} ${where}</h2><table>${rows}</table></section>`;
738
809
  })
739
810
  .join("\n");
740
811
 
@@ -745,7 +816,7 @@ export function renderHtml(report: InspectReport): string {
745
816
  const receipts = report.receipts.length
746
817
  ? `<table>${report.receipts
747
818
  .map((receipt) => {
748
- const bits = [receipt.state ?? "?", receipt.amount_minor !== null ? formatMinor(receipt.amount_minor) : "", receipt.payee ?? "", receipt.sandbox ? "sandbox" : "", receipt.money_moved === false ? "no money moved" : ""].filter(Boolean).join(" · ");
819
+ const bits = [receipt.state ?? "?", receipt.amount_minor !== null ? formatMinor(receipt.amount_minor) : "", receipt.payee ?? "", receipt.sandbox ? "sandbox" : "", receipt.money_moved === false ? "no money moved" : "", receipt.replayed ? "read back from a replay, not paid by this run" : ""].filter(Boolean).join(" · ");
749
820
  return `<tr><td class="k"><code>${esc(receipt.receipt_id)}</code></td><td>${esc(bits)}<div class="sub">${esc(receipt.file)}</div></td></tr>`;
750
821
  })
751
822
  .join("")}</table>`