synabun 2.0.9 → 2.0.10

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 (252) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -1
  3. package/THIRD-PARTY-LICENSES.md +46 -4
  4. package/launcher.mjs +9 -3
  5. package/lib/start-launcher.js +6 -1
  6. package/mcp-server/package-lock.json +2 -2
  7. package/mcp-server/package.json +1 -1
  8. package/neural-interface/i18n/en.json +218 -7
  9. package/neural-interface/i18n/pt-BR.json +220 -9
  10. package/neural-interface/lib/account-usage.js +5 -3
  11. package/neural-interface/lib/app-controls-api.js +161 -0
  12. package/neural-interface/lib/assistant-api.js +21 -7
  13. package/neural-interface/lib/assistant-brains/opencode.js +13 -1
  14. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +44 -0
  15. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +57 -0
  16. package/neural-interface/lib/assistant-catalog.js +17 -2
  17. package/neural-interface/lib/assistant-dispatch.js +3 -0
  18. package/neural-interface/lib/assistant-envelope.js +19 -1
  19. package/neural-interface/lib/assistant-runtime.js +127 -8
  20. package/neural-interface/lib/claude-model-catalog.js +64 -14
  21. package/neural-interface/lib/codex-settings-schema.js +109 -47
  22. package/neural-interface/lib/editor-completion-opencode.js +132 -35
  23. package/neural-interface/lib/exec-loop-command.js +8 -1
  24. package/neural-interface/lib/launch-cache.js +293 -0
  25. package/neural-interface/lib/login-start.js +524 -0
  26. package/neural-interface/lib/native-loop-providers.js +18 -3
  27. package/neural-interface/lib/native-loop-runtime.js +19 -0
  28. package/neural-interface/lib/opencode-db-schema.js +75 -0
  29. package/neural-interface/lib/opencode-history.js +16 -1
  30. package/neural-interface/lib/opencode-protocol.js +173 -0
  31. package/neural-interface/lib/opencode-provider-view.js +81 -0
  32. package/neural-interface/lib/opencode-runtime-config.js +10 -3
  33. package/neural-interface/lib/opencode-serve-records.js +606 -0
  34. package/neural-interface/lib/opencode-v2-client.js +33 -6
  35. package/neural-interface/lib/opencode-v2-ws-requests.js +19 -5
  36. package/neural-interface/lib/opencode-worker-activity.js +229 -0
  37. package/neural-interface/lib/opencode2-client.js +760 -0
  38. package/neural-interface/lib/opencode2-proxy.js +116 -0
  39. package/neural-interface/lib/opencode2-translate.js +1008 -0
  40. package/neural-interface/lib/process-identity.js +361 -0
  41. package/neural-interface/lib/session-cache-builder.js +26 -5
  42. package/neural-interface/lib/session-title-generator.js +18 -0
  43. package/neural-interface/lib/style-guide/api.js +4 -3
  44. package/neural-interface/lib/untrusted-file-headers.js +27 -0
  45. package/neural-interface/package-lock.json +1343 -45
  46. package/neural-interface/package.json +5 -1
  47. package/neural-interface/public/index.html +2 -2
  48. package/neural-interface/public/shared/agent-runtime-options.js +55 -11
  49. package/neural-interface/public/shared/assistant/asst-agents-dock.js +172 -17
  50. package/neural-interface/public/shared/assistant/asst-api.js +11 -3
  51. package/neural-interface/public/shared/assistant/asst-brain-picker.js +195 -80
  52. package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
  53. package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
  54. package/neural-interface/public/shared/assistant/asst-menu.js +77 -6
  55. package/neural-interface/public/shared/assistant/asst-panel.js +197 -33
  56. package/neural-interface/public/shared/assistant/asst-rack-styles.js +28 -10
  57. package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
  58. package/neural-interface/public/shared/assistant/asst-render.js +382 -36
  59. package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
  60. package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
  61. package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
  62. package/neural-interface/public/shared/assistant/asst-scenes.js +528 -0
  63. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
  64. package/neural-interface/public/shared/assistant/asst-state.js +14 -0
  65. package/neural-interface/public/shared/assistant/asst-styles.js +43 -0
  66. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +13 -1
  67. package/neural-interface/public/shared/cc-dropdown.js +480 -0
  68. package/neural-interface/public/shared/cdx/cdx-panel.js +13 -1
  69. package/neural-interface/public/shared/cdx/cdx-render.js +15 -3
  70. package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
  71. package/neural-interface/public/shared/cdx/cdx-tabs.js +149 -35
  72. package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
  73. package/neural-interface/public/shared/data-cache.js +223 -0
  74. package/neural-interface/public/shared/desktop-bridge.js +11 -0
  75. package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
  76. package/neural-interface/public/shared/desktop-titlebar.js +214 -28
  77. package/neural-interface/public/shared/desktop-update-view.js +15 -5
  78. package/neural-interface/public/shared/file-links.js +73 -8
  79. package/neural-interface/public/shared/html-shell.js +74 -80
  80. package/neural-interface/public/shared/launch-prefetch.js +59 -0
  81. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
  82. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +7 -2
  83. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
  84. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +93 -2
  85. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +3 -2
  86. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
  87. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
  88. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1 -1
  89. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
  90. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +16 -9
  91. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +60 -0
  92. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +48 -19
  93. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +195 -19
  94. package/neural-interface/public/shared/opencode-providers.js +39 -0
  95. package/neural-interface/public/shared/schedules-view.js +318 -0
  96. package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
  97. package/neural-interface/public/shared/settings/settings-app.js +243 -0
  98. package/neural-interface/public/shared/settings/settings-data.js +88 -0
  99. package/neural-interface/public/shared/settings/settings-ia.js +17 -0
  100. package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
  101. package/neural-interface/public/shared/styles.css +540 -371
  102. package/neural-interface/public/shared/ui-assistant.js +27 -5
  103. package/neural-interface/public/shared/ui-automation-studio.js +67 -27
  104. package/neural-interface/public/shared/ui-bookmarks.js +2 -1
  105. package/neural-interface/public/shared/ui-claude-panel.js +76 -8
  106. package/neural-interface/public/shared/ui-codex-panel.js +1 -0
  107. package/neural-interface/public/shared/ui-detail.js +6 -6
  108. package/neural-interface/public/shared/ui-file-links.js +1 -0
  109. package/neural-interface/public/shared/ui-image-gallery.js +6 -5
  110. package/neural-interface/public/shared/ui-invite.js +18 -2
  111. package/neural-interface/public/shared/ui-link.js +9 -9
  112. package/neural-interface/public/shared/ui-menubar.js +232 -33
  113. package/neural-interface/public/shared/ui-native-loop-router.js +2 -0
  114. package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
  115. package/neural-interface/public/shared/ui-schedules-studio.js +2099 -869
  116. package/neural-interface/public/shared/ui-sessions.js +15 -4
  117. package/neural-interface/public/shared/ui-settings.js +87 -36
  118. package/neural-interface/public/shared/ui-sidebar.js +4 -4
  119. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
  120. package/neural-interface/public/shared/ui-sidepanel-sessions.js +55 -4
  121. package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
  122. package/neural-interface/public/shared/ui-skills.js +70 -12
  123. package/neural-interface/public/shared/ui-sync.js +7 -0
  124. package/neural-interface/public/shared/ui-terminal.js +36 -20
  125. package/neural-interface/public/shared/ui-trash.js +8 -1
  126. package/neural-interface/public/shared/ui-tutorial-steps.js +7 -3
  127. package/neural-interface/public/shared/ui-tutorial.js +15 -5
  128. package/neural-interface/public/shared/ui-update.js +83 -14
  129. package/neural-interface/public/shared/ui-whiteboard.js +2 -1
  130. package/neural-interface/public/variant/2d/main.js +4 -1
  131. package/neural-interface/public/variant/3d/main.js +3 -0
  132. package/neural-interface/public/vendor/highlight/LICENSE +29 -0
  133. package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
  134. package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
  135. package/neural-interface/public/vendor/highlight/manifest.json +5 -0
  136. package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
  137. package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
  138. package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
  139. package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
  140. package/neural-interface/public/vendor/marked/manifest.json +4 -0
  141. package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
  142. package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
  143. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
  144. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
  145. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
  146. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
  147. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
  148. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
  149. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
  150. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
  151. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
  152. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
  153. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
  154. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
  155. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
  156. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
  157. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
  158. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
  159. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
  160. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
  161. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
  162. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
  163. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
  164. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
  165. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
  166. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
  167. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
  168. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
  169. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
  170. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
  171. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
  172. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
  173. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
  174. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
  175. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
  176. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
  177. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
  178. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
  179. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
  180. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
  181. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
  182. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
  183. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
  184. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
  185. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
  186. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
  187. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
  188. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
  189. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
  190. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
  191. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
  192. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
  193. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
  194. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
  195. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
  196. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
  197. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
  198. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
  199. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
  200. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
  201. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
  202. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
  203. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
  204. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
  205. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
  206. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
  207. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
  208. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
  209. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
  210. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
  211. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
  212. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
  213. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
  214. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
  215. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
  216. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
  217. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
  218. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
  219. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
  220. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
  221. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
  222. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
  223. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
  224. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
  225. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
  226. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
  227. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
  228. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
  229. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
  230. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
  231. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
  232. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
  233. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
  234. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
  235. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
  236. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
  237. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
  238. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
  239. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
  240. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
  241. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
  242. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
  243. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
  244. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
  245. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
  246. package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
  247. package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
  248. package/neural-interface/scripts/build-vendor.mjs +84 -3
  249. package/neural-interface/server.js +1099 -286
  250. package/npm-shrinkwrap.json +2 -2
  251. package/package.json +1 -1
  252. package/skills/synabun/modules/schedule.md +1 -1
@@ -15,6 +15,7 @@ import '../account-i18n.js';
15
15
  import { restoreMcpAppCards, teardownMcpApps, retireMcpAppNode, stripMcpAppRuntime } from './cdx-mcp-app-host.js';
16
16
  import { renderTurnDiff, completeTurnOutputs } from './cdx-render.js';
17
17
  import { hydrateOutputControls } from './cdx-output.js';
18
+ import { sanitizeStoredHtml } from '../assistant/asst-sanitize.js';
18
19
  import {
19
20
  beginPlanTurn, capturePlanItem, finishPlanTurn, getPlanMarkdown, syncPlanMirrors, recordPlanTurn,
20
21
  migrateLegacyPlan, recoverPlanFromHistory, planBelongsToTab, useMessageAsPlan,
@@ -378,6 +379,9 @@ function buildWsCallbacks(tab, options = {}) {
378
379
  if (_boundTab) _boundTab.running = true;
379
380
  setStatus('Resuming…', 'working');
380
381
  resetStallTimer();
382
+ // The turn it found is still at work: so is the tab's pill (the panel may be hidden, the tab in the background).
383
+ updateTrayPillRunning();
384
+ renderPills();
381
385
  } else if (msg.running === false && (!msg.threadId || String(msg.threadId) === String(_threadId || ''))) {
382
386
  // A plan can finish while disconnected. The server's idle reply
383
387
  // releases the stale running/query state before history recovery.
@@ -589,20 +593,17 @@ function buildWsCallbacks(tab, options = {}) {
589
593
  },
590
594
 
591
595
  onInterruptAck(msg) {
592
- _running = false;
593
- _activeTurnId = null;
594
- if (_boundTab) {
595
- _boundTab.running = false;
596
- _boundTab.activeTurnId = null;
597
- if (_boundTab._abortRetry) {
598
- clearTimeout(_boundTab._abortRetry);
599
- _boundTab._abortRetry = null;
600
- }
596
+ if (_boundTab?._abortRetry) {
597
+ clearTimeout(_boundTab._abortRetry);
598
+ _boundTab._abortRetry = null;
601
599
  }
602
600
  clearInterruptTimer();
603
- stopStallTimer();
601
+ // A prompt sent after the Stop has a turn of its own: the ack is not about it.
602
+ if (!interruptAckEndsTurn(_boundTab)) return;
603
+ // The stopped turn is over: the tab, its pill and the saved tabs say so (setRunning), even
604
+ // when something marked it working again before the ack came back.
605
+ setRunning(false);
604
606
  setStatus('Interrupted', 'muted');
605
- syncInputEnabled();
606
607
  syncSessionControls();
607
608
  releaseInactiveIdleTab(_boundTab);
608
609
  },
@@ -959,6 +960,7 @@ function rememberBlockingServerRequest(requestId, method, params = {}) {
959
960
  if (_boundTab) _boundTab.blockingServerRequests = _blockingServerRequests;
960
961
  syncWorkStatus();
961
962
  syncInputEnabled();
963
+ updateTrayPillRunning(); // the pill needs you
962
964
  saveTabs();
963
965
  }
964
966
 
@@ -968,6 +970,7 @@ function clearBlockingServerRequest(requestId, { flushBuffered = true } = {}) {
968
970
  if (_boundTab) _boundTab.blockingServerRequests = _blockingServerRequests;
969
971
  syncWorkStatus();
970
972
  syncInputEnabled();
973
+ updateTrayPillRunning();
971
974
  saveTabs();
972
975
  if (flushBuffered && !hasBlockingServerRequests()) flushBufferedSocketMessages();
973
976
  releaseInactiveIdleTab(_boundTab);
@@ -985,6 +988,7 @@ function clearAllBlockingServerRequests() {
985
988
  }
986
989
  syncWorkStatus();
987
990
  syncInputEnabled();
991
+ updateTrayPillRunning();
988
992
  }
989
993
 
990
994
  function shouldBufferSocketMessage(kind, payload) {
@@ -1064,6 +1068,11 @@ function applySocketError(msg) {
1064
1068
 
1065
1069
  function applySocketClosed() {
1066
1070
  appendSystem('Codex session closed', 'muted');
1071
+ // The app-server ran the turn: it exited, the turn went with it (the server forgot it too).
1072
+ if (_running) {
1073
+ setRunning(false);
1074
+ setStatus('Codex session closed', 'muted');
1075
+ }
1067
1076
  }
1068
1077
 
1069
1078
  function applyBufferedSocketMessage(entry) {
@@ -1459,7 +1468,7 @@ let _hljs = null;
1459
1468
 
1460
1469
  (async () => {
1461
1470
  try {
1462
- const mod = await import('https://cdn.jsdelivr.net/npm/marked@14/lib/marked.esm.js').catch(() => null);
1471
+ const mod = await import('/vendor/marked/marked-14.1.4.esm.js').catch(() => null);
1463
1472
  if (mod) {
1464
1473
  _marked = mod.marked || mod.default;
1465
1474
  if (_marked?.setOptions) _marked.setOptions({ breaks: true, gfm: true });
@@ -1471,10 +1480,10 @@ let _hljs = null;
1471
1480
  try {
1472
1481
  const link = document.createElement('link');
1473
1482
  link.rel = 'stylesheet';
1474
- link.href = 'https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github-dark-dimmed.min.css';
1483
+ link.href = '/vendor/highlight/github-dark-dimmed-11.12.0.min.css';
1475
1484
  document.head.appendChild(link);
1476
1485
  const script = document.createElement('script');
1477
- script.src = 'https://cdn.jsdelivr.net/npm/highlight.js@11/lib/highlight.min.js';
1486
+ script.src = '/vendor/highlight/highlight-11.12.0.min.js';
1478
1487
  script.onload = () => { _hljs = window.hljs || null; };
1479
1488
  document.head.appendChild(script);
1480
1489
  } catch {}
@@ -2417,14 +2426,26 @@ export function restoreActiveBinding(fallbackState) {
2417
2426
  else restoreBoundState(fallbackState);
2418
2427
  }
2419
2428
 
2429
+ // How many withTab calls are under way. The outermost one hands the binding back to the active tab; a
2430
+ // nested one hands it back to the tab the call around it bound, with what that call had done so far
2431
+ // written to it first. (The history of a tab in the background renders while another tab is shown, and
2432
+ // a nested withTab in it used to leave the rest of that history to the shown tab: its held approvals
2433
+ // were looked up there and never came back.)
2434
+ let _withTabDepth = 0;
2435
+
2420
2436
  export function withTab(tab, fn) {
2421
2437
  const prev = snapshotBoundState();
2438
+ const outer = _withTabDepth > 0 ? _boundTab : null;
2439
+ if (outer) commitBoundState();
2440
+ _withTabDepth += 1;
2422
2441
  bindTabState(tab);
2423
2442
  try {
2424
2443
  return fn();
2425
2444
  } finally {
2426
2445
  commitBoundState();
2427
- restoreActiveBinding(prev);
2446
+ _withTabDepth -= 1;
2447
+ if (outer) bindTabState(outer);
2448
+ else restoreActiveBinding(prev);
2428
2449
  }
2429
2450
  }
2430
2451
 
@@ -2676,12 +2697,16 @@ function createTrayPill(tab) {
2676
2697
  export function renderPills() {
2677
2698
  const active = activeTab();
2678
2699
  for (const tab of _tabs) {
2679
- if (!tab.pillEl?.isConnected) tab.pillEl = createTrayPill(tab);
2700
+ if (!tab.pillEl?.isConnected) {
2701
+ tab.pillEl = createTrayPill(tab);
2702
+ // The bound tab's own reference too, or its running state would go on reaching the old node.
2703
+ if (tab === _boundTab) _trayPill = tab.pillEl;
2704
+ }
2680
2705
  if (!tab.pillEl) continue;
2681
2706
  // Read directly from tab to avoid nested withTab clobbering uncommitted state
2682
2707
  const label = tab.pillEl.querySelector('.term-minimized-pill-label');
2683
2708
  if (label) label.textContent = tab.sessionLabel || 'New session';
2684
- tab.pillEl.classList.toggle('cxp-pill-running', !!(tab.running || tab.startingThread));
2709
+ paintTrayPill(tab.pillEl, tab);
2685
2710
  const shouldShow = hasMeaningfulTrayState(tab) && (!_getVisible() || tab !== active);
2686
2711
  tab.pillEl.style.display = shouldShow ? '' : 'none';
2687
2712
  }
@@ -2874,6 +2899,7 @@ export function createTab(saved = {}, { autoSwitch = true } = {}) {
2874
2899
  ownedThreadIds: new Set(),
2875
2900
  automationRunId,
2876
2901
  automationActive: !!saved.automationActive,
2902
+ automationAwaits: false, // the run's turn ended asking the user (runAwaitsAnswer, set by its attach): the pill needs you
2877
2903
  automationOwnerId: saved.automationOwnerId || null,
2878
2904
  releasedRunId: automationRunId ? null : (saved.releasedRunId || null),
2879
2905
  };
@@ -3039,6 +3065,13 @@ export function saveTabs() {
3039
3065
  automationActive: !!tab.automationActive,
3040
3066
  automationOwnerId: tab.automationOwnerId || null,
3041
3067
  releasedRunId: tab.releasedRunId || null,
3068
+ // Whether it was working when this was written: after a reload its placeholder pill says so and
3069
+ // the panel boots to ask (ui-sidepanel-tray.js), and the tab reattaches at once (restoreTabs).
3070
+ // Never restored as running: only the reattach's answer says that. `needsYou`: an approval or a
3071
+ // question card waited on the user; the reattach replays the request the bridge still holds.
3072
+ running: !!tab.running,
3073
+ startingThread: !!tab.startingThread,
3074
+ needsYou: tab.blockingServerRequests?.size > 0 || !!tab.automationAwaits,
3042
3075
  };
3043
3076
  });
3044
3077
  const localRunIds = new Set(localTabs.map((tab) => tab.automationRunId).filter(Boolean));
@@ -3125,9 +3158,11 @@ export function restoreTabs() {
3125
3158
  if (raw) {
3126
3159
  const data = JSON.parse(raw);
3127
3160
  if (Array.isArray(data?.tabs) && data.tabs.length) {
3161
+ const wereWorking = [];
3128
3162
  for (const saved of data.tabs) {
3129
3163
  if (saved.automationActive && saved.automationOwnerId !== nativeLoopWindowId) continue;
3130
- createTab(saved, { autoSwitch: false });
3164
+ const tab = createTab(saved, { autoSwitch: false });
3165
+ if (tab && !tab.automationRunId && (saved.running || saved.startingThread || saved.needsYou)) wereWorking.push(tab);
3131
3166
  }
3132
3167
  if (!_tabs.length) throw new Error('No restorable Codex tabs');
3133
3168
  _activeTabIdx = Math.min(Math.max(Number(data.activeIdx) || 0, 0), _tabs.length - 1);
@@ -3135,6 +3170,11 @@ export function restoreTabs() {
3135
3170
  if (!_tabs.length) throw new Error('No restorable Codex tabs');
3136
3171
  updateActiveTabView();
3137
3172
  saveTabs();
3173
+ // A tab that was working when the page went away asks after its turn now, hidden or in the
3174
+ // background (a restored tab reattaches first: its turn outlives the page on the server), so
3175
+ // its pill says what the thread does. An idle one is let go again once it is ready
3176
+ // (releaseInactiveIdleTab); idle tabs stay unconnected until they are shown.
3177
+ for (const tab of wereWorking) if (_tabs.includes(tab) && !tab.ws) connectTab(tab);
3138
3178
  return;
3139
3179
  }
3140
3180
  }
@@ -3158,8 +3198,47 @@ export function updateTrayPillLabel() {
3158
3198
  if (label) label.textContent = _sessionLabel;
3159
3199
  }
3160
3200
 
3201
+ /**
3202
+ * What a tab's tray pill says: it needs you while an approval or a question card waits on your answer
3203
+ * (its blocking server requests), or, for a dispatched worker, while its turn ended asking you something
3204
+ * (the run's outcome: automationAwaits), else it works while a turn runs or a thread is being made.
3205
+ * sidepanel-session-status.js reads the same classes for a detached window's pill.
3206
+ */
3207
+ function paintTrayPill(pill, { running, startingThread, blockingServerRequests, automationAwaits }) {
3208
+ if (!pill) return;
3209
+ const needsYou = blockingServerRequests?.size > 0 || !!automationAwaits;
3210
+ pill.classList.toggle('cxp-pill-attention', needsYou);
3211
+ pill.classList.toggle('cxp-pill-running', !needsYou && !!(running || startingThread));
3212
+ }
3213
+
3161
3214
  export function updateTrayPillRunning() {
3162
- _trayPill?.classList.toggle('cxp-pill-running', !!(_running || _startingThread));
3215
+ paintTrayPill(_trayPill, {
3216
+ running: _running, startingThread: _startingThread, blockingServerRequests: _blockingServerRequests, automationAwaits: _boundTab?.automationAwaits,
3217
+ });
3218
+ }
3219
+
3220
+ /**
3221
+ * The bound tab's work ended (or began) outside setRunning: the tab, its pill and the saved tabs say
3222
+ * so now. The tab is written first: renderPills and saveTabs read it, never the bound copy, and a
3223
+ * nested withTab binds the tab again from it (withTab itself writes it back only when it returns).
3224
+ */
3225
+ function publishWorkState() {
3226
+ if (_boundTab) {
3227
+ _boundTab.running = _running;
3228
+ _boundTab.startingThread = _startingThread;
3229
+ }
3230
+ updateTrayPillRunning();
3231
+ renderPills();
3232
+ saveTabs();
3233
+ }
3234
+
3235
+ /**
3236
+ * Whether a Stop's ack ends the tab's running state: not once a prompt was sent after that Stop
3237
+ * (dispatchPrompt counts them, interruptTab notes the count it stopped at), whose turn is its own.
3238
+ */
3239
+ function interruptAckEndsTurn(tab) {
3240
+ if (!tab || tab.interruptedAtPrompt == null) return true;
3241
+ return (tab.promptCount || 0) === tab.interruptedAtPrompt;
3163
3242
  }
3164
3243
 
3165
3244
 
@@ -3258,6 +3337,7 @@ export function clearTranscript(emptyText = freshThreadText()) {
3258
3337
  showEmpty(emptyText);
3259
3338
  setCompactingUI(false);
3260
3339
  renderStatusChrome();
3340
+ updateTrayPillRunning(); // (its request cards went with the transcript)
3261
3341
  }
3262
3342
 
3263
3343
  export function renderStoredTranscript(snapshot, emptyText = freshThreadText()) {
@@ -3267,7 +3347,10 @@ export function renderStoredTranscript(snapshot, emptyText = freshThreadText())
3267
3347
 
3268
3348
  clearTranscript(emptyText);
3269
3349
  _messagesEl.querySelectorAll(':scope > .cxp-empty').forEach(node => node.remove());
3270
- _messagesEl.insertAdjacentHTML('beforeend', normalized.html);
3350
+ // A snapshot is the transcript's own markup, saved and read back from storage, and a build before the panel
3351
+ // sanitised its Markdown saved model HTML in it as it was: it is rebuilt from the stored-transcript allowlist
3352
+ // (asst-sanitize.js, the sanitiser live output goes through) before it reaches the page.
3353
+ _messagesEl.append(sanitizeStoredHtml(normalized.html));
3271
3354
  const acceptedItemIds = new Set(normalized.acceptedItemIds);
3272
3355
  const acceptedTurnIds = new Set(normalized.acceptedTurnIds);
3273
3356
  const restoredNodes = [..._messagesEl.children].filter((node) => (
@@ -3365,6 +3448,11 @@ export function resetThreadState({ tone = 'ready', preserveStatus = false } = {}
3365
3448
  _running = false;
3366
3449
  _startingThread = false;
3367
3450
  if (_boundTab) {
3451
+ // On the tab at once: clearPlanHandoffState below binds the tab again (updatePostPlanTranscriptMeta's
3452
+ // withTab), which read its old running state back over these and saved the reset tab as working.
3453
+ _boundTab.running = false;
3454
+ _boundTab.startingThread = false;
3455
+ _boundTab.activeTurnId = null;
3368
3456
  _boundTab.ownedThreadIds = new Set();
3369
3457
  _boundTab.expectedThreadId = null;
3370
3458
  _boundTab.expectedThreadRequestId = null;
@@ -3385,8 +3473,7 @@ export function resetThreadState({ tone = 'ready', preserveStatus = false } = {}
3385
3473
  clearTranscript();
3386
3474
  syncInputEnabled();
3387
3475
  syncSessionControls();
3388
- renderPills();
3389
- saveTabs();
3476
+ publishWorkState();
3390
3477
  }
3391
3478
 
3392
3479
  export function setActiveProject(projectPath, { reset = true, preserveStatus = false, tone = 'ready' } = {}) {
@@ -3577,12 +3664,12 @@ async function startNewThread(tab = activeTab()) {
3577
3664
  } finally {
3578
3665
  if (!tab.closed) withTab(tab, () => {
3579
3666
  _startingThread = false;
3667
+ // The tab first, then what reads it (the pill, the saved tabs, the toolbar): renderPills
3668
+ // used to find it still starting and put the running class back on the pill.
3669
+ publishWorkState();
3580
3670
  syncInputEnabled();
3581
3671
  syncToolbarState();
3582
3672
  syncSessionControls();
3583
- updateTrayPillRunning();
3584
- renderPills();
3585
- saveTabs();
3586
3673
  releaseInactiveIdleTab(tab);
3587
3674
  });
3588
3675
  }
@@ -4438,7 +4525,7 @@ export function promptNameNewSession() {
4438
4525
  <div class="cxp-name-modal-row">
4439
4526
  <label class="cxp-name-modal-label">Project</label>
4440
4527
  <select class="cxp-name-modal-select" data-role="project">
4441
- ${projectOptions.map(p => `<option value="${String(p.value).replace(/"/g, '&quot;')}">${p.label}</option>`).join('')}
4528
+ ${projectOptions.map(p => `<option value="${esc(p.value)}">${esc(p.label)}</option>`).join('')}
4442
4529
  </select>
4443
4530
  </div>
4444
4531
  <div class="cxp-name-modal-row">
@@ -4476,7 +4563,8 @@ export function promptNameNewSession() {
4476
4563
  branchSel.innerHTML = '<option value="">(none)</option>';
4477
4564
  branchSel.disabled = true;
4478
4565
  } else {
4479
- branchSel.innerHTML = branches.map(b => `<option value="${b.replace(/"/g, '&quot;')}">${b}</option>`).join('');
4566
+ // A branch name is the repository's (an agent can make one): text, never markup.
4567
+ branchSel.innerHTML = branches.map(b => `<option value="${esc(b)}">${esc(b)}</option>`).join('');
4480
4568
  if (branchOriginal) branchSel.value = branchOriginal;
4481
4569
  branchSel.disabled = false;
4482
4570
  }
@@ -5078,6 +5166,8 @@ export function dispatchPrompt(prompt, { tab = activeTab(), images = null, paths
5078
5166
  }
5079
5167
  if (tab) {
5080
5168
  tab.extendedContextVerificationArmed = normalizeCodexContextMode(tab.contextMode) === 'extended';
5169
+ // A Stop's late ack must not end this prompt's turn (interruptAckEndsTurn).
5170
+ tab.promptCount = (tab.promptCount || 0) + 1;
5081
5171
  }
5082
5172
  requestCodexSessionTitle(tab, inputText, {
5083
5173
  paths: [...pathList, ...mentionList.map((mention) => mention.path).filter(Boolean)],
@@ -5417,7 +5507,8 @@ export function handleNotify(method, params) {
5417
5507
  flushPostCompactionPrompt(_boundTab);
5418
5508
  }
5419
5509
  if (_boundTab?.providerTitleDirty) scheduleCodexTitleReassert(_boundTab);
5420
- if (!shouldHoldForPlanApproval(_boundTab)) advanceQueue();
5510
+ // The queue of the tab whose turn this was, never the one on screen.
5511
+ if (!shouldHoldForPlanApproval(tab)) advanceQueue(tab);
5421
5512
  releaseInactiveIdleTab(tab);
5422
5513
  }
5423
5514
  break;
@@ -6130,6 +6221,7 @@ export function interruptTab(tab = activeTab()) {
6130
6221
  clearTimeout(tab._abortRetry);
6131
6222
  tab._abortRetry = null;
6132
6223
  }
6224
+ tab.interruptedAtPrompt = tab.promptCount || 0;
6133
6225
  sendSocket({ type: 'interrupt', sessionId: tab.id, threadId });
6134
6226
  tab._abortRetry = setTimeout(() => {
6135
6227
  tab._abortRetry = null;
@@ -6160,6 +6252,7 @@ export function interruptAllTabs() {
6160
6252
  const ws = tab.ws;
6161
6253
  const threadId = tab.threadId || null;
6162
6254
  if (ws && ws.readyState === 1) {
6255
+ tab.interruptedAtPrompt = tab.promptCount || 0;
6163
6256
  try {
6164
6257
  ws.send(JSON.stringify({
6165
6258
  type: 'interrupt',
@@ -6935,6 +7028,14 @@ export function steerActiveTurn() {
6935
7028
  return true;
6936
7029
  }
6937
7030
 
7031
+ /**
7032
+ * Whether `tab` has a turn running. The bound tab's is the module's own state (the freshest: withTab
7033
+ * writes it back to the tab only when it returns); any other tab's is its own.
7034
+ */
7035
+ function tabTurnRunning(tab) {
7036
+ return tab === _boundTab ? _running : !!tab?.running;
7037
+ }
7038
+
6938
7039
  export function syncQueueTray() {
6939
7040
  const tab = activeTab();
6940
7041
  if (!tab) return;
@@ -6952,7 +7053,8 @@ export function syncQueueTray() {
6952
7053
  if (hint) {
6953
7054
  hint.textContent = count > 0
6954
7055
  ? `${count} message${count > 1 ? 's' : ''} queued${tab.queuePaused ? ' (paused)' : ''}. Enter steers. Tab queues the next turn.`
6955
- : _running
7056
+ // The tab on screen's turn, not the bound tab's (a tab working in the background is bound while its events run).
7057
+ : tabTurnRunning(tab)
6956
7058
  ? 'Enter steers the active turn. Tab queues the next turn. Shift+Enter inserts a newline.'
6957
7059
  : 'Enter sends. Shift+Enter inserts a newline.';
6958
7060
  }
@@ -7012,7 +7114,7 @@ export function toggleQueuePause() {
7012
7114
  if (!tab) return;
7013
7115
  tab.queuePaused = !tab.queuePaused;
7014
7116
  syncQueueTray();
7015
- if (!tab.queuePaused) advanceQueue();
7117
+ if (!tab.queuePaused) advanceQueue(tab);
7016
7118
  saveTabs();
7017
7119
  }
7018
7120
 
@@ -7024,11 +7126,17 @@ export function clearQueue() {
7024
7126
  saveTabs();
7025
7127
  }
7026
7128
 
7027
- export function advanceQueue() {
7028
- const tab = activeTab();
7029
- if (!tab || _running || tab.queuePaused || !tab.queue.length || hasBlockingServerRequests() || shouldHoldForPlanApproval(tab)) return;
7129
+ /**
7130
+ * Send the next prompt queued in `tab`, the tab it was typed in, on that tab's own connection and
7131
+ * thread: a background tab whose turn ends advances its own queue, never the one on screen (the
7132
+ * module state is the bound tab's, so the tab is bound first).
7133
+ */
7134
+ export function advanceQueue(tab = activeTab()) {
7135
+ if (!tab || tab.closed) return false;
7136
+ if (_boundTab !== tab) return withTab(tab, () => advanceQueue(tab));
7137
+ if (_running || tab.queuePaused || !tab.queue?.length || hasBlockingServerRequests() || shouldHoldForPlanApproval(tab)) return false;
7030
7138
  const next = tab.queue.shift();
7031
- if (!next) return;
7139
+ if (!next) return false;
7032
7140
  if (tab.planMode) {
7033
7141
  preparePlanModeTurn(tab);
7034
7142
  }
@@ -7040,13 +7148,19 @@ export function advanceQueue() {
7040
7148
  mentions: next.mentions || [],
7041
7149
  forcePlanModePrefix: tab.planMode,
7042
7150
  });
7043
- if (!sent) return;
7151
+ if (!sent) {
7152
+ // Not sent: it stays first in its tab's queue.
7153
+ tab.queue.unshift(next);
7154
+ syncQueueTray();
7155
+ return false;
7156
+ }
7044
7157
  // Render queued user message immediately with images
7045
7158
  if (queueImages?.length) {
7046
7159
  appendLocalUserMessage(next.text || '', queueImages);
7047
7160
  tab._pendingSendImages = queueImages;
7048
7161
  }
7049
7162
  syncQueueTray();
7163
+ return true;
7050
7164
  }
7051
7165
 
7052
7166
  // ── Phase 2: Image attachments ──
@@ -1,5 +1,4 @@
1
- // Markdown → HTML for every Markdown sink of the Claude panel, and the scrub a
2
- // stored transcript snapshot goes through before it is put back on the page.
1
+ // Markdown → HTML for every Markdown sink of the Claude panel, and the panel's one escaper.
3
2
  //
4
3
  // What a model writes, what a command prints and what a transcript replays is
5
4
  // not ours: marked passes raw HTML through, so `<img onerror>` or a
@@ -47,58 +46,6 @@ export function renderMarkdown(text, { parse = null, sanitize = sanitizeHtmlStri
47
46
  }
48
47
  }
49
48
 
50
- // ── Stored snapshots ──
51
- // A snapshot is the transcript's own innerHTML, saved to be shown again on a
52
- // reopen. It is the panel's markup (cards, icons, buttons, data attributes),
53
- // so the Markdown allowlist would destroy it; but it may have been written by
54
- // a build that did not sanitise, and it comes back from storage. It is parsed
55
- // into an inert <template> and stripped of everything that can run or load
56
- // code before it reaches the page.
57
-
58
- const STORED_DROPPED = new Set(['script', 'iframe', 'frame', 'frameset', 'object', 'embed', 'applet', 'base', 'meta', 'link', 'style', 'template', 'noscript', 'foreignobject', 'animate', 'set', 'animatetransform', 'animatemotion']);
59
- const URL_ATTRS = new Set(['href', 'src', 'xlink:href', 'action', 'formaction', 'poster', 'data', 'background', 'ping']);
60
- const REMOVED_ATTRS = new Set(['srcdoc', 'srcset']);
61
- const SAFE_URL_SCHEMES = new Set(['http', 'https', 'mailto']);
62
-
63
- /** The scheme of a URL attribute as a browser reads it (whitespace and control characters ignored), or ''. */
64
- function schemeOf(value) {
65
- const m = /^([a-z][a-z0-9+.-]*):/i.exec(String(value ?? '').replace(/[\u0000- ]/g, ''));
66
- return m ? m[1].toLowerCase() : '';
67
- }
68
-
69
- function storedImageAllowed(src) {
70
- const compact = String(src ?? '').replace(/[\u0000- ]/g, '');
71
- if (!compact) return false;
72
- if (/^data:image\//i.test(compact) || /^blob:/i.test(compact)) return true;
73
- // A path on this server; a remote image is not loaded again from storage.
74
- return !schemeOf(compact) && !compact.startsWith('//');
75
- }
76
-
77
- function scrubNode(parent) {
78
- for (const node of [...parent.childNodes]) {
79
- if (node.nodeType === 3) continue;
80
- if (node.nodeType !== 1) { parent.removeChild(node); continue; }
81
- const tag = String(node.localName || '').toLowerCase();
82
- if (STORED_DROPPED.has(tag) || (tag === 'img' && !storedImageAllowed(node.getAttribute('src')))) { parent.removeChild(node); continue; }
83
- for (const name of node.getAttributeNames()) {
84
- const lower = name.toLowerCase();
85
- if (lower.startsWith('on') || REMOVED_ATTRS.has(lower)) { node.removeAttribute(name); continue; }
86
- if (!URL_ATTRS.has(lower)) continue;
87
- const scheme = schemeOf(node.getAttribute(name));
88
- if (!scheme || SAFE_URL_SCHEMES.has(scheme)) continue;
89
- if (tag === 'img' && lower === 'src') continue; // data:image / blob, checked above
90
- node.removeAttribute(name);
91
- }
92
- scrubNode(node);
93
- }
94
- }
95
-
96
- /** A stored snapshot's markup → a DocumentFragment with nothing executable left in it. */
97
- export function scrubStoredHtml(html, doc = globalThis.document) {
98
- const tpl = doc.createElement('template');
99
- tpl.innerHTML = String(html ?? '');
100
- scrubNode(tpl.content);
101
- const out = doc.createDocumentFragment();
102
- for (const node of [...tpl.content.childNodes]) out.appendChild(node);
103
- return out;
104
- }
49
+ // A stored transcript snapshot is not scrubbed here: the panel puts it back through
50
+ // sanitizeStoredHtml() of assistant/asst-sanitize.js, the stored-transcript allowlist
51
+ // every panel uses.