synabun 2.0.0 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/NOTICE +5 -0
  3. package/README.md +2 -1
  4. package/THIRD-PARTY-LICENSES.md +59 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +153 -18
  8. package/hooks/claude-code/pre-compact.mjs +11 -0
  9. package/hooks/claude-code/prompt-submit.mjs +60 -184
  10. package/hooks/claude-code/session-start.mjs +73 -16
  11. package/hooks/claude-code/shared.mjs +26 -3
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/lib/child-path.js +303 -0
  14. package/lib/claude-hooks.js +2 -1
  15. package/lib/data-home-migration.js +2 -0
  16. package/lib/desktop-app.js +265 -0
  17. package/lib/external-tools.js +7 -3
  18. package/lib/log-redact.js +102 -0
  19. package/lib/packaged-runtime.js +138 -11
  20. package/lib/start-launcher.js +88 -1
  21. package/mcp-server/dist/http.d.ts +3 -1
  22. package/mcp-server/dist/http.d.ts.map +1 -1
  23. package/mcp-server/dist/http.js +15 -4
  24. package/mcp-server/dist/http.js.map +1 -1
  25. package/mcp-server/dist/index.d.ts.map +1 -1
  26. package/mcp-server/dist/index.js +9 -6
  27. package/mcp-server/dist/index.js.map +1 -1
  28. package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
  29. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
  30. package/mcp-server/dist/services/budget-judgments.js +153 -0
  31. package/mcp-server/dist/services/budget-judgments.js.map +1 -0
  32. package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
  33. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  34. package/mcp-server/dist/services/codex-config-heal.js +41 -4
  35. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  36. package/mcp-server/dist/services/identity.d.ts +11 -0
  37. package/mcp-server/dist/services/identity.d.ts.map +1 -1
  38. package/mcp-server/dist/services/identity.js +24 -0
  39. package/mcp-server/dist/services/identity.js.map +1 -1
  40. package/mcp-server/dist/services/neural-interface.d.ts +13 -0
  41. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  42. package/mcp-server/dist/services/neural-interface.js +34 -2
  43. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  44. package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
  45. package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
  46. package/mcp-server/dist/services/typesafe-config.js +4 -1
  47. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  48. package/mcp-server/dist/tools/agents.d.ts +10 -7
  49. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  50. package/mcp-server/dist/tools/agents.js +34 -13
  51. package/mcp-server/dist/tools/agents.js.map +1 -1
  52. package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
  53. package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
  54. package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
  55. package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
  56. package/mcp-server/dist/tui.js +2 -1
  57. package/mcp-server/dist/tui.js.map +1 -1
  58. package/mcp-server/dist/version.d.ts +5 -0
  59. package/mcp-server/dist/version.d.ts.map +1 -0
  60. package/mcp-server/dist/version.js +21 -0
  61. package/mcp-server/dist/version.js.map +1 -0
  62. package/mcp-server/package-lock.json +2 -2
  63. package/mcp-server/package.json +1 -3
  64. package/mcp-server/run.mjs +15 -9
  65. package/mcp-server/src/http.ts +18 -3
  66. package/mcp-server/src/index.ts +9 -6
  67. package/mcp-server/src/services/budget-judgments.ts +183 -0
  68. package/mcp-server/src/services/codex-config-heal.ts +35 -4
  69. package/mcp-server/src/services/identity.ts +27 -0
  70. package/mcp-server/src/services/neural-interface.ts +34 -2
  71. package/mcp-server/src/services/typesafe-config.ts +4 -1
  72. package/mcp-server/src/tools/agents.ts +33 -14
  73. package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
  74. package/mcp-server/src/tui.ts +2 -1
  75. package/mcp-server/src/version.ts +22 -0
  76. package/neural-interface/i18n/en.json +2126 -209
  77. package/neural-interface/i18n/pt-BR.json +2123 -207
  78. package/neural-interface/lib/account-usage.js +163 -0
  79. package/neural-interface/lib/assistant-api.js +316 -57
  80. package/neural-interface/lib/assistant-brains/claude.js +19 -2
  81. package/neural-interface/lib/assistant-brains/codex.js +3 -0
  82. package/neural-interface/lib/assistant-brains/opencode.js +17 -4
  83. package/neural-interface/lib/assistant-budget-planner.js +390 -0
  84. package/neural-interface/lib/assistant-budget-split.js +408 -0
  85. package/neural-interface/lib/assistant-budget.js +94 -95
  86. package/neural-interface/lib/assistant-catalog.js +179 -27
  87. package/neural-interface/lib/assistant-config.js +91 -14
  88. package/neural-interface/lib/assistant-dispatch.js +494 -138
  89. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  90. package/neural-interface/lib/assistant-jev.js +26 -3
  91. package/neural-interface/lib/assistant-memory.js +24 -10
  92. package/neural-interface/lib/assistant-persona.js +73 -12
  93. package/neural-interface/lib/assistant-plan-permissions.js +8 -1
  94. package/neural-interface/lib/assistant-pricing.js +21 -6
  95. package/neural-interface/lib/assistant-route-accounts.js +14 -0
  96. package/neural-interface/lib/assistant-route-gate.js +19 -3
  97. package/neural-interface/lib/assistant-router.js +373 -42
  98. package/neural-interface/lib/assistant-runtime.js +488 -59
  99. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  100. package/neural-interface/lib/assistant-test-density.js +142 -0
  101. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  102. package/neural-interface/lib/assistant-user-context.js +908 -0
  103. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  104. package/neural-interface/lib/assistant-user-learn.js +404 -0
  105. package/neural-interface/lib/assistant-user-threads.js +226 -0
  106. package/neural-interface/lib/assistant-user-writer.js +183 -0
  107. package/neural-interface/lib/augmented-path.js +317 -53
  108. package/neural-interface/lib/browser-background-tab.js +134 -0
  109. package/neural-interface/lib/browser-screenshot.js +678 -61
  110. package/neural-interface/lib/claude-accounts.js +342 -31
  111. package/neural-interface/lib/claude-agent-bridge.js +123 -9
  112. package/neural-interface/lib/claude-executable.js +6 -1
  113. package/neural-interface/lib/claude-model-catalog.js +33 -5
  114. package/neural-interface/lib/claude-panel-auth.js +221 -0
  115. package/neural-interface/lib/claude-profile-api-key.js +62 -0
  116. package/neural-interface/lib/claude-temporary.js +46 -7
  117. package/neural-interface/lib/cli-install-api.js +137 -0
  118. package/neural-interface/lib/cli-install.js +797 -0
  119. package/neural-interface/lib/cli-path.js +130 -0
  120. package/neural-interface/lib/cli-resolver.js +744 -0
  121. package/neural-interface/lib/cli-update-planner.js +143 -7
  122. package/neural-interface/lib/cloudflared/install.js +533 -0
  123. package/neural-interface/lib/cloudflared/manager.js +545 -0
  124. package/neural-interface/lib/cloudflared/pins.js +115 -0
  125. package/neural-interface/lib/cloudflared/pins.json +63 -0
  126. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  127. package/neural-interface/lib/codex-account-auth.js +178 -0
  128. package/neural-interface/lib/codex-accounts.js +489 -0
  129. package/neural-interface/lib/codex-capabilities.js +2 -1
  130. package/neural-interface/lib/codex-compat-rpc.js +8 -2
  131. package/neural-interface/lib/codex-mcp-approvals.js +5 -1
  132. package/neural-interface/lib/codex-panel-auth.js +62 -0
  133. package/neural-interface/lib/codex-session-settings.js +1 -1
  134. package/neural-interface/lib/codex-settings-schema.js +120 -0
  135. package/neural-interface/lib/desktop/config.js +3 -0
  136. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  137. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  138. package/neural-interface/lib/editor-completion.js +714 -0
  139. package/neural-interface/lib/editor-config.js +149 -0
  140. package/neural-interface/lib/editor-files-api.js +268 -0
  141. package/neural-interface/lib/editor-git-api.js +134 -0
  142. package/neural-interface/lib/file-explorer-api.js +1039 -0
  143. package/neural-interface/lib/file-explorer-system.js +355 -0
  144. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  145. package/neural-interface/lib/file-explorer-watch.js +239 -0
  146. package/neural-interface/lib/git-bash/bzip2.js +339 -0
  147. package/neural-interface/lib/git-bash/claude-settings.js +73 -0
  148. package/neural-interface/lib/git-bash/extract-worker.js +34 -0
  149. package/neural-interface/lib/git-bash/install.js +529 -0
  150. package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
  151. package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
  152. package/neural-interface/lib/git-bash/manager.js +268 -0
  153. package/neural-interface/lib/git-bash/pins.js +206 -0
  154. package/neural-interface/lib/git-bash/pins.json +34 -0
  155. package/neural-interface/lib/git-bash/resolver.js +194 -0
  156. package/neural-interface/lib/git-diff-api.js +103 -0
  157. package/neural-interface/lib/git-read.js +234 -0
  158. package/neural-interface/lib/greeting/api.js +89 -0
  159. package/neural-interface/lib/greeting/budgets.js +90 -0
  160. package/neural-interface/lib/greeting/engine.js +461 -0
  161. package/neural-interface/lib/greeting/facts.js +320 -0
  162. package/neural-interface/lib/greeting/sources.js +252 -0
  163. package/neural-interface/lib/greeting/writer.js +139 -0
  164. package/neural-interface/lib/http-guards.js +189 -13
  165. package/neural-interface/lib/install-details.js +145 -0
  166. package/neural-interface/lib/machine-names.js +88 -0
  167. package/neural-interface/lib/mcp-installer.js +14 -2
  168. package/neural-interface/lib/memory-api.js +31 -7
  169. package/neural-interface/lib/native-loop-providers.js +26 -8
  170. package/neural-interface/lib/native-loop-runtime.js +9 -4
  171. package/neural-interface/lib/os-path.js +319 -0
  172. package/neural-interface/lib/plugin-installer.js +4 -2
  173. package/neural-interface/lib/project-storage.js +5 -7
  174. package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
  175. package/neural-interface/lib/provider-panel-terminal-auth.js +95 -0
  176. package/neural-interface/lib/pty-host/core.js +2 -1
  177. package/neural-interface/lib/pty-host/manager.js +27 -2
  178. package/neural-interface/lib/remote-policy.js +20 -11
  179. package/neural-interface/lib/request-gate.js +589 -0
  180. package/neural-interface/lib/session-title-generator.js +4 -3
  181. package/neural-interface/lib/system-about.js +340 -0
  182. package/neural-interface/lib/system-activity.js +66 -0
  183. package/neural-interface/lib/terminal-env.js +11 -3
  184. package/neural-interface/lib/terminal-path.js +55 -0
  185. package/neural-interface/lib/ui-blob-api.js +108 -0
  186. package/neural-interface/lib/ui-blob-store.js +68 -0
  187. package/neural-interface/lib/virtual-socket.js +12 -1
  188. package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
  189. package/neural-interface/lib/whatsapp/bridge.js +78 -34
  190. package/neural-interface/lib/whatsapp/commands.js +13 -14
  191. package/neural-interface/lib/whatsapp/config.js +134 -20
  192. package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
  193. package/neural-interface/lib/whatsapp/host-core.js +168 -35
  194. package/neural-interface/lib/whatsapp/inbound.js +5 -3
  195. package/neural-interface/lib/whatsapp/local-file.js +524 -0
  196. package/neural-interface/lib/whatsapp/manager.js +92 -32
  197. package/neural-interface/lib/whatsapp/paths.js +11 -1
  198. package/neural-interface/lib/whatsapp/protocol.js +65 -5
  199. package/neural-interface/lib/whatsapp/redact.js +63 -0
  200. package/neural-interface/lib/whatsapp/service.js +343 -91
  201. package/neural-interface/lib/whatsapp/transcription.js +463 -0
  202. package/neural-interface/package-lock.json +701 -2
  203. package/neural-interface/package.json +13 -2
  204. package/neural-interface/public/index.html +2 -0
  205. package/neural-interface/public/index2d.html +2 -0
  206. package/neural-interface/public/install-app.html +9 -6
  207. package/neural-interface/public/offline.html +19 -3
  208. package/neural-interface/public/onboarding.html +107 -2
  209. package/neural-interface/public/shared/account-i18n.js +7 -0
  210. package/neural-interface/public/shared/account-menu.js +539 -0
  211. package/neural-interface/public/shared/account-usage.js +19 -0
  212. package/neural-interface/public/shared/account-view.js +335 -0
  213. package/neural-interface/public/shared/agent-runtime-options.js +50 -14
  214. package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
  215. package/neural-interface/public/shared/assistant/asst-api.js +32 -2
  216. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  217. package/neural-interface/public/shared/assistant/asst-brain-picker.js +430 -81
  218. package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
  219. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  220. package/neural-interface/public/shared/assistant/asst-mascot.js +140 -61
  221. package/neural-interface/public/shared/assistant/asst-menu.js +27 -11
  222. package/neural-interface/public/shared/assistant/asst-panel.js +198 -42
  223. package/neural-interface/public/shared/assistant/asst-render.js +197 -23
  224. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  225. package/neural-interface/public/shared/assistant/asst-route.js +95 -343
  226. package/neural-interface/public/shared/assistant/asst-routes-editor.js +534 -0
  227. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  228. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  229. package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
  230. package/neural-interface/public/shared/assistant/asst-state.js +186 -2
  231. package/neural-interface/public/shared/assistant/asst-styles.js +247 -11
  232. package/neural-interface/public/shared/blob-store.js +111 -22
  233. package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
  234. package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
  235. package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
  236. package/neural-interface/public/shared/cdx/cdx-panel.js +80 -118
  237. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  238. package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
  239. package/neural-interface/public/shared/cdx/cdx-styles.js +164 -107
  240. package/neural-interface/public/shared/cdx/cdx-tabs.js +348 -668
  241. package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
  242. package/neural-interface/public/shared/claude-account-view.js +3 -0
  243. package/neural-interface/public/shared/cli-install-view.js +392 -0
  244. package/neural-interface/public/shared/cli-status.js +282 -22
  245. package/neural-interface/public/shared/constants.js +6 -1
  246. package/neural-interface/public/shared/cp/cp-events.js +2 -1
  247. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  248. package/neural-interface/public/shared/cp/cp-styles.js +61 -0
  249. package/neural-interface/public/shared/desktop-bridge.js +39 -0
  250. package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
  251. package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
  252. package/neural-interface/public/shared/desktop-titlebar.js +153 -0
  253. package/neural-interface/public/shared/desktop-update-view.js +462 -0
  254. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  255. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  256. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  257. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  258. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  259. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  260. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  261. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  262. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  263. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  264. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  265. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  266. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  267. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  268. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  269. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  270. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  271. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  272. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  273. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  274. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  275. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  276. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  277. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  278. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  279. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  280. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  281. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  282. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  283. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  284. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  285. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  286. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  287. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  288. package/neural-interface/public/shared/file-links.js +339 -0
  289. package/neural-interface/public/shared/git-bash-view.js +145 -0
  290. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  291. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  292. package/neural-interface/public/shared/html-shell.js +161 -165
  293. package/neural-interface/public/shared/i18n.js +19 -1
  294. package/neural-interface/public/shared/install-details-view.js +86 -0
  295. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  296. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  297. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +131 -17
  298. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  299. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +22 -0
  300. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +158 -0
  301. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  302. package/neural-interface/public/shared/pwa-install-page.js +32 -2
  303. package/neural-interface/public/shared/pwa-install.css +3 -3
  304. package/neural-interface/public/shared/pwa-install.js +100 -1
  305. package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
  306. package/neural-interface/public/shared/settings/settings-about.js +254 -0
  307. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  308. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  309. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  310. package/neural-interface/public/shared/settings/settings-ia.js +33 -4
  311. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  312. package/neural-interface/public/shared/showcase-privacy.js +489 -0
  313. package/neural-interface/public/shared/start-bridge.js +238 -19
  314. package/neural-interface/public/shared/storage.js +30 -3
  315. package/neural-interface/public/shared/styles.css +1710 -770
  316. package/neural-interface/public/shared/synabun-mascot.js +68 -58
  317. package/neural-interface/public/shared/tunnel-view.js +167 -0
  318. package/neural-interface/public/shared/ui-claude-panel.js +369 -229
  319. package/neural-interface/public/shared/ui-cli-banner.js +355 -0
  320. package/neural-interface/public/shared/ui-detail.js +15 -0
  321. package/neural-interface/public/shared/ui-explorer.js +22 -0
  322. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  323. package/neural-interface/public/shared/ui-file-links.js +103 -0
  324. package/neural-interface/public/shared/ui-git-bash.js +124 -0
  325. package/neural-interface/public/shared/ui-help.js +26 -0
  326. package/neural-interface/public/shared/ui-invite.js +126 -116
  327. package/neural-interface/public/shared/ui-judgments.js +10 -1
  328. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  329. package/neural-interface/public/shared/ui-loading.js +187 -19
  330. package/neural-interface/public/shared/ui-menubar.js +25 -33
  331. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  332. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  333. package/neural-interface/public/shared/ui-navbar.js +48 -22
  334. package/neural-interface/public/shared/ui-provider-auth.js +104 -0
  335. package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
  336. package/neural-interface/public/shared/ui-sessions.js +9 -3
  337. package/neural-interface/public/shared/ui-settings.js +509 -490
  338. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  339. package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
  340. package/neural-interface/public/shared/ui-sync.js +22 -0
  341. package/neural-interface/public/shared/ui-terminal.js +40 -5
  342. package/neural-interface/public/shared/ui-tool-updates.js +5 -0
  343. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  344. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  345. package/neural-interface/public/shared/ui-update.js +594 -5
  346. package/neural-interface/public/shared/ui-whatsapp.js +21 -6
  347. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  348. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  349. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  350. package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
  351. package/neural-interface/public/shared/worker-end.js +253 -0
  352. package/neural-interface/public/sw.js +2 -2
  353. package/neural-interface/public/variant/2d/main.js +10 -1
  354. package/neural-interface/public/variant/3d/main.js +10 -1
  355. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  356. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  357. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  358. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  359. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  360. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  361. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  362. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  363. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  364. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  365. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  366. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  367. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  368. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  369. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  370. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  371. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  372. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  373. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  374. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  375. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  376. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  377. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  378. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  379. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  380. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  381. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  382. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  383. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  384. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  385. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  386. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  387. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  388. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  389. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  390. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  391. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  392. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  393. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  394. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  395. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  396. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  397. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  398. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  399. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  400. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  401. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  402. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  403. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  404. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  405. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  406. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  407. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  408. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  409. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  410. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  411. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  412. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  413. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  414. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  415. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  416. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  417. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  418. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  419. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  420. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  421. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  422. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  423. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  424. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  425. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  426. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  427. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  428. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  429. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  430. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  431. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  432. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  433. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  434. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  435. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  436. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  437. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  438. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  439. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  440. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  441. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  442. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  443. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  444. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  445. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  446. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  447. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  448. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  449. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  450. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  451. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  452. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  453. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  454. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  455. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  456. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  457. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  458. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  459. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  460. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  461. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  462. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  463. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  464. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  465. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  466. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  467. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  468. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  469. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  470. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  471. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  472. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  473. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  474. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  475. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  476. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  477. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  478. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  479. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  480. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  481. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  482. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  483. package/neural-interface/scripts/build-vendor.mjs +78 -2
  484. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  485. package/neural-interface/server.js +2085 -1629
  486. package/neural-interface/templates/rulesets/README.md +1 -1
  487. package/package.json +5 -8
  488. package/setup.js +53 -15
  489. package/benchmarks/browser-live-results.json +0 -79
  490. package/benchmarks/browser-v2-results.json +0 -258
  491. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  492. package/neural-interface/public/category-logos/claude.svg +0 -1
  493. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  494. package/neural-interface/public/category-logos/openai.svg +0 -1
  495. package/neural-interface/public/category-logos/synabun.png +0 -0
  496. package/neural-interface/public/claude.svg +0 -1
  497. package/neural-interface/public/gallery.svg +0 -6
  498. package/neural-interface/public/leonardoai.svg +0 -1
  499. package/neural-interface/public/mcp.svg +0 -4
  500. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  501. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  502. package/neural-interface/public/sessionicon.svg +0 -8
  503. package/neural-interface/public/toolbar-album.svg +0 -8
  504. package/neural-interface/public/toolbar-question.svg +0 -6
  505. package/neural-interface/public/toolbar-sessions.svg +0 -6
  506. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  507. package/skills/synabun/synabunicon.png +0 -0
@@ -0,0 +1,125 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — Code editor: the command palette and go-to-file
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Two lists under a search field, at the top of the editor panel: the
6
+ // editor's commands (F1 or Mod-Shift-P), and the files of the project
7
+ // (Mod-P; with nothing typed, the open tabs). Enter runs or opens what is
8
+ // selected, Escape closes the list and nothing else happens. Both are the
9
+ // panel's one popup (editor-menu.js); what they list and in which order is
10
+ // decided in editor-palette-logic.js.
11
+ // Takes its words, the menu and what a choice does as arguments.
12
+
13
+ import { FILE_SEARCH_DELAY_MS, fileListEmpty, fileRows, fileSearchParams, paletteCommands, queryTerms, rankRows, tabRows } from './editor-palette-logic.js';
14
+ import { formatKey } from './editor-commands.js';
15
+
16
+ /**
17
+ * @param {object} o
18
+ * @param {(key: string, params?: object) => string} o.t
19
+ * @param {(menu: object) => { close: Function, setItems: Function }} o.openMenu editor-menu.js, already given the panel as its host
20
+ * @param {() => { x: number, y: number }} o.position where a list opens: its top-left corner, in page coordinates
21
+ * @param {boolean} o.mac
22
+ * @param {object[]} o.commands editor-commands.js
23
+ * @param {() => string[]} o.features the features this server has ('ai', 'git')
24
+ * @param {(id: string) => void} o.run run a command by its id
25
+ * @param {() => string | null | Promise<string | null>} o.project the folder files are searched in (it may have to be asked for)
26
+ * @param {() => { path: string, name: string }[]} o.tabs the open files, the one used last first
27
+ * @param {(path: string) => void} o.openFile
28
+ * @param {() => void} [o.onClose] a list closed (the keyboard goes back to the text)
29
+ * @param {typeof fetch} [o.fetchImpl]
30
+ */
31
+ export function createPalette({ t, openMenu, position, mac, commands, features, run, project, tabs, openFile, onClose = () => {}, fetchImpl = (...args) => fetch(...args) }) {
32
+ const item = (row, hint) => ({ id: row.id, label: row.label, ...(hint ? { hint } : {}) });
33
+
34
+ function openCommands() {
35
+ const rows = paletteCommands(commands, { features: features() }).map((row) => ({ id: row.id, label: t(row.titleKey), key: row.key }));
36
+ return openMenu({
37
+ className: 'fe-editor-palette',
38
+ at: position(),
39
+ label: t('editor.palette.commands'),
40
+ items: [],
41
+ search: {
42
+ label: t('editor.palette.commands'),
43
+ placeholder: t('editor.palette.commandsPlaceholder'),
44
+ empty: t('editor.palette.noCommand'),
45
+ filter: (query) => rankRows(rows, query, { limit: rows.length }).map((row) => item(row, row.key ? formatKey(row.key, mac) : '')),
46
+ },
47
+ onSelect: (id) => run(id),
48
+ onClose,
49
+ });
50
+ }
51
+
52
+ function openFiles() {
53
+ let root = null; // the folder that is searched, once it is known
54
+ let rootKnown = false;
55
+ let found = []; // the files of the last answer
56
+ let typed = '';
57
+ let asked = ''; // the query string of the request that was last sent
58
+ let timer = 0;
59
+ let request = null;
60
+ let failed = false;
61
+ let pending = false; // a search for what is typed is waiting to be sent, or has not answered yet
62
+ let handle = null;
63
+
64
+ const list = (query) => {
65
+ const rows = queryTerms(query).length ? rankRows(found, query) : tabRows(tabs(), root);
66
+ return rows.map((row) => item(row, row.detail));
67
+ };
68
+ // Still searching, failed, nothing found and nothing asked yet are four different things to say.
69
+ const empty = () => t(fileListEmpty({ rootKnown, root, failed, pending, typed }));
70
+
71
+ async function search(params) {
72
+ request?.abort();
73
+ const mine = new AbortController();
74
+ request = mine;
75
+ let rows = [];
76
+ let ok = false;
77
+ try {
78
+ const res = await fetchImpl(`/api/project-files?${params}`, { signal: mine.signal });
79
+ if (res.ok) { rows = fileRows(await res.json()); ok = true; }
80
+ } catch { /* aborted, or no answer */ }
81
+ if (request !== mine) return; // a newer search is on its way
82
+ request = null;
83
+ pending = false;
84
+ found = rows;
85
+ failed = !ok;
86
+ handle?.setItems(list(typed));
87
+ }
88
+
89
+ function schedule(query) {
90
+ const params = fileSearchParams(root, query);
91
+ if (params === asked) return;
92
+ asked = params;
93
+ clearTimeout(timer);
94
+ if (!params) { request?.abort(); request = null; found = []; failed = false; pending = false; return; }
95
+ pending = true;
96
+ timer = setTimeout(() => search(params), FILE_SEARCH_DELAY_MS);
97
+ }
98
+
99
+ handle = openMenu({
100
+ className: 'fe-editor-palette',
101
+ at: position(),
102
+ label: t('editor.palette.files'),
103
+ items: [],
104
+ search: {
105
+ label: t('editor.palette.files'),
106
+ placeholder: t('editor.palette.filesPlaceholder'),
107
+ empty,
108
+ filter: (query) => { typed = query; schedule(query); return list(query); },
109
+ },
110
+ onSelect: (path) => openFile(path),
111
+ onClose: () => { clearTimeout(timer); request?.abort(); request = null; handle = null; onClose(); },
112
+ });
113
+ // The folder may have to be asked for: what was typed meanwhile is searched as soon as it is known.
114
+ Promise.resolve().then(project).catch(() => null).then((folder) => {
115
+ root = folder || null;
116
+ rootKnown = true;
117
+ if (!handle) return;
118
+ schedule(typed);
119
+ handle.setItems(list(typed));
120
+ });
121
+ return handle;
122
+ }
123
+
124
+ return { openCommands, openFiles };
125
+ }
@@ -0,0 +1,288 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — Code editor: the panel's decisions
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // What the editor panel decides without touching the page: the path it shows,
6
+ // the state of its buttons, the events of a plan being edited, and what a
7
+ // refused file means. editor-panel.js renders from these. No DOM and no
8
+ // imports: loaded by `node --test` as it is.
9
+
10
+ /** A file size the way the status bar writes it. */
11
+ export function formatSize(bytes) {
12
+ const n = Number(bytes) || 0;
13
+ if (n < 1024) return `${n} B`;
14
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
15
+ return `${(n / (1024 * 1024)).toFixed(1)} MB`;
16
+ }
17
+
18
+ /**
19
+ * The path the header shows: relative to the selected project, or the whole path without its leading slash
20
+ * when no project is selected (or the file is not in it).
21
+ */
22
+ export function displayPath(path, projectRoot) {
23
+ const full = String(path ?? '');
24
+ const rel = projectRoot ? full.replace(String(projectRoot).replace(/\\/g, '/'), '') : full;
25
+ return rel.startsWith('/') ? rel.slice(1) : rel;
26
+ }
27
+
28
+ /** The name a plan's banner uses for the panel that opened it. */
29
+ export function planSourceLabel(source) {
30
+ if (source === 'codex') return 'Codex';
31
+ if (source === 'opencode') return 'OpenCode';
32
+ return 'Claude';
33
+ }
34
+
35
+ /**
36
+ * The identity every plan event carries, from the contract `open-plan-editor` delivered.
37
+ * @param {{ source?: string, tabId?: any, planId?: any, revision?: any, accountId?: any, threadId?: any, sidepanelWindowId?: any }} contract
38
+ * @param {object} [extra] the fields of the particular event
39
+ */
40
+ export function planEvent(contract, extra = {}) {
41
+ const { source = 'claude', tabId = null, planId, revision, accountId, threadId, sidepanelWindowId = null } = contract || {};
42
+ return { source, tabId, planId, revision, accountId, threadId, sidepanelWindowId: sidepanelWindowId || null, ...extra };
43
+ }
44
+
45
+ /** What tells one plan request from another: the panel and tab that asked, the plan and its revision. */
46
+ export function planIdentityKey(contract) {
47
+ const { source = 'claude', tabId = null, planId, revision, sidepanelWindowId = null } = contract || {};
48
+ return [source, tabId ?? '', planId ?? '', revision ?? '', sidepanelWindowId || ''].join('|');
49
+ }
50
+
51
+ /**
52
+ * Whether two plan requests come from the same place: the same tab of the same panel. That place follows one
53
+ * plan editor at a time, so a second plan of its own takes the first one's tab.
54
+ */
55
+ export function isSamePlanOwner(a, b) {
56
+ if (!a || !b) return false;
57
+ return (a.source ?? 'claude') === (b.source ?? 'claude')
58
+ && (a.tabId ?? null) === (b.tabId ?? null)
59
+ && (a.sidepanelWindowId || null) === (b.sidepanelWindowId || null);
60
+ }
61
+
62
+ /** Whether `contract` asks for the plan revision that is already open (the editor is then only focused). */
63
+ export function isSamePlan(open, contract) {
64
+ if (!open || !contract) return false;
65
+ return open.filePath === contract.filePath
66
+ && (open.source ?? 'claude') === (contract.source ?? 'claude')
67
+ && (open.tabId ?? null) === (contract.tabId ?? null)
68
+ && open.planId === contract.planId
69
+ && open.revision === contract.revision;
70
+ }
71
+
72
+ /**
73
+ * Whether the file on disk still holds the plan revision the panel asked to edit. Line endings are not part of
74
+ * a revision: both sides are compared with "\n".
75
+ * @param {string} content the file as read
76
+ * @param {string | undefined} expected the contract's `expectedMarkdown`; anything but a string means no check
77
+ */
78
+ export function matchesExpectedMarkdown(content, expected) {
79
+ if (typeof expected !== 'string') return true;
80
+ return String(content).replace(/\r\n/g, '\n') === expected.replace(/\r\n/g, '\n');
81
+ }
82
+
83
+ /** Whether a path is the user's OpenCode configuration file. */
84
+ export function isOpencodeConfigPath(path) {
85
+ return String(path || '').replace(/\\/g, '/').endsWith('/.config/opencode/config.json');
86
+ }
87
+
88
+ const OUTSIDE_ROOTS = 'Path outside registered project roots';
89
+
90
+ /**
91
+ * What a failed `GET /api/file-content` means for the panel.
92
+ * @param {{ status: number, body?: object, path?: string }} failure
93
+ * @returns {{ kind: 'toast' | 'refused', key: string, params?: object, text?: string }}
94
+ * `toast`: nothing opens; `text` (the server's own words) wins over the translation of `key` when present.
95
+ * `refused`: the panel opens with the message of `key` in place of an editor.
96
+ */
97
+ export function describeOpenFailure({ status, body, path } = {}) {
98
+ const error = typeof body?.error === 'string' ? body.error : '';
99
+ if (status === 403 && error === OUTSIDE_ROOTS && isOpencodeConfigPath(path)) {
100
+ return { kind: 'toast', key: 'editor.toast.restartForOpencodeConfig' };
101
+ }
102
+ if (status === 415) {
103
+ return body?.reason === 'encoding'
104
+ ? { kind: 'refused', key: 'editor.refused.encoding' }
105
+ : { kind: 'refused', key: 'editor.refused.binary' };
106
+ }
107
+ if (status === 413) {
108
+ const max = Number(body?.maxBytes);
109
+ return Number.isFinite(max) && max > 0
110
+ ? { kind: 'toast', key: 'editor.toast.tooLargeOver', params: { size: formatSize(max) } }
111
+ : { kind: 'toast', key: 'editor.toast.tooLarge' };
112
+ }
113
+ return { kind: 'toast', key: 'editor.toast.cannotOpen', text: error };
114
+ }
115
+
116
+ /**
117
+ * The state of the header's buttons.
118
+ * @param {{ ready: boolean, dirty: boolean, saving: boolean, plan: boolean, changelog?: boolean }} s `ready`: a
119
+ * document is open; `plan`, `changelog`: a plan or a changelog draft is being edited (either can be saved
120
+ * unchanged, which approves it as it is)
121
+ */
122
+ export function controlsState({ ready, dirty, saving, plan, changelog = false }) {
123
+ return {
124
+ saveDisabled: !ready || saving || (!dirty && !plan && !changelog),
125
+ discardDisabled: !ready || saving || !dirty,
126
+ };
127
+ }
128
+
129
+ /**
130
+ * The status bar's indentation item.
131
+ * @param {{ kind: 'spaces' | 'tabs', tabSize: number }} indent from resolveIndentation()
132
+ * @returns {{ key: string, params: { n: number } }}
133
+ */
134
+ export function indentStatus(indent) {
135
+ return { key: indent?.kind === 'tabs' ? 'editor.status.tabSize' : 'editor.status.spaces', params: { n: indent?.tabSize ?? 2 } };
136
+ }
137
+
138
+ /**
139
+ * The status bar's line-ending item: the style, or what a save turns a mixed file into.
140
+ * @param {{ eol: 'LF' | 'CRLF', mixed: boolean }} ending from detectLineEnding()
141
+ * @returns {{ key: string | null, params?: { eol: string }, text?: string }} `key: null` → show `text` as it is
142
+ */
143
+ export function eolStatus(ending) {
144
+ const eol = ending?.eol === 'CRLF' ? 'CRLF' : 'LF';
145
+ return ending?.mixed ? { key: 'editor.status.eolMixed', params: { eol } } : { key: null, text: eol };
146
+ }
147
+
148
+ /**
149
+ * The status bar's position item.
150
+ * @param {{ line: number, column: number, selected: number, cursors: number }} at
151
+ * @returns {{ key: string, params: object }}
152
+ */
153
+ export function positionStatus({ line, column, selected = 0, cursors = 1 }) {
154
+ // Several carets: the place of the main one, how many there are, and what they select together.
155
+ if (cursors > 1) {
156
+ return selected > 0
157
+ ? { key: 'editor.status.cursorsSelected', params: { line, column, count: cursors, selected } }
158
+ : { key: 'editor.status.cursors', params: { line, column, count: cursors } };
159
+ }
160
+ if (selected > 0) return { key: 'editor.status.positionSelected', params: { line, column, selected } };
161
+ return { key: 'editor.status.position', params: { line, column } };
162
+ }
163
+
164
+ /**
165
+ * The question asked before tabs with unsaved changes are closed.
166
+ * @param {string[]} unsaved the names of the files that have unsaved changes
167
+ * @param {{ only?: boolean }} [o] `only`: the one tab that is open is being closed (the question the editor
168
+ * asked before it had tabs)
169
+ * @returns {{ key: string, params?: object } | null} null: nothing is unsaved, nothing is asked
170
+ */
171
+ export function closeConfirm(unsaved, { only = false } = {}) {
172
+ const names = Array.isArray(unsaved) ? unsaved : [];
173
+ if (!names.length) return null;
174
+ if (only) return { key: 'editor.confirm.close' };
175
+ if (names.length === 1) return { key: 'editor.confirm.closeOne', params: { name: names[0] } };
176
+ return { key: 'editor.confirm.closeMany', params: { count: names.length, files: names.map((name) => `\u2022 ${name}`).join('\n') } };
177
+ }
178
+
179
+ /** The indentations the status bar offers, beside "Detect". */
180
+ export const INDENT_CHOICES = Object.freeze([
181
+ Object.freeze({ id: 'spaces-2', kind: 'spaces', size: 2 }),
182
+ Object.freeze({ id: 'spaces-4', kind: 'spaces', size: 4 }),
183
+ Object.freeze({ id: 'spaces-8', kind: 'spaces', size: 8 }),
184
+ Object.freeze({ id: 'tabs', kind: 'tabs' }),
185
+ ]);
186
+
187
+ /** The choice an id of the indentation menu stands for; null for "detect" (and for anything else). */
188
+ export function indentChoice(id) {
189
+ const found = INDENT_CHOICES.find((choice) => choice.id === id);
190
+ return found ? { kind: found.kind, ...(found.size ? { size: found.size } : {}) } : null;
191
+ }
192
+
193
+ /** The id of the menu item that is in force: the user's choice, or 'detect' when there is none. */
194
+ export function indentChoiceId(choice) {
195
+ if (!choice) return 'detect';
196
+ return choice.kind === 'tabs' ? 'tabs' : `spaces-${choice.size}`;
197
+ }
198
+
199
+ /**
200
+ * The languages a search of the status bar's list finds: those whose name or other names hold the words typed,
201
+ * the ones whose name starts with them first.
202
+ * @param {{ name: string, alias?: readonly string[] }[]} languages
203
+ * @param {string} query
204
+ * @returns {string[]} names
205
+ */
206
+ export function filterLanguages(languages, query) {
207
+ const list = (languages || []).filter((language) => language && typeof language.name === 'string');
208
+ const wanted = String(query ?? '').trim().toLowerCase();
209
+ const byName = (a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' });
210
+ if (!wanted) return list.map((language) => language.name).sort(byName);
211
+ const starts = []; const holds = [];
212
+ for (const language of list) {
213
+ const name = language.name.toLowerCase();
214
+ if (name.startsWith(wanted)) starts.push(language.name);
215
+ else if (name.includes(wanted) || (language.alias || []).some((alias) => String(alias).toLowerCase().includes(wanted))) holds.push(language.name);
216
+ }
217
+ return [...starts.sort(byName), ...holds.sort(byName)];
218
+ }
219
+
220
+ // ── The View menu ──
221
+
222
+ /** The sizes the text can have, as the preferences allow them (editor-prefs.js keeps the same numbers). */
223
+ export const VIEW_FONT = Object.freeze({ min: 10, max: 18, base: 12 });
224
+
225
+ /**
226
+ * The View menu's entries for the preferences in force.
227
+ * @param {{ wordWrap: boolean, minimap: boolean, indentGuides: boolean, renderWhitespace: string, fontSize: number }} editing
228
+ * @returns {({ separator: true } | { id: string, labelKey: string, checked?: boolean, toggle?: boolean,
229
+ * disabled?: boolean, hintKey?: string, hintParams?: object })[]} `toggle`: a switch (the others with `checked`
230
+ * are one choice among several)
231
+ */
232
+ export function viewMenuItems(editing = {}) {
233
+ const size = Number(editing.fontSize) || VIEW_FONT.base;
234
+ const whitespace = ['none', 'selection', 'all'].includes(editing.renderWhitespace) ? editing.renderWhitespace : 'none';
235
+ return [
236
+ { id: 'wordWrap', labelKey: 'editor.view.wordWrap', checked: editing.wordWrap !== false, toggle: true },
237
+ { id: 'minimap', labelKey: 'editor.view.minimap', checked: editing.minimap !== false, toggle: true },
238
+ { id: 'indentGuides', labelKey: 'editor.view.indentGuides', checked: editing.indentGuides !== false, toggle: true },
239
+ { separator: true },
240
+ { id: 'whitespace:none', labelKey: 'editor.view.whitespaceNone', checked: whitespace === 'none' },
241
+ { id: 'whitespace:selection', labelKey: 'editor.view.whitespaceSelection', checked: whitespace === 'selection' },
242
+ { id: 'whitespace:all', labelKey: 'editor.view.whitespaceAll', checked: whitespace === 'all' },
243
+ { separator: true },
244
+ { id: 'font:larger', labelKey: 'editor.view.fontLarger', disabled: size >= VIEW_FONT.max, hintKey: 'editor.view.fontSize', hintParams: { size } },
245
+ { id: 'font:smaller', labelKey: 'editor.view.fontSmaller', disabled: size <= VIEW_FONT.min },
246
+ { id: 'font:reset', labelKey: 'editor.view.fontReset', disabled: size === VIEW_FONT.base },
247
+ ];
248
+ }
249
+
250
+ /**
251
+ * What choosing an entry of the View menu changes.
252
+ * @param {string} id an entry's id
253
+ * @param {object} editing the preferences in force
254
+ * @returns {object | null} the part of the `editing` preferences to store, or null for an entry that changes nothing
255
+ */
256
+ export function viewMenuChange(id, editing = {}) {
257
+ const size = Number(editing.fontSize) || VIEW_FONT.base;
258
+ switch (id) {
259
+ case 'wordWrap': return { wordWrap: editing.wordWrap === false };
260
+ case 'minimap': return { minimap: editing.minimap === false };
261
+ case 'indentGuides': return { indentGuides: editing.indentGuides === false };
262
+ case 'whitespace:none': return editing.renderWhitespace === 'none' ? null : { renderWhitespace: 'none' };
263
+ case 'whitespace:selection': return editing.renderWhitespace === 'selection' ? null : { renderWhitespace: 'selection' };
264
+ case 'whitespace:all': return editing.renderWhitespace === 'all' ? null : { renderWhitespace: 'all' };
265
+ case 'font:larger': return size >= VIEW_FONT.max ? null : { fontSize: size + 1 };
266
+ case 'font:smaller': return size <= VIEW_FONT.min ? null : { fontSize: size - 1 };
267
+ case 'font:reset': return size === VIEW_FONT.base ? null : { fontSize: VIEW_FONT.base };
268
+ default: return null;
269
+ }
270
+ }
271
+
272
+ /** The next way of drawing whitespace, for a command that goes through them: none → selection → all → none. */
273
+ export function nextWhitespace(current) {
274
+ const order = ['none', 'selection', 'all'];
275
+ return order[(order.indexOf(current) + 1) % order.length] || 'none';
276
+ }
277
+
278
+ /** Narrower than this, the editor has no room for a minimap. */
279
+ export const MINIMAP_MIN_WIDTH = 760;
280
+
281
+ /**
282
+ * Whether a document shows the minimap.
283
+ * @param {{ preference: boolean, width: number, large: boolean }} o `width`: the editor's, in pixels; `large`: the
284
+ * document is over the size the minimap is drawn for (editor-doc.js: isLargeDocument)
285
+ */
286
+ export function minimapShown({ preference, width, large }) {
287
+ return preference !== false && !large && Number(width) >= MINIMAP_MIN_WIDTH;
288
+ }