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,21 +1,27 @@
1
1
  // ═══════════════════════════════════════════
2
2
  // SynaBun Assistant — account profiles (Claude + Codex)
3
3
  // ═══════════════════════════════════════════
4
- // Claude: POST /api/assistant/claude/accounts → POST …/:id/login opens a
5
- // claude-code terminal tab under CLAUDE_CONFIG_DIR (emit terminal:attach-floating)
6
- // → wait for sync:assistant:accounts-changed. Codex: POST …/codex/accounts/add-start
7
- // → show the device-auth URL/code → poll fetchCodexAccounts(true).
4
+ // One manager for both providers, from the same server state as the side
5
+ // panels' header account menus (lib/claude-accounts.js, lib/codex-accounts.js
6
+ // describe()): every account with what it runs on and who it is, its "Uses"
7
+ // switch when it holds both credentials, each credential's sign-in or sign-out,
8
+ // an API key pasted into it, the worker choice, rename and remove. Adding an
9
+ // account makes it at once; its row then offers the two ways to sign it in:
10
+ // the provider's own login in a SynaBun terminal (`claude auth login` /
11
+ // `codex login` under the account's folder), or an API key.
8
12
 
9
- import { emit, on } from '../state.js';
10
- import { fetchClaudeAccounts, fetchCodexAccounts, getCachedClaudeAccounts, getCachedCodexAccounts } from '../agent-runtime-options.js';
13
+ import { on } from '../state.js';
14
+ import {
15
+ fetchClaudeAccounts, fetchCodexAccounts, getCachedClaudeAccounts, getCachedCodexAccounts, getClaudeWorkerAccountId, getCodexWorkerAccountId,
16
+ } from '../agent-runtime-options.js';
11
17
  import { getProviderMeta } from '../provider-icons.js';
12
18
  import {
13
- createClaudeAccount, deleteClaudeAccount, loginClaudeAccount, patchClaudeAccount,
14
- deleteCodexAccount, patchCodexAccount, startCodexAccountAdd,
19
+ createClaudeAccount, deleteClaudeAccount, loginClaudeAccount, patchClaudeAccount, setClaudeWorkerAccount, signOutClaudeAccount,
20
+ createCodexAccount, deleteCodexAccount, loginCodexAccount, patchCodexAccount, setCodexWorkerAccount, signOutCodexAccount,
15
21
  } from './asst-api.js';
22
+ import { accountBadge, accountIdentity, accountName, accountText, accountUsable, apiKeyErrorText, credentialRows, modeChoices } from '../account-view.js';
23
+ import { providerApiKeyRequest } from '../ui-provider-terminal-auth.js';
16
24
 
17
- const LOGIN_TIMEOUT_MS = 10 * 60 * 1000;
18
- const CODEX_POLL_MS = 3000;
19
25
  const ICON_X = '<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>';
20
26
 
21
27
  function el(tag, className, text) {
@@ -36,84 +42,44 @@ function tf(t) {
36
42
  };
37
43
  }
38
44
 
39
- function listFor(provider) {
40
- return provider === 'codex' ? getCachedCodexAccounts() : getCachedClaudeAccounts();
41
- }
42
-
43
- async function refreshFor(provider) {
44
- return provider === 'codex' ? fetchCodexAccounts(true) : fetchClaudeAccounts(true);
45
- }
46
-
47
- /** Resolve once `sync:assistant:accounts-changed` fires for the provider (or times out). */
48
- function waitForAccountsChanged(provider, timeoutMs = LOGIN_TIMEOUT_MS) {
49
- return new Promise((resolve) => {
50
- let done = false;
51
- const off = on('sync:assistant:accounts-changed', (msg) => {
52
- if (done) return;
53
- if (msg?.provider && msg.provider !== provider) return;
54
- done = true;
55
- off();
56
- clearTimeout(timer);
57
- resolve(true);
58
- });
59
- const timer = setTimeout(() => { if (!done) { done = true; off(); resolve(false); } }, timeoutMs);
60
- });
61
- }
45
+ // What each provider's account calls on the server (assistant API + the panels' owner-guarded routes).
46
+ const PROVIDER_API = {
47
+ 'claude-code': {
48
+ view: 'claude', list: getCachedClaudeAccounts, refresh: () => fetchClaudeAccounts(true), worker: getClaudeWorkerAccountId,
49
+ create: createClaudeAccount, login: loginClaudeAccount, patch: patchClaudeAccount, remove: deleteClaudeAccount,
50
+ setWorker: setClaudeWorkerAccount, signOut: signOutClaudeAccount, keyProvider: 'claude', changed: 'sync:claude:accounts-changed',
51
+ },
52
+ codex: {
53
+ view: 'codex', list: getCachedCodexAccounts, refresh: () => fetchCodexAccounts(true), worker: getCodexWorkerAccountId,
54
+ create: createCodexAccount, login: loginCodexAccount, patch: patchCodexAccount, remove: deleteCodexAccount,
55
+ setWorker: setCodexWorkerAccount, signOut: signOutCodexAccount, keyProvider: 'codex', changed: 'sync:codex:accounts-changed',
56
+ },
57
+ };
58
+ const apiFor = (provider) => PROVIDER_API[provider === 'codex' ? 'codex' : 'claude-code'];
62
59
 
63
60
  /**
64
- * Add-account flow. Returns { ok, account, cancelled }.
65
- * ui: { t, setStatus(text), showLogin({ authUrl, userCode }), isCancelled() }
61
+ * Add-account flow: the account is made at once; how it signs in (the provider's own login, or an API key)
62
+ * is chosen on its row next. Returns { ok, choose: true, account }.
66
63
  */
67
64
  export async function startAddAccount(provider, label, ui = {}) {
68
65
  const t = tf(ui.t);
69
- const name = String(label || '').trim() || (provider === 'codex' ? 'Codex account' : 'Claude account');
70
- if (provider === 'claude-code') {
71
- const created = await createClaudeAccount(name);
72
- const account = created?.account || created;
73
- if (!account?.id) throw new Error(t('assistant.accounts.createFailed', 'Account could not be created'));
74
- ui.setStatus?.(t('assistant.accounts.openingLogin', 'Opening a Claude Code terminal for login…'));
75
- const login = await loginClaudeAccount(account.id);
76
- if (login?.terminalSessionId) {
77
- emit('terminal:expect-managed');
78
- emit('terminal:attach-floating', { terminalSessionId: login.terminalSessionId, profile: login.profile || 'claude-code', snapToPanel: true });
79
- }
80
- ui.setStatus?.(t('assistant.accounts.waitingLogin', 'Finish the login in the terminal window. Waiting…'));
81
- const changed = await waitForAccountsChanged('claude-code');
82
- const accounts = await refreshFor('claude-code');
83
- const fresh = accounts.find(a => a.id === account.id) || account;
84
- return { ok: changed || !!fresh?.email, account: fresh, timedOut: !changed };
85
- }
86
- if (provider === 'codex') {
87
- const started = await startCodexAccountAdd(name);
88
- const accountId = started?.accountId || started?.account?.id;
89
- const login = started?.login || {};
90
- ui.showLogin?.({ authUrl: login.authUrl || login.url || '', userCode: login.userCode || login.code || '' });
91
- ui.setStatus?.(t('assistant.accounts.waitingDevice', 'Complete the sign-in in your browser. Waiting…'));
92
- const deadline = Date.now() + LOGIN_TIMEOUT_MS;
93
- let changedEarly = false;
94
- const offChanged = on('sync:assistant:accounts-changed', (msg) => { if (!msg?.provider || msg.provider === 'codex') changedEarly = true; });
95
- try {
96
- while (Date.now() < deadline) {
97
- if (ui.isCancelled?.()) return { ok: false, cancelled: true };
98
- const accounts = await fetchCodexAccounts(true).catch(() => []);
99
- const found = accounts.find(a => a.id === accountId);
100
- if (found && (found.email || found.loggedIn === true || found.status === 'ready' || changedEarly)) return { ok: true, account: found };
101
- await new Promise(r => setTimeout(r, CODEX_POLL_MS));
102
- }
103
- } finally {
104
- offChanged();
105
- }
106
- return { ok: false, timedOut: true, account: { id: accountId, label: name } };
107
- }
108
- throw new Error(`Unsupported provider: ${provider}`);
66
+ const api = apiFor(provider);
67
+ const name = String(label || '').trim();
68
+ const created = await api.create(name || undefined);
69
+ const account = created?.account || created;
70
+ if (!account?.id) throw new Error(t('assistant.accounts.createFailed', 'Account could not be created'));
71
+ const accounts = await api.refresh();
72
+ return { ok: true, choose: true, account: accounts.find((a) => a.id === account.id) || account };
109
73
  }
110
74
 
111
75
  /**
112
76
  * Accounts manager modal. hooks: { t, onChanged(provider), onSelect(accountId) }
113
- * Returns { el, close }.
77
+ * Returns { el, close, renderList, openAdd }.
114
78
  */
115
79
  export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChanged, onSelect } = {}) {
116
80
  const t = tf(tRaw);
81
+ const api = apiFor(provider);
82
+ const p = api.view;
117
83
  const meta = getProviderMeta(provider);
118
84
  const overlay = el('div', 'asst-modal-overlay');
119
85
  overlay.setAttribute('role', 'dialog');
@@ -124,8 +90,8 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
124
90
  <div class="asst-modal-head"><span class="asst-icon" style="color:${esc(meta.color)}">${meta.icon}</span><span>${esc(t('assistant.accounts.title', '{provider} accounts', { provider: meta.label }))}</span><button type="button" class="asst-iconbtn asst-modal-close" aria-label="${esc(t('common.close', 'Close'))}">${ICON_X}</button></div>
125
91
  <div class="asst-modal-body">
126
92
  <div class="asst-modal-note">${esc(provider === 'codex'
127
- ? t('assistant.accounts.noteCodex', 'Each account maps to its own CODEX_HOME. Removing an account that a run is using is refused.')
128
- : t('assistant.accounts.noteClaude', 'Each account gets its own CLAUDE_CONFIG_DIR (settings, credentials, sessions). "Default" is your ambient ~/.claude.'))}</div>
93
+ ? t('assistant.accounts.noteCodex2', 'Each account has its own CODEX_HOME (sign-in, sessions) and runs on its ChatGPT subscription or its API key. "Default" is your ambient ~/.codex.')
94
+ : t('assistant.accounts.noteClaude2', 'Each account has its own CLAUDE_CONFIG_DIR (settings, sign-in, sessions) and runs on its Claude subscription or its API key. "Default" is your ambient ~/.claude.'))}</div>
129
95
  <div class="asst-account-list"></div>
130
96
  <div class="asst-account-add"></div>
131
97
  </div>
@@ -140,12 +106,12 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
140
106
 
141
107
  const list = modal.querySelector('.asst-account-list');
142
108
  const addBox = modal.querySelector('.asst-account-add');
143
- let cancelled = false;
144
109
  let busy = false;
110
+ let offChanged = null;
145
111
 
146
112
  function close() {
147
- cancelled = true;
148
113
  document.removeEventListener('keydown', onKey, true);
114
+ offChanged?.();
149
115
  overlay.remove();
150
116
  }
151
117
  function onKey(e) {
@@ -157,94 +123,138 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
157
123
  modal.querySelector('.asst-modal-close').addEventListener('click', close);
158
124
  modal.querySelector('.asst-account-done').addEventListener('click', close);
159
125
 
126
+ // Which account is fresh (just added: its row offers the two ways to sign in), which row has its API-key
127
+ // form open, and the last thing a row said.
128
+ const ui = { fresh: '', keyOpen: '', notice: null };
129
+ async function openSignIn(acc) {
130
+ const res = await api.login(acc.id);
131
+ const sessionId = res?.login?.terminalSessionId || res?.terminalSessionId;
132
+ if (sessionId) {
133
+ const { openProviderLoginTerminal } = await import('../ui-terminal.js');
134
+ await openProviderLoginTerminal(sessionId, `${p === 'codex' ? 'Codex' : 'Claude'} sign-in · ${accountName(acc, p)}`);
135
+ }
136
+ }
137
+ function notice(id, text) { ui.notice = text ? { id, text } : null; renderList(); }
138
+ async function act(acc, work, done = '') {
139
+ try {
140
+ await work();
141
+ ui.notice = done ? { id: acc.id, text: done } : null;
142
+ await api.refresh();
143
+ onChanged?.(provider);
144
+ } catch (err) { ui.notice = { id: acc.id, text: err?.message || String(err) }; }
145
+ if (overlay.isConnected) renderList();
146
+ }
147
+ function button(row, text, onClick, kind = 'secondary') {
148
+ const b = el('button', `asst-btn asst-btn-${kind}`, text);
149
+ b.type = 'button';
150
+ b.addEventListener('click', async () => { b.disabled = true; try { await onClick(); } finally { b.disabled = false; } });
151
+ row.appendChild(b);
152
+ return b;
153
+ }
154
+ function renderActions(acc, actionsRow, row) {
155
+ const worker = api.worker() === acc.id;
156
+ const label = accountName(acc, p);
157
+ if (onSelect) {
158
+ const use = button(actionsRow, t('assistant.accounts.useBrain', 'Use for the brain'), async () => { onSelect(acc.id); close(); });
159
+ use.disabled = !accountUsable(acc);
160
+ }
161
+ if (!worker) {
162
+ const workersSet = provider === 'codex'
163
+ ? t('assistant.accounts.codexWorkersSet', 'Codex workers now use {label} when a dispatch names no account.', { label })
164
+ : t('assistant.accounts.workersSet', 'Claude Code workers now use {label} when a dispatch names no account.', { label });
165
+ const w = button(actionsRow, t('assistant.accounts.useWorkers', 'Use for workers'), () => act(acc, () => api.setWorker(acc.id), workersSet));
166
+ w.disabled = !accountUsable(acc);
167
+ }
168
+ for (const m of modeChoices(acc, p)) {
169
+ if (m.current) continue;
170
+ button(actionsRow, `${accountText('uses', {}, p)}: ${m.label}`, () => act(acc, () => api.patch(acc.id, { mode: m.mode }),
171
+ accountText(m.mode === 'apiKey' ? 'modeSetApiKey' : 'modeSetSubscription', { label }, p)));
172
+ }
173
+ for (const c of credentialRows(acc, p)) {
174
+ if (c.action === 'signIn') button(actionsRow, c.actionText, () => act(acc, () => openSignIn(acc), accountText('signInPending', {}, p)), ui.fresh === acc.id ? 'primary' : 'secondary');
175
+ if (c.action === 'addKey') button(actionsRow, c.actionText, async () => { ui.keyOpen = acc.id; ui.notice = null; renderList(); });
176
+ if (c.action === 'signOut') button(actionsRow, `${c.actionText} · ${c.name}`, async () => {
177
+ if (!window.confirm(accountText('confirmSignOut', { label }, p))) return;
178
+ await act(acc, () => api.signOut(acc.id, 'subscription'), accountText('signedOutNote', { label }, p));
179
+ });
180
+ if (c.action === 'removeKey') button(actionsRow, c.actionText, async () => {
181
+ if (!window.confirm(accountText('confirmRemoveKey', { label }, p))) return;
182
+ await act(acc, () => api.signOut(acc.id, 'apiKey'), accountText('keyRemovedNote', { label }, p));
183
+ });
184
+ }
185
+ if (ui.keyOpen === acc.id) {
186
+ const form = el('form', 'asst-account-form');
187
+ const input = document.createElement('input');
188
+ input.type = 'password'; input.autocomplete = 'off'; input.spellcheck = false; input.required = true;
189
+ input.className = 'asst-dd-input'; input.placeholder = accountText('keyPlaceholder', {}, p);
190
+ input.setAttribute('aria-label', accountText('keyLabel', { label }, p));
191
+ const save = el('button', 'asst-btn asst-btn-primary', accountText('save', {}, p)); save.type = 'submit';
192
+ const cancel = el('button', 'asst-btn asst-btn-secondary', accountText('cancel', {}, p)); cancel.type = 'button';
193
+ cancel.addEventListener('click', () => { input.value = ''; ui.keyOpen = ''; renderList(); });
194
+ input.addEventListener('keydown', (e) => e.stopPropagation());
195
+ form.addEventListener('submit', async (e) => {
196
+ e.preventDefault();
197
+ let key = input.value; input.value = '';
198
+ if (!key) return;
199
+ save.disabled = cancel.disabled = input.disabled = true;
200
+ notice(acc.id, accountText('checkingKey', {}, p));
201
+ try {
202
+ await providerApiKeyRequest(api.keyProvider, acc.id, key);
203
+ ui.keyOpen = ''; ui.fresh = '';
204
+ ui.notice = { id: acc.id, text: accountText('keySavedNote', { label }, p) };
205
+ await api.refresh();
206
+ onChanged?.(provider);
207
+ } catch (err) { ui.notice = { id: acc.id, text: apiKeyErrorText(p, err?.code) }; }
208
+ finally { key = null; }
209
+ if (overlay.isConnected) renderList();
210
+ });
211
+ form.append(input, save, cancel);
212
+ row.appendChild(form);
213
+ setTimeout(() => input.focus(), 0);
214
+ }
215
+ if (ui.notice?.id === acc.id) row.appendChild(el('div', 'asst-account-msg', ui.notice.text));
216
+ }
217
+
160
218
  function renderList() {
161
- const accounts = listFor(provider);
219
+ const accounts = api.list();
162
220
  list.innerHTML = '';
163
221
  if (!accounts.length) { list.appendChild(el('div', 'asst-modal-note', t('assistant.accounts.empty', 'No accounts yet.'))); return; }
164
222
  for (const acc of accounts) {
165
- const row = el('div', 'asst-account-row');
223
+ const row = el('div', `asst-account-row ${p}`);
166
224
  row.dataset.id = acc.id;
167
225
  const main = el('div', 'asst-account-main');
168
- main.appendChild(el('div', 'asst-account-label', acc.label || acc.id));
169
- const sub = [acc.email, acc.isDefault || acc.id === 'default' ? t('assistant.accounts.ambient', 'ambient config') : '', acc.inUse ? t('assistant.accounts.inUse', 'in use') : ''].filter(Boolean).join(' · ');
170
- main.appendChild(el('div', 'asst-account-sub', sub || acc.id));
171
- row.appendChild(main);
172
-
173
- if (onSelect) {
174
- const use = el('button', 'asst-btn asst-btn-secondary', t('assistant.accounts.use', 'Use'));
175
- use.type = 'button';
176
- use.addEventListener('click', () => { onSelect(acc.id); close(); });
177
- row.appendChild(use);
226
+ const head = el('div', 'asst-account-head');
227
+ head.appendChild(el('span', 'asst-account-label', accountName(acc, p)));
228
+ const badge = accountBadge(acc, p);
229
+ const chip = el('span', 'asst-account-badge', badge.text);
230
+ chip.dataset.tone = badge.tone;
231
+ head.appendChild(chip);
232
+ main.appendChild(head);
233
+ const worker = api.worker() === acc.id;
234
+ const sub = [accountIdentity(acc) || (acc.signedIn === false ? accountText('notSignedIn', {}, p) : accountText('checking', {}, p)), worker ? t('assistant.accounts.workerTag', 'workers use it') : ''].filter(Boolean).join(' · ');
235
+ main.appendChild(el('div', 'asst-account-sub', sub));
236
+ const creds = el('div', 'asst-account-creds');
237
+ for (const c of credentialRows(acc, p)) {
238
+ const line = el('div', 'asst-account-cred');
239
+ line.appendChild(el('span', 'asst-account-cred-k', c.name));
240
+ line.appendChild(el('span', '', `${c.text}${c.inUse ? ` · ${accountText('inUse', {}, p)}` : ''}`));
241
+ creds.appendChild(line);
178
242
  }
179
- if (provider === 'claude-code' && !acc.email && acc.id !== 'default') {
180
- const login = el('button', 'asst-btn asst-btn-secondary', t('assistant.accounts.login', 'Log in'));
181
- login.type = 'button';
182
- login.addEventListener('click', async () => {
183
- login.disabled = true;
184
- try {
185
- const res = await loginClaudeAccount(acc.id);
186
- if (res?.terminalSessionId) {
187
- emit('terminal:expect-managed');
188
- emit('terminal:attach-floating', { terminalSessionId: res.terminalSessionId, profile: res.profile || 'claude-code', snapToPanel: true });
189
- }
190
- await waitForAccountsChanged('claude-code');
191
- await refreshFor(provider);
192
- onChanged?.(provider);
193
- renderList();
194
- } catch (err) {
195
- addBox.textContent = err?.message || String(err);
196
- } finally { login.disabled = false; }
197
- });
198
- row.appendChild(login);
199
- }
200
- const rename = el('button', 'asst-btn asst-btn-secondary', t('common.rename', 'Rename'));
201
- rename.type = 'button';
202
- rename.addEventListener('click', () => {
203
- const input = document.createElement('input');
204
- input.type = 'text';
205
- input.className = 'asst-dd-input';
206
- input.value = acc.label || '';
207
- main.replaceWith(input);
208
- input.focus();
209
- input.select();
210
- const commit = async () => {
211
- const value = input.value.trim();
212
- if (value && value !== acc.label) {
213
- try {
214
- if (provider === 'codex') await patchCodexAccount(acc.id, { label: value });
215
- else await patchClaudeAccount(acc.id, { label: value });
216
- await refreshFor(provider);
217
- onChanged?.(provider);
218
- } catch (err) { addBox.textContent = err?.message || String(err); }
219
- }
220
- renderList();
221
- };
222
- input.addEventListener('blur', commit, { once: true });
223
- input.addEventListener('keydown', (e) => {
224
- e.stopPropagation();
225
- if (e.key === 'Enter') { e.preventDefault(); input.blur(); }
226
- if (e.key === 'Escape') { input.value = acc.label || ''; input.blur(); }
227
- });
228
- });
229
- row.appendChild(rename);
243
+ main.appendChild(creds);
244
+ row.appendChild(main);
245
+ const actions = el('div', 'asst-account-actions');
246
+ row.appendChild(actions);
247
+ renderActions(acc, actions, row);
230
248
  if (acc.id !== 'default' && !acc.isDefault) {
231
- const remove = el('button', 'asst-btn asst-btn-danger', t('common.remove', 'Remove'));
232
- remove.type = 'button';
233
- remove.addEventListener('click', async () => {
234
- if (!window.confirm(t('assistant.accounts.confirmRemove', 'Remove account "{label}"? Its config directory is kept on disk.', { label: acc.label || acc.id }))) return;
235
- remove.disabled = true;
236
- try {
237
- if (provider === 'codex') await deleteCodexAccount(acc.id);
238
- else await deleteClaudeAccount(acc.id);
239
- await refreshFor(provider);
240
- onChanged?.(provider);
241
- renderList();
242
- } catch (err) {
243
- addBox.textContent = err?.status === 409 ? t('assistant.accounts.inUseError', 'That account is in use by a running session.') : (err?.message || String(err));
244
- remove.disabled = false;
245
- }
249
+ button(actions, t('common.rename', 'Rename'), async () => {
250
+ const value = window.prompt(t('assistant.accounts.renamePrompt', 'Name for {label}', { label: accountName(acc, p) }), acc.label || '');
251
+ if (!value || !value.trim() || value.trim() === acc.label) return;
252
+ await act(acc, () => api.patch(acc.id, { label: value.trim() }));
246
253
  });
247
- row.appendChild(remove);
254
+ button(actions, t('common.remove', 'Remove'), async () => {
255
+ if (!window.confirm(accountText('confirmRemove', { label: accountName(acc, p) }, p))) return;
256
+ await act(acc, () => api.remove(acc.id));
257
+ }, 'danger');
248
258
  }
249
259
  list.appendChild(row);
250
260
  }
@@ -260,46 +270,29 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
260
270
  input.placeholder = t('assistant.accounts.labelPlaceholder', 'Label (e.g. Work)');
261
271
  input.setAttribute('aria-label', input.placeholder);
262
272
  const actions = el('div', 'asst-control-actions');
263
- const go = el('button', 'asst-btn asst-btn-primary', provider === 'codex' ? t('assistant.accounts.startDevice', 'Start sign-in') : t('assistant.accounts.createAndLogin', 'Create & log in'));
273
+ const go = el('button', 'asst-btn asst-btn-primary', t('assistant.accounts.create', 'Add account'));
264
274
  go.type = 'button';
265
275
  const cancel = el('button', 'asst-btn asst-btn-secondary', t('common.cancel', 'Cancel'));
266
276
  cancel.type = 'button';
267
277
  const status = el('div', 'asst-modal-note');
268
- const loginInfo = el('div', 'asst-login-box');
269
- loginInfo.hidden = true;
270
278
  actions.append(go, cancel);
271
- form.append(input, actions, status, loginInfo);
279
+ form.append(input, actions, status);
272
280
  addBox.appendChild(form);
273
281
  input.focus();
274
282
  input.addEventListener('keydown', (e) => { e.stopPropagation(); if (e.key === 'Enter') go.click(); });
275
- cancel.addEventListener('click', () => { cancelled = true; addBox.innerHTML = ''; });
283
+ cancel.addEventListener('click', () => { addBox.innerHTML = ''; });
276
284
  go.addEventListener('click', async () => {
277
285
  if (busy) return;
278
286
  busy = true;
279
- cancelled = false;
280
287
  go.disabled = true;
281
288
  input.disabled = true;
282
289
  try {
283
- const result = await startAddAccount(provider, input.value, {
284
- t: tRaw,
285
- setStatus: (text) => { status.textContent = text; },
286
- isCancelled: () => cancelled,
287
- showLogin: ({ authUrl, userCode }) => {
288
- loginInfo.hidden = false;
289
- loginInfo.innerHTML = `${authUrl ? `<a class="asst-btn asst-btn-primary" href="${esc(authUrl)}" target="_blank" rel="noopener">${esc(t('assistant.accounts.openLogin', 'Open sign-in page'))}</a>` : ''}${userCode ? `<div>${esc(t('assistant.accounts.enterCode', 'Enter this code:'))} <span class="asst-login-code">${esc(userCode)}</span></div>` : ''}`;
290
- },
291
- });
292
- await refreshFor(provider);
290
+ const result = await startAddAccount(provider, input.value, { t: tRaw });
293
291
  onChanged?.(provider);
292
+ ui.fresh = result.account.id;
293
+ ui.notice = { id: result.account.id, text: accountText('freshPrompt', { label: accountName(result.account, p) }, p) };
294
+ addBox.innerHTML = '';
294
295
  renderList();
295
- if (result.ok) {
296
- addBox.innerHTML = '';
297
- if (onSelect && result.account?.id) onSelect(result.account.id);
298
- } else if (result.cancelled) {
299
- addBox.innerHTML = '';
300
- } else {
301
- status.textContent = t('assistant.accounts.loginTimeout', 'Login was not confirmed. The account was created — use "Log in" to retry.');
302
- }
303
296
  } catch (err) {
304
297
  status.textContent = err?.message || String(err);
305
298
  } finally {
@@ -312,7 +305,12 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
312
305
 
313
306
  modal.querySelector('.asst-account-add-btn').addEventListener('click', renderAddForm);
314
307
  renderList();
315
- refreshFor(provider).then(() => { if (overlay.isConnected) renderList(); }).catch(() => {});
308
+ api.refresh().then(() => { if (overlay.isConnected) renderList(); }).catch(() => {});
309
+ // Another window or surface changed an account (signed in, a key, its mode): the list follows.
310
+ offChanged = on(api.changed, () => {
311
+ if (!overlay.isConnected) { offChanged?.(); return; }
312
+ api.refresh().then(() => { if (overlay.isConnected && !ui.keyOpen) renderList(); }).catch(() => {});
313
+ });
316
314
 
317
315
  return { el: overlay, close, renderList, openAdd: renderAddForm };
318
316
  }
@@ -75,9 +75,9 @@ export function putRouting(patch, version) {
75
75
  return jsonFetch('/api/assistant/routing', jsonBody({ version, routing: patch || {} }, 'PUT'));
76
76
  }
77
77
 
78
- // ── Budget (money caps) ─────────────────────
78
+ // ── Budget (one saved per-session amount) ─────────────────────
79
79
 
80
- /** → { ok, version, budget, defaults, sources, repairs, bounds, session|null, pricing, enforcement } */
80
+ /** → { ok, version, budget, defaults, bounds, session|null, pricing, enforcement } */
81
81
  export function getBudget(sessionId = null) {
82
82
  return jsonFetch(`/api/assistant/budget${sessionId ? `?sessionId=${enc(sessionId)}` : ''}`);
83
83
  }
@@ -255,8 +255,23 @@ export function loginClaudeAccount(id) {
255
255
  return jsonFetch(`/api/assistant/claude/accounts/${enc(id)}/login`, jsonBody({}));
256
256
  }
257
257
 
258
+ /** The account a Claude Code worker uses when its dispatch names none ('default' or null = Default). */
259
+ export function setClaudeWorkerAccount(accountId) {
260
+ return jsonFetch('/api/assistant/claude/worker-account', jsonBody({ accountId: accountId || null }, 'PUT'));
261
+ }
262
+
263
+ /** Remove one of an account's credentials: 'subscription' (Claude Code's own sign-out) or 'apiKey'. */
264
+ export function signOutClaudeAccount(id, credential) {
265
+ return jsonFetch(`/api/claude/accounts/${enc(id)}/auth/logout`, jsonBody({ credential }));
266
+ }
267
+
258
268
  // ── Codex accounts ───────────────────────────
259
269
 
270
+ export function createCodexAccount(label) {
271
+ return jsonFetch('/api/assistant/codex/accounts', jsonBody({ label }));
272
+ }
273
+
274
+ /** Older callers: create the account and open its ChatGPT sign-in at once. */
260
275
  export function startCodexAccountAdd(label) {
261
276
  return jsonFetch('/api/assistant/codex/accounts/add-start', jsonBody({ label }));
262
277
  }
@@ -268,3 +283,18 @@ export function patchCodexAccount(id, patch) {
268
283
  export function deleteCodexAccount(id) {
269
284
  return jsonFetch(`/api/assistant/codex/accounts/${enc(id)}`, { method: 'DELETE' });
270
285
  }
286
+
287
+ /** `codex login` under the account's CODEX_HOME, in a SynaBun terminal. */
288
+ export function loginCodexAccount(id) {
289
+ return jsonFetch(`/api/assistant/codex/accounts/${enc(id)}/login`, jsonBody({}));
290
+ }
291
+
292
+ /** The account a Codex worker uses when its dispatch names none ('default' or null = Default). */
293
+ export function setCodexWorkerAccount(accountId) {
294
+ return jsonFetch('/api/assistant/codex/worker-account', jsonBody({ accountId: accountId || null }, 'PUT'));
295
+ }
296
+
297
+ /** Remove one of an account's credentials: 'subscription' (Codex's own sign-out) or 'apiKey'. */
298
+ export function signOutCodexAccount(id, credential) {
299
+ return jsonFetch(`/api/codex/accounts/${enc(id)}/auth/logout`, jsonBody({ credential }));
300
+ }