@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,77 @@
1
+ export function parseMergeReport(value) {
2
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3
+ throw new Error("merge_report must be an object");
4
+ }
5
+ const row = value;
6
+ return {
7
+ org_policy_id: row.org_policy_id == null ? null : String(row.org_policy_id),
8
+ org_id: row.org_id == null ? null : String(row.org_id),
9
+ base_policy_name: String(row.base_policy_name ?? ""),
10
+ overlay_policy_name: row.overlay_policy_name == null ? null : String(row.overlay_policy_name),
11
+ overrides_applied: Array.isArray(row.overrides_applied)
12
+ ? row.overrides_applied.map((item) => String(item))
13
+ : [],
14
+ denied_widenings: Array.isArray(row.denied_widenings)
15
+ ? row.denied_widenings
16
+ .map((item) => {
17
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
18
+ return null;
19
+ }
20
+ const denied = item;
21
+ const path = String(denied.path ?? "");
22
+ const code = String(denied.code ?? "");
23
+ const message = String(denied.message ?? "");
24
+ if (!path || !code || !message) {
25
+ return null;
26
+ }
27
+ return { path, code, message };
28
+ })
29
+ .filter((item) => item !== null)
30
+ : [],
31
+ };
32
+ }
33
+ /** Parse a Gateway org-policy effective resolution JSON body. */
34
+ export function parsePolicyEffectiveResolveResponse(body) {
35
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
36
+ throw new Error("policy effective response must be a JSON object");
37
+ }
38
+ const row = body;
39
+ const digest = String(row.effective_policy_digest ?? "");
40
+ if (!digest) {
41
+ throw new Error("effective_policy_digest is required");
42
+ }
43
+ const version = String(row.effective_policy_version ?? "");
44
+ if (!version) {
45
+ throw new Error("effective_policy_version is required");
46
+ }
47
+ if (row.unchanged === true) {
48
+ return {
49
+ effective_policy: {},
50
+ effective_policy_digest: digest,
51
+ effective_policy_version: version,
52
+ merge_report: parseMergeReport(row.merge_report ?? {}),
53
+ org_base_version_seq: Number(row.org_base_version_seq ?? 0),
54
+ org_base_content_digest: String(row.org_base_content_digest ?? ""),
55
+ unchanged: true,
56
+ };
57
+ }
58
+ const effective = row.effective_policy;
59
+ if (!effective || typeof effective !== "object" || Array.isArray(effective)) {
60
+ throw new Error("effective_policy must be an object");
61
+ }
62
+ return {
63
+ effective_policy: effective,
64
+ effective_policy_digest: digest,
65
+ effective_policy_version: version,
66
+ merge_report: parseMergeReport(row.merge_report),
67
+ org_base_version_seq: Number(row.org_base_version_seq ?? 0),
68
+ org_base_content_digest: String(row.org_base_content_digest ?? ""),
69
+ };
70
+ }
71
+ /** Resolve merged effective policy via Gateway org-policy inheritance endpoint. */
72
+ export async function resolvePolicyEffectiveRemote(overlay, client) {
73
+ if (!overlay.extends?.org_policy_id) {
74
+ throw new Error("overlay must declare extends.org_policy_id");
75
+ }
76
+ return client.resolvePolicyEffective(overlay.extends.org_policy_id, overlay);
77
+ }
@@ -0,0 +1,85 @@
1
+ import type { PaybondToolRegistry } from "../agent/registry.js";
2
+ import { type PaybondPolicyIntentCreateInput, type PaybondPolicyIntentCreateOverrides } from "./intent-spec.js";
3
+ import { type PolicyMergeOptions, type PolicyMergeResult } from "./merge.js";
4
+ import { type PaybondPolicyDocument, type PaybondPolicyDocumentV1 } from "./schema.js";
5
+ import { type PaybondPolicySandboxBootstrapOptions } from "./sandbox-bootstrap.js";
6
+ import { type PolicyValidatorOptions, type PolicyValidatorResult } from "./validate.js";
7
+ import { type PolicyRemoteValidateClient, type PolicyRemoteValidateOptions, type PolicyRemoteValidateResult } from "./validate-remote.js";
8
+ import { type PolicyEffectiveResolveClient } from "./load-effective.js";
9
+ import type { PaybondRunBindingSandboxBootstrapInput } from "../agent/types.js";
10
+ export type PaybondPolicyLoadEffectiveResult = {
11
+ policy: PaybondPolicy;
12
+ report: PolicyMergeResult["report"];
13
+ effectivePolicyDigest: string;
14
+ effectivePolicyVersion: string;
15
+ orgBaseVersionSeq: number;
16
+ orgBaseContentDigest: string;
17
+ unchanged?: boolean;
18
+ };
19
+ export type PaybondPolicyLoadSource = string | PaybondPolicyDocumentV1 | PaybondPolicyDocument | Record<string, unknown>;
20
+ /**
21
+ * Portable policy-as-code document loaded from `paybond.policy.yaml` or an in-memory object.
22
+ * Drives tool registry construction and production intent create alignment.
23
+ */
24
+ export declare class PaybondPolicy {
25
+ readonly document: PaybondPolicyDocumentV1;
26
+ readonly source?: string;
27
+ private constructor();
28
+ /** Policy name from the document (`name` field). */
29
+ get name(): string;
30
+ /** Whether unregistered side-effecting tools should fail closed at intercept time. */
31
+ get defaultDeny(): boolean;
32
+ /** Optional intent section from the policy file. */
33
+ get intent(): PaybondPolicyDocumentV1["intent"];
34
+ /**
35
+ * Load and validate a policy from a file path or pre-parsed document object.
36
+ * File paths accept JSON (`.json`) or YAML (`.yaml` / `.yml`).
37
+ */
38
+ static load(source: PaybondPolicyLoadSource): Promise<PaybondPolicy>;
39
+ private static resolveEffectiveDocument;
40
+ /**
41
+ * Resolve merged effective policy via Gateway org-policy inheritance.
42
+ * Production tenants should prefer this over {@link mergeLocal}.
43
+ */
44
+ static loadEffective(options: {
45
+ overlay: PaybondPolicyLoadSource;
46
+ gateway: PolicyEffectiveResolveClient;
47
+ }): Promise<PaybondPolicyLoadEffectiveResult>;
48
+ /** Synchronous variant for pre-parsed effective (v1) document objects only. */
49
+ static fromDocument(document: PaybondPolicyDocumentV1): PaybondPolicy;
50
+ /**
51
+ * Offline merge of org base + tenant overlay into an effective v1 policy.
52
+ * Best-effort for CI; production should use Gateway effective resolution.
53
+ */
54
+ static mergeLocal(options: {
55
+ base: PaybondPolicyLoadSource;
56
+ overlay: PaybondPolicyLoadSource;
57
+ merge?: PolicyMergeOptions;
58
+ }): Promise<PolicyMergeResult & {
59
+ policy: PaybondPolicy;
60
+ }>;
61
+ private static loadDocument;
62
+ /** Load a raw overlay document payload for server-side inheritance validation. */
63
+ static loadOverlayPayload(source: PaybondPolicyLoadSource): Promise<Record<string, unknown>>;
64
+ /**
65
+ * Validate a tenant overlay with server-side org-base merge
66
+ * (`POST /v1/policy/validate?resolve_inheritance=1`).
67
+ */
68
+ static validateOverlayRemote(overlay: PaybondPolicyLoadSource, gateway: PolicyRemoteValidateClient, options?: PolicyRemoteValidateOptions): Promise<PolicyRemoteValidateResult>;
69
+ /** Build the tool registry consumed by agent middleware. */
70
+ toToolRegistry(): PaybondToolRegistry;
71
+ /**
72
+ * Build params for {@link PaybondIntents.createWithPolicyBinding} from policy intent alignment
73
+ * plus caller signing context and a published managed-policy head.
74
+ */
75
+ toIntentCreateInput(overrides: PaybondPolicyIntentCreateOverrides): PaybondPolicyIntentCreateInput;
76
+ /** Run client-side alignment checks (registry, presets, optional gateway template lookup). */
77
+ validate(options?: PolicyValidatorOptions): Promise<PolicyValidatorResult>;
78
+ /**
79
+ * Validate this policy against the tenant-scoped Gateway registry (`POST /v1/policy/validate`).
80
+ * Requires a logged-in Gateway Harbor client from `paybond.open()`.
81
+ */
82
+ validateRemote(gateway: PolicyRemoteValidateClient, options?: PolicyRemoteValidateOptions): Promise<PolicyRemoteValidateResult>;
83
+ /** Build sandbox bootstrap input for {@link PaybondAgentRun.bind} from this policy. */
84
+ sandboxBootstrap(options?: PaybondPolicySandboxBootstrapOptions): PaybondRunBindingSandboxBootstrapInput;
85
+ }
@@ -0,0 +1,164 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { policyToIntentCreateInput, } from "./intent-spec.js";
4
+ import { mergePaybondPolicies, toEffectivePolicyDocument, } from "./merge.js";
5
+ import { parsePolicyDocumentText } from "./parse-text.js";
6
+ import { policyToToolRegistry } from "./registry.js";
7
+ import { isPaybondPolicyDocumentV2, isPaybondPolicyOverlay, parsePaybondPolicyDocument, parsePaybondPolicyDocumentV1, } from "./schema.js";
8
+ import { policySandboxBootstrap, } from "./sandbox-bootstrap.js";
9
+ import { PolicyValidator } from "./validate.js";
10
+ import { validatePolicyRemote, validatePolicyPayloadRemote, } from "./validate-remote.js";
11
+ import { resolvePolicyEffectiveRemote, } from "./load-effective.js";
12
+ /**
13
+ * Portable policy-as-code document loaded from `paybond.policy.yaml` or an in-memory object.
14
+ * Drives tool registry construction and production intent create alignment.
15
+ */
16
+ export class PaybondPolicy {
17
+ document;
18
+ source;
19
+ constructor(document, source) {
20
+ this.document = document;
21
+ this.source = source;
22
+ }
23
+ /** Policy name from the document (`name` field). */
24
+ get name() {
25
+ return this.document.name;
26
+ }
27
+ /** Whether unregistered side-effecting tools should fail closed at intercept time. */
28
+ get defaultDeny() {
29
+ return this.document.default_deny;
30
+ }
31
+ /** Optional intent section from the policy file. */
32
+ get intent() {
33
+ return this.document.intent;
34
+ }
35
+ /**
36
+ * Load and validate a policy from a file path or pre-parsed document object.
37
+ * File paths accept JSON (`.json`) or YAML (`.yaml` / `.yml`).
38
+ */
39
+ static async load(source) {
40
+ if (typeof source === "string") {
41
+ const document = await PaybondPolicy.loadDocument(source);
42
+ const effective = await PaybondPolicy.resolveEffectiveDocument(document, source);
43
+ return new PaybondPolicy(effective, source);
44
+ }
45
+ const document = parsePaybondPolicyDocument(source);
46
+ const effective = await PaybondPolicy.resolveEffectiveDocument(document);
47
+ return new PaybondPolicy(effective);
48
+ }
49
+ static async resolveEffectiveDocument(document, sourcePath) {
50
+ if (isPaybondPolicyDocumentV2(document) && isPaybondPolicyOverlay(document)) {
51
+ const basePath = document.extends?.base_policy;
52
+ if (!basePath) {
53
+ return toEffectivePolicyDocument(document);
54
+ }
55
+ const resolvedBase = sourcePath
56
+ ? resolve(dirname(sourcePath), basePath)
57
+ : basePath;
58
+ const baseDoc = await PaybondPolicy.loadDocument(resolvedBase);
59
+ return mergePaybondPolicies(baseDoc, document).effective;
60
+ }
61
+ return toEffectivePolicyDocument(document);
62
+ }
63
+ /**
64
+ * Resolve merged effective policy via Gateway org-policy inheritance.
65
+ * Production tenants should prefer this over {@link mergeLocal}.
66
+ */
67
+ static async loadEffective(options) {
68
+ const overlayDoc = await PaybondPolicy.loadDocument(options.overlay);
69
+ if (!isPaybondPolicyDocumentV2(overlayDoc) || !isPaybondPolicyOverlay(overlayDoc)) {
70
+ throw new Error("overlay must be a v2 tenant policy with extends");
71
+ }
72
+ const resolved = await resolvePolicyEffectiveRemote(overlayDoc, options.gateway);
73
+ const effective = parsePaybondPolicyDocumentV1(resolved.effective_policy);
74
+ return {
75
+ policy: PaybondPolicy.fromDocument(effective),
76
+ report: resolved.merge_report,
77
+ effectivePolicyDigest: resolved.effective_policy_digest,
78
+ effectivePolicyVersion: resolved.effective_policy_version,
79
+ orgBaseVersionSeq: resolved.org_base_version_seq,
80
+ orgBaseContentDigest: resolved.org_base_content_digest,
81
+ ...(resolved.unchanged ? { unchanged: true } : {}),
82
+ };
83
+ }
84
+ /** Synchronous variant for pre-parsed effective (v1) document objects only. */
85
+ static fromDocument(document) {
86
+ return new PaybondPolicy(document);
87
+ }
88
+ /**
89
+ * Offline merge of org base + tenant overlay into an effective v1 policy.
90
+ * Best-effort for CI; production should use Gateway effective resolution.
91
+ */
92
+ static async mergeLocal(options) {
93
+ const baseDoc = await PaybondPolicy.loadDocument(options.base);
94
+ const overlayDoc = await PaybondPolicy.loadDocument(options.overlay);
95
+ if (!isPaybondPolicyDocumentV2(overlayDoc) || !isPaybondPolicyOverlay(overlayDoc)) {
96
+ throw new Error("overlay must be a v2 tenant policy with extends");
97
+ }
98
+ const merged = mergePaybondPolicies(baseDoc, overlayDoc, options.merge);
99
+ return {
100
+ ...merged,
101
+ policy: PaybondPolicy.fromDocument(merged.effective),
102
+ };
103
+ }
104
+ static async loadDocument(source) {
105
+ if (typeof source === "string") {
106
+ const text = await readFile(source, "utf8");
107
+ const raw = parsePolicyDocumentText(text, source);
108
+ return parsePaybondPolicyDocument(raw);
109
+ }
110
+ return parsePaybondPolicyDocument(source);
111
+ }
112
+ /** Load a raw overlay document payload for server-side inheritance validation. */
113
+ static async loadOverlayPayload(source) {
114
+ if (typeof source === "string") {
115
+ const text = await readFile(source, "utf8");
116
+ const raw = parsePolicyDocumentText(text, source);
117
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
118
+ throw new Error("overlay must be a JSON or YAML object");
119
+ }
120
+ return raw;
121
+ }
122
+ if (typeof source === "object" && source !== null && !Array.isArray(source)) {
123
+ return source;
124
+ }
125
+ throw new Error("overlay must be a file path or raw overlay object");
126
+ }
127
+ /**
128
+ * Validate a tenant overlay with server-side org-base merge
129
+ * (`POST /v1/policy/validate?resolve_inheritance=1`).
130
+ */
131
+ static async validateOverlayRemote(overlay, gateway, options) {
132
+ const payload = await PaybondPolicy.loadOverlayPayload(overlay);
133
+ return validatePolicyPayloadRemote(payload, gateway, {
134
+ ...options,
135
+ resolveInheritance: true,
136
+ });
137
+ }
138
+ /** Build the tool registry consumed by agent middleware. */
139
+ toToolRegistry() {
140
+ return policyToToolRegistry(this.document);
141
+ }
142
+ /**
143
+ * Build params for {@link PaybondIntents.createWithPolicyBinding} from policy intent alignment
144
+ * plus caller signing context and a published managed-policy head.
145
+ */
146
+ toIntentCreateInput(overrides) {
147
+ return policyToIntentCreateInput(this.document, overrides);
148
+ }
149
+ /** Run client-side alignment checks (registry, presets, optional gateway template lookup). */
150
+ validate(options) {
151
+ return PolicyValidator.validateDocument(this.document, options);
152
+ }
153
+ /**
154
+ * Validate this policy against the tenant-scoped Gateway registry (`POST /v1/policy/validate`).
155
+ * Requires a logged-in Gateway Harbor client from `paybond.open()`.
156
+ */
157
+ validateRemote(gateway, options) {
158
+ return validatePolicyRemote(this.document, gateway, options);
159
+ }
160
+ /** Build sandbox bootstrap input for {@link PaybondAgentRun.bind} from this policy. */
161
+ sandboxBootstrap(options = {}) {
162
+ return policySandboxBootstrap(this.document, options);
163
+ }
164
+ }
@@ -0,0 +1,29 @@
1
+ import { type PaybondPolicyDocument, type PaybondPolicyDocumentV1, type PaybondPolicyDocumentV2 } from "./schema.js";
2
+ export type PolicyMergeDeniedWidening = {
3
+ path: string;
4
+ code: string;
5
+ message: string;
6
+ };
7
+ export type PolicyMergeReport = {
8
+ org_policy_id: string | null;
9
+ org_id: string | null;
10
+ base_policy_name: string;
11
+ overlay_policy_name: string | null;
12
+ overrides_applied: string[];
13
+ denied_widenings: PolicyMergeDeniedWidening[];
14
+ };
15
+ export type PolicyMergeResult = {
16
+ effective: PaybondPolicyDocumentV1;
17
+ report: PolicyMergeReport;
18
+ };
19
+ export type PolicyMergeOptions = {
20
+ /** When set, tenant evidence_preset swaps must stay within this catalog subset. */
21
+ approvedEvidencePresets?: readonly string[];
22
+ };
23
+ /**
24
+ * Deterministically merge an org base policy with a tenant overlay.
25
+ * Returns a v1 effective document suitable for middleware and validation.
26
+ */
27
+ export declare function mergePaybondPolicies(base: PaybondPolicyDocumentV1 | PaybondPolicyDocumentV2, overlay: PaybondPolicyDocumentV2, options?: PolicyMergeOptions): PolicyMergeResult;
28
+ /** Normalize any supported policy document to a flat v1 effective document. */
29
+ export declare function toEffectivePolicyDocument(document: PaybondPolicyDocument): PaybondPolicyDocumentV1;
@@ -0,0 +1,297 @@
1
+ import { PaybondPolicyValidationError, PAYBOND_POLICY_SCHEMA_VERSION, isPaybondPolicyDocumentV1, isPaybondPolicyOverlay, } from "./schema.js";
2
+ function cloneToolEntry(entry) {
3
+ return { ...entry };
4
+ }
5
+ function mergeStricterDefaultDeny(...values) {
6
+ return values.some((value) => value === true);
7
+ }
8
+ function mergeToolFields(base, patch, toolName, report, denied) {
9
+ const merged = cloneToolEntry(base);
10
+ if (patch.side_effecting !== undefined) {
11
+ if (base.side_effecting && patch.side_effecting === false) {
12
+ denied.push({
13
+ path: `tools.${toolName}.side_effecting`,
14
+ code: "policy.cannot_disable_org_side_effecting_tool",
15
+ message: `cannot disable org-required side-effecting tool "${toolName}"`,
16
+ });
17
+ }
18
+ else {
19
+ merged.side_effecting = patch.side_effecting;
20
+ report.overrides_applied.push(`tools.${toolName}.side_effecting`);
21
+ }
22
+ }
23
+ if (patch.max_spend_cents !== undefined) {
24
+ if (base.max_spend_cents !== undefined &&
25
+ patch.max_spend_cents > base.max_spend_cents) {
26
+ denied.push({
27
+ path: `tools.${toolName}.max_spend_cents`,
28
+ code: "policy.cannot_raise_spend_cap",
29
+ message: `tenant max_spend_cents (${patch.max_spend_cents}) exceeds org cap (${base.max_spend_cents})`,
30
+ });
31
+ }
32
+ else {
33
+ merged.max_spend_cents = patch.max_spend_cents;
34
+ report.overrides_applied.push(`tools.${toolName}.max_spend_cents`);
35
+ }
36
+ }
37
+ if (patch.spend_from_args !== undefined) {
38
+ if (base.max_spend_cents !== undefined) {
39
+ denied.push({
40
+ path: `tools.${toolName}.spend_from_args`,
41
+ code: "policy.cannot_override_org_spend_mode",
42
+ message: `cannot replace org max_spend_cents with spend_from_args on "${toolName}"`,
43
+ });
44
+ }
45
+ else {
46
+ merged.spend_from_args = patch.spend_from_args;
47
+ delete merged.max_spend_cents;
48
+ report.overrides_applied.push(`tools.${toolName}.spend_from_args`);
49
+ }
50
+ }
51
+ if (patch.evidence_preset !== undefined) {
52
+ if (patch.evidence_preset !== base.evidence_preset &&
53
+ report.org_policy_id !== null) {
54
+ // Structural check only; catalog membership is validated downstream.
55
+ report.overrides_applied.push(`tools.${toolName}.evidence_preset`);
56
+ }
57
+ merged.evidence_preset = patch.evidence_preset;
58
+ }
59
+ if (patch.vendor_pack !== undefined) {
60
+ merged.vendor_pack = patch.vendor_pack;
61
+ report.overrides_applied.push(`tools.${toolName}.vendor_pack`);
62
+ }
63
+ if (patch.operation !== undefined) {
64
+ merged.operation = patch.operation;
65
+ report.overrides_applied.push(`tools.${toolName}.operation`);
66
+ }
67
+ if (merged.side_effecting && !merged.evidence_preset) {
68
+ denied.push({
69
+ path: `tools.${toolName}.evidence_preset`,
70
+ code: "policy.missing_evidence_preset",
71
+ message: `side-effecting tool "${toolName}" must declare evidence_preset after merge`,
72
+ });
73
+ }
74
+ if (merged.max_spend_cents !== undefined &&
75
+ merged.spend_from_args !== undefined) {
76
+ denied.push({
77
+ path: `tools.${toolName}`,
78
+ code: "policy.conflicting_spend_fields",
79
+ message: "max_spend_cents and spend_from_args are mutually exclusive",
80
+ });
81
+ }
82
+ return merged;
83
+ }
84
+ function mergePolicyBinding(base, overlay, override, denied, report) {
85
+ if (!base && !overlay && !override) {
86
+ return undefined;
87
+ }
88
+ const templateId = override?.template_id ?? overlay?.template_id ?? base?.template_id;
89
+ if (!templateId) {
90
+ return undefined;
91
+ }
92
+ const merged = { template_id: templateId };
93
+ const overlayTemplate = overlay?.template_id ?? override?.template_id;
94
+ if (base?.template_id && overlayTemplate && overlayTemplate !== base.template_id) {
95
+ denied.push({
96
+ path: "intent.policy_binding.template_id",
97
+ code: "policy.cannot_change_org_template",
98
+ message: `tenant template_id "${overlayTemplate}" must match org template "${base.template_id}"`,
99
+ });
100
+ }
101
+ const versionSeq = override?.version_seq ?? overlay?.version_seq ?? base?.version_seq;
102
+ if (versionSeq !== undefined) {
103
+ if (base?.version_seq !== undefined && versionSeq < base.version_seq) {
104
+ denied.push({
105
+ path: "intent.policy_binding.version_seq",
106
+ code: "policy.cannot_downgrade_template_version",
107
+ message: `tenant version_seq (${versionSeq}) is older than org version_seq (${base.version_seq})`,
108
+ });
109
+ }
110
+ else {
111
+ merged.version_seq = versionSeq;
112
+ if (override?.version_seq !== undefined) {
113
+ report.overrides_applied.push("intent.policy_binding.version_seq");
114
+ }
115
+ }
116
+ }
117
+ const headDigest = override?.head_digest ?? overlay?.head_digest ?? base?.head_digest;
118
+ if (headDigest !== undefined) {
119
+ if (base?.head_digest && headDigest !== base.head_digest) {
120
+ denied.push({
121
+ path: "intent.policy_binding.head_digest",
122
+ code: "policy.cannot_change_org_head_digest",
123
+ message: "tenant head_digest must match the org-pinned template head",
124
+ });
125
+ }
126
+ else {
127
+ merged.head_digest = headDigest;
128
+ if (override?.head_digest !== undefined) {
129
+ report.overrides_applied.push("intent.policy_binding.head_digest");
130
+ }
131
+ }
132
+ }
133
+ return merged;
134
+ }
135
+ function mergeBudget(base, overlay, override, denied, report) {
136
+ const merged = {
137
+ ...(base ?? {}),
138
+ ...(overlay ?? {}),
139
+ ...(override ?? {}),
140
+ };
141
+ if (!merged || Object.keys(merged).length === 0) {
142
+ return undefined;
143
+ }
144
+ const orgMax = base?.max_spend_usd;
145
+ const tenantMax = override?.max_spend_usd ?? overlay?.max_spend_usd;
146
+ if (orgMax !== undefined && tenantMax !== undefined && tenantMax > orgMax) {
147
+ denied.push({
148
+ path: "intent.budget.max_spend_usd",
149
+ code: "policy.cannot_raise_budget_cap",
150
+ message: `tenant max_spend_usd (${tenantMax}) exceeds org cap (${orgMax})`,
151
+ });
152
+ }
153
+ else if (override?.max_spend_usd !== undefined) {
154
+ report.overrides_applied.push("intent.budget.max_spend_usd");
155
+ }
156
+ return merged;
157
+ }
158
+ function intersectAllowedTools(orgAllowed, tenantAllowed, denied, report) {
159
+ if (!tenantAllowed || tenantAllowed.length === 0) {
160
+ return orgAllowed;
161
+ }
162
+ if (!orgAllowed || orgAllowed.length === 0) {
163
+ return tenantAllowed;
164
+ }
165
+ const orgSet = new Set(orgAllowed);
166
+ const widened = tenantAllowed.filter((tool) => !orgSet.has(tool));
167
+ if (widened.length > 0) {
168
+ denied.push({
169
+ path: "intent.allowed_tools",
170
+ code: "policy.cannot_widen_allowed_tools",
171
+ message: `tenant allowed_tools widens org allowlist: ${widened.join(", ")}`,
172
+ });
173
+ }
174
+ const intersection = tenantAllowed.filter((tool) => orgSet.has(tool));
175
+ if (intersection.length !== tenantAllowed.length) {
176
+ report.overrides_applied.push("intent.allowed_tools");
177
+ }
178
+ return intersection;
179
+ }
180
+ function baseDocumentToEffectiveV1(document) {
181
+ return {
182
+ version: PAYBOND_POLICY_SCHEMA_VERSION,
183
+ name: document.name,
184
+ default_deny: document.default_deny,
185
+ tools: Object.fromEntries(Object.entries(document.tools).map(([toolName, entry]) => [toolName, cloneToolEntry(entry)])),
186
+ intent: document.intent ? structuredClone(document.intent) : undefined,
187
+ };
188
+ }
189
+ function assertOverlay(document) {
190
+ if (!isPaybondPolicyOverlay(document)) {
191
+ throw new PaybondPolicyValidationError("merge requires a tenant overlay document with extends", [{ path: "extends", code: "required", message: "extends is required for overlay merge" }]);
192
+ }
193
+ }
194
+ /**
195
+ * Deterministically merge an org base policy with a tenant overlay.
196
+ * Returns a v1 effective document suitable for middleware and validation.
197
+ */
198
+ export function mergePaybondPolicies(base, overlay, options = {}) {
199
+ assertOverlay(overlay);
200
+ const denied = [];
201
+ const report = {
202
+ org_policy_id: overlay.extends.org_policy_id,
203
+ org_id: overlay.extends.org_id,
204
+ base_policy_name: base.name,
205
+ overlay_policy_name: overlay.name,
206
+ overrides_applied: [],
207
+ denied_widenings: [],
208
+ };
209
+ const effective = baseDocumentToEffectiveV1(base);
210
+ effective.name = overlay.name;
211
+ effective.default_deny = mergeStricterDefaultDeny(base.default_deny, overlay.default_deny, overlay.overrides?.default_deny);
212
+ if (overlay.overrides?.default_deny !== undefined) {
213
+ report.overrides_applied.push("overrides.default_deny");
214
+ }
215
+ for (const [toolName, patch] of Object.entries(overlay.overrides?.tools ?? {})) {
216
+ const existing = effective.tools[toolName];
217
+ if (!existing) {
218
+ denied.push({
219
+ path: `overrides.tools.${toolName}`,
220
+ code: "policy.unknown_org_tool_override",
221
+ message: `cannot override unknown org tool "${toolName}"`,
222
+ });
223
+ continue;
224
+ }
225
+ effective.tools[toolName] = mergeToolFields(existing, patch, toolName, report, denied);
226
+ }
227
+ for (const [toolName, entry] of Object.entries(overlay.tools)) {
228
+ if (effective.tools[toolName]) {
229
+ denied.push({
230
+ path: `tools.${toolName}`,
231
+ code: "policy.cannot_replace_org_tool",
232
+ message: `tenant tools must append new entries; "${toolName}" already exists in org base`,
233
+ });
234
+ continue;
235
+ }
236
+ effective.tools[toolName] = cloneToolEntry(entry);
237
+ }
238
+ const orgAllowed = base.intent?.allowed_tools;
239
+ const tenantAllowed = overlay.overrides?.intent?.allowed_tools ?? overlay.intent?.allowed_tools;
240
+ const mergedAllowed = intersectAllowedTools(orgAllowed, tenantAllowed, denied, report);
241
+ if (!overlay.intent && !overlay.overrides?.intent) {
242
+ effective.intent = base.intent ? structuredClone(base.intent) : undefined;
243
+ if (mergedAllowed && effective.intent) {
244
+ effective.intent.allowed_tools = mergedAllowed;
245
+ }
246
+ }
247
+ else {
248
+ const mergedBinding = mergePolicyBinding(base.intent?.policy_binding, overlay.intent?.policy_binding, overlay.overrides?.intent?.policy_binding, denied, report);
249
+ const mergedBudget = mergeBudget(base.intent?.budget, overlay.intent?.budget, overlay.overrides?.intent?.budget, denied, report);
250
+ if (mergedBinding || mergedBudget || mergedAllowed) {
251
+ effective.intent = {
252
+ ...(mergedBinding ? { policy_binding: mergedBinding } : {}),
253
+ ...(mergedBudget ? { budget: mergedBudget } : {}),
254
+ ...(mergedAllowed ? { allowed_tools: mergedAllowed } : {}),
255
+ };
256
+ }
257
+ else if (base.intent) {
258
+ effective.intent = structuredClone(base.intent);
259
+ }
260
+ }
261
+ if (options.approvedEvidencePresets) {
262
+ const approved = new Set(options.approvedEvidencePresets);
263
+ for (const [toolName, entry] of Object.entries(effective.tools)) {
264
+ if (!entry.side_effecting || !entry.evidence_preset) {
265
+ continue;
266
+ }
267
+ const basePreset = base.tools[toolName]?.evidence_preset;
268
+ if (basePreset && entry.evidence_preset !== basePreset && !approved.has(entry.evidence_preset)) {
269
+ denied.push({
270
+ path: `tools.${toolName}.evidence_preset`,
271
+ code: "policy.evidence_preset_not_org_approved",
272
+ message: `evidence preset "${entry.evidence_preset}" is not in the org-approved catalog subset`,
273
+ });
274
+ }
275
+ }
276
+ }
277
+ report.denied_widenings = denied;
278
+ if (denied.length > 0) {
279
+ const summary = denied.map((item) => `${item.path}: ${item.message}`).join("; ");
280
+ throw new PaybondPolicyValidationError(summary, denied.map((item) => ({
281
+ path: item.path,
282
+ code: item.code,
283
+ message: item.message,
284
+ })));
285
+ }
286
+ return { effective, report };
287
+ }
288
+ /** Normalize any supported policy document to a flat v1 effective document. */
289
+ export function toEffectivePolicyDocument(document) {
290
+ if (isPaybondPolicyDocumentV1(document)) {
291
+ return baseDocumentToEffectiveV1(document);
292
+ }
293
+ if (isPaybondPolicyOverlay(document)) {
294
+ throw new PaybondPolicyValidationError("tenant overlay requires merge with an org base policy before use", [{ path: "extends", code: "merge_required", message: "resolve inheritance before producing effective policy" }]);
295
+ }
296
+ return baseDocumentToEffectiveV1(document);
297
+ }
@@ -0,0 +1,2 @@
1
+ /** Parse policy file text (JSON or YAML) into a raw document object. */
2
+ export declare function parsePolicyDocumentText(text: string, sourceLabel?: string): Record<string, unknown>;