@maudecode/talaria-web 1.14.0 → 1.16.1

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 (348) hide show
  1. package/_release.json +4 -4
  2. package/dist/api/automation-router.d.ts +123 -7
  3. package/dist/api/automation-router.js +5 -0
  4. package/dist/api/automation-router.js.map +1 -1
  5. package/dist/api/chat-router.d.ts +728 -55
  6. package/dist/api/chat-router.js +122 -126
  7. package/dist/api/chat-router.js.map +1 -1
  8. package/dist/api/git-router.js +44 -32
  9. package/dist/api/git-router.js.map +1 -1
  10. package/dist/api/raw-routes.js +5 -58
  11. package/dist/api/raw-routes.js.map +1 -1
  12. package/dist/api/router.d.ts +6 -3
  13. package/dist/api/router.js +10 -8
  14. package/dist/api/router.js.map +1 -1
  15. package/dist/api/sessions-router.d.ts +2583 -297
  16. package/dist/api/sessions-router.js +92 -47
  17. package/dist/api/sessions-router.js.map +1 -1
  18. package/dist/api/settings-router.d.ts +188 -17
  19. package/dist/api/settings-router.js +75 -26
  20. package/dist/api/settings-router.js.map +1 -1
  21. package/dist/api/sse-routes.js +1 -1
  22. package/dist/api/sse-routes.js.map +1 -1
  23. package/dist/api/tools-router.d.ts +13 -1
  24. package/dist/api/tools-router.js +10 -8
  25. package/dist/api/tools-router.js.map +1 -1
  26. package/dist/app.d.ts +3620 -343
  27. package/dist/auth/gate.js +8 -4
  28. package/dist/auth/gate.js.map +1 -1
  29. package/dist/auth/oidc.d.ts +6 -2
  30. package/dist/auth/oidc.js +16 -11
  31. package/dist/auth/oidc.js.map +1 -1
  32. package/dist/auth/store.d.ts +14 -2
  33. package/dist/auth/store.js +26 -1
  34. package/dist/auth/store.js.map +1 -1
  35. package/dist/cli/dotenv.d.ts +1 -1
  36. package/dist/cli/dotenv.js +36 -3
  37. package/dist/cli/dotenv.js.map +1 -1
  38. package/dist/config/agent-config.js +20 -15
  39. package/dist/config/agent-config.js.map +1 -1
  40. package/dist/http/addresses.d.ts +6 -0
  41. package/dist/http/addresses.js +26 -0
  42. package/dist/http/addresses.js.map +1 -1
  43. package/dist/http/context.d.ts +7 -5
  44. package/dist/http/context.js.map +1 -1
  45. package/dist/links.d.ts +26 -0
  46. package/dist/links.js +60 -0
  47. package/dist/links.js.map +1 -0
  48. package/dist/onboarding.d.ts +1 -1
  49. package/dist/onboarding.js +28 -8
  50. package/dist/onboarding.js.map +1 -1
  51. package/dist/profiles/profiles.js +1 -1
  52. package/dist/profiles/profiles.js.map +1 -1
  53. package/dist/providers/catalog.d.ts +85 -1
  54. package/dist/providers/catalog.js +280 -43
  55. package/dist/providers/catalog.js.map +1 -1
  56. package/dist/providers/tables.d.ts +3 -1
  57. package/dist/providers/tables.js +9 -4
  58. package/dist/providers/tables.js.map +1 -1
  59. package/dist/redact.js +493 -13
  60. package/dist/redact.js.map +1 -1
  61. package/dist/runtime.js +104 -42
  62. package/dist/runtime.js.map +1 -1
  63. package/dist/sessions/anchor.d.ts +22 -3
  64. package/dist/sessions/anchor.js +87 -42
  65. package/dist/sessions/anchor.js.map +1 -1
  66. package/dist/sessions/background-tasks.d.ts +140 -0
  67. package/dist/sessions/background-tasks.js +352 -0
  68. package/dist/sessions/background-tasks.js.map +1 -0
  69. package/dist/sessions/background-updates.d.ts +56 -0
  70. package/dist/sessions/background-updates.js +152 -0
  71. package/dist/sessions/background-updates.js.map +1 -0
  72. package/dist/sessions/cli-sessions.d.ts +6 -0
  73. package/dist/sessions/cli-sessions.js +20 -7
  74. package/dist/sessions/cli-sessions.js.map +1 -1
  75. package/dist/sessions/completions.d.ts +17 -1
  76. package/dist/sessions/completions.js +84 -13
  77. package/dist/sessions/completions.js.map +1 -1
  78. package/dist/sessions/compress.d.ts +33 -0
  79. package/dist/sessions/compress.js +66 -0
  80. package/dist/sessions/compress.js.map +1 -0
  81. package/dist/sessions/list.d.ts +22 -4
  82. package/dist/sessions/list.js +113 -33
  83. package/dist/sessions/list.js.map +1 -1
  84. package/dist/sessions/merge.d.ts +81 -7
  85. package/dist/sessions/merge.js +391 -26
  86. package/dist/sessions/merge.js.map +1 -1
  87. package/dist/sessions/pending.d.ts +5 -0
  88. package/dist/sessions/pending.js +30 -10
  89. package/dist/sessions/pending.js.map +1 -1
  90. package/dist/sessions/relay.d.ts +7 -1
  91. package/dist/sessions/relay.js +17 -4
  92. package/dist/sessions/relay.js.map +1 -1
  93. package/dist/sessions/service.d.ts +118 -6
  94. package/dist/sessions/service.js +564 -65
  95. package/dist/sessions/service.js.map +1 -1
  96. package/dist/sessions/session.d.ts +22 -1
  97. package/dist/sessions/session.js +29 -2
  98. package/dist/sessions/session.js.map +1 -1
  99. package/dist/sessions/shares.js +11 -2
  100. package/dist/sessions/shares.js.map +1 -1
  101. package/dist/sessions/source-kind.d.ts +22 -0
  102. package/dist/sessions/source-kind.js +54 -0
  103. package/dist/sessions/source-kind.js.map +1 -0
  104. package/dist/sessions/state-db.d.ts +10 -1
  105. package/dist/sessions/state-db.js +48 -17
  106. package/dist/sessions/state-db.js.map +1 -1
  107. package/dist/sessions/store.d.ts +2 -0
  108. package/dist/sessions/store.js +24 -5
  109. package/dist/sessions/store.js.map +1 -1
  110. package/dist/sessions/streams.d.ts +3 -0
  111. package/dist/sessions/streams.js +0 -5
  112. package/dist/sessions/streams.js.map +1 -1
  113. package/dist/sessions/titles.d.ts +4 -0
  114. package/dist/sessions/titles.js +16 -0
  115. package/dist/sessions/titles.js.map +1 -1
  116. package/dist/sessions/turn-context.d.ts +1 -0
  117. package/dist/sessions/turn-context.js +3 -0
  118. package/dist/sessions/turn-context.js.map +1 -1
  119. package/dist/sessions/turn.d.ts +85 -7
  120. package/dist/sessions/turn.js +518 -170
  121. package/dist/sessions/turn.js.map +1 -1
  122. package/dist/settings.d.ts +2 -0
  123. package/dist/settings.js +13 -0
  124. package/dist/settings.js.map +1 -1
  125. package/dist/sidecar/fake.js +2 -0
  126. package/dist/sidecar/fake.js.map +1 -1
  127. package/dist/tools/commands.d.ts +15 -0
  128. package/dist/tools/commands.js +52 -0
  129. package/dist/tools/commands.js.map +1 -0
  130. package/dist/tools/crons.d.ts +38 -4
  131. package/dist/tools/crons.js +323 -36
  132. package/dist/tools/crons.js.map +1 -1
  133. package/dist/tools/mcp.js +5 -1
  134. package/dist/tools/mcp.js.map +1 -1
  135. package/dist/tools/update-notifications.d.ts +1 -1
  136. package/dist/tools/update-notifications.js +1 -1
  137. package/dist/tools/update-notifications.js.map +1 -1
  138. package/dist/tools/updates.d.ts +8 -3
  139. package/dist/tools/updates.js +133 -34
  140. package/dist/tools/updates.js.map +1 -1
  141. package/dist/workspace/git.d.ts +57 -10
  142. package/dist/workspace/git.js +302 -195
  143. package/dist/workspace/git.js.map +1 -1
  144. package/dist/workspace/media-refs.d.ts +13 -0
  145. package/dist/workspace/media-refs.js +165 -0
  146. package/dist/workspace/media-refs.js.map +1 -0
  147. package/dist/workspace/media.d.ts +19 -0
  148. package/dist/workspace/media.js +61 -2
  149. package/dist/workspace/media.js.map +1 -1
  150. package/dist/workspace/workspaces.d.ts +7 -1
  151. package/dist/workspace/workspaces.js +30 -21
  152. package/dist/workspace/workspaces.js.map +1 -1
  153. package/dist/workspace/worktrees.d.ts +2 -4
  154. package/dist/workspace/worktrees.js +28 -33
  155. package/dist/workspace/worktrees.js.map +1 -1
  156. package/package.json +4 -2
  157. package/sidecar/scripts/replay_sidecar.py +3 -1
  158. package/sidecar/talaria_sidecar/__init__.py +1 -1
  159. package/sidecar/talaria_sidecar/home.py +59 -2
  160. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  161. package/sidecar/talaria_sidecar/methods/aux.py +19 -3
  162. package/sidecar/talaria_sidecar/methods/chat.py +360 -27
  163. package/sidecar/talaria_sidecar/methods/commands.py +46 -31
  164. package/sidecar/talaria_sidecar/methods/config.py +14 -10
  165. package/sidecar/talaria_sidecar/methods/cron.py +22 -14
  166. package/sidecar/talaria_sidecar/methods/oauth.py +439 -0
  167. package/sidecar/talaria_sidecar/methods/process.py +318 -0
  168. package/sidecar/talaria_sidecar/methods/profiles.py +5 -4
  169. package/sidecar/talaria_sidecar/methods/providers.py +161 -1
  170. package/sidecar/talaria_sidecar/methods/runtime.py +2 -0
  171. package/sidecar/talaria_sidecar/methods/text.py +1 -20
  172. package/sidecar/talaria_sidecar/methods/usage.py +7 -1
  173. package/static/dist/FILES.txt +124 -119
  174. package/static/dist/assets/AppShell-ef3bhu32.js +1 -0
  175. package/static/dist/assets/Button-nx37f4u1.js +1 -0
  176. package/static/dist/assets/ChatPage-cdcpykcg.js +25 -0
  177. package/static/dist/assets/Dialog-mec42hvb.js +1 -0
  178. package/static/dist/assets/HubRoute-ecb65zpr.js +2 -0
  179. package/static/dist/assets/{Markdown-emii55o0.js → Markdown-jqrx5es0.js} +125 -125
  180. package/static/dist/assets/RightPanel-d1lgvk4s.js +1 -0
  181. package/static/dist/assets/Select-h4ivl9qf.js +1 -0
  182. package/static/dist/assets/SessionListPanel-ewib046b.js +1 -0
  183. package/static/dist/assets/SettingsLayout-lx654cup.js +1 -0
  184. package/static/dist/assets/States-ehsb6lzo.js +1 -0
  185. package/static/dist/assets/Toaster-mch1pa3t.js +1 -0
  186. package/static/dist/assets/_app-m8d961ef.js +1 -0
  187. package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +1 -0
  188. package/static/dist/assets/_app.index-dk6zp7e0.js +1 -0
  189. package/static/dist/assets/_app.insights-jt2fk4i1.js +1 -0
  190. package/static/dist/assets/_app.kanban-if4pubeu.js +1 -0
  191. package/static/dist/assets/_app.logs-mfaw9m6g.js +1 -0
  192. package/static/dist/assets/_app.memory-h3eaarb6.js +1 -0
  193. package/static/dist/assets/_app.profiles-ienktovs.js +1 -0
  194. package/static/dist/assets/{_app.session._sessionId-m6nx9g8t.js → _app.session._sessionId-hh27wwu2.js} +1 -1
  195. package/static/dist/assets/_app.settings-dpoe0bzf.js +1 -0
  196. package/static/dist/assets/_app.settings._section-l468ynag.js +3 -0
  197. package/static/dist/assets/_app.skills-kcbncc8i.js +1 -0
  198. package/static/dist/assets/_app.tasks-occdrqhw.js +2 -0
  199. package/static/dist/assets/_app.todos-nnke2rcc.js +1 -0
  200. package/static/dist/assets/_app.workspaces-cdlatvwj.js +1 -0
  201. package/static/dist/assets/{abnfDiagram-VCTEODGH-kejgxpil.js → abnfDiagram-VCTEODGH-oity9y4o.js} +1 -1
  202. package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +1 -0
  203. package/static/dist/assets/architectureDiagram-5GKGNRK7-ceaepnyr.js +36 -0
  204. package/static/dist/assets/back-eu64w89w.js +1 -0
  205. package/static/dist/assets/{blockDiagram-I7D4REHJ-l1466a7j.js → blockDiagram-I7D4REHJ-n79st4pj.js} +1 -1
  206. package/static/dist/assets/{c4Diagram-7LVT6UL2-gg3aq3sr.js → c4Diagram-7LVT6UL2-mi73akzk.js} +1 -1
  207. package/static/dist/assets/cancel-mzvkdjg8.js +1 -0
  208. package/static/dist/assets/channel-mbvmf2vv.js +1 -0
  209. package/static/dist/assets/{chunk-4HAMMTFA-oalgz5l8.js → chunk-4HAMMTFA-laat0g1q.js} +1 -1
  210. package/static/dist/assets/{chunk-75Z2AOVW-babmzhdg.js → chunk-75Z2AOVW-0psy1tr2.js} +1 -1
  211. package/static/dist/assets/{chunk-DU6HZSFF-lagu350c.js → chunk-DU6HZSFF-lw8uox8x.js} +3 -3
  212. package/static/dist/assets/{chunk-F27PBJKO-gjh2tqif.js → chunk-F27PBJKO-erassib3.js} +1 -1
  213. package/static/dist/assets/{chunk-GMAD6QVW-ipdgja5c.js → chunk-GMAD6QVW-fz7rx619.js} +1 -1
  214. package/static/dist/assets/{chunk-GVQU2GXP-j8wkn1at.js → chunk-GVQU2GXP-gdb0epb2.js} +1 -1
  215. package/static/dist/assets/{chunk-IMKFNOWR-k00laqyk.js → chunk-IMKFNOWR-ea8t26qw.js} +1 -1
  216. package/static/dist/assets/{chunk-L3NEJ4N5-fju6xqj4.js → chunk-L3NEJ4N5-mb1gu9kz.js} +1 -1
  217. package/static/dist/assets/{chunk-OSK3NFVY-bi6widqt.js → chunk-OSK3NFVY-eovmccvy.js} +1 -1
  218. package/static/dist/assets/{chunk-P2QGCYS3-czr4tebv.js → chunk-P2QGCYS3-bo55zjo5.js} +1 -1
  219. package/static/dist/assets/{chunk-POPQ4Y6H-ktdhn67w.js → chunk-POPQ4Y6H-ja7ohe4h.js} +1 -1
  220. package/static/dist/assets/{chunk-PWAF6VOD-ii4dsu0d.js → chunk-PWAF6VOD-e30g9nus.js} +1 -1
  221. package/static/dist/assets/{chunk-SHT3W25Y-fpwk3xxp.js → chunk-SHT3W25Y-gbb798f7.js} +3 -3
  222. package/static/dist/assets/{chunk-SVP7TREG-k0jrvhei.js → chunk-SVP7TREG-h2iw8urm.js} +1 -1
  223. package/static/dist/assets/{chunk-TICWLB2K-nkqv9ot0.js → chunk-TICWLB2K-fd2cottz.js} +1 -1
  224. package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +1 -0
  225. package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +1 -0
  226. package/static/dist/assets/{copied-gpchexqu.js → copied-h65fc3cx.js} +1 -1
  227. package/static/dist/assets/copy-e6977uwq.js +1 -0
  228. package/static/dist/assets/{cynefin-OW5HDTMX-lqxt8rs3.js → cynefin-OW5HDTMX-lbltyl5j.js} +1 -1
  229. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-j9eqovf5.js → cynefinDiagram-5FMLGOSQ-lxhsqq4a.js} +1 -1
  230. package/static/dist/assets/{dagre-GXQ25YYZ-m9agobjm.js → dagre-GXQ25YYZ-gn4nnaln.js} +4 -4
  231. package/static/dist/assets/{diagram-S7CK7UJ4-itodc50c.js → diagram-S7CK7UJ4-pa3ij6q7.js} +3 -3
  232. package/static/dist/assets/{diagram-UQ7AKVKN-n1h2t4ah.js → diagram-UQ7AKVKN-zbipyz57.js} +1 -1
  233. package/static/dist/assets/{diagram-VSXAHHWV-lvtvm9bj.js → diagram-VSXAHHWV-d1kbpzgf.js} +1 -1
  234. package/static/dist/assets/{diagram-VX7I27RA-cgas58sy.js → diagram-VX7I27RA-i3ty14xl.js} +1 -1
  235. package/static/dist/assets/{diagram-Z3DM3KII-d0aeps1q.js → diagram-Z3DM3KII-m8xefqa7.js} +1 -1
  236. package/static/dist/assets/{ebnfDiagram-PWID7BFC-md345fyq.js → ebnfDiagram-PWID7BFC-nz7wj05l.js} +1 -1
  237. package/static/dist/assets/endpoints-k7yf25m0.js +64 -0
  238. package/static/dist/assets/{erDiagram-RLTQ6QDP-i4rua63b.js → erDiagram-RLTQ6QDP-fa41ib83.js} +1 -1
  239. package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +1 -0
  240. package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +1 -0
  241. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-geqx7zgl.js → ganttDiagram-EL5Y4UJY-n7zq01qu.js} +1 -1
  242. package/static/dist/assets/{gitGraph-4MIJSDKK-leoq0z8t.js → gitGraph-4MIJSDKK-c89emb07.js} +1 -1
  243. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-llrlxfha.js → gitGraphDiagram-WWUBYQGX-cz7cgr6w.js} +1 -1
  244. package/static/dist/assets/{highlighted-body-KPVGNVTW-kq2cnw6q.js → highlighted-body-KPVGNVTW-d9bapmni.js} +1 -1
  245. package/static/dist/assets/{index-f9bzglkn.js → index-h00usru2.js} +3 -3
  246. package/static/dist/assets/index-n73ijkv2.css +2 -0
  247. package/static/dist/assets/{info-A6RAGUB7-lkly4xj6.js → info-A6RAGUB7-ndddhhhh.js} +1 -1
  248. package/static/dist/assets/infoDiagram-27XIBGKW-ccxigcpf.js +2 -0
  249. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-hq6jf374.js → ishikawaDiagram-5VMMS53U-le0z9vtc.js} +1 -1
  250. package/static/dist/assets/{journeyDiagram-3NMN7TZE-is03ntb0.js → journeyDiagram-3NMN7TZE-ivsmb26o.js} +1 -1
  251. package/static/dist/assets/{kanban-definition-UXKFOSKX-jmerizqb.js → kanban-definition-UXKFOSKX-h6n2awt0.js} +1 -1
  252. package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +1 -0
  253. package/static/dist/assets/{line-laaa8h99.js → line-dmzlfe0u.js} +1 -1
  254. package/static/dist/assets/link-budeg5t9.js +1 -0
  255. package/static/dist/assets/login-kjhasvp8.js +1 -0
  256. package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +1 -0
  257. package/static/dist/assets/{mermaid-parser.core-ix4junux.js → mermaid-parser.core-gwyd5bnq.js} +3 -3
  258. package/static/dist/assets/{mindmap-definition-YA3MSWOX-o0e0adl1.js → mindmap-definition-YA3MSWOX-l68gg5h7.js} +1 -1
  259. package/static/dist/assets/onboarding-cdfrk0pj.js +1 -0
  260. package/static/dist/assets/{packet-AYTQ26CC-kl8pwsyg.js → packet-AYTQ26CC-gpv06065.js} +1 -1
  261. package/static/dist/assets/{pegDiagram-XKGWAZYB-bbqn9jo4.js → pegDiagram-XKGWAZYB-e52vs23u.js} +1 -1
  262. package/static/dist/assets/{pie-WAS4IAKB-cpyo8bkr.js → pie-WAS4IAKB-l6m7nz5s.js} +1 -1
  263. package/static/dist/assets/{pieDiagram-E7YTZNPT-pelug34f.js → pieDiagram-E7YTZNPT-b4is36bq.js} +3 -3
  264. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-jds4jmr5.js → quadrantDiagram-AXDQQJYC-m8vt2788.js} +1 -1
  265. package/static/dist/assets/{radar-RG4KPBEZ-e02oxnvd.js → radar-RG4KPBEZ-nxbrhiov.js} +1 -1
  266. package/static/dist/assets/{railroad-74A4TZTK-kz3delwo.js → railroad-74A4TZTK-222mu9hi.js} +1 -1
  267. package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +1 -0
  268. package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +1 -0
  269. package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +1 -0
  270. package/static/dist/assets/{railroadDiagram-O6MQD6OU-jgroj2ew.js → railroadDiagram-O6MQD6OU-o8lldfzv.js} +1 -1
  271. package/static/dist/assets/{refresh-cw-k7yxjdn3.js → refresh-cw-kbcje1uy.js} +1 -1
  272. package/static/dist/assets/{requirementDiagram-BXWQKSXE-m4az5e0j.js → requirementDiagram-BXWQKSXE-ovyq38kv.js} +1 -1
  273. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-vlryqiv3.js → sankeyDiagram-P5KCCOFB-ou7lznor.js} +1 -1
  274. package/static/dist/assets/{saved-brdfjjnw.js → saved-bazmcup9.js} +1 -1
  275. package/static/dist/assets/search-jen74z4u.js +1 -0
  276. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-fr8hrpql.js → sequenceDiagram-WJ2MYXX4-ovckdzf2.js} +1 -1
  277. package/static/dist/assets/{settings_section_extensions_title-l0zodj0b.js → settings_section_extensions_title-ertwwhlx.js} +1 -1
  278. package/static/dist/assets/share._token-dan9hgvj.js +2 -0
  279. package/static/dist/assets/{sliders-horizontal-gcgscv8r.js → sliders-horizontal-f9cb3lh3.js} +1 -1
  280. package/static/dist/assets/{stateDiagram-D77RDMKH-bg548iyr.js → stateDiagram-D77RDMKH-fcrexkkv.js} +1 -1
  281. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +1 -0
  282. package/static/dist/assets/{swimlanes-42K2YHIH-hk5z3efh.js → swimlanes-42K2YHIH-f7usu8fw.js} +1 -1
  283. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +8 -0
  284. package/static/dist/assets/{timeline-definition-24CTP7MA-olvknr62.js → timeline-definition-24CTP7MA-gp1hvz9f.js} +1 -1
  285. package/static/dist/assets/todoStore-eqtid4r4.js +1 -0
  286. package/static/dist/assets/{treeView-Q6P3EWNA-ovvjsxtf.js → treeView-Q6P3EWNA-gb9gf11u.js} +1 -1
  287. package/static/dist/assets/{treemap-WGGIJYW6-ggkipj59.js → treemap-WGGIJYW6-nuvfnvvi.js} +1 -1
  288. package/static/dist/assets/{untitled-c8ydw0bu.js → untitled-htelhc68.js} +1 -1
  289. package/static/dist/assets/useForm-h2t0u14e.js +1 -0
  290. package/static/dist/assets/useLocale-hcsb84pj.js +1 -0
  291. package/static/dist/assets/useNavigate-nwy70ztj.js +1 -0
  292. package/static/dist/assets/{useParams-katwvzil.js → useParams-dqd64jv7.js} +1 -1
  293. package/static/dist/assets/{useSearch-c70sgau1.js → useSearch-j30pvsy7.js} +1 -1
  294. package/static/dist/assets/{vennDiagram-4TSXK5OY-hzld7zt7.js → vennDiagram-4TSXK5OY-fzchbzaj.js} +1 -1
  295. package/static/dist/assets/{wardley-WFR3VGLG-hxkeoms8.js → wardley-WFR3VGLG-m47mhfbh.js} +1 -1
  296. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ljh90mb1.js → wardleyDiagram-VM6X3IG4-odg6ct1z.js} +2 -2
  297. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mnuaes03.js → xychartDiagram-S5SC5T6Z-mrhms5um.js} +1 -1
  298. package/static/dist/index.html +1 -1
  299. package/static/dist/sw.js +1 -1
  300. package/static/dist/assets/AppShell-haqi9qzu.js +0 -1
  301. package/static/dist/assets/ChatPage-hjyu2g64.js +0 -22
  302. package/static/dist/assets/HubRoute-gkd8o1vg.js +0 -2
  303. package/static/dist/assets/RightPanel-o73y98dn.js +0 -1
  304. package/static/dist/assets/Select-jld3yeni.js +0 -1
  305. package/static/dist/assets/SessionListPanel-d3qx4ric.js +0 -1
  306. package/static/dist/assets/SettingsLayout-lnn2wo2s.js +0 -1
  307. package/static/dist/assets/States-e5hv6gdh.js +0 -1
  308. package/static/dist/assets/Toaster-c4jq1i26.js +0 -1
  309. package/static/dist/assets/_app-bnip2pjg.js +0 -1
  310. package/static/dist/assets/_app.ext._extensionId-egptzrfy.js +0 -1
  311. package/static/dist/assets/_app.index-vdz13ul5.js +0 -1
  312. package/static/dist/assets/_app.insights-lgjshsba.js +0 -1
  313. package/static/dist/assets/_app.kanban-c18cjrpz.js +0 -1
  314. package/static/dist/assets/_app.logs-ezhojgeg.js +0 -1
  315. package/static/dist/assets/_app.memory-i00paisv.js +0 -1
  316. package/static/dist/assets/_app.profiles-kd02bwjx.js +0 -1
  317. package/static/dist/assets/_app.settings-giaudkuk.js +0 -1
  318. package/static/dist/assets/_app.settings._section-k4qtlexk.js +0 -1
  319. package/static/dist/assets/_app.skills-bby2uvl8.js +0 -1
  320. package/static/dist/assets/_app.tasks-1kz9bosm.js +0 -2
  321. package/static/dist/assets/_app.todos-izjdbkm2.js +0 -1
  322. package/static/dist/assets/_app.workspaces-lfh2kw7s.js +0 -1
  323. package/static/dist/assets/architecture-7GRP2DOG-b4u9z1w3.js +0 -1
  324. package/static/dist/assets/architectureDiagram-5GKGNRK7-hqnf84fc.js +0 -36
  325. package/static/dist/assets/channel-o77ioktg.js +0 -1
  326. package/static/dist/assets/classDiagram-ZZMXUADV-f5rvod26.js +0 -1
  327. package/static/dist/assets/classDiagram-v2-VYDZK3BY-f5rvod26.js +0 -1
  328. package/static/dist/assets/endpoints-e58saih3.js +0 -9
  329. package/static/dist/assets/eventmodeling-NTZA5JFV-bn3fjsaq.js +0 -1
  330. package/static/dist/assets/flowDiagram-HODETNUW-li70d120.js +0 -1
  331. package/static/dist/assets/index-gkh7kum4.css +0 -2
  332. package/static/dist/assets/infoDiagram-27XIBGKW-oo7kdyte.js +0 -2
  333. package/static/dist/assets/lazyRouteComponent-b1h2ykmb.js +0 -1
  334. package/static/dist/assets/link-d8f0788e.js +0 -1
  335. package/static/dist/assets/login-llkohrcg.js +0 -1
  336. package/static/dist/assets/mermaid-HWGCJPDP-id0ffk2r.js +0 -1
  337. package/static/dist/assets/onboarding-lx0d6b38.js +0 -1
  338. package/static/dist/assets/railroad-abnf-HS5TGJTU-l13ped2z.js +0 -1
  339. package/static/dist/assets/railroad-ebnf-LZEXJU2U-c7rg3g4g.js +0 -1
  340. package/static/dist/assets/railroad-peg-WCYAUIDC-od0b8niq.js +0 -1
  341. package/static/dist/assets/search-gt2ueyvg.js +0 -1
  342. package/static/dist/assets/share._token-oyjv046r.js +0 -2
  343. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-j5v40qih.js +0 -1
  344. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-grzefo9c.js +0 -8
  345. package/static/dist/assets/tabBuild-idliyw9f.js +0 -56
  346. package/static/dist/assets/todoStore-j4c2xq0b.js +0 -1
  347. package/static/dist/assets/useForm-kd759sjk.js +0 -1
  348. package/static/dist/assets/useLocale-hds4xmja.js +0 -1
@@ -0,0 +1,52 @@
1
+ const ALL = ['web', 'ios'];
2
+ const client = (name, description, extra = {}) => ({ name, description, aliases: [], handler: 'client', clients: ALL, ...extra });
3
+ const webOnly = (unsupported_message) => ({ clients: ['web'], unsupported_message });
4
+ /** Commands a client handles itself, in display order. Every entry outside a client's `clients` carries `unsupported_message`. */
5
+ export const CLIENT_COMMANDS = [
6
+ client('help', 'Show available commands'),
7
+ client('new', 'Start a new conversation'),
8
+ client('clear', 'Clear this conversation'),
9
+ client('stop', 'Stop the running response'),
10
+ client('interrupt', 'Interrupt and send', { args_hint: '<message>' }),
11
+ client('queue', 'Queue a follow-up', { args_hint: '<message>' }),
12
+ client('steer', 'Steer the running response', { args_hint: '<message>' }),
13
+ client('model', 'Switch the conversation model', { args_hint: '<id>' }),
14
+ client('workspace', 'Switch workspace', { args_hint: '<path>' }),
15
+ client('terminal', 'Toggle the workspace terminal', webOnly('Terminal is not available in the mobile app.')),
16
+ client('title', 'Rename this conversation', { args_hint: '<text>' }),
17
+ client('retry', 'Retry the last turn'),
18
+ client('undo', 'Undo the last turn'),
19
+ client('compress', 'Compress the context', { aliases: ['compact'] }),
20
+ client('usage', 'Show token usage', webOnly('Token usage is not available in the mobile app.')),
21
+ client('theme', 'Switch theme', { args_hint: '<light|dark|system>', ...webOnly('Theme switching is not available from mobile slash commands.') }),
22
+ client('yolo', 'Toggle YOLO mode (skip approvals)', webOnly('YOLO mode is not available in the mobile app.')),
23
+ client('branch', 'Branch the conversation', { aliases: ['fork'] }),
24
+ client('voice', 'Toggle voice mode', webOnly('Voice commands are not available in the mobile app.')),
25
+ client('reasoning', 'Set reasoning effort', { args_hint: '<level>' }),
26
+ client('personality', 'Set the personality', { args_hint: '<name>' }),
27
+ client('goal', 'Set or show the goal', { args_hint: '<text>' }),
28
+ client('status', 'Show session status'),
29
+ client('btw', 'Side question without affecting the run', { args_hint: '<question>' }),
30
+ client('background', 'Run in the background', { args_hint: '<message>', aliases: ['bg'] }),
31
+ client('skills', 'List skills'),
32
+ client('use', 'Use a skill', { args_hint: '<skill>', ...webOnly('Use `/skills [query]` to search skills.') }),
33
+ ];
34
+ /**
35
+ * The client table followed by the Agent registry. An Agent command whose name is already a client name or alias is
36
+ * dropped, and client-claimed aliases are removed from the rest, so every typed name resolves to one entry.
37
+ * Gateway-only commands never reach a client; CLI-only ones stay listed for no client.
38
+ */
39
+ export function commandCatalog(agent) {
40
+ const claimed = new Set(CLIENT_COMMANDS.flatMap((c) => [c.name, ...c.aliases]));
41
+ const rows = agent.flatMap((c) => {
42
+ if (c.gateway_only || claimed.has(c.name))
43
+ return [];
44
+ claimed.add(c.name);
45
+ const aliases = c.aliases.filter((a) => !claimed.has(a));
46
+ for (const a of aliases)
47
+ claimed.add(a);
48
+ return [{ ...c, aliases, handler: 'agent', clients: c.cli_only ? [] : ALL, ...(c.cli_only ? { unsupported_message: `/${c.name} runs only in the Hermes CLI.` } : {}) }];
49
+ });
50
+ return [...CLIENT_COMMANDS, ...rows];
51
+ }
52
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/tools/commands.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- /** Cron jobs across profiles through the sidecar `cron.*` namespace (Python `api/routes.py` cron section). */
1
+ import type { CronRecentCompletion, CronContextSources } from '@maudecode/talaria-web-contracts';
2
2
  import type { SidecarLike } from '../sidecar/client.js';
3
- import type { Dict } from '../config/agent-config.js';
3
+ import { type Dict } from '../config/agent-config.js';
4
4
  export interface CronDeps {
5
5
  sidecar: () => SidecarLike | null;
6
6
  profileHome: (name: string) => string;
@@ -13,14 +13,26 @@ export interface CronDeps {
13
13
  log: (line: string) => void;
14
14
  /** Python `_publish_session_list_changed("cron_complete", profile=...)` once a manual run finishes. */
15
15
  publishSessionsChanged?: (reason: string, profile: string | null) => void;
16
+ /** TAL-301: the catalog entry id a job's stored `(model, provider)` selects in a profile home's picker catalog. */
17
+ modelOptionFor?: (home: string, model: string | null, provider: string | null) => Promise<string | null>;
16
18
  /** Python `_RUNNING_CRON_JOBS`: job id → start time, read by the session list's `cron_running` stamp. */
17
19
  runningJobs?: Map<string, number>;
18
20
  }
19
- /** Python `_cron_job_for_api`. */
20
- export declare function jobForApi(job: Dict): Dict;
21
+ /** Python `_cron_job_for_api`, plus the derived status every client renders (TAL-296). */
22
+ export declare function jobForApi(job: Dict, running?: boolean): Dict;
21
23
  /** Python `_cron_job_field_updates`. */
22
24
  export declare function jobFieldUpdates(body: Dict, currentContextFrom?: unknown): Dict;
23
25
  export declare function validJobId(id: string): boolean;
26
+ /** Python `float(since)` with its ValueError mapped to 0: a malformed `since` means "from the epoch", never a 500. */
27
+ export declare function parseSince(raw: string | undefined): number;
28
+ /**
29
+ * Python `_handle_cron_recent`'s `last_run_at` read (`datetime.fromisoformat` after `Z` → `+00:00`, or a number).
30
+ * Only ISO-shaped strings count, so `Date.parse` leniency ("Jan 2 2026") never invents a completion; a time without
31
+ * an offset is server-local, as in Python. Anything else is skipped.
32
+ */
33
+ export declare function completedAtSeconds(value: unknown): number | null;
34
+ /** The one place a job's `last_status` becomes the success/failure the clients render. */
35
+ export declare function completionOutcome(status: unknown): CronRecentCompletion['outcome'];
24
36
  export declare class CronService {
25
37
  private readonly deps;
26
38
  constructor(deps: CronDeps);
@@ -28,8 +40,30 @@ export declare class CronService {
28
40
  private profileNames;
29
41
  availableProfileNames(): Promise<Set<string>>;
30
42
  normalizeProfile(value: unknown): Promise<string | null>;
43
+ private profileForHome;
44
+ /** The physical store owns execution. Additive owner_profile metadata lets the creator manage a new job there. */
45
+ private storedJobs;
46
+ /** `pickerHome` is the profile whose `/api/models` catalog the requesting client shows. */
47
+ private view;
48
+ private requireExecutionStore;
49
+ private validateContext;
50
+ private resolveStore;
51
+ contextSources(home: string, input: {
52
+ profile?: string | undefined;
53
+ editing_job_id?: string | undefined;
54
+ exclude_job_id?: string | undefined;
55
+ selected_refs?: string[] | undefined;
56
+ }): Promise<CronContextSources>;
31
57
  /** Python `/api/crons`: the active profile's rows plus foreign rows (hidden unless `all_profiles`). */
32
58
  list(active: string, allProfiles: boolean): Promise<Dict>;
59
+ /**
60
+ * Python `/api/crons/recent`: each active-profile job's latest completion after `since`, newest first (ties by
61
+ * `job_id`), with the server's `outcome` and the newest cron session for that job. One row per job, not a run archive.
62
+ */
63
+ recent(home: string, rawSince: string | undefined): Promise<{
64
+ completions: CronRecentCompletion[];
65
+ since: number;
66
+ }>;
33
67
  create(home: string, body: Dict): Promise<Dict>;
34
68
  update(home: string, body: Dict): Promise<Dict>;
35
69
  private simple;
@@ -1,18 +1,87 @@
1
+ /** Cron jobs across profiles through the sidecar `cron.*` namespace (Python `api/routes.py` cron section). */
2
+ import { join } from 'node:path';
3
+ import { parseProviderQualifiedModel } from '../config/agent-config.js';
1
4
  import { HttpFailure } from '../sessions/service.js';
2
5
  import { SidecarError } from '../sidecar/client.js';
6
+ import { latestCronSessionInfo } from '../sessions/state-db.js';
7
+ import { stripToolCallXml } from '../sessions/merge.js';
3
8
  import { str } from '../util.js';
4
9
  const JOB_ID_RE = /^[A-Za-z0-9_-][A-Za-z0-9_.-]{0,63}$/;
5
10
  const PASSTHROUGH_FIELDS = ['script', 'no_agent', 'context_from', 'reasoning_effort'];
6
- /** Python `_cron_job_for_api`. */
7
- export function jobForApi(job) {
11
+ /** TAL-301: a picked catalog id (`@provider:model`) names its own provider, exactly as a chat request does; a bare id keeps the explicit one. */
12
+ function modelSelection(model, provider) {
13
+ const raw = str(model).trim();
14
+ const explicit = str(provider).trim() || null;
15
+ if (!raw)
16
+ return [null, explicit];
17
+ return parseProviderQualifiedModel(raw) ?? [raw, explicit];
18
+ }
19
+ /** Python `_cron_job_for_api`, plus the derived status every client renders (TAL-296). */
20
+ export function jobForApi(job, running = false) {
8
21
  const payload = { ...job };
22
+ // TAL-301: a job stored with a provider-qualified id (older clients) still reads back as a bare model and its provider.
23
+ const qualified = parseProviderQualifiedModel(job.model);
24
+ if (qualified)
25
+ [payload.model, payload.provider] = qualified;
9
26
  if (!('profile' in payload))
10
27
  payload.profile = null;
11
28
  payload.toast_notifications = payload.toast_notifications !== false;
12
29
  payload.monitor = str(payload.monitor_url) || str(payload.monitor_script) || '';
13
30
  payload.continuity = (Array.isArray(payload.context_from) ? payload.context_from : []).some((r) => str(r).trim().toLowerCase() === 'self');
31
+ const state = cronDerivedState(job);
32
+ payload.derived_state = state;
33
+ payload.needs_attention = state === 'needs_attention' || state === 'schedule_error';
34
+ payload.resumable = payload.needs_attention || state === 'paused' || state === 'off';
35
+ payload.running = running || job.running === true;
36
+ Object.assign(payload, scheduleText(job));
14
37
  return payload;
15
38
  }
39
+ /** TAL-298: the schedule's display text and the editor's prefill, in the scheduler's own vocabulary (not localized copy). */
40
+ function scheduleText(job) {
41
+ const schedule = job.schedule;
42
+ const legacy = typeof schedule === 'string' ? schedule : '';
43
+ const s = typeof schedule === 'object' && schedule ? schedule : {};
44
+ const minutes = typeof s.minutes === 'number' && s.minutes > 0 ? s.minutes : 0;
45
+ const runAt = str(s.run_at);
46
+ let input = '';
47
+ let built = '';
48
+ if (s.kind === 'cron')
49
+ input = built = str(s.expr);
50
+ else if (s.kind === 'interval' && minutes)
51
+ [input, built] = [`every ${minutes}m`, minutes % 60 ? `every ${minutes}m` : `every ${minutes / 60}h`];
52
+ else if (s.kind === 'once' && runAt)
53
+ [input, built] = [runAt, `once at ${runAt}`];
54
+ const display = str(job.schedule_display) || str(s.display) || legacy || built;
55
+ return { schedule_display: display, schedule_input: input || legacy || display };
56
+ }
57
+ /** `repeat.times == null` means "forever" in the store; a missing record is not unlimited. */
58
+ function hasUnlimitedRepeat(job) {
59
+ return !!job.repeat && typeof job.repeat === 'object' && job.repeat.times == null;
60
+ }
61
+ function isRecurring(job) {
62
+ const schedule = job.schedule;
63
+ if (typeof schedule === 'object' && schedule)
64
+ return schedule.kind === 'cron' || schedule.kind === 'interval';
65
+ // Legacy string schedules carry no kind; an unlimited repeat record marks the job recurring (a one-shot has times: 1).
66
+ return typeof schedule === 'string' && hasUnlimitedRepeat(job);
67
+ }
68
+ /** Older agents report `paused` / `status` / `next_run` instead of `state` / `last_status` / `next_run_at`; all stay supported. */
69
+ function cronDerivedState(job) {
70
+ const errored = job.state === 'error' || completionOutcome(job.last_status) === 'failed' || job.status === 'error';
71
+ const nextRun = job.next_run_at ?? (typeof job.next_run === 'number' || typeof job.next_run === 'string' ? job.next_run : null);
72
+ if (isRecurring(job) && hasUnlimitedRepeat(job) && job.enabled === false && job.state === 'completed' && !nextRun)
73
+ return 'needs_attention';
74
+ // A paused job keeps the last run's error and has no next run; that is not a schedule failure.
75
+ if (job.state === 'paused' || job.paused)
76
+ return 'paused';
77
+ if (isRecurring(job) && !nextRun && errored)
78
+ return 'schedule_error';
79
+ if (job.enabled === false)
80
+ return 'off';
81
+ if (errored)
82
+ return 'error';
83
+ return 'active';
84
+ }
16
85
  function monitorStorage(monitor) {
17
86
  const value = str(monitor).trim();
18
87
  if (!value)
@@ -53,6 +122,50 @@ export function jobFieldUpdates(body, currentContextFrom = null) {
53
122
  export function validJobId(id) {
54
123
  return JOB_ID_RE.test(id) && id !== '.' && id !== '..';
55
124
  }
125
+ const PY_FLOAT_RE = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
126
+ /** Python `float(since)` with its ValueError mapped to 0: a malformed `since` means "from the epoch", never a 500. */
127
+ export function parseSince(raw) {
128
+ const t = (raw ?? '').trim();
129
+ const n = PY_FLOAT_RE.test(t) ? Number(t) : 0;
130
+ return Number.isFinite(n) ? n : 0;
131
+ }
132
+ const ISO_RE = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2})(?::(\d{2})(?::(\d{2})(?:\.(\d{1,6}))?)?)?)?(Z|[+-]\d{2}(?::?\d{2})?)?$/;
133
+ /**
134
+ * Python `_handle_cron_recent`'s `last_run_at` read (`datetime.fromisoformat` after `Z` → `+00:00`, or a number).
135
+ * Only ISO-shaped strings count, so `Date.parse` leniency ("Jan 2 2026") never invents a completion; a time without
136
+ * an offset is server-local, as in Python. Anything else is skipped.
137
+ */
138
+ export function completedAtSeconds(value) {
139
+ if (typeof value === 'number')
140
+ return value && Number.isFinite(value) ? value : null;
141
+ if (typeof value !== 'string')
142
+ return null;
143
+ const m = ISO_RE.exec(value);
144
+ if (!m)
145
+ return null;
146
+ const [y, mo, d, h, mi, sec] = [1, 2, 3, 4, 5, 6].map((i) => Number(m[i] ?? 0));
147
+ const ms = Number((m[7] ?? '').padEnd(3, '0').slice(0, 3));
148
+ if (mo < 1 || mo > 12 || d < 1 || new Date(Date.UTC(y, mo - 1, d)).getUTCDate() !== d || h > 23 || mi > 59 || sec > 59)
149
+ return null;
150
+ const offset = m[8];
151
+ if (offset === undefined)
152
+ return new Date(y, mo - 1, d, h, mi, sec, ms).getTime() / 1000;
153
+ let offsetMinutes = 0;
154
+ if (offset !== 'Z') {
155
+ const digits = offset.slice(1).replace(':', '');
156
+ offsetMinutes = (offset.startsWith('-') ? -1 : 1) * (Number(digits.slice(0, 2)) * 60 + Number(digits.slice(2) || 0));
157
+ }
158
+ return (Date.UTC(y, mo - 1, d, h, mi, sec, ms) - offsetMinutes * 60_000) / 1000;
159
+ }
160
+ /** The one place a job's `last_status` becomes the success/failure the clients render. */
161
+ export function completionOutcome(status) {
162
+ const s = str(status).trim().toLowerCase();
163
+ if (s === 'error' || s === 'failed')
164
+ return 'failed';
165
+ if (s === 'ok' || s === 'success' || s === 'completed')
166
+ return 'succeeded';
167
+ return 'unknown';
168
+ }
56
169
  export class CronService {
57
170
  deps;
58
171
  constructor(deps) {
@@ -72,6 +185,8 @@ export class CronService {
72
185
  names.push(n);
73
186
  } };
74
187
  add(active);
188
+ if (this.deps.isolatedProfileMode())
189
+ return names;
75
190
  for (const row of await this.deps.profileNames())
76
191
  if (row.visible || this.deps.profilesMatch(row.name, active))
77
192
  add(row.name);
@@ -97,51 +212,195 @@ export class CronService {
97
212
  throw new HttpFailure(400, `Unknown profile: ${profile}`);
98
213
  return profile;
99
214
  }
100
- /** Python `/api/crons`: the active profile's rows plus foreign rows (hidden unless `all_profiles`). */
101
- async list(active, allProfiles) {
102
- const sidecar = this.sidecar();
103
- const activeJobs = [];
104
- const otherJobs = [];
105
- const seenHomes = new Set();
106
- for (const owner of await this.profileNames(active)) {
107
- const home = this.deps.profileHome(owner);
108
- if (seenHomes.has(home))
215
+ async profileForHome(home) {
216
+ const names = this.deps.isolatedProfileMode() ? (await this.deps.profileNames()).map((row) => row.name) : await this.availableProfileNames();
217
+ for (const profile of names)
218
+ if (this.deps.profileHome(profile) === home)
219
+ return profile;
220
+ throw new HttpFailure(403, 'Unknown cron profile home');
221
+ }
222
+ /** The physical store owns execution. Additive owner_profile metadata lets the creator manage a new job there. */
223
+ async storedJobs(active) {
224
+ // ponytail: scan visible stores per request; add an index only if profile/job counts make this expensive.
225
+ const rows = [];
226
+ const seen = new Set();
227
+ for (const profile of await this.profileNames(active)) {
228
+ const home = this.deps.profileHome(profile);
229
+ if (seen.has(home))
109
230
  continue;
110
- seenHomes.add(home);
111
- const isActive = this.deps.profilesMatch(owner, active);
231
+ seen.add(home);
232
+ const local = this.deps.profilesMatch(profile, active);
112
233
  let jobs;
113
234
  try {
114
- jobs = (await sidecar.call('cron.list', { profile_home: home })).jobs.map((j) => jobForApi(j));
235
+ jobs = (await this.sidecar().call('cron.list', { profile_home: home })).jobs;
115
236
  }
116
237
  catch (error) {
117
- if (!isActive)
118
- continue;
119
- if (error instanceof SidecarError && error.condition === 'cron_unavailable')
120
- return { jobs: [], cron_unavailable: true };
121
- throw error;
238
+ if (local)
239
+ throw error;
240
+ continue;
241
+ }
242
+ for (const job of jobs) {
243
+ const creator = str(job.owner_profile).trim();
244
+ rows.push({ home, profile, job, managed: local || Boolean(creator && this.deps.profilesMatch(creator, active)) });
122
245
  }
123
- for (const job of jobs)
124
- (isActive ? activeJobs : otherJobs).push({ ...job, owner_profile: owner, read_only: !isActive });
246
+ }
247
+ return rows;
248
+ }
249
+ /** `pickerHome` is the profile whose `/api/models` catalog the requesting client shows. */
250
+ async view(row, pickerHome) {
251
+ const payload = { ...jobForApi(row.job, this.deps.runningJobs?.has(str(row.job.id)) ?? false), profile: str(row.job.profile).trim() || row.profile, owner_profile: row.profile, read_only: !row.managed };
252
+ payload.model_option_id = (await this.deps.modelOptionFor?.(pickerHome, str(payload.model) || null, str(payload.provider) || null)) ?? null;
253
+ return payload;
254
+ }
255
+ requireExecutionStore(row) {
256
+ const profile = str(row.job.profile).trim();
257
+ if (profile && !this.deps.profilesMatch(profile, row.profile))
258
+ throw new HttpFailure(409, 'This legacy task must be recreated in its execution profile before it can run or resume');
259
+ }
260
+ async validateContext(home, fields) {
261
+ const refs = continuityRefs(fields.context_from, false);
262
+ if (!refs.length)
263
+ return;
264
+ const ids = new Set((await this.sidecar().call('cron.list', { profile_home: home })).jobs.map((job) => job.id));
265
+ if (refs.some((ref) => !ids.has(str(ref))))
266
+ throw new HttpFailure(400, 'Context jobs must belong to the execution profile');
267
+ }
268
+ async resolveStore(home, ref) {
269
+ const active = await this.profileForHome(home);
270
+ const allRows = await this.storedJobs(active);
271
+ const rows = allRows.filter((row) => row.managed);
272
+ const exact = rows.filter((row) => row.job.id === ref);
273
+ const matches = exact.length ? exact : rows.filter((row) => row.job.name === ref);
274
+ if (!matches.length)
275
+ throw new HttpFailure(404, 'Job not found');
276
+ if (matches.length !== 1)
277
+ throw new HttpFailure(409, 'Ambiguous cron job reference');
278
+ const match = matches[0];
279
+ if (allRows.filter((row) => row.home === match.home && row.job.id === match.job.id).length !== 1)
280
+ throw new HttpFailure(409, 'Ambiguous cron job reference');
281
+ return match;
282
+ }
283
+ async contextSources(home, input) {
284
+ const active = await this.profileForHome(home);
285
+ const editing = input.editing_job_id ? await this.resolveStore(home, input.editing_job_id) : null;
286
+ const profile = await this.normalizeProfile(input.profile);
287
+ if (profile && !(await this.profileNames(active)).some((name) => this.deps.profilesMatch(name, profile)))
288
+ throw new HttpFailure(403, 'Execution profile is not accessible');
289
+ const executionHome = profile ? this.deps.profileHome(profile) : editing?.home ?? home;
290
+ const rows = await this.storedJobs(active);
291
+ const inStore = rows.filter((row) => row.home === executionHome);
292
+ const excludeId = editing ? str(editing.job.id) : input.exclude_job_id;
293
+ const counts = new Map();
294
+ for (const row of inStore)
295
+ counts.set(str(row.job.id), (counts.get(str(row.job.id)) ?? 0) + 1);
296
+ const sources = [];
297
+ const included = new Set();
298
+ for (const row of inStore) {
299
+ const id = str(row.job.id).trim();
300
+ if (!row.managed || !id || id === excludeId || counts.get(id) !== 1)
301
+ continue;
302
+ sources.push({ job_id: id, label: str(row.job.name).trim() || id, selectable: true });
303
+ included.add(id);
304
+ }
305
+ for (const raw of input.selected_refs ?? []) {
306
+ const id = raw.trim();
307
+ if (!id || id.toLowerCase() === 'self' || included.has(id))
308
+ continue;
309
+ const owned = rows.find((row) => row.managed && row.job.id === id);
310
+ sources.push({ job_id: id, label: str(owned?.job.name).trim() || id, selectable: false });
311
+ included.add(id);
312
+ }
313
+ return { profile: profile ?? editing?.profile ?? active, sources };
314
+ }
315
+ /** Python `/api/crons`: the active profile's rows plus foreign rows (hidden unless `all_profiles`). */
316
+ async list(active, allProfiles) {
317
+ const activeJobs = [];
318
+ const otherJobs = [];
319
+ const pickerHome = this.deps.profileHome(active);
320
+ try {
321
+ for (const row of await this.storedJobs(active))
322
+ (row.managed ? activeJobs : otherJobs).push(await this.view(row, pickerHome));
323
+ }
324
+ catch (error) {
325
+ if (error instanceof SidecarError && error.condition === 'cron_unavailable')
326
+ return { jobs: [], cron_unavailable: true };
327
+ throw error;
125
328
  }
126
329
  const all = allProfiles && !this.deps.isolatedProfileMode();
127
330
  return { jobs: all ? [...activeJobs, ...otherJobs] : activeJobs, all_profiles: all, active_profile: active, other_profile_count: all ? 0 : otherJobs.length };
128
331
  }
332
+ /**
333
+ * Python `/api/crons/recent`: each active-profile job's latest completion after `since`, newest first (ties by
334
+ * `job_id`), with the server's `outcome` and the newest cron session for that job. One row per job, not a run archive.
335
+ */
336
+ async recent(home, rawSince) {
337
+ const since = parseSince(rawSince);
338
+ let rows;
339
+ try {
340
+ rows = (await this.storedJobs(await this.profileForHome(home))).filter((row) => row.managed);
341
+ }
342
+ catch (error) {
343
+ if (error instanceof SidecarError && error.condition === 'cron_unavailable')
344
+ return { completions: [], since };
345
+ throw error;
346
+ }
347
+ const completions = [];
348
+ for (const { job } of rows) {
349
+ const jobId = str(job.id).trim();
350
+ const completedAt = completedAtSeconds(job.last_run_at);
351
+ if (!jobId || completedAt === null || completedAt <= since)
352
+ continue;
353
+ const status = 'last_status' in job ? (job.last_status === null ? null : str(job.last_status)) : 'unknown';
354
+ completions.push({
355
+ job_id: jobId,
356
+ name: 'name' in job ? (job.name === null ? null : str(job.name)) : 'Unknown',
357
+ status,
358
+ outcome: completionOutcome(status),
359
+ completed_at: completedAt,
360
+ toast_notifications: job.toast_notifications !== false,
361
+ session_id: '',
362
+ });
363
+ }
364
+ completions.sort((a, b) => b.completed_at - a.completed_at || (a.job_id < b.job_id ? -1 : a.job_id > b.job_id ? 1 : 0));
365
+ for (const storeHome of new Set(rows.map((row) => row.home))) {
366
+ const ids = rows.filter((row) => row.home === storeHome).map((row) => str(row.job.id));
367
+ const sessions = latestCronSessionInfo(join(storeHome, 'state.db'), ids, completions.filter((c) => ids.includes(c.job_id)).map((c) => c.job_id));
368
+ for (const completion of completions) {
369
+ if (!ids.includes(completion.job_id))
370
+ continue;
371
+ const info = sessions.get(completion.job_id);
372
+ if (!info)
373
+ continue;
374
+ completion.session_id = info.session_id;
375
+ if (info.message_count !== null)
376
+ completion.message_count = info.message_count;
377
+ }
378
+ }
379
+ return { completions, since };
380
+ }
129
381
  async create(home, body) {
130
382
  if (!('schedule' in body) || body.schedule === null || body.schedule === undefined)
131
383
  throw new HttpFailure(400, 'Missing required field(s): schedule');
132
384
  if (!body.prompt && !body.script && !body.skills)
133
385
  throw new HttpFailure(400, 'Missing required field(s): prompt');
134
386
  const profile = await this.normalizeProfile(body.profile);
135
- const job = { prompt: body.prompt ?? '', schedule: body.schedule, name: body.name ?? null, deliver: body.deliver ?? 'local', skills: body.skills ?? [], model: body.model ?? null, provider: body.provider ?? null, ...jobFieldUpdates(body) };
387
+ const active = await this.profileForHome(home);
388
+ if (profile && !(await this.profileNames(active)).some((name) => this.deps.profilesMatch(name, profile)))
389
+ throw new HttpFailure(403, 'Execution profile is not accessible');
390
+ const executionHome = profile ? this.deps.profileHome(profile) : home;
391
+ const [model, provider] = modelSelection(body.model, body.provider);
392
+ const job = { prompt: body.prompt ?? '', schedule: body.schedule, name: body.name ?? null, deliver: body.deliver ?? 'local', skills: body.skills ?? [], model, provider, ...jobFieldUpdates(body) };
136
393
  if (body.repeat !== null && body.repeat !== undefined)
137
394
  job.repeat = body.repeat;
138
395
  if (profile !== null)
139
396
  job.profile = profile;
140
397
  if (body.toast_notifications === false)
141
398
  job.toast_notifications = false;
399
+ job.owner_profile = active;
400
+ await this.validateContext(executionHome, job);
142
401
  try {
143
- const result = await this.sidecar().call('cron.create', { profile_home: home, job, execution_home: profile ? this.deps.profileHome(profile) : null });
144
- return { ok: true, job: jobForApi(result.job) };
402
+ const result = await this.sidecar().call('cron.create', { profile_home: executionHome, job, execution_home: profile ? executionHome : null });
403
+ return { ok: true, job: await this.view({ home: executionHome, profile: profile ?? active, job: result.job, managed: true }, home) };
145
404
  }
146
405
  catch (error) {
147
406
  throw new HttpFailure(400, str(error.message));
@@ -151,32 +410,47 @@ export class CronService {
151
410
  const jobId = str(body.job_id);
152
411
  if (!jobId)
153
412
  throw new HttpFailure(400, 'Missing required field(s): job_id');
413
+ const store = await this.resolveStore(home, jobId);
414
+ const storedId = str(store.job.id);
415
+ const pickerHome = home;
416
+ home = store.home;
154
417
  const updates = {};
155
418
  for (const [k, v] of Object.entries(body)) {
156
- if (k === 'job_id')
419
+ if (k === 'job_id' || k === 'id' || k === 'owner_profile')
157
420
  continue;
158
- if (k === 'profile')
159
- updates.profile = await this.normalizeProfile(v);
160
- else if (k === 'model' || k === 'provider')
161
- updates[k] = v ? v : null;
162
- else if (k === 'monitor' || k === 'continuity' || k === 'repeat')
421
+ if (k === 'profile') {
422
+ const profile = await this.normalizeProfile(v);
423
+ if (profile && !this.deps.profilesMatch(profile, store.profile))
424
+ throw new HttpFailure(400, 'To change the execution profile, duplicate the task in that profile and delete the old task');
425
+ updates.profile = profile;
426
+ }
427
+ else if (k === 'model' || k === 'provider' || k === 'monitor' || k === 'continuity' || k === 'repeat')
163
428
  continue;
164
429
  else if (v !== null && v !== undefined)
165
430
  updates[k] = v;
166
431
  }
432
+ if ('model' in body) {
433
+ const [model, provider] = modelSelection(body.model, body.provider);
434
+ updates.model = model;
435
+ if (provider !== null || 'provider' in body)
436
+ updates.provider = provider;
437
+ }
438
+ else if ('provider' in body)
439
+ updates.provider = str(body.provider).trim() || null;
167
440
  let currentContextFrom = null;
168
441
  if ('continuity' in body && !('context_from' in body)) {
169
442
  try {
170
- currentContextFrom = (await this.sidecar().call('cron.get', { profile_home: home, job_id: jobId })).job?.context_from ?? null;
443
+ currentContextFrom = (await this.sidecar().call('cron.get', { profile_home: home, job_id: storedId })).job?.context_from ?? null;
171
444
  }
172
445
  catch {
173
446
  currentContextFrom = null;
174
447
  }
175
448
  }
176
449
  Object.assign(updates, jobFieldUpdates(body, currentContextFrom));
450
+ await this.validateContext(home, updates);
177
451
  try {
178
- const result = await this.sidecar().call('cron.update', { profile_home: home, job_id: jobId, updates });
179
- return { ok: true, job: jobForApi(result.job) };
452
+ const result = await this.sidecar().call('cron.update', { profile_home: home, job_id: storedId, updates });
453
+ return { ok: true, job: await this.view({ ...store, job: result.job }, pickerHome) };
180
454
  }
181
455
  catch (error) {
182
456
  if (error instanceof SidecarError && error.condition === 'not_found')
@@ -187,10 +461,13 @@ export class CronService {
187
461
  async simple(method, home, jobId, extra = {}) {
188
462
  if (!jobId)
189
463
  throw new HttpFailure(400, method === 'cron.delete' ? 'Missing required field(s): job_id' : 'job_id required');
464
+ const store = await this.resolveStore(home, jobId);
465
+ if (method === 'cron.resume')
466
+ this.requireExecutionStore(store);
190
467
  try {
191
- const result = await this.sidecar().call(method, { profile_home: home, job_id: jobId, ...extra });
468
+ const result = await this.sidecar().call(method, { profile_home: store.home, job_id: str(store.job.id), ...extra });
192
469
  // Python returned the raw `pause_job`/`resume_job` record and `{ok, job_id}` for delete.
193
- return 'job' in result ? { ok: true, job: result.job } : { ok: true, job_id: jobId };
470
+ return 'job' in result ? { ok: true, job: await this.view({ ...store, job: result.job }, home) } : { ok: true, job_id: jobId };
194
471
  }
195
472
  catch (error) {
196
473
  if (error instanceof SidecarError && error.condition === 'not_found')
@@ -216,6 +493,11 @@ export class CronService {
216
493
  running?.set(jobId, Date.now() / 1000);
217
494
  try {
218
495
  const sidecar = this.sidecar();
496
+ const store = await this.resolveStore(home, jobId);
497
+ if (store.job.id !== jobId)
498
+ throw new HttpFailure(404, 'Job not found');
499
+ this.requireExecutionStore(store);
500
+ home = store.home;
219
501
  let job;
220
502
  try {
221
503
  job = (await sidecar.call('cron.get', { profile_home: home, job_id: jobId })).job;
@@ -287,6 +569,7 @@ export class CronService {
287
569
  const l = pyInt(limit, 50);
288
570
  if (!Number.isFinite(o) || !Number.isFinite(l))
289
571
  throw new HttpFailure(400, 'offset and limit must be integers');
572
+ home = (await this.resolveStore(home, jobId)).home;
290
573
  return this.sidecar().call('cron.history', { profile_home: home, job_id: jobId, offset: Math.max(0, o), limit: Math.max(1, Math.min(500, l)) });
291
574
  }
292
575
  async runDetail(home, jobId, filename) {
@@ -296,8 +579,11 @@ export class CronService {
296
579
  throw new HttpFailure(400, 'invalid job_id');
297
580
  if (filename.includes('/') || filename.includes('\\') || filename === '..')
298
581
  throw new HttpFailure(400, 'invalid filename');
582
+ home = (await this.resolveStore(home, jobId)).home;
299
583
  try {
300
- return await this.sidecar().call('cron.run_detail', { profile_home: home, job_id: jobId, filename });
584
+ const detail = await this.sidecar().call('cron.run_detail', { profile_home: home, job_id: jobId, filename });
585
+ // Leaked tool-call XML is removed from the run's text, as from a transcript reply (TAL-302).
586
+ return { ...detail, content: stripToolCallXml(detail.content), snippet: stripToolCallXml(detail.snippet) };
301
587
  }
302
588
  catch (error) {
303
589
  if (error instanceof SidecarError && error.condition === 'not_found')
@@ -311,6 +597,7 @@ export class CronService {
311
597
  if (!JOB_ID_RE.test(jobId))
312
598
  throw new HttpFailure(400, 'invalid job_id');
313
599
  const l = Number.parseInt(limit ?? '5', 10);
600
+ home = (await this.resolveStore(home, jobId)).home;
314
601
  return this.sidecar().call('cron.output', { profile_home: home, job_id: jobId, limit: Number.isFinite(l) ? Math.max(1, Math.min(500, l)) : 5 });
315
602
  }
316
603
  async deliveryOptions() {