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
@@ -0,0 +1,63 @@
1
+ {
2
+ "version": "2026.10.0",
3
+ "baseUrl": "https://github.com/cloudflare/cloudflared/releases/download/2026.10.0/",
4
+ "release": "https://github.com/cloudflare/cloudflared/releases/tag/2026.10.0",
5
+ "license": "Apache-2.0",
6
+ "origin": "Cloudflare's own release files, the stable release of 2026-10-05. `sha256` is the digest GitHub publishes for the release asset (the `digest` of the asset in the releases API). `binary.sha256` is the checksum in the release's own notes (SHA256 Checksums): for the macOS archives that is the checksum of the cloudflared inside, for the other files it is the file itself. Each file was downloaded on 2026-10-13 and both values, and the sizes, were computed from it and found equal to what is published.",
7
+ "platforms": {
8
+ "darwin-arm64": {
9
+ "file": "cloudflared-darwin-arm64.tgz",
10
+ "sha256": "a2f79ff7b9420aa537d74af239f376da170bbabeb529aec416002adac6a72e70",
11
+ "size": 19809074,
12
+ "archive": "tgz",
13
+ "member": "cloudflared",
14
+ "binary": {
15
+ "sha256": "72edfd3eea463aef4d5cb89e2e209cecb048cc756c2b01915de2e0ad7cb39830",
16
+ "size": 39364384,
17
+ "format": "macho"
18
+ }
19
+ },
20
+ "darwin-x64": {
21
+ "file": "cloudflared-darwin-amd64.tgz",
22
+ "sha256": "903845b81828c8cb3c5d13d816a2de71c06a3da5785469df8eb0e1b736d92f9f",
23
+ "size": 21741581,
24
+ "archive": "tgz",
25
+ "member": "cloudflared",
26
+ "binary": {
27
+ "sha256": "0560c9ab7281ac3f746055323623ed23bc0405b6dab9400474020cba33a978da",
28
+ "size": 42328240,
29
+ "format": "macho"
30
+ }
31
+ },
32
+ "linux-x64": {
33
+ "file": "cloudflared-linux-amd64",
34
+ "sha256": "d33ff2d14475178d2012c2c56beba87389ac5ded27649519f198a7d3134a99db",
35
+ "size": 40129756,
36
+ "binary": {
37
+ "sha256": "d33ff2d14475178d2012c2c56beba87389ac5ded27649519f198a7d3134a99db",
38
+ "size": 40129756,
39
+ "format": "elf"
40
+ }
41
+ },
42
+ "linux-arm64": {
43
+ "file": "cloudflared-linux-arm64",
44
+ "sha256": "e6422b9d4f72d3194bc5a38676f13667c06666523217b842a877d72a80b5ac08",
45
+ "size": 37687584,
46
+ "binary": {
47
+ "sha256": "e6422b9d4f72d3194bc5a38676f13667c06666523217b842a877d72a80b5ac08",
48
+ "size": 37687584,
49
+ "format": "elf"
50
+ }
51
+ },
52
+ "win32-x64": {
53
+ "file": "cloudflared-windows-amd64.exe",
54
+ "sha256": "86aee4017b26625cee8484c113558f48effa4cd47f7aa05fcf425604e5d2b23c",
55
+ "size": 55365048,
56
+ "binary": {
57
+ "sha256": "86aee4017b26625cee8484c113558f48effa4cd47f7aa05fcf425604e5d2b23c",
58
+ "size": 55365048,
59
+ "format": "pe"
60
+ }
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,265 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — the public address (a Cloudflare quick tunnel)
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // `cloudflared tunnel --url http://localhost:<port>`: no Cloudflare account, an
6
+ // address under trycloudflare.com for as long as the process runs. One tunnel
7
+ // at a time. What server.js keeps of it are three thin routes (/api/tunnel/…)
8
+ // and the address itself, which it needs for its Host and remote rules: it
9
+ // gets every change through `onUrl`, the moment cloudflared prints the address.
10
+ //
11
+ // start() answers at once. Behind it: the copy of cloudflared to run
12
+ // (manager.js: a download on a machine that has none), then the
13
+ // process, then its address. A second start while one is on its
14
+ // way, or running, changes nothing.
15
+ // stop() ends the process, and whatever a start was still waiting for.
16
+ // status() what is happening, for the page: idle, downloading (with
17
+ // progress), starting, running (the address, which copy runs and
18
+ // its version), failed (a code and a sentence; a start tries again).
19
+ // shutdown() stop(), then waits (a bounded time) until cloudflared has
20
+ // really exited. killNow(): at the server's exit, kill it now.
21
+ //
22
+ // A copy of SynaBun's own is started with --no-autoupdate: it is a pinned file,
23
+ // and cloudflared would otherwise replace itself where it stands, inside an
24
+ // installed application too. The user's own cloudflared is started as before.
25
+ // Whatever copy it is, the manager checks it once more right before the start
26
+ // (confirm: the very file its check read, by its real path), and that path is
27
+ // what is started, at once.
28
+ //
29
+ // An ended process is not forgotten: it is asked to end (SIGTERM), killed when
30
+ // it is still there a moment later (SIGKILL), and kept until it has exited.
31
+
32
+ import { spawn as nodeSpawn } from 'node:child_process';
33
+
34
+ const exited = (proc) => !proc.pid || proc.exitCode !== null || proc.signalCode !== null;
35
+
36
+ /**
37
+ * End a child process for sure: SIGTERM now, SIGKILL when it is still there `killAfterMs` later. Resolves once it
38
+ * has exited (at once for one that is gone, or never started). How long to wait for that is the caller's choice.
39
+ */
40
+ export function endChild(proc, { killAfterMs = 1000 } = {}) {
41
+ return new Promise((done) => {
42
+ if (!proc || exited(proc)) { done(); return; }
43
+ let timer = null;
44
+ proc.once('exit', () => { clearTimeout(timer); done(); });
45
+ try { proc.kill('SIGTERM'); } catch { /* gone already */ }
46
+ timer = setTimeout(() => {
47
+ if (!exited(proc)) { try { proc.kill('SIGKILL'); } catch { /* gone already */ } }
48
+ }, killAfterMs);
49
+ });
50
+ }
51
+
52
+ /** The address of a quick tunnel, as cloudflared prints it. */
53
+ const TUNNEL_URL = /https:\/\/([a-z0-9-]+)\.trycloudflare\.com/g;
54
+ /** Names under trycloudflare.com that are Cloudflare's own, never a tunnel's (they appear in its error lines). */
55
+ const NOT_A_TUNNEL = new Set(['api', 'www']);
56
+ const OUTPUT_KEPT = 4096;
57
+
58
+ /** The first quick-tunnel address in a piece of cloudflared's output, or null. */
59
+ export function tunnelUrlIn(text) {
60
+ TUNNEL_URL.lastIndex = 0;
61
+ for (let match = TUNNEL_URL.exec(text); match; match = TUNNEL_URL.exec(text)) {
62
+ if (!NOT_A_TUNNEL.has(match[1])) return match[0];
63
+ }
64
+ return null;
65
+ }
66
+
67
+ /** The arguments cloudflared is started with for a copy from `source` (manager.js). */
68
+ export function tunnelArguments(port, source) {
69
+ return ['tunnel', ...(source === 'system' ? [] : ['--no-autoupdate']), '--url', `http://localhost:${port}`];
70
+ }
71
+
72
+ /** What cloudflared said last that reads like a reason: its last error line, without the timestamp. */
73
+ function lastReason(output) {
74
+ const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
75
+ const said = [...lines].reverse().find((line) => /\b(?:ERR|error|failed)\b/i.test(line)) || '';
76
+ return said.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z?\s+/, '').replace(/^(?:ERR|INF|WRN)\s+/, '').slice(0, 240);
77
+ }
78
+
79
+ /**
80
+ * @param {object} o
81
+ * @param {{ ensure: Function, inspect: Function, status: Function, cancel: Function, confirm?: Function, killNow?: Function }} o.cloudflared manager.js
82
+ * @param {number | string} o.port the port of this server
83
+ * @param {(url: string | null) => void} [o.onUrl] every change of the address: set when it is known, null when it is gone
84
+ * @param {typeof nodeSpawn} [o.spawn]
85
+ * @param {number} [o.urlTimeoutMs] how long a started cloudflared may take to print its address
86
+ * @param {number} [o.killAfterMs] how long an ended cloudflared has to exit before it is killed
87
+ * @param {(line: string) => void} [o.log]
88
+ */
89
+ export function createQuickTunnel({ cloudflared, port, onUrl = () => {}, spawn = nodeSpawn, urlTimeoutMs = 90_000, killAfterMs = 1000, log = () => {} }) {
90
+ let phase = 'idle'; // idle | preparing | starting | running | failed
91
+ let child = null;
92
+ let url = null;
93
+ let copy = null; // { source, version } of the cloudflared that runs
94
+ let error = null; // { code, message, reason } of the start that failed, until the next one (`reason`: cloudflared's own words, when it gave any)
95
+ let attempt = 0; // a start that is not the current attempt any more does nothing
96
+ let preparing = null; // the AbortController of the start that is getting its copy ready
97
+ const ending = new Map(); // a process that was asked to end → its endChild(): kept until it has really exited
98
+
99
+ /** Ask a process to end, kill it when it does not, and keep it until it has exited. */
100
+ function end(proc) {
101
+ if (!proc) return Promise.resolve();
102
+ if (!ending.has(proc)) ending.set(proc, endChild(proc, { killAfterMs }).then(() => { ending.delete(proc); }));
103
+ return ending.get(proc);
104
+ }
105
+
106
+ const setUrl = (value) => {
107
+ if (url === value) return;
108
+ url = value;
109
+ try { onUrl(value); } catch { /* the address is still ours to report */ }
110
+ };
111
+
112
+ function fail(code, message, reason = null) {
113
+ phase = 'failed';
114
+ error = { code, message, reason };
115
+ copy = null;
116
+ setUrl(null);
117
+ log(` Tunnel: ${code === 'ended' ? 'stopped' : 'not started'} (${code}): ${message}`);
118
+ }
119
+
120
+ function launch(found, mine) {
121
+ // Checked once more as it is about to run (the manager's confirm: the very file its check read, still where
122
+ // nobody else can change it), and started at once by the real path that was checked: nothing runs in between.
123
+ let path = found.path;
124
+ try {
125
+ if (typeof cloudflared.confirm === 'function') path = cloudflared.confirm(found);
126
+ } catch (failure) {
127
+ return fail(typeof failure?.code === 'string' ? failure.code : 'launch', failure?.message || String(failure));
128
+ }
129
+ let proc;
130
+ try {
131
+ proc = spawn(path, tunnelArguments(port, found.source), { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
132
+ } catch (failure) {
133
+ return fail('launch', `cloudflared could not be started (${failure?.code || failure?.message || failure}).`);
134
+ }
135
+ child = proc;
136
+ copy = { source: found.source, version: found.version };
137
+ phase = 'starting';
138
+ let output = '';
139
+ const timer = setTimeout(() => {
140
+ if (mine !== attempt || phase !== 'starting') return;
141
+ child = null;
142
+ end(proc);
143
+ fail('no_address', `cloudflared gave no address within ${Math.round(urlTimeoutMs / 1000)} seconds.`, lastReason(output) || null);
144
+ }, urlTimeoutMs);
145
+ timer.unref?.();
146
+ // cloudflared prints the address to stderr, in pieces that can end anywhere: the search runs over what
147
+ // came last, not over one piece.
148
+ const read = (data) => {
149
+ output = (output + data.toString()).slice(-OUTPUT_KEPT);
150
+ if (mine !== attempt || phase !== 'starting') return;
151
+ const address = tunnelUrlIn(output);
152
+ if (!address) return;
153
+ clearTimeout(timer);
154
+ phase = 'running';
155
+ setUrl(address);
156
+ log(` Tunnel: ${address} (cloudflared ${found.version}, ${found.source})`);
157
+ };
158
+ proc.stdout?.on('data', read);
159
+ proc.stderr?.on('data', read);
160
+ proc.on('error', (failure) => {
161
+ clearTimeout(timer);
162
+ if (mine !== attempt || child !== proc) return;
163
+ child = null;
164
+ fail('launch', `cloudflared could not be started (${failure?.code || failure?.message || failure}).`);
165
+ });
166
+ proc.on('close', (code, signal) => {
167
+ clearTimeout(timer);
168
+ if (mine !== attempt || child !== proc) return; // stopped on request, or already accounted for
169
+ child = null;
170
+ const said = lastReason(output) || null;
171
+ if (phase === 'running') fail('ended', 'The tunnel stopped by itself. Start it again for a new address.', said);
172
+ else fail('exited', said || `cloudflared stopped before it gave an address (${signal || `exit ${code}`}).`, said);
173
+ });
174
+ return undefined;
175
+ }
176
+
177
+ function answer(message) {
178
+ return { ok: true, state: phase, url, message };
179
+ }
180
+
181
+ function start() {
182
+ if (phase === 'running') return { ...answer('Already running.') };
183
+ if (phase === 'preparing' || phase === 'starting') return answer('Tunnel starting...');
184
+ const mine = ++attempt;
185
+ phase = 'preparing';
186
+ error = null;
187
+ copy = null;
188
+ setUrl(null);
189
+ // What the preparation runs (a hash, a `cloudflared --version`, a download) stops with this, on stop().
190
+ const ready = new AbortController();
191
+ preparing = ready;
192
+ const done = () => { if (preparing === ready) preparing = null; };
193
+ Promise.resolve().then(() => cloudflared.ensure({ signal: ready.signal })).then((found) => {
194
+ done();
195
+ if (mine === attempt) launch(found, mine);
196
+ }, (failure) => {
197
+ done();
198
+ if (mine !== attempt) return;
199
+ fail(typeof failure?.code === 'string' ? failure.code : 'unknown', failure?.message || String(failure));
200
+ });
201
+ return answer('Tunnel starting...');
202
+ }
203
+
204
+ function stop() {
205
+ const was = phase;
206
+ attempt++;
207
+ const proc = child;
208
+ child = null;
209
+ phase = 'idle';
210
+ error = null;
211
+ copy = null;
212
+ setUrl(null);
213
+ if (preparing) { preparing.abort(); preparing = null; }
214
+ if (was === 'preparing') { try { cloudflared.cancel(); } catch { /* nothing was running */ } }
215
+ end(proc);
216
+ return { ok: true, state: phase, message: was === 'idle' || was === 'failed' ? 'Not running.' : 'Tunnel stopped.' };
217
+ }
218
+
219
+ /**
220
+ * stop(), and a wait until cloudflared has really exited (killed when it does not end by itself): at most
221
+ * `timeoutMs`, so the server's shutdown never waits on it for long. `exited` says whether it did by then.
222
+ */
223
+ async function shutdown({ timeoutMs = 2000 } = {}) {
224
+ const stopped = stop();
225
+ let timer = null;
226
+ const exitedInTime = await Promise.race([
227
+ Promise.all([...ending.values()]).then(() => true),
228
+ new Promise((done) => { timer = setTimeout(() => done(false), timeoutMs); }),
229
+ ]);
230
+ clearTimeout(timer);
231
+ return { ...stopped, exited: exitedInTime && ending.size === 0 };
232
+ }
233
+
234
+ /** At the server's exit, when nothing can be waited for: every cloudflared this started that is still there is killed now. */
235
+ function killNow() {
236
+ stop();
237
+ for (const proc of ending.keys()) { if (!exited(proc)) { try { proc.kill('SIGKILL'); } catch { /* gone already */ } } }
238
+ try { cloudflared.killNow?.(); } catch { /* nothing of its own runs */ }
239
+ }
240
+
241
+ async function status() {
242
+ // While a start waits for the copy, the manager is asked what it knows, not sent to look again.
243
+ let tool;
244
+ try { tool = phase === 'preparing' ? cloudflared.status() : await cloudflared.inspect(); } catch (failure) { tool = { ...cloudflared.status(), state: 'failed', error: { code: 'unknown', message: failure?.message || String(failure) } }; }
245
+ const downloading = phase === 'preparing' && tool.state === 'downloading';
246
+ return {
247
+ ok: true,
248
+ // What a page that predates the download reads: can a tunnel be started here, is one up, is one on its way.
249
+ available: tool.state !== 'unsupported',
250
+ running: phase === 'running' || phase === 'starting',
251
+ starting: phase === 'preparing' || phase === 'starting',
252
+ url,
253
+ state: downloading ? 'downloading' : phase === 'preparing' ? 'starting' : phase,
254
+ error,
255
+ cloudflared: {
256
+ ...tool,
257
+ // The copy that runs, when one does; otherwise the one a start would run.
258
+ source: copy?.source ?? tool.source,
259
+ version: copy?.version ?? tool.version,
260
+ },
261
+ };
262
+ }
263
+
264
+ return { start, stop, status, url: () => url, phase: () => phase, shutdown, killNow };
265
+ }
@@ -0,0 +1,178 @@
1
+ // Codex account sign-in state and changes (docs/codex-sidepanel.md → Codex
2
+ // accounts). Codex owns its ChatGPT login and its store; SynaBun owns only the
3
+ // API key it keeps per account (lib/codex-accounts.js). This adapter asks
4
+ // Codex what an account's own store holds (`account/read` from an app-server
5
+ // started under that account), signs a credential out, saves a pasted key
6
+ // after OpenAI accepts it, and changes an account's mode, each through
7
+ // `changeCredentials` so the account's idle panel processes restart under the
8
+ // new credential and busy ones refuse the change.
9
+ import { spawn } from 'node:child_process';
10
+ import { verifyOpenAiApiKey } from './claude-profile-api-key.js';
11
+ import { validateProviderApiKey } from './provider-panel-api-key-auth.js';
12
+ import { applyCodexLaunchEnv } from './codex-accounts.js';
13
+
14
+ const fail = (message, status = 409, code = null) => Object.assign(new Error(message), { status, ...(code ? { code } : {}) });
15
+
16
+ export function createCodexAccountAuth({
17
+ accounts,
18
+ codexBin = () => 'codex',
19
+ env = () => process.env,
20
+ spawnProcess = spawn,
21
+ prepareConfig = () => {},
22
+ statusTimeoutMs = 15_000,
23
+ verifyKey = verifyOpenAiApiKey,
24
+ changeCredentials = async (_id, change) => change(),
25
+ } = {}) {
26
+ if (!accounts) throw new Error('createCodexAccountAuth requires accounts');
27
+ function account(id) {
28
+ if (typeof id !== 'string' || !/^[a-z0-9-]{1,64}$/.test(id)) throw fail('Unknown Codex account', 404);
29
+ const row = accounts.profileFor(id);
30
+ if (!row || row.id !== id) throw fail('Unknown Codex account', 404);
31
+ return row;
32
+ }
33
+ // Codex run under the account's own store: inherited credentials out, its
34
+ // CODEX_HOME in, never the key SynaBun holds (that is not Codex's store).
35
+ function launch(id, args) {
36
+ account(id);
37
+ const plan = accounts.launchFor(id);
38
+ if (!plan.ok) throw fail(plan.message, 404);
39
+ prepareConfig(plan.home);
40
+ let file = codexBin();
41
+ if (!file) throw fail('Codex CLI not found. Install Codex to sign in.', 503);
42
+ const script = /\.[cm]?js$/i.test(file);
43
+ const shell = process.platform === 'win32' && /\.(cmd|bat)$/i.test(file);
44
+ const proc = spawnProcess(script ? process.execPath : file, script ? [file, ...args] : args, {
45
+ env: { ...applyCodexLaunchEnv(env(), { unset: plan.unset, env: plan.env }), NO_COLOR: '1' },
46
+ stdio: ['pipe', 'pipe', 'pipe'], shell, windowsHide: true,
47
+ });
48
+ proc.stdin?.on('error', () => {});
49
+ return proc;
50
+ }
51
+ /** What Codex says the account's own store holds: { account: { type, email, planType } | null }. Never a credential. */
52
+ function nativeRead(id, method, params, { signal, timeoutMs = statusTimeoutMs } = {}) {
53
+ return new Promise((resolve, reject) => {
54
+ let proc;
55
+ try { proc = launch(id, ['app-server']); } catch (error) { reject(error); return; }
56
+ let buffer = '', settled = false, nextId = 1;
57
+ const waiting = new Map();
58
+ const finish = (error, result) => {
59
+ if (settled) return;
60
+ settled = true; clearTimeout(timer); signal?.removeEventListener('abort', abort);
61
+ try { proc.stdin.end(); } catch {}
62
+ try { proc.kill(); } catch {}
63
+ error ? reject(error) : resolve(result);
64
+ };
65
+ const abort = () => finish(new Error('Codex account read cancelled.'));
66
+ const timer = setTimeout(() => finish(new Error('Codex did not answer in time. Try Refresh.')), timeoutMs);
67
+ timer.unref?.();
68
+ signal?.addEventListener('abort', abort, { once: true });
69
+ if (signal?.aborted) { abort(); return; }
70
+ const call = (method, params) => new Promise((ok, no) => {
71
+ const callId = nextId++;
72
+ waiting.set(callId, { ok, no });
73
+ try { proc.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id: callId, method, params })}\n`); }
74
+ catch (error) { waiting.delete(callId); no(error); }
75
+ });
76
+ proc.stdout.setEncoding?.('utf8');
77
+ proc.stdout.on('data', (chunk) => {
78
+ buffer = (buffer + chunk).slice(-1_048_576);
79
+ let index;
80
+ while ((index = buffer.indexOf('\n')) >= 0) {
81
+ const line = buffer.slice(0, index).trim();
82
+ buffer = buffer.slice(index + 1);
83
+ if (!line) continue;
84
+ let msg;
85
+ try { msg = JSON.parse(line); } catch { continue; }
86
+ if (msg.id === undefined || msg.method) continue;
87
+ const entry = waiting.get(msg.id);
88
+ if (!entry) continue;
89
+ waiting.delete(msg.id);
90
+ if (msg.error) entry.no(new Error('Codex could not read the account.'));
91
+ else entry.ok(msg.result);
92
+ }
93
+ });
94
+ proc.stderr.on('data', () => {}); // Never forward CLI output: it can carry credential details.
95
+ proc.on('error', () => finish(new Error('Could not start Codex. Check its installation.')));
96
+ proc.on('close', () => finish(new Error('Codex closed before it answered.')));
97
+ (async () => {
98
+ try {
99
+ await call('initialize', { clientInfo: { name: 'synabun-codex-accounts', title: 'SynaBun Codex accounts', version: '0.0.1' } });
100
+ proc.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', method: 'initialized' })}\n`);
101
+ finish(null, await call(method, params));
102
+ } catch (error) { finish(error); }
103
+ })();
104
+ });
105
+ }
106
+ async function nativeStatus(id) {
107
+ const result = await nativeRead(id, 'account/read', { refreshToken: false });
108
+ const native = result?.account && typeof result.account === 'object' ? result.account : null;
109
+ return { account: native ? { type: native.type || null, email: native.email || null, planType: native.planType || null } : null };
110
+ }
111
+ const rateLimits = (id, options) => nativeRead(id, 'account/rateLimits/read', {}, options);
112
+ // `codex logout` in the account's home: Codex removes its own login (auth.json or its keyring entry).
113
+ function nativeLogout(id) {
114
+ return new Promise((resolve, reject) => {
115
+ let proc, timer;
116
+ try { proc = launch(id, ['logout']); } catch { reject(fail('Could not sign out of Codex. Try again.', 500)); return; }
117
+ let settled = false;
118
+ const finish = (ok) => { if (settled) return; settled = true; clearTimeout(timer); ok ? resolve() : reject(fail('Could not sign out of Codex. Try again.', 500)); };
119
+ proc.stdout.on('data', () => {}); proc.stderr.on('data', () => {});
120
+ proc.on('error', () => finish(false));
121
+ proc.on('close', (code) => finish(code === 0));
122
+ timer = setTimeout(() => { try { proc.kill(); } catch {} finish(false); }, statusTimeoutMs);
123
+ timer.unref?.();
124
+ });
125
+ }
126
+ /** The account as every surface shows it, after asking Codex about its own store. */
127
+ async function read(id) {
128
+ account(id);
129
+ let failure = null;
130
+ try { await accounts.refreshStatus([id], { force: true }); } catch (error) { failure = error; }
131
+ account(id);
132
+ const row = accounts.describeForClient(id);
133
+ if (failure && !row) throw failure;
134
+ return { accountId: id, account: row };
135
+ }
136
+ const pending = new Set();
137
+ async function guarded(id, work) {
138
+ account(id);
139
+ if (pending.has(id)) throw fail('Another sign-in change for this account is still running.');
140
+ pending.add(id);
141
+ try { return await work(); } finally { pending.delete(id); }
142
+ }
143
+ async function signInApiKey(id, key) {
144
+ account(id); key = validateProviderApiKey('codex', key);
145
+ try {
146
+ return await guarded(id, async () => {
147
+ await verifyKey(key);
148
+ account(id); // A removed account is never recreated by a late answer.
149
+ await changeCredentials(id, () => { account(id); accounts.saveApiKey(id, key); });
150
+ });
151
+ } finally { key = null; }
152
+ }
153
+ // `credential`: 'apiKey' removes the account's key (SynaBun's file, or Codex's own stored key),
154
+ // 'subscription' runs Codex's own logout in the account's home, 'all' both.
155
+ async function signOut(id, credential = 'all') {
156
+ account(id);
157
+ if (!['all', 'apiKey', 'subscription'].includes(credential)) throw fail('Choose which sign-in to remove.', 400);
158
+ return guarded(id, () => changeCredentials(id, async () => {
159
+ const row = accounts.describe(id);
160
+ const ownKey = row?.apiKey?.source === 'synabun';
161
+ const codexKey = row?.apiKey?.source === 'codex';
162
+ if (credential === 'apiKey' && !row?.apiKey?.present && !row?.apiKey?.error) throw fail(`${row?.label || id} has no API key.`);
163
+ if (credential === 'subscription' && codexKey) throw fail(`${row.label} has no ChatGPT sign-in: Codex holds an API key for it.`);
164
+ if (credential !== 'subscription' && (ownKey || row?.apiKey?.error)) accounts.clearApiKey(id);
165
+ // Codex's own store is cleared for a ChatGPT sign-out, or for a key Codex itself holds.
166
+ if (credential === 'subscription' || (credential === 'all' && !ownKey) || (credential === 'apiKey' && codexKey)) {
167
+ await nativeLogout(id);
168
+ accounts.noteNativeStatus(id, { account: null });
169
+ }
170
+ return accounts.describeForClient(id);
171
+ }));
172
+ }
173
+ /** What the account's sessions use from now on: its idle panel processes restart under it. */
174
+ async function setMode(id, mode) {
175
+ return guarded(id, () => changeCredentials(id, () => accounts.setMode(id, mode)));
176
+ }
177
+ return { read, nativeStatus, rateLimits, signInApiKey, signOut, setMode };
178
+ }