@maudecode/talaria-web 1.16.1 → 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.
Files changed (328) hide show
  1. package/_release.json +4 -4
  2. package/dist/api/automation-raw.js +6 -3
  3. package/dist/api/automation-raw.js.map +1 -1
  4. package/dist/api/automation-router.d.ts +137 -9
  5. package/dist/api/automation-router.js +9 -6
  6. package/dist/api/automation-router.js.map +1 -1
  7. package/dist/api/chat-router.d.ts +51 -0
  8. package/dist/api/chat-router.js +29 -12
  9. package/dist/api/chat-router.js.map +1 -1
  10. package/dist/api/git-router.d.ts +12 -1
  11. package/dist/api/git-router.js +17 -7
  12. package/dist/api/git-router.js.map +1 -1
  13. package/dist/api/raw-routes.d.ts +6 -0
  14. package/dist/api/raw-routes.js +30 -0
  15. package/dist/api/raw-routes.js.map +1 -1
  16. package/dist/api/sessions-router.d.ts +260 -0
  17. package/dist/api/sessions-router.js +30 -2
  18. package/dist/api/sessions-router.js.map +1 -1
  19. package/dist/api/settings-router.d.ts +101 -2
  20. package/dist/api/settings-router.js +7 -2
  21. package/dist/api/settings-router.js.map +1 -1
  22. package/dist/api/sse-routes.d.ts +11 -3
  23. package/dist/api/sse-routes.js +144 -64
  24. package/dist/api/sse-routes.js.map +1 -1
  25. package/dist/api/tools-raw.js +6 -2
  26. package/dist/api/tools-raw.js.map +1 -1
  27. package/dist/api/tools-router.d.ts +73 -8
  28. package/dist/api/tools-router.js +9 -7
  29. package/dist/api/tools-router.js.map +1 -1
  30. package/dist/app.d.ts +0 -9377
  31. package/dist/app.js +7 -2
  32. package/dist/app.js.map +1 -1
  33. package/dist/auth/gate.js +3 -0
  34. package/dist/auth/gate.js.map +1 -1
  35. package/dist/config/agent-config.d.ts +2 -0
  36. package/dist/config/agent-config.js +9 -0
  37. package/dist/config/agent-config.js.map +1 -1
  38. package/dist/http/context.d.ts +3 -0
  39. package/dist/http/context.js +10 -4
  40. package/dist/http/context.js.map +1 -1
  41. package/dist/onboarding.js +4 -0
  42. package/dist/onboarding.js.map +1 -1
  43. package/dist/providers/catalog.d.ts +96 -7
  44. package/dist/providers/catalog.js +434 -113
  45. package/dist/providers/catalog.js.map +1 -1
  46. package/dist/redact.d.ts +1 -0
  47. package/dist/redact.js +27 -4
  48. package/dist/redact.js.map +1 -1
  49. package/dist/runtime.js +27 -9
  50. package/dist/runtime.js.map +1 -1
  51. package/dist/sessions/anchor.d.ts +2 -0
  52. package/dist/sessions/anchor.js +8 -3
  53. package/dist/sessions/anchor.js.map +1 -1
  54. package/dist/sessions/claude-code.d.ts +19 -0
  55. package/dist/sessions/claude-code.js +250 -0
  56. package/dist/sessions/claude-code.js.map +1 -0
  57. package/dist/sessions/completions.d.ts +13 -1
  58. package/dist/sessions/completions.js +63 -11
  59. package/dist/sessions/completions.js.map +1 -1
  60. package/dist/sessions/compress.d.ts +14 -1
  61. package/dist/sessions/compress.js +52 -11
  62. package/dist/sessions/compress.js.map +1 -1
  63. package/dist/sessions/journal.d.ts +8 -0
  64. package/dist/sessions/journal.js +44 -10
  65. package/dist/sessions/journal.js.map +1 -1
  66. package/dist/sessions/list.d.ts +6 -2
  67. package/dist/sessions/list.js +33 -10
  68. package/dist/sessions/list.js.map +1 -1
  69. package/dist/sessions/merge.d.ts +52 -2
  70. package/dist/sessions/merge.js +213 -10
  71. package/dist/sessions/merge.js.map +1 -1
  72. package/dist/sessions/service.d.ts +44 -2
  73. package/dist/sessions/service.js +251 -57
  74. package/dist/sessions/service.js.map +1 -1
  75. package/dist/sessions/session.d.ts +11 -1
  76. package/dist/sessions/session.js +23 -2
  77. package/dist/sessions/session.js.map +1 -1
  78. package/dist/sessions/state-db.d.ts +26 -4
  79. package/dist/sessions/state-db.js +126 -8
  80. package/dist/sessions/state-db.js.map +1 -1
  81. package/dist/sessions/store.js +5 -0
  82. package/dist/sessions/store.js.map +1 -1
  83. package/dist/sessions/streams.d.ts +10 -0
  84. package/dist/sessions/streams.js +14 -3
  85. package/dist/sessions/streams.js.map +1 -1
  86. package/dist/sessions/todo.d.ts +6 -1
  87. package/dist/sessions/todo.js +11 -4
  88. package/dist/sessions/todo.js.map +1 -1
  89. package/dist/sessions/tool-display.d.ts +12 -1
  90. package/dist/sessions/tool-display.js +76 -1
  91. package/dist/sessions/tool-display.js.map +1 -1
  92. package/dist/sessions/turn.d.ts +30 -9
  93. package/dist/sessions/turn.js +247 -78
  94. package/dist/sessions/turn.js.map +1 -1
  95. package/dist/settings.d.ts +20 -2
  96. package/dist/settings.js +40 -2
  97. package/dist/settings.js.map +1 -1
  98. package/dist/sidecar/fake.d.ts +2 -2
  99. package/dist/sidecar/fake.js +5 -2
  100. package/dist/sidecar/fake.js.map +1 -1
  101. package/dist/spa.js +2 -1
  102. package/dist/spa.js.map +1 -1
  103. package/dist/test/harness.js +2 -0
  104. package/dist/test/harness.js.map +1 -1
  105. package/dist/tools/insights.d.ts +8 -2
  106. package/dist/tools/insights.js +18 -2
  107. package/dist/tools/insights.js.map +1 -1
  108. package/dist/tools/kanban.d.ts +41 -1
  109. package/dist/tools/kanban.js +113 -2
  110. package/dist/tools/kanban.js.map +1 -1
  111. package/dist/tools/mcp.d.ts +2 -1
  112. package/dist/tools/mcp.js +11 -5
  113. package/dist/tools/mcp.js.map +1 -1
  114. package/dist/tools/terminal.d.ts +1 -0
  115. package/dist/tools/terminal.js +1 -1
  116. package/dist/tools/terminal.js.map +1 -1
  117. package/dist/tools/updates.d.ts +7 -0
  118. package/dist/tools/updates.js +74 -7
  119. package/dist/tools/updates.js.map +1 -1
  120. package/dist/workspace/fs.d.ts +7 -3
  121. package/dist/workspace/fs.js +5 -1
  122. package/dist/workspace/fs.js.map +1 -1
  123. package/dist/workspace/media.js +2 -0
  124. package/dist/workspace/media.js.map +1 -1
  125. package/dist/workspace/preview.d.ts +28 -0
  126. package/dist/workspace/preview.js +110 -0
  127. package/dist/workspace/preview.js.map +1 -0
  128. package/dist/workspace/rollback.d.ts +5 -4
  129. package/dist/workspace/rollback.js +12 -9
  130. package/dist/workspace/rollback.js.map +1 -1
  131. package/dist/workspace/upload.d.ts +2 -0
  132. package/dist/workspace/upload.js +4 -1
  133. package/dist/workspace/upload.js.map +1 -1
  134. package/package.json +2 -2
  135. package/sidecar/scripts/replay_sidecar.py +1 -1
  136. package/sidecar/talaria_sidecar/__init__.py +1 -1
  137. package/sidecar/talaria_sidecar/__main__.py +7 -1
  138. package/sidecar/talaria_sidecar/home.py +39 -0
  139. package/sidecar/talaria_sidecar/methods/chat.py +422 -38
  140. package/sidecar/talaria_sidecar/methods/commands.py +15 -2
  141. package/sidecar/talaria_sidecar/methods/cron.py +10 -6
  142. package/sidecar/talaria_sidecar/methods/kanban.py +115 -15
  143. package/sidecar/talaria_sidecar/methods/process.py +60 -1
  144. package/sidecar/talaria_sidecar/methods/profiles.py +7 -1
  145. package/sidecar/talaria_sidecar/methods/runtime.py +3 -0
  146. package/sidecar/talaria_sidecar/methods/text.py +17 -1
  147. package/sidecar/talaria_sidecar/methods/usage.py +257 -4
  148. package/static/dist/FILES.txt +126 -125
  149. package/static/dist/assets/AppShell-fb2td9zi.js +1 -0
  150. package/static/dist/assets/ChatPage-cj96kiy9.js +25 -0
  151. package/static/dist/assets/Dialog-kxcg7ard.js +1 -0
  152. package/static/dist/assets/ExtensionRoute-jf7h0754.js +1 -0
  153. package/static/dist/assets/HubRoute-gmanpd5y.js +2 -0
  154. package/static/dist/assets/{Markdown-jqrx5es0.js → Markdown-mdwlvj3w.js} +29 -29
  155. package/static/dist/assets/RightPanel-ftvrjlcp.js +1 -0
  156. package/static/dist/assets/Select-bilaypej.js +1 -0
  157. package/static/dist/assets/SessionListPanel-og8n36qs.js +1 -0
  158. package/static/dist/assets/SettingsLayout-jonjefmj.js +1 -0
  159. package/static/dist/assets/States-nmejrwrm.js +1 -0
  160. package/static/dist/assets/Toaster-nnl8zkt9.js +1 -0
  161. package/static/dist/assets/_app-gdidzd94.js +1 -0
  162. package/static/dist/assets/_app.ext._extensionId-opyh9y0v.js +1 -0
  163. package/static/dist/assets/_app.index-hbarzbjx.js +1 -0
  164. package/static/dist/assets/_app.insights-luywlarz.js +1 -0
  165. package/static/dist/assets/_app.kanban-kincnbr8.js +1 -0
  166. package/static/dist/assets/_app.logs-oi2gr3gs.js +1 -0
  167. package/static/dist/assets/_app.memory-b6jfivt6.js +1 -0
  168. package/static/dist/assets/_app.profiles-lpvixmqp.js +1 -0
  169. package/static/dist/assets/{_app.session._sessionId-hh27wwu2.js → _app.session._sessionId-bfd4h3id.js} +1 -1
  170. package/static/dist/assets/_app.settings-vowx3iq0.js +1 -0
  171. package/static/dist/assets/_app.settings._section-cnntg1tu.js +3 -0
  172. package/static/dist/assets/_app.skills-fb57lpau.js +1 -0
  173. package/static/dist/assets/_app.tasks-eszpx1q7.js +2 -0
  174. package/static/dist/assets/_app.todos-nr05ac6w.js +1 -0
  175. package/static/dist/assets/_app.workspaces-d2luomu6.js +1 -0
  176. package/static/dist/assets/{abnfDiagram-VCTEODGH-oity9y4o.js → abnfDiagram-VCTEODGH-b2x1lqot.js} +1 -1
  177. package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +1 -0
  178. package/static/dist/assets/{architectureDiagram-5GKGNRK7-ceaepnyr.js → architectureDiagram-5GKGNRK7-h38o5l7b.js} +1 -1
  179. package/static/dist/assets/{back-eu64w89w.js → back-bemaer09.js} +1 -1
  180. package/static/dist/assets/{blockDiagram-I7D4REHJ-n79st4pj.js → blockDiagram-I7D4REHJ-bqquxv2u.js} +1 -1
  181. package/static/dist/assets/{c4Diagram-7LVT6UL2-mi73akzk.js → c4Diagram-7LVT6UL2-f3fb8w6z.js} +1 -1
  182. package/static/dist/assets/{cancel-mzvkdjg8.js → cancel-drd0g6d9.js} +1 -1
  183. package/static/dist/assets/channel-cpdgf867.js +1 -0
  184. package/static/dist/assets/{chunk-4HAMMTFA-laat0g1q.js → chunk-4HAMMTFA-bzfyyzp3.js} +1 -1
  185. package/static/dist/assets/{chunk-75Z2AOVW-0psy1tr2.js → chunk-75Z2AOVW-ly99rfx5.js} +1 -1
  186. package/static/dist/assets/{chunk-DU6HZSFF-lw8uox8x.js → chunk-DU6HZSFF-bg6ecfqf.js} +3 -3
  187. package/static/dist/assets/{chunk-F27PBJKO-erassib3.js → chunk-F27PBJKO-e8k7mmqw.js} +1 -1
  188. package/static/dist/assets/{chunk-GMAD6QVW-fz7rx619.js → chunk-GMAD6QVW-cmalnoaj.js} +1 -1
  189. package/static/dist/assets/{chunk-GVQU2GXP-gdb0epb2.js → chunk-GVQU2GXP-gmif5o01.js} +1 -1
  190. package/static/dist/assets/{chunk-IMKFNOWR-ea8t26qw.js → chunk-IMKFNOWR-f1nwwh6u.js} +1 -1
  191. package/static/dist/assets/{chunk-L3NEJ4N5-mb1gu9kz.js → chunk-L3NEJ4N5-oktfh5v7.js} +1 -1
  192. package/static/dist/assets/{chunk-OSK3NFVY-eovmccvy.js → chunk-OSK3NFVY-b1sdx96z.js} +1 -1
  193. package/static/dist/assets/{chunk-P2QGCYS3-bo55zjo5.js → chunk-P2QGCYS3-fhu4nzxt.js} +1 -1
  194. package/static/dist/assets/{chunk-POPQ4Y6H-ja7ohe4h.js → chunk-POPQ4Y6H-em31rnef.js} +1 -1
  195. package/static/dist/assets/{chunk-PWAF6VOD-e30g9nus.js → chunk-PWAF6VOD-bxhhyftw.js} +1 -1
  196. package/static/dist/assets/{chunk-SHT3W25Y-gbb798f7.js → chunk-SHT3W25Y-fmrvwcav.js} +1 -1
  197. package/static/dist/assets/{chunk-SVP7TREG-h2iw8urm.js → chunk-SVP7TREG-lymukl2j.js} +1 -1
  198. package/static/dist/assets/{chunk-TICWLB2K-fd2cottz.js → chunk-TICWLB2K-lmza6k23.js} +1 -1
  199. package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +1 -0
  200. package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +1 -0
  201. package/static/dist/assets/{copied-h65fc3cx.js → copied-ima3pysb.js} +1 -1
  202. package/static/dist/assets/copy-fw5b1pc6.js +1 -0
  203. package/static/dist/assets/{cynefin-OW5HDTMX-lbltyl5j.js → cynefin-OW5HDTMX-czlhbyhs.js} +1 -1
  204. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-lxhsqq4a.js → cynefinDiagram-5FMLGOSQ-gq7mvswb.js} +1 -1
  205. package/static/dist/assets/{dagre-GXQ25YYZ-gn4nnaln.js → dagre-GXQ25YYZ-cqdbf7dr.js} +1 -1
  206. package/static/dist/assets/{diagram-S7CK7UJ4-pa3ij6q7.js → diagram-S7CK7UJ4-o6arxa58.js} +1 -1
  207. package/static/dist/assets/{diagram-UQ7AKVKN-zbipyz57.js → diagram-UQ7AKVKN-nhnd68tz.js} +1 -1
  208. package/static/dist/assets/{diagram-VSXAHHWV-d1kbpzgf.js → diagram-VSXAHHWV-dk2sclzn.js} +1 -1
  209. package/static/dist/assets/{diagram-VX7I27RA-i3ty14xl.js → diagram-VX7I27RA-n3k5nyx3.js} +1 -1
  210. package/static/dist/assets/{diagram-Z3DM3KII-m8xefqa7.js → diagram-Z3DM3KII-m6q9cwdh.js} +1 -1
  211. package/static/dist/assets/{ebnfDiagram-PWID7BFC-nz7wj05l.js → ebnfDiagram-PWID7BFC-lsa5641p.js} +1 -1
  212. package/static/dist/assets/endpoints-d33siokx.js +64 -0
  213. package/static/dist/assets/{erDiagram-RLTQ6QDP-fa41ib83.js → erDiagram-RLTQ6QDP-fo2ckbe6.js} +1 -1
  214. package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +1 -0
  215. package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +1 -0
  216. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-n7zq01qu.js → ganttDiagram-EL5Y4UJY-nzqz6x9g.js} +1 -1
  217. package/static/dist/assets/{gitGraph-4MIJSDKK-c89emb07.js → gitGraph-4MIJSDKK-gukvcxe6.js} +1 -1
  218. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-cz7cgr6w.js → gitGraphDiagram-WWUBYQGX-lqhdp8f0.js} +1 -1
  219. package/static/dist/assets/{highlighted-body-KPVGNVTW-d9bapmni.js → highlighted-body-KPVGNVTW-igw6cp39.js} +1 -1
  220. package/static/dist/assets/index-cxq58xb1.js +11 -0
  221. package/static/dist/assets/index-hgtx08n5.css +2 -0
  222. package/static/dist/assets/{info-A6RAGUB7-ndddhhhh.js → info-A6RAGUB7-gvu7a93l.js} +1 -1
  223. package/static/dist/assets/{infoDiagram-27XIBGKW-ccxigcpf.js → infoDiagram-27XIBGKW-m8t8g6w1.js} +1 -1
  224. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-le0z9vtc.js → ishikawaDiagram-5VMMS53U-l07vkbgj.js} +1 -1
  225. package/static/dist/assets/{journeyDiagram-3NMN7TZE-ivsmb26o.js → journeyDiagram-3NMN7TZE-hybkgj8l.js} +1 -1
  226. package/static/dist/assets/{kanban-definition-UXKFOSKX-h6n2awt0.js → kanban-definition-UXKFOSKX-by13uvtn.js} +1 -1
  227. package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +1 -0
  228. package/static/dist/assets/{line-dmzlfe0u.js → line-osxq6fq7.js} +1 -1
  229. package/static/dist/assets/link-jyxicdhg.js +1 -0
  230. package/static/dist/assets/{login-kjhasvp8.js → login-ec21t39x.js} +1 -1
  231. package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +1 -0
  232. package/static/dist/assets/{mermaid-parser.core-gwyd5bnq.js → mermaid-parser.core-i91oxmou.js} +3 -3
  233. package/static/dist/assets/{mindmap-definition-YA3MSWOX-l68gg5h7.js → mindmap-definition-YA3MSWOX-m82mx8ww.js} +1 -1
  234. package/static/dist/assets/onboarding-btnltvyz.js +1 -0
  235. package/static/dist/assets/onboarding_model_label-dp7xffoh.js +1 -0
  236. package/static/dist/assets/{packet-AYTQ26CC-gpv06065.js → packet-AYTQ26CC-nbtgge2o.js} +1 -1
  237. package/static/dist/assets/{pegDiagram-XKGWAZYB-e52vs23u.js → pegDiagram-XKGWAZYB-f1zxzga1.js} +1 -1
  238. package/static/dist/assets/{pie-WAS4IAKB-l6m7nz5s.js → pie-WAS4IAKB-of8vuhxs.js} +1 -1
  239. package/static/dist/assets/{pieDiagram-E7YTZNPT-b4is36bq.js → pieDiagram-E7YTZNPT-o7y8ftio.js} +1 -1
  240. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-m8vt2788.js → quadrantDiagram-AXDQQJYC-iqiwia1t.js} +1 -1
  241. package/static/dist/assets/{radar-RG4KPBEZ-nxbrhiov.js → radar-RG4KPBEZ-delnsy2v.js} +1 -1
  242. package/static/dist/assets/{railroad-74A4TZTK-222mu9hi.js → railroad-74A4TZTK-nspnyq9u.js} +1 -1
  243. package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +1 -0
  244. package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +1 -0
  245. package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +1 -0
  246. package/static/dist/assets/{railroadDiagram-O6MQD6OU-o8lldfzv.js → railroadDiagram-O6MQD6OU-z41tqx5z.js} +1 -1
  247. package/static/dist/assets/refresh-b4uams1i.js +1 -0
  248. package/static/dist/assets/refresh-cw-nt1dtsx4.js +1 -0
  249. package/static/dist/assets/{requirementDiagram-BXWQKSXE-ovyq38kv.js → requirementDiagram-BXWQKSXE-bdvif194.js} +1 -1
  250. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-ou7lznor.js → sankeyDiagram-P5KCCOFB-h73e0rol.js} +1 -1
  251. package/static/dist/assets/{saved-bazmcup9.js → saved-kg52csy7.js} +1 -1
  252. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-ovckdzf2.js → sequenceDiagram-WJ2MYXX4-iv95mb1z.js} +1 -1
  253. package/static/dist/assets/{settings_section_extensions_title-ertwwhlx.js → settings_section_extensions_title-ej0iapxe.js} +1 -1
  254. package/static/dist/assets/share._token-f97e94r0.js +2 -0
  255. package/static/dist/assets/sliders-horizontal-fj18it47.js +1 -0
  256. package/static/dist/assets/sse-fwpqtzbg.js +1 -0
  257. package/static/dist/assets/{stateDiagram-D77RDMKH-fcrexkkv.js → stateDiagram-D77RDMKH-k417ixmf.js} +1 -1
  258. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +1 -0
  259. package/static/dist/assets/{swimlanes-42K2YHIH-f7usu8fw.js → swimlanes-42K2YHIH-esola70w.js} +1 -1
  260. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +8 -0
  261. package/static/dist/assets/{timeline-definition-24CTP7MA-gp1hvz9f.js → timeline-definition-24CTP7MA-getrz2y8.js} +1 -1
  262. package/static/dist/assets/todoStore-eginf9h4.js +1 -0
  263. package/static/dist/assets/{treeView-Q6P3EWNA-gb9gf11u.js → treeView-Q6P3EWNA-hc7ap1q7.js} +1 -1
  264. package/static/dist/assets/{treemap-WGGIJYW6-nuvfnvvi.js → treemap-WGGIJYW6-b7k1syy5.js} +1 -1
  265. package/static/dist/assets/tts-lxdxnmjd.js +1 -0
  266. package/static/dist/assets/{untitled-htelhc68.js → untitled-ovpfthg4.js} +1 -1
  267. package/static/dist/assets/{useForm-h2t0u14e.js → useForm-bcblv1rx.js} +1 -1
  268. package/static/dist/assets/useLocale-fi5jb8ma.js +1 -0
  269. package/static/dist/assets/{useParams-dqd64jv7.js → useParams-lhg566ew.js} +1 -1
  270. package/static/dist/assets/{useSearch-j30pvsy7.js → useSearch-lbrh6ejn.js} +1 -1
  271. package/static/dist/assets/{vennDiagram-4TSXK5OY-fzchbzaj.js → vennDiagram-4TSXK5OY-n6pcy5qb.js} +1 -1
  272. package/static/dist/assets/{wardley-WFR3VGLG-m47mhfbh.js → wardley-WFR3VGLG-lpa18vz1.js} +1 -1
  273. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-odg6ct1z.js → wardleyDiagram-VM6X3IG4-kpclwwg7.js} +1 -1
  274. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mrhms5um.js → xychartDiagram-S5SC5T6Z-paa2n8y0.js} +1 -1
  275. package/static/dist/index.html +1 -1
  276. package/static/dist/sw.js +2 -2
  277. package/static/dist/assets/AppShell-ef3bhu32.js +0 -1
  278. package/static/dist/assets/Button-nx37f4u1.js +0 -1
  279. package/static/dist/assets/ChatPage-cdcpykcg.js +0 -25
  280. package/static/dist/assets/Dialog-mec42hvb.js +0 -1
  281. package/static/dist/assets/HubRoute-ecb65zpr.js +0 -2
  282. package/static/dist/assets/RightPanel-d1lgvk4s.js +0 -1
  283. package/static/dist/assets/Select-h4ivl9qf.js +0 -1
  284. package/static/dist/assets/SessionListPanel-ewib046b.js +0 -1
  285. package/static/dist/assets/SettingsLayout-lx654cup.js +0 -1
  286. package/static/dist/assets/States-ehsb6lzo.js +0 -1
  287. package/static/dist/assets/Toaster-mch1pa3t.js +0 -1
  288. package/static/dist/assets/_app-m8d961ef.js +0 -1
  289. package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +0 -1
  290. package/static/dist/assets/_app.index-dk6zp7e0.js +0 -1
  291. package/static/dist/assets/_app.insights-jt2fk4i1.js +0 -1
  292. package/static/dist/assets/_app.kanban-if4pubeu.js +0 -1
  293. package/static/dist/assets/_app.logs-mfaw9m6g.js +0 -1
  294. package/static/dist/assets/_app.memory-h3eaarb6.js +0 -1
  295. package/static/dist/assets/_app.profiles-ienktovs.js +0 -1
  296. package/static/dist/assets/_app.settings-dpoe0bzf.js +0 -1
  297. package/static/dist/assets/_app.settings._section-l468ynag.js +0 -3
  298. package/static/dist/assets/_app.skills-kcbncc8i.js +0 -1
  299. package/static/dist/assets/_app.tasks-occdrqhw.js +0 -2
  300. package/static/dist/assets/_app.todos-nnke2rcc.js +0 -1
  301. package/static/dist/assets/_app.workspaces-cdlatvwj.js +0 -1
  302. package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +0 -1
  303. package/static/dist/assets/channel-mbvmf2vv.js +0 -1
  304. package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +0 -1
  305. package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +0 -1
  306. package/static/dist/assets/copy-e6977uwq.js +0 -1
  307. package/static/dist/assets/endpoints-k7yf25m0.js +0 -64
  308. package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +0 -1
  309. package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +0 -1
  310. package/static/dist/assets/index-h00usru2.js +0 -11
  311. package/static/dist/assets/index-n73ijkv2.css +0 -2
  312. package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +0 -1
  313. package/static/dist/assets/link-budeg5t9.js +0 -1
  314. package/static/dist/assets/matchContext-f8oy3lo7.js +0 -1
  315. package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +0 -1
  316. package/static/dist/assets/onboarding-cdfrk0pj.js +0 -1
  317. package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +0 -1
  318. package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +0 -1
  319. package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +0 -1
  320. package/static/dist/assets/refresh-cw-kbcje1uy.js +0 -1
  321. package/static/dist/assets/search-jen74z4u.js +0 -1
  322. package/static/dist/assets/share._token-dan9hgvj.js +0 -2
  323. package/static/dist/assets/sliders-horizontal-f9cb3lh3.js +0 -1
  324. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +0 -1
  325. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +0 -8
  326. package/static/dist/assets/todoStore-eqtid4r4.js +0 -1
  327. package/static/dist/assets/useLocale-hcsb84pj.js +0 -1
  328. package/static/dist/assets/useNavigate-nwy70ztj.js +0 -1
@@ -15,7 +15,14 @@ log = logging.getLogger("talaria_sidecar.commands")
15
15
 
16
16
  _NEVER_EXPOSE = frozenset({"sethome", "restart", "update", "commands"})
17
17
  _ALIASES = {"reload_mcp": "reload-mcp", "reload_skills": "reload-skills", "codex_runtime": "codex-runtime"}
18
- _ALLOWED = frozenset({"reload-mcp", "reload-skills", "codex-runtime", "credits"})
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)
19
26
  _RELOAD_MCP_LOCK = threading.Lock()
20
27
  _RELOAD_SKILLS_LOCK = threading.Lock()
21
28
  _CODEX_RUNTIME_LOCK = threading.Lock()
@@ -46,7 +53,13 @@ def list_commands() -> list[dict[str, Any]]:
46
53
  out.append({
47
54
  "name": cmd.name, "description": cmd.description, "category": cmd.category, "aliases": list(cmd.aliases),
48
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,
49
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})
50
63
  try:
51
64
  from hermes_cli.plugins import get_plugin_commands
52
65
 
@@ -55,7 +68,7 @@ def list_commands() -> list[dict[str, Any]]:
55
68
  if name in existing or name in _NEVER_EXPOSE:
56
69
  continue
57
70
  out.append({"name": name, "description": str(info.get("description", "Plugin command")), "category": "Plugin", "aliases": [],
58
- "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})
59
72
  except Exception: # noqa: BLE001 - plugin registry is optional
60
73
  log.debug("plugin command listing failed", exc_info=True)
61
74
  return out
@@ -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 time.monotonic() >= deadline:
256
- if process.is_alive():
257
- process.terminate()
258
- process.join(timeout=5)
259
- payload = [f"cron run subprocess produced no result within {_result_timeout(job):g}s and was terminated", ""]
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
- def _task_dict(task):
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 status, current_run_id FROM tasks WHERE id = ?", (task_id,)).fetchone()
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
- if not kb.archive_task(conn, task_id):
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:
@@ -12,7 +12,7 @@ import time
12
12
  from contextlib import closing
13
13
  from pathlib import Path
14
14
 
15
- from ..errors import InvalidParams
15
+ from ..errors import InvalidParams, RpcError
16
16
  from ..home import profile_home_param, scoped_home
17
17
  from ..rpc import CallContext
18
18
 
@@ -54,6 +54,14 @@ def drain(max_events: int) -> list[dict]:
54
54
  completion_queue = getattr(registry, "completion_queue", None) if registry is not None else None
55
55
  if completion_queue is None:
56
56
  return []
57
+ try:
58
+ # A recovered process has no reader thread; only this probe notices its exit and queues its completion (TAL-533).
59
+ with registry._lock:
60
+ detached = [s for s in registry._running.values() if getattr(s, "detached", False)]
61
+ for session in detached:
62
+ registry._refresh_detached_session(session)
63
+ except Exception: # noqa: BLE001
64
+ log.debug("Failed to reconcile recovered processes", exc_info=True)
57
65
  out = []
58
66
  while len(out) < max_events:
59
67
  try:
@@ -94,6 +102,22 @@ def mark_consumed(process_id: str) -> bool:
94
102
  return False
95
103
 
96
104
 
105
+ def consumed_ids(process_ids: list[str]) -> list[str]:
106
+ """The processes the agent already holds from its own turn: consumed via wait/log, or observed exiting via poll.
107
+ Checked at wakeup delivery, since the completion is usually drained before the agent's wait returns (TAL-532)."""
108
+ registry = _registry()
109
+ if registry is None:
110
+ return []
111
+ out = []
112
+ for process_id in process_ids:
113
+ try:
114
+ if registry.is_completion_consumed(process_id) or process_id in (getattr(registry, "_poll_observed", None) or ()):
115
+ out.append(process_id)
116
+ except Exception: # noqa: BLE001
117
+ log.debug("Completion consumed check failed for %r", process_id, exc_info=True)
118
+ return out
119
+
120
+
97
121
  def _delivery_api():
98
122
  """The Agent's durable delivery ledger (``tools.async_delegation``), or None on an Agent without it."""
99
123
  try:
@@ -387,12 +411,40 @@ def delegation_result(home: Path, session_id: str, delegation_id: str) -> str:
387
411
  return format_notification(event) if event else ""
388
412
 
389
413
 
414
+ def recover(base_home: Path) -> int:
415
+ """TAL-533: re-adopt every profile's checkpointed processes when a sidecar starts, so a process in a profile nobody
416
+ uses yet is watched (and its exit reported) from the start. Entering a home's scope recovers it once; a failed
417
+ recovery fails the call, so the server retries."""
418
+ from hermes_cli.profiles import _PROFILE_ID_RE
419
+
420
+ profiles_root = base_home / "profiles"
421
+ named = sorted(p for p in profiles_root.iterdir() if p.is_dir() and _PROFILE_ID_RE.match(p.name)) if profiles_root.is_dir() else []
422
+ failed = []
423
+ for home in [base_home, *named]:
424
+ try:
425
+ with scoped_home(home):
426
+ pass
427
+ except RpcError as exc:
428
+ if exc.data.get("condition") != "agent_incompatible":
429
+ failed.append(str(exc))
430
+ continue
431
+ # An Agent without profile isolation refuses named profiles for good; their processes stay unadopted.
432
+ log.warning("Background process recovery skipped for %s", home, exc_info=True)
433
+ if failed:
434
+ raise RpcError("; ".join(failed))
435
+ return 1 + len(named)
436
+
437
+
390
438
  def register(registry_) -> None:
391
439
  @registry_.method("process.drain")
392
440
  def drain_(ctx: CallContext, params: dict) -> dict:
393
441
  with scoped_home(profile_home_param(params)):
394
442
  return {"events": drain(int(params.get("max_events") or 256))}
395
443
 
444
+ @registry_.method("process.recover")
445
+ def recover_(ctx: CallContext, params: dict) -> dict:
446
+ return {"homes": recover(profile_home_param(params, "base_home"))}
447
+
396
448
  @registry_.method("process.requeue")
397
449
  def requeue_(ctx: CallContext, params: dict) -> dict:
398
450
  events = params.get("events")
@@ -407,6 +459,13 @@ def register(registry_) -> None:
407
459
  raise InvalidParams("process_id is required")
408
460
  return {"ok": mark_consumed(process_id)}
409
461
 
462
+ @registry_.method("process.consumed")
463
+ def consumed_(ctx: CallContext, params: dict) -> dict:
464
+ ids = params.get("process_ids")
465
+ if not isinstance(ids, list) or not all(isinstance(i, str) and i for i in ids):
466
+ raise InvalidParams("process_ids must be a list of process ids")
467
+ return {"consumed": consumed_ids(ids)}
468
+
410
469
  def _delivery_params(params: dict) -> dict:
411
470
  evt = params.get("event")
412
471
  if not isinstance(evt, dict):
@@ -241,7 +241,13 @@ def register(registry) -> None:
241
241
 
242
242
  @registry.method("profiles.delete")
243
243
  def delete(ctx: CallContext, params: dict) -> dict:
244
- delete_profile(profile_home_param(params, "base_home"), str(params.get("name") or "").strip())
244
+ base_home, name = profile_home_param(params, "base_home"), str(params.get("name") or "").strip()
245
+ validate_name(name)
246
+ # Idle cached agents end their memory sessions while the profile's home still exists.
247
+ from .chat import release_profile_agents
248
+
249
+ release_profile_agents(base_home / "profiles" / name)
250
+ delete_profile(base_home, name)
245
251
  return {"ok": True}
246
252
 
247
253
  @registry.method("profiles.runtime_env")
@@ -66,5 +66,8 @@ def register(registry) -> None:
66
66
  code = params.get("exit_code", 0)
67
67
  if not isinstance(code, int):
68
68
  raise InvalidParams("exit_code must be an integer")
69
+ from .chat import drain_agents
70
+
71
+ drain_agents()
69
72
  ctx.server.request_shutdown(exit_code=code)
70
73
  return {"ok": True}
@@ -16,7 +16,7 @@ def image_mode(*, provider: str, model: str, cfg: dict | None, requested_provide
16
16
  try:
17
17
  from agent.image_routing import decide_image_input_mode
18
18
  except Exception: # noqa: BLE001
19
- return {"mode": "text", "reason": "image routing unavailable"}
19
+ return {"mode": "text", "reason": "image routing unavailable", "supports_vision": None}
20
20
  try:
21
21
  decision = decide_image_input_mode(provider, model, cfg, requested_provider=requested_provider)
22
22
  except TypeError:
@@ -34,6 +34,18 @@ def image_mode(*, provider: str, model: str, cfg: dict | None, requested_provide
34
34
  return {"mode": str(decision or "text"), "reason": "", "supports_vision": supports_vision}
35
35
 
36
36
 
37
+ def _profile_config() -> dict | None:
38
+ """The scoped profile's ``config.yaml``; None when the Agent cannot load it."""
39
+ try:
40
+ from hermes_cli.config import load_config
41
+
42
+ cfg = load_config()
43
+ except Exception: # noqa: BLE001
44
+ log.debug("image mode config load failed", exc_info=True)
45
+ return None
46
+ return cfg if isinstance(cfg, dict) else None
47
+
48
+
37
49
  def portal_tags() -> dict:
38
50
  try:
39
51
  from agent.portal_tags import conversation_tag, hermes_client_tag, nous_portal_tags
@@ -58,6 +70,10 @@ def register(registry) -> None:
58
70
  def image_mode_(ctx: CallContext, params: dict) -> dict:
59
71
  cfg = params.get("cfg") if isinstance(params.get("cfg"), dict) else None
60
72
  with scoped_home(profile_home_param(params)):
73
+ # TAL-545: without an explicit cfg the profile's config.yaml decides, so its vision overrides
74
+ # (``agent.image_input_mode``, ``supports_vision``) apply as they do for the Agent's own turn.
75
+ if cfg is None:
76
+ cfg = _profile_config()
61
77
  return image_mode(provider=str(params.get("provider") or ""), model=str(params.get("model") or ""), cfg=cfg, requested_provider=str(params.get("requested_provider") or ""))
62
78
 
63
79
  @registry.method("text.portal_tags")