@maudecode/talaria-web 1.11.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/LICENSE +22 -0
  2. package/_release.json +4 -4
  3. package/dist/api/chat-router.d.ts +68 -4
  4. package/dist/api/chat-router.js +11 -8
  5. package/dist/api/chat-router.js.map +1 -1
  6. package/dist/api/router.d.ts +10 -0
  7. package/dist/api/router.js +2 -1
  8. package/dist/api/router.js.map +1 -1
  9. package/dist/api/sessions-router.d.ts +407 -51
  10. package/dist/api/sessions-router.js +2 -2
  11. package/dist/api/sessions-router.js.map +1 -1
  12. package/dist/api/sse-routes.js +52 -8
  13. package/dist/api/sse-routes.js.map +1 -1
  14. package/dist/api/tools-router.d.ts +443 -0
  15. package/dist/api/tools-router.js +99 -4
  16. package/dist/api/tools-router.js.map +1 -1
  17. package/dist/app.d.ts +926 -55
  18. package/dist/auth/oidc.js +2 -0
  19. package/dist/auth/oidc.js.map +1 -1
  20. package/dist/auth/passkeys.js +1 -1
  21. package/dist/auth/passkeys.js.map +1 -1
  22. package/dist/auth/store.d.ts +17 -0
  23. package/dist/auth/store.js +77 -19
  24. package/dist/auth/store.js.map +1 -1
  25. package/dist/cli/ctl.d.ts +6 -3
  26. package/dist/cli/ctl.js +25 -16
  27. package/dist/cli/ctl.js.map +1 -1
  28. package/dist/cli/launcher.js +2 -2
  29. package/dist/cli/launcher.js.map +1 -1
  30. package/dist/fs/atomic.d.ts +8 -1
  31. package/dist/fs/atomic.js +52 -3
  32. package/dist/fs/atomic.js.map +1 -1
  33. package/dist/http/context.d.ts +2 -0
  34. package/dist/http/context.js.map +1 -1
  35. package/dist/mcp/server.js +1 -1
  36. package/dist/mcp/server.js.map +1 -1
  37. package/dist/redact.d.ts +15 -0
  38. package/dist/redact.js +1393 -9
  39. package/dist/redact.js.map +1 -1
  40. package/dist/release.js +3 -1
  41. package/dist/release.js.map +1 -1
  42. package/dist/runtime.js +20 -9
  43. package/dist/runtime.js.map +1 -1
  44. package/dist/server.d.ts +1 -1
  45. package/dist/server.js +12 -6
  46. package/dist/server.js.map +1 -1
  47. package/dist/sessions/anchor.d.ts +2 -0
  48. package/dist/sessions/anchor.js +22 -17
  49. package/dist/sessions/anchor.js.map +1 -1
  50. package/dist/sessions/export.js +1 -1
  51. package/dist/sessions/export.js.map +1 -1
  52. package/dist/sessions/file-changes.d.ts +15 -0
  53. package/dist/sessions/file-changes.js +58 -0
  54. package/dist/sessions/file-changes.js.map +1 -0
  55. package/dist/sessions/journal.d.ts +6 -1
  56. package/dist/sessions/journal.js +9 -15
  57. package/dist/sessions/journal.js.map +1 -1
  58. package/dist/sessions/list.d.ts +21 -1
  59. package/dist/sessions/list.js +81 -17
  60. package/dist/sessions/list.js.map +1 -1
  61. package/dist/sessions/merge.d.ts +66 -2
  62. package/dist/sessions/merge.js +291 -9
  63. package/dist/sessions/merge.js.map +1 -1
  64. package/dist/sessions/pending.d.ts +11 -2
  65. package/dist/sessions/pending.js +52 -3
  66. package/dist/sessions/pending.js.map +1 -1
  67. package/dist/sessions/relay.js +1 -1
  68. package/dist/sessions/relay.js.map +1 -1
  69. package/dist/sessions/service.d.ts +16 -3
  70. package/dist/sessions/service.js +92 -54
  71. package/dist/sessions/service.js.map +1 -1
  72. package/dist/sessions/state-db.d.ts +5 -0
  73. package/dist/sessions/state-db.js +34 -0
  74. package/dist/sessions/state-db.js.map +1 -1
  75. package/dist/sessions/streams.d.ts +4 -1
  76. package/dist/sessions/streams.js +3 -0
  77. package/dist/sessions/streams.js.map +1 -1
  78. package/dist/sessions/tool-display.d.ts +21 -0
  79. package/dist/sessions/tool-display.js +113 -0
  80. package/dist/sessions/tool-display.js.map +1 -0
  81. package/dist/sessions/turn.d.ts +25 -7
  82. package/dist/sessions/turn.js +153 -90
  83. package/dist/sessions/turn.js.map +1 -1
  84. package/dist/spa.d.ts +2 -0
  85. package/dist/spa.js +9 -0
  86. package/dist/spa.js.map +1 -1
  87. package/dist/test/harness.d.ts +2 -0
  88. package/dist/test/harness.js +1 -1
  89. package/dist/test/harness.js.map +1 -1
  90. package/dist/tools/terminal.d.ts +6 -0
  91. package/dist/tools/terminal.js +24 -3
  92. package/dist/tools/terminal.js.map +1 -1
  93. package/dist/tools/update-notifications.d.ts +133 -0
  94. package/dist/tools/update-notifications.js +407 -0
  95. package/dist/tools/update-notifications.js.map +1 -0
  96. package/dist/tools/updates.d.ts +53 -16
  97. package/dist/tools/updates.js +314 -351
  98. package/dist/tools/updates.js.map +1 -1
  99. package/package.json +3 -2
  100. package/sidecar/scripts/replay_sidecar.py +17 -0
  101. package/sidecar/talaria_sidecar/__init__.py +1 -1
  102. package/sidecar/talaria_sidecar/home.py +39 -16
  103. package/sidecar/talaria_sidecar/methods/chat.py +113 -4
  104. package/static/dist/FILES.txt +116 -116
  105. package/static/dist/THIRD_PARTY_LICENSES.md +5170 -0
  106. package/static/dist/assets/AppShell-irdqom6e.js +1 -0
  107. package/static/dist/assets/ChatPage-ldhqevjn.js +20 -0
  108. package/static/dist/assets/HubRoute-hq24vhj8.js +2 -0
  109. package/static/dist/assets/{Markdown-ftyfzds0.js → Markdown-bx4n7qs4.js} +7 -7
  110. package/static/dist/assets/{RightPanel-febk3dkd.js → RightPanel-ds4majj3.js} +1 -1
  111. package/static/dist/assets/Select-gpqmt6x1.js +1 -0
  112. package/static/dist/assets/SessionListPanel-hkvipik4.js +1 -0
  113. package/static/dist/assets/{SettingsLayout-pdpmhy1o.js → SettingsLayout-oigbg9rl.js} +1 -1
  114. package/static/dist/assets/States-fn4o2wdf.js +1 -0
  115. package/static/dist/assets/Toaster-cwnut53k.js +1 -0
  116. package/static/dist/assets/_app-h6ago6y6.js +1 -0
  117. package/static/dist/assets/_app.ext._extensionId-erqnfff5.js +1 -0
  118. package/static/dist/assets/_app.index-cq2fxmda.js +1 -0
  119. package/static/dist/assets/_app.insights-nzhld9gu.js +1 -0
  120. package/static/dist/assets/_app.kanban-m5uggety.js +1 -0
  121. package/static/dist/assets/_app.logs-d2kk9lza.js +1 -0
  122. package/static/dist/assets/_app.memory-gcmop1e7.js +1 -0
  123. package/static/dist/assets/_app.profiles-e9b2my7x.js +1 -0
  124. package/static/dist/assets/{_app.session._sessionId-n1ggcf5e.js → _app.session._sessionId-ciix6itb.js} +1 -1
  125. package/static/dist/assets/_app.settings-kcjum3c1.js +1 -0
  126. package/static/dist/assets/_app.settings._section-bi4jjex0.js +1 -0
  127. package/static/dist/assets/_app.skills-e4e61l23.js +1 -0
  128. package/static/dist/assets/_app.tasks-f1evdhbl.js +2 -0
  129. package/static/dist/assets/_app.todos-o7ijtk42.js +1 -0
  130. package/static/dist/assets/_app.workspaces-o18voh0w.js +1 -0
  131. package/static/dist/assets/{abnfDiagram-VCTEODGH-i4bgzu83.js → abnfDiagram-VCTEODGH-krt0yaru.js} +1 -1
  132. package/static/dist/assets/architecture-7GRP2DOG-notdhmpv.js +1 -0
  133. package/static/dist/assets/{architectureDiagram-5GKGNRK7-mx21lwqa.js → architectureDiagram-5GKGNRK7-i54t9ywl.js} +1 -1
  134. package/static/dist/assets/{blockDiagram-I7D4REHJ-o1hhchxv.js → blockDiagram-I7D4REHJ-fevbz4mz.js} +1 -1
  135. package/static/dist/assets/{c4Diagram-7LVT6UL2-jygqtvd8.js → c4Diagram-7LVT6UL2-np8eclmc.js} +1 -1
  136. package/static/dist/assets/channel-jpk1nas2.js +1 -0
  137. package/static/dist/assets/{chunk-4HAMMTFA-hjcpubgk.js → chunk-4HAMMTFA-owoi036m.js} +1 -1
  138. package/static/dist/assets/{chunk-75Z2AOVW-eibnex6m.js → chunk-75Z2AOVW-md44zf1n.js} +1 -1
  139. package/static/dist/assets/{chunk-DU6HZSFF-k1tp3qnp.js → chunk-DU6HZSFF-ka3rw8d6.js} +3 -3
  140. package/static/dist/assets/{chunk-F27PBJKO-lvcgn16f.js → chunk-F27PBJKO-iasnjsky.js} +1 -1
  141. package/static/dist/assets/{chunk-GMAD6QVW-ldlzruv1.js → chunk-GMAD6QVW-ex1up6tz.js} +1 -1
  142. package/static/dist/assets/{chunk-GVQU2GXP-hs1mva9d.js → chunk-GVQU2GXP-d4kmmg9p.js} +1 -1
  143. package/static/dist/assets/{chunk-IMKFNOWR-o7eqx3yb.js → chunk-IMKFNOWR-mwy42t85.js} +1 -1
  144. package/static/dist/assets/{chunk-L3NEJ4N5-bp1ofl70.js → chunk-L3NEJ4N5-fv7ry213.js} +1 -1
  145. package/static/dist/assets/{chunk-OSK3NFVY-o8m6mdz5.js → chunk-OSK3NFVY-jg9ir8ac.js} +1 -1
  146. package/static/dist/assets/{chunk-P2QGCYS3-kx83fti2.js → chunk-P2QGCYS3-pe9ms3ua.js} +1 -1
  147. package/static/dist/assets/{chunk-POPQ4Y6H-mwl99e9y.js → chunk-POPQ4Y6H-dimsjrn1.js} +1 -1
  148. package/static/dist/assets/{chunk-PWAF6VOD-oriuokxy.js → chunk-PWAF6VOD-m4hv98dy.js} +1 -1
  149. package/static/dist/assets/{chunk-SHT3W25Y-ab5cf00v.js → chunk-SHT3W25Y-gkjgl6qe.js} +1 -1
  150. package/static/dist/assets/{chunk-SVP7TREG-kqdrpr17.js → chunk-SVP7TREG-bc8qss5l.js} +1 -1
  151. package/static/dist/assets/{chunk-TICWLB2K-kfbnjabk.js → chunk-TICWLB2K-k9wzw38w.js} +1 -1
  152. package/static/dist/assets/classDiagram-ZZMXUADV-hld301gc.js +1 -0
  153. package/static/dist/assets/classDiagram-v2-VYDZK3BY-hld301gc.js +1 -0
  154. package/static/dist/assets/{copied-dp33szhq.js → copied-d5joolw7.js} +1 -1
  155. package/static/dist/assets/{cynefin-OW5HDTMX-mm5sj9s7.js → cynefin-OW5HDTMX-hueklikk.js} +1 -1
  156. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-nfon5q38.js → cynefinDiagram-5FMLGOSQ-e83o1wr1.js} +1 -1
  157. package/static/dist/assets/{dagre-GXQ25YYZ-dzdp9ypb.js → dagre-GXQ25YYZ-ir1tj2ar.js} +1 -1
  158. package/static/dist/assets/{diagram-S7CK7UJ4-ckxzqo01.js → diagram-S7CK7UJ4-o5218p2q.js} +1 -1
  159. package/static/dist/assets/{diagram-UQ7AKVKN-hw16h1um.js → diagram-UQ7AKVKN-ciad4o1i.js} +1 -1
  160. package/static/dist/assets/{diagram-VSXAHHWV-mu7wu2zg.js → diagram-VSXAHHWV-oharqjbt.js} +1 -1
  161. package/static/dist/assets/{diagram-VX7I27RA-k9uprwtj.js → diagram-VX7I27RA-wkwy62iv.js} +1 -1
  162. package/static/dist/assets/{diagram-Z3DM3KII-csdjzrg9.js → diagram-Z3DM3KII-bl252i7r.js} +1 -1
  163. package/static/dist/assets/{ebnfDiagram-PWID7BFC-n8mbw2jj.js → ebnfDiagram-PWID7BFC-nm0rcly7.js} +1 -1
  164. package/static/dist/assets/endpoints-d8n28yf3.js +64 -0
  165. package/static/dist/assets/{erDiagram-RLTQ6QDP-fsfe1uj0.js → erDiagram-RLTQ6QDP-m1w0vta2.js} +1 -1
  166. package/static/dist/assets/eventmodeling-NTZA5JFV-eaqs19mj.js +1 -0
  167. package/static/dist/assets/flowDiagram-HODETNUW-eli5764n.js +1 -0
  168. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-gsba3iq9.js → ganttDiagram-EL5Y4UJY-czxo6iew.js} +1 -1
  169. package/static/dist/assets/{gitGraph-4MIJSDKK-na86q1pu.js → gitGraph-4MIJSDKK-ip9j1rph.js} +1 -1
  170. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-g72ew3xz.js → gitGraphDiagram-WWUBYQGX-kalxdole.js} +1 -1
  171. package/static/dist/assets/{highlighted-body-KPVGNVTW-okn18cp1.js → highlighted-body-KPVGNVTW-lgsj6fsk.js} +1 -1
  172. package/static/dist/assets/index-l08181vr.js +11 -0
  173. package/static/dist/assets/index-pdtcl20t.css +2 -0
  174. package/static/dist/assets/{info-A6RAGUB7-i01jeltk.js → info-A6RAGUB7-fv4fbc5m.js} +1 -1
  175. package/static/dist/assets/{infoDiagram-27XIBGKW-cayiv6fa.js → infoDiagram-27XIBGKW-kinx5jsl.js} +1 -1
  176. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-g4rf14bv.js → ishikawaDiagram-5VMMS53U-kozvlqdv.js} +1 -1
  177. package/static/dist/assets/{journeyDiagram-3NMN7TZE-fusb2424.js → journeyDiagram-3NMN7TZE-lgpouxoe.js} +1 -1
  178. package/static/dist/assets/{kanban-definition-UXKFOSKX-g831pwlr.js → kanban-definition-UXKFOSKX-b320wo7b.js} +1 -1
  179. package/static/dist/assets/{lazyRouteComponent-ol965zwk.js → lazyRouteComponent-hy8doeye.js} +1 -1
  180. package/static/dist/assets/{line-md6em6gc.js → line-gxfwyhjq.js} +1 -1
  181. package/static/dist/assets/{login-kfclsqd2.js → login-llplsuey.js} +1 -1
  182. package/static/dist/assets/mermaid-HWGCJPDP-f3scrlds.js +1 -0
  183. package/static/dist/assets/{mermaid-parser.core-mq3uns9m.js → mermaid-parser.core-loxeqsu3.js} +3 -3
  184. package/static/dist/assets/{mindmap-definition-YA3MSWOX-oxafrned.js → mindmap-definition-YA3MSWOX-edi534gc.js} +1 -1
  185. package/static/dist/assets/{onboarding-fo6hnkyv.js → onboarding-n1xhlgym.js} +1 -1
  186. package/static/dist/assets/{packet-AYTQ26CC-ggxyvbym.js → packet-AYTQ26CC-gmb3yy71.js} +1 -1
  187. package/static/dist/assets/{pegDiagram-XKGWAZYB-nk7xcqgp.js → pegDiagram-XKGWAZYB-fxy5j8cx.js} +1 -1
  188. package/static/dist/assets/{pie-WAS4IAKB-ito2razh.js → pie-WAS4IAKB-do2pm4s6.js} +1 -1
  189. package/static/dist/assets/{pieDiagram-E7YTZNPT-g02xexar.js → pieDiagram-E7YTZNPT-mgjvb365.js} +1 -1
  190. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-d4jn4xq5.js → quadrantDiagram-AXDQQJYC-dhok6m1j.js} +1 -1
  191. package/static/dist/assets/{radar-RG4KPBEZ-nebvfdzt.js → radar-RG4KPBEZ-n5giw3vb.js} +1 -1
  192. package/static/dist/assets/{railroad-74A4TZTK-ny3gebse.js → railroad-74A4TZTK-h6nfs9bj.js} +1 -1
  193. package/static/dist/assets/railroad-abnf-HS5TGJTU-d5gaaud9.js +1 -0
  194. package/static/dist/assets/railroad-ebnf-LZEXJU2U-ihudnbec.js +1 -0
  195. package/static/dist/assets/railroad-peg-WCYAUIDC-lgpvhel7.js +1 -0
  196. package/static/dist/assets/{railroadDiagram-O6MQD6OU-m09mmu67.js → railroadDiagram-O6MQD6OU-lfwg92r4.js} +1 -1
  197. package/static/dist/assets/{refresh-cw-eitd7yva.js → refresh-cw-bg6oc499.js} +1 -1
  198. package/static/dist/assets/{requirementDiagram-BXWQKSXE-evggpcbk.js → requirementDiagram-BXWQKSXE-c5k5pg07.js} +1 -1
  199. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-bun89039.js → sankeyDiagram-P5KCCOFB-o9auio4y.js} +1 -1
  200. package/static/dist/assets/{saved-culx14ii.js → saved-j5wyhbik.js} +1 -1
  201. package/static/dist/assets/{search-nu6kzq55.js → search-ipa17zlr.js} +1 -1
  202. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-hhs9f09o.js → sequenceDiagram-WJ2MYXX4-pfgodnmk.js} +1 -1
  203. package/static/dist/assets/{settings_section_extensions_title-mj0gcozh.js → settings_section_extensions_title-fcfjf6l8.js} +1 -1
  204. package/static/dist/assets/share._token-i339gqj4.js +2 -0
  205. package/static/dist/assets/{sliders-horizontal-b9ljga1o.js → sliders-horizontal-bfrh4rch.js} +1 -1
  206. package/static/dist/assets/{stateDiagram-D77RDMKH-gi7t1tro.js → stateDiagram-D77RDMKH-m1y2cr3q.js} +1 -1
  207. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hehvfv55.js +1 -0
  208. package/static/dist/assets/{swimlanes-42K2YHIH-ea5urvph.js → swimlanes-42K2YHIH-hzai6fwo.js} +1 -1
  209. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-nfk9mtst.js +8 -0
  210. package/static/dist/assets/{timeline-definition-24CTP7MA-mq64rm3b.js → timeline-definition-24CTP7MA-gwefy9gi.js} +1 -1
  211. package/static/dist/assets/todoStore-fhvdsen0.js +1 -0
  212. package/static/dist/assets/{treeView-Q6P3EWNA-cimbtxlz.js → treeView-Q6P3EWNA-7q91p0dn.js} +1 -1
  213. package/static/dist/assets/{treemap-WGGIJYW6-wig5gi1y.js → treemap-WGGIJYW6-occom39a.js} +1 -1
  214. package/static/dist/assets/{untitled-mbwemvxf.js → untitled-cgw2enra.js} +1 -1
  215. package/static/dist/assets/{useForm-li4bljlv.js → useForm-jwbfla68.js} +1 -1
  216. package/static/dist/assets/useLocale-gieo1fn7.js +1 -0
  217. package/static/dist/assets/{vennDiagram-4TSXK5OY-ez63kh7n.js → vennDiagram-4TSXK5OY-ew4bhldi.js} +1 -1
  218. package/static/dist/assets/{wardley-WFR3VGLG-r7rftz31.js → wardley-WFR3VGLG-njdacy0u.js} +1 -1
  219. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-mvqg9eqc.js → wardleyDiagram-VM6X3IG4-mkvxx7u9.js} +1 -1
  220. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-eqxdfc91.js → xychartDiagram-S5SC5T6Z-8uriotdw.js} +1 -1
  221. package/static/dist/index.html +1 -1
  222. package/static/dist/manifest.webmanifest +1 -1
  223. package/static/dist/sw.js +114 -152
  224. package/static/dist/assets/AppShell-hikzkcql.js +0 -1
  225. package/static/dist/assets/ChatPage-ofqn89h9.js +0 -21
  226. package/static/dist/assets/HubRoute-f2zrs9si.js +0 -2
  227. package/static/dist/assets/Select-lvx8gihl.js +0 -1
  228. package/static/dist/assets/SessionListPanel-o70ljmik.js +0 -1
  229. package/static/dist/assets/States-i46tz8an.js +0 -1
  230. package/static/dist/assets/Toaster-fklyeeyh.js +0 -1
  231. package/static/dist/assets/_app-j3rors25.js +0 -1
  232. package/static/dist/assets/_app.ext._extensionId-c0ey5ec9.js +0 -1
  233. package/static/dist/assets/_app.index-coy9jrto.js +0 -1
  234. package/static/dist/assets/_app.insights-ebd2k0i5.js +0 -1
  235. package/static/dist/assets/_app.kanban-e2p7ypi5.js +0 -1
  236. package/static/dist/assets/_app.logs-ml21mfyz.js +0 -1
  237. package/static/dist/assets/_app.memory-lhu5mm47.js +0 -1
  238. package/static/dist/assets/_app.profiles-egx0fgjo.js +0 -1
  239. package/static/dist/assets/_app.settings-d0vqtyid.js +0 -1
  240. package/static/dist/assets/_app.settings._section-cnzj6pli.js +0 -1
  241. package/static/dist/assets/_app.skills-kkug8obu.js +0 -1
  242. package/static/dist/assets/_app.tasks-nf285d2o.js +0 -2
  243. package/static/dist/assets/_app.todos-dxalqp1e.js +0 -1
  244. package/static/dist/assets/_app.workspaces-bqtduujs.js +0 -1
  245. package/static/dist/assets/architecture-7GRP2DOG-o8zqevhv.js +0 -1
  246. package/static/dist/assets/channel-mw8l793e.js +0 -1
  247. package/static/dist/assets/classDiagram-ZZMXUADV-egajr1wp.js +0 -1
  248. package/static/dist/assets/classDiagram-v2-VYDZK3BY-egajr1wp.js +0 -1
  249. package/static/dist/assets/endpoints-f6ngsyu5.js +0 -64
  250. package/static/dist/assets/eventmodeling-NTZA5JFV-k3zhqcyl.js +0 -1
  251. package/static/dist/assets/flowDiagram-HODETNUW-bdxes51f.js +0 -1
  252. package/static/dist/assets/index-ab0wj9ik.css +0 -2
  253. package/static/dist/assets/index-fd27xooo.js +0 -11
  254. package/static/dist/assets/mermaid-HWGCJPDP-ejk0d88t.js +0 -1
  255. package/static/dist/assets/railroad-abnf-HS5TGJTU-gtd38edw.js +0 -1
  256. package/static/dist/assets/railroad-ebnf-LZEXJU2U-o238oax2.js +0 -1
  257. package/static/dist/assets/railroad-peg-WCYAUIDC-c4acqp2j.js +0 -1
  258. package/static/dist/assets/share._token-k4pcnxqu.js +0 -2
  259. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-jtadbol7.js +0 -1
  260. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ki7weepw.js +0 -8
  261. package/static/dist/assets/todoStore-azvfuqbv.js +0 -1
  262. package/static/dist/assets/trash-osyo895g.js +0 -1
  263. package/static/dist/assets/useLocale-kdew6auf.js +0 -1
@@ -1,15 +1,15 @@
1
1
  import { str } from '../util.js';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { rmSync } from 'node:fs';
4
- import { copyJson, redactSessionData, redactValue, stripPublicInternalFields } from '../redact.js';
4
+ import { buildActiveTurnToken, copyJson, redactSessionData, redactValue, stripPublicInternalFields, withSceneToolDisplay } from '../redact.js';
5
5
  import { DraftVersionConflict, normalizeDraftVersion } from './drafts.js';
6
- import { allSessions, buildSessionListPayload, isMessagingSessionRecord, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMessageText, sessionSearchPreview } from './list.js';
6
+ import { allSessions, buildSessionListPayload, isClaimableCliSource, isMessagingSessionRecord, withOwnerLocks, withSessionWireFlags, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMessageText, sessionSearchPreview } from './list.js';
7
7
  import { anchorSceneIntOrNull, hydrateAnchorActivityScenes, normalizeAnchorSceneMessageRef, readAnchorSceneRows, storeAnchorScene, withTurnIds } from './anchor.js';
8
8
  import { isSafeSessionId, lastMessageTimestamp, Session, titleFrom } from './session.js';
9
9
  import { SessionBusy, SessionNotFound, statSignature } from './store.js';
10
10
  import { attachTodoState } from './todo.js';
11
- import { stateDbSessionMessages, stateDbSessionRow } from './state-db.js';
12
- import { mergeSessionMessagesAppendOnly } from './merge.js';
11
+ import { stateDbSessionMessages, stateDbSessionRow, stateDbSessionSources } from './state-db.js';
12
+ import { mergeSessionMessagesAppendOnly, pendingUserRow, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
13
13
  import { messagesForLimitedPayload, messageWindowForDisplay, MAX_MSG_LIMIT, parseMsgLimit, toolCallsForMessageWindow } from './window.js';
14
14
  import { redactText } from '../redact.js';
15
15
  import { buildShareSnapshot } from './shares.js';
@@ -62,7 +62,7 @@ export class SessionService {
62
62
  isReadOnlyImport(sid) {
63
63
  try {
64
64
  const s = this.store.get(sid, { metadataOnly: true });
65
- if (s.read_only)
65
+ if (this.isReadOnly(s))
66
66
  return true;
67
67
  }
68
68
  catch {
@@ -85,11 +85,20 @@ export class SessionService {
85
85
  const meta = this.lookupCliMeta(sid);
86
86
  return meta !== null && str(meta.source_tag || meta.raw_source || meta.source).trim().toLowerCase() === 'subagent';
87
87
  }
88
+ /** TAL-358: batched `sessions.source` owners from the active profile's state.db. */
89
+ stateDbSources = (ids) => stateDbSessionSources(join(this.deps.profileHome(this.deps.activeProfile()), 'state.db'), ids);
90
+ /** The persisted flag folded with the state.db owner lock (TAL-358): the one read-only rule for mutation gates and the wire. */
91
+ isReadOnly(s) {
92
+ if (s.read_only)
93
+ return true;
94
+ const [row] = withOwnerLocks([{ session_id: s.session_id, source_tag: s.source_tag, raw_source: s.raw_source, session_source: s.session_source }], this.stateDbSources);
95
+ return Boolean(row?.read_only);
96
+ }
88
97
  /** Full session for mutation, refusing read-only imports (Python `_get_or_materialize_session`). */
89
98
  getForMutation(sid) {
90
99
  let s = this.get404(sid);
91
100
  s = this.store.ensureFull(sid, s);
92
- if (s.read_only)
101
+ if (this.isReadOnly(s))
93
102
  throw new HttpFailure(403, 'Read-only imported sessions cannot be modified from WebUI');
94
103
  if (str(s.source_tag || s.raw_source).trim().toLowerCase() === 'subagent')
95
104
  throw new HttpFailure(403, 'Read-only subagent child session');
@@ -141,23 +150,6 @@ export class SessionService {
141
150
  return null;
142
151
  }
143
152
  }
144
- /** Python `_is_claimable_cli_source`: a denylist of foreign families that own their sessions. */
145
- claimableCliSource(meta, stateDbSource) {
146
- if (meta.read_only)
147
- return false;
148
- const sessionSource = str(meta.session_source).trim().toLowerCase();
149
- if (['messaging', 'external_agent'].includes(sessionSource))
150
- return false;
151
- const tag = str(meta.source_tag || meta.raw_source).trim().toLowerCase();
152
- const refused = new Set(['claude_code', 'cron', 'external_agent', 'gateway', 'messaging', 'subagent', 'unknown']);
153
- if (tag && refused.has(tag))
154
- return false;
155
- if (isMessagingSessionRecord(meta))
156
- return false;
157
- if (!tag && stateDbSource && refused.has(stateDbSource.trim().toLowerCase()))
158
- return false;
159
- return true;
160
- }
161
153
  /** Python `_session_index_marks_was_webui`: an index row that once owned a WebUI sidecar (self-heal 404). */
162
154
  indexMarksWasWebui(sid) {
163
155
  let entries;
@@ -214,7 +206,7 @@ export class SessionService {
214
206
  if (!meta.updated_at && (row.ended_at || row.started_at))
215
207
  meta.updated_at = row.ended_at || row.started_at;
216
208
  }
217
- const claimable = this.claimableCliSource(meta, stateDbSource);
209
+ const claimable = isClaimableCliSource(meta, stateDbSource);
218
210
  const workspace = str(meta.workspace || meta.cwd).trim() || this.deps.workspaces.lastWorkspace(profile);
219
211
  const defaults = this.store.deps.defaults(profile);
220
212
  const session = new Session({
@@ -243,12 +235,16 @@ export class SessionService {
243
235
  }
244
236
  /** `compact()` plus messages, redacted for the wire (Python `_public_session_projection`). */
245
237
  publicSession(s, withMessages = true) {
246
- const payload = s.compact();
238
+ const payload = this.wireRow(s);
247
239
  // Mutation replies replace a client's transcript, so they carry the same server-built scenes as the detail.
248
240
  if (withMessages)
249
- payload.messages = hydrateAnchorActivityScenes(withTurnIds(s.messages), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id });
241
+ payload.messages = hydrateAnchorActivityScenes(withToolCallOutcomes(withTurnIds(s.messages), s.tool_calls, s.active_stream_id), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id });
250
242
  return redactSessionData(payload, this.deps.redactEnabled());
251
243
  }
244
+ /** `compact()` with the wire streaming/read-only flags (TAL-312), for replies that return the session row. */
245
+ wireRow(s) {
246
+ return withSessionWireFlags({ ...s.compact(), read_only: this.isReadOnly(s) }, this.deps.runtime.activeStreamIds);
247
+ }
252
248
  /** Python `public_session_projection(s.__dict__)`: every persisted field, redacted (session export). */
253
249
  publicSessionDocument(s) {
254
250
  return redactSessionData(s.toDocument(), this.deps.redactEnabled());
@@ -279,8 +275,15 @@ export class SessionService {
279
275
  throw new HttpFailure(404, 'Session not found');
280
276
  }
281
277
  this.clearStaleStreamState(s);
282
- // Turn ids and scenes are computed over the full transcript, so every window reports the same values.
283
- const all = loadMessages ? hydrateAnchorActivityScenes(withTurnIds(this.mergedTranscript(s)), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id, clipToolResults: msgLimit !== null }) : [];
278
+ const journaled = loadMessages ? this.journaledActiveTurn(s) : null;
279
+ let transcript = loadMessages ? this.mergedTranscript(s) : [];
280
+ const pending = loadMessages ? this.pendingTurn(s) : null;
281
+ if (pending)
282
+ transcript = withPendingUserTurn(transcript, pending);
283
+ if (journaled)
284
+ transcript = withoutRunningTurnOutput(transcript, { ...journaled, localCount: s.messages.length });
285
+ // Turn ids, tool outcomes and scenes are computed over the full transcript, so every window reports the same values.
286
+ const all = loadMessages ? hydrateAnchorActivityScenes(withToolCallOutcomes(withTurnIds(transcript), s.tool_calls, s.active_stream_id), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id, clipToolResults: msgLimit !== null }) : [];
284
287
  let truncated = [];
285
288
  let offset = 0;
286
289
  let summaryCount = null;
@@ -288,6 +291,14 @@ export class SessionService {
288
291
  if (loadMessages) {
289
292
  ;
290
293
  [truncated, offset] = messageWindowForDisplay(all, msgLimit, msgBefore);
294
+ // TAL-368: a tail window starts no later than the running turn's prompt, so a turn whose output stays in the
295
+ // transcript (no journal to replay it) keeps its prompt; older pages end before it, so it is never sent twice.
296
+ // ponytail: the window grows with that turn's persisted rows; clip the turn instead if degraded runs get long.
297
+ const prompt = pending && msgBefore === null ? all.findIndex((m) => isDict(m) && m.role === 'user' && m._active_turn_token === pending.activeTurnToken) : -1;
298
+ if (prompt >= 0 && prompt < offset) {
299
+ truncated = all.slice(prompt, offset + truncated.length);
300
+ offset = prompt;
301
+ }
291
302
  if (msgLimit !== null)
292
303
  truncated = messagesForLimitedPayload(truncated);
293
304
  }
@@ -310,7 +321,6 @@ export class SessionService {
310
321
  messages: truncated,
311
322
  message_count: mergedCount,
312
323
  tool_calls: toolCalls,
313
- active_stream_id: s.active_stream_id,
314
324
  pending_user_message: s.pending_user_message,
315
325
  pending_attachments: loadMessages ? s.pending_attachments : [],
316
326
  pending_started_at: s.pending_started_at,
@@ -319,6 +329,8 @@ export class SessionService {
319
329
  threshold_tokens: Number(s.threshold_tokens ?? 0) || 0,
320
330
  last_prompt_tokens: Number(s.last_prompt_tokens ?? 0) || 0,
321
331
  };
332
+ if (loadMessages)
333
+ raw.transcript_seq = journaled ? { stream_id: journaled.turnId, seq: 0 } : null;
322
334
  if (loadMessages && all.length)
323
335
  attachTodoState(raw, all);
324
336
  if (mergedLast) {
@@ -331,12 +343,34 @@ export class SessionService {
331
343
  raw._msg_limit_max = MAX_MSG_LIMIT;
332
344
  const revisionAfter = this.loadRevision(s);
333
345
  raw._load_revision = revisionBefore !== null && revisionBefore === revisionAfter ? hashRevision(revisionBefore) : `unstable-${randomUUID().replace(/-/g, '')}`;
334
- if (str(raw.source_tag || raw.raw_source || raw.session_source).trim().toLowerCase() === 'subagent') {
335
- raw.is_cli_session = false;
336
- raw.read_only = true;
337
- }
346
+ raw.read_only = this.isReadOnly(s);
347
+ withSessionWireFlags(raw, activeStreamIds);
338
348
  return redactSessionData(raw, this.deps.redactEnabled());
339
349
  }
350
+ /**
351
+ * TAL-316: the active run whose journal can replay its output from the start. The detail then leaves that output to the
352
+ * replay; with no active run, no identifiable prompt, or no complete journal, it returns the persisted transcript unchanged.
353
+ */
354
+ journaledActiveTurn(s) {
355
+ const turnId = str(s.active_stream_id).trim();
356
+ const activeTurnToken = buildActiveTurnToken(turnId, s.pending_started_at);
357
+ if (!turnId || !activeTurnToken || this.deps.runtime.journalDegraded(turnId))
358
+ return null;
359
+ const summary = this.deps.journal?.findRunSummary(turnId);
360
+ if (summary?.session_id !== s.session_id || summary.journal_pruned)
361
+ return null;
362
+ return { turnId, startedAt: Number(s.pending_started_at), activeTurnToken };
363
+ }
364
+ /** TAL-368: the active run's prompt, which the detail shows until settlement persists it; null when idle or promptless. */
365
+ pendingTurn(s) {
366
+ const turnId = str(s.active_stream_id).trim();
367
+ const activeTurnToken = buildActiveTurnToken(turnId, s.pending_started_at);
368
+ const text = str(s.pending_user_message);
369
+ if (!turnId || !activeTurnToken || (!text && !s.pending_attachments.length))
370
+ return null;
371
+ const startedAt = Number(s.pending_started_at);
372
+ return { turnId, startedAt, activeTurnToken, localCount: s.messages.length, prompt: pendingUserRow(text, s.pending_attachments, startedAt, s.pending_user_source || 'webui', turnId) };
373
+ }
340
374
  /** A session without a sidecar, synthesized from state.db for this profile; 404/409 like the detail. */
341
375
  foreignSession(sid) {
342
376
  const meta = this.lookupCliMeta(sid);
@@ -355,18 +389,18 @@ export class SessionService {
355
389
  /** Python `_handle_session_get` without a sidecar: the state.db transcript as a (read-only or claimable) foreign stub. */
356
390
  foreignSessionDetail(sid) {
357
391
  const { synth, meta } = this.foreignSession(sid);
358
- // The same turn projection as a WebUI session: turn ids, then each completed turn's scene.
359
- const msgs = hydrateAnchorActivityScenes(withTurnIds(synth.messages), {});
392
+ // The same turn projection as a WebUI session: turn ids, tool outcomes, then each completed turn's scene.
393
+ const msgs = hydrateAnchorActivityScenes(withToolCallOutcomes(withTurnIds(synth.messages), [], null), {});
360
394
  const lastTs = Number(msgs[msgs.length - 1]?.timestamp ?? 0) || 0;
361
395
  const sess = {
362
396
  session_id: synth.session_id, title: synth.title, workspace: synth.workspace, model: synth.model, message_count: msgs.length,
363
397
  created_at: synth.created_at, updated_at: synth.updated_at, last_message_at: meta?.last_message_at || meta?.updated_at || lastTs,
364
398
  pinned: synth.pinned, archived: synth.archived, project_id: synth.project_id ?? null, profile: synth.profile,
365
399
  is_cli_session: synth.is_cli_session, source_tag: synth.source_tag, raw_source: synth.raw_source, session_source: synth.session_source,
366
- source_label: synth.source_label, read_only: synth.read_only, messages: msgs, tool_calls: [],
400
+ source_label: synth.source_label, read_only: synth.read_only, can_duplicate: false, messages: msgs, tool_calls: [], transcript_seq: null,
367
401
  };
368
402
  attachTodoState(sess, msgs);
369
- const merged = meta ? mergeCliSidebarMetadata(sess, meta) : sess;
403
+ const merged = withSessionWireFlags(meta ? mergeCliSidebarMetadata(sess, meta) : sess, this.deps.runtime.activeStreamIds);
370
404
  return redactSessionData(merged, this.deps.redactEnabled());
371
405
  }
372
406
  /** Clear persisted streaming flags when no live stream backs them (Python `_clear_stale_stream_state`, no journal recovery). */
@@ -434,7 +468,7 @@ export class SessionService {
434
468
  // Python reads every profile's state.db under all_profiles; this port projects the active profile only.
435
469
  const cliRows = wantState ? this.deps.cliSessions(activeProfile, { sourceFilter: params.sourceFilter ?? null }) : undefined;
436
470
  const gatewayIdentity = loadGatewaySessionIdentityMap(join(this.deps.profileHome(activeProfile), 'sessions', 'sessions.json'));
437
- const payload = buildSessionListPayload(this.store, { ...params, ...(cliRows ? { cliRows } : {}), gatewayIdentity, activeProfile, isolatedProfileMode: this.deps.isolatedProfileMode(), profilesMatch: this.deps.profilesMatch });
471
+ const payload = buildSessionListPayload(this.store, { ...params, ...(cliRows ? { cliRows } : {}), gatewayIdentity, stateDbSources: this.stateDbSources, activeProfile, isolatedProfileMode: this.deps.isolatedProfileMode(), profilesMatch: this.deps.profilesMatch });
438
472
  return sessionListResponse(payload, this.deps.runtime, this.deps.redactEnabled(), this.deps.now());
439
473
  }
440
474
  search(q, opts) {
@@ -442,8 +476,10 @@ export class SessionService {
442
476
  let sessions = allSessions(this.store);
443
477
  if (!opts.allProfiles)
444
478
  sessions = sessions.filter((r) => this.deps.profilesMatch(str(r.profile) || null, activeProfile));
479
+ sessions = withOwnerLocks(sessions, this.stateDbSources);
445
480
  const redact = this.deps.redactEnabled();
446
481
  const redactRow = (item) => {
482
+ withSessionWireFlags(item, this.deps.runtime.activeStreamIds);
447
483
  if (typeof item.title === 'string')
448
484
  item.title = redactText(item.title, redact);
449
485
  for (const f of ['display_title', '_state_db_title', 'parent_title'])
@@ -499,10 +535,10 @@ export class SessionService {
499
535
  catch {
500
536
  hermesHome = '';
501
537
  }
502
- const live = full.active_stream_id && this.deps.runtime.activeStreamIds.has(full.active_stream_id) ? full.active_stream_id : null;
538
+ const { is_streaming: streaming, active_stream_id: live, read_only: readOnly } = this.wireRow(full);
503
539
  return {
504
540
  session_id: full.session_id, title: full.title, model: full.model, profile, hermes_home: hermesHome, workspace: full.workspace, personality: full.personality,
505
- message_count: full.messages.length, created_at: full.created_at, updated_at: full.updated_at, agent_running: Boolean(full.active_stream_id), active_stream_id: live,
541
+ message_count: full.messages.length, created_at: full.created_at, updated_at: full.updated_at, agent_running: streaming, is_streaming: streaming, active_stream_id: live, read_only: readOnly,
506
542
  input_tokens: inp, output_tokens: out, total_tokens: inp + out, estimated_cost: full.estimated_cost,
507
543
  };
508
544
  }
@@ -574,7 +610,7 @@ export class SessionService {
574
610
  catch {
575
611
  throw new HttpFailure(404, 'Session not found');
576
612
  }
577
- if (current.read_only)
613
+ if (this.isReadOnly(current))
578
614
  throw new HttpFailure(403, `Session ${sid} is read-only`);
579
615
  await this.store.withLock(sid, () => {
580
616
  current.title = title;
@@ -593,7 +629,7 @@ export class SessionService {
593
629
  });
594
630
  await this.deps.syncTitle(s);
595
631
  this.publish('session_rename', s.profile, s.session_id);
596
- return { session: s.compact() };
632
+ return { session: this.wireRow(s) };
597
633
  }
598
634
  // The pin quota is counted across sessions, so the count-and-save transaction runs on one process-wide chain;
599
635
  // per-session locks alone would let two pins of different sessions both see the last free slot.
@@ -623,7 +659,7 @@ export class SessionService {
623
659
  this.store.save(s);
624
660
  });
625
661
  this.publish('session_pin', s.profile, s.session_id);
626
- return { ok: true, session: s.compact() };
662
+ return { ok: true, session: this.wireRow(s) };
627
663
  }
628
664
  async archive(sid, archived) {
629
665
  this.rejectSubagent(sid, 'archived');
@@ -636,7 +672,7 @@ export class SessionService {
636
672
  this.store.save(s, { touchUpdatedAt: false });
637
673
  });
638
674
  this.publish('session_archive', s.profile, s.session_id);
639
- return { ok: true, session: s.compact(), ...worktreeRetainedPayload(s) };
675
+ return { ok: true, session: this.wireRow(s), ...worktreeRetainedPayload(s) };
640
676
  }
641
677
  async move(sid, targetProjectId) {
642
678
  const s = this.mutationTarget(sid, 'moved');
@@ -658,7 +694,7 @@ export class SessionService {
658
694
  throw error;
659
695
  }
660
696
  this.publish('session_move', s.profile, s.session_id);
661
- return { ok: true, session: s.compact() };
697
+ return { ok: true, session: this.wireRow(s) };
662
698
  }
663
699
  async update(sid, body) {
664
700
  const s = this.mutationTarget(sid, 'updated');
@@ -696,7 +732,7 @@ export class SessionService {
696
732
  async setToolsets(sid, toolsets) {
697
733
  this.rejectSubagent(sid, 'modified');
698
734
  const cleaned = this.validateToolsetsShape(toolsets);
699
- const s = this.get404(sid);
735
+ const s = this.mutationTarget(sid, 'modified');
700
736
  await this.store.withLock(sid, () => {
701
737
  s.enabled_toolsets = cleaned;
702
738
  this.store.save(s);
@@ -718,7 +754,7 @@ export class SessionService {
718
754
  this.rejectSubagent(sid, 'modified');
719
755
  if (keepRaw === null || keepRaw === undefined)
720
756
  throw new HttpFailure(400, 'Missing required field(s): keep_count');
721
- const s = this.get404(sid);
757
+ const s = this.mutationTarget(sid, 'modified');
722
758
  // Python `int(body["keep_count"])`: a float truncates, a non-integer string is rejected.
723
759
  let keep;
724
760
  if (typeof keepRaw === 'number')
@@ -740,7 +776,7 @@ export class SessionService {
740
776
  }
741
777
  async clear(sid) {
742
778
  this.rejectSubagent(sid, 'modified');
743
- const s = this.get404(sid);
779
+ const s = this.mutationTarget(sid, 'modified');
744
780
  await this.store.withLock(sid, () => {
745
781
  const hadMessages = s.messages.length > 0;
746
782
  truncateSessionAtKeep(s, 0);
@@ -775,12 +811,12 @@ export class SessionService {
775
811
  }
776
812
  });
777
813
  this.deps.runtime.evictAgent(sid);
778
- return { ok: true, session: s.compact() };
814
+ return { ok: true, session: this.wireRow(s) };
779
815
  }
780
816
  async retry(sid) {
781
817
  this.rejectSubagent(sid, 'modified');
782
818
  return this.store.withLock(sid, () => {
783
- const s = this.get404(sid);
819
+ const s = this.mutationTarget(sid, 'modified');
784
820
  const history = s.messages;
785
821
  const lastUser = findLastUserIndex(history);
786
822
  if (lastUser === null)
@@ -795,7 +831,7 @@ export class SessionService {
795
831
  async undo(sid) {
796
832
  this.rejectSubagent(sid, 'modified');
797
833
  return this.store.withLock(sid, () => {
798
- const s = this.get404(sid);
834
+ const s = this.mutationTarget(sid, 'modified');
799
835
  const history = s.messages;
800
836
  const lastUser = findLastUserIndex(history);
801
837
  if (lastUser === null)
@@ -833,7 +869,7 @@ export class SessionService {
833
869
  if (this.isSubagentViewOnly(sid))
834
870
  throw new HttpFailure(400, 'Subagent sessions are view-only and cannot be branched from WebUI');
835
871
  const source = this.get404(sid);
836
- if (source.read_only) {
872
+ if (this.isReadOnly(source)) {
837
873
  if (str(source.source_tag || source.raw_source).trim().toLowerCase() !== 'cron')
838
874
  throw new HttpFailure(403, 'Read-only sessions cannot be branched from WebUI');
839
875
  source.branchSourceReadonly = true;
@@ -1189,11 +1225,13 @@ export class SessionService {
1189
1225
  session = this.foreignSession(sid).synth;
1190
1226
  transcript = session.messages;
1191
1227
  }
1192
- const result = readAnchorSceneRows(session, { messageRef, messageIndex, before: anchorSceneIntOrNull(query.before), limit: anchorSceneIntOrNull(query.limit) }, withTurnIds(transcript));
1228
+ const result = readAnchorSceneRows(session, { messageRef, messageIndex, before: anchorSceneIntOrNull(query.before), limit: anchorSceneIntOrNull(query.limit) }, withToolCallOutcomes(withTurnIds(transcript), session.tool_calls, session.active_stream_id));
1193
1229
  if (!result)
1194
1230
  throw new HttpFailure(404, 'Anchor activity scene not found');
1195
1231
  // Paged rows come from the raw transcript, so they take the same credential redaction as the detail's preview.
1196
- return redactValue(result, this.deps.redactEnabled());
1232
+ const enabled = this.deps.redactEnabled();
1233
+ const redacted = redactValue(result, enabled);
1234
+ return { ...redacted, rows: withSceneToolDisplay(result.rows, redacted.rows, enabled) };
1197
1235
  }
1198
1236
  // ── shares ───────────────────────────────────────────────────────────────
1199
1237
  createShare(sid) {