@maudecode/talaria-web 1.21.0 → 1.22.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 +4 -4
- package/dist/api/automation-router.d.ts +14 -14
- package/dist/api/chat-router.d.ts +217 -68
- package/dist/api/groups-router.d.ts +764 -0
- package/dist/api/groups-router.js +79 -0
- package/dist/api/groups-router.js.map +1 -0
- package/dist/api/raw-routes.js +3 -1
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/sessions-router.d.ts +559 -160
- package/dist/api/sessions-router.js +9 -12
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +911 -1
- package/dist/api/settings-router.js +53 -2
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +1 -1
- package/dist/api/sse-routes.js +11 -3
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +27 -136
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +109 -24
- package/dist/api/tools-router.js +64 -7
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.js +5 -1
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +5 -1
- package/dist/auth/gate.js.map +1 -1
- package/dist/config/agent-config.d.ts +6 -1
- package/dist/config/agent-config.js +75 -3
- package/dist/config/agent-config.js.map +1 -1
- package/dist/feedback.d.ts +18 -0
- package/dist/feedback.js +145 -0
- package/dist/feedback.js.map +1 -0
- package/dist/fs/stat.d.ts +2 -0
- package/dist/fs/stat.js +4 -0
- package/dist/fs/stat.js.map +1 -1
- package/dist/http/context.d.ts +7 -0
- package/dist/http/context.js +0 -6
- package/dist/http/context.js.map +1 -1
- package/dist/http/pinned.js +19 -8
- package/dist/http/pinned.js.map +1 -1
- package/dist/providers/catalog.d.ts +9 -1
- package/dist/providers/catalog.js +86 -6
- package/dist/providers/catalog.js.map +1 -1
- package/dist/redact.js +9 -3
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +27 -4
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +3 -2
- package/dist/sessions/anchor.js +11 -10
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/cli-sessions.js +11 -6
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/compress.d.ts +10 -9
- package/dist/sessions/compress.js +31 -20
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +11 -0
- package/dist/sessions/gateway-sessions.js +79 -24
- package/dist/sessions/gateway-sessions.js.map +1 -1
- package/dist/sessions/gateway-watcher.js +8 -4
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/groups.d.ts +60 -0
- package/dist/sessions/groups.js +339 -0
- package/dist/sessions/groups.js.map +1 -0
- package/dist/sessions/list.d.ts +7 -2
- package/dist/sessions/list.js +13 -4
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +14 -5
- package/dist/sessions/merge.js +42 -13
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/pending.d.ts +1 -1
- package/dist/sessions/pending.js +15 -6
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +1 -14
- package/dist/sessions/prefix-index.js +1 -50
- package/dist/sessions/prefix-index.js.map +1 -1
- package/dist/sessions/reasoning-display.d.ts +2 -0
- package/dist/sessions/reasoning-display.js +31 -0
- package/dist/sessions/reasoning-display.js.map +1 -0
- package/dist/sessions/relay.d.ts +4 -1
- package/dist/sessions/relay.js +44 -7
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +7 -2
- package/dist/sessions/service.js +104 -64
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +6 -0
- package/dist/sessions/session.js +13 -0
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.d.ts +1 -1
- package/dist/sessions/shares.js +13 -4
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/state-db.d.ts +2 -1
- package/dist/sessions/state-db.js +7 -3
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/storage/json-documents.js +2 -0
- package/dist/sessions/storage/json-documents.js.map +1 -1
- package/dist/sessions/store.d.ts +1 -0
- package/dist/sessions/store.js +10 -3
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +2 -0
- package/dist/sessions/streams.js +12 -0
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/todo.js +10 -1
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/turn.js +33 -9
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.js +2 -1
- package/dist/settings.js.map +1 -1
- package/dist/spa.js +1 -1
- package/dist/spa.js.map +1 -1
- package/dist/test/group-fixture.d.ts +66 -0
- package/dist/test/group-fixture.js +89 -0
- package/dist/test/group-fixture.js.map +1 -0
- package/dist/test/harness.d.ts +3 -0
- package/dist/test/harness.js +3 -0
- package/dist/test/harness.js.map +1 -1
- package/dist/tools/connectors.d.ts +9 -1
- package/dist/tools/connectors.js +48 -0
- package/dist/tools/connectors.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +1 -1
- package/dist/tools/skills.d.ts +6 -0
- package/dist/tools/skills.js +17 -0
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/updates.d.ts +16 -9
- package/dist/tools/updates.js +63 -25
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/fs.d.ts +2 -0
- package/dist/workspace/fs.js +63 -1
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/upload.d.ts +1 -1
- package/dist/workspace/upload.js +52 -37
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +5 -1
- package/dist/workspace/workspaces.js +32 -6
- package/dist/workspace/workspaces.js.map +1 -1
- package/package.json +2 -2
- package/sidecar/agent_importer.json +8 -0
- package/sidecar/scripts/agent_importer_contract.py +19 -0
- package/sidecar/scripts/test.sh +3 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/home.py +12 -5
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/agent_imports.py +346 -0
- package/sidecar/talaria_sidecar/methods/chat.py +141 -58
- package/sidecar/talaria_sidecar/methods/commands.py +6 -4
- package/sidecar/talaria_sidecar/methods/config.py +8 -3
- package/sidecar/talaria_sidecar/methods/connectors.py +138 -4
- package/sidecar/talaria_sidecar/methods/dashboard_plugins.py +21 -0
- package/sidecar/talaria_sidecar/methods/delegation.py +126 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +5 -0
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +35 -6
- package/sidecar/talaria_sidecar/methods/groups.py +120 -0
- package/sidecar/talaria_sidecar/methods/memory.py +27 -3
- package/sidecar/talaria_sidecar/methods/nous_account.py +130 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +25 -4
- package/sidecar/talaria_sidecar/methods/outbound_drafts.py +1 -19
- package/sidecar/talaria_sidecar/methods/plugin_catalog.py +73 -2
- package/sidecar/talaria_sidecar/methods/providers.py +51 -1
- package/sidecar/talaria_sidecar/methods/skill_revisions.py +177 -0
- package/sidecar/talaria_sidecar/methods/skills.py +10 -0
- package/sidecar/talaria_sidecar/methods/tts.py +67 -0
- package/sidecar/talaria_sidecar/rpc.py +11 -2
- package/static/dist/FILES.txt +155 -143
- package/static/dist/THIRD_PARTY_LICENSES.md +1 -1
- package/static/dist/assets/AppShell-hvysbd9x.js +8 -0
- package/static/dist/assets/{Button-nuaikybd.js → Button-dlsibkzq.js} +1 -1
- package/static/dist/assets/ChatPage-jikwrwfd.js +2 -0
- package/static/dist/assets/Composer-mnke8ss2.js +5 -0
- package/static/dist/assets/ConnectTargets-ejplzo4q.js +1 -0
- package/static/dist/assets/Dialog-rksfyyq5.js +1 -0
- package/static/dist/assets/{ExtensionRoute-l1yjrso4.js → ExtensionRoute-igk5h0rj.js} +1 -1
- package/static/dist/assets/HubRoute-eooassx4.js +2 -0
- package/static/dist/assets/Markdown-m5pzgvtx.js +2 -0
- package/static/dist/assets/{MarkdownRenderer-ccgqrza3.js → MarkdownRenderer-74ysuomr.js} +6 -6
- package/static/dist/assets/OAuthSignIn-i4flsuq2.js +1 -0
- package/static/dist/assets/QueueCard-msz9wd1m.js +1 -0
- package/static/dist/assets/ResourceSwitch-b70zg4xd.js +1 -0
- package/static/dist/assets/RightPanel-f5v61m8j.js +1 -0
- package/static/dist/assets/Select-f3l897pt.js +1 -0
- package/static/dist/assets/SessionListPanel-brnzacw9.js +1 -0
- package/static/dist/assets/SettingsLayout-f4akmrt2.js +1 -0
- package/static/dist/assets/States-msohx3c0.js +1 -0
- package/static/dist/assets/TerminalPanel-bnu5xawo.js +16 -0
- package/static/dist/assets/Toaster-d6col3ch.js +1 -0
- package/static/dist/assets/_app-lrjgufcy.js +1 -0
- package/static/dist/assets/{_app.ext._extensionId-n797jp72.js → _app.ext._extensionId-k3xitxr1.js} +1 -1
- package/static/dist/assets/_app.groups-bt4wdwnd.js +1 -0
- package/static/dist/assets/{_app.index-ne43mdw2.js → _app.index-n3otiki0.js} +1 -1
- package/static/dist/assets/{_app.insights-fqonovb4.js → _app.insights-b0mzlh6m.js} +1 -1
- package/static/dist/assets/{_app.kanban-kysliv19.js → _app.kanban-d923g7j5.js} +1 -1
- package/static/dist/assets/{_app.logs-febut82r.js → _app.logs-donegue1.js} +1 -1
- package/static/dist/assets/{_app.memory-ha86oj1c.js → _app.memory-hdnled08.js} +1 -1
- package/static/dist/assets/{_app.profiles-cnu3gxxq.js → _app.profiles-fumot3jk.js} +1 -1
- package/static/dist/assets/{_app.session._sessionId-ifzjpcgn.js → _app.session._sessionId-crmdl2ux.js} +1 -1
- package/static/dist/assets/{_app.settings-nmakdiaf.js → _app.settings-jui8iesz.js} +1 -1
- package/static/dist/assets/_app.settings._section-do84hsqw.js +3 -0
- package/static/dist/assets/{_app.skills-f3wad8yo.js → _app.skills-heqcn21m.js} +1 -1
- package/static/dist/assets/_app.tasks-jiudtutt.js +1 -0
- package/static/dist/assets/{_app.todos-bml1m3r1.js → _app.todos-bl6kk2zq.js} +1 -1
- package/static/dist/assets/{_app.workspaces-f3d066lx.js → _app.workspaces-frvh3o7w.js} +1 -1
- package/static/dist/assets/_delete-qnxuo87s.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-i53jc4yp.js → abnfDiagram-VCTEODGH-dppg3yfx.js} +1 -1
- package/static/dist/assets/{architecture-7GRP2DOG-e3bv5m6f.js → architecture-7GRP2DOG-gbajejh3.js} +1 -1
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-pakekxu2.js → architectureDiagram-5GKGNRK7-bzrxyais.js} +1 -1
- package/static/dist/assets/archive-yhdyz231.js +1 -0
- package/static/dist/assets/autoReadClaim-nlyv8tu9.js +1 -0
- package/static/dist/assets/{blockDiagram-I7D4REHJ-bc6bo1n6.js → blockDiagram-I7D4REHJ-gmk9koab.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-btvwk2qx.js → c4Diagram-7LVT6UL2-bfqiqqcz.js} +1 -1
- package/static/dist/assets/channel-grt3rob4.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-dlwab11c.js → chunk-4HAMMTFA-i9s6h4wv.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-dp5gh7i8.js → chunk-75Z2AOVW-gnt6pnso.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-bi06zl1c.js → chunk-DU6HZSFF-gq439wot.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-kvv1rnlh.js → chunk-F27PBJKO-wvx90pbt.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-ji0rx9by.js → chunk-GMAD6QVW-mc2gu30k.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-nmz0j82p.js → chunk-GVQU2GXP-f8fxa2ym.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-kmi1qx88.js → chunk-IMKFNOWR-lnsl31hj.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-xhb7mebj.js → chunk-L3NEJ4N5-kbfdidwu.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-5a9sgscq.js → chunk-OSK3NFVY-dvxsduj6.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-dfezp4vu.js → chunk-P2QGCYS3-ivo3i1wf.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-gd2vq3c0.js → chunk-POPQ4Y6H-i0gfu0hx.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-wvw2nksf.js → chunk-PWAF6VOD-jb0fdyb0.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-f58q97px.js → chunk-SHT3W25Y-b7ou2xsp.js} +1 -1
- package/static/dist/assets/{chunk-SVP7TREG-abgwpyz9.js → chunk-SVP7TREG-e2v7me5v.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-h4sbs8ds.js → chunk-TICWLB2K-e5zlai62.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-nnsp49jr.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-nnsp49jr.js +1 -0
- package/static/dist/assets/completionAudio-c5at041z.js +1 -0
- package/static/dist/assets/{copy-m9h56qa8.js → copy-jj3oiw13.js} +1 -1
- package/static/dist/assets/{cynefin-OW5HDTMX-g081vffs.js → cynefin-OW5HDTMX-n5n1ck70.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-odxvjesk.js → cynefinDiagram-5FMLGOSQ-b33npu4f.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-cpdwzjs4.js → dagre-GXQ25YYZ-miwvae07.js} +1 -1
- package/static/dist/assets/{diagram-S7CK7UJ4-clv5mxvu.js → diagram-S7CK7UJ4-j8fphsp4.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-m2ia1mbf.js → diagram-UQ7AKVKN-5cixo166.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-ea6zv636.js → diagram-VSXAHHWV-ii3bf92m.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-oqlef685.js → diagram-VX7I27RA-b3cfgx81.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-kjubcbwu.js → diagram-Z3DM3KII-bey9lqr8.js} +1 -1
- package/static/dist/assets/{dist-carq1azj.js → dist-cb8um5dh.js} +4 -4
- package/static/dist/assets/{dist-crc46di9.js → dist-kpg5ccm9.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-fg0zri3e.js → ebnfDiagram-PWID7BFC-2m4wrnqc.js} +1 -1
- package/static/dist/assets/{erDiagram-RLTQ6QDP-eb7pmk3x.js → erDiagram-RLTQ6QDP-kak5te0n.js} +1 -1
- package/static/dist/assets/{eventmodeling-NTZA5JFV-gvi1fxhn.js → eventmodeling-NTZA5JFV-ojcc486t.js} +1 -1
- package/static/dist/assets/flowDiagram-HODETNUW-kxr9sicu.js +1 -0
- package/static/dist/assets/folder-plus-fk6j7tlv.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-jmisowrc.js → ganttDiagram-EL5Y4UJY-k6nfmhrh.js} +1 -1
- package/static/dist/assets/getPseudoElementBounds-mwj3vqni.js +1 -0
- package/static/dist/assets/{gitGraph-4MIJSDKK-m7kt3u6e.js → gitGraph-4MIJSDKK-bxq1lbhy.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-nq7vfzh2.js → gitGraphDiagram-WWUBYQGX-ehvoankt.js} +1 -1
- package/static/dist/assets/group_discussions-fk5hry4l.js +1 -0
- package/static/dist/assets/{highlighted-body-KPVGNVTW-gcu017ay.js → highlighted-body-KPVGNVTW-nr4nfdq7.js} +1 -1
- package/static/dist/assets/{host-ipp4e84c.js → host-dhgqiozp.js} +1 -1
- package/static/dist/assets/index-hx7z4wdj.js +13 -0
- package/static/dist/assets/index-o8ebuc5x.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-idazwfqe.js → info-A6RAGUB7-dtsj0ybw.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-bb9jh8gl.js → infoDiagram-27XIBGKW-jena90ao.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-nqc132rv.js → ishikawaDiagram-5VMMS53U-kia6bn5u.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-fpvnhy44.js → journeyDiagram-3NMN7TZE-ipsa6icb.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-ndzqm6fu.js → kanban-definition-UXKFOSKX-moxx59kp.js} +1 -1
- package/static/dist/assets/katex-ic33v820.js +257 -0
- package/static/dist/assets/katex-qcv7xo0t.css +1 -0
- package/static/dist/assets/{lazyRouteComponent-javud235.js → lazyRouteComponent-i74ujrfk.js} +1 -1
- package/static/dist/assets/{line-g625e7cj.js → line-lgrkg9no.js} +1 -1
- package/static/dist/assets/link-2-fp49mwl2.js +1 -0
- package/static/dist/assets/{link-gfdaho08.js → link-es18mse1.js} +2 -2
- package/static/dist/assets/{locale-cs-n41hptse.js → locale-cs-brltdkcp.js} +1 -1
- package/static/dist/assets/{locale-de-k7ht47ew.js → locale-de-h6e9oq6v.js} +1 -1
- package/static/dist/assets/{locale-es-ih078lco.js → locale-es-oklmh80f.js} +1 -1
- package/static/dist/assets/{locale-fr-ojabnf41.js → locale-fr-b17ozoi2.js} +1 -1
- package/static/dist/assets/{locale-it-kb96jufy.js → locale-it-whe01eef.js} +1 -1
- package/static/dist/assets/{locale-ja-jpsp3xs1.js → locale-ja-g1s0rtpc.js} +1 -1
- package/static/dist/assets/{locale-pl-dbap4leu.js → locale-pl-d9p3lqcb.js} +1 -1
- package/static/dist/assets/{locale-pt-nci7w72x.js → locale-pt-l75on74f.js} +1 -1
- package/static/dist/assets/{locale-ru-soghe4cs.js → locale-ru-wl3mbsaw.js} +1 -1
- package/static/dist/assets/{locale-tr-ks00mu68.js → locale-tr-cz87itrq.js} +1 -1
- package/static/dist/assets/{locale-vi-ij7twfm6.js → locale-vi-elqj1y4k.js} +1 -1
- package/static/dist/assets/{locale-zh-Hant-feakwr7a.js → locale-zh-Hant-hf8gqm7d.js} +1 -1
- package/static/dist/assets/{locale-zh-ren0vjyv.js → locale-zh-cdckwb0u.js} +1 -1
- package/static/dist/assets/login-o6gfl4gy.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-n2kbzsao.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-plzkuzov.js → mermaid-parser.core-fflovwf2.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-ojrgs569.js → mindmap-definition-YA3MSWOX-ic8l9whi.js} +1 -1
- package/static/dist/assets/onboarding-bxm7gdrr.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-gyaf9s8h.js → packet-AYTQ26CC-ntci3088.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-bf6xj8mq.js → pegDiagram-XKGWAZYB-e3btz04w.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-f5ymzelo.js → pie-WAS4IAKB-o2dc7l36.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-d0qjl3zi.js → pieDiagram-E7YTZNPT-gro55rrw.js} +1 -1
- package/static/dist/assets/presence-lq6m12ga.js +1 -0
- package/static/dist/assets/prompt_queue_cancelled-cebcuagu.js +1 -0
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-oqy1mras.js → quadrantDiagram-AXDQQJYC-fxulmd7d.js} +1 -1
- package/static/dist/assets/queryKeys-cnvn6pea.js +9 -0
- package/static/dist/assets/{radar-RG4KPBEZ-b6jcjvda.js → radar-RG4KPBEZ-9pcospra.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-e3a6lk5k.js → railroad-74A4TZTK-nzdga12j.js} +1 -1
- package/static/dist/assets/{railroad-abnf-HS5TGJTU-ff5hocrx.js → railroad-abnf-HS5TGJTU-ep3ytel0.js} +1 -1
- package/static/dist/assets/{railroad-ebnf-LZEXJU2U-exkhyw4n.js → railroad-ebnf-LZEXJU2U-iw7uc1wy.js} +1 -1
- package/static/dist/assets/{railroad-peg-WCYAUIDC-jefk9b7c.js → railroad-peg-WCYAUIDC-fo3b3gme.js} +1 -1
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-e4amks1i.js → railroadDiagram-O6MQD6OU-lxpxf8f0.js} +1 -1
- package/static/dist/assets/{refresh-cw-lfp4u1oh.js → refresh-cw-d14h79x5.js} +1 -1
- package/static/dist/assets/rename-ccd52yws.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-c77k1e2y.js → requirementDiagram-BXWQKSXE-lrozucd2.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-oa1cc52s.js → sankeyDiagram-P5KCCOFB-iusxy9mq.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-j20gqt22.js → sequenceDiagram-WJ2MYXX4-o987q8ti.js} +1 -1
- package/static/dist/assets/{share._token-kmfoflw6.js → share._token-bfw7f9m5.js} +2 -2
- package/static/dist/assets/sliders-horizontal-l65hoa3x.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-co2ghkdp.js → stateDiagram-D77RDMKH-hh23v7y5.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-jukr0d8h.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-m30cktqe.js → swimlanes-42K2YHIH-gj2t3rm8.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ik9m9j2m.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-liuep6fl.js → timeline-definition-24CTP7MA-84s2w2sr.js} +1 -1
- package/static/dist/assets/toast-gqqcvxiy.js +56 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-np5d2jv2.js → treeView-Q6P3EWNA-cmuj50l7.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-cmpltxh1.js → treemap-WGGIJYW6-dpjlg0xc.js} +1 -1
- package/static/dist/assets/tts-jw84jlqy.js +1 -0
- package/static/dist/assets/{useForm-f1udzsjf.js → useForm-lxzhiqao.js} +1 -1
- package/static/dist/assets/{useParams-ierevvts.js → useParams-dt6gkoq7.js} +1 -1
- package/static/dist/assets/{useSearch-i7nr9ypl.js → useSearch-o8t49csk.js} +1 -1
- package/static/dist/assets/useTranscript-gx9umcc2.js +1 -0
- package/static/dist/assets/{vennDiagram-4TSXK5OY-b2g42qrg.js → vennDiagram-4TSXK5OY-g9g5o8vy.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-lb0eqbff.js → wardley-WFR3VGLG-ij35obrl.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ermwaqha.js → wardleyDiagram-VM6X3IG4-f9my7q7w.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-dll0jldk.js → xychartDiagram-S5SC5T6Z-olqx1s1p.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +1 -1
- package/static/dist/assets/AppShell-c5989995.js +0 -8
- package/static/dist/assets/ChatPage-bfg4khph.js +0 -6
- package/static/dist/assets/ConnectTargets-k5wo9yo8.js +0 -1
- package/static/dist/assets/Dialog-o8vo2aws.js +0 -1
- package/static/dist/assets/Field-j7o8cfps.js +0 -1
- package/static/dist/assets/HubRoute-efnwe4xz.js +0 -2
- package/static/dist/assets/Markdown-clqf5m22.js +0 -2
- package/static/dist/assets/OAuthSignIn-h7bjaqp6.js +0 -1
- package/static/dist/assets/ResourceSwitch-oai2zqaj.js +0 -1
- package/static/dist/assets/RightPanel-ho161a45.js +0 -1
- package/static/dist/assets/Select-d1g5a8bm.js +0 -1
- package/static/dist/assets/SessionListPanel-i7kaokhi.js +0 -1
- package/static/dist/assets/SettingsLayout-lnecm87w.js +0 -1
- package/static/dist/assets/States-easntmry.js +0 -1
- package/static/dist/assets/TerminalPanel-lxhwd4jl.js +0 -16
- package/static/dist/assets/Toaster-l4sciy8t.js +0 -1
- package/static/dist/assets/_app-mqexqbg8.js +0 -1
- package/static/dist/assets/_app.settings._section-djglnjmi.js +0 -3
- package/static/dist/assets/_app.tasks-l10py1c0.js +0 -1
- package/static/dist/assets/archive-ihqi7z2x.js +0 -1
- package/static/dist/assets/channel-jn4f8443.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-dzrw66se.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-dzrw66se.js +0 -1
- package/static/dist/assets/completionAudio-ce86msbu.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-abekab15.js +0 -1
- package/static/dist/assets/folder-plus-ksaons88.js +0 -1
- package/static/dist/assets/index-d6vbxlra.js +0 -13
- package/static/dist/assets/index-ey6qo0zx.css +0 -2
- package/static/dist/assets/katex-cbdd1ohw.css +0 -1
- package/static/dist/assets/katex-pbij2oo6.js +0 -257
- package/static/dist/assets/login-iv6yq4xf.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-cwj5cl6k.js +0 -1
- package/static/dist/assets/onboarding-ff4emacu.js +0 -1
- package/static/dist/assets/queryKeys-x8fjxhut.js +0 -9
- package/static/dist/assets/sliders-horizontal-g5jkzd9k.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-faw1opgh.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hfil433g.js +0 -8
- package/static/dist/assets/toast-zmb35u3r.js +0 -56
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Provision reviewed native API bytes outside tests, into the checker's disposable directory."""
|
|
2
|
+
import hashlib
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from urllib.request import urlopen
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def provision(target):
|
|
9
|
+
reviewed = json.loads((Path(__file__).parents[1] / 'agent_importer.json').read_text())
|
|
10
|
+
pin = reviewed['revision']
|
|
11
|
+
target = Path(target)
|
|
12
|
+
target.mkdir()
|
|
13
|
+
for name, expected in reviewed['files'].items():
|
|
14
|
+
with urlopen(f'https://raw.githubusercontent.com/NousResearch/hermes-official-plugins/{pin}/agent-importers/{name}', timeout=30) as response:
|
|
15
|
+
body = response.read(256 * 1024)
|
|
16
|
+
if hashlib.sha256(body).hexdigest() != expected:
|
|
17
|
+
raise ValueError('Reviewed importer contract source changed')
|
|
18
|
+
(target / name).write_bytes(body)
|
|
19
|
+
return target
|
package/sidecar/scripts/test.sh
CHANGED
|
@@ -12,7 +12,8 @@ fi
|
|
|
12
12
|
venv="$here/.venv"
|
|
13
13
|
if [[ ! -x "$venv/bin/python" ]]; then
|
|
14
14
|
"$runner" -m venv "$venv"
|
|
15
|
-
|
|
15
|
+
# pytest 9.2 renames parametrized case ids, which the reviewed inventory in tests/process_inventory.json lists.
|
|
16
|
+
"$venv/bin/python" -m pip install --quiet --disable-pip-version-check "pytest>=8,<9.2"
|
|
16
17
|
fi
|
|
17
18
|
state="${TMPDIR:-/tmp}/talaria-sidecar-tests.$$"
|
|
18
19
|
mkdir -p "$state"
|
|
@@ -20,6 +21,7 @@ trap 'rm -rf -- "$state"' EXIT
|
|
|
20
21
|
cd "$here"
|
|
21
22
|
# GitHub's relocated Linux Python needs LD_LIBRARY_PATH; nothing else from the caller's environment leaks in.
|
|
22
23
|
env -i PATH="$PATH" HOME="$state" TMPDIR="$state" ${LD_LIBRARY_PATH:+LD_LIBRARY_PATH="$LD_LIBRARY_PATH"} \
|
|
24
|
+
HERMES_WEBUI_IMPORTER_DIR="${HERMES_WEBUI_IMPORTER_DIR:-}" \
|
|
23
25
|
HERMES_WEBUI_AGENT_DIR="${HERMES_WEBUI_AGENT_DIR:-}" \
|
|
24
26
|
HERMES_WEBUI_PYTHON="${HERMES_WEBUI_PYTHON:-}" \
|
|
25
27
|
${TALARIA_SIDECAR_WORKERS+TALARIA_SIDECAR_WORKERS="$TALARIA_SIDECAR_WORKERS"} \
|
|
@@ -310,8 +310,8 @@ def _recover_processes(home: Path) -> None:
|
|
|
310
310
|
|
|
311
311
|
|
|
312
312
|
@contextlib.contextmanager
|
|
313
|
-
def scoped_home(home: Path, *, load_plugins: bool = True):
|
|
314
|
-
"""
|
|
313
|
+
def scoped_home(home: Path, *, load_plugins: bool = True, recover_processes: bool = True, read_only: bool = False):
|
|
314
|
+
"""Bind the home; read-only inspection skips credential hydration, terminal defaults and recovery."""
|
|
315
315
|
home = Path(home).expanduser()
|
|
316
316
|
stamp = _scope_stamp(home)
|
|
317
317
|
try:
|
|
@@ -321,18 +321,25 @@ def scoped_home(home: Path, *, load_plugins: bool = True):
|
|
|
321
321
|
if set_hermes_home_override is not None:
|
|
322
322
|
token = set_hermes_home_override(home)
|
|
323
323
|
try:
|
|
324
|
-
|
|
325
|
-
_recover_processes(home)
|
|
324
|
+
if read_only:
|
|
326
325
|
yield home
|
|
326
|
+
else:
|
|
327
|
+
with _secret_scope(home, stamp, load_plugins=load_plugins), _terminal_scope(home, stamp):
|
|
328
|
+
if recover_processes:
|
|
329
|
+
_recover_processes(home)
|
|
330
|
+
yield home
|
|
327
331
|
finally:
|
|
328
332
|
reset_hermes_home_override(token)
|
|
329
333
|
return
|
|
334
|
+
if read_only:
|
|
335
|
+
raise RpcError("Read-only profile binding is unavailable", condition="agent_incompatible")
|
|
330
336
|
with _ENV_LOCK:
|
|
331
337
|
previous = os.environ.get("HERMES_HOME")
|
|
332
338
|
os.environ["HERMES_HOME"] = str(home)
|
|
333
339
|
try:
|
|
334
340
|
with _secret_scope(home, stamp, load_plugins=load_plugins), _terminal_scope(home, stamp):
|
|
335
|
-
|
|
341
|
+
if recover_processes:
|
|
342
|
+
_recover_processes(home)
|
|
336
343
|
yield home
|
|
337
344
|
finally:
|
|
338
345
|
if previous is None:
|
|
@@ -29,9 +29,9 @@ class Registry:
|
|
|
29
29
|
|
|
30
30
|
def build_methods(runtime: AgentRuntime) -> dict[str, Handler]:
|
|
31
31
|
registry = Registry(runtime)
|
|
32
|
-
from . import aux, chat, checkpoints, commands, config, connectors, cron, dashboard_plugins, gateway, goals, kanban, mcp, managed_buffers, memory, oauth, outbound_drafts, plugin_oauth, process, profiles, providers, skills, state_db, stt, text, toolsets, usage, worktree, write_approval # noqa: WPS433
|
|
32
|
+
from . import agent_imports, aux, chat, checkpoints, commands, config, connectors, cron, dashboard_plugins, delegation, gateway, goals, kanban, mcp, managed_buffers, memory, oauth, outbound_drafts, plugin_oauth, process, profiles, providers, skills, state_db, stt, tts, text, toolsets, usage, worktree, write_approval # noqa: WPS433
|
|
33
33
|
from . import runtime as runtime_methods
|
|
34
34
|
|
|
35
|
-
for module in (runtime_methods, goals, commands, kanban, state_db, profiles, skills, mcp, stt, cron, providers, oauth, plugin_oauth, aux, text, process, usage, gateway, worktree, checkpoints, memory, chat, config, toolsets, write_approval, connectors, dashboard_plugins, outbound_drafts, managed_buffers):
|
|
35
|
+
for module in (agent_imports, runtime_methods, goals, commands, kanban, state_db, profiles, skills, mcp, stt, tts, cron, providers, oauth, plugin_oauth, aux, delegation, text, process, usage, gateway, worktree, checkpoints, memory, chat, config, toolsets, write_approval, connectors, dashboard_plugins, outbound_drafts, managed_buffers):
|
|
36
36
|
module.register(registry)
|
|
37
37
|
return registry.methods
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"""Profile import adapter. Native planning runs on private snapshots; publication uses anchored descriptors."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from contextlib import contextmanager, nullcontext
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
from itertools import islice
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import re
|
|
11
|
+
import secrets
|
|
12
|
+
import stat
|
|
13
|
+
import tempfile
|
|
14
|
+
import time
|
|
15
|
+
|
|
16
|
+
from .. import home as homes
|
|
17
|
+
from ..errors import InvalidParams, RpcError
|
|
18
|
+
from . import config, memory, plugin_catalog
|
|
19
|
+
|
|
20
|
+
_SOURCES = {'claude-code': ('.claude', 'Claude Code'), 'codex': ('.codex', 'Codex CLI'), 'cursor': ('.cursor', 'Cursor')}
|
|
21
|
+
_CREDENTIALS = {'.credentials.json', 'auth.json', 'credentials.json', 'cli-config.json', '.env'}
|
|
22
|
+
_TARGETS = ('config.yaml', 'memories', 'skills', 'import-sync.json')
|
|
23
|
+
_MEMORY_FILES = {'memories/MEMORY.md', 'memories/USER.md'}
|
|
24
|
+
_PREVIEWS = {}
|
|
25
|
+
_MAX_FILES = 2048
|
|
26
|
+
_MAX_BYTES = 16 * 1024 * 1024
|
|
27
|
+
_LEDGER = '.talaria-agent-imports'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _result(status, *, items=None, stripped=None, receipt=None, sources=None, message=None, can_apply=False, catalog_required=False):
|
|
31
|
+
return dict(status=status, items=items or [], stripped_secrets=stripped or [], receipt=receipt,
|
|
32
|
+
sources=sources or [], message=message, can_apply=can_apply, catalog_required=catalog_required)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@contextmanager
|
|
36
|
+
def _directory(path):
|
|
37
|
+
"""Open every ancestor without following links; the held descriptor owns all subsequent IO."""
|
|
38
|
+
path = Path(path)
|
|
39
|
+
if not path.is_absolute():
|
|
40
|
+
raise OSError('An absolute directory is required')
|
|
41
|
+
fd = os.open(path.anchor, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
|
|
42
|
+
try:
|
|
43
|
+
for part in path.parts[1:]:
|
|
44
|
+
child = os.open(part, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW, dir_fd=fd)
|
|
45
|
+
os.close(fd)
|
|
46
|
+
fd = child
|
|
47
|
+
yield fd
|
|
48
|
+
finally:
|
|
49
|
+
os.close(fd)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _read(fd, name):
|
|
53
|
+
child = os.open(name, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK, dir_fd=fd)
|
|
54
|
+
try:
|
|
55
|
+
info = os.fstat(child)
|
|
56
|
+
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_size > _MAX_BYTES:
|
|
57
|
+
raise OSError('Unsafe or oversized import file')
|
|
58
|
+
with os.fdopen(os.dup(child), 'rb') as stream:
|
|
59
|
+
body = stream.read(_MAX_BYTES + 1)
|
|
60
|
+
after = os.fstat(child)
|
|
61
|
+
if (info.st_size, info.st_mtime_ns, info.st_ctime_ns) != (after.st_size, after.st_mtime_ns, after.st_ctime_ns):
|
|
62
|
+
raise OSError('Import input changed during read')
|
|
63
|
+
return body, (info.st_dev, info.st_ino, info.st_mode, info.st_mtime_ns, info.st_ctime_ns)
|
|
64
|
+
finally:
|
|
65
|
+
os.close(child)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _snapshot(path, names):
|
|
69
|
+
"""Bounded snapshot of only importer inputs. Credential stores are never read."""
|
|
70
|
+
files, identities = {}, {}
|
|
71
|
+
def walk(fd, name, rel):
|
|
72
|
+
try:
|
|
73
|
+
info = os.stat(name, dir_fd=fd, follow_symlinks=False)
|
|
74
|
+
except FileNotFoundError:
|
|
75
|
+
return
|
|
76
|
+
if rel.endswith('.lock') and rel[:-5] in _MEMORY_FILES:
|
|
77
|
+
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1:
|
|
78
|
+
raise OSError('Unsafe memory lock')
|
|
79
|
+
return
|
|
80
|
+
if stat.S_ISDIR(info.st_mode):
|
|
81
|
+
child = os.open(name, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW, dir_fd=fd)
|
|
82
|
+
try:
|
|
83
|
+
identities[rel] = (info.st_dev, info.st_ino, info.st_mode)
|
|
84
|
+
if len(identities) > _MAX_FILES:
|
|
85
|
+
raise OSError('Import tree too large')
|
|
86
|
+
with os.scandir(child) as entries:
|
|
87
|
+
names = [entry.name for entry in islice(entries, _MAX_FILES + 1)]
|
|
88
|
+
if len(names) > _MAX_FILES:
|
|
89
|
+
raise OSError('Import directory too large')
|
|
90
|
+
for entry in sorted(names):
|
|
91
|
+
if entry not in _CREDENTIALS and entry not in {'.git', '__pycache__'}:
|
|
92
|
+
walk(child, entry, rel + '/' + entry)
|
|
93
|
+
finally:
|
|
94
|
+
os.close(child)
|
|
95
|
+
else:
|
|
96
|
+
body, identity = _read(fd, name)
|
|
97
|
+
files[rel], identities[rel] = body, identity
|
|
98
|
+
if len(identities) > _MAX_FILES or sum(map(len, files.values())) > _MAX_BYTES:
|
|
99
|
+
raise OSError('Import tree too large')
|
|
100
|
+
with _directory(path) as fd:
|
|
101
|
+
info = os.fstat(fd)
|
|
102
|
+
identities['.'] = (info.st_dev, info.st_ino, info.st_mode)
|
|
103
|
+
for name in names:
|
|
104
|
+
walk(fd, name, name)
|
|
105
|
+
return files, identities
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _source(agent):
|
|
109
|
+
os_home = Path.home()
|
|
110
|
+
source = os_home / _SOURCES[agent][0]
|
|
111
|
+
names = {'claude-code': ['CLAUDE.md', 'settings.json', 'skills', 'commands'],
|
|
112
|
+
'codex': ['AGENTS.md', 'config.toml', 'memories', 'skills'],
|
|
113
|
+
'cursor': ['AGENTS.md', 'mcp.json', 'rules', 'skills']}[agent]
|
|
114
|
+
files, identity = _snapshot(source, names)
|
|
115
|
+
if agent == 'claude-code':
|
|
116
|
+
extra, extra_identity = _snapshot(os_home, ['.claude.json'])
|
|
117
|
+
files.update({'../' + k: v for k, v in extra.items()})
|
|
118
|
+
identity.update({'../' + k: v for k, v in extra_identity.items()})
|
|
119
|
+
return source, files, identity
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _stamp(snapshot):
|
|
123
|
+
files, identities = snapshot
|
|
124
|
+
return hashlib.sha256(json.dumps([identities, {k: hashlib.sha256(v).hexdigest() for k, v in files.items()}], sort_keys=True).encode()).hexdigest()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _materialize(root, files, identities):
|
|
128
|
+
root.mkdir()
|
|
129
|
+
for name, info in identities.items():
|
|
130
|
+
if name != '.' and stat.S_ISDIR(info[2]):
|
|
131
|
+
(root / name).mkdir(parents=True, exist_ok=True)
|
|
132
|
+
for name, body in files.items():
|
|
133
|
+
path = root / name
|
|
134
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
135
|
+
path.write_bytes(body)
|
|
136
|
+
path.chmod(stat.S_IMODE(identities[name][2]))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _project(report):
|
|
140
|
+
# No native reason, path, command, content or arbitrary detail crosses the boundary.
|
|
141
|
+
kinds = {'source': 'Source', 'settings': 'Settings', 'claude-md': 'Claude Code instructions',
|
|
142
|
+
'agents-md': 'Instructions', 'command-allowlist': 'Allowed commands', 'command-denylist': 'Denied commands',
|
|
143
|
+
'mcp-servers': 'MCP servers', 'skills': 'Skills', 'skill': 'Skill', 'memories': 'Memories',
|
|
144
|
+
'rules': 'Cursor rules', 'config': 'Configuration', 'slash-commands': 'Slash commands'}
|
|
145
|
+
statuses = {'imported', 'skipped', 'conflict', 'error'}
|
|
146
|
+
items = report.get('items')
|
|
147
|
+
if not isinstance(items, list) or len(items) > _MAX_FILES:
|
|
148
|
+
raise ValueError('Invalid native report')
|
|
149
|
+
projected = []
|
|
150
|
+
for item in items:
|
|
151
|
+
if not isinstance(item, dict) or item.get('kind') not in kinds or item.get('status') not in statuses:
|
|
152
|
+
raise ValueError('Invalid native disposition')
|
|
153
|
+
projected.append(dict(kind=item['kind'], status=item['status'], label=kinds[item['kind']]))
|
|
154
|
+
stripped = report.get('stripped_secrets', [])
|
|
155
|
+
if not isinstance(stripped, list) or len(stripped) > _MAX_FILES:
|
|
156
|
+
raise ValueError('Invalid stripped-secret names')
|
|
157
|
+
return projected, [name for name in stripped if isinstance(name, str) and len(name) <= 200
|
|
158
|
+
and re.fullmatch(r'[A-Za-z0-9_.-]+', name)]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@contextmanager
|
|
162
|
+
def _parent(root_fd, rel, create=False):
|
|
163
|
+
parts = Path(rel).parts
|
|
164
|
+
if not parts or any(p in ('.', '..') for p in parts) or Path(rel).is_absolute():
|
|
165
|
+
raise OSError('Unsafe output path')
|
|
166
|
+
fd = os.dup(root_fd)
|
|
167
|
+
try:
|
|
168
|
+
for part in parts[:-1]:
|
|
169
|
+
if create:
|
|
170
|
+
try:
|
|
171
|
+
os.mkdir(part, 0o700, dir_fd=fd)
|
|
172
|
+
os.fsync(fd)
|
|
173
|
+
except FileExistsError:
|
|
174
|
+
pass
|
|
175
|
+
child = os.open(part, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW, dir_fd=fd)
|
|
176
|
+
os.close(fd)
|
|
177
|
+
fd = child
|
|
178
|
+
yield fd, parts[-1]
|
|
179
|
+
finally:
|
|
180
|
+
os.close(fd)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _write(root_fd, rel, body, *, exclusive=False, mode=0o600, expected=None):
|
|
184
|
+
with _parent(root_fd, rel, create=True) as (fd, name):
|
|
185
|
+
tmp = '.import-' + secrets.token_hex(16)
|
|
186
|
+
child = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600, dir_fd=fd)
|
|
187
|
+
try:
|
|
188
|
+
with os.fdopen(child, 'wb') as stream:
|
|
189
|
+
os.fchmod(stream.fileno(), stat.S_IMODE(mode) & 0o777)
|
|
190
|
+
stream.write(body)
|
|
191
|
+
stream.flush()
|
|
192
|
+
os.fsync(stream.fileno())
|
|
193
|
+
guard = memory.file_lock(Path(name), parent_fd=fd) if rel in _MEMORY_FILES else nullcontext()
|
|
194
|
+
with guard:
|
|
195
|
+
if expected is not None and _read(fd, name) != expected:
|
|
196
|
+
raise OSError('Import destination changed during publication')
|
|
197
|
+
if exclusive:
|
|
198
|
+
os.link(tmp, name, src_dir_fd=fd, dst_dir_fd=fd, follow_symlinks=False)
|
|
199
|
+
else:
|
|
200
|
+
# Replacing a link cannot follow it. Never mutate the old inode in place.
|
|
201
|
+
os.rename(tmp, name, src_dir_fd=fd, dst_dir_fd=fd)
|
|
202
|
+
os.fsync(fd)
|
|
203
|
+
finally:
|
|
204
|
+
try:
|
|
205
|
+
os.unlink(tmp, dir_fd=fd)
|
|
206
|
+
except FileNotFoundError:
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _ledger(root_fd, token, result=None):
|
|
211
|
+
name = _LEDGER + '/' + hashlib.sha256(token.encode()).hexdigest() + '.json'
|
|
212
|
+
if result is not None:
|
|
213
|
+
_write(root_fd, name, json.dumps(result).encode())
|
|
214
|
+
return result
|
|
215
|
+
try:
|
|
216
|
+
with _parent(root_fd, name) as (fd, leaf):
|
|
217
|
+
return json.loads(_read(fd, leaf)[0])
|
|
218
|
+
except FileNotFoundError:
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _refresh_runtime(home):
|
|
223
|
+
from .commands import _reload_mcp, _reload_skills
|
|
224
|
+
try:
|
|
225
|
+
with homes.scoped_home(home, load_plugins=False):
|
|
226
|
+
_reload_skills()
|
|
227
|
+
_reload_mcp(log_errors=False)
|
|
228
|
+
return True
|
|
229
|
+
except Exception:
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def run(ctx, params):
|
|
234
|
+
action, agent, token = params.get('action'), params.get('agent'), params.get('receipt')
|
|
235
|
+
if action not in ('discover', 'preview', 'apply', 'result') or action == 'preview' and agent not in _SOURCES or action in ('apply', 'result') and (not isinstance(token, str) or not 0 < len(token) <= 128):
|
|
236
|
+
raise InvalidParams('Invalid profile import request')
|
|
237
|
+
home = homes.profile_home_param(params)
|
|
238
|
+
with homes.scoped_home(home, load_plugins=False, read_only=True), plugin_catalog._lock:
|
|
239
|
+
try:
|
|
240
|
+
with _directory(home) as root_fd:
|
|
241
|
+
# Read the durable consumption record before plugin/source checks. A retry is readback only.
|
|
242
|
+
if action in ('apply', 'result'):
|
|
243
|
+
previous = _ledger(root_fd, token)
|
|
244
|
+
if previous is not None:
|
|
245
|
+
if 'expected' in previous:
|
|
246
|
+
files, _ = _snapshot(home, _TARGETS)
|
|
247
|
+
if all(name in files and hashlib.sha256(files[name]).hexdigest() == digest for name, digest in previous['expected'].items()):
|
|
248
|
+
return _ledger(root_fd, token, previous['confirmed'])
|
|
249
|
+
return previous['result']
|
|
250
|
+
return previous
|
|
251
|
+
if action == 'result':
|
|
252
|
+
# Fence a late apply that never reached the consumption record.
|
|
253
|
+
_PREVIEWS.pop(token, None)
|
|
254
|
+
return _result('changed', message='No import was confirmed. Preview again.')
|
|
255
|
+
try:
|
|
256
|
+
config.assert_config_writable(home)
|
|
257
|
+
except RpcError:
|
|
258
|
+
return _result('unavailable', message='Profile configuration is managed or its write policy cannot be verified. Import is unavailable.')
|
|
259
|
+
native = plugin_catalog.reviewed_importer(home)
|
|
260
|
+
if native is None:
|
|
261
|
+
return _result('unavailable', message='Install and enable Agent Importers from the plugin catalog.', catalog_required=True)
|
|
262
|
+
importer, sync, plugin = native
|
|
263
|
+
if action == 'discover':
|
|
264
|
+
sources = []
|
|
265
|
+
for name, (_, label) in _SOURCES.items():
|
|
266
|
+
try:
|
|
267
|
+
_source(name)
|
|
268
|
+
sources.append(dict(agent=name, label=label))
|
|
269
|
+
except OSError:
|
|
270
|
+
pass
|
|
271
|
+
return _result('available', sources=sources)
|
|
272
|
+
now = time.monotonic()
|
|
273
|
+
for old in list(_PREVIEWS):
|
|
274
|
+
if _PREVIEWS[old]['expires'] <= now:
|
|
275
|
+
del _PREVIEWS[old]
|
|
276
|
+
receipt = _PREVIEWS.get(token) if action == 'apply' else None
|
|
277
|
+
if action == 'apply' and (receipt is None or receipt['home'] != str(home)):
|
|
278
|
+
return _result('changed', message='Preview expired or belongs to another profile. Preview again.')
|
|
279
|
+
agent = receipt['agent'] if receipt else agent
|
|
280
|
+
source, source_files, source_identity = _source(agent)
|
|
281
|
+
if home == source or home in source.parents or source in home.parents:
|
|
282
|
+
raise OSError('Source overlaps the active profile')
|
|
283
|
+
target = _snapshot(home, _TARGETS)
|
|
284
|
+
identity = [str(home), str(source), plugin, _stamp((source_files, source_identity)), _stamp(target)]
|
|
285
|
+
if receipt and receipt['identity'] != identity:
|
|
286
|
+
return _result('changed', message='Source, profile or plugin changed. Preview again.')
|
|
287
|
+
if ctx is not None:
|
|
288
|
+
ctx.check_cancelled()
|
|
289
|
+
# Private temporary copies isolate the native path-based API from hostile path replacement.
|
|
290
|
+
with tempfile.TemporaryDirectory(prefix='talaria-import-') as temp:
|
|
291
|
+
stage_source, stage_target = Path(temp).resolve() / 'source', Path(temp).resolve() / 'target'
|
|
292
|
+
_materialize(stage_source, source_files, source_identity)
|
|
293
|
+
_materialize(stage_target, *target)
|
|
294
|
+
report = importer(agent, stage_source, stage_target, execute=False, overwrite=False).run()
|
|
295
|
+
items, stripped = _project(report)
|
|
296
|
+
plan = json.dumps([items, stripped], sort_keys=True)
|
|
297
|
+
if receipt and plan != receipt['plan']:
|
|
298
|
+
return _result('changed', message='Import plan changed. Preview again.')
|
|
299
|
+
if action == 'preview':
|
|
300
|
+
if not any(i['status'] == 'imported' for i in items):
|
|
301
|
+
return _result('preview', items=items, stripped=stripped)
|
|
302
|
+
token = secrets.token_urlsafe(32)
|
|
303
|
+
if len(_PREVIEWS) >= 64:
|
|
304
|
+
del _PREVIEWS[next(iter(_PREVIEWS))]
|
|
305
|
+
_PREVIEWS[token] = dict(home=str(home), agent=agent, identity=identity, plan=plan, expires=now + 300)
|
|
306
|
+
return _result('preview', items=items, stripped=stripped, receipt=token,
|
|
307
|
+
can_apply=any(i['status'] == 'imported' for i in items))
|
|
308
|
+
del _PREVIEWS[token]
|
|
309
|
+
unknown = _result('unknown', message='Import outcome is unknown. Check the profile before starting a new preview.')
|
|
310
|
+
# Fsync the consumed record before any native write. Restart or cancellation cannot replay it.
|
|
311
|
+
_ledger(root_fd, token, unknown)
|
|
312
|
+
try:
|
|
313
|
+
report = importer(agent, stage_source, stage_target, execute=True, overwrite=False).run()
|
|
314
|
+
items, stripped = _project(report)
|
|
315
|
+
sync.update_sync_manifest(agent, stage_source, stage_target, False, report,
|
|
316
|
+
refresh_digest=not any(i['status'] == 'error' for i in items))
|
|
317
|
+
manifest_path = stage_target / 'import-sync.json'
|
|
318
|
+
manifest = json.loads(manifest_path.read_text())
|
|
319
|
+
manifest['agents'][agent]['source'] = str(source)
|
|
320
|
+
manifest_path.write_text(json.dumps(manifest))
|
|
321
|
+
config.assert_config_writable(home)
|
|
322
|
+
output, output_identity = _snapshot(stage_target, _TARGETS)
|
|
323
|
+
# Check original objects again before publication; no write resolves a client/native path.
|
|
324
|
+
fresh_source = _source(agent)
|
|
325
|
+
if (plugin_catalog.reviewed_importer(home)[2] != plugin
|
|
326
|
+
or _stamp(fresh_source[1:]) != identity[3] or _stamp(_snapshot(home, _TARGETS)) != identity[4]):
|
|
327
|
+
return _ledger(root_fd, token, _result('changed', message='Import inputs changed before publication. Preview again.'))
|
|
328
|
+
result = _result('partial' if any(i['status'] == 'error' for i in items) else 'applied', items=items, stripped=stripped)
|
|
329
|
+
result['message'] = 'Files imported. Reload Skills and MCP before using the imported setup.'
|
|
330
|
+
_ledger(root_fd, token, dict(result=unknown, expected={k: hashlib.sha256(v).hexdigest() for k, v in output.items()}, confirmed=result))
|
|
331
|
+
for rel, body in output.items():
|
|
332
|
+
if target[0].get(rel) != body:
|
|
333
|
+
_write(root_fd, rel, body, exclusive=rel not in target[0], mode=output_identity[rel][2], expected=(target[0][rel], target[1][rel]) if rel in target[0] else None)
|
|
334
|
+
result = _result('partial' if any(i['status'] == 'error' for i in items) else 'applied', items=items, stripped=stripped)
|
|
335
|
+
if not _refresh_runtime(home):
|
|
336
|
+
result['message'] = 'Files imported. Reload Skills and MCP before using the imported setup.'
|
|
337
|
+
return _ledger(root_fd, token, result)
|
|
338
|
+
except Exception:
|
|
339
|
+
# Exceptions may include secret values. The durable unknown record is the only public result.
|
|
340
|
+
return unknown
|
|
341
|
+
except (OSError, ValueError, TypeError, KeyError):
|
|
342
|
+
return _result('unknown' if action == 'result' else 'changed' if action == 'apply' else 'unavailable', message='Import paths or state are unsafe, unavailable or changed. Check the profile before continuing.')
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def register(registry):
|
|
346
|
+
registry.method('profiles.import')(run)
|