@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
@@ -3,15 +3,16 @@ import { randomUUID } from 'node:crypto';
3
3
  import { rmSync } from 'node:fs';
4
4
  import { buildActiveTurnToken, copyJson, redactSessionData, redactValue, stripPublicInternalFields, withSceneToolDisplay } from '../redact.js';
5
5
  import { DraftVersionConflict, normalizeDraftVersion } from './drafts.js';
6
- import { allSessions, buildSessionListPayload, CLI_IDENTITY_FIELDS, isClaimableCliSource, isMessagingSessionRecord, withOwnerLocks, withSessionWireFlags, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMessageText, sessionSearchPreview } from './list.js';
6
+ import { allSessions, buildSessionListPayload, CLI_IDENTITY_FIELDS, isClaimableCliSource, isMessagingSessionRecord, withOwnerLocks, withSessionWireFlags, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMatches, sessionSearchMessageText, sessionSearchPreview, sessionSearchTerms } from './list.js';
7
7
  import { anchorSceneIntOrNull, fullToolResult, hydrateAnchorActivityScenes, normalizeAnchorSceneMessageRef, readAnchorSceneRows, storeAnchorScene, withTurnIds } from './anchor.js';
8
- import { isSafeSessionId, lastMessageTimestamp, Session, stripAttachedFilesMarker, titleFrom } from './session.js';
8
+ import { isSafeSessionId, lastMessageTimestamp, Session, sharePath, stripAttachedFilesMarker, titleFrom } from './session.js';
9
9
  import { SessionBusy, SessionNotFound, statSignature } from './store.js';
10
- import { attachTodoState } from './todo.js';
11
- import { stateDbSessionMessages, stateDbSessionRow, stateDbSessionSources } from './state-db.js';
12
- import { anchorMessageKey, anchorSummary, CompressionJobs, visibleMessagesForAnchor } from './compress.js';
10
+ import { UNSETTLED_TODO_KEY, attachTodoState } from './todo.js';
11
+ import { isClaudeCodeSessionId } from './claude-code.js';
12
+ import { stateDbCompressionLineage, stateDbSessionMessages, stateDbSessionRead, stateDbSessionRow, stateDbSessionSources } from './state-db.js';
13
+ import { anchorMessageKey, anchorSummary, CompressionJobs, compressionReference, visibleMessagesForAnchor } from './compress.js';
13
14
  import { SidecarError } from '../sidecar/client.js';
14
- import { attachmentObjects, isContextCompressionMarker, mergeSessionMessagesAppendOnly, pendingUserRow, sanitizeMessagesForApi, stripWorkspacePrefix, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withSceneRowMedia, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
15
+ import { agentSteerText, attachedFilesPrompt, attachmentObjects, dedupeContext, isContextCompressionMarker, journalOutputRows, looksLikeCurrentUserTurn, stoppedTurnContext, workspaceContextPrefix, mergeSessionMessagesAppendOnly, messageIdentity, pendingUserRow, reasoningFieldsText, sanitizeMessagesForApi, stateDbSeenId, stripWorkspacePrefix, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withSceneRowMedia, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
15
16
  import { withBackgroundUpdates } from './background-updates.js';
16
17
  import { withBackgroundLinks } from './background-tasks.js';
17
18
  import { messagesForLimitedPayload, messageWindowForDisplay, MAX_MSG_LIMIT, parseMsgLimit, toolCallsForMessageWindow } from './window.js';
@@ -50,6 +51,9 @@ export async function ensureAgentRuntimeCurrent(sidecar) {
50
51
  function staleRuntimeFailure(error) {
51
52
  return new HttpFailure(409, error.message, { type: 'agent_runtime_stale', retryable: true, restart_scheduled: false, ...(error.data.agent_update_state !== undefined ? { agent_update_state: error.data.agent_update_state } : {}) });
52
53
  }
54
+ /** TAL-536: the most of a dead run's journal stale-stream cleanup reads (Python's recovery window). */
55
+ const RECOVERY_JOURNAL_MAX_BYTES = 8 * 1024 * 1024;
56
+ const RECOVERY_JOURNAL_MAX_ROWS = 65536;
53
57
  const isDict = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
54
58
  export class SessionService {
55
59
  deps;
@@ -185,9 +189,18 @@ export class SessionService {
185
189
  }
186
190
  /** The Agent's state.db rows for this session (empty for subagent views, which never merge). */
187
191
  stateDbRows(s) {
192
+ return this.stateDbRead(s).rows;
193
+ }
194
+ /** `stateDbRows` and whether the read succeeded on a state.db whose messages carry ids (TAL-493). */
195
+ stateDbRead(s) {
188
196
  if (str(s.source_tag || s.raw_source || s.session_source).trim().toLowerCase() === 'subagent')
189
- return [];
190
- return stateDbSessionMessages(join(this.deps.profileHome(s.profile ?? this.deps.activeProfile()), 'state.db'), s.session_id, { stitch: false });
197
+ return { rows: [], idCapable: false, ok: false };
198
+ // TAL-529: after a compression rotation the Agent writes to the continuation, so the read follows the recorded lineage.
199
+ const lineage = s.state_db_lineage?.[0] === s.session_id ? s.state_db_lineage : null;
200
+ return stateDbSessionRead(this.stateDbPath(s.profile), s.session_id, { stitch: false, lineage });
201
+ }
202
+ stateDbPath(profile) {
203
+ return join(this.deps.profileHome(profile ?? this.deps.activeProfile()), 'state.db');
191
204
  }
192
205
  /**
193
206
  * Python `_merged_session_messages_for_display`: the sidecar transcript merged append-only with the Agent's state.db
@@ -197,7 +210,91 @@ export class SessionService {
197
210
  mergedTranscript(s, local = s.messages, stateRows = this.stateDbRows(s)) {
198
211
  if (!stateRows.length)
199
212
  return local;
200
- return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed });
213
+ return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed, stateDbSeenId: currentStateDbSeenId(s, stateRows) });
214
+ }
215
+ /**
216
+ * TAL-493: record the highest state.db id this boundary or settled turn read, under the session lock in the same save,
217
+ * so the merge never replays a covered row and appends every row committed after the read. Call it after the boundary
218
+ * fields are set: the marker holds only while they and the row it names stay as recorded.
219
+ */
220
+ markStateDbSeen(s, read = this.stateDbRead(s), opts = {}) {
221
+ // A failed read says nothing. A settlement keeps the marker; a boundary drops it (fail closed): it may cut rows the
222
+ // marker still admits without moving a field, and the timestamp rules honour its watermark.
223
+ if (!read.ok) {
224
+ if (opts.boundary) {
225
+ s.state_db_seen_id = null;
226
+ s.state_db_seen_boundary = null;
227
+ s.state_db_seen_stamp = null;
228
+ }
229
+ return;
230
+ }
231
+ // A successful read with no rows yet is a baseline: every row the session gets later is new.
232
+ s.state_db_seen_id = stateDbSeenId(read.rows) ?? (read.idCapable ? 0 : null);
233
+ s.state_db_seen_boundary = stateDbMarkKey(s, read.rows, s.state_db_seen_id);
234
+ s.state_db_seen_stamp = s.updated_at;
235
+ }
236
+ /**
237
+ * TAL-493: a turn's settlement. Each state.db row the merge shows now is matched to what the turn holds: a row already
238
+ * in the context it started from (by id), or one row the Agent added this turn (`agentRows` past that context, matched
239
+ * one to one by full text). An unmatched row is a CLI or gateway row committed while the turn ran: it joins the
240
+ * transcript and the model context before the marker passes it. Without the Agent's rows (`agentRows` empty), rows past
241
+ * `startId` (the highest id the turn read when it started) are its own unreported work: covered, never shown. Rows the
242
+ * turn started from but the transcript lacks (a CLI continuation read into its context) are kept before the turn.
243
+ */
244
+ settleStateDb(s, turn) {
245
+ const read = this.stateDbRead(s);
246
+ const startedWith = new Set(turn.previousContext.flatMap((m) => (typeof m._state_db_row_id === 'number' ? [m._state_db_row_id] : [])));
247
+ const earlier = mergeSessionMessagesAppendOnly(s.messages, read.rows.filter((m) => typeof m._state_db_row_id === 'number' && startedWith.has(m._state_db_row_id)), { stateDbSeenId: -1 }).slice(s.messages.length);
248
+ const added = new Map();
249
+ for (const m of withoutRows(turn.agentRows ?? [], turn.previousContext))
250
+ added.set(settledIdentity(m), (added.get(settledIdentity(m)) ?? 0) + 1);
251
+ const ownWorkAfter = turn.agentRows?.length ? null : turn.startId ?? null;
252
+ // Without a current marker, the turn's own starting read is the baseline: rows committed after it are judged here.
253
+ const seenId = currentStateDbSeenId(s, read.rows) ?? turn.startId ?? null;
254
+ const shown = read.rows.length ? mergeSessionMessagesAppendOnly(s.messages, read.rows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed, stateDbSeenId: seenId }) : s.messages;
255
+ const fresh = new Set(shown.slice(s.messages.length));
256
+ // The turn's own rows the merge already matched to their local copies use up their share before any shown row can.
257
+ if (seenId !== null) {
258
+ for (const m of read.rows) {
259
+ const id = m._state_db_row_id;
260
+ if (typeof id !== 'number' || id <= seenId || startedWith.has(id) || fresh.has(m))
261
+ continue;
262
+ const left = added.get(settledIdentity(m)) ?? 0;
263
+ if (left > 0)
264
+ added.set(settledIdentity(m), left - 1);
265
+ }
266
+ }
267
+ const missed = [...fresh].filter((m) => {
268
+ const id = m._state_db_row_id;
269
+ if (typeof id === 'number' && startedWith.has(id))
270
+ return false;
271
+ const key = settledIdentity(m);
272
+ const left = added.get(key) ?? 0;
273
+ if (left > 0) {
274
+ added.set(key, left - 1);
275
+ return false;
276
+ }
277
+ return !(ownWorkAfter !== null && typeof id === 'number' && id > ownWorkAfter);
278
+ });
279
+ if (earlier.length) {
280
+ const at = s.messages.findIndex((m) => m._turn_id === turn.turnId);
281
+ s.messages.splice(at < 0 ? s.messages.length : at, 0, ...copyJson(earlier));
282
+ }
283
+ if (missed.length) {
284
+ s.messages.push(...copyJson(missed));
285
+ if (s.context_messages.length)
286
+ s.context_messages.push(...copyJson(missed));
287
+ }
288
+ this.markStateDbSeen(s, read);
289
+ // TAL-529: a compression rotation moved the Agent to a continuation, whose first rows restate the compressed context.
290
+ // The read follows the new lineage from here, and everything it holds now is covered.
291
+ // ponytail: a CLI row committed to the continuation before this settlement is covered with them; telling them apart
292
+ // needs the Agent to mark the rows it writes at rotation.
293
+ const lineage = stateDbCompressionLineage(this.stateDbPath(s.profile), s.session_id);
294
+ if (JSON.stringify(lineage) !== JSON.stringify(s.state_db_lineage ?? [s.session_id])) {
295
+ s.state_db_lineage = lineage.length > 1 ? lineage : null;
296
+ this.markStateDbSeen(s);
297
+ }
201
298
  }
202
299
  /**
203
300
  * Python `reconciled_state_db_messages_for_session(prefer_context=True)`: the model history is the owner context
@@ -220,12 +317,17 @@ export class SessionService {
220
317
  /** Python `_lookup_cli_session_metadata`: the sidebar row for a state.db session in the active profile. */
221
318
  lookupCliMeta(sid) {
222
319
  try {
320
+ if (isClaudeCodeSessionId(sid))
321
+ return this.claudeCodeRows().find((r) => str(r.session_id) === sid) ?? null;
223
322
  return this.deps.cliSessions(this.deps.activeProfile(), { sourceFilter: null }).rows.find((r) => str(r.session_id) === sid) ?? null;
224
323
  }
225
324
  catch {
226
325
  return null;
227
326
  }
228
327
  }
328
+ claudeCodeRows() {
329
+ return this.deps.claudeCode?.rows(this.deps.workspaces.lastWorkspace(this.deps.activeProfile())) ?? [];
330
+ }
229
331
  /** Python `_session_index_marks_was_webui`: an index row that once owned a WebUI sidecar (self-heal 404). */
230
332
  indexMarksWasWebui(sid) {
231
333
  let entries;
@@ -262,7 +364,7 @@ export class SessionService {
262
364
  const subagentChild = stateDbSource === 'subagent';
263
365
  if ((this.indexMarksWasWebui(sid) || (this.store.wasDeleted(sid) && ['', 'webui', 'fork'].includes(stateDbSource))) && !subagentChild)
264
366
  return { session: null, reason: 'was_webui' };
265
- const msgs = stateDbSessionMessages(dbPath, sid, { stitch: true });
367
+ const msgs = isClaudeCodeSessionId(sid) ? this.deps.claudeCode?.messages(sid) ?? [] : stateDbSessionMessages(dbPath, sid, { stitch: true });
266
368
  if (!msgs.length)
267
369
  return { session: null, reason: 'no_foreign_state' };
268
370
  const meta = { ...(metaIn ?? this.lookupCliMeta(sid) ?? {}) };
@@ -309,7 +411,16 @@ export class SessionService {
309
411
  throw error;
310
412
  }
311
413
  }
414
+ /**
415
+ * TAL-551: a Claude Code import is a live view of a transcript Claude Code keeps writing. Web never stores a copy,
416
+ * which would freeze its messages and pin it to one profile.
417
+ */
418
+ rejectClaudeCode(sid, verb) {
419
+ if (isClaudeCodeSessionId(sid))
420
+ throw new HttpFailure(400, `Claude Code sessions are view-only and cannot be ${verb} from WebUI`);
421
+ }
312
422
  rejectSubagent(sid, verb) {
423
+ this.rejectClaudeCode(sid, verb);
313
424
  if (this.isSubagentViewOnly(sid))
314
425
  throw new HttpFailure(400, `Subagent sessions are view-only and cannot be ${verb} from WebUI`);
315
426
  }
@@ -321,8 +432,10 @@ export class SessionService {
321
432
  publicSession(s, withMessages = true) {
322
433
  const payload = this.wireRow(s);
323
434
  // Mutation replies replace a client's transcript, so they carry the same server-built scenes as the detail.
324
- if (withMessages)
435
+ if (withMessages) {
325
436
  payload.messages = this.backgroundLinked(s, hydrateAnchorActivityScenes(withToolCallOutcomes(withBackgroundUpdates(withMarkerKinds(withTurnIds(s.messages)), s), s.tool_calls, s.active_stream_id), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id, runningScene: !this.journaledActiveTurn(s) }));
437
+ payload.compression_reference = compressionReference(s, payload.messages);
438
+ }
326
439
  return redactSessionData(payload, this.deps.redactEnabled());
327
440
  }
328
441
  /** `compact()` with the wire streaming/read-only flags (TAL-312), for replies that return the session row. */
@@ -442,8 +555,10 @@ export class SessionService {
442
555
  };
443
556
  if (loadMessages)
444
557
  raw.transcript_seq = journaled ? { stream_id: journaled.turnId, seq: 0 } : null;
445
- if (loadMessages && all.length)
446
- attachTodoState(raw, all);
558
+ if (loadMessages)
559
+ attachTodoState(raw, all, s.extra[UNSETTLED_TODO_KEY]);
560
+ if (loadMessages)
561
+ raw.compression_reference = compressionReference(s, all);
447
562
  if (mergedLast) {
448
563
  raw.last_message_at = Math.max(Number(raw.last_message_at ?? 0) || 0, mergedLast);
449
564
  raw.updated_at = Math.max(Number(raw.updated_at ?? 0) || 0, mergedLast);
@@ -518,7 +633,7 @@ export class SessionService {
518
633
  const merged = withSessionWireFlags(meta ? mergeCliSidebarMetadata(sess, meta) : sess, this.deps.runtime.activeStreamIds);
519
634
  return redactSessionData(merged, this.deps.redactEnabled());
520
635
  }
521
- /** Clear persisted streaming flags when no live stream backs them (Python `_clear_stale_stream_state`, no journal recovery). */
636
+ /** Clear persisted streaming flags when no live stream backs them (Python `_clear_stale_stream_state`). */
522
637
  clearStaleStreamState(session) {
523
638
  const streamId = session.active_stream_id;
524
639
  if (!streamId)
@@ -545,15 +660,40 @@ export class SessionService {
545
660
  return false;
546
661
  }
547
662
  }
548
- // Python `_materialize_pending_user_turn_before_error` (#1361): the prompt that was in flight becomes a durable user
549
- // turn and an interruption marker follows it, so a dead stream never silently drops what the user sent.
663
+ // Python `_materialize_pending_user_turn_before_error` (#1361) and `_recover_dead_run_journal`: the prompt that was in
664
+ // flight becomes a durable user turn, the output its journal holds follows it, and an interruption marker closes a
665
+ // run that never finished with an answer, so a dead stream never silently drops what the user sent or what streamed.
666
+ const turnId = str(target.active_stream_id);
667
+ // ponytail: one bounded tail read (Python's recovery window); a journal past it recovers its latest output only.
668
+ const events = this.deps.journal?.readRunEventTail(target.session_id, turnId, RECOVERY_JOURNAL_MAX_BYTES, RECOVERY_JOURNAL_MAX_ROWS).events ?? [];
669
+ const { rows: output, answered } = journalOutputRows(events, turnId);
550
670
  const pendingText = str(target.pending_user_message);
671
+ const attachments = [...target.pending_attachments];
672
+ // The run's starting read died with its worker: the state.db rows from before it started stand in for it. Its own
673
+ // rows open with its prompt and run to the next prompt; anything else another client wrote meanwhile stays.
674
+ const read = this.stateDbRead(target);
675
+ const runStart = target.pending_started_at || events[0]?.created_at || this.deps.now();
676
+ const before = read.rows.filter((m) => Number(m.timestamp) < runStart);
677
+ const ownRows = target.hasPendingPrompt ? runStateDbRows(read.rows.filter((m) => Number(m.timestamp) >= runStart), pendingText) : null;
678
+ // Without this turn's rows: an eager save already put its prompt in the transcript a fresh context falls back to.
679
+ const previousContext = this.modelContext(target, before).filter((m) => m._turn_id !== turnId);
551
680
  if (target.hasPendingPrompt) {
552
- const turnId = str(target.active_stream_id);
553
681
  const startedAt = typeof target.pending_started_at === 'number' && target.pending_started_at > 0 ? target.pending_started_at : this.deps.now();
554
- const attachments = [...target.pending_attachments];
555
- target.messages.push({ role: 'user', content: pendingText, timestamp: Math.trunc(startedAt), ...(attachments.length ? { attachments } : {}), _recovered: true, _source: target.pending_user_source ?? 'webui', ...(turnId ? { _turn_id: turnId } : {}) });
556
- target.messages.push({ role: 'assistant', content: '**Interrupted:** The reply was interrupted before it could be saved.', timestamp: Math.trunc(this.deps.now()), _error: true, ...(turnId ? { _turn_id: turnId } : {}) });
682
+ // An eager save already checkpointed this prompt as the turn's user row.
683
+ if (!target.messages.some((m) => m.role === 'user' && !m._steer && m._turn_id === turnId))
684
+ target.messages.push({ role: 'user', content: pendingText, timestamp: Math.trunc(startedAt), ...(attachments.length ? { attachments } : {}), _recovered: true, _source: target.pending_user_source ?? 'webui', _turn_id: turnId });
685
+ // The model context settles as a Stop's does: the Agent's own rows when it committed the prompt, else the prompt it
686
+ // was sent; then the prose that streamed past them.
687
+ const prompt = attachedFilesPrompt((str(target.workspace) ? workspaceContextPrefix(str(target.workspace)) : '') + pendingText, attachments);
688
+ const streamed = output.map((m) => str(m.content)).filter(Boolean).join('\n\n');
689
+ target.context_messages = dedupeContext(stoppedTurnContext(previousContext, ownRows ? [...previousContext, ...ownRows] : null, prompt, pendingText, streamed, previousContext.length) ?? [...structuredClone(previousContext), { role: 'user', content: prompt }]);
690
+ }
691
+ if (target.hasPendingPrompt || output.length) {
692
+ target.messages.push(...output);
693
+ if (!answered)
694
+ target.messages.push({ role: 'assistant', content: '**Interrupted:** The reply was interrupted before it could be saved.', timestamp: Math.trunc(this.deps.now()), _error: true, _turn_id: turnId });
695
+ // Settled like a turn: the Agent's own rows are covered by the recovered turn; without them, every row past the run's start is.
696
+ this.settleStateDb(target, { turnId, previousContext, agentRows: ownRows, startId: stateDbSeenId(before) ?? (read.idCapable ? 0 : null) });
557
697
  }
558
698
  target.active_stream_id = null;
559
699
  target.pending_user_message = null;
@@ -582,7 +722,8 @@ export class SessionService {
582
722
  const wantState = params.showCliSessions || params.showCronSessions || params.showWebhookSessions || params.showKanbanSessions;
583
723
  // Python reads every profile's state.db under all_profiles; this port projects the active profile only.
584
724
  const cliRead = wantState ? this.deps.cliSessions(activeProfile, { sourceFilter: params.sourceFilter ?? null }) : undefined;
585
- const cliRows = cliRead?.rows;
725
+ const claudeCodeRows = params.showCliSessions && params.showClaudeCodeSessions ? this.claudeCodeRows() : [];
726
+ const cliRows = cliRead ? [...cliRead.rows, ...claudeCodeRows] : undefined;
586
727
  const gatewayIdentity = loadGatewaySessionIdentityMap(join(this.deps.profileHome(activeProfile), 'sessions', 'sessions.json'));
587
728
  const truncatedSources = cliRead?.truncated;
588
729
  const payload = buildSessionListPayload(this.store, { ...params, ...(cliRows ? { cliRows } : {}), ...(truncatedSources ? { truncatedSources } : {}), gatewayIdentity, stateDbSources: this.stateDbSources, activeProfile, isolatedProfileMode: this.deps.isolatedProfileMode(), profilesMatch: this.deps.profilesMatch });
@@ -609,15 +750,16 @@ export class SessionService {
609
750
  const query = q.toLowerCase().trim();
610
751
  if (!query)
611
752
  return { sessions: sessions.map((s) => redactRow({ ...s })), all_profiles: opts.allProfiles, active_profile: activeProfile };
753
+ const terms = sessionSearchTerms(query);
612
754
  const results = [];
613
755
  for (const s of sessions) {
614
- if (str(s.title).toLowerCase().includes(query)) {
756
+ if (sessionSearchMatches(str(s.title), terms)) {
615
757
  results.push(redactRow({ ...s, match_type: 'title' }));
616
758
  continue;
617
759
  }
618
760
  if (!opts.content)
619
761
  continue;
620
- const hit = this.contentMatch(str(s.session_id), query, opts.depth);
762
+ const hit = this.contentMatch(str(s.session_id), terms, opts.depth);
621
763
  if (hit)
622
764
  results.push(redactRow({ ...s, ...hit }));
623
765
  }
@@ -638,22 +780,23 @@ export class SessionService {
638
780
  const base = { all_profiles: params.allProfiles, active_profile: this.deps.activeProfile(), include_archived: params.includeArchived, sidebar_filtered: true };
639
781
  if (!query)
640
782
  return { ...base, sessions: rows };
783
+ const terms = sessionSearchTerms(query);
641
784
  const results = [];
642
785
  for (const row of rows) {
643
- if (str(row.title).toLowerCase().includes(query))
786
+ if (sessionSearchMatches(str(row.title), terms))
644
787
  results.push({ ...row, match_type: 'title' });
645
- else if (['workspace', 'workspace_name', 'model', 'model_provider', 'profile', 'source_label'].some((k) => str(row[k]).toLowerCase().includes(query)))
788
+ else if (['workspace', 'workspace_name', 'model', 'model_provider', 'profile', 'source_label'].some((k) => sessionSearchMatches(str(row[k]), terms)))
646
789
  results.push({ ...row, match_type: 'metadata' });
647
790
  else if (opts.content) {
648
- const hit = this.contentMatch(str(row.session_id), query, opts.depth);
791
+ const hit = this.contentMatch(str(row.session_id), terms, opts.depth);
649
792
  if (hit)
650
793
  results.push({ ...row, ...hit });
651
794
  }
652
795
  }
653
796
  return { ...base, sessions: results, query, count: results.length };
654
797
  }
655
- /** The first of a stored session's first `depth` messages (0: all) containing `query`, with its redacted excerpt. */
656
- contentMatch(sid, query, depth) {
798
+ /** The first of a stored session's first `depth` messages (0: all) containing every term, with its redacted excerpt. */
799
+ contentMatch(sid, terms, depth) {
657
800
  let sess;
658
801
  try {
659
802
  sess = this.store.get(sid, { promote: false, cacheOnMiss: false });
@@ -663,10 +806,10 @@ export class SessionService {
663
806
  }
664
807
  for (const m of depth ? sess.messages.slice(0, depth) : sess.messages) {
665
808
  const c = sessionSearchMessageText(m);
666
- if (!c.toLowerCase().includes(query))
809
+ if (!sessionSearchMatches(c, terms))
667
810
  continue;
668
811
  const item = { match_type: 'content' };
669
- const preview = sessionSearchPreview(c, query);
812
+ const preview = sessionSearchPreview(c, terms);
670
813
  if (preview)
671
814
  item.match_preview = redactText(preview, this.deps.redactEnabled());
672
815
  return item;
@@ -721,14 +864,16 @@ export class SessionService {
721
864
  const [workspace] = this.deps.workspaces.resolveImplicitWithRecovery(value, (p) => this.deps.workspaces.profileDefaultWorkspaceForBoot(p), profile);
722
865
  return workspace;
723
866
  }
867
+ /** The server owns the names' normalization (TAL-631): trimmed, blanks dropped, and nothing left is the profile's defaults. */
724
868
  validateToolsetsShape(toolsets) {
725
869
  if (toolsets === null || toolsets === undefined)
726
870
  return null;
727
- if (!Array.isArray(toolsets) || !toolsets.length)
728
- throw new HttpFailure(400, 'toolsets must be a non-empty list or null');
729
- if (!toolsets.every((t) => typeof t === 'string' && t))
730
- throw new HttpFailure(400, 'each toolset must be a non-empty string');
731
- return toolsets;
871
+ if (!Array.isArray(toolsets))
872
+ throw new HttpFailure(400, 'toolsets must be a list or null');
873
+ if (!toolsets.every((t) => typeof t === 'string'))
874
+ throw new HttpFailure(400, 'each toolset must be a string');
875
+ const names = toolsets.map((t) => t.trim()).filter(Boolean);
876
+ return names.length ? names : null;
732
877
  }
733
878
  create(body, opts = {}) {
734
879
  // Python `new_session`: a body without a profile takes the request's active profile (cookie first).
@@ -923,6 +1068,7 @@ export class SessionService {
923
1068
  throw new HttpFailure(400, 'keep_count must be non-negative');
924
1069
  await this.store.withLock(sid, () => {
925
1070
  truncateSessionAtKeep(s, keep);
1071
+ this.markStateDbSeen(s, undefined, { boundary: true });
926
1072
  this.store.save(s);
927
1073
  });
928
1074
  this.deps.runtime.evictAgent(sid);
@@ -1034,7 +1180,8 @@ export class SessionService {
1034
1180
  if (streamState(live) !== streamBefore)
1035
1181
  throw new HttpFailure(409, 'Session stream state changed during compression; please retry.');
1036
1182
  // One state.db read serves the check, the kept display rows, and the boundary.
1037
- const stateRows = this.stateDbRows(live);
1183
+ const read = this.stateDbRead(live);
1184
+ const stateRows = read.rows;
1038
1185
  if (transcriptKey(live, sanitizeMessagesForApi(this.modelContext(live, stateRows))) !== historyKey)
1039
1186
  throw new HttpFailure(409, 'Session was modified during compression; please retry.');
1040
1187
  // Rows the sidecar returns without a timestamp take the newest one this compression saw, never the clock: the
@@ -1065,6 +1212,7 @@ export class SessionService {
1065
1212
  live.truncation_watermark = truncationWatermarkFor(compressed);
1066
1213
  live.truncation_boundary = live.truncation_watermark;
1067
1214
  live.truncation_watermark_compressed = true;
1215
+ this.markStateDbSeen(live, read, { boundary: true });
1068
1216
  live.last_prompt_tokens = result.after_tokens;
1069
1217
  live.post_compression_context_tokens_estimate = result.after_tokens;
1070
1218
  this.store.save(live);
@@ -1126,6 +1274,7 @@ export class SessionService {
1126
1274
  s.pending_user_source = null;
1127
1275
  s.clear_generation = hadMessages ? randomUUID().replace(/-/g, '') : null;
1128
1276
  applySessionTitleRename(s, 'Untitled');
1277
+ this.markStateDbSeen(s, undefined, { boundary: true });
1129
1278
  this.store.save(s);
1130
1279
  if (hadMessages) {
1131
1280
  try {
@@ -1156,6 +1305,7 @@ export class SessionService {
1156
1305
  return { error: 'The last message has nothing to resend.' };
1157
1306
  const removed = history.length - lastUser;
1158
1307
  shrinkTo(s, lastUser);
1308
+ this.markStateDbSeen(s, undefined, { boundary: true });
1159
1309
  this.store.save(s);
1160
1310
  return { ok: true, last_user_text: lastUserText, last_user_prompt: lastUserPrompt, last_user_attachments: lastUserAttachments, removed_count: removed };
1161
1311
  });
@@ -1171,6 +1321,7 @@ export class SessionService {
1171
1321
  const removedText = extractText(history[lastUser]?.content);
1172
1322
  const removed = history.length - lastUser;
1173
1323
  shrinkTo(s, lastUser);
1324
+ this.markStateDbSeen(s, undefined, { boundary: true });
1174
1325
  this.store.save(s);
1175
1326
  const preview = removedText.length > 40 ? `${removedText.slice(0, 40)}...` : removedText;
1176
1327
  return { ok: true, removed_count: removed, removed_preview: preview };
@@ -1246,6 +1397,19 @@ export class SessionService {
1246
1397
  }
1247
1398
  return { session_id: branch.session_id, title, parent_session_id: source.session_id };
1248
1399
  }
1400
+ /** The run that keeps `delete` answering 409, if any; stream status reports it so a draining client can wait on it (TAL-622). */
1401
+ activeRunBlocking(sid) {
1402
+ const live = this.deps.runtime.activeRunStream(sid);
1403
+ if (live)
1404
+ return live;
1405
+ try {
1406
+ const candidate = str(this.store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false }).active_stream_id).trim();
1407
+ if (candidate && this.deps.runtime.activeStreamIds.has(candidate))
1408
+ return candidate;
1409
+ }
1410
+ catch { /* absent */ }
1411
+ return null;
1412
+ }
1249
1413
  async delete(sid) {
1250
1414
  if (!sid)
1251
1415
  throw new HttpFailure(400, 'session_id is required');
@@ -1278,24 +1442,11 @@ export class SessionService {
1278
1442
  return true;
1279
1443
  }
1280
1444
  catch { /* absent */ } const meta = this.lookupCliMeta(sid); return meta !== null && isMessagingSessionRecord(meta); })();
1281
- const blocking = () => {
1282
- const live = this.deps.runtime.activeRunStream(sid);
1283
- if (live)
1284
- return live;
1285
- try {
1286
- const snapshot = this.store.get(sid, { metadataOnly: true });
1287
- const candidate = str(snapshot.active_stream_id).trim();
1288
- if (candidate && this.deps.runtime.activeStreamIds.has(candidate))
1289
- return candidate;
1290
- }
1291
- catch { /* absent */ }
1292
- return null;
1293
- };
1294
- if (blocking())
1445
+ if (this.activeRunBlocking(sid))
1295
1446
  throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
1296
1447
  try {
1297
1448
  await this.store.withLock(sid, () => {
1298
- if (blocking())
1449
+ if (this.activeRunBlocking(sid))
1299
1450
  throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
1300
1451
  // A public share outlives its session file, and revokeShare needs the session, so revoke it first.
1301
1452
  try {
@@ -1329,11 +1480,15 @@ export class SessionService {
1329
1480
  // messaging channel's memory is never erased from the WebUI; the actual outcome is reported.
1330
1481
  let stateDbCleanupFailed = false;
1331
1482
  if (!isMessaging) {
1332
- try {
1333
- stateDbCleanupFailed = !(await this.deps.runtime.deleteCliSession(eventProfile, sid));
1334
- }
1335
- catch {
1336
- stateDbCleanupFailed = true;
1483
+ // TAL-529: the compression continuations go too, tip first; the Agent's delete keeps and detaches them otherwise.
1484
+ for (const id of stateDbCompressionLineage(this.stateDbPath(eventProfile), sid).reverse()) {
1485
+ try {
1486
+ if (!(await this.deps.runtime.deleteCliSession(eventProfile, id)))
1487
+ stateDbCleanupFailed = true;
1488
+ }
1489
+ catch {
1490
+ stateDbCleanupFailed = true;
1491
+ }
1337
1492
  }
1338
1493
  }
1339
1494
  this.publish('session_delete', eventProfile);
@@ -1603,6 +1758,7 @@ export class SessionService {
1603
1758
  }
1604
1759
  // ── shares ───────────────────────────────────────────────────────────────
1605
1760
  createShare(sid) {
1761
+ this.rejectClaudeCode(sid, 'shared');
1606
1762
  let s = this.get404(sid);
1607
1763
  if (!this.visibleToActiveProfile(s.profile))
1608
1764
  throw new HttpFailure(404, 'Session not found');
@@ -1621,7 +1777,7 @@ export class SessionService {
1621
1777
  this.publish('session_share_create', s.profile, sid);
1622
1778
  return {
1623
1779
  ok: true,
1624
- share: { token: meta.share_token, url: `/share/${meta.share_token}`, title: meta.share_title, message_count: meta.share_message_count, created_at: meta.share_created_at, updated_at: meta.share_updated_at },
1780
+ share: { token: meta.share_token, url: sharePath(meta.share_token) ?? '', title: meta.share_title, message_count: meta.share_message_count, created_at: meta.share_created_at, updated_at: meta.share_updated_at },
1625
1781
  session: this.publicSession(s),
1626
1782
  };
1627
1783
  }
@@ -1688,6 +1844,44 @@ function findLastUserIndex(history) {
1688
1844
  export function sanitizePaths(error) {
1689
1845
  return str(error?.message ?? error).replace(/(?:(?:\/[a-zA-Z0-9_.-]+)+|(?:[A-Z]:\\[^\s]+))/g, '<path>');
1690
1846
  }
1847
+ /** TAL-536: a dead run's own state.db rows: from its prompt to the next prompt (tool results and applied steers stay in it). */
1848
+ function runStateDbRows(rows, prompt) {
1849
+ const at = rows.findIndex((m) => looksLikeCurrentUserTurn(m, prompt));
1850
+ if (at < 0)
1851
+ return null;
1852
+ const toolResult = (m) => Array.isArray(m.content) && m.content.some((part) => isDict(part) && part.type === 'tool_result');
1853
+ const end = rows.findIndex((m, i) => i > at && m.role === 'user' && !toolResult(m) && agentSteerText(m) === null);
1854
+ return rows.slice(at, end < 0 ? undefined : end);
1855
+ }
1856
+ /** TAL-493: a row's full-text identity; one with no text (reasoning or media only) by its raw role, content, and reasoning. */
1857
+ function settledIdentity(m) {
1858
+ return messageIdentity(m, Infinity) ?? JSON.stringify([m.role ?? null, m.content ?? null, reasoningFieldsText(m)]);
1859
+ }
1860
+ /** `rows` minus one occurrence of each row of `base`, by `settledIdentity`. */
1861
+ function withoutRows(rows, base) {
1862
+ const left = new Map();
1863
+ for (const m of base)
1864
+ left.set(settledIdentity(m), (left.get(settledIdentity(m)) ?? 0) + 1);
1865
+ return rows.filter((m) => { const key = settledIdentity(m); const n = left.get(key) ?? 0; if (n > 0)
1866
+ left.set(key, n - 1); return n === 0; });
1867
+ }
1868
+ /**
1869
+ * TAL-493: what the state.db marker was recorded under: the boundary fields every boundary writer sets (an older release
1870
+ * moves them without the marker) and the role, timestamp, and database file identity of the row the marker names (a
1871
+ * recreated state.db, whose ids start over, has no such row).
1872
+ */
1873
+ function stateDbMarkKey(s, stateRows, seenId) {
1874
+ const anchor = seenId === null ? undefined : stateRows.find((m) => m._state_db_row_id === seenId);
1875
+ return JSON.stringify([s.truncation_watermark ?? null, s.truncation_boundary ?? null, s.intentional_shrink_generation ?? null, s.clear_generation ?? null, anchor ? [anchor.role ?? null, anchor.timestamp ?? null, anchor._state_db_generation ?? null] : null]);
1876
+ }
1877
+ /**
1878
+ * The recorded state.db marker while what it was recorded under still holds and this version wrote the session last (an
1879
+ * older release can apply a boundary that changes no field), else null (the timestamp rules apply).
1880
+ */
1881
+ function currentStateDbSeenId(s, stateRows) {
1882
+ const seenId = s.state_db_seen_id;
1883
+ return seenId !== null && s.state_db_seen_stamp === s.updated_at && s.state_db_seen_boundary === stateDbMarkKey(s, stateRows, seenId) ? seenId : null;
1884
+ }
1691
1885
  function truncationWatermarkFor(messages) {
1692
1886
  if (!messages.length)
1693
1887
  return 0.0;