synabun 2.0.0-beta → 2.0.5

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 (374) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +51 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +2 -2
  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 +20 -0
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/launcher.mjs +40 -0
  14. package/lib/claude-hooks.js +61 -8
  15. package/lib/client-config-repair.js +4 -3
  16. package/lib/data-home-migration.js +4 -0
  17. package/lib/desktop-pwa.js +206 -0
  18. package/lib/external-tools.js +221 -0
  19. package/lib/first-launch-protection.js +5 -0
  20. package/lib/packaged-runtime.js +110 -0
  21. package/lib/start-launcher.js +1396 -0
  22. package/mcp-server/package-lock.json +2 -2
  23. package/mcp-server/package.json +1 -3
  24. package/neural-interface/i18n/en.json +1540 -154
  25. package/neural-interface/i18n/pt-BR.json +1538 -153
  26. package/neural-interface/lib/assistant-api.js +62 -6
  27. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  28. package/neural-interface/lib/assistant-catalog.js +179 -27
  29. package/neural-interface/lib/assistant-config.js +31 -2
  30. package/neural-interface/lib/assistant-dispatch.js +62 -13
  31. package/neural-interface/lib/assistant-envelope.js +9 -6
  32. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  33. package/neural-interface/lib/assistant-memory.js +24 -10
  34. package/neural-interface/lib/assistant-persona.js +6 -2
  35. package/neural-interface/lib/assistant-pricing.js +21 -6
  36. package/neural-interface/lib/assistant-runtime.js +181 -12
  37. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  38. package/neural-interface/lib/assistant-test-density.js +142 -0
  39. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  40. package/neural-interface/lib/assistant-user-context.js +908 -0
  41. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  42. package/neural-interface/lib/assistant-user-learn.js +404 -0
  43. package/neural-interface/lib/assistant-user-threads.js +226 -0
  44. package/neural-interface/lib/assistant-user-writer.js +181 -0
  45. package/neural-interface/lib/augmented-path.js +23 -3
  46. package/neural-interface/lib/browser-background-tab.js +134 -0
  47. package/neural-interface/lib/browser-language.js +83 -0
  48. package/neural-interface/lib/browser-screenshot.js +678 -61
  49. package/neural-interface/lib/claude-agent-bridge.js +87 -153
  50. package/neural-interface/lib/claude-executable.js +241 -0
  51. package/neural-interface/lib/claude-model-catalog.js +82 -93
  52. package/neural-interface/lib/claude-temporary.js +46 -7
  53. package/neural-interface/lib/cloudflared/install.js +533 -0
  54. package/neural-interface/lib/cloudflared/manager.js +545 -0
  55. package/neural-interface/lib/cloudflared/pins.js +115 -0
  56. package/neural-interface/lib/cloudflared/pins.json +63 -0
  57. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  58. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  59. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  60. package/neural-interface/lib/editor-completion.js +714 -0
  61. package/neural-interface/lib/editor-config.js +149 -0
  62. package/neural-interface/lib/editor-files-api.js +268 -0
  63. package/neural-interface/lib/editor-git-api.js +134 -0
  64. package/neural-interface/lib/file-explorer-api.js +1039 -0
  65. package/neural-interface/lib/file-explorer-system.js +355 -0
  66. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  67. package/neural-interface/lib/file-explorer-watch.js +239 -0
  68. package/neural-interface/lib/git-diff-api.js +103 -0
  69. package/neural-interface/lib/git-read.js +202 -0
  70. package/neural-interface/lib/greeting/api.js +89 -0
  71. package/neural-interface/lib/greeting/budgets.js +90 -0
  72. package/neural-interface/lib/greeting/engine.js +461 -0
  73. package/neural-interface/lib/greeting/facts.js +320 -0
  74. package/neural-interface/lib/greeting/sources.js +252 -0
  75. package/neural-interface/lib/greeting/writer.js +139 -0
  76. package/neural-interface/lib/http-guards.js +189 -13
  77. package/neural-interface/lib/machine-names.js +88 -0
  78. package/neural-interface/lib/memory-api.js +31 -7
  79. package/neural-interface/lib/native-binary-runtime.js +69 -337
  80. package/neural-interface/lib/native-loop-providers.js +40 -49
  81. package/neural-interface/lib/offline-page.js +54 -0
  82. package/neural-interface/lib/plugin-installer.js +4 -2
  83. package/neural-interface/lib/project-storage.js +5 -7
  84. package/neural-interface/lib/request-gate.js +589 -0
  85. package/neural-interface/lib/session-title-generator.js +5 -0
  86. package/neural-interface/lib/synabun-update-plan.js +19 -0
  87. package/neural-interface/lib/ui-blob-api.js +108 -0
  88. package/neural-interface/lib/ui-blob-store.js +68 -0
  89. package/neural-interface/package-lock.json +701 -253
  90. package/neural-interface/package.json +13 -2
  91. package/neural-interface/public/install-app.html +34 -0
  92. package/neural-interface/public/manifest.json +2 -0
  93. package/neural-interface/public/offline.html +402 -66
  94. package/neural-interface/public/onboarding.html +264 -147
  95. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  96. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  97. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  98. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  99. package/neural-interface/public/shared/assistant/asst-mascot.js +26 -64
  100. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  101. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  102. package/neural-interface/public/shared/assistant/asst-rack-styles.js +0 -3
  103. package/neural-interface/public/shared/assistant/asst-render.js +219 -67
  104. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  105. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  106. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  107. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  108. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  109. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  110. package/neural-interface/public/shared/assistant/asst-styles.js +162 -6
  111. package/neural-interface/public/shared/blob-store.js +111 -22
  112. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  113. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  114. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  115. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  116. package/neural-interface/public/shared/command-runner-model.js +30 -0
  117. package/neural-interface/public/shared/constants.js +6 -1
  118. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  119. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  120. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  121. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  122. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  123. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  124. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  125. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  126. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  127. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  128. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  129. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  130. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  131. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  132. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  133. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  134. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  135. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  136. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  137. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  138. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  139. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  140. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  141. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  142. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  143. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  144. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  145. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  146. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  147. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  148. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  149. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  150. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  151. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  152. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  153. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  154. package/neural-interface/public/shared/file-links.js +339 -0
  155. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  156. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  157. package/neural-interface/public/shared/html-shell.js +169 -170
  158. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  159. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  160. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  161. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  162. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  163. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  164. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  165. package/neural-interface/public/shared/pwa-install-page.js +62 -0
  166. package/neural-interface/public/shared/pwa-install.css +12 -0
  167. package/neural-interface/public/shared/pwa-install.js +127 -0
  168. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  169. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  170. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  171. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  172. package/neural-interface/public/shared/settings/settings-rules.js +160 -0
  173. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  174. package/neural-interface/public/shared/start-bridge.js +802 -0
  175. package/neural-interface/public/shared/styleguide/sg-colors.js +5 -2
  176. package/neural-interface/public/shared/styleguide/sg-import-export.js +4 -3
  177. package/neural-interface/public/shared/styleguide/sg-kit.js +4 -1
  178. package/neural-interface/public/shared/styleguide/sg-panel.js +9 -1
  179. package/neural-interface/public/shared/styleguide/sg-typography.js +1 -0
  180. package/neural-interface/public/shared/styles.css +2219 -1117
  181. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  182. package/neural-interface/public/shared/term-ready.js +307 -0
  183. package/neural-interface/public/shared/tunnel-view.js +167 -0
  184. package/neural-interface/public/shared/ui-claude-panel.js +160 -19
  185. package/neural-interface/public/shared/ui-command-runner.js +251 -468
  186. package/neural-interface/public/shared/ui-detail.js +15 -0
  187. package/neural-interface/public/shared/ui-explorer.js +22 -0
  188. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  189. package/neural-interface/public/shared/ui-file-links.js +103 -0
  190. package/neural-interface/public/shared/ui-help.js +26 -0
  191. package/neural-interface/public/shared/ui-invite.js +126 -116
  192. package/neural-interface/public/shared/ui-judgments.js +1 -1
  193. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  194. package/neural-interface/public/shared/ui-loading.js +367 -12
  195. package/neural-interface/public/shared/ui-menubar.js +21 -55
  196. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  197. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  198. package/neural-interface/public/shared/ui-navbar.js +45 -21
  199. package/neural-interface/public/shared/ui-settings.js +491 -547
  200. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  201. package/neural-interface/public/shared/ui-sync.js +16 -0
  202. package/neural-interface/public/shared/ui-terminal.js +153 -149
  203. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  204. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  205. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  206. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  207. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  208. package/neural-interface/public/shared/worker-end.js +251 -0
  209. package/neural-interface/public/sw.js +3 -1
  210. package/neural-interface/public/variant/2d/main.js +2 -1
  211. package/neural-interface/public/variant/3d/main.js +2 -1
  212. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  309. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  310. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  311. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  312. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  313. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  314. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  315. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  316. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  317. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  318. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  319. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  320. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  321. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  322. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  323. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  324. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  325. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  326. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  327. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  328. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  329. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  330. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  331. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  332. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  333. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  334. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  335. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  336. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  337. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  338. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  339. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  340. package/neural-interface/scripts/build-vendor.mjs +78 -2
  341. package/neural-interface/scripts/rebuild-pty.js +15 -12
  342. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  343. package/neural-interface/server.js +1092 -1212
  344. package/neural-interface/templates/rulesets/README.md +1 -1
  345. package/package.json +13 -7
  346. package/postinstall.js +11 -81
  347. package/setup.js +111 -6
  348. package/benchmarks/browser-live-results.json +0 -79
  349. package/benchmarks/browser-v2-results.json +0 -258
  350. package/docs/browser-v2.md +0 -109
  351. package/docs/hook-integrity.md +0 -89
  352. package/docs/judgments.md +0 -182
  353. package/docs/style-guide.md +0 -246
  354. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  355. package/neural-interface/public/category-logos/claude.svg +0 -1
  356. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  357. package/neural-interface/public/category-logos/openai.svg +0 -1
  358. package/neural-interface/public/category-logos/synabun.png +0 -0
  359. package/neural-interface/public/claude.svg +0 -1
  360. package/neural-interface/public/gallery.svg +0 -6
  361. package/neural-interface/public/leonardoai.svg +0 -1
  362. package/neural-interface/public/mcp.svg +0 -4
  363. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  364. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  365. package/neural-interface/public/sessionicon.svg +0 -8
  366. package/neural-interface/public/toolbar-album.svg +0 -8
  367. package/neural-interface/public/toolbar-question.svg +0 -6
  368. package/neural-interface/public/toolbar-sessions.svg +0 -6
  369. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  370. package/scripts/audit-claude-hook-usage.mjs +0 -12
  371. package/scripts/audit-memory-duplicates.mjs +0 -44
  372. package/scripts/measure-claude-hook-overhead.mjs +0 -77
  373. package/scripts/recover-user-config.mjs +0 -254
  374. package/skills/synabun/synabunicon.png +0 -0
@@ -16,10 +16,10 @@
16
16
  // open. `synabun.route` events (phase card|auto|decided|pending|expired|
17
17
  // declined|cancelled) update the line in place by routeId.
18
18
 
19
- import { clampEffortId, getEffortLevelsForModel, modelEffortIds } from '../agent-runtime-options.js';
20
19
  import { getProviderMeta } from '../provider-icons.js';
21
- import { fetchManageCatalog, getRouting, patchHiddenModels, putRouting } from './asst-api.js';
22
- import { catalogModelRow, fmtModelPrice, hiddenModelFor, ICON_CARET, invalidateModelCatalog, loadModelCatalog, openModelMenu } from './asst-brain-picker.js';
20
+ import { fetchManageCatalog, patchHiddenModels } from './asst-api.js';
21
+ import { catalogModelRow, fmtModelPrice, hiddenModelFor, ICON_CARET, invalidateModelCatalog, openModelMenu } from './asst-brain-picker.js';
22
+ // The Routes editor's model lists (where they come from, how they stay current): asst-route-models.js.
23
23
  import { closeMenu, isMenuOpen, openMenu } from './asst-menu.js';
24
24
  import { decorateControlHead } from './asst-control.js';
25
25
  import {
@@ -63,13 +63,12 @@ export function routeModeLabel(mode, t) {
63
63
  return tr('assistant.routes.mode.unsure', 'Ask when unsure');
64
64
  }
65
65
 
66
- export function routeModeDescription(mode, model, t) {
66
+ export function routeModeDescription(mode, model, t, askBelow = 0.75) {
67
67
  const tr = tf(t);
68
- const who = str(model) || tr('assistant.routes.theBrain', 'The assistant');
69
68
  const m = normalizeRouteMode(mode, DEFAULT_ROUTE_MODE);
70
- if (m === 'always-ask') return tr('assistant.routes.mode.alwaysDesc', 'Show the route card before every task.');
71
- if (m === 'never') return tr('assistant.routes.mode.neverDesc', '{model} sorts each request; your task routes apply without asking.', { model: who });
72
- return tr('assistant.routes.mode.unsureDesc', '{model} routes on its own when confident, asks otherwise.', { model: who });
69
+ if (m === 'always-ask') return tr('assistant.routes.mode.alwaysDesc', 'Confirm every actionable task.');
70
+ if (m === 'never') return tr('assistant.routes.mode.neverDesc', 'Run saved routes immediately; otherwise the assistant chooses.');
71
+ return tr('assistant.routes.mode.unsureDesc', 'Confirm below {pct}% confidence or when a model cannot run the task.', { pct: Math.round(askBelow * 100) });
73
72
  }
74
73
 
75
74
  // ── Pure model ──────────────────────────────────────────────────────────────
@@ -208,7 +207,7 @@ function badgeText(o, n, tr) {
208
207
  const pct = fmtConfidence(n?.confidence);
209
208
  switch (o.badge) {
210
209
  case 'suggested': return pct ? tr('assistant.routes.badge.suggestedPct', 'Suggested · {pct}', { pct }) : tr('assistant.routes.badge.suggested', 'Suggested');
211
- case 'remembered': return tr('assistant.routes.badge.remembered', 'Remembered');
210
+ case 'remembered': return tr('assistant.routes.badge.remembered', 'Your choice');
212
211
  case 'current': return tr('assistant.routes.badge.current', 'Current');
213
212
  case 'capable':
214
213
  if (!n?.requires && n?.visionOnly) return tr('assistant.routes.badge.canSee', 'Can see');
@@ -344,6 +343,13 @@ export function designRouteSight(pref, catalog) {
344
343
  return row.status === 'unavailable' ? 'unavailable' : 'ok';
345
344
  }
346
345
 
346
+ /** Saved ids may resolve through a listed alias; all metadata still comes from this catalog. */
347
+ export function routeCatalogRow(pref, catalog) {
348
+ if (!pref?.provider || !catalog) return null;
349
+ const rows = Array.isArray(catalog[pref.provider]) ? catalog[pref.provider] : [];
350
+ return pref.model ? catalogModelRow(pref.provider, pref.model, catalog) || aliasRow(pref.provider, pref.model, rows) : rows.find(m => m.isDefault) || null;
351
+ }
352
+
347
353
  /** Text parts of a route line (pure). */
348
354
  export function routeLineParts(route, phase = 'decided', { brainLabel = '', t = null } = {}) {
349
355
  const tr = tf(t);
@@ -366,9 +372,9 @@ export function routeLineParts(route, phase = 'decided', { brainLabel = '', t =
366
372
  switch (str(r.decidedBy)) {
367
373
  case 'brain': decided = tr('assistant.routes.decidedBy', 'decided by {model}', { model: brainLabel || tr('assistant.routes.theBrainLower', 'the assistant') }); break;
368
374
  case 'user': decided = tr('assistant.routes.youChose', 'you chose'); break;
369
- case 'remembered': decided = tr('assistant.routes.remembered', 'remembered'); break;
375
+ case 'remembered': decided = tr('assistant.routes.remembered', 'your saved choice'); break;
370
376
  case 'timeout': decided = tr('assistant.routes.timeout', 'default after timeout'); break;
371
- default: decided = r.remembered ? tr('assistant.routes.remembered', 'remembered') : '';
377
+ default: decided = r.remembered ? tr('assistant.routes.remembered', 'your saved choice') : '';
372
378
  }
373
379
  const meta = [];
374
380
  if (effort && effort !== 'off') meta.push(effort);
@@ -598,7 +604,7 @@ export function createRouteModeControl(hostEl, hooks = {}) {
598
604
  kind: 'radio',
599
605
  id,
600
606
  label: routeModeLabel(id, hooks.t),
601
- desc: routeModeDescription(id, model, hooks.t),
607
+ desc: routeModeDescription(id, model, hooks.t, hooks.getMode?.()?.askBelow ?? 0.75),
602
608
  selected: id === mode,
603
609
  onSelect: () => { if (id !== mode) hooks.onChange?.(id); },
604
610
  })),
@@ -779,7 +785,7 @@ export function renderRouteCard(container, input, hooks = {}) {
779
785
  state.other = {
780
786
  id: 'other', kind, provider: target.provider, model: target.model, effort: null,
781
787
  label: target.label || '', badge: null, number: options.length + 1, here: false,
782
- title: target.label || target.model, badgeText: tr('assistant.routes.badge.other', 'Your pick'),
788
+ title: target.label || target.model, badgeText: tr('assistant.routes.badge.other', 'Your choice'),
783
789
  vision: target.vision === true, price: target.price || null, reason: '', warning: null, disabled: false,
784
790
  };
785
791
  state.selectedId = 'other';
@@ -798,7 +804,7 @@ export function renderRouteCard(container, input, hooks = {}) {
798
804
  rememberInput.type = 'checkbox';
799
805
  rememberInput.addEventListener('change', () => { state.remember = rememberInput.checked; });
800
806
  // `remember.label` is the task-class label ("Code"), not a sentence.
801
- const text = tr('assistant.routes.rememberFor', 'Remember for {taskClass} tasks', { taskClass: (n.remember.label || n.taskClassLabel).toLowerCase() });
807
+ const text = tr('assistant.routes.rememberFor', 'Use this choice for {taskClass} tasks', { taskClass: (n.remember.label || n.taskClassLabel).toLowerCase() });
802
808
  label.append(rememberInput, el('span', null, text));
803
809
  if (n.remember.current) label.appendChild(el('span', 'asst-route-remember-current', tr('assistant.routes.rememberCurrent', 'now: {current}', { current: n.remember.current })));
804
810
  card.appendChild(label);
@@ -1005,321 +1011,9 @@ export function renderRouteCard(container, input, hooks = {}) {
1005
1011
  return entry;
1006
1012
  }
1007
1013
 
1008
- // ── Routes editor (modal) ───────────────────────────────────────────────────
1009
-
1010
- let _editor = null;
1011
-
1012
- /**
1013
- * "Model routes…" editor. hooks: { t, providerIcon, getBrain() → brain, onSaved(routing), onClose() }
1014
- * Returns { el, close } (async: resolves after the first load).
1015
- */
1016
- export async function openRoutesEditor(hooks = {}) {
1017
- if (_editor) { _editor.close(); }
1018
- const tr = tf(hooks.t);
1019
- const overlay = el('div', 'asst-modal-overlay');
1020
- overlay.setAttribute('role', 'dialog');
1021
- overlay.setAttribute('aria-modal', 'true');
1022
- overlay.setAttribute('aria-label', tr('assistant.routes.editorTitle', 'Model routes'));
1023
- const modal = el('div', 'asst-modal asst-routes-modal');
1024
- modal.innerHTML = `
1025
- <div class="asst-modal-head"><span class="asst-icon" aria-hidden="true">${ICON_ROUTE}</span><span>${esc(tr('assistant.routes.editorTitle', 'Model routes'))}</span><button type="button" class="asst-iconbtn asst-modal-close" aria-label="${esc(tr('common.close', 'Close'))}">${ICON_X}</button></div>
1026
- <div class="asst-modal-body"><div class="asst-modal-note">${esc(tr('common.loading', 'Loading...'))}</div></div>
1027
- <div class="asst-modal-foot">
1028
- <button type="button" class="asst-btn asst-btn-secondary asst-routes-reset-all">${esc(tr('assistant.routes.resetAll', 'Reset all'))}</button>
1029
- <span class="asst-modal-spacer"></span>
1030
- <button type="button" class="asst-btn asst-btn-secondary asst-routes-cancel">${esc(tr('common.cancel', 'Cancel'))}</button>
1031
- <button type="button" class="asst-btn asst-btn-primary asst-routes-save">${esc(tr('common.save', 'Save'))}</button>
1032
- </div>`;
1033
- overlay.appendChild(modal);
1034
- const body = modal.querySelector('.asst-modal-body');
1035
- const saveBtn = modal.querySelector('.asst-routes-save');
1036
- const resetAllBtn = modal.querySelector('.asst-routes-reset-all');
1037
- const returnTo = document.activeElement;
1038
-
1039
- const state = { data: null, catalog: null, version: null, defaultMode: DEFAULT_ROUTE_MODE, prefs: {}, patch: {}, error: '', conflict: false, saving: false };
1040
-
1041
- function close() {
1042
- if (!overlay.isConnected) return;
1043
- closeMenu();
1044
- document.removeEventListener('keydown', onKey, true);
1045
- overlay.remove();
1046
- _editor = null;
1047
- try { hooks.onClose?.(); } catch { /* ignore */ }
1048
- if (returnTo?.isConnected) { try { returnTo.focus({ preventScroll: true }); } catch { /* ignore */ } }
1049
- }
1050
- function onKey(e) {
1051
- if (e.key === 'Escape') {
1052
- if (isMenuOpen()) return; // the menu closes itself first
1053
- e.preventDefault(); e.stopPropagation(); close();
1054
- return;
1055
- }
1056
- e.stopPropagation();
1057
- }
1058
- document.addEventListener('keydown', onKey, true);
1059
- overlay.addEventListener('mousedown', (e) => { if (e.target === overlay) close(); });
1060
- modal.querySelector('.asst-modal-close').addEventListener('click', close);
1061
- modal.querySelector('.asst-routes-cancel').addEventListener('click', close);
1062
- document.body.appendChild(overlay);
1063
- _editor = { close };
1064
-
1065
- function effectivePref(key) {
1066
- return Object.prototype.hasOwnProperty.call(state.patch, key) ? state.patch[key] : (state.prefs[key] || null);
1067
- }
1068
-
1069
- function sourceOf(key) {
1070
- if (Object.prototype.hasOwnProperty.call(state.patch, key)) return state.patch[key] ? 'yours' : 'default';
1071
- const pref = state.prefs[key];
1072
- if (!pref) return 'default';
1073
- return pref.by === 'user' ? 'yours' : 'remembered';
1074
- }
1075
-
1076
- function sourceLabel(source) {
1077
- if (source === 'disabled') return tr('assistant.routes.source.disabled', 'disabled');
1078
- if (source === 'incapable') return tr('assistant.routes.source.incapable', 'incapable');
1079
- if (source === 'yours') return tr('assistant.routes.source.yours', 'yours');
1080
- if (source === 'remembered') return tr('assistant.routes.source.remembered', 'remembered');
1081
- return tr('assistant.routes.source.default', 'default');
1082
- }
1083
-
1084
- /** Does the route's model generate `medium`? true | false | null (the catalog cannot tell). */
1085
- function routeMakes(pref, medium) {
1086
- if (!medium || !pref?.provider || !state.catalog) return null;
1087
- const rows = Array.isArray(state.catalog[pref.provider]) ? state.catalog[pref.provider] : [];
1088
- const row = pref.model ? catalogModelRow(pref.provider, pref.model, state.catalog) : rows.find(m => m.isDefault) || null;
1089
- if (!row?.outputs || typeof row.outputs !== 'object') return null;
1090
- return row.outputs[medium] === true;
1091
- }
1092
- /** No model in the loaded catalog makes `medium` (false while the catalog has no output data). */
1093
- function noMaker(medium) {
1094
- const rows = Object.values(state.catalog || {}).flatMap(list => (Array.isArray(list) ? list : []));
1095
- return rows.some(m => m?.outputs && typeof m.outputs === 'object') && !rows.some(m => m?.outputs?.[medium] === true);
1096
- }
1097
- /** No model in the loaded catalog can see (false while no catalog is loaded). */
1098
- function noSeer() {
1099
- const rows = Object.values(state.catalog || {}).flatMap(list => (Array.isArray(list) ? list : []));
1100
- return rows.length > 0 && !rows.some(m => m?.vision === true);
1101
- }
1102
-
1103
- function taskRows() {
1104
- const classes = Array.isArray(state.data?.taskClasses) ? state.data.taskClasses.filter(c => c?.id) : [];
1105
- const rows = classes.map(c => ({
1106
- id: String(c.id), label: str(c.label) || humanizeClass(c.id), description: str(c.description), defaultKind: str(c.defaultKind) || 'direct',
1107
- // Image / video creation: only models that generate the medium, always on a worker; design: only models that can see.
1108
- requires: c.requires === 'image' || c.requires === 'video' ? c.requires : null, dispatchOnly: c.dispatchOnly === true, visionOnly: c.vision === true,
1109
- }));
1110
- if (!rows.some(r => r.id === 'vision')) rows.push({ id: 'vision', label: tr('assistant.routes.visionRow', 'Screenshots & images'), description: tr('assistant.routes.visionDesc', 'Used when a task needs a model that can see.'), defaultKind: 'direct' });
1111
- return rows;
1112
- }
1113
-
1114
- function render() {
1115
- body.innerHTML = '';
1116
- if (state.error) {
1117
- const banner = el('div', 'asst-routes-error');
1118
- banner.setAttribute('role', 'alert');
1119
- banner.appendChild(el('span', null, state.error));
1120
- if (state.conflict) {
1121
- const reload = el('button', 'asst-btn asst-btn-secondary', tr('assistant.routes.reload', 'Reload'));
1122
- reload.type = 'button';
1123
- reload.addEventListener('click', () => load());
1124
- banner.appendChild(reload);
1125
- }
1126
- body.appendChild(banner);
1127
- }
1128
- if (!state.data) return;
1129
-
1130
- // When to ask (default route mode)
1131
- const modeSection = el('section', 'asst-routes-section');
1132
- modeSection.appendChild(el('div', 'asst-routes-section-title', tr('assistant.routes.whenToAsk', 'When to ask')));
1133
- const modes = el('div', 'asst-routes-modes');
1134
- modes.setAttribute('role', 'radiogroup');
1135
- modes.setAttribute('aria-label', tr('assistant.routes.whenToAsk', 'When to ask'));
1136
- const brainName = hooks.brainName?.() || '';
1137
- for (const id of ROUTE_MODES) {
1138
- const b = el('button', 'asst-routes-mode');
1139
- b.type = 'button';
1140
- b.setAttribute('role', 'radio');
1141
- b.setAttribute('aria-checked', state.defaultMode === id ? 'true' : 'false');
1142
- b.dataset.mode = id;
1143
- b.innerHTML = `<span class="asst-routes-mode-label">${esc(routeModeLabel(id, hooks.t))}</span><span class="asst-routes-mode-desc">${esc(routeModeDescription(id, brainName, hooks.t))}</span>`;
1144
- b.addEventListener('click', () => { state.defaultMode = id; render(); modal.querySelector(`.asst-routes-mode[data-mode="${id}"]`)?.focus(); });
1145
- modes.appendChild(b);
1146
- }
1147
- modeSection.appendChild(modes);
1148
- body.appendChild(modeSection);
1149
-
1150
- // Task routes
1151
- const section = el('section', 'asst-routes-section');
1152
- section.appendChild(el('div', 'asst-routes-section-title', tr('assistant.routes.taskRoutes', 'Task routes')));
1153
- const list = el('div', 'asst-routes-list');
1154
- for (const row of taskRows()) list.appendChild(taskRow(row));
1155
- section.appendChild(list);
1156
- body.appendChild(section);
1157
- saveBtn.disabled = state.saving;
1158
- }
1159
-
1160
- function taskRow(row) {
1161
- const pref = effectivePref(row.id);
1162
- const medium = row.requires || null;
1163
- const seeing = !medium && row.visionOnly === true;
1164
- // A saved route onto a model the user hid is never applied (the brain decides); nor, for
1165
- // image / video creation, one onto a model that cannot generate the medium, or for design one
1166
- // the router would skip (not known to see, missing from the catalog, unavailable).
1167
- const sight = seeing && pref ? designRouteSight(pref, state.catalog) : null;
1168
- const source = pref?.model && hiddenModelFor(pref.provider, pref.model) ? 'disabled'
1169
- : medium && pref && routeMakes(pref, medium) === false ? 'incapable'
1170
- : sight && sight !== 'ok' ? 'incapable' : sourceOf(row.id);
1171
- const emptyLabel = medium ? tr('assistant.routes.noCapableModel', 'No model in your catalog can make {medium} yet.', { medium: mediumWords(medium, tr) })
1172
- : seeing ? tr('assistant.routes.noSeeingModel', 'No model in your catalog can see images yet.') : '';
1173
- const node = el('div', 'asst-routes-row');
1174
- node.dataset.taskClass = row.id;
1175
- const main = el('div', 'asst-routes-row-main');
1176
- main.appendChild(el('div', 'asst-routes-row-label', row.label));
1177
- if (row.description) main.appendChild(el('div', 'asst-routes-row-desc', row.description));
1178
- if ((medium && noMaker(medium)) || (seeing && noSeer())) main.appendChild(el('div', 'asst-routes-row-note', emptyLabel));
1179
- node.appendChild(main);
1180
-
1181
- const modelBtn = el('button', 'asst-dd asst-routes-model');
1182
- modelBtn.type = 'button';
1183
- modelBtn.setAttribute('aria-haspopup', 'menu');
1184
- const label = pref ? routeTargetLabel(pref) : tr('assistant.routes.brainDecides', 'Let the brain decide');
1185
- modelBtn.innerHTML = `${pref?.provider ? `<span class="asst-icon" aria-hidden="true" style="color:${esc(providerColor(pref.provider))}">${providerIconHtml(pref.provider, hooks)}</span>` : ''}<span class="asst-dd-label"></span>`;
1186
- modelBtn.querySelector('.asst-dd-label').textContent = label;
1187
- modelBtn.setAttribute('aria-label', `${row.label}: ${label}`);
1188
- modelBtn.addEventListener('click', (e) => {
1189
- e.stopPropagation();
1190
- if (isMenuOpen(modelBtn)) { closeMenu(); return; }
1191
- openModelMenu(modelBtn, {
1192
- brain: hooks.getBrain?.() || null,
1193
- t: hooks.t,
1194
- includeHere: true,
1195
- hereLabel: tr('assistant.routes.brainDecides', 'Let the brain decide'),
1196
- title: row.label,
1197
- current: pref ? { provider: pref.provider, model: pref.model } : null,
1198
- onToast: hooks.onToast,
1199
- // Image / video creation: only models that generate the medium (no custom id: its output is unknown);
1200
- // design: only models that can see.
1201
- ...(medium ? { accept: (_p, m) => m?.outputs?.[medium] === true, allowCustom: false, emptyLabel } : {}),
1202
- ...(seeing ? { accept: (_p, m) => m?.vision === true && m?.status !== 'unavailable', allowCustom: false, emptyLabel } : {}),
1203
- onSelect: (target) => {
1204
- if (target?.here) state.patch[row.id] = null;
1205
- else if (target?.model) {
1206
- // The effort survives when the new model runs it; otherwise the nearest level it does.
1207
- const ids = modelEffortIds(catalogModelRow(target.provider, target.model, state.catalog));
1208
- const effort = !pref?.effort ? null : (ids ? clampEffortId(pref.effort, ids) : (pref.provider === target.provider ? pref.effort : null));
1209
- state.patch[row.id] = { kind: row.defaultKind || 'direct', provider: target.provider, model: target.model, effort, label: target.label || '' };
1210
- }
1211
- render();
1212
- modal.querySelector(`.asst-routes-row[data-task-class="${CSS.escape(row.id)}"] .asst-routes-model`)?.focus();
1213
- },
1214
- });
1215
- });
1216
- node.appendChild(modelBtn);
1217
-
1218
- // Exactly the selected model's levels (the provider list only for an unknown model).
1219
- const modelRow = pref?.provider ? catalogModelRow(pref.provider, pref.model, state.catalog) : null;
1220
- const efforts = pref?.provider ? getEffortLevelsForModel(pref.provider, modelRow) : [];
1221
- if (pref && efforts.some(e => e.id !== 'off')) {
1222
- const effortBtn = el('button', 'asst-dd asst-routes-effort');
1223
- effortBtn.type = 'button';
1224
- effortBtn.setAttribute('aria-haspopup', 'menu');
1225
- const level = efforts.find(e => e.id === pref.effort);
1226
- const autoLabel = modelRow?.defaultEffort
1227
- ? tr('assistant.routes.effortAutoDefault', 'auto ({effort})', { effort: efforts.find(e => e.id === modelRow.defaultEffort)?.label?.toLowerCase() || modelRow.defaultEffort })
1228
- : tr('assistant.routes.effortAuto', 'auto effort');
1229
- const effortLabel = level ? level.label
1230
- : pref.effort ? tr('assistant.routes.effortUnsupported', '{effort} · unsupported', { effort: pref.effort })
1231
- : autoLabel;
1232
- effortBtn.innerHTML = '<span class="asst-dd-label"></span>';
1233
- effortBtn.querySelector('.asst-dd-label').textContent = effortLabel;
1234
- effortBtn.setAttribute('aria-label', `${tr('assistant.brain.effort', 'Thinking effort')}: ${effortLabel}`);
1235
- effortBtn.addEventListener('click', (e) => {
1236
- e.stopPropagation();
1237
- if (isMenuOpen(effortBtn)) { closeMenu(); return; }
1238
- openMenu(effortBtn, {
1239
- title: tr('assistant.brain.effort', 'Thinking effort'),
1240
- role: 'menu',
1241
- items: [
1242
- { kind: 'radio', id: '', label: autoLabel, selected: !pref.effort, onSelect: () => { state.patch[row.id] = { ...pref, effort: null }; render(); } },
1243
- ...efforts.filter(x => x.id !== 'off').map(x => ({ kind: 'radio', id: x.id, label: x.label, desc: x.desc || '', selected: pref.effort === x.id, onSelect: () => { state.patch[row.id] = { ...pref, effort: x.id }; render(); } })),
1244
- ],
1245
- });
1246
- });
1247
- node.appendChild(effortBtn);
1248
- }
1249
-
1250
- const badge = el('span', 'asst-routes-source', sourceLabel(source));
1251
- badge.dataset.source = source;
1252
- if (source === 'incapable') {
1253
- badge.setAttribute('data-tooltip', !seeing ? tr('assistant.routes.incapableTip', "This model can't generate {medium}, so the route is not applied.", { medium: mediumWords(medium, tr) })
1254
- : sight === 'blind' ? tr('assistant.routes.incapableSeeTip', "This model can't see images, so the route is not applied.")
1255
- : sight === 'unavailable' ? tr('assistant.routes.unavailableTip', "This model isn't available right now, so the route is not applied.")
1256
- : tr('assistant.routes.unknownSeeTip', "This model isn't known to see images, so the route is not applied."));
1257
- }
1258
- node.appendChild(badge);
1259
-
1260
- const reset = el('button', 'asst-iconbtn asst-routes-reset', '↺');
1261
- reset.type = 'button';
1262
- reset.setAttribute('aria-label', tr('assistant.routes.reset', 'Reset {taskClass}', { taskClass: row.label }));
1263
- reset.setAttribute('data-tooltip', tr('assistant.routes.resetTip', 'Back to default'));
1264
- reset.hidden = source === 'default';
1265
- reset.addEventListener('click', () => { state.patch[row.id] = null; render(); });
1266
- node.appendChild(reset);
1267
- return node;
1268
- }
1269
-
1270
- async function load() {
1271
- state.error = '';
1272
- state.conflict = false;
1273
- try {
1274
- const [data, catalog] = await Promise.all([getRouting(), loadModelCatalog().catch(() => null)]);
1275
- state.catalog = catalog || null;
1276
- state.data = data || {};
1277
- state.version = data?.version ?? null;
1278
- state.defaultMode = normalizeRouteMode(data?.routing?.defaultMode, DEFAULT_ROUTE_MODE);
1279
- state.prefs = obj(data?.routing?.preferences) ? { ...data.routing.preferences } : {};
1280
- state.patch = {};
1281
- } catch (err) {
1282
- state.data = null;
1283
- state.error = err?.status === 404
1284
- ? tr('assistant.routes.unavailable', 'Model routing is not available on this server yet.')
1285
- : `${tr('assistant.routes.loadFailed', 'Could not load model routes')}: ${err?.message || err}`;
1286
- }
1287
- render();
1288
- modal.querySelector('.asst-routes-mode[aria-checked="true"]')?.focus();
1289
- }
1290
-
1291
- resetAllBtn.addEventListener('click', () => {
1292
- for (const key of new Set([...Object.keys(state.prefs), ...Object.keys(state.patch)])) state.patch[key] = null;
1293
- render();
1294
- });
1295
-
1296
- saveBtn.addEventListener('click', async () => {
1297
- if (!state.data || state.saving) return;
1298
- state.saving = true;
1299
- saveBtn.disabled = true;
1300
- const patch = { defaultMode: state.defaultMode };
1301
- if (Object.keys(state.patch).length) patch.preferences = { ...state.patch };
1302
- try {
1303
- const res = await putRouting(patch, state.version);
1304
- try { hooks.onSaved?.(res?.routing || null, res); } catch { /* ignore */ }
1305
- close();
1306
- } catch (err) {
1307
- state.saving = false;
1308
- if (err?.status === 409 || err?.code === 'VERSION_CONFLICT') {
1309
- state.error = tr('assistant.routes.conflict', 'Changed elsewhere — reload');
1310
- state.conflict = true;
1311
- } else if (err?.code === 'ROUTING_INVALID') {
1312
- state.error = tr('assistant.routes.invalidField', 'Invalid routing setting: {field}', { field: err?.message || '' });
1313
- } else {
1314
- state.error = `${tr('assistant.routes.saveFailed', 'Could not save')}: ${err?.message || err}`;
1315
- }
1316
- render();
1317
- }
1318
- });
1319
-
1320
- await load();
1321
- return { el: overlay, close };
1322
- }
1014
+ // ── Routes editor (draft, modes, task choices) ───────────────────────────────
1015
+ // Its model lists still come only through asst-route-models.js.
1016
+ export { openRoutesEditor } from './asst-routes-editor.js';
1323
1017
 
1324
1018
  // ── Models manager (Assistant → Models…) ───────────────────────────────────
1325
1019