@maudecode/talaria-web 1.19.0 → 1.21.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 +309 -2
- package/dist/api/automation-router.js +28 -2
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +646 -24
- package/dist/api/chat-router.js +54 -167
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +54 -0
- package/dist/api/git-router.js +18 -5
- 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 +3 -3
- package/dist/api/session-visibility.js +2 -2
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +1868 -79
- package/dist/api/sessions-router.js +72 -43
- 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 +45 -21
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-router.d.ts +773 -39
- package/dist/api/tools-router.js +167 -45
- 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 +16 -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.d.ts +2 -0
- package/dist/redact.js +55 -16
- package/dist/redact.js.map +1 -1
- package/dist/release.js +5 -3
- package/dist/release.js.map +1 -1
- package/dist/runtime.js +118 -26
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +25 -21
- package/dist/server.js.map +1 -1
- package/dist/sessions/admission.d.ts +21 -0
- package/dist/sessions/admission.js +176 -0
- package/dist/sessions/admission.js.map +1 -0
- package/dist/sessions/anchor.d.ts +4 -1
- package/dist/sessions/anchor.js +9 -5
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +41 -3
- package/dist/sessions/background-tasks.js +110 -10
- 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/events.d.ts +3 -0
- package/dist/sessions/events.js +4 -0
- package/dist/sessions/events.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 +92 -4
- package/dist/sessions/gateway-sessions.js +762 -93
- 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 +12 -5
- package/dist/sessions/merge.js +65 -18
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +15 -4
- package/dist/sessions/prefix-index.js +35 -13
- package/dist/sessions/prefix-index.js.map +1 -1
- package/dist/sessions/prompt-queues.d.ts +36 -0
- package/dist/sessions/prompt-queues.js +318 -0
- package/dist/sessions/prompt-queues.js.map +1 -0
- 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/relay.d.ts +12 -1
- package/dist/sessions/relay.js +75 -17
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +132 -37
- package/dist/sessions/service.js +688 -160
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +2 -0
- package/dist/sessions/session.js +5 -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 +71 -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 +6 -1
- package/dist/sessions/store.js +68 -27
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +10 -7
- package/dist/sessions/streams.js +49 -14
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +11 -2
- package/dist/sessions/tool-display.js +45 -4
- 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 +27 -6
- package/dist/sessions/turn.js +186 -89
- 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/kanban.d.ts +10 -1
- package/dist/tools/kanban.js +73 -1
- package/dist/tools/kanban.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.d.ts +3 -1
- package/dist/tools/mcp.js +92 -1
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/memory.d.ts +28 -0
- package/dist/tools/memory.js +120 -14
- package/dist/tools/memory.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 +77 -9
- package/dist/tools/update-notifications.js +390 -46
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/updates.d.ts +29 -3
- package/dist/tools/updates.js +166 -34
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/managed-buffers.d.ts +58 -0
- package/dist/workspace/managed-buffers.js +76 -0
- package/dist/workspace/managed-buffers.js.map +1 -0
- 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 +18 -8
- 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 +30 -15
- 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 +246 -32
- package/sidecar/talaria_sidecar/agent_services.py +157 -34
- 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 +304 -30
- package/sidecar/talaria_sidecar/methods/kanban.py +50 -3
- package/sidecar/talaria_sidecar/methods/managed_buffers.py +110 -0
- package/sidecar/talaria_sidecar/methods/mcp.py +55 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +139 -11
- package/sidecar/talaria_sidecar/methods/outbound_drafts.py +165 -0
- 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 +240 -213
- package/static/dist/THIRD_PARTY_LICENSES.md +6 -22
- package/static/dist/assets/AppShell-c5989995.js +8 -0
- package/static/dist/assets/Button-nuaikybd.js +1 -0
- package/static/dist/assets/ChatPage-bfg4khph.js +6 -0
- package/static/dist/assets/ConnectTargets-k5wo9yo8.js +1 -0
- package/static/dist/assets/Dialog-o8vo2aws.js +1 -0
- package/static/dist/assets/ExtensionRoute-l1yjrso4.js +1 -0
- package/static/dist/assets/Field-j7o8cfps.js +1 -0
- package/static/dist/assets/HubRoute-efnwe4xz.js +2 -0
- package/static/dist/assets/LinkCheckContext-ix6zqqkk.js +1 -0
- package/static/dist/assets/Markdown-clqf5m22.js +2 -0
- package/static/dist/assets/MarkdownRenderer-ccgqrza3.js +302 -0
- package/static/dist/assets/MarkdownRenderer-i9o6nr38.css +1 -0
- package/static/dist/assets/OAuthSignIn-h7bjaqp6.js +1 -0
- package/static/dist/assets/ResourceSwitch-oai2zqaj.js +1 -0
- package/static/dist/assets/RightPanel-ho161a45.js +1 -0
- package/static/dist/assets/Select-d1g5a8bm.js +1 -0
- package/static/dist/assets/SessionListPanel-i7kaokhi.js +1 -0
- package/static/dist/assets/SettingsLayout-lnecm87w.js +1 -0
- package/static/dist/assets/States-easntmry.js +1 -0
- package/static/dist/assets/TerminalPanel-lxhwd4jl.js +16 -0
- package/static/dist/assets/Toaster-l4sciy8t.js +1 -0
- package/static/dist/assets/_app-mqexqbg8.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-n797jp72.js +1 -0
- package/static/dist/assets/_app.index-ne43mdw2.js +1 -0
- package/static/dist/assets/_app.insights-fqonovb4.js +1 -0
- package/static/dist/assets/_app.kanban-kysliv19.js +1 -0
- package/static/dist/assets/_app.logs-febut82r.js +1 -0
- package/static/dist/assets/_app.memory-ha86oj1c.js +1 -0
- package/static/dist/assets/_app.profiles-cnu3gxxq.js +1 -0
- package/static/dist/assets/_app.session._sessionId-ifzjpcgn.js +1 -0
- package/static/dist/assets/_app.settings-nmakdiaf.js +1 -0
- package/static/dist/assets/_app.settings._section-djglnjmi.js +3 -0
- package/static/dist/assets/_app.skills-f3wad8yo.js +1 -0
- package/static/dist/assets/_app.tasks-l10py1c0.js +1 -0
- package/static/dist/assets/_app.todos-bml1m3r1.js +1 -0
- package/static/dist/assets/_app.workspaces-f3d066lx.js +1 -0
- package/static/dist/assets/abnfDiagram-VCTEODGH-i53jc4yp.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-e3bv5m6f.js +1 -0
- package/static/dist/assets/architectureDiagram-5GKGNRK7-pakekxu2.js +36 -0
- package/static/dist/assets/archive-ihqi7z2x.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-bc6bo1n6.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-btvwk2qx.js} +1 -1
- package/static/dist/assets/channel-jn4f8443.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-koouqbut.js → chunk-4HAMMTFA-dlwab11c.js} +20 -20
- package/static/dist/assets/{chunk-75Z2AOVW-bl4bhdnt.js → chunk-75Z2AOVW-dp5gh7i8.js} +1 -1
- package/static/dist/assets/chunk-DU6HZSFF-bi06zl1c.js +128 -0
- package/static/dist/assets/{chunk-F27PBJKO-d8xxi0zi.js → chunk-F27PBJKO-kvv1rnlh.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-ji0rx9by.js} +6 -6
- package/static/dist/assets/{chunk-GVQU2GXP-djn6gbyu.js → chunk-GVQU2GXP-nmz0j82p.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-vw4p5p7o.js → chunk-IMKFNOWR-kmi1qx88.js} +5 -5
- package/static/dist/assets/{chunk-L3NEJ4N5-n1hj77q8.js → chunk-L3NEJ4N5-xhb7mebj.js} +1 -1
- package/static/dist/assets/chunk-OSK3NFVY-5a9sgscq.js +10 -0
- package/static/dist/assets/{chunk-P2QGCYS3-onf1hz6c.js → chunk-P2QGCYS3-dfezp4vu.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-m8sqn7cs.js → chunk-POPQ4Y6H-gd2vq3c0.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-ek4smc8x.js → chunk-PWAF6VOD-wvw2nksf.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-g9gfvefo.js → chunk-SHT3W25Y-f58q97px.js} +13 -13
- package/static/dist/assets/{chunk-SVP7TREG-f9nfv2cu.js → chunk-SVP7TREG-abgwpyz9.js} +4 -4
- package/static/dist/assets/{chunk-TICWLB2K-bnk3m1mq.js → chunk-TICWLB2K-h4sbs8ds.js} +6 -6
- package/static/dist/assets/{chunk-XXDRQBXY-n40pf9vy.js → chunk-XXDRQBXY-jkmnqu65.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-dzrw66se.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-dzrw66se.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/completionAudio-ce86msbu.js +1 -0
- package/static/dist/assets/copied-bz3gkazh.js +1 -0
- package/static/dist/assets/copy-m9h56qa8.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-g081vffs.js +1 -0
- package/static/dist/assets/cynefinDiagram-5FMLGOSQ-odxvjesk.js +62 -0
- package/static/dist/assets/cytoscape.esm-fjn2algp.js +321 -0
- package/static/dist/assets/dagre-GXQ25YYZ-cpdwzjs4.js +4 -0
- package/static/dist/assets/dagre-o5jmjz46.js +1 -0
- package/static/dist/assets/{diagram-S7CK7UJ4-m6aeoe7c.js → diagram-S7CK7UJ4-clv5mxvu.js} +4 -4
- package/static/dist/assets/diagram-UQ7AKVKN-m2ia1mbf.js +41 -0
- package/static/dist/assets/{diagram-VSXAHHWV-hbawi7hn.js → diagram-VSXAHHWV-ea6zv636.js} +1 -1
- package/static/dist/assets/diagram-VX7I27RA-oqlef685.js +24 -0
- package/static/dist/assets/diagram-Z3DM3KII-kjubcbwu.js +24 -0
- package/static/dist/assets/dist-carq1azj.js +44 -0
- package/static/dist/assets/dist-crc46di9.js +7 -0
- package/static/dist/assets/{dist-c4c2m3kv.js → dist-nb670eu6.js} +1 -1
- package/static/dist/assets/ebnfDiagram-PWID7BFC-fg0zri3e.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-eb7pmk3x.js +99 -0
- package/static/dist/assets/{erb-idlyfheg.js → erb-flwsv146.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-gvi1fxhn.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-abekab15.js +1 -0
- package/static/dist/assets/folder-plus-ksaons88.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ma6jxj5i.js → ganttDiagram-EL5Y4UJY-jmisowrc.js} +1 -1
- package/static/dist/assets/{git-rebase-d9lpfpbn.js → git-rebase-bli19aoq.js} +1 -1
- package/static/dist/assets/gitGraph-4MIJSDKK-m7kt3u6e.js +1 -0
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-hzltvsod.js → gitGraphDiagram-WWUBYQGX-nq7vfzh2.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-gcu017ay.js +1 -0
- package/static/dist/assets/host-ipp4e84c.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-d6vbxlra.js +13 -0
- package/static/dist/assets/index-ey6qo0zx.css +2 -0
- package/static/dist/assets/info-A6RAGUB7-idazwfqe.js +1 -0
- package/static/dist/assets/infoDiagram-27XIBGKW-bb9jh8gl.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-e7bnwq7h.js → ishikawaDiagram-5VMMS53U-nqc132rv.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-fpvnhy44.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-ndzqm6fu.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-javud235.js +1 -0
- package/static/dist/assets/{line-h0ojzsvs.js → line-g625e7cj.js} +1 -1
- package/static/dist/assets/linear-jlwrvvy6.js +1 -0
- package/static/dist/assets/link-gfdaho08.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-iv6yq4xf.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-cwj5cl6k.js +1 -0
- package/static/dist/assets/mermaid-parser.core-plzkuzov.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-ojrgs569.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-ff4emacu.js +1 -0
- package/static/dist/assets/packet-AYTQ26CC-gyaf9s8h.js +1 -0
- package/static/dist/assets/pegDiagram-XKGWAZYB-bf6xj8mq.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-f5ymzelo.js +1 -0
- package/static/dist/assets/pieDiagram-E7YTZNPT-d0qjl3zi.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-oqy1mras.js} +1 -1
- package/static/dist/assets/queryKeys-x8fjxhut.js +9 -0
- package/static/dist/assets/{r-o3r9c7ao.js → r-epfzuw6q.js} +1 -1
- package/static/dist/assets/radar-RG4KPBEZ-b6jcjvda.js +1 -0
- package/static/dist/assets/railroad-74A4TZTK-e3a6lk5k.js +1 -0
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ff5hocrx.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-exkhyw4n.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-jefk9b7c.js +1 -0
- package/static/dist/assets/railroadDiagram-O6MQD6OU-e4amks1i.js +1 -0
- package/static/dist/assets/{razor-ilc585yr.js → razor-pea1u1d0.js} +1 -1
- package/static/dist/assets/refresh-cw-lfp4u1oh.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-c77k1e2y.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-oa1cc52s.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-j20gqt22.js} +11 -11
- package/static/dist/assets/settings_section_extensions_title-fadc7o65.js +1 -0
- package/static/dist/assets/share._token-kmfoflw6.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-g5jkzd9k.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-co2ghkdp.js +1 -0
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-faw1opgh.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-m30cktqe.js +1 -0
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hfil433g.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-liuep6fl.js} +8 -8
- package/static/dist/assets/toast-zmb35u3r.js +56 -0
- package/static/dist/assets/treeView-Q6P3EWNA-np5d2jv2.js +1 -0
- package/static/dist/assets/treemap-WGGIJYW6-cmpltxh1.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-f1udzsjf.js +1 -0
- package/static/dist/assets/{useParams-gjc70qru.js → useParams-ierevvts.js} +1 -1
- package/static/dist/assets/{useSearch-e6ae539u.js → useSearch-i7nr9ypl.js} +1 -1
- package/static/dist/assets/vennDiagram-4TSXK5OY-b2g42qrg.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-lb0eqbff.js +1 -0
- package/static/dist/assets/wardleyDiagram-VM6X3IG4-ermwaqha.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-dll0jldk.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
|
@@ -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
|
|
@@ -127,12 +164,15 @@ def snapshot(entry, *, records=None, expected=None):
|
|
|
127
164
|
from gateway.status import get_process_start_time, _pid_exists
|
|
128
165
|
service, pid = entry.get('service_pid', entry['pid']), entry['pid']
|
|
129
166
|
anchors = {service, pid}
|
|
130
|
-
observed =
|
|
167
|
+
observed = {**entry.get('departed_processes', {}), **(expected or {})}
|
|
131
168
|
seen_parents = {int(p): proof['parent'] for p, proof in observed.items() if 'parent' in proof}
|
|
132
|
-
departed = set()
|
|
169
|
+
departed = set(map(int, entry.get('departed_processes', {})))
|
|
133
170
|
|
|
134
171
|
def exited(p):
|
|
135
|
-
|
|
172
|
+
live = _pid_exists(p)
|
|
173
|
+
if live is None:
|
|
174
|
+
raise RuntimeError(f'{_name(entry)} process {p} liveness is unreadable; source was not changed.')
|
|
175
|
+
if live is False:
|
|
136
176
|
if p in anchors:
|
|
137
177
|
raise RuntimeError(f'{_name(entry)} anchor process {p} disappeared during discovery; source was not changed.')
|
|
138
178
|
departed.add(p)
|
|
@@ -142,7 +182,7 @@ def snapshot(entry, *, records=None, expected=None):
|
|
|
142
182
|
def inventory():
|
|
143
183
|
parents = _process_table()
|
|
144
184
|
if service not in _ancestors(pid, parents):
|
|
145
|
-
raise RuntimeError(f'{_name(entry)} does not own backend/gateway PID {pid}.')
|
|
185
|
+
raise RuntimeError(f'{_name(entry)} identity/ancestry changed: does not own backend/gateway PID {pid}.')
|
|
146
186
|
if service in _ancestors(os.getpid(), parents):
|
|
147
187
|
raise RuntimeError(f'{_name(entry)} owns the updater or an ancestor; source was not changed.')
|
|
148
188
|
for p, parent in seen_parents.items():
|
|
@@ -151,6 +191,10 @@ def snapshot(entry, *, records=None, expected=None):
|
|
|
151
191
|
continue
|
|
152
192
|
raise RuntimeError(f'{_name(entry)} process {p} identity/ancestry changed during discovery; source was not changed.')
|
|
153
193
|
descendants = _descendants(service, parents)
|
|
194
|
+
# Successor retries cannot discard a live writer from a previously observed tree.
|
|
195
|
+
for p in seen_parents.keys() - descendants - departed:
|
|
196
|
+
if not exited(p):
|
|
197
|
+
raise RuntimeError(f'{_name(entry)} process {p} remains live outside the attested tree; recovery remains owed.')
|
|
154
198
|
seen_parents.update({p: parents[p] for p in descendants})
|
|
155
199
|
# Zombies may remain in ps. Recheck departed PIDs at every inventory so
|
|
156
200
|
# neither a recycled PID nor unknown liveness can be silently excluded.
|
|
@@ -168,6 +212,8 @@ def snapshot(entry, *, records=None, expected=None):
|
|
|
168
212
|
if exited(p):
|
|
169
213
|
return None
|
|
170
214
|
raise RuntimeError(f'{_name(entry)} process {p} birth identity is live or unreadable; source was not changed.')
|
|
215
|
+
if exited(p):
|
|
216
|
+
return None
|
|
171
217
|
if any(proof.get(key) != value for key, value in observed.get(str(p), {}).items()):
|
|
172
218
|
raise RuntimeError(f'{_name(entry)} process {p} identity/ancestry changed during discovery; source was not changed.')
|
|
173
219
|
observed[str(p)] = proof
|
|
@@ -182,6 +228,8 @@ def snapshot(entry, *, records=None, expected=None):
|
|
|
182
228
|
_, final = inventory()
|
|
183
229
|
if live & departed or remaining != live or final != live:
|
|
184
230
|
continue
|
|
231
|
+
if departed:
|
|
232
|
+
entry['departed_processes'] = {str(p): observed.get(str(p), {'parent': seen_parents[p]}) for p in departed}
|
|
185
233
|
return proofs
|
|
186
234
|
raise RuntimeError(f'{_name(entry)} process inventory kept changing after {SNAPSHOT_ATTEMPTS} samples; retry when descendants settle. Source was not changed and recovery remains owed.')
|
|
187
235
|
|
|
@@ -366,8 +414,23 @@ def _service_pid(entry):
|
|
|
366
414
|
|
|
367
415
|
def verify_processes(entry, records, *, stopping=False, fenced=False):
|
|
368
416
|
from gateway.status import get_process_start_time, _pid_exists
|
|
417
|
+
if not stopping:
|
|
418
|
+
# Reuse discovery's bounded proof without granting permission to lose an anchor.
|
|
419
|
+
candidate = dict(entry)
|
|
420
|
+
for boundary in range(2):
|
|
421
|
+
_, service_pid = _service_pid(entry)
|
|
422
|
+
if service_pid != entry['service_pid']:
|
|
423
|
+
raise RuntimeError(f'{_name(entry)} supervisor respawned during quiescence; source was not changed.')
|
|
424
|
+
if 'config_stamp' in entry and _config_stamp(entry) != entry['config_stamp']:
|
|
425
|
+
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
426
|
+
if boundary == 0:
|
|
427
|
+
candidate['processes'] = snapshot(candidate, records=records, expected=entry['processes'])
|
|
428
|
+
entry.update(processes=candidate['processes'])
|
|
429
|
+
if candidate.get('departed_processes'):
|
|
430
|
+
entry['departed_processes'] = candidate['departed_processes']
|
|
431
|
+
return True
|
|
369
432
|
parents = _process_table()
|
|
370
|
-
departed = set()
|
|
433
|
+
departed = set(map(int, entry.get('departed_processes', {})))
|
|
371
434
|
for pid, expected in entry['processes'].items():
|
|
372
435
|
pid = int(pid)
|
|
373
436
|
if _pid_exists(pid) is False:
|
|
@@ -405,7 +468,6 @@ def verify_processes(entry, records, *, stopping=False, fenced=False):
|
|
|
405
468
|
|
|
406
469
|
def bind_processes(entry, records):
|
|
407
470
|
if entry.get('processes'):
|
|
408
|
-
entry['processes'] = snapshot(entry, records=records, expected=entry['processes'])
|
|
409
471
|
verify_processes(entry, records)
|
|
410
472
|
|
|
411
473
|
|
|
@@ -640,6 +702,10 @@ def _start(entry, pause):
|
|
|
640
702
|
raise RuntimeError(f'{_name(entry)} supervisor failed to start its backend.')
|
|
641
703
|
|
|
642
704
|
|
|
705
|
+
class GatewayDraining(RuntimeError):
|
|
706
|
+
"""An acknowledged native drain is still within its native budget: progress, not a recovery failure."""
|
|
707
|
+
|
|
708
|
+
|
|
643
709
|
class ServiceRecovery:
|
|
644
710
|
"""Companion to the native pause token; all calls hold its existing checkout lock."""
|
|
645
711
|
def __init__(self, root, home, records, identity, pause):
|
|
@@ -672,8 +738,20 @@ class ServiceRecovery:
|
|
|
672
738
|
or ('runtime_revision' in transaction and not re.fullmatch(r'[a-f0-9]{40}', str(transaction['runtime_revision'])))):
|
|
673
739
|
raise RuntimeError('Service recovery transaction has an unknown identity or format; its evidence is retained.')
|
|
674
740
|
|
|
741
|
+
operation = self.state.get('update_operation')
|
|
742
|
+
if operation is not None and (
|
|
743
|
+
not isinstance(operation, dict)
|
|
744
|
+
or not re.fullmatch(r'[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}', str(operation.get('operation_id', '')))
|
|
745
|
+
or any(not re.fullmatch(r'[a-f0-9]{40}', str(operation.get(key, ''))) for key in ('baseline_revision', 'target_revision'))
|
|
746
|
+
or ('attempt_error' in operation and (not isinstance(operation['attempt_error'], str) or len(operation['attempt_error']) > 2000))
|
|
747
|
+
or ('source_moved' in operation and not isinstance(operation['source_moved'], bool))
|
|
748
|
+
or ('failed_stage' in operation and operation['failed_stage'] not in {'install', 'gateway_restart', 'agent_ready'})
|
|
749
|
+
or operation.get('stage') not in {'install', 'gateway_restart', 'agent_ready'}
|
|
750
|
+
or ('recovered_revision' in operation and not re.fullmatch(r'[a-f0-9]{40}', str(operation['recovered_revision'])))):
|
|
751
|
+
raise RuntimeError('Update operation correlation is malformed; its evidence is retained.')
|
|
752
|
+
|
|
675
753
|
def save(self, token=None):
|
|
676
|
-
if not self.state['entries'] and not self.state.get('sync_failed') and not self.state.get('transaction'):
|
|
754
|
+
if not self.state['entries'] and not self.state.get('sync_failed') and not self.state.get('transaction') and not self.state.get('update_operation'):
|
|
677
755
|
if self.path.exists():
|
|
678
756
|
self.path.unlink()
|
|
679
757
|
self._sync_directory()
|
|
@@ -693,9 +771,9 @@ class ServiceRecovery:
|
|
|
693
771
|
with contextlib.suppress(FileNotFoundError):
|
|
694
772
|
os.unlink(temporary)
|
|
695
773
|
|
|
696
|
-
def _sync_directory(self):
|
|
774
|
+
def _sync_directory(self, directory=None):
|
|
697
775
|
if os.name != 'nt':
|
|
698
|
-
fd = os.open(self.path.parent, os.O_RDONLY)
|
|
776
|
+
fd = os.open(directory if directory is not None else self.path.parent, os.O_RDONLY)
|
|
699
777
|
try:
|
|
700
778
|
os.fsync(fd)
|
|
701
779
|
finally:
|
|
@@ -726,10 +804,17 @@ class ServiceRecovery:
|
|
|
726
804
|
self.records.write(token)
|
|
727
805
|
self.save(token)
|
|
728
806
|
|
|
807
|
+
def verify_processes(self, entry, **permissions):
|
|
808
|
+
owed = next(e for e in self.state['entries'] if _service_key(e) == _service_key(entry))
|
|
809
|
+
result = verify_processes(owed, self.records, **permissions)
|
|
810
|
+
self.save() # Updated custody must precede the next lifecycle effect.
|
|
811
|
+
return result
|
|
812
|
+
|
|
729
813
|
def stop(self, entry, stopped):
|
|
730
814
|
owed = next(e for e in self.state['entries'] if _service_key(e) == _service_key(entry))
|
|
731
|
-
verify_processes(owed
|
|
815
|
+
self.verify_processes(owed)
|
|
732
816
|
backend_request(owed)
|
|
817
|
+
self.verify_processes(owed)
|
|
733
818
|
permit = backend_request(owed, 'prepare')
|
|
734
819
|
if permit.get('ok') is not True or permit.get('idle') is not True or not isinstance(permit.get('token'), str):
|
|
735
820
|
if owed['phase'] == 'recorded':
|
|
@@ -742,7 +827,7 @@ class ServiceRecovery:
|
|
|
742
827
|
except BaseException:
|
|
743
828
|
backend_request(owed, 'cancel', permit['token'])
|
|
744
829
|
raise
|
|
745
|
-
verify_processes(owed
|
|
830
|
+
self.verify_processes(owed)
|
|
746
831
|
if backend_request(owed, 'commit', permit['token']).get('ok') is not True:
|
|
747
832
|
raise RuntimeError(f'{_name(owed)} did not commit its backend retirement; recovery remains owed.')
|
|
748
833
|
owed['backend_committed'] = True
|
|
@@ -753,14 +838,14 @@ class ServiceRecovery:
|
|
|
753
838
|
# Disarm through the original manager before its KeepAlive can admit a successor.
|
|
754
839
|
owed['backend_stop_requested'] = True
|
|
755
840
|
self.save()
|
|
756
|
-
verify_processes(owed,
|
|
841
|
+
self.verify_processes(owed, stopping=stopping)
|
|
757
842
|
if _config_stamp(owed) != owed['config_stamp']:
|
|
758
843
|
raise RuntimeError(f'{_name(owed)} service configuration changed before backend stop; recovery remains owed.')
|
|
759
844
|
if stopped.is_set():
|
|
760
845
|
raise RuntimeError(f'{_name(owed)} backend stop was cancelled; recovery remains owed.')
|
|
761
846
|
self.pause._disarm(service_entry(owed))
|
|
762
847
|
wait_stopped(owed, self.records, stopped)
|
|
763
|
-
verify_processes(owed,
|
|
848
|
+
self.verify_processes(owed, stopping=True)
|
|
764
849
|
owed['phase'] = 'stopped'
|
|
765
850
|
self.save()
|
|
766
851
|
|
|
@@ -770,15 +855,15 @@ class ServiceRecovery:
|
|
|
770
855
|
raise RuntimeError(f'{_name(entry)} legacy shutdown remains owed; no signal was replayed.')
|
|
771
856
|
if _config_stamp(owed) != owed['config_stamp']:
|
|
772
857
|
raise RuntimeError(f'{_name(entry)} configuration changed before legacy refresh.')
|
|
773
|
-
verify_processes(owed
|
|
858
|
+
self.verify_processes(owed)
|
|
774
859
|
verify_listener(owed)
|
|
775
860
|
owed.update(legacy_refresh=True, phase='refreshing')
|
|
776
861
|
self.save() # Older readers reject this phase and retain debt; no reader replays its signal.
|
|
777
|
-
verify_processes(owed
|
|
862
|
+
self.verify_processes(owed)
|
|
778
863
|
verify_listener(owed)
|
|
779
864
|
if _config_stamp(owed) != owed['config_stamp']:
|
|
780
865
|
raise RuntimeError(f'{_name(owed)} configuration changed before legacy refresh.')
|
|
781
|
-
verify_processes(owed
|
|
866
|
+
self.verify_processes(owed)
|
|
782
867
|
try:
|
|
783
868
|
if stopped.is_set():
|
|
784
869
|
raise InterruptedError('Legacy refresh was cancelled before interruption.')
|
|
@@ -825,7 +910,7 @@ class ServiceRecovery:
|
|
|
825
910
|
owed = next(e for e in self.state['entries'] if _service_key(e) == _service_key(entry))
|
|
826
911
|
owed['phase'] = 'retiring'
|
|
827
912
|
if acknowledged:
|
|
828
|
-
owed
|
|
913
|
+
owed.update(drain_acknowledged=True, drain_acknowledged_at=time.time())
|
|
829
914
|
self.save()
|
|
830
915
|
|
|
831
916
|
def _gateway_candidate(self, entry):
|
|
@@ -842,6 +927,8 @@ class ServiceRecovery:
|
|
|
842
927
|
if (_config_stamp(candidate) != entry['config_stamp']
|
|
843
928
|
or candidate.get('profile') != entry.get('profile')):
|
|
844
929
|
raise RuntimeError(f'{_name(entry)} successor configuration/profile changed; recovery remains owed.')
|
|
930
|
+
if entry.get('departed_processes'):
|
|
931
|
+
candidate['departed_processes'] = entry['departed_processes']
|
|
845
932
|
bind_processes(candidate, self.records)
|
|
846
933
|
parents = {int(pid): p['parent'] for pid, p in candidate['processes'].items()}
|
|
847
934
|
chain, pid = set(), candidate['pid']
|
|
@@ -853,7 +940,8 @@ class ServiceRecovery:
|
|
|
853
940
|
if chain | _descendants(candidate['pid'], parents) != set(parents):
|
|
854
941
|
raise RuntimeError(f'{_name(entry)} successor has unrelated descendants; recovery remains owed.')
|
|
855
942
|
for pid, process in candidate['processes'].items():
|
|
856
|
-
old = entry['processes'].get(pid) or entry.get('
|
|
943
|
+
old = (entry['processes'].get(pid) or entry.get('departed_processes', {}).get(pid)
|
|
944
|
+
or entry.get('retired_processes', {}).get(pid))
|
|
857
945
|
if old is not None and old != process:
|
|
858
946
|
raise RuntimeError(f'{_name(entry)} successor reused a recorded process identity; recovery remains owed.')
|
|
859
947
|
return candidate
|
|
@@ -864,14 +952,27 @@ class ServiceRecovery:
|
|
|
864
952
|
for pid, p in processes.items()
|
|
865
953
|
if int(pid) != entry['service_pid'] or int(pid) == entry['pid'])
|
|
866
954
|
|
|
867
|
-
def gateway_deadline(self):
|
|
868
|
-
|
|
955
|
+
def gateway_deadline(self, homes=None, ceiling=GATEWAY_DRAIN_CEILING):
|
|
956
|
+
if homes is None:
|
|
957
|
+
homes = [e['home'] for e in self.state['entries'] if e['purpose'] == 'gateway']
|
|
958
|
+
return time.monotonic() + drain_budget(self.pause, homes, ceiling)
|
|
959
|
+
|
|
960
|
+
def _drain_progressing(self, entry):
|
|
961
|
+
"""Live recorded writers still finishing an acknowledged drain within the native budget."""
|
|
962
|
+
if not entry.get('drain_acknowledged') or not self._gateway_writers_live(entry):
|
|
963
|
+
return False
|
|
964
|
+
now = time.time()
|
|
965
|
+
if not isinstance(entry.get('drain_acknowledged_at'), (int, float)):
|
|
966
|
+
entry['drain_acknowledged_at'] = now # Older custody has no time; its native budget starts when first observed.
|
|
967
|
+
self.save()
|
|
968
|
+
return 0 <= now - entry['drain_acknowledged_at'] < drain_budget(self.pause, [entry['home']])
|
|
869
969
|
|
|
870
970
|
def settle_gateway(self, entry, stopped, *, deadline=None):
|
|
871
971
|
owed = next(e for e in self.state['entries'] if _service_key(e) == _service_key(entry))
|
|
872
972
|
self._settle_gateway(owed, stopped, deadline=deadline)
|
|
873
973
|
|
|
874
|
-
def _settle_gateway(self, entry, stopped=None, *, deadline=None):
|
|
974
|
+
def _settle_gateway(self, entry, stopped=None, *, deadline=None, ready=None):
|
|
975
|
+
"""Stop the recorded gateway; True when ``ready`` adopts a verified successor after the drain instead."""
|
|
875
976
|
if not self._gateway_writers_live(entry) and not any(_service_pid(entry)):
|
|
876
977
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
877
978
|
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
@@ -880,9 +981,11 @@ class ServiceRecovery:
|
|
|
880
981
|
return
|
|
881
982
|
stopped = stopped or threading.Event()
|
|
882
983
|
if deadline is None:
|
|
883
|
-
deadline = self.gateway_deadline()
|
|
984
|
+
deadline = self.gateway_deadline([entry['home']], RECOVERY_DRAIN_SECONDS)
|
|
884
985
|
while True:
|
|
885
986
|
if stopped.is_set() or time.monotonic() >= deadline:
|
|
987
|
+
if not stopped.is_set() and self._drain_progressing(entry):
|
|
988
|
+
raise GatewayDraining(f'{_name(entry)} gateway drain remains owed while its acknowledged native drain finishes; recovery will retry.')
|
|
886
989
|
raise RuntimeError(f'{_name(entry)} gateway drain remains owed; retry Agent update recovery.')
|
|
887
990
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
888
991
|
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
@@ -891,6 +994,8 @@ class ServiceRecovery:
|
|
|
891
994
|
raise RuntimeError(f'{_name(entry)} gateway drain remains owed; retry Agent update recovery.')
|
|
892
995
|
stopped.wait(.05)
|
|
893
996
|
continue
|
|
997
|
+
if ready is not None and ready():
|
|
998
|
+
return True # The original drain finished under its supervisor; never drain or stop a ready successor.
|
|
894
999
|
entry['runtime_fence_requested'] = True
|
|
895
1000
|
self.save()
|
|
896
1001
|
with gateway_fence(entry) as fence:
|
|
@@ -908,7 +1013,7 @@ class ServiceRecovery:
|
|
|
908
1013
|
if pending:
|
|
909
1014
|
stopped.wait(.05)
|
|
910
1015
|
continue
|
|
911
|
-
if not verify_processes(entry,
|
|
1016
|
+
if not self.verify_processes(entry, stopping=True, fenced=True):
|
|
912
1017
|
stopped.wait(.05)
|
|
913
1018
|
continue
|
|
914
1019
|
if self._gateway_writers_live(entry) or _config_stamp(entry) != entry['config_stamp']:
|
|
@@ -929,14 +1034,14 @@ class ServiceRecovery:
|
|
|
929
1034
|
raise RuntimeError(f'{_name(entry)} repeatedly respawned during drain; recovery remains owed.')
|
|
930
1035
|
retired = {**entry.get('retired_processes', {}), **entry['processes']}
|
|
931
1036
|
entry.update(candidate, retired_processes=retired, phase='retiring',
|
|
932
|
-
drain_acknowledged=False, settle_attempts=attempts)
|
|
1037
|
+
drain_acknowledged=False, drain_acknowledged_at=None, settle_attempts=attempts)
|
|
933
1038
|
self.save() # Successor custody precedes its cooperative lifecycle request.
|
|
934
|
-
verify_processes(entry
|
|
1039
|
+
self.verify_processes(entry)
|
|
935
1040
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
936
1041
|
raise RuntimeError(f'{_name(entry)} service configuration changed; recovery remains owed.')
|
|
937
1042
|
if not self.pause._ask_to_drain(entry):
|
|
938
1043
|
raise RuntimeError(f'{_name(entry)} successor did not acknowledge cooperative drain; recovery remains owed.')
|
|
939
|
-
entry
|
|
1044
|
+
entry.update(drain_acknowledged=True, drain_acknowledged_at=time.time())
|
|
940
1045
|
self.save()
|
|
941
1046
|
stopped.wait(.05)
|
|
942
1047
|
|
|
@@ -946,7 +1051,7 @@ class ServiceRecovery:
|
|
|
946
1051
|
whole, why = self.records.tree_is_whole(self.state['tree'], self.root)
|
|
947
1052
|
if not whole or self.state.get('sync_failed'):
|
|
948
1053
|
raise RuntimeError('Backend recovery remains owed until source/dependency repair completes: ' + why)
|
|
949
|
-
failures = []
|
|
1054
|
+
failures, draining = [], True
|
|
950
1055
|
for entry in list(self.state['entries']):
|
|
951
1056
|
try:
|
|
952
1057
|
if self._ready(entry, ledger):
|
|
@@ -963,8 +1068,11 @@ class ServiceRecovery:
|
|
|
963
1068
|
continue
|
|
964
1069
|
if entry['purpose'] == 'gateway':
|
|
965
1070
|
if gateway_deadline is None:
|
|
966
|
-
gateway_deadline = self.gateway_deadline()
|
|
967
|
-
self._settle_gateway(entry, deadline=gateway_deadline)
|
|
1071
|
+
gateway_deadline = self.gateway_deadline(ceiling=RECOVERY_DRAIN_SECONDS)
|
|
1072
|
+
if self._settle_gateway(entry, deadline=gateway_deadline, ready=lambda entry=entry: self._ready(entry, ledger)):
|
|
1073
|
+
self.state['entries'].remove(entry)
|
|
1074
|
+
self.save()
|
|
1075
|
+
continue
|
|
968
1076
|
if not _service_pid(entry)[1]:
|
|
969
1077
|
_start(entry, self.pause)
|
|
970
1078
|
self._wait_ready(entry, ledger)
|
|
@@ -975,7 +1083,7 @@ class ServiceRecovery:
|
|
|
975
1083
|
raise RuntimeError(f'{_name(entry)} uncommitted retirement could not yet be cancelled; recovery remains owed.')
|
|
976
1084
|
self.stop(entry, threading.Event())
|
|
977
1085
|
elif any(self.records.identity_is_live({'pid': int(pid), 'ct': p['ct']}) for pid, p in entry['processes'].items()):
|
|
978
|
-
verify_processes(entry,
|
|
1086
|
+
self.verify_processes(entry, stopping=True)
|
|
979
1087
|
if any(self.records.identity_is_live({'pid': int(pid), 'ct': p['ct']}) for pid, p in entry['processes'].items() if int(pid) != entry['service_pid']):
|
|
980
1088
|
raise RuntimeError(f'{_name(entry)} still has live writer descendants; recovery remains owed.')
|
|
981
1089
|
self._stop_backend_supervisor(entry, threading.Event(), stopping=True)
|
|
@@ -984,9 +1092,11 @@ class ServiceRecovery:
|
|
|
984
1092
|
_start(entry, self.pause)
|
|
985
1093
|
self._wait_ready(entry, ledger)
|
|
986
1094
|
except Exception as exc:
|
|
1095
|
+
draining = draining and isinstance(exc, GatewayDraining)
|
|
987
1096
|
failures.append(str(exc))
|
|
988
1097
|
if failures:
|
|
989
|
-
|
|
1098
|
+
# Sibling obligations recover independently; only an all-draining remainder is progress.
|
|
1099
|
+
raise (GatewayDraining if draining else RuntimeError)('; '.join(failures))
|
|
990
1100
|
|
|
991
1101
|
def _wait_ready(self, entry, ledger):
|
|
992
1102
|
deadline = time.monotonic() + READY_SECONDS
|
|
@@ -999,6 +1109,18 @@ class ServiceRecovery:
|
|
|
999
1109
|
raise RuntimeError(f'{_name(entry)} readiness is unverified at its original endpoint; recovery remains owed.')
|
|
1000
1110
|
time.sleep(.1)
|
|
1001
1111
|
|
|
1112
|
+
def _verify_candidate(self, candidate, entry):
|
|
1113
|
+
# Readiness retries must retain both live observations and proved departures.
|
|
1114
|
+
candidate['config_stamp'] = entry['config_stamp']
|
|
1115
|
+
candidate['processes'] = {**candidate['processes'], **entry.get('readiness_processes', {})}
|
|
1116
|
+
candidate['departed_processes'] = {**entry.get('departed_processes', {}),
|
|
1117
|
+
**candidate.get('departed_processes', {})}
|
|
1118
|
+
bind_processes(candidate, self.records)
|
|
1119
|
+
entry['readiness_processes'] = candidate['processes']
|
|
1120
|
+
if candidate['departed_processes']:
|
|
1121
|
+
entry['departed_processes'] = candidate['departed_processes']
|
|
1122
|
+
self.save()
|
|
1123
|
+
|
|
1002
1124
|
def _ready(self, entry, ledger):
|
|
1003
1125
|
if _config_stamp(entry) != entry['config_stamp']:
|
|
1004
1126
|
raise RuntimeError(f'{_name(entry)} service configuration changed; backend recovery remains owed.')
|
|
@@ -1012,8 +1134,9 @@ class ServiceRecovery:
|
|
|
1012
1134
|
candidate = self._gateway_candidate(entry)
|
|
1013
1135
|
if candidate is None:
|
|
1014
1136
|
return False
|
|
1137
|
+
self._verify_candidate(candidate, entry)
|
|
1015
1138
|
ready = _gateway_home_matches(entry['home'], (candidate['pid'], candidate['ct']), self.pause)
|
|
1016
|
-
|
|
1139
|
+
self._verify_candidate(candidate, entry)
|
|
1017
1140
|
return ready
|
|
1018
1141
|
if entry.get('legacy_refresh') and any(self.records.identity_is_live({'pid': int(pid), 'ct': p['ct']})
|
|
1019
1142
|
for pid, p in entry['processes'].items()
|
|
@@ -1032,7 +1155,7 @@ class ServiceRecovery:
|
|
|
1032
1155
|
if (candidate['profile'] != entry['profile'] or _service_key(candidate) != _service_key(entry)
|
|
1033
1156
|
or _config_stamp(candidate) != entry['config_stamp']):
|
|
1034
1157
|
return False
|
|
1035
|
-
|
|
1158
|
+
self._verify_candidate(candidate, entry)
|
|
1036
1159
|
try:
|
|
1037
1160
|
if entry.get('legacy_refresh'):
|
|
1038
1161
|
verify_listener(candidate)
|
|
@@ -1043,7 +1166,7 @@ class ServiceRecovery:
|
|
|
1043
1166
|
return False
|
|
1044
1167
|
if backend_request(candidate, 'cancel', permit['token']).get('ok') is not True:
|
|
1045
1168
|
return False
|
|
1046
|
-
|
|
1169
|
+
self._verify_candidate(candidate, entry)
|
|
1047
1170
|
if self.identity._pid_alive_matches(row['pid'], row['create_time'], strict=True) is not True:
|
|
1048
1171
|
return False
|
|
1049
1172
|
except BackendLifecycleUnsupported:
|
|
@@ -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}
|