@maudecode/talaria-web 1.20.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/_release.json +8 -8
  2. package/dist/api/automation-router.d.ts +319 -14
  3. package/dist/api/automation-router.js +21 -1
  4. package/dist/api/automation-router.js.map +1 -1
  5. package/dist/api/chat-router.d.ts +615 -69
  6. package/dist/api/chat-router.js +22 -170
  7. package/dist/api/chat-router.js.map +1 -1
  8. package/dist/api/git-router.d.ts +50 -0
  9. package/dist/api/git-router.js +17 -4
  10. package/dist/api/git-router.js.map +1 -1
  11. package/dist/api/groups-router.d.ts +764 -0
  12. package/dist/api/groups-router.js +79 -0
  13. package/dist/api/groups-router.js.map +1 -0
  14. package/dist/api/raw-routes.js +3 -1
  15. package/dist/api/raw-routes.js.map +1 -1
  16. package/dist/api/router.d.ts +1 -1
  17. package/dist/api/sessions-router.d.ts +1675 -167
  18. package/dist/api/sessions-router.js +67 -53
  19. package/dist/api/sessions-router.js.map +1 -1
  20. package/dist/api/settings-router.d.ts +911 -1
  21. package/dist/api/settings-router.js +53 -2
  22. package/dist/api/settings-router.js.map +1 -1
  23. package/dist/api/sse-routes.d.ts +1 -1
  24. package/dist/api/sse-routes.js +15 -5
  25. package/dist/api/sse-routes.js.map +1 -1
  26. package/dist/api/tools-raw.js +27 -136
  27. package/dist/api/tools-raw.js.map +1 -1
  28. package/dist/api/tools-router.d.ts +588 -51
  29. package/dist/api/tools-router.js +98 -16
  30. package/dist/api/tools-router.js.map +1 -1
  31. package/dist/app.js +5 -1
  32. package/dist/app.js.map +1 -1
  33. package/dist/auth/gate.js +5 -1
  34. package/dist/auth/gate.js.map +1 -1
  35. package/dist/config/agent-config.d.ts +6 -1
  36. package/dist/config/agent-config.js +75 -3
  37. package/dist/config/agent-config.js.map +1 -1
  38. package/dist/feedback.d.ts +18 -0
  39. package/dist/feedback.js +145 -0
  40. package/dist/feedback.js.map +1 -0
  41. package/dist/fs/stat.d.ts +2 -0
  42. package/dist/fs/stat.js +4 -0
  43. package/dist/fs/stat.js.map +1 -1
  44. package/dist/http/context.d.ts +9 -0
  45. package/dist/http/context.js +0 -6
  46. package/dist/http/context.js.map +1 -1
  47. package/dist/http/pinned.js +19 -8
  48. package/dist/http/pinned.js.map +1 -1
  49. package/dist/providers/catalog.d.ts +9 -1
  50. package/dist/providers/catalog.js +86 -6
  51. package/dist/providers/catalog.js.map +1 -1
  52. package/dist/redact.d.ts +2 -0
  53. package/dist/redact.js +26 -5
  54. package/dist/redact.js.map +1 -1
  55. package/dist/runtime.js +62 -11
  56. package/dist/runtime.js.map +1 -1
  57. package/dist/server.js +2 -0
  58. package/dist/server.js.map +1 -1
  59. package/dist/sessions/admission.d.ts +21 -0
  60. package/dist/sessions/admission.js +176 -0
  61. package/dist/sessions/admission.js.map +1 -0
  62. package/dist/sessions/anchor.d.ts +5 -2
  63. package/dist/sessions/anchor.js +14 -13
  64. package/dist/sessions/anchor.js.map +1 -1
  65. package/dist/sessions/background-tasks.d.ts +19 -1
  66. package/dist/sessions/background-tasks.js +36 -6
  67. package/dist/sessions/background-tasks.js.map +1 -1
  68. package/dist/sessions/cli-sessions.js +11 -6
  69. package/dist/sessions/cli-sessions.js.map +1 -1
  70. package/dist/sessions/compress.d.ts +10 -9
  71. package/dist/sessions/compress.js +31 -20
  72. package/dist/sessions/compress.js.map +1 -1
  73. package/dist/sessions/events.d.ts +3 -0
  74. package/dist/sessions/events.js +4 -0
  75. package/dist/sessions/events.js.map +1 -1
  76. package/dist/sessions/gateway-sessions.d.ts +61 -2
  77. package/dist/sessions/gateway-sessions.js +223 -35
  78. package/dist/sessions/gateway-sessions.js.map +1 -1
  79. package/dist/sessions/gateway-watcher.js +8 -4
  80. package/dist/sessions/gateway-watcher.js.map +1 -1
  81. package/dist/sessions/groups.d.ts +60 -0
  82. package/dist/sessions/groups.js +339 -0
  83. package/dist/sessions/groups.js.map +1 -0
  84. package/dist/sessions/list.d.ts +7 -2
  85. package/dist/sessions/list.js +13 -4
  86. package/dist/sessions/list.js.map +1 -1
  87. package/dist/sessions/merge.d.ts +15 -5
  88. package/dist/sessions/merge.js +49 -15
  89. package/dist/sessions/merge.js.map +1 -1
  90. package/dist/sessions/pending.d.ts +1 -1
  91. package/dist/sessions/pending.js +15 -6
  92. package/dist/sessions/pending.js.map +1 -1
  93. package/dist/sessions/prefix-index.d.ts +9 -14
  94. package/dist/sessions/prefix-index.js +14 -52
  95. package/dist/sessions/prefix-index.js.map +1 -1
  96. package/dist/sessions/prompt-queues.d.ts +36 -0
  97. package/dist/sessions/prompt-queues.js +318 -0
  98. package/dist/sessions/prompt-queues.js.map +1 -0
  99. package/dist/sessions/reasoning-display.d.ts +2 -0
  100. package/dist/sessions/reasoning-display.js +31 -0
  101. package/dist/sessions/reasoning-display.js.map +1 -0
  102. package/dist/sessions/relay.d.ts +16 -2
  103. package/dist/sessions/relay.js +119 -24
  104. package/dist/sessions/relay.js.map +1 -1
  105. package/dist/sessions/service.d.ts +33 -3
  106. package/dist/sessions/service.js +304 -70
  107. package/dist/sessions/service.js.map +1 -1
  108. package/dist/sessions/session.d.ts +6 -0
  109. package/dist/sessions/session.js +14 -0
  110. package/dist/sessions/session.js.map +1 -1
  111. package/dist/sessions/shares.d.ts +1 -1
  112. package/dist/sessions/shares.js +13 -4
  113. package/dist/sessions/shares.js.map +1 -1
  114. package/dist/sessions/state-db.d.ts +2 -1
  115. package/dist/sessions/state-db.js +7 -3
  116. package/dist/sessions/state-db.js.map +1 -1
  117. package/dist/sessions/storage/json-documents.js +3 -0
  118. package/dist/sessions/storage/json-documents.js.map +1 -1
  119. package/dist/sessions/store.d.ts +2 -0
  120. package/dist/sessions/store.js +11 -3
  121. package/dist/sessions/store.js.map +1 -1
  122. package/dist/sessions/streams.d.ts +4 -0
  123. package/dist/sessions/streams.js +12 -0
  124. package/dist/sessions/streams.js.map +1 -1
  125. package/dist/sessions/todo.js +10 -1
  126. package/dist/sessions/todo.js.map +1 -1
  127. package/dist/sessions/tool-display.d.ts +8 -1
  128. package/dist/sessions/tool-display.js +39 -4
  129. package/dist/sessions/tool-display.js.map +1 -1
  130. package/dist/sessions/turn.d.ts +4 -1
  131. package/dist/sessions/turn.js +53 -22
  132. package/dist/sessions/turn.js.map +1 -1
  133. package/dist/settings.js +2 -1
  134. package/dist/settings.js.map +1 -1
  135. package/dist/spa.js +1 -1
  136. package/dist/spa.js.map +1 -1
  137. package/dist/test/group-fixture.d.ts +66 -0
  138. package/dist/test/group-fixture.js +89 -0
  139. package/dist/test/group-fixture.js.map +1 -0
  140. package/dist/test/harness.d.ts +3 -0
  141. package/dist/test/harness.js +3 -0
  142. package/dist/test/harness.js.map +1 -1
  143. package/dist/tools/connectors.d.ts +9 -1
  144. package/dist/tools/connectors.js +48 -0
  145. package/dist/tools/connectors.js.map +1 -1
  146. package/dist/tools/kanban.d.ts +10 -1
  147. package/dist/tools/kanban.js +73 -1
  148. package/dist/tools/kanban.js.map +1 -1
  149. package/dist/tools/mcp.d.ts +3 -1
  150. package/dist/tools/mcp.js +73 -0
  151. package/dist/tools/mcp.js.map +1 -1
  152. package/dist/tools/memory.d.ts +28 -0
  153. package/dist/tools/memory.js +120 -14
  154. package/dist/tools/memory.js.map +1 -1
  155. package/dist/tools/skills.d.ts +6 -0
  156. package/dist/tools/skills.js +17 -0
  157. package/dist/tools/skills.js.map +1 -1
  158. package/dist/tools/update-notifications.d.ts +12 -10
  159. package/dist/tools/update-notifications.js +124 -14
  160. package/dist/tools/update-notifications.js.map +1 -1
  161. package/dist/tools/updates.d.ts +38 -12
  162. package/dist/tools/updates.js +180 -44
  163. package/dist/tools/updates.js.map +1 -1
  164. package/dist/workspace/fs.d.ts +2 -0
  165. package/dist/workspace/fs.js +63 -1
  166. package/dist/workspace/fs.js.map +1 -1
  167. package/dist/workspace/managed-buffers.d.ts +58 -0
  168. package/dist/workspace/managed-buffers.js +76 -0
  169. package/dist/workspace/managed-buffers.js.map +1 -0
  170. package/dist/workspace/rollback.js +1 -1
  171. package/dist/workspace/rollback.js.map +1 -1
  172. package/dist/workspace/upload.d.ts +1 -1
  173. package/dist/workspace/upload.js +52 -37
  174. package/dist/workspace/upload.js.map +1 -1
  175. package/dist/workspace/workspaces.d.ts +5 -1
  176. package/dist/workspace/workspaces.js +32 -6
  177. package/dist/workspace/workspaces.js.map +1 -1
  178. package/package.json +2 -2
  179. package/sidecar/agent_dependency.json +4 -4
  180. package/sidecar/agent_importer.json +8 -0
  181. package/sidecar/agent_support.json +20 -8
  182. package/sidecar/scripts/agent_importer_contract.py +19 -0
  183. package/sidecar/scripts/test.sh +3 -1
  184. package/sidecar/talaria_sidecar/__init__.py +1 -1
  185. package/sidecar/talaria_sidecar/agent_mutation.py +87 -9
  186. package/sidecar/talaria_sidecar/agent_services.py +83 -23
  187. package/sidecar/talaria_sidecar/home.py +12 -5
  188. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  189. package/sidecar/talaria_sidecar/methods/agent_imports.py +346 -0
  190. package/sidecar/talaria_sidecar/methods/chat.py +141 -58
  191. package/sidecar/talaria_sidecar/methods/commands.py +6 -4
  192. package/sidecar/talaria_sidecar/methods/config.py +8 -3
  193. package/sidecar/talaria_sidecar/methods/connectors.py +138 -4
  194. package/sidecar/talaria_sidecar/methods/dashboard_plugins.py +25 -4
  195. package/sidecar/talaria_sidecar/methods/delegation.py +126 -0
  196. package/sidecar/talaria_sidecar/methods/gateway.py +5 -0
  197. package/sidecar/talaria_sidecar/methods/gateway_sessions.py +142 -23
  198. package/sidecar/talaria_sidecar/methods/groups.py +120 -0
  199. package/sidecar/talaria_sidecar/methods/kanban.py +48 -0
  200. package/sidecar/talaria_sidecar/methods/managed_buffers.py +110 -0
  201. package/sidecar/talaria_sidecar/methods/mcp.py +55 -0
  202. package/sidecar/talaria_sidecar/methods/memory.py +27 -3
  203. package/sidecar/talaria_sidecar/methods/nous_account.py +130 -0
  204. package/sidecar/talaria_sidecar/methods/oauth.py +25 -4
  205. package/sidecar/talaria_sidecar/methods/outbound_drafts.py +147 -0
  206. package/sidecar/talaria_sidecar/methods/plugin_catalog.py +73 -2
  207. package/sidecar/talaria_sidecar/methods/providers.py +51 -1
  208. package/sidecar/talaria_sidecar/methods/skill_revisions.py +177 -0
  209. package/sidecar/talaria_sidecar/methods/skills.py +10 -0
  210. package/sidecar/talaria_sidecar/methods/tts.py +67 -0
  211. package/sidecar/talaria_sidecar/rpc.py +11 -2
  212. package/static/dist/FILES.txt +155 -144
  213. package/static/dist/THIRD_PARTY_LICENSES.md +1 -1
  214. package/static/dist/assets/AppShell-hvysbd9x.js +8 -0
  215. package/static/dist/assets/Button-dlsibkzq.js +1 -0
  216. package/static/dist/assets/ChatPage-jikwrwfd.js +2 -0
  217. package/static/dist/assets/Composer-mnke8ss2.js +5 -0
  218. package/static/dist/assets/ConnectTargets-ejplzo4q.js +1 -0
  219. package/static/dist/assets/Dialog-rksfyyq5.js +1 -0
  220. package/static/dist/assets/{ExtensionRoute-zrhjn0wm.js → ExtensionRoute-igk5h0rj.js} +1 -1
  221. package/static/dist/assets/HubRoute-eooassx4.js +2 -0
  222. package/static/dist/assets/Markdown-m5pzgvtx.js +2 -0
  223. package/static/dist/assets/{MarkdownRenderer-fbswsgld.js → MarkdownRenderer-74ysuomr.js} +18 -18
  224. package/static/dist/assets/OAuthSignIn-i4flsuq2.js +1 -0
  225. package/static/dist/assets/QueueCard-msz9wd1m.js +1 -0
  226. package/static/dist/assets/ResourceSwitch-b70zg4xd.js +1 -0
  227. package/static/dist/assets/RightPanel-f5v61m8j.js +1 -0
  228. package/static/dist/assets/Select-f3l897pt.js +1 -0
  229. package/static/dist/assets/SessionListPanel-brnzacw9.js +1 -0
  230. package/static/dist/assets/SettingsLayout-f4akmrt2.js +1 -0
  231. package/static/dist/assets/States-msohx3c0.js +1 -0
  232. package/static/dist/assets/TerminalPanel-bnu5xawo.js +16 -0
  233. package/static/dist/assets/Toaster-d6col3ch.js +1 -0
  234. package/static/dist/assets/_app-lrjgufcy.js +1 -0
  235. package/static/dist/assets/{_app.ext._extensionId-na62087t.js → _app.ext._extensionId-k3xitxr1.js} +1 -1
  236. package/static/dist/assets/_app.groups-bt4wdwnd.js +1 -0
  237. package/static/dist/assets/{_app.index-jypgdqoi.js → _app.index-n3otiki0.js} +1 -1
  238. package/static/dist/assets/{_app.insights-kabejdtm.js → _app.insights-b0mzlh6m.js} +1 -1
  239. package/static/dist/assets/{_app.kanban-m19kfcmx.js → _app.kanban-d923g7j5.js} +1 -1
  240. package/static/dist/assets/{_app.logs-iw4m96sz.js → _app.logs-donegue1.js} +1 -1
  241. package/static/dist/assets/{_app.memory-jq5frwcg.js → _app.memory-hdnled08.js} +1 -1
  242. package/static/dist/assets/{_app.profiles-kwa3m7rp.js → _app.profiles-fumot3jk.js} +1 -1
  243. package/static/dist/assets/{_app.session._sessionId-o5lyeipj.js → _app.session._sessionId-crmdl2ux.js} +1 -1
  244. package/static/dist/assets/{_app.settings-ckl8hdll.js → _app.settings-jui8iesz.js} +1 -1
  245. package/static/dist/assets/_app.settings._section-do84hsqw.js +3 -0
  246. package/static/dist/assets/{_app.skills-n016rihd.js → _app.skills-heqcn21m.js} +1 -1
  247. package/static/dist/assets/_app.tasks-jiudtutt.js +1 -0
  248. package/static/dist/assets/{_app.todos-btew5v2s.js → _app.todos-bl6kk2zq.js} +1 -1
  249. package/static/dist/assets/{_app.workspaces-lnfk95ch.js → _app.workspaces-frvh3o7w.js} +1 -1
  250. package/static/dist/assets/_delete-qnxuo87s.js +1 -0
  251. package/static/dist/assets/{abnfDiagram-VCTEODGH-dttheegb.js → abnfDiagram-VCTEODGH-dppg3yfx.js} +1 -1
  252. package/static/dist/assets/{architecture-7GRP2DOG-ic435919.js → architecture-7GRP2DOG-gbajejh3.js} +1 -1
  253. package/static/dist/assets/{architectureDiagram-5GKGNRK7-8r3glgiq.js → architectureDiagram-5GKGNRK7-bzrxyais.js} +1 -1
  254. package/static/dist/assets/archive-yhdyz231.js +1 -0
  255. package/static/dist/assets/autoReadClaim-nlyv8tu9.js +1 -0
  256. package/static/dist/assets/{blockDiagram-I7D4REHJ-jenyos6c.js → blockDiagram-I7D4REHJ-gmk9koab.js} +1 -1
  257. package/static/dist/assets/{c4Diagram-7LVT6UL2-nzlx7yc4.js → c4Diagram-7LVT6UL2-bfqiqqcz.js} +1 -1
  258. package/static/dist/assets/channel-grt3rob4.js +1 -0
  259. package/static/dist/assets/{chunk-4HAMMTFA-g0cru63b.js → chunk-4HAMMTFA-i9s6h4wv.js} +1 -1
  260. package/static/dist/assets/{chunk-75Z2AOVW-7rkswkjw.js → chunk-75Z2AOVW-gnt6pnso.js} +1 -1
  261. package/static/dist/assets/{chunk-DU6HZSFF-fn73jzdo.js → chunk-DU6HZSFF-gq439wot.js} +3 -3
  262. package/static/dist/assets/{chunk-F27PBJKO-oey8e72m.js → chunk-F27PBJKO-wvx90pbt.js} +1 -1
  263. package/static/dist/assets/{chunk-GMAD6QVW-l2a32wiy.js → chunk-GMAD6QVW-mc2gu30k.js} +1 -1
  264. package/static/dist/assets/{chunk-GVQU2GXP-o9dwzh8h.js → chunk-GVQU2GXP-f8fxa2ym.js} +1 -1
  265. package/static/dist/assets/{chunk-IMKFNOWR-eblwj20b.js → chunk-IMKFNOWR-lnsl31hj.js} +1 -1
  266. package/static/dist/assets/{chunk-L3NEJ4N5-o2mufspb.js → chunk-L3NEJ4N5-kbfdidwu.js} +1 -1
  267. package/static/dist/assets/{chunk-OSK3NFVY-ijp9pw29.js → chunk-OSK3NFVY-dvxsduj6.js} +1 -1
  268. package/static/dist/assets/{chunk-P2QGCYS3-hs9hqwl4.js → chunk-P2QGCYS3-ivo3i1wf.js} +1 -1
  269. package/static/dist/assets/{chunk-POPQ4Y6H-bp9rsqez.js → chunk-POPQ4Y6H-i0gfu0hx.js} +1 -1
  270. package/static/dist/assets/{chunk-PWAF6VOD-brkprov6.js → chunk-PWAF6VOD-jb0fdyb0.js} +1 -1
  271. package/static/dist/assets/{chunk-SHT3W25Y-gmpv0pxz.js → chunk-SHT3W25Y-b7ou2xsp.js} +1 -1
  272. package/static/dist/assets/{chunk-SVP7TREG-oldm08fu.js → chunk-SVP7TREG-e2v7me5v.js} +1 -1
  273. package/static/dist/assets/{chunk-TICWLB2K-ooqilfv7.js → chunk-TICWLB2K-e5zlai62.js} +1 -1
  274. package/static/dist/assets/classDiagram-ZZMXUADV-nnsp49jr.js +1 -0
  275. package/static/dist/assets/classDiagram-v2-VYDZK3BY-nnsp49jr.js +1 -0
  276. package/static/dist/assets/completionAudio-c5at041z.js +1 -0
  277. package/static/dist/assets/{copy-jo006coq.js → copy-jj3oiw13.js} +1 -1
  278. package/static/dist/assets/{cynefin-OW5HDTMX-d47op7qs.js → cynefin-OW5HDTMX-n5n1ck70.js} +1 -1
  279. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-doa7594y.js → cynefinDiagram-5FMLGOSQ-b33npu4f.js} +1 -1
  280. package/static/dist/assets/{dagre-GXQ25YYZ-os768dp4.js → dagre-GXQ25YYZ-miwvae07.js} +1 -1
  281. package/static/dist/assets/{diagram-S7CK7UJ4-fyi81nxd.js → diagram-S7CK7UJ4-j8fphsp4.js} +1 -1
  282. package/static/dist/assets/{diagram-UQ7AKVKN-j3exggaq.js → diagram-UQ7AKVKN-5cixo166.js} +1 -1
  283. package/static/dist/assets/{diagram-VSXAHHWV-omo1en2l.js → diagram-VSXAHHWV-ii3bf92m.js} +1 -1
  284. package/static/dist/assets/{diagram-VX7I27RA-oro2cyu0.js → diagram-VX7I27RA-b3cfgx81.js} +1 -1
  285. package/static/dist/assets/{diagram-Z3DM3KII-byt9vdb7.js → diagram-Z3DM3KII-bey9lqr8.js} +1 -1
  286. package/static/dist/assets/{dist-etpoyscq.js → dist-cb8um5dh.js} +4 -4
  287. package/static/dist/assets/{dist-crc46di9.js → dist-kpg5ccm9.js} +1 -1
  288. package/static/dist/assets/{ebnfDiagram-PWID7BFC-ee3haugh.js → ebnfDiagram-PWID7BFC-2m4wrnqc.js} +1 -1
  289. package/static/dist/assets/{erDiagram-RLTQ6QDP-d1e93yff.js → erDiagram-RLTQ6QDP-kak5te0n.js} +1 -1
  290. package/static/dist/assets/{eventmodeling-NTZA5JFV-i1ihb40c.js → eventmodeling-NTZA5JFV-ojcc486t.js} +1 -1
  291. package/static/dist/assets/flowDiagram-HODETNUW-kxr9sicu.js +1 -0
  292. package/static/dist/assets/folder-plus-fk6j7tlv.js +1 -0
  293. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-m7g0jud4.js → ganttDiagram-EL5Y4UJY-k6nfmhrh.js} +1 -1
  294. package/static/dist/assets/getPseudoElementBounds-mwj3vqni.js +1 -0
  295. package/static/dist/assets/{gitGraph-4MIJSDKK-hzdj07yy.js → gitGraph-4MIJSDKK-bxq1lbhy.js} +1 -1
  296. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-dm9agbna.js → gitGraphDiagram-WWUBYQGX-ehvoankt.js} +1 -1
  297. package/static/dist/assets/group_discussions-fk5hry4l.js +1 -0
  298. package/static/dist/assets/{highlighted-body-KPVGNVTW-mmgz2czu.js → highlighted-body-KPVGNVTW-nr4nfdq7.js} +1 -1
  299. package/static/dist/assets/{host-fr6lni1p.js → host-dhgqiozp.js} +1 -1
  300. package/static/dist/assets/index-hx7z4wdj.js +13 -0
  301. package/static/dist/assets/index-o8ebuc5x.css +2 -0
  302. package/static/dist/assets/{info-A6RAGUB7-lll1dqmm.js → info-A6RAGUB7-dtsj0ybw.js} +1 -1
  303. package/static/dist/assets/{infoDiagram-27XIBGKW-k7esc639.js → infoDiagram-27XIBGKW-jena90ao.js} +1 -1
  304. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-lgr6k9wo.js → ishikawaDiagram-5VMMS53U-kia6bn5u.js} +1 -1
  305. package/static/dist/assets/{journeyDiagram-3NMN7TZE-ndmbxuqk.js → journeyDiagram-3NMN7TZE-ipsa6icb.js} +1 -1
  306. package/static/dist/assets/{kanban-definition-UXKFOSKX-mjxym0jp.js → kanban-definition-UXKFOSKX-moxx59kp.js} +1 -1
  307. package/static/dist/assets/katex-ic33v820.js +257 -0
  308. package/static/dist/assets/katex-qcv7xo0t.css +1 -0
  309. package/static/dist/assets/{lazyRouteComponent-cwb6l7xh.js → lazyRouteComponent-i74ujrfk.js} +1 -1
  310. package/static/dist/assets/{line-mtr5k6il.js → line-lgrkg9no.js} +1 -1
  311. package/static/dist/assets/link-2-fp49mwl2.js +1 -0
  312. package/static/dist/assets/{link-iadw4ghw.js → link-es18mse1.js} +2 -2
  313. package/static/dist/assets/{locale-cs-n41hptse.js → locale-cs-brltdkcp.js} +1 -1
  314. package/static/dist/assets/{locale-de-k7ht47ew.js → locale-de-h6e9oq6v.js} +1 -1
  315. package/static/dist/assets/{locale-es-ih078lco.js → locale-es-oklmh80f.js} +1 -1
  316. package/static/dist/assets/{locale-fr-ojabnf41.js → locale-fr-b17ozoi2.js} +1 -1
  317. package/static/dist/assets/{locale-it-kb96jufy.js → locale-it-whe01eef.js} +1 -1
  318. package/static/dist/assets/{locale-ja-jpsp3xs1.js → locale-ja-g1s0rtpc.js} +1 -1
  319. package/static/dist/assets/{locale-pl-dbap4leu.js → locale-pl-d9p3lqcb.js} +1 -1
  320. package/static/dist/assets/{locale-pt-nci7w72x.js → locale-pt-l75on74f.js} +1 -1
  321. package/static/dist/assets/{locale-ru-soghe4cs.js → locale-ru-wl3mbsaw.js} +1 -1
  322. package/static/dist/assets/{locale-tr-ks00mu68.js → locale-tr-cz87itrq.js} +1 -1
  323. package/static/dist/assets/{locale-vi-ij7twfm6.js → locale-vi-elqj1y4k.js} +1 -1
  324. package/static/dist/assets/{locale-zh-Hant-feakwr7a.js → locale-zh-Hant-hf8gqm7d.js} +1 -1
  325. package/static/dist/assets/{locale-zh-ren0vjyv.js → locale-zh-cdckwb0u.js} +1 -1
  326. package/static/dist/assets/login-o6gfl4gy.js +1 -0
  327. package/static/dist/assets/mermaid-HWGCJPDP-n2kbzsao.js +1 -0
  328. package/static/dist/assets/{mermaid-parser.core-k91vdnvi.js → mermaid-parser.core-fflovwf2.js} +3 -3
  329. package/static/dist/assets/{mindmap-definition-YA3MSWOX-ehztfea4.js → mindmap-definition-YA3MSWOX-ic8l9whi.js} +1 -1
  330. package/static/dist/assets/onboarding-bxm7gdrr.js +1 -0
  331. package/static/dist/assets/{packet-AYTQ26CC-ok2xrblz.js → packet-AYTQ26CC-ntci3088.js} +1 -1
  332. package/static/dist/assets/{pegDiagram-XKGWAZYB-ec3rpj0m.js → pegDiagram-XKGWAZYB-e3btz04w.js} +1 -1
  333. package/static/dist/assets/{pie-WAS4IAKB-iwkir23u.js → pie-WAS4IAKB-o2dc7l36.js} +1 -1
  334. package/static/dist/assets/{pieDiagram-E7YTZNPT-fcpqpekh.js → pieDiagram-E7YTZNPT-gro55rrw.js} +1 -1
  335. package/static/dist/assets/presence-lq6m12ga.js +1 -0
  336. package/static/dist/assets/prompt_queue_cancelled-cebcuagu.js +1 -0
  337. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-lqsync43.js → quadrantDiagram-AXDQQJYC-fxulmd7d.js} +1 -1
  338. package/static/dist/assets/queryKeys-cnvn6pea.js +9 -0
  339. package/static/dist/assets/{radar-RG4KPBEZ-hje4jbk6.js → radar-RG4KPBEZ-9pcospra.js} +1 -1
  340. package/static/dist/assets/{railroad-74A4TZTK-gll9n6qi.js → railroad-74A4TZTK-nzdga12j.js} +1 -1
  341. package/static/dist/assets/{railroad-abnf-HS5TGJTU-o6h6lpn4.js → railroad-abnf-HS5TGJTU-ep3ytel0.js} +1 -1
  342. package/static/dist/assets/{railroad-ebnf-LZEXJU2U-juaefj6o.js → railroad-ebnf-LZEXJU2U-iw7uc1wy.js} +1 -1
  343. package/static/dist/assets/{railroad-peg-WCYAUIDC-cgfhvpah.js → railroad-peg-WCYAUIDC-fo3b3gme.js} +1 -1
  344. package/static/dist/assets/{railroadDiagram-O6MQD6OU-lp3w7awf.js → railroadDiagram-O6MQD6OU-lxpxf8f0.js} +1 -1
  345. package/static/dist/assets/{refresh-cw-iccm7a4e.js → refresh-cw-d14h79x5.js} +1 -1
  346. package/static/dist/assets/rename-ccd52yws.js +1 -0
  347. package/static/dist/assets/{requirementDiagram-BXWQKSXE-ha8eibcf.js → requirementDiagram-BXWQKSXE-lrozucd2.js} +1 -1
  348. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-oxf31pr9.js → sankeyDiagram-P5KCCOFB-iusxy9mq.js} +1 -1
  349. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-jiq8lhyo.js → sequenceDiagram-WJ2MYXX4-o987q8ti.js} +1 -1
  350. package/static/dist/assets/{share._token-o76ki0ly.js → share._token-bfw7f9m5.js} +1 -1
  351. package/static/dist/assets/sliders-horizontal-l65hoa3x.js +1 -0
  352. package/static/dist/assets/{stateDiagram-D77RDMKH-f3fslnon.js → stateDiagram-D77RDMKH-hh23v7y5.js} +1 -1
  353. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-jukr0d8h.js +1 -0
  354. package/static/dist/assets/{swimlanes-42K2YHIH-k1hmk7jf.js → swimlanes-42K2YHIH-gj2t3rm8.js} +1 -1
  355. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ik9m9j2m.js +8 -0
  356. package/static/dist/assets/{timeline-definition-24CTP7MA-n3ncfy9r.js → timeline-definition-24CTP7MA-84s2w2sr.js} +1 -1
  357. package/static/dist/assets/toast-gqqcvxiy.js +56 -0
  358. package/static/dist/assets/{treeView-Q6P3EWNA-l3y2pejt.js → treeView-Q6P3EWNA-cmuj50l7.js} +1 -1
  359. package/static/dist/assets/{treemap-WGGIJYW6-jown9axh.js → treemap-WGGIJYW6-dpjlg0xc.js} +1 -1
  360. package/static/dist/assets/tts-jw84jlqy.js +1 -0
  361. package/static/dist/assets/{useForm-o4uu74mx.js → useForm-lxzhiqao.js} +1 -1
  362. package/static/dist/assets/{useParams-ftsveu84.js → useParams-dt6gkoq7.js} +1 -1
  363. package/static/dist/assets/{useSearch-crqueqga.js → useSearch-o8t49csk.js} +1 -1
  364. package/static/dist/assets/useTranscript-gx9umcc2.js +1 -0
  365. package/static/dist/assets/{vennDiagram-4TSXK5OY-dh59uq1c.js → vennDiagram-4TSXK5OY-g9g5o8vy.js} +1 -1
  366. package/static/dist/assets/{wardley-WFR3VGLG-e6d74b0j.js → wardley-WFR3VGLG-ij35obrl.js} +1 -1
  367. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-hnofh78f.js → wardleyDiagram-VM6X3IG4-f9my7q7w.js} +1 -1
  368. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-bpymjelb.js → xychartDiagram-S5SC5T6Z-olqx1s1p.js} +1 -1
  369. package/static/dist/index.html +1 -1
  370. package/static/dist/sw.js +1 -1
  371. package/static/dist/assets/AppShell-3isgvoro.js +0 -8
  372. package/static/dist/assets/Button-f4n6dapf.js +0 -1
  373. package/static/dist/assets/ChatPage-k7b6xfax.js +0 -4
  374. package/static/dist/assets/ConnectTargets-juqvt5lm.js +0 -1
  375. package/static/dist/assets/Dialog-hta5utr3.js +0 -1
  376. package/static/dist/assets/Field-b6ez48oz.js +0 -1
  377. package/static/dist/assets/HubRoute-iwvso2tz.js +0 -2
  378. package/static/dist/assets/Markdown-jdeth7zq.js +0 -2
  379. package/static/dist/assets/OAuthSignIn-bpd8hom3.js +0 -1
  380. package/static/dist/assets/ResourceSwitch-odi6dy2o.js +0 -1
  381. package/static/dist/assets/RightPanel-eu6enlo6.js +0 -1
  382. package/static/dist/assets/Select-kr07928w.js +0 -1
  383. package/static/dist/assets/SessionListPanel-etb2i54l.js +0 -1
  384. package/static/dist/assets/SettingsLayout-eu3xxp23.js +0 -1
  385. package/static/dist/assets/States-icab19yg.js +0 -1
  386. package/static/dist/assets/TerminalPanel-hngmsr8b.js +0 -16
  387. package/static/dist/assets/Toaster-nb2uzjw1.js +0 -1
  388. package/static/dist/assets/_app-ga1moszl.js +0 -1
  389. package/static/dist/assets/_app.settings._section-dtdjk98a.js +0 -3
  390. package/static/dist/assets/_app.tasks-n8zuqsqe.js +0 -1
  391. package/static/dist/assets/archive-il7c6053.js +0 -1
  392. package/static/dist/assets/cancel-bsnfo36u.js +0 -1
  393. package/static/dist/assets/channel-dsbtk01y.js +0 -1
  394. package/static/dist/assets/classDiagram-ZZMXUADV-fvgcv24g.js +0 -1
  395. package/static/dist/assets/classDiagram-v2-VYDZK3BY-fvgcv24g.js +0 -1
  396. package/static/dist/assets/flowDiagram-HODETNUW-jahfpiod.js +0 -1
  397. package/static/dist/assets/folder-plus-ivoglq98.js +0 -1
  398. package/static/dist/assets/index-73649w7o.js +0 -10
  399. package/static/dist/assets/index-lhf1fsdf.css +0 -2
  400. package/static/dist/assets/katex-cbdd1ohw.css +0 -1
  401. package/static/dist/assets/katex-pbij2oo6.js +0 -257
  402. package/static/dist/assets/login-lkhtzfcl.js +0 -1
  403. package/static/dist/assets/mermaid-HWGCJPDP-jx0q5dm2.js +0 -1
  404. package/static/dist/assets/onboarding-f67z0a2r.js +0 -1
  405. package/static/dist/assets/queryKeys-ed4n2egc.js +0 -9
  406. package/static/dist/assets/refresh-i9ya9dvl.js +0 -1
  407. package/static/dist/assets/sliders-horizontal-ddcs88av.js +0 -1
  408. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hlt6yphw.js +0 -1
  409. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hd5t9tnt.js +0 -8
  410. package/static/dist/assets/toast-liparz2j.js +0 -56
@@ -1,5 +1,6 @@
1
- import { type ContextDetail } from '@maudecode/talaria-web-contracts';
1
+ import { type CheckpointDiff, type SessionActivityPhase, type ContextDetail } from '@maudecode/talaria-web-contracts';
2
2
  /** One native-owner seam. Talaria observes its history and never settles it into a local Session. */
3
+ import type { QueueAdmissionFence } from './admission.js';
3
4
  import type { StartupTiming } from '../startup-timing.js';
4
5
  import { type ExecutionModes, type GatewayCreateParams, type GatewaySessionParams, type GatewaySessionResult } from '@maudecode/talaria-web-contracts';
5
6
  import type { SidecarLike } from '../sidecar/client.js';
@@ -8,6 +9,12 @@ import type { SessionChannels, StreamRegistry } from './streams.js';
8
9
  import type { RunJournal } from './journal.js';
9
10
  import { SessionEventBus } from './events.js';
10
11
  type Row = Record<string, unknown>;
12
+ interface Target {
13
+ sid: string;
14
+ profile: string;
15
+ home: string;
16
+ key: string;
17
+ }
11
18
  /** The scope remains verifiable after a server restart, before a journal lookup or stream subscription. */
12
19
  export declare const gatewayStreamVisible: (stream: string, home: string) => boolean;
13
20
  export declare class GatewaySessions {
@@ -22,6 +29,7 @@ export declare class GatewaySessions {
22
29
  private rememberModelChange;
23
30
  private currentModelChange;
24
31
  constructor(deps: {
32
+ onWebCompletion?: (profile: string, sessionId: string, identity: string) => void;
25
33
  service: SessionService;
26
34
  sidecar: () => SidecarLike | null;
27
35
  registry: StreamRegistry;
@@ -39,6 +47,7 @@ export declare class GatewaySessions {
39
47
  private noticeState;
40
48
  private nativeNotices;
41
49
  private changed;
50
+ private nativeTodo;
42
51
  /** One shared connection, acquired by viewers and run projections, with no local Agent admission. */
43
52
  private transport;
44
53
  private lease;
@@ -49,7 +58,56 @@ export declare class GatewaySessions {
49
58
  } | null>;
50
59
  private target;
51
60
  contextDetail(sid: string, expectedKey: string): Promise<ContextDetail>;
61
+ private activityPhaseFor;
62
+ activityPhase(sid: string, profile: string): Promise<SessionActivityPhase | null | undefined>;
52
63
  isOwned(sid: string): Promise<boolean>;
64
+ /** Exact native receipt lookup for a durable queue step, never another submit. */
65
+ queueReceipt(sid: string, admissionId?: string): Promise<GatewaySessionResult | null>;
66
+ checkpointDiff(sid: string): Promise<CheckpointDiff | null>;
67
+ private terminalKey;
68
+ terminal(sid: string): Promise<{
69
+ target: Target;
70
+ snap: {
71
+ session_id: string;
72
+ stored_session_id: string;
73
+ messages: Record<string, unknown>[];
74
+ message_count: number;
75
+ running: boolean;
76
+ authority_epoch: number;
77
+ replay_epoch: string;
78
+ last_sequence: number;
79
+ subscription_id: string;
80
+ revision: number;
81
+ execution_generation: number;
82
+ pending: {
83
+ admission_id: string;
84
+ sequence: number;
85
+ status: "unknown" | "terminal" | "queued" | "started";
86
+ outcome: string | null;
87
+ authority_epoch: number;
88
+ execution_generation: number | null;
89
+ controls?: string[] | undefined;
90
+ steering?: boolean | undefined;
91
+ text?: string | undefined;
92
+ input_id?: string | undefined;
93
+ }[];
94
+ prompts: Record<string, unknown>[];
95
+ info: Record<string, unknown>;
96
+ plan_gauge?: {
97
+ id: string;
98
+ label: string;
99
+ used_bp: number;
100
+ resets_at_ms: number | null;
101
+ } | null | undefined;
102
+ reactions_supported?: boolean | undefined;
103
+ todo_state?: {
104
+ todos: Record<string, unknown>[];
105
+ revision?: number | undefined;
106
+ } | null | undefined;
107
+ };
108
+ key: string;
109
+ } | null>;
110
+ capturedCommand(sid: string, key: string, command: string): Promise<NonNullable<GatewaySessionResult['shell']>>;
53
111
  export(sid: string, format: NonNullable<GatewaySessionParams['format']>): Promise<NonNullable<GatewaySessionResult['export']> | null>;
54
112
  private createCall;
55
113
  /** TAL-1040: normal always runs; the bypass modes need an owner that freezes them before any Agent import. */
@@ -62,10 +120,11 @@ export declare class GatewaySessions {
62
120
  private call;
63
121
  private attachment;
64
122
  private contextDetailKey;
123
+ private reactionView;
65
124
  private view;
66
125
  project(base: Row, limit?: number | null, before?: number | null, withMessages?: boolean): Promise<Row>;
67
126
  /** Called before the direct-chat admission path, including for an already materialized foreign session. */
68
- submit(sid: string, body: Row, timing?: StartupTiming): Promise<Row | null>;
127
+ submit(sid: string, body: Row, timing?: StartupTiming, fence?: QueueAdmissionFence): Promise<Row | null>;
69
128
  action(sid: string, params: Omit<GatewaySessionParams, 'session_id' | 'profile_home'>): Promise<GatewaySessionResult>;
70
129
  /** The display preview is redacted; an explicit retry returns the original text for review, like direct-chat retry. */
71
130
  retry(sid: string, admissionId: string, generation: number): Promise<string>;
@@ -1,10 +1,13 @@
1
- import { unavailableContextDetail } from '@maudecode/talaria-web-contracts';
1
+ import { applyPlanGauge } from './session.js';
2
+ import { reasoningProjection } from './reasoning-display.js';
3
+ import { CHECKPOINT_DIFF_MAX_BYTES, ReactionEmojiSchema, unavailableContextDetail } from '@maudecode/talaria-web-contracts';
4
+ import { checkpointDiffFiles } from '../workspace/rollback.js';
2
5
  import { createHash, randomUUID } from 'node:crypto';
3
6
  import { OWNER_EXPORT_MAX_BYTES, SessionNoticeSchema, GatewayClarifyBatchSchema, GatewaySessionResultSchema } from '@maudecode/talaria-web-contracts';
4
7
  import { redactNestedMessageContainers, publicToolFrame, redactString } from '../redact.js';
5
8
  import { str } from '../util.js';
6
9
  import { PendingPrompts } from './pending.js';
7
- import { wrapExportHtml } from './export.js';
10
+ import { wrapExportHtml, renderSessionHtml, renderSessionMarkdown } from './export.js';
8
11
  import { clarifyReply } from './pending.js';
9
12
  import { HttpFailure } from './service.js';
10
13
  import { SessionNotices } from './notices.js';
@@ -14,6 +17,7 @@ import { pendingUserRow } from './merge.js';
14
17
  import { ReasoningTitleTracker, reasoningEventPayload } from './reasoning-titles.js';
15
18
  import { CANONICAL_READ_ONLY_REASON, WEB_DIAGNOSTIC_REQUEST_PREFIX } from './state-db.js';
16
19
  import { toolProgress } from './tool-display.js';
20
+ import { deriveTodoState, normalizeTodoSnapshot } from './todo.js';
17
21
  const ownerStreamPrefix = (home) => `owner-${createHash('sha256').update(home).digest('hex').slice(0, 16)}-`;
18
22
  const ownerStateId = (identity) => `owner-${createHash('sha256').update(identity).digest('hex')}`;
19
23
  /** The scope remains verifiable after a server restart, before a journal lookup or stream subscription. */
@@ -36,8 +40,12 @@ function retryText(admission) {
36
40
  /** Steering belongs to the current turn; it must never replace that turn's transcript anchor. */
37
41
  const runningAdmission = (snapshot) => snapshot.pending.find((p) => p.status === 'started' && !p.steering);
38
42
  const sameExecution = (a, b) => a.authority_epoch === b.authority_epoch && a.replay_epoch === b.replay_epoch && a.execution_generation === b.execution_generation;
43
+ /** Todo revisions belong to a single owner execution; sequence also fences explicit null clears. */
44
+ const newerTodo = (a, b) => Object.hasOwn(a, 'todo_state') && sameExecution(a, b)
45
+ && (a.last_sequence > b.last_sequence || !Object.hasOwn(b, 'todo_state') || a.todo_state != null && b.todo_state != null && (a.todo_state.revision ?? 0) > (b.todo_state.revision ?? 0));
39
46
  /** Native counters and the owner's compact turn-end usage share one existing Web usage shape. */
40
- function ownerUsage(data) {
47
+ function ownerUsage(payload, complete = false) {
48
+ const data = payload.usage && typeof payload.usage === 'object' ? { ...payload, ...payload.usage } : payload;
41
49
  const fields = {
42
50
  input_tokens: ['prompt_tokens', 'prompt', 'input_tokens', 'input'], output_tokens: ['completion_tokens', 'completion', 'output_tokens', 'output'],
43
51
  cache_read_tokens: ['cache_read_tokens'], cache_write_tokens: ['cache_write_tokens'],
@@ -45,6 +53,7 @@ function ownerUsage(data) {
45
53
  context_length: ['context_length', 'context_max'], cache_hit_percent: ['cache_hit_pct'], tps: ['tokens_per_s', 'avg_tps'],
46
54
  };
47
55
  const usage = {};
56
+ applyPlanGauge(usage, data, complete || typeof data.calls === 'number' || typeof data.api_calls === 'number');
48
57
  for (const [field, keys] of Object.entries(fields)) {
49
58
  const value = keys.map((key) => data[key]).find((value) => typeof value === 'number' && Number.isFinite(value) && value >= 0);
50
59
  if (value !== undefined)
@@ -121,20 +130,27 @@ export class GatewaySessions {
121
130
  changed(target) {
122
131
  this.deps.channels.emit(target.sid, 'session-updated', { session_id: target.sid, source: 'native_owner' }, target.profile);
123
132
  }
133
+ nativeTodo(target, snapshot) {
134
+ const observed = this.observations.get(target.key)?.snapshot;
135
+ const current = observed && (newerTodo(observed, snapshot) || observed.authority_epoch > snapshot.authority_epoch
136
+ || observed.authority_epoch === snapshot.authority_epoch && observed.replay_epoch === snapshot.replay_epoch && observed.execution_generation > snapshot.execution_generation) ? observed : snapshot;
137
+ return Object.hasOwn(current, 'todo_state')
138
+ ? normalizeTodoSnapshot(current.todo_state ?? { todos: [] }) : deriveTodoState(current.messages);
139
+ }
124
140
  /** One shared connection, acquired by viewers and run projections, with no local Agent admission. */
125
141
  transport(target, base, snapshot) {
126
142
  const prior = this.observations.get(target.key);
127
143
  if (prior && !prior.controller.signal.aborted)
128
144
  return prior;
129
- const observation = { controller: new AbortController(), snapshot, replaying: true, completion: null, listeners: new Set(), leases: 0, ended: Promise.resolve({ state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null }) };
145
+ const observation = { controller: new AbortController(), snapshot, todoSequence: 0, replaying: true, completion: null, listeners: new Set(), leases: 0, ended: Promise.resolve({ state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null }) };
130
146
  this.observations.set(target.key, observation);
131
147
  this.noticeState(target, snapshot);
132
148
  observation.ended = (async () => {
133
- const showReasoning = await this.deps.showReasoning(target.home).catch(() => false);
134
149
  const sidecar = this.deps.sidecar();
135
150
  if (!sidecar || observation.controller.signal.aborted)
136
151
  return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
137
- return sidecar.call('gateway.session', { profile_home: target.home, session_id: target.sid, action: 'watch', show_reasoning: showReasoning }, {
152
+ // Keep reasoning available when Show changes during this observation; delivery applies the current preference.
153
+ return sidecar.call('gateway.session', { profile_home: target.home, session_id: target.sid, action: 'watch', show_reasoning: true }, {
138
154
  signal: observation.controller.signal, timeoutMs: 0,
139
155
  onStream: (frame) => {
140
156
  if (observation.controller.signal.aborted || this.observations.get(target.key) !== observation)
@@ -143,10 +159,18 @@ export class GatewaySessions {
143
159
  const result = GatewaySessionResultSchema.parse(frame.data);
144
160
  if (result.snapshot?.session_id !== target.sid)
145
161
  return;
162
+ // Reaction readback invalidates display data only. Queued native turn events still own settlement.
163
+ if (frame.data.reaction_only === true) {
164
+ this.changed(target);
165
+ return;
166
+ }
146
167
  const completed = observation.completion?.data;
147
168
  if (result.replay_gap || completed && (completed.authority_epoch !== result.snapshot.authority_epoch || completed.replay_epoch !== result.snapshot.replay_epoch))
148
169
  observation.completion = null;
149
- observation.snapshot = result.snapshot;
170
+ const prior = observation.snapshot;
171
+ if (!sameExecution(prior, result.snapshot))
172
+ observation.todoSequence = 0;
173
+ observation.snapshot = newerTodo(prior, result.snapshot) ? { ...result.snapshot, todo_state: prior.todo_state, last_sequence: prior.last_sequence } : result.snapshot;
150
174
  observation.replaying = frame.data.replaying === true;
151
175
  this.noticeState(target, result.snapshot, result.replay_gap === true);
152
176
  if ((result.snapshot.running || result.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')) && !this.watches.has(target.key))
@@ -159,7 +183,23 @@ export class GatewaySessions {
159
183
  else if (frame.event === 'event') {
160
184
  const event = frame.data;
161
185
  const data = (event.payload ?? {});
162
- if (event.type === 'notification.show' || event.type === 'notification.clear') {
186
+ if (event.type === 'todo.updated') {
187
+ const snap = observation.snapshot;
188
+ if (event.session_id !== target.sid || event.replay_epoch !== snap.replay_epoch
189
+ || event.authority_epoch !== snap.authority_epoch || event.execution_generation !== snap.execution_generation
190
+ || !Number.isSafeInteger(event.seq) || Number(event.seq) <= observation.todoSequence
191
+ || !Array.isArray(data.todos) || !Number.isSafeInteger(data.revision) || Number(data.revision) < 0
192
+ || snap.todo_state != null && Number(data.revision) <= (snap.todo_state.revision ?? -1))
193
+ return;
194
+ // A retained event may be newer than the transcript-derived plan in an attach snapshot.
195
+ // Explicit null still fences all events at or before that snapshot's sequence.
196
+ if (Number(event.seq) <= snap.last_sequence && snap.todo_state === null)
197
+ return;
198
+ observation.todoSequence = Number(event.seq);
199
+ observation.snapshot = { ...snap, todo_state: { todos: data.todos, revision: Number(data.revision) }, last_sequence: Math.max(snap.last_sequence, Number(event.seq)) };
200
+ this.changed(target);
201
+ }
202
+ else if (event.type === 'notification.show' || event.type === 'notification.clear') {
163
203
  const snap = observation.snapshot;
164
204
  const state = this.noticeState(target, snap);
165
205
  if (event.session_id !== target.sid || event.replay_epoch !== snap.replay_epoch
@@ -180,7 +220,12 @@ export class GatewaySessions {
180
220
  else if (event.type === 'session.info') {
181
221
  if (data.authority_epoch !== observation.snapshot.authority_epoch || Number(data.execution_generation) < observation.snapshot.execution_generation)
182
222
  return;
183
- observation.snapshot = { ...observation.snapshot, ...data };
223
+ const nextGeneration = Number(data.execution_generation) > observation.snapshot.execution_generation;
224
+ if (nextGeneration)
225
+ observation.todoSequence = 0;
226
+ observation.snapshot = { ...observation.snapshot, ...data,
227
+ ...(nextGeneration && observation.snapshot.todo_state ? { todo_state: { ...observation.snapshot.todo_state, revision: 0 } } : {}),
228
+ };
184
229
  if ((observation.snapshot.running || observation.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')) && !this.watches.has(target.key))
185
230
  this.watch(target, base, observation.snapshot);
186
231
  this.changed(target);
@@ -228,14 +273,20 @@ export class GatewaySessions {
228
273
  signal.addEventListener('abort', release, { once: true });
229
274
  return { release: () => { signal.removeEventListener('abort', release); release(); }, ended: observation.ended };
230
275
  }
231
- async target(sid, profile = this.deps.activeProfile()) {
276
+ async target(sid, profile = this.deps.activeProfile(), requireKnownOwnership = false) {
232
277
  if (sid.length === 0 || sid !== sid.trim())
233
278
  return null;
234
- const owner = (await this.deps.service.stateDbSources([sid], profile))?.get(sid);
279
+ const sources = await this.deps.service.stateDbSources([sid], profile);
280
+ if (requireKnownOwnership && !sources)
281
+ throw new HttpFailure(503, 'Agent session ownership could not be verified');
282
+ const owner = sources?.get(sid);
235
283
  if (typeof owner !== 'object')
236
284
  return null;
237
- if (owner.reason)
285
+ if (owner.reason) {
286
+ if (requireKnownOwnership)
287
+ throw new HttpFailure(403, owner.reason);
238
288
  return null;
289
+ }
239
290
  const home = this.deps.profileHome(profile);
240
291
  return { sid, profile, home, key: JSON.stringify([home, sid]) };
241
292
  }
@@ -247,17 +298,87 @@ export class GatewaySessions {
247
298
  const result = await this.call(target, { action: 'context_detail' });
248
299
  return profile === this.deps.activeProfile() && result.state === 'attached' && this.contextDetailKey(target, result.snapshot) === expectedKey ? result.context_detail ?? unavailableContextDetail('unsupported') : unavailableContextDetail('changed');
249
300
  }
301
+ activityPhaseFor(result, target) {
302
+ if (result.state !== 'attached' || !result.snapshot)
303
+ return 'stale';
304
+ const pending = this.prompts(result.snapshot, target.sid, this.batch(target));
305
+ if (pending.approvalPending(target.sid).pending)
306
+ return 'waiting_for_approval';
307
+ if (pending.clarifyPending(target.sid).pending)
308
+ return 'waiting_for_input';
309
+ if (result.snapshot.running || result.snapshot.pending.some((entry) => entry.status === 'queued' || entry.status === 'started'))
310
+ return 'running';
311
+ return result.snapshot.pending.some((entry) => entry.status === 'unknown') ? 'stale' : null;
312
+ }
313
+ async activityPhase(sid, profile) {
314
+ const target = await this.target(sid, profile);
315
+ return target ? this.activityPhaseFor(await this.call(target, { action: 'snapshot' }), target) : undefined;
316
+ }
250
317
  async isOwned(sid) { return (await this.target(sid)) !== null; }
318
+ /** Exact native receipt lookup for a durable queue step, never another submit. */
319
+ async queueReceipt(sid, admissionId) {
320
+ const target = await this.target(sid);
321
+ return target ? this.call(target, admissionId ? { action: 'receipt', admission_id: admissionId } : { action: 'snapshot' }) : null;
322
+ }
323
+ async checkpointDiff(sid) {
324
+ const profile = this.deps.activeProfile();
325
+ const target = await this.target(sid, profile);
326
+ if (!target)
327
+ return null;
328
+ const result = await this.call(target, { action: 'checkpoint_diff' });
329
+ const read = profile === this.deps.activeProfile() && result.state === 'attached' ? result.checkpoint_diff : undefined;
330
+ const comparison = read ? { ...read.comparison } : { provenance: 'native_owner', baseline: 'earliest_retained_project_checkpoint', available: false, reason: 'owner_unavailable', truncated: false };
331
+ if (read && (Buffer.byteLength(JSON.stringify(read.diff), 'utf8') + Buffer.byteLength(JSON.stringify(read.stat), 'utf8') - 4 > CHECKPOINT_DIFF_MAX_BYTES)) {
332
+ comparison.available = false;
333
+ comparison.reason = 'payload_too_large';
334
+ }
335
+ const diff = comparison.available ? read?.diff ?? '' : '';
336
+ const files = checkpointDiffFiles(diff);
337
+ return { checkpoint: 'earliest-retained', workspace: '', diff: diff.trimEnd(), files_changed: files, total_changes: files.length, comparison };
338
+ }
339
+ terminalKey(target, snap) {
340
+ return ownerStateId(JSON.stringify([target.key, snap.session_id, snap.authority_epoch, snap.replay_epoch, snap.info.cwd]));
341
+ }
342
+ async terminal(sid) {
343
+ const target = await this.target(sid, this.deps.activeProfile(), true);
344
+ if (!target)
345
+ return null;
346
+ const result = await this.call(target, { action: 'terminal_info' });
347
+ const snap = result.snapshot;
348
+ if (target.profile !== this.deps.activeProfile() || result.state !== 'attached' || snap?.session_id !== sid)
349
+ throw new HttpFailure(409, 'The native owner cannot run captured commands. Reopen the terminal after checking the gateway.', { code: 'owner_shell_unavailable' });
350
+ return { target, snap, key: this.terminalKey(target, snap) };
351
+ }
352
+ async capturedCommand(sid, key, command) {
353
+ const selected = await this.terminal(sid);
354
+ if (key !== selected?.key)
355
+ throw new HttpFailure(409, 'The native owner changed. Reopen the terminal before running a command.');
356
+ const { target, snap } = selected;
357
+ const result = await this.call(target, { action: 'shell_exec', command, authority_epoch: snap.authority_epoch, replay_epoch: snap.replay_epoch });
358
+ if (result.state !== 'attached' || !result.shell) {
359
+ // Only allowlisted native policy refusals are safe to show. A transport failure may have executed.
360
+ const messages = {
361
+ unsupported_terminal_backend: 'Captured commands require the native owner’s local terminal backend.',
362
+ cwd_unavailable: 'The native workspace no longer exists.', dangerous_command: 'The native owner refused this command.',
363
+ permission_denied: 'The native owner denied this command.', command_timeout: 'The command timed out on the native owner.',
364
+ owner_changed: 'The native owner changed. Reopen the terminal.',
365
+ };
366
+ throw new HttpFailure(409, messages[result.reason ?? ''] ?? 'The command outcome is unknown. Check the native workspace before running it again.', { code: 'owner_shell_failed' });
367
+ }
368
+ return { stdout: redactString(result.shell.stdout, true), stderr: redactString(result.shell.stderr, true), code: result.shell.code };
369
+ }
251
370
  async export(sid, format) {
252
371
  const target = await this.target(sid);
253
372
  if (!target)
254
373
  return null;
255
374
  const redact = this.deps.redactEnabled();
256
- const result = await this.call(target, { action: 'export', format, redact });
375
+ const show = await this.deps.showReasoning(target.home).catch(() => false);
376
+ const requestedFormat = show ? format : 'json';
377
+ const result = await this.call(target, { action: 'export', format: requestedFormat, redact });
257
378
  const value = result.export;
258
379
  if (result.reason === 'export_too_large')
259
380
  throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
260
- if (result.state !== 'attached' || value?.format !== format) {
381
+ if (result.state !== 'attached' || value?.format !== requestedFormat) {
261
382
  throw new HttpFailure(409, 'The Agent owner cannot export this chat. Check that its gateway is running and supports transcript export.', { code: 'owner_export_unavailable' });
262
383
  }
263
384
  if (Buffer.byteLength(value.content, 'utf8') > OWNER_EXPORT_MAX_BYTES)
@@ -265,16 +386,21 @@ export class GatewaySessions {
265
386
  let content;
266
387
  try {
267
388
  // The owner redacts HTML's structured transcript before rendering. A shell/text redactor corrupts its markup.
268
- content = format === 'html' ? wrapExportHtml(value.content) : format === 'json'
269
- ? JSON.stringify(redactNestedMessageContainers(JSON.parse(value.content), redact), null, 2)
270
- : redactString(value.content, redact);
389
+ if (!show) {
390
+ const document = reasoningProjection(redactNestedMessageContainers(JSON.parse(value.content), redact), false);
391
+ content = format === 'html' ? renderSessionHtml(document) : format === 'markdown' ? renderSessionMarkdown(document) : JSON.stringify(document, null, 2);
392
+ }
393
+ else
394
+ content = format === 'html' ? wrapExportHtml(value.content) : format === 'json'
395
+ ? JSON.stringify(redactNestedMessageContainers(JSON.parse(value.content), redact), null, 2)
396
+ : redactString(value.content, redact);
271
397
  }
272
398
  catch {
273
399
  throw new HttpFailure(409, 'The Agent owner returned an invalid transcript export', { code: 'owner_export_invalid' });
274
400
  }
275
401
  if (Buffer.byteLength(content, 'utf8') > OWNER_EXPORT_MAX_BYTES)
276
402
  throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
277
- return { ...value, content };
403
+ return { ...value, format, content };
278
404
  }
279
405
  async createCall(params) {
280
406
  const sidecar = this.deps.sidecar();
@@ -292,7 +418,7 @@ export class GatewaySessions {
292
418
  const result = await this.createCall({ profile_home: this.deps.profileHome(profile), probe: true });
293
419
  const reason = result.state === 'attached' ? null : unavailableReason(result);
294
420
  // Owner chats take no file attachments (`submit` refuses them), so a fresh chat in either bypass mode cannot attach.
295
- return { modes: [{ mode: 'normal', available: true, reason: null, can_attach: true }, ...['ignore_config', 'safe'].map((mode) => ({ mode, available: reason === null, reason, can_attach: false }))] };
421
+ return { modes: [{ mode: 'normal', available: true, reason: null, can_attach: true, can_reference: true }, ...['ignore_config', 'safe'].map((mode) => ({ mode, available: reason === null, reason, can_attach: false, can_reference: false }))] };
296
422
  }
297
423
  /**
298
424
  * TAL-1040: the owner mints a diagnostic chat, freezes its bypass in the creation receipt and runs each turn in a fresh
@@ -315,7 +441,7 @@ export class GatewaySessions {
315
441
  if (modelMutation)
316
442
  this.modelMutations.set(target.key, (this.modelMutations.get(target.key) ?? 0) + 1);
317
443
  try {
318
- const result = await sidecar.call('gateway.session', { ...params, profile_home: target.home, session_id: target.sid }, { timeoutMs: params.action === 'mutate' ? 675_000 : 35_000, ...(signal ? { signal } : {}) });
444
+ const result = await sidecar.call('gateway.session', { ...params, profile_home: target.home, session_id: target.sid }, { timeoutMs: params.action === 'mutate' ? 675_000 : params.action === 'shell_exec' ? 40_000 : 35_000, ...(signal ? { signal } : {}) });
319
445
  if (params.action === 'mutate' && params.operation === 'model' && result.snapshot) {
320
446
  const change = modelChange(result.receipt ?? {}, params.payload);
321
447
  // The stream can resolve a deferred pick before its HTTP ACK returns. Keep the later observation.
@@ -362,13 +488,39 @@ export class GatewaySessions {
362
488
  contextDetailKey(target, snapshot) {
363
489
  return snapshot ? ownerStateId(JSON.stringify([target.key, snapshot.authority_epoch, snapshot.replay_epoch, snapshot.revision, snapshot.execution_generation, snapshot.info, snapshot.last_sequence])) : null;
364
490
  }
491
+ reactionView(row, allowed) {
492
+ if (!Number.isSafeInteger(row.row_id) || Number(row.row_id) <= 0 || !['user', 'assistant'].includes(str(row.role)))
493
+ return undefined;
494
+ const authors = new Map();
495
+ for (const raw of Array.isArray(row.reactions) ? row.reactions : []) {
496
+ const reaction = raw;
497
+ const emoji = ReactionEmojiSchema.safeParse(reaction?.emoji);
498
+ if (emoji.success && (reaction.author === 'user' || reaction.author === 'agent'))
499
+ authors.set(reaction.author, emoji.data);
500
+ }
501
+ const state = (selected) => {
502
+ const values = [authors.get('agent'), selected].filter((emoji) => emoji !== undefined && emoji !== null);
503
+ return { selected, items: ReactionEmojiSchema.options.flatMap((emoji) => {
504
+ const count = values.filter((value) => value === emoji).length;
505
+ return count ? [{ emoji, count, mine: selected === emoji }] : [];
506
+ }) };
507
+ };
508
+ const selected = authors.get('user') ?? null;
509
+ return { row_id: Number(row.row_id), state: state(selected), actions: allowed
510
+ ? [...ReactionEmojiSchema.options, ...(selected ? [null] : [])].map((emoji) => ({ emoji, result: state(emoji === selected ? null : emoji) })) : [] };
511
+ }
365
512
  async view(base, result, stream, target, limit = 120, before = null, withMessages = true) {
366
513
  const snapshot = result.snapshot;
367
- const fields = { ...base, owner_attachment: this.attachment({ ...result, model_change: this.currentModelChange(target, snapshot) }), composer_state_key: ownerStateId(target.key), context_detail_key: this.contextDetailKey(target, snapshot), active_stream_id: stream, is_streaming: Boolean(stream) };
514
+ const showReasoning = await this.deps.service.deps.showReasoning?.(target.profile) ?? true;
515
+ const fields = { ...base, plan_gauge: snapshot?.plan_gauge ?? null, show_reasoning: showReasoning, owner_attachment: this.attachment({ ...result, model_change: this.currentModelChange(target, snapshot) }), composer_state_key: ownerStateId(target.key), context_detail_key: this.contextDetailKey(target, snapshot), active_stream_id: stream, is_streaming: Boolean(stream) };
368
516
  if (snapshot) {
369
517
  fields.notices = this.nativeNotices(target, snapshot);
518
+ fields.todo_state = this.nativeTodo(target, snapshot) ?? normalizeTodoSnapshot({ todos: [] });
370
519
  const observed = this.watches.get(target.key)?.snapshot;
371
- const nativeRows = [...snapshot.messages];
520
+ const canReact = snapshot.reactions_supported === true && this.attachment(result).can_submit;
521
+ const nativeRows = snapshot.messages.map(({ reactions, ...row }) => ({ ...row,
522
+ reaction_view: this.reactionView({ ...row, reactions }, canReact),
523
+ }));
372
524
  const active = stream ? runningAdmission(snapshot) : null;
373
525
  let start = active ? nativeRows.findIndex((m) => m.role === 'user' && m.message_id === active.admission_id) : -1;
374
526
  if (active && stream && start < 0) {
@@ -376,7 +528,7 @@ export class GatewaySessions {
376
528
  nativeRows.push({ ...pendingUserRow(active.text ?? '', [], null, str(snapshot.info.source) || 'gateway', stream), message_id: active.admission_id });
377
529
  }
378
530
  const messages = start < 0 ? nativeRows : nativeRows.map((row, index) => index >= start ? { ...row, _turn_id: stream } : row);
379
- const projected = withMessages ? this.deps.service.foreignMessages(messages, base) : [];
531
+ const projected = withMessages ? this.deps.service.foreignMessages(messages, base, showReasoning) : [];
380
532
  const [rows, offset] = messageWindowForDisplay(projected, limit, before);
381
533
  const model = str(snapshot.info.model) || str(base.model) || null;
382
534
  const provider = Object.hasOwn(snapshot.info, 'provider')
@@ -411,7 +563,7 @@ export class GatewaySessions {
411
563
  return this.view(base, result, watch?.stream ?? null, target, limit, before, withMessages);
412
564
  }
413
565
  /** Called before the direct-chat admission path, including for an already materialized foreign session. */
414
- async submit(sid, body, timing) {
566
+ async submit(sid, body, timing, fence) {
415
567
  const target = await this.target(sid);
416
568
  if (!target)
417
569
  return null;
@@ -431,6 +583,8 @@ export class GatewaySessions {
431
583
  throw new HttpFailure(400, 'File attachments are unavailable through this owner connection', { code: 'owner_attachments_unavailable' });
432
584
  // Resolve display state before admission; a failed post-ACK read must never turn accepted work into a refusal.
433
585
  const base = await (timing ? timing.measure('owner_detail', () => this.deps.service.detail(sid, {})) : this.deps.service.detail(sid, {}));
586
+ if (fence && (!this.deps.service.deps.profilesMatch(str(base.profile) || null, fence.profile) || (str(base.project_id) || null) !== fence.project_id || before.snapshot?.authority_epoch !== fence.authority_epoch || before.snapshot.running || before.snapshot.pending.some((p) => p.status !== 'terminal')))
587
+ throw new HttpFailure(409, 'Queue target changed or is busy');
434
588
  const closeSubmit = timing?.begin('owner_submit');
435
589
  const result = await this.call(target, { action: 'submit', request_id: body.submission_id, text });
436
590
  closeSubmit?.(result.receipt ? 'ok' : result.state === 'unavailable' ? 'unknown' : 'refused');
@@ -461,9 +615,24 @@ export class GatewaySessions {
461
615
  throw new HttpFailure(400, 'The workspace must be trusted before selecting it');
462
616
  }
463
617
  }
464
- const result = await this.call(target, params);
618
+ if (params.action === 'react') {
619
+ const current = await this.call(target, { action: 'snapshot' });
620
+ const row = current.snapshot?.messages.find((row) => row.row_id === params.row_id);
621
+ if (!row || current.snapshot?.reactions_supported !== true || !this.attachment(current).can_submit
622
+ || !['user', 'assistant'].includes(str(row.role)))
623
+ throw new HttpFailure(409, 'Reactions are unavailable for this message');
624
+ }
625
+ let result = await this.call(target, params);
626
+ if (params.action === 'react' && result.state === 'unavailable') {
627
+ // A toggle has no idempotency key. Read the owner after a lost ACK; never replay the write.
628
+ result = await this.call(target, { action: 'snapshot' });
629
+ if (result.state !== 'attached' || !result.snapshot)
630
+ throw new HttpFailure(503, 'Could not confirm the reaction. Reconnect to read its current value.', { outcome_unknown: true });
631
+ }
465
632
  if (result.state !== 'attached' || !result.snapshot)
466
633
  throw new HttpFailure(409, 'The owning Agent refused the action', { owner_attachment: this.attachment(result) });
634
+ if (params.action === 'react')
635
+ this.changed(target);
467
636
  this.deps.events.publish('owner_changed', { profile: target.profile, sessionId: sid });
468
637
  return result;
469
638
  }
@@ -600,6 +769,8 @@ export class GatewaySessions {
600
769
  const registry = this.deps.registry;
601
770
  const channel = registry.create(watch.stream, target.sid);
602
771
  registry.registerActiveRun({ stream_id: watch.stream, session_id: target.sid, phase: 'running', started_at: this.deps.now(), workspace: str(base.workspace), model: str(base.model) || null, provider: null, ephemeral: false, origin: 'user' });
772
+ // TAL-1564: the sidebar row turns streaming now, including for an idle observation whose owner just started a run.
773
+ this.deps.events.publish('owner_changed', { profile: target.profile, sessionId: target.sid });
603
774
  let chain = Promise.resolve();
604
775
  let terminal = false;
605
776
  let streamError = null;
@@ -615,9 +786,9 @@ export class GatewaySessions {
615
786
  const journalSession = ownerStateId(target.key);
616
787
  const writer = await this.deps.journal.writer(journalSession, watch.stream);
617
788
  closeWriter = writer;
618
- const showReasoning = await this.deps.showReasoning(target.home).catch(() => false);
619
789
  let completion = null;
620
790
  let replaying = true;
791
+ let liveRunning = false;
621
792
  let usage = {};
622
793
  let reasoning = '';
623
794
  let titles = new ReasoningTitleTracker();
@@ -638,9 +809,9 @@ export class GatewaySessions {
638
809
  await put('tool_progress', { id: call.tid, progress: null });
639
810
  calls.length = 0;
640
811
  };
641
- const resetProjection = async () => { await clearTools(); reasoning = ''; usage = {}; completion = null; titles = new ReasoningTitleTracker(); };
642
- const meter = async (data) => {
643
- usage = { ...usage, ...ownerUsage(data) };
812
+ const resetProjection = async () => { await clearTools(); liveRunning = false; reasoning = ''; usage = {}; completion = null; titles = new ReasoningTitleTracker(); };
813
+ const meter = async (data, complete = false) => {
814
+ usage = { ...usage, ...ownerUsage(data, complete) };
644
815
  if (['input_tokens', 'output_tokens', 'cache_read_tokens', 'cache_write_tokens'].every((key) => typeof usage[key] === 'number'))
645
816
  await put('metering', { session_id: target.sid, usage: { ...usage, estimated_cost: usage.estimated_cost ?? null }, tps: usage.tps ?? null, tps_available: usage.tps !== undefined, estimated: false });
646
817
  };
@@ -652,7 +823,7 @@ export class GatewaySessions {
652
823
  // A new claim may arrive while this turn's receipt is being read. Give it its own projection immediately.
653
824
  if (this.watches.get(target.key) === watch)
654
825
  this.watches.delete(target.key);
655
- registry.retire(watch.stream);
826
+ registry.activeRuns.delete(watch.stream);
656
827
  await clearTools();
657
828
  const current = await this.call(target, { action: 'snapshot' });
658
829
  const rawReceipt = activeAdmission ? (await this.call(target, { action: 'receipt', admission_id: activeAdmission })).receipt : null;
@@ -666,11 +837,17 @@ export class GatewaySessions {
666
837
  // A terminal frame for the previous generation must not overwrite the newer turn's state.
667
838
  const session = current.snapshot && !sameExecution(current.snapshot, observation.snapshot)
668
839
  ? undefined : { ...await this.view(base, current, null, target), ...usage };
840
+ if (session)
841
+ session.activity_phase = await this.deps.service.deps.sessionActivity?.(target.sid, target.profile, { terminalPhase: cancelled ? 'cancelled' : failed ? 'failed' : 'completed' });
669
842
  await put(cancelled ? 'cancel' : failed ? 'apperror' : 'done', { session_id: target.sid,
670
843
  terminal_state: cancelled ? 'cancelled' : failed ? 'error' : 'completed',
671
844
  ...(failed ? refusal ?? { message: 'The owning Agent could not complete this turn', type: current.reason ?? 'owner_turn_failed' } : {}),
672
845
  ...(Object.keys(usage).length ? { usage } : {}),
673
846
  ...(session ? { session } : {}) });
847
+ if (liveRunning && !cancelled && !failed && receipt?.admission_id === activeAdmission && receipt?.authority_epoch === watch.snapshot.authority_epoch
848
+ && receipt.execution_generation === watch.snapshot.execution_generation) {
849
+ this.deps.onWebCompletion?.(target.profile, target.sid, JSON.stringify(['owner', target.sid, watch.snapshot.authority_epoch, watch.snapshot.replay_epoch, watch.snapshot.execution_generation, receipt.admission_id]));
850
+ }
674
851
  await put('stream_end', { session_id: target.sid });
675
852
  watch.controller.abort();
676
853
  };
@@ -700,6 +877,7 @@ export class GatewaySessions {
700
877
  enqueue(async () => {
701
878
  if (frame.event === 'replay_complete') {
702
879
  replaying = false;
880
+ liveRunning ||= watch.snapshot.running;
703
881
  if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
704
882
  await finish();
705
883
  return;
@@ -719,12 +897,15 @@ export class GatewaySessions {
719
897
  if (frame.event === 'snapshot') {
720
898
  const result = GatewaySessionResultSchema.parse(frame.data);
721
899
  replaying = frame.data.replaying === true;
900
+ if (replaying)
901
+ liveRunning = false;
722
902
  if (!result.snapshot)
723
903
  return;
724
904
  if (result.replay_gap || !sameExecution(result.snapshot, watch.snapshot))
725
905
  await resetProjection();
726
906
  await put('session_snapshot', { session: await this.view(base, result, watch.stream, target), replay_gap: result.replay_gap === true });
727
907
  await prompts(result.snapshot);
908
+ liveRunning ||= !replaying && result.snapshot.running;
728
909
  if (!result.snapshot.running && !result.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
729
910
  await finish();
730
911
  return;
@@ -736,6 +917,10 @@ export class GatewaySessions {
736
917
  await put('notices', { session_id: target.sid, notices: this.nativeNotices(target, observation.snapshot) });
737
918
  return;
738
919
  }
920
+ if (kind === 'todo.updated') {
921
+ await put('todo_state', { ...normalizeTodoSnapshot(data), session_id: target.sid, stream_id: watch.stream, source: 'live' });
922
+ return;
923
+ }
739
924
  if (kind === 'request.cancel') {
740
925
  // The owner withdraws a settled, timed-out or interrupted batch from every viewer.
741
926
  if (!watch.batch || watch.batch.request_id !== data.id)
@@ -776,6 +961,7 @@ export class GatewaySessions {
776
961
  if (firstClaim && claimed)
777
962
  activeAdmission = claimed.admission_id;
778
963
  ran ||= data.running === true;
964
+ liveRunning ||= !replaying && data.running === true;
779
965
  if (firstClaim)
780
966
  await put('session_snapshot', { session: await this.view(base, { state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null, restarting: watch.restarting }, watch.stream, target) });
781
967
  if (data.running === false && (ran || !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')))
@@ -786,18 +972,20 @@ export class GatewaySessions {
786
972
  return;
787
973
  if (kind === 'message.delta') {
788
974
  const stable = titles.stableSnapshot(reasoning);
789
- if (stable !== null)
975
+ if (stable !== null && await this.deps.showReasoning(target.home).catch(() => false))
790
976
  await put('reasoning', { text: '', titles: stable });
791
977
  await put('token', { text: str(data.text || data.delta || data.content) });
792
978
  }
793
- else if (kind === 'reasoning.delta' && showReasoning) {
979
+ else if (kind === 'reasoning.delta') {
794
980
  reasoning += str(data.text);
795
- await put('reasoning', titles.prepare(reasoningEventPayload(data.text, reasoning)));
981
+ if (await this.deps.showReasoning(target.home).catch(() => false))
982
+ await put('reasoning', titles.prepare(reasoningEventPayload(data.text, reasoning)));
796
983
  }
797
984
  else if (kind.startsWith('subagent.') && str(data.subagent_id)) {
798
985
  // Reuse the delegate activity row; each child keeps one identity through progress and completion.
799
986
  const complete = kind === 'subagent.complete';
800
- const preview = kind === 'subagent.thinking' && !showReasoning ? '' : str(data.summary || data.tool_preview || data.text);
987
+ const visible = kind !== 'subagent.thinking' || await this.deps.showReasoning(target.home).catch(() => false);
988
+ const preview = visible ? str(data.summary || data.tool_preview || data.text) : '';
801
989
  await put(complete ? 'tool_complete' : 'tool', { id: `owner-subagent-${str(data.subagent_id)}`, name: 'subagent_progress',
802
990
  args: { task: str(data.goal) }, preview: preview || null,
803
991
  ...(complete ? { is_error: data.status !== 'completed', duration: data.duration_seconds } : {}) });
@@ -815,7 +1003,7 @@ export class GatewaySessions {
815
1003
  completion = { admission: activeAdmission, message: data.text, type: 'cron_session_read_only', code: 'cron_session_read_only', retryable: false };
816
1004
  }
817
1005
  if (data.usage && typeof data.usage === 'object')
818
- await meter(data.usage);
1006
+ await meter(data.usage, true);
819
1007
  }
820
1008
  else if (kind === 'tool.start' || kind === 'tool.progress' || kind === 'tool.complete') {
821
1009
  if (event.session_id !== target.sid || event.replay_epoch !== undefined && event.replay_epoch !== watch.snapshot.replay_epoch)