synabun 2.0.0-beta → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/THIRD-PARTY-LICENSES.md +51 -0
  5. package/benchmarks/fixtures/browser/README.md +1 -1
  6. package/benchmarks/fixtures/desktop/README.md +1 -1
  7. package/docs/whatsapp.md +2 -2
  8. package/hooks/claude-code/pre-compact.mjs +11 -0
  9. package/hooks/claude-code/prompt-submit.mjs +60 -184
  10. package/hooks/claude-code/session-start.mjs +73 -16
  11. package/hooks/claude-code/shared.mjs +20 -0
  12. package/hooks/claude-code/stop.mjs +5 -5
  13. package/launcher.mjs +40 -0
  14. package/lib/claude-hooks.js +61 -8
  15. package/lib/client-config-repair.js +4 -3
  16. package/lib/data-home-migration.js +4 -0
  17. package/lib/desktop-pwa.js +206 -0
  18. package/lib/external-tools.js +221 -0
  19. package/lib/first-launch-protection.js +5 -0
  20. package/lib/packaged-runtime.js +110 -0
  21. package/lib/start-launcher.js +1396 -0
  22. package/mcp-server/package-lock.json +2 -2
  23. package/mcp-server/package.json +1 -3
  24. package/neural-interface/i18n/en.json +1540 -154
  25. package/neural-interface/i18n/pt-BR.json +1538 -153
  26. package/neural-interface/lib/assistant-api.js +62 -6
  27. package/neural-interface/lib/assistant-brains/claude.js +4 -0
  28. package/neural-interface/lib/assistant-catalog.js +179 -27
  29. package/neural-interface/lib/assistant-config.js +31 -2
  30. package/neural-interface/lib/assistant-dispatch.js +62 -13
  31. package/neural-interface/lib/assistant-envelope.js +9 -6
  32. package/neural-interface/lib/assistant-hidden-models.js +393 -66
  33. package/neural-interface/lib/assistant-memory.js +24 -10
  34. package/neural-interface/lib/assistant-persona.js +6 -2
  35. package/neural-interface/lib/assistant-pricing.js +21 -6
  36. package/neural-interface/lib/assistant-runtime.js +181 -12
  37. package/neural-interface/lib/assistant-task-prompt.js +13 -3
  38. package/neural-interface/lib/assistant-test-density.js +142 -0
  39. package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
  40. package/neural-interface/lib/assistant-user-context.js +908 -0
  41. package/neural-interface/lib/assistant-user-knowledge.js +328 -0
  42. package/neural-interface/lib/assistant-user-learn.js +404 -0
  43. package/neural-interface/lib/assistant-user-threads.js +226 -0
  44. package/neural-interface/lib/assistant-user-writer.js +181 -0
  45. package/neural-interface/lib/augmented-path.js +23 -3
  46. package/neural-interface/lib/browser-background-tab.js +134 -0
  47. package/neural-interface/lib/browser-language.js +83 -0
  48. package/neural-interface/lib/browser-screenshot.js +678 -61
  49. package/neural-interface/lib/claude-agent-bridge.js +87 -153
  50. package/neural-interface/lib/claude-executable.js +241 -0
  51. package/neural-interface/lib/claude-model-catalog.js +82 -93
  52. package/neural-interface/lib/claude-temporary.js +46 -7
  53. package/neural-interface/lib/cloudflared/install.js +533 -0
  54. package/neural-interface/lib/cloudflared/manager.js +545 -0
  55. package/neural-interface/lib/cloudflared/pins.js +115 -0
  56. package/neural-interface/lib/cloudflared/pins.json +63 -0
  57. package/neural-interface/lib/cloudflared/tunnel.js +265 -0
  58. package/neural-interface/lib/editor-completion-endpoint.js +264 -0
  59. package/neural-interface/lib/editor-completion-opencode.js +436 -0
  60. package/neural-interface/lib/editor-completion.js +714 -0
  61. package/neural-interface/lib/editor-config.js +149 -0
  62. package/neural-interface/lib/editor-files-api.js +268 -0
  63. package/neural-interface/lib/editor-git-api.js +134 -0
  64. package/neural-interface/lib/file-explorer-api.js +1039 -0
  65. package/neural-interface/lib/file-explorer-system.js +355 -0
  66. package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
  67. package/neural-interface/lib/file-explorer-watch.js +239 -0
  68. package/neural-interface/lib/git-diff-api.js +103 -0
  69. package/neural-interface/lib/git-read.js +202 -0
  70. package/neural-interface/lib/greeting/api.js +89 -0
  71. package/neural-interface/lib/greeting/budgets.js +90 -0
  72. package/neural-interface/lib/greeting/engine.js +461 -0
  73. package/neural-interface/lib/greeting/facts.js +320 -0
  74. package/neural-interface/lib/greeting/sources.js +252 -0
  75. package/neural-interface/lib/greeting/writer.js +139 -0
  76. package/neural-interface/lib/http-guards.js +189 -13
  77. package/neural-interface/lib/machine-names.js +88 -0
  78. package/neural-interface/lib/memory-api.js +31 -7
  79. package/neural-interface/lib/native-binary-runtime.js +69 -337
  80. package/neural-interface/lib/native-loop-providers.js +40 -49
  81. package/neural-interface/lib/offline-page.js +54 -0
  82. package/neural-interface/lib/plugin-installer.js +4 -2
  83. package/neural-interface/lib/project-storage.js +5 -7
  84. package/neural-interface/lib/request-gate.js +589 -0
  85. package/neural-interface/lib/session-title-generator.js +5 -0
  86. package/neural-interface/lib/synabun-update-plan.js +19 -0
  87. package/neural-interface/lib/ui-blob-api.js +108 -0
  88. package/neural-interface/lib/ui-blob-store.js +68 -0
  89. package/neural-interface/package-lock.json +701 -253
  90. package/neural-interface/package.json +13 -2
  91. package/neural-interface/public/install-app.html +34 -0
  92. package/neural-interface/public/manifest.json +2 -0
  93. package/neural-interface/public/offline.html +402 -66
  94. package/neural-interface/public/onboarding.html +264 -147
  95. package/neural-interface/public/shared/agent-runtime-options.js +22 -6
  96. package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
  97. package/neural-interface/public/shared/assistant/asst-brain-picker.js +312 -62
  98. package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
  99. package/neural-interface/public/shared/assistant/asst-mascot.js +26 -64
  100. package/neural-interface/public/shared/assistant/asst-menu.js +12 -8
  101. package/neural-interface/public/shared/assistant/asst-panel.js +150 -28
  102. package/neural-interface/public/shared/assistant/asst-rack-styles.js +0 -3
  103. package/neural-interface/public/shared/assistant/asst-render.js +219 -67
  104. package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
  105. package/neural-interface/public/shared/assistant/asst-route.js +23 -329
  106. package/neural-interface/public/shared/assistant/asst-routes-editor.js +495 -0
  107. package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
  108. package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
  109. package/neural-interface/public/shared/assistant/asst-state.js +185 -1
  110. package/neural-interface/public/shared/assistant/asst-styles.js +162 -6
  111. package/neural-interface/public/shared/blob-store.js +111 -22
  112. package/neural-interface/public/shared/cdx/cdx-panel.js +32 -11
  113. package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
  114. package/neural-interface/public/shared/cdx/cdx-styles.js +36 -0
  115. package/neural-interface/public/shared/cdx/cdx-tabs.js +87 -4
  116. package/neural-interface/public/shared/command-runner-model.js +30 -0
  117. package/neural-interface/public/shared/constants.js +6 -1
  118. package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
  119. package/neural-interface/public/shared/cp/cp-styles.js +15 -0
  120. package/neural-interface/public/shared/editor/editor-ai-logic.js +409 -0
  121. package/neural-interface/public/shared/editor/editor-ai.js +619 -0
  122. package/neural-interface/public/shared/editor/editor-commands.js +212 -0
  123. package/neural-interface/public/shared/editor/editor-compare.js +103 -0
  124. package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
  125. package/neural-interface/public/shared/editor/editor-doc.js +257 -0
  126. package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
  127. package/neural-interface/public/shared/editor/editor-git.js +95 -0
  128. package/neural-interface/public/shared/editor/editor-languages.js +156 -0
  129. package/neural-interface/public/shared/editor/editor-lint.js +229 -0
  130. package/neural-interface/public/shared/editor/editor-loader.js +51 -0
  131. package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
  132. package/neural-interface/public/shared/editor/editor-menu.js +233 -0
  133. package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
  134. package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
  135. package/neural-interface/public/shared/editor/editor-palette.js +125 -0
  136. package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
  137. package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
  138. package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
  139. package/neural-interface/public/shared/editor/editor-safety.js +500 -0
  140. package/neural-interface/public/shared/editor/editor-search.js +352 -0
  141. package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
  142. package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
  143. package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
  144. package/neural-interface/public/shared/editor/editor-theme.js +244 -0
  145. package/neural-interface/public/shared/editor/editor-view.js +332 -0
  146. package/neural-interface/public/shared/explorer/fx-api.js +216 -0
  147. package/neural-interface/public/shared/explorer/fx-links.js +204 -0
  148. package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
  149. package/neural-interface/public/shared/explorer/fx-main.js +865 -0
  150. package/neural-interface/public/shared/explorer/fx-names.js +87 -0
  151. package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
  152. package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
  153. package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
  154. package/neural-interface/public/shared/file-links.js +339 -0
  155. package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
  156. package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
  157. package/neural-interface/public/shared/html-shell.js +169 -170
  158. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -0
  159. package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
  160. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +99 -17
  161. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  162. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +5 -0
  163. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +40 -0
  164. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
  165. package/neural-interface/public/shared/pwa-install-page.js +62 -0
  166. package/neural-interface/public/shared/pwa-install.css +12 -0
  167. package/neural-interface/public/shared/pwa-install.js +127 -0
  168. package/neural-interface/public/shared/settings/settings-code-editor-pane.js +412 -0
  169. package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
  170. package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
  171. package/neural-interface/public/shared/settings/settings-ia.js +18 -4
  172. package/neural-interface/public/shared/settings/settings-rules.js +160 -0
  173. package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
  174. package/neural-interface/public/shared/start-bridge.js +802 -0
  175. package/neural-interface/public/shared/styleguide/sg-colors.js +5 -2
  176. package/neural-interface/public/shared/styleguide/sg-import-export.js +4 -3
  177. package/neural-interface/public/shared/styleguide/sg-kit.js +4 -1
  178. package/neural-interface/public/shared/styleguide/sg-panel.js +9 -1
  179. package/neural-interface/public/shared/styleguide/sg-typography.js +1 -0
  180. package/neural-interface/public/shared/styles.css +2219 -1117
  181. package/neural-interface/public/shared/synabun-mascot.js +20 -56
  182. package/neural-interface/public/shared/term-ready.js +307 -0
  183. package/neural-interface/public/shared/tunnel-view.js +167 -0
  184. package/neural-interface/public/shared/ui-claude-panel.js +160 -19
  185. package/neural-interface/public/shared/ui-command-runner.js +251 -468
  186. package/neural-interface/public/shared/ui-detail.js +15 -0
  187. package/neural-interface/public/shared/ui-explorer.js +22 -0
  188. package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
  189. package/neural-interface/public/shared/ui-file-links.js +103 -0
  190. package/neural-interface/public/shared/ui-help.js +26 -0
  191. package/neural-interface/public/shared/ui-invite.js +126 -116
  192. package/neural-interface/public/shared/ui-judgments.js +1 -1
  193. package/neural-interface/public/shared/ui-keybinds.js +4 -0
  194. package/neural-interface/public/shared/ui-loading.js +367 -12
  195. package/neural-interface/public/shared/ui-menubar.js +21 -55
  196. package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
  197. package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
  198. package/neural-interface/public/shared/ui-navbar.js +45 -21
  199. package/neural-interface/public/shared/ui-settings.js +491 -547
  200. package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
  201. package/neural-interface/public/shared/ui-sync.js +16 -0
  202. package/neural-interface/public/shared/ui-terminal.js +153 -149
  203. package/neural-interface/public/shared/ui-tunnel.js +130 -0
  204. package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
  205. package/neural-interface/public/shared/ui-whiteboard.js +12 -0
  206. package/neural-interface/public/shared/ui-worker-end.js +245 -0
  207. package/neural-interface/public/shared/ui-workspaces.js +41 -27
  208. package/neural-interface/public/shared/worker-end.js +251 -0
  209. package/neural-interface/public/sw.js +3 -1
  210. package/neural-interface/public/variant/2d/main.js +2 -1
  211. package/neural-interface/public/variant/3d/main.js +2 -1
  212. package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
  213. package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
  214. package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
  215. package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
  216. package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
  217. package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
  218. package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
  219. package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
  220. package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
  221. package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
  222. package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
  223. package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
  224. package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
  225. package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
  226. package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
  227. package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
  228. package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
  229. package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
  230. package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
  231. package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
  232. package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
  233. package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
  234. package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
  235. package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
  236. package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
  237. package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
  238. package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
  239. package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
  240. package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
  241. package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
  242. package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
  243. package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
  244. package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
  245. package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
  246. package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
  247. package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
  248. package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
  249. package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
  250. package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
  251. package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
  252. package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
  253. package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
  254. package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
  255. package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
  256. package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
  257. package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
  258. package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
  259. package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
  260. package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
  261. package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
  262. package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
  263. package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
  264. package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
  265. package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
  266. package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
  267. package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
  268. package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
  269. package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
  270. package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
  271. package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
  272. package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
  273. package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
  274. package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
  275. package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
  276. package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
  277. package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
  278. package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
  279. package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
  280. package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
  281. package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
  282. package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
  283. package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
  284. package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
  285. package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
  286. package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
  287. package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
  288. package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
  289. package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
  290. package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
  291. package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
  292. package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
  293. package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
  294. package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
  295. package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
  296. package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
  297. package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
  298. package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
  299. package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
  300. package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
  301. package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
  302. package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
  303. package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
  304. package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
  305. package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
  306. package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
  307. package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
  308. package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
  309. package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
  310. package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
  311. package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
  312. package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
  313. package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
  314. package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
  315. package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
  316. package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
  317. package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
  318. package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
  319. package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
  320. package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
  321. package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
  322. package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
  323. package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
  324. package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
  325. package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
  326. package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
  327. package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
  328. package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
  329. package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
  330. package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
  331. package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
  332. package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
  333. package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
  334. package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
  335. package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
  336. package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
  337. package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
  338. package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
  339. package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
  340. package/neural-interface/scripts/build-vendor.mjs +78 -2
  341. package/neural-interface/scripts/rebuild-pty.js +15 -12
  342. package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
  343. package/neural-interface/server.js +1092 -1212
  344. package/neural-interface/templates/rulesets/README.md +1 -1
  345. package/package.json +13 -7
  346. package/postinstall.js +11 -81
  347. package/setup.js +111 -6
  348. package/benchmarks/browser-live-results.json +0 -79
  349. package/benchmarks/browser-v2-results.json +0 -258
  350. package/docs/browser-v2.md +0 -109
  351. package/docs/hook-integrity.md +0 -89
  352. package/docs/judgments.md +0 -182
  353. package/docs/style-guide.md +0 -246
  354. package/neural-interface/lib/codex-capabilities.d.ts +0 -41
  355. package/neural-interface/public/category-logos/claude.svg +0 -1
  356. package/neural-interface/public/category-logos/gemini-color.svg +0 -1
  357. package/neural-interface/public/category-logos/openai.svg +0 -1
  358. package/neural-interface/public/category-logos/synabun.png +0 -0
  359. package/neural-interface/public/claude.svg +0 -1
  360. package/neural-interface/public/gallery.svg +0 -6
  361. package/neural-interface/public/leonardoai.svg +0 -1
  362. package/neural-interface/public/mcp.svg +0 -4
  363. package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
  364. package/neural-interface/public/pin-svgrepo-com.svg +0 -25
  365. package/neural-interface/public/sessionicon.svg +0 -8
  366. package/neural-interface/public/toolbar-album.svg +0 -8
  367. package/neural-interface/public/toolbar-question.svg +0 -6
  368. package/neural-interface/public/toolbar-sessions.svg +0 -6
  369. package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
  370. package/scripts/audit-claude-hook-usage.mjs +0 -12
  371. package/scripts/audit-memory-duplicates.mjs +0 -44
  372. package/scripts/measure-claude-hook-overhead.mjs +0 -77
  373. package/scripts/recover-user-config.mjs +0 -254
  374. package/skills/synabun/synabunicon.png +0 -0
@@ -8,11 +8,13 @@
8
8
  // the face, plus one prop drawn in the face's own pill geometry. Rigs draw
9
9
  // from the shared ticker (shared/synabun-ticker.js): 30 fps while a pose
10
10
  // loops, 60 fps for blends and reactions, no frames at all while still. One
11
- // pointermove listener and one IntersectionObserver serve every rig, and only
12
- // one rig at a time plays a pose loop (the one posed most recently); the
13
- // others hold their pose's still frame. Under prefers-reduced-motion every
14
- // pose is its still frame and changes are instant. A rig tears itself down
15
- // once its SVG leaves the document.
11
+ // loop, one pointermove listener and one IntersectionObserver serve every rig,
12
+ // and every rig that is active and on screen plays its own pose: N rigs move
13
+ // at once, each on its own clock. No rig waits for another; a host that wants
14
+ // one moving character among several of its own (an Assistant panel's hero,
15
+ // stage and "Thinking" row) says so with setActive(). Under
16
+ // prefers-reduced-motion every pose is its still frame and changes are
17
+ // instant. A rig tears itself down once its SVG leaves the document.
16
18
  //
17
19
  // v1 callers are unchanged: createMascot(container, opts) → { el, destroy,
18
20
  // look, blink }, idle, blinking every 3-7 s and following the cursor.
@@ -307,7 +309,7 @@ const MINIS = [
307
309
  ];
308
310
 
309
311
  /**
310
- * motion: 'loop' (30 fps while it leads), 'blink' (still between slow blinks),
312
+ * motion: 'loop' (30 fps), 'blink' (still between slow blinks),
311
313
  * 'once' (plays `settle` ms, then still; `hold` before opts.then), 'still'.
312
314
  * blinks: random blinks every 3-7 s. tracks: follows the cursor.
313
315
  * look: follows look(), easing with this time constant (ms).
@@ -994,26 +996,15 @@ export function paintMascot(svg, frame) {
994
996
  painter.paint(frame);
995
997
  }
996
998
 
997
- // ── Shared runtime: one observer, one motion listener, one lead ──
999
+ // ── Shared runtime: one observer and one motion listener for every rig ──
1000
+ // Nothing here picks a rig: each one decides from its own state (active, on
1001
+ // screen, motion allowed) whether it moves.
998
1002
 
999
1003
  const rigs = new Set();
1000
- let leadRig = null;
1001
- let promoteSeq = 0;
1002
1004
  let stopMotionWatch = null;
1003
1005
  let io = null;
1004
1006
  const ioRigs = new WeakMap();
1005
1007
 
1006
- /** Only one rig plays a pose loop: the most recently posed one that wants to. */
1007
- function elect() {
1008
- let best = null;
1009
- for (const rig of rigs) if (rig.wantsLead() && (!best || rig.promotedAt() > best.promotedAt())) best = rig;
1010
- if (best === leadRig) return;
1011
- const prev = leadRig;
1012
- leadRig = best;
1013
- prev?.leadChanged();
1014
- best?.leadChanged();
1015
- }
1016
-
1017
1008
  function observe(el, rig) {
1018
1009
  if (typeof IntersectionObserver !== 'function') return;
1019
1010
  try {
@@ -1034,13 +1025,11 @@ function register(rig) {
1034
1025
  rigs.add(rig);
1035
1026
  stopMotionWatch ||= onReducedMotionChange(() => {
1036
1027
  for (const r of Array.from(rigs)) r.motionChanged();
1037
- elect();
1038
1028
  });
1039
1029
  }
1040
1030
 
1041
1031
  function unregister(rig) {
1042
1032
  rigs.delete(rig);
1043
- if (leadRig === rig) { leadRig = null; elect(); }
1044
1033
  if (!rigs.size && stopMotionWatch) { stopMotionWatch(); stopMotionWatch = null; }
1045
1034
  }
1046
1035
 
@@ -1088,14 +1077,12 @@ export function createMascot(container, options) {
1088
1077
  let active = startActive !== false;
1089
1078
  let visible = true;
1090
1079
  let seenConnected = svg.isConnected;
1091
- let promotedAt = (promoteSeq += 1);
1092
1080
  let clock = 0; // rig time in ms: the ticker's dt while drawing, real time while still
1093
1081
  let frozenAt = tickerNow(); // while not drawing: when the clock was last brought up to date; -1 while drawing
1094
1082
  let pose = { name: 'idle', raw: {}, start: 0, then: null };
1095
1083
  let settled = false; // a one-shot's opts.then has fired
1096
1084
  let blend = null; // { from, start, dur }
1097
1085
  let lastFrame = null; // the last frame before blinks and reactions
1098
- let drawn = false; // has drawn a live frame (a never-drawn rig has nothing to blend from)
1099
1086
  let look = { x: 0, y: 0 }; // eased gaze
1100
1087
  let track = { x: 0, y: 0 }; // idle: where the cursor (or look()) points
1101
1088
  let hostLook = { x: 0, y: 0 };
@@ -1119,10 +1106,10 @@ export function createMascot(container, options) {
1119
1106
 
1120
1107
  const def = () => POSES[pose.name];
1121
1108
  const animating = () => !destroyed && active && visible && !isReducedMotion();
1122
- const isLead = () => leadRig === rig;
1123
1109
  const poseTime = () => clock - pose.start;
1124
1110
 
1125
- function wantsLead() {
1111
+ /** This pose moves on its own right now: a loop, a patient pose, a one-shot still playing. */
1112
+ function playing() {
1126
1113
  if (!animating()) return false;
1127
1114
  const { motion, settle } = def();
1128
1115
  if (motion === 'loop' || motion === 'blink') return true;
@@ -1186,7 +1173,6 @@ export function createMascot(container, options) {
1186
1173
  function nextRate() {
1187
1174
  if (!animating()) return 0;
1188
1175
  if (blend || blinkStart >= 0 || reactions.length || aim || easing() || miniPopping()) return 60;
1189
- if (!isLead()) return 0;
1190
1176
  const d = def();
1191
1177
  const t = poseTime();
1192
1178
  if (d.motion === 'loop') return 30;
@@ -1208,9 +1194,9 @@ export function createMascot(container, options) {
1208
1194
  const d = def();
1209
1195
  const at0 = tickerNow();
1210
1196
  let at = Infinity;
1211
- if (d.blinks && (d.motion === 'still' || isLead())) at = Math.min(at, nextBlinkAt);
1197
+ if (d.blinks) at = Math.min(at, nextBlinkAt);
1212
1198
  if (d.tracks) at = Math.min(at, nextGlanceAt, nextFidgetAt, glance ? glance.until : Infinity);
1213
- if (d.motion === 'blink' && isLead()) at = Math.min(at, at0 + d.idleFor(poseTime()));
1199
+ if (d.motion === 'blink') at = Math.min(at, at0 + d.idleFor(poseTime()));
1214
1200
  if (d.motion === 'once' && pose.then && !settled) at = Math.min(at, at0 + Math.max(0, d.settle + (d.hold || 0) - poseTime()));
1215
1201
  if (!Number.isFinite(at)) return;
1216
1202
  wakeTimer = setTimeout(() => {
@@ -1243,15 +1229,15 @@ export function createMascot(container, options) {
1243
1229
  function handleDue() {
1244
1230
  const d = def();
1245
1231
  const t = tickerNow();
1246
- if (d.blinks && (d.motion === 'still' || isLead()) && t >= nextBlinkAt) {
1232
+ if (d.blinks && t >= nextBlinkAt) {
1247
1233
  nextBlinkAt = t + rand(3000, 7000);
1248
1234
  startBlink();
1249
1235
  }
1250
1236
  if (d.tracks) {
1251
1237
  if (glance && t >= glance.until) glance = null;
1252
1238
  if (t >= nextGlanceAt) {
1253
- // Only while the cursor is still and no other rig is busy.
1254
- if (t - pointerAt < 2500 || leadRig) nextGlanceAt = t + 3000;
1239
+ // Only while the cursor is still.
1240
+ if (t - pointerAt < 2500) nextGlanceAt = t + 3000;
1255
1241
  else {
1256
1242
  const [x, y] = GLANCES[Math.floor(Math.random() * GLANCES.length)];
1257
1243
  glance = { x, y, until: t + rand(700, 1000) };
@@ -1261,7 +1247,6 @@ export function createMascot(container, options) {
1261
1247
  if (t >= nextFidgetAt) {
1262
1248
  const quietFor = t - Math.max(lastInputAt(), pointerAt);
1263
1249
  if (quietFor < 20000) nextFidgetAt = t + (20000 - quietFor) + rand(0, 5000);
1264
- else if (leadRig) nextFidgetAt = t + 10000;
1265
1250
  else {
1266
1251
  nextFidgetAt = t + rand(45000, 75000);
1267
1252
  startReaction(Math.random() < 0.5 ? 'hop' : 'wiggle');
@@ -1303,8 +1288,7 @@ export function createMascot(container, options) {
1303
1288
 
1304
1289
  /** The pose frame this rig would draw now, before blends and overlays. */
1305
1290
  function frameNow() {
1306
- const loopOn = isLead() && def().motion !== 'still';
1307
- return poseFrame(pose.name, poseTime(), { ...pose.raw, look, range, ticks, still: !loopOn });
1291
+ return poseFrame(pose.name, poseTime(), { ...pose.raw, look, range, ticks, still: !playing() });
1308
1292
  }
1309
1293
 
1310
1294
  /** Ease from what is on screen to what comes next, unless they already match. */
@@ -1400,10 +1384,7 @@ export function createMascot(container, options) {
1400
1384
  handleDue();
1401
1385
  if (aim) { aimAt(aim); aim = null; }
1402
1386
  easeLook(dt);
1403
- const wasLead = isLead();
1404
1387
  painter.paint(compose());
1405
- drawn = true;
1406
- if (wasLead && def().motion === 'once' && poseTime() >= def().settle) elect();
1407
1388
  const rate = nextRate();
1408
1389
  setRate(rate);
1409
1390
  if (!rate) armWake();
@@ -1497,9 +1478,7 @@ export function createMascot(container, options) {
1497
1478
  }
1498
1479
  scheduleIdle();
1499
1480
  }
1500
- promotedAt = (promoteSeq += 1);
1501
1481
  if (animating()) requestFrames(BLEND_MS);
1502
- elect();
1503
1482
  refresh();
1504
1483
  return api;
1505
1484
  }
@@ -1537,8 +1516,7 @@ export function createMascot(container, options) {
1537
1516
  const next = !!on;
1538
1517
  if (destroyed || next === active) return api;
1539
1518
  active = next;
1540
- if (active) { promotedAt = (promoteSeq += 1); revive(); }
1541
- elect();
1519
+ if (active) revive();
1542
1520
  refresh();
1543
1521
  return api;
1544
1522
  }
@@ -1560,18 +1538,6 @@ export function createMascot(container, options) {
1560
1538
  }
1561
1539
 
1562
1540
  const rig = {
1563
- promotedAt: () => promotedAt,
1564
- wantsLead,
1565
- leadChanged() {
1566
- if (destroyed) return;
1567
- // Gaining or losing the loop swaps the still frame for the live one: blend
1568
- // when they differ (a patient pose between blinks, a settled one-shot: no).
1569
- if (drawn && animating()) {
1570
- syncClock();
1571
- blendIn();
1572
- }
1573
- refresh();
1574
- },
1575
1541
  visibilityChanged(inView) {
1576
1542
  if (destroyed) return;
1577
1543
  if (svg.isConnected) seenConnected = true;
@@ -1579,7 +1545,6 @@ export function createMascot(container, options) {
1579
1545
  const was = visible;
1580
1546
  visible = inView;
1581
1547
  if (visible && !was) revive();
1582
- elect();
1583
1548
  refresh(); // also wakes a rig that was built before it was attached
1584
1549
  },
1585
1550
  motionChanged() {
@@ -1619,7 +1584,6 @@ export function createMascot(container, options) {
1619
1584
  if (p) aim = p;
1620
1585
  }
1621
1586
  }
1622
- elect();
1623
1587
  refresh();
1624
1588
  return api;
1625
1589
  }
@@ -0,0 +1,307 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — Terminal readiness
3
+ // When a freshly opened terminal can take a typed command, and how to hand it
4
+ // over. DOM-free: ui-terminal.js feeds it the output stream and does the I/O.
5
+ // ═══════════════════════════════════════════
6
+
7
+ // CSI, OSC (BEL or ST terminated), charset selection, and the two-byte escapes.
8
+ const ESCAPES_RE = /\x1b\[[\x20-\x3f]*[\x40-\x7e]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[()][AB012]|\x1b[=>78MDEHNOc]/g;
9
+
10
+ // What _sendOnceReady has always stripped and matched for the CLIs (Claude
11
+ // Code, Codex, …). Kept as it was: the loops depend on this exact reading.
12
+ const CLI_ANSI_RE = /\x1b\[[\x20-\x3f]*[\x40-\x7e]|\x1b\][^\x07]*\x07|\x1b[()][AB012]/g;
13
+ const CLI_READY_PATTERNS = [
14
+ /^>\s*$/m, // Claude Code prompt: ">" on its own line
15
+ /\n>\s*$/, // ">" after newline at end of output
16
+ />\s*$/, // ">" at end of buffer (catch partial lines)
17
+ /❯/, // ❯ (some CLI prompts)
18
+ /\$ $/, // Shell prompt fallback
19
+ ];
20
+
21
+ // The line editor (zsh's ZLE, readline in bash 5, fish) turns bracketed paste
22
+ // on when it starts reading a line and off when a command runs.
23
+ const PASTE_ON = '\x1b[?2004h';
24
+ const PASTE_OFF = '\x1b[?2004l';
25
+ // Shell integration marks (FinalTerm / OSC 133): B = the prompt has ended,
26
+ // C = a command is running.
27
+ const MARK_PROMPT_END = '\x1b]133;B';
28
+ const MARK_RUNNING = '\x1b]133;C';
29
+
30
+ // The character a prompt ends in: zsh %, bash/sh $, root #, cmd.exe / PowerShell
31
+ // / fish >, and the arrows the common themes use. A reconnect snapshot trims the
32
+ // trailing space, so the space is optional.
33
+ const PROMPT_TAIL_RE = /[%$#>❯➜»›→▶λ][ \t]*$/;
34
+
35
+ const BUFFER_MAX = 16384;
36
+ const BUFFER_KEEP = 8192;
37
+
38
+ // capMs runs from the moment the terminal's socket is open, never from the
39
+ // call: a socket that takes its time must not eat into the wait for a prompt.
40
+ // openGraceMs is how much longer than that a socket may take to open at all.
41
+ export const READY_LIMITS = Object.freeze({
42
+ // A shell takes typeahead, so its limits are short: the worst case is a
43
+ // command typed a moment before the prompt is drawn, never a lost one.
44
+ shell: Object.freeze({ quietMs: 350, capMs: 5000, settleMs: 40, openGraceMs: 2000 }),
45
+ // A CLI started inside the shell swallows input typed before its own prompt.
46
+ cli: Object.freeze({ quietMs: 0, capMs: 15000, settleMs: 500, openGraceMs: 2000 }),
47
+ });
48
+
49
+ /** Which reading a terminal profile gets. */
50
+ export function readinessKind(profile) {
51
+ return profile === 'shell' ? 'shell' : 'cli';
52
+ }
53
+
54
+ export function stripEscapes(text) {
55
+ return String(text || '').replace(ESCAPES_RE, '');
56
+ }
57
+
58
+ function lastOn(raw, on, off) {
59
+ const at = raw.lastIndexOf(on);
60
+ return at >= 0 && at > raw.lastIndexOf(off);
61
+ }
62
+
63
+ /**
64
+ * Read everything a terminal printed so far. Returns the reason it is ready
65
+ * ('line-editor', 'prompt-mark', 'prompt') or null.
66
+ */
67
+ export function readySignal(raw, kind = 'shell') {
68
+ const text = String(raw || '');
69
+ if (!text) return null;
70
+ if (kind !== 'shell') {
71
+ const clean = text.replace(CLI_ANSI_RE, '');
72
+ return CLI_READY_PATTERNS.some(p => p.test(clean)) ? 'prompt' : null;
73
+ }
74
+ if (lastOn(text, PASTE_ON, PASTE_OFF)) return 'line-editor';
75
+ if (lastOn(text, MARK_PROMPT_END, MARK_RUNNING)) return 'prompt-mark';
76
+ // The line the cursor is on: zsh draws its prompt after "\r \r", so a
77
+ // carriage return starts a line here just like a newline does.
78
+ const clean = stripEscapes(text);
79
+ const line = clean.slice(Math.max(clean.lastIndexOf('\n'), clean.lastIndexOf('\r')) + 1);
80
+ return line.trim() && PROMPT_TAIL_RE.test(line) ? 'prompt' : null;
81
+ }
82
+
83
+ /**
84
+ * Watch one terminal until it can take input, then call onReady(reason) once.
85
+ * output(text) — output arrived (live bytes, or what was already buffered)
86
+ * replace(text) — a snapshot replaced the screen (connect / reconnect)
87
+ * poke() — the emulator parsed something: re-read its line-editor mode
88
+ * start() — the wait begins
89
+ * opened() — the terminal's socket is open
90
+ * cancel()
91
+ * Nothing is decided before opened(): the readiness window (capMs, and the
92
+ * quiet rule) runs from there, in full, however late the socket opens. What
93
+ * was fed in earlier is read at that moment. A socket that never opens ends
94
+ * the wait capMs + openGraceMs after start().
95
+ * Reasons: 'line-editor' | 'prompt-mark' | 'prompt' | 'quiet' | 'timeout'.
96
+ */
97
+ export function createReadyWatch({
98
+ kind = 'shell',
99
+ onReady,
100
+ lineEditorActive = null,
101
+ limits = READY_LIMITS[kind] || READY_LIMITS.cli,
102
+ timers = { set: (fn, ms) => setTimeout(fn, ms), clear: (id) => clearTimeout(id) },
103
+ } = {}) {
104
+ let buf = '';
105
+ let done = false;
106
+ let started = false;
107
+ let open = false;
108
+ let sawOutput = false;
109
+ let quietTimer = null;
110
+ let capTimer = null;
111
+ let openTimer = null;
112
+
113
+ function clearTimers() {
114
+ if (quietTimer) timers.clear(quietTimer);
115
+ if (capTimer) timers.clear(capTimer);
116
+ if (openTimer) timers.clear(openTimer);
117
+ quietTimer = capTimer = openTimer = null;
118
+ }
119
+
120
+ function finish(reason) {
121
+ if (done) return;
122
+ done = true;
123
+ clearTimers();
124
+ try { onReady?.(reason); } catch {}
125
+ }
126
+
127
+ // Something a person could see. A connect snapshot of an empty screen and a
128
+ // shell's terminal queries are escape codes only: not a sign of life yet.
129
+ function noteOutput(text) {
130
+ if (!sawOutput && /\S/.test(stripEscapes(text))) sawOutput = true;
131
+ }
132
+
133
+ function armQuiet() {
134
+ if (done || !open || !sawOutput || !(limits.quietMs > 0)) return;
135
+ if (quietTimer) timers.clear(quietTimer);
136
+ quietTimer = timers.set(() => { quietTimer = null; finish('quiet'); }, limits.quietMs);
137
+ }
138
+
139
+ function evaluate() {
140
+ if (done || !open) return;
141
+ const signal = readySignal(buf, kind);
142
+ if (signal) { finish(signal); return; }
143
+ if (kind === 'shell' && lineEditorActive) {
144
+ let active = false;
145
+ try { active = lineEditorActive() === true; } catch {}
146
+ if (active) { finish('line-editor'); return; }
147
+ }
148
+ armQuiet();
149
+ }
150
+
151
+ return {
152
+ output(text) {
153
+ if (done || !text) return;
154
+ noteOutput(text);
155
+ buf += text;
156
+ if (buf.length > BUFFER_MAX) buf = buf.slice(-BUFFER_KEEP);
157
+ evaluate();
158
+ },
159
+ replace(text) {
160
+ if (done) return;
161
+ buf = String(text || '');
162
+ noteOutput(buf);
163
+ evaluate();
164
+ },
165
+ poke() {
166
+ if (done || !open || kind !== 'shell' || !lineEditorActive) return;
167
+ let active = false;
168
+ try { active = lineEditorActive() === true; } catch {}
169
+ if (active) finish('line-editor');
170
+ },
171
+ start() {
172
+ if (done || started) return;
173
+ started = true;
174
+ if (open) return;
175
+ openTimer = timers.set(() => { openTimer = null; finish('timeout'); }, limits.capMs + (limits.openGraceMs || 0));
176
+ },
177
+ opened() {
178
+ if (done || open) return; // a reconnect later on does not restart the window
179
+ started = true;
180
+ open = true;
181
+ if (openTimer) timers.clear(openTimer);
182
+ openTimer = null;
183
+ capTimer = timers.set(() => { capTimer = null; finish('timeout'); }, limits.capMs);
184
+ evaluate();
185
+ },
186
+ cancel() {
187
+ if (done) return;
188
+ done = true;
189
+ clearTimers();
190
+ },
191
+ get done() { return done; },
192
+ get open() { return open; },
193
+ };
194
+ }
195
+
196
+ /** Split typed input into the writes the PTY gets (ConPTY drops long ones). */
197
+ export function inputChunks(text, size = 256) {
198
+ const full = String(text ?? '');
199
+ const out = [];
200
+ for (let i = 0; i < full.length; i += size) out.push(full.slice(i, i + size));
201
+ return out;
202
+ }
203
+
204
+ /**
205
+ * Type `text` into a terminal: every chunk in order, each through the socket
206
+ * that is current at that moment (a reconnect swaps it). Waits for an open
207
+ * socket instead of dropping the input, and stops for good the moment a chunk
208
+ * cannot be delivered — a command with a hole in it must never reach Enter.
209
+ * socket() → the session's current socket ({ readyState, send }) or null
210
+ * alive() → false once the terminal is gone
211
+ * Resolves { ok, sent, chunks, reason? } with reason 'closed' | 'no-socket'.
212
+ */
213
+ export async function typeInto({
214
+ socket,
215
+ alive = () => true,
216
+ text,
217
+ chunkSize = 256,
218
+ gapMs = 30,
219
+ openWaitMs = 10000,
220
+ pollMs = 25,
221
+ OPEN = 1,
222
+ sleep = (ms) => new Promise(r => setTimeout(r, ms)),
223
+ now = () => Date.now(),
224
+ } = {}) {
225
+ const chunks = inputChunks(text, chunkSize);
226
+ let sent = 0;
227
+ for (const chunk of chunks) {
228
+ const deadline = now() + openWaitMs;
229
+ let ws = socket();
230
+ while (alive() && (!ws || ws.readyState !== OPEN) && now() < deadline) {
231
+ // Mid-command the wait is over: what follows a gap would be a different command.
232
+ if (sent > 0) return { ok: false, sent, chunks: chunks.length, reason: 'closed' };
233
+ await sleep(pollMs);
234
+ ws = socket();
235
+ }
236
+ if (!alive()) return { ok: false, sent, chunks: chunks.length, reason: 'closed' };
237
+ if (!ws || ws.readyState !== OPEN) return { ok: false, sent, chunks: chunks.length, reason: 'no-socket' };
238
+ try { ws.send(JSON.stringify({ type: 'input', data: chunk })); }
239
+ catch { return { ok: false, sent, chunks: chunks.length, reason: 'closed' }; }
240
+ sent++;
241
+ if (sent < chunks.length) await sleep(gapMs);
242
+ }
243
+ return { ok: true, sent, chunks: chunks.length };
244
+ }
245
+
246
+ /**
247
+ * The whole hand-over of one message: wait until the terminal can take it, let
248
+ * it settle, type it. Everything that touches the page is handed in, so this
249
+ * runs the same under a test clock.
250
+ * socket() → the session's current socket (a reconnect swaps it)
251
+ * alive() → false once the terminal is gone
252
+ * lineEditorActive() → the emulator's bracketed-paste mode
253
+ * buffered → output that arrived before this call
254
+ * subscribe({ output(text, replaced), opened(), parsed() }) → unsubscribe
255
+ * output for every chunk, opened whenever a socket of
256
+ * this session opens, parsed after the emulator parsed
257
+ * onReady(reason, waitedMs)
258
+ * Resolves { ok: true, reason, waitedMs } or { ok: false, reason, sent, chunks }.
259
+ */
260
+ export function typeWhenReady({
261
+ kind = 'shell',
262
+ text,
263
+ socket,
264
+ alive = () => true,
265
+ lineEditorActive = null,
266
+ buffered = '',
267
+ subscribe = null,
268
+ onReady = () => {},
269
+ OPEN = 1,
270
+ limits = READY_LIMITS[kind] || READY_LIMITS.cli,
271
+ timers = { set: (fn, ms) => setTimeout(fn, ms), clear: (id) => clearTimeout(id) },
272
+ now = () => Date.now(),
273
+ sleep = (ms) => new Promise(r => timers.set(r, ms)),
274
+ } = {}) {
275
+ return new Promise((resolve) => {
276
+ const t0 = now();
277
+ let unsubscribe = null;
278
+ const watch = createReadyWatch({
279
+ kind,
280
+ lineEditorActive,
281
+ limits,
282
+ timers,
283
+ onReady: (reason) => {
284
+ try { unsubscribe?.(); } catch {}
285
+ unsubscribe = null;
286
+ const waitedMs = Math.round(now() - t0);
287
+ try { onReady(reason, waitedMs); } catch {}
288
+ timers.set(async () => {
289
+ const result = await typeInto({ socket, alive, text, OPEN, sleep, now });
290
+ resolve(result.ok
291
+ ? { ok: true, reason, waitedMs }
292
+ : { ok: false, reason: result.reason, sent: result.sent, chunks: result.chunks });
293
+ }, limits.settleMs);
294
+ },
295
+ });
296
+ // Subscribed before anything can be decided: no verdict comes before opened().
297
+ unsubscribe = subscribe?.({
298
+ output: (chunk, replaced) => { if (replaced) watch.replace(chunk); else watch.output(chunk); },
299
+ opened: () => watch.opened(),
300
+ parsed: () => watch.poke(),
301
+ }) || null;
302
+ if (buffered) watch.output(buffered);
303
+ watch.start();
304
+ const ws = socket?.();
305
+ if (ws && ws.readyState === OPEN) watch.opened();
306
+ });
307
+ }