@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
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -58,6 +58,7 @@ import { runCli as runTrackCli } from "@sentropic/track";
|
|
|
58
58
|
// `install-skills` renders `harness-<name>` from it (no hard-coded list, no
|
|
59
59
|
// skill copies committed here; SOURCE UNIQUE = the installed npm package).
|
|
60
60
|
import { runHarnessCli, HARNESS_SKILLS } from "./vendor/harness/index.js";
|
|
61
|
+
import { renderCommandMap } from "./cli-command-map.js";
|
|
61
62
|
import { H2A_ATTESTER_COMPREHENSION_RIGHT, H2A_COMPREHENSION_ATTESTATION_BODY_KIND, H2A_DECLARATION_INTERET_BODY_KIND, H2A_ORG_MANIFEST_FILENAME, H2A_ORG_PROPOSAL_BODY_KIND, H2A_ORG_RATIFIED_BODY_KIND, H2A_ROLES, H2A_WORK_STATUSES, auditNhiPosture, buildComprehensionAttestation, canAttestComprehension, checkEnvelopeFreshness, computeHash, createEnvelope, deriveWorkspaceId, diffOrgManifest, effectiveOrgInstances, isComprehensionAttestation, nhiAttestationEnvelope, nhiInventory, deriveConnectionConfidence, nhiTrustBundle, orgAssignmentEnvelope, parseOrgManifest, signCanonical, signEnvelope, subagentAddress, validateOrgManifest, verifyComprehensionAttestation } from "@sentropic/h2a";
|
|
62
63
|
import { H2A_CLAUDE_HOST } from "./hosts/claude.js";
|
|
63
64
|
import { H2A_CODEX_HOST } from "./hosts/codex.js";
|
|
@@ -72,7 +73,7 @@ import { H2A_MCP_READY_FILE_ENV, H2A_MCP_READY_NONCE_ENV, runMcpStdio } from "./
|
|
|
72
73
|
import { renderK8sSidecar } from "./runtime/deploy/k8s-sidecar.js";
|
|
73
74
|
import { renderK8sTenant } from "./runtime/deploy/k8s-tenant.js";
|
|
74
75
|
import { remoteServerForStore, sendRemoteEnvelope } from "./runtime/remote/index.js";
|
|
75
|
-
import { buildInstanceMirror, mirrorServerForStore } from "./runtime/mirror/index.js";
|
|
76
|
+
import { buildInstanceMirror, isPushableHttpUrl, mirrorPushGloballyDisabled, mirrorServerForStore, redactEndpoint, runMirrorPushDaemon, MIN_MIRROR_PUSH_INTERVAL_MS, MIRROR_PUSH_INVALID_URL_MESSAGE, MIRROR_PUSH_OFF_ENV } from "./runtime/mirror/index.js";
|
|
76
77
|
import { recordStop, scanDrumbeat, clearDrumbeatEntry, runDrumbeatWatch as runDrumbeatWatchLoop, loggingRelauncher, localTmuxRelauncher, headlessRelauncher, remoteRelauncher, chainRelauncher, relanceFromInbox, loggingDecider, subagentDecider, H2A_DEFAULT_MAX_RELANCES } from "./runtime/drumbeat/index.js";
|
|
77
78
|
import { gatherNhiSnapshot } from "./runtime/nhi.js";
|
|
78
79
|
import { raiseBlockage, listBlockages, resolveBlockage } from "./runtime/blockage/index.js";
|
|
@@ -80,7 +81,8 @@ import { recordEscalation, listEscalations, clearEscalation } from "./runtime/es
|
|
|
80
81
|
import { authorizeDrive, chainDriver, formatSignedDriveInstruction, headlessDriver, localTmuxDriver, loggingDriver, nativeBackchannelDriver, remoteDriveServerForStore, verifyDriveOnReceive } from "./runtime/drive/index.js";
|
|
81
82
|
import { verifyEnvelopeSysmlRef } from "./runtime/sysml/index.js";
|
|
82
83
|
import { checkUpgrade, performUpgrade, currentCliVersion, upgradeCachePath, canReexec, reexecSelf, H2A_AUTO_UPGRADE_CHECK_TTL_MS, H2A_REEXEC_GUARD_ENV, H2A_UPGRADE_CHECK_TTL_MS } from "./runtime/upgrade/index.js";
|
|
83
|
-
import { resolveLiveIdentity } from "./runtime/identity/index.js";
|
|
84
|
+
import { H2A_CLI_DECLARED_CAPABILITIES, createHostSessionNameRefresher, resolveLiveIdentity } from "./runtime/identity/index.js";
|
|
85
|
+
import { buildEnrollmentProof, enrollmentProofSignedPayload, listUnusablePrivateKeys, sanitizeEnrollmentChallenge } from "./runtime/enrollment/index.js";
|
|
84
86
|
import { conductorFor } from "./runtime/governance/conductor.js";
|
|
85
87
|
import { appendConductorClaim } from "./runtime/governance/claims.js";
|
|
86
88
|
import { conductorLaunchCheck } from "./runtime/governance/launch-check.js";
|
|
@@ -139,10 +141,19 @@ export function renderCliHelp() {
|
|
|
139
141
|
return [
|
|
140
142
|
"h2a",
|
|
141
143
|
"",
|
|
142
|
-
"Human-to-agent coordination CLI.",
|
|
144
|
+
"Human-to-agent coordination CLI — the unified sentropic CLI and core.",
|
|
145
|
+
"It also fronts agent work sessions, the work record (@sentropic/track) and the",
|
|
146
|
+
"harness method; a verb it does not serve itself loads the h2a runtime on demand.",
|
|
147
|
+
"h2a runs and coordinates agents; it is not itself an agent.",
|
|
148
|
+
"",
|
|
149
|
+
"The list below is a flat usage reference, and it is NOT exhaustive. For every",
|
|
150
|
+
"command grouped by what you are trying to do — core and runtime, derived from",
|
|
151
|
+
"the frozen verb contract so it cannot go stale — run:",
|
|
152
|
+
" h2a explain",
|
|
143
153
|
"",
|
|
144
154
|
"Usage:",
|
|
145
155
|
" h2a --help",
|
|
156
|
+
" h2a explain",
|
|
146
157
|
" h2a hosts",
|
|
147
158
|
" h2a mcp-tools",
|
|
148
159
|
" h2a init [--root <path>]",
|
|
@@ -175,6 +186,13 @@ export function renderCliHelp() {
|
|
|
175
186
|
" entry's id, and correlationId from the previous entry's correlationId.",
|
|
176
187
|
" Explicit --causation-id / --correlation-id flags always override the",
|
|
177
188
|
" inherited default; pass them on the first offer to start a fresh thread.",
|
|
189
|
+
"",
|
|
190
|
+
// These 24 lines used to be nested under the "Auto-propagation (DEC-033):"
|
|
191
|
+
// prose block above, which described only offer/counter/sign/event causation.
|
|
192
|
+
// They have nothing to do with it — mailboxes, local servers and host wiring
|
|
193
|
+
// were appended inside someone else's section. Heading added; every usage line
|
|
194
|
+
// below is byte-identical to before.
|
|
195
|
+
"Mailboxes, local services and host wiring:",
|
|
178
196
|
" h2a inbox put --instance <id> --json <envelope> [--root <path>]",
|
|
179
197
|
" h2a inbox read --instance <id> [--root <path>]",
|
|
180
198
|
" h2a inbox pop --instance <id> --envelope <id> [--root <path>]",
|
|
@@ -185,7 +203,7 @@ export function renderCliHelp() {
|
|
|
185
203
|
" h2a remote serve [--port <n>] [--host <h>] [--path </h2a/envelopes>] [--root <path>]",
|
|
186
204
|
" h2a remote send --url <u> --instance <signer> --private-key <pem> --json <envelope>",
|
|
187
205
|
" h2a remote mirror-serve [--port <n>] [--host <h>] [--path </h2a/mirror>] [--enrolled-keys-file <json>] [--root <path>] (EVO-13 instance-mirror ingester; enrolled keys also via H2A_MIRROR_ENROLLED_KEYS base64)",
|
|
188
|
-
" h2a remote mirror --url <u> --instance <id> --private-key <pem> [--root <path>] (push this instance's registration to a remote ingester)",
|
|
206
|
+
" h2a remote mirror --url <u> --instance <id> --private-key <pem> [--root <path>] [--interval-ms <n> [--max <n>]] (push this instance's registration to a remote ingester; ONE-SHOT by default. --interval-ms >= 5000 opts into the live daemon: same payload, repeated on a monotonic beat (15000-30000 recommended), overlap-guarded, backing off on transient errors and STOPPING on repeated 401/403 because re-enrollment is required. Kill-switch: H2A_MIRROR_PUSH_OFF)",
|
|
189
207
|
" h2a drive --from <instance> --to <instance> --instruction <text> --private-key <pem> [--driver logging|native|local-tmux|headless|auto] [--host <host>] [--root <path>]",
|
|
190
208
|
" h2a drive receive --to <instance> (--line <signed-line> | --stdin) [--ignore-non-drive] [--root <path>] (verify-before-act gate for host hooks)",
|
|
191
209
|
" h2a drive serve --to <instance> --inject-command <command> [--port <n>] [--host <h>] [--path </h2a/drive>] [--root <path>] (remote verify-before-inject service)",
|
|
@@ -209,6 +227,7 @@ export function renderCliHelp() {
|
|
|
209
227
|
" h2a keepalive [--root <path>] [--interval <ms>] [--once] (external keepalive prober — refreshes presence for agents whose tmux pane is still alive)",
|
|
210
228
|
" h2a rename --instance <id> --name <name> [--root <path>] (set a live session's display name so peers can find it via discover --name)",
|
|
211
229
|
" h2a status [--root <path>] [--scope <s>] [--instance <i>]",
|
|
230
|
+
" h2a status --human [--watch] [--tmux-session <exact>] [--interval <duration>] (read-only tmux/work/gateway/inbox/loop status; --bar is the terse tmux segment)",
|
|
212
231
|
" h2a sessions [--root <path>] [--scope <s>] [--instance <i>]",
|
|
213
232
|
" h2a thread --id <threadId> --instance <self> [--root <path>] (the ordered conversation for a thread, from your inbox+outbox)",
|
|
214
233
|
" h2a keys generate --instance <id> [--out <dir>] [--root <path>]",
|
|
@@ -1191,22 +1210,53 @@ export function resolveAutoOpen(flags, cwd) {
|
|
|
1191
1210
|
root: resolveRoot(flags, cwd),
|
|
1192
1211
|
host: host ?? "agent",
|
|
1193
1212
|
cwd: cwd(),
|
|
1213
|
+
// Declared DISPLAY list only, never an authorization input (feed contract
|
|
1214
|
+
// ratification condition #3). Lands in the registration's
|
|
1215
|
+
// `declaredCapabilities`, never in the authority-bearing `capabilities`.
|
|
1216
|
+
declaredCapabilities: H2A_CLI_DECLARED_CAPABILITIES,
|
|
1194
1217
|
...(flags.instance !== undefined ? { explicitInstance: flags.instance } : {}),
|
|
1195
1218
|
...(flags.name !== undefined ? { name: flags.name } : {}),
|
|
1196
1219
|
...(flags.scope !== undefined ? { scopes: [flags.scope] } : {})
|
|
1197
1220
|
});
|
|
1221
|
+
// §D1b: only follow the host title when the operator left the name implicit,
|
|
1222
|
+
// and only when a real provider session id was readable (the synthetic
|
|
1223
|
+
// `fallback:` id names no transcript, so there is nothing to re-read).
|
|
1224
|
+
//
|
|
1225
|
+
// The host gate is EXPLICIT, not incidental. `createHostSessionNameRefresher`
|
|
1226
|
+
// can only read `claude` and `codex` transcripts; for any other host it returns
|
|
1227
|
+
// `undefined` forever. `resolveProviderSession` does resolve a provider session
|
|
1228
|
+
// id for `remote`, `gemini` and `agy`, so without this gate those three install
|
|
1229
|
+
// a callback that is called on every heartbeat and can never return a name — a
|
|
1230
|
+
// guard whose premise cannot hold. Installing nothing is behaviourally
|
|
1231
|
+
// identical (the heartbeat keeps the previous name either way) and does not
|
|
1232
|
+
// pretend to a capability the reader does not have.
|
|
1233
|
+
const refreshableHost = host === "claude" || host === "codex";
|
|
1234
|
+
const refreshDisplayName = flags.name === undefined &&
|
|
1235
|
+
identity.providerSessionId !== undefined &&
|
|
1236
|
+
refreshableHost
|
|
1237
|
+
? createHostSessionNameRefresher({
|
|
1238
|
+
host,
|
|
1239
|
+
cwd: cwd(),
|
|
1240
|
+
sessionId: identity.providerSessionId
|
|
1241
|
+
})
|
|
1242
|
+
: undefined;
|
|
1198
1243
|
return {
|
|
1199
1244
|
instance: identity.instance,
|
|
1200
1245
|
...(host ? { host } : {}),
|
|
1201
1246
|
...(identity.workspace !== undefined ? { workspace: identity.workspace } : {}),
|
|
1202
1247
|
...(identity.name !== undefined ? { name: identity.name } : {}),
|
|
1248
|
+
...(refreshDisplayName ? { refreshDisplayName } : {}),
|
|
1203
1249
|
...(flags.scope ? { scopes: [flags.scope] } : {}),
|
|
1204
1250
|
...(identity.migrationNotice !== undefined
|
|
1205
1251
|
? { migrationNotice: identity.migrationNotice }
|
|
1206
1252
|
: {}),
|
|
1207
1253
|
...(identity.privateKeyPath !== undefined
|
|
1208
1254
|
? { privateKeyPath: identity.privateKeyPath }
|
|
1209
|
-
: {})
|
|
1255
|
+
: {}),
|
|
1256
|
+
// An explicit --instance is an operator-provided label, not an identity
|
|
1257
|
+
// derived and owned by this sidecar. It may open presence, but it cannot
|
|
1258
|
+
// cause h2a_run to be attributed to that claimed owner in the status bar.
|
|
1259
|
+
...(flags.instance === undefined ? { delegationEligible: true } : {})
|
|
1210
1260
|
};
|
|
1211
1261
|
}
|
|
1212
1262
|
/**
|
|
@@ -1595,8 +1645,35 @@ export async function runMirrorServe(flags, io = { stdout: process.stdout, stder
|
|
|
1595
1645
|
* `h2a remote mirror` (EVO-13 P1): build the local instance's own registration
|
|
1596
1646
|
* mirror, sign it with `--private-key`, and POST it to a remote ingester `--url`.
|
|
1597
1647
|
* Exit 0 on a 2xx. Async (network) → dispatched from bin.ts.
|
|
1648
|
+
*
|
|
1649
|
+
* ONE-SHOT BY DEFAULT. Passing `--interval-ms <n>` — and only that — opts into
|
|
1650
|
+
* the live daemon (feed-contract P1 step 4a): the identical build → sign → POST
|
|
1651
|
+
* cycle, repeated on a monotonic beat with overlap prevention, transient-error
|
|
1652
|
+
* backoff, and a hard stop on repeated 401/403 (re-enrollment required). With no
|
|
1653
|
+
* `--interval-ms` the code path below is byte-identical to the pre-daemon one.
|
|
1654
|
+
* The global kill-switch `H2A_MIRROR_PUSH_OFF` disables the daemon entirely.
|
|
1598
1655
|
*/
|
|
1599
|
-
export async function runMirrorPush(flags, streams = { stdout: process.stdout, stderr: process.stderr }) {
|
|
1656
|
+
export async function runMirrorPush(flags, streams = { stdout: process.stdout, stderr: process.stderr }, signal, overrides = {}) {
|
|
1657
|
+
// OPT-IN GATE, evaluated BEFORE any validation. The daemon exists only for a
|
|
1658
|
+
// caller that explicitly asked for an interval — and on that path the
|
|
1659
|
+
// kill-switch has to be the very first thing that runs, ahead even of the
|
|
1660
|
+
// required-flag presence check. Otherwise a HALF-EDITED unit (placeholders
|
|
1661
|
+
// partly replaced, a `--private-key <path>` pair accidentally dropped) exits 1
|
|
1662
|
+
// and lands in systemd `failed`, while the README promises a disarmed unit is
|
|
1663
|
+
// `inactive (dead)`. Mid-edit is exactly when that promise has to hold.
|
|
1664
|
+
if (flags["interval-ms"] !== undefined) {
|
|
1665
|
+
return runMirrorPushWatch(flags, streams, signal, overrides);
|
|
1666
|
+
}
|
|
1667
|
+
// `--interval-ms=20000` parses as the flag KEY `interval-ms=20000` (this CLI
|
|
1668
|
+
// takes `--flag value`, never `--flag=value`), so the opt-in above would miss
|
|
1669
|
+
// it and this would silently run as a one-shot. Fail loudly instead of
|
|
1670
|
+
// quietly doing something other than what was asked.
|
|
1671
|
+
const equalsForm = Object.keys(flags).find((k) => k.startsWith("interval-ms="));
|
|
1672
|
+
if (equalsForm) {
|
|
1673
|
+
streams.stderr.write(`h2a remote mirror: use "--interval-ms ${equalsForm.slice("interval-ms=".length)}", not "--${equalsForm}" (this CLI does not take --flag=value)\n`);
|
|
1674
|
+
return 1;
|
|
1675
|
+
}
|
|
1676
|
+
// --- one-shot, byte-identical to the pre-daemon path from here down ---
|
|
1600
1677
|
if (!flags.url || !flags.instance || !flags["private-key"]) {
|
|
1601
1678
|
streams.stderr.write("h2a remote mirror: --url, --instance and --private-key are required\n");
|
|
1602
1679
|
return 1;
|
|
@@ -1630,6 +1707,92 @@ export async function runMirrorPush(flags, streams = { stdout: process.stdout, s
|
|
|
1630
1707
|
streams.stdout.write(`${JSON.stringify({ status: result.status, body: result.body }, null, 2)}\n`);
|
|
1631
1708
|
return result.status >= 200 && result.status < 300 ? 0 : 1;
|
|
1632
1709
|
}
|
|
1710
|
+
/**
|
|
1711
|
+
* `h2a remote mirror --interval-ms <n>` (feed-contract P1 step 4a): the SAME
|
|
1712
|
+
* one-shot push, live. Reached only from {@link runMirrorPush} when the operator
|
|
1713
|
+
* passed an interval — never by default, never as a side effect.
|
|
1714
|
+
*
|
|
1715
|
+
* Emits one JSON status line per cycle on stdout (no key material, no request or
|
|
1716
|
+
* response body — see `MirrorPushCycleLog`). Exit 0 when it stops cleanly
|
|
1717
|
+
* (SIGTERM, `--max`, or the kill-switch), 1 when it stops because the endpoint
|
|
1718
|
+
* refuses this instance's key and re-enrollment is required.
|
|
1719
|
+
*/
|
|
1720
|
+
async function runMirrorPushWatch(flags, streams, signal, overrides = {}) {
|
|
1721
|
+
// KILL-SWITCH FIRST, before ANY validation and before ANY input is read. A
|
|
1722
|
+
// disabled daemon short-circuits without touching the filesystem and without
|
|
1723
|
+
// judging its own arguments — including whether the required ones are even
|
|
1724
|
+
// present. That is what makes the promise "a disarmed unit is inactive (dead),
|
|
1725
|
+
// not failed" true for a PARTIALLY edited unit, which is the state an operator
|
|
1726
|
+
// is actually in while replacing the placeholders.
|
|
1727
|
+
if (mirrorPushGloballyDisabled(process.env)) {
|
|
1728
|
+
streams.stderr.write(`h2a remote mirror: ${MIRROR_PUSH_OFF_ENV} is set — the live push is disabled, nothing was sent\n`);
|
|
1729
|
+
return 0;
|
|
1730
|
+
}
|
|
1731
|
+
// Armed: now the same required-flag contract as the one-shot applies.
|
|
1732
|
+
if (!flags.url || !flags.instance || !flags["private-key"]) {
|
|
1733
|
+
streams.stderr.write("h2a remote mirror: --url, --instance and --private-key are required\n");
|
|
1734
|
+
return 1;
|
|
1735
|
+
}
|
|
1736
|
+
const intervalMs = Number.parseInt(flags["interval-ms"] ?? "", 10);
|
|
1737
|
+
if (!Number.isInteger(intervalMs) || intervalMs < MIN_MIRROR_PUSH_INTERVAL_MS) {
|
|
1738
|
+
streams.stderr.write(`h2a remote mirror: --interval-ms must be an integer >= ${MIN_MIRROR_PUSH_INTERVAL_MS} (got "${flags["interval-ms"]}")\n`);
|
|
1739
|
+
return 1;
|
|
1740
|
+
}
|
|
1741
|
+
const max = flags.max !== undefined ? Number.parseInt(flags.max, 10) : undefined;
|
|
1742
|
+
if (max !== undefined && (!Number.isInteger(max) || max < 1)) {
|
|
1743
|
+
streams.stderr.write(`h2a remote mirror: --max must be an integer >= 1 (got "${flags.max}")\n`);
|
|
1744
|
+
return 1;
|
|
1745
|
+
}
|
|
1746
|
+
// The one-shot POSTs once and surfaces the transport error; a daemon would
|
|
1747
|
+
// instead classify an unusable --url as a transient failure and retry it
|
|
1748
|
+
// forever (an unfilled placeholder or a typo would look "active (running)"
|
|
1749
|
+
// while pushing nothing). So the daemon form requires a usable http(s) URL
|
|
1750
|
+
// up front and fails fast, like the other pre-flight checks.
|
|
1751
|
+
// Emits the SAME text the library's `config-invalid` stop carries, so the
|
|
1752
|
+
// string an operator greps for in the journal is the one the docs document —
|
|
1753
|
+
// the CLI's fail-fast makes the library branch unreachable in practice, and
|
|
1754
|
+
// two different wordings for one condition would send them looking for a
|
|
1755
|
+
// message that never appears.
|
|
1756
|
+
if (!isPushableHttpUrl(flags.url)) {
|
|
1757
|
+
streams.stderr.write(`h2a remote mirror: ${MIRROR_PUSH_INVALID_URL_MESSAGE} (got "${flags.url}")\n`);
|
|
1758
|
+
return 1;
|
|
1759
|
+
}
|
|
1760
|
+
const cwd = streams.cwd ?? (() => process.cwd());
|
|
1761
|
+
const root = resolveRoot(flags, cwd);
|
|
1762
|
+
// The key is read ONCE, at start, and kept only in memory: a rotated key needs
|
|
1763
|
+
// a restart, which a re-enrollment needs anyway.
|
|
1764
|
+
let privateKeyPem;
|
|
1765
|
+
try {
|
|
1766
|
+
privateKeyPem = readFileSync(flags["private-key"], "utf8");
|
|
1767
|
+
}
|
|
1768
|
+
catch (error) {
|
|
1769
|
+
streams.stderr.write(`h2a remote mirror: cannot read --private-key (${error.message})\n`);
|
|
1770
|
+
return 1;
|
|
1771
|
+
}
|
|
1772
|
+
streams.stderr.write(`h2a remote mirror: pushing instance ${flags.instance} to ${redactEndpoint(flags.url)} every ${intervalMs}ms (root ${root})\n`);
|
|
1773
|
+
const summary = await runMirrorPushDaemon({
|
|
1774
|
+
root,
|
|
1775
|
+
url: flags.url,
|
|
1776
|
+
instance: flags.instance,
|
|
1777
|
+
privateKeyPem,
|
|
1778
|
+
intervalMs,
|
|
1779
|
+
...(max !== undefined ? { max } : {}),
|
|
1780
|
+
...(signal ? { signal } : {}),
|
|
1781
|
+
...overrides,
|
|
1782
|
+
onCycle: (line) => {
|
|
1783
|
+
streams.stdout.write(`${JSON.stringify(line)}\n`);
|
|
1784
|
+
}
|
|
1785
|
+
});
|
|
1786
|
+
// Every stop that needs a human act carries its own actionable message and
|
|
1787
|
+
// exits 1, so systemd's RestartPreventExitStatus=1 keeps it stopped instead of
|
|
1788
|
+
// restarting into the same wall.
|
|
1789
|
+
if (summary.message) {
|
|
1790
|
+
streams.stderr.write(`h2a remote mirror: ${summary.message}\n`);
|
|
1791
|
+
return 1;
|
|
1792
|
+
}
|
|
1793
|
+
streams.stderr.write(`h2a remote mirror: stopped (${summary.stopReason}) after ${summary.cycles} cycles, ${summary.ok} accepted\n`);
|
|
1794
|
+
return 0;
|
|
1795
|
+
}
|
|
1633
1796
|
function parseLoopRepo(value) {
|
|
1634
1797
|
const [path, role] = value.split(":");
|
|
1635
1798
|
if (!path)
|
|
@@ -4421,6 +4584,151 @@ function cmdKeysRevoke(flags, streams) {
|
|
|
4421
4584
|
streams.stdout.write(`${JSON.stringify({ ok: true, instance: flags.instance, status: "revoked", keys: store.listInstanceKeys(flags.instance).length }, null, 2)}\n`);
|
|
4422
4585
|
return 0;
|
|
4423
4586
|
}
|
|
4587
|
+
/**
|
|
4588
|
+
* `h2a keys prove-control` — the OWNER-facing half of the principal↔agent
|
|
4589
|
+
* enrollment ceremony (Part B of the session-exposure feed contract ratified
|
|
4590
|
+
* 2026-07-24; step 3 of the P1 joint plan).
|
|
4591
|
+
*
|
|
4592
|
+
* The verb is named for what it does and only what it does: it PROVES CONTROL
|
|
4593
|
+
* of the live agent key over a gateway-issued challenge. It does not "enroll"
|
|
4594
|
+
* anything, because h2a cannot — the 39-auth principal is the authorizing
|
|
4595
|
+
* authority and sentropic mints the binding record. Naming this `enroll` would
|
|
4596
|
+
* misstate the authority model in the one place the owner reads it.
|
|
4597
|
+
*
|
|
4598
|
+
* It makes NO network call. The proof is printed for the owner to hand to the
|
|
4599
|
+
* gateway (which requires an active FIRST-PARTY session — deliberately not
|
|
4600
|
+
* reachable by a bearer token). Nothing is stored: no binding, no challenge,
|
|
4601
|
+
* no proof.
|
|
4602
|
+
*/
|
|
4603
|
+
function cmdKeysProveControl(flags, streams) {
|
|
4604
|
+
if (!flags.host) {
|
|
4605
|
+
streams.stderr.write("h2a keys prove-control: --host <codex|claude|gemini|agy|hermes|opencode|remote> is required\n");
|
|
4606
|
+
return 1;
|
|
4607
|
+
}
|
|
4608
|
+
if (!["codex", "claude", "gemini", "agy", "hermes", "opencode", "remote"].includes(flags.host)) {
|
|
4609
|
+
streams.stderr.write(`h2a keys prove-control: unknown --host "${flags.host}". Supported: codex, claude, gemini, agy, hermes, opencode, remote.\n`);
|
|
4610
|
+
return 1;
|
|
4611
|
+
}
|
|
4612
|
+
// A NAMED instance-id ROTS. A stale recorded mapping has already sent work to
|
|
4613
|
+
// the wrong instance in this project, and the 2026-06-07 identity re-anchor
|
|
4614
|
+
// means yesterday's id names yesterday's key. The ceremony therefore resolves
|
|
4615
|
+
// the LIVE identity itself, every run — so an override is refused loudly
|
|
4616
|
+
// rather than quietly honoured.
|
|
4617
|
+
if (flags.instance !== undefined) {
|
|
4618
|
+
streams.stderr.write("h2a keys prove-control: --instance is refused. The ceremony must prove the key that is LIVE " +
|
|
4619
|
+
"now, so the identity is resolved at run time; a recorded id would name a key that may " +
|
|
4620
|
+
"already have been re-anchored away. Re-run `h2a connect` if the live identity is wrong.\n");
|
|
4621
|
+
return 1;
|
|
4622
|
+
}
|
|
4623
|
+
if (flags.nonce !== undefined && flags.challenge !== undefined) {
|
|
4624
|
+
streams.stderr.write("h2a keys prove-control: pass either --nonce <value> or --challenge <json-file>, not both\n");
|
|
4625
|
+
return 1;
|
|
4626
|
+
}
|
|
4627
|
+
let challenge;
|
|
4628
|
+
if (flags.challenge !== undefined) {
|
|
4629
|
+
let raw;
|
|
4630
|
+
try {
|
|
4631
|
+
raw = readFileSync(flags.challenge, "utf8");
|
|
4632
|
+
}
|
|
4633
|
+
catch (error) {
|
|
4634
|
+
streams.stderr.write(`h2a keys prove-control: cannot read --challenge (${error.message})\n`);
|
|
4635
|
+
return 1;
|
|
4636
|
+
}
|
|
4637
|
+
let parsed;
|
|
4638
|
+
try {
|
|
4639
|
+
parsed = JSON.parse(raw);
|
|
4640
|
+
}
|
|
4641
|
+
catch (error) {
|
|
4642
|
+
streams.stderr.write(`h2a keys prove-control: --challenge is not valid JSON (${error.message})\n`);
|
|
4643
|
+
return 1;
|
|
4644
|
+
}
|
|
4645
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
4646
|
+
streams.stderr.write("h2a keys prove-control: --challenge must be a JSON object { nonce, expiresAt? }\n");
|
|
4647
|
+
return 1;
|
|
4648
|
+
}
|
|
4649
|
+
// MINIMAL DISCLOSURE is enforced by the challenge-key ALLOWLIST inside
|
|
4650
|
+
// `assertSignableEnrollmentChallenge` below, not by a check here. A top-level
|
|
4651
|
+
// `"principalSub" in parsed` blocklist used to live at this spot and was
|
|
4652
|
+
// incomplete against its own stated harm: `{ nonce, meta: { principalSub } }`
|
|
4653
|
+
// and `{ nonce, "__proto__": { principalSub } }` both put a principal id into
|
|
4654
|
+
// this process while passing it. The allowlist refuses every field that is
|
|
4655
|
+
// not `nonce` or `expiresAt`, so nesting is unreachable rather than hunted.
|
|
4656
|
+
challenge = parsed;
|
|
4657
|
+
}
|
|
4658
|
+
else if (flags.nonce !== undefined && flags.nonce !== "true") {
|
|
4659
|
+
// `"true"` is `parseFlags`' bare-flag sentinel (`--nonce` with no value), not
|
|
4660
|
+
// a nonce. It is also not a valid nonce under the base64url + 256-bit shape,
|
|
4661
|
+
// so rejecting it here only improves the error message.
|
|
4662
|
+
challenge = { nonce: flags.nonce };
|
|
4663
|
+
}
|
|
4664
|
+
else {
|
|
4665
|
+
streams.stderr.write("h2a keys prove-control: --nonce <value> or --challenge <json-file> is required " +
|
|
4666
|
+
"(the gateway issues it to your authenticated session)\n");
|
|
4667
|
+
return 1;
|
|
4668
|
+
}
|
|
4669
|
+
// The challenge is the caller's input, so a bad one is a USER error (exit 1);
|
|
4670
|
+
// a broken local key state is a STATE error (exit 2). Classified by checking
|
|
4671
|
+
// the two separately, never by matching on an error string.
|
|
4672
|
+
//
|
|
4673
|
+
// `sanitize` both validates (allowlist over own keys) and hands back a FRESH
|
|
4674
|
+
// null-prototype object, so nothing downstream carries a parsed document's own
|
|
4675
|
+
// `"__proto__"` key even by accident.
|
|
4676
|
+
try {
|
|
4677
|
+
challenge = sanitizeEnrollmentChallenge(challenge, Date.now());
|
|
4678
|
+
}
|
|
4679
|
+
catch (error) {
|
|
4680
|
+
streams.stderr.write(`h2a keys prove-control: ${error.message}\n`);
|
|
4681
|
+
return 1;
|
|
4682
|
+
}
|
|
4683
|
+
const cwd = streams.cwd ?? (() => process.cwd());
|
|
4684
|
+
warnIfCwdRootFallback(flags, cwd, streams);
|
|
4685
|
+
const root = resolveRoot(flags, cwd);
|
|
4686
|
+
// NAME A DAMAGED KEY BEFORE MINTING OVER IT. A corrupt, truncated or
|
|
4687
|
+
// passphrase-protected private key does not fail the ceremony: live resolution
|
|
4688
|
+
// silently mints a fresh identity and this verb exits 0 on a brand-new key. The
|
|
4689
|
+
// mint is defensible; doing it silently is not, because it is indistinguishable
|
|
4690
|
+
// from tampering. So say which file is unusable, on stderr, before it happens.
|
|
4691
|
+
for (const path of listUnusablePrivateKeys(root)) {
|
|
4692
|
+
streams.stderr.write(`h2a keys prove-control: WARNING — private key at ${path} exists but cannot be loaded ` +
|
|
4693
|
+
"(corrupt, truncated, or passphrase-protected). If it belongs to the identity you meant to " +
|
|
4694
|
+
"re-prove, a NEW identity will be minted instead and the proof will be for a different key.\n");
|
|
4695
|
+
}
|
|
4696
|
+
let result;
|
|
4697
|
+
try {
|
|
4698
|
+
result = buildEnrollmentProof({ root, host: flags.host, cwd: cwd(), challenge });
|
|
4699
|
+
}
|
|
4700
|
+
catch (error) {
|
|
4701
|
+
streams.stderr.write(`h2a keys prove-control: ${error.message}\n`);
|
|
4702
|
+
return 2;
|
|
4703
|
+
}
|
|
4704
|
+
// Deliberately PATH-FREE output. This envelope exists to be copied into a
|
|
4705
|
+
// browser, so it holds no `root`, no key path and no private key — the same
|
|
4706
|
+
// discipline the feed applies to its descriptors, applied to the one h2a
|
|
4707
|
+
// output whose purpose is to leave the machine.
|
|
4708
|
+
const envelope = {
|
|
4709
|
+
ok: true,
|
|
4710
|
+
instance: result.instance,
|
|
4711
|
+
publicKeyFingerprint: result.publicKeyFingerprint,
|
|
4712
|
+
// So a MINT is never silent. `mint` means this run proved a key that did not
|
|
4713
|
+
// exist before — expected after a re-anchor, but also what a damaged key
|
|
4714
|
+
// produces, which is why the stderr warning above names the file.
|
|
4715
|
+
...(result.identityAction !== undefined ? { identityAction: result.identityAction } : {}),
|
|
4716
|
+
// Explicit branch, not a defaulted field: h2a ships no transport at all, so
|
|
4717
|
+
// "not attempted" is an established fact about this run.
|
|
4718
|
+
submission: { attempted: false, reason: "no-transport-configured" },
|
|
4719
|
+
proof: result.proof,
|
|
4720
|
+
// Derived from the proof itself, never a hand-kept list: the signed set is
|
|
4721
|
+
// whatever the proof carries minus the signature.
|
|
4722
|
+
signedFields: Object.keys(enrollmentProofSignedPayload(result.proof)).sort(),
|
|
4723
|
+
authority: "Proof of KEY CONTROL only. The signature covers every field of the proof except itself — " +
|
|
4724
|
+
"including the versioned `type` tag, so the proof attests what it IS as well as what it " +
|
|
4725
|
+
"carries. But SIGNED IS NOT AUTHORIZED: it proves this key produced this payload; it proves " +
|
|
4726
|
+
"nothing about what the key may see. The 39-auth principal authorizes, and sentropic mints " +
|
|
4727
|
+
"and stores the binding."
|
|
4728
|
+
};
|
|
4729
|
+
streams.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
4730
|
+
return 0;
|
|
4731
|
+
}
|
|
4424
4732
|
function cmdConnect(flags, streams) {
|
|
4425
4733
|
if (!flags.host) {
|
|
4426
4734
|
streams.stderr.write("h2a connect: --host <codex|claude|gemini|agy|hermes|opencode|remote> is required\n");
|
|
@@ -4437,6 +4745,10 @@ function cmdConnect(flags, streams) {
|
|
|
4437
4745
|
root,
|
|
4438
4746
|
host: flags.host,
|
|
4439
4747
|
cwd: cwd(),
|
|
4748
|
+
// Declared DISPLAY list only, never an authorization input (feed contract
|
|
4749
|
+
// ratification condition #3). Lands in the registration's
|
|
4750
|
+
// `declaredCapabilities`, never in the authority-bearing `capabilities`.
|
|
4751
|
+
declaredCapabilities: H2A_CLI_DECLARED_CAPABILITIES,
|
|
4440
4752
|
...(flags.instance !== undefined ? { explicitInstance: flags.instance } : {}),
|
|
4441
4753
|
...(flags.name !== undefined ? { name: flags.name } : {})
|
|
4442
4754
|
});
|
|
@@ -5288,6 +5600,41 @@ export function runCli(argv = process.argv.slice(2), streams = {
|
|
|
5288
5600
|
streams.stdout.write(`${renderCliHelp()}\n`);
|
|
5289
5601
|
return 0;
|
|
5290
5602
|
}
|
|
5603
|
+
// `explain` — the grouped command map. Added 2026-07-25 as a NEW verb; it
|
|
5604
|
+
// repurposes no existing argv and no existing output. DEC-034's no-argv-is-help
|
|
5605
|
+
// rule above is untouched: bare `h2a` still renders `renderCliHelp()`.
|
|
5606
|
+
//
|
|
5607
|
+
// GRAMMAR, and why it is strict. Review measured that this verb accepted
|
|
5608
|
+
// ANY trailing argv and returned the map with exit 0 — `explain foo`,
|
|
5609
|
+
// `explain --json`, `explain --root /tmp` all "succeeded". That contradicted
|
|
5610
|
+
// the contract, which declares no flags at all, and it manufactures a
|
|
5611
|
+
// successful-looking result for input nobody implemented: a caller who pipes
|
|
5612
|
+
// `explain --json` into a JSON parser gets prose and exit 0.
|
|
5613
|
+
//
|
|
5614
|
+
// The ambient convention in this file is laxer — `hosts foo` and
|
|
5615
|
+
// `mcp-tools --json` also exit 0, measured. `explain` is deliberately NOT
|
|
5616
|
+
// following it, because it is a NEW verb: no caller can already depend on
|
|
5617
|
+
// junk argv being tolerated, so strictness is free here and impossible to
|
|
5618
|
+
// retrofit later without a breaking change. Tightening the siblings is a
|
|
5619
|
+
// separate change against verbs that DO have callers, and is not in scope.
|
|
5620
|
+
//
|
|
5621
|
+
// Accepted: bare `explain`, plus `--help`/`-h` which print the same map (the
|
|
5622
|
+
// map IS this verb's help; erroring there would be user-hostile). Everything
|
|
5623
|
+
// else — any other flag, any positional — is a usage error: exit 1, nothing
|
|
5624
|
+
// on stdout, the offending token named on stderr. `optionalFlags: ["help"]`
|
|
5625
|
+
// and `exitCodes: [0, 1]` in cli-contract.ts say exactly this.
|
|
5626
|
+
if (command === "explain") {
|
|
5627
|
+
const rest = argv.slice(1);
|
|
5628
|
+
const unsupported = rest.filter((token) => token !== "--help" && token !== "-h");
|
|
5629
|
+
if (unsupported.length > 0) {
|
|
5630
|
+
streams.stderr.write(`h2a explain: unsupported argument${unsupported.length > 1 ? "s" : ""}: ${unsupported.join(", ")}\n` +
|
|
5631
|
+
" usage: h2a explain [--help]\n" +
|
|
5632
|
+
" `explain` takes no arguments; it always prints the whole grouped map.\n");
|
|
5633
|
+
return 1;
|
|
5634
|
+
}
|
|
5635
|
+
streams.stdout.write(`${renderCommandMap([...TRACK_FACADE_VERBS])}\n`);
|
|
5636
|
+
return 0;
|
|
5637
|
+
}
|
|
5291
5638
|
if (command === "hosts") {
|
|
5292
5639
|
streams.stdout.write(`${JSON.stringify(CLI_HOSTS, null, 2)}\n`);
|
|
5293
5640
|
return 0;
|
|
@@ -5426,7 +5773,9 @@ export function runCli(argv = process.argv.slice(2), streams = {
|
|
|
5426
5773
|
return cmdKeysList(subFlags, streams);
|
|
5427
5774
|
if (sub === "revoke")
|
|
5428
5775
|
return cmdKeysRevoke(subFlags, streams);
|
|
5429
|
-
|
|
5776
|
+
if (sub === "prove-control")
|
|
5777
|
+
return cmdKeysProveControl(subFlags, streams);
|
|
5778
|
+
streams.stderr.write(`h2a keys: unknown subcommand "${sub ?? ""}" (generate, add, list, revoke, prove-control)\n`);
|
|
5430
5779
|
return 1;
|
|
5431
5780
|
}
|
|
5432
5781
|
streams.stderr.write(`Unknown command: ${command}\n`);
|