@sentropic/h2a 0.85.25 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/dist/bin.js +51 -2
  4. package/dist/bin.js.map +1 -1
  5. package/dist/cli-command-map.d.ts +119 -0
  6. package/dist/cli-command-map.d.ts.map +1 -0
  7. package/dist/cli-command-map.js +396 -0
  8. package/dist/cli-command-map.js.map +1 -0
  9. package/dist/cli-contract.d.ts.map +1 -1
  10. package/dist/cli-contract.js +39 -1
  11. package/dist/cli-contract.js.map +1 -1
  12. package/dist/cli.d.ts +25 -1
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +356 -7
  15. package/dist/cli.js.map +1 -1
  16. package/dist/identity.d.ts +37 -3
  17. package/dist/identity.d.ts.map +1 -1
  18. package/dist/identity.js +0 -0
  19. package/dist/identity.js.map +1 -1
  20. package/dist/index.d.ts +7 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +9 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/runtime/enrollment/ceremony.d.ts +542 -0
  25. package/dist/runtime/enrollment/ceremony.d.ts.map +1 -0
  26. package/dist/runtime/enrollment/ceremony.js +777 -0
  27. package/dist/runtime/enrollment/ceremony.js.map +1 -0
  28. package/dist/runtime/enrollment/index.d.ts +16 -0
  29. package/dist/runtime/enrollment/index.d.ts.map +1 -0
  30. package/dist/runtime/enrollment/index.js +16 -0
  31. package/dist/runtime/enrollment/index.js.map +1 -0
  32. package/dist/runtime/feed/descriptors.d.ts +261 -0
  33. package/dist/runtime/feed/descriptors.d.ts.map +1 -0
  34. package/dist/runtime/feed/descriptors.js +425 -0
  35. package/dist/runtime/feed/descriptors.js.map +1 -0
  36. package/dist/runtime/feed/index.d.ts +12 -0
  37. package/dist/runtime/feed/index.d.ts.map +1 -0
  38. package/dist/runtime/feed/index.js +12 -0
  39. package/dist/runtime/feed/index.js.map +1 -0
  40. package/dist/runtime/identity/index.d.ts +3 -3
  41. package/dist/runtime/identity/index.d.ts.map +1 -1
  42. package/dist/runtime/identity/index.js +2 -2
  43. package/dist/runtime/identity/index.js.map +1 -1
  44. package/dist/runtime/identity/live.d.ts +68 -0
  45. package/dist/runtime/identity/live.d.ts.map +1 -1
  46. package/dist/runtime/identity/live.js +78 -2
  47. package/dist/runtime/identity/live.js.map +1 -1
  48. package/dist/runtime/identity/readers.d.ts +89 -5
  49. package/dist/runtime/identity/readers.d.ts.map +1 -1
  50. package/dist/runtime/identity/readers.js +242 -33
  51. package/dist/runtime/identity/readers.js.map +1 -1
  52. package/dist/runtime/local-files/presence.d.ts +16 -1
  53. package/dist/runtime/local-files/presence.d.ts.map +1 -1
  54. package/dist/runtime/local-files/presence.js +32 -20
  55. package/dist/runtime/local-files/presence.js.map +1 -1
  56. package/dist/runtime/loop/index.d.ts +5 -0
  57. package/dist/runtime/loop/index.d.ts.map +1 -1
  58. package/dist/runtime/loop/index.js +48 -5
  59. package/dist/runtime/loop/index.js.map +1 -1
  60. package/dist/runtime/mcp/agent-launch.d.ts +15 -1
  61. package/dist/runtime/mcp/agent-launch.d.ts.map +1 -1
  62. package/dist/runtime/mcp/agent-launch.js +45 -4
  63. package/dist/runtime/mcp/agent-launch.js.map +1 -1
  64. package/dist/runtime/mcp/index.d.ts +1 -1
  65. package/dist/runtime/mcp/index.d.ts.map +1 -1
  66. package/dist/runtime/mcp/index.js +1 -1
  67. package/dist/runtime/mcp/index.js.map +1 -1
  68. package/dist/runtime/mcp/server.d.ts +3 -1
  69. package/dist/runtime/mcp/server.d.ts.map +1 -1
  70. package/dist/runtime/mcp/server.js +7 -2
  71. package/dist/runtime/mcp/server.js.map +1 -1
  72. package/dist/runtime/mcp/sessions.d.ts +19 -0
  73. package/dist/runtime/mcp/sessions.d.ts.map +1 -1
  74. package/dist/runtime/mcp/sessions.js +44 -2
  75. package/dist/runtime/mcp/sessions.js.map +1 -1
  76. package/dist/runtime/mcp/stdio.d.ts +8 -0
  77. package/dist/runtime/mcp/stdio.d.ts.map +1 -1
  78. package/dist/runtime/mcp/stdio.js +42 -0
  79. package/dist/runtime/mcp/stdio.js.map +1 -1
  80. package/dist/runtime/mcp-registry/broker.d.ts +175 -0
  81. package/dist/runtime/mcp-registry/broker.d.ts.map +1 -0
  82. package/dist/runtime/mcp-registry/broker.js +203 -0
  83. package/dist/runtime/mcp-registry/broker.js.map +1 -0
  84. package/dist/runtime/mcp-registry/broker.typecheck.d.ts +2 -0
  85. package/dist/runtime/mcp-registry/broker.typecheck.d.ts.map +1 -0
  86. package/dist/runtime/mcp-registry/broker.typecheck.js +48 -0
  87. package/dist/runtime/mcp-registry/broker.typecheck.js.map +1 -0
  88. package/dist/runtime/mirror/accept.d.ts +43 -5
  89. package/dist/runtime/mirror/accept.d.ts.map +1 -1
  90. package/dist/runtime/mirror/accept.js +55 -7
  91. package/dist/runtime/mirror/accept.js.map +1 -1
  92. package/dist/runtime/mirror/build.d.ts +23 -4
  93. package/dist/runtime/mirror/build.d.ts.map +1 -1
  94. package/dist/runtime/mirror/build.js +34 -4
  95. package/dist/runtime/mirror/build.js.map +1 -1
  96. package/dist/runtime/mirror/index.d.ts +3 -0
  97. package/dist/runtime/mirror/index.d.ts.map +1 -1
  98. package/dist/runtime/mirror/index.js +3 -0
  99. package/dist/runtime/mirror/index.js.map +1 -1
  100. package/dist/runtime/mirror/ingest.d.ts +109 -0
  101. package/dist/runtime/mirror/ingest.d.ts.map +1 -0
  102. package/dist/runtime/mirror/ingest.js +117 -0
  103. package/dist/runtime/mirror/ingest.js.map +1 -0
  104. package/dist/runtime/mirror/push-daemon.d.ts +376 -0
  105. package/dist/runtime/mirror/push-daemon.d.ts.map +1 -0
  106. package/dist/runtime/mirror/push-daemon.js +644 -0
  107. package/dist/runtime/mirror/push-daemon.js.map +1 -0
  108. package/dist/runtime/mirror/sanitize.d.ts +477 -0
  109. package/dist/runtime/mirror/sanitize.d.ts.map +1 -0
  110. package/dist/runtime/mirror/sanitize.js +625 -0
  111. package/dist/runtime/mirror/sanitize.js.map +1 -0
  112. package/dist/runtime/mirror/serve.d.ts.map +1 -1
  113. package/dist/runtime/mirror/serve.js +104 -24
  114. package/dist/runtime/mirror/serve.js.map +1 -1
  115. package/dist/runtime/reporting/report-ai.d.ts.map +1 -1
  116. package/dist/runtime/reporting/report-ai.js +1 -0
  117. package/dist/runtime/reporting/report-ai.js.map +1 -1
  118. package/dist/runtime/reporting/stdin.d.ts +2 -0
  119. package/dist/runtime/reporting/stdin.d.ts.map +1 -0
  120. package/dist/runtime/reporting/stdin.js +8 -0
  121. package/dist/runtime/reporting/stdin.js.map +1 -0
  122. package/dist/status-surface.d.ts +167 -0
  123. package/dist/status-surface.d.ts.map +1 -0
  124. package/dist/status-surface.js +670 -0
  125. package/dist/status-surface.js.map +1 -0
  126. package/dist/types.d.ts +17 -0
  127. package/dist/types.d.ts.map +1 -1
  128. package/dist/types.js +3 -0
  129. package/dist/types.js.map +1 -1
  130. package/dist/vendor/harness/skills/manifest.d.ts.map +1 -1
  131. package/dist/vendor/harness/skills/manifest.js +2 -0
  132. package/dist/vendor/harness/skills/manifest.js.map +1 -1
  133. package/focus-app/client/_app/immutable/assets/{0.BdzHFb9q.css → 0.CgEVz9YW.css} +1 -1
  134. package/focus-app/client/_app/immutable/assets/0.CgEVz9YW.css.br +0 -0
  135. package/focus-app/client/_app/immutable/assets/0.CgEVz9YW.css.gz +0 -0
  136. package/focus-app/client/_app/immutable/assets/2.DaTmt6o7.css +1 -0
  137. package/focus-app/client/_app/immutable/assets/2.DaTmt6o7.css.br +0 -0
  138. package/focus-app/client/_app/immutable/assets/2.DaTmt6o7.css.gz +0 -0
  139. package/focus-app/client/_app/immutable/assets/3.vWQUAHjz.css +1 -0
  140. package/focus-app/client/_app/immutable/assets/3.vWQUAHjz.css.br +0 -0
  141. package/focus-app/client/_app/immutable/assets/3.vWQUAHjz.css.gz +0 -0
  142. package/focus-app/client/_app/immutable/assets/AppShell.CDPwj3zU.css +1 -0
  143. package/focus-app/client/_app/immutable/assets/AppShell.CDPwj3zU.css.br +0 -0
  144. package/focus-app/client/_app/immutable/assets/AppShell.CDPwj3zU.css.gz +0 -0
  145. package/focus-app/client/_app/immutable/chunks/{Cj6wo28J.js → 1NK_OeRJ.js} +1 -1
  146. package/focus-app/client/_app/immutable/chunks/1NK_OeRJ.js.br +0 -0
  147. package/focus-app/client/_app/immutable/chunks/1NK_OeRJ.js.gz +0 -0
  148. package/focus-app/client/_app/immutable/chunks/{Bs3f1UbD.js → B1veta3r.js} +2 -2
  149. package/focus-app/client/_app/immutable/chunks/B1veta3r.js.br +0 -0
  150. package/focus-app/client/_app/immutable/chunks/B1veta3r.js.gz +0 -0
  151. package/focus-app/client/_app/immutable/chunks/{DEmooz0s.js → BZ4lcC0v.js} +1 -1
  152. package/focus-app/client/_app/immutable/chunks/BZ4lcC0v.js.br +0 -0
  153. package/focus-app/client/_app/immutable/chunks/BZ4lcC0v.js.gz +0 -0
  154. package/focus-app/client/_app/immutable/chunks/Bu7F9NOv.js +2 -0
  155. package/focus-app/client/_app/immutable/chunks/Bu7F9NOv.js.br +0 -0
  156. package/focus-app/client/_app/immutable/chunks/Bu7F9NOv.js.gz +0 -0
  157. package/focus-app/client/_app/immutable/chunks/C6KhNEX3.js +1 -0
  158. package/focus-app/client/_app/immutable/chunks/C6KhNEX3.js.br +0 -0
  159. package/focus-app/client/_app/immutable/chunks/C6KhNEX3.js.gz +0 -0
  160. package/focus-app/client/_app/immutable/chunks/DIljKPJN.js +1 -0
  161. package/focus-app/client/_app/immutable/chunks/DIljKPJN.js.br +0 -0
  162. package/focus-app/client/_app/immutable/chunks/DIljKPJN.js.gz +0 -0
  163. package/focus-app/client/_app/immutable/chunks/iXQate3J.js +2 -0
  164. package/focus-app/client/_app/immutable/chunks/iXQate3J.js.br +0 -0
  165. package/focus-app/client/_app/immutable/chunks/iXQate3J.js.gz +0 -0
  166. package/focus-app/client/_app/immutable/chunks/{ZxFklh9T.js → kCE9wz0g.js} +1 -1
  167. package/focus-app/client/_app/immutable/chunks/kCE9wz0g.js.br +0 -0
  168. package/focus-app/client/_app/immutable/chunks/kCE9wz0g.js.gz +0 -0
  169. package/focus-app/client/_app/immutable/chunks/x-hq5fDG.js +1 -0
  170. package/focus-app/client/_app/immutable/chunks/x-hq5fDG.js.br +0 -0
  171. package/focus-app/client/_app/immutable/chunks/x-hq5fDG.js.gz +0 -0
  172. package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js +2 -0
  173. package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js.br +0 -0
  174. package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js.gz +0 -0
  175. package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js +1 -0
  176. package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js.br +2 -0
  177. package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js.gz +0 -0
  178. package/focus-app/client/_app/immutable/nodes/0.gLl44WzG.js +5 -0
  179. package/focus-app/client/_app/immutable/nodes/0.gLl44WzG.js.br +0 -0
  180. package/focus-app/client/_app/immutable/nodes/0.gLl44WzG.js.gz +0 -0
  181. package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js +1 -0
  182. package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js.br +0 -0
  183. package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js.gz +0 -0
  184. package/focus-app/client/_app/immutable/nodes/2.Bp7JE7Pz.js +1 -0
  185. package/focus-app/client/_app/immutable/nodes/2.Bp7JE7Pz.js.br +0 -0
  186. package/focus-app/client/_app/immutable/nodes/2.Bp7JE7Pz.js.gz +0 -0
  187. package/focus-app/client/_app/immutable/nodes/3.Cml8enOG.js +12 -0
  188. package/focus-app/client/_app/immutable/nodes/3.Cml8enOG.js.br +0 -0
  189. package/focus-app/client/_app/immutable/nodes/3.Cml8enOG.js.gz +0 -0
  190. package/focus-app/client/_app/version.json +1 -1
  191. package/focus-app/client/_app/version.json.br +0 -0
  192. package/focus-app/client/_app/version.json.gz +0 -0
  193. package/focus-app/h2a-focus.json +108 -80
  194. package/focus-app/handler.js +7 -7
  195. package/focus-app/index.js +7 -7
  196. package/focus-app/server/chunks/chunks/AppShell.js-6Pi87dO0.js +1353 -0
  197. package/focus-app/server/chunks/chunks/AppShell.js-6Pi87dO0.js.map +1 -0
  198. package/focus-app/server/chunks/chunks/agent-memory-dossier.js-nmFG_rgx.js +1036 -0
  199. package/focus-app/server/chunks/chunks/agent-memory-dossier.js-nmFG_rgx.js.map +1 -0
  200. package/focus-app/server/chunks/chunks/{exports.js-DUTkELZq.js → exports.js-CdqPbjm1.js} +3 -3
  201. package/focus-app/server/chunks/chunks/{exports.js-DUTkELZq.js.map → exports.js-CdqPbjm1.js.map} +1 -1
  202. package/focus-app/server/chunks/chunks/h2a-bus.js-bLEJ_Adi.js +233 -0
  203. package/focus-app/server/chunks/chunks/h2a-bus.js-bLEJ_Adi.js.map +1 -0
  204. package/focus-app/server/chunks/chunks/{index.js-Di21TltP.js → index.js-laGHLarB.js} +5 -2
  205. package/focus-app/server/chunks/chunks/index.js-laGHLarB.js.map +1 -0
  206. package/focus-app/server/chunks/chunks/{internal.js-33vbd70h.js → internal.js-C6T8nHkl.js} +4 -4
  207. package/focus-app/server/chunks/chunks/{internal.js-33vbd70h.js.map → internal.js-C6T8nHkl.js.map} +1 -1
  208. package/focus-app/server/chunks/chunks/{root.js-DO1m-gJA.js → root.js-CtVQOgDw.js} +2 -2
  209. package/focus-app/server/chunks/chunks/{root.js-DO1m-gJA.js.map → root.js-CtVQOgDw.js.map} +1 -1
  210. package/focus-app/server/chunks/entries/endpoints/api/decisions/inject/{_server.ts.js-j0NNcOSZ.js → _server.ts.js-hrbMnsV0.js} +13 -42
  211. package/focus-app/server/chunks/entries/endpoints/api/decisions/inject/_server.ts.js-hrbMnsV0.js.map +1 -0
  212. package/focus-app/server/chunks/entries/endpoints/api/dossiers/agent-memory/include/_server.ts.js-Dw4odGdV.js +138 -0
  213. package/focus-app/server/chunks/entries/endpoints/api/dossiers/agent-memory/include/_server.ts.js-Dw4odGdV.js.map +1 -0
  214. package/focus-app/server/chunks/entries/endpoints/api/h2a/targets/_server.ts.js-BLjYv7vg.js +41 -0
  215. package/focus-app/server/chunks/entries/endpoints/api/h2a/targets/_server.ts.js-BLjYv7vg.js.map +1 -0
  216. package/focus-app/server/chunks/entries/fallbacks/{error.svelte.js-Dj3sETSX.js → error.svelte.js-RbeaNF5a.js} +4 -4
  217. package/focus-app/server/chunks/entries/fallbacks/{error.svelte.js-Dj3sETSX.js.map → error.svelte.js-RbeaNF5a.js.map} +1 -1
  218. package/focus-app/server/chunks/entries/pages/{_layout.svelte.js-BoLsbuC2.js → _layout.svelte.js-e1E_I04z.js} +2 -2
  219. package/focus-app/server/chunks/entries/pages/{_layout.svelte.js-BoLsbuC2.js.map → _layout.svelte.js-e1E_I04z.js.map} +1 -1
  220. package/focus-app/server/chunks/entries/pages/{_page.svelte.js-QDldMYhk.js → _page.svelte.js-DbaEG23x.js} +31 -1373
  221. package/focus-app/server/chunks/entries/pages/_page.svelte.js-DbaEG23x.js.map +1 -0
  222. package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.server.ts.js-CFC-wn6U.js +88 -0
  223. package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.server.ts.js-CFC-wn6U.js.map +1 -0
  224. package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.svelte.js-BpR26NMa.js +1574 -0
  225. package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.svelte.js-BpR26NMa.js.map +1 -0
  226. package/focus-app/server/chunks/{handler-Cp_5hLyY.js → handler-Be3dyNi0.js} +3 -3
  227. package/focus-app/server/chunks/{handler-Cp_5hLyY.js.map → handler-Be3dyNi0.js.map} +1 -1
  228. package/focus-app/server/chunks/{index.js-CBh7Wjqp.js → index.js-siUxMMnK.js} +3 -3
  229. package/focus-app/server/chunks/{index.js-CBh7Wjqp.js.map → index.js-siUxMMnK.js.map} +1 -1
  230. package/focus-app/server/chunks/manifest.js-CXJqSHHn.js +78 -0
  231. package/focus-app/server/chunks/manifest.js-CXJqSHHn.js.map +1 -0
  232. package/focus-app/server/chunks/nodes/0.js-leU6sfRR.js +9 -0
  233. package/focus-app/server/chunks/nodes/{0.js-4wlmdsk8.js.map → 0.js-leU6sfRR.js.map} +1 -1
  234. package/focus-app/server/chunks/nodes/1.js-os6QXm6B.js +9 -0
  235. package/focus-app/server/chunks/nodes/{1.js-B-LpY-lC.js.map → 1.js-os6QXm6B.js.map} +1 -1
  236. package/focus-app/server/chunks/nodes/2.js-DAaLjh93.js +19 -0
  237. package/focus-app/server/chunks/nodes/2.js-DAaLjh93.js.map +1 -0
  238. package/focus-app/server/chunks/nodes/3.js-Cmgi6Uy0.js +18 -0
  239. package/focus-app/server/chunks/nodes/3.js-Cmgi6Uy0.js.map +1 -0
  240. package/package.json +5 -5
  241. package/skills/h2a-run/SKILL.md +100 -0
  242. package/skills/harness/SKILL.md +3 -1
  243. package/skills/harness/review/SKILL.md +99 -8
  244. package/skills/harness/security/SKILL.md +55 -0
  245. package/skills/harness/track-report/SKILL.md +103 -0
  246. package/skills/harness/using-harness/SKILL.md +3 -1
  247. package/focus-app/client/_app/immutable/assets/0.BdzHFb9q.css.br +0 -2
  248. package/focus-app/client/_app/immutable/assets/0.BdzHFb9q.css.gz +0 -0
  249. package/focus-app/client/_app/immutable/assets/2.Ddxq02y4.css +0 -1
  250. package/focus-app/client/_app/immutable/assets/2.Ddxq02y4.css.br +0 -0
  251. package/focus-app/client/_app/immutable/assets/2.Ddxq02y4.css.gz +0 -0
  252. package/focus-app/client/_app/immutable/chunks/Bs3f1UbD.js.br +0 -0
  253. package/focus-app/client/_app/immutable/chunks/Bs3f1UbD.js.gz +0 -0
  254. package/focus-app/client/_app/immutable/chunks/Bv8OL8ib.js +0 -1
  255. package/focus-app/client/_app/immutable/chunks/Bv8OL8ib.js.br +0 -0
  256. package/focus-app/client/_app/immutable/chunks/Bv8OL8ib.js.gz +0 -0
  257. package/focus-app/client/_app/immutable/chunks/CVq_IFFr.js +0 -2
  258. package/focus-app/client/_app/immutable/chunks/CVq_IFFr.js.br +0 -0
  259. package/focus-app/client/_app/immutable/chunks/CVq_IFFr.js.gz +0 -0
  260. package/focus-app/client/_app/immutable/chunks/Cj6wo28J.js.br +0 -0
  261. package/focus-app/client/_app/immutable/chunks/Cj6wo28J.js.gz +0 -0
  262. package/focus-app/client/_app/immutable/chunks/DEmooz0s.js.br +0 -0
  263. package/focus-app/client/_app/immutable/chunks/DEmooz0s.js.gz +0 -0
  264. package/focus-app/client/_app/immutable/chunks/DQIRXgdC.js +0 -2
  265. package/focus-app/client/_app/immutable/chunks/DQIRXgdC.js.br +0 -0
  266. package/focus-app/client/_app/immutable/chunks/DQIRXgdC.js.gz +0 -0
  267. package/focus-app/client/_app/immutable/chunks/ZxFklh9T.js.br +0 -0
  268. package/focus-app/client/_app/immutable/chunks/ZxFklh9T.js.gz +0 -0
  269. package/focus-app/client/_app/immutable/chunks/_wRuVGPs.js +0 -1
  270. package/focus-app/client/_app/immutable/chunks/_wRuVGPs.js.br +0 -0
  271. package/focus-app/client/_app/immutable/chunks/_wRuVGPs.js.gz +0 -0
  272. package/focus-app/client/_app/immutable/entry/app.6DKouWRt.js +0 -2
  273. package/focus-app/client/_app/immutable/entry/app.6DKouWRt.js.br +0 -0
  274. package/focus-app/client/_app/immutable/entry/app.6DKouWRt.js.gz +0 -0
  275. package/focus-app/client/_app/immutable/entry/start.DlLmkUb7.js +0 -1
  276. package/focus-app/client/_app/immutable/entry/start.DlLmkUb7.js.br +0 -2
  277. package/focus-app/client/_app/immutable/entry/start.DlLmkUb7.js.gz +0 -0
  278. package/focus-app/client/_app/immutable/nodes/0.CuSOF0Of.js +0 -5
  279. package/focus-app/client/_app/immutable/nodes/0.CuSOF0Of.js.br +0 -0
  280. package/focus-app/client/_app/immutable/nodes/0.CuSOF0Of.js.gz +0 -0
  281. package/focus-app/client/_app/immutable/nodes/1.D39jdnqm.js +0 -1
  282. package/focus-app/client/_app/immutable/nodes/1.D39jdnqm.js.br +0 -0
  283. package/focus-app/client/_app/immutable/nodes/1.D39jdnqm.js.gz +0 -0
  284. package/focus-app/client/_app/immutable/nodes/2.CnU8ifRl.js +0 -1
  285. package/focus-app/client/_app/immutable/nodes/2.CnU8ifRl.js.br +0 -0
  286. package/focus-app/client/_app/immutable/nodes/2.CnU8ifRl.js.gz +0 -0
  287. package/focus-app/server/chunks/chunks/index.js-Di21TltP.js.map +0 -1
  288. package/focus-app/server/chunks/entries/endpoints/api/decisions/inject/_server.ts.js-j0NNcOSZ.js.map +0 -1
  289. package/focus-app/server/chunks/entries/pages/_page.svelte.js-QDldMYhk.js.map +0 -1
  290. package/focus-app/server/chunks/manifest.js-Cm6cC7mC.js +0 -56
  291. package/focus-app/server/chunks/manifest.js-Cm6cC7mC.js.map +0 -1
  292. package/focus-app/server/chunks/nodes/0.js-4wlmdsk8.js +0 -9
  293. package/focus-app/server/chunks/nodes/1.js-B-LpY-lC.js +0 -9
  294. package/focus-app/server/chunks/nodes/2.js-F6jp5eD9.js +0 -19
  295. package/focus-app/server/chunks/nodes/2.js-F6jp5eD9.js.map +0 -1
@@ -0,0 +1,542 @@
1
+ import type { H2ASignature } from "../../types.js";
2
+ /**
3
+ * THE NONCE BRACKET — four bounds, each labelled with what it is FOR.
4
+ * =================================================================
5
+ *
6
+ * The general form, which is the correction to the first draft of this contract:
7
+ * **a positive specification does not mean a single value — it means every
8
+ * accepted-set boundary is stated, and each one says what it is for.** A floor
9
+ * that protects strength and a ceiling that protects against blobs are different
10
+ * parameters and must not be described in the same breath. The first attempt
11
+ * specified `fixed ~43`, which pinned an issuer that DOES NOT EXIST YET to an
12
+ * entropy choice made on its behalf: if the auth lane later picks 384 or 512 bits
13
+ * — the *safer* choice — a fixed verifier turns their improvement into our
14
+ * outage.
15
+ *
16
+ * 1. {@link H2A_ENROLLMENT_NONCE_PATTERN} — alphabet base64url.
17
+ * **POSITIVE, SECURITY-BEARING.**
18
+ * 2. {@link H2A_ENROLLMENT_NONCE_MIN_BITS} / {@link H2A_ENROLLMENT_NONCE_MIN_LENGTH}
19
+ * — minimum 256 bits. **POSITIVE, SECURITY-BEARING.**
20
+ * 3. {@link H2A_ENROLLMENT_NONCE_MAX_BITS} / {@link H2A_ENROLLMENT_NONCE_MAX_LENGTH}
21
+ * — maximum 1024 bits. **SANITY CEILING, EXPLICITLY NOT A SECURITY
22
+ * PARAMETER.** It means *"beyond this it is not a nonce"*. It must NEVER be
23
+ * read as *"this much entropy is enough"* — the floor is the only bound that
24
+ * speaks about strength.
25
+ * 4. {@link H2A_ENROLLMENT_MAX_NONCE_LENGTH} — 4096 chars, pre-parse DoS guard
26
+ * only. Not a definition of anything.
27
+ */
28
+ /**
29
+ * Minimum entropy a gateway nonce must carry. **POSITIVE, SECURITY-BEARING.**
30
+ * Below this a "nonce" is guessable, and a guessable challenge is one an attacker
31
+ * can pre-compute a proof for.
32
+ */
33
+ export declare const H2A_ENROLLMENT_NONCE_MIN_BITS = 256;
34
+ /**
35
+ * Upper end of the bracket. **SANITY CEILING — NOT A SECURITY PARAMETER.**
36
+ *
37
+ * It says "beyond this it is not a nonce", nothing about sufficiency.
38
+ *
39
+ * Set at 1024 rather than 512 for HEADROOM — and the arithmetic has to be stated
40
+ * correctly, because an earlier draft of this comment said "88 base64url
41
+ * characters" and then drew a conclusion that only the wrong number supports.
42
+ * Base64url packs 6 bits per character, so a perfectly reasonable 64-byte nonce is
43
+ * 512 bits / **86** characters — and a 512-bit ceiling derives to `ceil(512 / 6) =
44
+ * 86` as well. It would therefore land EXACTLY on such a nonce and ACCEPT it, not
45
+ * reject it. So "512 would reject a 64-byte nonce" was never true; the real
46
+ * objection is that it leaves ZERO margin. A bound never meant to bound entropy
47
+ * must not sit flush against a legitimate value, where one more byte of issuer
48
+ * entropy — or base64 padding the issuer does not strip — turns a sanity bound
49
+ * into an outage. 1024 buys that margin. The corrected number does not weaken the
50
+ * choice; it removes a justification that misreported its own arithmetic, which is
51
+ * the defect class this module exists to argue against.
52
+ */
53
+ export declare const H2A_ENROLLMENT_NONCE_MAX_BITS = 1024;
54
+ /**
55
+ * The nonce's accepted alphabet, stated POSITIVELY: base64url characters only.
56
+ * **POSITIVE, SECURITY-BEARING** — it is what refuses free text, JSON, a URL, or
57
+ * a message borrowed from some other protocol, rather than enumerating those.
58
+ */
59
+ export declare const H2A_ENROLLMENT_NONCE_PATTERN: RegExp;
60
+ /**
61
+ * Minimum nonce length, DERIVED not asserted: base64url packs 6 bits per
62
+ * character, so `ceil(256 / 6) = 43` characters is the 256-bit floor.
63
+ * **POSITIVE, SECURITY-BEARING.**
64
+ *
65
+ * A MINIMUM, never an exact length — see the bracket note above for why pinning
66
+ * an as-yet-unbuilt issuer to one value is the error this replaces.
67
+ */
68
+ export declare const H2A_ENROLLMENT_NONCE_MIN_LENGTH: number;
69
+ /**
70
+ * Maximum nonce length, derived the same way: `ceil(1024 / 6) = 171` characters.
71
+ * **SANITY CEILING, NOT A SECURITY PARAMETER** — see
72
+ * {@link H2A_ENROLLMENT_NONCE_MAX_BITS}.
73
+ */
74
+ export declare const H2A_ENROLLMENT_NONCE_MAX_LENGTH: number;
75
+ /**
76
+ * Cheap PRE-PARSE cap, and nothing more.
77
+ *
78
+ * A DoS sanity bound, not a definition of a nonce — the definition is the
79
+ * alphabet plus the floor, with the ceiling as a separate sanity bound. Kept
80
+ * distinct so none of the four is mistaken for another.
81
+ */
82
+ export declare const H2A_ENROLLMENT_MAX_NONCE_LENGTH = 4096;
83
+ /**
84
+ * The ONLY keys a challenge document may carry. An ALLOWLIST, not a blocklist.
85
+ *
86
+ * The nonce was specified positively while the challenge *object* was left
87
+ * specified negatively — a blocklist of one key, `principalSub`. That control did
88
+ * not cover the harm it was written for: the harm is *"a principal id reaching an
89
+ * agent process and context window"*, and `{ nonce, meta: { principalSub } }` or
90
+ * `{ nonce, "__proto__": { principalSub } }` both do exactly that while passing a
91
+ * top-level `"principalSub" in challenge` check. A blocklist of one key stops one
92
+ * spelling of one field; nesting is a different spelling.
93
+ *
94
+ * So the same positive-specification move is applied one level up: only `nonce`
95
+ * and `expiresAt` may appear, both must be strings, and anything else is refused
96
+ * without needing to know what it means. No nesting is reachable, so no
97
+ * deep scan for a forbidden name is needed — that would be the blocklist again,
98
+ * one level deeper.
99
+ */
100
+ export declare const H2A_ENROLLMENT_CHALLENGE_KEYS: readonly ["nonce", "expiresAt"];
101
+ /**
102
+ * The domain-separation tag carried and signed by every proof — see
103
+ * {@link H2AEnrollmentProof.type}.
104
+ *
105
+ * Versioned so a format change is distinguishable rather than silently
106
+ * reinterpreted. Bump this and the verifier stops accepting the old shape, which
107
+ * is the entire point of it being here.
108
+ */
109
+ export declare const H2A_ENROLLMENT_PROOF_TYPE = "h2a-enrollment-proof-v1";
110
+ /**
111
+ * A gateway-issued enrollment challenge, as the local agent receives it.
112
+ *
113
+ * Part B, flow step 2: *"Gateway issues a challenge: a random nonce, TTL-bound,
114
+ * scoped to that `sub`."* The `sub`-scoping is a fact the GATEWAY holds and
115
+ * re-checks at verification time (flow step 5a) and the agent never sees it —
116
+ * see consequence 2 in the module header.
117
+ */
118
+ export interface H2AEnrollmentChallenge {
119
+ /**
120
+ * The random nonce: base64url, ≥256 bits. It is one of the three signed
121
+ * fields — see {@link enrollmentProofSignedPayload}.
122
+ */
123
+ readonly nonce: string;
124
+ /**
125
+ * Optional ISO-8601 expiry, as told to the agent. **Advisory**: the gateway
126
+ * remains the authority on the TTL (flow step 5a). Present, it lets the agent
127
+ * refuse to spend a signature on a challenge it can already see is dead —
128
+ * which can only ever narrow what happens, never widen it.
129
+ */
130
+ readonly expiresAt?: string;
131
+ }
132
+ /**
133
+ * The proof payload the agent returns to the gateway — Part B, flow step 4:
134
+ * *"The agent returns `{ nonce, signature, publicKeyPem, instance }`."*
135
+ *
136
+ * Exactly those four fields, and nothing else. In particular: no private key
137
+ * material, no filesystem path, no principal identifier, no bearer token, no
138
+ * capability list. What the gateway does with it is Part B flow step 5.
139
+ */
140
+ export interface H2AEnrollmentProof {
141
+ /**
142
+ * WHAT THIS MESSAGE IS — the domain-separation tag, signed like every other
143
+ * carried field.
144
+ *
145
+ * The rule "a proof must attest to everything it CARRIES" is only
146
+ * content-completeness. The other half: **a proof must also attest WHAT IT
147
+ * IS.** Attesting content while leaving the message type unstated is exactly
148
+ * how cross-protocol attacks work — signature valid, content honest,
149
+ * *interpretation attacker-chosen*.
150
+ *
151
+ * That is precisely the oracle this contract already closed once: moving from a
152
+ * signed string to a signed object fixed it, but bound the type only
153
+ * ACCIDENTALLY, via a key set that happens to be unique among h2a's signing
154
+ * sites today. "Safe because no other site currently signs this shape" is the
155
+ * same negative property — satisfied by absence, expiring when someone adds the
156
+ * colliding site. This field makes it positive.
157
+ *
158
+ * **VERSIONED deliberately.** A future format change must be
159
+ * *distinguishable*, not silently reinterpreted; an unversioned tag only defers
160
+ * the same problem to the next revision. {@link verifyEnrollmentProof} checks
161
+ * this value, so a `-v2` proof cannot pass a v1 verifier.
162
+ */
163
+ readonly type: typeof H2A_ENROLLMENT_PROOF_TYPE;
164
+ /** The gateway's nonce, echoed verbatim. Signed. */
165
+ readonly nonce: string;
166
+ /**
167
+ * `signCanonical(enrollmentProofSignedPayload(proof), { by: instance,
168
+ * privateKeyPem })` — an `H2ASignature` `{ by, alg: 'ed25519', value }`
169
+ * (`types.ts` `H2ASignature`, reused unchanged per Part B's "Reuse vs. new"
170
+ * table).
171
+ *
172
+ * `signature.by` is NOT part of the signed message; it is a routing label that
173
+ * duplicates the signed `instance`. A verifier must read `instance`, never
174
+ * `by`.
175
+ */
176
+ readonly signature: H2ASignature;
177
+ /**
178
+ * The agent's CURRENT public key PEM (SPKI). Public material, not a secret.
179
+ * Signed — so a payload cannot be re-pointed at another key and still verify
180
+ * against this signature.
181
+ */
182
+ readonly publicKeyPem: string;
183
+ /**
184
+ * The agent's CURRENT live instance id. Signed, so its PROVENANCE is
185
+ * trustworthy. That is emphatically not permission: see SIGNED ≠ AUTHORIZED in
186
+ * the module header. It maps to Part B's `agentInstanceIdAtBinding`, which the
187
+ * contract already marks "provenance only — NEVER re-used as authority at read
188
+ * time".
189
+ */
190
+ readonly instance: string;
191
+ }
192
+ /**
193
+ * The exact object the signature covers: **every field the proof carries except
194
+ * the signature itself**.
195
+ *
196
+ * Single definition on purpose. The gateway's verification (Part B flow step 5b,
197
+ * as amended) is `verifyCanonical(enrollmentProofSignedPayload(proof),
198
+ * proof.signature, proof.publicKeyPem)`, and field ordering is irrelevant
199
+ * because `canonicalize` normalizes it — so an independent implementation cannot
200
+ * disagree about what was signed by guessing at key order.
201
+ *
202
+ * The rule is STRUCTURAL, not asserted. Coverage is a rest-spread that removes
203
+ * exactly one field, so "every field except the signature" is what the code
204
+ * *does* rather than a list that has to be kept in step — the same shape as
205
+ * `envelope.ts` `envelopeSigningView` (`const { signatures: _omit, ...rest }`).
206
+ * Three things follow, and the third is why this beats an enumeration:
207
+ *
208
+ * 1. `Omit<…, "signature">` on the parameter makes **tsc** reject a caller that
209
+ * does not hold every non-signature field, so a new required field on
210
+ * {@link H2AEnrollmentProof} is a compile error, not a test failure.
211
+ * 2. A new field flows into the signature automatically. There is no second list
212
+ * to forget.
213
+ * 3. A field carried on the proof but NOT signed becomes impossible to emit:
214
+ * signing sees the unsigned view, verification re-derives it from the finished
215
+ * proof, so any extra field makes the two disagree and
216
+ * {@link signEnrollmentChallenge}'s self-verification throws. The rule holds
217
+ * even with every test deleted.
218
+ *
219
+ * The keys test is kept anyway — it documents the intent and costs nothing.
220
+ */
221
+ export declare function enrollmentProofSignedPayload(proof: Omit<H2AEnrollmentProof, "signature"> & {
222
+ readonly signature?: H2ASignature;
223
+ }): Omit<H2AEnrollmentProof, "signature">;
224
+ /**
225
+ * Verify a proof the way the gateway must: the signature over the whole
226
+ * composite, checked against the key the proof ships.
227
+ *
228
+ * **This answers "did this key produce this payload", and NOTHING else.** It is
229
+ * not an authorization check and must never be used as one: a `true` here on a
230
+ * key with no active binding row still authorizes nothing (Part B, fail-closed
231
+ * item 3 — "verifying the signature must never, by itself, cause any row to be
232
+ * returned"). Provided so the two lanes verify the same bytes, not so a caller
233
+ * can shortcut a binding lookup.
234
+ */
235
+ export declare function verifyEnrollmentProof(proof: H2AEnrollmentProof): boolean;
236
+ /**
237
+ * Refuse to prove control of a key h2a itself does not list as ACTIVE.
238
+ *
239
+ * h2a-side key validity is *necessary but not sufficient* for exposure — the
240
+ * binding governs that (Part B, fail-closed item 4) — but a key h2a considers
241
+ * revoked must never be offered up for a NEW binding.
242
+ *
243
+ * This is DEFENCE IN DEPTH, and its call site is unreachable in practice: when
244
+ * the live key has been revoked, `resolveLiveIdentity`'s reclaim proof
245
+ * (`provesLocalKey`, which requires at least one active key) fails, so it MINTS
246
+ * a fresh identity instead of returning the revoked one — verified by the
247
+ * "a locally revoked key is never the key proved" test. The guard exists so that
248
+ * remains a CHECKED fact rather than a relied-upon one, and it is exported so it
249
+ * can be exercised directly instead of sitting untested behind a path that
250
+ * cannot reach it.
251
+ *
252
+ * An empty key list is an ERROR here, never a silent pass: "no active keys" is
253
+ * not the fact "this key is fine".
254
+ */
255
+ export declare function assertKeyIsLocallyActive(input: {
256
+ readonly instance: string;
257
+ readonly publicKeyPem: string;
258
+ readonly activeKeys: readonly string[];
259
+ }): void;
260
+ /** The local key material the ceremony proves control of. */
261
+ export interface H2AEnrollmentIdentity {
262
+ /** The live instance id, resolved at run time — never a recorded value. */
263
+ readonly instance: string;
264
+ /** PKCS#8 PEM. Read from disk, used to sign, and NEVER returned outward. */
265
+ readonly privateKeyPem: string;
266
+ /** SPKI PEM. Public material; this one does go on the wire. */
267
+ readonly publicKeyPem: string;
268
+ /**
269
+ * How live resolution arrived at this identity: `reclaim` re-proved an existing
270
+ * local key, `mint` created a NEW one. Reported so a mint is never silent — a
271
+ * mint the owner did not expect means an earlier keypair was unusable (see
272
+ * {@link listUnusablePrivateKeys}) or the agent re-anchored. Optional so an
273
+ * injected resolver need not synthesize a provenance it does not have.
274
+ */
275
+ readonly identityAction?: "override" | "reclaim" | "mint";
276
+ }
277
+ /** Where {@link buildEnrollmentProof} looks for the live agent identity. */
278
+ export interface ResolveEnrollmentIdentityInput {
279
+ /** The h2a store root (`<root>/keys/...`). */
280
+ readonly root: string;
281
+ /** The provider host (`claude`, `codex`, ...) — an input to live resolution. */
282
+ readonly host: string;
283
+ /** The working directory, for workspace resolution. */
284
+ readonly cwd: string;
285
+ }
286
+ /**
287
+ * Seam for the identity resolution. Injected by tests; the default
288
+ * ({@link resolveEnrollmentIdentity}) is the only production implementation.
289
+ */
290
+ export type EnrollmentIdentityResolver = (input: ResolveEnrollmentIdentityInput) => H2AEnrollmentIdentity;
291
+ /**
292
+ * Resolve the CURRENT live identity and load its keypair.
293
+ *
294
+ * Why this resolves live, every single time, and takes no instance id:
295
+ * **a memory that names an instance-id ROTS.** That is a documented failure in
296
+ * this project (a stale recorded mapping sent a consultation to the wrong
297
+ * instance), and it is the same failure the identity re-anchor of 2026-06-07
298
+ * created for enrollment: the stability unit moved from `(host, workspaceId)`
299
+ * to the provider conversation UUID, so an agent enrolled before it now
300
+ * presents a DIFFERENT instance handle and a DIFFERENT keypair (Part B,
301
+ * "Re-enrollment of a post-re-anchor key"). The previously enrolled
302
+ * `agentPubKey` is simply no longer produced by any live agent — which is why a
303
+ * push today is rejected 401.
304
+ *
305
+ * So there is deliberately **no `instance` parameter anywhere in this module's
306
+ * public surface**. The id cannot be passed in, therefore a stale one cannot be
307
+ * used. `resolveLiveIdentity` is called without `explicitInstance` (which would
308
+ * short-circuit before any keypair exists — `identity/live.ts`), and the key is
309
+ * then read from the paths THAT resolution returned.
310
+ *
311
+ * WHAT ACTUALLY HAPPENS WHEN THE LOCAL KEY IS UNUSABLE — stated because the
312
+ * obvious reading ("it fails closed") is wrong, and an overstated guard comment
313
+ * is worse than none:
314
+ *
315
+ * - **Corrupt, truncated or passphrase-protected private key** → `provesLocalKey`
316
+ * catches its own failure and returns `false`, so `resolveLiveIdentity` MINTS a
317
+ * fresh identity. The ceremony then succeeds, with exit 0, proving control of a
318
+ * BRAND-NEW key — the corrupt file is left on disk and the old instance stays
319
+ * listed active. It does not fail, and it does not prove the damaged key. The
320
+ * mint is the same self-healing mechanism as the revoked-key case, but here it
321
+ * would MASK TAMPERING, so silence is the defect: the CLI names any unusable
322
+ * key file on stderr before this runs (see {@link listUnusablePrivateKeys}),
323
+ * and `identityAction` reports the mint. Pinned by an OBSERVED BEHAVIOUR test.
324
+ * - **Unreadable private key (EACCES)** → `readKeypair` reads the same file
325
+ * earlier, inside `resolveLiveIdentity` and outside any `try`, so the raw errno
326
+ * escapes from there rather than from the guard below. That is why the whole
327
+ * resolution call is wrapped: the failure is re-thrown with the root named,
328
+ * instead of surfacing as a bare `EACCES` with no indication of which store it
329
+ * came from.
330
+ * - **The two guards below are NARROWING, not behaviour.** The
331
+ * `privateKeyPath === undefined` branch exists because the type is optional
332
+ * (`explicitInstance` is the only resolution path that omits the paths, and
333
+ * this function never passes one), and the `readFileSync` branch is belt and
334
+ * braces behind the earlier read. Neither is reachable on this path; they are
335
+ * not the reason a broken key is safe. {@link assertKeyIsLocallyActive} is in
336
+ * the same position and says so itself.
337
+ *
338
+ * DOCUMENTED LIMIT on what the returned `instance` contains: an instance id is
339
+ * `<host>:<label>:<uuid>` and its label is the host-native session name or the
340
+ * workspace directory's BASENAME (`identity/live.ts` `deriveInstanceId`). So the
341
+ * proof carries a workspace *label*, which Part A's opacity boundary explicitly
342
+ * permits ("never a filesystem path beyond a human label") — but never a path.
343
+ * It is free text the owner controls, so a consumer must escape it like any
344
+ * user content; see joint plan §9.
345
+ */
346
+ export declare function resolveEnrollmentIdentity(input: ResolveEnrollmentIdentityInput): H2AEnrollmentIdentity;
347
+ /**
348
+ * Every private key file under `<root>/keys` that exists but cannot be loaded as
349
+ * a private key — corrupt, truncated, or passphrase-protected.
350
+ *
351
+ * This exists because of what does NOT happen when the live key is one of those:
352
+ * live resolution's reclaim proof fails silently and MINTS a fresh identity, so
353
+ * the ceremony succeeds with exit 0 on a brand-new key while a damaged file sits
354
+ * on disk. The mint is defensible; doing it silently is not, because it is
355
+ * indistinguishable from tampering. So the caller can name the file.
356
+ *
357
+ * Read-only and total: it never throws, and a missing `keys` directory yields an
358
+ * empty list from an EXPLICIT branch — "there is no key directory" is an
359
+ * established fact, not a default.
360
+ */
361
+ export declare function listUnusablePrivateKeys(root: string): string[];
362
+ /** Input to the pure signing step. No I/O, no clock unless injected. */
363
+ export interface SignEnrollmentChallengeInput {
364
+ /** The gateway-issued challenge. */
365
+ readonly challenge: H2AEnrollmentChallenge;
366
+ /** The identity whose control is being proved. */
367
+ readonly identity: H2AEnrollmentIdentity;
368
+ /** Clock, for the advisory expiry check. Defaults to `Date.now`. */
369
+ readonly now?: () => number;
370
+ }
371
+ /**
372
+ * Reject a challenge we must not sign. Narrowing only — this can refuse a
373
+ * signature, never authorize one. Throws with a message naming the reason.
374
+ *
375
+ * Exported so a caller that classifies errors (the CLI, which owes a distinct
376
+ * exit code for "your challenge is bad" vs "my local key state is bad") can
377
+ * check the input it was handed BEFORE touching any identity.
378
+ * {@link signEnrollmentChallenge} validates again regardless: each entry point
379
+ * validates its own input, and an upstream check is never assumed.
380
+ *
381
+ * IMPLEMENTED AS the sanitize path with the result discarded, deliberately. The
382
+ * validator and the sanitizer used to be two independent readers of the caller's
383
+ * object, which is precisely how `expiresAt` came to be validated *through the
384
+ * prototype chain* while the allowlist looked only at own keys. One reader means
385
+ * they cannot disagree.
386
+ */
387
+ export declare function assertSignableEnrollmentChallenge(challenge: H2AEnrollmentChallenge, nowMs: number): void;
388
+ /**
389
+ * Validate a parsed challenge document and return a FRESH, NULL-PROTOTYPE object
390
+ * carrying only the allowlisted keys.
391
+ *
392
+ * Three distinct jobs, all load-bearing:
393
+ *
394
+ * 1. It takes the OWN-ONLY view first ({@link carriedChallengeFields}), so what is
395
+ * validated and what is returned are the same object. An inherited field is
396
+ * invisible to both.
397
+ * 2. It refuses ({@link assertCarriedChallengeIsSignable}). Refuse-the-rest means
398
+ * refuse, not ignore.
399
+ * 3. What flows onward is a **new object with `null` prototype**, so the
400
+ * `JSON.parse` result — which may carry an own `"__proto__"` key, a
401
+ * prototype-pollution vector the moment anything spreads or assigns it into
402
+ * another object — never propagates past this boundary. Even though such a
403
+ * document is already refused above, nothing downstream has to depend on that
404
+ * having happened.
405
+ *
406
+ * Order matters and is the point: sanitize-then-validate, never validate-then-copy.
407
+ * The copy is what removes the second accessor, so validating the caller's object
408
+ * first would put the bug back.
409
+ *
410
+ * Use this at any boundary where the challenge came from parsed input. The CLI
411
+ * does, and so does {@link signEnrollmentChallenge}.
412
+ */
413
+ export declare function sanitizeEnrollmentChallenge(challenge: H2AEnrollmentChallenge, nowMs: number): H2AEnrollmentChallenge;
414
+ /**
415
+ * Sign a gateway-issued challenge with the agent's identity key and return the
416
+ * Part B proof payload. PURE apart from the injected clock: no I/O, no network,
417
+ * no store.
418
+ *
419
+ * The signed message is the CANONICAL COMPOSITE
420
+ * {@link enrollmentProofSignedPayload} — `{ type, nonce, instance, publicKeyPem }`
421
+ * — per the signed-composite amendment. The earlier shape signed the bare nonce
422
+ * (Part B flow steps 3 and 5b as originally written), which was safe only
423
+ * because nothing yet consumed `instance`: safety derived from the *absence* of a
424
+ * consumer, which expires the moment someone adds one.
425
+ *
426
+ * The rule, in its amended form: **a proof must attest to everything it carries
427
+ * AND to what it is.** Content-completeness plus context-binding — the first
428
+ * without the second leaves the interpretation attacker-chosen.
429
+ *
430
+ * A structural consequence worth knowing, because it removes a whole finding
431
+ * rather than guarding against it: the reclaim proof-of-possession signs a
432
+ * STRING (`identity-reclaim:<instance>:<fingerprint>`), and this signs an
433
+ * OBJECT. `canonicalize` type-tags the two differently, so no enrollment
434
+ * signature can ever satisfy `verifyReclaimProof` — the signing-oracle collision
435
+ * is impossible by construction, not by refusal. There is deliberately no guard
436
+ * against it: a guard that cannot fire is the defect this PR spent its time
437
+ * finding. The property is pinned by a regression test instead.
438
+ *
439
+ * Note that that separation was ACCIDENTAL — it held because the two payload
440
+ * types differ, not because either said what it was. The signed `type` field is
441
+ * what makes it deliberate, and it generalizes: no h2a signing site can collide
442
+ * with this one now, whatever shape it later adopts.
443
+ *
444
+ * Before returning, the proof is VERIFIED against the public key it ships. A
445
+ * proof we cannot verify ourselves is never emitted: that is what catches a
446
+ * mismatched keypair locally instead of at the gateway, where the failure is
447
+ * indistinguishable from an attack.
448
+ */
449
+ export declare function signEnrollmentChallenge(input: SignEnrollmentChallengeInput): H2AEnrollmentProof;
450
+ /** Options for the synchronous, network-free proof build. */
451
+ export interface BuildEnrollmentProofOptions {
452
+ /** The h2a store root. */
453
+ readonly root: string;
454
+ /** The provider host (`claude`, `codex`, ...). */
455
+ readonly host: string;
456
+ /** The working directory. */
457
+ readonly cwd: string;
458
+ /** The gateway-issued challenge. */
459
+ readonly challenge: H2AEnrollmentChallenge;
460
+ /** Clock, for the advisory expiry check. */
461
+ readonly now?: () => number;
462
+ /** Identity-resolution seam. Defaults to {@link resolveEnrollmentIdentity}. */
463
+ readonly resolveIdentityImpl?: EnrollmentIdentityResolver;
464
+ }
465
+ /** What the ceremony produced, plus the owner-facing provenance. */
466
+ export interface EnrollmentProofResult {
467
+ /** The payload to hand to the gateway. */
468
+ readonly proof: H2AEnrollmentProof;
469
+ /** The live instance the proof was produced for (same as `proof.instance`). */
470
+ readonly instance: string;
471
+ /**
472
+ * Short sha256 prefix of the proved public key — the same fingerprint the
473
+ * reclaim proof uses. For the OWNER to eyeball which key was proved; it is
474
+ * not part of the proof and carries no authority.
475
+ */
476
+ readonly publicKeyFingerprint: string;
477
+ /**
478
+ * Provenance of the identity this run proved — see
479
+ * {@link H2AEnrollmentIdentity.identityAction}. Absent when an injected
480
+ * resolver did not report one.
481
+ */
482
+ readonly identityAction?: "override" | "reclaim" | "mint";
483
+ }
484
+ /**
485
+ * Resolve the live identity, sign the challenge, return the proof.
486
+ *
487
+ * SYNCHRONOUS and network-free by construction: there is no transport in this
488
+ * function at all, so the CLI path (`h2a keys prove-control`) cannot reach one.
489
+ * Re-enrollment needs no separate entry point — this IS the re-enrollment path,
490
+ * because it resolves the current identity every time and can therefore only
491
+ * ever produce a proof for the key that is live now. A changed controlling key
492
+ * means the owner re-runs this and the gateway mints a NEW binding, revoking the
493
+ * old row (Part B, "Re-enrollment of a post-re-anchor key"); nothing here
494
+ * reuses or rotates anything.
495
+ */
496
+ export declare function buildEnrollmentProof(options: BuildEnrollmentProofOptions): EnrollmentProofResult;
497
+ /**
498
+ * Seam for handing the proof to the gateway.
499
+ *
500
+ * **There is no default implementation and h2a ships none.** The gateway's
501
+ * challenge/verify endpoint is the auth lane's step 2 and is not built yet; the
502
+ * per-binding push keying is step 4b and carries its own BLOCKING cross-verify
503
+ * requirement (path-identity vs key-identity). Until then a submitter is
504
+ * supplied by the caller — in tests, always a fake — and its absence is
505
+ * REPORTED as a fact, never papered over.
506
+ */
507
+ export type EnrollmentProofSubmitter = (proof: H2AEnrollmentProof) => Promise<unknown>;
508
+ /**
509
+ * What happened to the proof, from an EXPLICIT branch on whether a transport
510
+ * exists — never a defaulted value. "Not attempted" is a fact the caller can
511
+ * act on; a silent `undefined` would be indistinguishable from a failed send.
512
+ */
513
+ export type EnrollmentSubmission = {
514
+ readonly attempted: false;
515
+ /** No transport was supplied, so nothing was sent anywhere. */
516
+ readonly reason: "no-transport-configured";
517
+ } | {
518
+ readonly attempted: true;
519
+ /** Whatever the injected submitter returned. Opaque to h2a. */
520
+ readonly response: unknown;
521
+ };
522
+ /** Options for the full ceremony, including the optional injected transport. */
523
+ export interface RunEnrollmentCeremonyOptions extends BuildEnrollmentProofOptions {
524
+ /**
525
+ * Injected transport. Omitted (the production default), the proof is returned
526
+ * for out-of-band delivery and `submission.attempted` is `false`.
527
+ */
528
+ readonly submitImpl?: EnrollmentProofSubmitter;
529
+ }
530
+ /** The ceremony's outcome: the proof, plus what was done with it. */
531
+ export interface EnrollmentCeremonyResult extends EnrollmentProofResult {
532
+ readonly submission: EnrollmentSubmission;
533
+ }
534
+ /**
535
+ * Run the ceremony end to end: resolve the live identity, sign the challenge,
536
+ * and — only if a transport was injected — hand the proof over.
537
+ *
538
+ * With no `submitImpl` this makes NO network call of any kind. That is not a
539
+ * default-off flag; there is no hosted endpoint in this file to turn on.
540
+ */
541
+ export declare function runEnrollmentCeremony(options: RunEnrollmentCeremonyOptions): Promise<EnrollmentCeremonyResult>;
542
+ //# sourceMappingURL=ceremony.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../../src/runtime/enrollment/ceremony.ts"],"names":[],"mappings":"AAiGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQnD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,QAAqB,CAAC;AAE/D;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,QAA+C,CAAC;AAE5F;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAA+C,CAAC;AAE5F;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,OAAO,CAAC;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,6BAA6B,iCAAkC,CAAC;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,4BAA4B,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,yBAAyB,CAAC;IAChD,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,4BAA4B,CAM1C,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,YAAY,CAAA;CAAE,GACnF,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAGvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAWxE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,GAAG,IAAI,CAaP;AAED,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;CAC3D;AAED,4EAA4E;AAC5E,MAAM,WAAW,8BAA8B;IAC7C,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,CACvC,KAAK,EAAE,8BAA8B,KAClC,qBAAqB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,8BAA8B,GACpC,qBAAqB,CA0DvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAsB9D;AAED,wEAAwE;AACxE,MAAM,WAAW,4BAA4B;IAC3C,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAC3C,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,oEAAoE;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AA4MD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,MAAM,GACZ,IAAI,CAEN;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,sBAAsB,EACjC,KAAK,EAAE,MAAM,GACZ,sBAAsB,CAIxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,GAClC,kBAAkB,CAqCpB;AAED,6DAA6D;AAC7D,MAAM,WAAW,2BAA2B;IAC1C,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAC3C,4CAA4C;IAC5C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;CAC3D;AAED,oEAAoE;AACpE,MAAM,WAAW,qBAAqB;IACpC,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;CAC3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,2BAA2B,GACnC,qBAAqB,CAoBvB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,kBAAkB,KACtB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;CAC5C,GACD;IACE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEN,gFAAgF;AAChF,MAAM,WAAW,4BAA6B,SAAQ,2BAA2B;IAC/E;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,wBAAwB,CAAC;CAChD;AAED,qEAAqE;AACrE,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;CAC3C;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,wBAAwB,CAAC,CAOnC"}