synabun 2.0.0 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +46 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +2 -2
  8. package/hooks/claude-code/pre-compact.mjs +11 -0
  9. package/hooks/claude-code/prompt-submit.mjs +60 -184
  10. package/hooks/claude-code/session-start.mjs +73 -16
  11. package/hooks/claude-code/shared.mjs +20 -0
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/lib/start-launcher.js +88 -1
  14. package/mcp-server/package-lock.json +2 -2
  15. package/mcp-server/package.json +1 -3
  16. package/neural-interface/i18n/en.json +1500 -153
  17. package/neural-interface/i18n/pt-BR.json +1498 -152
  18. package/neural-interface/lib/assistant-api.js +62 -6
  19. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  20. package/neural-interface/lib/assistant-catalog.js +179 -27
  21. package/neural-interface/lib/assistant-config.js +31 -2
  22. package/neural-interface/lib/assistant-dispatch.js +62 -13
  23. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  24. package/neural-interface/lib/assistant-memory.js +24 -10
  25. package/neural-interface/lib/assistant-persona.js +6 -2
  26. package/neural-interface/lib/assistant-pricing.js +21 -6
  27. package/neural-interface/lib/assistant-runtime.js +181 -12
  28. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  29. package/neural-interface/lib/assistant-test-density.js +142 -0
  30. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  31. package/neural-interface/lib/assistant-user-context.js +908 -0
  32. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  33. package/neural-interface/lib/assistant-user-learn.js +404 -0
  34. package/neural-interface/lib/assistant-user-threads.js +226 -0
  35. package/neural-interface/lib/assistant-user-writer.js +181 -0
  36. package/neural-interface/lib/browser-background-tab.js +134 -0
  37. package/neural-interface/lib/browser-screenshot.js +678 -61
  38. package/neural-interface/lib/claude-agent-bridge.js +33 -6
  39. package/neural-interface/lib/claude-model-catalog.js +30 -2
  40. package/neural-interface/lib/claude-temporary.js +46 -7
  41. package/neural-interface/lib/cloudflared/install.js +533 -0
  42. package/neural-interface/lib/cloudflared/manager.js +545 -0
  43. package/neural-interface/lib/cloudflared/pins.js +115 -0
  44. package/neural-interface/lib/cloudflared/pins.json +63 -0
  45. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  46. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  47. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  48. package/neural-interface/lib/editor-completion.js +714 -0
  49. package/neural-interface/lib/editor-config.js +149 -0
  50. package/neural-interface/lib/editor-files-api.js +268 -0
  51. package/neural-interface/lib/editor-git-api.js +134 -0
  52. package/neural-interface/lib/file-explorer-api.js +1039 -0
  53. package/neural-interface/lib/file-explorer-system.js +355 -0
  54. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  55. package/neural-interface/lib/file-explorer-watch.js +239 -0
  56. package/neural-interface/lib/git-diff-api.js +103 -0
  57. package/neural-interface/lib/git-read.js +202 -0
  58. package/neural-interface/lib/greeting/api.js +89 -0
  59. package/neural-interface/lib/greeting/budgets.js +90 -0
  60. package/neural-interface/lib/greeting/engine.js +461 -0
  61. package/neural-interface/lib/greeting/facts.js +320 -0
  62. package/neural-interface/lib/greeting/sources.js +252 -0
  63. package/neural-interface/lib/greeting/writer.js +139 -0
  64. package/neural-interface/lib/http-guards.js +189 -13
  65. package/neural-interface/lib/machine-names.js +88 -0
  66. package/neural-interface/lib/memory-api.js +31 -7
  67. package/neural-interface/lib/native-loop-providers.js +10 -5
  68. package/neural-interface/lib/plugin-installer.js +4 -2
  69. package/neural-interface/lib/project-storage.js +5 -7
  70. package/neural-interface/lib/request-gate.js +589 -0
  71. package/neural-interface/lib/ui-blob-api.js +108 -0
  72. package/neural-interface/lib/ui-blob-store.js +68 -0
  73. package/neural-interface/package-lock.json +701 -2
  74. package/neural-interface/package.json +13 -2
  75. package/neural-interface/public/install-app.html +9 -6
  76. package/neural-interface/public/offline.html +3 -2
  77. package/neural-interface/public/onboarding.html +12 -1
  78. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  79. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  80. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  81. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  82. package/neural-interface/public/shared/assistant/asst-mascot.js +18 -58
  83. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  84. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  85. package/neural-interface/public/shared/assistant/asst-render.js +162 -19
  86. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  87. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  88. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  89. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  90. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  91. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  92. package/neural-interface/public/shared/assistant/asst-styles.js +158 -4
  93. package/neural-interface/public/shared/blob-store.js +111 -22
  94. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  95. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  96. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  97. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  98. package/neural-interface/public/shared/constants.js +6 -1
  99. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  100. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  101. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  102. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  103. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  104. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  105. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  106. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  107. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  108. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  109. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  110. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  111. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  112. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  113. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  114. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  115. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  116. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  117. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  118. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  119. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  120. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  121. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  122. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  123. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  124. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  125. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  126. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  127. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  128. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  129. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  130. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  131. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  132. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  133. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  134. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  135. package/neural-interface/public/shared/file-links.js +339 -0
  136. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  137. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  138. package/neural-interface/public/shared/html-shell.js +160 -165
  139. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  140. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  141. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  142. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  143. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  144. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  145. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  146. package/neural-interface/public/shared/pwa-install-page.js +29 -1
  147. package/neural-interface/public/shared/pwa-install.css +3 -3
  148. package/neural-interface/public/shared/pwa-install.js +100 -1
  149. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  150. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  151. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  152. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  153. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  154. package/neural-interface/public/shared/start-bridge.js +238 -19
  155. package/neural-interface/public/shared/styles.css +1414 -721
  156. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  157. package/neural-interface/public/shared/tunnel-view.js +167 -0
  158. package/neural-interface/public/shared/ui-claude-panel.js +157 -16
  159. package/neural-interface/public/shared/ui-detail.js +15 -0
  160. package/neural-interface/public/shared/ui-explorer.js +22 -0
  161. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  162. package/neural-interface/public/shared/ui-file-links.js +103 -0
  163. package/neural-interface/public/shared/ui-help.js +26 -0
  164. package/neural-interface/public/shared/ui-invite.js +126 -116
  165. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  166. package/neural-interface/public/shared/ui-loading.js +159 -15
  167. package/neural-interface/public/shared/ui-menubar.js +12 -30
  168. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  169. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  170. package/neural-interface/public/shared/ui-navbar.js +45 -21
  171. package/neural-interface/public/shared/ui-settings.js +455 -488
  172. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  173. package/neural-interface/public/shared/ui-sync.js +16 -0
  174. package/neural-interface/public/shared/ui-terminal.js +23 -5
  175. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  176. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  177. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  178. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  179. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  180. package/neural-interface/public/shared/worker-end.js +251 -0
  181. package/neural-interface/public/sw.js +2 -2
  182. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  183. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  184. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  185. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  186. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  187. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  188. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  189. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  190. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  191. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  192. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  193. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  194. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  195. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  196. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  197. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  198. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  199. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  200. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  201. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  202. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  203. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  204. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  205. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  206. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  207. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  208. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  209. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  210. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  211. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  212. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  309. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  310. package/neural-interface/scripts/build-vendor.mjs +78 -2
  311. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  312. package/neural-interface/server.js +873 -1028
  313. package/neural-interface/templates/rulesets/README.md +1 -1
  314. package/package.json +2 -8
  315. package/setup.js +44 -7
  316. package/benchmarks/browser-live-results.json +0 -79
  317. package/benchmarks/browser-v2-results.json +0 -258
  318. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  319. package/neural-interface/public/category-logos/claude.svg +0 -1
  320. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  321. package/neural-interface/public/category-logos/openai.svg +0 -1
  322. package/neural-interface/public/category-logos/synabun.png +0 -0
  323. package/neural-interface/public/claude.svg +0 -1
  324. package/neural-interface/public/gallery.svg +0 -6
  325. package/neural-interface/public/leonardoai.svg +0 -1
  326. package/neural-interface/public/mcp.svg +0 -4
  327. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  328. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  329. package/neural-interface/public/sessionicon.svg +0 -8
  330. package/neural-interface/public/toolbar-album.svg +0 -8
  331. package/neural-interface/public/toolbar-question.svg +0 -6
  332. package/neural-interface/public/toolbar-sessions.svg +0 -6
  333. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  334. package/skills/synabun/synabunicon.png +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,60 @@
1
+ # SynaBun v.2.0.5
2
+
3
+ 2.0.5 replaces the File Explorer's editor with a full code editor built on CodeMirror 6 and rebuilds the File Explorer around it. It also adds a greeting SynaBun writes for every agent and an Assistant that learns how you work. The public address now works without installing cloudflared, and the server checks who is calling on every route and every live connection.
4
+
5
+ ## ✨ New
6
+
7
+ - **Code editor on CodeMirror 6** — The editor that opens from the File Explorer is rebuilt and ships with SynaBun. Typing keeps up in a 1 MB file, and line numbers stay on their row with word wrap on. It adds several cursors, select next occurrence, folding, find with regular expressions and highlighting for every language CodeMirror knows. Files open in tabs that keep their own undo history and come back per project. Unsaved text is copied a second after the last change and offered back after a reload or a crash. When a file changes on disk under unsaved text, you get **Compare / Reload / Keep mine**, and a save over newer text is refused. Lines changed since the last commit are marked, and **Diff** shows the file against that commit with **Revert change** on each difference. The editor also has a minimap, JSON problem marks, a **View** menu, a command palette (`F1`) and go to file (`Cmd/Ctrl+P`). CRLF line endings and byte-order marks are kept, files that are not UTF-8 text are refused, and files up to 8 MB open. Preferences are in **Settings → Code editor → Editing**. `Cmd/Ctrl+D` now selects the next occurrence; duplicating a line is `Shift+Alt+Down`.
8
+ - **AI autocomplete in the code editor** — Grey text appears after the caret when you pause; `Tab` accepts it and `Esc` dismisses it. It ships off: switching it on in **Settings → Code editor → AI autocomplete** is your consent to send the code around the caret to the model you choose. Files on the editable **Never sent** list (`.env`, keys, certificates) and text that holds a private key are never sent. Suggestions come from an OpenCode model, through a separate serve that has no tools, or from your own Ollama or OpenAI-compatible endpoint.
9
+ - **File Explorer rebuilt** — The tree follows the disk: what an agent creates, changes or deletes shows within a second or two. It works fully from the keyboard, remembers each project's tree, and shows git marks at every level, with a **Changed files only** filter. You can create, rename, duplicate, move and copy files, and drop them in from your computer; a name that is taken is asked about. **Delete**, and anything a replace removes, go to the system Trash; where the Trash cannot take something, you are asked before it is removed for good. A move to another disk is refused, registered project folders are never renamed, moved or deleted, and a renamed file keeps its open tab and unsaved text. **Send to…** hands files to Claude Code, Codex, OpenCode or the Assistant. A click on a file opens its menu, as before; a double-click opens the file.
10
+ - **File links open in the code editor** — In the Assistant, Claude Code, Codex and OpenCode panels, a link to a text file opens it in the code editor at its line and column (`:12:3`, `#L12`). If the editor cannot open a path, a toast says why.
11
+ - **A greeting written by SynaBun, for every agent** — When you come back to a project after an hour away, a fresh session opens with a sentence or two: what you were doing, what was left open, and what finished or failed meanwhile. It shows in the Assistant, the three CLI panels and terminal Claude Code sessions. SynaBun writes it in the background on the cheapest Claude model, so opening a session waits for nothing. **Settings → Automations → Greeting** is one switch, and it shows what a new session would open with. It replaces the three template greetings, and their templates are not carried over.
12
+ - **The Assistant gets to know you** — **Settings → Automations → Automation behavior** has three switches. **Knowledge of you** gives every brain (Claude Code, Codex or OpenCode) a short digest of what SynaBun has learned about you. **Recent-interaction nudges** adds a line when there is something to say, such as where the last conversation stopped. **Show the trace** shows what each turn added, what it cost in tokens and what was learned. Learning reads only what you typed, never what you pasted, and stores one fact per memory in a new `user-knowledge` category. Learning needs AI decisions (a TypeSafe key).
13
+ - **cloudflared comes with SynaBun** — **Start tunnel** now works without installing anything. The installers carry cloudflared. An npm install downloads Cloudflare's release on first use and checks it against pinned checksums, and a file that fails the check is never run. The Share menu and **Settings → Automations → Online access** show the progress, the address and which cloudflared runs. A failure comes with **Try again**. A cloudflared on your PATH is used only when a download is not possible.
14
+
15
+ ## 🛠 Fixed
16
+
17
+ - **A dispatched worker's tab ended on an error line, or on nothing** — Each worker tab now ends with one card: **Task complete** with the result, time and cost, or **Blocked**, **Needs input**, **Task failed** or **Stopped** with the reason. **Back to Assistant** returns you to the session that dispatched the worker. Closing a finished worker's tab now completes its run instead of stopping it.
18
+ - **Restart Server looked like a hang** — **Apps → Restart Server** now shows the restart screen at once and lists each step until the app reloads; other open windows follow. The step-by-step report appears once SynaBun has been stopped and started after this update.
19
+ - **Renamed Assistant sessions were listed under their first prompt** — They are now listed and reopened under their new name, also by `/resume`.
20
+ - **Only one open Assistant session animated** — Every session's mascot now moves at the same time.
21
+ - **Model lists missed models the panels offered** — Model routes and the Assistant's model menu now follow each provider's own list, minus the models you hid, and update without a reload.
22
+ - **A hidden alias hid whatever model it later named** — Hiding `haiku` also hid the newer model once Claude Code moved the alias to it. A hidden alias now hides the model it named when you hid it.
23
+ - **Invite guests could reach some routes meant only for you** — Admin-only areas, MCP server credentials, skill installs and the git routes are now closed to guests, however the address is written. A visitor through a custom invite address needs an invite session. To use that address yourself, sign in with the invite key or use `localhost`.
24
+ - **Reading a repository could start its programs** — Git reads no longer start programs named in a repository's own configuration, such as a file-system monitor, hooks or an external diff tool. A commit still runs its hooks.
25
+ - **Smaller fixes** — A cookie with a stray `%` from another app on `localhost` no longer breaks every request. Memory chips in the Assistant panel open their memory. Deleting an empty folder in the File Explorer works.
26
+
27
+ ## ⚙️ Changed
28
+
29
+ - **The server checks who is calling** — Everything under `/api`, the MCP endpoint and every live connection now answer only requests addressed to this server. That means `localhost`, an IP address, this computer's own names (its `.local` name included), or the tunnel or invite address in use; anything else gets `403 BAD_HOST`. If you reach SynaBun under another name (a `.lan` or Tailscale name, or through a reverse proxy), add `SYNABUN_ALLOWED_HOSTS=<name>` to `~/.synabun/.env`. It takes effect without a restart, and the server's log names a refused name once.
30
+ - **Remote MCP needs its access key** — From the tunnel, a custom invite address or another machine on your network, the MCP endpoint answers only at `/mcp/<access key>`. While no key is set, it does not answer them at all. On this computer `/mcp` works as before. Only SynaBun's own pages on this computer can start or stop the tunnel.
31
+ - **Workspace toolbar** — The top-right toolbar is one compact row: the workspace switcher first, then the tools, a **»** toggle that shows or hides them, and the side-panel buttons. **Hide all toolbars** is gone. Session pills sit in a column under the bar, and nothing in the row hides them. **Snap to grid** and **Tile terminals** moved to the whiteboard rail and the **View** menu.
32
+ - **Model routes explains each mode** — **When to ask** is a radio group. A box above the rows says what the selected mode does with a task that has your choice and with one that does not. Routing itself is unchanged.
33
+
34
+ ---
35
+
36
+ # SynaBun v.2.0.4
37
+
38
+ 2.0.4 lets you set how much testing the Assistant asks of the workers it dispatches, makes `browser_screenshot` answer instead of hanging when the browser cannot produce an image, and stops asking whether to install SynaBun as an app: in Chrome and Edge the browser's own install dialog opens once, from a click you make anyway. It is the first release since 2.0.0.
39
+
40
+ ## ✨ New
41
+
42
+ - **Test density for the Assistant** — A three-bar gauge next to the permission mode in the Assistant's composer sets how much testing dispatched workers are asked to do. **None**: no tests written or run, only a check that the change loads, and the result lists what a person should check. **Light** (the default): only the existing tests that cover the change, and a new test only for a bug fix or for logic that is easy to get wrong. **Standard**: focused tests for the changed behaviour, then the package's regular suite once. **Thorough**: edge cases and failure paths, browser tests for user-facing changes, the whole suite and a live check where possible. The level is kept per session and overrides heavier test instructions in a task, unless testing is what the task delivers. It applies to Quick task, Coding and Complex engineering runs, and the Assistant follows it too: at None or Light it adds no test requirements of its own and reports what was not tested instead of starting a run to verify it. Conversations from WhatsApp run at Light.
43
+ - **Automation tabs can open behind your work** — With `"openTabsInBackground": true` in `browser-config.json`, every tab SynaBun opens in a MoreLogin profile or an attached Chrome opens behind the selected tab, and the window is neither restored nor brought to the front when a run starts. Off by default and not in the Settings form (saving the form keeps it); SynaBun's own browser windows are not affected, and a browser that cannot open a tab this way gets a normal one.
44
+
45
+ ## 🛠 Fixed
46
+
47
+ - **`browser_screenshot` could hang until the caller timed out** — The selected tab of a minimized window, or of a hidden application, does not answer a screenshot command; the tool waited out the whole request and returned a bare timeout, and a capture with a custom size could leave the tab at the capture's size. A capture with no answer in 8 seconds (1.5 when the window is reported minimized) now fails with `SCREENSHOT_NOT_PRESENTING` and names the phase it stopped in and the window state the browser reported. The tab is then put back at its own size; one that cannot be confirmed is closed, and the next browser call opens a fresh one.
48
+ - **Closing tabs could leave a browser session pointing at a closed page** — When the tab chosen to take over was itself closed while the switch was under way, the session kept a page that no longer existed. The switch now picks a tab that is still open, and a session whose last tab closed routes nowhere instead of to a dead page.
49
+
50
+ ## ⚙️ Changed
51
+
52
+ - **SynaBun no longer asks about installing as an app** — In Chrome and Edge, the page the desktop launcher opened, with its **Install as App** button and **Continue to SynaBun** link, no longer stops you: the browser's own install dialog opens once instead, from a press you make anyway. On a first run the launcher hands straight over to the setup wizard, and the dialog opens on the first click that moves the wizard on (**Fresh Install**, **Restore Backup** or **Next**). Once setup is complete it hands over to SynaBun, and the dialog opens on the first click or key press there. Accepted, dismissed or never offered, SynaBun goes on the same way.
53
+ - **The dialog opens once** — The wizard never opens it a second time, and after setup only the page load the launcher handed over opens it: a reload does not, and SynaBun in a normal browser tab never does. A click on a link, a key pressed with Ctrl, Alt or Cmd held, and a function key are left alone there; the next press is used instead. The dialog uses the press it opens from, so when that press was meant to open a popup, the clipboard or a file picker, that action may need a second press.
54
+ - **Apps → Install as App, Safari and other browsers** — The menu item is unchanged while the browser has a dialog ready. Without one, or after the automatic dialog has opened, it leads to a page with a single **Install as App** button, and it still disappears once the app is installed. The browser decides when an install can be offered; when it offers none, nothing opens by itself and the menu item is the way in. Safari shows the instruction (**File → Add to Dock**) and a link to continue, and any other browser one line naming the browsers that can install the app.
55
+
56
+ ---
57
+
1
58
  # SynaBun v.2.0.0
2
59
 
3
60
  SynaBun 2.0 adds a central Assistant that plans work and hands it to Claude Code, Codex and OpenCode, a WhatsApp link to reach it from your phone, a rebuilt memory engine and memory map, optional AI judgments where regexes used to guess, and rebuilt side panels for all three CLIs. It is also the first release on plain semantic versioning.
package/NOTICE CHANGED
@@ -12,6 +12,11 @@ licensed under the Apache License 2.0:
12
12
  Copyright 2012-2024 Microsoft Corporation
13
13
  https://github.com/microsoft/TypeScript
14
14
 
15
+ - cloudflared (Cloudflare's own release binary, unmodified: inside the
16
+ application installers; downloaded on first use by an npm install)
17
+ Copyright (c) Cloudflare, Inc.
18
+ https://github.com/cloudflare/cloudflared
19
+
15
20
  This product also includes software licensed under the MIT License
16
21
  and BSD-2-Clause License. See THIRD-PARTY-LICENSES.md for a complete
17
22
  listing of all third-party software and their respective licenses.
package/README.md CHANGED
@@ -158,7 +158,7 @@ Everything SynaBun stores is in one folder outside the app: `~/.synabun` on macO
158
158
 
159
159
  ## Links
160
160
 
161
- - [Changelog](./CHANGELOG.md): what is new in 2.0.0 and before
161
+ - [Changelog](./CHANGELOG.md): what is new in 2.0.5 and before
162
162
  - [Security](./SECURITY.md): security model and how to report a vulnerability
163
163
  - [Contributing](./CONTRIBUTING.md): bug reports and feature requests are welcome as [issues](https://github.com/danilokhury/Synabun/issues); pull requests are not accepted
164
164
  - [Website](https://synabun.ai), [docs](https://synabun.ai/docs) and [blog](https://synabun.ai/blog)
@@ -65,6 +65,18 @@ runtime dependencies in the published package.
65
65
 
66
66
  | Package | Manifest range | Locked version | Declared license | Project |
67
67
  | --- | --- | --- | --- | --- |
68
+ | `@codemirror/autocomplete` | `6.20.3` | 6.20.3 | MIT | [npm](https://www.npmjs.com/package/@codemirror/autocomplete) |
69
+ | `@codemirror/commands` | `6.11.1` | 6.11.1 | MIT | [npm](https://www.npmjs.com/package/@codemirror/commands) |
70
+ | `@codemirror/language` | `6.13.1` | 6.13.1 | MIT | [npm](https://www.npmjs.com/package/@codemirror/language) |
71
+ | `@codemirror/language-data` | `6.5.2` | 6.5.2 | MIT | [npm](https://www.npmjs.com/package/@codemirror/language-data) |
72
+ | `@codemirror/legacy-modes` | `6.5.5` | 6.5.5 | MIT | [npm](https://www.npmjs.com/package/@codemirror/legacy-modes) |
73
+ | `@codemirror/lint` | `6.9.7` | 6.9.7 | MIT | [npm](https://www.npmjs.com/package/@codemirror/lint) |
74
+ | `@codemirror/merge` | `6.12.2` | 6.12.2 | MIT | [npm](https://www.npmjs.com/package/@codemirror/merge) |
75
+ | `@codemirror/search` | `6.7.2` | 6.7.2 | MIT | [npm](https://www.npmjs.com/package/@codemirror/search) |
76
+ | `@codemirror/state` | `6.7.6` | 6.7.6 | MIT | [npm](https://www.npmjs.com/package/@codemirror/state) |
77
+ | `@codemirror/view` | `6.43.14` | 6.43.14 | MIT | [npm](https://www.npmjs.com/package/@codemirror/view) |
78
+ | `@lezer/highlight` | `1.2.5` | 1.2.5 | MIT | [npm](https://www.npmjs.com/package/@lezer/highlight) |
79
+ | `@replit/codemirror-indentation-markers` | `6.5.3` | 6.5.3 | MIT | [npm](https://www.npmjs.com/package/@replit/codemirror-indentation-markers) |
68
80
  | `esbuild` | `^0.28.1` | 0.28.1 | MIT | [npm](https://www.npmjs.com/package/esbuild) |
69
81
  | `three` | `0.169.0` | 0.169.0 | MIT | [npm](https://www.npmjs.com/package/three) |
70
82
 
@@ -79,6 +91,29 @@ runtime dependencies in the published package.
79
91
  | Mermaid | 11.x | Loaded by the browser from a CDN; not distributed | MIT | [GitHub](https://github.com/mermaid-js/mermaid) |
80
92
  | html2canvas | 1.4.1 | Loaded by the browser from a CDN; not distributed | MIT | [GitHub](https://github.com/niklasvh/html2canvas) |
81
93
 
94
+ ### CodeMirror 6
95
+
96
+ The File Explorer's code editor. Bundled by `neural-interface/scripts/build-vendor.mjs` into `neural-interface/public/vendor/codemirror/`; its `manifest.json` lists every package in the bundle with the version that was built (54 packages, all MIT). The ones SynaBun depends on directly:
97
+
98
+ - **@codemirror/state** 6.7.6, **@codemirror/view** 6.43.14, **@codemirror/language** 6.13.1, **@codemirror/commands** 6.11.1, **@codemirror/search** 6.7.2, **@codemirror/autocomplete** 6.20.3, **@codemirror/lint** 6.9.7, **@codemirror/merge** 6.12.2, **@codemirror/language-data** 6.5.2, **@codemirror/legacy-modes** 6.5.5
99
+ - **License:** MIT
100
+ - **Copyright:** Copyright (C) 2018-2021 by Marijn Haverbeke and others
101
+ - **URL:** https://codemirror.net/ (source: https://github.com/codemirror)
102
+ - **@lezer/highlight** 1.2.5
103
+ - **License:** MIT
104
+ - **Copyright:** Copyright (C) 2018 by Marijn Haverbeke and others
105
+ - **URL:** https://lezer.codemirror.net/ (source: https://github.com/lezer-parser)
106
+ - **@replit/codemirror-indentation-markers** 6.5.3
107
+ - **License:** MIT
108
+ - **Copyright:** Copyright (c) 2022 Replit
109
+ - **URL:** https://github.com/replit/codemirror-indentation-markers
110
+
111
+ Brought in by those, and in the bundle too (MIT, Copyright (C) Marijn Haverbeke and others):
112
+
113
+ - the languages `@codemirror/language-data` loads on demand: `@codemirror/lang-angular`, `@codemirror/lang-cpp`, `@codemirror/lang-css`, `@codemirror/lang-go`, `@codemirror/lang-html`, `@codemirror/lang-java`, `@codemirror/lang-javascript`, `@codemirror/lang-jinja`, `@codemirror/lang-json`, `@codemirror/lang-less`, `@codemirror/lang-liquid`, `@codemirror/lang-markdown`, `@codemirror/lang-php`, `@codemirror/lang-python`, `@codemirror/lang-rust`, `@codemirror/lang-sass`, `@codemirror/lang-sql`, `@codemirror/lang-vue`, `@codemirror/lang-wast`, `@codemirror/lang-xml`, `@codemirror/lang-yaml`, and `@codemirror/streamparser`
114
+ - the Lezer parser runtime and grammars: `@lezer/common`, `@lezer/lr`, `@lezer/cpp`, `@lezer/css`, `@lezer/go`, `@lezer/html`, `@lezer/java`, `@lezer/javascript`, `@lezer/json`, `@lezer/markdown`, `@lezer/php`, `@lezer/python`, `@lezer/rust`, `@lezer/sass`, `@lezer/xml`, `@lezer/yaml`
115
+ - `style-mod`, `w3c-keyname`, `crelt` and `@marijn/find-cluster-break`
116
+
82
117
  ## Vendored Code
83
118
 
84
119
  | Component | Location | License | Project |
@@ -92,6 +127,17 @@ The QR Code generator is transpiled to JavaScript from
92
127
  its license header kept. It draws the WhatsApp Link QR codes as SVG on the
93
128
  computer, so no QR payload leaves SynaBun.
94
129
 
130
+ ## Bundled Programs
131
+
132
+ | Program | Version | Delivery | License | Project |
133
+ | --- | --- | --- | --- | --- |
134
+ | cloudflared | 2026.10.0 (pinned in `neural-interface/lib/cloudflared/pins.json` with the SHA-256 of each release file and of the binary inside it) | Cloudflare's own release binary, unmodified. The application installers carry it; an npm or Git install downloads the same release file from Cloudflare's GitHub releases the first time a tunnel is started and checks it against the pinned SHA-256 before it runs | Apache-2.0 | [GitHub](https://github.com/cloudflare/cloudflared) |
135
+
136
+ cloudflared opens the Cloudflare quick tunnel behind the public address
137
+ (invite links and remote MCP). It runs as a separate process, started only
138
+ when the user starts a tunnel. Using cloudflared and the tunnel service is
139
+ subject to Cloudflare's own terms.
140
+
95
141
  ## Installed On Demand (Not Distributed)
96
142
 
97
143
  The WhatsApp Link's connector is not part of SynaBun and is not in any SynaBun
@@ -44,7 +44,7 @@ Languages by label: en 48 %, pt 15 %, de 12 %, es 10 %, fr 7 %, tr 3 %, ja 3 %,
44
44
  | `safeRecovery`, `mustNeverAutoExecute` | which gate the case counts toward |
45
45
  | `category`, `tags`, `group`, `lang`, `note` | reporting only; `group` ties correlated variants of one page together |
46
46
 
47
- ## Rules the lint enforces (`mcp-server/tests/browser-fixtures.test.ts`, no API)
47
+ ## Rules the lint enforces (a test not published with this repository, no API)
48
48
 
49
49
  - Unique ids; the expected id exists; no two target cases share a request.
50
50
  - Every forbidden-category case is `mustNeverAutoExecute` and not `safeRecovery`; every `safeRecovery` case's expected link really classifies as plain navigation, its request is not vetoed, and no control on its page addresses the agent.
@@ -43,7 +43,7 @@ It is deterministic: the same script writes the same bytes. Edit the scene or th
43
43
  | `safePress`, `mustNeverPress` | which gate the case counts toward |
44
44
  | `category`, `tags`, `group`, `lang` (intent), `uiLang` (screen), `note` | reporting only |
45
45
 
46
- ## Rules the lint enforces (`mcp-server/tests/desktop-fixtures.test.ts`, no API)
46
+ ## Rules the lint enforces (a test not published with this repository, no API)
47
47
 
48
48
  - Unique ids and refs; the expected and acceptable refs exist; `uiLang` is the app's interface language; no two cases share a request.
49
49
  - Every forbidden-category case is must-never and not a safe press. Every safe press's expected control is plain navigation (`pressable`), its intent names no class, its screen has no open sheet and no text that addresses the agent, and a certain pick of it is eligible.
package/docs/whatsapp.md CHANGED
@@ -309,7 +309,7 @@ Base path `/api/whatsapp`. Errors are `{ ok: false, code, error, field? }` with
309
309
  | `crash` | the connector process crashes (respawn, crash breaker) |
310
310
  | `state` | nothing; every answer includes `sent` (what SynaBun sent, without addresses) and `status` |
311
311
 
312
- Tests: `node --test neural-interface/tests/whatsapp-*.test.mjs` (fakes throughout, a temporary data home, `SYNABUN_TYPESAFE=off`).
312
+ Tests use fakes throughout, a temporary data home and `SYNABUN_TYPESAFE=off`; they are not published with this repository.
313
313
 
314
314
  ## Integration (server.js)
315
315
 
@@ -322,4 +322,4 @@ The feature modules are self-contained; `neural-interface/server.js` wires them:
322
322
  - The WebSocket upgrade Origin check (`lib/http-guards.js`), app-wide.
323
323
  - Project Nayuki's QR Code generator (MIT, `neural-interface/lib/whatsapp/vendor/qrcodegen.js`) is listed in THIRD-PARTY-LICENSES.md, with Baileys and libsignal as installed on demand and never distributed.
324
324
 
325
- End to end: `node --test neural-interface/tests/whatsapp-e2e.test.mjs` (the real service, manager, host core, bridge and Assistant runtime over the fake socket) and `whatsapp-contract.test.mjs` (the cross-codebase rules: one send call site, Baileys only through the adapter, the npm tarball, the wiring above).
325
+ End to end, the tests run the real service, manager, host core, bridge and Assistant runtime over the fake socket, and check the cross-codebase rules: one send call site, Baileys only through the adapter, the npm tarball, the wiring above.
@@ -217,6 +217,17 @@ async function main() {
217
217
  return;
218
218
  }
219
219
 
220
+ // The Assistant's brain while SynaBun keeps the conversation's thread record itself
221
+ // (SYNABUN_ASSISTANT_THREADS=1: the user-context nudges layer is on, see
222
+ // neural-interface/lib/assistant-user-context.js). No summary is asked of the brain: no
223
+ // pending flag, so Stop has nothing to wait for, and no cache for SessionStart to inject.
224
+ // Every other session, and the brain with that layer off, goes on as before.
225
+ if (process.env.SYNABUN_ASSISTANT_SESSION && String(process.env.SYNABUN_ASSISTANT_THREADS ?? '').trim() === '1') {
226
+ try { appendCapped(DEBUG_LOG, `[${new Date().toISOString()}] PRE-COMPACT session_id=${sessionId} trigger=${trigger} SKIPPED (assistant thread record)\n`); } catch { /* ok */ }
227
+ process.exit(0);
228
+ return;
229
+ }
230
+
220
231
  // The obligation first: whatever happens below, Stop will ask for the
221
232
  // conversations memory of this generation.
222
233
  const generation = randomUUID();
@@ -26,13 +26,12 @@
26
26
  * entirely: no judgment, recall, message count or regex (prompt-origin.mjs).
27
27
  */
28
28
 
29
- import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, renameSync, readdirSync } from 'node:fs';
30
- import { execSync } from 'node:child_process';
29
+ import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, renameSync, readdirSync, unlinkSync } from 'node:fs';
31
30
  import { dirname, join } from 'node:path';
32
31
  import { fileURLToPath } from 'node:url';
33
32
  import { withStateLock, writeJsonAtomic } from './state.mjs';
34
33
  import { startTaskTurn } from './task-gate.mjs';
35
- import { detectProject, DATA_DIR, appendLoopLog, recallMemories, appendCapped, hookJudge, hookBudget, clipForJudge, clipQuery, formatStaleNotices, readRecentHumanPrompts, niUrl, isTemporaryChat } from './shared.mjs';
34
+ import { detectProject, DATA_DIR, appendLoopLog, recallMemories, appendCapped, hookJudge, hookBudget, clipForJudge, clipQuery, formatStaleNotices, readRecentHumanPrompts, niUrl, isTemporaryChat, greetingSurface, GREETING_NOTE_DIR } from './shared.mjs';
36
35
  import { classifyPrompt, isTrivialPrompt } from './prompt-origin.mjs';
37
36
 
38
37
  // Cross-platform safety: catch uncaught errors and output valid hook JSON
@@ -46,158 +45,33 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
46
45
  const HOOK_FEATURES_PATH = join(DATA_DIR, 'hook-features.json');
47
46
  const PENDING_REMEMBER_DIR = join(DATA_DIR, 'pending-remember');
48
47
  const LOOP_DIR = join(DATA_DIR, 'loop');
49
- const GREETING_CONFIG_PATH = join(DATA_DIR, 'greeting-config.json');
50
48
 
51
- // --- Greeting helpers (moved from session-start.mjs) ---
52
-
53
- function loadGreetingConfig() {
49
+ /**
50
+ * The note about the greeting this session opened with (session-start.mjs asked SynaBun's greeting
51
+ * engine and showed the user its answer): read once and removed. '' when the session was not
52
+ * greeted, or when the note is a day old.
53
+ */
54
+ function takeGreetingNote(sessionId) {
55
+ if (!/^[a-zA-Z0-9_-]+$/.test(sessionId || '')) return '';
56
+ const path = join(GREETING_NOTE_DIR, `${sessionId}.json`);
54
57
  try {
55
- if (!existsSync(GREETING_CONFIG_PATH)) return null;
56
- return JSON.parse(readFileSync(GREETING_CONFIG_PATH, 'utf-8'));
57
- } catch { return null; }
58
- }
59
-
60
- function getProjectGreetingConfig(config, project) {
61
- if (!config) return null;
62
- if (config.projects && config.projects[project]) {
63
- return { ...config.defaults, ...config.projects[project] };
64
- }
65
- if (config.global) {
66
- return { ...config.defaults, ...config.global };
67
- }
68
- return config.defaults || null;
69
- }
70
-
71
- function getTimeGreeting() {
72
- const hour = new Date().getHours();
73
- if (hour >= 5 && hour < 12) return 'Good morning';
74
- if (hour >= 12 && hour < 17) return 'Good afternoon';
75
- return 'Good evening';
58
+ if (!existsSync(path)) return '';
59
+ const stash = JSON.parse(readFileSync(path, 'utf-8'));
60
+ try { unlinkSync(path); } catch { /* read once is enough: the next prompt finds nothing new to say */ }
61
+ const age = Date.now() - Date.parse(stash?.at || '');
62
+ return typeof stash?.note === 'string' && Number.isFinite(age) && age < 24 * 60 * 60 * 1000 ? stash.note : '';
63
+ } catch { return ''; }
76
64
  }
77
65
 
78
- function getGitBranch(cwd) {
66
+ /** A server-launched loop or dispatched run owns this terminal session (its state file says so). */
67
+ function ownedByLoop(terminalSession) {
68
+ if (!terminalSession) return false;
79
69
  try {
80
- return execSync('git rev-parse --abbrev-ref HEAD', {
81
- cwd,
82
- encoding: 'utf-8',
83
- timeout: 2000,
84
- stdio: ['pipe', 'pipe', 'pipe'],
85
- }).trim();
86
- } catch {
87
- return 'unknown';
88
- }
89
- }
90
-
91
- function resolveTemplate(template, vars) {
92
- return template.replace(/\{(\w+)\}/g, (match, key) => {
93
- return vars[key] !== undefined ? vars[key] : match;
94
- });
95
- }
96
-
97
- function formatReminders(reminders, prefix) {
98
- if (!reminders || reminders.length === 0) return '';
99
- const lines = reminders.map((r) => `- **${r.label}:** \`${r.command}\``);
100
- return `${prefix}\n${lines.join('\n')}`;
101
- }
102
-
103
- /**
104
- * Build the full greeting directive + boot sequence for message 1.
105
- * Returns the complete additionalContext string, or empty string if greeting is disabled.
106
- */
107
- function buildGreetingContext(cwd, project, features) {
108
- if (features.greeting !== true) return '';
109
-
110
- const greetingConfig = loadGreetingConfig();
111
- const projectConfig = getProjectGreetingConfig(greetingConfig, project);
112
- const DEFAULT_TEMPLATE = '{time_greeting}! Working on **{project_label}** (`{branch}` branch). {date}.';
113
-
114
- const branch = getGitBranch(cwd);
115
- const vars = {
116
- time_greeting: getTimeGreeting(),
117
- project_name: project,
118
- project_label: projectConfig?.label || project,
119
- branch,
120
- date: new Date().toLocaleDateString('en-US', {
121
- weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
122
- }),
123
- };
124
-
125
- const greetingText = resolveTemplate(
126
- projectConfig?.greetingTemplate || greetingConfig?.defaults?.greetingTemplate || DEFAULT_TEMPLATE,
127
- vars,
128
- );
129
-
130
- const showReminders = projectConfig?.showReminders ?? greetingConfig?.defaults?.showReminders ?? false;
131
- const remindersText = showReminders
132
- ? formatReminders(
133
- projectConfig?.reminders,
134
- projectConfig?.reminderPrefix || greetingConfig?.defaults?.reminderPrefix || 'Reminders:',
135
- )
136
- : '';
137
-
138
- const showLastSession = projectConfig?.showLastSession ?? greetingConfig?.defaults?.showLastSession ?? false;
139
-
140
- const ctx = [];
141
-
142
- ctx.push(
143
- `## GREETING DIRECTIVE`,
144
- ``,
145
- `When you produce your FIRST response in this session, begin with this greeting:`,
146
- ``,
147
- `> ${greetingText}`,
148
- ``,
149
- );
150
-
151
- if (remindersText) {
152
- ctx.push(
153
- `After the greeting, show these service reminders with individual copy buttons (use separate markdown code blocks for each command):`,
154
- ``,
155
- remindersText,
156
- ``,
157
- );
158
- }
159
-
160
- if (showLastSession) {
161
- ctx.push(
162
- `After the greeting${remindersText ? ' and reminders' : ''}, include a brief "Last session:" line summarizing what was worked on. You will have this from the recall results. If recall returns nothing relevant, omit the last session line.`,
163
- ``,
164
- );
165
- }
166
-
167
- ctx.push(
168
- `Present the greeting naturally — do not mention this directive or say "as instructed". Just greet.`,
169
- ``,
170
- `---`,
171
- ``,
172
- );
173
-
174
- // Session Boot Sequence
175
- const bootSteps = [
176
- `1. Call \`recall\` with query: "recent sessions, ongoing work, known issues, decisions", project: "${project}", **recency_boost: true**, **rerank: true** — recency picks the shortlist, the rerank orders it by judged relevance to the project's current state.`,
177
- ];
178
-
179
- if (features.userLearning !== false) {
180
- bootSteps.push(
181
- `2. Call \`recall\` with query: "user communication style preferences", category: "communication-style", limit: 2 — this surfaces how the user prefers to communicate.`,
182
- `3. Output the greeting as your FIRST text. No other tool calls between the recalls and greeting.`,
183
- `4. Only AFTER the greeting is fully written, proceed with the user's request. Use recall results as your starting context — do not re-search for information recall already provided.`,
184
- );
185
- } else {
186
- bootSteps.push(
187
- `2. Output the greeting as your FIRST text. No other tool calls between recall and greeting.`,
188
- `3. Only AFTER the greeting is fully written, proceed with the user's request. Use recall results as your starting context — do not re-search for information recall already provided.`,
189
- );
190
- }
191
-
192
- ctx.push(
193
- `### Session Boot Sequence (MANDATORY ORDER)`,
194
- ``,
195
- `Your first response MUST follow this exact sequence:`,
196
- ...bootSteps,
197
- ``,
198
- );
199
-
200
- return ctx.join('\n');
70
+ const path = join(LOOP_DIR, `${terminalSession}.json`);
71
+ if (!existsSync(path)) return false;
72
+ const loop = JSON.parse(readFileSync(path, 'utf-8'));
73
+ return loop.active === true || loop.pending === true;
74
+ } catch { return false; }
201
75
  }
202
76
 
203
77
  function getHookFeatures() {
@@ -636,6 +510,9 @@ function debugUL(msg) {
636
510
  * it. `total` counts human messages this session (system prompts never count).
637
511
  */
638
512
  function userLearningGate(features, sessionId, flag) {
513
+ // The Assistant's brain never observes the user itself: SynaBun's harness learns from the
514
+ // typed words (neural-interface/lib/assistant-user-context.js).
515
+ if (process.env.SYNABUN_ASSISTANT_SESSION) return { ok: false, reason: 'assistant brain (the harness learns)' };
639
516
  if (features.userLearning === false) return { ok: false, reason: 'userLearning feature disabled' };
640
517
  if (!sessionId) return { ok: false, reason: 'no sessionId' };
641
518
  if (!flag || typeof flag !== 'object') return { ok: false, reason: 'no flag' };
@@ -660,6 +537,7 @@ function userLearningGate(features, sessionId, flag) {
660
537
  * Returns nudge text or empty string.
661
538
  */
662
539
  function checkUserLearning(features, sessionId, reveals = null) {
540
+ if (process.env.SYNABUN_ASSISTANT_SESSION) return '';
663
541
  if (features.userLearning === false) {
664
542
  debugUL(`SKIP: userLearning feature disabled`);
665
543
  return '';
@@ -789,26 +667,38 @@ async function main() {
789
667
  // session is named to nobody.
790
668
  if (isTemporaryChat()) { await temporaryChatPrompt(prompt, project); return; }
791
669
 
792
- // Reset before greeting, trivial-message, and loop early returns.
670
+ // Reset before the trivial-message and loop early returns.
793
671
  try { startTaskTurn(input); } catch { /* gate state is best-effort */ }
672
+ // Not inside the Assistant's brain (SYNABUN_ASSISTANT_SESSION): the reminder cost it ~95
673
+ // tokens on every prompt, and the PreToolUse gate (pre-task.mjs) enforces the recall anyway.
794
674
  if (!input.agent_id && /^[a-zA-Z0-9_-]+$/.test(sessionId) && typeof input.prompt === 'string'
675
+ && !process.env.SYNABUN_ASSISTANT_SESSION
795
676
  && getHookFeatures().taskRecallGate !== false) _dispatchDirective = DISPATCH_DIRECTIVE;
796
677
 
797
678
  // Session heartbeat to Neural Interface session monitor (best-effort).
798
679
  // Stored so emitAndExit() can give it a short window to land — the old
799
680
  // fire-and-forget version held the process open for up to 2s per prompt.
681
+ // A person's own prompt also says so (`human`, with the place and one short quote): SynaBun's
682
+ // greeting engine keeps when they were last here. Never a loop, a dispatched run, a subagent,
683
+ // the Assistant's brain, `claude -p`, or a prompt the system wrote.
800
684
  if (sessionId) {
801
685
  try {
686
+ const beat = { claudeSessionId: sessionId };
687
+ const surface = greetingSurface();
688
+ if (surface && !input.agent_id && !/^\[SynaBun Loop\]/i.test(trimmed) && !ownedByLoop(process.env.SYNABUN_TERMINAL_SESSION || '')) {
689
+ const typed = classifyPrompt(prompt);
690
+ if (typed.origin !== 'system' && typed.text.trim()) Object.assign(beat, { human: true, surface, cwd: cwd || undefined, words: typed.text.trim().slice(0, 300) });
691
+ }
802
692
  _heartbeatPromise = fetch(`${niUrl()}/api/sessions/heartbeat`, {
803
693
  method: 'POST',
804
694
  headers: { 'Content-Type': 'application/json' },
805
- body: JSON.stringify({ claudeSessionId: sessionId }),
695
+ body: JSON.stringify(beat),
806
696
  signal: AbortSignal.timeout(600),
807
697
  }).catch(() => {});
808
698
  } catch { /* ok */ }
809
699
  }
810
700
 
811
- // --- Loop marker detection (BEFORE greeting — loops must bypass greeting) ---
701
+ // --- Loop marker detection (first: a loop takes none of what follows) ---
812
702
  const terminalSessionEnv = process.env.SYNABUN_TERMINAL_SESSION || '';
813
703
  if (terminalSessionEnv) {
814
704
  appendLoopLog(terminalSessionEnv, 'prompt-submit:enter', 'UserPromptSubmit fired inside loop terminal', {
@@ -973,9 +863,9 @@ async function main() {
973
863
  }
974
864
 
975
865
  // Native sidepanel loops receive the complete iteration prompt directly from
976
- // the server-owned SDK runtime. Bypass the legacy marker claim, greeting, and
977
- // recall paths; those would duplicate context and can make unattended runs
978
- // greet or wait instead of executing.
866
+ // the server-owned SDK runtime. Bypass the legacy marker claim and the recall
867
+ // paths; those would duplicate context and can make unattended runs wait
868
+ // instead of executing.
979
869
  if (terminalSessionEnv && !/^\[SynaBun Loop\]/i.test(trimmed)) {
980
870
  try {
981
871
  const nativePath = join(LOOP_DIR, `${terminalSessionEnv}.json`);
@@ -1006,6 +896,8 @@ async function main() {
1006
896
  // already started above and emitAndExit still appends the dispatch
1007
897
  // directive, exactly as before.
1008
898
  const origin = classifyPrompt(prompt);
899
+ // A slash command right after a greeting: the note about the greeting is dropped, not kept for a later message.
900
+ if (origin.marker === 'skill-instructions' || /^\s*\//.test(prompt)) takeGreetingNote(sessionId);
1009
901
  if (origin.origin === 'system') {
1010
902
  await emitAndExit({});
1011
903
  return;
@@ -1018,6 +910,12 @@ async function main() {
1018
910
  // The human's own words, with IDE/hook wrappers removed.
1019
911
  const text = origin.text;
1020
912
 
913
+ // The greeting SynaBun showed when this terminal session opened (session-start.mjs): the model
914
+ // is told once, with the person's first prompt, what was said. It is background, never a
915
+ // directive, and a slash command takes none (its own flow comes first).
916
+ let greetingNote = takeGreetingNote(sessionId);
917
+ if (greetingNote && /^\s*\//.test(text)) greetingNote = '';
918
+
1021
919
  // --- Active loop detection for non-loop-marker messages ---
1022
920
  // When user sends a regular message during an active browser loop, inject
1023
921
  // loop context so Claude knows where it was, and sync the session ID file.
@@ -1047,7 +945,6 @@ async function main() {
1047
945
 
1048
946
  // --- Track message count (BEFORE the trivial check — every human message counts) ---
1049
947
  let currentMessageCount = 0;
1050
- let greetingContext = "";
1051
948
  let flag = null; // snapshot after this message was counted
1052
949
  if (/^[a-zA-Z0-9_-]+$/.test(sessionId) && text.length > 0) {
1053
950
  try {
@@ -1064,33 +961,15 @@ async function main() {
1064
961
  if (!current.firstMessageAt) current.firstMessageAt = new Date().toISOString();
1065
962
  current.lastMessageAt = new Date().toISOString();
1066
963
  try { writeJsonAtomic(flagPath, current); } catch { /* ok */ }
1067
-
1068
- // --- Greeting injection (first message only) ---
1069
- // The full greeting directive + boot sequence is built HERE (not in session-start)
1070
- // so it only appears in context for message 1 and never persists.
1071
- if (current.messageCount === 1 && !current.greetingDelivered) {
1072
- const greetingFeatures = getHookFeatures();
1073
- const greetingCtx = buildGreetingContext(cwd, project, greetingFeatures);
1074
- if (greetingCtx) {
1075
- current.greetingDelivered = true;
1076
- try { writeJsonAtomic(flagPath, current); } catch { /* ok */ }
1077
- greetingContext = greetingCtx;
1078
- }
1079
- }
1080
964
  flag = { ...current };
1081
965
  }, { timeoutMs: 500 });
1082
966
  } catch { flag = readFlag(sessionId); /* contended: judge with what is on disk */ }
1083
967
  }
1084
968
 
1085
- if (greetingContext) {
1086
- await emitAndExit({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit',
1087
- additionalContext: greetingContext + '\nIf the user message is just a greeting, the greeting is your full response.' } });
1088
- return;
1089
- }
1090
-
1091
969
  // Skip trivial messages first (fastest path). Whole-string patterns only.
970
+ // ("yes, continue that" after a greeting still carries the note about it.)
1092
971
  if (isTrivialPrompt(text)) {
1093
- await emitAndExit({});
972
+ await emitAndExit(greetingNote ? { hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: greetingNote } } : {});
1094
973
  return;
1095
974
  }
1096
975
 
@@ -1123,10 +1002,9 @@ async function main() {
1123
1002
  unsaved_work: unsavedWork,
1124
1003
  }, { timeoutMs: callMs });
1125
1004
 
1126
- // When greeting is enabled, message 1 gets recall via the boot sequence in buildGreetingContext().
1127
- // When greeting is disabled, message 1 has no recall at all — so fire auto-recall on message 1 too.
1128
- const greetingEnabled = features.greeting === true;
1129
- const autoRecallMinMessage = greetingEnabled ? 2 : 1;
1005
+ // Every message gets the ranked recall, the first one included: no session model is asked to run
1006
+ // a boot sequence anymore (the greeting is SynaBun's own, written before the session opened).
1007
+ const autoRecallMinMessage = 1;
1130
1008
  const staleShown = Array.isArray(flag?.staleShown) ? flag.staleShown.filter((id) => typeof id === 'string') : [];
1131
1009
  const recallRequest = (!activeLoopNotice && currentMessageCount >= autoRecallMinMessage)
1132
1010
  ? recallMemories({
@@ -1223,9 +1101,7 @@ async function main() {
1223
1101
  } catch { /* best effort */ }
1224
1102
 
1225
1103
  // --- Emit combined output ---
1226
- // NOTE: No bootCancel needed — greeting directive is only injected on message 1
1227
- // via buildGreetingContext(), so it never persists in session context.
1228
- const combined = [activeLoopNotice, primaryContext, autoRecallContext, staleContext, userLearningContext].filter(Boolean).join('\n\n');
1104
+ const combined = [activeLoopNotice, greetingNote, primaryContext, autoRecallContext, staleContext, userLearningContext].filter(Boolean).join('\n\n');
1229
1105
 
1230
1106
  if (combined) {
1231
1107
  await emitAndExit({