synabun 2.0.0 → 2.0.5

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 (334) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +46 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +2 -2
  8. package/hooks/claude-code/pre-compact.mjs +11 -0
  9. package/hooks/claude-code/prompt-submit.mjs +60 -184
  10. package/hooks/claude-code/session-start.mjs +73 -16
  11. package/hooks/claude-code/shared.mjs +20 -0
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/lib/start-launcher.js +88 -1
  14. package/mcp-server/package-lock.json +2 -2
  15. package/mcp-server/package.json +1 -3
  16. package/neural-interface/i18n/en.json +1500 -153
  17. package/neural-interface/i18n/pt-BR.json +1498 -152
  18. package/neural-interface/lib/assistant-api.js +62 -6
  19. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  20. package/neural-interface/lib/assistant-catalog.js +179 -27
  21. package/neural-interface/lib/assistant-config.js +31 -2
  22. package/neural-interface/lib/assistant-dispatch.js +62 -13
  23. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  24. package/neural-interface/lib/assistant-memory.js +24 -10
  25. package/neural-interface/lib/assistant-persona.js +6 -2
  26. package/neural-interface/lib/assistant-pricing.js +21 -6
  27. package/neural-interface/lib/assistant-runtime.js +181 -12
  28. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  29. package/neural-interface/lib/assistant-test-density.js +142 -0
  30. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  31. package/neural-interface/lib/assistant-user-context.js +908 -0
  32. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  33. package/neural-interface/lib/assistant-user-learn.js +404 -0
  34. package/neural-interface/lib/assistant-user-threads.js +226 -0
  35. package/neural-interface/lib/assistant-user-writer.js +181 -0
  36. package/neural-interface/lib/browser-background-tab.js +134 -0
  37. package/neural-interface/lib/browser-screenshot.js +678 -61
  38. package/neural-interface/lib/claude-agent-bridge.js +33 -6
  39. package/neural-interface/lib/claude-model-catalog.js +30 -2
  40. package/neural-interface/lib/claude-temporary.js +46 -7
  41. package/neural-interface/lib/cloudflared/install.js +533 -0
  42. package/neural-interface/lib/cloudflared/manager.js +545 -0
  43. package/neural-interface/lib/cloudflared/pins.js +115 -0
  44. package/neural-interface/lib/cloudflared/pins.json +63 -0
  45. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  46. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  47. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  48. package/neural-interface/lib/editor-completion.js +714 -0
  49. package/neural-interface/lib/editor-config.js +149 -0
  50. package/neural-interface/lib/editor-files-api.js +268 -0
  51. package/neural-interface/lib/editor-git-api.js +134 -0
  52. package/neural-interface/lib/file-explorer-api.js +1039 -0
  53. package/neural-interface/lib/file-explorer-system.js +355 -0
  54. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  55. package/neural-interface/lib/file-explorer-watch.js +239 -0
  56. package/neural-interface/lib/git-diff-api.js +103 -0
  57. package/neural-interface/lib/git-read.js +202 -0
  58. package/neural-interface/lib/greeting/api.js +89 -0
  59. package/neural-interface/lib/greeting/budgets.js +90 -0
  60. package/neural-interface/lib/greeting/engine.js +461 -0
  61. package/neural-interface/lib/greeting/facts.js +320 -0
  62. package/neural-interface/lib/greeting/sources.js +252 -0
  63. package/neural-interface/lib/greeting/writer.js +139 -0
  64. package/neural-interface/lib/http-guards.js +189 -13
  65. package/neural-interface/lib/machine-names.js +88 -0
  66. package/neural-interface/lib/memory-api.js +31 -7
  67. package/neural-interface/lib/native-loop-providers.js +10 -5
  68. package/neural-interface/lib/plugin-installer.js +4 -2
  69. package/neural-interface/lib/project-storage.js +5 -7
  70. package/neural-interface/lib/request-gate.js +589 -0
  71. package/neural-interface/lib/ui-blob-api.js +108 -0
  72. package/neural-interface/lib/ui-blob-store.js +68 -0
  73. package/neural-interface/package-lock.json +701 -2
  74. package/neural-interface/package.json +13 -2
  75. package/neural-interface/public/install-app.html +9 -6
  76. package/neural-interface/public/offline.html +3 -2
  77. package/neural-interface/public/onboarding.html +12 -1
  78. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  79. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  80. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  81. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  82. package/neural-interface/public/shared/assistant/asst-mascot.js +18 -58
  83. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  84. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  85. package/neural-interface/public/shared/assistant/asst-render.js +162 -19
  86. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  87. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  88. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  89. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  90. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  91. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  92. package/neural-interface/public/shared/assistant/asst-styles.js +158 -4
  93. package/neural-interface/public/shared/blob-store.js +111 -22
  94. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  95. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  96. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  97. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  98. package/neural-interface/public/shared/constants.js +6 -1
  99. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  100. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  101. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  102. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  103. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  104. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  105. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  106. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  107. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  108. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  109. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  110. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  111. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  112. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  113. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  114. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  115. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  116. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  117. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  118. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  119. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  120. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  121. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  122. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  123. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  124. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  125. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  126. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  127. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  128. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  129. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  130. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  131. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  132. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  133. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  134. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  135. package/neural-interface/public/shared/file-links.js +339 -0
  136. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  137. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  138. package/neural-interface/public/shared/html-shell.js +160 -165
  139. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  140. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  141. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  142. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  143. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  144. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  145. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  146. package/neural-interface/public/shared/pwa-install-page.js +29 -1
  147. package/neural-interface/public/shared/pwa-install.css +3 -3
  148. package/neural-interface/public/shared/pwa-install.js +100 -1
  149. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  150. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  151. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  152. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  153. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  154. package/neural-interface/public/shared/start-bridge.js +238 -19
  155. package/neural-interface/public/shared/styles.css +1414 -721
  156. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  157. package/neural-interface/public/shared/tunnel-view.js +167 -0
  158. package/neural-interface/public/shared/ui-claude-panel.js +157 -16
  159. package/neural-interface/public/shared/ui-detail.js +15 -0
  160. package/neural-interface/public/shared/ui-explorer.js +22 -0
  161. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  162. package/neural-interface/public/shared/ui-file-links.js +103 -0
  163. package/neural-interface/public/shared/ui-help.js +26 -0
  164. package/neural-interface/public/shared/ui-invite.js +126 -116
  165. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  166. package/neural-interface/public/shared/ui-loading.js +159 -15
  167. package/neural-interface/public/shared/ui-menubar.js +12 -30
  168. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  169. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  170. package/neural-interface/public/shared/ui-navbar.js +45 -21
  171. package/neural-interface/public/shared/ui-settings.js +455 -488
  172. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  173. package/neural-interface/public/shared/ui-sync.js +16 -0
  174. package/neural-interface/public/shared/ui-terminal.js +23 -5
  175. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  176. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  177. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  178. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  179. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  180. package/neural-interface/public/shared/worker-end.js +251 -0
  181. package/neural-interface/public/sw.js +2 -2
  182. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  183. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  184. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  185. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  186. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  187. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  188. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  189. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  190. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  191. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  192. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  193. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  194. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  195. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  196. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  197. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  198. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  199. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  200. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  201. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  202. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  203. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  204. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  205. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  206. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  207. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  208. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  209. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  210. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  211. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  212. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  309. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  310. package/neural-interface/scripts/build-vendor.mjs +78 -2
  311. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  312. package/neural-interface/server.js +873 -1028
  313. package/neural-interface/templates/rulesets/README.md +1 -1
  314. package/package.json +2 -8
  315. package/setup.js +44 -7
  316. package/benchmarks/browser-live-results.json +0 -79
  317. package/benchmarks/browser-v2-results.json +0 -258
  318. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  319. package/neural-interface/public/category-logos/claude.svg +0 -1
  320. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  321. package/neural-interface/public/category-logos/openai.svg +0 -1
  322. package/neural-interface/public/category-logos/synabun.png +0 -0
  323. package/neural-interface/public/claude.svg +0 -1
  324. package/neural-interface/public/gallery.svg +0 -6
  325. package/neural-interface/public/leonardoai.svg +0 -1
  326. package/neural-interface/public/mcp.svg +0 -4
  327. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  328. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  329. package/neural-interface/public/sessionicon.svg +0 -8
  330. package/neural-interface/public/toolbar-album.svg +0 -8
  331. package/neural-interface/public/toolbar-question.svg +0 -6
  332. package/neural-interface/public/toolbar-sessions.svg +0 -6
  333. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  334. package/skills/synabun/synabunicon.png +0 -0
@@ -1,13 +1,14 @@
1
1
  // ═══════════════════════════════════════════
2
2
  // SynaBun Neural Interface — Loading Overlay
3
- // Health check, server start, server-offline retry, command copy
3
+ // Health check, server start, server-offline retry, command copy,
4
+ // and the restart the user asked for (the same screen, one more reason)
4
5
  // ═══════════════════════════════════════════
5
6
 
6
7
  import { fetchHealth, startHealth } from './api.js';
7
- import { emit } from './state.js';
8
+ import { emit, on } from './state.js';
8
9
  import { t } from './i18n.js';
9
10
  import {
10
- START_STORAGE, createStartBridge, fetchStartBeacon, isMacPlatform, isWindowsPlatform,
11
+ START_LIMITS, START_STORAGE, createStartBridge, fetchStartBeacon, isMacPlatform, isWindowsPlatform,
11
12
  manualStartCommands, openStartLink, startBeaconTarget, startButtonUsable, startStatusView,
12
13
  } from './start-bridge.js';
13
14
  // Imported with the app, not when it is needed: once the server is down
@@ -25,6 +26,12 @@ let _offlineBridge = null;
25
26
  let _offlineTitle = '';
26
27
  // The mascot rig in the overlay, mounted the first time the server is offline.
27
28
  let _mascot = null;
29
+ // The overlay was put over the running app for a restart. Everything the page
30
+ // held (sockets, terminals, panel sessions) was the old server's, so once the
31
+ // server is back the page loads again instead of carrying on.
32
+ let _restartShown = false;
33
+ // The tab's title from before the restart, for when it is refused.
34
+ let _restartTitle = null;
28
35
 
29
36
  // What the mascot does for each thing the page knows about a start
30
37
  // (startStatusView's `mascot`), as poses of the shared rig.
@@ -83,6 +90,7 @@ export function showLoadingError(title, sub, canStart, serverOffline) {
83
90
  }
84
91
 
85
92
  clearStartStatus();
93
+ clearRestartLook();
86
94
 
87
95
  if (serverOffline) {
88
96
  const $hint = $('loading-server-cmd-hint');
@@ -131,6 +139,7 @@ function resetLoadingToConnecting() {
131
139
  if ($action) $action.style.display = 'none';
132
140
  if ($actionStatus) $actionStatus.textContent = '';
133
141
  clearStartStatus();
142
+ clearRestartLook();
134
143
  if (_statusDot) _statusDot.classList.remove('error');
135
144
  }
136
145
 
@@ -222,6 +231,14 @@ function clearStartStatus() {
222
231
  if ($trail) $trail.replaceChildren();
223
232
  }
224
233
 
234
+ /** What a restart changed about the overlay's look, undone. */
235
+ function clearRestartLook() {
236
+ const $overlay = $('loading-overlay');
237
+ if ($overlay) $overlay.classList.remove('over-app', 'restart-busy', 'restart-refused');
238
+ const btn = $('loading-action-btn');
239
+ if (btn) btn.style.display = '';
240
+ }
241
+
225
242
  /**
226
243
  * The overlay's mascot as the shared rig, so a start can be acted out. The
227
244
  * markup's own still drawing stays as the fallback when the rig cannot mount.
@@ -259,24 +276,51 @@ function renderStart(snap) {
259
276
  const platform = isWindowsPlatform(navigator) ? 'windows' : isMacPlatform(navigator) ? 'mac' : 'linux';
260
277
  const view = startStatusView(snap, { platform });
261
278
  const say = (line) => (line ? t(`loading.start.${line.key}`, line.params) : '');
279
+ // A restart this page asked for or was told of, while it runs.
280
+ const restarting = !!snap.restart && (view.busy || view.state === 'online');
262
281
 
263
282
  poseMascot(view.mascot);
264
283
 
284
+ const $overlay = $('loading-overlay');
285
+ if ($overlay) {
286
+ // While a restart runs there is nothing to press and no command to type;
287
+ // refused, the server is still there and only the way back is offered.
288
+ $overlay.classList.toggle('restart-busy', restarting);
289
+ $overlay.classList.toggle('restart-refused', view.state === 'refused');
290
+ }
291
+
265
292
  const $text = $('loading-text');
266
293
  if ($text) {
267
- const title = view.mascot === 'waking' || view.mascot === 'working' ? t('loading.start.headingStarting')
268
- : view.mascot === 'ready' ? t('loading.start.headingReady')
269
- : view.mascot === 'failed' ? t('loading.start.headingFailed')
270
- : _offlineTitle || t('loading.serverOffline');
294
+ const title = view.heading ? t(`loading.start.${view.heading}`)
295
+ : view.mascot === 'waking' || view.mascot === 'working' ? t('loading.start.headingStarting')
296
+ : view.mascot === 'ready' ? t('loading.start.headingReady')
297
+ : view.mascot === 'failed' ? t('loading.start.headingFailed')
298
+ : _offlineTitle || t('loading.serverOffline');
271
299
  if ($text.textContent !== title) $text.textContent = title;
272
300
  }
273
301
 
302
+ // Under the title: whose restart this is, for as long as it is one.
303
+ const $sub = $('loading-sub');
304
+ if ($sub && _restartShown) {
305
+ const sub = view.state === 'refused' ? t('loading.restartSubRefused')
306
+ : restarting ? (snap.restart.asked ? t('loading.restartSubAsked') : t('loading.restartSubTold'))
307
+ : t('loading.serverNotRunning');
308
+ if ($sub.textContent !== sub) $sub.textContent = sub;
309
+ }
310
+
274
311
  const btn = $('loading-action-btn');
275
312
  const $label = $('loading-action-label');
276
- if (btn) btn.disabled = view.busy || view.state === 'online';
313
+ if (btn) {
314
+ btn.disabled = view.busy || view.state === 'online';
315
+ // No dead button: when a restart did not bring the server back, Start is
316
+ // offered only if its launcher is there (the command below always is).
317
+ const startOffered = view.button === 'start' || view.button === 'retry';
318
+ btn.style.display = _restartShown && startOffered && !startButtonUsable(stored(START_STORAGE.launcher)) ? 'none' : '';
319
+ }
277
320
  if ($label) {
278
321
  $label.textContent = view.button === 'starting' ? t('loading.starting')
279
- : view.button === 'retry' ? t('common.retry') : t('loading.startServer');
322
+ : view.button === 'retry' ? t('common.retry')
323
+ : view.button === 'back' ? t('loading.restartBack') : t('loading.startServer');
280
324
  }
281
325
 
282
326
  const $status = $('loading-action-status');
@@ -286,7 +330,7 @@ function renderStart(snap) {
286
330
  const $elapsed = $('loading-action-elapsed');
287
331
  if ($elapsed) {
288
332
  $elapsed.textContent = view.elapsed;
289
- $elapsed.setAttribute('aria-label', view.elapsed ? `${t('loading.start.elapsedLabel')}: ${view.elapsed}` : '');
333
+ $elapsed.setAttribute('aria-label', view.elapsed ? `${t(`loading.start.${view.elapsedLabel}`)}: ${view.elapsed}` : '');
290
334
  }
291
335
 
292
336
  const $hint = $('loading-action-hint');
@@ -319,13 +363,28 @@ function renderStart(snap) {
319
363
  */
320
364
  function watchForServer() {
321
365
  if (_offlineBridge) return;
366
+ openBridge().watch();
367
+ }
368
+
369
+ /**
370
+ * Is the server answering, which server is it (`bootId`), and does it say it
371
+ * is on its way out for a restart. One that predates those two says neither.
372
+ */
373
+ async function probeServer() {
374
+ const health = await fetchHealth();
375
+ return {
376
+ up: !!health && health.ok !== false,
377
+ boot: typeof health?.bootId === 'string' ? health.bootId : '',
378
+ stopping: health?.restarting === true,
379
+ };
380
+ }
381
+
382
+ /** The bridge behind the overlay, for either reason it is up: the server is offline, or it is being restarted. */
383
+ function openBridge() {
322
384
  mountMascot();
323
385
  const beaconAt = startBeaconTarget(window.location);
324
386
  const bridge = createStartBridge({
325
- probe: async () => {
326
- const health = await fetchHealth();
327
- return !!health && health.ok !== false;
328
- },
387
+ probe: probeServer,
329
388
  launch: () => openStartLink({ document, location: window.location, userAgent: navigator.userAgent }),
330
389
  beacon: beaconAt ? () => fetchStartBeacon(beaconAt) : null,
331
390
  port: beaconAt ? beaconAt.port : 0,
@@ -336,13 +395,91 @@ function watchForServer() {
336
395
  onState(state) {
337
396
  if (_offlineBridge !== bridge) return;
338
397
  if (state !== 'online') return;
398
+ // Back from a restart: the page loads again, after the frame that says so.
399
+ if (_restartShown) {
400
+ setTimeout(() => window.location.reload(), START_LIMITS.reloadDelayMs);
401
+ return;
402
+ }
339
403
  resetLoadingToConnecting();
340
404
  emit('loading:retried');
341
405
  if (_initCallback) _initCallback();
342
406
  },
343
407
  });
344
408
  _offlineBridge = bridge;
345
- bridge.watch();
409
+ return bridge;
410
+ }
411
+
412
+ // ═══════════════════════════════════════════
413
+ // Restart Server
414
+ // ═══════════════════════════════════════════
415
+
416
+ /**
417
+ * The user chose Restart Server. The screen changes here, in the click: the
418
+ * overlay is up and says a restart was asked for before the request has even
419
+ * left, and nothing on the way to that first frame waits for the network.
420
+ * From there it shows what is really known (start-bridge.js `restart()`): the
421
+ * server's answer, its own word that it is shutting down, the probe that finds
422
+ * it gone, the supervisor's report of bringing it back. The page loads again
423
+ * by itself when another server than the one that was asked answers.
424
+ */
425
+ export function requestServerRestart() {
426
+ return beginRestart({ request: postRestart });
427
+ }
428
+
429
+ /** Ask for the restart: { ok, boot } when the server says it will, { ok: false, status, message } when it will not. */
430
+ async function postRestart() {
431
+ const res = await fetch('/api/server/restart', { method: 'POST', signal: AbortSignal.timeout(10000) });
432
+ let body = null;
433
+ try { body = await res.json(); } catch {}
434
+ if (!res.ok || !body || body.ok === false) {
435
+ return { ok: false, status: res.status, message: String(body?.error || body?.message || '') };
436
+ }
437
+ return { ok: true, boot: typeof body.bootId === 'string' ? body.bootId : '' };
438
+ }
439
+
440
+ /**
441
+ * Show the restart: this window asked for it (`request`), or the server told
442
+ * every window that it is restarting (`announced`, over the sync socket).
443
+ */
444
+ function beginRestart({ request = null, announced = false, boot = '' } = {}) {
445
+ // Already on screen (this window asked, and here is the server saying so too).
446
+ if (_restartShown && _offlineBridge) {
447
+ _offlineBridge.restart({ announced, boot });
448
+ return false;
449
+ }
450
+ // The overlay is up because the server is offline: there is nothing to restart.
451
+ if (_offlineBridge) return false;
452
+ const $overlay = $('loading-overlay');
453
+ if (!$overlay) return false;
454
+
455
+ _restartShown = true;
456
+ _restartTitle = document.title;
457
+ document.title = t('loading.start.headingRestarting');
458
+ _offlineTitle = t('loading.serverOffline');
459
+ // `over-app`: no fade-in and above whatever is open. The screen is there in the frame of the click.
460
+ $overlay.classList.add('over-app', 'error', 'server-offline');
461
+ $overlay.classList.remove('hidden');
462
+ // Nothing behind the screen keeps the keyboard (a terminal, an editor).
463
+ try { document.activeElement?.blur?.(); } catch {}
464
+ if (_statusDot) _statusDot.classList.add('error');
465
+ const $action = $('loading-action');
466
+ if ($action) $action.style.display = 'block';
467
+ const $hint = $('loading-server-cmd-hint');
468
+ if ($hint) $hint.textContent = startButtonUsable(stored(START_STORAGE.launcher)) ? t('loading.runCommandOr') : t('loading.runCommandSetup');
469
+ const $retry = $('loading-retry-status');
470
+ if ($retry) $retry.textContent = '';
471
+ clearStartStatus();
472
+ return openBridge().restart({ request, announced, boot });
473
+ }
474
+
475
+ /** The restart did not happen and the server is still there: give the app back. */
476
+ function dismissRestart() {
477
+ resetLoadingToConnecting();
478
+ _restartShown = false;
479
+ if (_restartTitle !== null) document.title = _restartTitle;
480
+ _restartTitle = null;
481
+ const $overlay = $('loading-overlay');
482
+ if ($overlay) $overlay.classList.add('hidden');
346
483
  }
347
484
 
348
485
  // ═══════════════════════════════════════════
@@ -354,6 +491,8 @@ function watchForServer() {
354
491
  * Calls /api/health/start and re-triggers init on success.
355
492
  */
356
493
  async function handleStartAction() {
494
+ // A restart the server refused: the button is the way back to the app.
495
+ if (_offlineBridge && _offlineBridge.state === 'refused') { dismissRestart(); return; }
357
496
  // Server offline: nothing to call, the OS starts it.
358
497
  if (_offlineBridge) { _offlineBridge.start(); return; }
359
498
 
@@ -416,6 +555,8 @@ async function handleRetryConnection() {
416
555
  // fetchHealth uses AbortSignal.timeout(3000) internally
417
556
  if (health && health.ok !== false) {
418
557
  if ($status) $status.textContent = t('loading.connectedLoading');
558
+ // After a restart the page loads again (see openBridge).
559
+ if (_restartShown) { window.location.reload(); return; }
419
560
  resetLoadingToConnecting();
420
561
  emit('loading:retried');
421
562
  if (_initCallback) _initCallback();
@@ -463,4 +604,7 @@ export function initLoading({ onInit } = {}) {
463
604
  // ── Retry connection ──
464
605
  const retryBtn = $('loading-retry-btn');
465
606
  if (retryBtn) retryBtn.addEventListener('click', handleRetryConnection);
607
+
608
+ // ── The server says it is restarting (ui-sync.js): every window shows it ──
609
+ on('server:restarting', (msg) => beginRestart({ announced: true, boot: typeof msg?.bootId === 'string' ? msg.bootId : '' }));
466
610
  }
@@ -9,12 +9,13 @@ import { storage } from './storage.js';
9
9
  import { KEYS } from './constants.js';
10
10
  import { getMenuItems } from './registry.js';
11
11
  import { openHelp } from './ui-help.js';
12
- import { initPwaInstall, isStandalone, requestPwaInstall } from './pwa-install.js';
12
+ import { armPwaInstallHandoff, initPwaInstall, installGuideUrl, isStandalone, requestPwaInstall } from './pwa-install.js';
13
13
  import { registerAction } from './ui-keybinds.js';
14
14
  import { isGuest, hasPermission } from './ui-sync.js';
15
15
  import { sendToPanel } from './ui-claude-panel.js';
16
16
  import { forceCheckToolUpdates, showUpdateToast, TOOL_LABELS } from './ui-tool-updates.js';
17
17
  import { forceCheckSynabunUpdate, openSynabunUpdateModal } from './ui-update.js';
18
+ import { requestServerRestart } from './ui-loading.js';
18
19
 
19
20
  const $ = (id) => document.getElementById(id);
20
21
 
@@ -369,6 +370,7 @@ function wireAutomationsMenu() {
369
370
  // ── Apps Menu (formerly Terminal) ──
370
371
 
371
372
  function wireTerminalMenu() {
373
+ let disarmInstallHandoff = () => {};
372
374
  const items = {
373
375
  'menu-terminal-assistant': () => emit('assistant:open'),
374
376
  'menu-terminal-claude': () => emit('terminal:open', { profile: 'claude-code' }),
@@ -415,37 +417,14 @@ function wireTerminalMenu() {
415
417
  'menu-terminal-link': () => emit('link:toggle'),
416
418
  'menu-terminal-toggle': () => emit('terminal:toggle'),
417
419
  'menu-install-app': async () => {
420
+ disarmInstallHandoff(); // asked for here: this click opens the dialog, no later one does
418
421
  const result = await requestPwaInstall();
419
- if (result === 'instructions') location.assign('/install-app.html');
420
- },
421
- 'menu-restart-server': async () => {
422
- try {
423
- // Cache project path before server goes down
424
- try {
425
- const h = await fetch('/api/health');
426
- const hd = await h.json();
427
- if (hd.projectDir) localStorage.setItem('synabun-project-dir', hd.projectDir);
428
- } catch {}
429
- document.title = 'Restarting...';
430
- await fetch('/api/server/restart', { method: 'POST' });
431
-
432
- // Poll /api/health until the server has gone down AND come back up.
433
- // The everDown flag prevents premature reload during the brief window
434
- // where the old process is still serving requests during shutdown grace.
435
- const deadline = Date.now() + 15000;
436
- let everDown = false;
437
- while (Date.now() < deadline) {
438
- await new Promise(r => setTimeout(r, 250));
439
- try {
440
- const r = await fetch('/api/health', { cache: 'no-store' });
441
- if (!r.ok) { everDown = true; continue; }
442
- if (everDown) { location.reload(); return; }
443
- } catch { everDown = true; }
444
- }
445
- // Timeout safety net — reload anyway so the user isn't stranded.
446
- location.reload();
447
- } catch {}
422
+ if (result === 'instructions') location.assign(installGuideUrl());
448
423
  },
424
+ // The restart screen is drawn in this click, before anything is asked of
425
+ // the network; from there it follows the restart and loads the page again
426
+ // when the server is back (ui-loading.js requestServerRestart).
427
+ 'menu-restart-server': () => { requestServerRestart(); },
449
428
  'menu-stop-server': async () => {
450
429
  const previousTitle = document.title;
451
430
  try {
@@ -478,6 +457,9 @@ function wireTerminalMenu() {
478
457
  } });
479
458
  const installItem = $('menu-install-app');
480
459
  if (installItem && !isStandalone()) installItem.style.display = '';
460
+ // Sent on by the launcher's guide page: the browser's install dialog opens from the first click or key press,
461
+ // for this one page load. The event it uses is spent, so the menu item goes to the guide page after that.
462
+ disarmInstallHandoff = armPwaInstallHandoff({ leave: event => !!installItem?.contains(event.target) });
481
463
 
482
464
  }
483
465
 
@@ -92,3 +92,14 @@ export class LocalReleaseTracker {
92
92
  }
93
93
  }
94
94
  }
95
+
96
+ /**
97
+ * The saved list of dismissed runs (localStorage, `[{ runId, at }]`) without
98
+ * one run: what the agents dock's Focus leaves when it reopens a closed tab.
99
+ * Anything unreadable becomes an empty list.
100
+ */
101
+ export function withoutDismissed(raw, runId) {
102
+ let stored;
103
+ try { stored = JSON.parse(raw || '[]'); } catch { stored = []; }
104
+ return JSON.stringify((Array.isArray(stored) ? stored : []).filter((entry) => entry?.runId && entry.runId !== runId));
105
+ }
@@ -7,6 +7,7 @@ import {
7
7
  isNewerRunDescriptor,
8
8
  LocalReleaseTracker,
9
9
  resolveRouteClaim,
10
+ withoutDismissed,
10
11
  } from './ui-native-loop-router-state.js';
11
12
 
12
13
  const DISMISSED_KEY = 'synabun-native-loop-dismissed';
@@ -48,6 +49,15 @@ function mergeDismissed(raw) {
48
49
 
49
50
  try { mergeDismissed(localStorage.getItem(DISMISSED_KEY)); } catch {}
50
51
 
52
+ // A closed tab's run is dismissed: nothing routes it back here by itself (a
53
+ // reconcile, a late event, another window's claim). Only the user asks for it
54
+ // again, with the agents dock's Focus (focusNativeLoopRun with `reopen`).
55
+ function undismiss(runId) {
56
+ if (!_dismissed.delete(runId)) return false;
57
+ try { localStorage.setItem(DISMISSED_KEY, withoutDismissed(localStorage.getItem(DISMISSED_KEY), runId)); } catch {}
58
+ return true;
59
+ }
60
+
51
61
  function persistDismissed() {
52
62
  try {
53
63
  const existing = JSON.parse(localStorage.getItem(DISMISSED_KEY) || '[]');
@@ -279,10 +289,13 @@ export function getNativeLoopRun(runId) {
279
289
  * Bring a dispatched run's sidepanel tab to the front. Attaches with
280
290
  * focus:true even when this window already owns the claim (the normal route
281
291
  * path only focuses on first attach). Falls back to a fetch when the run has
282
- * not been broadcast to this window yet.
292
+ * not been broadcast to this window yet. With `reopen` (the user's own Focus,
293
+ * in the agents dock) a run whose tab was closed opens again: a live run
294
+ * attaches as it would have, an ended one with its transcript and end card.
283
295
  */
284
- export async function focusNativeLoopRun(runId) {
296
+ export async function focusNativeLoopRun(runId, { reopen = false } = {}) {
285
297
  if (!runId || _suspended) return false;
298
+ if (reopen) undismiss(runId);
286
299
  let run = getNativeLoopRun(runId);
287
300
  if (!run) {
288
301
  try {
@@ -8,6 +8,8 @@ import { initDetachedAgentSessions } from './ui-sidepanel-sessions.js';
8
8
  import { state, emit, on } from './state.js';
9
9
  import { getVariant } from './registry.js';
10
10
  import { KEYS } from './constants.js';
11
+ import { storage } from './storage.js';
12
+ import { t } from './i18n.js';
11
13
  import { loadIfaceConfig, saveIfaceConfig, applyIfaceConfig } from './ui-settings.js';
12
14
  import { registerAction } from './ui-keybinds.js';
13
15
  import { startTutorial } from './ui-tutorial.js';
@@ -324,33 +326,55 @@ export function initNavbar() {
324
326
  document.addEventListener('visibilitychange', () => { if (!document.hidden) updateClock(); });
325
327
  }
326
328
 
327
- // ── "Hide all toolbars" toggle (workspace toolbar + whiteboard tool rail) ──
328
- // Sidepanel buttons and the session-pill tray (#term-minimized-tray) stay visible.
329
- const collapseBtn = $('topright-collapse-btn');
329
+ // ── The workspace tools toggle (#topright-tools-btn) ──
330
+ // A plain on/off button for the dock (the workspace switcher and the tools), remembered across reloads. The agent
331
+ // buttons and the session pills stay where they are either way. A menu the dock had open closes with it.
330
332
  const controls = $('topright-controls');
331
- if (collapseBtn && controls) {
332
- const applyToolbarsHidden = (hidden) => {
333
- controls.classList.toggle('collapsed', hidden);
334
- // Body-level flag reaches #wb-toolbar, which lives outside #topright-controls.
335
- document.body.classList.toggle('toolbars-hidden', hidden);
336
- collapseBtn.setAttribute('data-tooltip', hidden ? 'Show all toolbars' : 'Hide all toolbars');
333
+ const toolsBtn = $('topright-tools-btn');
334
+ if (controls && toolsBtn) {
335
+ const showTools = (shown) => {
336
+ if (!shown) emit('panel:close-all-dropdowns');
337
+ controls.classList.toggle('tools-hidden', !shown);
338
+ const label = t(shown ? 'toolbar.hideTools' : 'toolbar.showTools');
339
+ toolsBtn.dataset.tooltip = label;
340
+ toolsBtn.setAttribute('aria-label', label);
341
+ toolsBtn.setAttribute('aria-expanded', String(shown));
337
342
  };
338
-
339
- // Restore persisted state
340
- applyToolbarsHidden(localStorage.getItem('synabun-toolbar-collapsed') === '1');
341
-
342
- collapseBtn.addEventListener('click', (e) => {
343
- e.stopPropagation();
344
- const hidden = !controls.classList.contains('collapsed');
345
- applyToolbarsHidden(hidden);
346
- localStorage.setItem('synabun-toolbar-collapsed', hidden ? '1' : '0');
347
- // Close any open dropdowns when hiding
348
- if (hidden) emit('panel:close-all-dropdowns');
343
+ showTools(storage.getItem(KEYS.TOPRIGHT_TOOLS_HIDDEN) !== 'true');
344
+ toolsBtn.addEventListener('click', () => {
345
+ const shown = controls.classList.contains('tools-hidden');
346
+ showTools(shown);
347
+ storage.setItem(KEYS.TOPRIGHT_TOOLS_HIDDEN, String(!shown));
349
348
  });
349
+ }
350
350
 
351
- registerAction('toggle-toolbar', () => collapseBtn.click());
351
+ // ── Session pills in the row: the whole name is the tooltip ──
352
+ // Laid out in a row, a pill keeps its width on hover (styles.css): widening, it would push the others onto another
353
+ // line under the pointer. A name cut short is read from the tooltip instead; a pill that brings a tooltip of its own
354
+ // (the Assistant's) keeps it.
355
+ const tray = $('term-minimized-tray');
356
+ if (controls && tray && controls.contains(tray)) {
357
+ const nameTips = () => {
358
+ for (const pill of tray.children) {
359
+ const name = pill.querySelector('.term-minimized-pill-label')?.textContent.trim() || '';
360
+ if (pill.hasAttribute('data-tooltip') && pill.dataset.tooltip !== pill.dataset.nameTip) {
361
+ delete pill.dataset.nameTip;
362
+ } else if (name) {
363
+ pill.dataset.tooltip = name;
364
+ pill.dataset.nameTip = name;
365
+ } else if (pill.dataset.nameTip != null) {
366
+ pill.removeAttribute('data-tooltip');
367
+ delete pill.dataset.nameTip;
368
+ }
369
+ }
370
+ };
371
+ new MutationObserver(nameTips).observe(tray, { childList: true, subtree: true, characterData: true });
372
+ nameTips();
352
373
  }
353
374
 
375
+ // "Hide all toolbars" is gone: whoever had it on gets every toolbar back, and its key goes with it.
376
+ try { localStorage.removeItem('synabun-toolbar-collapsed'); } catch { /* storage refused: nothing to clear */ }
377
+
354
378
  // ── Update alert ──
355
379
  initUpdate();
356
380
  initToolUpdates();