@maudecode/talaria-web 1.19.0 → 1.20.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/_release.json +8 -8
- package/dist/api/automation-raw.js +61 -6
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +8 -6
- package/dist/api/automation-router.js +7 -1
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +258 -33
- package/dist/api/chat-router.js +60 -25
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +4 -0
- package/dist/api/git-router.js +1 -1
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.js +13 -1
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +2 -2
- package/dist/api/session-visibility.js +2 -2
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +787 -107
- package/dist/api/sessions-router.js +16 -4
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +34 -13
- package/dist/api/settings-router.js +54 -17
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.js +41 -19
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-router.d.ts +314 -32
- package/dist/api/tools-router.js +135 -38
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.js +15 -11
- package/dist/app.js.map +1 -1
- package/dist/auth/crypto.d.ts +3 -0
- package/dist/auth/crypto.js +18 -0
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/gate.js +5 -1
- package/dist/auth/gate.js.map +1 -1
- package/dist/cli/ctl.js +6 -1
- package/dist/cli/ctl.js.map +1 -1
- package/dist/cli/main.js +23 -18
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/supervise.d.ts +22 -0
- package/dist/cli/supervise.js +80 -2
- package/dist/cli/supervise.js.map +1 -1
- package/dist/config/agent-config.d.ts +3 -0
- package/dist/config/agent-config.js +36 -9
- package/dist/config/agent-config.js.map +1 -1
- package/dist/fs/atomic.d.ts +3 -0
- package/dist/fs/atomic.js +19 -5
- package/dist/fs/atomic.js.map +1 -1
- package/dist/fs/stat.d.ts +6 -0
- package/dist/fs/stat.js +18 -2
- package/dist/fs/stat.js.map +1 -1
- package/dist/http/context.d.ts +14 -0
- package/dist/http/context.js +48 -5
- package/dist/http/context.js.map +1 -1
- package/dist/profiles/profiles.d.ts +2 -0
- package/dist/profiles/profiles.js +1 -0
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/providers/catalog.d.ts +11 -6
- package/dist/providers/catalog.js +76 -24
- package/dist/providers/catalog.js.map +1 -1
- package/dist/redact.js +38 -14
- package/dist/redact.js.map +1 -1
- package/dist/release.js +5 -3
- package/dist/release.js.map +1 -1
- package/dist/runtime.js +85 -21
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +24 -21
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +2 -1
- package/dist/sessions/anchor.js +5 -1
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +23 -3
- package/dist/sessions/background-tasks.js +74 -4
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/cli-sessions.d.ts +9 -2
- package/dist/sessions/cli-sessions.js +38 -57
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +8 -0
- package/dist/sessions/completions.js +55 -25
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/export.d.ts +2 -0
- package/dist/sessions/export.js +6 -2
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +44 -4
- package/dist/sessions/gateway-sessions.js +626 -90
- package/dist/sessions/gateway-sessions.js.map +1 -1
- package/dist/sessions/gateway-watcher.d.ts +10 -11
- package/dist/sessions/gateway-watcher.js +25 -21
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/list.d.ts +9 -2
- package/dist/sessions/list.js +38 -26
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +11 -5
- package/dist/sessions/merge.js +59 -17
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +7 -4
- package/dist/sessions/prefix-index.js +21 -10
- package/dist/sessions/prefix-index.js.map +1 -1
- package/dist/sessions/recovery.d.ts +1 -1
- package/dist/sessions/recovery.js +4 -3
- package/dist/sessions/recovery.js.map +1 -1
- package/dist/sessions/service.d.ts +107 -37
- package/dist/sessions/service.js +490 -156
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +2 -0
- package/dist/sessions/session.js +4 -0
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/state-db-worker.js +22 -5
- package/dist/sessions/state-db-worker.js.map +1 -1
- package/dist/sessions/state-db.d.ts +106 -15
- package/dist/sessions/state-db.js +651 -236
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/state-saved.d.ts +1 -1
- package/dist/sessions/state-saved.js +35 -11
- package/dist/sessions/state-saved.js.map +1 -1
- package/dist/sessions/storage/backend.d.ts +10 -1
- package/dist/sessions/storage/backend.js.map +1 -1
- package/dist/sessions/storage/conformance.js +1 -1
- package/dist/sessions/storage/conformance.js.map +1 -1
- package/dist/sessions/storage/json-documents.d.ts +2 -0
- package/dist/sessions/storage/json-documents.js +70 -26
- package/dist/sessions/storage/json-documents.js.map +1 -1
- package/dist/sessions/storage/json-files.d.ts +13 -2
- package/dist/sessions/storage/json-files.js +126 -6
- package/dist/sessions/storage/json-files.js.map +1 -1
- package/dist/sessions/storage/json-journal.d.ts +6 -7
- package/dist/sessions/storage/json-journal.js +143 -73
- package/dist/sessions/storage/json-journal.js.map +1 -1
- package/dist/sessions/storage/json.d.ts +15 -1
- package/dist/sessions/storage/json.js +125 -33
- package/dist/sessions/storage/json.js.map +1 -1
- package/dist/sessions/store.d.ts +5 -1
- package/dist/sessions/store.js +67 -27
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +8 -7
- package/dist/sessions/streams.js +49 -14
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +3 -1
- package/dist/sessions/tool-display.js +6 -0
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.js +6 -2
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +23 -5
- package/dist/sessions/turn.js +168 -78
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sidecar/client.d.ts +24 -1
- package/dist/sidecar/client.js +118 -38
- package/dist/sidecar/client.js.map +1 -1
- package/dist/sidecar/fake.d.ts +6 -2
- package/dist/sidecar/fake.js +15 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/spa.d.ts +9 -4
- package/dist/spa.js +36 -12
- package/dist/spa.js.map +1 -1
- package/dist/startup-timing.d.ts +66 -0
- package/dist/startup-timing.js +129 -0
- package/dist/startup-timing.js.map +1 -0
- package/dist/test/fs-handles.d.ts +11 -0
- package/dist/test/fs-handles.js +31 -0
- package/dist/test/fs-handles.js.map +1 -0
- package/dist/tools/connectors.d.ts +1 -1
- package/dist/tools/connectors.js +2 -2
- package/dist/tools/connectors.js.map +1 -1
- package/dist/tools/crons.d.ts +8 -4
- package/dist/tools/crons.js +25 -18
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +29 -0
- package/dist/tools/dashboard-plugins.js +132 -0
- package/dist/tools/dashboard-plugins.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +25 -5
- package/dist/tools/gateway-restart.js +103 -23
- package/dist/tools/gateway-restart.js.map +1 -1
- package/dist/tools/health.d.ts +13 -1
- package/dist/tools/health.js +80 -22
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/insights.d.ts +1 -1
- package/dist/tools/insights.js +2 -2
- package/dist/tools/insights.js.map +1 -1
- package/dist/tools/mcp-health.js +74 -24
- package/dist/tools/mcp-health.js.map +1 -1
- package/dist/tools/mcp.js +19 -1
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/plugin-oauth.d.ts +14 -0
- package/dist/tools/plugin-oauth.js +53 -0
- package/dist/tools/plugin-oauth.js.map +1 -0
- package/dist/tools/prune-advice.d.ts +50 -0
- package/dist/tools/prune-advice.js +114 -0
- package/dist/tools/prune-advice.js.map +1 -0
- package/dist/tools/skills.d.ts +5 -2
- package/dist/tools/skills.js +9 -6
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +73 -7
- package/dist/tools/update-notifications.js +277 -43
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/updates.d.ts +8 -1
- package/dist/tools/updates.js +51 -17
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/media.js +69 -20
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/preview.js +4 -14
- package/dist/workspace/preview.js.map +1 -1
- package/dist/workspace/rollback.d.ts +6 -2
- package/dist/workspace/rollback.js +17 -7
- package/dist/workspace/rollback.js.map +1 -1
- package/package.json +3 -3
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/agent_support.json +17 -14
- package/sidecar/scripts/suite_runner.py +183 -27
- package/sidecar/scripts/test.sh +5 -7
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +10 -3
- package/sidecar/talaria_sidecar/agent_mutation.py +159 -23
- package/sidecar/talaria_sidecar/agent_services.py +74 -11
- package/sidecar/talaria_sidecar/context_detail.py +59 -0
- package/sidecar/talaria_sidecar/home.py +97 -20
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +80 -18
- package/sidecar/talaria_sidecar/methods/chat.py +571 -106
- package/sidecar/talaria_sidecar/methods/checkpoints.py +29 -4
- package/sidecar/talaria_sidecar/methods/commands.py +277 -16
- package/sidecar/talaria_sidecar/methods/config.py +73 -3
- package/sidecar/talaria_sidecar/methods/connectors.py +45 -13
- package/sidecar/talaria_sidecar/methods/cron.py +8 -2
- package/sidecar/talaria_sidecar/methods/dashboard_plugins.py +301 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +24 -4
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +211 -27
- package/sidecar/talaria_sidecar/methods/kanban.py +2 -3
- package/sidecar/talaria_sidecar/methods/oauth.py +139 -11
- package/sidecar/talaria_sidecar/methods/plugin_catalog.py +198 -0
- package/sidecar/talaria_sidecar/methods/plugin_oauth.py +234 -0
- package/sidecar/talaria_sidecar/methods/process.py +70 -6
- package/sidecar/talaria_sidecar/methods/profiles.py +4 -3
- package/sidecar/talaria_sidecar/methods/runtime.py +2 -0
- package/sidecar/talaria_sidecar/methods/skills.py +22 -7
- package/sidecar/talaria_sidecar/methods/state_db.py +128 -42
- package/sidecar/talaria_sidecar/methods/toolsets.py +4 -2
- package/sidecar/talaria_sidecar/methods/worktree.py +121 -2
- package/sidecar/talaria_sidecar/rpc.py +25 -3
- package/sidecar/talaria_sidecar/runtime.py +42 -3
- package/sidecar/talaria_sidecar/speed.py +13 -1
- package/sidecar/talaria_sidecar/startup_timing.py +119 -0
- package/static/dist/FILES.txt +241 -213
- package/static/dist/THIRD_PARTY_LICENSES.md +6 -22
- package/static/dist/assets/AppShell-3isgvoro.js +8 -0
- package/static/dist/assets/Button-f4n6dapf.js +1 -0
- package/static/dist/assets/ChatPage-k7b6xfax.js +4 -0
- package/static/dist/assets/ConnectTargets-juqvt5lm.js +1 -0
- package/static/dist/assets/Dialog-hta5utr3.js +1 -0
- package/static/dist/assets/ExtensionRoute-zrhjn0wm.js +1 -0
- package/static/dist/assets/Field-b6ez48oz.js +1 -0
- package/static/dist/assets/HubRoute-iwvso2tz.js +2 -0
- package/static/dist/assets/LinkCheckContext-ix6zqqkk.js +1 -0
- package/static/dist/assets/Markdown-jdeth7zq.js +2 -0
- package/static/dist/assets/MarkdownRenderer-fbswsgld.js +302 -0
- package/static/dist/assets/MarkdownRenderer-i9o6nr38.css +1 -0
- package/static/dist/assets/OAuthSignIn-bpd8hom3.js +1 -0
- package/static/dist/assets/ResourceSwitch-odi6dy2o.js +1 -0
- package/static/dist/assets/RightPanel-eu6enlo6.js +1 -0
- package/static/dist/assets/Select-kr07928w.js +1 -0
- package/static/dist/assets/SessionListPanel-etb2i54l.js +1 -0
- package/static/dist/assets/SettingsLayout-eu3xxp23.js +1 -0
- package/static/dist/assets/States-icab19yg.js +1 -0
- package/static/dist/assets/TerminalPanel-hngmsr8b.js +16 -0
- package/static/dist/assets/Toaster-nb2uzjw1.js +1 -0
- package/static/dist/assets/_app-ga1moszl.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-na62087t.js +1 -0
- package/static/dist/assets/_app.index-jypgdqoi.js +1 -0
- package/static/dist/assets/_app.insights-kabejdtm.js +1 -0
- package/static/dist/assets/_app.kanban-m19kfcmx.js +1 -0
- package/static/dist/assets/_app.logs-iw4m96sz.js +1 -0
- package/static/dist/assets/_app.memory-jq5frwcg.js +1 -0
- package/static/dist/assets/_app.profiles-kwa3m7rp.js +1 -0
- package/static/dist/assets/_app.session._sessionId-o5lyeipj.js +1 -0
- package/static/dist/assets/_app.settings-ckl8hdll.js +1 -0
- package/static/dist/assets/_app.settings._section-dtdjk98a.js +3 -0
- package/static/dist/assets/_app.skills-n016rihd.js +1 -0
- package/static/dist/assets/_app.tasks-n8zuqsqe.js +1 -0
- package/static/dist/assets/_app.todos-btew5v2s.js +1 -0
- package/static/dist/assets/_app.workspaces-lnfk95ch.js +1 -0
- package/static/dist/assets/abnfDiagram-VCTEODGH-dttheegb.js +1 -0
- package/static/dist/assets/{angular-html-nu6l31w3.js → angular-html-l28bd5fo.js} +1 -1
- package/static/dist/assets/{angular-ts-fbx4f8mm.js → angular-ts-ffzx1vj0.js} +1 -1
- package/static/dist/assets/{apl-bx2xr7dh.js → apl-b7h7mmy4.js} +1 -1
- package/static/dist/assets/{arc-7popfhbk.js → arc-fk1b21lm.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-ic435919.js +1 -0
- package/static/dist/assets/architectureDiagram-5GKGNRK7-8r3glgiq.js +36 -0
- package/static/dist/assets/archive-il7c6053.js +1 -0
- package/static/dist/assets/{astro-g77i97cb.js → astro-k117fy0t.js} +1 -1
- package/static/dist/assets/back-gu3nu279.js +1 -0
- package/static/dist/assets/{blade-boo0u92y.js → blade-npefsmn8.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-joedghi3.js → blockDiagram-I7D4REHJ-jenyos6c.js} +4 -4
- package/static/dist/assets/{c-cat0w3sc.js → c-2umg6kbn.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-hyrjrohe.js → c4Diagram-7LVT6UL2-nzlx7yc4.js} +1 -1
- package/static/dist/assets/cancel-bsnfo36u.js +1 -0
- package/static/dist/assets/channel-dsbtk01y.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-koouqbut.js → chunk-4HAMMTFA-g0cru63b.js} +20 -20
- package/static/dist/assets/{chunk-75Z2AOVW-bl4bhdnt.js → chunk-75Z2AOVW-7rkswkjw.js} +1 -1
- package/static/dist/assets/chunk-DU6HZSFF-fn73jzdo.js +128 -0
- package/static/dist/assets/{chunk-F27PBJKO-d8xxi0zi.js → chunk-F27PBJKO-oey8e72m.js} +1 -1
- package/static/dist/assets/{chunk-FOHPRMQF-opuflp73.js → chunk-FOHPRMQF-ipewusgj.js} +8 -8
- package/static/dist/assets/{chunk-GMAD6QVW-jro0hl73.js → chunk-GMAD6QVW-l2a32wiy.js} +6 -6
- package/static/dist/assets/{chunk-GVQU2GXP-djn6gbyu.js → chunk-GVQU2GXP-o9dwzh8h.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-vw4p5p7o.js → chunk-IMKFNOWR-eblwj20b.js} +5 -5
- package/static/dist/assets/{chunk-L3NEJ4N5-n1hj77q8.js → chunk-L3NEJ4N5-o2mufspb.js} +1 -1
- package/static/dist/assets/chunk-OSK3NFVY-ijp9pw29.js +10 -0
- package/static/dist/assets/{chunk-P2QGCYS3-onf1hz6c.js → chunk-P2QGCYS3-hs9hqwl4.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-m8sqn7cs.js → chunk-POPQ4Y6H-bp9rsqez.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-ek4smc8x.js → chunk-PWAF6VOD-brkprov6.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-g9gfvefo.js → chunk-SHT3W25Y-gmpv0pxz.js} +13 -13
- package/static/dist/assets/{chunk-SVP7TREG-f9nfv2cu.js → chunk-SVP7TREG-oldm08fu.js} +4 -4
- package/static/dist/assets/{chunk-TICWLB2K-bnk3m1mq.js → chunk-TICWLB2K-ooqilfv7.js} +6 -6
- package/static/dist/assets/{chunk-XXDRQBXY-n40pf9vy.js → chunk-XXDRQBXY-jkmnqu65.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-fvgcv24g.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-fvgcv24g.js +1 -0
- package/static/dist/assets/{cobol-go622aep.js → cobol-ssf9hkh7.js} +1 -1
- package/static/dist/assets/{coffee-jwo1xjhq.js → coffee-lsi9fwae.js} +1 -1
- package/static/dist/assets/copied-bz3gkazh.js +1 -0
- package/static/dist/assets/copy-jo006coq.js +1 -0
- package/static/dist/assets/cose-bilkent-JH36ORCC-layy2r27.js +1 -0
- package/static/dist/assets/{cpp-nre7j0kq.js → cpp-lfrh4y55.js} +1 -1
- package/static/dist/assets/{crystal-lviso2je.js → crystal-efh4pte7.js} +1 -1
- package/static/dist/assets/{css-ywz9j4hb.js → css-i82qdo89.js} +1 -1
- package/static/dist/assets/cynefin-OW5HDTMX-d47op7qs.js +1 -0
- package/static/dist/assets/cynefinDiagram-5FMLGOSQ-doa7594y.js +62 -0
- package/static/dist/assets/cytoscape.esm-fjn2algp.js +321 -0
- package/static/dist/assets/dagre-GXQ25YYZ-os768dp4.js +4 -0
- package/static/dist/assets/dagre-o5jmjz46.js +1 -0
- package/static/dist/assets/{diagram-S7CK7UJ4-m6aeoe7c.js → diagram-S7CK7UJ4-fyi81nxd.js} +4 -4
- package/static/dist/assets/diagram-UQ7AKVKN-j3exggaq.js +41 -0
- package/static/dist/assets/{diagram-VSXAHHWV-hbawi7hn.js → diagram-VSXAHHWV-omo1en2l.js} +1 -1
- package/static/dist/assets/diagram-VX7I27RA-oro2cyu0.js +24 -0
- package/static/dist/assets/diagram-Z3DM3KII-byt9vdb7.js +24 -0
- package/static/dist/assets/dist-crc46di9.js +7 -0
- package/static/dist/assets/dist-etpoyscq.js +44 -0
- package/static/dist/assets/{dist-c4c2m3kv.js → dist-nb670eu6.js} +1 -1
- package/static/dist/assets/ebnfDiagram-PWID7BFC-ee3haugh.js +1 -0
- package/static/dist/assets/{edge-dvv35byi.js → edge-lrob635n.js} +1 -1
- package/static/dist/assets/{elixir-i2f1ki1g.js → elixir-kdpxeq93.js} +1 -1
- package/static/dist/assets/{elm-cpepyjm4.js → elm-c8irj9uh.js} +1 -1
- package/static/dist/assets/erDiagram-RLTQ6QDP-d1e93yff.js +99 -0
- package/static/dist/assets/{erb-idlyfheg.js → erb-flwsv146.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-i1ihb40c.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-jahfpiod.js +1 -0
- package/static/dist/assets/folder-plus-ivoglq98.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ma6jxj5i.js → ganttDiagram-EL5Y4UJY-m7g0jud4.js} +1 -1
- package/static/dist/assets/{git-rebase-d9lpfpbn.js → git-rebase-bli19aoq.js} +1 -1
- package/static/dist/assets/gitGraph-4MIJSDKK-hzdj07yy.js +1 -0
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-hzltvsod.js → gitGraphDiagram-WWUBYQGX-dm9agbna.js} +1 -1
- package/static/dist/assets/{glimmer-js-39i0urfb.js → glimmer-js-d4icg38p.js} +1 -1
- package/static/dist/assets/{glimmer-ts-gdtd6n73.js → glimmer-ts-bk75772u.js} +1 -1
- package/static/dist/assets/{glsl-o1djm5pp.js → glsl-lqormp2b.js} +1 -1
- package/static/dist/assets/{graphql-kj6rz55t.js → graphql-hw6s5qzd.js} +1 -1
- package/static/dist/assets/{hack-pe1qqr2i.js → hack-ozrv6l4d.js} +1 -1
- package/static/dist/assets/{haml-cknnbcqs.js → haml-gytfosdt.js} +1 -1
- package/static/dist/assets/{handlebars-hwq64orh.js → handlebars-b6g7jffd.js} +1 -1
- package/static/dist/assets/highlighted-body-KPVGNVTW-mmgz2czu.js +1 -0
- package/static/dist/assets/host-fr6lni1p.js +1 -0
- package/static/dist/assets/{html-derivative-h2i2pyjc.js → html-derivative-f1tqcroo.js} +1 -1
- package/static/dist/assets/{html-ha05xtvt.js → html-on6oj6yj.js} +1 -1
- package/static/dist/assets/{http-cf94zu27.js → http-odhufsl7.js} +1 -1
- package/static/dist/assets/{hurl-lslax568.js → hurl-mu680336.js} +1 -1
- package/static/dist/assets/index-73649w7o.js +10 -0
- package/static/dist/assets/index-lhf1fsdf.css +2 -0
- package/static/dist/assets/info-A6RAGUB7-lll1dqmm.js +1 -0
- package/static/dist/assets/infoDiagram-27XIBGKW-k7esc639.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-e7bnwq7h.js → ishikawaDiagram-5VMMS53U-lgr6k9wo.js} +6 -6
- package/static/dist/assets/{java-ndjf2o89.js → java-nxbe8uju.js} +1 -1
- package/static/dist/assets/{javascript-coftlwy3.js → javascript-lz3kxcyz.js} +1 -1
- package/static/dist/assets/{jinja-etei9wy7.js → jinja-l5pk84gt.js} +1 -1
- package/static/dist/assets/{jison-hyekgft1.js → jison-jdutdwyy.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-etd1bi6p.js → journeyDiagram-3NMN7TZE-ndmbxuqk.js} +1 -1
- package/static/dist/assets/{json-lok0yaho.js → json-dnge4ssf.js} +1 -1
- package/static/dist/assets/{jsx-b64w0nbx.js → jsx-c3lwhkep.js} +1 -1
- package/static/dist/assets/{jsx-runtime-eu92a5pu.js → jsx-runtime-o40ukmjl.js} +1 -1
- package/static/dist/assets/{julia-jxxzz2yn.js → julia-hwd4rrcb.js} +1 -1
- package/static/dist/assets/{just-mc29iw9t.js → just-nka3oxdx.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-emb1g9dz.js → kanban-definition-UXKFOSKX-mjxym0jp.js} +28 -28
- package/static/dist/assets/katex-cbdd1ohw.css +1 -0
- package/static/dist/assets/katex-pbij2oo6.js +257 -0
- package/static/dist/assets/{latex-pafa03ft.js → latex-iqmr7e40.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-cwb6l7xh.js +1 -0
- package/static/dist/assets/{line-h0ojzsvs.js → line-mtr5k6il.js} +1 -1
- package/static/dist/assets/linear-jlwrvvy6.js +1 -0
- package/static/dist/assets/link-iadw4ghw.js +2 -0
- package/static/dist/assets/{liquid-hz5c2pov.js → liquid-okmk9tbp.js} +1 -1
- package/static/dist/assets/locale-cs-n41hptse.js +5 -0
- package/static/dist/assets/locale-de-k7ht47ew.js +5 -0
- package/static/dist/assets/locale-es-ih078lco.js +5 -0
- package/static/dist/assets/locale-fr-ojabnf41.js +5 -0
- package/static/dist/assets/locale-it-kb96jufy.js +5 -0
- package/static/dist/assets/locale-ja-jpsp3xs1.js +7 -0
- package/static/dist/assets/locale-ko-cpzuy0n7.js +5 -0
- package/static/dist/assets/locale-pl-dbap4leu.js +5 -0
- package/static/dist/assets/locale-pt-nci7w72x.js +5 -0
- package/static/dist/assets/locale-ru-soghe4cs.js +7 -0
- package/static/dist/assets/locale-tr-ks00mu68.js +5 -0
- package/static/dist/assets/locale-vi-ij7twfm6.js +5 -0
- package/static/dist/assets/locale-zh-Hant-feakwr7a.js +5 -0
- package/static/dist/assets/locale-zh-ren0vjyv.js +7 -0
- package/static/dist/assets/login-lkhtzfcl.js +1 -0
- package/static/dist/assets/{lua-leyf8mlb.js → lua-krx4xj5h.js} +1 -1
- package/static/dist/assets/{marko-cn1fzpdv.js → marko-gbvpfehz.js} +1 -1
- package/static/dist/assets/{mdc-huhy88df.js → mdc-c21zlyi5.js} +1 -1
- package/static/dist/assets/mermaid-HWGCJPDP-jx0q5dm2.js +1 -0
- package/static/dist/assets/mermaid-parser.core-k91vdnvi.js +7 -0
- package/static/dist/assets/micromark-factory-space-fnmnpi6s.js +1 -0
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-o1vathns.js → mindmap-definition-YA3MSWOX-ehztfea4.js} +28 -28
- package/static/dist/assets/{nginx-e7lvhsmn.js → nginx-f3d68ed4.js} +1 -1
- package/static/dist/assets/{nim-dun5d8mk.js → nim-dw0jcy70.js} +1 -1
- package/static/dist/assets/onboarding-f67z0a2r.js +1 -0
- package/static/dist/assets/packet-AYTQ26CC-ok2xrblz.js +1 -0
- package/static/dist/assets/pegDiagram-XKGWAZYB-ec3rpj0m.js +1 -0
- package/static/dist/assets/{perl-bj3oqtet.js → perl-3c0r45c8.js} +1 -1
- package/static/dist/assets/{php-buzp12r0.js → php-rznhidvp.js} +1 -1
- package/static/dist/assets/pie-WAS4IAKB-iwkir23u.js +1 -0
- package/static/dist/assets/pieDiagram-E7YTZNPT-fcpqpekh.js +39 -0
- package/static/dist/assets/{pug-mjad7he9.js → pug-f2le4f3y.js} +1 -1
- package/static/dist/assets/{qml-d1gdp10s.js → qml-e2wbq9cr.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-owqc4uqn.js → quadrantDiagram-AXDQQJYC-lqsync43.js} +1 -1
- package/static/dist/assets/queryKeys-ed4n2egc.js +9 -0
- package/static/dist/assets/{r-o3r9c7ao.js → r-epfzuw6q.js} +1 -1
- package/static/dist/assets/radar-RG4KPBEZ-hje4jbk6.js +1 -0
- package/static/dist/assets/railroad-74A4TZTK-gll9n6qi.js +1 -0
- package/static/dist/assets/railroad-abnf-HS5TGJTU-o6h6lpn4.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-juaefj6o.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-cgfhvpah.js +1 -0
- package/static/dist/assets/railroadDiagram-O6MQD6OU-lp3w7awf.js +1 -0
- package/static/dist/assets/{razor-ilc585yr.js → razor-pea1u1d0.js} +1 -1
- package/static/dist/assets/refresh-cw-iccm7a4e.js +1 -0
- package/static/dist/assets/refresh-i9ya9dvl.js +1 -0
- package/static/dist/assets/{regexp-mpjtcvwm.js → regexp-hzte0a5x.js} +1 -1
- package/static/dist/assets/registry-g7w3353u.js +1 -0
- package/static/dist/assets/requirementDiagram-BXWQKSXE-ha8eibcf.js +84 -0
- package/static/dist/assets/rolldown-runtime-bnnw9q4a.js +1 -0
- package/static/dist/assets/{rst-jrkwjdyi.js → rst-m6tugj5o.js} +1 -1
- package/static/dist/assets/{ruby-n4tjcbpz.js → ruby-l19vq3w1.js} +1 -1
- package/static/dist/assets/runtime-nlxpnegr.js +1 -0
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-iqc02emv.js → sankeyDiagram-P5KCCOFB-oxf31pr9.js} +1 -1
- package/static/dist/assets/{sas-hjo6y93k.js → sas-ktdxo397.js} +1 -1
- package/static/dist/assets/{scss-ncidjv48.js → scss-kn3oxfwf.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-i0v116q0.js → sequenceDiagram-WJ2MYXX4-jiq8lhyo.js} +11 -11
- package/static/dist/assets/settings_section_extensions_title-fadc7o65.js +1 -0
- package/static/dist/assets/share._token-o76ki0ly.js +2 -0
- package/static/dist/assets/{shellscript-m8whjpqd.js → shellscript-l100jtrg.js} +1 -1
- package/static/dist/assets/{shellsession-i5bj6syz.js → shellsession-m5qukwow.js} +1 -1
- package/static/dist/assets/sizeCapture-INFHLROL-dk1io13w.js +1 -0
- package/static/dist/assets/sliders-horizontal-ddcs88av.js +1 -0
- package/static/dist/assets/{soy-hhh36ysq.js → soy-mexlscur.js} +1 -1
- package/static/dist/assets/{sql-j21bzcl6.js → sql-o0ho5suh.js} +1 -1
- package/static/dist/assets/src-h89s0hs4.js +1 -0
- package/static/dist/assets/{stata-bbu2onh1.js → stata-be9ck1q3.js} +1 -1
- package/static/dist/assets/stateDiagram-D77RDMKH-f3fslnon.js +1 -0
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hlt6yphw.js +1 -0
- package/static/dist/assets/{surrealql-l5vczuco.js → surrealql-gk1xkkyy.js} +1 -1
- package/static/dist/assets/{svelte-idn422g6.js → svelte-k6ecjilf.js} +1 -1
- package/static/dist/assets/swimlanes-42K2YHIH-k1hmk7jf.js +1 -0
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hd5t9tnt.js +8 -0
- package/static/dist/assets/{templ-e22qou3c.js → templ-gf3bftk6.js} +1 -1
- package/static/dist/assets/{tex-deqpc5ee.js → tex-d21fqv1z.js} +1 -1
- package/static/dist/assets/{timeline-definition-24CTP7MA-ol2hnvma.js → timeline-definition-24CTP7MA-n3ncfy9r.js} +8 -8
- package/static/dist/assets/toast-liparz2j.js +56 -0
- package/static/dist/assets/treeView-Q6P3EWNA-l3y2pejt.js +1 -0
- package/static/dist/assets/treemap-WGGIJYW6-jown9axh.js +1 -0
- package/static/dist/assets/{ts-tags-ctnibc27.js → ts-tags-n0g61gr6.js} +1 -1
- package/static/dist/assets/{tsx-i163n32g.js → tsx-cvv7wv6q.js} +1 -1
- package/static/dist/assets/{twig-x0fi7wm8.js → twig-n1f67204.js} +1 -1
- package/static/dist/assets/{typescript-g18c34xz.js → typescript-og7o55cx.js} +1 -1
- package/static/dist/assets/untitled-mj86r4gz.js +1 -0
- package/static/dist/assets/useDebounced-g8r0ggve.js +1 -0
- package/static/dist/assets/useForm-o4uu74mx.js +1 -0
- package/static/dist/assets/{useParams-gjc70qru.js → useParams-ftsveu84.js} +1 -1
- package/static/dist/assets/{useSearch-e6ae539u.js → useSearch-crqueqga.js} +1 -1
- package/static/dist/assets/vennDiagram-4TSXK5OY-dh59uq1c.js +34 -0
- package/static/dist/assets/{vue-mwu5l1bb.js → vue-ej4xpwqw.js} +1 -1
- package/static/dist/assets/{vue-html-nskj3du0.js → vue-html-d48xsjuo.js} +1 -1
- package/static/dist/assets/{vue-vine-cqe77smq.js → vue-vine-pev88ip6.js} +1 -1
- package/static/dist/assets/wardley-WFR3VGLG-e6d74b0j.js +1 -0
- package/static/dist/assets/wardleyDiagram-VM6X3IG4-hnofh78f.js +78 -0
- package/static/dist/assets/with-selector-nu1b5z0v.js +1 -0
- package/static/dist/assets/{xml-gau7gvrv.js → xml-ifxp6gqb.js} +1 -1
- package/static/dist/assets/{xsl-ew09zq8b.js → xsl-fug2cckc.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-aqbgvujg.js → xychartDiagram-S5SC5T6Z-bpymjelb.js} +6 -6
- package/static/dist/assets/{yaml-ofnrxtvf.js → yaml-fjmafnlo.js} +1 -1
- package/static/dist/extension-sdk.js +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +180 -136
- package/static/dist/assets/AppShell-cey33v9s.js +0 -8
- package/static/dist/assets/ChatPage-i8wnugr7.js +0 -18
- package/static/dist/assets/ConnectTargets-hg19553x.js +0 -1
- package/static/dist/assets/ExtensionRoute-cly4apm5.js +0 -1
- package/static/dist/assets/Field-j8uqoigz.js +0 -9
- package/static/dist/assets/HubRoute-e4bgz41j.js +0 -2
- package/static/dist/assets/Markdown-lahuichm.js +0 -598
- package/static/dist/assets/Markdown-lwviulmg.css +0 -1
- package/static/dist/assets/RightPanel-lbo4i0fn.js +0 -1
- package/static/dist/assets/Select-gqatm2e0.js +0 -1
- package/static/dist/assets/SessionListPanel-mfqayfjh.js +0 -1
- package/static/dist/assets/SettingsLayout-b8980u7k.js +0 -1
- package/static/dist/assets/States-e7dkgtxf.js +0 -1
- package/static/dist/assets/Toaster-bfqqy786.js +0 -1
- package/static/dist/assets/_app-n1n6pfx1.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-buxjxav3.js +0 -1
- package/static/dist/assets/_app.index-jt8zwiu2.js +0 -1
- package/static/dist/assets/_app.insights-cv76ml71.js +0 -1
- package/static/dist/assets/_app.kanban-h6ts53j7.js +0 -1
- package/static/dist/assets/_app.logs-dm873z90.js +0 -1
- package/static/dist/assets/_app.memory-glk5y6m8.js +0 -1
- package/static/dist/assets/_app.profiles-ka6zpstq.js +0 -1
- package/static/dist/assets/_app.session._sessionId-g2vzghvc.js +0 -1
- package/static/dist/assets/_app.settings-hgjdhzcd.js +0 -1
- package/static/dist/assets/_app.settings._section-jf2kmhae.js +0 -3
- package/static/dist/assets/_app.skills-cii852yq.js +0 -1
- package/static/dist/assets/_app.tasks-fp9q7atm.js +0 -1
- package/static/dist/assets/_app.todos-dw94qzue.js +0 -1
- package/static/dist/assets/_app.workspaces-inyygzze.js +0 -1
- package/static/dist/assets/abnfDiagram-VCTEODGH-gjayq3ra.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +0 -1
- package/static/dist/assets/architectureDiagram-5GKGNRK7-nwb3xovn.js +0 -36
- package/static/dist/assets/archive-b1j004vn.js +0 -1
- package/static/dist/assets/back-g74gkozu.js +0 -1
- package/static/dist/assets/channel-es95o4y8.js +0 -1
- package/static/dist/assets/chunk-DU6HZSFF-gpedttsp.js +0 -128
- package/static/dist/assets/chunk-OSK3NFVY-oy0gwn2n.js +0 -10
- package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +0 -1
- package/static/dist/assets/copied-bli9tbcx.js +0 -1
- package/static/dist/assets/copy-jamtd1pf.js +0 -1
- package/static/dist/assets/cose-bilkent-JH36ORCC-eclcy6ja.js +0 -1
- package/static/dist/assets/cynefin-OW5HDTMX-f8xfdd3f.js +0 -1
- package/static/dist/assets/cynefinDiagram-5FMLGOSQ-n9lb99h9.js +0 -62
- package/static/dist/assets/cytoscape.esm-bqu53u12.js +0 -321
- package/static/dist/assets/dagre-GXQ25YYZ-dgailddi.js +0 -4
- package/static/dist/assets/dagre-lkoknbjn.js +0 -1
- package/static/dist/assets/diagram-UQ7AKVKN-jall3j0x.js +0 -41
- package/static/dist/assets/diagram-VX7I27RA-hendl2tt.js +0 -24
- package/static/dist/assets/diagram-Z3DM3KII-igwc35p3.js +0 -24
- package/static/dist/assets/ebnfDiagram-PWID7BFC-c64knz08.js +0 -1
- package/static/dist/assets/erDiagram-RLTQ6QDP-brdu9lcm.js +0 -99
- package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +0 -1
- package/static/dist/assets/folder-plus-lvt9kudb.js +0 -1
- package/static/dist/assets/gitGraph-4MIJSDKK-naa9w6xa.js +0 -1
- package/static/dist/assets/highlighted-body-KPVGNVTW-ghoavj8d.js +0 -1
- package/static/dist/assets/host-hzm8n85n.js +0 -1
- package/static/dist/assets/index-drdcaqeq.css +0 -2
- package/static/dist/assets/index-jzm844he.js +0 -11
- package/static/dist/assets/info-A6RAGUB7-mn2ut5ko.js +0 -1
- package/static/dist/assets/infoDiagram-27XIBGKW-h6kuqvsb.js +0 -2
- package/static/dist/assets/lazyRouteComponent-o816ytzl.js +0 -1
- package/static/dist/assets/linear-becwlnhk.js +0 -1
- package/static/dist/assets/link-k01ryaf9.js +0 -1
- package/static/dist/assets/login-bsae49ew.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +0 -1
- package/static/dist/assets/mermaid-parser.core-bnre27u8.js +0 -7
- package/static/dist/assets/not-found-ccnnac39.js +0 -1
- package/static/dist/assets/onboarding-c65tysya.js +0 -1
- package/static/dist/assets/onboarding_model_label-gpn28uix.js +0 -1
- package/static/dist/assets/packet-AYTQ26CC-hatq7m2e.js +0 -1
- package/static/dist/assets/pegDiagram-XKGWAZYB-gwisz8jv.js +0 -1
- package/static/dist/assets/pie-WAS4IAKB-fpftf0mk.js +0 -1
- package/static/dist/assets/pieDiagram-E7YTZNPT-khm1o9a6.js +0 -39
- package/static/dist/assets/radar-RG4KPBEZ-cntfwjpq.js +0 -1
- package/static/dist/assets/railroad-74A4TZTK-a7t5eibp.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +0 -1
- package/static/dist/assets/railroadDiagram-O6MQD6OU-etuh0qa0.js +0 -1
- package/static/dist/assets/refresh-cw-mqbkv2a3.js +0 -1
- package/static/dist/assets/refresh-l29ljp76.js +0 -1
- package/static/dist/assets/requirementDiagram-BXWQKSXE-oq2ulk22.js +0 -84
- package/static/dist/assets/rolldown-runtime-b9miacsj.js +0 -1
- package/static/dist/assets/root-mbklpuv4.js +0 -1
- package/static/dist/assets/saved-ndd4t2xb.js +0 -1
- package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +0 -1
- package/static/dist/assets/share._token-c1ri0hy1.js +0 -2
- package/static/dist/assets/sizeCapture-INFHLROL-g612l48j.js +0 -1
- package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +0 -1
- package/static/dist/assets/src-hjyib4mu.js +0 -1
- package/static/dist/assets/stateDiagram-D77RDMKH-dnpt1ato.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +0 -1
- package/static/dist/assets/swimlanes-42K2YHIH-loqbdazb.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +0 -8
- package/static/dist/assets/toast-i3h34v6o.js +0 -64
- package/static/dist/assets/treeView-Q6P3EWNA-idrj6iox.js +0 -1
- package/static/dist/assets/treemap-WGGIJYW6-lzr49vv5.js +0 -1
- package/static/dist/assets/untitled-oaoya4qj.js +0 -1
- package/static/dist/assets/useForm-nfaxgmsk.js +0 -1
- package/static/dist/assets/vennDiagram-4TSXK5OY-bvwr9o2z.js +0 -34
- package/static/dist/assets/wardley-WFR3VGLG-31ui8tma.js +0 -1
- package/static/dist/assets/wardleyDiagram-VM6X3IG4-k5wqtx4b.js +0 -78
- /package/static/dist/assets/{ChatPage-gmu5c7lf.css → TerminalPanel-gmu5c7lf.css} +0 -0
|
@@ -29,6 +29,8 @@ _SESSIONS = {}
|
|
|
29
29
|
_SESSIONS_LOCK = threading.Lock()
|
|
30
30
|
_CONSENTS = {}
|
|
31
31
|
CONSENT_SECONDS = 300
|
|
32
|
+
# One lease exchange, including the worker's unwind after a refused drain.
|
|
33
|
+
LEASE_SECONDS = 330
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
def _close(session):
|
|
@@ -119,7 +121,59 @@ def _native_source_repair(root):
|
|
|
119
121
|
raise
|
|
120
122
|
|
|
121
123
|
|
|
122
|
-
def
|
|
124
|
+
def _receipt_candidates(path, pattern, cache):
|
|
125
|
+
"""Cache discovery, never receipt presence; missing paths watch their nearest existing ancestor."""
|
|
126
|
+
key = (path, pattern)
|
|
127
|
+
if cache is not None:
|
|
128
|
+
ancestor = path
|
|
129
|
+
while True:
|
|
130
|
+
try:
|
|
131
|
+
stat = ancestor.stat()
|
|
132
|
+
break
|
|
133
|
+
except FileNotFoundError:
|
|
134
|
+
if ancestor == ancestor.parent:
|
|
135
|
+
raise
|
|
136
|
+
ancestor = ancestor.parent
|
|
137
|
+
stamp = (ancestor, stat.st_dev, stat.st_ino, stat.st_mode, stat.st_mtime_ns, stat.st_ctime_ns, stat.st_size)
|
|
138
|
+
now = time.monotonic()
|
|
139
|
+
previous = cache.get(key)
|
|
140
|
+
if previous is not None and previous[0] == stamp and 0 <= now - previous[1] < 1:
|
|
141
|
+
return previous[2]
|
|
142
|
+
if pattern is not None:
|
|
143
|
+
try:
|
|
144
|
+
# glob suppresses enumeration errors, which cannot authorize Agent admission.
|
|
145
|
+
with os.scandir(path) as children:
|
|
146
|
+
found = tuple(path / child.name for child in children if Path(child.name).match(pattern))
|
|
147
|
+
except FileNotFoundError:
|
|
148
|
+
found = ()
|
|
149
|
+
else:
|
|
150
|
+
try:
|
|
151
|
+
found = (path,) if any(' refs/talaria/autostash/pending/' in line for line in path.read_text().splitlines()) else ()
|
|
152
|
+
except FileNotFoundError:
|
|
153
|
+
found = ()
|
|
154
|
+
if cache is not None:
|
|
155
|
+
if len(cache) >= 16:
|
|
156
|
+
cache.clear() # Bound retained paths if an installer repeatedly redirects Git metadata.
|
|
157
|
+
cache[key] = (stamp, now, found)
|
|
158
|
+
return found
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _process_presence(pid):
|
|
162
|
+
"""A stdlib rearm trigger only; native identity verification alone decides recovery."""
|
|
163
|
+
if os.name == 'nt' or pid <= 0:
|
|
164
|
+
return 'unknown'
|
|
165
|
+
try:
|
|
166
|
+
os.kill(pid, 0)
|
|
167
|
+
except ProcessLookupError:
|
|
168
|
+
return 'exited'
|
|
169
|
+
except PermissionError:
|
|
170
|
+
pass
|
|
171
|
+
except (OSError, OverflowError):
|
|
172
|
+
return 'unknown'
|
|
173
|
+
return 'present'
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def recovery_receipts(runtime, *, watch=False, discovery_cache=None):
|
|
123
177
|
"""Read only the configured checkout's receipts without importing its possibly torn code."""
|
|
124
178
|
root, home = runtime.agent_dir, runtime.hermes_home
|
|
125
179
|
if root is None:
|
|
@@ -133,19 +187,15 @@ def recovery_receipts(runtime, *, watch=False):
|
|
|
133
187
|
paths = [services.recovery_path(root, home), marker, native,
|
|
134
188
|
root / '.update-incomplete', root / '.lazy-refresh-incomplete',
|
|
135
189
|
gitdir / 'hermes-update-pull', root / '.hermes-update-zip-swap']
|
|
136
|
-
paths.extend(home
|
|
190
|
+
paths.extend(_receipt_candidates(home, native.name + '.*.claim', discovery_cache))
|
|
137
191
|
common = gitdir
|
|
138
192
|
try:
|
|
139
193
|
common = (gitdir / (gitdir / 'commondir').read_text().strip()).resolve()
|
|
140
194
|
except FileNotFoundError:
|
|
141
195
|
pass
|
|
142
|
-
paths.extend((common / 'refs/talaria/autostash/pending'
|
|
196
|
+
paths.extend(_receipt_candidates(common / 'refs/talaria/autostash/pending', '*', discovery_cache))
|
|
143
197
|
packed = common / 'packed-refs'
|
|
144
|
-
|
|
145
|
-
if any(' refs/talaria/autostash/pending/' in line for line in packed.read_text().splitlines()):
|
|
146
|
-
paths.append(packed)
|
|
147
|
-
except FileNotFoundError:
|
|
148
|
-
pass
|
|
198
|
+
paths.extend(_receipt_candidates(packed, None, discovery_cache))
|
|
149
199
|
def stamps(candidates):
|
|
150
200
|
result = []
|
|
151
201
|
for path in sorted(set(candidates)):
|
|
@@ -169,15 +219,23 @@ def recovery_receipts(runtime, *, watch=False):
|
|
|
169
219
|
watched.append(common / ref)
|
|
170
220
|
except (OSError, UnicodeError):
|
|
171
221
|
pass
|
|
222
|
+
lifecycle = []
|
|
172
223
|
try:
|
|
173
224
|
body = json.loads(services.recovery_path(root, home).read_text())
|
|
174
225
|
for baseline in body.get('tree', {}).get('baselines', []):
|
|
175
226
|
changed = [*baseline.get('dirty_at_pause', []), *baseline.get('move_paths', [])]
|
|
176
227
|
changed.extend(path for paths in baseline.get('landed', {}).values() for path in paths)
|
|
177
228
|
watched.extend(root / path for path in changed if isinstance(path, str) and not Path(path).is_absolute() and '..' not in Path(path).parts)
|
|
229
|
+
# A retained gateway's exit or successor rearms exhausted recovery without changing any receipt.
|
|
230
|
+
for entry in body.get('entries', []):
|
|
231
|
+
if entry.get('purpose') == 'gateway' and isinstance(entry.get('home'), str):
|
|
232
|
+
watched.append(Path(entry['home']) / 'gateway.pid')
|
|
233
|
+
pids = {**entry.get('retired_processes', {}), **entry.get('processes', {})}
|
|
234
|
+
lifecycle.extend(('process', int(pid), _process_presence(int(pid))) for pid in sorted(pids, key=int))
|
|
178
235
|
except (OSError, ValueError, TypeError, AttributeError):
|
|
179
236
|
pass # The receipt's own stamp still rearms corrected evidence; the worker reports its exact refusal.
|
|
180
237
|
found.extend(stamps(watched))
|
|
238
|
+
found.extend(lifecycle)
|
|
181
239
|
return found, marker
|
|
182
240
|
|
|
183
241
|
|
|
@@ -203,6 +261,8 @@ def recover_retained(runtime, ctx, *, probe=False, complete_revision=None):
|
|
|
203
261
|
env.update(HERMES_HOME=str(runtime.hermes_home), HERMES_DISABLE_LAZY_INSTALLS='1',
|
|
204
262
|
PYTHONPATH=str(Path(__file__).parents[1]) + os.pathsep + str(root))
|
|
205
263
|
try:
|
|
264
|
+
if complete_revision is None:
|
|
265
|
+
runtime.retire()
|
|
206
266
|
with tempfile.TemporaryFile() as stdout, tempfile.TemporaryFile() as stderr:
|
|
207
267
|
child = subprocess.Popen([sys.executable, '-m', 'talaria_sidecar.agent_mutation', '--recover-current', str(root), complete_revision or ''],
|
|
208
268
|
cwd=root, env=env, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr)
|
|
@@ -237,12 +297,22 @@ def recover_retained(runtime, ctx, *, probe=False, complete_revision=None):
|
|
|
237
297
|
_ACTION_LOCK.release()
|
|
238
298
|
|
|
239
299
|
|
|
300
|
+
def _drain_progress(result):
|
|
301
|
+
progress = result.get("progress") if isinstance(result, dict) and result.keys() == {"progress"} else None
|
|
302
|
+
if (not isinstance(progress, dict) or progress.get("phase") != "gateway_drain"
|
|
303
|
+
or not isinstance(progress.get("deadline_seconds"), (int, float)) or isinstance(progress["deadline_seconds"], bool)
|
|
304
|
+
or not 0 <= progress["deadline_seconds"] <= services.GATEWAY_DRAIN_CEILING
|
|
305
|
+
or not isinstance(progress.get("services"), list) or not all(isinstance(name, str) for name in progress["services"])):
|
|
306
|
+
return None
|
|
307
|
+
return {"phase": "gateway_drain", "deadline_seconds": progress["deadline_seconds"], "services": progress["services"]}
|
|
308
|
+
|
|
309
|
+
|
|
240
310
|
def _exchange(session, request, ctx):
|
|
241
311
|
with session["lock"]:
|
|
242
312
|
if request is not None:
|
|
243
313
|
session["proc"].stdin.write(json.dumps(request) + "\n")
|
|
244
314
|
session["proc"].stdin.flush()
|
|
245
|
-
deadline = time.monotonic() +
|
|
315
|
+
deadline = time.monotonic() + LEASE_SECONDS
|
|
246
316
|
while True:
|
|
247
317
|
ctx.check_cancelled()
|
|
248
318
|
if time.monotonic() >= deadline:
|
|
@@ -254,6 +324,14 @@ def _exchange(session, request, ctx):
|
|
|
254
324
|
if line is None:
|
|
255
325
|
raise RpcError("Agent writer lease exited; its pause journal retains recovery.", condition="agent_update_unsafe")
|
|
256
326
|
result = json.loads(line)
|
|
327
|
+
if isinstance(result, dict) and "progress" in result:
|
|
328
|
+
progress = _drain_progress(result)
|
|
329
|
+
if progress is None:
|
|
330
|
+
raise RpcError("Invalid Agent writer lease response.", condition="agent_update_unsafe")
|
|
331
|
+
# The worker's own drain deadline is bounded; unwind keeps the ordinary lease margin.
|
|
332
|
+
deadline = max(deadline, time.monotonic() + progress["deadline_seconds"] + LEASE_SECONDS)
|
|
333
|
+
ctx.emit("progress", progress)
|
|
334
|
+
continue
|
|
257
335
|
if not isinstance(result, dict) or not isinstance(result.get("ok"), bool):
|
|
258
336
|
raise RpcError("Invalid Agent writer lease response.", condition="agent_update_unsafe")
|
|
259
337
|
return {"ok": result["ok"], "skipped": result.get("skipped") is True, "detail": str(result.get("detail") or ""),
|
|
@@ -358,6 +436,7 @@ def call(runtime, ctx, params):
|
|
|
358
436
|
_CONSENTS[nonce].update(binding=confirmation['binding'], expires=time.monotonic() + CONSENT_SECONDS)
|
|
359
437
|
result['refresh_confirmation'] = {'token': nonce, 'services': confirmation['services']}
|
|
360
438
|
if action == "begin" and result["ok"]:
|
|
439
|
+
runtime.retire()
|
|
361
440
|
return {**result, "token": token}
|
|
362
441
|
if action != "finish" and result["ok"]:
|
|
363
442
|
return result
|
|
@@ -583,7 +662,11 @@ def _worker(root, revision, homes, requests, stopped, send, refresh_binding=None
|
|
|
583
662
|
records.mark_stop_requested(token, sorted({pid for e in gateway_entries for pid in (e['pid'], e.get('service_pid', e['pid']))}))
|
|
584
663
|
for entry in backend_entries:
|
|
585
664
|
recovery.stop(entry, stopped)
|
|
586
|
-
|
|
665
|
+
# Every profile shares the longest native drain; the lease reports it so its RPC keeps custody.
|
|
666
|
+
gateway_deadline = recovery.gateway_deadline(homes)
|
|
667
|
+
if gateway_entries:
|
|
668
|
+
send({'progress': {'phase': 'gateway_drain', 'deadline_seconds': round(max(gateway_deadline - time.monotonic(), 0), 3),
|
|
669
|
+
'services': sorted({services._name(e) for e in gateway_entries})}})
|
|
587
670
|
for entry in gateway_entries:
|
|
588
671
|
if stopped.is_set() or time.monotonic() >= gateway_deadline:
|
|
589
672
|
raise RuntimeError('Gateway drain has not completed; its durable resume obligation is retained.')
|
|
@@ -708,6 +791,8 @@ def _worker(root, revision, homes, requests, stopped, send, refresh_binding=None
|
|
|
708
791
|
error = str(exc)
|
|
709
792
|
finally:
|
|
710
793
|
try:
|
|
794
|
+
# Cancellation or a lost lease pipe ends the drain wait; the retained debt keeps the gateway owed.
|
|
795
|
+
unwind_deadline = time.monotonic() if stopped.is_set() else gateway_deadline
|
|
711
796
|
if token:
|
|
712
797
|
live = any(records.identity_is_live({"pid": int(pid), "ct": ct}) for pid, ct in token.get("identities", {}).items())
|
|
713
798
|
found = _command(modules["update_custody"].git_argv(["git"], ["rev-parse", "HEAD"]), root, 10, threading.Event(), modules["update_custody"])
|
|
@@ -720,7 +805,7 @@ def _worker(root, revision, homes, requests, stopped, send, refresh_binding=None
|
|
|
720
805
|
if live and not changed and not sync_failed and records.tree_is_whole(token, root)[0]:
|
|
721
806
|
# An untouched gateway must not strand a backend stopped earlier in a partial pause.
|
|
722
807
|
recovery.save(token)
|
|
723
|
-
recovery.resume(_writer_ledger, gateway_deadline=
|
|
808
|
+
recovery.resume(_writer_ledger, gateway_deadline=unwind_deadline)
|
|
724
809
|
if live or sync_failed or (changed and needs_sync and not locals().get("response", {}).get("ok")):
|
|
725
810
|
raise RuntimeError("Gateway resume remains owed until writer drain and dependency repair complete.")
|
|
726
811
|
whole, why = records.tree_is_whole(token, root)
|
|
@@ -742,7 +827,7 @@ def _worker(root, revision, homes, requests, stopped, send, refresh_binding=None
|
|
|
742
827
|
if token.get("resume_needed") or token.get("resume_deferred"):
|
|
743
828
|
raise RuntimeError("Gateway resume could not be verified; its obligation is retained.")
|
|
744
829
|
recovery.save(token)
|
|
745
|
-
recovery.resume(_writer_ledger, gateway_deadline=
|
|
830
|
+
recovery.resume(_writer_ledger, gateway_deadline=unwind_deadline)
|
|
746
831
|
if token and not handed_off:
|
|
747
832
|
records.discharge(token)
|
|
748
833
|
from .runtime import AgentRuntime
|
|
@@ -763,16 +848,19 @@ def _worker(root, revision, homes, requests, stopped, send, refresh_binding=None
|
|
|
763
848
|
|
|
764
849
|
|
|
765
850
|
def _resume_current(root, custody, stopped=None, complete_revision=None):
|
|
851
|
+
# Resolve target PM code in a fresh stdlib process, after any source/dependency change.
|
|
766
852
|
try:
|
|
767
|
-
|
|
768
|
-
|
|
853
|
+
launchers = importlib.import_module('hermes_cli._launchers')
|
|
854
|
+
if not Path(launchers.__file__).resolve().is_relative_to(root):
|
|
855
|
+
raise RuntimeError('Recovery loaded another Agent bootstrap selector.')
|
|
856
|
+
bootstrap = launchers.resolve_store_python(root)
|
|
769
857
|
except ModuleNotFoundError as exc:
|
|
770
|
-
if exc.name !=
|
|
858
|
+
if exc.name != 'hermes_cli._launchers':
|
|
771
859
|
raise
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
result = _command([str(
|
|
860
|
+
bootstrap = None
|
|
861
|
+
# A copied macOS venv interpreter can be its own _base_executable and later be retired.
|
|
862
|
+
bootstrap = bootstrap or getattr(sys, '_base_executable', None) or sys.executable
|
|
863
|
+
result = _command([str(bootstrap), "-m", "talaria_sidecar.agent_mutation", "--select-resume", str(root), complete_revision or "", sys.executable], root, 660, stopped or threading.Event(), custody, cooperative=True)
|
|
776
864
|
try:
|
|
777
865
|
reply = json.loads(result["detail"]) if result["ok"] else {}
|
|
778
866
|
return {**reply, "ok": result["ok"] and reply.get("ok") is True, "detail": str(reply.get("detail") or result["detail"])}
|
|
@@ -780,6 +868,46 @@ def _resume_current(root, custody, stopped=None, complete_revision=None):
|
|
|
780
868
|
return {"ok": False, "detail": "The current Agent could not verify its retained gateway resume obligation."}
|
|
781
869
|
|
|
782
870
|
|
|
871
|
+
def _recovery_environment(root):
|
|
872
|
+
"""Reuse PM's selector and packaged launch policy without copying its facts/path rules."""
|
|
873
|
+
sys.path.insert(0, str(root))
|
|
874
|
+
environments = importlib.import_module('pm.environments')
|
|
875
|
+
if any(not Path(sys.modules[name].__file__).resolve().is_relative_to(root)
|
|
876
|
+
for name in ('pm', 'pm.environments', 'hermes_constants')):
|
|
877
|
+
raise RuntimeError('Recovery loaded another Agent environment selector.')
|
|
878
|
+
selected = environments.committed_venv(root)
|
|
879
|
+
if selected is None:
|
|
880
|
+
if environments.install_state_dir(root).exists():
|
|
881
|
+
raise RuntimeError('No dependency environment is committed for this Agent install; recovery remains owed.')
|
|
882
|
+
selected = environments.selected_venv(root)
|
|
883
|
+
return environments, selected
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def _select_resume(root, complete_revision, legacy_python):
|
|
887
|
+
if (root / 'pm').exists():
|
|
888
|
+
environments, selected = _recovery_environment(root)
|
|
889
|
+
command = environments.venv_command(root, selected)
|
|
890
|
+
environment = str(selected)
|
|
891
|
+
else:
|
|
892
|
+
python = next((path for venv in ('.venv', 'venv')
|
|
893
|
+
for path in (root / venv / 'bin/python', root / venv / 'Scripts/python.exe') if path.is_file()), Path(legacy_python))
|
|
894
|
+
command, environment = [str(python)], ''
|
|
895
|
+
# Keep bin/python intact: realpath would turn a POSIX venv into its bare tool.
|
|
896
|
+
argv = [*command, '-m', 'talaria_sidecar.agent_mutation', '--resume-leased', str(root), complete_revision or '', environment]
|
|
897
|
+
os.execv(argv[0], argv)
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
def _verify_recovery_environment(root, expected):
|
|
901
|
+
from .runtime import _check_site_packages_python
|
|
902
|
+
environments, selected = _recovery_environment(root)
|
|
903
|
+
if str(selected) != expected or environments.venv_python_version(selected) != sys.version_info[:2]:
|
|
904
|
+
raise RuntimeError('Agent recovery dependency environment changed or has an incompatible Python ABI.')
|
|
905
|
+
site = environments.site_packages(selected)
|
|
906
|
+
if not site.is_dir() or site.resolve() not in {Path(entry).resolve() for entry in sys.path if entry}:
|
|
907
|
+
raise RuntimeError('Agent recovery did not enter its selected dependency environment.')
|
|
908
|
+
_check_site_packages_python()
|
|
909
|
+
|
|
910
|
+
|
|
783
911
|
def _resume_worker(root, stopped=None, complete_revision=None):
|
|
784
912
|
sys.path.insert(0, str(root))
|
|
785
913
|
from hermes_cli import update_lock, update_pause_record as records, process_identity, update_cmd_posix_pause
|
|
@@ -833,9 +961,10 @@ def _resume_worker(root, stopped=None, complete_revision=None):
|
|
|
833
961
|
if response.get('ok') is not True:
|
|
834
962
|
return {'ok': False, 'detail': 'Recorded dependency repair failed: ' + str(response.get('detail') or synced['detail'])}
|
|
835
963
|
recovery.state['sync_failed'] = False
|
|
836
|
-
|
|
837
|
-
|
|
964
|
+
transaction = recovery.state.setdefault('transaction', {'revision': revision, 'homes': [str(runtime.hermes_home)]})
|
|
965
|
+
transaction['dependencies_verified'] = True
|
|
838
966
|
recovery.save(tree)
|
|
967
|
+
return _resume_current(root, custody, stopped, complete_revision)
|
|
839
968
|
elif recovery.state.get('sync_failed'):
|
|
840
969
|
return {'ok': False, 'detail': 'The recorded dependency repair module is missing.'}
|
|
841
970
|
whole, why = records.tree_is_whole(tree, root)
|
|
@@ -850,7 +979,10 @@ def _resume_worker(root, stopped=None, complete_revision=None):
|
|
|
850
979
|
if not Path(main_module.__file__).resolve().is_relative_to(root):
|
|
851
980
|
raise RuntimeError("Gateway recovery loaded another Agent runtime.")
|
|
852
981
|
records.recover(argv=[])
|
|
853
|
-
|
|
982
|
+
try:
|
|
983
|
+
recovery.resume(_writer_ledger)
|
|
984
|
+
except services.GatewayDraining as exc:
|
|
985
|
+
return {'ok': False, 'draining': True, 'detail': str(exc)}
|
|
854
986
|
owed = records.record_path().exists() or bool(records._claims(records.record_path())) or bool(recovery.state['entries'])
|
|
855
987
|
runtime_pending = bool((marker and marker.exists()) or (recovery.state.get('transaction') or {}).get('runtime_revision'))
|
|
856
988
|
if not owed and runtime_pending:
|
|
@@ -926,9 +1058,11 @@ def _command(argv, root, timeout, stopped, custody, *, cooperative=False):
|
|
|
926
1058
|
def main():
|
|
927
1059
|
for key in ("GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"):
|
|
928
1060
|
os.environ.pop(key, None)
|
|
929
|
-
if len(sys.argv) > 2 and sys.argv[1] in {'--recover-current', '--resume', '--resume-leased'}:
|
|
1061
|
+
if len(sys.argv) > 2 and sys.argv[1] in {'--recover-current', '--resume', '--resume-leased', '--select-resume'}:
|
|
930
1062
|
try:
|
|
931
1063
|
_native_source_repair(Path(sys.argv[2]).resolve())
|
|
1064
|
+
if sys.argv[1] == '--select-resume':
|
|
1065
|
+
_select_resume(Path(sys.argv[2]).resolve(), sys.argv[3], sys.argv[4])
|
|
932
1066
|
except BaseException as exc:
|
|
933
1067
|
print(json.dumps({'ok': False, 'detail': str(exc) if str(exc) != '1' else 'Native recorded source repair could not complete; its receipt remains owed.'}), flush=True)
|
|
934
1068
|
return
|
|
@@ -962,6 +1096,8 @@ def main():
|
|
|
962
1096
|
return
|
|
963
1097
|
if sys.argv[1] in {"--resume", "--resume-leased"}:
|
|
964
1098
|
with contextlib.redirect_stdout(sys.stderr):
|
|
1099
|
+
if len(sys.argv) > 4 and sys.argv[4]:
|
|
1100
|
+
_verify_recovery_environment(Path(sys.argv[2]).resolve(), sys.argv[4])
|
|
965
1101
|
reply = _resume_worker(Path(sys.argv[2]).resolve(), stopped if sys.argv[1] == "--resume-leased" else None, sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else None)
|
|
966
1102
|
send(reply)
|
|
967
1103
|
return
|
|
@@ -11,6 +11,7 @@ import hashlib
|
|
|
11
11
|
import http.client
|
|
12
12
|
import ipaddress
|
|
13
13
|
import json
|
|
14
|
+
import math
|
|
14
15
|
import os
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
import plistlib
|
|
@@ -27,6 +28,42 @@ import time
|
|
|
27
28
|
STOP_SECONDS = 30.0
|
|
28
29
|
READY_SECONDS = 30.0
|
|
29
30
|
SNAPSHOT_ATTEMPTS = 4
|
|
31
|
+
# Bounds a native drain configured to wait indefinitely; the retained debt outlives it.
|
|
32
|
+
GATEWAY_DRAIN_CEILING = 4 * 3600.0
|
|
33
|
+
# One orphan-recovery attempt must fit its 660-second recovery RPC; its debt drives the next attempt.
|
|
34
|
+
RECOVERY_DRAIN_SECONDS = 300.0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@contextlib.contextmanager
|
|
38
|
+
def _native_home(home):
|
|
39
|
+
"""Resolve native per-profile configuration for one home in this single-purpose worker."""
|
|
40
|
+
previous = os.environ.get('HERMES_HOME')
|
|
41
|
+
os.environ['HERMES_HOME'] = str(home)
|
|
42
|
+
try:
|
|
43
|
+
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
|
|
44
|
+
except ImportError: # Older Agents resolve the home from the environment alone.
|
|
45
|
+
set_hermes_home_override = None
|
|
46
|
+
token = set_hermes_home_override(home) if set_hermes_home_override else None
|
|
47
|
+
try:
|
|
48
|
+
yield
|
|
49
|
+
finally:
|
|
50
|
+
if token is not None:
|
|
51
|
+
reset_hermes_home_override(token)
|
|
52
|
+
if previous is None:
|
|
53
|
+
os.environ.pop('HERMES_HOME', None)
|
|
54
|
+
else:
|
|
55
|
+
os.environ['HERMES_HOME'] = previous
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def drain_budget(pause, homes, ceiling=GATEWAY_DRAIN_CEILING):
|
|
59
|
+
"""One shared drain budget: the longest native after-turn + stop-drain budget among the homes, bounded."""
|
|
60
|
+
budget = 0.0
|
|
61
|
+
for home in sorted({str(home) for home in homes}):
|
|
62
|
+
with _native_home(home):
|
|
63
|
+
native = float(pause._drain_budget())
|
|
64
|
+
# A native wait-indefinitely budget (inf or NaN) takes the ceiling before any comparison.
|
|
65
|
+
budget = max(budget, native if math.isfinite(native) else ceiling)
|
|
66
|
+
return min(budget, ceiling)
|
|
30
67
|
|
|
31
68
|
|
|
32
69
|
@contextlib.contextmanager
|
|
@@ -640,6 +677,10 @@ def _start(entry, pause):
|
|
|
640
677
|
raise RuntimeError(f'{_name(entry)} supervisor failed to start its backend.')
|
|
641
678
|
|
|
642
679
|
|
|
680
|
+
class GatewayDraining(RuntimeError):
|
|
681
|
+
"""An acknowledged native drain is still within its native budget: progress, not a recovery failure."""
|
|
682
|
+
|
|
683
|
+
|
|
643
684
|
class ServiceRecovery:
|
|
644
685
|
"""Companion to the native pause token; all calls hold its existing checkout lock."""
|
|
645
686
|
def __init__(self, root, home, records, identity, pause):
|
|
@@ -825,7 +866,7 @@ class ServiceRecovery:
|
|
|
825
866
|
owed = next(e for e in self.state['entries'] if _service_key(e) == _service_key(entry))
|
|
826
867
|
owed['phase'] = 'retiring'
|
|
827
868
|
if acknowledged:
|
|
828
|
-
owed
|
|
869
|
+
owed.update(drain_acknowledged=True, drain_acknowledged_at=time.time())
|
|
829
870
|
self.save()
|
|
830
871
|
|
|
831
872
|
def _gateway_candidate(self, entry):
|
|
@@ -864,14 +905,27 @@ class ServiceRecovery:
|
|
|
864
905
|
for pid, p in processes.items()
|
|
865
906
|
if int(pid) != entry['service_pid'] or int(pid) == entry['pid'])
|
|
866
907
|
|
|
867
|
-
def gateway_deadline(self):
|
|
868
|
-
|
|
908
|
+
def gateway_deadline(self, homes=None, ceiling=GATEWAY_DRAIN_CEILING):
|
|
909
|
+
if homes is None:
|
|
910
|
+
homes = [e['home'] for e in self.state['entries'] if e['purpose'] == 'gateway']
|
|
911
|
+
return time.monotonic() + drain_budget(self.pause, homes, ceiling)
|
|
912
|
+
|
|
913
|
+
def _drain_progressing(self, entry):
|
|
914
|
+
"""Live recorded writers still finishing an acknowledged drain within the native budget."""
|
|
915
|
+
if not entry.get('drain_acknowledged') or not self._gateway_writers_live(entry):
|
|
916
|
+
return False
|
|
917
|
+
now = time.time()
|
|
918
|
+
if not isinstance(entry.get('drain_acknowledged_at'), (int, float)):
|
|
919
|
+
entry['drain_acknowledged_at'] = now # Older custody has no time; its native budget starts when first observed.
|
|
920
|
+
self.save()
|
|
921
|
+
return 0 <= now - entry['drain_acknowledged_at'] < drain_budget(self.pause, [entry['home']])
|
|
869
922
|
|
|
870
923
|
def settle_gateway(self, entry, stopped, *, deadline=None):
|
|
871
924
|
owed = next(e for e in self.state['entries'] if _service_key(e) == _service_key(entry))
|
|
872
925
|
self._settle_gateway(owed, stopped, deadline=deadline)
|
|
873
926
|
|
|
874
|
-
def _settle_gateway(self, entry, stopped=None, *, deadline=None):
|
|
927
|
+
def _settle_gateway(self, entry, stopped=None, *, deadline=None, ready=None):
|
|
928
|
+
"""Stop the recorded gateway; True when ``ready`` adopts a verified successor after the drain instead."""
|
|
875
929
|
if not self._gateway_writers_live(entry) and not any(_service_pid(entry)):
|
|
876
930
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
877
931
|
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
@@ -880,9 +934,11 @@ class ServiceRecovery:
|
|
|
880
934
|
return
|
|
881
935
|
stopped = stopped or threading.Event()
|
|
882
936
|
if deadline is None:
|
|
883
|
-
deadline = self.gateway_deadline()
|
|
937
|
+
deadline = self.gateway_deadline([entry['home']], RECOVERY_DRAIN_SECONDS)
|
|
884
938
|
while True:
|
|
885
939
|
if stopped.is_set() or time.monotonic() >= deadline:
|
|
940
|
+
if not stopped.is_set() and self._drain_progressing(entry):
|
|
941
|
+
raise GatewayDraining(f'{_name(entry)} gateway drain remains owed while its acknowledged native drain finishes; recovery will retry.')
|
|
886
942
|
raise RuntimeError(f'{_name(entry)} gateway drain remains owed; retry Agent update recovery.')
|
|
887
943
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
888
944
|
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
@@ -891,6 +947,8 @@ class ServiceRecovery:
|
|
|
891
947
|
raise RuntimeError(f'{_name(entry)} gateway drain remains owed; retry Agent update recovery.')
|
|
892
948
|
stopped.wait(.05)
|
|
893
949
|
continue
|
|
950
|
+
if ready is not None and ready():
|
|
951
|
+
return True # The original drain finished under its supervisor; never drain or stop a ready successor.
|
|
894
952
|
entry['runtime_fence_requested'] = True
|
|
895
953
|
self.save()
|
|
896
954
|
with gateway_fence(entry) as fence:
|
|
@@ -929,14 +987,14 @@ class ServiceRecovery:
|
|
|
929
987
|
raise RuntimeError(f'{_name(entry)} repeatedly respawned during drain; recovery remains owed.')
|
|
930
988
|
retired = {**entry.get('retired_processes', {}), **entry['processes']}
|
|
931
989
|
entry.update(candidate, retired_processes=retired, phase='retiring',
|
|
932
|
-
drain_acknowledged=False, settle_attempts=attempts)
|
|
990
|
+
drain_acknowledged=False, drain_acknowledged_at=None, settle_attempts=attempts)
|
|
933
991
|
self.save() # Successor custody precedes its cooperative lifecycle request.
|
|
934
992
|
verify_processes(entry, self.records)
|
|
935
993
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
936
994
|
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
937
995
|
if not self.pause._ask_to_drain(entry):
|
|
938
996
|
raise RuntimeError(f'{_name(entry)} successor did not acknowledge cooperative drain; recovery remains owed.')
|
|
939
|
-
entry
|
|
997
|
+
entry.update(drain_acknowledged=True, drain_acknowledged_at=time.time())
|
|
940
998
|
self.save()
|
|
941
999
|
stopped.wait(.05)
|
|
942
1000
|
|
|
@@ -946,7 +1004,7 @@ class ServiceRecovery:
|
|
|
946
1004
|
whole, why = self.records.tree_is_whole(self.state['tree'], self.root)
|
|
947
1005
|
if not whole or self.state.get('sync_failed'):
|
|
948
1006
|
raise RuntimeError('Backend recovery remains owed until source/dependency repair completes: ' + why)
|
|
949
|
-
failures = []
|
|
1007
|
+
failures, draining = [], True
|
|
950
1008
|
for entry in list(self.state['entries']):
|
|
951
1009
|
try:
|
|
952
1010
|
if self._ready(entry, ledger):
|
|
@@ -963,8 +1021,11 @@ class ServiceRecovery:
|
|
|
963
1021
|
continue
|
|
964
1022
|
if entry['purpose'] == 'gateway':
|
|
965
1023
|
if gateway_deadline is None:
|
|
966
|
-
gateway_deadline = self.gateway_deadline()
|
|
967
|
-
self._settle_gateway(entry, deadline=gateway_deadline)
|
|
1024
|
+
gateway_deadline = self.gateway_deadline(ceiling=RECOVERY_DRAIN_SECONDS)
|
|
1025
|
+
if self._settle_gateway(entry, deadline=gateway_deadline, ready=lambda entry=entry: self._ready(entry, ledger)):
|
|
1026
|
+
self.state['entries'].remove(entry)
|
|
1027
|
+
self.save()
|
|
1028
|
+
continue
|
|
968
1029
|
if not _service_pid(entry)[1]:
|
|
969
1030
|
_start(entry, self.pause)
|
|
970
1031
|
self._wait_ready(entry, ledger)
|
|
@@ -984,9 +1045,11 @@ class ServiceRecovery:
|
|
|
984
1045
|
_start(entry, self.pause)
|
|
985
1046
|
self._wait_ready(entry, ledger)
|
|
986
1047
|
except Exception as exc:
|
|
1048
|
+
draining = draining and isinstance(exc, GatewayDraining)
|
|
987
1049
|
failures.append(str(exc))
|
|
988
1050
|
if failures:
|
|
989
|
-
|
|
1051
|
+
# Sibling obligations recover independently; only an all-draining remainder is progress.
|
|
1052
|
+
raise (GatewayDraining if draining else RuntimeError)('; '.join(failures))
|
|
990
1053
|
|
|
991
1054
|
def _wait_ready(self, entry, ledger):
|
|
992
1055
|
deadline = time.monotonic() + READY_SECONDS
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""The shared allowlist for native/resident context reads. Never includes prompt bodies or paths."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import math
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
CATEGORIES = {'system_prompt', 'tool_definitions', 'rules', 'skills', 'mcp', 'subagent_definitions', 'memory', 'conversation'}
|
|
8
|
+
STATUSES = {'loaded', 'truncated', 'flagged', 'shadowed', 'blocked', 'empty', 'unreadable', 'suppressed'}
|
|
9
|
+
FILE_NAMES = {'AGENTS.md', 'SOUL.md', '.hermes.md', 'CLAUDE.md', 'GEMINI.md', 'CONTEXT.md'}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def number(value):
|
|
13
|
+
return value if type(value) in (int, float) and 0 <= value <= 2**53 - 1 and math.isfinite(value) and int(value) == value else None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def unavailable(reason='unavailable') -> dict:
|
|
17
|
+
return {'available': False, 'reason': reason, 'used_tokens': None, 'window_tokens': None,
|
|
18
|
+
'source': None, 'estimated': None, 'estimated_total': None, 'categories': [], 'files': [],
|
|
19
|
+
'truncated': False, 'current_turn_output_tokens': None, 'last_turn_output_tokens': None}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def project(payload, *, usage=None, running=False) -> dict:
|
|
23
|
+
if not isinstance(payload, dict):
|
|
24
|
+
return unavailable('unsupported')
|
|
25
|
+
rows = payload.get('categories')
|
|
26
|
+
if not isinstance(rows, list) or not rows:
|
|
27
|
+
return unavailable('not_built')
|
|
28
|
+
maximum = number(payload.get('context_max')) or None
|
|
29
|
+
categories, seen = [], set()
|
|
30
|
+
for row in rows[:64]:
|
|
31
|
+
if not isinstance(row, dict) or not isinstance(row.get('id'), str) or row.get('id') not in CATEGORIES or row['id'] in seen:
|
|
32
|
+
continue
|
|
33
|
+
tokens = number(row.get('tokens'))
|
|
34
|
+
if tokens is None:
|
|
35
|
+
continue
|
|
36
|
+
seen.add(row['id'])
|
|
37
|
+
categories.append({'id': row['id'], 'tokens': int(tokens), 'percent': min(100, tokens / maximum * 100) if maximum else None, 'estimated': True})
|
|
38
|
+
if not categories:
|
|
39
|
+
return unavailable('not_built')
|
|
40
|
+
source = payload.get('context_source')
|
|
41
|
+
source = source if isinstance(source, str) and source in {'provider_usage', 'local_estimate', 'provider_usage_plus_estimate'} else None
|
|
42
|
+
files = payload.get('context_files')
|
|
43
|
+
files = files if isinstance(files, list) else []
|
|
44
|
+
safe_files = []
|
|
45
|
+
for row in files[:64]:
|
|
46
|
+
if not isinstance(row, dict):
|
|
47
|
+
continue
|
|
48
|
+
# Labels from owners can include the entire private directory. Keep known context basenames only.
|
|
49
|
+
name = re.split(r'[/\\]', str(row.get('path') or ''))[-1]
|
|
50
|
+
label = name if name in FILE_NAMES else row.get('label') if isinstance(row.get('label'), str) and row.get('label') in FILE_NAMES else 'Context file'
|
|
51
|
+
status = row.get('status') if isinstance(row.get('status'), str) and row.get('status') in STATUSES else 'unknown'
|
|
52
|
+
safe_files.append({'label': label, 'characters': number(row.get('chars')), 'tokens': number(row.get('est_tokens')),
|
|
53
|
+
'status': status, 'loaded': status in {'loaded', 'truncated', 'flagged'} if status != 'unknown' else None})
|
|
54
|
+
output = number(usage.get('last_turn_tokens')) if isinstance(usage, dict) else None
|
|
55
|
+
return {'available': True, 'reason': None, 'used_tokens': number(payload.get('context_used')), 'window_tokens': maximum,
|
|
56
|
+
'source': source, 'estimated': source != 'provider_usage' if source else None,
|
|
57
|
+
'estimated_total': number(payload.get('estimated_total')), 'categories': categories, 'files': safe_files,
|
|
58
|
+
'truncated': len(rows) > 64 or len(files) > 64,
|
|
59
|
+
'current_turn_output_tokens': output if running else None, 'last_turn_output_tokens': output if not running else None}
|