synabun 2.0.9 → 2.0.10

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 (252) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -1
  3. package/THIRD-PARTY-LICENSES.md +46 -4
  4. package/launcher.mjs +9 -3
  5. package/lib/start-launcher.js +6 -1
  6. package/mcp-server/package-lock.json +2 -2
  7. package/mcp-server/package.json +1 -1
  8. package/neural-interface/i18n/en.json +218 -7
  9. package/neural-interface/i18n/pt-BR.json +220 -9
  10. package/neural-interface/lib/account-usage.js +5 -3
  11. package/neural-interface/lib/app-controls-api.js +161 -0
  12. package/neural-interface/lib/assistant-api.js +21 -7
  13. package/neural-interface/lib/assistant-brains/opencode.js +13 -1
  14. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +44 -0
  15. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +57 -0
  16. package/neural-interface/lib/assistant-catalog.js +17 -2
  17. package/neural-interface/lib/assistant-dispatch.js +3 -0
  18. package/neural-interface/lib/assistant-envelope.js +19 -1
  19. package/neural-interface/lib/assistant-runtime.js +127 -8
  20. package/neural-interface/lib/claude-model-catalog.js +64 -14
  21. package/neural-interface/lib/codex-settings-schema.js +109 -47
  22. package/neural-interface/lib/editor-completion-opencode.js +132 -35
  23. package/neural-interface/lib/exec-loop-command.js +8 -1
  24. package/neural-interface/lib/launch-cache.js +293 -0
  25. package/neural-interface/lib/login-start.js +524 -0
  26. package/neural-interface/lib/native-loop-providers.js +18 -3
  27. package/neural-interface/lib/native-loop-runtime.js +19 -0
  28. package/neural-interface/lib/opencode-db-schema.js +75 -0
  29. package/neural-interface/lib/opencode-history.js +16 -1
  30. package/neural-interface/lib/opencode-protocol.js +173 -0
  31. package/neural-interface/lib/opencode-provider-view.js +81 -0
  32. package/neural-interface/lib/opencode-runtime-config.js +10 -3
  33. package/neural-interface/lib/opencode-serve-records.js +606 -0
  34. package/neural-interface/lib/opencode-v2-client.js +33 -6
  35. package/neural-interface/lib/opencode-v2-ws-requests.js +19 -5
  36. package/neural-interface/lib/opencode-worker-activity.js +229 -0
  37. package/neural-interface/lib/opencode2-client.js +760 -0
  38. package/neural-interface/lib/opencode2-proxy.js +116 -0
  39. package/neural-interface/lib/opencode2-translate.js +1008 -0
  40. package/neural-interface/lib/process-identity.js +361 -0
  41. package/neural-interface/lib/session-cache-builder.js +26 -5
  42. package/neural-interface/lib/session-title-generator.js +18 -0
  43. package/neural-interface/lib/style-guide/api.js +4 -3
  44. package/neural-interface/lib/untrusted-file-headers.js +27 -0
  45. package/neural-interface/package-lock.json +1343 -45
  46. package/neural-interface/package.json +5 -1
  47. package/neural-interface/public/index.html +2 -2
  48. package/neural-interface/public/shared/agent-runtime-options.js +55 -11
  49. package/neural-interface/public/shared/assistant/asst-agents-dock.js +172 -17
  50. package/neural-interface/public/shared/assistant/asst-api.js +11 -3
  51. package/neural-interface/public/shared/assistant/asst-brain-picker.js +195 -80
  52. package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
  53. package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
  54. package/neural-interface/public/shared/assistant/asst-menu.js +77 -6
  55. package/neural-interface/public/shared/assistant/asst-panel.js +197 -33
  56. package/neural-interface/public/shared/assistant/asst-rack-styles.js +28 -10
  57. package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
  58. package/neural-interface/public/shared/assistant/asst-render.js +382 -36
  59. package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
  60. package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
  61. package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
  62. package/neural-interface/public/shared/assistant/asst-scenes.js +528 -0
  63. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
  64. package/neural-interface/public/shared/assistant/asst-state.js +14 -0
  65. package/neural-interface/public/shared/assistant/asst-styles.js +43 -0
  66. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +13 -1
  67. package/neural-interface/public/shared/cc-dropdown.js +480 -0
  68. package/neural-interface/public/shared/cdx/cdx-panel.js +13 -1
  69. package/neural-interface/public/shared/cdx/cdx-render.js +15 -3
  70. package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
  71. package/neural-interface/public/shared/cdx/cdx-tabs.js +149 -35
  72. package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
  73. package/neural-interface/public/shared/data-cache.js +223 -0
  74. package/neural-interface/public/shared/desktop-bridge.js +11 -0
  75. package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
  76. package/neural-interface/public/shared/desktop-titlebar.js +214 -28
  77. package/neural-interface/public/shared/desktop-update-view.js +15 -5
  78. package/neural-interface/public/shared/file-links.js +73 -8
  79. package/neural-interface/public/shared/html-shell.js +74 -80
  80. package/neural-interface/public/shared/launch-prefetch.js +59 -0
  81. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
  82. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +7 -2
  83. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
  84. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +93 -2
  85. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +3 -2
  86. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
  87. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
  88. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1 -1
  89. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
  90. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +16 -9
  91. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +60 -0
  92. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +48 -19
  93. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +195 -19
  94. package/neural-interface/public/shared/opencode-providers.js +39 -0
  95. package/neural-interface/public/shared/schedules-view.js +318 -0
  96. package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
  97. package/neural-interface/public/shared/settings/settings-app.js +243 -0
  98. package/neural-interface/public/shared/settings/settings-data.js +88 -0
  99. package/neural-interface/public/shared/settings/settings-ia.js +17 -0
  100. package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
  101. package/neural-interface/public/shared/styles.css +540 -371
  102. package/neural-interface/public/shared/ui-assistant.js +27 -5
  103. package/neural-interface/public/shared/ui-automation-studio.js +67 -27
  104. package/neural-interface/public/shared/ui-bookmarks.js +2 -1
  105. package/neural-interface/public/shared/ui-claude-panel.js +76 -8
  106. package/neural-interface/public/shared/ui-codex-panel.js +1 -0
  107. package/neural-interface/public/shared/ui-detail.js +6 -6
  108. package/neural-interface/public/shared/ui-file-links.js +1 -0
  109. package/neural-interface/public/shared/ui-image-gallery.js +6 -5
  110. package/neural-interface/public/shared/ui-invite.js +18 -2
  111. package/neural-interface/public/shared/ui-link.js +9 -9
  112. package/neural-interface/public/shared/ui-menubar.js +232 -33
  113. package/neural-interface/public/shared/ui-native-loop-router.js +2 -0
  114. package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
  115. package/neural-interface/public/shared/ui-schedules-studio.js +2099 -869
  116. package/neural-interface/public/shared/ui-sessions.js +15 -4
  117. package/neural-interface/public/shared/ui-settings.js +87 -36
  118. package/neural-interface/public/shared/ui-sidebar.js +4 -4
  119. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
  120. package/neural-interface/public/shared/ui-sidepanel-sessions.js +55 -4
  121. package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
  122. package/neural-interface/public/shared/ui-skills.js +70 -12
  123. package/neural-interface/public/shared/ui-sync.js +7 -0
  124. package/neural-interface/public/shared/ui-terminal.js +36 -20
  125. package/neural-interface/public/shared/ui-trash.js +8 -1
  126. package/neural-interface/public/shared/ui-tutorial-steps.js +7 -3
  127. package/neural-interface/public/shared/ui-tutorial.js +15 -5
  128. package/neural-interface/public/shared/ui-update.js +83 -14
  129. package/neural-interface/public/shared/ui-whiteboard.js +2 -1
  130. package/neural-interface/public/variant/2d/main.js +4 -1
  131. package/neural-interface/public/variant/3d/main.js +3 -0
  132. package/neural-interface/public/vendor/highlight/LICENSE +29 -0
  133. package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
  134. package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
  135. package/neural-interface/public/vendor/highlight/manifest.json +5 -0
  136. package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
  137. package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
  138. package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
  139. package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
  140. package/neural-interface/public/vendor/marked/manifest.json +4 -0
  141. package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
  142. package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
  143. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
  144. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
  145. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
  146. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
  147. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
  148. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
  149. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
  150. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
  151. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
  152. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
  153. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
  154. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
  155. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
  156. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
  157. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
  158. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
  159. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
  160. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
  161. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
  162. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
  163. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
  164. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
  165. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
  166. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
  167. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
  168. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
  169. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
  170. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
  171. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
  172. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
  173. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
  174. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
  175. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
  176. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
  177. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
  178. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
  179. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
  180. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
  181. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
  182. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
  183. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
  184. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
  185. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
  186. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
  187. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
  188. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
  189. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
  190. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
  191. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
  192. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
  193. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
  194. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
  195. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
  196. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
  197. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
  198. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
  199. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
  200. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
  201. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
  202. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
  203. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
  204. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
  205. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
  206. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
  207. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
  208. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
  209. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
  210. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
  211. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
  212. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
  213. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
  214. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
  215. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
  216. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
  217. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
  218. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
  219. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
  220. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
  221. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
  222. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
  223. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
  224. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
  225. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
  226. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
  227. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
  228. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
  229. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
  230. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
  231. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
  232. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
  233. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
  234. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
  235. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
  236. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
  237. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
  238. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
  239. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
  240. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
  241. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
  242. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
  243. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
  244. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
  245. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
  246. package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
  247. package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
  248. package/neural-interface/scripts/build-vendor.mjs +84 -3
  249. package/neural-interface/server.js +1099 -286
  250. package/npm-shrinkwrap.json +2 -2
  251. package/package.json +1 -1
  252. package/skills/synabun/modules/schedule.md +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neural-memory-interface",
3
- "version": "2.0.9",
3
+ "version": "2.0.10",
4
4
  "private": true,
5
5
  "description": "Private local SynaBun interface for memory visualization and multi-agent workflows",
6
6
  "license": "Apache-2.0",
@@ -61,9 +61,13 @@
61
61
  "@codemirror/search": "6.7.2",
62
62
  "@codemirror/state": "6.7.6",
63
63
  "@codemirror/view": "6.43.14",
64
+ "@highlightjs/cdn-assets": "11.12.0",
64
65
  "@lezer/highlight": "1.2.5",
65
66
  "@replit/codemirror-indentation-markers": "6.5.3",
66
67
  "esbuild": "^0.28.1",
68
+ "html2canvas": "1.4.1",
69
+ "marked": "14.1.4",
70
+ "mermaid": "11.17.2",
67
71
  "three": "0.169.0"
68
72
  }
69
73
  }
@@ -56,8 +56,8 @@
56
56
  </head>
57
57
  <body>
58
58
 
59
- <!-- html2canvas for card screenshot MCP tool -->
60
- <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js" defer></script>
59
+ <!-- html2canvas for card screenshot MCP tool (vendored: public/vendor/html2canvas/) -->
60
+ <script src="/vendor/html2canvas/html2canvas-1.4.1.min.js" defer></script>
61
61
 
62
62
  <script type="module" src="/variant/3d/main.js"></script>
63
63
  </body>
@@ -1,6 +1,7 @@
1
1
  // Shared launch/runtime metadata for Automation Studio, Schedules Studio,
2
2
  // and agent sidepanels.
3
3
  import { normalizeAutomationSelection } from './automation-context.js';
4
+ import { fetchOpencodeProviders, opencodeProviders } from './opencode-providers.js';
4
5
 
5
6
  export const CLI_PROFILES = [
6
7
  { id: 'claude-code', label: 'Claude Code', desc: 'Anthropic' },
@@ -145,6 +146,27 @@ let _opencodeModelsLoading = null;
145
146
  let _claudeModelsCache = null;
146
147
  let _claudeModelsLoading = null;
147
148
  let _mcpProfilePresets = null;
149
+ let _mcpProfilePresetsLoading = null;
150
+
151
+ // The verified Claude and Codex lists are also kept in sessionStorage (this tab only): after a reload the
152
+ // pickers paint from them at once (a list read back is due, so the first load still asks the server).
153
+ const LIST_STORE_PREFIX = 'synabun:runtime-models:v1:';
154
+ function keepList(key, list) {
155
+ try { if (typeof sessionStorage !== 'undefined') sessionStorage.setItem(LIST_STORE_PREFIX + key, JSON.stringify(list)); } catch { /* full or unavailable */ }
156
+ }
157
+ function keptList(key) {
158
+ try {
159
+ if (typeof sessionStorage === 'undefined') return null;
160
+ const list = JSON.parse(sessionStorage.getItem(LIST_STORE_PREFIX + key) || 'null');
161
+ return Array.isArray(list) && list.length ? list : null;
162
+ } catch { return null; }
163
+ }
164
+ (() => {
165
+ const claude = keptList('claude-code');
166
+ if (claude && !_claudeModelsCache) _claudeModelsCache = claude;
167
+ const codex = keptList('codex:default');
168
+ if (codex && !_codexModelsCache.has('default')) _codexModelsCache.set('default', codex);
169
+ })();
148
170
 
149
171
  function localJsonArray(key) {
150
172
  try {
@@ -287,6 +309,7 @@ export async function fetchCodexModels(force = false, accountId = 'default') {
287
309
  const normalized = mergeCodexModelOptions(models, { fallback: false });
288
310
  _codexModelsCache.set(account, normalized);
289
311
  _modelListAt.set(`codex:${account}`, Date.now());
312
+ if (normalized.length) keepList(`codex:${account}`, normalized);
290
313
  return normalized;
291
314
  } catch {
292
315
  const previous = _codexModelsCache.get(account) || [];
@@ -466,8 +489,8 @@ export async function fetchOpencodeModels(force = false) {
466
489
  if (_opencodeModelsLoading) return _opencodeModelsLoading;
467
490
  _opencodeModelsLoading = (async () => {
468
491
  try {
469
- const resp = await fetch('/api/opencode/providers/full');
470
- const data = await resp.json().catch(() => ({}));
492
+ // The connected providers, from the page's one kept read (opencode-providers.js).
493
+ const data = await fetchOpencodeProviders({ force }).catch(() => ({}));
471
494
  if (!data || data.ok === false) return [];
472
495
  const out = parseOpencodeProviderModels(data);
473
496
  if (out.length) _opencodeModelsCache = out;
@@ -497,6 +520,7 @@ export async function fetchClaudeModels(force = false) {
497
520
  if (models.length && data?.source !== 'fallback') {
498
521
  _claudeModelsCache = models.map(model => ({ ...model, catalogSource: data?.source || 'cli' }));
499
522
  _modelListAt.set('claude-code', Date.now());
523
+ keepList('claude-code', _claudeModelsCache);
500
524
  } else {
501
525
  _claudeModelsCache = verified() || (models.length ? models.map(model => ({ ...model, catalogSource: 'fallback' })) : [...CLAUDE_FALLBACK_MODELS]);
502
526
  }
@@ -524,9 +548,19 @@ export async function ensureModelsForProfile(profileId, force = false, accountId
524
548
  return getModelsForProfile(profileId, accountId);
525
549
  }
526
550
 
551
+ // OpenCode's list parsed from the provider list the page already holds (read at launch, kept across a reload,
552
+ // or by another module): no request, and the hidden models of this window are applied as it is parsed.
553
+ function keptOpencodeModels() {
554
+ const kept = opencodeProviders.peek('');
555
+ if (!kept || kept.ok === false) return null;
556
+ const out = parseOpencodeProviderModels(kept);
557
+ if (out.length) _opencodeModelsCache = out;
558
+ return out;
559
+ }
560
+
527
561
  export function getModelsForProfile(profileId, accountId = 'default') {
528
562
  if (profileId === 'codex') return _codexModelsCache.get(String(accountId || 'default')) || [];
529
- if (profileId === 'opencode') return _opencodeModelsCache || [];
563
+ if (profileId === 'opencode') return _opencodeModelsCache || keptOpencodeModels() || [];
530
564
  if (profileId === 'claude-code') return _claudeModelsCache || [];
531
565
  return STATIC_MODELS[profileId] || [];
532
566
  }
@@ -601,14 +635,21 @@ export function normalizeEffortForProfile(profileId, effort) {
601
635
 
602
636
  export async function fetchMcpProfilePresets(force = false) {
603
637
  if (!force && _mcpProfilePresets) return _mcpProfilePresets;
604
- try {
605
- const resp = await fetch('/api/mcp/profile');
606
- const data = await resp.json().catch(() => ({}));
607
- _mcpProfilePresets = data?.ok && data.presets ? data.presets : {};
608
- return _mcpProfilePresets;
609
- } catch {
610
- return {};
611
- }
638
+ // Callers asking at the same time share one request.
639
+ if (_mcpProfilePresetsLoading) return _mcpProfilePresetsLoading;
640
+ _mcpProfilePresetsLoading = (async () => {
641
+ try {
642
+ const resp = await fetch('/api/mcp/profile');
643
+ const data = await resp.json().catch(() => ({}));
644
+ _mcpProfilePresets = data?.ok && data.presets ? data.presets : {};
645
+ return _mcpProfilePresets;
646
+ } catch {
647
+ return {};
648
+ } finally {
649
+ _mcpProfilePresetsLoading = null;
650
+ }
651
+ })();
652
+ return _mcpProfilePresetsLoading;
612
653
  }
613
654
 
614
655
  export function getCachedMcpProfilePresets() {
@@ -619,6 +660,7 @@ export function clearRuntimeOptionCaches() {
619
660
  _codexModelsCache.clear();
620
661
  _codexModelsLoading.clear();
621
662
  _opencodeModelsCache = null;
663
+ opencodeProviders.invalidate('');
622
664
  _claudeModelsCache = null;
623
665
  _modelListAt.clear();
624
666
  _mcpProfilePresets = null;
@@ -630,3 +672,5 @@ if (typeof document !== 'undefined') {
630
672
  document.addEventListener('ocp-hidden-models-changed', () => { _opencodeModelsCache = null; });
631
673
  document.addEventListener('ocp-providers-changed', () => { _opencodeModelsCache = null; });
632
674
  }
675
+ // A background read of the provider list brought another one: the parsed copy is made again from it.
676
+ opencodeProviders.subscribe(() => { _opencodeModelsCache = null; });
@@ -11,16 +11,28 @@
11
11
  // mount, then sync:sidepanel:run-* and sync:assistant:* bus events. A run
12
12
  // removed here (or in another window: sync:assistant:run-removed) never comes
13
13
  // back from a late event.
14
+ // The head is always on screen while there are runs: beside the summary, one
15
+ // mini scene per working agent (asst-scenes.js; up to three, then "+N"), all
16
+ // moving at once. Open, each working agent's row has a lane: its mini scene
17
+ // and current step. A mini scene or a lane brings that run's card into view
18
+ // in the transcript (hooks.onReveal). hooks.onRunChange hears every change
19
+ // to a run, whatever its source, so the transcript's card follows the tray.
14
20
 
15
21
  import { on } from '../state.js';
16
22
  import { getProviderMeta } from '../provider-icons.js';
17
23
  import { listAssistantRuns } from './asst-api.js';
18
24
  import { buildRunCard, tickRunCard, updateRunCard } from './asst-render.js';
25
+ import { awaitsAnswer, compactActivity, isLivePhase, phaseLine, sceneFor, sceneSvg, stageLabel, stagePhase, stepLine } from './asst-scenes.js';
26
+ import { injectSceneStyles } from './asst-scene-styles.js';
27
+ import { plural } from './asst-tool-kinds.js';
19
28
  import { isRemovableRun, isRunIdle, isTerminalRunStatus, mergeRunDescriptor, runFromPayload, runNeedsAttention, sortRuns } from './asst-state.js';
20
29
 
21
30
  const TICK_MS = 5000;
22
31
  const SHOW_ALL_LIMIT = 40;
23
32
  const RECENT_WINDOW_MS = 6 * 60 * 60 * 1000;
33
+ const MINI_LIMIT = 3; // mini scenes in the head, then "+N"
34
+ const SCENE_DWELL_MS = 2500; // a scene the activity picked stays at least this long
35
+ const WORKING_PHASES = new Set(['queued', 'starting', 'working']); // live and not waiting on you (asst-scenes.js stagePhase)
24
36
 
25
37
  function el(tag, className, text) {
26
38
  const node = document.createElement(tag);
@@ -36,11 +48,12 @@ function esc(value) {
36
48
  /**
37
49
  * createAgentsDock(hostEl, hooks)
38
50
  * hooks: { t, sessionId, onFocus(runId), onStop(runId), onRead(runId), onEscalate(runId, target), onStopAll(),
39
- * onRemove(runId), onClearFinished(runIds),
51
+ * onRemove(runId), onClearFinished(runIds), onReveal(runId), onRunChange(run),
40
52
  * open, showAll, onToggle(open), onShowAllChange(showAll),
41
- * onCountChange({ total, active, attention, visible }) }
53
+ * onCountChange({ total, active, attention, answer, idle, working, waiting, visible }) }
42
54
  */
43
55
  export function createAgentsDock(hostEl, hooks = {}) {
56
+ injectSceneStyles();
44
57
  const t = (key, fallback, params) => {
45
58
  const v = typeof hooks.t === 'function' ? hooks.t(key, params) : undefined;
46
59
  if (v && v !== key && typeof v === 'string') return v;
@@ -53,6 +66,7 @@ export function createAgentsDock(hostEl, hooks = {}) {
53
66
  root.innerHTML = `
54
67
  <div class="asst-dock-head">
55
68
  <button type="button" class="asst-dock-toggle" aria-expanded="false" aria-controls="${bodyId}"><span class="asst-dock-chev" aria-hidden="true">&#x203A;</span><span class="asst-dock-title">${esc(t('assistant.dock.title', 'Agents'))}</span><span class="asst-dock-summary"></span></button>
69
+ <div class="asst-dock-minis" role="group" aria-label="${esc(t('assistant.dock.working', 'Agents at work'))}"></div>
56
70
  <span class="asst-dock-spacer"></span>
57
71
  <button type="button" class="asst-tb-btn asst-dock-showall" aria-pressed="false" hidden>${esc(t('assistant.dock.showAll', 'Show all'))}</button>
58
72
  <button type="button" class="asst-tb-btn asst-dock-clear" hidden>${esc(t('assistant.dock.clearFinished', 'Clear finished'))}</button>
@@ -64,6 +78,7 @@ export function createAgentsDock(hostEl, hooks = {}) {
64
78
 
65
79
  const toggle = root.querySelector('.asst-dock-toggle');
66
80
  const summaryEl = root.querySelector('.asst-dock-summary');
81
+ const minisEl = root.querySelector('.asst-dock-minis');
67
82
  const showAllBtn = root.querySelector('.asst-dock-showall');
68
83
  const stopAllBtn = root.querySelector('.asst-dock-stopall');
69
84
  const clearBtn = root.querySelector('.asst-dock-clear');
@@ -72,6 +87,9 @@ export function createAgentsDock(hostEl, hooks = {}) {
72
87
  const runs = new Map(); // runId → descriptor
73
88
  const cards = new Map(); // runId → element
74
89
  const removed = new Set(); // runIds the user removed: late events never revive them
90
+ const activities = new Map(); // runId → what its worker does now, compact ({ kind, name, step, at }), while the run lasts
91
+ const minis = new Map(); // runId → its mini scene in the head
92
+ let moreBtn = null;
75
93
  let open = hooks.open === true;
76
94
  let showAll = hooks.showAll === true;
77
95
  let ticker = null;
@@ -96,20 +114,31 @@ export function createAgentsDock(hostEl, hooks = {}) {
96
114
  return {
97
115
  total: list.length,
98
116
  active: list.filter(r => !isTerminalRunStatus(r.status)).length,
99
- attention: list.filter(runNeedsAttention).length,
100
- idle: list.filter(isRunIdle).length,
117
+ // Waiting on you, whatever for (a permission, a route card, your answer); `answer` is the part that
118
+ // needs your answer, as its lane says (asst-scenes.js awaitsAnswer: a turn that ended asking, a question
119
+ // mid-turn), and a warm worker that asked is never counted idle.
120
+ attention: list.filter(r => runNeedsAttention(r) || awaitsAnswer(r)).length,
121
+ answer: list.filter(awaitsAnswer).length,
122
+ idle: list.filter(r => isRunIdle(r) && !awaitsAnswer(r)).length,
101
123
  finished: list.length - list.filter(r => !isTerminalRunStatus(r.status)).length,
124
+ // The session's status reads these (asst-state.js sessionStatus): agents at work (queued for a free slot,
125
+ // starting, in a turn) keep it working after its own turn ended; agents waiting on you make it need you.
126
+ working: list.filter(r => WORKING_PHASES.has(stagePhase(r))).length,
127
+ waiting: list.filter(r => stagePhase(r) === 'waiting').length,
102
128
  visible: list.length > 0,
103
129
  };
104
130
  }
105
131
 
132
+ /** "2 running · 1 idle · 1 needs approval": each count in its own plural form (`key.one` / `key.other`, asst-tool-kinds.js plural). */
106
133
  function summaryText(c) {
107
134
  const bits = [];
108
135
  const running = c.active - c.attention - c.idle;
109
- if (running > 0) bits.push(t('assistant.dock.running', '{n} running', { n: running }));
110
- if (c.idle > 0) bits.push(t('assistant.dock.idle', '{n} idle', { n: c.idle }));
111
- if (c.attention > 0) bits.push(t('assistant.dock.needsApproval', '{n} needs approval', { n: c.attention }));
112
- if (!bits.length && c.total) bits.push(t('assistant.dock.done', '{n} finished', { n: c.total }));
136
+ if (running > 0) bits.push(plural(t, 'assistant.dock.running', running, '{count} running', '{count} running'));
137
+ if (c.idle > 0) bits.push(plural(t, 'assistant.dock.idle', c.idle, '{count} idle', '{count} idle'));
138
+ const approval = c.attention - (c.answer || 0);
139
+ if (approval > 0) bits.push(plural(t, 'assistant.dock.needsApproval', approval, '{count} needs approval', '{count} need approval'));
140
+ if (c.answer > 0) bits.push(plural(t, 'assistant.dock.needsAnswer', c.answer, '{count} waiting for your answer', '{count} waiting for your answer'));
141
+ if (!bits.length && c.total) bits.push(plural(t, 'assistant.dock.done', c.total, '{count} finished', '{count} finished'));
113
142
  return bits.join(' · ');
114
143
  }
115
144
 
@@ -131,18 +160,21 @@ export function createAgentsDock(hostEl, hooks = {}) {
131
160
  if (destroyed) return;
132
161
  const list = visibleRuns();
133
162
  const seen = new Set();
134
- const frag = document.createDocumentFragment();
163
+ // Reconciled in place: a row that keeps its place keeps its node (and its mini scene keeps moving).
164
+ let at = 0;
135
165
  for (const run of list) {
136
166
  seen.add(run.runId);
137
167
  let card = cards.get(run.runId);
138
168
  if (!card) { card = buildRunCard(run, cardOpts()); cards.set(run.runId, card); }
139
169
  else updateRunCard(card, run, cardOpts());
140
170
  card.setAttribute('role', 'listitem');
141
- frag.appendChild(card);
171
+ syncLane(card, run);
172
+ if (body.children[at] !== card) body.insertBefore(card, body.children[at] || null);
173
+ at += 1;
142
174
  }
143
175
  for (const [runId, card] of cards) { if (!seen.has(runId)) { card.remove(); cards.delete(runId); } }
144
- body.innerHTML = '';
145
- body.appendChild(frag);
176
+ while (body.children.length > at) body.lastElementChild.remove();
177
+ renderMinis();
146
178
 
147
179
  const c = counts();
148
180
  root.hidden = c.total === 0;
@@ -159,18 +191,126 @@ export function createAgentsDock(hostEl, hooks = {}) {
159
191
  syncTicker();
160
192
  }
161
193
 
194
+ // ── Working agents at a glance: mini scenes in the head, a lane per open row ──
195
+ const workingRuns = () => sortRuns([...runs.values()]).filter(r => isLivePhase(stagePhase(r)));
196
+
197
+ /** "Coding · Settings: App controls section · 3 min" (the stage's own name). */
198
+ function labelOf(run, scene, phase) {
199
+ const from = new Date(run.startedAt || run.createdAt || 0).getTime();
200
+ return stageLabel({ scene, phase, title: run.title || run.task || run.runId, ms: from ? Date.now() - from : 0, run }, t);
201
+ }
202
+
203
+ /** Draw `scene` into `host` (an SVG of its own), unless the one there was picked under the dwell. */
204
+ function paintScene(node, host, run, phase) {
205
+ const now = Date.now();
206
+ const scene = sceneFor(run, activities.get(run.runId), now);
207
+ if (node.dataset.scene !== scene && (!node.dataset.scene || node.dataset.scene === 'generic' || now - (node._sceneAt || 0) >= SCENE_DWELL_MS)) {
208
+ host.innerHTML = sceneSvg(scene, { mini: true });
209
+ node.dataset.scene = scene;
210
+ node._sceneAt = now;
211
+ }
212
+ node.dataset.phase = phase;
213
+ host.firstElementChild?.toggleAttribute('data-live', phase !== 'waiting');
214
+ return node.dataset.scene;
215
+ }
216
+
217
+ function reveal(runId) {
218
+ if (runId) hooks.onReveal?.(runId);
219
+ }
220
+
221
+ function renderMinis() {
222
+ const live = workingRuns();
223
+ const shown = live.slice(0, MINI_LIMIT);
224
+ const keep = new Set(shown.map(r => r.runId));
225
+ for (const [runId, node] of minis) if (!keep.has(runId)) { node.remove(); minis.delete(runId); }
226
+ shown.forEach((run, i) => {
227
+ let node = minis.get(run.runId);
228
+ if (!node) {
229
+ node = el('button', 'asst-dock-mini');
230
+ node.type = 'button';
231
+ node.dataset.runId = run.runId;
232
+ node.addEventListener('click', (e) => { e.stopPropagation(); reveal(node.dataset.runId); });
233
+ minis.set(run.runId, node);
234
+ }
235
+ const phase = stagePhase(run);
236
+ const scene = paintScene(node, node, run, phase);
237
+ const label = labelOf(run, scene, phase);
238
+ node.setAttribute('aria-label', t('assistant.dock.reveal', '{label}. Show it in the conversation', { label }));
239
+ node.setAttribute('data-tooltip', label);
240
+ if (minisEl.children[i] !== node) minisEl.insertBefore(node, minisEl.children[i] || null);
241
+ });
242
+ const extra = live.length - shown.length;
243
+ if (extra > 0) {
244
+ if (!moreBtn) {
245
+ moreBtn = el('button', 'asst-dock-more');
246
+ moreBtn.type = 'button';
247
+ moreBtn.addEventListener('click', (e) => { e.stopPropagation(); setOpen(true); });
248
+ }
249
+ moreBtn.textContent = `+${extra}`;
250
+ const more = extra === 1 ? t('assistant.dock.more.one', '{count} more agent at work: show the list', { count: extra }) : t('assistant.dock.more.other', '{count} more agents at work: show the list', { count: extra });
251
+ moreBtn.setAttribute('aria-label', more);
252
+ moreBtn.setAttribute('data-tooltip', more);
253
+ if (minisEl.lastElementChild !== moreBtn) minisEl.appendChild(moreBtn);
254
+ } else moreBtn?.remove();
255
+ }
256
+
257
+ /** An open row's lane while its agent works: its mini scene and current step; a click shows its card. */
258
+ function syncLane(card, run) {
259
+ let lane = card.querySelector(':scope > .asst-run-lane');
260
+ const phase = stagePhase(run);
261
+ if (!isLivePhase(phase)) { lane?.remove(); return; }
262
+ if (!lane) {
263
+ lane = el('button', 'asst-run-lane');
264
+ lane.type = 'button';
265
+ lane.innerHTML = '<span class="asst-run-lane-scene" aria-hidden="true"></span><span class="asst-run-lane-step"></span>';
266
+ lane.addEventListener('click', (e) => { e.stopPropagation(); reveal(card.dataset.runId); });
267
+ const meta = card.querySelector(':scope > .asst-run-meta');
268
+ if (meta) meta.after(lane); else card.appendChild(lane);
269
+ }
270
+ const scene = paintScene(lane, lane.querySelector('.asst-run-lane-scene'), run, phase);
271
+ const step = phase === 'working' ? (stepLine(activities.get(run.runId), t) || phaseLine(phase, run, scene, t)) : phaseLine(phase, run, scene, t);
272
+ const stepEl = lane.querySelector('.asst-run-lane-step');
273
+ if (stepEl.textContent !== step) stepEl.textContent = step;
274
+ lane.setAttribute('aria-label', t('assistant.dock.reveal', '{label}. Show it in the conversation', { label: labelOf(run, scene, phase) }));
275
+ }
276
+
277
+ /** The worker's provider events say what it does now: its mini scene and lane follow. Kept compact, and only while the run lasts. */
278
+ function setRunActivity(runId, activity) {
279
+ if (!runId || !runs.has(runId)) return;
280
+ const run = runs.get(runId);
281
+ const next = isTerminalRunStatus(run.status) ? null : compactActivity(activity, t);
282
+ if (next) activities.set(runId, next); else activities.delete(runId);
283
+ const card = cards.get(runId);
284
+ if (card) syncLane(card, run);
285
+ if (minis.has(runId)) renderMinis();
286
+ }
287
+
162
288
  function syncTicker() {
163
- const needs = open && !root.hidden && [...runs.values()].some(r => !isTerminalRunStatus(r.status));
164
- if (needs && !ticker) ticker = setInterval(() => { for (const [runId, card] of cards) tickRunCard(card, runs.get(runId)); }, TICK_MS);
289
+ // Open: the rows' clocks; collapsed with agents at work: their mini scenes' names (whole minutes) and steps.
290
+ const needs = !root.hidden && (open || minis.size > 0) && [...runs.values()].some(r => !isTerminalRunStatus(r.status));
291
+ if (needs && !ticker) {
292
+ ticker = setInterval(() => {
293
+ if (open) for (const [runId, card] of cards) { const run = runs.get(runId); tickRunCard(card, run); if (run) syncLane(card, run); }
294
+ renderMinis();
295
+ }, TICK_MS);
296
+ }
165
297
  if (!needs && ticker) { clearInterval(ticker); ticker = null; }
166
298
  }
167
299
 
300
+ /** Every change to a run, whatever its source, reaches the panel (its transcript card follows). */
301
+ function changed(run) {
302
+ if (!run) return;
303
+ try { hooks.onRunChange?.(run); } catch { /* the panel is gone */ }
304
+ }
305
+
168
306
  function upsertRun(run) {
169
307
  const descriptor = runFromPayload(run) || run;
170
308
  if (!belongs(descriptor)) return null;
171
309
  const merged = mergeRunDescriptor(runs.get(descriptor.runId), descriptor);
172
310
  runs.set(descriptor.runId, merged);
311
+ if (isTerminalRunStatus(merged.status)) activities.delete(merged.runId); // the run is over: so is what it was doing
173
312
  render();
313
+ changed(merged);
174
314
  return merged;
175
315
  }
176
316
 
@@ -180,6 +320,7 @@ export function createAgentsDock(hostEl, hooks = {}) {
180
320
  for (const runId of Array.isArray(runIds) ? runIds : [runIds]) {
181
321
  if (!runId) continue;
182
322
  removed.add(runId);
323
+ activities.delete(runId);
183
324
  if (runs.delete(runId)) changed = true;
184
325
  }
185
326
  if (changed) render();
@@ -192,6 +333,7 @@ export function createAgentsDock(hostEl, hooks = {}) {
192
333
  const next = { ...current, ...patch, updatedAt: new Date().toISOString() };
193
334
  runs.set(runId, next);
194
335
  render();
336
+ changed(next);
195
337
  return next;
196
338
  }
197
339
 
@@ -220,14 +362,23 @@ export function createAgentsDock(hostEl, hooks = {}) {
220
362
  listed.add(id);
221
363
  return true;
222
364
  });
223
- for (const run of list) { const d = runFromPayload(run) || run; if (belongs(d)) runs.set(d.runId, mergeRunDescriptor(runs.get(d.runId), d)); }
365
+ const merged = [];
366
+ for (const run of list) {
367
+ const d = runFromPayload(run) || run;
368
+ if (!belongs(d)) continue;
369
+ const next = mergeRunDescriptor(runs.get(d.runId), d);
370
+ runs.set(d.runId, next);
371
+ if (isTerminalRunStatus(next.status)) activities.delete(d.runId);
372
+ merged.push(next);
373
+ }
224
374
  // When the terminal page was complete, previously known terminal runs
225
375
  // absent from it were removed elsewhere. A run arriving during refresh
226
376
  // must never be pruned by this older snapshot.
227
377
  if (terminal.length < 100) {
228
- for (const runId of knownTerminal) if (!listed.has(runId)) { runs.delete(runId); removed.add(runId); }
378
+ for (const runId of knownTerminal) if (!listed.has(runId)) { runs.delete(runId); removed.add(runId); activities.delete(runId); }
229
379
  }
230
380
  render();
381
+ for (const run of merged) changed(run);
231
382
  } catch { /* offline or not built yet */ }
232
383
  }
233
384
 
@@ -269,13 +420,16 @@ export function createAgentsDock(hostEl, hooks = {}) {
269
420
  }));
270
421
 
271
422
  render();
272
- refresh();
423
+ // The first fetch: what a reload knows about this session's runs (the panel restores their cards from it).
424
+ const ready = Promise.resolve(refresh());
273
425
 
274
426
  return {
275
427
  el: root,
428
+ ready,
276
429
  upsertRun,
277
430
  patchRun,
278
431
  patchUsageRun,
432
+ setRunActivity,
279
433
  dropRuns,
280
434
  getRun: (runId) => runs.get(runId) || null,
281
435
  getRuns: () => sortRuns([...runs.values()]),
@@ -289,6 +443,7 @@ export function createAgentsDock(hostEl, hooks = {}) {
289
443
  destroy() {
290
444
  destroyed = true;
291
445
  if (ticker) clearInterval(ticker);
446
+ activities.clear();
292
447
  unsubs.forEach(off => { try { off(); } catch { /* ignore */ } });
293
448
  root.remove();
294
449
  },
@@ -123,9 +123,12 @@ export async function fetchProjects() {
123
123
 
124
124
  // ── Sessions ─────────────────────────────────
125
125
 
126
- /** `fallback`: a model disabled in Assistant → Models starts on its enabled stand-in (session.fallback says which) instead of a 400. */
127
- export function createAssistantSession({ brain, label, fallback = false } = {}) {
128
- return jsonFetch('/api/assistant/sessions', jsonBody({ brain, label, fallback: fallback === true || undefined }));
126
+ /**
127
+ * `fallback`: a model disabled in Assistant → Models starts on its enabled stand-in (session.fallback says which) instead of a 400.
128
+ * `draft`: the server keeps it in memory, out of every list, until its first prompt stores it; closed or left unused, it is gone.
129
+ */
130
+ export function createAssistantSession({ brain, label, fallback = false, draft = false } = {}) {
131
+ return jsonFetch('/api/assistant/sessions', jsonBody({ brain, label, fallback: fallback === true || undefined, draft: draft === true || undefined }));
129
132
  }
130
133
 
131
134
  export async function listAssistantSessions() {
@@ -149,6 +152,11 @@ export function closeAssistantSession(id) {
149
152
  return jsonFetch(`/api/assistant/sessions/${enc(id)}/close`, jsonBody({}));
150
153
  }
151
154
 
155
+ /** Remove for good (Sessions menu): its running turn and workers stop, then the record and transcript go → { removed, stoppedRuns }. */
156
+ export function removeAssistantSession(id) {
157
+ return jsonFetch(`/api/assistant/sessions/${enc(id)}`, { method: 'DELETE' });
158
+ }
159
+
152
160
  // ── Attachments ──────────────────────────────
153
161
 
154
162
  /**