synabun 2.0.0 → 2.0.7

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