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
@@ -0,0 +1,243 @@
1
+ // ═══════════════════════════════════════════
2
+ // SETTINGS — App (what the page says)
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // The software's own controls: updates, start at login, the window, the
6
+ // folders and a restart. Two kinds of install answer them:
7
+ //
8
+ // desktop the SynaBun desktop app: its settings are the window's
9
+ // (window.synabunDesktop.app, packaging/desktop/src/app-prefs.mjs),
10
+ // its updates the app's updater (window.synabunDesktop.updates)
11
+ // server an npm or Git install: GET /api/system/app (lib/app-controls-api.js)
12
+ // and the update check of GET /api/system/version
13
+ //
14
+ // A row that does not apply to this install is not shown, or is shown off
15
+ // with one line that says why. This file decides; settings-app-pane.js draws.
16
+ // No imports and no DOM: `node --test` loads it as it is (tests/settings-app.test.mjs).
17
+
18
+ export const APP_URL = '/api/system/app';
19
+ const K = 'settings.redesign.app';
20
+
21
+ const bool = (value) => value === true;
22
+ const text = (value, max = 400) => (typeof value === 'string' && value ? value.slice(0, max) : null);
23
+ const PLATFORMS = new Set(['darwin', 'win32', 'linux']);
24
+ const LOGIN_STATUSES = new Set(['on', 'off', 'requires-approval', 'disabled', 'not-found']);
25
+ const SERVER_STATES = new Set(['on', 'off', 'stale', 'disabled']);
26
+
27
+ /** The desktop app's report (window.synabunDesktop.app.state()), checked field by field; null when there is none. */
28
+ export function readDesktopAppState(state) {
29
+ if (!state || typeof state !== 'object') return null;
30
+ const prefs = state.prefs && typeof state.prefs === 'object' ? state.prefs : {};
31
+ const login = state.login && typeof state.login === 'object' ? state.login : {};
32
+ const gpu = state.hardwareAcceleration && typeof state.hardwareAcceleration === 'object' ? state.hardwareAcceleration : {};
33
+ return {
34
+ platform: PLATFORMS.has(state.platform) ? state.platform : null,
35
+ packaged: bool(state.packaged),
36
+ prefs: {
37
+ autoUpdate: prefs.autoUpdate !== false,
38
+ openAtLogin: bool(prefs.openAtLogin),
39
+ startHidden: prefs.startHidden !== false,
40
+ hardwareAcceleration: prefs.hardwareAcceleration !== false,
41
+ closeToTray: prefs.closeToTray !== false,
42
+ },
43
+ login: {
44
+ supported: bool(login.supported),
45
+ reason: text(login.reason, 40),
46
+ enabled: bool(login.enabled),
47
+ status: LOGIN_STATUSES.has(login.status) ? login.status : 'off',
48
+ replaced: text(login.replaced, 40),
49
+ },
50
+ gpuRestartNeeded: bool(gpu.restartNeeded),
51
+ tray: bool(state.tray),
52
+ error: text(state.error, 40),
53
+ };
54
+ }
55
+
56
+ /** GET /api/system/app (or a refusal of a write, which carries the same body), checked; null when it is not one. */
57
+ export function readServerAppState(answer) {
58
+ if (!answer || typeof answer !== 'object' || typeof answer.install !== 'string') return null;
59
+ const startup = answer.startup && typeof answer.startup === 'object' ? answer.startup : {};
60
+ return {
61
+ install: text(answer.install, 20),
62
+ desktop: bool(answer.desktop),
63
+ autoUpdate: answer.updates?.auto !== false,
64
+ startup: {
65
+ supported: bool(startup.supported),
66
+ reason: text(startup.reason, 40),
67
+ enabled: bool(startup.enabled),
68
+ state: SERVER_STATES.has(startup.state) ? startup.state : 'off',
69
+ owner: text(startup.owner, 4096),
70
+ },
71
+ error: answer.ok === false ? text(answer.code, 40) || 'refused' : null,
72
+ };
73
+ }
74
+
75
+ /** Why GET /api/system/app gave no state: 'remote' (asked from another computer), 'old' (a server from before it), 'offline'. */
76
+ export function serverRefusal(status, body) {
77
+ const code = body && typeof body === 'object' ? String(body.code || '') : '';
78
+ if (status === 403 && ['LOCAL_ONLY', 'REMOTE_FORBIDDEN', 'BAD_HOST', 'GUEST_FORBIDDEN'].includes(code)) return 'remote';
79
+ if (status === 404 || status === 405) return 'old';
80
+ return 'offline';
81
+ }
82
+
83
+ // ── Updates ──
84
+
85
+ /**
86
+ * The line under the version: what the last check found. `data` is the page's
87
+ * update data (ui-update.js getSynabunUpdateData): the desktop app's report as
88
+ * versionDataFromDesktop() reads it, or GET /api/system/version.
89
+ * Returns { key, params, tone } (tone: ok | warn | err | off | busy).
90
+ */
91
+ export function updateStatus(data) {
92
+ if (!data || typeof data !== 'object') return { key: `${K}.update.notChecked`, params: {}, tone: 'off' };
93
+ const latest = text(data.latest, 64) || '';
94
+ if (data.desktop) {
95
+ if (data.supported === false) return { key: `${K}.update.unsupported`, params: {}, tone: 'off' };
96
+ switch (data.status) {
97
+ case 'checking': return { key: `${K}.update.checking`, params: {}, tone: 'busy' };
98
+ case 'downloading': return { key: `${K}.update.downloading`, params: { version: latest, percent: Math.floor(Number(data.progress?.percent) || 0) }, tone: 'busy' };
99
+ case 'downloaded': return { key: `${K}.update.ready`, params: { version: latest }, tone: 'warn' };
100
+ case 'installing': return { key: `${K}.update.installing`, params: { version: latest }, tone: 'busy' };
101
+ case 'error': return { key: `${K}.update.failed`, params: {}, tone: 'err' };
102
+ case 'not-available': return { key: `${K}.update.upToDate`, params: {}, tone: 'ok' };
103
+ default:
104
+ if (data.updateAvailable && latest) return { key: `${K}.update.available`, params: { version: latest }, tone: 'warn' };
105
+ return { key: `${K}.update.notChecked`, params: {}, tone: 'off' };
106
+ }
107
+ }
108
+ if (data.updateAvailable && latest) return { key: `${K}.update.available`, params: { version: latest }, tone: 'warn' };
109
+ if (!data.checkedAt) return { key: `${K}.update.notChecked`, params: {}, tone: 'off' };
110
+ if (data.npmError && data.gitError) return { key: `${K}.update.failed`, params: {}, tone: 'err' };
111
+ return { key: `${K}.update.upToDate`, params: {}, tone: 'ok' };
112
+ }
113
+
114
+ /** "Checked at 14:05" (`time` writes an ISO time the page's way), or '' before any check. */
115
+ export function checkedLine(data, { tx, time }) {
116
+ const at = text(data?.checkedAt, 64);
117
+ if (!at || !Number.isFinite(Date.parse(at))) return '';
118
+ return tx(`${K}.update.checkedAt`, { time: time(at) });
119
+ }
120
+
121
+ /** Is there an update to install now (the Install update button)? */
122
+ export function canInstallUpdate(data) {
123
+ if (!data?.updateAvailable) return false;
124
+ if (data.desktop) return ['available', 'downloaded', 'error'].includes(data.status) || !data.status;
125
+ return true;
126
+ }
127
+
128
+ /** The automatic updates switch: { checked, disabled, helpKey }. */
129
+ export function autoUpdateRow({ desktop, server, update }) {
130
+ if (desktop) {
131
+ return { checked: desktop.prefs.autoUpdate, disabled: update?.supported === false, helpKey: `${K}.update.autoHelpDesktop` };
132
+ }
133
+ return { checked: server ? server.autoUpdate : update?.autoCheck !== false, disabled: !server || server.desktop, helpKey: `${K}.update.autoHelpServer` };
134
+ }
135
+
136
+ // ── Startup ──
137
+
138
+ /** The sentence for an error code of a change, '' for none. */
139
+ export function startupErrorKey(code) {
140
+ if (!code) return '';
141
+ const known = ['refused', 'write-failed', 'no-wscript', 'bad-path', 'desktop-app', 'npm-entry', 'save-failed', 'network'];
142
+ return `${K}.startup.error.${known.includes(code) ? code : 'refused'}`;
143
+ }
144
+
145
+ /**
146
+ * The start at login switch and the line under it:
147
+ * { shown, checked, disabled, helpKey, note: { key, params, tone } | null, settingsButton: 'darwin' | 'win32' | null }
148
+ * `platform` is the computer's (the desktop app says its own; the browser's guess otherwise).
149
+ */
150
+ export function loginRow({ desktop, server, remote = false, platform = null }) {
151
+ const note = (key, tone = 'off', params = {}) => ({ key, params, tone });
152
+ if (desktop) {
153
+ const { login } = desktop;
154
+ const os = desktop.platform;
155
+ const row = {
156
+ shown: true, checked: login.enabled || login.status === 'requires-approval', disabled: !login.supported,
157
+ helpKey: `${K}.startup.helpDesktop`, note: null, settingsButton: null,
158
+ };
159
+ if (!login.supported) row.note = note(`${K}.startup.reason.${['unpackaged', 'move-to-applications', 'no-appimage'].includes(login.reason) ? login.reason : 'unsupported'}`);
160
+ else if (desktop.error && !['save-failed'].includes(desktop.error)) row.note = note(startupErrorKey(desktop.error), 'err');
161
+ else if (login.status === 'requires-approval') {
162
+ row.note = note(`${K}.startup.requiresApproval`, 'warn');
163
+ row.settingsButton = 'darwin';
164
+ } else if (login.status === 'disabled' || (desktop.prefs.openAtLogin && !login.enabled)) {
165
+ row.note = note(`${K}.startup.disabledInSystem.${os || 'linux'}`, 'warn');
166
+ if (os === 'darwin' || os === 'win32') row.settingsButton = os;
167
+ } else if (login.replaced) row.note = note(`${K}.startup.replaced`, 'ok');
168
+ if (desktop.error === 'save-failed') row.note = note(startupErrorKey('save-failed'), 'err');
169
+ return row;
170
+ }
171
+ const row = { shown: true, checked: !!server?.startup.enabled, disabled: true, helpKey: `${K}.startup.helpServer`, note: null, settingsButton: null };
172
+ if (remote) { row.note = note(`${K}.remote`); return row; }
173
+ if (!server) { row.note = note(`${K}.serverOld`); return row; }
174
+ const { startup } = server;
175
+ if (!startup.supported) {
176
+ // 'desktop': the SynaBun app answers for itself, and this one is from before its own settings.
177
+ row.note = note(`${K}.startup.reason.${['not-here', 'desktop'].includes(startup.reason) ? startup.reason : 'unsupported'}`);
178
+ return row;
179
+ }
180
+ row.disabled = false;
181
+ if (server.error) row.note = note(startupErrorKey(server.error), 'err');
182
+ else if (startup.owner && !startup.enabled) {
183
+ row.note = note(`${K}.startup.owner`, 'off');
184
+ row.disabled = true;
185
+ } else if (startup.state === 'disabled') {
186
+ row.note = note(`${K}.startup.disabledInSystem.${PLATFORMS.has(platform) ? platform : 'linux'}`, 'warn');
187
+ }
188
+ return row;
189
+ }
190
+
191
+ /** Start in the background (desktop only; shown under start at login, live while it is on). */
192
+ export function hiddenRow({ desktop }) {
193
+ if (!desktop) return { shown: false, checked: false, disabled: true };
194
+ const on = desktop.login.enabled || desktop.login.status === 'requires-approval';
195
+ return { shown: true, checked: desktop.prefs.startHidden, disabled: !desktop.login.supported || !on, noteKey: on ? '' : `${K}.startup.hiddenNeedsLogin` };
196
+ }
197
+
198
+ // ── Window ──
199
+
200
+ /**
201
+ * The window section: { reasonKey, closeToTray: { shown, checked, disabled, noteKey }, gpu: { checked, disabled, restartNeeded } }.
202
+ * Outside the desktop app the rows are shown off, with the one line that says they belong to it.
203
+ */
204
+ export function windowRows({ desktop }) {
205
+ if (!desktop) {
206
+ return {
207
+ reasonKey: `${K}.window.desktopOnly`,
208
+ closeToTray: { shown: true, checked: false, disabled: true, noteKey: '' },
209
+ gpu: { checked: false, disabled: true, restartNeeded: false },
210
+ };
211
+ }
212
+ const mac = desktop.platform === 'darwin';
213
+ return {
214
+ reasonKey: '',
215
+ closeToTray: {
216
+ shown: true,
217
+ checked: mac ? true : desktop.prefs.closeToTray,
218
+ disabled: mac,
219
+ // macOS keeps an app in the Dock; elsewhere without a tray icon, opening SynaBun again shows the window.
220
+ noteKey: mac ? `${K}.window.macDock` : (!desktop.tray && desktop.prefs.closeToTray ? `${K}.window.noTray` : ''),
221
+ },
222
+ gpu: { checked: desktop.prefs.hardwareAcceleration, disabled: false, restartNeeded: desktop.gpuRestartNeeded },
223
+ };
224
+ }
225
+
226
+ // ── Maintenance ──
227
+
228
+ /** The folder buttons and the restart: { folders: boolean, restart: boolean, noteKey }. */
229
+ export function maintenanceRow({ desktop, server, remote = false, restartAvailable = true }) {
230
+ if (desktop) return { folders: true, restart: restartAvailable, noteKey: '' };
231
+ if (remote) return { folders: false, restart: restartAvailable, noteKey: `${K}.remote` };
232
+ if (!server) return { folders: false, restart: restartAvailable, noteKey: `${K}.serverOld` };
233
+ return { folders: true, restart: restartAvailable, noteKey: '' };
234
+ }
235
+
236
+ /** The platform of this computer as the browser says it, when nothing better is known. */
237
+ export function guessPlatform(userAgent = '') {
238
+ const ua = String(userAgent);
239
+ if (/Mac OS X|Macintosh/i.test(ua)) return 'darwin';
240
+ if (/Windows/i.test(ua)) return 'win32';
241
+ if (/Linux|X11/i.test(ua)) return 'linux';
242
+ return null;
243
+ }
@@ -0,0 +1,88 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — Settings' reads
3
+ // ═══════════════════════════════════════════
4
+ // The answers the Settings modal is built from (openSettingsModal in
5
+ // ui-settings.js), kept in the page's data cache (data-cache.js): Settings
6
+ // opens from them at once and they are read again in the background once they
7
+ // are old. Only a first open waits for them; the launch prefetch reads them
8
+ // once the page has painted, and closing Settings reads them again, so the next
9
+ // open shows what was changed in this one. Each open gets its own copy (the
10
+ // panes edit theirs in place). Never kept in sessionStorage: this is
11
+ // configuration.
12
+ // No DOM: runs under node --test as well.
13
+
14
+ import { createDataCache } from '../data-cache.js';
15
+
16
+ const MINUTE = 60_000;
17
+
18
+ // `ok`: the endpoint says it answered (`{ ok: true, … }`). `raw`: the status and body are kept as they came, for
19
+ // a reader that tells the states apart itself (settings-greeting.js, settings-user-context.js).
20
+ const okBody = (body) => !!body && typeof body === 'object' && body.ok !== false && !body.error;
21
+ export const SETTINGS_READS = Object.freeze({
22
+ settings: { url: '/api/settings', accept: okBody },
23
+ connections: { url: '/api/connections', accept: (body) => Array.isArray(body?.connections) },
24
+ integrations: { url: '/api/claude-code/integrations', accept: (body) => body?.ok === true },
25
+ skills: { url: '/api/claude-code/skills', accept: (body) => body?.ok === true },
26
+ // The tunnel changes by itself (starting, stopping from the Share menu): asked again after a few seconds.
27
+ tunnel: { url: '/api/tunnel/status', accept: (body) => body?.ok === true, ttlMs: 10_000 },
28
+ mcpKey: { url: '/api/mcp-key', accept: (body) => body?.ok === true },
29
+ openclaw: { url: '/api/bridges/openclaw', accept: (body) => body?.ok === true },
30
+ greeting: { url: '/api/greeting', raw: true },
31
+ setup: { url: '/api/setup/status', accept: (body) => body?.ok === true },
32
+ cli: { url: '/api/cli/config', accept: (body) => body?.ok === true },
33
+ toolPermissions: { url: '/api/claude-code/tool-permissions', accept: (body) => body?.ok === true },
34
+ toolCategories: { url: '/api/claude-code/tool-categories', accept: (body) => body?.ok === true, ttlMs: 10 * MINUTE },
35
+ discord: { url: '/api/discord/config', accept: (body) => body?.ok === true },
36
+ skins: { url: '/api/skins', accept: (body) => body?.ok === true },
37
+ icons: { url: '/api/file-icons', accept: (body) => body?.ok === true },
38
+ youtube: { url: '/api/youtube/config', accept: (body) => body?.ok === true },
39
+ typesafe: { url: '/api/typesafe/config', accept: (body) => body?.ok === true },
40
+ userContext: { url: '/api/assistant/user-context', raw: true },
41
+ });
42
+
43
+ const caches = Object.fromEntries(Object.entries(SETTINGS_READS).map(([name, spec]) => [name, createDataCache(`settings:${name}`, {
44
+ ttlMs: spec.ttlMs || MINUTE,
45
+ load: async () => {
46
+ const res = await fetch(spec.url);
47
+ if (spec.raw) return { status: res.status, body: await res.json().catch(() => null) };
48
+ if (!res.ok) throw new Error(`${spec.url}: HTTP ${res.status}`);
49
+ return res.json();
50
+ },
51
+ accept: spec.raw ? (value) => value?.status >= 200 && value.status < 300 && !!value.body : spec.accept,
52
+ })]));
53
+
54
+ function copy(value) {
55
+ try { return typeof structuredClone === 'function' ? structuredClone(value) : JSON.parse(JSON.stringify(value)); } catch { return value; }
56
+ }
57
+
58
+ /**
59
+ * Every read, as Promise.allSettled gives them: `{ [name]: { status: 'fulfilled', value } | { status: 'rejected',
60
+ * reason } }`. A kept answer is given at once (a copy of it) and read again in the background when it is old;
61
+ * a read never made waits for its request, as the modal always did.
62
+ */
63
+ export async function readSettingsData() {
64
+ const names = Object.keys(SETTINGS_READS);
65
+ const settled = await Promise.allSettled(names.map((name) => caches[name].get('')));
66
+ return Object.fromEntries(names.map((name, i) => [name, settled[i].status === 'fulfilled' ? { status: 'fulfilled', value: copy(settled[i].value) } : settled[i]]));
67
+ }
68
+
69
+ /** Read whatever is not fresh now (launch prefetch); resolves when done, never rejects. */
70
+ export function prefetchSettingsData() {
71
+ return Promise.allSettled(Object.values(caches).map((cache) => cache.prefetch(''))).then(() => undefined);
72
+ }
73
+
74
+ /**
75
+ * The answers are due (Settings closed: something may have been changed in it; a sync event said so): the next
76
+ * open waits for none of them that are read again in time, and `names` limits it to some.
77
+ */
78
+ export function refreshSettingsData(names = null) {
79
+ for (const [name, cache] of Object.entries(caches)) {
80
+ if (names && !names.includes(name)) continue;
81
+ cache.invalidate('', { refetch: true });
82
+ }
83
+ }
84
+
85
+ /** True when every read has an answer kept (Settings can open without waiting). */
86
+ export function settingsDataReady() {
87
+ return Object.values(caches).every((cache) => cache.has(''));
88
+ }
@@ -184,6 +184,19 @@ export const SETTINGS_PAGES = [
184
184
  { id: 'stg-sec-2d-graph', key: 'd2_graph', state: 'advanced', variant: 'graphics' },
185
185
  ],
186
186
  },
187
+ {
188
+ // The software itself (settings-app-pane.js): updates, start at login, the window, the folders and a restart.
189
+ // A row shows where it applies: the desktop app's own settings come from the app (window.synabunDesktop.app),
190
+ // an npm or Git install's from GET /api/system/app; settings-app.js decides what each install shows.
191
+ id: 'app', key: 'app', group: 'app', icon: 'app',
192
+ panes: [{ id: 'app' }],
193
+ sections: [
194
+ { id: 'stg-sec-app-updates', key: 'updates', state: 'open' },
195
+ { id: 'stg-sec-app-startup', key: 'startup', state: 'open' },
196
+ { id: 'stg-sec-app-window', key: 'window', state: 'open' },
197
+ { id: 'stg-sec-app-maintenance', key: 'maintenance', state: 'open' },
198
+ ],
199
+ },
187
200
  {
188
201
  // The last page: version, links, system and dependencies (settings-about-pane.js, GET /api/system/about).
189
202
  // Its header (icon, version, Check for updates, Copy info) is not a section: it is always shown.
@@ -290,6 +303,10 @@ export const SETTINGS_CONTROLS = {
290
303
  'stg-sec-visual-tuning': 'UI003 UI004 UI005 UI006 UI007 UI008 UI009 UI010',
291
304
  'stg-sec-file-icons': 'ICO001 ICO003 ICO002 ICO004 ICO005',
292
305
  'stg-sec-2d-graph': 'GFX001 GFX002 GFX003 GFX004 GFX005 GFX006 GFX007 GFX008',
306
+ 'stg-sec-app-updates': 'SYS001 SYS002 SYS003',
307
+ 'stg-sec-app-startup': 'SYS004 SYS005',
308
+ 'stg-sec-app-window': 'SYS006 SYS007 SYS008',
309
+ 'stg-sec-app-maintenance': 'SYS009 SYS010 SYS011',
293
310
  'stg-sec-about-dependencies': 'ABT003',
294
311
  };
295
312
  /** Controls of a page that sit outside its sections (a pane's save bar, the tabs of a pane). */
@@ -0,0 +1,49 @@
1
+ // What a detached session window (ui-sidepanel-sessions.js) is doing, for the
2
+ // pill the main window shows for it. It is read from the window's own tray
3
+ // pills, the ones its provider panel paints from its sessions' state: Claude
4
+ // (tabWorking: a turn or background agents and shells; tabNeedsYou: a
5
+ // permission or a question waiting), Codex (a turn or a thread being made; an
6
+ // approval or a question card waiting), OpenCode (tabPillState: a turn, an
7
+ // automation's turn, a sub-agent's, one waiting on you) and the SynaBun
8
+ // Assistant (sessionStatus). The same source as the tray pills, never a second
9
+ // guess. DOM-free.
10
+
11
+ const WORKING = /^(cp|cxp|ocpv2|asp)-pill-running$/;
12
+ const NEEDS_YOU = /^((cp|cxp|asp)-pill-attention|ocpv2-pill-waiting)$/;
13
+
14
+ /** The states a detached window's pill shows: a session in it needs you > one works > none. */
15
+ export const SESSION_WINDOW_STATES = Object.freeze(['action', 'working', 'idle']);
16
+
17
+ /**
18
+ * 'action' when a session in the window waits on you, 'working' when one works,
19
+ * else 'idle'. `pills`: the class names of each tray pill of the window.
20
+ */
21
+ export function sessionWindowStatus(pills) {
22
+ let working = false;
23
+ for (const classes of pills || []) {
24
+ for (const cls of classes || []) {
25
+ if (NEEDS_YOU.test(cls)) return 'action';
26
+ if (WORKING.test(cls)) working = true;
27
+ }
28
+ }
29
+ return working ? 'working' : 'idle';
30
+ }
31
+
32
+ /** A status a window reported, or 'idle' for anything else. */
33
+ export function normalizeSessionWindowStatus(status) {
34
+ return SESSION_WINDOW_STATES.includes(status) ? status : 'idle';
35
+ }
36
+
37
+ /**
38
+ * A dispatched worker's run (its descriptor) waits on your answer with no card
39
+ * in its tab: its turn ended asking you something (the run's outcome is
40
+ * needs_input while the warm worker rests between turns). Claude's and Codex's
41
+ * tabs say "needs you" for it, as OpenCode's do (automationTurnPhase); a card
42
+ * of their own (a permission, a question) says it already. A run that ended
43
+ * waits on nobody.
44
+ */
45
+ export function runAwaitsAnswer(run) {
46
+ if (run?.status !== 'starting' && run?.status !== 'running') return false;
47
+ if (run.turnState === 'needs_input') return true;
48
+ return run.turnState === 'idle' && (run.outcome || run.lastResult?.status) === 'needs_input';
49
+ }