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,408 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Assistant budget split (pure: buckets, shares, coverage)
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // A session with a budget (assistant-budget.js) divides what is left across
6
+ // three buckets, one per provider: claude-code, codex, opencode. A provider's
7
+ // runs draw from its share; the Assistant's own turns (brain turns, direct and
8
+ // continuation routes) draw from the share of the brain's provider, which
9
+ // keeps a reserve for them that the workers on that provider cannot spend.
10
+ //
11
+ // Who decides the weights: Jev (surface budget-split, one Score per provider:
12
+ // how much of the spend still to come lands there), else the fixed heuristic
13
+ // fallbackWeights(). Either way the code here does the money: the weights are
14
+ // normalised, the brain's reserve applied, and what is left is divided in whole
15
+ // cents that add up exactly to it. A provider a checkpoint found short gets
16
+ // more only when the weights give it more: when they do not, its tasks move to
17
+ // another provider (the router) and its runs stop. Nothing here raises the
18
+ // total or picks a model.
19
+ //
20
+ // Everything in this file is pure; assistant-budget-planner.js owns the state.
21
+
22
+ import { listedCount, priceText, providerAllHidden, providerEmpty, rowIsHidden, findModel, defaultModelRow } from './assistant-catalog.js';
23
+ import { BUDGET_WARN_RATIO, floorCents, roundUsd } from './assistant-budget.js';
24
+
25
+ export const BUDGET_PROVIDERS = Object.freeze(['claude-code', 'codex', 'opencode']);
26
+ export const PROVIDER_LABELS = Object.freeze({ 'claude-code': 'Claude Code', codex: 'Codex', opencode: 'OpenCode' });
27
+
28
+ // The brain's reserve inside its provider's share: 10 % of what is left, at least $0.50 (never more than is left).
29
+ export const BRAIN_FLOOR_RATIO = 0.1;
30
+ export const BRAIN_FLOOR_MIN_USD = 0.5;
31
+ // Less than this cannot pay for a model call: the share counts as used up.
32
+ export const MIN_SPEND_USD = 0.01;
33
+
34
+ // What each level of Jev's Score question (mcp-server/src/services/budget-judgments.ts SHARE_LEVELS, lowest
35
+ // first) stands for as a share of the spend still to come. The expected share is these weighted by the
36
+ // answer's probabilities, else read off its probability-weighted position.
37
+ export const SHARE_LEVEL_FRACTIONS = Object.freeze([0, 0.1, 0.3, 0.6, 0.9]);
38
+
39
+ // What one task of a class tends to cost, relative to a quick task (the fallback's weights).
40
+ export const CLASS_COST_WEIGHTS = Object.freeze({
41
+ chat: 0.5, quick: 1, research: 1.5, browser: 1.5, computer: 1.5, automation: 1,
42
+ review: 2, code: 3, design: 3, image_gen: 2, video_gen: 2, complex: 4,
43
+ });
44
+ // A model's blended list price ($/MTok: (3 × input + output) / 4) is divided by this to give its price index.
45
+ export const PRICE_INDEX_BASE_USD = 5;
46
+
47
+ const arr = (value) => (Array.isArray(value) ? value : []);
48
+ const num = (value, fallback = 0) => (Number.isFinite(Number(value)) ? Number(value) : fallback);
49
+ const r8 = (value) => Number((Number(value) || 0).toFixed(8));
50
+ const isProvider = (value) => BUDGET_PROVIDERS.includes(value);
51
+
52
+ // ── buckets ───────────────────────────────────────────────────────────────
53
+
54
+ /**
55
+ * Which providers can take a share now → { [provider]: { eligible, reason } }.
56
+ * no_models the user disabled every model, or the provider answered with none connected
57
+ * signed_out every account of the provider is signed out
58
+ * limited every signed-in account is out of subscription usage
59
+ * A provider whose model list is merely unavailable stays eligible (routing is lenient there too). The
60
+ * brain's provider is always eligible (its turns are paid from it); `reason` then says what else is wrong.
61
+ */
62
+ export function bucketEligibility({ catalog = null, accounts = null, brainProvider = null } = {}) {
63
+ const out = {};
64
+ for (const provider of BUDGET_PROVIDERS) {
65
+ let reason = null;
66
+ if (catalog) {
67
+ if (providerEmpty(catalog, provider) || providerAllHidden(catalog, provider)) reason = 'no_models';
68
+ else if (listedCount(catalog, provider) > 0 || arr(catalog.models?.[provider]).length) {
69
+ const usable = arr(catalog.models?.[provider]).filter((row) => !rowIsHidden(catalog, { ...row, provider: row.provider || provider }) && row.status !== 'unavailable');
70
+ if (!usable.length) reason = 'no_models';
71
+ }
72
+ }
73
+ if (!reason && accounts && Object.hasOwn(accounts, provider)) {
74
+ const rows = arr(accounts[provider]);
75
+ if (rows.length) {
76
+ const usable = rows.filter((row) => row && row.signedIn !== false && row.usage?.limited !== true);
77
+ if (!usable.length) reason = rows.every((row) => row?.signedIn === false) ? 'signed_out' : 'limited';
78
+ }
79
+ }
80
+ out[provider] = provider === brainProvider ? { eligible: true, reason: reason ? `brain:${reason}` : 'brain' } : { eligible: !reason, reason };
81
+ }
82
+ return out;
83
+ }
84
+
85
+ // ── prices ────────────────────────────────────────────────────────────────
86
+
87
+ /** The catalog row a target runs on (its provider default when it names no model), or null. */
88
+ export function rowOf(catalog, provider, model) {
89
+ if (!catalog || !provider) return null;
90
+ try { return model ? findModel(catalog, provider, model)?.row || null : defaultModelRow(catalog, provider); } catch { return null; }
91
+ }
92
+ /** A row's list price: its own (Claude, OpenCode), else its list-price equivalent (Codex: billed by plan). */
93
+ export function listPriceOf(row, { pricing = null, provider = null, model = null } = {}) {
94
+ if (row?.price) return row.price;
95
+ if (row?.listPrice) return row.listPrice;
96
+ if ((provider || row?.provider) === 'codex' && pricing?.codexPrice) {
97
+ try { return pricing.codexPrice(model || row?.id || null) || null; } catch { return null; }
98
+ }
99
+ return null;
100
+ }
101
+ /** Is the model free (catalog basis free)? Free models need no share. */
102
+ export function isFreePrice(price) { return !!price && (price.basis === 'free' || (num(price.input) === 0 && num(price.output) === 0 && price.basis !== 'plan')); }
103
+ /** A model's price index for the fallback: its blended list price / $5, 0 when free, 1 when unknown. */
104
+ export function priceIndex(price) {
105
+ if (!price) return 1;
106
+ if (isFreePrice(price)) return 0;
107
+ const blended = (3 * num(price.input) + num(price.output)) / 4;
108
+ if (!(blended > 0)) return 1;
109
+ return Math.min(20, Math.max(0.05, blended / PRICE_INDEX_BASE_USD));
110
+ }
111
+ /** "$5/$25" (or "free", "plan (list …)") for the Jev state; null when unknown. */
112
+ export function priceLabel(row, price) {
113
+ if (!price && !row) return null;
114
+ try { return row ? priceText(row.price || null, row.listPrice || (row.price ? null : price)) : priceText(price); } catch { return null; }
115
+ }
116
+ /**
117
+ * How the work is paid for: 'free' (a free model), 'api' (an API key, or OpenCode's own providers), 'plan'
118
+ * (a Claude / ChatGPT subscription). `account`: the account row the work would run under, when known.
119
+ */
120
+ export function billingOf(provider, price, account = null) {
121
+ if (isFreePrice(price)) return 'free';
122
+ if (provider === 'opencode') return 'api';
123
+ if (account?.mode === 'apiKey') return 'api';
124
+ return 'plan';
125
+ }
126
+
127
+ // ── weights ───────────────────────────────────────────────────────────────
128
+
129
+ const classWeight = (taskClass) => CLASS_COST_WEIGHTS[taskClass] ?? 1;
130
+
131
+ /**
132
+ * The deterministic split's weights, used when Jev is off, unreachable or answers nothing usable. Each
133
+ * eligible provider is weighted by the work the session is likely to send it, times what that work's models
134
+ * cost (priceIndex):
135
+ * - every task class once: on the provider its saved route names, else on the brain's provider (chat
136
+ * always on the brain's: it never runs anywhere else)
137
+ * - every task routed so far in this session: twice, on the provider it went to
138
+ * - the task being routed now: three times, on its provider
139
+ * - the Assistant's own turns: twice a quick task, on the brain's provider at the brain's model price
140
+ * - every live run: once its class, on its provider
141
+ * - a provider a checkpoint found short (`needs`): at least one quick task
142
+ * Ineligible providers get 0. When nothing weighs anything (every model free), every eligible provider weighs
143
+ * the same. → { [provider]: number }
144
+ */
145
+ export function fallbackWeights({
146
+ eligible = {}, routing = {}, brain = null, catalog = null, pricing = null,
147
+ tasks = [], task = null, liveRuns = [], needs = [], classes = Object.keys(CLASS_COST_WEIGHTS),
148
+ } = {}) {
149
+ const weights = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, 0]));
150
+ const brainProvider = isProvider(brain?.provider) ? brain.provider : null;
151
+ const price = (provider, model) => priceIndex(listPriceOf(rowOf(catalog, provider, model), { pricing, provider, model }));
152
+ const add = (provider, model, weight) => { if (isProvider(provider) && eligible[provider]?.eligible !== false) weights[provider] += weight * price(provider, model); };
153
+ const prefs = routing?.preferences && typeof routing.preferences === 'object' ? routing.preferences : {};
154
+ for (const taskClass of classes) {
155
+ // Chat always runs here, on the brain, whatever its saved route says (assistant-router.js evaluateRoute).
156
+ const pref = taskClass === 'chat' ? null : prefs[taskClass];
157
+ if (pref?.provider) add(pref.provider, pref.model || (pref.kind === 'direct' && pref.provider === brainProvider ? brain?.model || null : null), classWeight(taskClass));
158
+ else if (brainProvider) add(brainProvider, brain?.model || null, classWeight(taskClass));
159
+ }
160
+ for (const row of arr(tasks)) add(row?.provider, row?.model || null, 2 * classWeight(row?.taskClass));
161
+ if (task?.provider) add(task.provider, task.model || null, 3 * classWeight(task.taskClass));
162
+ if (brainProvider) add(brainProvider, brain?.model || null, 2);
163
+ for (const run of arr(liveRuns)) add(run?.provider, run?.model || null, classWeight(run?.taskClass));
164
+ for (const provider of arr(needs)) if (isProvider(provider) && eligible[provider]?.eligible !== false && weights[provider] <= 0) weights[provider] = Math.max(weights[provider], price(provider, null) > 0 ? 1 : 0);
165
+ const pool = BUDGET_PROVIDERS.filter((p) => eligible[p]?.eligible !== false);
166
+ if (pool.length && pool.every((p) => !(weights[p] > 0))) for (const p of pool) weights[p] = 1;
167
+ return weights;
168
+ }
169
+
170
+ /** The expected share (0-1) one Score answer stands for: SHARE_LEVEL_FRACTIONS weighted by its probabilities, else interpolated at its position. */
171
+ export function shareFromScore(answer) {
172
+ if (!answer || typeof answer !== 'object') return null;
173
+ const levels = SHARE_LEVEL_FRACTIONS;
174
+ const probs = answer.probabilities && typeof answer.probabilities === 'object' ? answer.probabilities : null;
175
+ if (probs) {
176
+ let total = 0;
177
+ let expected = 0;
178
+ for (const [key, value] of Object.entries(probs)) {
179
+ const index = Number(key);
180
+ const p = Number(value);
181
+ if (!Number.isInteger(index) || index < 0 || index >= levels.length || !Number.isFinite(p) || p < 0) continue;
182
+ total += p;
183
+ expected += p * levels[index];
184
+ }
185
+ if (total > 0.5) return expected / total;
186
+ }
187
+ const position = Number(answer.score);
188
+ if (!Number.isFinite(position)) return null;
189
+ const at = Math.min(levels.length - 1, Math.max(0, position));
190
+ const low = Math.floor(at);
191
+ const high = Math.min(levels.length - 1, low + 1);
192
+ return levels[low] + (levels[high] - levels[low]) * (at - low);
193
+ }
194
+
195
+ /**
196
+ * Jev's answer → weights over the eligible providers, or null when it does not cover every one of them
197
+ * (the deterministic split is used then). An ineligible provider weighs 0 whatever was answered.
198
+ */
199
+ export function jevWeights(judgment, eligible = {}) {
200
+ const scores = judgment?.scores;
201
+ if (!scores || typeof scores !== 'object') return null;
202
+ const out = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, 0]));
203
+ for (const provider of BUDGET_PROVIDERS) {
204
+ if (eligible[provider]?.eligible === false) continue;
205
+ const share = shareFromScore(scores[provider]);
206
+ if (share === null) return null;
207
+ out[provider] = Math.max(0, share);
208
+ }
209
+ return out;
210
+ }
211
+
212
+ // ── dividing ──────────────────────────────────────────────────────────────
213
+
214
+ /** `total` cents over `parts` (weights ≥ 0) by largest remainder: whole cents that add up exactly to `total`. */
215
+ export function apportion(total, parts) {
216
+ const keys = Object.keys(parts);
217
+ const out = Object.fromEntries(keys.map((key) => [key, 0]));
218
+ const sum = keys.reduce((acc, key) => acc + Math.max(0, num(parts[key])), 0);
219
+ if (!(total > 0) || !(sum > 0)) return out;
220
+ const rows = keys.map((key, index) => {
221
+ const exact = (total * Math.max(0, num(parts[key]))) / sum;
222
+ return { key, index, base: Math.floor(exact + 1e-9), rest: exact - Math.floor(exact + 1e-9) };
223
+ });
224
+ let given = rows.reduce((acc, row) => acc + row.base, 0);
225
+ for (const row of [...rows].sort((a, b) => b.rest - a.rest || a.index - b.index)) {
226
+ if (given >= total) break;
227
+ row.base += 1;
228
+ given += 1;
229
+ }
230
+ for (const row of rows) out[row.key] = row.base;
231
+ return out;
232
+ }
233
+
234
+ /**
235
+ * Divide what is left (`leftUsd`, rounded down to the cent) across the providers by `weights`, then raise the
236
+ * brain's reserve on its provider, taken from the others in proportion to what they got. Ineligible providers
237
+ * get nothing. → { allocCents: { [provider]: cents }, leftCents, brainFloorCents, floorsCents }
238
+ * Σ allocCents === leftCents, always.
239
+ */
240
+ export function divideLeft({ leftUsd = 0, weights = {}, eligible = {}, brainProvider = null } = {}) {
241
+ const leftCents = floorCents(leftUsd);
242
+ const pool = BUDGET_PROVIDERS.filter((p) => eligible[p]?.eligible !== false);
243
+ const zero = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, 0]));
244
+ if (!leftCents || !pool.length) return { allocCents: zero, leftCents, brainFloorCents: 0, floorsCents: { ...zero } };
245
+ const parts = Object.fromEntries(pool.map((p) => [p, Math.max(0, num(weights[p]))]));
246
+ if (pool.every((p) => !(parts[p] > 0))) {
247
+ // Nothing weighs anything: the brain's provider takes it (its turns must be paid), else equal shares.
248
+ if (brainProvider && pool.includes(brainProvider)) parts[brainProvider] = 1;
249
+ else for (const p of pool) parts[p] = 1;
250
+ }
251
+ const alloc = { ...zero, ...apportion(leftCents, parts) };
252
+ // Floors.
253
+ const brainFloorCents = brainProvider && pool.includes(brainProvider)
254
+ ? Math.min(leftCents, Math.max(Math.round(BRAIN_FLOOR_RATIO * leftCents), Math.round(BRAIN_FLOOR_MIN_USD * 100)))
255
+ : 0;
256
+ const floors = { ...zero };
257
+ if (brainFloorCents) floors[brainProvider] = brainFloorCents;
258
+ const deficit = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, Math.max(0, floors[p] - alloc[p])]));
259
+ const needed = BUDGET_PROVIDERS.reduce((acc, p) => acc + deficit[p], 0);
260
+ if (needed > 0) {
261
+ const surplus = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, Math.max(0, alloc[p] - floors[p])]));
262
+ const taken = apportion(needed, surplus);
263
+ for (const p of BUDGET_PROVIDERS) alloc[p] = alloc[p] - (taken[p] || 0) + deficit[p];
264
+ }
265
+ return { allocCents: alloc, leftCents, brainFloorCents: floors[brainProvider] || 0, floorsCents: floors };
266
+ }
267
+
268
+ // ── what a session can still spend ────────────────────────────────────────
269
+
270
+ /** spend.providers[p] → { brainUsd, runsUsd, spentUsd, liveRuns, runningRuns }, zeros for the missing. */
271
+ export function providerSpendOf(spend, provider) {
272
+ const row = spend?.providers?.[provider] || {};
273
+ const brainUsd = Math.max(0, num(row.brainUsd));
274
+ const runsUsd = Math.max(0, num(row.runsUsd));
275
+ return { brainUsd, runsUsd, spentUsd: r8(brainUsd + runsUsd), liveRuns: Math.max(0, num(row.liveRuns)), runningRuns: Math.max(0, num(row.runningRuns)) };
276
+ }
277
+ /** Every provider's spend added up. */
278
+ export function totalSpentOf(spend) { return r8(BUDGET_PROVIDERS.reduce((acc, p) => acc + providerSpendOf(spend, p).spentUsd, 0)); }
279
+
280
+ /**
281
+ * What a session with a budget can still spend, from its split and what was spent since.
282
+ * Without a split (none was made yet) every eligible provider may use everything that is left.
283
+ * leftUsd the session's: budget − everything spent (≥ 0)
284
+ * providers[p] { spentUsd, brainUsd, runsUsd, shareUsd, leftUsd, workerLeftUsd, liveRuns, runningRuns, eligible }
285
+ * leftUsd = share − spent; workerLeftUsd = that minus the brain's reserve still unspent
286
+ * (on the reserve's provider); both capped at the session's leftUsd
287
+ * brainProvider the provider the brain runs on now; brainLeftUsd what its turns may still spend
288
+ * brainReserveLeftUsd the reserve the brain has not used yet (workers on its provider cannot touch it)
289
+ */
290
+ export function coverageOf({ amountUsd = 0, split = null, spend = null, brainProvider = null } = {}) {
291
+ const spent = totalSpentOf(spend);
292
+ const leftUsd = Math.max(0, r8(num(amountUsd) - spent));
293
+ const reserveProvider = split?.brainProvider || null;
294
+ const reserveSpent = reserveProvider ? providerSpendOf(spend, reserveProvider).brainUsd : 0;
295
+ const brainReserveLeftUsd = split && reserveProvider
296
+ ? Math.max(0, r8(num(split.brainSpentAtSplitUsd) + num(split.brainFloorUsd) - reserveSpent))
297
+ : 0;
298
+ const providers = {};
299
+ for (const provider of BUDGET_PROVIDERS) {
300
+ const used = providerSpendOf(spend, provider);
301
+ const eligible = split ? split.eligible?.[provider]?.eligible !== false : true;
302
+ if (!split) {
303
+ providers[provider] = { ...used, shareUsd: null, leftUsd, workerLeftUsd: leftUsd, eligible };
304
+ continue;
305
+ }
306
+ const shareUsd = r8(num(split.shares?.[provider]));
307
+ const own = Math.max(0, r8(shareUsd - used.spentUsd));
308
+ const reserve = provider === reserveProvider ? Math.min(own, brainReserveLeftUsd) : 0;
309
+ providers[provider] = {
310
+ ...used, shareUsd, eligible,
311
+ leftUsd: Math.min(leftUsd, own),
312
+ workerLeftUsd: Math.min(leftUsd, Math.max(0, r8(own - reserve))),
313
+ };
314
+ }
315
+ const current = isProvider(brainProvider) ? brainProvider : reserveProvider;
316
+ return {
317
+ amountUsd: num(amountUsd), spentUsd: spent, leftUsd, hasSplit: !!split, providers,
318
+ brainProvider: current || null, brainLeftUsd: current ? providers[current].leftUsd : leftUsd, brainReserveLeftUsd,
319
+ };
320
+ }
321
+
322
+ /**
323
+ * Can `provider` pay for more work now? `forBrain`: the Assistant's own turn (it may use its reserve); a
324
+ * worker may not. `free`: the work runs on a free model and needs no share (the session must still be under
325
+ * its budget).
326
+ */
327
+ export function coversWork(coverage, { provider, forBrain = false, free = false, minUsd = MIN_SPEND_USD } = {}) {
328
+ if (!coverage) return true;
329
+ if (coverage.leftUsd < minUsd) return false;
330
+ if (free) return true;
331
+ const row = coverage.providers?.[provider];
332
+ if (!row) return false;
333
+ return (forBrain ? row.leftUsd : row.workerLeftUsd) >= minUsd;
334
+ }
335
+
336
+ /** The providers whose share is used up for workers (or ineligible), in BUDGET_PROVIDERS order. */
337
+ export function dryProviders(coverage, { minUsd = MIN_SPEND_USD } = {}) {
338
+ if (!coverage?.hasSplit) return coverage && coverage.leftUsd < minUsd ? [...BUDGET_PROVIDERS] : [];
339
+ return BUDGET_PROVIDERS.filter((p) => !coverage.providers[p] || coverage.providers[p].workerLeftUsd < minUsd);
340
+ }
341
+
342
+ // ── the view (API, live packet, agent_usage) ──────────────────────────────
343
+
344
+ /**
345
+ * The session's budget as the UI and the brain see it.
346
+ * setting { unlimited, amountUsd, version }
347
+ * coverage coverageOf() (ignored under No limit)
348
+ * split the session's split record, or null
349
+ * spend what the session spent (by provider, brain and runs)
350
+ */
351
+ export function budgetView({ sessionId = null, setting = null, coverage = null, split = null, spend = null, unpricedRuns = 0, brainProvider = null } = {}) {
352
+ const unlimited = !setting || setting.unlimited === true;
353
+ const spentUsd = totalSpentOf(spend);
354
+ const brainUsd = r8(BUDGET_PROVIDERS.reduce((acc, p) => acc + providerSpendOf(spend, p).brainUsd, 0));
355
+ const dispatchUsd = r8(spentUsd - brainUsd);
356
+ const base = {
357
+ sessionId, mode: unlimited ? 'unlimited' : 'limited', unlimited, version: Number(setting?.version) || 0,
358
+ amountUsd: unlimited ? null : roundUsd(setting.amountUsd),
359
+ spentUsd: roundUsd(spentUsd), brainUsd: roundUsd(brainUsd), dispatchUsd: roundUsd(dispatchUsd),
360
+ // Before rounding: whether money is left is decided on the exact numbers.
361
+ totalUsd: Number(spentUsd.toFixed(4)), unpricedRuns: Math.max(0, num(unpricedRuns)),
362
+ };
363
+ if (unlimited) {
364
+ // No limit: no shares, but each provider's spend is still shown.
365
+ const providers = BUDGET_PROVIDERS.map((provider) => {
366
+ const used = providerSpendOf(spend, provider);
367
+ return {
368
+ provider, label: PROVIDER_LABELS[provider], eligible: true, reason: null, isBrain: provider === brainProvider,
369
+ shareUsd: null, spentUsd: roundUsd(used.spentUsd), brainSpentUsd: roundUsd(used.brainUsd), runsSpentUsd: roundUsd(used.runsUsd),
370
+ leftUsd: null, workerLeftUsd: null, liveRuns: used.liveRuns, runningRuns: used.runningRuns, weight: null, judged: null,
371
+ };
372
+ });
373
+ return { ...base, leftUsd: null, warnAtUsd: null, warned: false, exceeded: false, split: null, brainProvider: brainProvider || null, providers, dry: [] };
374
+ }
375
+ const amount = num(setting.amountUsd);
376
+ const warnAtUsd = roundUsd(amount * BUDGET_WARN_RATIO);
377
+ const cov = coverage || coverageOf({ amountUsd: amount, split, spend, brainProvider });
378
+ const providers = BUDGET_PROVIDERS.map((provider) => {
379
+ const row = cov.providers[provider];
380
+ const judged = split?.jev?.scores?.[provider] || null;
381
+ return {
382
+ provider, label: PROVIDER_LABELS[provider],
383
+ eligible: row.eligible, reason: split?.eligible?.[provider]?.reason || null,
384
+ isBrain: provider === (cov.brainProvider || split?.brainProvider || null),
385
+ shareUsd: row.shareUsd === null ? null : roundUsd(row.shareUsd),
386
+ spentUsd: roundUsd(row.spentUsd), brainSpentUsd: roundUsd(row.brainUsd), runsSpentUsd: roundUsd(row.runsUsd),
387
+ leftUsd: roundUsd(row.leftUsd), workerLeftUsd: roundUsd(row.workerLeftUsd),
388
+ liveRuns: row.liveRuns, runningRuns: row.runningRuns,
389
+ weight: split ? Number(num(split.weights?.[provider]).toFixed(4)) : null,
390
+ judged: judged ? { score: Number(num(judged.score).toFixed(3)), confidence: Number(num(judged.confidence).toFixed(3)) } : null,
391
+ };
392
+ });
393
+ return {
394
+ ...base,
395
+ leftUsd: roundUsd(cov.leftUsd), warnAtUsd, warned: spentUsd >= warnAtUsd, exceeded: spentUsd >= amount || cov.leftUsd < MIN_SPEND_USD,
396
+ brainProvider: cov.brainProvider || null,
397
+ split: split ? {
398
+ source: split.source, reason: split.reason || null, updatedAt: split.at || null, fallbackWhy: split.fallbackWhy || null,
399
+ leftAtSplitUsd: roundUsd(split.leftUsd), brainProvider: split.brainProvider || null,
400
+ brainFloorUsd: roundUsd(split.brainFloorUsd), brainReserveLeftUsd: roundUsd(cov.brainReserveLeftUsd),
401
+ needs: arr(split.needs), logId: split.jev?.logId ?? null,
402
+ providers,
403
+ } : null,
404
+ // Before the first split every provider shares what is left; `providers` still says what each spent.
405
+ providers,
406
+ dry: dryProviders(cov),
407
+ };
408
+ }