@sentropic/h2a 0.85.25 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- 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 +39 -1
- 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/dist/vendor/harness/skills/manifest.d.ts.map +1 -1
- package/dist/vendor/harness/skills/manifest.js +2 -0
- package/dist/vendor/harness/skills/manifest.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 +5 -5
- package/skills/h2a-run/SKILL.md +100 -0
- package/skills/harness/SKILL.md +3 -1
- package/skills/harness/review/SKILL.md +99 -8
- package/skills/harness/security/SKILL.md +55 -0
- package/skills/harness/track-report/SKILL.md +103 -0
- package/skills/harness/using-harness/SKILL.md +3 -1
- 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,644 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-13 / feed-contract P1 step 4a — the mirror push as an OPT-IN live daemon.
|
|
3
|
+
*
|
|
4
|
+
* `h2a remote mirror` is a ONE-SHOT push (build → sign → POST once). The
|
|
5
|
+
* ratified feed contract
|
|
6
|
+
* (`docs/superpowers/specs/2026-07-24-h2a-feed-contract-for-sentropic.md`,
|
|
7
|
+
* Part C) needs that same push to run continuously on a 15–30s beat, so the
|
|
8
|
+
* hosted read-only store stays warm for a UI that only ever pulls. A laptop
|
|
9
|
+
* behind NAT cannot accept inbound, so the data path must be push — the daemon
|
|
10
|
+
* is the pipeline, not a new trust boundary.
|
|
11
|
+
*
|
|
12
|
+
* This module changes NOTHING about what is pushed. It wraps the existing
|
|
13
|
+
* one-shot cycle (`buildInstanceMirror` → `sendRemoteEnvelope`) in the same
|
|
14
|
+
* supervisor idioms already shipped for the L1 objective loop
|
|
15
|
+
* (`runtime/loop/supervisor.ts`): opt-in only, a global kill-switch, an
|
|
16
|
+
* injectable clock, a drainable abort signal, and a per-beat summary that is
|
|
17
|
+
* observability — never control. The signed-envelope trust boundary, the
|
|
18
|
+
* payload shape, the sequence fencing and the accept-side verification are
|
|
19
|
+
* untouched.
|
|
20
|
+
*
|
|
21
|
+
* Safety properties, in the order they matter:
|
|
22
|
+
*
|
|
23
|
+
* - OPT-IN, NEVER DEFAULT-ON. Nothing here runs unless a caller explicitly
|
|
24
|
+
* asks for an interval. `h2a remote mirror` with no `--interval-ms` still
|
|
25
|
+
* takes the byte-identical one-shot path it took before this module existed.
|
|
26
|
+
* The global kill-switch `H2A_MIRROR_PUSH_OFF` hard-disables the loop even
|
|
27
|
+
* when a unit file or an operator asked for it — checked before the FIRST
|
|
28
|
+
* cycle, so a frozen daemon never emits a single request.
|
|
29
|
+
*
|
|
30
|
+
* - AUTH FAILURE STOPS, IT DOES NOT RETRY FOREVER. A 401/403 means the
|
|
31
|
+
* receiving side does not trust this instance's signing key (never enrolled,
|
|
32
|
+
* revoked, or — the live case today — the agent re-anchored and mints a
|
|
33
|
+
* different keypair than the one enrolled). No amount of retrying fixes
|
|
34
|
+
* that: it needs a human re-enrollment ceremony. So consecutive auth
|
|
35
|
+
* rejections are backed off and then the daemon STOPS with an actionable
|
|
36
|
+
* message, instead of hammering a rejecting endpoint indefinitely. Only a
|
|
37
|
+
* genuinely accepted push (`ok`) clears the counter — a transient error in
|
|
38
|
+
* between does NOT, because "network flap between two 401s" must not be a
|
|
39
|
+
* way to loop forever against a server that is refusing us.
|
|
40
|
+
*
|
|
41
|
+
* - NO OVERLAP. The daemon cannot overlap itself: it awaits each cycle before
|
|
42
|
+
* scheduling the next, so a slow push delays the next beat rather than
|
|
43
|
+
* stacking on top of it (and the slot arithmetic below then skips the beats
|
|
44
|
+
* that were missed). The exported runner ALSO carries an in-flight guard, for
|
|
45
|
+
* the different case of two concurrent callers sharing one runner: the second
|
|
46
|
+
* gets `skipped-overlap` without building or sending anything. That guard is
|
|
47
|
+
* defence for external callers, not what protects the daemon's own loop.
|
|
48
|
+
*
|
|
49
|
+
* - NO DRIFT. Cycles are scheduled against a monotonic slot anchor
|
|
50
|
+
* (`anchor + n × interval`), not by sleeping a fixed interval after each
|
|
51
|
+
* cycle, so per-cycle duration does not accumulate into lateness. Slots
|
|
52
|
+
* already in the past are skipped rather than fired back-to-back. A small
|
|
53
|
+
* bounded jitter de-synchronises several agents pushing to one endpoint.
|
|
54
|
+
*
|
|
55
|
+
* - TRANSIENT ERRORS KEEP LOOPING. A network throw, a 5xx or a 429 is the
|
|
56
|
+
* endpoint's problem, not ours: exponential backoff (capped), then carry on.
|
|
57
|
+
*
|
|
58
|
+
* - A STATUS MUST NOT BE WIDER THAN ITS EVIDENCE. The dividing line for every
|
|
59
|
+
* stop rule above is "can this self-heal": a network outage can, a refused
|
|
60
|
+
* key / a refused request / a root that cannot build this instance's mirror
|
|
61
|
+
* cannot. The non-self-healing cases therefore TERMINATE rather than idle,
|
|
62
|
+
* because idling would make this process the dishonest layer. Consider a
|
|
63
|
+
* wrong `H2A_ROOT`: nothing is ever sent, so the feed downstream correctly
|
|
64
|
+
* starts reporting those rows `stale` once `mirroredAt` stops advancing —
|
|
65
|
+
* while `systemctl status` would still read `active (running)`. The two
|
|
66
|
+
* layers would disagree and the only honest signal would be the one FURTHEST
|
|
67
|
+
* from the operator, in a UI nobody is watching. The signal nearest the fault
|
|
68
|
+
* has to be at least as honest as the far one, so we exit 1 and say why.
|
|
69
|
+
* Correspondingly, the per-cycle line reports what the push CONTAINED (seq +
|
|
70
|
+
* counts), so a successful push of an empty mirror is never mistaken for a
|
|
71
|
+
* healthy feed.
|
|
72
|
+
*
|
|
73
|
+
* - DRAINABLE. `signal` is honored before each cycle and inside every sleep,
|
|
74
|
+
* so SIGTERM stops promptly instead of finishing the schedule.
|
|
75
|
+
*
|
|
76
|
+
* - LOGS ARE SAFE BY CONSTRUCTION. The per-cycle line carries an outcome, an
|
|
77
|
+
* HTTP status, a closed-vocabulary rejection reason and a redacted endpoint.
|
|
78
|
+
* It NEVER carries key material, a token, a request body or a response body.
|
|
79
|
+
* Everything free-form (an error message) goes through `sanitizeForLog`.
|
|
80
|
+
*/
|
|
81
|
+
import { createLocalStore } from "../local-files/index.js";
|
|
82
|
+
import { sendRemoteEnvelope } from "../remote/client.js";
|
|
83
|
+
import { buildInstanceMirror } from "./build.js";
|
|
84
|
+
/**
|
|
85
|
+
* Default beat. The ratified contract asks for 15–30s; 20s sits in the middle
|
|
86
|
+
* and keeps a UI's worst-case staleness under the 90s presence keepalive
|
|
87
|
+
* window, so a `stale` row means the pipeline really is down.
|
|
88
|
+
*/
|
|
89
|
+
export const DEFAULT_MIRROR_PUSH_INTERVAL_MS = 20_000;
|
|
90
|
+
/**
|
|
91
|
+
* Floor the CLI enforces on `--interval-ms`. The library itself accepts any
|
|
92
|
+
* positive interval (tests drive it at millisecond speed against a fake
|
|
93
|
+
* transport); the operator-facing surface refuses anything that would hammer a
|
|
94
|
+
* hosted endpoint faster than the contract's own range.
|
|
95
|
+
*/
|
|
96
|
+
export const MIN_MIRROR_PUSH_INTERVAL_MS = 5_000;
|
|
97
|
+
/** Bounded de-synchronisation jitter, as a fraction of the interval (±10%). */
|
|
98
|
+
export const MIRROR_PUSH_JITTER_FRACTION = 0.1;
|
|
99
|
+
/** First transient-failure backoff; doubles per consecutive failure. */
|
|
100
|
+
export const MIRROR_PUSH_BACKOFF_BASE_MS = 5_000;
|
|
101
|
+
/** Backoff ceiling — a long outage retries every 5 min, not every 5 hours. */
|
|
102
|
+
export const MIRROR_PUSH_BACKOFF_MAX_MS = 300_000;
|
|
103
|
+
/**
|
|
104
|
+
* How many CONSECUTIVE auth rejections are tolerated (each backed off) before
|
|
105
|
+
* the daemon stops. 3 absorbs a key-rotation race on the accept side while
|
|
106
|
+
* still stopping in well under a minute of real rejection.
|
|
107
|
+
*/
|
|
108
|
+
export const DEFAULT_MIRROR_AUTH_FAILURE_LIMIT = 3;
|
|
109
|
+
/**
|
|
110
|
+
* How many CONSECUTIVE non-auth rejections (a 4xx that is not 401/403) are
|
|
111
|
+
* tolerated before the daemon stops. Some of these genuinely self-heal — a
|
|
112
|
+
* stale-sequence or replay rejection clears as `seq` advances — which is why the
|
|
113
|
+
* budget is looser than the auth one. But a permanently malformed request or a
|
|
114
|
+
* wrong path returning 404 will never heal, and retrying it forever is the same
|
|
115
|
+
* failure mode as retrying a refused key: a unit that reads "active (running)"
|
|
116
|
+
* while pushing nothing. 5 tolerates a real fencing race, then stops.
|
|
117
|
+
*/
|
|
118
|
+
export const DEFAULT_MIRROR_REJECT_LIMIT = 5;
|
|
119
|
+
/**
|
|
120
|
+
* How many CONSECUTIVE local build failures are tolerated before the daemon
|
|
121
|
+
* stops. `buildInstanceMirror` throwing means this root does not know this
|
|
122
|
+
* instance — overwhelmingly because `H2A_ROOT` points somewhere the agent never
|
|
123
|
+
* registered, the misconfiguration the shipped unit file explicitly warns about.
|
|
124
|
+
* A wrong root NEVER self-heals, and looping on it forever is the worst possible
|
|
125
|
+
* failure shape: no request is ever sent, yet `systemctl status` reads
|
|
126
|
+
* `active (running)` indefinitely, so monitoring keyed on systemd state reads
|
|
127
|
+
* green while the feed is dead. It must terminate loudly instead. 5 leaves room
|
|
128
|
+
* for a genuinely transient race (an agent re-registering, a root being created).
|
|
129
|
+
*
|
|
130
|
+
* The contract-level argument (from the feed contract's own architect): in this
|
|
131
|
+
* failure mode the feed WOULD report `stale` correctly, because `mirroredAt` stops
|
|
132
|
+
* advancing — so the honest signal exists, but only at the layer furthest from the
|
|
133
|
+
* operator. Idling here would ship a daemon that claims health next to a contract
|
|
134
|
+
* written specifically to refuse claiming it.
|
|
135
|
+
*/
|
|
136
|
+
export const DEFAULT_MIRROR_BUILD_FAILURE_LIMIT = 5;
|
|
137
|
+
/** Name of the global kill-switch env var. */
|
|
138
|
+
export const MIRROR_PUSH_OFF_ENV = "H2A_MIRROR_PUSH_OFF";
|
|
139
|
+
/**
|
|
140
|
+
* Global kill-switch for the live mirror push. When `H2A_MIRROR_PUSH_OFF` is
|
|
141
|
+
* set to any non-empty, non-"0"/"false" value, NO mirror push daemon runs
|
|
142
|
+
* anywhere, regardless of flags or unit files. Same semantics as
|
|
143
|
+
* `H2A_LOOP_AUTOTICK_OFF` for the objective-loop supervisor — one lever to
|
|
144
|
+
* freeze the pipeline without editing any invocation.
|
|
145
|
+
*/
|
|
146
|
+
export function mirrorPushGloballyDisabled(env = process.env) {
|
|
147
|
+
const v = env[MIRROR_PUSH_OFF_ENV];
|
|
148
|
+
if (v === undefined)
|
|
149
|
+
return false;
|
|
150
|
+
const norm = v.trim().toLowerCase();
|
|
151
|
+
return norm !== "" && norm !== "0" && norm !== "false";
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Emitted when the daemon stops because the endpoint keeps rejecting the request
|
|
155
|
+
* itself (not the key). Like the auth stop, retrying cannot fix a permanently
|
|
156
|
+
* malformed request or a wrong path.
|
|
157
|
+
*/
|
|
158
|
+
export const MIRROR_PUSH_REJECTED_MESSAGE = "mirror push STOPPED: the endpoint rejected this mirror on every attempt with a 4xx that is not an auth failure. " +
|
|
159
|
+
"The request itself is being refused, so retrying cannot fix it — check that --url points at the ingester's mirror path " +
|
|
160
|
+
"(a wrong path typically answers 404) and that this instance's clock is accurate (a skewed clock is refused as expired/future). " +
|
|
161
|
+
"The per-cycle status lines carry the endpoint and the rejection reason. Nothing further will be pushed until the daemon is restarted.";
|
|
162
|
+
/**
|
|
163
|
+
* Emitted when the daemon is asked to push to something that is not a usable
|
|
164
|
+
* http(s) endpoint. Returned BEFORE any cycle runs, because a URL `fetch` cannot
|
|
165
|
+
* even parse would otherwise be retried forever as a transient network failure.
|
|
166
|
+
*/
|
|
167
|
+
/**
|
|
168
|
+
* Emitted when the daemon stops because it cannot even BUILD a mirror locally.
|
|
169
|
+
* Names the likely cause, because this failure never reaches the network and so
|
|
170
|
+
* leaves no server-side trace for the operator to correlate against.
|
|
171
|
+
*/
|
|
172
|
+
export const MIRROR_PUSH_BUILD_FAILED_MESSAGE = "mirror push STOPPED: this h2a root does not know the instance being mirrored, on every attempt. " +
|
|
173
|
+
"Nothing was ever sent, and this cannot self-heal by retrying. " +
|
|
174
|
+
"Check that --instance names an instance registered in THIS root and that H2A_ROOT / --root points at the root where that agent actually registers " +
|
|
175
|
+
"(h2a discover --root <root> lists them). Nothing further will be pushed until the daemon is restarted.";
|
|
176
|
+
export const MIRROR_PUSH_INVALID_URL_MESSAGE = "mirror push NOT STARTED: the push target is not a usable http(s) URL, so no request could ever succeed. " +
|
|
177
|
+
"Set --url to the ingester's full mirror endpoint (for example https://host/h2a/mirror). " +
|
|
178
|
+
"If this is a systemd unit, its ExecStart placeholder was not filled in.";
|
|
179
|
+
/**
|
|
180
|
+
* The actionable message emitted when the daemon stops on repeated auth
|
|
181
|
+
* rejection. Deliberately explicit: the failure is NOT retryable and the
|
|
182
|
+
* operator must know exactly which human act unblocks it.
|
|
183
|
+
*/
|
|
184
|
+
export const MIRROR_PUSH_REENROLLMENT_MESSAGE = "mirror push STOPPED: the endpoint rejected this instance's signing key (HTTP 401/403) on every attempt. " +
|
|
185
|
+
"This is not a transient error and retrying cannot fix it — the key is not enrolled on the receiving side " +
|
|
186
|
+
"(never enrolled, revoked, or the agent re-anchored and now signs with a different keypair). " +
|
|
187
|
+
"RE-ENROLLMENT IS REQUIRED: enroll this instance's CURRENT public key on the receiving side, then restart the daemon. " +
|
|
188
|
+
"Nothing further will be pushed until then.";
|
|
189
|
+
/** Accept-side rejection vocabulary (`runtime/mirror/accept.ts`). */
|
|
190
|
+
const MIRROR_REJECTION_REASONS = new Set([
|
|
191
|
+
"malformed",
|
|
192
|
+
"not-mirror",
|
|
193
|
+
"no-signature",
|
|
194
|
+
"unauthorized-key",
|
|
195
|
+
"bad-signature",
|
|
196
|
+
"invalid-timestamp",
|
|
197
|
+
"expired",
|
|
198
|
+
"future",
|
|
199
|
+
"replayed",
|
|
200
|
+
"stale-sequence",
|
|
201
|
+
"instance-key-mismatch"
|
|
202
|
+
]);
|
|
203
|
+
/**
|
|
204
|
+
* Strip anything that could be secret out of free-form text before it is
|
|
205
|
+
* logged. Defence in depth: nothing here is SUPPOSED to see key material, but a
|
|
206
|
+
* thrown error can carry whatever the thrower put in it, and this daemon holds a
|
|
207
|
+
* private key in memory. PEM blocks, bearer tokens and token-ish query params
|
|
208
|
+
* are replaced; the result is length-capped so a giant blob cannot be smuggled
|
|
209
|
+
* out one line at a time.
|
|
210
|
+
*/
|
|
211
|
+
export function sanitizeForLog(text) {
|
|
212
|
+
return (text
|
|
213
|
+
.replace(/-----BEGIN[\s\S]*?-----END[^-]*-----/g, "[redacted-key]")
|
|
214
|
+
.replace(/-----BEGIN[\s\S]*/g, "[redacted-key]")
|
|
215
|
+
// URL userinfo (https://user:password@host) anywhere in free-form text.
|
|
216
|
+
.replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[redacted]@")
|
|
217
|
+
.replace(/\b(bearer|basic)\s+[\w.\-+/=]+/gi, "$1 [redacted]")
|
|
218
|
+
// Credential-ish parameters. The name prefix is matched explicitly rather
|
|
219
|
+
// than with `\b`, because `\b` does not fire after an underscore — which
|
|
220
|
+
// let every `access_token=` / `session_key=` form through untouched.
|
|
221
|
+
.replace(/([\w.-]*(?:token|key|secret|password|passwd|signature|credential)s?)=([^&\s]+)/gi, "$1=[redacted]")
|
|
222
|
+
// HEADER form (`X-Api-Key: literal`, `cookie: sid=…`). The `name=value`
|
|
223
|
+
// rule above cannot see these, because the delimiter is a colon.
|
|
224
|
+
.replace(/^([ \t]*[\w-]*(?:token|key|secret|password|passwd|auth|authorization|cookie|credential)s?)[ \t]*:[ \t]*\S.*$/gim, "$1: [redacted]")
|
|
225
|
+
.slice(0, 300));
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Text of a caught value, for a value that is NOT guaranteed to be an `Error`.
|
|
229
|
+
* A rejection can carry anything — a string, an object, `undefined` from a bare
|
|
230
|
+
* `Promise.reject()` — and this daemon's whole contract is that a cycle never
|
|
231
|
+
* throws. Reading `.message` off a non-Error would itself throw, escape the
|
|
232
|
+
* classifier, and land in the CLI's unsanitized fatal handler.
|
|
233
|
+
*
|
|
234
|
+
* EVERY read is inside the `try`, deliberately. Accessing `.message` is not a
|
|
235
|
+
* safe operation: it can be a getter that throws (including on a real `Error`
|
|
236
|
+
* subclass), so a guard that only wraps the `String()` fallback still lets a
|
|
237
|
+
* hostile object escape. The whole inspection is therefore fallible-by-default.
|
|
238
|
+
*/
|
|
239
|
+
function errorText(error) {
|
|
240
|
+
try {
|
|
241
|
+
if (error instanceof Error && typeof error.message === "string")
|
|
242
|
+
return error.message;
|
|
243
|
+
const message = error?.message;
|
|
244
|
+
if (typeof message === "string")
|
|
245
|
+
return message;
|
|
246
|
+
return String(error);
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// A hostile `message` getter or `toString` still must not break the cycle.
|
|
250
|
+
return "[unrepresentable error]";
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* True when a logging failure means the status sink is GONE for good rather than
|
|
255
|
+
* momentarily unhappy — a closed or destroyed stream. A piped stdout that the
|
|
256
|
+
* reader closed (`| head -3`, a journald restart) surfaces as EPIPE and never
|
|
257
|
+
* reopens, so the honest response is to stop, not to keep pushing unobservably.
|
|
258
|
+
*/
|
|
259
|
+
function isClosedStreamError(error) {
|
|
260
|
+
let code;
|
|
261
|
+
try {
|
|
262
|
+
code = error?.code;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
return code === "EPIPE" || code === "ERR_STREAM_DESTROYED" || code === "ERR_STREAM_WRITE_AFTER_END";
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Read the non-secret shape of the envelope about to be pushed: its sequence
|
|
271
|
+
* number and the cardinality of each collection. Never its contents. Defensive
|
|
272
|
+
* about shape, because a caller can inject any `buildImpl`.
|
|
273
|
+
*/
|
|
274
|
+
function payloadShapeOf(envelope) {
|
|
275
|
+
const body = envelope.body;
|
|
276
|
+
const count = (v) => (Array.isArray(v) ? v.length : 0);
|
|
277
|
+
return {
|
|
278
|
+
...(typeof body?.seq === "number" ? { seq: body.seq } : {}),
|
|
279
|
+
registrations: count(body?.registrations),
|
|
280
|
+
presence: count(body?.presence),
|
|
281
|
+
subagents: count(body?.subagents)
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* True when `url` is something a push could actually reach: parseable, and
|
|
286
|
+
* http(s). Anything else — an unfilled placeholder, a typo, a `file:` or `ws:`
|
|
287
|
+
* scheme — makes `fetch` throw a parse error that would otherwise be classified
|
|
288
|
+
* as a retryable network failure and retried forever.
|
|
289
|
+
*/
|
|
290
|
+
export function isPushableHttpUrl(url) {
|
|
291
|
+
if (typeof url !== "string" || url.trim() === "")
|
|
292
|
+
return false;
|
|
293
|
+
let parsed;
|
|
294
|
+
try {
|
|
295
|
+
parsed = new URL(url);
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Reduce a URL to scheme + host + path. Drops query and userinfo, which are the
|
|
304
|
+
* two places a credential can hide in a URL, and keeps enough for an operator to
|
|
305
|
+
* recognise which endpoint is being pushed to.
|
|
306
|
+
*/
|
|
307
|
+
export function redactEndpoint(url) {
|
|
308
|
+
try {
|
|
309
|
+
const u = new URL(url);
|
|
310
|
+
return `${u.protocol}//${u.host}${u.pathname}`;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return "[unparseable-url]";
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/** True for a status that means "your key is not trusted here". */
|
|
317
|
+
function isAuthRejection(status) {
|
|
318
|
+
return status === 401 || status === 403;
|
|
319
|
+
}
|
|
320
|
+
/** True for a status worth retrying: server-side or rate-limit. */
|
|
321
|
+
function isTransientStatus(status) {
|
|
322
|
+
return status === 408 || status === 429 || status >= 500;
|
|
323
|
+
}
|
|
324
|
+
/** Pull the closed-vocabulary rejection reason out of an accept-side body. */
|
|
325
|
+
function rejectionReasonOf(body) {
|
|
326
|
+
if (!body || typeof body !== "object")
|
|
327
|
+
return undefined;
|
|
328
|
+
const reason = body.reason;
|
|
329
|
+
if (typeof reason === "string" && MIRROR_REJECTION_REASONS.has(reason))
|
|
330
|
+
return reason;
|
|
331
|
+
return undefined;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Create the guarded one-cycle runner: build → sign → POST once, classified.
|
|
335
|
+
*
|
|
336
|
+
* The returned function is the ONLY thing that touches the network. It carries an
|
|
337
|
+
* in-flight guard for CONCURRENT callers of the same runner: while one cycle is
|
|
338
|
+
* running, a second call returns `skipped-overlap` immediately without building
|
|
339
|
+
* an envelope or issuing a request. (The daemon itself awaits each cycle, so it
|
|
340
|
+
* never trips this guard on its own — see the module header.) Exposed so a caller
|
|
341
|
+
* or a test can drive single cycles without the timer loop, exactly as
|
|
342
|
+
* `runSupervisorBeat` is exposed next to `runLoopSupervisor`.
|
|
343
|
+
*
|
|
344
|
+
* Never throws: every failure is classified into a {@link MirrorPushOutcome}.
|
|
345
|
+
*/
|
|
346
|
+
export function createMirrorPushRunner(options) {
|
|
347
|
+
const nowFn = options.now ?? (() => Date.now());
|
|
348
|
+
const build = options.buildImpl ??
|
|
349
|
+
((nowMs) => buildInstanceMirror(createLocalStore({ root: options.root }), options.instance, nowMs));
|
|
350
|
+
const send = options.sendImpl ?? sendRemoteEnvelope;
|
|
351
|
+
let inFlight = false;
|
|
352
|
+
return async function runCycle() {
|
|
353
|
+
// OVERLAP GUARD: a slow push must not stack. Checked before any work, so a
|
|
354
|
+
// skipped cycle costs nothing and, crucially, sends nothing.
|
|
355
|
+
if (inFlight)
|
|
356
|
+
return { outcome: "skipped-overlap", durationMs: 0 };
|
|
357
|
+
inFlight = true;
|
|
358
|
+
const startedAt = nowFn();
|
|
359
|
+
try {
|
|
360
|
+
let envelope;
|
|
361
|
+
try {
|
|
362
|
+
envelope = build(startedAt);
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
// Local build failure (e.g. the instance is not in this root's
|
|
366
|
+
// registry). Not fatal: an agent can re-register, so we back off and
|
|
367
|
+
// keep looping rather than tearing the daemon down. No request was made.
|
|
368
|
+
return {
|
|
369
|
+
outcome: "build-failed",
|
|
370
|
+
error: sanitizeForLog(errorText(error)),
|
|
371
|
+
durationMs: nowFn() - startedAt
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// Read once, before the send, so the shape is reported even for a failed
|
|
375
|
+
// push (the envelope is what WAS attempted).
|
|
376
|
+
const payload = payloadShapeOf(envelope);
|
|
377
|
+
let status;
|
|
378
|
+
let body;
|
|
379
|
+
try {
|
|
380
|
+
const res = await send(options.url, envelope, {
|
|
381
|
+
by: options.instance,
|
|
382
|
+
privateKeyPem: options.privateKeyPem
|
|
383
|
+
});
|
|
384
|
+
status = res.status;
|
|
385
|
+
body = res.body;
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
// Transport threw: DNS, refused, TLS, timeout. Retryable.
|
|
389
|
+
return {
|
|
390
|
+
outcome: "transient",
|
|
391
|
+
error: sanitizeForLog(errorText(error)),
|
|
392
|
+
durationMs: nowFn() - startedAt,
|
|
393
|
+
payload
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
const durationMs = nowFn() - startedAt;
|
|
397
|
+
const reason = rejectionReasonOf(body);
|
|
398
|
+
if (status >= 200 && status < 300) {
|
|
399
|
+
return { outcome: "ok", status, durationMs, payload };
|
|
400
|
+
}
|
|
401
|
+
if (isAuthRejection(status)) {
|
|
402
|
+
// The key itself is refused. Counted toward the stop budget.
|
|
403
|
+
return { outcome: "auth-rejected", status, ...(reason ? { reason } : {}), durationMs, payload };
|
|
404
|
+
}
|
|
405
|
+
if (isTransientStatus(status)) {
|
|
406
|
+
return { outcome: "transient", status, ...(reason ? { reason } : {}), durationMs, payload };
|
|
407
|
+
}
|
|
408
|
+
// Other 4xx: a rejected envelope (stale sequence, replay, clock skew).
|
|
409
|
+
// Some of these self-heal as the sequence advances, so we keep looping —
|
|
410
|
+
// but backed off, so a permanently malformed push is not a hot loop.
|
|
411
|
+
return { outcome: "rejected", status, ...(reason ? { reason } : {}), durationMs, payload };
|
|
412
|
+
}
|
|
413
|
+
finally {
|
|
414
|
+
inFlight = false;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
/** Abort-aware sleep. Resolves early (does not reject) when aborted. */
|
|
419
|
+
function delay(ms, signal) {
|
|
420
|
+
return new Promise((resolve) => {
|
|
421
|
+
if (signal?.aborted)
|
|
422
|
+
return resolve();
|
|
423
|
+
const timer = setTimeout(() => {
|
|
424
|
+
signal?.removeEventListener("abort", onAbort);
|
|
425
|
+
resolve();
|
|
426
|
+
}, ms);
|
|
427
|
+
function onAbort() {
|
|
428
|
+
clearTimeout(timer);
|
|
429
|
+
resolve();
|
|
430
|
+
}
|
|
431
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Run the live mirror push until `signal` aborts, `max` cycles elapse, or the
|
|
436
|
+
* endpoint has refused this key often enough to stop (see
|
|
437
|
+
* {@link MIRROR_PUSH_REENROLLMENT_MESSAGE}).
|
|
438
|
+
*
|
|
439
|
+
* This is what the systemd `--user` unit runs. It is NEVER on any default code
|
|
440
|
+
* path: no caller reaches it without an explicit interval, and the kill-switch
|
|
441
|
+
* short-circuits it before the first request.
|
|
442
|
+
*/
|
|
443
|
+
export async function runMirrorPushDaemon(options) {
|
|
444
|
+
const env = options.env ?? process.env;
|
|
445
|
+
const nowFn = options.now ?? (() => Date.now());
|
|
446
|
+
const random = options.random ?? (() => Math.random());
|
|
447
|
+
const sleep = options.sleep ?? delay;
|
|
448
|
+
const intervalMs = options.intervalMs && options.intervalMs > 0
|
|
449
|
+
? options.intervalMs
|
|
450
|
+
: DEFAULT_MIRROR_PUSH_INTERVAL_MS;
|
|
451
|
+
const authLimit = options.authFailureLimit && options.authFailureLimit > 0
|
|
452
|
+
? options.authFailureLimit
|
|
453
|
+
: DEFAULT_MIRROR_AUTH_FAILURE_LIMIT;
|
|
454
|
+
const rejectLimit = options.rejectLimit && options.rejectLimit > 0
|
|
455
|
+
? options.rejectLimit
|
|
456
|
+
: DEFAULT_MIRROR_REJECT_LIMIT;
|
|
457
|
+
const buildLimit = options.buildFailureLimit && options.buildFailureLimit > 0
|
|
458
|
+
? options.buildFailureLimit
|
|
459
|
+
: DEFAULT_MIRROR_BUILD_FAILURE_LIMIT;
|
|
460
|
+
const backoffBase = options.backoffBaseMs && options.backoffBaseMs > 0
|
|
461
|
+
? options.backoffBaseMs
|
|
462
|
+
: MIRROR_PUSH_BACKOFF_BASE_MS;
|
|
463
|
+
const backoffMax = options.backoffMaxMs && options.backoffMaxMs > 0
|
|
464
|
+
? options.backoffMaxMs
|
|
465
|
+
: MIRROR_PUSH_BACKOFF_MAX_MS;
|
|
466
|
+
const endpoint = redactEndpoint(options.url);
|
|
467
|
+
let cycles = 0;
|
|
468
|
+
let ok = 0;
|
|
469
|
+
let failures = 0;
|
|
470
|
+
let skippedOverlap = 0;
|
|
471
|
+
let authFailures = 0;
|
|
472
|
+
let rejections = 0;
|
|
473
|
+
let buildFailures = 0;
|
|
474
|
+
let logFailures = 0;
|
|
475
|
+
let consecutiveFailures = 0;
|
|
476
|
+
const finish = (stopReason, message) => ({
|
|
477
|
+
cycles,
|
|
478
|
+
ok,
|
|
479
|
+
failures,
|
|
480
|
+
skippedOverlap,
|
|
481
|
+
authFailures,
|
|
482
|
+
rejections,
|
|
483
|
+
buildFailures,
|
|
484
|
+
logFailures,
|
|
485
|
+
stopReason,
|
|
486
|
+
...(message ? { message } : {})
|
|
487
|
+
});
|
|
488
|
+
// KILL-SWITCH, checked BEFORE the first cycle: a frozen daemon must not emit
|
|
489
|
+
// a single request, not even one.
|
|
490
|
+
if (mirrorPushGloballyDisabled(env))
|
|
491
|
+
return finish("kill-switch");
|
|
492
|
+
if (options.signal?.aborted)
|
|
493
|
+
return finish("aborted");
|
|
494
|
+
// A target `fetch` cannot even parse would throw a parse TypeError that this
|
|
495
|
+
// daemon would classify as a retryable network failure and retry forever. Stop
|
|
496
|
+
// before the first cycle instead — the CLI refuses such a URL up front, but the
|
|
497
|
+
// library is public API and must not be loopable into that state either.
|
|
498
|
+
if (!isPushableHttpUrl(options.url)) {
|
|
499
|
+
return finish("config-invalid", MIRROR_PUSH_INVALID_URL_MESSAGE);
|
|
500
|
+
}
|
|
501
|
+
const runCycle = options.runner ?? createMirrorPushRunner(options);
|
|
502
|
+
// Monotonic slot anchor — cycle n is due at `anchor + n × intervalMs`, so a
|
|
503
|
+
// slow cycle does not push every later cycle late (no drift). Re-anchored
|
|
504
|
+
// after a backoff, whose delay is deliberate rather than lateness.
|
|
505
|
+
let anchor = nowFn();
|
|
506
|
+
let slot = 0;
|
|
507
|
+
for (;;) {
|
|
508
|
+
// Re-checked each cycle so a mutated environment freezes an already-running
|
|
509
|
+
// daemon at the next beat instead of only at (re)start.
|
|
510
|
+
if (mirrorPushGloballyDisabled(env))
|
|
511
|
+
return finish("kill-switch");
|
|
512
|
+
if (options.signal?.aborted)
|
|
513
|
+
return finish("aborted");
|
|
514
|
+
const result = await runCycle();
|
|
515
|
+
cycles += 1;
|
|
516
|
+
if (result.outcome === "skipped-overlap") {
|
|
517
|
+
skippedOverlap += 1;
|
|
518
|
+
}
|
|
519
|
+
else if (result.outcome === "ok") {
|
|
520
|
+
ok += 1;
|
|
521
|
+
consecutiveFailures = 0;
|
|
522
|
+
// Only a genuinely ACCEPTED push clears either stop budget.
|
|
523
|
+
authFailures = 0;
|
|
524
|
+
rejections = 0;
|
|
525
|
+
buildFailures = 0;
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
failures += 1;
|
|
529
|
+
consecutiveFailures += 1;
|
|
530
|
+
if (result.outcome === "auth-rejected")
|
|
531
|
+
authFailures += 1;
|
|
532
|
+
if (result.outcome === "rejected")
|
|
533
|
+
rejections += 1;
|
|
534
|
+
if (result.outcome === "build-failed")
|
|
535
|
+
buildFailures += 1;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Emit the status line. OBSERVABILITY MUST NOT BREAK THE PIPELINE: `onCycle`
|
|
539
|
+
* is caller-supplied and writes to a stream the caller owns, so it can throw
|
|
540
|
+
* — the common case being EPIPE once a piped stdout closes (`| head -3`, a
|
|
541
|
+
* journald restart). Unguarded, that rejection escaped the daemon into the
|
|
542
|
+
* CLI's raw fatal handler and pinned the unit `failed` with a message
|
|
543
|
+
* matching none of the documented stops.
|
|
544
|
+
*
|
|
545
|
+
* A dead sink is not a reason to keep pushing blind, though: a closed stream
|
|
546
|
+
* never reopens, so we stop CLEANLY (exit 0, no message) instead of running
|
|
547
|
+
* unobservable. Any other logging error is counted and ignored.
|
|
548
|
+
*
|
|
549
|
+
* Returns false when the caller should stop.
|
|
550
|
+
*/
|
|
551
|
+
const emit = async (nextInMs) => {
|
|
552
|
+
if (!options.onCycle)
|
|
553
|
+
return true;
|
|
554
|
+
try {
|
|
555
|
+
await options.onCycle({
|
|
556
|
+
cycle: cycles,
|
|
557
|
+
at: new Date(nowFn()).toISOString(),
|
|
558
|
+
instance: options.instance,
|
|
559
|
+
endpoint,
|
|
560
|
+
outcome: result.outcome,
|
|
561
|
+
...(result.status !== undefined ? { status: result.status } : {}),
|
|
562
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
563
|
+
...(result.error ? { error: result.error } : {}),
|
|
564
|
+
durationMs: result.durationMs,
|
|
565
|
+
...(result.payload?.seq !== undefined ? { seq: result.payload.seq } : {}),
|
|
566
|
+
...(result.payload
|
|
567
|
+
? {
|
|
568
|
+
registrations: result.payload.registrations,
|
|
569
|
+
presence: result.payload.presence,
|
|
570
|
+
subagents: result.payload.subagents
|
|
571
|
+
}
|
|
572
|
+
: {}),
|
|
573
|
+
...(nextInMs !== undefined ? { nextInMs } : {}),
|
|
574
|
+
authFailures,
|
|
575
|
+
rejections,
|
|
576
|
+
buildFailures
|
|
577
|
+
});
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
logFailures += 1;
|
|
582
|
+
return !isClosedStreamError(error);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
// AUTH STOP: the budget is spent, so stop instead of hammering a server
|
|
586
|
+
// that is refusing this key. Backoff already happened between attempts.
|
|
587
|
+
if (authFailures >= authLimit) {
|
|
588
|
+
await emit(undefined);
|
|
589
|
+
return finish("auth-stop", MIRROR_PUSH_REENROLLMENT_MESSAGE);
|
|
590
|
+
}
|
|
591
|
+
// REJECT STOP: the same reasoning for a request the endpoint keeps refusing
|
|
592
|
+
// on non-auth grounds. A looser budget, because a fencing rejection can
|
|
593
|
+
// genuinely clear — but not an unbounded one, because a wrong path cannot.
|
|
594
|
+
if (rejections >= rejectLimit) {
|
|
595
|
+
await emit(undefined);
|
|
596
|
+
return finish("reject-stop", MIRROR_PUSH_REJECTED_MESSAGE);
|
|
597
|
+
}
|
|
598
|
+
// BUILD STOP: we cannot even assemble a mirror. Nothing was sent and nothing
|
|
599
|
+
// will be, so idling `active (running)` forever would report green while the
|
|
600
|
+
// feed is dead. A wrong H2A_ROOT never self-heals — terminate loudly.
|
|
601
|
+
if (buildFailures >= buildLimit) {
|
|
602
|
+
await emit(undefined);
|
|
603
|
+
return finish("build-stop", MIRROR_PUSH_BUILD_FAILED_MESSAGE);
|
|
604
|
+
}
|
|
605
|
+
if (options.max !== undefined && cycles >= options.max) {
|
|
606
|
+
await emit(undefined);
|
|
607
|
+
return finish("max-cycles");
|
|
608
|
+
}
|
|
609
|
+
if (options.signal?.aborted) {
|
|
610
|
+
await emit(undefined);
|
|
611
|
+
return finish("aborted");
|
|
612
|
+
}
|
|
613
|
+
// Schedule the next cycle: backoff after a failure, otherwise the next
|
|
614
|
+
// monotonic slot with bounded jitter.
|
|
615
|
+
let waitMs;
|
|
616
|
+
if (consecutiveFailures > 0) {
|
|
617
|
+
const exp = Math.min(backoffMax, backoffBase * 2 ** (consecutiveFailures - 1));
|
|
618
|
+
waitMs = Math.max(0, Math.round(exp * (1 + MIRROR_PUSH_JITTER_FRACTION * (random() * 2 - 1))));
|
|
619
|
+
// The backoff wait is intentional, so the drift anchor restarts from here.
|
|
620
|
+
anchor = nowFn() + waitMs;
|
|
621
|
+
slot = 0;
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
slot += 1;
|
|
625
|
+
let due = anchor + slot * intervalMs;
|
|
626
|
+
// A cycle that overran one or more whole slots must not fire the missed
|
|
627
|
+
// ones back-to-back: skip straight to the next slot in the future.
|
|
628
|
+
while (due <= nowFn()) {
|
|
629
|
+
slot += 1;
|
|
630
|
+
due = anchor + slot * intervalMs;
|
|
631
|
+
}
|
|
632
|
+
const jitter = intervalMs * MIRROR_PUSH_JITTER_FRACTION * (random() * 2 - 1);
|
|
633
|
+
waitMs = Math.max(0, Math.round(due - nowFn() + jitter));
|
|
634
|
+
}
|
|
635
|
+
// A dead status sink stops the daemon cleanly rather than leaving it to push
|
|
636
|
+
// where nobody can see what it is doing.
|
|
637
|
+
if (!(await emit(waitMs)))
|
|
638
|
+
return finish("log-unavailable");
|
|
639
|
+
await sleep(waitMs, options.signal);
|
|
640
|
+
if (options.signal?.aborted)
|
|
641
|
+
return finish("aborted");
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
//# sourceMappingURL=push-daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push-daemon.js","sourceRoot":"","sources":["../../../src/runtime/mirror/push-daemon.ts"],"names":[],"mappings":"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"}
|