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
@@ -174,11 +174,29 @@ export function getLocaleChoice() {
174
174
  return matchLocale(saved) || SYSTEM_LOCALE;
175
175
  }
176
176
 
177
+ /**
178
+ * The locale the page address asks for with `?lang=<tag>`, matched like a stored choice
179
+ * ('pt' → 'pt-BR'), or null (no tag, or one no locale answers). It holds for this page
180
+ * load only and is never stored: showcase captures use it to get an English UI without
181
+ * touching the user's own choice.
182
+ */
183
+ export function getAddressLocale() {
184
+ const search = globalThis.window?.location?.search;
185
+ if (!search) return null;
186
+ try {
187
+ return matchLocale(new URLSearchParams(search).get('lang'));
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+
177
193
  /**
178
194
  * Detect the user's preferred locale.
179
- * Priority: stored explicit choice → system language → 'en'
195
+ * Priority: the page address (?lang=) → stored explicit choice → system language → 'en'
180
196
  */
181
197
  function detectLocale() {
198
+ const address = getAddressLocale();
199
+ if (address) return address;
182
200
  const choice = getLocaleChoice();
183
201
  return choice === SYSTEM_LOCALE ? getSystemLocale() : choice;
184
202
  }
@@ -0,0 +1,86 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — the setup wizard's Details: what they say
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Inside the SynaBun desktop app, the setup wizard (onboarding.html) shows
6
+ // what it checked and what this copy has, step by step, in a Details area
7
+ // under Environment Check and under Install & Build: the commands SynaBun ran
8
+ // and what they answered, where `npm i -g` puts packages, and every part's
9
+ // dependencies with the version installed. The facts are
10
+ // GET /api/setup/install-details (lib/install-details.js); this turns them into
11
+ // the lines shown. English, like the rest of the wizard.
12
+ //
13
+ // No imports and no DOM: `node --test` loads this file as it is
14
+ // (tests/install-details-view.test.mjs).
15
+
16
+ const said = (tool) => (tool.ok ? tool.output || '(no answer)' : `did not run: ${tool.output || 'no output'}`);
17
+
18
+ /** Environment Check: the Node.js SynaBun runs on, its npm and npx (the command and the answer), and the user's own npm. */
19
+ export function environmentLines(details) {
20
+ if (!details || typeof details !== 'object') return [];
21
+ const lines = [];
22
+ const node = details.node;
23
+ if (node) {
24
+ lines.push('$ node --version');
25
+ lines.push(`${node.version} ${node.path}${node.bundled ? ' (the Node.js that came with SynaBun)' : ''}`);
26
+ }
27
+ for (const name of ['npm', 'npx']) {
28
+ const tool = details[name];
29
+ if (!tool) { lines.push(`${name}: not found`); continue; }
30
+ lines.push(`$ ${tool.command}`);
31
+ lines.push(`${said(tool)}${tool.ok && tool.bundled ? ' (came with SynaBun)' : ''}`);
32
+ }
33
+ const prefix = details.globalPrefix;
34
+ if (prefix?.path) {
35
+ const setIn = prefix.from === 'npm_config_prefix' ? ', from npm_config_prefix' : prefix.from ? `, set in ${prefix.from}` : '';
36
+ const why = prefix.source === 'user' ? `your own npm prefix${setIn}` : 'a folder of SynaBun\'s, outside the app';
37
+ lines.push(`npm i -g installs into ${prefix.path} (${why})${prefix.bin ? `, commands in ${prefix.bin}` : ''}`);
38
+ }
39
+ if (details.kind === 'app') {
40
+ const user = details.userNpm;
41
+ lines.push(user
42
+ ? `Your own npm: ${user.path} ${user.ok ? user.output : '(did not answer)'}. SynaBun's terminals find it first.`
43
+ : 'No npm of your own: SynaBun\'s terminals use the one that came with SynaBun.');
44
+ }
45
+ return lines;
46
+ }
47
+
48
+ /** One part's packages: how many, then each dependency with the version installed. */
49
+ function partLines(part, bundled) {
50
+ const lines = [`${part.name}: ${part.packages} package${part.packages === 1 ? '' : 's'} installed${bundled ? ' (came with SynaBun)' : ''}`];
51
+ for (const dep of part.dependencies || []) {
52
+ lines.push(` ${dep.name} ${dep.installed || `not installed (wants ${dep.wanted})`}`);
53
+ }
54
+ return lines;
55
+ }
56
+
57
+ /** Install & Build: what this copy has, from the runtime to every dependency, and what is still to come. */
58
+ export function installLines(details) {
59
+ if (!details || typeof details !== 'object') return [];
60
+ const app = details.kind === 'app';
61
+ const lines = [];
62
+ if (app) {
63
+ const where = details.app?.target ? ` for ${details.app.target}` : '';
64
+ lines.push(`SynaBun ${details.app?.version || ''}${where}: nothing to install, this copy came with its dependencies.`.replace(/\s+:/, ':'));
65
+ }
66
+ if (details.node) {
67
+ const npm = details.npm?.ok ? `, npm ${details.npm.output}` : '';
68
+ const npx = details.npx?.ok ? `, npx ${details.npx.output}` : '';
69
+ lines.push(`Node.js ${String(details.node.version).replace(/^v/, '')}${npm}${npx}${details.node.bundled ? ' (the runtime that came with SynaBun)' : ''}`);
70
+ }
71
+ for (const part of details.parts || []) lines.push(...partLines(part, app));
72
+ lines.push(details.mcp?.built ? `MCP server: built (${details.mcp.file})` : 'MCP server: not built yet');
73
+ const bundled = details.bundled;
74
+ if (bundled) {
75
+ lines.push(bundled.embeddingModel ? `Local embedding model: ${bundled.embeddingModel} (came with SynaBun)` : 'Local embedding model: not included (keyword recall only)');
76
+ if (bundled.cloudflared) lines.push(`cloudflared ${bundled.cloudflared}, for invite links and remote MCP (came with SynaBun)`);
77
+ if (bundled.gitBash) lines.push(`Git for Windows ${bundled.gitBash}, the Git Bash Claude Code needs (came with SynaBun)`);
78
+ if (details.app?.electron) lines.push(`The window: Electron ${details.app.electron}`);
79
+ }
80
+ if (details.browser) {
81
+ lines.push(details.browser.installed
82
+ ? `Automation browser (Chromium for Playwright): installed, ${details.browser.path}`
83
+ : 'Automation browser (Chromium for Playwright): not downloaded yet; SynaBun downloads it at its next start.');
84
+ }
85
+ return lines;
86
+ }
@@ -18,6 +18,8 @@
18
18
 
19
19
  import { state, emit } from '../state.js';
20
20
  import { injectStyles } from './ocp-v2-styles.js';
21
+ import { getDefaultStore } from './ocp-v2-state.js';
22
+ import { wireFileLinks } from '../ui-file-links.js';
21
23
  import { mountRenderer } from './ocp-v2-render.js';
22
24
  import { mountCompose } from './ocp-v2-send.js';
23
25
  import { trackContextGauge } from './ocp-v2-context-gauge.js';
@@ -212,6 +214,8 @@ export function createChildPanel({
212
214
  messages.className = 'ocpv2-messages';
213
215
  messagesContainer.appendChild(messages);
214
216
  panel.appendChild(messagesContainer);
217
+ // File links open in the code editor, as in the main panel: a sub-agent works in its parent's directory.
218
+ wireFileLinks(messagesContainer, { cwd: () => store.getState().cwd || getDefaultStore().getState().cwd || '' });
215
219
 
216
220
  // This panel's own questions (closing it with prompts waiting, deleting a
217
221
  // message) show above its compose box.
@@ -0,0 +1,47 @@
1
+ // OpenCode panel — the greeting in the empty state (shared/greeting/, lib/greeting/).
2
+ //
3
+ // What SynaBun says when a person comes back and opens a new session: one or
4
+ // two sentences, written by SynaBun ahead of time (the session's model never
5
+ // greets). Only for a session with nothing in it that a person opened: never
6
+ // an automation run's. The greeting's id goes back with the first message
7
+ // (`greetingId` on message:send), so the model is told once what was said.
8
+ // A server older than this page simply answers nothing.
9
+
10
+ import { clearGreeting, forgetGreeting, mountGreeting } from '../greeting/greeting-card.js';
11
+
12
+ const SURFACE = 'opencode-panel';
13
+ let pending = null; // { id, sessionId } — the greeting on screen, until a first message carries it
14
+
15
+ /**
16
+ * The empty state is on screen. `host`: its element (kept between renders, so asked once).
17
+ * ctx: { sessionId, cwd, automation, onOpenMemory(id), isCurrent() }
18
+ */
19
+ export function offerGreeting(host, { sessionId = null, cwd = '', automation = false, onOpenMemory = null, isCurrent = null } = {}) {
20
+ if (!host) return;
21
+ const key = sessionId || '';
22
+ if (host.dataset.greetingFor === key && host.dataset.greetingAsked === '1') return;
23
+ host.dataset.greetingFor = key;
24
+ host.dataset.greetingAsked = '1';
25
+ clearGreeting(host);
26
+ if (automation) return;
27
+ mountGreeting(host, {
28
+ surface: SURFACE, session: sessionId || null, cwd,
29
+ onOpenMemory,
30
+ isCurrent: () => host.dataset.greetingFor === key && (typeof isCurrent !== 'function' || isCurrent() !== false),
31
+ }).then((greeting) => {
32
+ if (greeting && host.dataset.greetingFor === key) pending = { id: greeting.id, sessionId: sessionId || null };
33
+ }).catch(() => { /* a session always opens */ });
34
+ }
35
+
36
+ /** The id to send with a person's message to `sessionId`, once ('' when this session opened with no greeting). */
37
+ export function takeGreetingId(sessionId) {
38
+ const held = pending;
39
+ if (!held) return '';
40
+ // A greeting shown before the session had an id belongs to the first session a message goes to.
41
+ if (held.sessionId && sessionId && held.sessionId !== sessionId) return '';
42
+ pending = null;
43
+ if (held.sessionId) forgetGreeting(SURFACE, held.sessionId);
44
+ return held.id || '';
45
+ }
46
+
47
+ export const _test = { reset() { pending = null; }, pending: () => pending };
@@ -43,13 +43,18 @@ import { mountChangesBar } from './ocp-v2-changes.js';
43
43
  import { mountEnvironmentPopover } from './ocp-v2-status.js';
44
44
  import { watchWorktree, newSessionPlan, checkoutOutcome } from './ocp-v2-changes-logic.js';
45
45
  import { mountRenderer } from './ocp-v2-render.js';
46
+ import { offerGreeting } from './ocp-v2-greeting.js';
46
47
  import { mountCompose, focusCompose, appendPathToCompose } from './ocp-v2-send.js';
47
48
  import { mountProjectBar, unmountProjectBar } from './ocp-v2-projectbar.js';
48
49
  import { registerSidepanel, syncSidepanelLayout, focusSidepanel, openAnotherSidepanelSession, isHostedSessionFocused } from '../ui-sidepanel-windows.js';
49
50
  import { nativeLoopWindowId } from '../ui-native-window-id.js';
50
51
  import { requestGeneratedSessionTitle } from '../session-title.js';
52
+ import { wireFileLinks } from '../ui-file-links.js';
53
+ import { mountCliBanner } from '../ui-cli-banner.js';
54
+ import { backToAssistant, buildWorkerEndCard, endWorkerRunOnClose, forgetWorkerEnd, trackWorkerEnd } from '../ui-worker-end.js';
55
+ import { isDispatchedRun } from '../worker-end.js';
51
56
  import {
52
- registerAutomationSession, unregisterAutomationSession, stopAutomationRun,
57
+ registerAutomationSession, unregisterAutomationSession, stopAutomationRun, isAutomationSession,
53
58
  } from './ocp-v2-automation-ownership.js';
54
59
  import {
55
60
  registerPrimaryPanel, bindPrimarySession, isChildPanelOpen, getVisibleChildPanel, openChildSession,
@@ -92,6 +97,8 @@ const _automationRunning = new Set();
92
97
  const _automationContinuedManually = new Set();
93
98
  const _automationManualSendInFlight = new Set();
94
99
  const _foreignActiveAutomationSessions = new Set();
100
+ const _workerEnds = new Map(); // sessionId -> end card of the dispatched worker it belongs to (ui-worker-end.js)
101
+ let _renderer = null;
95
102
  let _visible = false;
96
103
  let _booted = false;
97
104
  let _bootPromise = null;
@@ -115,6 +122,8 @@ const _titleReassertTimers = new Map();
115
122
  // rename carries is not the session's: nothing shows it or pushes it again.
116
123
  const _pendingRenames = createPendingRenames();
117
124
  let _composer = null; // the primary panel's composer (mountCompose)
125
+ let _cliBanner = null; // the CLI banner and send-block (ui-cli-banner.js)
126
+ let _cliWasBlocked = false; // the banner held sends back last time it said (a change to usable heals the serve)
118
127
  // Where the panel goes. Every choice of the user (a tab, a session in the
119
128
  // menu, New session, a project, a worktree) begins an intent, and a navigation
120
129
  // binds the panel only while its intent is the latest one: a later choice wins
@@ -420,6 +429,33 @@ function buildPanel() {
420
429
  messages.className = 'ocpv2-messages';
421
430
  messagesContainer.appendChild(messages);
422
431
  panel.appendChild(messagesContainer);
432
+ // A link to a file the code editor can open opens it there (shared with the other panels). A relative
433
+ // path is a path in the session's directory.
434
+ wireFileLinks(messagesContainer, { cwd: () => getState().cwd || '' });
435
+
436
+ // ── The CLI banner (ui-cli-banner.js) ───────────────────────────────────
437
+ // Above the transcript while OpenCode is not usable: not installed (with
438
+ // Install, which runs OpenCode's own installer or official release on the
439
+ // server), being installed, failed to install, or found but failed to start
440
+ // (with the error it gave). The panel gets `ocp-cli-blocked` meanwhile, and
441
+ // the composer holds sends back (sendBlocked below).
442
+ _cliBanner = mountCliBanner({
443
+ toolKey: 'opencode',
444
+ prefix: 'ocp',
445
+ panel: () => panel,
446
+ anchor: () => messagesContainer,
447
+ // OpenCode was installed (or found again) while its serve could not start: start it now rather than at the
448
+ // next retry of the auto-heal, whose wait has grown by then.
449
+ onBlockedChange: (blocked) => {
450
+ const usableAgain = _cliWasBlocked && !blocked;
451
+ _cliWasBlocked = blocked;
452
+ if (usableAgain && getState().serverStatus !== 'ready') {
453
+ clearTimeout(_healTimer);
454
+ _healTimer = null;
455
+ scheduleAutoHeal('cli-usable', 0);
456
+ }
457
+ },
458
+ });
423
459
 
424
460
  // ── What the session changed on disk (session.diff) ─────────────────────
425
461
  mountChangesBar(panel, getDefaultStore());
@@ -445,7 +481,17 @@ function buildPanel() {
445
481
  });
446
482
 
447
483
  let composer = null;
448
- const renderer = mountRenderer(messages, getDefaultStore(), {
484
+ const renderer = _renderer = mountRenderer(messages, getDefaultStore(), {
485
+ // A dispatched worker's end: the last card of its session's transcript.
486
+ endCard: (s) => workerEndCard(s?.sessionId),
487
+ // SynaBun's greeting for a person who comes back to a new session: never for an automation run's.
488
+ onEmpty: (host, s) => offerGreeting(host, {
489
+ sessionId: s?.sessionId || null,
490
+ cwd: s?.cwd || '',
491
+ automation: !!s?.sessionId && (_automationRunIds.has(s.sessionId) || isAutomationSession(s.sessionId)),
492
+ onOpenMemory: (id) => { if (id) emit('memory:open', { id }); },
493
+ isCurrent: () => (getState().sessionId || null) === (s?.sessionId || null) && getState().messageOrder.length === 0,
494
+ }),
449
495
  onOpenSession: (session, extra) => openCreatedSession(session, extra),
450
496
  // Fork is a navigation: its intent begins at the click, and the fork takes
451
497
  // the panel only while that click is still the user's latest choice.
@@ -500,11 +546,26 @@ function buildPanel() {
500
546
  // (ocp-v2-binding.js): the session the prompt or the Stop was for, frozen
501
547
  // before the first await. It is never the live state.
502
548
  canSend: (session) => !_automationRunning.has(session?.sessionId),
549
+ // While the CLI banner shows (OpenCode missing, broken or being installed),
550
+ // a send stays in the box and the banner is pointed at instead.
551
+ sendBlocked: () => !!_cliBanner?.blocked(),
552
+ onSendBlocked: () => _cliBanner?.nudge(),
503
553
  onManualSend: (session, phase, meta) => {
504
554
  const sessionId = session?.sessionId;
505
555
  if (phase === 'started') requestOpenCodeSessionTitle(session, meta);
506
556
  if (!sessionId || !_automationRunIds.has(sessionId) || _automationRunning.has(sessionId)) return;
507
- if (phase === 'started') _automationManualSendInFlight.add(sessionId);
557
+ if (phase === 'started') {
558
+ const first = !_automationContinuedManually.has(sessionId) && !_automationManualSendInFlight.has(sessionId);
559
+ _automationManualSendInFlight.add(sessionId);
560
+ if (first) {
561
+ // The tab is the user's from here on (Codex's releaseAutomationForManualUse): the run's
562
+ // end card goes, and the router leaves the run alone, so nothing of it comes back here.
563
+ const runId = _automationRunIds.get(sessionId);
564
+ forgetWorkerEnd(runId);
565
+ showWorkerEnd(sessionId, null);
566
+ window.dispatchEvent(new CustomEvent('native-loop:dismissed', { detail: { runId } }));
567
+ }
568
+ }
508
569
  if (phase === 'failed') _automationManualSendInFlight.delete(sessionId);
509
570
  if (phase === 'succeeded') {
510
571
  _automationManualSendInFlight.delete(sessionId);
@@ -2180,6 +2241,7 @@ function applyVisibility(nextVisible) {
2180
2241
  _panelEl.classList.toggle('ocpv2-open', _visible);
2181
2242
  if (_visible) {
2182
2243
  state.lastActivePanel = 'opencode';
2244
+ _cliBanner?.refresh();
2183
2245
  } else {
2184
2246
  // The popover is a child of <body>: it does not go with the panel by itself.
2185
2247
  _contextMenu?.close();
@@ -2238,11 +2300,12 @@ function dismissAutomationSession(sessionId) {
2238
2300
  if (!runId) return false;
2239
2301
  window.dispatchEvent(new CustomEvent('native-loop:dismissed', { detail: { runId } }));
2240
2302
  if (_automationRunning.has(sessionId)) {
2241
- fetch('/api/loop/stop', {
2303
+ // A worker that finished its task is completed; any other run is stopped.
2304
+ endWorkerRunOnClose(runId, () => fetch('/api/loop/stop', {
2242
2305
  method: 'POST',
2243
2306
  headers: { 'Content-Type': 'application/json' },
2244
2307
  body: JSON.stringify({ runId }),
2245
- }).catch(() => {});
2308
+ }).catch(() => {}));
2246
2309
  }
2247
2310
  return true;
2248
2311
  }
@@ -2317,6 +2380,8 @@ function removeTab(sessionId, { byUser = false } = {}) {
2317
2380
  const titleTimer = _titleReassertTimers.get(sessionId);
2318
2381
  if (titleTimer) clearTimeout(titleTimer);
2319
2382
  _titleReassertTimers.delete(sessionId);
2383
+ forgetWorkerEnd(_automationRunIds.get(sessionId));
2384
+ _workerEnds.delete(sessionId);
2320
2385
  _automationRunIds.delete(sessionId);
2321
2386
  unregisterAutomationSession(sessionId);
2322
2387
  _automationRunning.delete(sessionId);
@@ -2354,22 +2419,56 @@ function createTabPill(sessionId) {
2354
2419
  if (event.target.closest('.term-minimized-pill-close')) return;
2355
2420
  handlePillClick(sessionId);
2356
2421
  });
2357
- pill.querySelector('.term-minimized-pill-close')?.addEventListener('click', async (event) => {
2422
+ pill.querySelector('.term-minimized-pill-close')?.addEventListener('click', (event) => {
2358
2423
  event.stopPropagation();
2359
- // Mirror header X. Native transcripts are preserved unless the user has
2360
- // continued the terminal automation manually; backend cleanup is best-effort.
2361
- // Asked first when prompts are still waiting in that session; declined:
2362
- // the tab stays and nothing is deleted.
2363
- if (!(await mayCloseTab(sessionId))) return;
2364
- const wasRunning = sessionId === getState().sessionId && !!getState().running;
2365
- closeSessionBackend(sessionId, { wasRunning, context: 'pill close' }).catch(() => {});
2366
- try { await handlePillClose(sessionId, { byUser: true }); }
2367
- catch (err) { console.warn('[ocp-v2-panel] local pill close failed', err); }
2424
+ closeTabByUser(sessionId, 'pill close');
2368
2425
  });
2369
2426
  tray.appendChild(pill);
2370
2427
  return pill;
2371
2428
  }
2372
2429
 
2430
+ // Mirror header X. Native transcripts are preserved unless the user has
2431
+ // continued the terminal automation manually; backend cleanup is best-effort.
2432
+ // Asked first when prompts are still waiting in that session; declined: the
2433
+ // tab stays, nothing is deleted, and this resolves false.
2434
+ async function closeTabByUser(sessionId, context) {
2435
+ if (!(await mayCloseTab(sessionId))) return false;
2436
+ const wasRunning = sessionId === getState().sessionId && !!getState().running;
2437
+ closeSessionBackend(sessionId, { wasRunning, context }).catch(() => {});
2438
+ try { await handlePillClose(sessionId, { byUser: true }); }
2439
+ catch (err) { console.warn(`[ocp-v2-panel] local ${context} failed`, err); }
2440
+ return true;
2441
+ }
2442
+
2443
+ // The end of a worker the Assistant dispatched: its button closes the tab the
2444
+ // way the tab's X does (a warm worker that finished its task is completed, one
2445
+ // still at work is stopped; its record stays for the Assistant) and shows the
2446
+ // Assistant session that dispatched it.
2447
+ function workerEndCard(sessionId) {
2448
+ const view = sessionId ? _workerEnds.get(sessionId) : null;
2449
+ if (!view) return null;
2450
+ return {
2451
+ sig: view.sig,
2452
+ build: () => buildWorkerEndCard(view, {
2453
+ classes: {
2454
+ card: 'ocpv2-post-plan-card ocpv2-worker-end', title: 'ocpv2-post-plan-header', detail: 'ocpv2-post-plan-body',
2455
+ meta: 'ocpv2-post-plan-saved', note: 'ocpv2-post-plan-note', actions: 'ocpv2-post-plan-actions', button: 'ocpv2-post-plan-btn primary',
2456
+ },
2457
+ onBack: async () => {
2458
+ if (!(await closeTabByUser(sessionId, 'worker end close'))) return false;
2459
+ backToAssistant(view.assistantSessionId);
2460
+ return true;
2461
+ },
2462
+ }),
2463
+ };
2464
+ }
2465
+
2466
+ function showWorkerEnd(sessionId, view) {
2467
+ if (view) _workerEnds.set(sessionId, view);
2468
+ else if (!_workerEnds.delete(sessionId)) return;
2469
+ _renderer?.render();
2470
+ }
2471
+
2373
2472
  function escapeHtml(s) {
2374
2473
  return String(s || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
2375
2474
  }
@@ -2539,9 +2638,12 @@ export async function attachOpenCodeAutomation(run, { focus = !!run?.focus, isCa
2539
2638
  // Establish ownership before connect()/boot(): native provider events use a
2540
2639
  // separate socket and may report a Task child while this attach is awaiting.
2541
2640
  const previousRunId = _automationRunIds.get(sessionId);
2641
+ const running = run.status === 'starting' || run.status === 'running';
2642
+ // The user continued this run's session by hand after the run ended: the tab stays theirs.
2643
+ const released = !running && previousRunId === run.runId
2644
+ && (_automationContinuedManually.has(sessionId) || _automationManualSendInFlight.has(sessionId));
2542
2645
  _automationRunIds.set(sessionId, run.runId);
2543
2646
  registerAutomationSession(sessionId, run.runId);
2544
- const running = run.status === 'starting' || run.status === 'running';
2545
2647
  if (running || previousRunId !== run.runId) {
2546
2648
  _automationContinuedManually.delete(sessionId);
2547
2649
  _automationManualSendInFlight.delete(sessionId);
@@ -2565,6 +2667,16 @@ export async function attachOpenCodeAutomation(run, { focus = !!run?.focus, isCa
2565
2667
  await handlePillClose(sessionId).catch(() => {});
2566
2668
  return { ok: false, reason: 'dismissed' };
2567
2669
  }
2670
+ if (released) {
2671
+ // The dock's Focus raises it; the run is let go again, and nothing in the tab changes.
2672
+ window.dispatchEvent(new CustomEvent('native-loop:dismissed', { detail: { runId: run.runId } }));
2673
+ if (focus && _nav.latest() === attachBegan && _tabSessionIds.includes(sessionId)) {
2674
+ const nav = _nav.observe();
2675
+ if (!_visible) await showPrimaryOpencodePanel();
2676
+ await switchToSession(sessionId, _tabInfoCache.get(sessionId) || null, { nav });
2677
+ }
2678
+ return { ok: true, sessionId, released: true };
2679
+ }
2568
2680
  ensureTab(sessionId, info);
2569
2681
  if (focus && _nav.latest() === attachBegan) {
2570
2682
  // (Its own navigation, observed after boot landed: a click made while the
@@ -2577,13 +2689,15 @@ export async function attachOpenCodeAutomation(run, { focus = !!run?.focus, isCa
2577
2689
  await rehydrateActiveSession().catch(() => {});
2578
2690
  }
2579
2691
  if (getState().sessionId === sessionId) setRunning(running);
2580
- if (run.status === 'failed' && run.error && getState().sessionId === sessionId
2692
+ // (A dispatched worker's failure, with its reason, is on its end card.)
2693
+ if (run.status === 'failed' && run.error && !isDispatchedRun(run) && getState().sessionId === sessionId
2581
2694
  && _tabInfoCache.get(sessionId)?._automationLifecycleError !== run.error) {
2582
2695
  const cachedInfo = _tabInfoCache.get(sessionId) || info;
2583
2696
  cachedInfo._automationLifecycleError = run.error;
2584
2697
  _tabInfoCache.set(sessionId, _stoppedShares.clean(cachedInfo));
2585
2698
  pushError({ message: run.error });
2586
2699
  }
2700
+ trackWorkerEnd(run, { apply: (view) => showWorkerEnd(sessionId, view) });
2587
2701
  renderPill();
2588
2702
  return { ok: true, sessionId };
2589
2703
  }
@@ -212,9 +212,13 @@ function render(_container, store, opts = {}) {
212
212
  );
213
213
  const questions = requestsVisibleIn(s.pendingQuestions, s.sessionId, isKnownDescendantSession);
214
214
  const retry = retryBannerView(s.sessionStatus);
215
- const hasInteractiveCards = permissions.length > 0 || questions.length > 0 || !!s.showPostPlanActions;
215
+ // The panel's last card for the session on screen (a dispatched worker's end): { sig, build } or null.
216
+ const endCard = typeof opts.endCard === 'function' ? opts.endCard(s) : null;
217
+ const hasInteractiveCards = permissions.length > 0 || questions.length > 0 || !!s.showPostPlanActions || !!endCard;
216
218
  if (s.messageOrder.length === 0 && !hasInteractiveCards && !s.errors.length && !retry && !revertBanner) {
217
219
  _reconcile(_container, [{ key: '__empty__', sig: 'empty', build: _buildEmpty }]);
220
+ // The panel may put SynaBun's greeting in it (ocp-v2-greeting.js).
221
+ try { opts.onEmpty?.(_container.querySelector(':scope > .ocpv2-empty'), s); } catch { /* the empty state stands on its own */ }
218
222
  return;
219
223
  }
220
224
 
@@ -346,6 +350,8 @@ function render(_container, store, opts = {}) {
346
350
  });
347
351
  }
348
352
 
353
+ if (endCard) desired.push({ key: 'end', sig: `end:${endCard.sig}`, build: endCard.build });
354
+
349
355
  _reconcile(_container, desired);
350
356
  }
351
357
 
@@ -33,6 +33,7 @@ import {
33
33
  } from './ocp-v2-send-logic.js';
34
34
  import { hydrateTranscript } from './ocp-v2-rehydrate.js';
35
35
  import { captureBinding, trackBinding, isBindingToken, searchOnBinding } from './ocp-v2-binding.js';
36
+ import { takeGreetingId } from './ocp-v2-greeting.js';
36
37
 
37
38
  const STOR_MODE = 'opencode-v2-mode'; // the last agent picked (build / plan / a custom one)
38
39
  const STOR_HISTORY = 'ocp-v2-prompt-history';
@@ -965,6 +966,16 @@ export function mountCompose(rootEl, store = getDefaultStore(), opts = {}) {
965
966
  syncButton();
966
967
  }
967
968
 
969
+ // The panel holds sends back while its CLI banner shows (opts.sendBlocked,
970
+ // ui-cli-banner.js): nothing is sent, nothing is cleared, the banner is
971
+ // pointed at. A composer mounted without the option (a sub-agent's) never is.
972
+ function sendHeldBack() {
973
+ let held = false;
974
+ try { held = !!opts.sendBlocked?.(); } catch { held = false; }
975
+ if (held) { try { opts.onSendBlocked?.(); } catch {} }
976
+ return held;
977
+ }
978
+
968
979
  function rememberPrompt(text) {
969
980
  if (!text) return;
970
981
  _history.push(text);
@@ -1037,6 +1048,7 @@ export function mountCompose(rootEl, store = getDefaultStore(), opts = {}) {
1037
1048
  // read this snapshot.
1038
1049
  const turn = captureBinding(store);
1039
1050
  if (!turn.sessionId) { store.pushError({ message: 'No session. Reopen the panel to retry.' }); return false; }
1051
+ if (sendHeldBack()) return false;
1040
1052
  if (opts.canSend && opts.canSend(turn) === false) {
1041
1053
  store.pushError({ message: 'Stop the running automation before sending a manual turn.' });
1042
1054
  return false;
@@ -1139,6 +1151,11 @@ export function mountCompose(rootEl, store = getDefaultStore(), opts = {}) {
1139
1151
  const hasPaths = (s.pendingPaths?.length || 0) > 0;
1140
1152
 
1141
1153
  if (_shell) {
1154
+ // The CLI is missing, broken or being installed (the panel's CLI banner
1155
+ // says so): the command stays in the box, in shell mode. (Prompts and
1156
+ // server commands are held back where they are sent, and come back into
1157
+ // the box from there; a local slash command needs no CLI.)
1158
+ if (sendHeldBack()) return false;
1142
1159
  // Only what the user typed (or pasted) into the shell-mode composer runs.
1143
1160
  // Anything that got into the box another way drops back to a prompt.
1144
1161
  const allowed = shellRunAllowed({ shell: _shell, value: _input.value, typedValue: _shellTypedValue });
@@ -1223,6 +1240,7 @@ export function mountCompose(rootEl, store = getDefaultStore(), opts = {}) {
1223
1240
  // first await; everything after it reads `turn`.
1224
1241
  const turn = captureBinding(store);
1225
1242
  const s = store.getState();
1243
+ if (sendHeldBack()) return false;
1226
1244
  if (opts.canSend && opts.canSend(turn) === false) {
1227
1245
  store.pushError({ message: 'Stop the running automation before sending a manual turn.' });
1228
1246
  return false;
@@ -1449,6 +1467,10 @@ export function mountCompose(rootEl, store = getDefaultStore(), opts = {}) {
1449
1467
  variant: turn.variant || undefined,
1450
1468
  cwd: options.cwd || turn.cwd || undefined,
1451
1469
  mcpProfile: turn.mcpProfile || undefined,
1470
+ // A person's own message (the greeting engine keeps when they were last here), and the
1471
+ // greeting this session opened with, told to the model once.
1472
+ human: true,
1473
+ greetingId: takeGreetingId(turnSessionId) || undefined,
1452
1474
  });
1453
1475
  if (res?.error) return failSend(shouldSuppressAbortError(res.error) ? '' : res.error);
1454
1476
  // Delivered: that stands, whatever the panel shows by now.