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
@@ -0,0 +1,528 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Assistant — worker scenes
3
+ // ═══════════════════════════════════════════
4
+ // What a dispatched worker is doing, as a small scene: one per task class
5
+ // (the route's class, else the run's own), plus a generic one. A run card's
6
+ // stage (asst-run-stage.js) shows the full scene beside the mascot; the
7
+ // agents tray shows the mini one; the Assistant's own activity rack shows it
8
+ // too while it works on a direct route (asst-render.js). The scene follows
9
+ // the worker's live tool activity (sync:sidepanel:provider-event: Claude and
10
+ // Codex workers, and a compact copy of an OpenCode worker's tool calls) and
11
+ // the rack's current call: a coding run that drives the browser shows the
12
+ // browser scene for as long as that is what it does, the class is the fallback.
13
+ //
14
+ // DOM-free on purpose (node:test, tests/assistant-worker-stage.test.mjs):
15
+ // the phases, the scene a run shows, its step line and its accessible name,
16
+ // and the scenes' SVG markup as strings. The motion is CSS
17
+ // (asst-scene-styles.js): transform and opacity only, run while the scene
18
+ // carries data-live. Decorative SVG only: the stage is named by stageLabel().
19
+
20
+ import { isRunIdle, isTerminalRunStatus, runNeedsAttention, runStatusFromState, runTone } from './asst-state.js';
21
+ import { kindOf, parseToolName, sayCall, tFallback, verbText } from './asst-tool-kinds.js';
22
+ import { redactSecrets, safeStepInput } from './asst-redact.js';
23
+
24
+ /** The scenes: one per task class SynaBun dispatches, and the generic one. */
25
+ export const SCENES = Object.freeze(['quick', 'code', 'complex', 'review', 'research', 'browser', 'computer', 'automation', 'design', 'image_gen', 'video_gen', 'generic']);
26
+
27
+ /**
28
+ * Per scene: its words (an i18n key and the English), the mascot's pose
29
+ * (synabun-mascot.js MASCOT_POSES; the stage drives `gaze` and `pop` on the
30
+ * ticker's 1 Hz beat, see asst-run-stage.js).
31
+ */
32
+ export const SCENE_SPECS = Object.freeze({
33
+ quick: { label: ['assistant.stage.scene.quick', 'Quick fix'], pose: 'mcp' },
34
+ code: { label: ['assistant.stage.scene.code', 'Coding'], pose: 'shell' },
35
+ complex: { label: ['assistant.stage.scene.complex', 'Complex task'], pose: 'think' },
36
+ review: { label: ['assistant.stage.scene.review', 'Reviewing'], pose: 'read' },
37
+ research: { label: ['assistant.stage.scene.research', 'Researching'], pose: 'search' },
38
+ browser: { label: ['assistant.stage.scene.browser', 'Browsing'], pose: 'web' },
39
+ computer: { label: ['assistant.stage.scene.computer', 'Using the computer'], pose: 'computer', gaze: 'pointer' },
40
+ automation: { label: ['assistant.stage.scene.automation', 'Automating'], pose: 'plan', pop: true },
41
+ design: { label: ['assistant.stage.scene.design', 'Designing'], pose: 'edit' },
42
+ image_gen: { label: ['assistant.stage.scene.image_gen', 'Making an image'], pose: 'watch', gaze: 'canvas' },
43
+ video_gen: { label: ['assistant.stage.scene.video_gen', 'Making a video'], pose: 'watch', gaze: 'strip' },
44
+ generic: { label: ['assistant.stage.scene.generic', 'Working'], pose: 'think' },
45
+ });
46
+
47
+ /** Phases a stage is open and moving (or waiting on you) in; the rest settle it. */
48
+ export const LIVE_PHASES = Object.freeze(['queued', 'starting', 'working', 'waiting']);
49
+ const LIVE = new Set(LIVE_PHASES);
50
+
51
+ /** How long the worker's last tool call speaks for it: the step line, and the scene it implies. */
52
+ export const ACTIVITY_FRESH_MS = 90_000;
53
+
54
+ const str = (v) => (v == null ? '' : String(v));
55
+
56
+ /** The run's task class: its own, else its route's ('' when neither says). */
57
+ export function runTaskClass(run) {
58
+ return str(run?.taskClass || run?.route?.taskClass || '').trim();
59
+ }
60
+
61
+ /** The scene of a task class (chat, unknown or none → generic). */
62
+ export function sceneOfClass(taskClass) {
63
+ const id = str(taskClass).trim();
64
+ return id && id !== 'generic' && Object.hasOwn(SCENE_SPECS, id) ? id : 'generic';
65
+ }
66
+
67
+ /**
68
+ * Where a run stands for its stage: queued | starting | working | waiting
69
+ * (on you: a permission, a question, a route card, or a turn that ended
70
+ * asking you) (live), idle (a warm worker between turns) | done | failed |
71
+ * stopped (settled), or null for no run.
72
+ */
73
+ export function stagePhase(run) {
74
+ if (!run || typeof run !== 'object') return null;
75
+ const status = str(run.status || runStatusFromState(run.state));
76
+ if (status === 'completed') return 'done';
77
+ if (status === 'failed' || status === 'interrupted') return 'failed';
78
+ if (status === 'stopped') return 'stopped';
79
+ if (isTerminalRunStatus(status)) return 'done';
80
+ if (runNeedsAttention(run) || awaitsAnswer({ ...run, status })) return 'waiting';
81
+ if (isRunIdle({ ...run, status })) return 'idle';
82
+ if (status === 'queued' || run.queued === true || run.state === 'queued') return 'queued';
83
+ if (status === 'starting' || run.state === 'starting') return 'starting';
84
+ if (status === 'running') return 'working';
85
+ return null;
86
+ }
87
+
88
+ export const isLivePhase = (phase) => LIVE.has(phase);
89
+
90
+ /**
91
+ * The worker waits on your answer. Either its turn ended asking you something:
92
+ * the dispatcher reports that as a warm run (state and turnState idle) whose
93
+ * outcome (lastResult.status) is needs_input, until a follow-up starts the next
94
+ * turn (state running). Or it asked mid-turn: awaiting_permission with a
95
+ * pending question (Claude's AskUserQuestion, OpenCode's question tool).
96
+ */
97
+ export function awaitsAnswer(run) {
98
+ if (!run || typeof run !== 'object') return false;
99
+ if (run.turnState === 'needs_input') return true;
100
+ if (run.state === 'awaiting_permission' || run.turnState === 'awaiting_permission') {
101
+ return (Array.isArray(run.pending) ? run.pending : []).some((request) => request?.kind === 'question');
102
+ }
103
+ return isRunIdle(run) && str(run.outcome || run.lastResult?.status) === 'needs_input';
104
+ }
105
+
106
+ /**
107
+ * The run card's status chip, `{ tone, label }` (asst-render.js updateRunCard).
108
+ * A run that waits on your answer says so as its stage does (awaitsAnswer:
109
+ * "Waiting for your answer"), in the waiting tone, a warm worker whose turn
110
+ * ended asking you included; a warm worker between turns otherwise says what
111
+ * its last turn ended with.
112
+ */
113
+ export function runChip(run, t = tFallback) {
114
+ if (run?.state === 'awaiting_route' || run?.turnState === 'awaiting_route' || run?.route?.status === 'pending') {
115
+ return { tone: 'action', label: t('assistant.run.awaitingRoute', 'waiting for your model choice') };
116
+ }
117
+ if (awaitsAnswer(run)) return { tone: 'action', label: t('assistant.run.waitingInput', 'waiting for your answer') };
118
+ const tone = runTone(run);
119
+ if (run?.turnState === 'awaiting_permission') return { tone, label: t('assistant.run.needsApproval', 'needs approval') };
120
+ if (run?.turnState === 'needs_input') return { tone, label: t('assistant.run.needsInput', 'needs input') };
121
+ if (run?.queued && run.status !== 'running') return { tone, label: t('assistant.run.queued', 'queued') };
122
+ if (isRunIdle(run)) {
123
+ const outcome = run.outcome || run.lastResult?.status;
124
+ return { tone, label: outcome ? t('assistant.run.idleWith', '{outcome} · idle', { outcome }) : t('assistant.run.idle', 'idle') };
125
+ }
126
+ return { tone, label: run?.status || tone };
127
+ }
128
+
129
+ /** The final frame a settled phase draws: done, failed or stopped. */
130
+ export function finalFrame(phase, run = null) {
131
+ if (phase === 'failed') return 'failed';
132
+ if (phase === 'stopped') return 'stopped';
133
+ if (phase === 'idle') {
134
+ const outcome = str(run?.outcome || run?.lastResult?.status);
135
+ return outcome === 'failed' ? 'failed' : outcome === 'blocked' ? 'stopped' : 'done';
136
+ }
137
+ return 'done';
138
+ }
139
+
140
+ // ── The worker's live activity (provider events) ─────────────────────────────
141
+
142
+ /**
143
+ * Which of Codex's item events (codex exec --json, @openai/codex-sdk
144
+ * ThreadEvent) say what the worker does now, per item type. A command, an MCP
145
+ * call and the plan begin with item.started (their item.completed reports a
146
+ * call that is over; the plan's comes at the turn's end), the plan changes
147
+ * with item.updated. A patch and a reasoning summary arrive only as
148
+ * item.completed (the SDK's FileChangeItem is "emitted once the patch succeeds
149
+ * or fails"); a web search has come either way.
150
+ */
151
+ export const CODEX_ITEM_EVENTS = Object.freeze({
152
+ command_execution: Object.freeze(['item.started']),
153
+ mcp_tool_call: Object.freeze(['item.started']),
154
+ todo_list: Object.freeze(['item.started', 'item.updated']),
155
+ file_change: Object.freeze(['item.started', 'item.completed']),
156
+ reasoning: Object.freeze(['item.started', 'item.completed']),
157
+ web_search: Object.freeze(['item.started', 'item.completed']),
158
+ });
159
+
160
+ /**
161
+ * Which of an OpenCode tool part's states (message.part.updated, the SDK's
162
+ * ToolPart) say what the worker does: `running` is a call that started (a
163
+ * `pending` part's input is still streaming), `completed` or `error` one that
164
+ * ended. The server forwards one start and one finish per call
165
+ * (lib/opencode-worker-activity.js); a finish counts, like Codex's
166
+ * completion-only items, for a call whose start the bounded relay folded into it.
167
+ */
168
+ export const OPENCODE_TOOL_STATES = Object.freeze(['running', 'completed', 'error']);
169
+
170
+ /**
171
+ * A worker's provider event ({ provider, eventType?, event }, the payload of
172
+ * sync:sidepanel:provider-event) as what it is doing: { kind, name, input }
173
+ * for a tool call (the asst-tool-kinds.js kind), { kind: 'think' } for a
174
+ * thinking block, or null (text, results, stream deltas: nothing new). The
175
+ * stage and the tray keep only compactActivity() of it. OpenCode names its
176
+ * tools bash, read, edit, write, patch, glob, grep, list, webfetch,
177
+ * websearch, codesearch, task, todowrite, and MCP tools `<server>_<tool>`
178
+ * (SynaBun_browser_navigate): kindOf() reads all of them.
179
+ */
180
+ export function activityOf(payload) {
181
+ const provider = str(payload?.provider);
182
+ const event = payload?.event && typeof payload.event === 'object' ? payload.event : null;
183
+ if (!event) return null;
184
+ if (provider === 'claude-code' || provider === 'claude') {
185
+ if (event.type !== 'assistant') return null;
186
+ const blocks = Array.isArray(event.message?.content) ? event.message.content : [];
187
+ let found = null;
188
+ for (const block of blocks) {
189
+ if (block?.type === 'tool_use' && block.name) found = { kind: kindOf(block.name, block.input), name: String(block.name), input: obj(block.input) };
190
+ else if (!found && (block?.type === 'thinking' || block?.type === 'redacted_thinking')) found = { kind: 'think', name: 'thinking', input: {} };
191
+ }
192
+ return found;
193
+ }
194
+ if (provider === 'codex') {
195
+ const item = event.item && typeof event.item === 'object' ? event.item : {};
196
+ if (!Object.hasOwn(CODEX_ITEM_EVENTS, str(item.type)) || !CODEX_ITEM_EVENTS[item.type].includes(event.type)) return null;
197
+ switch (item.type) {
198
+ case 'command_execution': return { kind: 'shell', name: 'exec_command', input: { command: str(item.command) } };
199
+ case 'file_change': {
200
+ const paths = (Array.isArray(item.changes) ? item.changes : []).map((c) => str(c?.path)).filter(Boolean);
201
+ return { kind: 'edit', name: 'apply_patch', input: paths.length > 1 ? { files: paths.map((path) => ({ path })) } : { file_path: paths[0] || '' } };
202
+ }
203
+ case 'mcp_tool_call': {
204
+ const name = `mcp__${str(item.server) || 'tool'}__${str(item.tool) || 'call'}`;
205
+ const input = obj(item.arguments);
206
+ return { kind: kindOf(name, input), name, input };
207
+ }
208
+ case 'web_search': return { kind: 'web', name: 'WebSearch', input: { query: str(item.query) } };
209
+ case 'todo_list': return { kind: 'plan', name: 'update_plan', input: { items: Array.isArray(item.items) ? item.items : [] } };
210
+ case 'reasoning': return { kind: 'think', name: 'thinking', input: {} };
211
+ default: return null;
212
+ }
213
+ }
214
+ if (provider === 'opencode') {
215
+ // { eventType: 'message.part.updated', event: { sessionID, part: ToolPart } }; a sub-agent's session is not the worker's call.
216
+ if (payload.childSession || !/^message[.:]part[.:]updated$/i.test(str(payload.eventType))) return null;
217
+ const part = event.part && typeof event.part === 'object' ? event.part : null;
218
+ if (part?.type !== 'tool' || !str(part.tool).trim() || !OPENCODE_TOOL_STATES.includes(str(part.state?.status))) return null;
219
+ const name = str(part.tool).trim();
220
+ const input = obj(part.state?.input);
221
+ return { kind: kindOf(name, input), name, input };
222
+ }
223
+ return null;
224
+ }
225
+
226
+ function obj(v) {
227
+ if (v && typeof v === 'object' && !Array.isArray(v)) return v;
228
+ if (typeof v === 'string' && v.trim().startsWith('{')) { try { const parsed = JSON.parse(v); return parsed && typeof parsed === 'object' ? parsed : {}; } catch { return {}; } }
229
+ return {};
230
+ }
231
+
232
+ /** The scene a tool call implies on its own, or null (the class decides). */
233
+ export function activityScene(activity, taskClass = '') {
234
+ if (!activity?.kind) return null;
235
+ if (activity.kind === 'computer') return 'computer';
236
+ if (activity.kind !== 'web') return null;
237
+ const tool = parseToolName(activity.name).tool;
238
+ if (tool.startsWith('browser_')) return 'browser';
239
+ // A page read or a web search reads as research, unless the run already browses or researches.
240
+ const cls = sceneOfClass(taskClass);
241
+ return cls === 'browser' || cls === 'research' ? null : 'research';
242
+ }
243
+
244
+ /** The activity while it still speaks for the worker (at most ACTIVITY_FRESH_MS old), else null. */
245
+ export function freshActivity(activity, now = Date.now()) {
246
+ if (!activity?.kind) return null;
247
+ const at = Number(activity.at);
248
+ return Number.isFinite(at) && now - at > ACTIVITY_FRESH_MS ? null : activity;
249
+ }
250
+
251
+ /** The scene a run's stage shows now: what its current call implies, else its class's. */
252
+ export function sceneFor(run, activity = null, now = Date.now()) {
253
+ const cls = runTaskClass(run);
254
+ return activityScene(freshActivity(activity, now), cls) || sceneOfClass(cls);
255
+ }
256
+
257
+ /** The longest step line a stage or the tray keeps. */
258
+ export const STEP_MAX_CHARS = 120;
259
+
260
+ const clip = (v, max) => {
261
+ const s = str(v).replace(/\s+/g, ' ').trim();
262
+ return s.length > max ? `${s.slice(0, max - 1).trimEnd()}…` : s;
263
+ };
264
+
265
+ /**
266
+ * A call in words: its verb and subject, clipped. Worded from the input as a step line may read it
267
+ * (asst-redact.js: credentials masked, a command's heredoc and inline file bodies omitted, an address without its
268
+ * query), so no step line ever shows a credential, whichever worker's call it is.
269
+ */
270
+ function wordStep(a, t) {
271
+ if (a.kind === 'think') return verbText('think', true, t);
272
+ const say = sayCall({ name: a.name, kind: a.kind, input: safeStepInput(a.input || {}), state: 'running' }, { t });
273
+ const subject = redactSecrets(str(say.text)).replace(/^\$ /, '').replace(/\s+/g, ' ').trim();
274
+ return clip(`${verbText(say.verb, true, t)}${subject ? ` ${subject}` : ''}`, STEP_MAX_CHARS);
275
+ }
276
+
277
+ /**
278
+ * What a stage and the tray keep of a worker's call: { kind, name, step, at },
279
+ * the kind and tool name its scene reads, its step line worded once and
280
+ * clipped, and when it was seen. Never the call's arguments: an edit's can
281
+ * hold a whole file; and never a credential the call carries. null for no call.
282
+ */
283
+ export function compactActivity(activity, t = tFallback, now = Date.now()) {
284
+ if (!activity?.kind) return null;
285
+ const at = Number(activity.at);
286
+ return {
287
+ kind: str(activity.kind),
288
+ name: clip(activity.name, 160),
289
+ step: typeof activity.step === 'string' ? clip(redactSecrets(activity.step), STEP_MAX_CHARS) : wordStep(activity, t),
290
+ at: Number.isFinite(at) && at > 0 ? at : now,
291
+ };
292
+ }
293
+
294
+ /** "Editing asst-render.js", "Running npm test", "Thinking"; '' when nothing current is known. */
295
+ export function stepLine(activity, t = tFallback, now = Date.now()) {
296
+ const a = freshActivity(activity, now);
297
+ if (!a) return '';
298
+ return typeof a.step === 'string' ? redactSecrets(a.step) : wordStep(a, t);
299
+ }
300
+
301
+ /** A scene's words ("Coding"), localized. */
302
+ export function sceneLabel(scene, t = tFallback) {
303
+ const [key, fallback] = (SCENE_SPECS[scene] || SCENE_SPECS.generic).label;
304
+ return t(key, fallback);
305
+ }
306
+
307
+ /** The stage's line when no step is known: the phase's words, or "Coding…" while it works. */
308
+ export function phaseLine(phase, run, scene, t = tFallback) {
309
+ switch (phase) {
310
+ case 'queued': return Number(run?.position) > 0 ? t('assistant.stage.queuedAt', 'Queued · position {n}', { n: run.position }) : t('assistant.stage.queued', 'Queued');
311
+ case 'starting': return t('assistant.stage.starting', 'Starting…');
312
+ case 'waiting':
313
+ if (run?.state === 'awaiting_route' || run?.route?.status === 'pending' || run?.awaitingRoute) return t('assistant.stage.waitingRoute', 'Waiting for your model choice');
314
+ if (awaitsAnswer(run)) return t('assistant.stage.waitingInput', 'Waiting for your answer');
315
+ return t('assistant.stage.waitingApproval', 'Waiting for your approval');
316
+ case 'idle': case 'done': return finalFrame(phase, run) === 'failed' ? t('assistant.stage.failed', 'Failed')
317
+ : finalFrame(phase, run) === 'stopped' ? t('assistant.stage.stopped', 'Stopped') : t('assistant.stage.done', 'Done');
318
+ case 'failed': return t('assistant.stage.failed', 'Failed');
319
+ case 'stopped': return t('assistant.stage.stopped', 'Stopped');
320
+ default: return t('assistant.stage.doing', '{scene}…', { scene: sceneLabel(scene, t) });
321
+ }
322
+ }
323
+
324
+ /** Whole minutes of `ms`, as the stage's name says them: "under a minute", "1 min", "12 min". */
325
+ export function minutesText(ms, t = tFallback) {
326
+ const m = Math.floor(Math.max(0, Number(ms) || 0) / 60000);
327
+ if (m < 1) return t('assistant.stage.underMinute', 'under a minute');
328
+ return m === 1 ? t('assistant.stage.minutes.one', '{count} min', { count: m }) : t('assistant.stage.minutes.other', '{count} min', { count: m });
329
+ }
330
+
331
+ /**
332
+ * The stage's accessible name, one line that changes at most once a minute
333
+ * (the step is visible text only, so nothing chatters):
334
+ * "Coding · Settings: App controls section · 3 min"; waiting says why first.
335
+ */
336
+ export function stageLabel({ scene = 'generic', phase = 'working', title = '', ms = 0, run = null } = {}, t = tFallback) {
337
+ const what = phase === 'waiting' ? phaseLine('waiting', run, scene, t)
338
+ : isLivePhase(phase) ? sceneLabel(scene, t) : phaseLine(phase, run, scene, t);
339
+ return [what, str(title).replace(/\s+/g, ' ').trim(), minutesText(ms, t)].filter(Boolean).join(' · ');
340
+ }
341
+
342
+ // ── Scene markup ─────────────────────────────────────────────────────────────
343
+ // Full scenes are drawn in a 120×40 box (the stage shows them at 1:1 beside
344
+ // the mascot); minis in 40×20 (the tray, at 32×16). Strokes are 1.5 units in
345
+ // currentColor (the container's muted text); `sc-gold` is the one live part
346
+ // (gold only means live). Every part sits where its still frame wants it:
347
+ // with no animation (reduced motion, waiting, settled) the scene still reads.
348
+
349
+ /** The code scene's six lines, repeated twice so its stepped scroll loops seamlessly: [indent, keyword, rest]. */
350
+ export const CODE_LINES = Object.freeze([[6, 8, 26], [12, 10, 42], [12, 6, 22], [18, 9, 35], [12, 12, 48], [6, 7, 14]]);
351
+ export const CODE_STEP = 6; // one line, in viewBox units
352
+
353
+ const r1 = (v) => Math.round(v * 100) / 100;
354
+
355
+ /** A gear outline: n trapezoid teeth between radius r and R round (cx, cy). */
356
+ export function gearPath(cx, cy, r, R, n) {
357
+ const pts = [];
358
+ const step = (Math.PI * 2) / n;
359
+ for (let i = 0; i < n; i += 1) {
360
+ const a = i * step;
361
+ for (const [rad, off] of [[r, -0.32], [R, -0.18], [R, 0.18], [r, 0.32]]) {
362
+ pts.push(`${r1(cx + rad * Math.cos(a + off * step))},${r1(cy + rad * Math.sin(a + off * step))}`);
363
+ }
364
+ }
365
+ return `M${pts.join('L')}Z`;
366
+ }
367
+
368
+ /** Where the code scene's caret sits after step `s` (the newest line at the bottom slot): its x. */
369
+ export function codeCaretX(s) {
370
+ const [indent, key, rest] = CODE_LINES[(4 + s) % CODE_LINES.length];
371
+ return 4 + indent + key + 3 + rest + 2;
372
+ }
373
+
374
+ function codeFull() {
375
+ let lines = '';
376
+ for (let i = 0; i < CODE_LINES.length * 2; i += 1) {
377
+ const [indent, key, rest] = CODE_LINES[i % CODE_LINES.length];
378
+ const y = 5 + CODE_STEP * i;
379
+ lines += `<path class="sc-mid" d="M${indent} ${y}h${key}"/><path class="sc-dim" d="M${indent + key + 3} ${y}h${rest}"/>`;
380
+ }
381
+ return '<rect class="sc-dim" x="1" y="1.5" width="118" height="37" rx="5"/>'
382
+ + `<svg x="4" y="4" width="112" height="32" overflow="hidden"><g class="sc-code-scroll">${lines}</g></svg>`
383
+ + `<g class="sc-code-caret" style="transform:translateX(${codeCaretX(0)}px)"><rect class="sc-gold sc-fill sc-caret" x="0" y="30.5" width="2" height="5" rx="1"/></g>`;
384
+ }
385
+
386
+ const GEAR_BIG = gearPath(66, 20, 9, 12.5, 8);
387
+ const GEAR_SMALL = gearPath(86.5, 12.5, 5.5, 8, 6);
388
+
389
+ function complexFull() {
390
+ return '<path class="sc-dim" d="M14 7h13l5 5v21H14z"/><path class="sc-mid" d="M8 11h13l5 5v21H8zM21 11v5h5M12 23h9M12 28h11"/>'
391
+ + `<g class="sc-gear-big sc-box"><path class="sc-mid" d="${GEAR_BIG}"/><circle class="sc-dim" cx="66" cy="20" r="3.2"/></g>`
392
+ + `<g class="sc-gear-small sc-box"><path class="sc-gold" d="${GEAR_SMALL}"/><circle class="sc-gold" cx="86.5" cy="12.5" r="2"/></g>`
393
+ + '<path class="sc-dim" d="M98 30h14M102 25h10"/>';
394
+ }
395
+
396
+ function reviewFull() {
397
+ const rows = [[9, '+', 52], [16, '-', 64], [23, '+', 40], [30, '+', 58]];
398
+ let out = '<rect class="sc-dim" x="1" y="1.5" width="118" height="37" rx="5"/>';
399
+ rows.forEach(([y, sign, len], i) => {
400
+ out += sign === '+' ? `<path class="sc-mid" d="M6 ${y}h4M8 ${y - 2}v4"/>` : `<path class="sc-mid" d="M6 ${y}h4"/>`;
401
+ out += `<path class="sc-dim" d="M15 ${y}h${len}"/>`;
402
+ out += `<path class="sc-gold sc-tick sc-box" style="--i:${i}" d="M${95} ${y}l2.2 2.2 4.4-4.6"/>`;
403
+ });
404
+ return out;
405
+ }
406
+
407
+ function researchFull() {
408
+ const page = (x) => `<rect class="sc-dim" x="${x}" y="4" width="40" height="32" rx="3"/><path class="sc-dim" d="M${x + 6} 11h26M${x + 6} 17h22M${x + 6} 23h28M${x + 6} 29h16"/>`;
409
+ return page(8) + page(56)
410
+ + '<g class="sc-lens"><circle class="sc-gold" cx="24" cy="17" r="7"/><path class="sc-gold" d="M29.2 22.2l5 5"/></g>';
411
+ }
412
+
413
+ const POINTER = 'M0 0v10.5l2.8-2.6 2 4.4 2-.9-2-4.3h3.9z';
414
+
415
+ function browserFull() {
416
+ return '<rect class="sc-dim" x="1" y="1.5" width="118" height="37" rx="5"/><path class="sc-dim" d="M1 9.5h118"/>'
417
+ + '<circle class="sc-mid sc-fill" cx="6" cy="5.5" r="1"/><circle class="sc-mid sc-fill" cx="10" cy="5.5" r="1"/><circle class="sc-mid sc-fill" cx="14" cy="5.5" r="1"/>'
418
+ + '<rect class="sc-dim" x="22" y="3.5" width="56" height="4" rx="2"/>'
419
+ + '<path class="sc-mid" d="M8 16h36"/><path class="sc-dim" d="M8 22h54M8 27h44M8 32h30"/><rect class="sc-mid" x="78" y="25" width="28" height="8" rx="2"/>'
420
+ + '<circle class="sc-gold sc-ring sc-ripple-browser sc-box" cx="92" cy="29" r="5"/>'
421
+ + `<g class="sc-point-browser" style="transform:translate(92px,29px)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`;
422
+ }
423
+
424
+ function computerFull() {
425
+ return '<rect class="sc-dim" x="10" y="1.5" width="100" height="30" rx="3"/><path class="sc-dim" d="M60 31.5v4M48 37.5h24"/>'
426
+ + '<rect class="sc-mid sc-shade" x="16" y="6" width="44" height="20" rx="2"/><path class="sc-dim" d="M16 10h44M21 15h20M21 20h28"/>'
427
+ + '<rect class="sc-mid sc-shade" x="52" y="11" width="50" height="17" rx="2"/><path class="sc-dim" d="M52 15h50"/><rect class="sc-mid" x="84" y="20" width="13" height="5" rx="1.5"/>'
428
+ + '<circle class="sc-gold sc-ring sc-ripple-computer sc-box" cx="90" cy="22.5" r="4.5"/>'
429
+ + `<g class="sc-point-computer" style="transform:translate(90px,22.5px)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`;
430
+ }
431
+
432
+ function automationFull() {
433
+ return '<circle class="sc-mid" cx="18" cy="20" r="13"/><path class="sc-dim" d="M18 9v2M18 29v2M7 20h2M27 20h2"/>'
434
+ + '<path class="sc-mid" d="M18 20l5-4"/>'
435
+ + '<g class="sc-hand sc-vb" style="transform-origin:18px 20px"><path class="sc-gold" d="M18 20v-9"/></g><circle class="sc-gold sc-fill" cx="18" cy="20" r="1.6"/>'
436
+ + '<path class="sc-dim" d="M52 24h14M76 24h14"/><rect class="sc-mid" x="44" y="20" width="8" height="8" rx="2"/><rect class="sc-mid" x="66" y="20" width="10" height="8" rx="2"/><rect class="sc-mid" x="90" y="20" width="8" height="8" rx="2"/>'
437
+ + '<path class="sc-dim" d="M94 17c0-9-46-9-46 0M48 17l-2.5-3M48 17l3-2"/>'
438
+ + '<g class="sc-run-dot"><circle class="sc-gold sc-fill" cx="48" cy="24" r="2.2"/></g>';
439
+ }
440
+
441
+ function designFull() {
442
+ return '<rect class="sc-gold sc-fill sc-swatch" x="4" y="5" width="9" height="9" rx="2"/><rect class="sc-mid sc-fill sc-swatch-b" x="4" y="16" width="9" height="9" rx="2"/><rect class="sc-dim sc-fill sc-swatch-c" x="4" y="27" width="9" height="9" rx="2"/>'
443
+ + '<rect class="sc-dim" x="20" y="2.5" width="96" height="35" rx="4"/>'
444
+ + '<circle class="sc-mid sc-shape sc-box" style="--i:0" cx="40" cy="20" r="8"/>'
445
+ + '<rect class="sc-mid sc-shape sc-box" style="--i:1" x="58" y="12" width="16" height="16" rx="3"/>'
446
+ + '<path class="sc-mid sc-shape sc-box" style="--i:2" d="M86 28l9-16 9 16z"/>'
447
+ + '<g class="sc-pen" style="transform:translate(40px,20px)"><path class="sc-gold" d="M0 0l6-6M6-6l2.5 2.5M0 0l-1.2 3.7L2.5 2.5z"/></g>';
448
+ }
449
+
450
+ function imageFull() {
451
+ let tiles = '';
452
+ for (let row = 0; row < 3; row += 1) {
453
+ for (let col = 0; col < 4; col += 1) {
454
+ const gold = (row === 1 && col === 2) || (row === 2 && col === 0);
455
+ tiles += `<rect class="${gold ? 'sc-gold' : 'sc-mid'} sc-fill sc-tile" style="--i:${row + col}" x="${34 + col * 13.5}" y="${6 + row * 10}" width="11.5" height="8" rx="1.5"/>`;
456
+ }
457
+ }
458
+ return `<rect class="sc-dim" x="30" y="2.5" width="61" height="35" rx="3"/>${tiles}`
459
+ + '<g class="sc-sparkle sc-box"><path class="sc-gold sc-fill" d="M104 6l1.6 4.4L110 12l-4.4 1.6L104 18l-1.6-4.4L98 12l4.4-1.6z"/></g>'
460
+ + '<path class="sc-dim" d="M100 26h12M100 31h8"/>';
461
+ }
462
+
463
+ function filmFrames(width, y, h, frameW, count) {
464
+ let out = `<rect class="sc-dim" x="0" y="${y}" width="${width}" height="${h}" rx="2"/>`;
465
+ for (let i = 0; i < count; i += 1) out += `<rect class="sc-mid" x="${i * frameW + 3}" y="${y + 5}" width="${frameW - 6}" height="${h - 10}" rx="1.5"/>`;
466
+ for (let x = 2; x < width; x += 6) out += `<rect class="sc-dim sc-fill" x="${x}" y="${y + 1.5}" width="2.4" height="2" rx=".6"/><rect class="sc-dim sc-fill" x="${x}" y="${y + h - 3.5}" width="2.4" height="2" rx=".6"/>`;
467
+ return out;
468
+ }
469
+
470
+ function videoFull() {
471
+ return `<svg x="4" y="4" width="112" height="32" overflow="hidden"><g class="sc-film">${filmFrames(160, 2, 28, 24, 7)}</g></svg>`
472
+ + '<path class="sc-gold" d="M58 2v36M55 2h6l-3 3z"/>';
473
+ }
474
+
475
+ /** An open-end wrench, horizontal, its jaw round (0, 0): place it with translate(bolt) rotate(a) translate(3.5 0). */
476
+ const WRENCH = 'M-4.6 -3.86L-1 -2V2L-4.6 3.86A6 6 0 0 0 5.5 2.4H24A2.4 2.4 0 0 0 24 -2.4H5.5A6 6 0 0 0 -4.6 -3.86Z';
477
+ const hexagon = (cx, cy, r) => `M${[0, 1, 2, 3, 4, 5].map(i => `${r1(cx + r * Math.cos(i * Math.PI / 3))} ${r1(cy + r * Math.sin(i * Math.PI / 3))}`).join('L')}Z`;
478
+
479
+ function quickFull() {
480
+ return `<path class="sc-mid" d="${hexagon(38, 24, 3.4)}"/>`
481
+ + `<g class="sc-wrench sc-vb" style="transform-origin:38px 24px"><path class="sc-gold" transform="translate(38 24) rotate(-32) translate(3.5 0)" d="${WRENCH}"/></g>`
482
+ + '<path class="sc-gold sc-spark" style="--i:0" d="M30.5 19.5l-3-2"/><path class="sc-gold sc-spark" style="--i:1" d="M29.5 24.5h-3.5"/><path class="sc-gold sc-spark" style="--i:2" d="M30.5 29.5l-3 2"/>'
483
+ + '<g class="sc-zap sc-box"><path class="sc-gold" d="M92 5l-8 15h7l-3 14 11-18h-7.5z"/></g>';
484
+ }
485
+
486
+ function genericFull() {
487
+ return '<path class="sc-dim" d="M14 20h92"/><circle class="sc-mid" cx="14" cy="20" r="3"/><circle class="sc-mid" cx="60" cy="20" r="3"/><circle class="sc-mid" cx="106" cy="20" r="3"/>'
488
+ + '<g class="sc-slide"><rect class="sc-gold sc-fill" x="14" y="18.5" width="24" height="3" rx="1.5"/></g>';
489
+ }
490
+
491
+ // Minis (40×20, the tray at 32×16): one gesture each.
492
+ const MINI = {
493
+ code: () => '<path class="sc-mid" d="M5 5h20M9 10h24M5 15h14"/><rect class="sc-gold sc-fill sc-caret" x="21.5" y="12.5" width="1.8" height="5" rx=".9"/>',
494
+ complex: () => `<g class="sc-gear-big sc-box"><path class="sc-mid" d="${gearPath(14, 11, 4.5, 6.6, 6)}"/></g><g class="sc-gear-small sc-box"><path class="sc-gold" d="${gearPath(26.5, 7.5, 3, 4.6, 6)}"/></g>`,
495
+ review: () => '<path class="sc-dim" d="M4 5h20M4 10h24M4 15h18"/><path class="sc-gold sc-tick sc-box" style="--i:0" d="M30 5l1.6 1.6 3.2-3.4"/><path class="sc-gold sc-tick sc-box" style="--i:1" d="M32 10l1.6 1.6 3.2-3.4"/>',
496
+ research: () => '<rect class="sc-dim" x="3" y="2.5" width="26" height="15" rx="2"/><path class="sc-dim" d="M7 7h16M7 11h12M7 15h14"/><g class="sc-lens-mini"><circle class="sc-gold" cx="12" cy="9" r="3.8"/><path class="sc-gold" d="M14.8 11.8l2.8 2.8"/></g>',
497
+ browser: () => `<rect class="sc-dim" x="2" y="2" width="36" height="16" rx="2.5"/><path class="sc-dim" d="M2 6h36"/><rect class="sc-mid" x="24" y="11" width="10" height="4" rx="1.2"/><g class="sc-point-mini" style="transform:translate(29px,13px) scale(.6)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`,
498
+ computer: () => `<rect class="sc-dim" x="5" y="1.5" width="30" height="14" rx="2"/><path class="sc-dim" d="M20 15.5v2M15 18.5h10"/><rect class="sc-mid" x="8" y="4.5" width="13" height="8" rx="1"/><g class="sc-point-mini" style="transform:translate(29px,13px) scale(.6)"><path class="sc-gold sc-fill" d="${POINTER}"/></g>`,
499
+ automation: () => '<circle class="sc-mid" cx="11" cy="10" r="7.5"/><path class="sc-dim" d="M11 10l3-2.5"/><g class="sc-hand sc-vb" style="transform-origin:11px 10px"><path class="sc-gold" d="M11 10V4.5"/></g>'
500
+ + '<path class="sc-mid" d="M33.5 10a5 5 0 1 1-1.5-3.6M32 3.6v2.8h-2.8"/>',
501
+ design: () => '<rect class="sc-mid sc-fill" x="3" y="3" width="6" height="6" rx="1.5"/><rect class="sc-dim sc-fill" x="3" y="11" width="6" height="6" rx="1.5"/><circle class="sc-gold sc-shape sc-box" style="--i:0" cx="21" cy="10" r="5"/><path class="sc-mid sc-shape sc-box" style="--i:1" d="M29 15l4.5-8 4.5 8z"/>',
502
+ image_gen: () => {
503
+ let tiles = '';
504
+ for (let row = 0; row < 2; row += 1) for (let col = 0; col < 3; col += 1) tiles += `<rect class="${row === 1 && col === 2 ? 'sc-gold' : 'sc-mid'} sc-fill sc-tile" style="--i:${row + col}" x="${11 + col * 6.4}" y="${5 + row * 5.6}" width="5" height="4.2" rx="1"/>`;
505
+ return `<rect class="sc-dim" x="9" y="2.5" width="22" height="15" rx="2"/>${tiles}`;
506
+ },
507
+ video_gen: () => `<svg x="2" y="2" width="36" height="16" overflow="hidden"><g class="sc-film-mini">${filmFrames(60, 1, 14, 12, 5)}</g></svg><path class="sc-gold" d="M20 1v18"/>`,
508
+ quick: () => `<path class="sc-mid" d="${hexagon(11, 11, 2.6)}"/><g class="sc-wrench sc-vb" style="transform-origin:11px 11px"><path class="sc-gold" stroke-width="2.4" transform="translate(11 11) rotate(-32) scale(.62) translate(3.5 0)" d="${WRENCH}"/></g>`
509
+ + '<path class="sc-gold sc-spark" style="--i:0" d="M5.5 7.5l-2-1.3"/><path class="sc-gold sc-spark" style="--i:1" d="M5 11.5H2.6"/>',
510
+ generic: () => '<circle class="sc-gold sc-fill sc-dot" style="--i:0" cx="11" cy="10" r="2.4"/><circle class="sc-gold sc-fill sc-dot" style="--i:1" cx="20" cy="10" r="2.4"/><circle class="sc-gold sc-fill sc-dot" style="--i:2" cx="29" cy="10" r="2.4"/>',
511
+ };
512
+
513
+ const FULL = {
514
+ quick: quickFull, code: codeFull, complex: complexFull, review: reviewFull, research: researchFull, browser: browserFull,
515
+ computer: computerFull, automation: automationFull, design: designFull, image_gen: imageFull, video_gen: videoFull, generic: genericFull,
516
+ };
517
+
518
+ /**
519
+ * A scene's SVG (decorative: aria-hidden). `mini` draws the tray's 40×20
520
+ * version. `live` starts it moving (the stage and tray set data-live
521
+ * themselves later; this is only the first state).
522
+ */
523
+ export function sceneSvg(scene, { mini = false, live = false, className = '' } = {}) {
524
+ const id = Object.hasOwn(FULL, scene) ? scene : 'generic';
525
+ const [w, h] = mini ? [40, 20] : [120, 40];
526
+ const body = (mini ? MINI[id] : FULL[id])();
527
+ return `<svg class="asst-scene${mini ? ' is-mini' : ''}${className ? ` ${className}` : ''}" data-scene="${id}"${live ? ' data-live=""' : ''} viewBox="0 0 ${w} ${h}" width="${w}" height="${h}" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${body}</svg>`;
528
+ }
@@ -450,21 +450,9 @@ export function injectAssistantSidepanelStyles() {
450
450
  .assistant-panel .asst-send[data-state="ready"]::before { transform: scaleX(1); }
451
451
  .assistant-panel .asst-send[data-state="ready"]:hover { box-shadow: inset 0 0 0 1px var(--asp-gold); }
452
452
 
453
- /* ── Tray pill (#term-minimized-tray, outside the panel) ─────────────
454
- The shared .term-minimized-pill of styles.css, drawn exactly like the
455
- Claude, Codex and OpenCode pills: 32px, 8px corners, a 1px hairline,
456
- icon · name · ✕, no geometry of its own. Only the identity is
457
- SynaBun's: the two-pill mark, and the cameo in its place while working
458
- (gold, with a gold hairline); a session that needs you tints the mark
459
- and the hairline. It is a button (Enter/Space) with the panel's focus
460
- ring, and its ✕ keeps the tray's 24px target. */
461
- .asp-session-pill .term-minimized-pill-icon .syna-cameo { display: none; }
462
- .asp-session-pill.asp-pill-running { border-color: var(--asst-pill-on-ring); }
463
- .asp-session-pill.asp-pill-running .term-minimized-pill-icon { color: var(--asst-brand); }
464
- .asp-session-pill.asp-pill-running .term-minimized-pill-icon > svg:not(.syna-cameo) { display: none; }
465
- .asp-session-pill.asp-pill-running .term-minimized-pill-icon .syna-cameo { display: inline-flex; }
466
- .asp-session-pill.asp-pill-attention { border-color: var(--asst-pill-warn-ring); }
467
- .asp-session-pill.asp-pill-attention .term-minimized-pill-icon { color: var(--asst-warn); }
453
+ /* The tray pill (#term-minimized-tray, outside the panel) is the
454
+ component's (asst-styles.js "Tray pill"): the terminal tab minimises to
455
+ the same one, so its states load with the component in either host. */
468
456
 
469
457
  /* ── Motion ─────────────────────────────────────────────────────── */
470
458
  @keyframes asp-sweep { from { transform: translateX(-100%); } to { transform: translateX(270%); } }
@@ -429,6 +429,20 @@ export function runTone(run) {
429
429
  return 'running';
430
430
  }
431
431
 
432
+ /**
433
+ * What a session's status is (the tray pill, the sidepanel header, the terminal tab's badge):
434
+ * 'action' while anything waits on you (a card of its own, or a worker's permission, question or
435
+ * model choice), 'working' while its own turn runs or any worker it dispatched works (queued for a
436
+ * free slot, starting, in a turn), else what its own last turn left ('done' when it ended out of
437
+ * sight, else 'idle'). A worker outlives the turn that dispatched it, and so does the gold.
438
+ * `own` is the brain's own status; `workers` the agents tray's counts (asst-agents-dock.js counts()).
439
+ */
440
+ export function sessionStatus(own, workers = {}) {
441
+ if (own === 'action' || Number(workers?.waiting) > 0) return 'action';
442
+ if (own === 'working' || Number(workers?.working) > 0) return 'working';
443
+ return own === 'done' ? 'done' : 'idle';
444
+ }
445
+
432
446
  function toMs(value) {
433
447
  if (value == null || value === '') return 0;
434
448
  if (typeof value === 'number') return Number.isFinite(value) ? value : 0;