synabun 2.0.0 → 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 (334) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +46 -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/lib/start-launcher.js +88 -1
  14. package/mcp-server/package-lock.json +2 -2
  15. package/mcp-server/package.json +1 -3
  16. package/neural-interface/i18n/en.json +1500 -153
  17. package/neural-interface/i18n/pt-BR.json +1498 -152
  18. package/neural-interface/lib/assistant-api.js +62 -6
  19. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  20. package/neural-interface/lib/assistant-catalog.js +179 -27
  21. package/neural-interface/lib/assistant-config.js +31 -2
  22. package/neural-interface/lib/assistant-dispatch.js +62 -13
  23. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  24. package/neural-interface/lib/assistant-memory.js +24 -10
  25. package/neural-interface/lib/assistant-persona.js +6 -2
  26. package/neural-interface/lib/assistant-pricing.js +21 -6
  27. package/neural-interface/lib/assistant-runtime.js +181 -12
  28. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  29. package/neural-interface/lib/assistant-test-density.js +142 -0
  30. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  31. package/neural-interface/lib/assistant-user-context.js +908 -0
  32. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  33. package/neural-interface/lib/assistant-user-learn.js +404 -0
  34. package/neural-interface/lib/assistant-user-threads.js +226 -0
  35. package/neural-interface/lib/assistant-user-writer.js +181 -0
  36. package/neural-interface/lib/browser-background-tab.js +134 -0
  37. package/neural-interface/lib/browser-screenshot.js +678 -61
  38. package/neural-interface/lib/claude-agent-bridge.js +33 -6
  39. package/neural-interface/lib/claude-model-catalog.js +30 -2
  40. package/neural-interface/lib/claude-temporary.js +46 -7
  41. package/neural-interface/lib/cloudflared/install.js +533 -0
  42. package/neural-interface/lib/cloudflared/manager.js +545 -0
  43. package/neural-interface/lib/cloudflared/pins.js +115 -0
  44. package/neural-interface/lib/cloudflared/pins.json +63 -0
  45. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  46. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  47. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  48. package/neural-interface/lib/editor-completion.js +714 -0
  49. package/neural-interface/lib/editor-config.js +149 -0
  50. package/neural-interface/lib/editor-files-api.js +268 -0
  51. package/neural-interface/lib/editor-git-api.js +134 -0
  52. package/neural-interface/lib/file-explorer-api.js +1039 -0
  53. package/neural-interface/lib/file-explorer-system.js +355 -0
  54. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  55. package/neural-interface/lib/file-explorer-watch.js +239 -0
  56. package/neural-interface/lib/git-diff-api.js +103 -0
  57. package/neural-interface/lib/git-read.js +202 -0
  58. package/neural-interface/lib/greeting/api.js +89 -0
  59. package/neural-interface/lib/greeting/budgets.js +90 -0
  60. package/neural-interface/lib/greeting/engine.js +461 -0
  61. package/neural-interface/lib/greeting/facts.js +320 -0
  62. package/neural-interface/lib/greeting/sources.js +252 -0
  63. package/neural-interface/lib/greeting/writer.js +139 -0
  64. package/neural-interface/lib/http-guards.js +189 -13
  65. package/neural-interface/lib/machine-names.js +88 -0
  66. package/neural-interface/lib/memory-api.js +31 -7
  67. package/neural-interface/lib/native-loop-providers.js +10 -5
  68. package/neural-interface/lib/plugin-installer.js +4 -2
  69. package/neural-interface/lib/project-storage.js +5 -7
  70. package/neural-interface/lib/request-gate.js +589 -0
  71. package/neural-interface/lib/ui-blob-api.js +108 -0
  72. package/neural-interface/lib/ui-blob-store.js +68 -0
  73. package/neural-interface/package-lock.json +701 -2
  74. package/neural-interface/package.json +13 -2
  75. package/neural-interface/public/install-app.html +9 -6
  76. package/neural-interface/public/offline.html +3 -2
  77. package/neural-interface/public/onboarding.html +12 -1
  78. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  79. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  80. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  81. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  82. package/neural-interface/public/shared/assistant/asst-mascot.js +18 -58
  83. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  84. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  85. package/neural-interface/public/shared/assistant/asst-render.js +162 -19
  86. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  87. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  88. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  89. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  90. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  91. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  92. package/neural-interface/public/shared/assistant/asst-styles.js +158 -4
  93. package/neural-interface/public/shared/blob-store.js +111 -22
  94. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  95. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  96. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  97. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  98. package/neural-interface/public/shared/constants.js +6 -1
  99. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  100. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  101. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  102. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  103. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  104. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  105. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  106. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  107. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  108. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  109. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  110. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  111. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  112. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  113. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  114. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  115. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  116. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  117. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  118. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  119. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  120. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  121. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  122. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  123. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  124. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  125. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  126. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  127. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  128. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  129. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  130. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  131. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  132. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  133. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  134. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  135. package/neural-interface/public/shared/file-links.js +339 -0
  136. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  137. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  138. package/neural-interface/public/shared/html-shell.js +160 -165
  139. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  140. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  141. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  142. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  143. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  144. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  145. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  146. package/neural-interface/public/shared/pwa-install-page.js +29 -1
  147. package/neural-interface/public/shared/pwa-install.css +3 -3
  148. package/neural-interface/public/shared/pwa-install.js +100 -1
  149. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  150. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  151. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  152. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  153. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  154. package/neural-interface/public/shared/start-bridge.js +238 -19
  155. package/neural-interface/public/shared/styles.css +1414 -721
  156. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  157. package/neural-interface/public/shared/tunnel-view.js +167 -0
  158. package/neural-interface/public/shared/ui-claude-panel.js +157 -16
  159. package/neural-interface/public/shared/ui-detail.js +15 -0
  160. package/neural-interface/public/shared/ui-explorer.js +22 -0
  161. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  162. package/neural-interface/public/shared/ui-file-links.js +103 -0
  163. package/neural-interface/public/shared/ui-help.js +26 -0
  164. package/neural-interface/public/shared/ui-invite.js +126 -116
  165. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  166. package/neural-interface/public/shared/ui-loading.js +159 -15
  167. package/neural-interface/public/shared/ui-menubar.js +12 -30
  168. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  169. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  170. package/neural-interface/public/shared/ui-navbar.js +45 -21
  171. package/neural-interface/public/shared/ui-settings.js +455 -488
  172. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  173. package/neural-interface/public/shared/ui-sync.js +16 -0
  174. package/neural-interface/public/shared/ui-terminal.js +23 -5
  175. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  176. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  177. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  178. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  179. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  180. package/neural-interface/public/shared/worker-end.js +251 -0
  181. package/neural-interface/public/sw.js +2 -2
  182. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  183. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  184. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  185. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  186. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  187. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  188. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  189. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  190. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  191. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  192. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  193. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  194. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  195. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  196. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  197. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  198. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  199. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  200. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  201. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  202. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  203. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  204. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  205. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  206. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  207. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  208. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  209. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  210. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  211. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  212. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  309. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  310. package/neural-interface/scripts/build-vendor.mjs +78 -2
  311. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  312. package/neural-interface/server.js +873 -1028
  313. package/neural-interface/templates/rulesets/README.md +1 -1
  314. package/package.json +2 -8
  315. package/setup.js +44 -7
  316. package/benchmarks/browser-live-results.json +0 -79
  317. package/benchmarks/browser-v2-results.json +0 -258
  318. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  319. package/neural-interface/public/category-logos/claude.svg +0 -1
  320. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  321. package/neural-interface/public/category-logos/openai.svg +0 -1
  322. package/neural-interface/public/category-logos/synabun.png +0 -0
  323. package/neural-interface/public/claude.svg +0 -1
  324. package/neural-interface/public/gallery.svg +0 -6
  325. package/neural-interface/public/leonardoai.svg +0 -1
  326. package/neural-interface/public/mcp.svg +0 -4
  327. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  328. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  329. package/neural-interface/public/sessionicon.svg +0 -8
  330. package/neural-interface/public/toolbar-album.svg +0 -8
  331. package/neural-interface/public/toolbar-question.svg +0 -6
  332. package/neural-interface/public/toolbar-sessions.svg +0 -6
  333. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  334. package/skills/synabun/synabunicon.png +0 -0
@@ -20,6 +20,7 @@
20
20
 
21
21
  import { assistantEventKey, fmtCost, fmtElapsed, isRemovableRun, isRunIdle, isTerminalRunStatus, modelShortName, providerShortLabel, routeTargetLabel, runTone, summarizeMailbox } from './asst-state.js';
22
22
  import { createRouteLine } from './asst-route.js';
23
+ import { closeMenu, isMenuOpen } from './asst-menu.js';
23
24
  import { computerToolName, describeComputerAction, frameUrls, markerPercent, openFrameLightbox, parseComputerResult, swapImage } from './asst-computer.js';
24
25
  import * as mascotLib from '../synabun-mascot.js';
25
26
  import { isReducedMotion, subscribe } from '../synabun-ticker.js';
@@ -27,6 +28,7 @@ import { KIND_SPECS, callOutcome, commandOf, editDiff, editPaths, fmtDuration, g
27
28
  import { injectRackStyles } from './asst-rack-styles.js';
28
29
  import { formatRunTokens } from './asst-usage.js';
29
30
  import { sanitizeHtmlString, sanitizeInto } from './asst-sanitize.js';
31
+ import { automationView } from './asst-automation.js';
30
32
 
31
33
  // ── Markdown (lazy marked, same CDN build as the sidepanels) ───────────────
32
34
  let _marked = null;
@@ -227,7 +229,7 @@ export function updateRunCard(card, run, opts = {}) {
227
229
  const routeBits = [r.taskClassLabel || r.taskClass || t('assistant.routes.task', 'task')];
228
230
  if (r.status === 'pending') routeBits.push(t('assistant.routes.state.pending', 'waiting for your choice'));
229
231
  else if (r.decidedBy === 'user') routeBits.push(t('assistant.routes.youChose', 'you chose'));
230
- else if (r.remembered || r.decidedBy === 'remembered') routeBits.push(t('assistant.routes.remembered', 'remembered'));
232
+ else if (r.remembered || r.decidedBy === 'remembered') routeBits.push(t('assistant.routes.remembered', 'your saved choice'));
231
233
  else if (Number.isFinite(Number(r.confidence))) routeBits.push(`${Math.round(Number(r.confidence) <= 1 ? Number(r.confidence) * 100 : Number(r.confidence))}%`);
232
234
  const tip = r.target ? `${t('assistant.routes.routedTo', 'Routed to')} ${routeTargetLabel(r.target, { effort: true })}` : t('assistant.routes.title', 'Model routing');
233
235
  bits.push(`<span class="asst-run-route" data-tooltip="${esc(tip)}">⇄ ${esc(routeBits.join(', '))}</span>`);
@@ -434,12 +436,12 @@ export function createRenderer(transcriptEl, hooks = {}) {
434
436
  const scopes = new Map(); // parent_tool_use_id → { container, stream, key }
435
437
  const runCards = new Map(); // runId → card element
436
438
  const routeLines = new Map(); // routeId → line handle
439
+ const autoRows = new Map(); // traceId → the turn's automation trace row
437
440
  let working = null;
438
441
  let workingFace = null; // the "Thinking" row's character: { still, rig?, el, target? } (syncWorkingFace)
439
442
  let followTail = true;
440
443
  let emptyEl = null;
441
444
  let hero = null; // the empty state's character: { rig, el, box, parked, leaving, held, dock, egg, target }
442
- let rigsOn = true; // this panel's rigs may animate (asst-mascot.js lets one panel at a time)
443
445
  const mcpWarned = new Set();
444
446
  let lastErrorText = ''; // a synthetic API-error message's text, so the result does not repeat it
445
447
  let turnFrames = []; // computer cards with inline thumbnails in the current turn
@@ -539,10 +541,17 @@ export function createRenderer(transcriptEl, hooks = {}) {
539
541
  function hideEmpty({ park = false } = {}) {
540
542
  if (!emptyEl) return;
541
543
  if (!(park && parkHero())) dropHero();
544
+ closeEmptyMenu();
542
545
  emptyEl.remove();
543
546
  emptyEl = null;
544
547
  }
545
548
 
549
+ /** A menu opened from the empty state's project picker does not outlive it. */
550
+ function closeEmptyMenu() {
551
+ const btn = emptyEl?.querySelector('.asst-empty-project-btn');
552
+ if (btn && isMenuOpen(btn)) closeMenu();
553
+ }
554
+
546
555
  // ── The hero ──
547
556
  const cssEase = (name, fallback) => {
548
557
  try { return getComputedStyle($msgs).getPropertyValue(name).trim() || fallback; } catch { return fallback; }
@@ -698,13 +707,6 @@ export function createRenderer(transcriptEl, hooks = {}) {
698
707
  try { hooks.onMascotChange?.(); } catch { /* the director is gone */ }
699
708
  }
700
709
 
701
- /** Whether this panel's rigs animate (another panel may lead); still frames otherwise. */
702
- function setRigsEnabled(on) {
703
- if (rigsOn === !!on) return;
704
- rigsOn = !!on;
705
- activateRigs();
706
- }
707
-
708
710
  function prune() {
709
711
  const rows = $msgs.children;
710
712
  while (rows.length > MAX_MESSAGES && rows[0] !== working) rows[0].remove();
@@ -757,8 +759,8 @@ export function createRenderer(transcriptEl, hooks = {}) {
757
759
  const a = el('a', 'file-link', match[0]);
758
760
  a.href = '#';
759
761
  a.title = t('assistant.copyPath', 'Click to copy path');
760
- const path = match[0].replace(/:\d+$/, '');
761
- a.addEventListener('click', (e) => { e.preventDefault(); hooks.copy?.(path); a.style.opacity = '0.5'; setTimeout(() => { a.style.opacity = ''; }, 300); });
762
+ // The click is taken on the transcript (asst-panel.js → ui-file-links.js): the code editor when it
763
+ // can open the path, else the copy a click has always made.
762
764
  frag.appendChild(a);
763
765
  last = match.index + match[0].length;
764
766
  }
@@ -1502,7 +1504,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
1502
1504
  rack.clearTimer = 0;
1503
1505
  rack.row.classList.add('is-staged');
1504
1506
  if (!rack.rig) {
1505
- try { rack.rig = mascotLib.createMascot(rack.stage.face, { width: 72, height: 36, rangeX: 10, rangeY: 7, active: rigsOn, pose: 'idle' }); } catch { rack.rig = null; }
1507
+ try { rack.rig = mascotLib.createMascot(rack.stage.face, { width: 72, height: 36, rangeX: 10, rangeY: 7, pose: 'idle' }); } catch { rack.rig = null; }
1506
1508
  rack.pose = null;
1507
1509
  rack.target = rack.rig ? stageTarget(rack) : null;
1508
1510
  if (hero?.parked) dropHero(); // the stage is the character now: a hero still on its way out goes at once
@@ -1564,12 +1566,16 @@ export function createRenderer(transcriptEl, hooks = {}) {
1564
1566
  rack.bubble = { step: null, since: 0, key: '', open: false };
1565
1567
  }
1566
1568
 
1567
- /** One rig animates: the hero, else the newest stage, else the "Thinking" row's; none while another panel leads (setRigsEnabled). */
1569
+ /**
1570
+ * One rig of this transcript animates: the hero, else the newest stage, else
1571
+ * the "Thinking" row's. The rule ends at this renderer: every other panel
1572
+ * runs its own, so N live sessions show N moving characters.
1573
+ */
1568
1574
  function activateRigs() {
1569
1575
  const newest = hero?.rig ? null : newestStage();
1570
- for (const rack of racks) if (rack.rig) rack.rig.setActive?.(rigsOn && rack === newest);
1571
- hero?.rig?.setActive?.(rigsOn);
1572
- workingFace?.rig?.setActive?.(rigsOn && !hero?.rig && !newest);
1576
+ for (const rack of racks) if (rack.rig) rack.rig.setActive?.(rack === newest);
1577
+ hero?.rig?.setActive?.(true);
1578
+ workingFace?.rig?.setActive?.(!hero?.rig && !newest);
1573
1579
  }
1574
1580
 
1575
1581
  /** The bubble's call: the awake one, else the newest; it holds 900 ms (3 s for thinking) before the next wins. */
@@ -2634,7 +2640,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
2634
2640
  return;
2635
2641
  }
2636
2642
  try {
2637
- const rig = mascotLib.createMascot(host, { width: 56, height: 28, active: rigsOn, pose: 'think' });
2643
+ const rig = mascotLib.createMascot(host, { width: 56, height: 28, pose: 'think' });
2638
2644
  const face = { still: false, rig, el: rig.el, held: false };
2639
2645
  face.target = { kind: 'working', rig, el: rig.el, hold(on) { face.held = !!on; }, restore() { if (workingFace === face) rig.setPose('think'); } };
2640
2646
  workingFace = face;
@@ -2761,6 +2767,115 @@ export function createRenderer(transcriptEl, hooks = {}) {
2761
2767
  if (line) { line.el.remove(); routeLines.delete(routeId); }
2762
2768
  }
2763
2769
 
2770
+ // ── The automation trace ──
2771
+ // What the harness did for a turn (`synabun.automation`, asst-automation.js):
2772
+ // one disclosure row per turn, upserted by its traceId. It appears where the
2773
+ // turn was sent, moves under the reply when the turn ends and updates in
2774
+ // place when learning finishes. Drawn from the event alone, so the live row
2775
+ // and the replayed one are the same. Opening one keeps the next ones open.
2776
+ let autoUid = 0;
2777
+ const TRACE_OPEN_KEY = 'synabun-asst-trace-open';
2778
+ const traceOpenPref = () => { try { return localStorage.getItem(TRACE_OPEN_KEY) === '1'; } catch { return false; } };
2779
+
2780
+ function buildAutoRow() {
2781
+ const node = el('div', 'asst-route-line asst-auto');
2782
+ const detailId = `asst-auto-detail-${++autoUid}`;
2783
+ node.innerHTML = `
2784
+ <button type="button" class="asst-route-line-head asst-auto-head" aria-expanded="false" aria-controls="${detailId}">
2785
+ <span class="asst-route-glyph asst-icon" aria-hidden="true">${ICON_MEMORY}</span>
2786
+ <span class="asst-route-class asst-auto-title"></span>
2787
+ <span class="asst-route-meta asst-auto-summary"></span>
2788
+ <span class="asst-route-state asst-auto-state"></span>
2789
+ <span class="asst-route-chev" aria-hidden="true">&#x203A;</span>
2790
+ </button>
2791
+ <div class="asst-route-detail asst-auto-detail" id="${detailId}" hidden></div>`;
2792
+ const head = node.querySelector('.asst-auto-head');
2793
+ const detail = node.querySelector('.asst-auto-detail');
2794
+ const setOpen = (open) => {
2795
+ head.setAttribute('aria-expanded', open ? 'true' : 'false');
2796
+ detail.hidden = !open;
2797
+ node.classList.toggle('open', open);
2798
+ };
2799
+ head.addEventListener('click', () => {
2800
+ const open = head.getAttribute('aria-expanded') !== 'true';
2801
+ setOpen(open);
2802
+ try { localStorage.setItem(TRACE_OPEN_KEY, open ? '1' : '0'); } catch { /* no storage: this row only */ }
2803
+ });
2804
+ setOpen(traceOpenPref());
2805
+ return { el: node, detail, atEnd: false };
2806
+ }
2807
+
2808
+ function paintAutoRow(row, ev) {
2809
+ const view = automationView(ev, { t: hooks.t });
2810
+ row.el.dataset.traceId = view.traceId;
2811
+ row.el.dataset.phase = view.phase;
2812
+ row.el.classList.toggle('busy', view.tone === 'busy');
2813
+ row.el.classList.toggle('learned', view.tone === 'learned');
2814
+ row.el.querySelector('.asst-auto-title').textContent = view.title;
2815
+ row.el.querySelector('.asst-auto-summary').textContent = view.summary;
2816
+ const state = row.el.querySelector('.asst-auto-state');
2817
+ state.textContent = view.state;
2818
+ state.hidden = !view.state;
2819
+ row.detail.replaceChildren();
2820
+ for (const group of view.groups) {
2821
+ const box = el('div', 'asst-auto-group');
2822
+ box.dataset.group = group.key;
2823
+ box.appendChild(el('div', 'asst-auto-h', group.title));
2824
+ for (const item of group.rows) {
2825
+ const line = el('div', `asst-auto-row${item.tone ? ` ${item.tone}` : ''}`);
2826
+ if (item.label || item.meta) {
2827
+ const lead = el('div', 'asst-auto-row-head');
2828
+ if (item.label) lead.appendChild(el('span', 'asst-auto-tier', item.label));
2829
+ if (item.meta) lead.appendChild(el('span', 'asst-auto-meta', item.meta));
2830
+ line.appendChild(lead);
2831
+ }
2832
+ // Memory text and the user's own words: always as text, never as markup.
2833
+ if (item.text) line.appendChild(el(item.pre ? 'pre' : 'div', 'asst-auto-text', item.text));
2834
+ if (item.ids.length) {
2835
+ const ids = el('div', 'asst-auto-ids');
2836
+ for (const id of item.ids) {
2837
+ const link = el('button', 'asst-link', String(id).slice(0, 8));
2838
+ link.type = 'button';
2839
+ link.dataset.memoryId = id;
2840
+ link.title = `${t('assistant.automation.open', 'Open memory')} ${id}`;
2841
+ link.setAttribute('aria-label', link.title);
2842
+ link.addEventListener('click', () => hooks.onMemoryClick?.(id, { id }));
2843
+ ids.appendChild(link);
2844
+ }
2845
+ line.appendChild(ids);
2846
+ }
2847
+ box.appendChild(line);
2848
+ }
2849
+ row.detail.appendChild(box);
2850
+ }
2851
+ }
2852
+
2853
+ /** Create or update the trace row for `ev.traceId`. */
2854
+ function upsertAutomation(ev) {
2855
+ const id = String(ev?.traceId || '');
2856
+ if (!id) return null;
2857
+ let row = autoRows.get(id);
2858
+ const fresh = !row || !row.el.isConnected;
2859
+ if (fresh) {
2860
+ row = buildAutoRow();
2861
+ autoRows.set(id, row);
2862
+ while (autoRows.size > 200) autoRows.delete(autoRows.keys().next().value);
2863
+ }
2864
+ paintAutoRow(row, ev);
2865
+ // Under the reply once the turn has ended; a later snapshot (learning) never moves it again.
2866
+ const ended = ev.phase !== 'sent';
2867
+ if (fresh || (ended && !row.atEnd)) {
2868
+ // Placed like any row (before "Working…"), but a status line of the harness never dismisses the hero.
2869
+ if (working && working.parentNode === $msgs) $msgs.insertBefore(row.el, working);
2870
+ else $msgs.appendChild(row.el);
2871
+ if (ended) row.atEnd = true;
2872
+ prune();
2873
+ if (racks.size) syncRacks();
2874
+ scrollEnd();
2875
+ }
2876
+ return row.el;
2877
+ }
2878
+
2764
2879
  // ── Empty state ──
2765
2880
  function showEmpty() {
2766
2881
  if (emptyEl || $msgs.querySelector(':scope > :not(.asst-working)')) return;
@@ -2769,14 +2884,22 @@ export function createRenderer(transcriptEl, hooks = {}) {
2769
2884
  <div class="asst-empty-mascot" aria-hidden="true"></div>
2770
2885
  <div class="asst-empty-title" role="heading" aria-level="2">${esc(t('assistant.empty.heading', 'What should we do?'))}</div>
2771
2886
  <div class="asst-empty-body">${esc(t('assistant.empty.lead', 'I can use your Mac, look things up on the web, edit files and run commands, and remember or schedule things.'))}</div>
2887
+ <div class="asst-empty-greet"></div>
2888
+ <div class="asst-empty-project" hidden></div>
2772
2889
  <div class="asst-suggestions" role="list"></div>`;
2773
2890
  const box = emptyEl.querySelector('.asst-empty-mascot');
2774
2891
  try {
2775
- const rig = mascotLib.createMascot(box, { width: 120, height: 60, active: rigsOn });
2892
+ const rig = mascotLib.createMascot(box, { width: 120, height: 60 });
2776
2893
  hero = { rig, el: rig.el, box, parked: false, leaving: false, held: false, dock: null, egg: false, leaveTimer: 0 };
2777
2894
  hero.target = heroTarget(hero);
2778
2895
  wireEgg(hero);
2779
2896
  } catch { hero = null; }
2897
+ // The project the conversation works in, under the lead: the host draws the picker (the brain
2898
+ // picker's project field), so it and the toolbar's Working project are one control.
2899
+ const projectSlot = emptyEl.querySelector('.asst-empty-project');
2900
+ let picker = null;
2901
+ try { picker = typeof hooks.mountEmptyProject === 'function' ? hooks.mountEmptyProject(projectSlot) : null; } catch { picker = null; }
2902
+ projectSlot.hidden = !picker;
2780
2903
  renderSuggestions();
2781
2904
  $msgs.appendChild(emptyEl);
2782
2905
  // The host's "Starting…" character flies into place (not on replay or reduced motion).
@@ -2786,6 +2909,20 @@ export function createRenderer(transcriptEl, hooks = {}) {
2786
2909
  mascotChanged();
2787
2910
  }
2788
2911
 
2912
+ /**
2913
+ * The greeting SynaBun prepared for this return (public/shared/greeting/) takes the lead's place.
2914
+ * The panel calls it once it knows the conversation is new: a restored one is never greeted.
2915
+ */
2916
+ function offerGreeting() {
2917
+ const owner = emptyEl;
2918
+ if (!owner || owner.dataset.greetingAsked === '1' || typeof hooks.greeting !== 'function') return;
2919
+ owner.dataset.greetingAsked = '1';
2920
+ const slot = owner.querySelector('.asst-empty-greet');
2921
+ Promise.resolve().then(() => hooks.greeting(slot))
2922
+ .then((greeting) => { if (greeting && emptyEl === owner) owner.classList.add('has-greeting'); })
2923
+ .catch(() => { /* no greeting: the lead stays */ });
2924
+ }
2925
+
2789
2926
  function renderSuggestions() {
2790
2927
  if (!emptyEl) return;
2791
2928
  const host = emptyEl.querySelector('.asst-suggestions');
@@ -3111,6 +3248,9 @@ export function createRenderer(transcriptEl, hooks = {}) {
3111
3248
  // The card itself arrives as a control_request; its outcome is a line (the panel's card shows it live).
3112
3249
  if (ev.phase !== 'card') appendStatus(clarifyLine(ev), 'info');
3113
3250
  return true;
3251
+ case 'synabun.automation':
3252
+ upsertAutomation(ev);
3253
+ return true;
3114
3254
  default:
3115
3255
  return false;
3116
3256
  }
@@ -3233,6 +3373,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
3233
3373
  scopes.clear();
3234
3374
  runCards.clear();
3235
3375
  routeLines.clear();
3376
+ autoRows.clear();
3236
3377
  turnFrames = [];
3237
3378
  rootScope.stream = null;
3238
3379
  rootScope.kept = null;
@@ -3249,6 +3390,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
3249
3390
  seen.clear();
3250
3391
  snapshot = null;
3251
3392
  waiting = null;
3393
+ closeEmptyMenu();
3252
3394
  $msgs.innerHTML = '';
3253
3395
  emptyEl = null;
3254
3396
  followTail = true;
@@ -3273,6 +3415,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
3273
3415
  registerRouteLine,
3274
3416
  removeRouteLine,
3275
3417
  getRouteLine: (routeId) => routeLines.get(routeId) || null,
3418
+ upsertAutomation,
3276
3419
  getRunCard: (runId) => runCards.get(runId) || null,
3277
3420
  handleEvent,
3278
3421
  /** The live gate for an event (false: already drawn); registers what it lets through. */
@@ -3289,6 +3432,7 @@ export function createRenderer(transcriptEl, hooks = {}) {
3289
3432
  hideWorking,
3290
3433
  isWorkingShown: () => !!working?.isConnected,
3291
3434
  showEmpty,
3435
+ offerGreeting,
3292
3436
  refreshEmpty: renderSuggestions,
3293
3437
  isEmpty: () => !!emptyEl,
3294
3438
  scrollEnd,
@@ -3296,7 +3440,6 @@ export function createRenderer(transcriptEl, hooks = {}) {
3296
3440
  md,
3297
3441
  /** The character on screen, for the panel's director: { kind, rig, el, hold(on), restore() } or null. */
3298
3442
  mascot: visibleMascot,
3299
- setRigsEnabled,
3300
3443
  /** What this turn did: real calls (not the prompt-time recall), whether the last one failed, a turn error. */
3301
3444
  turnStats: () => ({ calls: turn.calls, lastFailed: turn.last?.state === 'error', errored: turn.errored }),
3302
3445
  /** The text of the turn's last message at the root ('' when it folded into a rack or there was none). */
@@ -0,0 +1,108 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Assistant — Model routes editor: where its model lists come from
3
+ // ═══════════════════════════════════════════
4
+ // The data side of the Routes editor (asst-route.js `openRoutesEditor`), kept
5
+ // apart from its markup. No DOM is built here.
6
+ //
7
+ // One list per provider, the one every Assistant model menu shows:
8
+ // loadModelCatalog() of asst-brain-picker.js, which is GET /api/assistant/catalog,
9
+ // itself built from the lists the Claude, Codex and OpenCode panels' own
10
+ // selectors read. Nothing here, and nothing in the editor, may keep a second
11
+ // list of models: a label, a tier, a price or an effort level is read from the
12
+ // catalog row each time it is drawn.
13
+
14
+ import { catalogModelRow, loadModelCatalog, modelCatalogStatus, onModelCatalogChange } from './asst-brain-picker.js';
15
+ import { routeTargetLabel } from './asst-state.js';
16
+
17
+ /** The catalog as the editor opens: a new build, never the copy another menu loaded a minute ago. */
18
+ export function loadRouteModels() {
19
+ return loadModelCatalog({ force: true });
20
+ }
21
+
22
+ /** Loading/partial state belongs to the same model source, without changing the catalog shape. */
23
+ export function routeModelsStatus() { return modelCatalogStatus(); }
24
+
25
+ /**
26
+ * The name shown for a saved route's model. The catalog's label for that id wins:
27
+ * a route keeps the label it was saved with, and an alias moves ("haiku" was
28
+ * Haiku 4.5, then Haiku 5.5). A model the catalog no longer lists (removed by its
29
+ * provider, hidden, or its provider is not answering) keeps the saved label,
30
+ * then its id, then the provider's name: never an empty name.
31
+ */
32
+ export function routeModelLabel(pref, catalog) {
33
+ if (!pref || typeof pref !== 'object') return '';
34
+ const row = pref.provider && pref.model ? catalogModelRow(pref.provider, pref.model, catalog) : null;
35
+ const live = row?.label ? String(row.label).trim() : '';
36
+ return live || routeTargetLabel(pref);
37
+ }
38
+
39
+ /** What the editor draws from a catalog: when this is unchanged, there is nothing to redraw. */
40
+ export function catalogSignature(catalog) {
41
+ if (!catalog || typeof catalog !== 'object') return '';
42
+ return JSON.stringify(Object.keys(catalog).sort().map(provider => [
43
+ provider,
44
+ (Array.isArray(catalog[provider]) ? catalog[provider] : []).map(m => [
45
+ m?.id, m?.label, m?.status ?? null, m?.vision ?? null, m?.outputs?.image ?? null, m?.outputs?.video ?? null,
46
+ (m?.efforts || []).join(','), m?.defaultEffort || '', m?.isDefault === true,
47
+ ]),
48
+ ]));
49
+ }
50
+
51
+ /**
52
+ * Keeps an open editor on the current lists. `apply(catalog)` is called with a
53
+ * newly loaded catalog whenever it differs from the last one applied:
54
+ * - after a change event (a model hidden or shown, a provider listing other
55
+ * models, an OpenCode provider connected or removed): a new build is asked;
56
+ * - when the window is shown again: the catalog is read again, and reloaded
57
+ * once its copy has aged out (no event tells a window that slept).
58
+ * Returns { seed(catalog), stop() }: seed with the catalog the editor loaded
59
+ * itself, stop when it closes. No timer runs while nothing changes.
60
+ */
61
+ export function watchRouteModels(apply, {
62
+ load = loadModelCatalog,
63
+ subscribe = onModelCatalogChange,
64
+ doc = typeof document !== 'undefined' ? document : null,
65
+ delayMs = 150,
66
+ setTimer = setTimeout,
67
+ clearTimer = clearTimeout,
68
+ } = {}) {
69
+ let stopped = false;
70
+ let timer = null;
71
+ let last = null;
72
+ let run = 0;
73
+
74
+ async function reload(force) {
75
+ const mine = ++run;
76
+ let catalog = null;
77
+ try { catalog = await load({ force }); } catch { return; }
78
+ if (stopped || mine !== run || !catalog) return;
79
+ const signature = catalogSignature(catalog);
80
+ if (signature === last) return;
81
+ last = signature;
82
+ try { apply(catalog); } catch { /* the editor's own failure */ }
83
+ }
84
+
85
+ // Several events for one change (a hide broadcasts twice) become one reload.
86
+ let pendingForce = false;
87
+ function schedule(force) {
88
+ if (stopped) return;
89
+ pendingForce = pendingForce || force;
90
+ if (timer != null) clearTimer(timer);
91
+ timer = setTimer(() => { timer = null; const f = pendingForce; pendingForce = false; reload(f); }, delayMs);
92
+ }
93
+
94
+ const unsubscribe = subscribe(() => schedule(true));
95
+ const onVisible = () => { if (doc?.visibilityState !== 'hidden') schedule(false); };
96
+ doc?.addEventListener?.('visibilitychange', onVisible);
97
+
98
+ return {
99
+ seed(catalog) { last = catalogSignature(catalog); },
100
+ stop() {
101
+ stopped = true;
102
+ if (timer != null) clearTimer(timer);
103
+ timer = null;
104
+ try { unsubscribe?.(); } catch { /* ignore */ }
105
+ doc?.removeEventListener?.('visibilitychange', onVisible);
106
+ },
107
+ };
108
+ }