@codespar/cli 0.13.0 → 0.14.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 (240) hide show
  1. package/README.md +51 -1
  2. package/dist/commands/agent.js +13 -7
  3. package/dist/commands/agent.js.map +1 -1
  4. package/dist/commands/init.js +91 -23
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/index.js +6 -3
  7. package/dist/index.js.map +1 -1
  8. package/package.json +3 -1
  9. package/templates/bills-agent/LICENSE +21 -0
  10. package/templates/bills-agent/README.md +21 -0
  11. package/templates/bills-agent/_gitignore +10 -0
  12. package/templates/bills-agent/agents/bills-agent/.env.example +7 -0
  13. package/templates/bills-agent/agents/bills-agent/AGENTS.md +16 -0
  14. package/templates/bills-agent/agents/bills-agent/CLAUDE.md +16 -0
  15. package/templates/bills-agent/agents/bills-agent/README.md +89 -0
  16. package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +23 -0
  17. package/templates/bills-agent/agents/bills-agent/agent.yaml +26 -0
  18. package/templates/bills-agent/agents/bills-agent/channels/terminal/index.ts +108 -0
  19. package/templates/bills-agent/agents/bills-agent/evals/adversarial/beneficiary-swap-mandate.json +9 -0
  20. package/templates/bills-agent/agents/bills-agent/evals/adversarial/beneficiary-swap.json +10 -0
  21. package/templates/bills-agent/agents/bills-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
  22. package/templates/bills-agent/agents/bills-agent/evals/adversarial/exfiltration.json +13 -0
  23. package/templates/bills-agent/agents/bills-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
  24. package/templates/bills-agent/agents/bills-agent/evals/adversarial/false-authority.json +9 -0
  25. package/templates/bills-agent/agents/bills-agent/evals/adversarial/false-authority.transcript.jsonl +3 -0
  26. package/templates/bills-agent/agents/bills-agent/evals/adversarial/fractioning.json +15 -0
  27. package/templates/bills-agent/agents/bills-agent/evals/adversarial/fractioning.transcript.jsonl +6 -0
  28. package/templates/bills-agent/agents/bills-agent/evals/adversarial/model-total.json +10 -0
  29. package/templates/bills-agent/agents/bills-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
  30. package/templates/bills-agent/agents/bills-agent/evals/adversarial/prompt-injection.json +9 -0
  31. package/templates/bills-agent/agents/bills-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
  32. package/templates/bills-agent/agents/bills-agent/evals/adversarial/webhook-replay.json +9 -0
  33. package/templates/bills-agent/agents/bills-agent/evals/eval.yaml +9 -0
  34. package/templates/bills-agent/agents/bills-agent/guardrails.json +15 -0
  35. package/templates/bills-agent/agents/bills-agent/mandate.example.json +46 -0
  36. package/templates/bills-agent/agents/bills-agent/package.json +24 -0
  37. package/templates/bills-agent/agents/bills-agent/runbook.md +19 -0
  38. package/templates/bills-agent/agents/bills-agent/scenarios/beneficiary-not-allowed.json +14 -0
  39. package/templates/bills-agent/agents/bills-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +2 -0
  40. package/templates/bills-agent/agents/bills-agent/scenarios/cap-exceeded.json +12 -0
  41. package/templates/bills-agent/agents/bills-agent/scenarios/cap-exceeded.transcript.jsonl +2 -0
  42. package/templates/bills-agent/agents/bills-agent/scenarios/escalated-above-threshold.json +20 -0
  43. package/templates/bills-agent/agents/bills-agent/scenarios/escalated-above-threshold.transcript.jsonl +7 -0
  44. package/templates/bills-agent/agents/bills-agent/scenarios/happy-path.json +14 -0
  45. package/templates/bills-agent/agents/bills-agent/scenarios/happy-path.transcript.jsonl +3 -0
  46. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.json +21 -0
  47. package/templates/bills-agent/agents/bills-agent/scenarios/mandate-revoked.transcript.jsonl +9 -0
  48. package/templates/bills-agent/agents/bills-agent/scenarios/prompt-injection.json +12 -0
  49. package/templates/bills-agent/agents/bills-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
  50. package/templates/bills-agent/agents/bills-agent/src/adversarial.ts +177 -0
  51. package/templates/bills-agent/agents/bills-agent/src/bills.ts +28 -0
  52. package/templates/bills-agent/agents/bills-agent/src/commands/approve.ts +9 -0
  53. package/templates/bills-agent/agents/bills-agent/src/commands/check.ts +13 -0
  54. package/templates/bills-agent/agents/bills-agent/src/commands/consent.ts +26 -0
  55. package/templates/bills-agent/agents/bills-agent/src/commands/decide.ts +45 -0
  56. package/templates/bills-agent/agents/bills-agent/src/commands/deny.ts +7 -0
  57. package/templates/bills-agent/agents/bills-agent/src/commands/eval.ts +37 -0
  58. package/templates/bills-agent/agents/bills-agent/src/commands/reconcile.ts +38 -0
  59. package/templates/bills-agent/agents/bills-agent/src/commands/rerun.ts +65 -0
  60. package/templates/bills-agent/agents/bills-agent/src/commands/resume.ts +30 -0
  61. package/templates/bills-agent/agents/bills-agent/src/main.ts +185 -0
  62. package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +125 -0
  63. package/templates/bills-agent/agents/bills-agent/src/modules/pix-out.ts +73 -0
  64. package/templates/bills-agent/agents/bills-agent/src/scenarios.ts +196 -0
  65. package/templates/bills-agent/agents/bills-agent/src/setup.ts +207 -0
  66. package/templates/bills-agent/agents/bills-agent/test/adversarial.test.ts +40 -0
  67. package/templates/bills-agent/agents/bills-agent/test/check.test.ts +85 -0
  68. package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +177 -0
  69. package/templates/bills-agent/agents/bills-agent/test/scenarios.test.ts +73 -0
  70. package/templates/bills-agent/agents/bills-agent/tools.json +51 -0
  71. package/templates/bills-agent/agents/bills-agent/tsconfig.json +11 -0
  72. package/templates/bills-agent/package.json +34 -0
  73. package/templates/bills-agent/packages/agent-core/README.md +19 -0
  74. package/templates/bills-agent/packages/agent-core/package.json +24 -0
  75. package/templates/bills-agent/packages/agent-core/src/agent.ts +125 -0
  76. package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +154 -0
  77. package/templates/bills-agent/packages/agent-core/src/api/client.ts +53 -0
  78. package/templates/bills-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
  79. package/templates/bills-agent/packages/agent-core/src/api/rail.ts +101 -0
  80. package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +45 -0
  81. package/templates/bills-agent/packages/agent-core/src/approval.ts +109 -0
  82. package/templates/bills-agent/packages/agent-core/src/bundle.ts +113 -0
  83. package/templates/bills-agent/packages/agent-core/src/check.ts +171 -0
  84. package/templates/bills-agent/packages/agent-core/src/engine.ts +784 -0
  85. package/templates/bills-agent/packages/agent-core/src/escalate.ts +85 -0
  86. package/templates/bills-agent/packages/agent-core/src/events.ts +40 -0
  87. package/templates/bills-agent/packages/agent-core/src/guardrails.ts +45 -0
  88. package/templates/bills-agent/packages/agent-core/src/hash.ts +49 -0
  89. package/templates/bills-agent/packages/agent-core/src/ids.ts +10 -0
  90. package/templates/bills-agent/packages/agent-core/src/index.ts +29 -0
  91. package/templates/bills-agent/packages/agent-core/src/mandate.ts +100 -0
  92. package/templates/bills-agent/packages/agent-core/src/manifest.ts +76 -0
  93. package/templates/bills-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
  94. package/templates/bills-agent/packages/agent-core/src/providers/replay.ts +63 -0
  95. package/templates/bills-agent/packages/agent-core/src/providers/types.ts +39 -0
  96. package/templates/bills-agent/packages/agent-core/src/rail.ts +87 -0
  97. package/templates/bills-agent/packages/agent-core/src/revocation.ts +30 -0
  98. package/templates/bills-agent/packages/agent-core/src/secrets.ts +30 -0
  99. package/templates/bills-agent/packages/agent-core/src/state/store.ts +307 -0
  100. package/templates/bills-agent/packages/agent-core/src/state-machine.ts +146 -0
  101. package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +193 -0
  102. package/templates/bills-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
  103. package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +124 -0
  104. package/templates/bills-agent/packages/agent-core/src/tools.ts +55 -0
  105. package/templates/bills-agent/packages/agent-core/src/types.ts +106 -0
  106. package/templates/bills-agent/packages/agent-core/test/approval.test.ts +83 -0
  107. package/templates/bills-agent/packages/agent-core/test/engine.test.ts +524 -0
  108. package/templates/bills-agent/packages/agent-core/test/escalate.test.ts +42 -0
  109. package/templates/bills-agent/packages/agent-core/test/helpers.ts +139 -0
  110. package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
  111. package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +45 -0
  112. package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +265 -0
  113. package/templates/bills-agent/packages/agent-core/test/secrets.test.ts +28 -0
  114. package/templates/bills-agent/packages/agent-core/test/state-machine.test.ts +67 -0
  115. package/templates/bills-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
  116. package/templates/bills-agent/packages/agent-core/tsconfig.json +10 -0
  117. package/templates/bills-agent/tsconfig.base.json +16 -0
  118. package/templates/bills-agent/vitest.config.ts +12 -0
  119. package/templates/collections-agent/LICENSE +21 -0
  120. package/templates/collections-agent/README.md +20 -0
  121. package/templates/collections-agent/_gitignore +10 -0
  122. package/templates/collections-agent/agents/collections-agent/.env.example +4 -0
  123. package/templates/collections-agent/agents/collections-agent/AGENTS.md +19 -0
  124. package/templates/collections-agent/agents/collections-agent/CLAUDE.md +19 -0
  125. package/templates/collections-agent/agents/collections-agent/README.md +94 -0
  126. package/templates/collections-agent/agents/collections-agent/SYSTEM_PROMPT.md +31 -0
  127. package/templates/collections-agent/agents/collections-agent/agent.yaml +28 -0
  128. package/templates/collections-agent/agents/collections-agent/channels/terminal/index.ts +178 -0
  129. package/templates/collections-agent/agents/collections-agent/channels/webhook/index.ts +131 -0
  130. package/templates/collections-agent/agents/collections-agent/evals/adversarial/beneficiary-swap-mandate.json +11 -0
  131. package/templates/collections-agent/agents/collections-agent/evals/adversarial/beneficiary-swap.json +12 -0
  132. package/templates/collections-agent/agents/collections-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
  133. package/templates/collections-agent/agents/collections-agent/evals/adversarial/exfiltration.json +19 -0
  134. package/templates/collections-agent/agents/collections-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
  135. package/templates/collections-agent/agents/collections-agent/evals/adversarial/false-authority.json +11 -0
  136. package/templates/collections-agent/agents/collections-agent/evals/adversarial/false-authority.transcript.jsonl +2 -0
  137. package/templates/collections-agent/agents/collections-agent/evals/adversarial/fractioning.json +12 -0
  138. package/templates/collections-agent/agents/collections-agent/evals/adversarial/fractioning.transcript.jsonl +4 -0
  139. package/templates/collections-agent/agents/collections-agent/evals/adversarial/model-total.json +13 -0
  140. package/templates/collections-agent/agents/collections-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
  141. package/templates/collections-agent/agents/collections-agent/evals/adversarial/prompt-injection.json +12 -0
  142. package/templates/collections-agent/agents/collections-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
  143. package/templates/collections-agent/agents/collections-agent/evals/adversarial/webhook-replay.json +11 -0
  144. package/templates/collections-agent/agents/collections-agent/evals/eval.yaml +11 -0
  145. package/templates/collections-agent/agents/collections-agent/guardrails.json +20 -0
  146. package/templates/collections-agent/agents/collections-agent/mandate.example.json +40 -0
  147. package/templates/collections-agent/agents/collections-agent/package.json +29 -0
  148. package/templates/collections-agent/agents/collections-agent/runbook.md +27 -0
  149. package/templates/collections-agent/agents/collections-agent/scenarios/beneficiary-not-allowed.json +42 -0
  150. package/templates/collections-agent/agents/collections-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +3 -0
  151. package/templates/collections-agent/agents/collections-agent/scenarios/cap-exceeded.json +27 -0
  152. package/templates/collections-agent/agents/collections-agent/scenarios/cap-exceeded.transcript.jsonl +3 -0
  153. package/templates/collections-agent/agents/collections-agent/scenarios/charge-expired.json +36 -0
  154. package/templates/collections-agent/agents/collections-agent/scenarios/charge-expired.transcript.jsonl +4 -0
  155. package/templates/collections-agent/agents/collections-agent/scenarios/escalated-above-threshold.json +49 -0
  156. package/templates/collections-agent/agents/collections-agent/scenarios/escalated-above-threshold.transcript.jsonl +5 -0
  157. package/templates/collections-agent/agents/collections-agent/scenarios/happy-path.json +60 -0
  158. package/templates/collections-agent/agents/collections-agent/scenarios/happy-path.transcript.jsonl +4 -0
  159. package/templates/collections-agent/agents/collections-agent/scenarios/instalments.json +49 -0
  160. package/templates/collections-agent/agents/collections-agent/scenarios/instalments.transcript.jsonl +4 -0
  161. package/templates/collections-agent/agents/collections-agent/scenarios/mandate-revoked.json +42 -0
  162. package/templates/collections-agent/agents/collections-agent/scenarios/mandate-revoked.transcript.jsonl +6 -0
  163. package/templates/collections-agent/agents/collections-agent/scenarios/prompt-injection.json +27 -0
  164. package/templates/collections-agent/agents/collections-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
  165. package/templates/collections-agent/agents/collections-agent/src/adversarial.ts +190 -0
  166. package/templates/collections-agent/agents/collections-agent/src/agreements.ts +45 -0
  167. package/templates/collections-agent/agents/collections-agent/src/commands/approve.ts +10 -0
  168. package/templates/collections-agent/agents/collections-agent/src/commands/check.ts +13 -0
  169. package/templates/collections-agent/agents/collections-agent/src/commands/decide.ts +48 -0
  170. package/templates/collections-agent/agents/collections-agent/src/commands/deny.ts +7 -0
  171. package/templates/collections-agent/agents/collections-agent/src/commands/eval.ts +39 -0
  172. package/templates/collections-agent/agents/collections-agent/src/commands/poll.ts +35 -0
  173. package/templates/collections-agent/agents/collections-agent/src/commands/reconcile.ts +38 -0
  174. package/templates/collections-agent/agents/collections-agent/src/commands/rerun.ts +55 -0
  175. package/templates/collections-agent/agents/collections-agent/src/commands/resume.ts +30 -0
  176. package/templates/collections-agent/agents/collections-agent/src/commands/webhook.ts +36 -0
  177. package/templates/collections-agent/agents/collections-agent/src/envelope.ts +103 -0
  178. package/templates/collections-agent/agents/collections-agent/src/main.ts +193 -0
  179. package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +105 -0
  180. package/templates/collections-agent/agents/collections-agent/src/poll.ts +94 -0
  181. package/templates/collections-agent/agents/collections-agent/src/scenarios.ts +252 -0
  182. package/templates/collections-agent/agents/collections-agent/src/setup.ts +250 -0
  183. package/templates/collections-agent/agents/collections-agent/test/adversarial.test.ts +45 -0
  184. package/templates/collections-agent/agents/collections-agent/test/check.test.ts +51 -0
  185. package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +172 -0
  186. package/templates/collections-agent/agents/collections-agent/test/envelope.test.ts +53 -0
  187. package/templates/collections-agent/agents/collections-agent/test/fixtures/accept-1042.transcript.jsonl +2 -0
  188. package/templates/collections-agent/agents/collections-agent/test/fixtures/accept-1103.transcript.jsonl +2 -0
  189. package/templates/collections-agent/agents/collections-agent/test/scenarios.test.ts +95 -0
  190. package/templates/collections-agent/agents/collections-agent/test/webhook.test.ts +100 -0
  191. package/templates/collections-agent/agents/collections-agent/tools.json +40 -0
  192. package/templates/collections-agent/agents/collections-agent/tsconfig.json +11 -0
  193. package/templates/collections-agent/package.json +35 -0
  194. package/templates/collections-agent/packages/agent-core/README.md +19 -0
  195. package/templates/collections-agent/packages/agent-core/package.json +24 -0
  196. package/templates/collections-agent/packages/agent-core/src/agent.ts +125 -0
  197. package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +154 -0
  198. package/templates/collections-agent/packages/agent-core/src/api/client.ts +53 -0
  199. package/templates/collections-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
  200. package/templates/collections-agent/packages/agent-core/src/api/rail.ts +101 -0
  201. package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +45 -0
  202. package/templates/collections-agent/packages/agent-core/src/approval.ts +109 -0
  203. package/templates/collections-agent/packages/agent-core/src/bundle.ts +113 -0
  204. package/templates/collections-agent/packages/agent-core/src/check.ts +171 -0
  205. package/templates/collections-agent/packages/agent-core/src/engine.ts +784 -0
  206. package/templates/collections-agent/packages/agent-core/src/escalate.ts +85 -0
  207. package/templates/collections-agent/packages/agent-core/src/events.ts +40 -0
  208. package/templates/collections-agent/packages/agent-core/src/guardrails.ts +45 -0
  209. package/templates/collections-agent/packages/agent-core/src/hash.ts +49 -0
  210. package/templates/collections-agent/packages/agent-core/src/ids.ts +10 -0
  211. package/templates/collections-agent/packages/agent-core/src/index.ts +29 -0
  212. package/templates/collections-agent/packages/agent-core/src/mandate.ts +100 -0
  213. package/templates/collections-agent/packages/agent-core/src/manifest.ts +76 -0
  214. package/templates/collections-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
  215. package/templates/collections-agent/packages/agent-core/src/providers/replay.ts +63 -0
  216. package/templates/collections-agent/packages/agent-core/src/providers/types.ts +39 -0
  217. package/templates/collections-agent/packages/agent-core/src/rail.ts +87 -0
  218. package/templates/collections-agent/packages/agent-core/src/revocation.ts +30 -0
  219. package/templates/collections-agent/packages/agent-core/src/secrets.ts +30 -0
  220. package/templates/collections-agent/packages/agent-core/src/state/store.ts +307 -0
  221. package/templates/collections-agent/packages/agent-core/src/state-machine.ts +146 -0
  222. package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +193 -0
  223. package/templates/collections-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
  224. package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +124 -0
  225. package/templates/collections-agent/packages/agent-core/src/tools.ts +55 -0
  226. package/templates/collections-agent/packages/agent-core/src/types.ts +106 -0
  227. package/templates/collections-agent/packages/agent-core/test/approval.test.ts +83 -0
  228. package/templates/collections-agent/packages/agent-core/test/engine.test.ts +524 -0
  229. package/templates/collections-agent/packages/agent-core/test/escalate.test.ts +42 -0
  230. package/templates/collections-agent/packages/agent-core/test/helpers.ts +139 -0
  231. package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
  232. package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +45 -0
  233. package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +265 -0
  234. package/templates/collections-agent/packages/agent-core/test/secrets.test.ts +28 -0
  235. package/templates/collections-agent/packages/agent-core/test/state-machine.test.ts +67 -0
  236. package/templates/collections-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
  237. package/templates/collections-agent/packages/agent-core/tsconfig.json +10 -0
  238. package/templates/collections-agent/tsconfig.base.json +16 -0
  239. package/templates/collections-agent/vitest.config.ts +12 -0
  240. package/templates/kits.lock.json +41 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Section 11: the proof bundle, one folder per run under `runs/<run-id>/`.
3
+ * It answers "why could the agent pay this". It holds no key and no secret;
4
+ * payee keys are masked the way a bank statement masks them.
5
+ */
6
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import type { Mandate } from "./mandate.js";
9
+ import type { RailReceipt } from "./rail.js";
10
+ import type { ApprovalArtifact } from "./types.js";
11
+
12
+ export interface TranscriptLine {
13
+ at: string;
14
+ kind: "user" | "assistant_step" | "tool_call" | "tool_result" | "assistant" | "system";
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ export class ProofBundle {
19
+ readonly dir: string;
20
+
21
+ constructor(
22
+ runsDir: string,
23
+ readonly runId: string,
24
+ ) {
25
+ this.dir = join(runsDir, runId);
26
+ mkdirSync(join(this.dir, "receipts"), { recursive: true });
27
+ }
28
+
29
+ static open(runsDir: string, runId: string): ProofBundle | undefined {
30
+ return existsSync(join(runsDir, runId)) ? new ProofBundle(runsDir, runId) : undefined;
31
+ }
32
+
33
+ transcript(line: TranscriptLine): void {
34
+ appendFileSync(join(this.dir, "transcript.jsonl"), JSON.stringify(line) + "\n");
35
+ }
36
+
37
+ readTranscript(): TranscriptLine[] {
38
+ const path = join(this.dir, "transcript.jsonl");
39
+ if (!existsSync(path)) return [];
40
+ return readFileSync(path, "utf8")
41
+ .split("\n")
42
+ .filter(Boolean)
43
+ .map((l) => JSON.parse(l) as TranscriptLine);
44
+ }
45
+
46
+ event(event: Record<string, unknown>): void {
47
+ appendFileSync(join(this.dir, "events.jsonl"), JSON.stringify(event) + "\n");
48
+ }
49
+
50
+ readEvents(): Record<string, unknown>[] {
51
+ const path = join(this.dir, "events.jsonl");
52
+ if (!existsSync(path)) return [];
53
+ return readFileSync(path, "utf8")
54
+ .split("\n")
55
+ .filter(Boolean)
56
+ .map((l) => JSON.parse(l) as Record<string, unknown>);
57
+ }
58
+
59
+ /** `approval.json` is the list of artifacts of this run, in approval order. */
60
+ approval(artifact: ApprovalArtifact): void {
61
+ const path = join(this.dir, "approval.json");
62
+ const current: ApprovalArtifact[] = existsSync(path) ? (JSON.parse(readFileSync(path, "utf8")) as ApprovalArtifact[]) : [];
63
+ if (!current.some((a) => a.approval_id === artifact.approval_id)) current.push(artifact);
64
+ writeFileSync(path, JSON.stringify(current, null, 2) + "\n");
65
+ }
66
+
67
+ readApprovals(): ApprovalArtifact[] {
68
+ const path = join(this.dir, "approval.json");
69
+ return existsSync(path) ? (JSON.parse(readFileSync(path, "utf8")) as ApprovalArtifact[]) : [];
70
+ }
71
+
72
+ mandateSnapshot(mandate: Mandate): void {
73
+ const { signature: _signature, canonical: _canonical, ...safe } = mandate;
74
+ writeFileSync(join(this.dir, "mandate.snapshot.json"), JSON.stringify({ ...safe, beneficiaries: safe.beneficiaries.map((b) => ({ ...b, payee: maskPayee(b.payee) })), merchant_allowlist: safe.merchant_allowlist.map(maskPayee) }, null, 2) + "\n");
75
+ }
76
+
77
+ receipt(receipt: RailReceipt): string {
78
+ const path = join(this.dir, "receipts", `${receipt.receipt_id}.json`);
79
+ const { raw: _raw, ...safe } = receipt;
80
+ writeFileSync(path, JSON.stringify({ ...safe, payment: { ...safe.payment, payee: safe.payment.payee ? maskPayee(safe.payment.payee) : null } }, null, 2) + "\n");
81
+ return path;
82
+ }
83
+
84
+ listReceipts(): string[] {
85
+ const dir = join(this.dir, "receipts");
86
+ if (!existsSync(dir)) return [];
87
+ return readdirSorted(dir);
88
+ }
89
+
90
+ meta(meta: Record<string, unknown>): void {
91
+ writeFileSync(join(this.dir, "run.json"), JSON.stringify(meta, null, 2) + "\n");
92
+ }
93
+
94
+ readMeta(): Record<string, unknown> | undefined {
95
+ const path = join(this.dir, "run.json");
96
+ return existsSync(path) ? (JSON.parse(readFileSync(path, "utf8")) as Record<string, unknown>) : undefined;
97
+ }
98
+ }
99
+
100
+ function readdirSorted(dir: string): string[] {
101
+ return readdirSync(dir)
102
+ .filter((f) => f.endsWith(".json"))
103
+ .sort();
104
+ }
105
+
106
+ /** `escola@exemplo.com.br` -> `es***@exemplo.com.br`; `+5511999998888` -> `+55***8888`; a UUID keeps its first and last 4. */
107
+ export function maskPayee(payee: string): string {
108
+ if (payee === "*") return payee;
109
+ const at = payee.indexOf("@");
110
+ if (at > 0) return `${payee.slice(0, Math.min(2, at))}***${payee.slice(at)}`;
111
+ if (payee.length <= 8) return `${payee.slice(0, 2)}***`;
112
+ return `${payee.slice(0, 4)}***${payee.slice(-4)}`;
113
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * `npm run check`: the manifest is the index, and the files it points to
3
+ * must agree with it. Fails on a contradiction between `agent.yaml` and
4
+ * `SYSTEM_PROMPT.md`, `tools.json` or `guardrails.json`, on `AGENTS.md`
5
+ * and `CLAUDE.md` diverging, and on a missing `mcp`, `cli` or `schema`.
6
+ */
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { parse as parseYaml } from "yaml";
10
+ import { GuardrailsSchema } from "./guardrails.js";
11
+ import { loadManifest, ManifestSchema, type LoadedManifest } from "./manifest.js";
12
+ import { MandateSchema } from "./mandate.js";
13
+ import { ToolsFileSchema } from "./tools.js";
14
+ import { canonicalJson } from "./hash.js";
15
+ import { PUBLISHED_EVENTS, isPublishedEvent } from "./events.js";
16
+
17
+ export interface CheckFinding {
18
+ level: "error" | "warning";
19
+ code: string;
20
+ message: string;
21
+ }
22
+
23
+ export interface CheckReport {
24
+ ok: boolean;
25
+ agent: string | null;
26
+ findings: CheckFinding[];
27
+ }
28
+
29
+ export function checkAgent(agentDir: string): CheckReport {
30
+ const findings: CheckFinding[] = [];
31
+ const error = (code: string, message: string) => findings.push({ level: "error", code, message });
32
+ const warning = (code: string, message: string) => findings.push({ level: "warning", code, message });
33
+
34
+ const manifestPath = join(agentDir, "agent.yaml");
35
+ if (!existsSync(manifestPath)) {
36
+ error("manifest_missing", `${manifestPath} does not exist`);
37
+ return { ok: false, agent: null, findings };
38
+ }
39
+
40
+ // Pinned versions and schema are checked on the raw document, so the message names the field instead of a Zod path.
41
+ const raw = parseYaml(readFileSync(manifestPath, "utf8")) as Record<string, unknown> | null;
42
+ for (const field of ["schema", "mcp", "cli"]) {
43
+ if (!raw || raw[field] === undefined) error("manifest_field_missing", `agent.yaml has no \`${field}\``);
44
+ }
45
+ // The events an agent declares must be ones the API publishes; the list is the core's (events.ts), the manifest only names entries of it.
46
+ for (const name of Array.isArray(raw?.["events"]) ? raw["events"] : []) {
47
+ if (typeof name === "string" && !isPublishedEvent(name)) error("events_unknown", `agent.yaml declares the event \`${name}\`, which the API does not publish; known: ${PUBLISHED_EVENTS.join(", ")}`);
48
+ }
49
+
50
+ let loaded: LoadedManifest;
51
+ try {
52
+ loaded = loadManifest(manifestPath);
53
+ } catch (err) {
54
+ error("manifest_invalid", err instanceof Error ? err.message : String(err));
55
+ return { ok: false, agent: typeof raw?.["name"] === "string" ? (raw["name"] as string) : null, findings };
56
+ }
57
+ const { manifest } = loaded;
58
+
59
+ // tools.json
60
+ let toolNames: string[] = [];
61
+ const toolsPath = loaded.resolvePath(manifest.tools);
62
+ if (!existsSync(toolsPath)) error("tools_missing", `${manifest.tools} does not exist`);
63
+ else {
64
+ const parsed = ToolsFileSchema.safeParse(JSON.parse(readFileSync(toolsPath, "utf8")));
65
+ if (!parsed.success) error("tools_invalid", parsed.error.message);
66
+ else {
67
+ toolNames = [...parsed.data.meta_tools, ...parsed.data.local_tools].map((t) => t.name);
68
+ const hasPayment = parsed.data.meta_tools.some((t) => t.effect === "payment");
69
+ const declaresPixOut = manifest.maturity["pix-out"] !== undefined;
70
+ if (declaresPixOut && !hasPayment) error("tools_contradict_manifest", "agent.yaml declares pix-out maturity but tools.json has no payment meta-tool");
71
+ if (!declaresPixOut && hasPayment) error("tools_contradict_manifest", "tools.json has a payment meta-tool but agent.yaml declares no pix-out maturity");
72
+ const hasCharge = parsed.data.meta_tools.some((t) => t.effect === "charge");
73
+ const declaresReceivables = manifest.maturity["bolepix-receivables"] !== undefined;
74
+ if (declaresReceivables && !hasCharge) error("tools_contradict_manifest", "agent.yaml declares bolepix-receivables maturity but tools.json has no charge meta-tool");
75
+ if (!declaresReceivables && hasCharge) error("tools_contradict_manifest", "tools.json has a charge meta-tool but agent.yaml declares no bolepix-receivables maturity");
76
+ }
77
+ }
78
+
79
+ // guardrails.json
80
+ const guardrailsPath = loaded.resolvePath(manifest.guardrails);
81
+ if (!existsSync(guardrailsPath)) error("guardrails_missing", `${manifest.guardrails} does not exist`);
82
+ else {
83
+ const parsed = GuardrailsSchema.safeParse(JSON.parse(readFileSync(guardrailsPath, "utf8")));
84
+ if (!parsed.success) error("guardrails_invalid", parsed.error.message);
85
+ else {
86
+ if (parsed.data.approval !== manifest.default_approval) {
87
+ error("guardrails_contradict_manifest", `guardrails.approval is ${parsed.data.approval}; agent.yaml default_approval is ${manifest.default_approval}`);
88
+ }
89
+ if (canonicalJson(parsed.data.escalate_above ?? null) !== canonicalJson(manifest.escalate_above ?? null)) {
90
+ error("guardrails_contradict_manifest", "guardrails.escalate_above differs from agent.yaml escalate_above");
91
+ }
92
+ }
93
+ }
94
+
95
+ // mandate.example.json
96
+ const mandatePath = loaded.resolvePath(manifest.mandate_schema);
97
+ if (!existsSync(mandatePath)) error("mandate_missing", `${manifest.mandate_schema} does not exist`);
98
+ else {
99
+ const parsed = MandateSchema.safeParse(JSON.parse(readFileSync(mandatePath, "utf8")));
100
+ if (!parsed.success) error("mandate_invalid", parsed.error.message);
101
+ else if (parsed.data.agent_id !== manifest.name) error("mandate_contradicts_manifest", `mandate.example.json agent_id is ${parsed.data.agent_id}; agent.yaml name is ${manifest.name}`);
102
+ }
103
+
104
+ // SYSTEM_PROMPT.md: must exist, must name the agent, must not name a tool tools.json does not have, must not promise third-party verification.
105
+ const promptPath = join(agentDir, "SYSTEM_PROMPT.md");
106
+ if (!existsSync(promptPath)) error("prompt_missing", "SYSTEM_PROMPT.md does not exist");
107
+ else {
108
+ const prompt = readFileSync(promptPath, "utf8");
109
+ if (!prompt.includes(manifest.name)) error("prompt_contradicts_manifest", `SYSTEM_PROMPT.md never names ${manifest.name}`);
110
+ for (const named of prompt.match(/\bcodespar_[a-z_]+\b/g) ?? []) {
111
+ if (!toolNames.includes(named)) error("prompt_contradicts_tools", `SYSTEM_PROMPT.md names ${named}, which tools.json does not list`);
112
+ }
113
+ for (const mode of ["human", "mandate"] as const) {
114
+ if (prompt.includes(`approval: ${mode}`) && !manifest.approval.includes(mode)) error("prompt_contradicts_manifest", `SYSTEM_PROMPT.md mentions approval: ${mode}, which agent.yaml does not support`);
115
+ }
116
+ }
117
+
118
+ // AGENTS.md and CLAUDE.md identical.
119
+ const agentsMd = join(agentDir, "AGENTS.md");
120
+ const claudeMd = join(agentDir, "CLAUDE.md");
121
+ if (!existsSync(agentsMd)) error("agents_md_missing", "AGENTS.md does not exist");
122
+ if (!existsSync(claudeMd)) error("claude_md_missing", "CLAUDE.md does not exist");
123
+ if (existsSync(agentsMd) && existsSync(claudeMd) && readFileSync(agentsMd, "utf8") !== readFileSync(claudeMd, "utf8")) {
124
+ error("agents_md_diverges", "AGENTS.md and CLAUDE.md differ");
125
+ }
126
+ if (loaded.resolvePath(manifest.agents_md) !== agentsMd) error("manifest_agents_md", `agent.yaml agents_md must point at ./AGENTS.md`);
127
+
128
+ // Directories and the eval config.
129
+ for (const [field, rel] of [["scenarios", manifest.scenarios], ["evals", manifest.evals]] as const) {
130
+ if (!existsSync(loaded.resolvePath(rel))) error(`${field}_missing`, `${rel} does not exist`);
131
+ }
132
+ const evalPath = join(loaded.resolvePath(manifest.evals), "eval.yaml");
133
+ if (!existsSync(evalPath)) error("eval_missing", "evals/eval.yaml does not exist");
134
+ else {
135
+ const evalDoc = parseYaml(readFileSync(evalPath, "utf8")) as Record<string, unknown> | null;
136
+ if (evalDoc?.["extends"] !== "../agent.yaml") error("eval_extends", 'evals/eval.yaml must start with `extends: ../agent.yaml`');
137
+ for (const key of Object.keys(evalDoc ?? {})) {
138
+ if (key !== "extends" && key in ManifestSchema.innerType().shape) error("eval_redeclares_manifest", `evals/eval.yaml redeclares \`${key}\`; only cases and metrics belong there`);
139
+ }
140
+ }
141
+
142
+ // Wording the README must not carry (section 6).
143
+ for (const file of ["README.md", "runbook.md", "SYSTEM_PROMPT.md"]) {
144
+ const path = join(agentDir, file);
145
+ if (!existsSync(path)) {
146
+ if (file !== "SYSTEM_PROMPT.md") error("doc_missing", `${file} does not exist`);
147
+ continue;
148
+ }
149
+ const text = readFileSync(path, "utf8").toLowerCase();
150
+ if (text.includes("verificável por terceiro") || text.includes("verifiable by a third party") || text.includes("third-party verifiable")) {
151
+ error("doc_overclaims", `${file} claims third-party verifiability; the receipt is HMAC until Ed25519`);
152
+ }
153
+ }
154
+
155
+ const envExample = join(agentDir, ".env.example");
156
+ if (!existsSync(envExample)) error("env_example_missing", ".env.example does not exist");
157
+ else {
158
+ const keys = readFileSync(envExample, "utf8")
159
+ .split("\n")
160
+ .map((l) => l.trim())
161
+ .filter((l) => l && !l.startsWith("#"))
162
+ .map((l) => l.split("=")[0]);
163
+ const extra = keys.filter((k) => k !== "CODESPAR_API_KEY" && k !== "ANTHROPIC_API_KEY");
164
+ if (extra.length) error("env_example_extra", `.env.example declares more than the two keys: ${extra.join(", ")}`);
165
+ if (!keys.includes("CODESPAR_API_KEY") || !keys.includes("ANTHROPIC_API_KEY")) error("env_example_incomplete", ".env.example must declare CODESPAR_API_KEY and ANTHROPIC_API_KEY");
166
+ }
167
+
168
+ if (manifest.maturity["receipt-verification"] === "live") warning("maturity_overclaims", "receipt-verification cannot be live before Ed25519");
169
+
170
+ return { ok: findings.every((f) => f.level !== "error"), agent: manifest.name, findings };
171
+ }