@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,670 @@
|
|
|
1
|
+
import { closeSync, existsSync, openSync, readSync, readFileSync, readdirSync, } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { isH2AEnvelope } from "./envelope.js";
|
|
4
|
+
import { isSessionExpired } from "./session.js";
|
|
5
|
+
import { canonicalAddress, inboxDir, inboxDirRaw, localStorePaths, } from "./runtime/local-files/paths.js";
|
|
6
|
+
import { listPresenceWithDiagnostics } from "./runtime/local-files/presence.js";
|
|
7
|
+
import { H2A_TERMINAL_LOOP_STATUSES, listObjectiveLoopsWithDiagnostics, } from "./runtime/loop/index.js";
|
|
8
|
+
import { loopAttendance } from "./runtime/loop/supervisor.js";
|
|
9
|
+
export function cleanStatusText(value, maxScalars = 96) {
|
|
10
|
+
const normalized = String(value ?? "")
|
|
11
|
+
// Host and tmux text is untrusted. Strip every Unicode control/format
|
|
12
|
+
// scalar (including ANSI controls, zero-width controls, and bidi marks)
|
|
13
|
+
// before it becomes terminal text.
|
|
14
|
+
.replace(/[\p{Cc}\p{Cf}\p{Cs}\u2028\u2029]/gu, " ")
|
|
15
|
+
.replace(/[#\[\]]/g, "")
|
|
16
|
+
.replace(/\s+/g, " ")
|
|
17
|
+
.trim();
|
|
18
|
+
const scalars = Array.from(normalized);
|
|
19
|
+
return scalars.length > maxScalars
|
|
20
|
+
? `${scalars.slice(0, maxScalars).join("")}[cut]`
|
|
21
|
+
: normalized;
|
|
22
|
+
}
|
|
23
|
+
const clean = cleanStatusText;
|
|
24
|
+
function readJsonLines(path, label, validate, warnings, options = {}) {
|
|
25
|
+
if (!existsSync(path)) {
|
|
26
|
+
if (options.requireExists) {
|
|
27
|
+
warnings.push(`${label} is absent`);
|
|
28
|
+
return { values: [], degraded: true };
|
|
29
|
+
}
|
|
30
|
+
return { values: [], degraded: false };
|
|
31
|
+
}
|
|
32
|
+
let text;
|
|
33
|
+
try {
|
|
34
|
+
if (options.maxBytes !== undefined) {
|
|
35
|
+
// Do not preflight with stat then read the whole file: an append between
|
|
36
|
+
// those operations would make this supposedly bounded bar reader ingest
|
|
37
|
+
// unbounded history. Read only one byte past the budget instead.
|
|
38
|
+
const fd = openSync(path, "r");
|
|
39
|
+
try {
|
|
40
|
+
const bytes = Buffer.allocUnsafe(options.maxBytes + 1);
|
|
41
|
+
const count = readSync(fd, bytes, 0, bytes.length, 0);
|
|
42
|
+
if (count > options.maxBytes) {
|
|
43
|
+
warnings.push(`${label} exceeds its bounded read budget`);
|
|
44
|
+
return { values: [], degraded: true };
|
|
45
|
+
}
|
|
46
|
+
text = bytes.subarray(0, count).toString("utf8");
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
closeSync(fd);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
text = readFileSync(path, "utf8");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
warnings.push(`${label} could not be read`);
|
|
58
|
+
return { values: [], degraded: true };
|
|
59
|
+
}
|
|
60
|
+
const values = [];
|
|
61
|
+
let degraded = false;
|
|
62
|
+
for (const line of text.split("\n")) {
|
|
63
|
+
if (!line.trim())
|
|
64
|
+
continue;
|
|
65
|
+
try {
|
|
66
|
+
const value = JSON.parse(line);
|
|
67
|
+
if (!validate(value))
|
|
68
|
+
throw new Error("invalid shape");
|
|
69
|
+
values.push(value);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
degraded = true;
|
|
73
|
+
warnings.push(`${label} contains a malformed record`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { values, degraded };
|
|
77
|
+
}
|
|
78
|
+
function isStoredSubagent(value) {
|
|
79
|
+
if (!value || typeof value !== "object")
|
|
80
|
+
return false;
|
|
81
|
+
const row = value;
|
|
82
|
+
const expectedId = `${row.parentInstance ?? ""}~${row.name ?? ""}`;
|
|
83
|
+
return (typeof row.id === "string" &&
|
|
84
|
+
typeof row.parentInstance === "string" &&
|
|
85
|
+
row.parentInstance.length > 0 &&
|
|
86
|
+
typeof row.name === "string" &&
|
|
87
|
+
row.name.length > 0 &&
|
|
88
|
+
!row.name.includes("~") &&
|
|
89
|
+
row.id === expectedId &&
|
|
90
|
+
typeof row.createdAt === "string" &&
|
|
91
|
+
Number.isFinite(Date.parse(row.createdAt)));
|
|
92
|
+
}
|
|
93
|
+
function isStoredAudit(value) {
|
|
94
|
+
if (!value || typeof value !== "object")
|
|
95
|
+
return false;
|
|
96
|
+
const row = value;
|
|
97
|
+
const validType = row.type === "registered" || row.type === "routed" || row.type === "revoked";
|
|
98
|
+
return (typeof row.subagent === "string" &&
|
|
99
|
+
validType &&
|
|
100
|
+
typeof row.at === "string" &&
|
|
101
|
+
Number.isFinite(Date.parse(row.at)) &&
|
|
102
|
+
(row.envelopeId === undefined || typeof row.envelopeId === "string") &&
|
|
103
|
+
(row.mailbox === undefined || row.mailbox === "inbox" || row.mailbox === "outbox") &&
|
|
104
|
+
(row.type !== "routed" ||
|
|
105
|
+
(typeof row.envelopeId === "string" &&
|
|
106
|
+
(row.mailbox === "inbox" || row.mailbox === "outbox"))));
|
|
107
|
+
}
|
|
108
|
+
function isStoredMcpDelegationAttestation(value) {
|
|
109
|
+
if (!value || typeof value !== "object")
|
|
110
|
+
return false;
|
|
111
|
+
const row = value;
|
|
112
|
+
return row.version === 1 &&
|
|
113
|
+
row.origin === "mcp:h2a_run" &&
|
|
114
|
+
typeof row.workerTmuxSession === "string" &&
|
|
115
|
+
/^(?:h2a|remote)-[A-Za-z0-9_.#-]{1,120}$/.test(row.workerTmuxSession) &&
|
|
116
|
+
typeof row.workerPid === "number" && Number.isInteger(row.workerPid) && row.workerPid > 0 &&
|
|
117
|
+
typeof row.delegatorInstance === "string" &&
|
|
118
|
+
INSTANCE_TOKEN.test(row.delegatorInstance) &&
|
|
119
|
+
typeof row.delegatorTmuxSession === "string" &&
|
|
120
|
+
/^(?:h2a|remote)-[A-Za-z0-9_.#-]{1,120}$/.test(row.delegatorTmuxSession) &&
|
|
121
|
+
typeof row.recordedAt === "string" &&
|
|
122
|
+
Number.isFinite(Date.parse(row.recordedAt));
|
|
123
|
+
}
|
|
124
|
+
function readMcpDelegationAttestations(root, warnings) {
|
|
125
|
+
const paths = localStorePaths(root);
|
|
126
|
+
const records = readJsonLines(join(paths.registry, "mcp-delegations.jsonl"), "MCP delegation attestation", isStoredMcpDelegationAttestation, warnings,
|
|
127
|
+
// This append-only launch history is not a status index. Bound the legacy
|
|
128
|
+
// reader so a long-lived owner gets J? rather than an ever-growing five-
|
|
129
|
+
// second scan or a partial-looking count.
|
|
130
|
+
{ maxBytes: 32 * 1024 });
|
|
131
|
+
return { values: records.values, known: !records.degraded };
|
|
132
|
+
}
|
|
133
|
+
function readStoreProjection(root, ownerInstance) {
|
|
134
|
+
const warnings = [];
|
|
135
|
+
if (!existsSync(root)) {
|
|
136
|
+
return {
|
|
137
|
+
subagents: [],
|
|
138
|
+
inbox: [],
|
|
139
|
+
subagentsDegraded: true,
|
|
140
|
+
inboxDegraded: true,
|
|
141
|
+
warnings: ["h2a store is absent"],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const paths = localStorePaths(root);
|
|
145
|
+
const storedSubagents = readJsonLines(paths.subagents, "subagent registry", isStoredSubagent, warnings, { requireExists: true });
|
|
146
|
+
const audit = readJsonLines(paths.subagentAudit, "subagent audit", isStoredAudit, warnings, { requireExists: true });
|
|
147
|
+
const revoked = new Set(audit.values
|
|
148
|
+
.filter((event) => event.type === "revoked")
|
|
149
|
+
.map((event) => event.subagent));
|
|
150
|
+
const byId = new Map();
|
|
151
|
+
for (const item of storedSubagents.values) {
|
|
152
|
+
byId.set(item.id, {
|
|
153
|
+
id: item.id,
|
|
154
|
+
parentInstance: item.parentInstance,
|
|
155
|
+
name: item.name,
|
|
156
|
+
state: revoked.has(item.id) ? "revoked" : "addressable",
|
|
157
|
+
waiting: 0,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const subagents = [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
161
|
+
const inboxByRecipientAndId = new Map();
|
|
162
|
+
// An existing root alone is not an initialized h2a store. Without the inbox
|
|
163
|
+
// collection there is no authority to report a reassuring zero.
|
|
164
|
+
let inboxDegraded = !ownerInstance || !existsSync(paths.inbox);
|
|
165
|
+
if (!ownerInstance) {
|
|
166
|
+
warnings.push("exact tmux owner is unavailable");
|
|
167
|
+
}
|
|
168
|
+
if (!existsSync(paths.inbox)) {
|
|
169
|
+
warnings.push("h2a inbox collection is absent");
|
|
170
|
+
}
|
|
171
|
+
const scopedRecipients = ownerInstance
|
|
172
|
+
? [
|
|
173
|
+
ownerInstance,
|
|
174
|
+
...subagents
|
|
175
|
+
.filter((subagent) => canonicalAddress(subagent.parentInstance) ===
|
|
176
|
+
canonicalAddress(ownerInstance))
|
|
177
|
+
.map((subagent) => subagent.id),
|
|
178
|
+
]
|
|
179
|
+
: [];
|
|
180
|
+
const inboxDirectories = new Map();
|
|
181
|
+
for (const recipient of scopedRecipients) {
|
|
182
|
+
const canonical = canonicalAddress(recipient);
|
|
183
|
+
inboxDirectories.set(inboxDir(paths, recipient), canonical);
|
|
184
|
+
inboxDirectories.set(inboxDirRaw(paths, recipient), canonical);
|
|
185
|
+
}
|
|
186
|
+
for (const [directoryPath, recipient] of inboxDirectories) {
|
|
187
|
+
let files;
|
|
188
|
+
try {
|
|
189
|
+
files = readdirSync(directoryPath);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (error.code === "ENOENT")
|
|
193
|
+
continue;
|
|
194
|
+
warnings.push(`inbox ${clean(directoryPath)} could not be read`);
|
|
195
|
+
inboxDegraded = true;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
for (const file of files) {
|
|
199
|
+
if (!file.endsWith(".json"))
|
|
200
|
+
continue;
|
|
201
|
+
try {
|
|
202
|
+
const value = JSON.parse(readFileSync(join(directoryPath, file), "utf8"));
|
|
203
|
+
if (!isH2AEnvelope(value))
|
|
204
|
+
throw new Error("invalid envelope");
|
|
205
|
+
const envelope = value;
|
|
206
|
+
const waitingKey = `${recipient}\u0000${envelope.id}`;
|
|
207
|
+
if (!inboxByRecipientAndId.has(waitingKey)) {
|
|
208
|
+
inboxByRecipientAndId.set(waitingKey, {
|
|
209
|
+
id: clean(envelope.id),
|
|
210
|
+
recipient,
|
|
211
|
+
from: clean(envelope.actor.instance),
|
|
212
|
+
type: clean(envelope.type),
|
|
213
|
+
createdAt: clean(envelope.createdAt),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
warnings.push(`inbox ${clean(directoryPath)} contains a malformed envelope`);
|
|
219
|
+
inboxDegraded = true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const inbox = [...inboxByRecipientAndId.values()].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
224
|
+
const lastRouted = new Map();
|
|
225
|
+
for (const event of audit.values) {
|
|
226
|
+
if (event.type !== "routed")
|
|
227
|
+
continue;
|
|
228
|
+
const current = lastRouted.get(event.subagent);
|
|
229
|
+
if (!current || (event.at ?? "") >= (current.at ?? "")) {
|
|
230
|
+
lastRouted.set(event.subagent, event);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const enrichedSubagents = subagents.map((subagent) => {
|
|
234
|
+
const route = lastRouted.get(subagent.id);
|
|
235
|
+
return {
|
|
236
|
+
...subagent,
|
|
237
|
+
waiting: inbox.filter((envelope) => canonicalAddress(envelope.recipient) === canonicalAddress(subagent.id)).length,
|
|
238
|
+
...(route?.at ? { lastRoutedAt: route.at } : {}),
|
|
239
|
+
...(route?.envelopeId ? { lastRoutedEnvelopeId: route.envelopeId } : {}),
|
|
240
|
+
...(route?.mailbox ? { lastRoutedMailbox: route.mailbox } : {}),
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
return {
|
|
244
|
+
subagents: enrichedSubagents,
|
|
245
|
+
inbox,
|
|
246
|
+
subagentsDegraded: storedSubagents.degraded || audit.degraded,
|
|
247
|
+
inboxDegraded: inboxDegraded || storedSubagents.degraded || audit.degraded,
|
|
248
|
+
warnings,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const ATTENTION_LOOP_STATES = new Set([
|
|
252
|
+
"waiting-human",
|
|
253
|
+
"stalled",
|
|
254
|
+
"degraded",
|
|
255
|
+
"blocked",
|
|
256
|
+
"failed",
|
|
257
|
+
]);
|
|
258
|
+
const INSTANCE_TOKEN = /^[A-Za-z0-9][A-Za-z0-9._:~-]{0,255}$/;
|
|
259
|
+
async function defaultRuntimeProjection(input) {
|
|
260
|
+
const packageName = "@sentropic/h2a-runtime/status";
|
|
261
|
+
const runtime = (await import(packageName));
|
|
262
|
+
if (typeof runtime.projectStatusForH2a !== "function") {
|
|
263
|
+
throw new Error("runtime status projection is unavailable");
|
|
264
|
+
}
|
|
265
|
+
return runtime.projectStatusForH2a(input);
|
|
266
|
+
}
|
|
267
|
+
export async function readStatusSnapshot(input, dependencies = {}) {
|
|
268
|
+
const warnings = [];
|
|
269
|
+
const ownerInstance = input.ownerInstance && INSTANCE_TOKEN.test(input.ownerInstance)
|
|
270
|
+
? input.ownerInstance
|
|
271
|
+
: undefined;
|
|
272
|
+
if (input.ownerInstance && !ownerInstance) {
|
|
273
|
+
warnings.push("tmux owner instance is invalid");
|
|
274
|
+
}
|
|
275
|
+
// The gateway segment must stay independent of workload storage. It does
|
|
276
|
+
// not need provenance records, so avoid even opening that collection there.
|
|
277
|
+
const mcpDelegations = input.includeDelegations === false
|
|
278
|
+
? { values: [], known: true }
|
|
279
|
+
: readMcpDelegationAttestations(input.root, warnings);
|
|
280
|
+
let runtime;
|
|
281
|
+
try {
|
|
282
|
+
runtime = await (dependencies.projectRuntime ?? defaultRuntimeProjection)({
|
|
283
|
+
...(input.tmuxSession ? { tmuxSession: input.tmuxSession } : {}),
|
|
284
|
+
...(ownerInstance ? { ownerInstance } : {}),
|
|
285
|
+
...(input.includeGateway === false ? { includeGateway: false } : {}),
|
|
286
|
+
...(input.includeDelegations === false ? { includeDelegations: false } : {}),
|
|
287
|
+
...(input.includeManagedInventory === false
|
|
288
|
+
? { includeManagedInventory: false }
|
|
289
|
+
: {}),
|
|
290
|
+
delegationAttestations: mcpDelegations.values,
|
|
291
|
+
delegationAttestationsKnown: mcpDelegations.known,
|
|
292
|
+
});
|
|
293
|
+
warnings.push(...runtime.warnings);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
runtime = {
|
|
297
|
+
kind: "h2a-status-runtime",
|
|
298
|
+
version: 1,
|
|
299
|
+
session: {
|
|
300
|
+
state: "unknown",
|
|
301
|
+
...(input.tmuxSession ? { tmuxSession: input.tmuxSession } : {}),
|
|
302
|
+
},
|
|
303
|
+
managed: { agents: [], degraded: true, attentionComplete: false },
|
|
304
|
+
gateway: { state: "unknown", reason: "runtime projection unavailable" },
|
|
305
|
+
warnings: [],
|
|
306
|
+
};
|
|
307
|
+
warnings.push("optional h2a runtime projection is unavailable");
|
|
308
|
+
}
|
|
309
|
+
let presenceInstances = [];
|
|
310
|
+
let presenceDegraded = input.includePresence === false;
|
|
311
|
+
if (input.includePresence !== false) {
|
|
312
|
+
try {
|
|
313
|
+
const presence = listPresenceWithDiagnostics(input.root, {
|
|
314
|
+
includeExpired: true,
|
|
315
|
+
sweep: false,
|
|
316
|
+
});
|
|
317
|
+
presenceInstances = presence.sessions
|
|
318
|
+
.filter((session) => !isSessionExpired(session))
|
|
319
|
+
.map((session) => session.instance);
|
|
320
|
+
presenceDegraded = presence.warnings.length > 0;
|
|
321
|
+
warnings.push(...presence.warnings);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
presenceDegraded = true;
|
|
325
|
+
warnings.push("presence could not be read");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const store = input.includeInbox === false
|
|
329
|
+
? {
|
|
330
|
+
subagents: [],
|
|
331
|
+
inbox: [],
|
|
332
|
+
subagentsDegraded: true,
|
|
333
|
+
inboxDegraded: true,
|
|
334
|
+
warnings: [],
|
|
335
|
+
}
|
|
336
|
+
: readStoreProjection(input.root, ownerInstance);
|
|
337
|
+
warnings.push(...store.warnings);
|
|
338
|
+
let loops = [];
|
|
339
|
+
let loopsDegraded = false;
|
|
340
|
+
if (input.includeLoops === false) {
|
|
341
|
+
loopsDegraded = true;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
try {
|
|
345
|
+
if (!existsSync(join(input.root, "loops"))) {
|
|
346
|
+
loopsDegraded = true;
|
|
347
|
+
warnings.push("h2a loops collection is absent");
|
|
348
|
+
}
|
|
349
|
+
const result = listObjectiveLoopsWithDiagnostics(input.root);
|
|
350
|
+
loops = result.loops;
|
|
351
|
+
loopsDegraded = loopsDegraded || result.warnings.length > 0;
|
|
352
|
+
warnings.push(...result.warnings);
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
loopsDegraded = true;
|
|
356
|
+
warnings.push("objective loops could not be read");
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const delegatedExecutions = runtime.delegations?.executions ?? [];
|
|
360
|
+
const openLoops = loops.filter((loop) => !H2A_TERMINAL_LOOP_STATUSES.has(loop.status));
|
|
361
|
+
const loopAttention = new Set(loops
|
|
362
|
+
.filter((loop) => ATTENTION_LOOP_STATES.has(loop.status))
|
|
363
|
+
.map((loop) => loop.id));
|
|
364
|
+
for (const loop of openLoops) {
|
|
365
|
+
try {
|
|
366
|
+
if (loopAttendance(input.root, loop) === "unattended") {
|
|
367
|
+
loopAttention.add(loop.id);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
loopsDegraded = true;
|
|
372
|
+
warnings.push(`loop ${clean(loop.id)} attendance could not be read`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
kind: "h2a-status",
|
|
377
|
+
version: 1,
|
|
378
|
+
...(input.tmuxSession || runtime.session.tmuxSession
|
|
379
|
+
? { tmuxSession: input.tmuxSession ?? runtime.session.tmuxSession }
|
|
380
|
+
: {}),
|
|
381
|
+
session: runtime.session,
|
|
382
|
+
managed: {
|
|
383
|
+
active: runtime.managed.agents.length,
|
|
384
|
+
attention: 0,
|
|
385
|
+
attentionComplete: runtime.managed.attentionComplete === true,
|
|
386
|
+
degraded: runtime.managed.degraded,
|
|
387
|
+
agents: runtime.managed.agents,
|
|
388
|
+
},
|
|
389
|
+
delegations: {
|
|
390
|
+
open: delegatedExecutions.filter((execution) => execution.state !== "failed").length,
|
|
391
|
+
attention: delegatedExecutions.filter((execution) => execution.state === "pending" ||
|
|
392
|
+
execution.state === "throttled" ||
|
|
393
|
+
execution.state === "failed").length,
|
|
394
|
+
// A runtime built before delegated-execution provenance is deliberately
|
|
395
|
+
// UNKNOWN: it has no authority to report a reassuring zero.
|
|
396
|
+
degraded: runtime.delegations?.degraded !== false,
|
|
397
|
+
items: delegatedExecutions,
|
|
398
|
+
},
|
|
399
|
+
subagents: {
|
|
400
|
+
addressable: store.subagents.filter((subagent) => subagent.state === "addressable").length,
|
|
401
|
+
degraded: store.subagentsDegraded,
|
|
402
|
+
items: store.subagents,
|
|
403
|
+
},
|
|
404
|
+
inbox: {
|
|
405
|
+
waiting: store.inbox.length,
|
|
406
|
+
degraded: store.inboxDegraded,
|
|
407
|
+
envelopes: store.inbox,
|
|
408
|
+
},
|
|
409
|
+
loops: {
|
|
410
|
+
active: openLoops.length,
|
|
411
|
+
attention: loopAttention.size,
|
|
412
|
+
degraded: loopsDegraded,
|
|
413
|
+
items: loops,
|
|
414
|
+
},
|
|
415
|
+
presence: {
|
|
416
|
+
reachable: presenceInstances.length,
|
|
417
|
+
degraded: presenceDegraded,
|
|
418
|
+
instances: presenceInstances.sort(),
|
|
419
|
+
},
|
|
420
|
+
gateway: runtime.gateway,
|
|
421
|
+
warnings: [...new Set(warnings)],
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function countSegment(prefix, count, attention, degraded) {
|
|
425
|
+
if (degraded)
|
|
426
|
+
return `${prefix}?`;
|
|
427
|
+
if (attention === undefined)
|
|
428
|
+
return `${prefix}${count}`;
|
|
429
|
+
return attention > 0 ? `${prefix}${count}!${attention}` : `${prefix}${count}`;
|
|
430
|
+
}
|
|
431
|
+
export function renderWorkloadBar(snapshot) {
|
|
432
|
+
if (snapshot.session.state === "absent")
|
|
433
|
+
return "h2a absent";
|
|
434
|
+
if (snapshot.session.state === "unknown")
|
|
435
|
+
return "h2a ?";
|
|
436
|
+
return [
|
|
437
|
+
countSegment("J", snapshot.delegations.open, snapshot.delegations.attention, snapshot.delegations.degraded),
|
|
438
|
+
countSegment("I", snapshot.inbox.waiting, undefined, snapshot.inbox.degraded),
|
|
439
|
+
countSegment("L", snapshot.loops.active, snapshot.loops.attention, snapshot.loops.degraded),
|
|
440
|
+
].join(" ");
|
|
441
|
+
}
|
|
442
|
+
function displayColumns(value) {
|
|
443
|
+
// The bar's width tier is terminal-cell based, not JS UTF-16 length. Model
|
|
444
|
+
// ids are normally ASCII, but host-controlled text must not make us claim a
|
|
445
|
+
// route fits when full-width or combining scalars say otherwise.
|
|
446
|
+
let columns = 0;
|
|
447
|
+
for (const scalar of value) {
|
|
448
|
+
if (/\p{Mark}/u.test(scalar))
|
|
449
|
+
continue;
|
|
450
|
+
const code = scalar.codePointAt(0);
|
|
451
|
+
const wide = code >= 0x1100 &&
|
|
452
|
+
(code <= 0x115f ||
|
|
453
|
+
code === 0x2329 ||
|
|
454
|
+
code === 0x232a ||
|
|
455
|
+
(code >= 0x2e80 && code <= 0xa4cf && code !== 0x303f) ||
|
|
456
|
+
(code >= 0xac00 && code <= 0xd7a3) ||
|
|
457
|
+
(code >= 0xf900 && code <= 0xfaff) ||
|
|
458
|
+
(code >= 0xfe10 && code <= 0xfe19) ||
|
|
459
|
+
(code >= 0xfe30 && code <= 0xfe6f) ||
|
|
460
|
+
(code >= 0xff00 && code <= 0xff60) ||
|
|
461
|
+
(code >= 0xffe0 && code <= 0xffe6) ||
|
|
462
|
+
(code >= 0x1f300 && code <= 0x1faff) ||
|
|
463
|
+
(code >= 0x20000 && code <= 0x3fffd));
|
|
464
|
+
columns += wide ? 2 : 1;
|
|
465
|
+
}
|
|
466
|
+
return columns;
|
|
467
|
+
}
|
|
468
|
+
function wholeRouteId(value) {
|
|
469
|
+
// Model ids are identifiers, not a prose preview: a cut identifier could
|
|
470
|
+
// name a different route. Cap host text but omit this optional detail when
|
|
471
|
+
// that cap was reached, leaving the truthful gateway state visible.
|
|
472
|
+
const rendered = clean(value, 96);
|
|
473
|
+
return rendered.endsWith("[cut]") ? undefined : rendered;
|
|
474
|
+
}
|
|
475
|
+
export function renderGatewayBar(snapshot, maxColumns) {
|
|
476
|
+
if (snapshot.session.state === "absent")
|
|
477
|
+
return "gw n/a";
|
|
478
|
+
if (snapshot.session.state === "unknown")
|
|
479
|
+
return "gw ?";
|
|
480
|
+
const gateway = snapshot.gateway;
|
|
481
|
+
if (gateway.state === "off")
|
|
482
|
+
return "gw off";
|
|
483
|
+
if (gateway.state === "unavailable")
|
|
484
|
+
return "gw unavailable";
|
|
485
|
+
if (gateway.state === "unknown")
|
|
486
|
+
return "gw ?";
|
|
487
|
+
const state = gateway.state === "rate-limited" ? "429" : gateway.state;
|
|
488
|
+
const parts = [`gw ${state}`];
|
|
489
|
+
if (gateway.requestedModelTruncated || gateway.upstreamModelTruncated) {
|
|
490
|
+
// We deliberately do not show a prefix of an identifier as if it named a
|
|
491
|
+
// complete route. Make the omission explicit instead.
|
|
492
|
+
const cut = "route [cut]";
|
|
493
|
+
const candidate = `${parts[0]} · ${cut}`;
|
|
494
|
+
if (maxColumns === undefined || displayColumns(candidate) <= maxColumns) {
|
|
495
|
+
parts.push(cut);
|
|
496
|
+
}
|
|
497
|
+
return parts.join(" · ");
|
|
498
|
+
}
|
|
499
|
+
if (gateway.requestedModel &&
|
|
500
|
+
gateway.upstreamModel &&
|
|
501
|
+
!gateway.requestedModelTruncated &&
|
|
502
|
+
!gateway.upstreamModelTruncated) {
|
|
503
|
+
const requested = wholeRouteId(gateway.requestedModel);
|
|
504
|
+
const upstream = wholeRouteId(gateway.upstreamModel);
|
|
505
|
+
if (requested && upstream) {
|
|
506
|
+
const route = `${requested}→${upstream}`;
|
|
507
|
+
const candidate = `${parts[0]} · ${route}`;
|
|
508
|
+
if (maxColumns === undefined || displayColumns(candidate) <= maxColumns) {
|
|
509
|
+
parts.push(route);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
const cut = "route [cut]";
|
|
514
|
+
const candidate = `${parts[0]} · ${cut}`;
|
|
515
|
+
if (maxColumns === undefined || displayColumns(candidate) <= maxColumns) {
|
|
516
|
+
parts.push(cut);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return parts.join(" · ");
|
|
521
|
+
}
|
|
522
|
+
export function renderStatusBar(snapshot, segment = "all", maxColumns) {
|
|
523
|
+
if (segment === "workload")
|
|
524
|
+
return renderWorkloadBar(snapshot);
|
|
525
|
+
if (segment === "gateway")
|
|
526
|
+
return renderGatewayBar(snapshot, maxColumns);
|
|
527
|
+
return `${renderWorkloadBar(snapshot)} ${renderGatewayBar(snapshot, maxColumns)}`;
|
|
528
|
+
}
|
|
529
|
+
function rowsOrNone(rows) {
|
|
530
|
+
return rows.length > 0 ? [...rows] : [" (none)"];
|
|
531
|
+
}
|
|
532
|
+
export function renderHumanStatus(snapshot) {
|
|
533
|
+
const lines = [
|
|
534
|
+
`H2A STATUS${snapshot.tmuxSession ? ` — ${clean(snapshot.tmuxSession)}` : ""}`,
|
|
535
|
+
`SESSION ${snapshot.session.state}`,
|
|
536
|
+
"",
|
|
537
|
+
"RUNTIME INVENTORY (not used as liveness or owner-scoped work evidence)",
|
|
538
|
+
...rowsOrNone(snapshot.managed.agents.map((agent) => ` ${clean(agent.id)} ${clean(agent.kind)} ${clean(agent.tool)} ${clean(agent.state)}`)),
|
|
539
|
+
"",
|
|
540
|
+
"DELEGATED EXECUTIONS (owner-scoped, verified)",
|
|
541
|
+
...rowsOrNone(snapshot.delegations.items.map((execution) => ` ${clean(execution.id)} ${execution.origin} ${clean(execution.tool)} ${execution.state}`)),
|
|
542
|
+
"",
|
|
543
|
+
"H2A DELEGATION BINDINGS (inventory only)",
|
|
544
|
+
...rowsOrNone(snapshot.subagents.items.map((subagent) => {
|
|
545
|
+
const waiting = subagent.waiting > 0 ? ` ${subagent.waiting} waiting` : "";
|
|
546
|
+
const routed = subagent.lastRoutedAt
|
|
547
|
+
? ` last routed${subagent.lastRoutedEnvelopeId ? ` ${clean(subagent.lastRoutedEnvelopeId)}` : ""}${subagent.lastRoutedMailbox ? ` to ${subagent.lastRoutedMailbox}` : ""} at ${clean(subagent.lastRoutedAt)}`
|
|
548
|
+
: "";
|
|
549
|
+
return ` ${clean(subagent.id)} ${subagent.state} parent ${clean(subagent.parentInstance)}${waiting}${routed}`;
|
|
550
|
+
})),
|
|
551
|
+
"",
|
|
552
|
+
"INBOX",
|
|
553
|
+
...rowsOrNone(snapshot.inbox.envelopes.map((envelope) => ` ${clean(envelope.recipient)} from ${clean(envelope.from)} ${clean(envelope.type)} ${clean(envelope.createdAt)}`)),
|
|
554
|
+
"",
|
|
555
|
+
"OBJECTIVE LOOPS",
|
|
556
|
+
...rowsOrNone(snapshot.loops.items.map((loop) => ` ${clean(loop.id)} ${clean(loop.status)} ${loop.agents.length} agent(s) ${clean(loop.name)}`)),
|
|
557
|
+
"",
|
|
558
|
+
"PRESENCE (not liveness evidence)",
|
|
559
|
+
...rowsOrNone(snapshot.presence.instances.map((instance) => ` ${clean(instance)}`)),
|
|
560
|
+
"",
|
|
561
|
+
"GATEWAY",
|
|
562
|
+
` ${renderGatewayBar(snapshot)}`,
|
|
563
|
+
];
|
|
564
|
+
if (snapshot.gateway.provider) {
|
|
565
|
+
lines.push(` provider ${clean(snapshot.gateway.provider)}${snapshot.gateway.transport ? ` transport ${clean(snapshot.gateway.transport)}` : ""}`);
|
|
566
|
+
}
|
|
567
|
+
if (snapshot.gateway.accountId) {
|
|
568
|
+
lines.push(` account id ${clean(snapshot.gateway.accountId)}`);
|
|
569
|
+
}
|
|
570
|
+
if (snapshot.gateway.reason)
|
|
571
|
+
lines.push(` ${clean(snapshot.gateway.reason)}`);
|
|
572
|
+
if (snapshot.warnings.length > 0) {
|
|
573
|
+
lines.push("", "WARNINGS", ...snapshot.warnings.map((warning) => ` ${clean(warning)}`));
|
|
574
|
+
}
|
|
575
|
+
return `${lines.join("\n")}\n`;
|
|
576
|
+
}
|
|
577
|
+
export function statusWatchIntervalMs(raw) {
|
|
578
|
+
if (!raw)
|
|
579
|
+
return 5000;
|
|
580
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s)?$/.exec(raw.trim());
|
|
581
|
+
if (!match)
|
|
582
|
+
throw new Error("--interval must be a duration such as 2s or 500ms");
|
|
583
|
+
const value = Number(match[1]);
|
|
584
|
+
const ms = match[2] === "ms" ? value : value * 1000;
|
|
585
|
+
if (!Number.isFinite(ms) || ms < 250)
|
|
586
|
+
throw new Error("--interval must be at least 250ms");
|
|
587
|
+
return Math.round(ms);
|
|
588
|
+
}
|
|
589
|
+
function delay(ms, signal) {
|
|
590
|
+
return new Promise((resolve) => {
|
|
591
|
+
let settled = false;
|
|
592
|
+
const finish = () => {
|
|
593
|
+
if (settled)
|
|
594
|
+
return;
|
|
595
|
+
settled = true;
|
|
596
|
+
clearTimeout(timer);
|
|
597
|
+
signal?.removeEventListener("abort", onAbort);
|
|
598
|
+
resolve();
|
|
599
|
+
};
|
|
600
|
+
const onAbort = () => finish();
|
|
601
|
+
const timer = setTimeout(finish, ms);
|
|
602
|
+
if (signal?.aborted)
|
|
603
|
+
finish();
|
|
604
|
+
else
|
|
605
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
export async function runStatusSurfaceCli(flags, streams, dependencies) {
|
|
609
|
+
const tmuxSession = flags["tmux-session"];
|
|
610
|
+
if (flags["tmux-window"] === "true" || flags["tmux-window"]) {
|
|
611
|
+
const target = flags["tmux-window"] === "true"
|
|
612
|
+
? tmuxSession
|
|
613
|
+
: flags["tmux-window"];
|
|
614
|
+
if (!target || !dependencies.openTmuxWindow) {
|
|
615
|
+
streams.stderr.write("h2a status --tmux-window requires an exact managed session\n");
|
|
616
|
+
return 1;
|
|
617
|
+
}
|
|
618
|
+
return (await dependencies.openTmuxWindow(target)) ? 0 : 1;
|
|
619
|
+
}
|
|
620
|
+
const renderOnce = async () => {
|
|
621
|
+
const segment = flags.segment === "workload" || flags.segment === "gateway"
|
|
622
|
+
? flags.segment
|
|
623
|
+
: "all";
|
|
624
|
+
const snapshot = await readStatusSnapshot({
|
|
625
|
+
root: dependencies.root,
|
|
626
|
+
...(tmuxSession ? { tmuxSession } : {}),
|
|
627
|
+
...(flags["owner-instance"] ? { ownerInstance: flags["owner-instance"] } : {}),
|
|
628
|
+
...(flags.bar === "true" && segment === "workload"
|
|
629
|
+
? { includeGateway: false, includeManagedInventory: false }
|
|
630
|
+
: {}),
|
|
631
|
+
...(flags.bar === "true" ? { includePresence: false } : {}),
|
|
632
|
+
...(flags.bar === "true" && segment === "gateway"
|
|
633
|
+
? {
|
|
634
|
+
includeDelegations: false,
|
|
635
|
+
includeManagedInventory: false,
|
|
636
|
+
includeInbox: false,
|
|
637
|
+
includeLoops: false,
|
|
638
|
+
}
|
|
639
|
+
: {}),
|
|
640
|
+
}, dependencies);
|
|
641
|
+
if (flags.bar === "true") {
|
|
642
|
+
const width = flags.width && /^\d+$/.test(flags.width)
|
|
643
|
+
? Number(flags.width)
|
|
644
|
+
: undefined;
|
|
645
|
+
// Reserve room for the static left marker and the owner's prior right
|
|
646
|
+
// segment. Route is omitted rather than silently cut when it cannot fit.
|
|
647
|
+
const gatewayWidth = width === undefined ? undefined : Math.max(0, width - 32);
|
|
648
|
+
return `${renderStatusBar(snapshot, segment, gatewayWidth)}\n`;
|
|
649
|
+
}
|
|
650
|
+
return renderHumanStatus(snapshot);
|
|
651
|
+
};
|
|
652
|
+
if (flags.watch !== "true") {
|
|
653
|
+
streams.stdout.write(await renderOnce());
|
|
654
|
+
return 0;
|
|
655
|
+
}
|
|
656
|
+
let wait;
|
|
657
|
+
try {
|
|
658
|
+
wait = statusWatchIntervalMs(flags.interval);
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
streams.stderr.write(`h2a status: ${error.message}\n`);
|
|
662
|
+
return 1;
|
|
663
|
+
}
|
|
664
|
+
do {
|
|
665
|
+
streams.stdout.write(`\u001b[2J\u001b[H${await renderOnce()}`);
|
|
666
|
+
await delay(wait, dependencies.signal);
|
|
667
|
+
} while (!dependencies.signal?.aborted);
|
|
668
|
+
return 0;
|
|
669
|
+
}
|
|
670
|
+
//# sourceMappingURL=status-surface.js.map
|