synabun 2.0.0-beta → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +51 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +2 -2
  8. package/hooks/claude-code/pre-compact.mjs +11 -0
  9. package/hooks/claude-code/prompt-submit.mjs +60 -184
  10. package/hooks/claude-code/session-start.mjs +73 -16
  11. package/hooks/claude-code/shared.mjs +20 -0
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/launcher.mjs +40 -0
  14. package/lib/claude-hooks.js +61 -8
  15. package/lib/client-config-repair.js +4 -3
  16. package/lib/data-home-migration.js +4 -0
  17. package/lib/desktop-pwa.js +206 -0
  18. package/lib/external-tools.js +221 -0
  19. package/lib/first-launch-protection.js +5 -0
  20. package/lib/packaged-runtime.js +110 -0
  21. package/lib/start-launcher.js +1396 -0
  22. package/mcp-server/package-lock.json +2 -2
  23. package/mcp-server/package.json +1 -3
  24. package/neural-interface/i18n/en.json +1540 -154
  25. package/neural-interface/i18n/pt-BR.json +1538 -153
  26. package/neural-interface/lib/assistant-api.js +62 -6
  27. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  28. package/neural-interface/lib/assistant-catalog.js +179 -27
  29. package/neural-interface/lib/assistant-config.js +31 -2
  30. package/neural-interface/lib/assistant-dispatch.js +62 -13
  31. package/neural-interface/lib/assistant-envelope.js +9 -6
  32. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  33. package/neural-interface/lib/assistant-memory.js +24 -10
  34. package/neural-interface/lib/assistant-persona.js +6 -2
  35. package/neural-interface/lib/assistant-pricing.js +21 -6
  36. package/neural-interface/lib/assistant-runtime.js +181 -12
  37. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  38. package/neural-interface/lib/assistant-test-density.js +142 -0
  39. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  40. package/neural-interface/lib/assistant-user-context.js +908 -0
  41. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  42. package/neural-interface/lib/assistant-user-learn.js +404 -0
  43. package/neural-interface/lib/assistant-user-threads.js +226 -0
  44. package/neural-interface/lib/assistant-user-writer.js +181 -0
  45. package/neural-interface/lib/augmented-path.js +23 -3
  46. package/neural-interface/lib/browser-background-tab.js +134 -0
  47. package/neural-interface/lib/browser-language.js +83 -0
  48. package/neural-interface/lib/browser-screenshot.js +678 -61
  49. package/neural-interface/lib/claude-agent-bridge.js +87 -153
  50. package/neural-interface/lib/claude-executable.js +241 -0
  51. package/neural-interface/lib/claude-model-catalog.js +82 -93
  52. package/neural-interface/lib/claude-temporary.js +46 -7
  53. package/neural-interface/lib/cloudflared/install.js +533 -0
  54. package/neural-interface/lib/cloudflared/manager.js +545 -0
  55. package/neural-interface/lib/cloudflared/pins.js +115 -0
  56. package/neural-interface/lib/cloudflared/pins.json +63 -0
  57. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  58. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  59. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  60. package/neural-interface/lib/editor-completion.js +714 -0
  61. package/neural-interface/lib/editor-config.js +149 -0
  62. package/neural-interface/lib/editor-files-api.js +268 -0
  63. package/neural-interface/lib/editor-git-api.js +134 -0
  64. package/neural-interface/lib/file-explorer-api.js +1039 -0
  65. package/neural-interface/lib/file-explorer-system.js +355 -0
  66. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  67. package/neural-interface/lib/file-explorer-watch.js +239 -0
  68. package/neural-interface/lib/git-diff-api.js +103 -0
  69. package/neural-interface/lib/git-read.js +202 -0
  70. package/neural-interface/lib/greeting/api.js +89 -0
  71. package/neural-interface/lib/greeting/budgets.js +90 -0
  72. package/neural-interface/lib/greeting/engine.js +461 -0
  73. package/neural-interface/lib/greeting/facts.js +320 -0
  74. package/neural-interface/lib/greeting/sources.js +252 -0
  75. package/neural-interface/lib/greeting/writer.js +139 -0
  76. package/neural-interface/lib/http-guards.js +189 -13
  77. package/neural-interface/lib/machine-names.js +88 -0
  78. package/neural-interface/lib/memory-api.js +31 -7
  79. package/neural-interface/lib/native-binary-runtime.js +69 -337
  80. package/neural-interface/lib/native-loop-providers.js +40 -49
  81. package/neural-interface/lib/offline-page.js +54 -0
  82. package/neural-interface/lib/plugin-installer.js +4 -2
  83. package/neural-interface/lib/project-storage.js +5 -7
  84. package/neural-interface/lib/request-gate.js +589 -0
  85. package/neural-interface/lib/session-title-generator.js +5 -0
  86. package/neural-interface/lib/synabun-update-plan.js +19 -0
  87. package/neural-interface/lib/ui-blob-api.js +108 -0
  88. package/neural-interface/lib/ui-blob-store.js +68 -0
  89. package/neural-interface/package-lock.json +701 -253
  90. package/neural-interface/package.json +13 -2
  91. package/neural-interface/public/install-app.html +34 -0
  92. package/neural-interface/public/manifest.json +2 -0
  93. package/neural-interface/public/offline.html +402 -66
  94. package/neural-interface/public/onboarding.html +264 -147
  95. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  96. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  97. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  98. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  99. package/neural-interface/public/shared/assistant/asst-mascot.js +26 -64
  100. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  101. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  102. package/neural-interface/public/shared/assistant/asst-rack-styles.js +0 -3
  103. package/neural-interface/public/shared/assistant/asst-render.js +219 -67
  104. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  105. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  106. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  107. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  108. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  109. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  110. package/neural-interface/public/shared/assistant/asst-styles.js +162 -6
  111. package/neural-interface/public/shared/blob-store.js +111 -22
  112. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  113. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  114. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  115. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  116. package/neural-interface/public/shared/command-runner-model.js +30 -0
  117. package/neural-interface/public/shared/constants.js +6 -1
  118. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  119. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  120. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  121. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  122. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  123. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  124. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  125. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  126. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  127. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  128. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  129. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  130. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  131. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  132. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  133. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  134. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  135. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  136. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  137. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  138. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  139. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  140. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  141. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  142. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  143. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  144. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  145. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  146. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  147. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  148. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  149. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  150. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  151. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  152. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  153. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  154. package/neural-interface/public/shared/file-links.js +339 -0
  155. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  156. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  157. package/neural-interface/public/shared/html-shell.js +169 -170
  158. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  159. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  160. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  161. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  162. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  163. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  164. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  165. package/neural-interface/public/shared/pwa-install-page.js +62 -0
  166. package/neural-interface/public/shared/pwa-install.css +12 -0
  167. package/neural-interface/public/shared/pwa-install.js +127 -0
  168. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  169. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  170. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  171. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  172. package/neural-interface/public/shared/settings/settings-rules.js +160 -0
  173. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  174. package/neural-interface/public/shared/start-bridge.js +802 -0
  175. package/neural-interface/public/shared/styleguide/sg-colors.js +5 -2
  176. package/neural-interface/public/shared/styleguide/sg-import-export.js +4 -3
  177. package/neural-interface/public/shared/styleguide/sg-kit.js +4 -1
  178. package/neural-interface/public/shared/styleguide/sg-panel.js +9 -1
  179. package/neural-interface/public/shared/styleguide/sg-typography.js +1 -0
  180. package/neural-interface/public/shared/styles.css +2219 -1117
  181. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  182. package/neural-interface/public/shared/term-ready.js +307 -0
  183. package/neural-interface/public/shared/tunnel-view.js +167 -0
  184. package/neural-interface/public/shared/ui-claude-panel.js +160 -19
  185. package/neural-interface/public/shared/ui-command-runner.js +251 -468
  186. package/neural-interface/public/shared/ui-detail.js +15 -0
  187. package/neural-interface/public/shared/ui-explorer.js +22 -0
  188. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  189. package/neural-interface/public/shared/ui-file-links.js +103 -0
  190. package/neural-interface/public/shared/ui-help.js +26 -0
  191. package/neural-interface/public/shared/ui-invite.js +126 -116
  192. package/neural-interface/public/shared/ui-judgments.js +1 -1
  193. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  194. package/neural-interface/public/shared/ui-loading.js +367 -12
  195. package/neural-interface/public/shared/ui-menubar.js +21 -55
  196. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  197. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  198. package/neural-interface/public/shared/ui-navbar.js +45 -21
  199. package/neural-interface/public/shared/ui-settings.js +491 -547
  200. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  201. package/neural-interface/public/shared/ui-sync.js +16 -0
  202. package/neural-interface/public/shared/ui-terminal.js +153 -149
  203. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  204. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  205. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  206. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  207. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  208. package/neural-interface/public/shared/worker-end.js +251 -0
  209. package/neural-interface/public/sw.js +3 -1
  210. package/neural-interface/public/variant/2d/main.js +2 -1
  211. package/neural-interface/public/variant/3d/main.js +2 -1
  212. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  309. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  310. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  311. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  312. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  313. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  314. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  315. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  316. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  317. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  318. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  319. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  320. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  321. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  322. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  323. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  324. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  325. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  326. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  327. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  328. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  329. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  330. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  331. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  332. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  333. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  334. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  335. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  336. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  337. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  338. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  339. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  340. package/neural-interface/scripts/build-vendor.mjs +78 -2
  341. package/neural-interface/scripts/rebuild-pty.js +15 -12
  342. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  343. package/neural-interface/server.js +1092 -1212
  344. package/neural-interface/templates/rulesets/README.md +1 -1
  345. package/package.json +13 -7
  346. package/postinstall.js +11 -81
  347. package/setup.js +111 -6
  348. package/benchmarks/browser-live-results.json +0 -79
  349. package/benchmarks/browser-v2-results.json +0 -258
  350. package/docs/browser-v2.md +0 -109
  351. package/docs/hook-integrity.md +0 -89
  352. package/docs/judgments.md +0 -182
  353. package/docs/style-guide.md +0 -246
  354. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  355. package/neural-interface/public/category-logos/claude.svg +0 -1
  356. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  357. package/neural-interface/public/category-logos/openai.svg +0 -1
  358. package/neural-interface/public/category-logos/synabun.png +0 -0
  359. package/neural-interface/public/claude.svg +0 -1
  360. package/neural-interface/public/gallery.svg +0 -6
  361. package/neural-interface/public/leonardoai.svg +0 -1
  362. package/neural-interface/public/mcp.svg +0 -4
  363. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  364. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  365. package/neural-interface/public/sessionicon.svg +0 -8
  366. package/neural-interface/public/toolbar-album.svg +0 -8
  367. package/neural-interface/public/toolbar-question.svg +0 -6
  368. package/neural-interface/public/toolbar-sessions.svg +0 -6
  369. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  370. package/scripts/audit-claude-hook-usage.mjs +0 -12
  371. package/scripts/audit-memory-duplicates.mjs +0 -44
  372. package/scripts/measure-claude-hook-overhead.mjs +0 -77
  373. package/scripts/recover-user-config.mjs +0 -254
  374. package/skills/synabun/synabunicon.png +0 -0
@@ -0,0 +1,412 @@
1
+ // ═══════════════════════════════════════════
2
+ // SETTINGS — Code editor (the pane)
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Two sections. "Editing": one control for each `editing` preference (text size, wrapping, the minimap,
6
+ // indentation, what a save does); the editor's own View menu changes the same preferences, and each follows the
7
+ // other. "AI autocomplete": the switch, where suggestions come from, the model list with its Test buttons and
8
+ // "Find fastest", the endpoint (kind, address, model, request shape, key set or not), the files that are never
9
+ // sent, and today's use. settings-code-editor.js reads the server's answers and decides what is true; this asks
10
+ // and draws. Every change is saved as it is made (PUT /api/editor/config with only what changed) and the
11
+ // section then shows what the server stored: a change that could not be saved goes back to where it was.
12
+ //
13
+ // The endpoint's key is write-only here: the field is always empty, and the page only ever learns whether a key
14
+ // is set.
15
+
16
+ import { on } from '../state.js';
17
+ import * as kit from './settings-kit.js';
18
+ import { getSettingsPage, pageKeys } from './settings-ia.js';
19
+ import { AI_EXCLUDE_DEFAULTS } from '../editor/editor-prefs.js';
20
+ import {
21
+ EDITING_FIELDS, describeEditorAi, describeEditorEditing, describeEditorFastest, describeEditorModels, describeEditorSaveFailure, describeEditorTest,
22
+ describeEditorUsage, editingChange, editingOptionLabel, isEndpointUrl, parseExcludeList, readEditorAiResponse, readEditorEditingResponse,
23
+ } from './settings-code-editor.js';
24
+
25
+ const K = 'settings.redesign.code_editor';
26
+ const CONFIG_URL = '/api/editor/config';
27
+ const COMPLETE_URL = '/api/editor/complete';
28
+ const c = (key, params) => kit.te(`${K}.${key}`, params);
29
+ /** The id of the control of an editing preference. */
30
+ const editingId = (key) => `edt-ed-${key}`;
31
+
32
+ // One row for each editing preference: a switch, or a list of its choices. Switched off until the server answered.
33
+ function editingRow(field) {
34
+ const id = editingId(field.key);
35
+ if (field.kind === 'toggle') return kit.toggleField(field.id, kit.switchInput(id, { attrs: 'disabled' }), { forId: id });
36
+ const options = field.values.map((value) => `<option value="${value}">${kit.esc(editingOptionLabel(field.key, value, { tx: kit.tx }))}</option>`).join('');
37
+ return kit.field(field.id, `
38
+ <select class="stg-input" id="${id}" aria-describedby="${id}-help" disabled>${options}</select>`, { forId: id });
39
+ }
40
+
41
+ export function buildCodeEditorTab() {
42
+ const view = describeEditorAi(null, { tx: kit.tx });
43
+ const option = (value, key) => `<option value="${value}">${c(key)}</option>`;
44
+ return `
45
+ <div class="stg-pane" data-stg-pane="editor">
46
+ ${kit.card({
47
+ id: 'stg-sec-editor-editing', section: 'code_editor.editing',
48
+ body: `
49
+ <div class="stg-help edt-note" id="edt-ed-note" role="status" data-stg-data hidden></div>
50
+ ${EDITING_FIELDS.map(editingRow).join('')}
51
+ <div class="stg-help edt-save-status" id="edt-ed-save-status" role="alert" data-stg-data hidden></div>`,
52
+ })}
53
+ ${kit.card({
54
+ id: 'stg-sec-editor-ai', section: 'code_editor.ai_autocomplete',
55
+ // empty until the server has answered: the stylesheet hides an empty status word
56
+ status: kit.pill(kit.esc(view.pill.text), { state: view.pill.state, id: 'edt-ai-pill' }),
57
+ body: `
58
+ <div class="stg-help edt-note" id="edt-ai-note" role="status" data-stg-data hidden></div>
59
+ ${kit.toggleField('EDT001', kit.switchInput('edt-ai-enabled', { attrs: 'disabled' }), { forId: 'edt-ai-enabled' })}
60
+ ${kit.field('EDT002', `
61
+ <select class="stg-input" id="edt-ai-engine" aria-describedby="edt-ai-engine-help" disabled>
62
+ ${option('opencode', 'engine.opencode')}${option('endpoint', 'engine.endpoint')}
63
+ </select>`, { forId: 'edt-ai-engine' })}
64
+
65
+ <div class="edt-engine" id="edt-ai-opencode">
66
+ <div class="stg-field edt-models-field" ${kit.inv('EDT003')}>
67
+ <div class="edt-models-head">
68
+ <label id="edt-ai-models-title">${kit.L('EDT003')}</label>
69
+ <button type="button" class="stg-action-btn" id="edt-ai-fastest" ${kit.inv('EDT004')} title="${kit.H('EDT004')}" disabled>${kit.L('EDT004')}</button>
70
+ </div>
71
+ <div class="stg-help" id="edt-ai-models-help">${kit.H('EDT003')}</div>
72
+ <div class="stg-help edt-result" id="edt-ai-fastest-result" role="status" aria-live="polite" data-stg-data hidden></div>
73
+ <div class="edt-models" id="edt-ai-models" role="radiogroup" aria-labelledby="edt-ai-models-title" aria-describedby="edt-ai-models-help" data-stg-data data-stg-search="off"></div>
74
+ </div>
75
+ </div>
76
+
77
+ <div class="edt-engine" id="edt-ai-endpoint" hidden>
78
+ ${kit.field('EDT005', `
79
+ <select class="stg-input" id="edt-ai-kind" aria-describedby="edt-ai-kind-help" disabled>
80
+ ${option('ollama', 'kind.ollama')}${option('openai', 'kind.openai')}
81
+ </select>`, { forId: 'edt-ai-kind' })}
82
+ ${kit.field('EDT006', `
83
+ <div class="settings-key-row">
84
+ <input id="edt-ai-url" type="url" inputmode="url" autocomplete="off" spellcheck="false" aria-describedby="edt-ai-url-help" disabled>
85
+ </div>`, { forId: 'edt-ai-url' })}
86
+ ${kit.field('EDT007', `
87
+ <div class="settings-key-row">
88
+ <input id="edt-ai-endpoint-model" type="text" autocomplete="off" spellcheck="false" aria-describedby="edt-ai-endpoint-model-help" disabled>
89
+ </div>`, { forId: 'edt-ai-endpoint-model' })}
90
+ ${kit.field('EDT008', `
91
+ <select class="stg-input" id="edt-ai-shape" aria-describedby="edt-ai-shape-help" disabled>
92
+ ${option('fim', 'shape.fim')}${option('chat', 'shape.chat')}
93
+ </select>`, { forId: 'edt-ai-shape' })}
94
+ ${kit.field('EDT009', `
95
+ <div class="settings-key-row edt-key-row">
96
+ <input id="edt-ai-key" type="password" autocomplete="off" spellcheck="false" aria-describedby="edt-ai-key-help edt-ai-key-state" disabled>
97
+ <button type="button" class="stg-action-btn" id="edt-ai-key-save" disabled>${c('key.save')}</button>
98
+ <button type="button" class="cc-copy-btn stg-text-btn" id="edt-ai-key-remove" hidden>${c('key.remove')}</button>
99
+ </div>
100
+ <div class="stg-help edt-key-state" id="edt-ai-key-state" role="status" data-stg-data></div>`, { forId: 'edt-ai-key' })}
101
+ <div class="stg-field" ${kit.inv('EDT010')}>
102
+ <div class="stg-action-row" style="align-items:center">
103
+ <button type="button" class="stg-action-btn" id="edt-ai-endpoint-test" aria-describedby="edt-ai-endpoint-test-help" disabled>${kit.L('EDT010')}</button>
104
+ <span class="stg-help edt-result" id="edt-ai-endpoint-result" role="status" aria-live="polite" data-stg-data style="margin:0"></span>
105
+ </div>
106
+ ${kit.help('EDT010', { forId: 'edt-ai-endpoint-test' })}
107
+ </div>
108
+ </div>
109
+
110
+ <div class="stg-field edt-exclude-field" ${kit.inv('EDT011')}>
111
+ <label for="edt-ai-exclude">${kit.L('EDT011')}</label>
112
+ <div class="stg-help" id="edt-ai-exclude-help">${kit.H('EDT011')}</div>
113
+ <textarea class="edt-exclude" id="edt-ai-exclude" rows="6" autocomplete="off" autocapitalize="off" spellcheck="false" aria-describedby="edt-ai-exclude-help edt-ai-exclude-count" data-stg-search="off" disabled></textarea>
114
+ <div class="stg-action-row" style="align-items:center">
115
+ <button type="button" class="cc-copy-btn stg-text-btn" id="edt-ai-exclude-reset" ${kit.inv('EDT012')} title="${kit.H('EDT012')}" disabled>${kit.L('EDT012')}</button>
116
+ <span class="stg-help" id="edt-ai-exclude-count" data-stg-data style="margin:0"></span>
117
+ </div>
118
+ </div>
119
+
120
+ <div class="stg-field edt-usage-field" ${kit.inv('EDT013')}>
121
+ <label id="edt-ai-usage-label">${kit.L('EDT013')}</label>
122
+ <div class="stg-help" id="edt-ai-usage" aria-labelledby="edt-ai-usage-label" title="${kit.H('EDT013')}" data-stg-data></div>
123
+ </div>
124
+ <div class="stg-help edt-save-status" id="edt-ai-save-status" role="alert" data-stg-data hidden></div>`,
125
+ })}
126
+ </div>`;
127
+ }
128
+
129
+ /**
130
+ * Load the section and wire its controls. Called once per opened Settings panel.
131
+ * @param {HTMLElement} overlay the Settings panel
132
+ * @param {{ fetchImpl?: typeof fetch }} [o]
133
+ */
134
+ export function wireCodeEditorTab(overlay, { fetchImpl = (...args) => fetch(...args) } = {}) {
135
+ const pane = kit.paneOf(overlay, 'editor');
136
+ if (!pane) return;
137
+ const $ = (id) => pane.querySelector(`#${id}`);
138
+ const tx = kit.tx;
139
+ const alive = () => document.body.contains(overlay);
140
+ const providersPage = (() => { const page = getSettingsPage('ai-connections'); return page ? tx(pageKeys(page).title) : ''; })();
141
+
142
+ let editing = null; // what the server answered about the editing preferences, or null until it has
143
+ let reading = null; // what the server answered (readEditorAiResponse), or null until it has
144
+ let view = describeEditorAi(reading, { tx });
145
+ let models = null; // what GET …/models answered, or null while it is asked
146
+ let busy = false; // a test or "Find fastest" is running: one at a time
147
+ const results = new Map(); // model id → the result of its last test, for this panel
148
+
149
+ const request = async (method, url, body) => {
150
+ try {
151
+ const res = await fetchImpl(url, { method, headers: body === undefined ? {} : { 'Content-Type': 'application/json' }, body: body === undefined ? undefined : JSON.stringify(body) });
152
+ return { status: res.status, body: await res.json().catch(() => null) };
153
+ } catch (error) {
154
+ return { status: 0, body: null, error: error?.message || '' };
155
+ }
156
+ };
157
+
158
+ const say = (node, text, tone = '') => {
159
+ if (!node) return;
160
+ node.textContent = text || '';
161
+ node.hidden = !text;
162
+ if (tone) node.dataset.edtTone = tone; else delete node.dataset.edtTone;
163
+ };
164
+
165
+ // ── Editing ──
166
+
167
+ function drawEditing() {
168
+ const shown = describeEditorEditing(editing, { tx });
169
+ say($('edt-ed-note'), shown.note?.text || '', shown.note?.tone === 'neutral' ? 'neutral' : '');
170
+ for (const field of EDITING_FIELDS) {
171
+ const node = $(editingId(field.key));
172
+ if (!node) continue;
173
+ if (field.kind === 'toggle') node.checked = shown.values[field.key];
174
+ else node.value = shown.values[field.key];
175
+ node.disabled = !shown.ready;
176
+ }
177
+ }
178
+
179
+ /** Save one editing preference; the section then shows what the server holds, whichever way it went. */
180
+ async function saveEditing(field, node) {
181
+ const change = editingChange(field.key, field.kind === 'toggle' ? node.checked : node.value);
182
+ if (!change) { drawEditing(); return; }
183
+ const answer = await request('PUT', CONFIG_URL, change);
184
+ if (!alive()) return;
185
+ const stored = readEditorEditingResponse(answer);
186
+ const ok = stored.state === 'ready';
187
+ if (ok) {
188
+ editing = stored;
189
+ if (reading?.state === 'ready' && answer.body.config.ai) reading = { ...reading, config: answer.body.config };
190
+ }
191
+ say($('edt-ed-save-status'), ok ? '' : describeEditorSaveFailure(answer, { tx }));
192
+ drawEditing();
193
+ }
194
+
195
+ for (const field of EDITING_FIELDS) {
196
+ const node = $(editingId(field.key));
197
+ node?.addEventListener('change', () => { saveEditing(field, node); });
198
+ }
199
+
200
+ // ── Drawing ──
201
+
202
+ function draw() {
203
+ view = describeEditorAi(reading, { tx });
204
+ const off = !view.ready;
205
+ say($('edt-ai-note'), view.note?.text || '', view.note?.tone === 'neutral' ? 'neutral' : '');
206
+ const pill = $('edt-ai-pill');
207
+ if (pill) { pill.textContent = view.pill.text; pill.dataset.state = view.pill.state; }
208
+ const set = (id, change) => { const node = $(id); if (node) change(node); };
209
+ set('edt-ai-enabled', (node) => { node.checked = view.enabled; node.disabled = off; });
210
+ set('edt-ai-engine', (node) => { node.value = view.engine; node.disabled = off; });
211
+ $('edt-ai-opencode').hidden = view.engine !== 'opencode';
212
+ $('edt-ai-endpoint').hidden = view.engine !== 'endpoint';
213
+ set('edt-ai-kind', (node) => { node.value = view.endpoint.kind; node.disabled = off; });
214
+ set('edt-ai-shape', (node) => { node.value = view.endpoint.shape; node.disabled = off; });
215
+ // A field that holds the keyboard keeps what is being typed into it.
216
+ const typing = (node) => node === document.activeElement;
217
+ set('edt-ai-url', (node) => { if (!typing(node)) node.value = view.endpoint.url; node.placeholder = view.urlPlaceholder; node.disabled = off; });
218
+ set('edt-ai-endpoint-model', (node) => { if (!typing(node)) node.value = view.endpoint.model; node.disabled = off; });
219
+ set('edt-ai-key', (node) => { node.placeholder = view.keyPlaceholder; node.disabled = off; });
220
+ set('edt-ai-key-save', (node) => { node.disabled = off || !$('edt-ai-key').value.trim(); });
221
+ set('edt-ai-key-remove', (node) => { node.hidden = off || !view.hasKey; });
222
+ set('edt-ai-key-state', (node) => { if (!node.dataset.edtTone) node.textContent = view.keyState; node.dataset.edtKey = view.hasKey ? 'set' : 'none'; });
223
+ set('edt-ai-endpoint-test', (node) => { node.disabled = off || busy || !(view.endpoint.url && view.endpoint.model); });
224
+ set('edt-ai-exclude', (node) => { if (!typing(node)) node.value = view.exclude; node.disabled = off; });
225
+ set('edt-ai-exclude-reset', (node) => { node.disabled = off; });
226
+ set('edt-ai-exclude-count', (node) => { node.textContent = view.excludeCount; });
227
+ drawModels();
228
+ }
229
+
230
+ function drawModels() {
231
+ const box = $('edt-ai-models');
232
+ if (!box) return;
233
+ const list = view.ready ? describeEditorModels(models, view.model, { tx, providersPage }) : { state: 'unavailable', message: '', canStart: false, rows: [] };
234
+ box.dataset.edtModels = list.state;
235
+ const fastest = $('edt-ai-fastest');
236
+ if (fastest) fastest.disabled = !view.ready || busy;
237
+ const row = (model) => {
238
+ const id = kit.esc(model.id);
239
+ const result = results.get(model.id);
240
+ return `
241
+ <div class="edt-model${model.selected ? ' selected' : ''}" data-edt-model="${id}">
242
+ <label class="edt-model-pick">
243
+ <input type="radio" name="edt-ai-model" value="${id}"${model.selected ? ' checked' : ''} aria-label="${c('models.pick', { model: model.label })}">
244
+ <span class="edt-model-name">${kit.esc(model.label)}</span>
245
+ <span class="edt-model-meta">${kit.esc(model.listed ? `${model.provider} · ${model.meta}` : model.meta)}</span>
246
+ </label>
247
+ <button type="button" class="cc-copy-btn stg-text-btn edt-model-test" data-edt-test="${id}" aria-label="${c('models.testNamed', { model: model.label })}"${busy ? ' disabled' : ''}>${c('models.test')}</button>
248
+ <div class="stg-help edt-model-result" role="status" aria-live="polite"${result ? ` data-edt-tone="${result.tone}"` : ' hidden'}>${result ? kit.esc(result.text) : ''}</div>
249
+ </div>`;
250
+ };
251
+ const message = list.message
252
+ ? `<div class="stg-help edt-models-message">${kit.esc(list.message)}${list.canStart ? ` <button type="button" class="cc-copy-btn stg-text-btn" id="edt-ai-models-start">${c('models.start')}</button>` : ''}</div>`
253
+ : '';
254
+ box.innerHTML = list.rows.map(row).join('') + message;
255
+ }
256
+
257
+ // ── Loading ──
258
+
259
+ async function loadModels({ start = false } = {}) {
260
+ if (view.engine !== 'opencode' && !start) return;
261
+ models = null;
262
+ drawModels();
263
+ const answer = await request('GET', `${COMPLETE_URL}/models${start ? '?start=1' : ''}`);
264
+ if (!alive()) return;
265
+ models = answer;
266
+ drawModels();
267
+ }
268
+
269
+ async function loadUsage() {
270
+ const answer = await request('GET', `${COMPLETE_URL}/usage`);
271
+ if (!alive()) return;
272
+ const usage = $('edt-ai-usage');
273
+ if (usage) usage.textContent = describeEditorUsage(answer.status === 200 ? answer.body?.today : null, { tx });
274
+ }
275
+
276
+ async function load() {
277
+ const [config, caps] = await Promise.all([request('GET', CONFIG_URL), request('GET', '/api/editor/capabilities')]);
278
+ if (!alive()) return;
279
+ editing = readEditorEditingResponse(config);
280
+ drawEditing();
281
+ reading = readEditorAiResponse({ ...config, capabilities: Array.isArray(caps.body?.capabilities) ? caps.body.capabilities : null });
282
+ draw();
283
+ if (reading.state !== 'ready') return;
284
+ loadModels();
285
+ loadUsage();
286
+ }
287
+
288
+ // ── Saving ──
289
+
290
+ /** Save a partial change; the section then shows what the server holds, whichever way it went. */
291
+ async function save(partial) {
292
+ const answer = await request('PUT', CONFIG_URL, partial);
293
+ if (!alive()) return false;
294
+ const ok = answer.status === 200 && answer.body?.ok === true && !!answer.body.config?.ai;
295
+ if (ok) reading = { state: 'ready', config: answer.body.config, hasEndpointKey: answer.body.hasEndpointKey === true, reason: null };
296
+ if (ok && editing?.state === 'ready' && answer.body.config.editing) editing = { ...editing, editing: answer.body.config.editing };
297
+ say($('edt-ai-save-status'), ok ? '' : describeEditorSaveFailure(answer, { tx }));
298
+ draw();
299
+ return ok;
300
+ }
301
+
302
+ const enabled = $('edt-ai-enabled');
303
+ enabled?.addEventListener('change', () => { save({ ai: { enabled: enabled.checked } }); });
304
+ $('edt-ai-engine')?.addEventListener('change', async (event) => {
305
+ if (await save({ ai: { engine: event.target.value } }) && view.engine === 'opencode' && !models) loadModels();
306
+ });
307
+ $('edt-ai-kind')?.addEventListener('change', (event) => { save({ ai: { endpoint: { kind: event.target.value } } }); });
308
+ $('edt-ai-shape')?.addEventListener('change', (event) => { save({ ai: { endpoint: { shape: event.target.value } } }); });
309
+ $('edt-ai-url')?.addEventListener('change', (event) => {
310
+ const url = event.target.value.trim();
311
+ // Not an address: nothing is sent, and the field says why instead of silently emptying itself.
312
+ if (url && !isEndpointUrl(url)) { say($('edt-ai-save-status'), tx(`${K}.url.invalid`)); return; }
313
+ save({ ai: { endpoint: { url } } });
314
+ });
315
+ $('edt-ai-endpoint-model')?.addEventListener('change', (event) => { save({ ai: { endpoint: { model: event.target.value.trim() } } }); });
316
+ $('edt-ai-exclude')?.addEventListener('change', (event) => { save({ ai: { exclude: parseExcludeList(event.target.value) } }); });
317
+ $('edt-ai-exclude-reset')?.addEventListener('click', () => { save({ ai: { exclude: [...AI_EXCLUDE_DEFAULTS] } }); });
318
+
319
+ // The key: written, never read back.
320
+ const keyInput = $('edt-ai-key');
321
+ const keyState = $('edt-ai-key-state');
322
+ keyInput?.addEventListener('input', () => { $('edt-ai-key-save').disabled = !view.ready || !keyInput.value.trim(); });
323
+ async function saveKey(value) {
324
+ const answer = await request('PUT', CONFIG_URL, { endpointKey: value });
325
+ if (!alive()) return;
326
+ const ok = answer.status === 200 && answer.body?.ok === true;
327
+ if (ok) {
328
+ reading = { state: 'ready', config: answer.body.config, hasEndpointKey: answer.body.hasEndpointKey === true, reason: null };
329
+ keyInput.value = '';
330
+ say(keyState, tx(value ? `${K}.key.saved` : `${K}.key.removed`), 'ok');
331
+ } else {
332
+ say(keyState, describeEditorSaveFailure(answer, { tx }), 'err');
333
+ }
334
+ draw();
335
+ // The line goes back to saying whether a key is set.
336
+ setTimeout(() => { if (alive()) { delete keyState.dataset.edtTone; keyState.textContent = view.keyState; } }, 4000);
337
+ }
338
+ $('edt-ai-key-save')?.addEventListener('click', () => { const value = keyInput.value.trim(); if (value) saveKey(value); });
339
+ keyInput?.addEventListener('keydown', (event) => { if (event.key === 'Enter' && keyInput.value.trim()) { event.preventDefault(); saveKey(keyInput.value.trim()); } });
340
+ $('edt-ai-key-remove')?.addEventListener('click', () => saveKey(''));
341
+
342
+ // ── Tests ──
343
+
344
+ async function runTest(body) {
345
+ busy = true;
346
+ draw();
347
+ const answer = await request('POST', `${COMPLETE_URL}/test`, body);
348
+ busy = false;
349
+ return answer;
350
+ }
351
+
352
+ $('edt-ai-models')?.addEventListener('change', (event) => {
353
+ const radio = event.target.closest?.('input[name="edt-ai-model"]');
354
+ if (radio?.checked) save({ ai: { model: radio.value } });
355
+ });
356
+ $('edt-ai-models')?.addEventListener('click', async (event) => {
357
+ if (event.target.closest?.('#edt-ai-models-start')) { loadModels({ start: true }); return; }
358
+ const button = event.target.closest?.('[data-edt-test]');
359
+ if (!button || busy) return;
360
+ const model = button.dataset.edtTest;
361
+ results.set(model, { tone: '', text: tx(`${K}.test.running`) });
362
+ const answer = await runTest({ engine: 'opencode', model });
363
+ if (!alive()) return;
364
+ results.set(model, describeEditorTest(answer.status === 200 ? answer.body?.results?.[0] : null, { tx }));
365
+ draw();
366
+ loadUsage();
367
+ });
368
+ $('edt-ai-fastest')?.addEventListener('click', async () => {
369
+ if (busy) return;
370
+ const line = $('edt-ai-fastest-result');
371
+ say(line, tx(`${K}.fastest.running`));
372
+ const answer = await runTest({ fastest: true });
373
+ if (!alive()) return;
374
+ const body = answer.status === 200 ? answer.body : null;
375
+ for (const result of Array.isArray(body?.results) ? body.results : []) results.set(result.model, describeEditorTest(result, { tx }));
376
+ const found = describeEditorFastest(body, { tx });
377
+ say(line, found.text, found.tone);
378
+ if (found.model) await save({ ai: { model: found.model } });
379
+ else draw();
380
+ // the list may have come from a serve that was just started for this
381
+ if (!models || models.body?.available === false) loadModels();
382
+ loadUsage();
383
+ });
384
+ $('edt-ai-endpoint-test')?.addEventListener('click', async () => {
385
+ if (busy) return;
386
+ const line = $('edt-ai-endpoint-result');
387
+ say(line, tx(`${K}.test.running`));
388
+ const answer = await runTest({ engine: 'endpoint' });
389
+ if (!alive()) return;
390
+ const result = describeEditorTest(answer.status === 200 ? answer.body?.results?.[0] : null, { tx });
391
+ say(line, result.text, result.tone);
392
+ draw();
393
+ loadUsage();
394
+ });
395
+
396
+ // The editor's View menu, its AI popover, or another window, changed the preferences.
397
+ const off = on('sync:editor:config-changed', (message) => {
398
+ if (!alive() || !message?.config) return;
399
+ if (editing?.state === 'ready' && message.config.editing) {
400
+ editing = { ...editing, editing: message.config.editing };
401
+ drawEditing();
402
+ }
403
+ if (reading?.state !== 'ready' || !message.config.ai) return;
404
+ reading = { ...reading, config: message.config, hasEndpointKey: typeof message.hasEndpointKey === 'boolean' ? message.hasEndpointKey : reading.hasEndpointKey };
405
+ draw();
406
+ });
407
+ overlay.addEventListener('settings-close', off, { once: true });
408
+
409
+ drawEditing();
410
+ draw();
411
+ load();
412
+ }