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
@@ -25,17 +25,12 @@ import { detectProject as memoryProject } from '../../mcp-server/dist/config.js'
25
25
  // WS bound, so page-refresh reattach is the same object.
26
26
 
27
27
  import { query, startup } from '@anthropic-ai/claude-agent-sdk';
28
- import { CLAUDE_EFFORT_LEVELS, checkClaudeCliSkew, markAlignedClaudeExecutableFailed } from './claude-model-catalog.js';
29
- import {
30
- claudeRuntime,
31
- clearNativeBinaryCache,
32
- isNativeBinaryLaunchFailure,
33
- planRuntimeRecovery,
34
- resolveClaudeExecutableOverride,
35
- } from './native-binary-runtime.js';
28
+ import { CLAUDE_EFFORT_LEVELS } from './claude-model-catalog.js';
29
+ import { CLAUDE_NOT_INSTALLED, resolveClaudeSdkExecutable } from './claude-executable.js';
30
+ import { diagnoseLaunchFailure, isNativeBinaryLaunchFailure } from './native-binary-runtime.js';
36
31
  import { normalizePanelSession, startSignature, applyPanelSessionOptions, liveSettingsPatch, normalizeMcpServers, mergeTabMcpServers } from './claude-panel-session.js';
37
32
  import { SESSION_REQUESTS, runSessionRequest, slimRewind, slimMcpStatus } from './claude-panel-requests.js';
38
- import { applyTemporaryOptions, plansDirsOf, planFileOfToolCall, removeTemporaryPlanFiles } from './claude-temporary.js';
33
+ import { applyTemporaryOptions, plansDirsOf, snapshotPlanFiles, planFileOfToolCall, removeTemporaryPlanFiles } from './claude-temporary.js';
39
34
  import { rootBypassBlock } from './claude-bypass-policy.js';
40
35
  import { randomUUID } from 'node:crypto';
41
36
  import { dirname, join } from 'node:path';
@@ -112,6 +107,7 @@ export const PANEL_CAPABILITIES = Object.freeze([
112
107
  'message_flags', // session.hookEvents / promptSuggestions / subagentText / agentSummaries → the matching SDK options
113
108
  'task_control', // inbound `stop_task` / `background_tasks` → `task_control_result`; system/session_crons events
114
109
  'origin_human', // a query marked `typed: true` is sent with origin {kind:'human'}
110
+ 'greeting', // query `greetingId`: the model is told once what SynaBun greeted the user with (lib/greeting/)
115
111
  'session_requests', // inbound `session_request {id, what, args}` → `session_response`: context_usage, usage, mcp_status, mcp_reconnect, mcp_toggle, rewind_preview
116
112
  'rewind_stats', // `rewind_result` carries filesChanged / insertions / deletions
117
113
  'session_title', // query `title` names a new session where the CLI reads it
@@ -231,7 +227,7 @@ function log(...args) { console.log('[claude-sdk]', ...args); }
231
227
 
232
228
  // Panel sessions, a temporary chat (lib/claude-temporary.js): the plan files
233
229
  // Claude Code wrote for one that still have to be removed. path → { plansDirs,
234
- // since, ended, last }. One is removed once the pump of the process that wrote
230
+ // since, before, ended, last }. One is removed once the pump of the process that wrote
235
231
  // it has settled (`ended`), and stays owed after that removal, whether it
236
232
  // removed the file or found none: the pump settles when the SDK's own cleanup
237
233
  // stops waiting for the process, which can be before the process is gone, and
@@ -348,15 +344,9 @@ export class ClaudeSession {
348
344
  this.lastPrompt = null;
349
345
  this.stallRetries = 0;
350
346
 
351
- // Native-runtime recovery latches. Set here and NOWHERE else — resetting
352
- // them on query recreation would turn a permanently broken binary into an
353
- // infinite repair/retry loop.
354
- this._nativeRepairTried = false;
355
- this._fallbackBin = null;
356
- // The installed CLI the current Query runs on because it is newer than the
357
- // bundled one (see ensureQuery). Per-Query, not a latch: a launch failure is
358
- // latched process-wide in claude-model-catalog.js instead.
359
- this._alignedBin = null;
347
+ // The Claude Code executable the current Query was started with (see
348
+ // ensureQuery): what a launch failure is diagnosed against.
349
+ this._claudeExecutable = null;
360
350
 
361
351
  this.pendingPerms = new Map(); // requestId → { toolName, resolve, input, kind, wire }
362
352
  this.alwaysAllowed = new Set();
@@ -499,6 +489,31 @@ export class ClaudeSession {
499
489
  return null;
500
490
  }
501
491
  }
492
+ // Which Claude Code runs this session: the user's own installation, always.
493
+ // SynaBun carries none (lib/external-tools.js at the package root) and the
494
+ // SDK is never left to look for one. The host answers (deps.claudeExecutable,
495
+ // lib/claude-executable.js): an explicit override from cli-config.json
496
+ // ("claude-skin": { "sdkExecutable": "…" }), else the installed Claude Code.
497
+ // The model picker lists that same installation's models, so an alias means
498
+ // in the session what it meant in the picker.
499
+ //
500
+ // Nothing installed is an ordinary state: the start is refused with the
501
+ // sentence the panel shows its install help on, and nothing was started.
502
+ // The SDK itself is never called without an executable; only a host that
503
+ // brings its own query factory and no resolver (a test) starts without one.
504
+ let executable = null;
505
+ if (typeof deps.claudeExecutable === 'function') {
506
+ try { executable = deps.claudeExecutable() || null; } catch { executable = null; }
507
+ } else if (deps.sdkExecutable) {
508
+ executable = resolveClaudeSdkExecutable({ sdkExecutable: deps.sdkExecutable });
509
+ }
510
+ const ownFactory = typeof (warm ? deps.startupFactory : deps.queryFactory) === 'function';
511
+ if (!executable?.path && (typeof deps.claudeExecutable === 'function' || !ownFactory)) {
512
+ this._closeWarm();
513
+ this._startRefused = { code: 'claude_not_installed', message: executable?.reason || CLAUDE_NOT_INSTALLED };
514
+ log(`session create refused: no Claude Code to run (${executable?.reason || 'not installed'})`);
515
+ return null;
516
+ }
502
517
  if (this._warm) {
503
518
  const w = this._warm;
504
519
  this._warm = null;
@@ -588,8 +603,9 @@ export class ClaudeSession {
588
603
  // `typesafe:'off'` on a query (the live skin test) keeps this CLI's hooks
589
604
  // from paying for judgments: they read the kill switch from their env.
590
605
  // (Panel sessions: the CLI reports running / idle / requires_action only when
591
- // asked to; `idle` is its own word that a turn is over. See _noteSessionState.)
592
- env: { ...cleanEnv(), ...(this.typesafeOff ? { SYNABUN_TYPESAFE: 'off' } : {}), ...(sessionOpts.env || {}), ...(accountEnv || {}), ...(this.panel ? { CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS: '1' } : {}) },
606
+ // asked to; `idle` is its own word that a turn is over. See _noteSessionState.
607
+ // SYNABUN_PANEL_SESSION tells the user-level SynaBun hooks that the panel greets here, not they.)
608
+ env: { ...cleanEnv(), ...(this.typesafeOff ? { SYNABUN_TYPESAFE: 'off' } : {}), ...(sessionOpts.env || {}), ...(accountEnv || {}), ...(this.panel ? { CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS: '1', SYNABUN_PANEL_SESSION: '1' } : {}) },
593
609
  abortController: this.abortController,
594
610
  stderr: (text) => {
595
611
  const t = String(text || '').trim();
@@ -629,6 +645,16 @@ export class ClaudeSession {
629
645
  // Resuming a session whose prompt cache has expired pays to write it
630
646
  // again: the CLI says how much at SessionStart.
631
647
  options.hooks = mergeHookMatchers(options.hooks, {
648
+ // The greeting SynaBun showed when this conversation opened (lib/greeting/): said to the
649
+ // model once, with the first prompt, as background. The model is never asked to greet.
650
+ UserPromptSubmit: [{
651
+ hooks: [async () => {
652
+ const note = gen === this._queryGen ? this._greetingNote : '';
653
+ if (!note) return {};
654
+ this._greetingNote = '';
655
+ return { hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: note } };
656
+ }],
657
+ }],
632
658
  SessionStart: [{
633
659
  hooks: [async (input) => {
634
660
  if (gen === this._queryGen && input?.prompt_cache_likely_expired === true && Number(input?.estimated_cache_write_usd) > 0) {
@@ -730,54 +756,26 @@ export class ClaudeSession {
730
756
  // (Which of the session's MCP connections is SynaBun's is asked of the live process when a tool of one is called.)
731
757
  applyTemporaryOptions(options, { mcpUrl: deps.mcpUrl || '', mcpStatus: () => this.q?.mcpServerStatus?.() });
732
758
  this._tempPlansDirs = plansDirsOf(options.env, { cwd: workDir, settings: options.settings });
733
- if (!this._tempSince) this._tempSince = Date.now();
734
- }
735
- // Which Claude binary runs this session, first match wins:
736
- // 1. an explicit override — cli-config.json → "claude-skin": { "sdkExecutable": "…" },
737
- // either a .js entrypoint (launched via node) or a native binary path;
738
- // 2. the installed CLI we fell back to after the bundled one failed to launch;
739
- // 3. the installed CLI when it is newer than the bundled one. The model picker
740
- // lists the installed CLI's models, and an older binary resolves the same
741
- // alias to an older model (alignedClaudeExecutable, claude-model-catalog.js);
742
- // 4. the SDK's bundled, version-matched CLI.
743
- //
744
- // The SDK uses pathToClaudeCodeExecutable verbatim with zero validation, so
745
- // everything is vetted here first — notably a bare command name, which would
746
- // ENOENT under the SDK's spawn(shell:false).
747
- const sdkExec = deps.sdkExecutable;
748
- const override = resolveClaudeExecutableOverride(sdkExec);
749
- this._alignedBin = null;
750
- let runtimeLabel = 'bundled';
751
- if (override.path) {
752
- options.pathToClaudeCodeExecutable = override.path;
753
- runtimeLabel = 'override';
754
- } else if (sdkExec) {
755
- log('ignoring sdkExecutable override:', override.reason);
756
- this.send({ type: 'stderr', text: `Ignoring sdkExecutable override — ${override.reason}` });
757
- }
758
-
759
- if (!options.pathToClaudeCodeExecutable) {
760
- let aligned = null;
761
- if (!this._fallbackBin) {
762
- try { aligned = deps.alignedClaudeBin?.() || null; } catch { aligned = null; }
763
- }
764
- if (this._fallbackBin) {
765
- // A previous turn proved the bundled binary unusable; stay on the CLI we
766
- // already fell back to rather than re-failing every turn.
767
- options.pathToClaudeCodeExecutable = this._fallbackBin;
768
- runtimeLabel = 'fallback';
769
- } else if (aligned) {
770
- options.pathToClaudeCodeExecutable = aligned;
771
- this._alignedBin = aligned;
772
- runtimeLabel = aligned;
773
- } else {
774
- // Called for its side effect only: this stats the binary the SDK is about
775
- // to resolve and restores the execute bit if it is missing. We
776
- // deliberately do NOT pass the resolved path on — letting the SDK resolve
777
- // for itself keeps us correct even if its resolution logic changes.
778
- claudeRuntime();
759
+ if (!this._tempSince) {
760
+ this._tempPlansBefore = snapshotPlanFiles(this._tempPlansDirs);
761
+ this._tempSince = Date.now();
779
762
  }
780
763
  }
764
+ // The executable resolved at the top of this call. The SDK uses
765
+ // pathToClaudeCodeExecutable verbatim with zero validation, so it was vetted
766
+ // there — notably a bare command name, which would ENOENT under the SDK's
767
+ // spawn(shell:false).
768
+ let runtimeLabel = 'unset';
769
+ this._claudeExecutable = null;
770
+ if (executable?.ignored) {
771
+ log('ignoring sdkExecutable override:', executable.ignored);
772
+ this.send({ type: 'stderr', text: `Ignoring sdkExecutable override — ${executable.ignored}` });
773
+ }
774
+ if (executable?.path) {
775
+ options.pathToClaudeCodeExecutable = executable.path;
776
+ this._claudeExecutable = executable.path;
777
+ runtimeLabel = executable.source === 'override' ? 'override' : executable.path;
778
+ }
781
779
 
782
780
  if (warm) {
783
781
  // Start the process now; hand it the input queue when the first prompt comes.
@@ -1096,7 +1094,7 @@ export class ClaudeSession {
1096
1094
  // stay owed and are swept once more when it can no longer be alive.
1097
1095
  _removeTemporaryPlans() {
1098
1096
  if (!this._tempPlans?.size) return;
1099
- const owed = { plansDirs: this._tempPlansDirs, since: this._tempSince, ended: false, last: false };
1097
+ const owed = { plansDirs: this._tempPlansDirs, since: this._tempSince, before: this._tempPlansBefore, ended: false, last: false };
1100
1098
  for (const path of this._tempPlans) _temporaryPlansOwed.set(path, owed);
1101
1099
  this._tempPlans.clear();
1102
1100
  Promise.resolve(this.pumpPromise).catch(() => {}).then(() => {
@@ -1115,6 +1113,7 @@ export class ClaudeSession {
1115
1113
  this._tempLive = false;
1116
1114
  this._tempOver = false;
1117
1115
  this._tempSince = 0;
1116
+ this._tempPlansBefore = null;
1118
1117
  }
1119
1118
 
1120
1119
  // Whether this message makes, keeps or may not make the conversation a
@@ -1256,94 +1255,18 @@ export class ClaudeSession {
1256
1255
  }
1257
1256
 
1258
1257
  /**
1259
- * The bundled native CLI failed to launch.
1258
+ * The user's Claude Code would not start.
1260
1259
  *
1261
1260
  * The SDK's own message for this always blames a musl/glibc mismatch, which is
1262
- * only ever right on Linux — on macOS and Windows the real cause is almost
1263
- * always a missing execute bit (npm does not preserve it for binaries shipped
1264
- * without a `bin` entry, and this repo commits node_modules).
1265
- *
1266
- * Recovery is: re-stat and repair → retry once → fall back to the user's
1267
- * installed CLI with a visible notice → give up with an accurate diagnosis.
1261
+ * only ever right on Linux — elsewhere the cause is a missing execute bit, a
1262
+ * quarantined download, a build for another processor or a file that is gone.
1263
+ * There is no other runtime to move to (SynaBun carries none), so the turn
1264
+ * ends with what is wrong with that installation and how to fix it.
1268
1265
  */
1269
1266
  _recoverNativeRuntime(err) {
1270
- const prompt = this.lastPrompt;
1271
- // The newer installed CLI this session was aligned to would not launch. Latch
1272
- // it off for the whole process and go back to the bundled runtime, which has
1273
- // its own repair path below if it fails too.
1274
- if (this._alignedBin) {
1275
- const failed = this._alignedBin;
1276
- this._alignedBin = null;
1277
- markAlignedClaudeExecutableFailed(failed);
1278
- log(`aligned CLI failed to launch (${failed}) — using the bundled runtime`);
1279
- this.sendEvent({
1280
- type: 'system',
1281
- subtype: 'runtime_notice',
1282
- level: 'warn',
1283
- message: `Your installed Claude CLI (${failed}) failed to launch; using the bundled runtime instead.`,
1284
- });
1285
- this._recreateQuery(prompt);
1286
- return;
1287
- }
1288
- // The cached verdict predates the failure; re-stat so a repair performed by
1289
- // another session (or the boot sweep) is visible.
1290
- clearNativeBinaryCache();
1291
- const runtime = claudeRuntime();
1292
-
1293
- let fallbackBin = this._fallbackBin;
1294
- if (!fallbackBin) {
1295
- // getClaudeBin()'s last resort is the bare string 'claude'. The SDK spawns
1296
- // with shell:false, so a bare name is a guaranteed ENOENT — the override
1297
- // validator rejects it, leaving fallbackBin null and giving the user a
1298
- // real diagnosis instead of a second, more confusing failure.
1299
- const candidate = resolveClaudeExecutableOverride(deps.getClaudeBin?.());
1300
- if (candidate.ok && candidate.path) fallbackBin = candidate.path;
1301
- }
1302
-
1303
- const plan = planRuntimeRecovery({
1304
- err,
1305
- runtime,
1306
- fallbackBin,
1307
- alreadyTried: this._nativeRepairTried,
1308
- });
1309
- log(`native runtime recovery: action=${plan.action} state=${runtime.state} kind=${plan.kind}`);
1310
-
1311
- if (plan.action === 'retry') {
1312
- this._nativeRepairTried = true;
1313
- this.sendEvent({ type: 'system', subtype: 'runtime_notice', level: 'warn', message: plan.message });
1314
- this._recreateQuery(prompt);
1315
- return;
1316
- }
1317
-
1318
- if (plan.action === 'fallback') {
1319
- this._fallbackBin = fallbackBin;
1320
- this.sendEvent({ type: 'system', subtype: 'runtime_notice', level: 'warn', message: plan.message });
1321
- // Report-only: the fallback CLI may be a different version than the SDK
1322
- // was built against, and alias ids like "opus[1m]" resolve per-binary — so
1323
- // a picked model can silently launch as another version.
1324
- this._announceSkew(fallbackBin);
1325
- this._recreateQuery(prompt);
1326
- return;
1327
- }
1328
-
1329
- this._finishTurnWithError(plan.message);
1330
- }
1331
-
1332
- _announceSkew(bin) {
1333
- Promise.resolve()
1334
- .then(() => checkClaudeCliSkew(bin, { log: () => {} }))
1335
- .then((skew) => {
1336
- if (!skew?.skewed || this.destroyed) return;
1337
- this.sendEvent({
1338
- type: 'system',
1339
- subtype: 'runtime_notice',
1340
- level: 'warn',
1341
- message: `Version skew: your installed Claude CLI is ${skew.discovered}, but the bundled `
1342
- + `runtime is ${skew.bundled}. Model aliases and effort levels resolve per-binary, so `
1343
- + 'behaviour may differ until the bundled binary is repaired.',
1344
- });
1345
- })
1346
- .catch(() => {});
1267
+ const dx = diagnoseLaunchFailure({ err, executable: this._claudeExecutable });
1268
+ log(`Claude Code failed to launch: kind=${dx.kind} executable=${this._claudeExecutable || 'unset'}`);
1269
+ this._finishTurnWithError(dx.message);
1347
1270
  }
1348
1271
 
1349
1272
  _pushUserText(text, images, { human = false } = {}) {
@@ -2222,7 +2145,7 @@ export class ClaudeSession {
2222
2145
  // AskUserQuestion answers arrive as updatedInput {questions, answers} from the
2223
2146
  // existing frontend card. The CLI's AskUserQuestion tool reads ONLY the
2224
2147
  // top-level `answers` map, looked up by each question's exact `question` text
2225
- // (verified against the bundled CLI: missing/empty map → "The user did not
2148
+ // (verified against the CLI itself: missing/empty map → "The user did not
2226
2149
  // answer the questions."). So: keep the original questions, pass the answers
2227
2150
  // map through, and re-key any answer the panel stored under a fallback key
2228
2151
  // (text/header) back onto the question text.
@@ -2904,6 +2827,17 @@ export class ClaudeSession {
2904
2827
  } catch {}
2905
2828
  }
2906
2829
 
2830
+ // The panel echoes the id of the greeting it showed when this conversation opened: the model is
2831
+ // told once, with this prompt (the UserPromptSubmit hook in _startQuery). A slash command takes none.
2832
+ // (A prompt the person typed in the panel is also them being here, whether or not the user-level hooks are installed.)
2833
+ if (this.panel && !warmOnly && msg.typed === true && typeof prompt === 'string' && prompt.trim() && typeof deps.greetingActivity === 'function') {
2834
+ try { deps.greetingActivity({ cwd: cwd || this.cwd || null, words: prompt, temporary: this.temporary === true }); } catch { /* the prompt goes on */ }
2835
+ }
2836
+ if (this.panel && !warmOnly && typeof msg.greetingId === 'string' && typeof deps.greetingNote === 'function') {
2837
+ try { this._greetingNote = String(deps.greetingNote(msg.greetingId, { skip: typeof prompt === 'string' && prompt.trimStart().startsWith('/') }) || ''); }
2838
+ catch { this._greetingNote = ''; }
2839
+ }
2840
+
2907
2841
  // SynaBun skill injection runs FIRST; unrecognized /commands pass through to the CLI
2908
2842
  if (prompt && prompt.startsWith('/')) {
2909
2843
  try {
@@ -0,0 +1,241 @@
1
+ // ── Which Claude Code runs: the user's own installation ──
2
+ //
3
+ // Claude Code is installed by the user, separately from SynaBun (the native
4
+ // installer, Homebrew, npm). Nothing in SynaBun carries a copy: the Claude
5
+ // Agent SDK is installed without the executable it would otherwise bring (see
6
+ // lib/external-tools.js at the package root), so every SDK call has to be told
7
+ // which executable to start. This module is where that answer comes from, for
8
+ // the side panel, the Assistant's Claude brain, native loops, session titles
9
+ // and the model probe alike:
10
+ //
11
+ // resolveClaudeLauncher what a terminal or a shell would start: the
12
+ // user's configured command, else the first
13
+ // `claude` on PATH that is not inside SynaBun
14
+ // resolveClaudeSdkExecutable what the SDK can start. It spawns with
15
+ // shell:false, so an npm command file on Windows
16
+ // is followed to the executable behind it
17
+ //
18
+ // A missing installation is an ordinary state, not a failure: both answer with
19
+ // `path: null` and the caller says CLAUDE_NOT_INSTALLED.
20
+ //
21
+ // Every dependency is injectable (platform, PATH, the file system), so Windows
22
+ // resolution is tested from any host. Nothing here throws.
23
+
24
+ import { accessSync, constants, existsSync, statSync } from 'node:fs';
25
+ import path from 'node:path';
26
+ import { getAugmentedPath } from './augmented-path.js';
27
+ import { resolveClaudeExecutableOverride } from './native-binary-runtime.js';
28
+
29
+ /**
30
+ * What a session says when no Claude Code is installed. The words "Claude CLI
31
+ * not found" are what the side panel shows its install help on.
32
+ */
33
+ export const CLAUDE_NOT_INSTALLED = 'Claude CLI not found. Claude Code is installed separately from SynaBun: install it, then send your message again.';
34
+
35
+ /** A real executable first, then the command files a shell can run. */
36
+ const WINDOWS_LAUNCHER_ORDER = ['.exe', '.cmd', '.bat', '.ps1'];
37
+
38
+ const pathFor = (platform) => (platform === 'win32' ? path.win32 : path.posix);
39
+
40
+ function unique(values, pathImpl, insensitive) {
41
+ const seen = new Set();
42
+ const out = [];
43
+ for (const value of values) {
44
+ const text = String(value || '').trim();
45
+ if (!text) continue;
46
+ const normal = pathImpl.normalize(text);
47
+ const key = insensitive ? normal.toLowerCase() : normal;
48
+ if (seen.has(key)) continue;
49
+ seen.add(key);
50
+ out.push(normal);
51
+ }
52
+ return out;
53
+ }
54
+
55
+ /**
56
+ * The launcher Windows should start, from a list in PATH order (as `where`
57
+ * prints it, or findOnPath below). PATH order decides between folders; inside
58
+ * one folder a real executable beats a command file, and npm's extensionless
59
+ * shell script (which Windows cannot start) is only ever the last resort.
60
+ */
61
+ export function selectWindowsLauncher(launchers = [], accept = () => true) {
62
+ const accepted = unique(launchers, path.win32, true).filter(accept);
63
+ const folders = new Map();
64
+ for (const launcher of accepted) {
65
+ const folder = path.win32.dirname(launcher).toLowerCase();
66
+ if (!folders.has(folder)) folders.set(folder, []);
67
+ folders.get(folder).push(launcher);
68
+ }
69
+ for (const group of folders.values()) {
70
+ for (const extension of WINDOWS_LAUNCHER_ORDER) {
71
+ const hit = group.find(launcher => launcher.toLowerCase().endsWith(extension));
72
+ if (hit) return hit;
73
+ }
74
+ }
75
+ return accepted[0] || null;
76
+ }
77
+
78
+ function defaultIsLaunchable(file, platform) {
79
+ try {
80
+ if (!statSync(file).isFile()) return false;
81
+ if (platform !== 'win32') accessSync(file, constants.X_OK);
82
+ return true;
83
+ } catch {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ /** PATH without any `node_modules/.bin` folder: a dependency's command is never the user's tool. */
89
+ export function withoutPackageBins(pathValue, platform = process.platform) {
90
+ const delimiter = platform === 'win32' ? ';' : ':';
91
+ return String(pathValue || '').split(delimiter)
92
+ .filter(entry => entry && !/[\\/]node_modules[\\/]\.bin[\\/]?$/i.test(entry))
93
+ .join(delimiter);
94
+ }
95
+
96
+ /**
97
+ * Every file a command name resolves to, in PATH order, read from the file
98
+ * system (no `which`, no shell: a folder with a space in its name is just a
99
+ * folder). On Windows each folder is tried with the launcher extensions, then
100
+ * bare.
101
+ */
102
+ export function findOnPath(command, {
103
+ platform = process.platform,
104
+ pathValue = getAugmentedPath(),
105
+ isLaunchable = defaultIsLaunchable,
106
+ } = {}) {
107
+ const name = String(command || '').trim();
108
+ if (!name) return [];
109
+ const pathImpl = pathFor(platform);
110
+ const windows = platform === 'win32';
111
+ const names = windows && !pathImpl.extname(name) ? [...WINDOWS_LAUNCHER_ORDER.map(extension => name + extension), name] : [name];
112
+ const found = [];
113
+ for (const folder of String(pathValue || '').split(windows ? ';' : ':')) {
114
+ if (!folder) continue;
115
+ for (const candidate of names) {
116
+ const file = pathImpl.join(folder, candidate);
117
+ if (isLaunchable(file, platform)) found.push(file);
118
+ }
119
+ }
120
+ return unique(found, pathImpl, windows);
121
+ }
122
+
123
+ /**
124
+ * The Claude Code a terminal would start.
125
+ *
126
+ * configured cli-config.json → "claude-code": { "command": "…" } (Settings > Terminal):
127
+ * a path is taken as it is, a name is looked up on PATH
128
+ * path the first `claude` on PATH
129
+ *
130
+ * Never a file inside SynaBun (`isInsideSynabun`) and never one from a
131
+ * `node_modules/.bin` folder on PATH: a copy that came with a dependency must
132
+ * not stand in for the user's own.
133
+ *
134
+ * @returns {{path: string|null, source: 'configured'|'path'|'missing', rejected: string[]}}
135
+ */
136
+ export function resolveClaudeLauncher({
137
+ configured = '',
138
+ platform = process.platform,
139
+ pathValue = getAugmentedPath(),
140
+ isInsideSynabun = () => false,
141
+ exists = existsSync,
142
+ isLaunchable = defaultIsLaunchable,
143
+ } = {}) {
144
+ const pathImpl = pathFor(platform);
145
+ const windows = platform === 'win32';
146
+ const rejected = [];
147
+ const outside = (file) => {
148
+ if (!isInsideSynabun(file)) return true;
149
+ rejected.push(file);
150
+ return false;
151
+ };
152
+ const lookup = (command) => {
153
+ const hits = findOnPath(command, { platform, pathValue: withoutPackageBins(pathValue, platform), isLaunchable }).filter(outside);
154
+ return (windows ? selectWindowsLauncher(hits) : hits[0]) || null;
155
+ };
156
+
157
+ const wanted = String(configured || '').trim();
158
+ if (wanted && wanted !== 'claude') {
159
+ const isPath = wanted.includes('/') || (windows && wanted.includes('\\'));
160
+ if (isPath) {
161
+ if (exists(wanted) && outside(wanted)) return { path: pathImpl.normalize(wanted), source: 'configured', rejected };
162
+ } else {
163
+ const hit = lookup(wanted);
164
+ if (hit) return { path: hit, source: 'configured', rejected };
165
+ }
166
+ }
167
+
168
+ const hit = lookup('claude');
169
+ return hit ? { path: hit, source: 'path', rejected } : { path: null, source: 'missing', rejected };
170
+ }
171
+
172
+ /**
173
+ * Where the executable behind an npm command file is, most likely first. npm
174
+ * puts `claude.cmd` next to `node_modules\@anthropic-ai\claude-code`, whose
175
+ * `bin\claude.exe` is the program (older releases: `cli.js`, run by Node). A
176
+ * `.bin` folder has the package one level up instead.
177
+ */
178
+ export function windowsClaudeTargets(launcher) {
179
+ const pathImpl = path.win32;
180
+ const folder = pathImpl.dirname(String(launcher || ''));
181
+ const roots = [pathImpl.join(folder, 'node_modules')];
182
+ if (pathImpl.basename(folder).toLowerCase() === '.bin') roots.push(pathImpl.dirname(folder));
183
+ return roots.flatMap((root) => {
184
+ const packageDir = pathImpl.join(root, '@anthropic-ai', 'claude-code');
185
+ return [pathImpl.join(packageDir, 'bin', 'claude.exe'), pathImpl.join(packageDir, 'cli.js')];
186
+ });
187
+ }
188
+
189
+ /**
190
+ * The executable an Agent SDK call is given as `pathToClaudeCodeExecutable`.
191
+ *
192
+ * override cli-config.json → "claude-skin": { "sdkExecutable": "…" }, when it is usable
193
+ * installed the user's Claude Code (`launcher`, from resolveClaudeLauncher)
194
+ *
195
+ * The SDK starts this path itself, without a shell, so it has to be a program
196
+ * or a script: on Windows a `.cmd`, `.bat` or `.ps1` launcher is followed to
197
+ * what it runs. `path: null` means there is nothing to start; `reason` says
198
+ * why in a sentence a person can act on, `ignored` why an override was passed
199
+ * over.
200
+ *
201
+ * @returns {{path: string|null, source: 'override'|'installed'|'missing', kind: string|null, reason: string|null, ignored: string|null, launcher: string|null}}
202
+ */
203
+ export function resolveClaudeSdkExecutable({
204
+ launcher = null,
205
+ sdkExecutable = null,
206
+ platform = process.platform,
207
+ exists = existsSync,
208
+ isInsideSynabun = () => false,
209
+ validate = resolveClaudeExecutableOverride,
210
+ } = {}) {
211
+ const answer = (fields) => ({ path: null, source: 'missing', kind: null, reason: null, ignored: null, launcher: launcher || null, ...fields });
212
+ let ignored = null;
213
+
214
+ const explicit = typeof sdkExecutable === 'string' ? sdkExecutable.trim() : '';
215
+ if (explicit) {
216
+ const verdict = validate(explicit, { platform });
217
+ if (verdict.ok && verdict.path) return answer({ path: verdict.path, source: 'override', kind: verdict.kind });
218
+ ignored = verdict.reason || `Not usable: ${explicit}`;
219
+ }
220
+
221
+ const installed = typeof launcher === 'string' ? launcher.trim() : '';
222
+ // A bare name is what "nothing was found" looks like to older callers.
223
+ if (!installed || !(installed.includes('/') || installed.includes('\\'))) return answer({ reason: CLAUDE_NOT_INSTALLED, ignored });
224
+
225
+ const candidates = platform === 'win32' && !/\.exe$/i.test(installed) && !/\.[cm]?js$/i.test(installed)
226
+ ? windowsClaudeTargets(installed).filter(file => exists(file))
227
+ : [installed];
228
+ let refusal = null;
229
+ for (const candidate of candidates) {
230
+ if (isInsideSynabun(candidate)) { refusal = `${candidate} is inside SynaBun, not an installation of Claude Code`; continue; }
231
+ const verdict = validate(candidate, { platform });
232
+ if (verdict.ok && verdict.path) return answer({ path: verdict.path, source: 'installed', kind: verdict.kind, ignored });
233
+ refusal = verdict.reason || `Not usable: ${candidate}`;
234
+ }
235
+ return answer({
236
+ reason: refusal
237
+ ? `Claude Code was found at ${installed}, but it cannot be started from there: ${refusal}.`
238
+ : `Claude Code was found at ${installed}, but not the program that command runs. Reinstall Claude Code, or name its executable in cli-config.json ("claude-skin": { "sdkExecutable": "…" }).`,
239
+ ignored,
240
+ });
241
+ }