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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neural-memory-interface",
3
- "version": "2.0.0",
3
+ "version": "2.0.5",
4
4
  "private": true,
5
5
  "description": "Private local SynaBun interface for memory visualization and multi-agent workflows",
6
6
  "license": "Apache-2.0",
@@ -17,7 +17,6 @@
17
17
  "scripts": {
18
18
  "start": "node server.js",
19
19
  "dev": "node --watch server.js",
20
- "test": "node --test tests/*.test.mjs",
21
20
  "build:vendor": "node scripts/build-vendor.mjs",
22
21
  "postinstall": "node scripts/rebuild-pty.js && node scripts/build-vendor.mjs"
23
22
  },
@@ -52,6 +51,18 @@
52
51
  "tar": "^7.5.19"
53
52
  },
54
53
  "devDependencies": {
54
+ "@codemirror/autocomplete": "6.20.3",
55
+ "@codemirror/commands": "6.11.1",
56
+ "@codemirror/language": "6.13.1",
57
+ "@codemirror/language-data": "6.5.2",
58
+ "@codemirror/legacy-modes": "6.5.5",
59
+ "@codemirror/lint": "6.9.7",
60
+ "@codemirror/merge": "6.12.2",
61
+ "@codemirror/search": "6.7.2",
62
+ "@codemirror/state": "6.7.6",
63
+ "@codemirror/view": "6.43.14",
64
+ "@lezer/highlight": "1.2.5",
65
+ "@replit/codemirror-indentation-markers": "6.5.3",
55
66
  "esbuild": "^0.28.1",
56
67
  "three": "0.169.0"
57
68
  }
@@ -11,21 +11,24 @@
11
11
  <link rel="stylesheet" href="/shared/pwa-install.css">
12
12
  </head>
13
13
  <body id="pwa-install">
14
- <main aria-labelledby="install-title">
14
+ <!-- Hidden until pwa-install-page.js knows what this browser gets: the wizard or the main UI (Chrome or Edge
15
+ sent here by the launcher), one button (asked for from the Apps menu), or one plain instruction. -->
16
+ <main aria-labelledby="install-title" hidden>
15
17
  <img src="/icon-192.png" width="48" height="48" alt="SynaBun">
16
18
  <h1 id="install-title">Install SynaBun as an app</h1>
17
19
  <p id="install-intro">The server is running in the background. Confirm installation once in your browser to give SynaBun its own app window.</p>
18
- <ol>
19
- <li id="install-chromium">Chrome or Edge: choose Install as App below, or the browser's Install app menu.</li>
20
- <li id="install-safari">Safari on macOS: choose File → Add to Dock. Keep the name SynaBun.</li>
21
- </ol>
20
+ <p id="install-chromium" hidden>Chrome or Edge: choose Install as App below, or the browser's Install app menu.</p>
21
+ <p id="install-safari" hidden>Safari on macOS: choose File → Add to Dock. Keep the name SynaBun.</p>
22
+ <p id="install-other" hidden>SynaBun installs as an app from Chrome, Edge, or Safari on macOS. Open it in one of them to install.</p>
22
23
  <p id="install-later">After installation, reopen the native SynaBun launcher. It starts or reuses the server and opens your installed PWA. Closing the app window leaves the server running. Use Apps → Stop Server to stop it.</p>
23
24
  <div class="actions">
24
- <button id="install-button" type="button">Install as App</button>
25
+ <button id="install-button" type="button" hidden>Install as App</button>
25
26
  <a id="install-continue" href="/">Continue to SynaBun</a>
26
27
  </div>
27
28
  <p id="install-status" role="status" aria-live="polite"></p>
28
29
  </main>
30
+ <!-- Should the script never answer, the page and its way on still show. -->
31
+ <script>setTimeout(() => { document.querySelector('main').hidden = false; }, 4000);</script>
29
32
  <script type="module" src="/shared/pwa-install-page.js"></script>
30
33
  </body>
31
34
  </html>
@@ -614,7 +614,8 @@
614
614
  function render(snap) {
615
615
  const view = startStatusView(snap, { platform });
616
616
  $('mascot').setAttribute('data-state', view.mascot);
617
- $('heading').textContent = headings[view.mascot][0];
617
+ // A restart read from the supervisor's report names itself (view.heading).
618
+ $('heading').textContent = view.heading ? START_COPY[view.heading] : headings[view.mascot][0];
618
619
  $('subtext').textContent = headings[view.mascot][1];
619
620
  startBtn.disabled = view.busy || view.state === 'online';
620
621
  startLabel.textContent = labels[view.button];
@@ -622,7 +623,7 @@
622
623
  const line = say(view.headline);
623
624
  if (startStatus.textContent !== line) startStatus.textContent = line;
624
625
  $('startElapsed').textContent = view.elapsed;
625
- $('startElapsed').setAttribute('aria-label', view.elapsed ? START_COPY.elapsedLabel + ': ' + view.elapsed : '');
626
+ $('startElapsed').setAttribute('aria-label', view.elapsed ? START_COPY[view.elapsedLabel] + ': ' + view.elapsed : '');
626
627
  $('startHint').textContent = say(view.hint);
627
628
  $('startTrail').replaceChildren(...view.trail.map((row) => {
628
629
  const item = document.createElement('li');
@@ -7,6 +7,7 @@
7
7
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
8
8
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
9
9
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
10
+ <link rel="manifest" href="/manifest.json">
10
11
  <style>
11
12
  *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
12
13
 
@@ -1412,6 +1413,12 @@ import { fetchRulesStatus, fetchRulesTextWithFallback, installRules, installAllR
1412
1413
  import {
1413
1414
  describeRulesHost, describeRulesInstall, describeRulesInstallAll, describeRulesInPlace, rulesInstallPlan, catalogueTranslator,
1414
1415
  } from './shared/settings/settings-rules.js';
1416
+ // Install as an app: the wizard has no step for it. The browser's own dialog opens once, from a click that
1417
+ // moves the wizard on anyway (the welcome choices, Next), and the wizard never reads the answer. Also import-free.
1418
+ import { initPwaInstall, isStandalone, offerPwaInstallOnce } from './shared/pwa-install.js';
1419
+
1420
+ // Chrome and Edge hand the page their install event when it can be installed; Safari and Firefox have none.
1421
+ if (!isStandalone()) initPwaInstall();
1415
1422
 
1416
1423
  // ═══════════════════════════════════════════
1417
1424
  // STATE
@@ -1538,6 +1545,7 @@ function updateNav() {
1538
1545
  $prevBtn.addEventListener('click', () => goToStep(currentStep - 1));
1539
1546
  $nextBtn.addEventListener('click', () => {
1540
1547
  if (validateStep(currentStep)) {
1548
+ offerPwaInstallOnce(); // first, while the click still counts as the user's: see pwa-install.js
1541
1549
  goToStep(currentStep + 1);
1542
1550
  }
1543
1551
  });
@@ -1821,11 +1829,14 @@ function renderHappyBun() {}
1821
1829
 
1822
1830
  // Fresh Install → proceed to step 1
1823
1831
  document.getElementById('choiceFreshInstall').addEventListener('click', () => {
1832
+ offerPwaInstallOnce();
1824
1833
  goToStep(1);
1825
1834
  });
1826
1835
 
1827
- // Restore → show restore panel
1836
+ // Restore → show restore panel. A restore never passes Next, so this is its click for the browser's
1837
+ // install dialog; the file picker opens on a later click of its own.
1828
1838
  document.getElementById('choiceRestore').addEventListener('click', () => {
1839
+ offerPwaInstallOnce();
1829
1840
  $choices.style.display = 'none';
1830
1841
  $restorePanel.style.display = 'block';
1831
1842
  requestAnimationFrame(() => {
@@ -130,6 +130,14 @@ export function clampEffortId(effort, ids) {
130
130
 
131
131
  export const CODEX_EFFORT_VALUE_IDS = EFFORT_LEVELS_BY_PROFILE.codex.map(e => e.id);
132
132
 
133
+ // The Claude and Codex lists are asked again once a copy is this old (the server
134
+ // answers from its own discovery cache, so it is a local round trip): a page that
135
+ // stays open for days must not keep the list it loaded with. OpenCode's copy is
136
+ // dropped by its change events instead (`ocp-providers-changed`): its list is large.
137
+ const MODEL_LIST_MAX_AGE_MS = 60_000;
138
+ const _modelListAt = new Map();
139
+ function modelListIsFresh(key) { return Date.now() - (_modelListAt.get(key) || 0) < MODEL_LIST_MAX_AGE_MS; }
140
+
133
141
  const _codexModelsCache = new Map();
134
142
  const _codexModelsLoading = new Map();
135
143
  let _opencodeModelsCache = null;
@@ -268,7 +276,7 @@ export function mergeCodexModelIds(models = []) {
268
276
 
269
277
  export async function fetchCodexModels(force = false, accountId = 'default') {
270
278
  const account = String(accountId || 'default');
271
- if (!force && _codexModelsCache.has(account)) return _codexModelsCache.get(account);
279
+ if (!force && _codexModelsCache.has(account) && modelListIsFresh(`codex:${account}`)) return _codexModelsCache.get(account);
272
280
  if (_codexModelsLoading.has(account)) return _codexModelsLoading.get(account);
273
281
  const loading = (async () => {
274
282
  try {
@@ -278,6 +286,7 @@ export async function fetchCodexModels(force = false, accountId = 'default') {
278
286
  const models = Array.isArray(data?.models) ? data.models : [];
279
287
  const normalized = mergeCodexModelOptions(models, { fallback: false });
280
288
  _codexModelsCache.set(account, normalized);
289
+ _modelListAt.set(`codex:${account}`, Date.now());
281
290
  return normalized;
282
291
  } catch {
283
292
  const previous = _codexModelsCache.get(account) || [];
@@ -455,19 +464,25 @@ export async function fetchOpencodeModels(force = false) {
455
464
  // Live model list from the installed Claude Code CLI. Falls back to the static
456
465
  // list so the picker still renders when the CLI is missing or discovery fails.
457
466
  export async function fetchClaudeModels(force = false) {
458
- if (!force && _claudeModelsCache && _claudeModelsCache.length) return _claudeModelsCache;
467
+ if (!force && _claudeModelsCache && _claudeModelsCache.length && modelListIsFresh('claude-code')) return _claudeModelsCache;
459
468
  if (_claudeModelsLoading) return _claudeModelsLoading;
469
+ // A list the CLI verified is never traded for the unverified stand-in: a discovery
470
+ // that fails once (mid-update, mid-restart) must not strip a working picker.
471
+ const verified = () => (_claudeModelsCache?.length && _claudeModelsCache.some(m => m.catalogSource !== 'fallback') ? _claudeModelsCache : null);
460
472
  _claudeModelsLoading = (async () => {
461
473
  try {
462
474
  const resp = await fetch(`/api/claude/models${force ? '?refresh=1' : ''}`);
463
475
  const data = await resp.json().catch(() => ({}));
464
476
  const models = Array.isArray(data?.models) ? data.models : [];
465
- _claudeModelsCache = models.length
466
- ? models.map(model => ({ ...model, catalogSource: data?.source || 'cli' }))
467
- : [...CLAUDE_FALLBACK_MODELS];
477
+ if (models.length && data?.source !== 'fallback') {
478
+ _claudeModelsCache = models.map(model => ({ ...model, catalogSource: data?.source || 'cli' }));
479
+ _modelListAt.set('claude-code', Date.now());
480
+ } else {
481
+ _claudeModelsCache = verified() || (models.length ? models.map(model => ({ ...model, catalogSource: 'fallback' })) : [...CLAUDE_FALLBACK_MODELS]);
482
+ }
468
483
  return _claudeModelsCache;
469
484
  } catch {
470
- _claudeModelsCache = [...CLAUDE_FALLBACK_MODELS];
485
+ _claudeModelsCache = verified() || [...CLAUDE_FALLBACK_MODELS];
471
486
  return _claudeModelsCache;
472
487
  } finally {
473
488
  _claudeModelsLoading = null;
@@ -585,6 +600,7 @@ export function clearRuntimeOptionCaches() {
585
600
  _codexModelsLoading.clear();
586
601
  _opencodeModelsCache = null;
587
602
  _claudeModelsCache = null;
603
+ _modelListAt.clear();
588
604
  _mcpProfilePresets = null;
589
605
  _claudeAccountsCache = null;
590
606
  _opencodeAgentsCache = null;
@@ -0,0 +1,286 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Assistant: the automation trace, as words (DOM-free)
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // One `synabun.automation` event per turn phase (lib/assistant-user-context.js)
6
+ // says what the harness did for the turn: what it put into the brain's context
7
+ // (the standing digest, the per-turn notes, the related memories), what it held
8
+ // back and why, and what it learned from the user's own words afterwards.
9
+ // This module turns one snapshot into the lines asst-render.js draws: nothing
10
+ // here touches the DOM, so it is unit-tested in Node.
11
+ //
12
+ // AUTOMATION_COPY is the English; `assistant.automation.*` in i18n/*.json must
13
+ // equal it (tests/assistant-automation-view.test.mjs).
14
+
15
+ export const AUTOMATION_EVENT = 'synabun.automation';
16
+
17
+ export const AUTOMATION_COPY = Object.freeze({
18
+ title: 'Automation',
19
+ 'sum.turn': '{n} tok this turn',
20
+ 'sum.standing': '{n} standing',
21
+ 'sum.none': 'nothing injected',
22
+ 'state.waiting': 'learning after the reply',
23
+ 'state.running': 'learning…',
24
+ 'state.learned': 'learned 1 thing',
25
+ 'state.confirmed': 'confirmed 1 thing',
26
+ 'state.replaced': 'replaced 1 thing',
27
+ 'group.injected': 'Injected',
28
+ 'group.withheld': 'Withheld',
29
+ 'group.learning': 'Learning',
30
+ 'group.session': 'This conversation',
31
+ 'tier.greeting': 'Greeting',
32
+ 'tier.digest': 'Knowledge digest',
33
+ 'tier.last-thread': 'Last conversation',
34
+ 'tier.environment': 'Environment',
35
+ 'tier.open-item': 'Open item',
36
+ 'tier.cue': 'Knowledge cue',
37
+ 'tier.delta': 'New knowledge',
38
+ 'tier.recall': 'Related memories',
39
+ 'tier.knowledge': 'Knowledge of you',
40
+ 'tier.nudges': 'Recent-interaction nudges',
41
+ 'tier.turn': 'Per-turn notes',
42
+ tok: '{n} tok',
43
+ 'meta.standing': 'system slot · frozen {time}',
44
+ 'meta.standingRef': 'already in the system slot, not resent',
45
+ 'meta.memories': '{n} memories',
46
+ 'meta.memory': '1 memory',
47
+ 'meta.alreadyPresent': 'already supplied earlier',
48
+ 'meta.budget': 'budget {used}/{max} tok',
49
+ 'meta.greetingWriter': 'said at session open · written ahead by {model}',
50
+ 'meta.greetingFallback': 'said at session open · from the records, no model',
51
+ 'reason.layer-off': 'switched off in Settings',
52
+ 'reason.nothing-known': 'nothing learned yet',
53
+ 'reason.no-recent-thread': 'no recent conversation to mention',
54
+ 'reason.in-greeting': 'already said in the greeting',
55
+ 'reason.budget': 'over the turn budget, kept for a later turn',
56
+ 'reason.not-ranked': 'not ranked relevant by Jev',
57
+ 'reason.in-digest': 'already in the digest',
58
+ 'reason.already-told': 'already told in this conversation',
59
+ 'reason.replaced': 'replaced by a newer statement',
60
+ 'reason.one-per-turn': 'one cue per turn',
61
+ 'reason.unusable': 'no usable statement',
62
+ 'reason.not-delivered': 'the turn ended before the notes could be delivered',
63
+ 'reason.trivial': 'trivial prompt',
64
+ 'reason.pattern': 'a command or an acknowledgement',
65
+ 'reason.judged': 'Jev: memory would not change the reply',
66
+ 'reason.nothing-retrieved': 'nothing relevant found',
67
+ 'reason.disabled': 'automatic recall is off',
68
+ 'reason.error': 'the search failed',
69
+ 'reason.system': 'not a prompt of yours',
70
+ 'learn.waiting': 'Your words are judged once the reply is done.',
71
+ 'learn.running': 'Jev is reading what you typed…',
72
+ 'learn.skipped': 'Not judged: {reason}.',
73
+ 'learn.cues': 'Cue words: {cues}',
74
+ 'learn.judged': 'Jev: lasting signal {p} · {facet} · {scope}',
75
+ 'learn.matched': 'Matches: {statement}',
76
+ 'learn.contradicts': 'Contradicts: {statement}',
77
+ 'learn.created': 'Learned: {statement}',
78
+ 'learn.updated': 'Confirmed (seen {n}×): {statement}',
79
+ 'learn.superseded': 'Replaced “{old}” with: {statement}',
80
+ 'learn.none': 'Nothing stored: {reason}.',
81
+ 'learn.evidence': 'Evidence: “{quote}”',
82
+ 'learn.writer': 'Written by {engine}',
83
+ 'learn.writerOwn': 'Kept as your own sentence ({reason})',
84
+ 'learn.writerKept': 'Statement kept as recorded',
85
+ 'learn.cost': '{requests} Jev requests · {tokens} tok · {cost}',
86
+ 'learn.scope.global': 'all projects',
87
+ 'skip.no-cue': 'no always / never / from-now-on wording',
88
+ 'skip.trivial': 'trivial prompt',
89
+ 'skip.short': 'too short',
90
+ 'skip.origin': 'not typed by you',
91
+ 'skip.untrusted': 'forwarded content',
92
+ 'skip.no-typed-text': 'only attachments or pasted text',
93
+ 'skip.seen': 'the same words were already judged',
94
+ 'skip.gate-cap': 'this conversation reached its limit of judgments',
95
+ 'skip.write-cap': 'this conversation reached its limit of learned facts',
96
+ 'skip.layer-off': 'Knowledge of you is off',
97
+ 'skip.system': 'not a prompt of yours',
98
+ 'none.not-durable': 'not a lasting preference',
99
+ 'none.no-answer': 'Jev did not answer',
100
+ 'none.jev-unavailable': 'Jev is off or has no key',
101
+ 'none.duplicate': 'memory already states this',
102
+ 'none.write-cap': 'this conversation reached its limit of learned facts',
103
+ 'none.no-evidence': 'no sentence carried it',
104
+ 'none.no-statement': 'no usable statement',
105
+ 'none.write-error': 'the memory write failed',
106
+ 'none.no-store': 'memory is not available',
107
+ 'none.error': 'the learning step failed',
108
+ 'writer.unverified': 'the rewrite could not be checked',
109
+ 'writer.not-faithful': 'the rewrite added something',
110
+ 'writer.no-writer': 'no writer model',
111
+ 'writer.writer-cap': 'writer limit reached',
112
+ 'writer.other': 'the writer failed',
113
+ totals: 'Judged {gate}/{gateCap} · writer {writer}/{writerCap} · learned {writes}/{writeCap} · {tokens} tok injected over {turns} turns · {cost}',
114
+ open: 'Open memory',
115
+ });
116
+
117
+ const fill = (text, params) => (params ? String(text).replace(/\{(\w+)\}/g, (_, key) => (params[key] != null ? params[key] : `{${key}}`)) : String(text));
118
+
119
+ /** The translator: `t(key, params)` when it knows the key, else the English above. */
120
+ export function automationText(t, key, params) {
121
+ const full = `assistant.automation.${key}`;
122
+ let value;
123
+ try { value = typeof t === 'function' ? t(full, params) : undefined; } catch { value = undefined; }
124
+ if (typeof value === 'string' && value && value !== full) return value;
125
+ const fallback = AUTOMATION_COPY[key];
126
+ return fallback == null ? key : fill(fallback, params);
127
+ }
128
+
129
+ const num = (value) => (Number.isFinite(Number(value)) ? Number(value) : 0);
130
+
131
+ /** A dollar amount small enough to matter: 5 decimals under a cent, 2 above. */
132
+ export function formatUsd(value) {
133
+ const n = num(value);
134
+ if (n <= 0) return '$0';
135
+ return n < 0.01 ? `$${n.toFixed(5).replace(/0+$/, '').replace(/\.$/, '')}` : `$${n.toFixed(2)}`;
136
+ }
137
+ const pct = (value) => `${Math.round(num(value) * 100)}%`;
138
+ const defaultTime = (iso) => {
139
+ const ms = Date.parse(iso ?? '');
140
+ if (!Number.isFinite(ms)) return '';
141
+ try { return new Date(ms).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } catch { return ''; }
142
+ };
143
+
144
+ function writerLine(tx, learning) {
145
+ const action = learning.action || {};
146
+ const writer = learning.writer || {};
147
+ if (!action.engine) return null;
148
+ if (action.engine === 'kept') return tx('learn.writerKept');
149
+ if (action.engine === 'user-sentence') {
150
+ const code = writer.reason && AUTOMATION_COPY[`writer.${writer.reason}`] ? writer.reason : 'other';
151
+ return tx('learn.writerOwn', { reason: tx(`writer.${code}`) });
152
+ }
153
+ return tx('learn.writer', { engine: writer.verified != null ? `${action.engine} · ${pct(writer.verified)}` : action.engine });
154
+ }
155
+
156
+ /**
157
+ * One snapshot → what the trace row shows.
158
+ * → { traceId, phase, summary, state, tone, groups:[{ key, title, rows:[{ label, meta, text, pre, ids, tone }] }] }
159
+ * tone: '' | 'busy' | 'learned'. `pre`: `text` is exact injected text (keep its line breaks).
160
+ */
161
+ export function automationView(ev = {}, { t = null, formatTime = defaultTime } = {}) {
162
+ const tx = (key, params) => automationText(t, key, params);
163
+ const tokens = ev.tokens || {};
164
+ const injected = Array.isArray(ev.injected) ? ev.injected : [];
165
+ const withheld = Array.isArray(ev.withheld) ? ev.withheld : [];
166
+ const learning = ev.learning || {};
167
+ const totals = ev.totals || {};
168
+ const tok = (n) => tx('tok', { n: num(n) });
169
+ const tier = (code) => tx(`tier.${AUTOMATION_COPY[`tier.${code}`] ? code : 'turn'}`);
170
+
171
+ // ── the one-line summary ──
172
+ const turnTokens = num(tokens.turn) + num(tokens.recall);
173
+ const parts = [];
174
+ if (turnTokens > 0) parts.push(tx('sum.turn', { n: turnTokens }));
175
+ if (num(tokens.digest) > 0) parts.push(tx('sum.standing', { n: num(tokens.digest) }));
176
+ const summary = parts.length ? parts.join(' · ') : tx('sum.none');
177
+ let state = '';
178
+ let tone = '';
179
+ const action = learning.action || null;
180
+ if (learning.state === 'waiting') { state = tx('state.waiting'); tone = 'busy'; }
181
+ else if (learning.state === 'running') { state = tx('state.running'); tone = 'busy'; }
182
+ else if (learning.state === 'done' && action && action.type && action.type !== 'none') {
183
+ state = tx(action.type === 'update' ? 'state.confirmed' : action.type === 'supersede' ? 'state.replaced' : 'state.learned');
184
+ tone = 'learned';
185
+ }
186
+
187
+ const groups = [];
188
+ // ── injected ──
189
+ const injectedRows = injected.map((item) => {
190
+ const meta = [tok(item.tokens)];
191
+ if (item.tier === 'digest') meta.push(item.text ? tx('meta.standing', { time: formatTime(item.frozenAt) }) : tx('meta.standingRef'));
192
+ // The greeting: who wrote it and what that cost (the records it was built from are the links below it).
193
+ if (item.tier === 'greeting') {
194
+ meta.push(item.source === 'writer' ? tx('meta.greetingWriter', { model: item.model || 'Claude' }) : tx('meta.greetingFallback'));
195
+ if (item.source === 'writer' && Number(item.costUsd) > 0) meta.push(formatUsd(item.costUsd));
196
+ }
197
+ if (item.tier === 'recall') {
198
+ const n = Array.isArray(item.ids) ? item.ids.length : 0;
199
+ meta.push(n === 1 ? tx('meta.memory') : tx('meta.memories', { n }));
200
+ if (item.alreadyPresent) meta.push(tx('meta.alreadyPresent'));
201
+ }
202
+ return { label: tier(item.tier), meta: meta.filter(Boolean).join(' · '), text: item.text || '', pre: item.tier === 'digest' && !!item.text, ids: item.tier === 'recall' ? [] : (Array.isArray(item.ids) ? item.ids : []), tone: '' };
203
+ });
204
+ if (injectedRows.length) {
205
+ if (num(tokens.budget) > 0) injectedRows.push({ label: tier('turn'), meta: tx('meta.budget', { used: num(tokens.turn), max: num(tokens.budget) }), text: '', pre: false, ids: [], tone: 'muted' });
206
+ groups.push({ key: 'injected', title: tx('group.injected'), rows: injectedRows });
207
+ }
208
+ // ── withheld ──
209
+ if (withheld.length) {
210
+ groups.push({
211
+ key: 'withheld', title: tx('group.withheld'),
212
+ rows: withheld.map((item) => ({
213
+ label: tier(item.tier), meta: tx(`reason.${AUTOMATION_COPY[`reason.${item.reason}`] ? item.reason : 'unusable'}`),
214
+ text: item.text || '', pre: false, ids: Array.isArray(item.ids) ? item.ids : [], tone: 'muted',
215
+ })),
216
+ });
217
+ }
218
+ // ── learning ──
219
+ const learnRows = [];
220
+ const pre = learning.prefilter || {};
221
+ if (learning.state === 'skipped') {
222
+ learnRows.push({ label: '', meta: '', text: tx('learn.skipped', { reason: tx(`skip.${AUTOMATION_COPY[`skip.${pre.reason}`] ? pre.reason : 'no-cue'}`) }), pre: false, ids: [], tone: 'muted' });
223
+ } else if (learning.state === 'waiting' || learning.state === 'running') {
224
+ if (Array.isArray(pre.cues) && pre.cues.length) learnRows.push({ label: '', meta: '', text: tx('learn.cues', { cues: pre.cues.join(', ') }), pre: false, ids: [], tone: '' });
225
+ learnRows.push({ label: '', meta: '', text: tx(learning.state === 'waiting' ? 'learn.waiting' : 'learn.running'), pre: false, ids: [], tone: 'muted' });
226
+ } else if (learning.state === 'done') {
227
+ const gate = learning.gate || null;
228
+ if (Array.isArray(pre.cues) && pre.cues.length) learnRows.push({ label: '', meta: '', text: tx('learn.cues', { cues: pre.cues.join(', ') }), pre: false, ids: [], tone: '' });
229
+ if (gate?.answered) {
230
+ learnRows.push({ label: '', meta: '', text: tx('learn.judged', { p: pct(gate.durable), facet: gate.facet || '', scope: !gate.scope || gate.scope === 'global' ? tx('learn.scope.global') : gate.scope }), pre: false, ids: [], tone: '' });
231
+ if (gate.contradicts) learnRows.push({ label: '', meta: pct(gate.contradicts.probability), text: tx('learn.contradicts', { statement: gate.contradicts.statement }), pre: false, ids: [gate.contradicts.id].filter(Boolean), tone: '' });
232
+ else if (gate.match) learnRows.push({ label: '', meta: pct(gate.match.confidence), text: tx('learn.matched', { statement: gate.match.statement }), pre: false, ids: [gate.match.id].filter(Boolean), tone: '' });
233
+ }
234
+ const act = action || { type: 'none', reason: 'error' };
235
+ if (act.type === 'none') {
236
+ const code = AUTOMATION_COPY[`none.${act.reason}`] ? act.reason : 'error';
237
+ const extra = act.reason === 'not-durable' && gate?.durable != null ? ` (${pct(gate.durable)})` : '';
238
+ learnRows.push({ label: '', meta: '', text: tx('learn.none', { reason: `${tx(`none.${code}`)}${extra}` }), pre: false, ids: [act.duplicateOf].filter(Boolean), tone: 'muted' });
239
+ } else {
240
+ const text = act.type === 'update' ? tx('learn.updated', { n: num(act.seen) || 2, statement: act.statement })
241
+ : act.type === 'supersede' ? tx('learn.superseded', { old: act.replaced || '', statement: act.statement })
242
+ : tx('learn.created', { statement: act.statement });
243
+ learnRows.push({ label: '', meta: [act.facet, !act.scope || act.scope === 'global' ? tx('learn.scope.global') : act.scope].filter(Boolean).join(' · '), text, pre: false, ids: [act.memoryId, act.supersedes].filter(Boolean), tone: 'learned' });
244
+ if (act.evidence) learnRows.push({ label: '', meta: '', text: tx('learn.evidence', { quote: act.evidence }), pre: false, ids: [], tone: '' });
245
+ const written = writerLine(tx, learning);
246
+ if (written) learnRows.push({ label: '', meta: '', text: written, pre: false, ids: [], tone: 'muted' });
247
+ }
248
+ const cost = learning.cost || {};
249
+ if (num(cost.jevRequests) > 0 || num(cost.writerUsd) > 0) {
250
+ const writerTokens = cost.writerTokens ? num(cost.writerTokens.input) + num(cost.writerTokens.output) + num(cost.writerTokens.cacheRead) + num(cost.writerTokens.cacheWrite) : 0;
251
+ learnRows.push({ label: '', meta: '', text: tx('learn.cost', { requests: num(cost.jevRequests), tokens: num(cost.jevInputTokens) + num(cost.jevOutputTokens) + writerTokens, cost: formatUsd(cost.totalUsd) }), pre: false, ids: [], tone: 'muted' });
252
+ }
253
+ }
254
+ if (learnRows.length) groups.push({ key: 'learning', title: tx('group.learning'), rows: learnRows });
255
+ // ── session totals ──
256
+ if (num(totals.turns) > 0) {
257
+ groups.push({
258
+ key: 'session', title: tx('group.session'),
259
+ rows: [{ label: '', meta: '', text: tx('totals', { gate: num(totals.gate), gateCap: num(totals.gateCap), writer: num(totals.writer), writerCap: num(totals.writerCap), writes: num(totals.writes), writeCap: num(totals.writeCap), tokens: num(totals.injectedTokens), turns: num(totals.turns), cost: formatUsd(totals.costUsd) }), pre: false, ids: [], tone: 'muted' }],
260
+ });
261
+ }
262
+ return { traceId: String(ev.traceId || ''), phase: String(ev.phase || 'sent'), title: tx('title'), summary, state, tone, groups };
263
+ }
264
+
265
+ // ── typed words (the composer) ──────────────────────────────────────────────
266
+ // A paste this long, or this many lines, is text the user did not type
267
+ // (lib/assistant-user-context-budgets.js LEARN.pasteChars / pasteLines): the
268
+ // prompt still carries it, the `typed` text the server may learn from does not.
269
+ export const PASTE_MIN_CHARS = 200;
270
+ export const PASTE_MIN_LINES = 4;
271
+
272
+ export function isLongPaste(text) {
273
+ const value = String(text ?? '');
274
+ if (!value.trim()) return false;
275
+ return value.length >= PASTE_MIN_CHARS || value.split(/\r\n|\r|\n/).filter((line) => line.trim()).length >= PASTE_MIN_LINES;
276
+ }
277
+
278
+ /** The composer's text without the long pastes still in it (those edited since count as typed). */
279
+ export function typedText(text, pastes = []) {
280
+ let out = String(text ?? '').replace(/\r\n?/g, '\n');
281
+ for (const paste of Array.isArray(pastes) ? pastes : []) {
282
+ const block = String(paste ?? '').replace(/\r\n?/g, '\n').trim();
283
+ if (block && out.includes(block)) out = out.split(block).join('\n');
284
+ }
285
+ return out.replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n').trim();
286
+ }