@sentropic/h2a 0.85.24 → 0.86.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.
- package/.claude-plugin/plugin.json +2 -3
- package/.codex-plugin/plugin.json +1 -1
- package/dist/bin.js +51 -2
- package/dist/bin.js.map +1 -1
- package/dist/cli-command-map.d.ts +119 -0
- package/dist/cli-command-map.d.ts.map +1 -0
- package/dist/cli-command-map.js +396 -0
- package/dist/cli-command-map.js.map +1 -0
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli-contract.js +38 -0
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli.d.ts +25 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +356 -7
- package/dist/cli.js.map +1 -1
- package/dist/identity.d.ts +37 -3
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -0
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/runtime/enrollment/ceremony.d.ts +542 -0
- package/dist/runtime/enrollment/ceremony.d.ts.map +1 -0
- package/dist/runtime/enrollment/ceremony.js +777 -0
- package/dist/runtime/enrollment/ceremony.js.map +1 -0
- package/dist/runtime/enrollment/index.d.ts +16 -0
- package/dist/runtime/enrollment/index.d.ts.map +1 -0
- package/dist/runtime/enrollment/index.js +16 -0
- package/dist/runtime/enrollment/index.js.map +1 -0
- package/dist/runtime/feed/descriptors.d.ts +261 -0
- package/dist/runtime/feed/descriptors.d.ts.map +1 -0
- package/dist/runtime/feed/descriptors.js +425 -0
- package/dist/runtime/feed/descriptors.js.map +1 -0
- package/dist/runtime/feed/index.d.ts +12 -0
- package/dist/runtime/feed/index.d.ts.map +1 -0
- package/dist/runtime/feed/index.js +12 -0
- package/dist/runtime/feed/index.js.map +1 -0
- package/dist/runtime/identity/index.d.ts +3 -3
- package/dist/runtime/identity/index.d.ts.map +1 -1
- package/dist/runtime/identity/index.js +2 -2
- package/dist/runtime/identity/index.js.map +1 -1
- package/dist/runtime/identity/live.d.ts +68 -0
- package/dist/runtime/identity/live.d.ts.map +1 -1
- package/dist/runtime/identity/live.js +78 -2
- package/dist/runtime/identity/live.js.map +1 -1
- package/dist/runtime/identity/readers.d.ts +89 -5
- package/dist/runtime/identity/readers.d.ts.map +1 -1
- package/dist/runtime/identity/readers.js +242 -33
- package/dist/runtime/identity/readers.js.map +1 -1
- package/dist/runtime/local-files/presence.d.ts +16 -1
- package/dist/runtime/local-files/presence.d.ts.map +1 -1
- package/dist/runtime/local-files/presence.js +32 -20
- package/dist/runtime/local-files/presence.js.map +1 -1
- package/dist/runtime/loop/index.d.ts +5 -0
- package/dist/runtime/loop/index.d.ts.map +1 -1
- package/dist/runtime/loop/index.js +48 -5
- package/dist/runtime/loop/index.js.map +1 -1
- package/dist/runtime/mcp/agent-launch.d.ts +15 -1
- package/dist/runtime/mcp/agent-launch.d.ts.map +1 -1
- package/dist/runtime/mcp/agent-launch.js +45 -4
- package/dist/runtime/mcp/agent-launch.js.map +1 -1
- package/dist/runtime/mcp/index.d.ts +1 -1
- package/dist/runtime/mcp/index.d.ts.map +1 -1
- package/dist/runtime/mcp/index.js +1 -1
- package/dist/runtime/mcp/index.js.map +1 -1
- package/dist/runtime/mcp/server.d.ts +3 -1
- package/dist/runtime/mcp/server.d.ts.map +1 -1
- package/dist/runtime/mcp/server.js +7 -2
- package/dist/runtime/mcp/server.js.map +1 -1
- package/dist/runtime/mcp/sessions.d.ts +19 -0
- package/dist/runtime/mcp/sessions.d.ts.map +1 -1
- package/dist/runtime/mcp/sessions.js +44 -2
- package/dist/runtime/mcp/sessions.js.map +1 -1
- package/dist/runtime/mcp/stdio.d.ts +8 -0
- package/dist/runtime/mcp/stdio.d.ts.map +1 -1
- package/dist/runtime/mcp/stdio.js +42 -0
- package/dist/runtime/mcp/stdio.js.map +1 -1
- package/dist/runtime/mcp-registry/broker.d.ts +175 -0
- package/dist/runtime/mcp-registry/broker.d.ts.map +1 -0
- package/dist/runtime/mcp-registry/broker.js +203 -0
- package/dist/runtime/mcp-registry/broker.js.map +1 -0
- package/dist/runtime/mcp-registry/broker.typecheck.d.ts +2 -0
- package/dist/runtime/mcp-registry/broker.typecheck.d.ts.map +1 -0
- package/dist/runtime/mcp-registry/broker.typecheck.js +48 -0
- package/dist/runtime/mcp-registry/broker.typecheck.js.map +1 -0
- package/dist/runtime/mirror/accept.d.ts +43 -5
- package/dist/runtime/mirror/accept.d.ts.map +1 -1
- package/dist/runtime/mirror/accept.js +55 -7
- package/dist/runtime/mirror/accept.js.map +1 -1
- package/dist/runtime/mirror/build.d.ts +23 -4
- package/dist/runtime/mirror/build.d.ts.map +1 -1
- package/dist/runtime/mirror/build.js +34 -4
- package/dist/runtime/mirror/build.js.map +1 -1
- package/dist/runtime/mirror/index.d.ts +3 -0
- package/dist/runtime/mirror/index.d.ts.map +1 -1
- package/dist/runtime/mirror/index.js +3 -0
- package/dist/runtime/mirror/index.js.map +1 -1
- package/dist/runtime/mirror/ingest.d.ts +109 -0
- package/dist/runtime/mirror/ingest.d.ts.map +1 -0
- package/dist/runtime/mirror/ingest.js +117 -0
- package/dist/runtime/mirror/ingest.js.map +1 -0
- package/dist/runtime/mirror/push-daemon.d.ts +376 -0
- package/dist/runtime/mirror/push-daemon.d.ts.map +1 -0
- package/dist/runtime/mirror/push-daemon.js +644 -0
- package/dist/runtime/mirror/push-daemon.js.map +1 -0
- package/dist/runtime/mirror/sanitize.d.ts +477 -0
- package/dist/runtime/mirror/sanitize.d.ts.map +1 -0
- package/dist/runtime/mirror/sanitize.js +625 -0
- package/dist/runtime/mirror/sanitize.js.map +1 -0
- package/dist/runtime/mirror/serve.d.ts.map +1 -1
- package/dist/runtime/mirror/serve.js +104 -24
- package/dist/runtime/mirror/serve.js.map +1 -1
- package/dist/runtime/reporting/report-ai.d.ts.map +1 -1
- package/dist/runtime/reporting/report-ai.js +1 -0
- package/dist/runtime/reporting/report-ai.js.map +1 -1
- package/dist/runtime/reporting/stdin.d.ts +2 -0
- package/dist/runtime/reporting/stdin.d.ts.map +1 -0
- package/dist/runtime/reporting/stdin.js +8 -0
- package/dist/runtime/reporting/stdin.js.map +1 -0
- package/dist/status-surface.d.ts +167 -0
- package/dist/status-surface.d.ts.map +1 -0
- package/dist/status-surface.js +670 -0
- package/dist/status-surface.js.map +1 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/focus-app/client/_app/immutable/assets/{0.BdzHFb9q.css → 0.CgEVz9YW.css} +1 -1
- package/focus-app/client/_app/immutable/assets/0.CgEVz9YW.css.br +0 -0
- package/focus-app/client/_app/immutable/assets/0.CgEVz9YW.css.gz +0 -0
- package/focus-app/client/_app/immutable/assets/2.DaTmt6o7.css +1 -0
- package/focus-app/client/_app/immutable/assets/2.DaTmt6o7.css.br +0 -0
- package/focus-app/client/_app/immutable/assets/2.DaTmt6o7.css.gz +0 -0
- package/focus-app/client/_app/immutable/assets/3.vWQUAHjz.css +1 -0
- package/focus-app/client/_app/immutable/assets/3.vWQUAHjz.css.br +0 -0
- package/focus-app/client/_app/immutable/assets/3.vWQUAHjz.css.gz +0 -0
- package/focus-app/client/_app/immutable/assets/AppShell.CDPwj3zU.css +1 -0
- package/focus-app/client/_app/immutable/assets/AppShell.CDPwj3zU.css.br +0 -0
- package/focus-app/client/_app/immutable/assets/AppShell.CDPwj3zU.css.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/{Cj6wo28J.js → 1NK_OeRJ.js} +1 -1
- package/focus-app/client/_app/immutable/chunks/1NK_OeRJ.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/1NK_OeRJ.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/{Bs3f1UbD.js → B1veta3r.js} +2 -2
- package/focus-app/client/_app/immutable/chunks/B1veta3r.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/B1veta3r.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/{DEmooz0s.js → BZ4lcC0v.js} +1 -1
- package/focus-app/client/_app/immutable/chunks/BZ4lcC0v.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/BZ4lcC0v.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/Bu7F9NOv.js +2 -0
- package/focus-app/client/_app/immutable/chunks/Bu7F9NOv.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/Bu7F9NOv.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/C6KhNEX3.js +1 -0
- package/focus-app/client/_app/immutable/chunks/C6KhNEX3.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/C6KhNEX3.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/DIljKPJN.js +1 -0
- package/focus-app/client/_app/immutable/chunks/DIljKPJN.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/DIljKPJN.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/iXQate3J.js +2 -0
- package/focus-app/client/_app/immutable/chunks/iXQate3J.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/iXQate3J.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/{ZxFklh9T.js → kCE9wz0g.js} +1 -1
- package/focus-app/client/_app/immutable/chunks/kCE9wz0g.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/kCE9wz0g.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/x-hq5fDG.js +1 -0
- package/focus-app/client/_app/immutable/chunks/x-hq5fDG.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/x-hq5fDG.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js +2 -0
- package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js.br +0 -0
- package/focus-app/client/_app/immutable/entry/app.C1sDdCg5.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js +1 -0
- package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js.br +2 -0
- package/focus-app/client/_app/immutable/entry/start.X3j_A5RN.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/0.gLl44WzG.js +5 -0
- package/focus-app/client/_app/immutable/nodes/0.gLl44WzG.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/0.gLl44WzG.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js +1 -0
- package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/1.DUrghq2x.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/2.Bp7JE7Pz.js +1 -0
- package/focus-app/client/_app/immutable/nodes/2.Bp7JE7Pz.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/2.Bp7JE7Pz.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/3.Cml8enOG.js +12 -0
- package/focus-app/client/_app/immutable/nodes/3.Cml8enOG.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/3.Cml8enOG.js.gz +0 -0
- package/focus-app/client/_app/version.json +1 -1
- package/focus-app/client/_app/version.json.br +0 -0
- package/focus-app/client/_app/version.json.gz +0 -0
- package/focus-app/h2a-focus.json +108 -80
- package/focus-app/handler.js +7 -7
- package/focus-app/index.js +7 -7
- package/focus-app/server/chunks/chunks/AppShell.js-6Pi87dO0.js +1353 -0
- package/focus-app/server/chunks/chunks/AppShell.js-6Pi87dO0.js.map +1 -0
- package/focus-app/server/chunks/chunks/agent-memory-dossier.js-nmFG_rgx.js +1036 -0
- package/focus-app/server/chunks/chunks/agent-memory-dossier.js-nmFG_rgx.js.map +1 -0
- package/focus-app/server/chunks/chunks/{exports.js-DUTkELZq.js → exports.js-CdqPbjm1.js} +3 -3
- package/focus-app/server/chunks/chunks/{exports.js-DUTkELZq.js.map → exports.js-CdqPbjm1.js.map} +1 -1
- package/focus-app/server/chunks/chunks/h2a-bus.js-bLEJ_Adi.js +233 -0
- package/focus-app/server/chunks/chunks/h2a-bus.js-bLEJ_Adi.js.map +1 -0
- package/focus-app/server/chunks/chunks/{index.js-Di21TltP.js → index.js-laGHLarB.js} +5 -2
- package/focus-app/server/chunks/chunks/index.js-laGHLarB.js.map +1 -0
- package/focus-app/server/chunks/chunks/{internal.js-33vbd70h.js → internal.js-C6T8nHkl.js} +4 -4
- package/focus-app/server/chunks/chunks/{internal.js-33vbd70h.js.map → internal.js-C6T8nHkl.js.map} +1 -1
- package/focus-app/server/chunks/chunks/{root.js-DO1m-gJA.js → root.js-CtVQOgDw.js} +2 -2
- package/focus-app/server/chunks/chunks/{root.js-DO1m-gJA.js.map → root.js-CtVQOgDw.js.map} +1 -1
- package/focus-app/server/chunks/entries/endpoints/api/decisions/inject/{_server.ts.js-j0NNcOSZ.js → _server.ts.js-hrbMnsV0.js} +13 -42
- package/focus-app/server/chunks/entries/endpoints/api/decisions/inject/_server.ts.js-hrbMnsV0.js.map +1 -0
- package/focus-app/server/chunks/entries/endpoints/api/dossiers/agent-memory/include/_server.ts.js-Dw4odGdV.js +138 -0
- package/focus-app/server/chunks/entries/endpoints/api/dossiers/agent-memory/include/_server.ts.js-Dw4odGdV.js.map +1 -0
- package/focus-app/server/chunks/entries/endpoints/api/h2a/targets/_server.ts.js-BLjYv7vg.js +41 -0
- package/focus-app/server/chunks/entries/endpoints/api/h2a/targets/_server.ts.js-BLjYv7vg.js.map +1 -0
- package/focus-app/server/chunks/entries/fallbacks/{error.svelte.js-Dj3sETSX.js → error.svelte.js-RbeaNF5a.js} +4 -4
- package/focus-app/server/chunks/entries/fallbacks/{error.svelte.js-Dj3sETSX.js.map → error.svelte.js-RbeaNF5a.js.map} +1 -1
- package/focus-app/server/chunks/entries/pages/{_layout.svelte.js-BoLsbuC2.js → _layout.svelte.js-e1E_I04z.js} +2 -2
- package/focus-app/server/chunks/entries/pages/{_layout.svelte.js-BoLsbuC2.js.map → _layout.svelte.js-e1E_I04z.js.map} +1 -1
- package/focus-app/server/chunks/entries/pages/{_page.svelte.js-QDldMYhk.js → _page.svelte.js-DbaEG23x.js} +31 -1373
- package/focus-app/server/chunks/entries/pages/_page.svelte.js-DbaEG23x.js.map +1 -0
- package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.server.ts.js-CFC-wn6U.js +88 -0
- package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.server.ts.js-CFC-wn6U.js.map +1 -0
- package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.svelte.js-BpR26NMa.js +1574 -0
- package/focus-app/server/chunks/entries/pages/dossier/agent-memory/_page.svelte.js-BpR26NMa.js.map +1 -0
- package/focus-app/server/chunks/{handler-Cp_5hLyY.js → handler-Be3dyNi0.js} +3 -3
- package/focus-app/server/chunks/{handler-Cp_5hLyY.js.map → handler-Be3dyNi0.js.map} +1 -1
- package/focus-app/server/chunks/{index.js-CBh7Wjqp.js → index.js-siUxMMnK.js} +3 -3
- package/focus-app/server/chunks/{index.js-CBh7Wjqp.js.map → index.js-siUxMMnK.js.map} +1 -1
- package/focus-app/server/chunks/manifest.js-CXJqSHHn.js +78 -0
- package/focus-app/server/chunks/manifest.js-CXJqSHHn.js.map +1 -0
- package/focus-app/server/chunks/nodes/0.js-leU6sfRR.js +9 -0
- package/focus-app/server/chunks/nodes/{0.js-4wlmdsk8.js.map → 0.js-leU6sfRR.js.map} +1 -1
- package/focus-app/server/chunks/nodes/1.js-os6QXm6B.js +9 -0
- package/focus-app/server/chunks/nodes/{1.js-B-LpY-lC.js.map → 1.js-os6QXm6B.js.map} +1 -1
- package/focus-app/server/chunks/nodes/2.js-DAaLjh93.js +19 -0
- package/focus-app/server/chunks/nodes/2.js-DAaLjh93.js.map +1 -0
- package/focus-app/server/chunks/nodes/3.js-Cmgi6Uy0.js +18 -0
- package/focus-app/server/chunks/nodes/3.js-Cmgi6Uy0.js.map +1 -0
- package/package.json +2 -2
- package/skills/h2a-run/SKILL.md +100 -0
- package/focus-app/client/_app/immutable/assets/0.BdzHFb9q.css.br +0 -2
- package/focus-app/client/_app/immutable/assets/0.BdzHFb9q.css.gz +0 -0
- package/focus-app/client/_app/immutable/assets/2.Ddxq02y4.css +0 -1
- package/focus-app/client/_app/immutable/assets/2.Ddxq02y4.css.br +0 -0
- package/focus-app/client/_app/immutable/assets/2.Ddxq02y4.css.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/Bs3f1UbD.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/Bs3f1UbD.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/Bv8OL8ib.js +0 -1
- package/focus-app/client/_app/immutable/chunks/Bv8OL8ib.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/Bv8OL8ib.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/CVq_IFFr.js +0 -2
- package/focus-app/client/_app/immutable/chunks/CVq_IFFr.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/CVq_IFFr.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/Cj6wo28J.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/Cj6wo28J.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/DEmooz0s.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/DEmooz0s.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/DQIRXgdC.js +0 -2
- package/focus-app/client/_app/immutable/chunks/DQIRXgdC.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/DQIRXgdC.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/ZxFklh9T.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/ZxFklh9T.js.gz +0 -0
- package/focus-app/client/_app/immutable/chunks/_wRuVGPs.js +0 -1
- package/focus-app/client/_app/immutable/chunks/_wRuVGPs.js.br +0 -0
- package/focus-app/client/_app/immutable/chunks/_wRuVGPs.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/app.6DKouWRt.js +0 -2
- package/focus-app/client/_app/immutable/entry/app.6DKouWRt.js.br +0 -0
- package/focus-app/client/_app/immutable/entry/app.6DKouWRt.js.gz +0 -0
- package/focus-app/client/_app/immutable/entry/start.DlLmkUb7.js +0 -1
- package/focus-app/client/_app/immutable/entry/start.DlLmkUb7.js.br +0 -2
- package/focus-app/client/_app/immutable/entry/start.DlLmkUb7.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/0.CuSOF0Of.js +0 -5
- package/focus-app/client/_app/immutable/nodes/0.CuSOF0Of.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/0.CuSOF0Of.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/1.D39jdnqm.js +0 -1
- package/focus-app/client/_app/immutable/nodes/1.D39jdnqm.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/1.D39jdnqm.js.gz +0 -0
- package/focus-app/client/_app/immutable/nodes/2.CnU8ifRl.js +0 -1
- package/focus-app/client/_app/immutable/nodes/2.CnU8ifRl.js.br +0 -0
- package/focus-app/client/_app/immutable/nodes/2.CnU8ifRl.js.gz +0 -0
- package/focus-app/server/chunks/chunks/index.js-Di21TltP.js.map +0 -1
- package/focus-app/server/chunks/entries/endpoints/api/decisions/inject/_server.ts.js-j0NNcOSZ.js.map +0 -1
- package/focus-app/server/chunks/entries/pages/_page.svelte.js-QDldMYhk.js.map +0 -1
- package/focus-app/server/chunks/manifest.js-Cm6cC7mC.js +0 -56
- package/focus-app/server/chunks/manifest.js-Cm6cC7mC.js.map +0 -1
- package/focus-app/server/chunks/nodes/0.js-4wlmdsk8.js +0 -9
- package/focus-app/server/chunks/nodes/1.js-B-LpY-lC.js +0 -9
- package/focus-app/server/chunks/nodes/2.js-F6jp5eD9.js +0 -19
- package/focus-app/server/chunks/nodes/2.js-F6jp5eD9.js.map +0 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import type { H2AActorRef, H2AActorRegistration, H2AAgentVersion, H2ASession, H2ASessionInterests, H2ASessionNotificationTopic, H2ASessionState, H2ASubagentBinding, H2AWorkStatus, H2AWorkspaceRef } from "@sentropic/h2a";
|
|
2
|
+
/**
|
|
3
|
+
* Why a field is withheld. A closed vocabulary rather than free text: the
|
|
4
|
+
* reasons are asserted by tests and read by reviewers, and "some comment
|
|
5
|
+
* somewhere" is not a contract.
|
|
6
|
+
*/
|
|
7
|
+
export type MirrorWithholdReason =
|
|
8
|
+
/** A real path on the sender's filesystem. */
|
|
9
|
+
"filesystem-path"
|
|
10
|
+
/** A command line — reveals tooling, flags, and often paths inside it. */
|
|
11
|
+
| "command-line"
|
|
12
|
+
/** Identifies a process on the sender's machine (pid, tty). */
|
|
13
|
+
| "process-identity"
|
|
14
|
+
/** tmux session/window/pane — coordinates of a live terminal. */
|
|
15
|
+
| "terminal-coordinates"
|
|
16
|
+
/** The RECEIVER establishes this itself; a sender's value would be a forgery. */
|
|
17
|
+
| "receiver-stamped"
|
|
18
|
+
/** Nothing downstream reads it, so it has no business travelling. */
|
|
19
|
+
| "not-consumed-downstream";
|
|
20
|
+
interface SendPlan {
|
|
21
|
+
readonly kind: "send";
|
|
22
|
+
}
|
|
23
|
+
interface WithholdPlan {
|
|
24
|
+
readonly kind: "withhold";
|
|
25
|
+
readonly because: MirrorWithholdReason;
|
|
26
|
+
}
|
|
27
|
+
interface NarrowPlan<T> {
|
|
28
|
+
readonly kind: "narrow";
|
|
29
|
+
readonly narrow: (value: NonNullable<T>) => unknown;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A value that may be transmitted VERBATIM: a primitive, or an array of
|
|
33
|
+
* primitives. Deliberately narrow — an array of arrays or an array of objects is
|
|
34
|
+
* composite and does not qualify.
|
|
35
|
+
*
|
|
36
|
+
* This is the type that makes "no composite is ever copied by reference" a
|
|
37
|
+
* STRUCTURAL property instead of a convention, and it exists because convention
|
|
38
|
+
* demonstrably was not enough. The `interests` leak this module was written to
|
|
39
|
+
* fix was precisely a composite classified `send`: `applyPlan` copied the whole
|
|
40
|
+
* object by reference, `isInterests` tolerated the extra keys, and a nested
|
|
41
|
+
* `cwd`/`pid`/tmux payload came to rest on the receiver's disk. The field plan
|
|
42
|
+
* was already in place at the time. It forced a classification and the
|
|
43
|
+
* classification was `send`, which is a LEGAL classification — so the ratchet
|
|
44
|
+
* fired, was answered, and the leak shipped anyway.
|
|
45
|
+
*
|
|
46
|
+
* A plan that forces you to classify does not force you to classify CORRECTLY.
|
|
47
|
+
* Making `send` inexpressible for a composite removes the wrong answer from the
|
|
48
|
+
* menu rather than trusting the next author not to pick it.
|
|
49
|
+
*
|
|
50
|
+
* ── WHERE THIS RULE STOPS ──────────────────────────────────────────────────
|
|
51
|
+
*
|
|
52
|
+
* It is structural for any field with a real type, and it is NOT structural for
|
|
53
|
+
* a field typed `any`: a conditional type on `any` resolves to both branches, so
|
|
54
|
+
* `SEND` stays assignable and the compiler says nothing. `unknown` is fine
|
|
55
|
+
* (forced to `narrow`); `any` is the hole, and `any` is exactly what a field
|
|
56
|
+
* added in a hurry looks like. That case is covered one rung lower, by a runtime
|
|
57
|
+
* test that reads the plans directly rather than through a fixture
|
|
58
|
+
* (`mirror-send-boundary.test.js`, "no plan classifies a COMPOSITE field as
|
|
59
|
+
* `send`"). Naming the boundary here rather than letting "structural" be heard
|
|
60
|
+
* as "total".
|
|
61
|
+
*/
|
|
62
|
+
type MirrorSendableValue = string | number | boolean | readonly (string | number | boolean)[];
|
|
63
|
+
/**
|
|
64
|
+
* How one source field is treated at the send boundary.
|
|
65
|
+
*
|
|
66
|
+
* `send` is only in the union when the field's type is a
|
|
67
|
+
* {@link MirrorSendableValue}. For a composite field the union collapses to
|
|
68
|
+
* `withhold | narrow`, so `SEND` is not assignable and the build fails until the
|
|
69
|
+
* field gets a plan of its own. That is the difference between "the ratchet
|
|
70
|
+
* forces you to classify" and "the ratchet forces a classification that cannot
|
|
71
|
+
* copy by reference".
|
|
72
|
+
*/
|
|
73
|
+
export type MirrorFieldPlan<T> = ([NonNullable<T>] extends [MirrorSendableValue] ? SendPlan : never) | WithholdPlan | NarrowPlan<T>;
|
|
74
|
+
/** Never transmitted, with the reason recorded in the closed vocabulary. */
|
|
75
|
+
declare function withhold(because: MirrorWithholdReason): WithholdPlan;
|
|
76
|
+
/** Transmitted, but through its own nested allowlist. */
|
|
77
|
+
declare function narrow<T>(fn: (value: NonNullable<T>) => unknown): NarrowPlan<T>;
|
|
78
|
+
/** A plan covering EVERY field of `Source` — the `satisfies` target. */
|
|
79
|
+
type MirrorPlanFor<Source> = {
|
|
80
|
+
readonly [K in keyof Required<Source>]: MirrorFieldPlan<Required<Source>[K]>;
|
|
81
|
+
};
|
|
82
|
+
/** Keys a plan withholds. */
|
|
83
|
+
type WithheldKey<Plan> = {
|
|
84
|
+
[K in keyof Plan]: Plan[K] extends WithholdPlan ? K : never;
|
|
85
|
+
}[keyof Plan];
|
|
86
|
+
/** Keys a plan transmits (verbatim or narrowed). */
|
|
87
|
+
type SentKey<Plan> = Exclude<keyof Plan, WithheldKey<Plan>>;
|
|
88
|
+
/**
|
|
89
|
+
* Compile-time type equality. Used to pin each `H2AMirrored*` wire type's key
|
|
90
|
+
* set to its plan: if they drift, `true` stops being assignable to `false` and
|
|
91
|
+
* the build fails.
|
|
92
|
+
*/
|
|
93
|
+
type Exact<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
|
|
94
|
+
/**
|
|
95
|
+
* Apply a plan: iterate the PLAN (never the record's own keys) and copy only
|
|
96
|
+
* what it permits.
|
|
97
|
+
*
|
|
98
|
+
* Iterating the plan is what makes this an allowlist rather than a filter — an
|
|
99
|
+
* unclassified field on `record` is not skipped, it is never looked at. Absent
|
|
100
|
+
* values are omitted rather than serialized as `undefined`, so the payload keeps
|
|
101
|
+
* the same "optional field absent" shape the store and the guards expect.
|
|
102
|
+
*
|
|
103
|
+
* ── THE TWO RUNTIME CHECKS, AND WHY A TYPE IS NOT ENOUGH ───────────────────
|
|
104
|
+
*
|
|
105
|
+
* Both exist because this function's input is UNVALIDATED. The compile-time
|
|
106
|
+
* ratchet governs the plan; nothing governs the record.
|
|
107
|
+
*
|
|
108
|
+
* - A `send` value that is not a primitive or an array of primitives is
|
|
109
|
+
* DROPPED. The declared type says what the field must be, so anything else is
|
|
110
|
+
* a lie, and a lie shaped like an object is how a `cwd` and a command line
|
|
111
|
+
* ride out through a field declared `string`. Dropped rather than thrown:
|
|
112
|
+
* throwing here would let any hostile registry row kill the push for every
|
|
113
|
+
* session on the machine, trading availability for a confidentiality win
|
|
114
|
+
* that dropping already secures. If the dropped field was required, the
|
|
115
|
+
* receiver's own guard rejects the record — fail-closed, and visible.
|
|
116
|
+
* - A `narrow` whose output was not itself built by this function is DROPPED.
|
|
117
|
+
* `NarrowPlan.narrow` is an arbitrary callback returning `unknown`, so
|
|
118
|
+
* `narrow((value) => value)` — an identity narrow — type-checks and copies a
|
|
119
|
+
* composite wholesale, which is precisely the leak the plans exist to stop.
|
|
120
|
+
* The compiler cannot reject it (identity returns a structurally compatible
|
|
121
|
+
* type), so the membership test in {@link PLAN_BUILT} does.
|
|
122
|
+
*
|
|
123
|
+
* `null` is passed THROUGH to a narrow rather than short-circuited, so the
|
|
124
|
+
* narrow's own hostile-input handling can run. That is what makes
|
|
125
|
+
* `endpoints: null` produce `[]` instead of an absent field.
|
|
126
|
+
*/
|
|
127
|
+
declare function applyPlan<Source extends object>(record: Source, plan: MirrorPlanFor<Source>): Record<string, unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* {@link applyPlan} and the plan constructors, exported for the send-boundary
|
|
130
|
+
* tests ONLY.
|
|
131
|
+
*
|
|
132
|
+
* Exporting internals to test them is usually a smell. It is justified here
|
|
133
|
+
* because the property under test is "a hostile PLAN cannot defeat the
|
|
134
|
+
* boundary", and a plan cannot be made hostile from outside without these. The
|
|
135
|
+
* alternative — trusting that no future plan uses an identity narrow — is the
|
|
136
|
+
* assumption this module exists to eliminate.
|
|
137
|
+
*/
|
|
138
|
+
export declare const MIRROR_TEST_HOOKS: {
|
|
139
|
+
readonly applyPlan: typeof applyPlan;
|
|
140
|
+
readonly send: SendPlan;
|
|
141
|
+
readonly narrow: typeof narrow;
|
|
142
|
+
readonly withhold: typeof withhold;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Fields present on `record` that the plan does not classify at all.
|
|
146
|
+
*
|
|
147
|
+
* **This is a TEST-TIME assertion helper, not a runtime half of the ratchet.**
|
|
148
|
+
* It is called from `test/mirror-send-boundary.test.js` and from nowhere on the
|
|
149
|
+
* send path, and the earlier claim that it "covers the paths the compiler cannot
|
|
150
|
+
* see" was wider than what is built — a guard that is never invoked cannot cover
|
|
151
|
+
* anything. It is kept, and kept exported, because it is what lets a test fail by
|
|
152
|
+
* NAMING the unclassified field instead of asserting an opaque key-set equality.
|
|
153
|
+
*
|
|
154
|
+
* It is deliberately not wired into the builders. Two reasons, and the second is
|
|
155
|
+
* the honest one: (a) throwing on an unclassified field would turn an additive,
|
|
156
|
+
* harmless field into a dead mirror pipeline — availability lost for no
|
|
157
|
+
* confidentiality gained, since `applyPlan` never reads the field anyway; and
|
|
158
|
+
* (b) the alternative, warning or counting, would make this module impure, and
|
|
159
|
+
* the purity claim above ("everything here is PURE and happens before signing")
|
|
160
|
+
* is load-bearing for the signature argument. The ratchet that actually holds is
|
|
161
|
+
* the compiler (`satisfies MirrorPlanFor<Source>` on every plan in the table) plus
|
|
162
|
+
* plan-iteration in {@link applyPlan}. There is no runtime ratchet; if one is
|
|
163
|
+
* wanted it belongs in the caller, where a side effect is allowed.
|
|
164
|
+
*/
|
|
165
|
+
export declare function unclassifiedMirrorFields(record: object, plan: Record<string, unknown>): string[];
|
|
166
|
+
/**
|
|
167
|
+
* A workspace as it may LEAVE the machine: identity + label, never a path.
|
|
168
|
+
*
|
|
169
|
+
* `H2AWorkspaceRef.path` is "the absolute realpath on **this machine**" — by its
|
|
170
|
+
* own definition it means nothing on any other host, and it is the single field
|
|
171
|
+
* the feed's opacity boundary names first. `repo` is withheld too: nothing
|
|
172
|
+
* downstream reads it and a git remote may itself be a local filesystem path.
|
|
173
|
+
*
|
|
174
|
+
* `id` survives because it lets a UI GROUP an owner's agents by place and because
|
|
175
|
+
* it is not reversible into a path. Be precise about WHY it is not, because the
|
|
176
|
+
* usual shorthand ("the salted `ws:<uuid>` digest") describes the wrong branch:
|
|
177
|
+
*
|
|
178
|
+
* - The PRIMARY id, tried first at `runtime/identity/live.ts`, is
|
|
179
|
+
* `durableWorkspaceId` (`runtime/identity/workspace-id.ts`) — an **unsalted**
|
|
180
|
+
* `sha256(rootCommitSHA + "\n" + worktreeRelPath)` rendered as `ws:<64 hex>`.
|
|
181
|
+
* Both inputs are PUBLIC: the repo's root-commit SHAs and a worktree name. It
|
|
182
|
+
* carries no path because the path is not an input, not because a secret hides
|
|
183
|
+
* it — so it is portable across clones by design, and an observer who already
|
|
184
|
+
* knows the repo can confirm a guess at the worktree name. That is the actual
|
|
185
|
+
* property, and it is weaker than "salted digest" implies.
|
|
186
|
+
* - The SECOND fallback is `provider.workspaceHint`, which for `host: "remote"`
|
|
187
|
+
* is the **unconstrained** `SESSION_WORKSPACE_ID` env var (`identity/
|
|
188
|
+
* resolver.ts` checks truthiness only — no prefix, charset or length check).
|
|
189
|
+
* - Only the THIRD fallback, reached in a non-git directory, is the salted
|
|
190
|
+
* `deriveWorkspaceId` (`identity.ts`: `sha256(machineId \0 realpath)` as
|
|
191
|
+
* `ws:<uuid>`). It is the branch the old comment described and the one least
|
|
192
|
+
* often taken.
|
|
193
|
+
*
|
|
194
|
+
* None of the three transmits a path, which is the property this boundary needs;
|
|
195
|
+
* the rationale is corrected because an inaccurate rationale inside a security
|
|
196
|
+
* module is how the next reader over-trusts the field.
|
|
197
|
+
*
|
|
198
|
+
* `host` survives because it is a CLI name (`claude` / `codex` / ...) and because
|
|
199
|
+
* `isH2AWorkspaceRef` requires it — see the note on `path` in `identity.ts`.
|
|
200
|
+
*/
|
|
201
|
+
export interface H2AMirroredWorkspaceRef {
|
|
202
|
+
readonly id: string;
|
|
203
|
+
readonly host: string;
|
|
204
|
+
readonly label: string;
|
|
205
|
+
}
|
|
206
|
+
declare const WORKSPACE_PLAN: {
|
|
207
|
+
id: SendPlan;
|
|
208
|
+
host: SendPlan;
|
|
209
|
+
label: SendPlan;
|
|
210
|
+
path: WithholdPlan;
|
|
211
|
+
repo: WithholdPlan;
|
|
212
|
+
};
|
|
213
|
+
/** The plan, for tests. */
|
|
214
|
+
export declare const MIRROR_WORKSPACE_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
215
|
+
/** Pins {@link H2AMirroredWorkspaceRef} to {@link WORKSPACE_PLAN}. */
|
|
216
|
+
export type WorkspaceKeysMatchPlan = Exact<keyof H2AMirroredWorkspaceRef, SentKey<typeof WORKSPACE_PLAN>>;
|
|
217
|
+
export declare function sanitizeWorkspaceRefForMirror(workspace: H2AWorkspaceRef): H2AMirroredWorkspaceRef;
|
|
218
|
+
/** The plan, for tests. */
|
|
219
|
+
export declare const MIRROR_VERSION_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
220
|
+
/**
|
|
221
|
+
* Session interests as they may LEAVE the machine.
|
|
222
|
+
*
|
|
223
|
+
* This type and its plan exist because `interests` used to be classified `SEND`,
|
|
224
|
+
* which made {@link applyPlan} copy the whole object **by reference**. The
|
|
225
|
+
* consequence was not theoretical: `isH2ASession` validates `interests` through a
|
|
226
|
+
* two-field spot-check (`session.ts` `isInterests` asserts `scopes` and
|
|
227
|
+
* `negotiations` are string arrays and does **not** reject extra keys), so a
|
|
228
|
+
* record carrying `interests: { scopes: [], negotiations: [], lc: { tmux: …,
|
|
229
|
+
* cwd: …, pid: … } }` was well-formed by the guard, travelled whole, and came to
|
|
230
|
+
* rest on the receiver's disk. A nested composite reached by reference is outside
|
|
231
|
+
* both halves of the ratchet: the plan cannot filter what it does not iterate,
|
|
232
|
+
* and `satisfies MirrorPlanFor<H2ASession>` says nothing about the fields of
|
|
233
|
+
* `H2ASessionInterests`.
|
|
234
|
+
*
|
|
235
|
+
* Both fields are transmitted — the hosted `writePresence` REQUIRES them, since
|
|
236
|
+
* `isInterests` rejects a record missing either — but the object is now rebuilt
|
|
237
|
+
* from the plan rather than passed through, so a third field cannot ride along.
|
|
238
|
+
* The element VALUES stay free text: `runtime/mcp/sessions.ts` copies
|
|
239
|
+
* `interests.scopes` verbatim from the `h2a_session_open` caller, so a scope
|
|
240
|
+
* naming a real directory is transmissible and is disclosed as such. A field
|
|
241
|
+
* allowlist bounds the SHAPE, never the content.
|
|
242
|
+
*/
|
|
243
|
+
export interface H2AMirroredSessionInterests {
|
|
244
|
+
readonly scopes: readonly string[];
|
|
245
|
+
readonly negotiations: readonly string[];
|
|
246
|
+
}
|
|
247
|
+
declare const INTERESTS_PLAN: {
|
|
248
|
+
scopes: SendPlan;
|
|
249
|
+
negotiations: SendPlan;
|
|
250
|
+
};
|
|
251
|
+
/** The plan, for tests. */
|
|
252
|
+
export declare const MIRROR_INTERESTS_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
253
|
+
/** Pins {@link H2AMirroredSessionInterests} to {@link INTERESTS_PLAN}. */
|
|
254
|
+
export type InterestsKeysMatchPlan = Exact<keyof H2AMirroredSessionInterests, SentKey<typeof INTERESTS_PLAN>>;
|
|
255
|
+
/**
|
|
256
|
+
* A presence record as it may LEAVE the machine.
|
|
257
|
+
*
|
|
258
|
+
* Assignable to `H2ASession` on purpose: the hosted ingester writes it through
|
|
259
|
+
* `writePresence`, which validates with `isH2ASession`, and the feed's
|
|
260
|
+
* descriptor builders consume it as a session. Narrowing the payload therefore
|
|
261
|
+
* required exactly one type change elsewhere — `H2AWorkspaceRef.path` became
|
|
262
|
+
* optional, because a type that makes a filesystem path MANDATORY on every
|
|
263
|
+
* workspace reference cannot express a sanitized reference at all. That
|
|
264
|
+
* mandatory field was compelling the leak, not merely permitting it.
|
|
265
|
+
*/
|
|
266
|
+
export interface H2AMirroredSession {
|
|
267
|
+
readonly sessionId: string;
|
|
268
|
+
readonly instance: string;
|
|
269
|
+
readonly host?: string;
|
|
270
|
+
readonly name?: string;
|
|
271
|
+
readonly startedAt: string;
|
|
272
|
+
readonly heartbeatAt: string;
|
|
273
|
+
readonly state: H2ASessionState;
|
|
274
|
+
readonly interests: H2AMirroredSessionInterests;
|
|
275
|
+
readonly subscribedTopics: readonly H2ASessionNotificationTopic[];
|
|
276
|
+
readonly workStatus?: H2AWorkStatus;
|
|
277
|
+
readonly lastMcpActivityAt?: string;
|
|
278
|
+
readonly version?: H2AAgentVersion;
|
|
279
|
+
readonly workspace?: H2AMirroredWorkspaceRef;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Every field of `H2ASession`, classified.
|
|
283
|
+
*
|
|
284
|
+
* The `send` set is exactly what a consumer of the mirror demonstrably needs:
|
|
285
|
+
* - `sessionId` / `instance` — the row's own identity (`accept.ts` authorizes a
|
|
286
|
+
* session by `instance`; the feed keys rows on both);
|
|
287
|
+
* - `startedAt` / `heartbeatAt` / `state` / `lastMcpActivityAt` — the liveness
|
|
288
|
+
* derivation (`deriveSessionState`, `deriveLiveness`, `isSessionExpired`);
|
|
289
|
+
* - `interests` / `subscribedTopics` — required by `isH2ASession`, so the
|
|
290
|
+
* hosted `writePresence` rejects the record without them;
|
|
291
|
+
* - `host` / `name` / `workspace` — the feed's `host`, `topicOrTitle`,
|
|
292
|
+
* `displayName` and `workspaceLabel`;
|
|
293
|
+
* - `workStatus` / `version` — closed vocabularies, shown by `h2a_discover_*`.
|
|
294
|
+
*/
|
|
295
|
+
declare const PRESENCE_PLAN: {
|
|
296
|
+
sessionId: SendPlan;
|
|
297
|
+
instance: SendPlan;
|
|
298
|
+
host: SendPlan;
|
|
299
|
+
name: SendPlan;
|
|
300
|
+
startedAt: SendPlan;
|
|
301
|
+
heartbeatAt: SendPlan;
|
|
302
|
+
state: SendPlan;
|
|
303
|
+
interests: NarrowPlan<H2ASessionInterests>;
|
|
304
|
+
subscribedTopics: SendPlan;
|
|
305
|
+
workStatus: SendPlan;
|
|
306
|
+
lastMcpActivityAt: SendPlan;
|
|
307
|
+
version: NarrowPlan<H2AAgentVersion>;
|
|
308
|
+
workspace: NarrowPlan<H2AWorkspaceRef>;
|
|
309
|
+
launchContext: WithholdPlan;
|
|
310
|
+
pid: WithholdPlan;
|
|
311
|
+
mirroredAt: WithholdPlan;
|
|
312
|
+
};
|
|
313
|
+
/** The plan, for tests and for callers that want to state the contract. */
|
|
314
|
+
export declare const MIRROR_PRESENCE_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
315
|
+
/** Pins {@link H2AMirroredSession} to {@link PRESENCE_PLAN}. */
|
|
316
|
+
export type PresenceKeysMatchPlan = Exact<keyof H2AMirroredSession, SentKey<typeof PRESENCE_PLAN>>;
|
|
317
|
+
/** One presence record → the record as it may leave the machine. */
|
|
318
|
+
export declare function sanitizePresenceForMirror(session: H2ASession): H2AMirroredSession;
|
|
319
|
+
/** One endpoint of a registration, as declared locally. */
|
|
320
|
+
type H2AEndpointDeclaration = H2AActorRegistration["endpoints"][number];
|
|
321
|
+
/**
|
|
322
|
+
* One endpoint as it may LEAVE the machine. Its own plan, so a field added to
|
|
323
|
+
* the endpoints ELEMENT type fails the build instead of travelling — before
|
|
324
|
+
* this, the element was copied whole by `Array.prototype.filter`, which is a
|
|
325
|
+
* pass-through, and the ratchet stopped at `H2AActorRegistration`.
|
|
326
|
+
*/
|
|
327
|
+
export interface H2AMirroredEndpoint {
|
|
328
|
+
readonly kind: H2AEndpointDeclaration["kind"];
|
|
329
|
+
readonly uri: string;
|
|
330
|
+
}
|
|
331
|
+
declare const ENDPOINT_PLAN: {
|
|
332
|
+
kind: SendPlan;
|
|
333
|
+
uri: SendPlan;
|
|
334
|
+
};
|
|
335
|
+
/** The plan, for tests. */
|
|
336
|
+
export declare const MIRROR_ENDPOINT_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
337
|
+
/** Pins {@link H2AMirroredEndpoint} to {@link ENDPOINT_PLAN}. */
|
|
338
|
+
export type EndpointKeysMatchPlan = Exact<keyof H2AMirroredEndpoint, SentKey<typeof ENDPOINT_PLAN>>;
|
|
339
|
+
/**
|
|
340
|
+
* A registry row as it may LEAVE the machine. Structurally assignable to
|
|
341
|
+
* `H2AActorRegistration`, which is what the ingest path expects when it applies
|
|
342
|
+
* the row via `store.registerInstance`.
|
|
343
|
+
*
|
|
344
|
+
* That assignability is a TYPE-level property only, and deliberately stated that
|
|
345
|
+
* way: `store.registerInstance` does **not** validate with
|
|
346
|
+
* `isH2AActorRegistration` — nothing in production does (see
|
|
347
|
+
* `sanitizeEndpointsForMirror`). So being assignable is what keeps the compiler
|
|
348
|
+
* honest here; it is not evidence that the receiver checks the shape.
|
|
349
|
+
*/
|
|
350
|
+
export interface H2AMirroredRegistration {
|
|
351
|
+
readonly id: string;
|
|
352
|
+
readonly instance: string;
|
|
353
|
+
readonly roles: H2AActorRegistration["roles"];
|
|
354
|
+
readonly scopes: string[];
|
|
355
|
+
readonly capabilities: string[];
|
|
356
|
+
readonly declaredCapabilities?: string[];
|
|
357
|
+
readonly endpoints: H2AMirroredEndpoint[];
|
|
358
|
+
readonly publicKeys: string[];
|
|
359
|
+
readonly acceptedPolicies: string[];
|
|
360
|
+
readonly createdAt: string;
|
|
361
|
+
readonly principal?: string;
|
|
362
|
+
readonly conductor?: string;
|
|
363
|
+
readonly agentUuid?: string;
|
|
364
|
+
readonly name?: string;
|
|
365
|
+
readonly workspace?: H2AMirroredWorkspaceRef;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Every field of `H2AActorRegistration`, classified.
|
|
369
|
+
*
|
|
370
|
+
* `capabilities` is transmitted DELIBERATELY, though it is authority-bearing and
|
|
371
|
+
* the feed never displays it. Two gates on the RECEIVING side read it off the
|
|
372
|
+
* registry row: the subagent capability ceiling (`subagents.ts`
|
|
373
|
+
* `capabilities-exceed-parent` compares a binding against `parent.capabilities`)
|
|
374
|
+
* and the attestation right (`canAttestComprehension(role,
|
|
375
|
+
* registration.capabilities)` in `mcp/handlers.ts`). Withholding it would not be
|
|
376
|
+
* "sanitizing" — it would silently change an authorization outcome on the
|
|
377
|
+
* receiver, which is a worse failure than the one being fixed. It carries no
|
|
378
|
+
* path, no command and no process identity.
|
|
379
|
+
*/
|
|
380
|
+
declare const REGISTRATION_PLAN: {
|
|
381
|
+
id: SendPlan;
|
|
382
|
+
instance: SendPlan;
|
|
383
|
+
roles: SendPlan;
|
|
384
|
+
scopes: SendPlan;
|
|
385
|
+
capabilities: SendPlan;
|
|
386
|
+
declaredCapabilities: SendPlan;
|
|
387
|
+
publicKeys: SendPlan;
|
|
388
|
+
acceptedPolicies: SendPlan;
|
|
389
|
+
createdAt: SendPlan;
|
|
390
|
+
principal: SendPlan;
|
|
391
|
+
conductor: SendPlan;
|
|
392
|
+
agentUuid: SendPlan;
|
|
393
|
+
name: SendPlan;
|
|
394
|
+
endpoints: NarrowPlan<{
|
|
395
|
+
kind: "mcp" | "local-files" | "remote";
|
|
396
|
+
uri: string;
|
|
397
|
+
}[]>;
|
|
398
|
+
workspace: NarrowPlan<H2AWorkspaceRef>;
|
|
399
|
+
};
|
|
400
|
+
/** The plan, for tests. */
|
|
401
|
+
export declare const MIRROR_REGISTRATION_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
402
|
+
/** Pins {@link H2AMirroredRegistration} to {@link REGISTRATION_PLAN}. */
|
|
403
|
+
export type RegistrationKeysMatchPlan = Exact<keyof H2AMirroredRegistration, SentKey<typeof REGISTRATION_PLAN>>;
|
|
404
|
+
export declare function sanitizeRegistrationForMirror(registration: H2AActorRegistration): H2AMirroredRegistration;
|
|
405
|
+
/**
|
|
406
|
+
* The envelope's `actor`, derived from the SANITIZED registration.
|
|
407
|
+
*
|
|
408
|
+
* Taking `H2AMirroredRegistration` rather than `H2AActorRegistration` is the
|
|
409
|
+
* whole point and is worth not "simplifying" later: the raw record is not in
|
|
410
|
+
* scope here, so this function CANNOT read a withheld field even by mistake.
|
|
411
|
+
* Every value it can reach has already been through {@link REGISTRATION_PLAN},
|
|
412
|
+
* which makes "the envelope carries nothing the body does not already carry" a
|
|
413
|
+
* consequence of the signature instead of a claim in a comment.
|
|
414
|
+
*
|
|
415
|
+
* `role` is re-intersected against `H2A_ROLES`. That is a genuinely closed
|
|
416
|
+
* vocabulary check, not a shape check: `roles[]` element VALUES are otherwise
|
|
417
|
+
* free text (disclosed above), and this is the one place where an element value
|
|
418
|
+
* escapes the body into the envelope, so it is the one place worth closing.
|
|
419
|
+
*
|
|
420
|
+
* ── STRUCK, AND LEFT VISIBLE ON PURPOSE ────────────────────────────────────
|
|
421
|
+
*
|
|
422
|
+
* An earlier version of this comment continued: ~~"`isH2AEnvelope` requires a
|
|
423
|
+
* vocabulary role anyway, so a non-role here produced an envelope that fails the
|
|
424
|
+
* protocol's own guard."~~ **That is false.** `isH2AEnvelope` delegates to
|
|
425
|
+
* `validateH2AEnvelope` (`envelope.ts:109`), which checks `actor` only for
|
|
426
|
+
* `typeof actor.instance === "string"`. It never looks at `role`. Measured:
|
|
427
|
+
*
|
|
428
|
+
* isH2AEnvelope(actor.role = "/home/antoinefa/NOTAROLE") -> true
|
|
429
|
+
* isH2AEnvelope(actor with no role at all) -> true
|
|
430
|
+
* isH2AEnvelope(actor with no instance) -> false
|
|
431
|
+
*
|
|
432
|
+
* There IS a function that checks the vocabulary — `isActorRef`, `envelope.ts:27`
|
|
433
|
+
* — but it is module-private and referenced nowhere in the tree. A guard that
|
|
434
|
+
* cannot fire.
|
|
435
|
+
*
|
|
436
|
+
* The sentence is struck rather than deleted because of what it was doing: it
|
|
437
|
+
* supplied a REASON TO DELETE THE RE-INTERSECTION BELOW. "The protocol guard
|
|
438
|
+
* catches it anyway" is exactly the argument someone would use to remove that
|
|
439
|
+
* line, and removing it restores the leak. A false justification for a live
|
|
440
|
+
* guard is more dangerous than no justification at all — nothing downstream
|
|
441
|
+
* validates this field, so the check here is the only one there is.
|
|
442
|
+
*
|
|
443
|
+
* `scope` is NOT closed — there is no scope vocabulary to close it against — but
|
|
444
|
+
* it is now sourced from the sanitized registration rather than hardcoded, so
|
|
445
|
+
* the trap is disarmed by construction: the "obvious edit" has already been made
|
|
446
|
+
* here, safely, under test. Its value is free text and rides out under the same
|
|
447
|
+
* disclosed gap as `scopes[]` in the body, which already transmits it verbatim.
|
|
448
|
+
*/
|
|
449
|
+
export declare function sanitizeActorForMirror(instance: string, mirrored: H2AMirroredRegistration): H2AActorRef;
|
|
450
|
+
/**
|
|
451
|
+
* A subagent (NHI) binding as it may leave the machine. Every field is
|
|
452
|
+
* transmitted — checked one by one, none is a path, a command or a process id —
|
|
453
|
+
* but the plan exists anyway, so a future field on `H2ASubagentBinding` must be
|
|
454
|
+
* classified before it can travel. That is the ratchet, not a formality: this
|
|
455
|
+
* payload member had no boundary of its own before.
|
|
456
|
+
*/
|
|
457
|
+
export interface H2AMirroredSubagentBinding {
|
|
458
|
+
readonly id: string;
|
|
459
|
+
readonly parentInstance: string;
|
|
460
|
+
readonly name: string;
|
|
461
|
+
readonly capabilities?: readonly string[];
|
|
462
|
+
readonly createdAt: string;
|
|
463
|
+
}
|
|
464
|
+
declare const SUBAGENT_PLAN: {
|
|
465
|
+
id: SendPlan;
|
|
466
|
+
parentInstance: SendPlan;
|
|
467
|
+
name: SendPlan;
|
|
468
|
+
capabilities: SendPlan;
|
|
469
|
+
createdAt: SendPlan;
|
|
470
|
+
};
|
|
471
|
+
/** The plan, for tests. */
|
|
472
|
+
export declare const MIRROR_SUBAGENT_PLAN: Readonly<Record<string, MirrorFieldPlan<never>>>;
|
|
473
|
+
/** Pins {@link H2AMirroredSubagentBinding} to {@link SUBAGENT_PLAN}. */
|
|
474
|
+
export type SubagentKeysMatchPlan = Exact<keyof H2AMirroredSubagentBinding, SentKey<typeof SUBAGENT_PLAN>>;
|
|
475
|
+
export declare function sanitizeSubagentForMirror(binding: H2ASubagentBinding): H2AMirroredSubagentBinding;
|
|
476
|
+
export {};
|
|
477
|
+
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../../src/runtime/mirror/sanitize.ts"],"names":[],"mappings":"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"}
|