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
@@ -8,11 +8,13 @@
8
8
  // the face, plus one prop drawn in the face's own pill geometry. Rigs draw
9
9
  // from the shared ticker (shared/synabun-ticker.js): 30 fps while a pose
10
10
  // loops, 60 fps for blends and reactions, no frames at all while still. One
11
- // pointermove listener and one IntersectionObserver serve every rig, and only
12
- // one rig at a time plays a pose loop (the one posed most recently); the
13
- // others hold their pose's still frame. Under prefers-reduced-motion every
14
- // pose is its still frame and changes are instant. A rig tears itself down
15
- // once its SVG leaves the document.
11
+ // loop, one pointermove listener and one IntersectionObserver serve every rig,
12
+ // and every rig that is active and on screen plays its own pose: N rigs move
13
+ // at once, each on its own clock. No rig waits for another; a host that wants
14
+ // one moving character among several of its own (an Assistant panel's hero,
15
+ // stage and "Thinking" row) says so with setActive(). Under
16
+ // prefers-reduced-motion every pose is its still frame and changes are
17
+ // instant. A rig tears itself down once its SVG leaves the document.
16
18
  //
17
19
  // v1 callers are unchanged: createMascot(container, opts) → { el, destroy,
18
20
  // look, blink }, idle, blinking every 3-7 s and following the cursor.
@@ -307,7 +309,7 @@ const MINIS = [
307
309
  ];
308
310
 
309
311
  /**
310
- * motion: 'loop' (30 fps while it leads), 'blink' (still between slow blinks),
312
+ * motion: 'loop' (30 fps), 'blink' (still between slow blinks),
311
313
  * 'once' (plays `settle` ms, then still; `hold` before opts.then), 'still'.
312
314
  * blinks: random blinks every 3-7 s. tracks: follows the cursor.
313
315
  * look: follows look(), easing with this time constant (ms).
@@ -994,26 +996,15 @@ export function paintMascot(svg, frame) {
994
996
  painter.paint(frame);
995
997
  }
996
998
 
997
- // ── Shared runtime: one observer, one motion listener, one lead ──
999
+ // ── Shared runtime: one observer and one motion listener for every rig ──
1000
+ // Nothing here picks a rig: each one decides from its own state (active, on
1001
+ // screen, motion allowed) whether it moves.
998
1002
 
999
1003
  const rigs = new Set();
1000
- let leadRig = null;
1001
- let promoteSeq = 0;
1002
1004
  let stopMotionWatch = null;
1003
1005
  let io = null;
1004
1006
  const ioRigs = new WeakMap();
1005
1007
 
1006
- /** Only one rig plays a pose loop: the most recently posed one that wants to. */
1007
- function elect() {
1008
- let best = null;
1009
- for (const rig of rigs) if (rig.wantsLead() && (!best || rig.promotedAt() > best.promotedAt())) best = rig;
1010
- if (best === leadRig) return;
1011
- const prev = leadRig;
1012
- leadRig = best;
1013
- prev?.leadChanged();
1014
- best?.leadChanged();
1015
- }
1016
-
1017
1008
  function observe(el, rig) {
1018
1009
  if (typeof IntersectionObserver !== 'function') return;
1019
1010
  try {
@@ -1034,13 +1025,11 @@ function register(rig) {
1034
1025
  rigs.add(rig);
1035
1026
  stopMotionWatch ||= onReducedMotionChange(() => {
1036
1027
  for (const r of Array.from(rigs)) r.motionChanged();
1037
- elect();
1038
1028
  });
1039
1029
  }
1040
1030
 
1041
1031
  function unregister(rig) {
1042
1032
  rigs.delete(rig);
1043
- if (leadRig === rig) { leadRig = null; elect(); }
1044
1033
  if (!rigs.size && stopMotionWatch) { stopMotionWatch(); stopMotionWatch = null; }
1045
1034
  }
1046
1035
 
@@ -1088,14 +1077,12 @@ export function createMascot(container, options) {
1088
1077
  let active = startActive !== false;
1089
1078
  let visible = true;
1090
1079
  let seenConnected = svg.isConnected;
1091
- let promotedAt = (promoteSeq += 1);
1092
1080
  let clock = 0; // rig time in ms: the ticker's dt while drawing, real time while still
1093
1081
  let frozenAt = tickerNow(); // while not drawing: when the clock was last brought up to date; -1 while drawing
1094
1082
  let pose = { name: 'idle', raw: {}, start: 0, then: null };
1095
1083
  let settled = false; // a one-shot's opts.then has fired
1096
1084
  let blend = null; // { from, start, dur }
1097
1085
  let lastFrame = null; // the last frame before blinks and reactions
1098
- let drawn = false; // has drawn a live frame (a never-drawn rig has nothing to blend from)
1099
1086
  let look = { x: 0, y: 0 }; // eased gaze
1100
1087
  let track = { x: 0, y: 0 }; // idle: where the cursor (or look()) points
1101
1088
  let hostLook = { x: 0, y: 0 };
@@ -1119,10 +1106,10 @@ export function createMascot(container, options) {
1119
1106
 
1120
1107
  const def = () => POSES[pose.name];
1121
1108
  const animating = () => !destroyed && active && visible && !isReducedMotion();
1122
- const isLead = () => leadRig === rig;
1123
1109
  const poseTime = () => clock - pose.start;
1124
1110
 
1125
- function wantsLead() {
1111
+ /** This pose moves on its own right now: a loop, a patient pose, a one-shot still playing. */
1112
+ function playing() {
1126
1113
  if (!animating()) return false;
1127
1114
  const { motion, settle } = def();
1128
1115
  if (motion === 'loop' || motion === 'blink') return true;
@@ -1186,7 +1173,6 @@ export function createMascot(container, options) {
1186
1173
  function nextRate() {
1187
1174
  if (!animating()) return 0;
1188
1175
  if (blend || blinkStart >= 0 || reactions.length || aim || easing() || miniPopping()) return 60;
1189
- if (!isLead()) return 0;
1190
1176
  const d = def();
1191
1177
  const t = poseTime();
1192
1178
  if (d.motion === 'loop') return 30;
@@ -1208,9 +1194,9 @@ export function createMascot(container, options) {
1208
1194
  const d = def();
1209
1195
  const at0 = tickerNow();
1210
1196
  let at = Infinity;
1211
- if (d.blinks && (d.motion === 'still' || isLead())) at = Math.min(at, nextBlinkAt);
1197
+ if (d.blinks) at = Math.min(at, nextBlinkAt);
1212
1198
  if (d.tracks) at = Math.min(at, nextGlanceAt, nextFidgetAt, glance ? glance.until : Infinity);
1213
- if (d.motion === 'blink' && isLead()) at = Math.min(at, at0 + d.idleFor(poseTime()));
1199
+ if (d.motion === 'blink') at = Math.min(at, at0 + d.idleFor(poseTime()));
1214
1200
  if (d.motion === 'once' && pose.then && !settled) at = Math.min(at, at0 + Math.max(0, d.settle + (d.hold || 0) - poseTime()));
1215
1201
  if (!Number.isFinite(at)) return;
1216
1202
  wakeTimer = setTimeout(() => {
@@ -1243,15 +1229,15 @@ export function createMascot(container, options) {
1243
1229
  function handleDue() {
1244
1230
  const d = def();
1245
1231
  const t = tickerNow();
1246
- if (d.blinks && (d.motion === 'still' || isLead()) && t >= nextBlinkAt) {
1232
+ if (d.blinks && t >= nextBlinkAt) {
1247
1233
  nextBlinkAt = t + rand(3000, 7000);
1248
1234
  startBlink();
1249
1235
  }
1250
1236
  if (d.tracks) {
1251
1237
  if (glance && t >= glance.until) glance = null;
1252
1238
  if (t >= nextGlanceAt) {
1253
- // Only while the cursor is still and no other rig is busy.
1254
- if (t - pointerAt < 2500 || leadRig) nextGlanceAt = t + 3000;
1239
+ // Only while the cursor is still.
1240
+ if (t - pointerAt < 2500) nextGlanceAt = t + 3000;
1255
1241
  else {
1256
1242
  const [x, y] = GLANCES[Math.floor(Math.random() * GLANCES.length)];
1257
1243
  glance = { x, y, until: t + rand(700, 1000) };
@@ -1261,7 +1247,6 @@ export function createMascot(container, options) {
1261
1247
  if (t >= nextFidgetAt) {
1262
1248
  const quietFor = t - Math.max(lastInputAt(), pointerAt);
1263
1249
  if (quietFor < 20000) nextFidgetAt = t + (20000 - quietFor) + rand(0, 5000);
1264
- else if (leadRig) nextFidgetAt = t + 10000;
1265
1250
  else {
1266
1251
  nextFidgetAt = t + rand(45000, 75000);
1267
1252
  startReaction(Math.random() < 0.5 ? 'hop' : 'wiggle');
@@ -1303,8 +1288,7 @@ export function createMascot(container, options) {
1303
1288
 
1304
1289
  /** The pose frame this rig would draw now, before blends and overlays. */
1305
1290
  function frameNow() {
1306
- const loopOn = isLead() && def().motion !== 'still';
1307
- return poseFrame(pose.name, poseTime(), { ...pose.raw, look, range, ticks, still: !loopOn });
1291
+ return poseFrame(pose.name, poseTime(), { ...pose.raw, look, range, ticks, still: !playing() });
1308
1292
  }
1309
1293
 
1310
1294
  /** Ease from what is on screen to what comes next, unless they already match. */
@@ -1400,10 +1384,7 @@ export function createMascot(container, options) {
1400
1384
  handleDue();
1401
1385
  if (aim) { aimAt(aim); aim = null; }
1402
1386
  easeLook(dt);
1403
- const wasLead = isLead();
1404
1387
  painter.paint(compose());
1405
- drawn = true;
1406
- if (wasLead && def().motion === 'once' && poseTime() >= def().settle) elect();
1407
1388
  const rate = nextRate();
1408
1389
  setRate(rate);
1409
1390
  if (!rate) armWake();
@@ -1497,9 +1478,7 @@ export function createMascot(container, options) {
1497
1478
  }
1498
1479
  scheduleIdle();
1499
1480
  }
1500
- promotedAt = (promoteSeq += 1);
1501
1481
  if (animating()) requestFrames(BLEND_MS);
1502
- elect();
1503
1482
  refresh();
1504
1483
  return api;
1505
1484
  }
@@ -1537,8 +1516,7 @@ export function createMascot(container, options) {
1537
1516
  const next = !!on;
1538
1517
  if (destroyed || next === active) return api;
1539
1518
  active = next;
1540
- if (active) { promotedAt = (promoteSeq += 1); revive(); }
1541
- elect();
1519
+ if (active) revive();
1542
1520
  refresh();
1543
1521
  return api;
1544
1522
  }
@@ -1560,18 +1538,6 @@ export function createMascot(container, options) {
1560
1538
  }
1561
1539
 
1562
1540
  const rig = {
1563
- promotedAt: () => promotedAt,
1564
- wantsLead,
1565
- leadChanged() {
1566
- if (destroyed) return;
1567
- // Gaining or losing the loop swaps the still frame for the live one: blend
1568
- // when they differ (a patient pose between blinks, a settled one-shot: no).
1569
- if (drawn && animating()) {
1570
- syncClock();
1571
- blendIn();
1572
- }
1573
- refresh();
1574
- },
1575
1541
  visibilityChanged(inView) {
1576
1542
  if (destroyed) return;
1577
1543
  if (svg.isConnected) seenConnected = true;
@@ -1579,7 +1545,6 @@ export function createMascot(container, options) {
1579
1545
  const was = visible;
1580
1546
  visible = inView;
1581
1547
  if (visible && !was) revive();
1582
- elect();
1583
1548
  refresh(); // also wakes a rig that was built before it was attached
1584
1549
  },
1585
1550
  motionChanged() {
@@ -1619,7 +1584,6 @@ export function createMascot(container, options) {
1619
1584
  if (p) aim = p;
1620
1585
  }
1621
1586
  }
1622
- elect();
1623
1587
  refresh();
1624
1588
  return api;
1625
1589
  }
@@ -0,0 +1,167 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — the public address: what the cards say
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // What the two places that start the Cloudflare tunnel show for an answer of
6
+ // GET /api/tunnel/status: the Share menu's Connection block (ui-invite.js) and
7
+ // Settings → Automations → Online access (ui-settings.js). One reading for
8
+ // both, so they never disagree: the state as a word, one sentence about it,
9
+ // the progress of a download, the action that fits, and whether to ask again.
10
+ //
11
+ // No imports and no DOM: `node --test` loads this file as it is
12
+ // (tests/tunnel-view.test.mjs). TUNNEL_COPY is the English of every sentence;
13
+ // `tunnel.*` in i18n/en.json must equal it and i18n/pt-BR.json must have the
14
+ // same keys (the test checks both). The page side is ui-tunnel.js.
15
+ //
16
+ // A server that was started before SynaBun brought its own tunnel program
17
+ // answers without the `cloudflared` part: the cards then work as they did (a
18
+ // tunnel starts when a cloudflared is installed), and where none is, they say
19
+ // that a restart is what is missing. Nothing here ever tells the user to
20
+ // install anything, except on a system Cloudflare publishes no file for.
21
+
22
+ export const TUNNEL_COPY = Object.freeze({
23
+ stateOff: 'Off',
24
+ stateDownloading: 'Getting the tunnel program',
25
+ stateStarting: 'Starting',
26
+ stateRunning: 'On',
27
+ stateFailed: 'Did not start',
28
+ stateUnsupported: 'Not available',
29
+ stateRestart: 'Restart needed',
30
+ idle: 'A public address through Cloudflare, for invite links and remote MCP.',
31
+ idleDownload: 'A public address through Cloudflare, for invite links and remote MCP. The first start downloads the tunnel program ({size} MB).',
32
+ downloading: 'Downloading the tunnel program: {received} of {total} MB',
33
+ starting: 'Waiting for Cloudflare to give an address…',
34
+ restart: 'Restart SynaBun to use the public address: the server that is running was started before it could download the tunnel program.',
35
+ unsupported: 'Cloudflare publishes no tunnel program for this system. If you install cloudflared yourself, SynaBun uses it.',
36
+ errorOffline: 'The tunnel program could not be downloaded: the download server was not reached. Check the connection and try again.',
37
+ errorHttp: 'The tunnel program could not be downloaded: the download server answered with an error. Try again in a moment.',
38
+ errorInterrupted: 'The download stopped before it was complete. Nothing was kept. Try again.',
39
+ errorTimeout: 'The download stalled. Nothing was kept. Try again.',
40
+ errorChecksum: 'The download was not the file SynaBun expects, so it was removed and never run. Try again; if it happens again, something on the network is changing the file.',
41
+ errorUnpack: 'The downloaded file could not be unpacked, so it was removed. Try again.',
42
+ errorDisk: 'The tunnel program could not be saved in SynaBun\'s data folder. Check free space and permissions, then try again.',
43
+ errorLaunch: 'The tunnel program could not be started on this computer. Try again.',
44
+ errorExited: 'Cloudflare gave no address. The tunnel program said: {reason}',
45
+ errorExitedNoReason: 'The tunnel program stopped before Cloudflare gave an address. Try again.',
46
+ errorNoAddress: 'Cloudflare gave no address in time. Try again.',
47
+ errorEnded: 'The tunnel stopped. Start it again for a new address.',
48
+ errorRefused: 'SynaBun refused this request. Start the tunnel from SynaBun on this computer.',
49
+ errorUnknown: 'The tunnel did not start: {reason}',
50
+ errorUnknownNoReason: 'The tunnel did not start. Try again.',
51
+ start: 'Start tunnel',
52
+ stop: 'Stop',
53
+ cancel: 'Cancel',
54
+ retry: 'Try again',
55
+ copyBundled: 'cloudflared {version}, included with SynaBun',
56
+ copyDownloaded: 'cloudflared {version}, downloaded by SynaBun',
57
+ copySystem: 'cloudflared {version}, installed on this computer',
58
+ copySystemWhy: 'SynaBun could not download its own copy, so the one installed on this computer is used.',
59
+ mcpKeyNeeded: 'Remote MCP needs an access key. Create one below; the address to connect is then this one followed by /mcp/ and the key.',
60
+ });
61
+
62
+ const ERROR_COPY = Object.freeze({
63
+ offline: 'errorOffline', http: 'errorHttp', interrupted: 'errorInterrupted', timeout: 'errorTimeout', checksum: 'errorChecksum',
64
+ unpack: 'errorUnpack', disk: 'errorDisk', launch: 'errorLaunch', no_address: 'errorNoAddress', ended: 'errorEnded',
65
+ unsupported: 'unsupported', refused: 'errorRefused',
66
+ });
67
+
68
+ /** A TUNNEL_COPY sentence with its `{params}` filled in: the translator when the page gives none. */
69
+ export function fillTunnelCopy(key, params = {}) {
70
+ return String(TUNNEL_COPY[key] ?? key).replace(/\{(\w+)\}/g, (whole, name) => (params[name] != null ? params[name] : whole));
71
+ }
72
+
73
+ const megabytes = (bytes) => Math.max(0, Number(bytes) || 0) / (1024 * 1024);
74
+
75
+ /**
76
+ * What a card shows for a status.
77
+ *
78
+ * @param {object | null} status the answer of GET /api/tunnel/status (or of the start / stop that came last)
79
+ * @param {object} [o]
80
+ * @param {(key: string, params?: object) => string} [o.t] a key of TUNNEL_COPY → the sentence in the page's language
81
+ * @param {(value: number, digits: number) => string} [o.number] a number as the page's language writes it
82
+ * @returns {{
83
+ * kind: 'restart' | 'unsupported' | 'idle' | 'downloading' | 'starting' | 'running' | 'failed',
84
+ * tone: 'off' | 'busy' | 'ok' | 'warn' | 'err',
85
+ * on: boolean,
86
+ * label: string, detail: string,
87
+ * progress: { percent: number, text: string } | null,
88
+ * url: string | null,
89
+ * action: 'start' | 'stop' | 'cancel' | 'retry' | null, actionLabel: string,
90
+ * copy: string, copyNote: string,
91
+ * poll: boolean,
92
+ * }}
93
+ * `on`: the switch stands on (something runs or is on its way). `action`: what a press does ("cancel" and
94
+ * "stop" are both POST /api/tunnel/stop; "start" and "retry" both POST /api/tunnel/start). `copy`: which
95
+ * cloudflared runs, when one does. `poll`: the state will change by itself, ask again.
96
+ */
97
+ export function tunnelView(status, { t = fillTunnelCopy, number = (value, digits) => value.toFixed(digits) } = {}) {
98
+ const s = status && typeof status === 'object' ? status : {};
99
+ const tool = s.cloudflared && typeof s.cloudflared === 'object' ? s.cloudflared : null;
100
+ const view = {
101
+ kind: 'idle', tone: 'off', on: false, label: t('stateOff'), detail: t('idle'), progress: null,
102
+ url: typeof s.url === 'string' && s.url ? s.url : null,
103
+ action: 'start', actionLabel: t('start'), copy: '', copyNote: '', poll: false,
104
+ };
105
+ const as = (kind, tone, labelKey, detail, action) => Object.assign(view, {
106
+ kind, tone, label: t(labelKey), detail, action, actionLabel: action ? t(action) : '',
107
+ on: kind === 'downloading' || kind === 'starting' || kind === 'running', poll: kind === 'downloading' || kind === 'starting',
108
+ });
109
+ const running = () => {
110
+ as('running', 'ok', 'stateRunning', view.url, 'stop');
111
+ const source = { bundled: 'copyBundled', downloaded: 'copyDownloaded', system: 'copySystem' }[tool?.source];
112
+ if (source && tool.version) {
113
+ view.copy = t(source, { version: tool.version });
114
+ if (tool.source === 'system' && tool.fallback && tool.fallback.code !== 'unsupported') view.copyNote = t('copySystemWhy');
115
+ }
116
+ return view;
117
+ };
118
+
119
+ // Nothing is known yet (the answer has not arrived): the card as it stands before a first start.
120
+ if (!status || typeof status !== 'object') return view;
121
+
122
+ // A server from before the tunnel program came with SynaBun: no `cloudflared` part in its answer.
123
+ if (!tool) {
124
+ if (view.url) return running();
125
+ if (s.starting || s.running) return as('starting', 'busy', 'stateStarting', t('starting'), 'cancel');
126
+ if (s.available) return as('idle', 'off', 'stateOff', t('idle'), 'start');
127
+ return as('restart', 'warn', 'stateRestart', t('restart'), null);
128
+ }
129
+
130
+ const state = typeof s.state === 'string' ? s.state : 'idle';
131
+ if (state === 'running' && view.url) return running();
132
+ if (state === 'downloading') {
133
+ const total = Number(tool.progress?.total) || Number(tool.download?.size) || 0;
134
+ const received = Math.min(Number(tool.progress?.received) || 0, total || Infinity);
135
+ const percent = total ? Math.max(0, Math.min(100, Math.floor((received / total) * 100))) : 0;
136
+ as('downloading', 'busy', 'stateDownloading', t('downloading', { received: number(megabytes(received), 1), total: number(megabytes(total), 1) }), 'cancel');
137
+ view.progress = { percent, text: `${percent}%` };
138
+ return view;
139
+ }
140
+ if (state === 'starting' || state === 'running') return as('starting', 'busy', 'stateStarting', t('starting'), 'cancel');
141
+ if (state === 'failed') {
142
+ const error = s.error && typeof s.error === 'object' ? s.error : {};
143
+ if (error.code === 'unsupported') return as('unsupported', 'off', 'stateUnsupported', t('unsupported'), null);
144
+ const reason = typeof error.reason === 'string' && error.reason.trim() ? error.reason.trim() : '';
145
+ let detail;
146
+ if (error.code === 'exited') detail = reason ? t('errorExited', { reason }) : t('errorExitedNoReason');
147
+ else if (ERROR_COPY[error.code]) detail = t(ERROR_COPY[error.code]);
148
+ else detail = typeof error.message === 'string' && error.message.trim() ? t('errorUnknown', { reason: error.message.trim() }) : t('errorUnknownNoReason');
149
+ return as('failed', 'err', 'stateFailed', detail, 'retry');
150
+ }
151
+ // idle
152
+ if (tool.state === 'unsupported') return as('unsupported', 'off', 'stateUnsupported', t('unsupported'), null);
153
+ if (tool.state === 'ready') return as('idle', 'off', 'stateOff', t('idle'), 'start');
154
+ const size = Number(tool.download?.size) || 0;
155
+ return as('idle', 'off', 'stateOff', size ? t('idleDownload', { size: number(megabytes(size), 0) }) : t('idle'), 'start');
156
+ }
157
+
158
+ /**
159
+ * The address an assistant outside connects to, or null while there is none to give: the public address
160
+ * followed by /mcp/ and the access key. Without a key there is no such address: the server refuses /mcp from
161
+ * outside (lib/request-gate.js mcpWithoutKey), so the cards offer nothing to copy and say what is missing.
162
+ */
163
+ export function remoteMcpAddress(url, key) {
164
+ const base = typeof url === 'string' ? url.trim().replace(/\/+$/, '') : '';
165
+ const secret = typeof key === 'string' ? key.trim() : '';
166
+ return base && secret ? `${base}/mcp/${secret}` : null;
167
+ }