@paybond/kit 0.10.0 → 0.11.1

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 (346) hide show
  1. package/README.md +59 -15
  2. package/completion-presets/catalog.json +1187 -0
  3. package/completion-presets/catalog.sha256 +1 -0
  4. package/dev/trace-ui/dashboard.html +617 -0
  5. package/dist/agent/adapter.d.ts +51 -0
  6. package/dist/agent/adapter.js +66 -0
  7. package/dist/agent/attach-bundle.d.ts +37 -0
  8. package/dist/agent/attach-bundle.js +118 -0
  9. package/dist/agent/authorization-cache.d.ts +22 -0
  10. package/dist/agent/authorization-cache.js +36 -0
  11. package/dist/agent/deferred-tools.d.ts +11 -0
  12. package/dist/agent/deferred-tools.js +62 -0
  13. package/dist/agent/discover.d.ts +41 -0
  14. package/dist/agent/discover.js +147 -0
  15. package/dist/agent/evidence.d.ts +9 -0
  16. package/dist/agent/evidence.js +28 -0
  17. package/dist/agent/facade.d.ts +48 -0
  18. package/dist/agent/facade.js +112 -0
  19. package/dist/agent/gateway-trace-reporter.d.ts +28 -0
  20. package/dist/agent/gateway-trace-reporter.js +49 -0
  21. package/dist/agent/generic-runner.d.ts +14 -0
  22. package/dist/agent/generic-runner.js +49 -0
  23. package/dist/agent/generic-sandbox-demo.d.ts +36 -0
  24. package/dist/agent/generic-sandbox-demo.js +82 -0
  25. package/dist/agent/guarded-agent.d.ts +49 -0
  26. package/dist/agent/guarded-agent.js +100 -0
  27. package/dist/agent/index.d.ts +13 -0
  28. package/dist/agent/index.js +13 -0
  29. package/dist/agent/instrument.d.ts +156 -0
  30. package/dist/agent/instrument.js +442 -0
  31. package/dist/agent/interceptor.d.ts +24 -0
  32. package/dist/agent/interceptor.js +440 -0
  33. package/dist/agent/lazy-context-tools.d.ts +15 -0
  34. package/dist/agent/lazy-context-tools.js +81 -0
  35. package/dist/agent/registry-file.d.ts +39 -0
  36. package/dist/agent/registry-file.js +219 -0
  37. package/dist/agent/registry.d.ts +37 -0
  38. package/dist/agent/registry.js +128 -0
  39. package/dist/agent/run.d.ts +124 -0
  40. package/dist/agent/run.js +301 -0
  41. package/dist/agent/types.d.ts +318 -0
  42. package/dist/agent/types.js +42 -0
  43. package/dist/agent-recognition.d.ts +72 -0
  44. package/dist/agent-recognition.js +165 -0
  45. package/dist/bincode-wire.d.ts +18 -0
  46. package/dist/bincode-wire.js +93 -0
  47. package/dist/claude-agents/config.d.ts +21 -0
  48. package/dist/claude-agents/config.js +145 -0
  49. package/dist/claude-agents/index.d.ts +2 -0
  50. package/dist/claude-agents/index.js +2 -0
  51. package/dist/claude-agents/sandbox-demo.d.ts +30 -0
  52. package/dist/claude-agents/sandbox-demo.js +91 -0
  53. package/dist/cli/agent/demo-loaders.d.ts +4 -0
  54. package/dist/cli/agent/demo-loaders.js +66 -0
  55. package/dist/cli/agent/env-quote.d.ts +1 -0
  56. package/dist/cli/agent/env-quote.js +6 -0
  57. package/dist/cli/agent/env-write.d.ts +8 -0
  58. package/dist/cli/agent/env-write.js +47 -0
  59. package/dist/cli/agent/paybond.d.ts +16 -0
  60. package/dist/cli/agent/paybond.js +55 -0
  61. package/dist/cli/agent/policy-file.d.ts +29 -0
  62. package/dist/cli/agent/policy-file.js +61 -0
  63. package/dist/cli/agent/production-evidence.d.ts +24 -0
  64. package/dist/cli/agent/production-evidence.js +98 -0
  65. package/dist/cli/agent/run-store.d.ts +30 -0
  66. package/dist/cli/agent/run-store.js +42 -0
  67. package/dist/cli/agent/run-trace-store.d.ts +39 -0
  68. package/dist/cli/agent/run-trace-store.js +143 -0
  69. package/dist/cli/agent-run-trace-table.d.ts +9 -0
  70. package/dist/cli/agent-run-trace-table.js +24 -0
  71. package/dist/cli/agent-sandbox-smoke-checklist.d.ts +9 -0
  72. package/dist/cli/agent-sandbox-smoke-checklist.js +50 -0
  73. package/dist/cli/command-spec.d.ts +1 -0
  74. package/dist/cli/command-spec.js +286 -5
  75. package/dist/cli/commands/agent.d.ts +16 -0
  76. package/dist/cli/commands/agent.js +1136 -0
  77. package/dist/cli/commands/dev.d.ts +7 -0
  78. package/dist/cli/commands/dev.js +348 -0
  79. package/dist/cli/commands/discovery.js +3 -3
  80. package/dist/cli/commands/policy.d.ts +13 -0
  81. package/dist/cli/commands/policy.js +769 -0
  82. package/dist/cli/commands/setup.d.ts +3 -0
  83. package/dist/cli/commands/setup.js +124 -8
  84. package/dist/cli/commands/workflows.js +9 -4
  85. package/dist/cli/config.d.ts +2 -0
  86. package/dist/cli/config.js +4 -2
  87. package/dist/cli/context.js +2 -1
  88. package/dist/cli/credentials.js +2 -2
  89. package/dist/cli/doctor-agent-middleware.d.ts +5 -0
  90. package/dist/cli/doctor-agent-middleware.js +49 -0
  91. package/dist/cli/globals.d.ts +1 -0
  92. package/dist/cli/globals.js +11 -1
  93. package/dist/cli/help.d.ts +1 -1
  94. package/dist/cli/help.js +35 -3
  95. package/dist/cli/mcp-install.js +2 -2
  96. package/dist/cli/mcp-policy.d.ts +3 -0
  97. package/dist/cli/mcp-policy.js +19 -13
  98. package/dist/cli/mcp-verify-config.js +9 -11
  99. package/dist/cli/redact.js +29 -8
  100. package/dist/cli/router.js +105 -2
  101. package/dist/cli/smoke-deep-links.d.ts +15 -0
  102. package/dist/cli/smoke-deep-links.js +63 -0
  103. package/dist/cli/telemetry.d.ts +17 -0
  104. package/dist/cli/telemetry.js +94 -0
  105. package/dist/completion-catalog-digest.d.ts +2 -0
  106. package/dist/completion-catalog-digest.js +2 -0
  107. package/dist/completion-catalog-integrity.d.ts +2 -0
  108. package/dist/completion-catalog-integrity.js +17 -0
  109. package/dist/completion-catalog.d.ts +49 -0
  110. package/dist/completion-catalog.js +62 -0
  111. package/dist/completion-contract-digest.d.ts +37 -0
  112. package/dist/completion-contract-digest.js +73 -0
  113. package/dist/completion-forbidden-fields.d.ts +5 -0
  114. package/dist/completion-forbidden-fields.js +26 -0
  115. package/dist/completion-init.d.ts +8 -0
  116. package/dist/completion-init.js +334 -0
  117. package/dist/completion-resolve.d.ts +21 -0
  118. package/dist/completion-resolve.js +86 -0
  119. package/dist/completion-validate-evidence.d.ts +24 -0
  120. package/dist/completion-validate-evidence.js +145 -0
  121. package/dist/dev/offline-gateway.d.ts +24 -0
  122. package/dist/dev/offline-gateway.js +102 -0
  123. package/dist/dev/trace-buffer.d.ts +61 -0
  124. package/dist/dev/trace-buffer.js +330 -0
  125. package/dist/dev/trace-security-headers.d.ts +11 -0
  126. package/dist/dev/trace-security-headers.js +16 -0
  127. package/dist/dev/trace-server.d.ts +8 -0
  128. package/dist/dev/trace-server.js +38 -0
  129. package/dist/dev/trace-ui.d.ts +4 -0
  130. package/dist/dev/trace-ui.js +25 -0
  131. package/dist/dev/wiremock-up.d.ts +15 -0
  132. package/dist/dev/wiremock-up.js +118 -0
  133. package/dist/doctor-completion.d.ts +17 -0
  134. package/dist/doctor-completion.js +428 -0
  135. package/dist/gateway-url.d.ts +7 -0
  136. package/dist/gateway-url.js +69 -0
  137. package/dist/index.d.ts +119 -2
  138. package/dist/index.js +267 -6
  139. package/dist/init.js +374 -57
  140. package/dist/langgraph/awrap-tool-call.d.ts +25 -0
  141. package/dist/langgraph/awrap-tool-call.js +81 -0
  142. package/dist/langgraph/config.d.ts +13 -0
  143. package/dist/langgraph/config.js +11 -0
  144. package/dist/langgraph/index.d.ts +4 -0
  145. package/dist/langgraph/index.js +4 -0
  146. package/dist/langgraph/sandbox-demo.d.ts +40 -0
  147. package/dist/langgraph/sandbox-demo.js +96 -0
  148. package/dist/langgraph/tool-node.d.ts +10 -0
  149. package/dist/langgraph/tool-node.js +38 -0
  150. package/dist/login.js +7 -0
  151. package/dist/mcp/index.d.ts +1 -0
  152. package/dist/mcp/index.js +1 -0
  153. package/dist/mcp/tool-surface.d.ts +25 -0
  154. package/dist/mcp/tool-surface.js +17 -0
  155. package/dist/mcp-capability-token-cache.d.ts +24 -0
  156. package/dist/mcp-capability-token-cache.js +101 -0
  157. package/dist/mcp-evidence-policy.d.ts +48 -0
  158. package/dist/mcp-evidence-policy.js +117 -0
  159. package/dist/mcp-policy-reload.d.ts +79 -0
  160. package/dist/mcp-policy-reload.js +200 -0
  161. package/dist/mcp-sep2828-evidence.d.ts +36 -0
  162. package/dist/mcp-sep2828-evidence.js +65 -0
  163. package/dist/mcp-server.d.ts +6 -0
  164. package/dist/mcp-server.js +224 -44
  165. package/dist/openai-agents/index.d.ts +40 -0
  166. package/dist/openai-agents/index.js +151 -0
  167. package/dist/openai-agents/sandbox-demo.d.ts +34 -0
  168. package/dist/openai-agents/sandbox-demo.js +118 -0
  169. package/dist/payee-evidence.js +2 -29
  170. package/dist/policy/catalog.d.ts +31 -0
  171. package/dist/policy/catalog.js +48 -0
  172. package/dist/policy/compose-utils.d.ts +3 -0
  173. package/dist/policy/compose-utils.js +4 -0
  174. package/dist/policy/compose.d.ts +20 -0
  175. package/dist/policy/compose.js +240 -0
  176. package/dist/policy/digest.d.ts +7 -0
  177. package/dist/policy/digest.js +75 -0
  178. package/dist/policy/domain.d.ts +15 -0
  179. package/dist/policy/domain.js +28 -0
  180. package/dist/policy/guardrail-spec.d.ts +17 -0
  181. package/dist/policy/guardrail-spec.js +140 -0
  182. package/dist/policy/guardrails.d.ts +48 -0
  183. package/dist/policy/guardrails.js +72 -0
  184. package/dist/policy/index.d.ts +21 -0
  185. package/dist/policy/index.js +21 -0
  186. package/dist/policy/init.d.ts +102 -0
  187. package/dist/policy/init.js +351 -0
  188. package/dist/policy/intent-spec.d.ts +52 -0
  189. package/dist/policy/intent-spec.js +176 -0
  190. package/dist/policy/json-path.d.ts +4 -0
  191. package/dist/policy/json-path.js +23 -0
  192. package/dist/policy/layers-io.d.ts +7 -0
  193. package/dist/policy/layers-io.js +28 -0
  194. package/dist/policy/load-effective.d.ts +22 -0
  195. package/dist/policy/load-effective.js +77 -0
  196. package/dist/policy/load.d.ts +85 -0
  197. package/dist/policy/load.js +164 -0
  198. package/dist/policy/merge.d.ts +29 -0
  199. package/dist/policy/merge.js +297 -0
  200. package/dist/policy/parse-text.d.ts +2 -0
  201. package/dist/policy/parse-text.js +126 -0
  202. package/dist/policy/policy-api.d.ts +45 -0
  203. package/dist/policy/policy-api.js +61 -0
  204. package/dist/policy/presets.d.ts +19 -0
  205. package/dist/policy/presets.js +66 -0
  206. package/dist/policy/registry.d.ts +7 -0
  207. package/dist/policy/registry.js +33 -0
  208. package/dist/policy/reload.d.ts +86 -0
  209. package/dist/policy/reload.js +233 -0
  210. package/dist/policy/render-yaml.d.ts +3 -0
  211. package/dist/policy/render-yaml.js +69 -0
  212. package/dist/policy/sandbox-bootstrap.d.ts +19 -0
  213. package/dist/policy/sandbox-bootstrap.js +66 -0
  214. package/dist/policy/schema.d.ts +204 -0
  215. package/dist/policy/schema.js +255 -0
  216. package/dist/policy/snapshot.d.ts +33 -0
  217. package/dist/policy/snapshot.js +23 -0
  218. package/dist/policy/validate-remote.d.ts +43 -0
  219. package/dist/policy/validate-remote.js +104 -0
  220. package/dist/policy/validate.d.ts +36 -0
  221. package/dist/policy/validate.js +150 -0
  222. package/dist/policy/watcher.d.ts +29 -0
  223. package/dist/policy/watcher.js +112 -0
  224. package/dist/principal-intent.d.ts +52 -0
  225. package/dist/principal-intent.js +193 -37
  226. package/dist/project-init.d.ts +34 -0
  227. package/dist/project-init.js +898 -0
  228. package/dist/sep2828-signature.d.ts +10 -0
  229. package/dist/sep2828-signature.js +134 -0
  230. package/dist/solutions/api.d.ts +22 -0
  231. package/dist/solutions/api.js +40 -0
  232. package/dist/solutions/catalog.d.ts +34 -0
  233. package/dist/solutions/catalog.js +129 -0
  234. package/dist/solutions/index.d.ts +2 -0
  235. package/dist/solutions/index.js +2 -0
  236. package/dist/template-init.d.ts +54 -0
  237. package/dist/template-init.js +203 -0
  238. package/dist/vercel-ai/config.d.ts +15 -0
  239. package/dist/vercel-ai/config.js +13 -0
  240. package/dist/vercel-ai/index.d.ts +4 -0
  241. package/dist/vercel-ai/index.js +4 -0
  242. package/dist/vercel-ai/sandbox-demo.d.ts +44 -0
  243. package/dist/vercel-ai/sandbox-demo.js +153 -0
  244. package/dist/vercel-ai/tool-approval.d.ts +16 -0
  245. package/dist/vercel-ai/tool-approval.js +41 -0
  246. package/dist/vercel-ai/wrap-tools.d.ts +9 -0
  247. package/dist/vercel-ai/wrap-tools.js +40 -0
  248. package/dist/x402-receipt-evidence.d.ts +29 -0
  249. package/dist/x402-receipt-evidence.js +97 -0
  250. package/dist/x402-receipt-signature.d.ts +12 -0
  251. package/dist/x402-receipt-signature.js +211 -0
  252. package/package.json +75 -3
  253. package/solutions/aws.json +17 -0
  254. package/solutions/saas.json +17 -0
  255. package/solutions/shopping.json +17 -0
  256. package/solutions/travel.json +18 -0
  257. package/templates/manifest.json +169 -0
  258. package/templates/openai-shopping-agent/.env.example +3 -0
  259. package/templates/openai-shopping-agent/.github/workflows/smoke.yml +20 -0
  260. package/templates/openai-shopping-agent/LICENSE +201 -0
  261. package/templates/openai-shopping-agent/README.md +29 -0
  262. package/templates/openai-shopping-agent/package-lock.json +1525 -0
  263. package/templates/openai-shopping-agent/package.json +22 -0
  264. package/templates/openai-shopping-agent/paybond.policy.yaml +22 -0
  265. package/templates/openai-shopping-agent/src/index.ts +22 -0
  266. package/templates/openai-shopping-agent/src/paybond.config.ts +51 -0
  267. package/templates/openai-shopping-agent/tsconfig.json +13 -0
  268. package/templates/paybond-aws-operator/.env.example +3 -0
  269. package/templates/paybond-aws-operator/.github/workflows/smoke.yml +20 -0
  270. package/templates/paybond-aws-operator/LICENSE +201 -0
  271. package/templates/paybond-aws-operator/README.md +29 -0
  272. package/templates/paybond-aws-operator/package-lock.json +151 -0
  273. package/templates/paybond-aws-operator/package.json +20 -0
  274. package/templates/paybond-aws-operator/paybond.policy.yaml +22 -0
  275. package/templates/paybond-aws-operator/src/index.ts +54 -0
  276. package/templates/paybond-aws-operator/src/paybond.config.ts +51 -0
  277. package/templates/paybond-aws-operator/tsconfig.json +13 -0
  278. package/templates/paybond-claude-agents-demo/.env.example +3 -0
  279. package/templates/paybond-claude-agents-demo/.github/workflows/smoke.yml +20 -0
  280. package/templates/paybond-claude-agents-demo/LICENSE +201 -0
  281. package/templates/paybond-claude-agents-demo/README.md +29 -0
  282. package/templates/paybond-claude-agents-demo/package-lock.json +1489 -0
  283. package/templates/paybond-claude-agents-demo/package.json +22 -0
  284. package/templates/paybond-claude-agents-demo/paybond.policy.yaml +22 -0
  285. package/templates/paybond-claude-agents-demo/src/index.ts +22 -0
  286. package/templates/paybond-claude-agents-demo/src/paybond.config.ts +51 -0
  287. package/templates/paybond-claude-agents-demo/tsconfig.json +13 -0
  288. package/templates/paybond-invoice-agent/.env.example +3 -0
  289. package/templates/paybond-invoice-agent/.github/workflows/smoke.yml +19 -0
  290. package/templates/paybond-invoice-agent/LICENSE +201 -0
  291. package/templates/paybond-invoice-agent/README.md +29 -0
  292. package/templates/paybond-invoice-agent/app.py +27 -0
  293. package/templates/paybond-invoice-agent/package.json +6 -0
  294. package/templates/paybond-invoice-agent/paybond.policy.yaml +22 -0
  295. package/templates/paybond-invoice-agent/paybond_config.py +45 -0
  296. package/templates/paybond-invoice-agent/requirements.txt +2 -0
  297. package/templates/paybond-mcp-coding-agent/.env.example +3 -0
  298. package/templates/paybond-mcp-coding-agent/.github/workflows/smoke.yml +20 -0
  299. package/templates/paybond-mcp-coding-agent/LICENSE +201 -0
  300. package/templates/paybond-mcp-coding-agent/README.md +39 -0
  301. package/templates/paybond-mcp-coding-agent/package-lock.json +151 -0
  302. package/templates/paybond-mcp-coding-agent/package.json +20 -0
  303. package/templates/paybond-mcp-coding-agent/paybond.policy.yaml +25 -0
  304. package/templates/paybond-mcp-coding-agent/src/index.ts +40 -0
  305. package/templates/paybond-mcp-coding-agent/src/paybond.config.ts +51 -0
  306. package/templates/paybond-mcp-coding-agent/tsconfig.json +13 -0
  307. package/templates/paybond-openai-agents-demo/.env.example +3 -0
  308. package/templates/paybond-openai-agents-demo/.github/workflows/smoke.yml +20 -0
  309. package/templates/paybond-openai-agents-demo/LICENSE +201 -0
  310. package/templates/paybond-openai-agents-demo/README.md +29 -0
  311. package/templates/paybond-openai-agents-demo/package-lock.json +1525 -0
  312. package/templates/paybond-openai-agents-demo/package.json +22 -0
  313. package/templates/paybond-openai-agents-demo/paybond.policy.yaml +22 -0
  314. package/templates/paybond-openai-agents-demo/src/index.ts +22 -0
  315. package/templates/paybond-openai-agents-demo/src/paybond.config.ts +51 -0
  316. package/templates/paybond-openai-agents-demo/tsconfig.json +13 -0
  317. package/templates/paybond-procurement-agent/.env.example +3 -0
  318. package/templates/paybond-procurement-agent/.github/workflows/smoke.yml +20 -0
  319. package/templates/paybond-procurement-agent/LICENSE +201 -0
  320. package/templates/paybond-procurement-agent/README.md +29 -0
  321. package/templates/paybond-procurement-agent/package-lock.json +151 -0
  322. package/templates/paybond-procurement-agent/package.json +20 -0
  323. package/templates/paybond-procurement-agent/paybond.policy.yaml +25 -0
  324. package/templates/paybond-procurement-agent/src/index.ts +54 -0
  325. package/templates/paybond-procurement-agent/src/paybond.config.ts +51 -0
  326. package/templates/paybond-procurement-agent/tsconfig.json +13 -0
  327. package/templates/paybond-travel-agent/.env.example +3 -0
  328. package/templates/paybond-travel-agent/.github/workflows/smoke.yml +20 -0
  329. package/templates/paybond-travel-agent/LICENSE +201 -0
  330. package/templates/paybond-travel-agent/README.md +29 -0
  331. package/templates/paybond-travel-agent/package-lock.json +444 -0
  332. package/templates/paybond-travel-agent/package.json +23 -0
  333. package/templates/paybond-travel-agent/paybond.policy.yaml +22 -0
  334. package/templates/paybond-travel-agent/src/index.ts +22 -0
  335. package/templates/paybond-travel-agent/src/paybond.config.ts +51 -0
  336. package/templates/paybond-travel-agent/tsconfig.json +13 -0
  337. package/templates/paybond-vercel-shopping-agent/.env.example +3 -0
  338. package/templates/paybond-vercel-shopping-agent/.github/workflows/smoke.yml +20 -0
  339. package/templates/paybond-vercel-shopping-agent/LICENSE +201 -0
  340. package/templates/paybond-vercel-shopping-agent/README.md +29 -0
  341. package/templates/paybond-vercel-shopping-agent/package-lock.json +265 -0
  342. package/templates/paybond-vercel-shopping-agent/package.json +22 -0
  343. package/templates/paybond-vercel-shopping-agent/paybond.policy.yaml +22 -0
  344. package/templates/paybond-vercel-shopping-agent/src/index.ts +22 -0
  345. package/templates/paybond-vercel-shopping-agent/src/paybond.config.ts +51 -0
  346. package/templates/paybond-vercel-shopping-agent/tsconfig.json +13 -0
@@ -0,0 +1,769 @@
1
+ import { readJsonBody } from "../automation.js";
2
+ import { withGateway } from "../context.js";
3
+ import { describeCredentialSource } from "../credentials.js";
4
+ import { getCompletionPreset, getCompletionPresetByTemplateId, loadCompletionCatalog, } from "../../completion-catalog.js";
5
+ import { resolveCompletionPreset, isVendorPack } from "../../completion-resolve.js";
6
+ import { mapSep2828ReceiptsToArtifactAttestedEvidence } from "../../mcp-sep2828-evidence.js";
7
+ import { validateCompletionEvidence } from "../../completion-validate-evidence.js";
8
+ import { mapX402ReceiptToArtifactAttestedEvidence } from "../../x402-receipt-evidence.js";
9
+ import { scaffoldOrgBasePolicy, scaffoldPaybondPolicy, scaffoldComposedPolicy, scaffoldPolicyFromPreset, scaffoldTenantOverlayPolicy, renderPolicyPresetPreviewYaml, renderComposedPolicyPreviewYaml } from "../../policy/init.js";
10
+ import { PaybondPolicy } from "../../policy/load.js";
11
+ import { listPolicyPresetsCatalog } from "../../policy/catalog.js";
12
+ import { isKnownPolicyPresetId } from "../../policy/presets.js";
13
+ import { LAYERED_POLICY_PRESET_IDS } from "../../policy/compose.js";
14
+ import { PolicyValidator } from "../../policy/validate.js";
15
+ import { parsePolicyRemoteValidateResponse, policyRemoteValidateResultToDict, policyValidateQueryString, } from "../../policy/validate-remote.js";
16
+ import { PaybondPolicyValidationError } from "../../policy/schema.js";
17
+ import { consumeBooleanFlag, consumeFlag, parseOptionalNonNegativeInt } from "../globals.js";
18
+ import { CliError } from "../types.js";
19
+ import { resolve } from "node:path";
20
+ async function readJsonFile(path) {
21
+ return readJsonBody(path, process.stdin);
22
+ }
23
+ async function resolvePolicyValidateToolsMode(ctx, flags) {
24
+ if (flags.remote && flags.localOnly) {
25
+ throw new CliError("policy validate-tools: --remote and --local-only are mutually exclusive", {
26
+ category: "usage",
27
+ code: "cli.usage.conflicting_flags",
28
+ });
29
+ }
30
+ if (flags.localOnly) {
31
+ return "local";
32
+ }
33
+ if (flags.remote) {
34
+ return "remote";
35
+ }
36
+ if (flags.checkGateway) {
37
+ return "check_gateway";
38
+ }
39
+ const credentials = await describeCredentialSource(ctx.globals, ctx.cwd);
40
+ return credentials.source === "missing" ? "local" : "remote";
41
+ }
42
+ function gatewayPolicyRemoteValidateClient(gateway) {
43
+ return {
44
+ async validatePolicy(document, options) {
45
+ const qs = policyValidateQueryString(options ?? {});
46
+ const body = await gateway.postJson(`/v1/policy/validate${qs}`, document);
47
+ return parsePolicyRemoteValidateResponse(body);
48
+ },
49
+ };
50
+ }
51
+ async function runPolicyValidateTools(ctx, path, mode, strict, resolveInheritance) {
52
+ if (mode === "remote") {
53
+ const clientFactory = gatewayPolicyRemoteValidateClient;
54
+ const wrapped = await withGateway(ctx, async (gateway) => {
55
+ const client = clientFactory(gateway);
56
+ if (resolveInheritance) {
57
+ const report = await PaybondPolicy.validateOverlayRemote(path, client, { strict });
58
+ return { data: report };
59
+ }
60
+ const policy = await PaybondPolicy.load(path);
61
+ const report = await policy.validateRemote(client, { strict });
62
+ return { data: report };
63
+ });
64
+ return wrapped.data;
65
+ }
66
+ if (mode === "check_gateway") {
67
+ const wrapped = await withGateway(ctx, async (gateway) => {
68
+ const report = await PolicyValidator.validate(path, {
69
+ strict,
70
+ checkGateway: true,
71
+ gateway: {
72
+ async listTemplateIds() {
73
+ const body = await gateway.getJson("/harbor/policy/v1/templates");
74
+ const rows = Array.isArray(body) ? body : Array.isArray(body.templates) ? body.templates : [];
75
+ return rows
76
+ .map((row) => row && typeof row === "object" && !Array.isArray(row)
77
+ ? String(row.template_id ?? "")
78
+ : "")
79
+ .filter((id) => id.length > 0);
80
+ },
81
+ },
82
+ });
83
+ return { data: report };
84
+ });
85
+ return wrapped.data;
86
+ }
87
+ return PolicyValidator.validate(path, { strict });
88
+ }
89
+ function policyValidateToolsPayload(report) {
90
+ if ("local_valid" in report) {
91
+ return policyRemoteValidateResultToDict(report);
92
+ }
93
+ return {
94
+ valid: report.valid,
95
+ policy_name: report.policy_name,
96
+ tools: report.tools,
97
+ errors: report.errors,
98
+ };
99
+ }
100
+ export async function handlePolicyPresetsList(_ctx, argv) {
101
+ if (argv.length > 0 && argv[0] !== "--help" && argv[0] !== "-h") {
102
+ throw new CliError(`unexpected arguments: ${argv.join(" ")}`, {
103
+ category: "usage",
104
+ code: "cli.usage.unexpected_args",
105
+ });
106
+ }
107
+ return { data: listPolicyPresetsCatalog() };
108
+ }
109
+ export async function handlePolicyPresetsShow(ctx, argv) {
110
+ let rest = argv;
111
+ const presetFlag = consumeFlag(rest, "--preset");
112
+ rest = presetFlag.rest;
113
+ const maxSpendFlag = consumeFlag(rest, "--max-spend");
114
+ rest = maxSpendFlag.rest;
115
+ const domainFlag = consumeFlag(rest, "--domain");
116
+ rest = domainFlag.rest;
117
+ const guardrailsFlag = consumeFlag(rest, "--guardrails");
118
+ rest = guardrailsFlag.rest;
119
+ let positionalPreset;
120
+ if (!presetFlag.value && rest.length === 1 && !rest[0].startsWith("-")) {
121
+ positionalPreset = rest[0].trim();
122
+ rest = [];
123
+ }
124
+ if (rest.length > 0) {
125
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
126
+ category: "usage",
127
+ code: "cli.usage.unexpected_args",
128
+ });
129
+ }
130
+ let maxSpendUsd;
131
+ if (maxSpendFlag.value !== undefined) {
132
+ const parsed = parseOptionalNonNegativeInt(maxSpendFlag.value, "--max-spend");
133
+ if (parsed === undefined) {
134
+ throw new CliError("invalid --max-spend", {
135
+ category: "usage",
136
+ code: "cli.usage.invalid_amount",
137
+ });
138
+ }
139
+ maxSpendUsd = parsed;
140
+ }
141
+ if (domainFlag.value) {
142
+ const domainId = domainFlag.value.trim();
143
+ if (!LAYERED_POLICY_PRESET_IDS.includes(domainId)) {
144
+ throw new CliError(`unknown policy domain: ${domainId}`, {
145
+ category: "validation",
146
+ code: "cli.policy.domain_invalid",
147
+ exitCode: 3,
148
+ });
149
+ }
150
+ if (!guardrailsFlag.value) {
151
+ throw new CliError("policy presets show --domain requires --guardrails", {
152
+ category: "usage",
153
+ code: "cli.usage.missing_args",
154
+ });
155
+ }
156
+ if (presetFlag.value) {
157
+ throw new CliError("policy presets show: --preset cannot be combined with --domain", {
158
+ category: "usage",
159
+ code: "cli.usage.conflicting_flags",
160
+ });
161
+ }
162
+ try {
163
+ const yaml = renderComposedPolicyPreviewYaml({
164
+ domainId: domainId,
165
+ guardrails: guardrailsFlag.value,
166
+ });
167
+ const yamlLines = yaml.split(/\r?\n/);
168
+ return {
169
+ data: {
170
+ domain: domainId,
171
+ guardrails: guardrailsFlag.value,
172
+ yaml,
173
+ yaml_lines: yamlLines,
174
+ },
175
+ };
176
+ }
177
+ catch (err) {
178
+ const message = err instanceof Error ? err.message : String(err);
179
+ throw new CliError(message, {
180
+ category: "validation",
181
+ code: "cli.policy.presets_show_failed",
182
+ exitCode: 3,
183
+ });
184
+ }
185
+ }
186
+ const presetId = (presetFlag.value ?? positionalPreset ?? "").trim();
187
+ if (!presetId) {
188
+ throw new CliError("policy presets show requires a preset id or --preset", {
189
+ category: "usage",
190
+ code: "cli.usage.missing_args",
191
+ });
192
+ }
193
+ if (guardrailsFlag.value) {
194
+ throw new CliError("policy presets show: --guardrails requires --domain", {
195
+ category: "usage",
196
+ code: "cli.usage.conflicting_flags",
197
+ });
198
+ }
199
+ if (!isKnownPolicyPresetId(presetId)) {
200
+ throw new CliError(`unknown policy preset: ${presetId}`, {
201
+ category: "validation",
202
+ code: "cli.policy.preset_invalid",
203
+ exitCode: 3,
204
+ });
205
+ }
206
+ const yaml = renderPolicyPresetPreviewYaml(presetId, { maxSpendUsd });
207
+ const yamlLines = yaml.split(/\r?\n/);
208
+ return {
209
+ data: {
210
+ preset: presetId,
211
+ ...(maxSpendUsd !== undefined ? { max_spend_usd: maxSpendUsd } : {}),
212
+ yaml,
213
+ yaml_lines: yamlLines,
214
+ },
215
+ };
216
+ }
217
+ export async function handlePolicyInit(ctx, argv) {
218
+ let rest = argv;
219
+ const outFlag = consumeFlag(rest, "--out");
220
+ rest = outFlag.rest;
221
+ const presetFlag = consumeFlag(rest, "--preset");
222
+ rest = presetFlag.rest;
223
+ const domainFlag = consumeFlag(rest, "--domain");
224
+ rest = domainFlag.rest;
225
+ const guardrailsFlag = consumeFlag(rest, "--guardrails");
226
+ rest = guardrailsFlag.rest;
227
+ const maxSpendFlag = consumeFlag(rest, "--max-spend");
228
+ rest = maxSpendFlag.rest;
229
+ const operationFlag = consumeFlag(rest, "--operation");
230
+ rest = operationFlag.rest;
231
+ const evidencePresetFlag = consumeFlag(rest, "--evidence-preset");
232
+ rest = evidencePresetFlag.rest;
233
+ const forceFlag = consumeBooleanFlag(rest, "--force");
234
+ rest = forceFlag.rest;
235
+ if (rest.length > 0) {
236
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
237
+ category: "usage",
238
+ code: "cli.usage.unexpected_args",
239
+ });
240
+ }
241
+ const out = resolve(ctx.cwd, outFlag.value ?? "paybond.policy.yaml");
242
+ let maxSpendUsd;
243
+ if (maxSpendFlag.value !== undefined) {
244
+ const parsed = parseOptionalNonNegativeInt(maxSpendFlag.value, "--max-spend");
245
+ if (parsed === undefined) {
246
+ throw new CliError("invalid --max-spend", {
247
+ category: "usage",
248
+ code: "cli.usage.invalid_amount",
249
+ });
250
+ }
251
+ maxSpendUsd = parsed;
252
+ }
253
+ if (domainFlag.value) {
254
+ const domainId = domainFlag.value.trim();
255
+ if (!LAYERED_POLICY_PRESET_IDS.includes(domainId)) {
256
+ throw new CliError(`unknown policy domain: ${domainId}`, {
257
+ category: "validation",
258
+ code: "cli.policy.domain_invalid",
259
+ exitCode: 3,
260
+ });
261
+ }
262
+ if (!guardrailsFlag.value) {
263
+ throw new CliError("policy init --domain requires --guardrails", {
264
+ category: "usage",
265
+ code: "cli.usage.missing_args",
266
+ });
267
+ }
268
+ if (presetFlag.value || operationFlag.value || evidencePresetFlag.value || maxSpendUsd !== undefined) {
269
+ throw new CliError("policy init --domain cannot be combined with --preset, --operation, --evidence-preset, or --max-spend", { category: "usage", code: "cli.usage.conflicting_flags" });
270
+ }
271
+ try {
272
+ const result = await scaffoldComposedPolicy({
273
+ out,
274
+ domainId: domainId,
275
+ guardrails: guardrailsFlag.value,
276
+ force: forceFlag.present,
277
+ });
278
+ return { data: result };
279
+ }
280
+ catch (err) {
281
+ const message = err instanceof Error ? err.message : String(err);
282
+ throw new CliError(message, {
283
+ category: "validation",
284
+ code: "cli.policy.init_failed",
285
+ exitCode: 3,
286
+ });
287
+ }
288
+ }
289
+ if (guardrailsFlag.value) {
290
+ throw new CliError("policy init --guardrails requires --domain", {
291
+ category: "usage",
292
+ code: "cli.usage.missing_args",
293
+ });
294
+ }
295
+ if (presetFlag.value) {
296
+ const presetId = presetFlag.value.trim();
297
+ if (!isKnownPolicyPresetId(presetId)) {
298
+ throw new CliError(`unknown policy preset: ${presetId}`, {
299
+ category: "validation",
300
+ code: "cli.policy.preset_invalid",
301
+ exitCode: 3,
302
+ });
303
+ }
304
+ if (operationFlag.value || evidencePresetFlag.value) {
305
+ throw new CliError("policy init: --preset cannot be combined with --operation or --evidence-preset", { category: "usage", code: "cli.usage.conflicting_flags" });
306
+ }
307
+ try {
308
+ const result = await scaffoldPolicyFromPreset({
309
+ out,
310
+ presetId,
311
+ maxSpendUsd,
312
+ force: forceFlag.present,
313
+ });
314
+ return { data: result };
315
+ }
316
+ catch (err) {
317
+ const message = err instanceof Error ? err.message : String(err);
318
+ throw new CliError(message, {
319
+ category: "validation",
320
+ code: "cli.policy.init_failed",
321
+ exitCode: 3,
322
+ });
323
+ }
324
+ }
325
+ if (maxSpendUsd !== undefined) {
326
+ throw new CliError("policy init --max-spend requires --preset", {
327
+ category: "usage",
328
+ code: "cli.usage.missing_args",
329
+ });
330
+ }
331
+ const operation = operationFlag.value ?? "travel.book_hotel";
332
+ const evidencePreset = evidencePresetFlag.value ?? "cost_and_completion";
333
+ try {
334
+ const result = await scaffoldPaybondPolicy({
335
+ out,
336
+ operation,
337
+ evidencePreset,
338
+ force: forceFlag.present,
339
+ });
340
+ return { data: result };
341
+ }
342
+ catch (err) {
343
+ const message = err instanceof Error ? err.message : String(err);
344
+ throw new CliError(message, {
345
+ category: err instanceof PaybondPolicyValidationError ? "validation" : "validation",
346
+ code: "cli.policy.init_failed",
347
+ exitCode: 3,
348
+ });
349
+ }
350
+ }
351
+ export async function handlePolicyInitOrg(ctx, argv) {
352
+ let rest = argv;
353
+ const outFlag = consumeFlag(rest, "--out");
354
+ rest = outFlag.rest;
355
+ const policyIdFlag = consumeFlag(rest, "--policy-id");
356
+ rest = policyIdFlag.rest;
357
+ const operationFlag = consumeFlag(rest, "--operation");
358
+ rest = operationFlag.rest;
359
+ const presetFlag = consumeFlag(rest, "--evidence-preset");
360
+ rest = presetFlag.rest;
361
+ const maxSpendFlag = consumeFlag(rest, "--max-spend-cents");
362
+ rest = maxSpendFlag.rest;
363
+ const forceFlag = consumeBooleanFlag(rest, "--force");
364
+ rest = forceFlag.rest;
365
+ if (rest.length > 0) {
366
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
367
+ category: "usage",
368
+ code: "cli.usage.unexpected_args",
369
+ });
370
+ }
371
+ if (!policyIdFlag.value) {
372
+ throw new CliError("policy init-org requires --policy-id", {
373
+ category: "usage",
374
+ code: "cli.usage.missing_args",
375
+ });
376
+ }
377
+ const policyId = policyIdFlag.value;
378
+ const out = resolve(ctx.cwd, outFlag.value ?? `${policyId}.yaml`);
379
+ let maxSpendCents;
380
+ if (maxSpendFlag.value !== undefined) {
381
+ const parsed = parseOptionalNonNegativeInt(maxSpendFlag.value, "--max-spend-cents");
382
+ if (parsed === undefined) {
383
+ throw new CliError("invalid --max-spend-cents", {
384
+ category: "usage",
385
+ code: "cli.usage.invalid_amount_cents",
386
+ });
387
+ }
388
+ maxSpendCents = parsed;
389
+ }
390
+ try {
391
+ const result = await scaffoldOrgBasePolicy({
392
+ out,
393
+ policyId,
394
+ operation: operationFlag.value ?? "travel.book_hotel",
395
+ evidencePreset: presetFlag.value ?? "cost_and_completion",
396
+ maxSpendCents,
397
+ force: forceFlag.present,
398
+ });
399
+ return { data: result };
400
+ }
401
+ catch (err) {
402
+ const message = err instanceof Error ? err.message : String(err);
403
+ throw new CliError(message, {
404
+ category: "validation",
405
+ code: "cli.policy.init_org_failed",
406
+ exitCode: 3,
407
+ });
408
+ }
409
+ }
410
+ export async function handlePolicyExtend(ctx, argv) {
411
+ let rest = argv;
412
+ const extendsFlag = consumeFlag(rest, "--extends");
413
+ rest = extendsFlag.rest;
414
+ const outFlag = consumeFlag(rest, "--out");
415
+ rest = outFlag.rest;
416
+ const nameFlag = consumeFlag(rest, "--name");
417
+ rest = nameFlag.rest;
418
+ const operationFlag = consumeFlag(rest, "--operation");
419
+ rest = operationFlag.rest;
420
+ const presetFlag = consumeFlag(rest, "--evidence-preset");
421
+ rest = presetFlag.rest;
422
+ const basePolicyFlag = consumeFlag(rest, "--base-policy");
423
+ rest = basePolicyFlag.rest;
424
+ const forceFlag = consumeBooleanFlag(rest, "--force");
425
+ rest = forceFlag.rest;
426
+ if (rest.length > 0) {
427
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
428
+ category: "usage",
429
+ code: "cli.usage.unexpected_args",
430
+ });
431
+ }
432
+ if (!extendsFlag.value) {
433
+ throw new CliError("policy extend requires --extends org_id/org_policy_id", {
434
+ category: "usage",
435
+ code: "cli.usage.missing_args",
436
+ });
437
+ }
438
+ const out = resolve(ctx.cwd, outFlag.value ?? "paybond.policy.yaml");
439
+ try {
440
+ const result = await scaffoldTenantOverlayPolicy({
441
+ out,
442
+ extendsRef: extendsFlag.value,
443
+ name: nameFlag.value,
444
+ operation: operationFlag.value,
445
+ evidencePreset: presetFlag.value,
446
+ basePolicy: basePolicyFlag.value,
447
+ force: forceFlag.present,
448
+ });
449
+ return { data: result };
450
+ }
451
+ catch (err) {
452
+ const message = err instanceof Error ? err.message : String(err);
453
+ throw new CliError(message, {
454
+ category: "validation",
455
+ code: "cli.policy.extend_failed",
456
+ exitCode: 3,
457
+ });
458
+ }
459
+ }
460
+ export async function handlePolicyValidateTools(ctx, argv) {
461
+ let rest = argv;
462
+ const fileFlag = consumeFlag(rest, "--file");
463
+ rest = fileFlag.rest;
464
+ const remoteFlag = consumeBooleanFlag(rest, "--remote");
465
+ rest = remoteFlag.rest;
466
+ const localOnlyFlag = consumeBooleanFlag(rest, "--local-only");
467
+ rest = localOnlyFlag.rest;
468
+ const checkGatewayFlag = consumeBooleanFlag(rest, "--check-gateway");
469
+ rest = checkGatewayFlag.rest;
470
+ const strictFlag = consumeBooleanFlag(rest, "--strict");
471
+ rest = strictFlag.rest;
472
+ const resolveInheritanceFlag = consumeBooleanFlag(rest, "--resolve-inheritance");
473
+ rest = resolveInheritanceFlag.rest;
474
+ if (rest.length > 0) {
475
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
476
+ category: "usage",
477
+ code: "cli.usage.unexpected_args",
478
+ });
479
+ }
480
+ if (!fileFlag.value) {
481
+ throw new CliError("policy validate-tools requires --file", {
482
+ category: "usage",
483
+ code: "cli.usage.missing_args",
484
+ });
485
+ }
486
+ const path = resolve(ctx.cwd, fileFlag.value);
487
+ const strict = strictFlag.present || PolicyValidator.isStrictFromEnv();
488
+ const mode = await resolvePolicyValidateToolsMode(ctx, {
489
+ remote: remoteFlag.present,
490
+ localOnly: localOnlyFlag.present,
491
+ checkGateway: checkGatewayFlag.present,
492
+ });
493
+ if (resolveInheritanceFlag.present && mode !== "remote") {
494
+ throw new CliError("policy validate-tools: --resolve-inheritance requires remote validation (use --remote or log in)", {
495
+ category: "usage",
496
+ code: "cli.usage.conflicting_flags",
497
+ });
498
+ }
499
+ const report = await runPolicyValidateTools(ctx, path, mode, strict, resolveInheritanceFlag.present);
500
+ const payload = policyValidateToolsPayload(report);
501
+ if (!report.valid) {
502
+ throw new CliError("policy validation failed", {
503
+ category: "validation",
504
+ code: "cli.policy.validation_failed",
505
+ exitCode: 3,
506
+ details: payload,
507
+ });
508
+ }
509
+ return { data: payload };
510
+ }
511
+ export async function handlePolicyTemplates(_ctx, argv) {
512
+ if (argv.length > 0 && argv[0] !== "--help" && argv[0] !== "-h") {
513
+ throw new CliError(`unexpected arguments: ${argv.join(" ")}`, {
514
+ category: "usage",
515
+ code: "cli.usage.unexpected_args",
516
+ });
517
+ }
518
+ const catalog = loadCompletionCatalog();
519
+ const presets = catalog.presets.map((preset) => ({
520
+ preset_id: preset.preset_id,
521
+ title: preset.title,
522
+ harbor_template_id: preset.harbor_template_id,
523
+ human_summary: preset.human_summary,
524
+ recommended_amount_cents: preset.recommended_amount_cents ?? null,
525
+ kind: preset.kind ?? "archetype",
526
+ archetype_preset_id: preset.archetype_preset_id ?? null,
527
+ scope: preset.scope ?? null,
528
+ rail_hints: preset.rail_hints ?? null,
529
+ deprecated: preset.deprecated ?? false,
530
+ superseded_by: preset.superseded_by ?? null,
531
+ }));
532
+ return { data: { catalog_version: catalog.version, presets } };
533
+ }
534
+ export async function handlePolicyPreview(ctx, argv) {
535
+ let rest = argv;
536
+ const templateFlag = consumeFlag(rest, "--template");
537
+ rest = templateFlag.rest;
538
+ const presetFlag = consumeFlag(rest, "--preset");
539
+ rest = presetFlag.rest;
540
+ const parametersFlag = consumeFlag(rest, "--parameters-file");
541
+ rest = parametersFlag.rest;
542
+ const evidenceFlag = consumeFlag(rest, "--evidence-file");
543
+ rest = evidenceFlag.rest;
544
+ const schemaFlag = consumeFlag(rest, "--schema-file");
545
+ rest = schemaFlag.rest;
546
+ const amountFlag = consumeFlag(rest, "--amount-cents");
547
+ rest = amountFlag.rest;
548
+ if (rest.length > 0) {
549
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
550
+ category: "usage",
551
+ code: "cli.usage.unexpected_args",
552
+ });
553
+ }
554
+ let templateId = templateFlag.value ?? "";
555
+ let catalogPreset = presetFlag.value ? getCompletionPreset(presetFlag.value) : undefined;
556
+ if (!templateId && catalogPreset) {
557
+ templateId = resolveCompletionPreset(catalogPreset.preset_id).harborTemplateId;
558
+ }
559
+ if (!templateId) {
560
+ throw new CliError("policy preview requires --template or --preset", {
561
+ category: "usage",
562
+ code: "cli.usage.missing_args",
563
+ });
564
+ }
565
+ if (!catalogPreset) {
566
+ catalogPreset = getCompletionPresetByTemplateId(templateId);
567
+ }
568
+ let parameters;
569
+ if (parametersFlag.value) {
570
+ parameters = await readJsonFile(parametersFlag.value);
571
+ }
572
+ else if (catalogPreset) {
573
+ parameters = resolveCompletionPreset(catalogPreset.preset_id).parameters;
574
+ }
575
+ else {
576
+ throw new CliError("policy preview requires --parameters-file when template is not in the catalog", {
577
+ category: "usage",
578
+ code: "cli.usage.missing_args",
579
+ });
580
+ }
581
+ if (!evidenceFlag.value) {
582
+ throw new CliError("policy preview requires --evidence-file", {
583
+ category: "usage",
584
+ code: "cli.usage.missing_args",
585
+ });
586
+ }
587
+ const evidence = await readJsonFile(evidenceFlag.value);
588
+ let evidenceSchema;
589
+ if (schemaFlag.value) {
590
+ evidenceSchema = await readJsonFile(schemaFlag.value);
591
+ }
592
+ else if (catalogPreset) {
593
+ evidenceSchema = resolveCompletionPreset(catalogPreset.preset_id).evidenceSchema;
594
+ }
595
+ else {
596
+ throw new CliError("policy preview requires --schema-file when template is not in the catalog", {
597
+ category: "usage",
598
+ code: "cli.usage.missing_args",
599
+ });
600
+ }
601
+ let amountCents;
602
+ if (amountFlag.value !== undefined) {
603
+ const parsed = parseOptionalNonNegativeInt(amountFlag.value, "--amount-cents");
604
+ if (parsed === undefined) {
605
+ throw new CliError("invalid --amount-cents", { category: "usage", code: "cli.usage.invalid_amount_cents" });
606
+ }
607
+ amountCents = parsed;
608
+ }
609
+ else if (catalogPreset?.recommended_amount_cents) {
610
+ amountCents = catalogPreset.recommended_amount_cents;
611
+ }
612
+ else {
613
+ amountCents = 100;
614
+ }
615
+ return withGateway(ctx, async (gateway) => {
616
+ const preview = await gateway.postJson("/harbor/policy/v1/preview", {
617
+ template_id: templateId,
618
+ parameters,
619
+ });
620
+ const test = await gateway.postJson("/harbor/policy/v1/test", {
621
+ template_id: templateId,
622
+ parameters,
623
+ evidence,
624
+ evidence_schema: evidenceSchema,
625
+ amount_cents: amountCents,
626
+ });
627
+ const evaluation = (test.predicate_evaluation ?? {});
628
+ const pass = Boolean(evaluation.passed ?? evaluation.pass ?? evaluation.ok);
629
+ return {
630
+ data: {
631
+ template_id: templateId,
632
+ preset_id: catalogPreset?.preset_id ?? null,
633
+ materialized_dsl: preview.materialized_dsl ?? null,
634
+ human_summary: preview.human_summary ?? null,
635
+ predicate_evaluation: evaluation,
636
+ pass,
637
+ amount_cents: amountCents,
638
+ },
639
+ };
640
+ });
641
+ }
642
+ export async function handlePolicyImportMcpReceipt(ctx, argv) {
643
+ let rest = argv;
644
+ const decisionFlag = consumeFlag(rest, "--decision-file");
645
+ rest = decisionFlag.rest;
646
+ const outcomeFlag = consumeFlag(rest, "--outcome-file");
647
+ rest = outcomeFlag.rest;
648
+ const writeFlag = consumeFlag(rest, "--write-evidence-file");
649
+ rest = writeFlag.rest;
650
+ if (rest.length > 0) {
651
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
652
+ category: "usage",
653
+ code: "cli.usage.unexpected_args",
654
+ });
655
+ }
656
+ if (!decisionFlag.value || !outcomeFlag.value) {
657
+ throw new CliError("policy import-mcp-receipt requires --decision-file and --outcome-file", { category: "usage", code: "cli.usage.missing_args" });
658
+ }
659
+ const decision = await readJsonFile(decisionFlag.value);
660
+ const outcome = await readJsonFile(outcomeFlag.value);
661
+ const evidence = mapSep2828ReceiptsToArtifactAttestedEvidence(decision, outcome);
662
+ const artifactPreset = getCompletionPreset("artifact_attested");
663
+ if (writeFlag.value) {
664
+ const { writeFile } = await import("node:fs/promises");
665
+ await writeFile(writeFlag.value, `${JSON.stringify(evidence, null, 2)}\n`, "utf8");
666
+ }
667
+ return {
668
+ data: {
669
+ preset_id: artifactPreset.preset_id,
670
+ harbor_template_id: artifactPreset.harbor_template_id,
671
+ evidence,
672
+ source: "sep2828_mcp_receipt",
673
+ },
674
+ };
675
+ }
676
+ export async function handlePolicyValidateEvidence(_ctx, argv) {
677
+ let rest = argv;
678
+ const presetFlag = consumeFlag(rest, "--preset");
679
+ rest = presetFlag.rest;
680
+ const vendorFlag = consumeFlag(rest, "--vendor-file");
681
+ rest = vendorFlag.rest;
682
+ const canonicalFlag = consumeFlag(rest, "--canonical-file");
683
+ rest = canonicalFlag.rest;
684
+ const frozenApiFlag = consumeFlag(rest, "--frozen-api-version");
685
+ rest = frozenApiFlag.rest;
686
+ const frozenVendorDigestFlag = consumeFlag(rest, "--frozen-vendor-schema-digest");
687
+ rest = frozenVendorDigestFlag.rest;
688
+ const frozenCanonicalDigestFlag = consumeFlag(rest, "--frozen-canonical-schema-digest");
689
+ rest = frozenCanonicalDigestFlag.rest;
690
+ if (rest.length > 0) {
691
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
692
+ category: "usage",
693
+ code: "cli.usage.unexpected_args",
694
+ });
695
+ }
696
+ if (!presetFlag.value) {
697
+ throw new CliError("policy validate-evidence requires --preset", {
698
+ category: "usage",
699
+ code: "cli.usage.missing_args",
700
+ });
701
+ }
702
+ const preset = getCompletionPreset(presetFlag.value);
703
+ let vendorPayload;
704
+ if (vendorFlag.value) {
705
+ vendorPayload = await readJsonFile(vendorFlag.value);
706
+ }
707
+ let canonicalPayload;
708
+ if (canonicalFlag.value) {
709
+ canonicalPayload = await readJsonFile(canonicalFlag.value);
710
+ }
711
+ if (isVendorPack(preset) && !vendorPayload && !canonicalPayload) {
712
+ throw new CliError("policy validate-evidence requires --vendor-file for vendor_pack presets (or --canonical-file)", { category: "usage", code: "cli.usage.missing_args" });
713
+ }
714
+ if (!isVendorPack(preset) && !vendorPayload && !canonicalPayload) {
715
+ throw new CliError("policy validate-evidence requires --canonical-file or --vendor-file", { category: "usage", code: "cli.usage.missing_args" });
716
+ }
717
+ const report = validateCompletionEvidence({
718
+ presetId: preset.preset_id,
719
+ vendorPayload,
720
+ canonicalPayload,
721
+ frozenVendorApiVersion: frozenApiFlag.value,
722
+ frozenVendorSchemaDigestHex: frozenVendorDigestFlag.value,
723
+ frozenCanonicalSchemaDigestHex: frozenCanonicalDigestFlag.value,
724
+ });
725
+ return {
726
+ data: {
727
+ ...report,
728
+ ok: report.drift_kinds.length === 0,
729
+ },
730
+ };
731
+ }
732
+ export async function handlePolicyImportX402Receipt(ctx, argv) {
733
+ let rest = argv;
734
+ const receiptFlag = consumeFlag(rest, "--receipt-file");
735
+ rest = receiptFlag.rest;
736
+ const writeFlag = consumeFlag(rest, "--write-evidence-file");
737
+ rest = writeFlag.rest;
738
+ if (rest.length > 0) {
739
+ throw new CliError(`unexpected arguments: ${rest.join(" ")}`, {
740
+ category: "usage",
741
+ code: "cli.usage.unexpected_args",
742
+ });
743
+ }
744
+ if (!receiptFlag.value) {
745
+ throw new CliError("policy import-x402-receipt requires --receipt-file", { category: "usage", code: "cli.usage.missing_args" });
746
+ }
747
+ const receipt = await readJsonFile(receiptFlag.value);
748
+ let evidence;
749
+ try {
750
+ evidence = mapX402ReceiptToArtifactAttestedEvidence(receipt);
751
+ }
752
+ catch (err) {
753
+ const message = err instanceof Error ? err.message : String(err);
754
+ throw new CliError(message, { category: "usage", code: "cli.usage.invalid_receipt" });
755
+ }
756
+ const deliveryPreset = getCompletionPreset("x402_delivery_receipt");
757
+ if (writeFlag.value) {
758
+ const { writeFile } = await import("node:fs/promises");
759
+ await writeFile(writeFlag.value, `${JSON.stringify(evidence, null, 2)}\n`, "utf8");
760
+ }
761
+ return {
762
+ data: {
763
+ preset_id: deliveryPreset.preset_id,
764
+ harbor_template_id: deliveryPreset.harbor_template_id,
765
+ evidence,
766
+ source: "x402_receipt_v1",
767
+ },
768
+ };
769
+ }