@maudecode/talaria-web 1.15.0 → 1.17.2
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 +4 -4
- package/dist/api/automation-raw.js +6 -3
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +158 -16
- package/dist/api/automation-router.js +12 -6
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +193 -6
- package/dist/api/chat-router.js +39 -16
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +12 -1
- package/dist/api/git-router.js +60 -38
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +6 -0
- package/dist/api/raw-routes.js +35 -58
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +4 -2
- package/dist/api/router.js +8 -8
- package/dist/api/router.js.map +1 -1
- package/dist/api/sessions-router.d.ts +974 -42
- package/dist/api/sessions-router.js +87 -25
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +254 -11
- package/dist/api/settings-router.js +68 -18
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +11 -3
- package/dist/api/sse-routes.js +145 -65
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +6 -2
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +86 -9
- package/dist/api/tools-router.js +19 -15
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.d.ts +0 -8397
- package/dist/app.js +7 -2
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +11 -4
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +6 -2
- package/dist/auth/oidc.js +16 -11
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/store.d.ts +14 -2
- package/dist/auth/store.js +26 -1
- package/dist/auth/store.js.map +1 -1
- package/dist/cli/dotenv.d.ts +1 -1
- package/dist/cli/dotenv.js +36 -3
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/config/agent-config.d.ts +2 -0
- package/dist/config/agent-config.js +9 -0
- package/dist/config/agent-config.js.map +1 -1
- package/dist/http/addresses.d.ts +6 -0
- package/dist/http/addresses.js +26 -0
- package/dist/http/addresses.js.map +1 -1
- package/dist/http/context.d.ts +6 -3
- package/dist/http/context.js +10 -4
- package/dist/http/context.js.map +1 -1
- package/dist/links.d.ts +26 -0
- package/dist/links.js +60 -0
- package/dist/links.js.map +1 -0
- package/dist/onboarding.js +30 -7
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.js +1 -1
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/providers/catalog.d.ts +167 -5
- package/dist/providers/catalog.js +662 -135
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/tables.d.ts +3 -1
- package/dist/providers/tables.js +9 -4
- package/dist/providers/tables.js.map +1 -1
- package/dist/redact.d.ts +1 -0
- package/dist/redact.js +518 -15
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +79 -37
- package/dist/runtime.js.map +1 -1
- package/dist/sessions/anchor.d.ts +24 -3
- package/dist/sessions/anchor.js +94 -44
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +4 -1
- package/dist/sessions/background-tasks.js +7 -4
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/claude-code.d.ts +19 -0
- package/dist/sessions/claude-code.js +250 -0
- package/dist/sessions/claude-code.js.map +1 -0
- package/dist/sessions/completions.d.ts +13 -1
- package/dist/sessions/completions.js +64 -12
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +14 -1
- package/dist/sessions/compress.js +52 -11
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/journal.d.ts +8 -0
- package/dist/sessions/journal.js +44 -10
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +13 -5
- package/dist/sessions/list.js +56 -26
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +122 -9
- package/dist/sessions/merge.js +544 -33
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/pending.d.ts +5 -0
- package/dist/sessions/pending.js +30 -10
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/service.d.ts +100 -4
- package/dist/sessions/service.js +567 -102
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +16 -1
- package/dist/sessions/session.js +29 -2
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.js +11 -2
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/state-db.d.ts +26 -4
- package/dist/sessions/state-db.js +126 -8
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/store.js +6 -1
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +10 -0
- package/dist/sessions/streams.js +14 -3
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/todo.d.ts +6 -1
- package/dist/sessions/todo.js +11 -4
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +12 -1
- package/dist/sessions/tool-display.js +76 -1
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn.d.ts +49 -10
- package/dist/sessions/turn.js +459 -185
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.d.ts +20 -2
- package/dist/settings.js +49 -2
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/fake.d.ts +2 -2
- package/dist/sidecar/fake.js +7 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/spa.js +2 -1
- package/dist/spa.js.map +1 -1
- package/dist/test/harness.js +2 -0
- package/dist/test/harness.js.map +1 -1
- package/dist/tools/commands.d.ts +15 -0
- package/dist/tools/commands.js +52 -0
- package/dist/tools/commands.js.map +1 -0
- package/dist/tools/crons.d.ts +4 -1
- package/dist/tools/crons.js +58 -11
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/insights.d.ts +8 -2
- package/dist/tools/insights.js +18 -2
- package/dist/tools/insights.js.map +1 -1
- package/dist/tools/kanban.d.ts +41 -1
- package/dist/tools/kanban.js +113 -2
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +2 -1
- package/dist/tools/mcp.js +16 -6
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/terminal.d.ts +1 -0
- package/dist/tools/terminal.js +1 -1
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +1 -1
- package/dist/tools/update-notifications.js +1 -1
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/updates.d.ts +15 -3
- package/dist/tools/updates.js +207 -41
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/fs.d.ts +7 -3
- package/dist/workspace/fs.js +5 -1
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/git.d.ts +57 -10
- package/dist/workspace/git.js +302 -195
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media-refs.d.ts +13 -0
- package/dist/workspace/media-refs.js +165 -0
- package/dist/workspace/media-refs.js.map +1 -0
- package/dist/workspace/media.d.ts +19 -0
- package/dist/workspace/media.js +63 -2
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/preview.d.ts +28 -0
- package/dist/workspace/preview.js +110 -0
- package/dist/workspace/preview.js.map +1 -0
- package/dist/workspace/rollback.d.ts +5 -4
- package/dist/workspace/rollback.js +12 -9
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/upload.d.ts +2 -0
- package/dist/workspace/upload.js +4 -1
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +7 -1
- package/dist/workspace/workspaces.js +30 -21
- package/dist/workspace/workspaces.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -4
- package/dist/workspace/worktrees.js +28 -33
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +4 -2
- package/sidecar/scripts/replay_sidecar.py +4 -2
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +7 -1
- package/sidecar/talaria_sidecar/home.py +98 -2
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +19 -3
- package/sidecar/talaria_sidecar/methods/chat.py +551 -61
- package/sidecar/talaria_sidecar/methods/commands.py +61 -33
- package/sidecar/talaria_sidecar/methods/config.py +14 -10
- package/sidecar/talaria_sidecar/methods/cron.py +10 -6
- package/sidecar/talaria_sidecar/methods/kanban.py +115 -15
- package/sidecar/talaria_sidecar/methods/oauth.py +439 -0
- package/sidecar/talaria_sidecar/methods/process.py +60 -1
- package/sidecar/talaria_sidecar/methods/profiles.py +12 -5
- package/sidecar/talaria_sidecar/methods/providers.py +161 -1
- package/sidecar/talaria_sidecar/methods/runtime.py +5 -0
- package/sidecar/talaria_sidecar/methods/text.py +18 -21
- package/sidecar/talaria_sidecar/methods/usage.py +264 -5
- package/static/dist/FILES.txt +126 -121
- package/static/dist/assets/AppShell-fb2td9zi.js +1 -0
- package/static/dist/assets/ChatPage-cj96kiy9.js +25 -0
- package/static/dist/assets/Dialog-kxcg7ard.js +1 -0
- package/static/dist/assets/ExtensionRoute-jf7h0754.js +1 -0
- package/static/dist/assets/HubRoute-gmanpd5y.js +2 -0
- package/static/dist/assets/{Markdown-dy8t4dy7.js → Markdown-mdwlvj3w.js} +125 -125
- package/static/dist/assets/RightPanel-ftvrjlcp.js +1 -0
- package/static/dist/assets/Select-bilaypej.js +1 -0
- package/static/dist/assets/SessionListPanel-og8n36qs.js +1 -0
- package/static/dist/assets/SettingsLayout-jonjefmj.js +1 -0
- package/static/dist/assets/States-nmejrwrm.js +1 -0
- package/static/dist/assets/Toaster-nnl8zkt9.js +1 -0
- package/static/dist/assets/_app-gdidzd94.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-opyh9y0v.js +1 -0
- package/static/dist/assets/_app.index-hbarzbjx.js +1 -0
- package/static/dist/assets/_app.insights-luywlarz.js +1 -0
- package/static/dist/assets/_app.kanban-kincnbr8.js +1 -0
- package/static/dist/assets/_app.logs-oi2gr3gs.js +1 -0
- package/static/dist/assets/_app.memory-b6jfivt6.js +1 -0
- package/static/dist/assets/_app.profiles-lpvixmqp.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-gyoh5ylx.js → _app.session._sessionId-bfd4h3id.js} +1 -1
- package/static/dist/assets/_app.settings-vowx3iq0.js +1 -0
- package/static/dist/assets/_app.settings._section-cnntg1tu.js +3 -0
- package/static/dist/assets/_app.skills-fb57lpau.js +1 -0
- package/static/dist/assets/_app.tasks-eszpx1q7.js +2 -0
- package/static/dist/assets/_app.todos-nr05ac6w.js +1 -0
- package/static/dist/assets/_app.workspaces-d2luomu6.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-cjqletra.js → abnfDiagram-VCTEODGH-b2x1lqot.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +1 -0
- package/static/dist/assets/architectureDiagram-5GKGNRK7-h38o5l7b.js +36 -0
- package/static/dist/assets/{back-e4m6nsnm.js → back-bemaer09.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-b195z021.js → blockDiagram-I7D4REHJ-bqquxv2u.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-olu212k1.js → c4Diagram-7LVT6UL2-f3fb8w6z.js} +1 -1
- package/static/dist/assets/cancel-drd0g6d9.js +1 -0
- package/static/dist/assets/channel-cpdgf867.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-b8o1nufs.js → chunk-4HAMMTFA-bzfyyzp3.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-l1seddto.js → chunk-75Z2AOVW-ly99rfx5.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lo5zg15v.js → chunk-DU6HZSFF-bg6ecfqf.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-dsdzrp16.js → chunk-F27PBJKO-e8k7mmqw.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-f3fxqq8b.js → chunk-GMAD6QVW-cmalnoaj.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-h8egxtf6.js → chunk-GVQU2GXP-gmif5o01.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-iolwd8s0.js → chunk-IMKFNOWR-f1nwwh6u.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-b88bbtwi.js → chunk-L3NEJ4N5-oktfh5v7.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-e3e7nr6s.js → chunk-OSK3NFVY-b1sdx96z.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-mdc46rt1.js → chunk-P2QGCYS3-fhu4nzxt.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-kqlllrrm.js → chunk-POPQ4Y6H-em31rnef.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-he585k2x.js → chunk-PWAF6VOD-bxhhyftw.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-gh94y9a4.js → chunk-SHT3W25Y-fmrvwcav.js} +3 -3
- package/static/dist/assets/{chunk-SVP7TREG-euxp9y7e.js → chunk-SVP7TREG-lymukl2j.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-c8cxes1q.js → chunk-TICWLB2K-lmza6k23.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +1 -0
- package/static/dist/assets/{copied-kq0u3ht7.js → copied-ima3pysb.js} +1 -1
- package/static/dist/assets/copy-fw5b1pc6.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lxd44ux4.js → cynefin-OW5HDTMX-czlhbyhs.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-njpiwat8.js → cynefinDiagram-5FMLGOSQ-gq7mvswb.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-nvgy6yju.js → dagre-GXQ25YYZ-cqdbf7dr.js} +4 -4
- package/static/dist/assets/{diagram-S7CK7UJ4-g98nyv72.js → diagram-S7CK7UJ4-o6arxa58.js} +3 -3
- package/static/dist/assets/{diagram-UQ7AKVKN-ovgm6lvv.js → diagram-UQ7AKVKN-nhnd68tz.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-pb2bn2e4.js → diagram-VSXAHHWV-dk2sclzn.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-6j4mvfqo.js → diagram-VX7I27RA-n3k5nyx3.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-dqmb982r.js → diagram-Z3DM3KII-m6q9cwdh.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-ozbpzb6d.js → ebnfDiagram-PWID7BFC-lsa5641p.js} +1 -1
- package/static/dist/assets/endpoints-d33siokx.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-hl7m8vua.js → erDiagram-RLTQ6QDP-fo2ckbe6.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ompixqmh.js → ganttDiagram-EL5Y4UJY-nzqz6x9g.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-b6vxwp9q.js → gitGraph-4MIJSDKK-gukvcxe6.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-k98f57on.js → gitGraphDiagram-WWUBYQGX-lqhdp8f0.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-cd3ff6ge.js → highlighted-body-KPVGNVTW-igw6cp39.js} +1 -1
- package/static/dist/assets/index-cxq58xb1.js +11 -0
- package/static/dist/assets/index-hgtx08n5.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-hjcwjami.js → info-A6RAGUB7-gvu7a93l.js} +1 -1
- package/static/dist/assets/infoDiagram-27XIBGKW-m8t8g6w1.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-bxak4mwu.js → ishikawaDiagram-5VMMS53U-l07vkbgj.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-khmihclr.js → journeyDiagram-3NMN7TZE-hybkgj8l.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-h1r32wdx.js → kanban-definition-UXKFOSKX-by13uvtn.js} +1 -1
- package/static/dist/assets/{lazyRouteComponent-b2eg0fws.js → lazyRouteComponent-af0lvgjx.js} +1 -1
- package/static/dist/assets/{line-friyjof3.js → line-osxq6fq7.js} +1 -1
- package/static/dist/assets/link-jyxicdhg.js +1 -0
- package/static/dist/assets/login-ec21t39x.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-f1gvpwrt.js → mermaid-parser.core-i91oxmou.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-mt2oxwue.js → mindmap-definition-YA3MSWOX-m82mx8ww.js} +1 -1
- package/static/dist/assets/onboarding-btnltvyz.js +1 -0
- package/static/dist/assets/onboarding_model_label-dp7xffoh.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-jik4ixlf.js → packet-AYTQ26CC-nbtgge2o.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-erxlv6cc.js → pegDiagram-XKGWAZYB-f1zxzga1.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-mnkoldfl.js → pie-WAS4IAKB-of8vuhxs.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-i7lwrada.js → pieDiagram-E7YTZNPT-o7y8ftio.js} +3 -3
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-fr8ejdoy.js → quadrantDiagram-AXDQQJYC-iqiwia1t.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-otarjte2.js → radar-RG4KPBEZ-delnsy2v.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-lw362oto.js → railroad-74A4TZTK-nspnyq9u.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-esyn75pw.js → railroadDiagram-O6MQD6OU-z41tqx5z.js} +1 -1
- package/static/dist/assets/refresh-b4uams1i.js +1 -0
- package/static/dist/assets/refresh-cw-nt1dtsx4.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-cyhi5u29.js → requirementDiagram-BXWQKSXE-bdvif194.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-jljpbo0h.js → sankeyDiagram-P5KCCOFB-h73e0rol.js} +1 -1
- package/static/dist/assets/{saved-do49si3v.js → saved-kg52csy7.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-fz0dhlu7.js → sequenceDiagram-WJ2MYXX4-iv95mb1z.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-b7lojn0o.js → settings_section_extensions_title-ej0iapxe.js} +1 -1
- package/static/dist/assets/share._token-f97e94r0.js +2 -0
- package/static/dist/assets/sliders-horizontal-fj18it47.js +1 -0
- package/static/dist/assets/sse-fwpqtzbg.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-kdnithdx.js → stateDiagram-D77RDMKH-k417ixmf.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-esd6gmz3.js → swimlanes-42K2YHIH-esola70w.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-g0qygccv.js → timeline-definition-24CTP7MA-getrz2y8.js} +1 -1
- package/static/dist/assets/todoStore-eginf9h4.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-ndchzkuu.js → treeView-Q6P3EWNA-hc7ap1q7.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-hwjxj0zz.js → treemap-WGGIJYW6-b7k1syy5.js} +1 -1
- package/static/dist/assets/tts-lxdxnmjd.js +1 -0
- package/static/dist/assets/{untitled-mbr6tuhu.js → untitled-ovpfthg4.js} +1 -1
- package/static/dist/assets/useForm-bcblv1rx.js +1 -0
- package/static/dist/assets/useLocale-fi5jb8ma.js +1 -0
- package/static/dist/assets/{useParams-lo9u33d1.js → useParams-lhg566ew.js} +1 -1
- package/static/dist/assets/{useSearch-lq1mr090.js → useSearch-lbrh6ejn.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-gubovd1r.js → vennDiagram-4TSXK5OY-n6pcy5qb.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-ir3om65j.js → wardley-WFR3VGLG-lpa18vz1.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ce0or1ie.js → wardleyDiagram-VM6X3IG4-kpclwwg7.js} +2 -2
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-dexylcjg.js → xychartDiagram-S5SC5T6Z-paa2n8y0.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +2 -2
- package/static/dist/assets/AppShell-orat1s43.js +0 -1
- package/static/dist/assets/ChatPage-ojhka3hy.js +0 -22
- package/static/dist/assets/HubRoute-gxgw1t33.js +0 -2
- package/static/dist/assets/RightPanel-c66ani1s.js +0 -1
- package/static/dist/assets/Select-fswf66up.js +0 -1
- package/static/dist/assets/SessionListPanel-goh5mtt8.js +0 -1
- package/static/dist/assets/SettingsLayout-n5d4wq4m.js +0 -1
- package/static/dist/assets/States-kxyu50at.js +0 -1
- package/static/dist/assets/Toaster-6zmbcqgg.js +0 -1
- package/static/dist/assets/_app-fowyruiu.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-nvjyrwhy.js +0 -1
- package/static/dist/assets/_app.index-c9zv4y7w.js +0 -1
- package/static/dist/assets/_app.insights-jf12nofo.js +0 -1
- package/static/dist/assets/_app.kanban-lri5a4yu.js +0 -1
- package/static/dist/assets/_app.logs-md1p0zqo.js +0 -1
- package/static/dist/assets/_app.memory-bzvf2e28.js +0 -1
- package/static/dist/assets/_app.profiles-jpg7zmbn.js +0 -1
- package/static/dist/assets/_app.settings-mpuwlx4j.js +0 -1
- package/static/dist/assets/_app.settings._section-knz8rwoj.js +0 -1
- package/static/dist/assets/_app.skills-fwu1dkir.js +0 -1
- package/static/dist/assets/_app.tasks-h9gphtl3.js +0 -2
- package/static/dist/assets/_app.todos-hd1dnvrh.js +0 -1
- package/static/dist/assets/_app.workspaces-l8toyn5f.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-cavnusaw.js +0 -1
- package/static/dist/assets/architectureDiagram-5GKGNRK7-k5a7v36n.js +0 -36
- package/static/dist/assets/channel-gozy3dp3.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-n0vs2f2q.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-n0vs2f2q.js +0 -1
- package/static/dist/assets/endpoints-k8agnro8.js +0 -9
- package/static/dist/assets/eventmodeling-NTZA5JFV-j1y2ekec.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-g2cvcbm5.js +0 -1
- package/static/dist/assets/index-nfy0ezs6.css +0 -2
- package/static/dist/assets/index-nqed3oum.js +0 -11
- package/static/dist/assets/infoDiagram-27XIBGKW-fm06rj36.js +0 -2
- package/static/dist/assets/link-m90ahx3n.js +0 -1
- package/static/dist/assets/login-bw7m2fzo.js +0 -1
- package/static/dist/assets/matchContext-f8oy3lo7.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-njwcl62n.js +0 -1
- package/static/dist/assets/onboarding-ret37j1e.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-m741owar.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-noa4fbia.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-o4bpw4nb.js +0 -1
- package/static/dist/assets/refresh-cw-k66keho6.js +0 -1
- package/static/dist/assets/search-j5ki6a9o.js +0 -1
- package/static/dist/assets/share._token-kg8w647b.js +0 -2
- package/static/dist/assets/sliders-horizontal-c4wya4dy.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-k2wg2645.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-n5kvjtgr.js +0 -8
- package/static/dist/assets/tabBuild-bjmyvmn5.js +0 -56
- package/static/dist/assets/todoStore-kjk5l0sy.js +0 -1
- package/static/dist/assets/useForm-ocxu460f.js +0 -1
- package/static/dist/assets/useLocale-fzy5jhg6.js +0 -1
|
@@ -7,14 +7,22 @@ import threading
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
9
|
from ..errors import InvalidParams, RpcError
|
|
10
|
-
from ..home import profile_home_param, scoped_home
|
|
10
|
+
from ..home import _is_named_profile, profile_home_param, scoped_home
|
|
11
11
|
from ..rpc import CallContext
|
|
12
|
+
from .providers import plugin_providers
|
|
12
13
|
|
|
13
14
|
log = logging.getLogger("talaria_sidecar.commands")
|
|
14
15
|
|
|
15
16
|
_NEVER_EXPOSE = frozenset({"sethome", "restart", "update", "commands"})
|
|
16
17
|
_ALIASES = {"reload_mcp": "reload-mcp", "reload_skills": "reload-skills", "codex_runtime": "codex-runtime"}
|
|
17
|
-
|
|
18
|
+
# The commands ``commands.exec`` runs, with the catalog row the sidecar lists when the Agent registry lacks one.
|
|
19
|
+
_RUNTIME_COMMANDS = {
|
|
20
|
+
"reload-mcp": ("Reload MCP servers from config", "Tools & Skills", ""),
|
|
21
|
+
"reload-skills": ("Re-scan skills from disk", "Tools & Skills", ""),
|
|
22
|
+
"codex-runtime": ("Toggle codex app-server runtime for OpenAI/Codex models", "Configuration", "[auto|codex_app_server]"),
|
|
23
|
+
"credits": ("Show your Nous credits", "Info", ""),
|
|
24
|
+
}
|
|
25
|
+
_ALLOWED = frozenset(_RUNTIME_COMMANDS)
|
|
18
26
|
_RELOAD_MCP_LOCK = threading.Lock()
|
|
19
27
|
_RELOAD_SKILLS_LOCK = threading.Lock()
|
|
20
28
|
_CODEX_RUNTIME_LOCK = threading.Lock()
|
|
@@ -45,7 +53,13 @@ def list_commands() -> list[dict[str, Any]]:
|
|
|
45
53
|
out.append({
|
|
46
54
|
"name": cmd.name, "description": cmd.description, "category": cmd.category, "aliases": list(cmd.aliases),
|
|
47
55
|
"args_hint": cmd.args_hint, "subcommands": list(cmd.subcommands), "cli_only": bool(cmd.cli_only), "gateway_only": bool(cmd.gateway_only),
|
|
56
|
+
"exec": cmd.name in _ALLOWED,
|
|
48
57
|
})
|
|
58
|
+
listed = {c["name"] for c in out}
|
|
59
|
+
for name, (description, category, args_hint) in _RUNTIME_COMMANDS.items():
|
|
60
|
+
if name not in listed:
|
|
61
|
+
out.append({"name": name, "description": description, "category": category, "aliases": [a for a, n in _ALIASES.items() if n == name],
|
|
62
|
+
"args_hint": args_hint, "subcommands": [], "cli_only": False, "gateway_only": False, "exec": True})
|
|
49
63
|
try:
|
|
50
64
|
from hermes_cli.plugins import get_plugin_commands
|
|
51
65
|
|
|
@@ -54,25 +68,60 @@ def list_commands() -> list[dict[str, Any]]:
|
|
|
54
68
|
if name in existing or name in _NEVER_EXPOSE:
|
|
55
69
|
continue
|
|
56
70
|
out.append({"name": name, "description": str(info.get("description", "Plugin command")), "category": "Plugin", "aliases": [],
|
|
57
|
-
"args_hint": str(info.get("args_hint", "")), "subcommands": [], "cli_only": False, "gateway_only": False})
|
|
71
|
+
"args_hint": str(info.get("args_hint", "")), "subcommands": [], "cli_only": False, "gateway_only": False, "exec": True})
|
|
58
72
|
except Exception: # noqa: BLE001 - plugin registry is optional
|
|
59
73
|
log.debug("plugin command listing failed", exc_info=True)
|
|
60
74
|
return out
|
|
61
75
|
|
|
62
76
|
|
|
77
|
+
def retire_unscoped_launch_mcp_servers() -> set[str]:
|
|
78
|
+
"""Close the launch profile's connections opened before multiplexing started; returns their server names.
|
|
79
|
+
|
|
80
|
+
Until the first named-profile call, the launch profile's connections and tools are unscoped (process-wide). Once
|
|
81
|
+
multiplexing is active, a scoped shutdown never selects them and scoped discovery opens duplicates beside them, so
|
|
82
|
+
the launch profile's own calls close them first and its scope reconnects them from the current config."""
|
|
83
|
+
from agent.secret_scope import is_multiplex_active
|
|
84
|
+
from hermes_constants import get_hermes_home
|
|
85
|
+
from tools.mcp_tool import _lock, _servers
|
|
86
|
+
from tools.mcp_tool_lifecycle import shutdown_mcp_servers
|
|
87
|
+
from tools.mcp_tool_scope import _key_name, _key_scope
|
|
88
|
+
|
|
89
|
+
if not is_multiplex_active() or _is_named_profile(get_hermes_home()):
|
|
90
|
+
return set()
|
|
91
|
+
with _lock:
|
|
92
|
+
names = {_key_name(key) for key in _servers if _key_scope(key) is None}
|
|
93
|
+
if names:
|
|
94
|
+
shutdown_mcp_servers(scope=None, names=names)
|
|
95
|
+
return names
|
|
96
|
+
|
|
97
|
+
|
|
63
98
|
def _reload_mcp() -> str:
|
|
64
99
|
with _RELOAD_MCP_LOCK:
|
|
65
100
|
try:
|
|
66
|
-
from
|
|
101
|
+
from agent.secret_scope import is_multiplex_active
|
|
102
|
+
from tools.mcp_tool import _lock, _mcp_tool_server_names, _server_visible_in_scope, _servers
|
|
103
|
+
from tools.mcp_tool_discovery import discover_mcp_tools
|
|
104
|
+
from tools.mcp_tool_lifecycle import shutdown_mcp_servers
|
|
105
|
+
from tools.mcp_tool_scope import _key_name
|
|
106
|
+
from tools.registry import registry
|
|
67
107
|
except Exception as exc: # noqa: BLE001
|
|
68
108
|
raise RpcError("MCP runtime unavailable", condition="mcp_unavailable") from exc
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
109
|
+
# Like the gateway's ``_execute_mcp_reload``: under multiplexing only this profile's connections go down and
|
|
110
|
+
# come back. The bare shutdown is the process-wide wildcard, which would drop every other profile's servers.
|
|
111
|
+
scope = registry.current_scope_key() if is_multiplex_active() else None
|
|
112
|
+
|
|
113
|
+
def server_names() -> set[str]:
|
|
74
114
|
with _lock:
|
|
75
|
-
|
|
115
|
+
return {_key_name(key) for key in _servers if _server_visible_in_scope(key, scope)}
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
old = server_names() | retire_unscoped_launch_mcp_servers()
|
|
119
|
+
shutdown_mcp_servers(scope=scope)
|
|
120
|
+
tools = discover_mcp_tools() or []
|
|
121
|
+
connected = server_names()
|
|
122
|
+
if scope is not None:
|
|
123
|
+
with _lock:
|
|
124
|
+
tools = [name for name in tools if _mcp_tool_server_names.get(name) in connected]
|
|
76
125
|
except Exception as exc: # noqa: BLE001
|
|
77
126
|
log.warning("Failed to reload MCP servers", exc_info=True)
|
|
78
127
|
raise RpcError("Failed to reload MCP servers", condition="mcp_reload_failed") from exc
|
|
@@ -84,7 +133,7 @@ def _reload_mcp() -> str:
|
|
|
84
133
|
lines.append(f"Added: {', '.join(sorted(added))}")
|
|
85
134
|
if removed:
|
|
86
135
|
lines.append(f"Removed: {', '.join(sorted(removed))}")
|
|
87
|
-
lines.append(f"{len(tools
|
|
136
|
+
lines.append(f"{len(tools)} tool(s) available across {len(connected)} server(s)" if connected else "No MCP servers connected")
|
|
88
137
|
if not reconnected and not added and not removed:
|
|
89
138
|
lines.append("Tooling state was already current")
|
|
90
139
|
return "\n".join(lines)
|
|
@@ -230,27 +279,6 @@ def resolve_moa_config(preset: str | None) -> dict:
|
|
|
230
279
|
return resolved
|
|
231
280
|
|
|
232
281
|
|
|
233
|
-
def plugin_provider_profiles() -> list[dict]:
|
|
234
|
-
"""Model-provider plugins registered with the Agent's provider registry."""
|
|
235
|
-
try:
|
|
236
|
-
from providers import list_providers
|
|
237
|
-
except Exception: # noqa: BLE001
|
|
238
|
-
return []
|
|
239
|
-
out = []
|
|
240
|
-
try:
|
|
241
|
-
for profile in list_providers():
|
|
242
|
-
name = str(getattr(profile, "name", "") or "").strip().lower()
|
|
243
|
-
if not name:
|
|
244
|
-
continue
|
|
245
|
-
env_vars = [str(v) for v in (getattr(profile, "env_vars", ()) or ())]
|
|
246
|
-
api_key_env = next((v for v in env_vars if not v.upper().endswith(("_BASE_URL", "_URL", "_FOLDER_ID"))), None)
|
|
247
|
-
out.append({"name": name, "display_name": str(getattr(profile, "display_name", "") or name).strip(), "env_vars": env_vars, "api_key_env": api_key_env})
|
|
248
|
-
except Exception: # noqa: BLE001
|
|
249
|
-
log.debug("Failed to enumerate model-provider plugins", exc_info=True)
|
|
250
|
-
return []
|
|
251
|
-
return out
|
|
252
|
-
|
|
253
|
-
|
|
254
282
|
PLUGIN_VISIBILITY_HOOKS = ("pre_tool_call", "post_tool_call", "pre_llm_call", "post_llm_call")
|
|
255
283
|
|
|
256
284
|
|
|
@@ -332,7 +360,7 @@ def register(registry) -> None:
|
|
|
332
360
|
@registry.method("plugins.providers")
|
|
333
361
|
def providers(ctx: CallContext, params: dict) -> dict:
|
|
334
362
|
with scoped_home(profile_home_param(params)):
|
|
335
|
-
return {"providers":
|
|
363
|
+
return {"providers": plugin_providers()}
|
|
336
364
|
|
|
337
365
|
@registry.method("plugins.list")
|
|
338
366
|
def list_(ctx: CallContext, params: dict) -> dict:
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Agent's per-model reasoning capability.
|
|
3
3
|
|
|
4
4
|
The TypeScript server owns every config.yaml *policy* (which keys mean what);
|
|
5
|
-
the sidecar only parses and serialises YAML with the Agent's
|
|
6
|
-
side needs no YAML dependency. Writes are atomic and keep the file's mode.
|
|
5
|
+
the sidecar only parses and serialises YAML with the Agent's own parser so the
|
|
6
|
+
Node side needs no YAML dependency. Writes are atomic and keep the file's mode.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import importlib
|
|
11
12
|
import logging
|
|
12
13
|
import os
|
|
13
14
|
import tempfile
|
|
@@ -20,12 +21,15 @@ from ..rpc import CallContext
|
|
|
20
21
|
log = logging.getLogger("talaria_sidecar.config")
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
def yaml_parser():
|
|
25
|
+
"""The Agent's YAML module: ``hermes_yaml`` on Agents that ship it, PyYAML on released Agents."""
|
|
26
|
+
failures = []
|
|
27
|
+
for name in ("hermes_yaml", "yaml"):
|
|
28
|
+
try:
|
|
29
|
+
return importlib.import_module(name)
|
|
30
|
+
except Exception as exc: # noqa: BLE001
|
|
31
|
+
failures.append(f"{name}: {exc}")
|
|
32
|
+
raise RpcError(f"No YAML parser available ({'; '.join(failures)})", condition="yaml_unavailable")
|
|
29
33
|
|
|
30
34
|
|
|
31
35
|
def config_path_param(params: dict) -> Path:
|
|
@@ -45,7 +49,7 @@ def read_config(path: Path) -> dict:
|
|
|
45
49
|
if not path.exists():
|
|
46
50
|
return {"path": str(path), "exists": False, "config": {}}
|
|
47
51
|
try:
|
|
48
|
-
data =
|
|
52
|
+
data = yaml_parser().safe_load(path.read_text(encoding="utf-8"))
|
|
49
53
|
except RpcError:
|
|
50
54
|
raise
|
|
51
55
|
except Exception as exc: # noqa: BLE001
|
|
@@ -70,7 +74,7 @@ def write_config(path: Path, config: dict) -> dict:
|
|
|
70
74
|
raise InvalidParams("config must be an object")
|
|
71
75
|
target = _write_target(path)
|
|
72
76
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
-
text =
|
|
77
|
+
text = yaml_parser().safe_dump(config, sort_keys=False, allow_unicode=True)
|
|
74
78
|
mode = None
|
|
75
79
|
try:
|
|
76
80
|
mode = target.stat().st_mode & 0o777
|
|
@@ -252,14 +252,18 @@ def _run_in_child(job, execution_home, ctx: CallContext):
|
|
|
252
252
|
process.join(timeout=5)
|
|
253
253
|
status, payload = "cancelled", ["cancelled", ""]
|
|
254
254
|
break
|
|
255
|
-
if
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
else:
|
|
255
|
+
if not process.is_alive():
|
|
256
|
+
# The child may have put its result just before exiting; otherwise it died (OOM, signal) without one.
|
|
257
|
+
try:
|
|
258
|
+
status, *payload = result_queue.get_nowait()
|
|
259
|
+
except queue.Empty:
|
|
261
260
|
payload = [f"cron run subprocess exited with code {process.exitcode} without producing a result", ""]
|
|
262
261
|
break
|
|
262
|
+
if time.monotonic() >= deadline:
|
|
263
|
+
process.terminate()
|
|
264
|
+
process.join(timeout=5)
|
|
265
|
+
payload = [f"cron run subprocess produced no result within {_result_timeout(job):g}s and was terminated", ""]
|
|
266
|
+
break
|
|
263
267
|
process.join(timeout=5)
|
|
264
268
|
if process.is_alive():
|
|
265
269
|
process.terminate()
|
|
@@ -8,6 +8,7 @@ server; the sidecar receives typed params.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import secrets
|
|
11
12
|
import time
|
|
12
13
|
from dataclasses import asdict, is_dataclass
|
|
13
14
|
from typing import Any
|
|
@@ -82,10 +83,102 @@ def _obj_dict(value):
|
|
|
82
83
|
return dict(getattr(value, "__dict__", {}))
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
LIVE_CLAIM_MESSAGE = "task has a live worker; archive it to stop the worker"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _row_claim_live(row) -> bool:
|
|
90
|
+
"""The Agent's ``_claim_is_live`` for a ``tasks`` row: a running task's worker process still holds its claim.
|
|
91
|
+
|
|
92
|
+
Releasing that claim (block, a direct status change) leaves the worker running, so the card
|
|
93
|
+
policy withholds those writes and the write paths refuse them (TAL-557). Unknown liveness counts as live.
|
|
94
|
+
"""
|
|
95
|
+
if row is None or row["status"] != "running":
|
|
96
|
+
return False
|
|
97
|
+
columns = row.keys()
|
|
98
|
+
claim = {k: row[k] if k in columns else None for k in ("status", "claim_lock", "worker_pid", "worker_started_at")}
|
|
99
|
+
try:
|
|
100
|
+
return bool(_kb()._claim_is_live(claim))
|
|
101
|
+
except Exception: # noqa: BLE001 - an older Agent without the helper
|
|
102
|
+
return bool(claim["claim_lock"] and claim["worker_pid"])
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _claim_live(conn, task_id) -> bool:
|
|
106
|
+
return _row_claim_live(conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone())
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
RUNNING_EXIT_MESSAGE = "task is running; confirm leaving Running"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _guard_running_exit(row, confirm_running_exit: bool) -> None:
|
|
113
|
+
"""A write that takes a task out of Running needs the client's explicit confirmation, judged on the row the
|
|
114
|
+
write sees: a client's card policy can predate a dispatcher claim (TAL-557)."""
|
|
115
|
+
if row["status"] == "running" and not confirm_running_exit:
|
|
116
|
+
raise Conflict(RUNNING_EXIT_MESSAGE)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
FENCE_PREFIX = "talaria-fence:"
|
|
120
|
+
FENCE_SECONDS = 60
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _clear_stale_fences(conn) -> None:
|
|
124
|
+
"""Release fences whose write never finished (the sidecar died mid-write), so the dispatcher can claim again."""
|
|
125
|
+
now = int(time.time())
|
|
126
|
+
stale = []
|
|
127
|
+
for row in conn.execute("SELECT id, claim_lock FROM tasks WHERE claim_lock LIKE ?", (FENCE_PREFIX + "%",)).fetchall():
|
|
128
|
+
try:
|
|
129
|
+
expires = int(str(row["claim_lock"])[len(FENCE_PREFIX):].split(":", 1)[0])
|
|
130
|
+
except ValueError:
|
|
131
|
+
expires = 0
|
|
132
|
+
if expires < now:
|
|
133
|
+
stale.append((row["id"], row["claim_lock"]))
|
|
134
|
+
if not stale:
|
|
135
|
+
return
|
|
136
|
+
kb = _kb()
|
|
137
|
+
with kb.write_txn(conn):
|
|
138
|
+
for task_id, fence in stale:
|
|
139
|
+
conn.execute("UPDATE tasks SET claim_lock = NULL WHERE id = ? AND claim_lock = ?", (task_id, fence))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _fenced(conn, task_id: str, write, *, confirm_running_exit: bool, releases_claim: bool = True):
|
|
143
|
+
"""Run an Agent transition (block, complete, archive) with the dispatcher fenced out.
|
|
144
|
+
|
|
145
|
+
The Agent's helpers open their own write transaction, which cannot nest, so the checks and a fence lock share
|
|
146
|
+
one transaction first: ``claim_task`` claims only a ``ready`` task with ``claim_lock IS NULL``, so the card cannot
|
|
147
|
+
become a live run before the helper runs. ``releases_claim`` writes (block, complete) refuse a live worker's claim;
|
|
148
|
+
archive keeps it, because ``archive_task`` terminates that worker. The fence expires, so a write the sidecar never
|
|
149
|
+
finished stops holding the card once ``_clear_stale_fences`` next runs.
|
|
150
|
+
"""
|
|
151
|
+
kb = _kb()
|
|
152
|
+
_clear_stale_fences(conn)
|
|
153
|
+
fence = f"{FENCE_PREFIX}{int(time.time()) + FENCE_SECONDS}:{secrets.token_hex(8)}"
|
|
154
|
+
with kb.write_txn(conn):
|
|
155
|
+
row = conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone()
|
|
156
|
+
if row is None:
|
|
157
|
+
raise NotFound("task not found")
|
|
158
|
+
_guard_running_exit(row, confirm_running_exit)
|
|
159
|
+
live = _row_claim_live(row)
|
|
160
|
+
if live and releases_claim:
|
|
161
|
+
raise Conflict(LIVE_CLAIM_MESSAGE)
|
|
162
|
+
# Only an unclaimed ready task is claimable; anything else needs no fence.
|
|
163
|
+
fenced = row["status"] == "ready" and row["claim_lock"] is None
|
|
164
|
+
if fenced:
|
|
165
|
+
conn.execute("UPDATE tasks SET claim_lock = ? WHERE id = ?", (fence, task_id))
|
|
166
|
+
try:
|
|
167
|
+
return write()
|
|
168
|
+
finally:
|
|
169
|
+
if fenced:
|
|
170
|
+
with kb.write_txn(conn):
|
|
171
|
+
conn.execute("UPDATE tasks SET claim_lock = NULL WHERE id = ? AND claim_lock = ?", (task_id, fence))
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _task_dict(task, conn):
|
|
86
175
|
data = _obj_dict(task)
|
|
87
176
|
if not data:
|
|
88
177
|
return data
|
|
178
|
+
# Facts the server's card policy needs (TAL-557): the Agent completes a non-review task only with
|
|
179
|
+
# stored or supplied evidence, and refuses to release a live worker's claim.
|
|
180
|
+
data["claim_live"] = data.get("status") == "running" and _claim_live(conn, data.get("id"))
|
|
181
|
+
data["has_completion_evidence"] = bool(str(data.get("result") or "").strip())
|
|
89
182
|
try:
|
|
90
183
|
age = _kb().task_age(task)
|
|
91
184
|
except Exception: # noqa: BLE001
|
|
@@ -131,12 +224,16 @@ def _validate_status(status: str) -> str:
|
|
|
131
224
|
return value
|
|
132
225
|
|
|
133
226
|
|
|
134
|
-
def _set_status_direct(conn, task_id: str, new_status: str) -> bool:
|
|
227
|
+
def _set_status_direct(conn, task_id: str, new_status: str, *, confirm_running_exit: bool = False) -> bool:
|
|
135
228
|
kb = _kb()
|
|
136
229
|
with kb.write_txn(conn):
|
|
137
|
-
prev = conn.execute("SELECT
|
|
230
|
+
prev = conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone()
|
|
138
231
|
if prev is None:
|
|
139
232
|
return False
|
|
233
|
+
# Checked inside the write transaction, so a claim taken since the client's read is never released.
|
|
234
|
+
_guard_running_exit(prev, confirm_running_exit)
|
|
235
|
+
if _row_claim_live(prev):
|
|
236
|
+
raise Conflict(LIVE_CLAIM_MESSAGE)
|
|
140
237
|
was_running = prev["status"] == "running"
|
|
141
238
|
cur = conn.execute(
|
|
142
239
|
"UPDATE tasks SET status = ?, "
|
|
@@ -202,14 +299,15 @@ def _patch_task(conn, task_id: str, body: dict) -> None:
|
|
|
202
299
|
if "status" not in body or body.get("status") in (None, ""):
|
|
203
300
|
return
|
|
204
301
|
status = _validate_status(body.get("status"))
|
|
302
|
+
confirm = bool(body.get("confirm_running_exit"))
|
|
205
303
|
if status == "done":
|
|
206
|
-
if not kb.complete_task(conn, task_id, result=body.get("result"), summary=body.get("summary")):
|
|
304
|
+
if not _fenced(conn, task_id, lambda: kb.complete_task(conn, task_id, result=body.get("result"), summary=body.get("summary")), confirm_running_exit=confirm):
|
|
207
305
|
raise NotFound("task not found")
|
|
208
306
|
elif status == "blocked":
|
|
209
|
-
if not kb.block_task(conn, task_id, reason=body.get("block_reason") or body.get("reason")):
|
|
307
|
+
if not _fenced(conn, task_id, lambda: kb.block_task(conn, task_id, reason=body.get("block_reason") or body.get("reason")), confirm_running_exit=confirm):
|
|
210
308
|
raise NotFound("task not found")
|
|
211
309
|
elif status == "archived":
|
|
212
|
-
if not kb.archive_task(conn, task_id):
|
|
310
|
+
if not _fenced(conn, task_id, lambda: kb.archive_task(conn, task_id), confirm_running_exit=confirm, releases_claim=False):
|
|
213
311
|
raise NotFound("task not found")
|
|
214
312
|
elif status == "running":
|
|
215
313
|
raise InvalidParams("Cannot set status to 'running' directly; use the dispatcher/claim path")
|
|
@@ -220,10 +318,10 @@ def _patch_task(conn, task_id: str, body: dict) -> None:
|
|
|
220
318
|
if current.status == "blocked":
|
|
221
319
|
if not kb.unblock_task(conn, task_id):
|
|
222
320
|
raise NotFound("task not found")
|
|
223
|
-
elif not _set_status_direct(conn, task_id, "ready"):
|
|
321
|
+
elif not _set_status_direct(conn, task_id, "ready", confirm_running_exit=confirm):
|
|
224
322
|
raise NotFound("task not found")
|
|
225
323
|
elif status in ("triage", "todo"):
|
|
226
|
-
if not _set_status_direct(conn, task_id, status):
|
|
324
|
+
if not _set_status_direct(conn, task_id, status, confirm_running_exit=confirm):
|
|
227
325
|
raise NotFound("task not found")
|
|
228
326
|
|
|
229
327
|
|
|
@@ -320,6 +418,7 @@ def board_payload(params: dict) -> dict:
|
|
|
320
418
|
profile = _str(params, "profile") or "default"
|
|
321
419
|
assignee = profile
|
|
322
420
|
with _conn(board=board) as conn:
|
|
421
|
+
_clear_stale_fences(conn)
|
|
323
422
|
latest = _latest_event_id(conn)
|
|
324
423
|
if since is not None and since >= latest:
|
|
325
424
|
return {"changed": False, "latest_event_id": latest, "read_only": False}
|
|
@@ -327,7 +426,7 @@ def board_payload(params: dict) -> dict:
|
|
|
327
426
|
link_counts, comment_counts = _link_counts(conn, tasks), _comment_counts(conn)
|
|
328
427
|
|
|
329
428
|
def row(task):
|
|
330
|
-
data = _task_dict(task)
|
|
429
|
+
data = _task_dict(task, conn)
|
|
331
430
|
data["link_counts"] = link_counts.get(task.id, {"parents": 0, "children": 0})
|
|
332
431
|
data["comment_count"] = comment_counts.get(task.id, 0)
|
|
333
432
|
return data
|
|
@@ -365,7 +464,7 @@ def create_task_payload(params: dict) -> dict:
|
|
|
365
464
|
)
|
|
366
465
|
if body.get("status"):
|
|
367
466
|
_patch_task(conn, task_id, {"status": body.get("status")})
|
|
368
|
-
return {"task": _task_dict(kb.get_task(conn, task_id)), "read_only": False}
|
|
467
|
+
return {"task": _task_dict(kb.get_task(conn, task_id), conn), "read_only": False}
|
|
369
468
|
|
|
370
469
|
|
|
371
470
|
def patch_task_payload(params: dict) -> dict:
|
|
@@ -375,7 +474,7 @@ def patch_task_payload(params: dict) -> dict:
|
|
|
375
474
|
kb = _kb()
|
|
376
475
|
with _conn(board=_board(params)) as conn:
|
|
377
476
|
_patch_task(conn, task_id, params.get("patch") or {})
|
|
378
|
-
return {"task": _task_dict(kb.get_task(conn, task_id)), "read_only": False}
|
|
477
|
+
return {"task": _task_dict(kb.get_task(conn, task_id), conn), "read_only": False}
|
|
379
478
|
|
|
380
479
|
|
|
381
480
|
def comment_payload(params: dict) -> dict:
|
|
@@ -418,7 +517,7 @@ def task_detail_payload(params: dict) -> dict:
|
|
|
418
517
|
if not task:
|
|
419
518
|
raise NotFound("task not found")
|
|
420
519
|
return {
|
|
421
|
-
"task": _task_dict(task),
|
|
520
|
+
"task": _task_dict(task, conn),
|
|
422
521
|
"comments": [_obj_dict(c) for c in kb.list_comments(conn, task_id)],
|
|
423
522
|
"events": [_obj_dict(e) for e in kb.list_events(conn, task_id)],
|
|
424
523
|
"links": {"parents": kb.parent_ids(conn, task_id), "children": kb.child_ids(conn, task_id)},
|
|
@@ -533,7 +632,8 @@ def bulk_payload(params: dict) -> dict:
|
|
|
533
632
|
results.append(entry)
|
|
534
633
|
continue
|
|
535
634
|
if body.get("archive"):
|
|
536
|
-
|
|
635
|
+
# Bulk carries no running-exit confirmation, so a running row is refused like a card write.
|
|
636
|
+
if not _fenced(conn, task_id, lambda: kb.archive_task(conn, task_id), confirm_running_exit=False, releases_claim=False):
|
|
537
637
|
entry.update(ok=False, error="archive refused")
|
|
538
638
|
elif body.get("status") is not None:
|
|
539
639
|
_patch_task(conn, task_id, {"status": body.get("status")})
|
|
@@ -578,7 +678,7 @@ def task_action_payload(params: dict) -> dict:
|
|
|
578
678
|
if not kb.get_task(conn, task_id):
|
|
579
679
|
raise NotFound("task not found")
|
|
580
680
|
if action == "block":
|
|
581
|
-
ok = kb.block_task(conn, task_id, reason=params.get("reason"))
|
|
681
|
+
ok = _fenced(conn, task_id, lambda: kb.block_task(conn, task_id, reason=params.get("reason")), confirm_running_exit=bool(params.get("confirm_running_exit")))
|
|
582
682
|
elif action == "unblock":
|
|
583
683
|
if hasattr(kb, "unblock_task"):
|
|
584
684
|
ok = kb.unblock_task(conn, task_id)
|
|
@@ -589,7 +689,7 @@ def task_action_payload(params: dict) -> dict:
|
|
|
589
689
|
raise InvalidParams(f"invalid action: {action}")
|
|
590
690
|
if not ok:
|
|
591
691
|
raise Conflict(f"{action} refused")
|
|
592
|
-
return {"task": _task_dict(kb.get_task(conn, task_id)), "read_only": False}
|
|
692
|
+
return {"task": _task_dict(kb.get_task(conn, task_id), conn), "read_only": False}
|
|
593
693
|
|
|
594
694
|
|
|
595
695
|
def list_boards_payload(params: dict) -> dict:
|