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
@@ -10,6 +10,38 @@
10
10
  const _putTimers = new Map(); // `${ns}/${id}` -> timeout id
11
11
  const _pendingPuts = new Map(); // `${ns}/${id}` -> { ns, id, value, opts }
12
12
  const DEFAULT_DEBOUNCE_MS = 500;
13
+ // One request per entry at a time, in the order they were asked for: a delete
14
+ // (or a newer write) that overtook a write still on its way would be undone by it.
15
+ const _inFlight = new Map(); // `${ns}/${id}` -> the request under way (a write or a delete); never rejects
16
+ const _waitingDeletes = new Map(); // `${ns}/${id}` -> sends the delete that waits behind that request
17
+ const _asked = new Map(); // `${ns}/${id}` -> counts the puts and deletes asked for
18
+
19
+ // Every put and delete of this page is numbered when it is asked for, and says which page it is of. Of two
20
+ // requests of one page for an entry the server keeps the one with the higher number, whichever arrives first
21
+ // (lib/ui-blob-store.js): what is sent while the page is being left (flushBlobs) cannot be put in an order here.
22
+ // A server from before this ignores the two fields; the order kept above is then all there is, as it was.
23
+ const _writer = (() => {
24
+ try { return Array.from(crypto.getRandomValues(new Uint8Array(12)), (byte) => byte.toString(16).padStart(2, '0')).join(''); }
25
+ catch { return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`; }
26
+ })();
27
+ let _revision = 0;
28
+
29
+ /** The address of one entry, for the request numbered `rev` (and what a write asks to be evicted). */
30
+ const _url = (ns, id, rev, opts = {}) => {
31
+ const params = new URLSearchParams();
32
+ if (opts.maxEntries) params.set('maxEntries', String(opts.maxEntries));
33
+ if (opts.maxChars) params.set('maxChars', String(opts.maxChars));
34
+ params.set('rev', String(rev));
35
+ params.set('writer', _writer);
36
+ return `/api/ui-blobs/${encodeURIComponent(ns)}/${encodeURIComponent(id)}?${params.toString()}`;
37
+ };
38
+ const _ask = (key) => { const n = (_asked.get(key) || 0) + 1; _asked.set(key, n); return n; };
39
+
40
+ function _track(key, request) {
41
+ const tracked = Promise.resolve(request).then(() => {}, () => {}).then(() => { if (_inFlight.get(key) === tracked) _inFlight.delete(key); });
42
+ _inFlight.set(key, tracked);
43
+ return tracked;
44
+ }
13
45
 
14
46
  export async function fetchBlobNamespace(ns) {
15
47
  try {
@@ -22,68 +54,125 @@ export async function fetchBlobNamespace(ns) {
22
54
  }
23
55
  }
24
56
 
57
+ // One entry, or null: there is none, or the server has no such namespace.
58
+ export async function fetchBlob(ns, id) {
59
+ try {
60
+ const res = await fetch(`/api/ui-blobs/${encodeURIComponent(ns)}/${encodeURIComponent(id)}`);
61
+ if (!res.ok) return null;
62
+ return await res.json();
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+
25
68
  async function _sendPut(key) {
26
69
  const pending = _pendingPuts.get(key);
27
70
  if (!pending) return;
28
- _pendingPuts.delete(key);
29
71
  _putTimers.delete(key);
30
- const { ns, id, value, opts } = pending;
31
- const params = new URLSearchParams();
32
- if (opts.maxEntries) params.set('maxEntries', String(opts.maxEntries));
33
- if (opts.maxChars) params.set('maxChars', String(opts.maxChars));
34
- const qs = params.toString();
35
- try {
36
- const res = await fetch(`/api/ui-blobs/${encodeURIComponent(ns)}/${encodeURIComponent(id)}${qs ? '?' + qs : ''}`, {
72
+ // Something of this entry is on its way: this write goes when that is settled (still pending until then).
73
+ const busy = _inFlight.get(key);
74
+ if (busy) { busy.then(() => _sendPut(key)); return; }
75
+ _pendingPuts.delete(key);
76
+ const { ns, id, value, opts, rev } = pending;
77
+ const asked = _asked.get(key);
78
+ const request = (async () => {
79
+ const res = await fetch(_url(ns, id, rev, opts), {
37
80
  method: 'PUT',
38
81
  headers: { 'Content-Type': 'application/json' },
39
82
  body: JSON.stringify(value),
40
83
  });
41
84
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
85
+ })();
86
+ _track(key, request);
87
+ try {
88
+ await request;
89
+ _answer(pending.waiters, true);
42
90
  } catch (err) {
43
- console.warn(`[blob-store] PUT ${ns}/${id} failed:`, err.message, '— will retry');
44
- // Re-queue unless a newer value superseded this one while in flight.
45
- if (!_pendingPuts.has(key)) {
91
+ // Re-queue only if nothing was asked for this entry meanwhile: a newer value superseded this one, or the
92
+ // entry was deleted (a retry would bring back what was removed).
93
+ const retry = _asked.get(key) === asked && !_pendingPuts.has(key);
94
+ console.warn(`[blob-store] PUT ${ns}/${id} failed:`, err.message, retry ? '— will retry' : '— superseded');
95
+ if (retry) {
46
96
  _pendingPuts.set(key, pending);
47
97
  _putTimers.set(key, setTimeout(() => _sendPut(key), 2000));
98
+ } else {
99
+ // Whoever waits for this write waits for the newer one that took its place; without one (the entry was
100
+ // deleted) it was given up.
101
+ const newer = _pendingPuts.get(key);
102
+ if (newer) newer.waiters.push(...pending.waiters.splice(0));
103
+ else _answer(pending.waiters, false);
48
104
  }
49
105
  }
50
106
  }
51
107
 
52
- // Debounced per-(ns,id), latest value wins.
108
+ // What the callers of putBlob that wait for it are told: `true`, the server has the value (or a newer one of the
109
+ // entry); `false`, the write was given up.
110
+ const _answer = (waiters, stored) => { for (const done of waiters.splice(0)) done(stored); };
111
+
112
+ // Debounced per-(ns,id), latest value wins. Answers a promise, for a caller that must not go on before the value
113
+ // is in the store: `true` once the server has stored it (or a newer value of the entry, when one was asked for
114
+ // meanwhile), `false` when the write was given up (the entry was deleted, or the page is going and the write was
115
+ // handed to a beacon, which says nothing back). It never rejects; a write that fails is tried again as before, and
116
+ // the promise waits with it.
53
117
  export function putBlob(ns, id, value, opts = {}) {
54
118
  const key = `${ns}/${id}`;
55
119
  const debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
56
- _pendingPuts.set(key, { ns, id, value, opts });
120
+ _ask(key);
121
+ const waiters = _pendingPuts.get(key)?.waiters || [];
122
+ const stored = new Promise((done) => { waiters.push(done); });
123
+ _pendingPuts.set(key, { ns, id, value, opts, rev: ++_revision, waiters });
57
124
  if (_putTimers.has(key)) clearTimeout(_putTimers.get(key));
58
125
  _putTimers.set(key, setTimeout(() => _sendPut(key), debounceMs));
126
+ return stored;
59
127
  }
60
128
 
129
+ // A delete is tried once: one that failed (the server could not make it, refused it, or was not reached) is not
130
+ // sent again. This page cannot know what another page has written to the entry since, and a delete that arrived
131
+ // late would remove that.
61
132
  export function deleteBlob(ns, id) {
62
133
  const key = `${ns}/${id}`;
63
134
  if (_putTimers.has(key)) { clearTimeout(_putTimers.get(key)); _putTimers.delete(key); }
135
+ const dropped = _pendingPuts.get(key);
64
136
  _pendingPuts.delete(key);
65
- fetch(`/api/ui-blobs/${encodeURIComponent(ns)}/${encodeURIComponent(id)}`, { method: 'DELETE' })
66
- .catch(() => {});
137
+ if (dropped) _answer(dropped.waiters, false);
138
+ _ask(key);
139
+ const rev = ++_revision;
140
+ const send = (init = {}) => fetch(_url(ns, id, rev), { method: 'DELETE', ...init }).catch(() => {});
141
+ const busy = _inFlight.get(key);
142
+ if (!busy) { _track(key, send()); return; }
143
+ // After the request of this entry that is on its way (sent once, also when the page goes first: flushBlobs).
144
+ // Its turn sends it only while it is still the one that waits: a later delete has taken its place, or the
145
+ // page that was about to be left has sent it already.
146
+ _waitingDeletes.set(key, send);
147
+ _track(key, busy.then(() => {
148
+ if (_waitingDeletes.get(key) !== send) return undefined;
149
+ _waitingDeletes.delete(key);
150
+ return send();
151
+ }));
67
152
  }
68
153
 
69
154
  // Flush all pending puts immediately. With useBeacon (pagehide path), bodies
70
155
  // under ~60KB go via sendBeacon (survives unload); larger ones use a best-
71
156
  // effort fetch — the last debounced PUT was at most a debounce window ago, so
72
- // little is lost if it doesn't complete.
157
+ // little is lost if it doesn't complete. What goes out here goes out at once,
158
+ // beside a request that may still be on its way: each carries its number, and
159
+ // the server keeps what was asked for last.
73
160
  export function flushBlobs({ useBeacon = false } = {}) {
161
+ // The page is going: a delete that waits behind a request cannot wait any longer.
162
+ if (useBeacon) {
163
+ for (const [key, send] of [..._waitingDeletes.entries()]) { _waitingDeletes.delete(key); send({ keepalive: true }); }
164
+ }
74
165
  for (const [key, pending] of [..._pendingPuts.entries()]) {
75
166
  if (_putTimers.has(key)) { clearTimeout(_putTimers.get(key)); _putTimers.delete(key); }
76
167
  if (useBeacon) {
77
- const { ns, id, value } = pending;
168
+ const { ns, id, value, rev } = pending;
78
169
  const body = JSON.stringify(value);
79
170
  _pendingPuts.delete(key);
171
+ _answer(pending.waiters, false); // a beacon says nothing back: nobody is told it arrived
80
172
  if (body.length < 60_000) {
81
- navigator.sendBeacon(
82
- `/api/ui-blobs/${encodeURIComponent(ns)}/${encodeURIComponent(id)}`,
83
- new Blob([body], { type: 'application/json' })
84
- );
173
+ navigator.sendBeacon(_url(ns, id, rev), new Blob([body], { type: 'application/json' }));
85
174
  } else {
86
- fetch(`/api/ui-blobs/${encodeURIComponent(ns)}/${encodeURIComponent(id)}`, {
175
+ fetch(_url(ns, id, rev), {
87
176
  method: 'PUT',
88
177
  headers: { 'Content-Type': 'application/json' },
89
178
  body,
@@ -7,6 +7,9 @@ import { registerSidepanel, setSidepanelVisible, sidepanelAcceptsKeyboard, openA
7
7
  import { subscribeCliStatus, recheckCliStatus, getCliDocUrl, getCliInstallCommand, getCliLabel } from '../cli-status.js';
8
8
  import { nativeLoopWindowId } from '../ui-native-window-id.js';
9
9
  import { createStickyScrollController, getStickyScrollController } from '../ui-scroll-follow.js';
10
+ import { wireFileLinks } from '../ui-file-links.js';
11
+ import { trackWorkerEnd } from '../ui-worker-end.js';
12
+ import { isDispatchedRun } from '../worker-end.js';
10
13
  import { injectStyles } from './cdx-styles.js';
11
14
  import { mountContextMenu } from './cdx-context-menu.js';
12
15
  import { teardownMcpApps } from './cdx-mcp-app-host.js';
@@ -39,6 +42,7 @@ import {
39
42
  handleNotify,
40
43
  appendLocalUserMessage, hydrateCodexAutomationHistory,
41
44
  clearPlanHandoffState,
45
+ placeWorkerEnd,
42
46
  withTab,
43
47
  ensureProjectsLoaded,
44
48
  setActiveProject,
@@ -107,7 +111,6 @@ let _contextMenu = null;
107
111
  * monolith and are referenced by wireEvents / ensurePanel.
108
112
  *
109
113
  * Expected shape:
110
- * maybeOpenProjectFileLink(href, event) -> bool
111
114
  * flushCardBody(itemState)
112
115
  * resetThreadState(opts)
113
116
  * appendSystem(text, tone)
@@ -785,14 +788,18 @@ async function saveRecallProfile(profile) {
785
788
  // ═══════════════════════════════════════════
786
789
 
787
790
  function wireEvents() {
788
- // Project links retain their existing handling; card heads bind in cdx-render.
789
- const msgContainer = panelEl('#cxp-messages-container');
790
- if (msgContainer) {
791
- msgContainer.addEventListener('click', (e) => {
792
- const link = e.target.closest('a[href]');
793
- if (link && msgContainer.contains(link) && _host.maybeOpenProjectFileLink?.(link.getAttribute('href'), e)) return;
794
- });
795
- }
791
+ // File links open in the code editor (../ui-file-links.js, shared with the other panels): one listener for
792
+ // every tab's transcript, so stored and streaming messages behave alike. Card heads bind in cdx-render.
793
+ wireFileLinks(panelEl('#cxp-messages-container'), {
794
+ // A relative path is a path in the project of the tab on screen (a worker run's tab has the run's folder).
795
+ cwd: (link) => (allTabs().find((tab) => tab.messagesEl?.contains(link)) || activeTab())?.project || '',
796
+ textLinks: 'a.cxp-file-link',
797
+ // A path the editor does not open keeps what a click on it did: it is copied.
798
+ copyPath: (link, path) => navigator.clipboard.writeText(path).then(() => {
799
+ link.classList.add('cxp-file-link-copied');
800
+ setTimeout(() => link.classList.remove('cxp-file-link-copied'), 1500);
801
+ }),
802
+ });
796
803
 
797
804
  const input = panelEl('#cxp-input');
798
805
  const send = panelEl('#cxp-send');
@@ -1274,6 +1281,19 @@ export async function attachCodexAutomation(run, {
1274
1281
  ensurePanel();
1275
1282
  await ensureProjectsLoaded();
1276
1283
  if (isCancelled()) return { ok: false, reason: 'dismissed' };
1284
+ const running = run.status === 'starting' || run.status === 'running';
1285
+ // The user continued this run's thread by hand after the run ended: the tab stays theirs. The
1286
+ // dock's Focus raises it; the run is let go again, and nothing in the tab changes.
1287
+ const own = allTabs().find((entry) => !entry.automationRunId && entry.releasedRunId === run.runId && entry.threadId === threadId);
1288
+ if (own && !running) {
1289
+ window.dispatchEvent(new CustomEvent('native-loop:dismissed', { detail: { runId: run.runId } }));
1290
+ if (focus) {
1291
+ if (!_visible) await toggleCodexPanel();
1292
+ const ownIdx = allTabs().indexOf(own);
1293
+ if (ownIdx >= 0) switchTab(ownIdx);
1294
+ }
1295
+ return { ok: true, tabId: own.id, released: true };
1296
+ }
1277
1297
  let tab = allTabs().find((entry) => entry.automationRunId === run.runId);
1278
1298
  if (!tab) {
1279
1299
  tab = createTab({
@@ -1291,7 +1311,6 @@ export async function attachCodexAutomation(run, {
1291
1311
  }, { autoSwitch: false });
1292
1312
  }
1293
1313
  if (!tab) return { ok: false, reason: 'tab_limit' };
1294
- const running = run.status === 'starting' || run.status === 'running';
1295
1314
  // A task-mode worker between turns (waiting for a follow-up) is alive, not working.
1296
1315
  const working = running && run.turnState !== 'idle' && run.turnState !== 'terminal';
1297
1316
  tab.automationRunId = run.runId;
@@ -1315,10 +1334,12 @@ export async function attachCodexAutomation(run, {
1315
1334
  return { ok: false, reason: 'dismissed' };
1316
1335
  }
1317
1336
  }
1318
- if (run.status === 'failed' && run.error && tab._automationLifecycleError !== run.error) {
1337
+ // (A dispatched worker's failure, with its reason, is on its end card.)
1338
+ if (run.status === 'failed' && run.error && !isDispatchedRun(run) && tab._automationLifecycleError !== run.error) {
1319
1339
  tab._automationLifecycleError = run.error;
1320
1340
  withTab(tab, () => appendSystem(run.error, 'error'));
1321
1341
  }
1342
+ trackWorkerEnd(run, { apply: (view) => { tab._workerEnd = view; placeWorkerEnd(tab); } });
1322
1343
  saveTabs();
1323
1344
  renderPills();
1324
1345
  if (focus) {
@@ -16,6 +16,7 @@ import { bindExpandableCard, setCardExpanded } from './cdx-cards.js';
16
16
  import { mountMcpAppCard } from './cdx-mcp-app-host.js';
17
17
  import { OUTPUT_LIMITS, boundedText, jsonAnswer, prettyJsonFences, readableStructuredValue, fileChangeDiffs, parseUnifiedDiff, deduplicateTurnDiff } from './cdx-output-model.js';
18
18
  import { renderReadableOutput, renderReadableBlock, cleanOutputBlocks, hydrateOutputControls, observeOutputBlocks, renderDiffView, restoreDiffViews } from './cdx-output.js';
19
+ import { fileLinkTitle, fillFileLinkCopy, isInsideRoots, parseFileLinkTarget } from '../file-links.js';
19
20
  export { setCardExpanded } from './cdx-cards.js';
20
21
 
21
22
  // ── Shared context (set by cdx-tabs via setRenderContext) ──
@@ -375,101 +376,45 @@ export function postProcessRenderedHtml(container) {
375
376
  // ═══════════════════════════════════════════
376
377
  // File Path Linking
377
378
  // ═══════════════════════════════════════════
379
+ // What a target means is decided in ../file-links.js, shared with the other panels; a click is taken by the
380
+ // one listener cdx-panel.js puts on the transcript (../ui-file-links.js), so links in a stored transcript
381
+ // work like fresh ones.
378
382
 
379
383
  export function normalizePathForCompare(path) {
380
384
  return String(path || '').replace(/\\/g, '/').replace(/\/+$/, '');
381
385
  }
382
386
 
383
- export function isProjectFilePath(path) {
384
- const normalized = normalizePathForCompare(path);
385
- if (!normalized.startsWith('/')) return false;
386
- const roots = new Set([
387
- normalizePathForCompare(_ctx.project),
388
- ...(_ctx.projects || []).map((entry) => normalizePathForCompare(entry?.path)).filter(Boolean),
389
- ]);
390
- for (const root of roots) {
391
- if (!root) continue;
392
- if (normalized === root || normalized.startsWith(`${root}/`)) return true;
393
- }
394
- return false;
387
+ // The folder a relative link is read from: the project of the tab the transcript belongs to.
388
+ function fileLinkWhere() {
389
+ return {
390
+ cwd: _ctx.boundTab?.project || _ctx.project || '',
391
+ origin: globalThis.location?.origin || '',
392
+ };
395
393
  }
396
394
 
397
- export function parseProjectFileTarget(rawTarget) {
398
- if (!rawTarget) return null;
399
- let raw = String(rawTarget).trim();
400
- if (!raw || raw === '#') return null;
401
- if (raw.startsWith('file://')) {
402
- try { raw = decodeURIComponent(new URL(raw).pathname || ''); }
403
- catch { raw = raw.replace(/^file:\/\//, ''); }
404
- }
405
-
406
- let pathPart = raw;
407
- let hash = '';
408
- if (/^[a-z]+:\/\//i.test(raw)) {
409
- try {
410
- const parsed = new URL(raw, window.location.origin);
411
- if (parsed.origin !== window.location.origin) return null;
412
- pathPart = parsed.pathname || '';
413
- hash = parsed.hash || '';
414
- } catch {
415
- return null;
416
- }
417
- } else {
418
- const hashIndex = raw.indexOf('#');
419
- if (hashIndex >= 0) {
420
- pathPart = raw.slice(0, hashIndex);
421
- hash = raw.slice(hashIndex);
422
- }
423
- }
424
-
425
- try { pathPart = decodeURIComponent(pathPart); } catch {}
426
- pathPart = normalizePathForCompare(pathPart);
427
-
428
- let line = null;
429
- let column = null;
430
- const suffixMatch = pathPart.match(/:(\d+)(?::(\d+))?$/);
431
- if (suffixMatch) {
432
- line = Number(suffixMatch[1]) || null;
433
- column = Number(suffixMatch[2]) || null;
434
- pathPart = normalizePathForCompare(pathPart.slice(0, suffixMatch.index));
435
- }
436
- if (!isProjectFilePath(pathPart)) return null;
437
- const hashMatch = hash.match(/^#L(\d+)(?:C(\d+))?$/i);
438
- if (hashMatch) {
439
- line = Number(hashMatch[1]) || line;
440
- column = Number(hashMatch[2]) || column;
441
- }
442
-
443
- return { filePath: pathPart, line, column };
395
+ export function isProjectFilePath(path) {
396
+ return isInsideRoots(path, [_ctx.boundTab?.project, _ctx.project, ...(_ctx.projects || []).map((entry) => entry?.path)]);
444
397
  }
445
398
 
446
- export function openProjectFileTarget(target) {
447
- if (!target?.filePath) return false;
448
- _ctx.emit('open-file-editor', {
449
- filePath: target.filePath,
450
- line: target.line || undefined,
451
- column: target.column || undefined,
452
- });
453
- return true;
399
+ // A link target that is a file of this tab's project or of a registered one, or null.
400
+ function projectFileTarget(rawTarget) {
401
+ const target = parseFileLinkTarget(rawTarget, fileLinkWhere());
402
+ return target?.path && isProjectFilePath(target.path) ? target : null;
454
403
  }
455
404
 
456
- export function maybeOpenProjectFileLink(rawTarget, event) {
457
- const target = parseProjectFileTarget(rawTarget);
458
- if (!target) return false;
459
- event?.preventDefault?.();
460
- return openProjectFileTarget(target);
405
+ function openInEditorTitle(target) {
406
+ const { key, params } = fileLinkTitle(target);
407
+ return _ctx.fileLinkText?.(key, params) || fillFileLinkCopy(key, params);
461
408
  }
462
409
 
463
410
  export function markProjectFileAnchors(container) {
464
411
  if (!container) return;
465
412
  container.querySelectorAll('a[href]').forEach((link) => {
466
- const target = parseProjectFileTarget(link.getAttribute('href'));
413
+ const target = projectFileTarget(link.getAttribute('href'));
467
414
  if (!target) return;
468
415
  link.classList.add('cxp-file-link');
469
- link.dataset.projectFilePath = target.filePath;
470
- link.title = target.line
471
- ? `Open in editor${target.column ? ` at line ${target.line}, column ${target.column}` : ` at line ${target.line}`}`
472
- : 'Open in editor';
416
+ link.dataset.projectFilePath = target.path;
417
+ link.title = openInEditorTitle(target);
473
418
  });
474
419
  }
475
420
 
@@ -497,19 +442,10 @@ export function linkifyFilePaths(container) {
497
442
  const link = document.createElement('a');
498
443
  link.className = 'cxp-file-link';
499
444
  link.textContent = pathStr;
500
- const target = parseProjectFileTarget(pathStr);
501
- link.title = target?.line
502
- ? `Open in editor${target.column ? ` at line ${target.line}, column ${target.column}` : ` at line ${target.line}`}`
503
- : target ? 'Open in editor' : 'Click to copy path';
445
+ const target = projectFileTarget(pathStr);
446
+ link.title = target ? openInEditorTitle(target) : 'Click to copy path';
504
447
  link.href = '#';
505
- link.addEventListener('click', (e) => {
506
- if (maybeOpenProjectFileLink(pathStr, e)) return;
507
- e.preventDefault();
508
- const cleanPath = pathStr.replace(/:\d+(:\d+)?$/, '');
509
- navigator.clipboard.writeText(cleanPath).catch(() => {});
510
- link.classList.add('cxp-file-link-copied');
511
- setTimeout(() => link.classList.remove('cxp-file-link-copied'), 1500);
512
- });
448
+ // The click is taken on the transcript (cdx-panel.js): the editor when it can open the path, else a copy.
513
449
  frag.appendChild(link);
514
450
  lastIndex = match.index + match[0].length;
515
451
  }
@@ -2442,6 +2442,42 @@ export function injectStyles() {
2442
2442
  .cxp-post-plan-utilities .cxp-request-btn { flex: 1; justify-content: center; }
2443
2443
  }
2444
2444
 
2445
+ /* ── A dispatched worker's end (ui-worker-end.js): the post-plan header and note in the
2446
+ compaction card's hairline frame, in the transcript column. The title says the state in words. ── */
2447
+ .cxp-worker-end {
2448
+ display: grid;
2449
+ gap: var(--cxp-space-2);
2450
+ min-width: 0;
2451
+ margin: var(--cxp-space-2) var(--cxp-space-2) var(--cxp-space-3) calc(var(--cxp-space-2) + 24px + var(--cxp-space-2));
2452
+ padding: var(--cxp-space-3) var(--cxp-space-4);
2453
+ border: 1px solid var(--cxp-border-strong);
2454
+ border-radius: var(--cxp-radius-md);
2455
+ font-family: var(--cxp-font);
2456
+ }
2457
+ .cxp-worker-end[data-tone="ok"] .cxp-post-plan-header { color: var(--cxp-success); }
2458
+ .cxp-worker-end[data-tone="warn"] .cxp-post-plan-header { color: var(--cxp-warning); }
2459
+ .cxp-worker-end[data-tone="err"] .cxp-post-plan-header { color: var(--cxp-danger); }
2460
+ .cxp-worker-end .cxp-post-plan-note { overflow-wrap: anywhere; }
2461
+ .cxp-worker-end .worker-end-meta {
2462
+ font-family: var(--cxp-mono);
2463
+ font-size: var(--cxp-fs-xs);
2464
+ color: var(--cxp-text-3);
2465
+ }
2466
+ .cxp-worker-end .worker-end-note {
2467
+ font-size: var(--cxp-fs-sm);
2468
+ line-height: var(--cxp-lh-tight);
2469
+ color: var(--cxp-text-3);
2470
+ }
2471
+ .cxp-worker-end .worker-end-actions { display: flex; margin-top: var(--cxp-space-1); }
2472
+ .cxp-worker-end .cxp-request-btn:focus-visible {
2473
+ outline: 2px solid var(--cxp-focus);
2474
+ outline-offset: 2px;
2475
+ }
2476
+ @media (max-width: 390px) {
2477
+ .cxp-worker-end { margin-left: var(--cxp-space-2); padding: var(--cxp-space-3); }
2478
+ .cxp-worker-end .cxp-request-btn { flex: 1; justify-content: center; }
2479
+ }
2480
+
2445
2481
  /* ── Composer ── */
2446
2482
  .cxp-bottom {
2447
2483
  flex-shrink: 0;