synabun 2.1.0 → 2.2.1

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 (332) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/README.md +1 -1
  3. package/docs/whatsapp.md +11 -11
  4. package/lib/client-config-repair.js +13 -9
  5. package/lib/external-tools.js +6 -5
  6. package/lib/update-snapshot.js +77 -3
  7. package/lib/virustotal.mjs +12 -1
  8. package/mcp-server/dist/index.js +1 -1
  9. package/mcp-server/dist/index.js.map +1 -1
  10. package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
  11. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  12. package/mcp-server/dist/services/budget-judgments.js +5 -3
  13. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  14. package/mcp-server/dist/services/identity.d.ts +2 -2
  15. package/mcp-server/dist/services/identity.js +2 -2
  16. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  17. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  18. package/mcp-server/dist/services/memory-sessions.js +28 -2
  19. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  20. package/mcp-server/dist/services/neural-interface.d.ts +2 -1
  21. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  22. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  23. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  24. package/mcp-server/dist/services/server-instructions.js +2 -1
  25. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  26. package/mcp-server/dist/services/tool-catalog.js +1 -1
  27. package/mcp-server/dist/services/tool-catalog.js.map +1 -1
  28. package/mcp-server/dist/services/tool-list.d.ts +1 -1
  29. package/mcp-server/dist/services/tool-list.d.ts.map +1 -1
  30. package/mcp-server/dist/services/tool-runtime.d.ts +2 -2
  31. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -1
  32. package/mcp-server/dist/services/tool-runtime.js +1 -1
  33. package/mcp-server/dist/services/tool-runtime.js.map +1 -1
  34. package/mcp-server/dist/services/typesafe-config.js +1 -1
  35. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  36. package/mcp-server/dist/tools/agents.d.ts +8 -8
  37. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  38. package/mcp-server/dist/tools/agents.js +10 -9
  39. package/mcp-server/dist/tools/agents.js.map +1 -1
  40. package/mcp-server/dist/tools/choice.d.ts +6 -0
  41. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  42. package/mcp-server/dist/tools/choice.js +18 -13
  43. package/mcp-server/dist/tools/choice.js.map +1 -1
  44. package/mcp-server/dist/tools/git-tools.js +2 -2
  45. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  46. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  47. package/mcp-server/dist/tools/morelogin.js +9 -6
  48. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  49. package/mcp-server/dist/tools/skill-tools.d.ts +8 -8
  50. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -1
  51. package/mcp-server/dist/tools/skill-tools.js +11 -8
  52. package/mcp-server/dist/tools/skill-tools.js.map +1 -1
  53. package/mcp-server/package-lock.json +2 -2
  54. package/mcp-server/package.json +1 -1
  55. package/mcp-server/src/index.ts +1 -1
  56. package/mcp-server/src/services/budget-judgments.ts +5 -3
  57. package/mcp-server/src/services/identity.ts +2 -2
  58. package/mcp-server/src/services/memory-sessions.ts +24 -3
  59. package/mcp-server/src/services/neural-interface.ts +2 -1
  60. package/mcp-server/src/services/server-instructions.ts +2 -1
  61. package/mcp-server/src/services/tool-catalog.ts +1 -1
  62. package/mcp-server/src/services/tool-list.ts +1 -1
  63. package/mcp-server/src/services/tool-runtime.ts +2 -2
  64. package/mcp-server/src/services/typesafe-config.ts +1 -1
  65. package/mcp-server/src/tools/agents.ts +10 -9
  66. package/mcp-server/src/tools/choice.ts +17 -12
  67. package/mcp-server/src/tools/git-tools.ts +2 -2
  68. package/mcp-server/src/tools/morelogin.ts +6 -4
  69. package/mcp-server/src/tools/skill-tools.ts +11 -8
  70. package/neural-interface/i18n/en.json +504 -39
  71. package/neural-interface/i18n/pt-BR.json +504 -39
  72. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  73. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  74. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  75. package/neural-interface/lib/antigravity/bypass.js +100 -0
  76. package/neural-interface/lib/antigravity/catalog.js +273 -0
  77. package/neural-interface/lib/antigravity/home.js +260 -0
  78. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  79. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  80. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  81. package/neural-interface/lib/antigravity/policy.js +74 -0
  82. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  83. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  84. package/neural-interface/lib/antigravity/usage.js +43 -0
  85. package/neural-interface/lib/assistant-api.js +1 -0
  86. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  87. package/neural-interface/lib/assistant-brains/codex.js +6 -1
  88. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  89. package/neural-interface/lib/assistant-budget-split.js +42 -15
  90. package/neural-interface/lib/assistant-catalog.js +76 -9
  91. package/neural-interface/lib/assistant-config.js +6 -3
  92. package/neural-interface/lib/assistant-dispatch.js +211 -50
  93. package/neural-interface/lib/assistant-envelope.js +153 -1
  94. package/neural-interface/lib/assistant-evidence.js +80 -0
  95. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  96. package/neural-interface/lib/assistant-persona.js +16 -11
  97. package/neural-interface/lib/assistant-plan-permissions.js +15 -0
  98. package/neural-interface/lib/assistant-router.js +237 -35
  99. package/neural-interface/lib/assistant-runtime.js +158 -12
  100. package/neural-interface/lib/assistant-task-prompt.js +10 -8
  101. package/neural-interface/lib/assistant-tools.js +2 -2
  102. package/neural-interface/lib/assistant-usage.js +29 -0
  103. package/neural-interface/lib/backup-service.js +6 -1
  104. package/neural-interface/lib/browser-guard-cdp.js +5 -4
  105. package/neural-interface/lib/browser-network-guard.js +274 -82
  106. package/neural-interface/lib/browser-tool-policy.js +12 -7
  107. package/neural-interface/lib/claude-agent-bridge.js +7 -0
  108. package/neural-interface/lib/claude-history-cache.js +210 -0
  109. package/neural-interface/lib/claude-model-catalog.js +5 -1
  110. package/neural-interface/lib/cli-install-api.js +1 -1
  111. package/neural-interface/lib/cli-install.js +160 -31
  112. package/neural-interface/lib/cli-resolver.js +9 -2
  113. package/neural-interface/lib/cli-update-planner.js +25 -15
  114. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  115. package/neural-interface/lib/codex-worker-app-server.js +25 -6
  116. package/neural-interface/lib/editor-git-api.js +3 -20
  117. package/neural-interface/lib/exec-loop-command.js +9 -2
  118. package/neural-interface/lib/file-explorer-api.js +74 -40
  119. package/neural-interface/lib/file-explorer-watch.js +9 -3
  120. package/neural-interface/lib/git-bash/install.js +52 -6
  121. package/neural-interface/lib/git-bash/manager.js +59 -17
  122. package/neural-interface/lib/git-bash/pins.js +12 -0
  123. package/neural-interface/lib/git-read.js +2 -2
  124. package/neural-interface/lib/git-status-runner.js +390 -0
  125. package/neural-interface/lib/git-status-watchdog.js +40 -0
  126. package/neural-interface/lib/greeting/budgets.js +1 -0
  127. package/neural-interface/lib/greeting/engine.js +2 -2
  128. package/neural-interface/lib/greeting/sources.js +10 -12
  129. package/neural-interface/lib/greeting/writer.js +1 -1
  130. package/neural-interface/lib/mcp-client-config.js +37 -6
  131. package/neural-interface/lib/mcp-external-servers.js +40 -7
  132. package/neural-interface/lib/mcp-installer.js +2 -1
  133. package/neural-interface/lib/memory-session-capture.js +17 -3
  134. package/neural-interface/lib/morelogin.js +147 -25
  135. package/neural-interface/lib/native-loop-providers.js +423 -23
  136. package/neural-interface/lib/native-loop-runtime.js +23 -2
  137. package/neural-interface/lib/opencode-native-boundary.js +165 -22
  138. package/neural-interface/lib/owner-authority.js +1 -1
  139. package/neural-interface/lib/path-confine.js +12 -9
  140. package/neural-interface/lib/peer-identity.js +80 -6
  141. package/neural-interface/lib/pty-host/core.js +28 -1
  142. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  143. package/neural-interface/lib/pty-host/manager.js +12 -1
  144. package/neural-interface/lib/remote-policy.js +1 -1
  145. package/neural-interface/lib/request-gate.js +3 -0
  146. package/neural-interface/lib/rulesets/api.js +6 -5
  147. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  148. package/neural-interface/lib/rulesets/installer.js +89 -10
  149. package/neural-interface/lib/rulesets/render.js +1 -1
  150. package/neural-interface/lib/session-cache-builder.js +64 -1
  151. package/neural-interface/lib/skills/catalog.js +5 -1
  152. package/neural-interface/lib/skills/creation-brief.js +1 -1
  153. package/neural-interface/lib/skills/creation-sources.js +19 -1
  154. package/neural-interface/lib/skills/deploy.js +9 -4
  155. package/neural-interface/lib/skills/draft-confinement.js +3 -1
  156. package/neural-interface/lib/skills/eval-confinement.js +3 -1
  157. package/neural-interface/lib/skills/eval-trace.js +16 -0
  158. package/neural-interface/lib/skills/export.js +5 -2
  159. package/neural-interface/lib/skills/known-bridge-digests.json +58 -4
  160. package/neural-interface/lib/skills/ownership.js +1 -1
  161. package/neural-interface/lib/skills/roots.js +10 -3
  162. package/neural-interface/lib/skills/runtime-checks.js +6 -3
  163. package/neural-interface/lib/skills/service.js +15 -7
  164. package/neural-interface/lib/skills/telemetry.js +6 -0
  165. package/neural-interface/lib/synabun-version.js +1 -1
  166. package/neural-interface/lib/system-activity.js +1 -1
  167. package/neural-interface/lib/whatsapp/brain.js +7 -3
  168. package/neural-interface/lib/whatsapp/cards.js +22 -9
  169. package/neural-interface/lib/whatsapp/config.js +1 -1
  170. package/neural-interface/lib/worker-confinement.js +77 -1
  171. package/neural-interface/lib/worker-question.js +74 -0
  172. package/neural-interface/lib/worker-resume.js +13 -4
  173. package/neural-interface/lib/worker-sandbox.js +46 -16
  174. package/neural-interface/package-lock.json +18 -2
  175. package/neural-interface/package.json +2 -1
  176. package/neural-interface/public/onboarding.html +1 -1
  177. package/neural-interface/public/shared/agent-runtime-options.js +89 -11
  178. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  179. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  180. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  181. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  182. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  183. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  184. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  185. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  186. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  187. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  188. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  189. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  190. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  191. package/neural-interface/public/shared/api.js +4 -4
  192. package/neural-interface/public/shared/assistant/asst-agents-dock.js +3 -4
  193. package/neural-interface/public/shared/assistant/asst-api.js +15 -3
  194. package/neural-interface/public/shared/assistant/asst-brain-picker.js +56 -9
  195. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  196. package/neural-interface/public/shared/assistant/asst-computer.js +26 -2
  197. package/neural-interface/public/shared/assistant/asst-control.js +48 -0
  198. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  199. package/neural-interface/public/shared/assistant/asst-limit-dock.js +6 -1
  200. package/neural-interface/public/shared/assistant/asst-limit-wait.js +38 -5
  201. package/neural-interface/public/shared/assistant/asst-motion-gate.js +80 -0
  202. package/neural-interface/public/shared/assistant/asst-panel.js +46 -9
  203. package/neural-interface/public/shared/assistant/asst-render.js +112 -18
  204. package/neural-interface/public/shared/assistant/asst-route.js +237 -57
  205. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  206. package/neural-interface/public/shared/assistant/asst-scene-styles.js +55 -23
  207. package/neural-interface/public/shared/assistant/asst-scenes.js +279 -80
  208. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +4 -4
  209. package/neural-interface/public/shared/assistant/asst-sidepanel.js +51 -7
  210. package/neural-interface/public/shared/assistant/asst-slash.js +8 -2
  211. package/neural-interface/public/shared/assistant/asst-state.js +76 -9
  212. package/neural-interface/public/shared/assistant/asst-style-cache.js +44 -0
  213. package/neural-interface/public/shared/assistant/asst-styles.js +58 -4
  214. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +34 -7
  215. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  216. package/neural-interface/public/shared/cdx/cdx-output.js +26 -3
  217. package/neural-interface/public/shared/cdx/cdx-panel.js +14 -2
  218. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  219. package/neural-interface/public/shared/cdx/cdx-protocol.js +11 -10
  220. package/neural-interface/public/shared/cdx/cdx-render.js +10 -9
  221. package/neural-interface/public/shared/cdx/cdx-requests.js +11 -1
  222. package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
  223. package/neural-interface/public/shared/cdx/cdx-tabs.js +75 -5
  224. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  225. package/neural-interface/public/shared/cli-install-view.js +7 -4
  226. package/neural-interface/public/shared/cli-status.js +9 -8
  227. package/neural-interface/public/shared/constants.js +3 -2
  228. package/neural-interface/public/shared/context-menu-model.js +1 -0
  229. package/neural-interface/public/shared/cp/cp-permissions.js +12 -0
  230. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  231. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  232. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  233. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  234. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  235. package/neural-interface/public/shared/desktop-update-view.js +1 -0
  236. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  237. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  238. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  239. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  240. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  241. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  242. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  243. package/neural-interface/public/shared/html-shell.js +21 -4
  244. package/neural-interface/public/shared/loading-teardown.js +34 -0
  245. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +6 -1
  246. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +28 -7
  247. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  248. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +17 -1
  249. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +6 -0
  250. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +101 -68
  251. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +46 -3
  252. package/neural-interface/public/shared/provider-icons.js +4 -2
  253. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  254. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +1 -1
  255. package/neural-interface/public/shared/settings/settings-skill-folders.js +2 -2
  256. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  257. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  258. package/neural-interface/public/shared/skills/ss-creation.js +6 -3
  259. package/neural-interface/public/shared/skills/ss-dialog.js +5 -2
  260. package/neural-interface/public/shared/skills/ss-lint.js +9 -1
  261. package/neural-interface/public/shared/skills/ss-profiles.js +44 -6
  262. package/neural-interface/public/shared/skills/ss-review-view.js +2 -2
  263. package/neural-interface/public/shared/skills/studio/sx-actions.js +1 -1
  264. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +1 -1
  265. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +2 -1
  266. package/neural-interface/public/shared/skills/studio/sx-dom.js +2 -1
  267. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  268. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  269. package/neural-interface/public/shared/skills/studio/sx-inspector.js +1 -1
  270. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +9 -6
  271. package/neural-interface/public/shared/skills/studio/sx-install.js +20 -3
  272. package/neural-interface/public/shared/skills/studio/sx-library-view.js +144 -35
  273. package/neural-interface/public/shared/skills/studio/sx-library.js +6 -2
  274. package/neural-interface/public/shared/skills/studio/sx-main.js +11 -2
  275. package/neural-interface/public/shared/skills/studio/sx-review-view.js +1 -1
  276. package/neural-interface/public/shared/skills/studio/sx-subject.js +7 -6
  277. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +6 -5
  278. package/neural-interface/public/shared/state.js +1 -1
  279. package/neural-interface/public/shared/storage-retry.js +47 -0
  280. package/neural-interface/public/shared/storage.js +25 -4
  281. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  282. package/neural-interface/public/shared/styles.css +362 -35
  283. package/neural-interface/public/shared/synabun-mascot.js +27 -8
  284. package/neural-interface/public/shared/synabun-ticker.js +147 -12
  285. package/neural-interface/public/shared/text-cache.js +29 -0
  286. package/neural-interface/public/shared/tool-list-picker.js +2 -2
  287. package/neural-interface/public/shared/tool-list-view.js +2 -2
  288. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  289. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  290. package/neural-interface/public/shared/ui-assistant.js +2 -0
  291. package/neural-interface/public/shared/ui-automation-studio.js +20 -12
  292. package/neural-interface/public/shared/ui-claude-panel.js +374 -134
  293. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  294. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  295. package/neural-interface/public/shared/ui-file-links.js +2 -2
  296. package/neural-interface/public/shared/ui-games.js +2 -2
  297. package/neural-interface/public/shared/ui-judgments.js +1 -1
  298. package/neural-interface/public/shared/ui-keybinds.js +8 -2
  299. package/neural-interface/public/shared/ui-link.js +3 -3
  300. package/neural-interface/public/shared/ui-loading.js +5 -4
  301. package/neural-interface/public/shared/ui-menubar.js +2 -2
  302. package/neural-interface/public/shared/ui-native-loop-router.js +4 -0
  303. package/neural-interface/public/shared/ui-navbar.js +45 -0
  304. package/neural-interface/public/shared/ui-notifications.js +1 -0
  305. package/neural-interface/public/shared/ui-resume.js +9 -7
  306. package/neural-interface/public/shared/ui-schedules-studio.js +41 -10
  307. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  308. package/neural-interface/public/shared/ui-sessions.js +22 -12
  309. package/neural-interface/public/shared/ui-settings.js +90 -65
  310. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  311. package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -3
  312. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  313. package/neural-interface/public/shared/ui-sidepanel-windows.js +3 -3
  314. package/neural-interface/public/shared/ui-terminal.js +146 -10
  315. package/neural-interface/public/shared/ui-tool-updates.js +3 -3
  316. package/neural-interface/public/shared/ui-tooltip.js +71 -46
  317. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  318. package/neural-interface/public/shared/ui-whiteboard.js +1 -1
  319. package/neural-interface/public/shared/ui-worker-end.js +1 -1
  320. package/neural-interface/public/shared/whatsapp/wa-view.js +2 -2
  321. package/neural-interface/public/shared/worker-questions.js +34 -0
  322. package/neural-interface/public/sidepanel-session.html +1 -1
  323. package/neural-interface/server.js +731 -466
  324. package/neural-interface/templates/rulesets/README.md +1 -1
  325. package/neural-interface/templates/rulesets/legacy-hashes.json +5 -5
  326. package/neural-interface/templates/rulesets/manifest.json +1 -1
  327. package/npm-shrinkwrap.json +18 -2
  328. package/package.json +2 -1
  329. package/skills/skill-forge/SKILL.md +4 -4
  330. package/skills/synabun/SKILL.md +1 -1
  331. package/skills/synabun/modules/schedule.md +3 -3
  332. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -177,10 +177,10 @@ export function getSharedHTML() {
177
177
  <span class="menu-text"><span class="menu-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"/></svg></span> ${t('menu.apps.codexCli')} <span class="count-badge count-badge--green menu-update-badge" id="codex-menu-update-badge"></span></span>
178
178
  <span class="menu-shortcut" data-keybind-for="launch-codex"></span>
179
179
  </div>
180
- <div class="menu-item" id="menu-terminal-gemini">
180
+ <div class="menu-item" id="menu-terminal-antigravity">
181
181
  <span class="menu-check"></span>
182
- <span class="menu-text"><span class="menu-icon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z"/></svg></span> ${t('menu.apps.geminiCli')} <span class="count-badge count-badge--green menu-update-badge" id="gemini-menu-update-badge"></span></span>
183
- <span class="menu-shortcut" data-keybind-for="launch-gemini"></span>
182
+ <span class="menu-text"><span class="menu-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 20 12 4l7.5 16"/><path d="M8.2 20a3.8 3.8 0 0 1 7.6 0"/></svg></span> ${t('menu.apps.antigravityCli')} <span class="count-badge count-badge--green menu-update-badge" id="antigravity-menu-update-badge"></span></span>
183
+ <span class="menu-shortcut" data-keybind-for="launch-antigravity"></span>
184
184
  </div>
185
185
  <div class="menu-item" id="menu-terminal-opencode">
186
186
  <span class="menu-check"></span>
@@ -495,7 +495,8 @@ ${is3D ? '' : `
495
495
  </div>
496
496
 
497
497
  <!-- Top-Right Controls: one row. The glass dock (workspace switcher, then the tools), then #topright-buttons: the
498
- tools toggle (#topright-tools-btn, shows and hides the dock) and the agent side panels, always one row of their own.
498
+ ⋯ (#topright-overflow-btn: what does not fit the band, ui-topright-overflow.js), the tools toggle
499
+ (#topright-tools-btn, shows and hides the dock) and the agent side panels. Always one row, never wrapped.
499
500
  Snap to grid and Tile terminals are on the whiteboard rail (#wb-toolbar) and in View. The session pills
500
501
  (#term-minimized-tray) are a row under the bar, right-aligned with it (styles.css: "Fit"). -->
501
502
  <div id="topright-controls">
@@ -569,6 +570,10 @@ ${is3D ? '' : `
569
570
  </button>
570
571
  </div>
571
572
  <div id="topright-buttons">
573
+ <button id="topright-overflow-btn" class="topright-icon-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="topright-overflow-menu" aria-label="${t('toolbar.more')}" data-tooltip="${t('toolbar.more')}">
574
+ <svg viewBox="0 0 24 24"><circle cx="5" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="19" cy="12" r="1.4" fill="currentColor" stroke="none"/></svg>
575
+ </button>
576
+ <div id="topright-overflow-menu" role="menu" aria-label="${t('toolbar.more')}" hidden></div>
572
577
  <button id="topright-tools-btn" class="topright-icon-btn" type="button" aria-expanded="true" aria-controls="topright-inner" aria-label="${t('toolbar.hideTools')}" data-tooltip="${t('toolbar.hideTools')}">
573
578
  <svg viewBox="0 0 24 24"><path d="M13 17l5-5-5-5"/><path d="M6 17l5-5-5-5"/></svg>
574
579
  <span class="topright-tools-dot" aria-hidden="true"></span>
@@ -588,9 +593,16 @@ ${is3D ? '' : `
588
593
  <svg viewBox="0 0 24 30" fill="currentColor"><path d="M18 6H6V24H18V6ZM24 30H0V0H24V30Z"/></svg>
589
594
  <span class="count-badge count-badge--green" id="opencode-update-badge"></span>
590
595
  </button>
596
+ <button id="topright-antigravity-panel-btn" class="topright-icon-btn" data-tooltip="${t('antigravityPanel.toolbar')}">
597
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 20 12 4l7.5 16"/><path d="M8.2 20a3.8 3.8 0 0 1 7.6 0"/></svg>
598
+ <span class="count-badge count-badge--green" id="antigravity-update-badge"></span>
599
+ </button>
591
600
  </div>
592
601
  <div id="term-minimized-tray"></div>
593
602
  </div>
603
+ <button id="toolbar-show-btn" type="button" aria-pressed="true" aria-controls="wb-toolbar" aria-label="${t('toolbar.showWhiteboardToolbar')}" data-tooltip="${t('toolbar.showWhiteboardToolbar')}" hidden>
604
+ <img src="logo-synabun.png" alt="" draggable="false">
605
+ </button>
594
606
 
595
607
  <!-- Help Modal -->
596
608
  <div id="help-overlay">
@@ -701,6 +713,7 @@ ${is3D ? '' : `
701
713
  <span class="fe-branch-btn-name" id="fe-branch-btn-name"></span>
702
714
  <span class="fe-branch-btn-badge" id="fe-branch-btn-badge"></span>
703
715
  </button>
716
+ <span class="fe-git-scan-live" id="fe-git-scan-live" role="status" aria-live="polite"></span>
704
717
  </div>
705
718
  <div class="fe-filter">
706
719
  <svg class="fe-filter-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 5h18l-7 8v6l-4-2v-4z"/></svg>
@@ -821,6 +834,10 @@ ${getEditorPanelHTML()}
821
834
  <button class="wb-tool wb-tool-sm" id="wb-toggle-logo" data-tooltip="Toggle logo">
822
835
  <img src="logo-synabun.png" alt="" style="width:18px;height:auto;opacity:0.6;">
823
836
  </button>
837
+ <div class="wb-tool-sep"></div>
838
+ <button class="wb-tool" id="wb-hide-btn" type="button" aria-pressed="false" aria-controls="wb-toolbar" aria-label="${t('toolbar.hideWhiteboardToolbar')}" data-tooltip="${t('toolbar.hideWhiteboardToolbar')}">
839
+ <svg viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M15 6l-6 6 6 6"/></svg>
840
+ </button>
824
841
  </div>
825
842
 
826
843
  <div id="wb-canvas">
@@ -0,0 +1,34 @@
1
+ // SynaBun — taking the loading overlay out of rendering once it has faded (ui-loading.js). No imports, no DOM globals:
2
+ // the element and the timer are handed in (unit-tested under node --test).
3
+ //
4
+ // `hidden` fades the overlay to opacity 0 (0.8 s). A transparent overlay still renders, and its `#loading-text` pulse
5
+ // kept the page drawing 60 frames a second forever. After the fade the overlay also gets `gone` (display: none), which
6
+ // stops every animation inside it; showing it again removes both classes in the same call.
7
+
8
+ export const FADE_MS = 800;
9
+
10
+ /** Fade `el` out, then take it out of rendering. Returns a cancel function. */
11
+ export function concealOverlay(el, { setTimer = setTimeout, clearTimer = clearTimeout, fadeMs = FADE_MS } = {}) {
12
+ if (!el) return () => {};
13
+ el.classList.add('hidden');
14
+ let timer = null;
15
+ const done = () => {
16
+ timer = null;
17
+ el.removeEventListener?.('transitionend', onEnd);
18
+ if (el.classList.contains('hidden')) el.classList.add('gone');
19
+ };
20
+ const onEnd = (event) => { if (!event || event.target === el) { if (timer) clearTimer(timer); done(); } };
21
+ el.addEventListener?.('transitionend', onEnd);
22
+ // A transition that never runs (reduced motion, a background tab, display already none) still ends here.
23
+ timer = setTimer(done, fadeMs + 100);
24
+ el._synabunConceal = () => { if (timer) clearTimer(timer); timer = null; el.removeEventListener?.('transitionend', onEnd); };
25
+ return el._synabunConceal;
26
+ }
27
+
28
+ /** Show `el` again (cancels a pending conceal). */
29
+ export function revealOverlay(el) {
30
+ if (!el) return;
31
+ el._synabunConceal?.();
32
+ el._synabunConceal = null;
33
+ el.classList.remove('gone', 'hidden');
34
+ }
@@ -517,7 +517,12 @@ export function createChildPanel({
517
517
  close.setAttribute('data-tooltip', 'Close');
518
518
  close.setAttribute('data-tooltip-pos', 'left');
519
519
  close.textContent = '×';
520
- pill.append(icon, _pillLabel, _pillBadge, close);
520
+ // The working ring (ocp-v2-styles.js .ocpv2-pill-ring): a box the compositor turns under a mask.
521
+ const ring = document.createElement('span');
522
+ ring.className = 'ocpv2-pill-ring';
523
+ ring.setAttribute('aria-hidden', 'true');
524
+ ring.appendChild(document.createElement('i'));
525
+ pill.append(ring, icon, _pillLabel, _pillBadge, close);
521
526
  // A click shows this sub-agent's panel; on the pill of the panel that is
522
527
  // on screen it minimizes it (as the main panel's pill does).
523
528
  pill.addEventListener('click', (event) => {
@@ -1,3 +1,4 @@
1
+ import { syncOpenCodeWorkerQuestions, forgetWorkerQuestions } from './ocp-v2-ws.js';
1
2
  import { workerRestart } from '../worker-restart.js';
2
3
  import { t } from '../i18n.js';
3
4
  import { hostedSidepanelId, sidepanelHost } from '../ui-sidepanel-runtime.js';
@@ -1616,7 +1617,12 @@ async function boot() {
1616
1617
  // the session on screen stays.
1617
1618
  renderPill();
1618
1619
  } else if (liveTabs.length) {
1619
- const targetSid = liveTabs[liveTabs.length - 1];
1620
+ const pendingSid = globalThis.__synabunPendingTab?.provider === 'opencode'
1621
+ ? String(globalThis.__synabunPendingTab.tabId || '')
1622
+ : '';
1623
+ const targetSid = (pendingSid && liveTabs.includes(pendingSid))
1624
+ ? pendingSid
1625
+ : liveTabs[liveTabs.length - 1];
1620
1626
  const targetInfo = _tabInfoCache.get(targetSid) || null;
1621
1627
  bootNav.apply(() => {
1622
1628
  setSession(targetSid, targetInfo);
@@ -2233,6 +2239,8 @@ function removeTab(sessionId, { byUser = false } = {}) {
2233
2239
  forgetWorkerEnd(_automationRunIds.get(sessionId));
2234
2240
  _workerEnds.delete(sessionId);
2235
2241
  _automationRunIds.delete(sessionId);
2242
+ forgetWorkerQuestions(sessionId);
2243
+ forgetWorkerQuestions(sessionId);
2236
2244
  unregisterAutomationSession(sessionId);
2237
2245
  _automationRunning.delete(sessionId);
2238
2246
  _automationTurn.delete(sessionId);
@@ -2263,6 +2271,7 @@ function createTabPill(sessionId) {
2263
2271
  pill.dataset.owner = PANEL_OWNER;
2264
2272
  pill.dataset.sessionId = sessionId;
2265
2273
  pill.innerHTML = `
2274
+ <span class="ocpv2-pill-ring" aria-hidden="true"><i></i></span>
2266
2275
  <span class="term-minimized-pill-icon">${OPENCODE_ICON}</span>
2267
2276
  <span class="term-minimized-pill-label">${escapeHtml(tabLabelFor(sessionId))}</span>
2268
2277
  <button class="term-minimized-pill-close" data-tooltip="Close" data-tooltip-pos="top">&times;</button>
@@ -2273,7 +2282,7 @@ function createTabPill(sessionId) {
2273
2282
  });
2274
2283
  pill.querySelector('.term-minimized-pill-close')?.addEventListener('click', (event) => {
2275
2284
  event.stopPropagation();
2276
- closeTabByUser(sessionId, 'pill close');
2285
+ closeTabByUser(sessionId, 'pill close', { deleteBeforeClose: true });
2277
2286
  });
2278
2287
  tray.appendChild(pill);
2279
2288
  return pill;
@@ -2283,10 +2292,16 @@ function createTabPill(sessionId) {
2283
2292
  // continued the terminal automation manually; backend cleanup is best-effort.
2284
2293
  // Asked first when prompts are still waiting in that session; declined: the
2285
2294
  // tab stays, nothing is deleted, and this resolves false.
2286
- async function closeTabByUser(sessionId, context) {
2295
+ async function closeTabByUser(sessionId, context, { deleteBeforeClose = false } = {}) {
2287
2296
  if (!(await mayCloseTab(sessionId))) return false;
2288
- const wasRunning = sessionId === getState().sessionId && !!getState().running;
2289
- closeSessionBackend(sessionId, { wasRunning, context }).catch(() => {});
2297
+ // Only the tray X waits for deletion, including a turn in a background tab.
2298
+ // Worker tabs retain their existing stop/dismiss and transcript ownership.
2299
+ const deletePillSession = deleteBeforeClose && !_automationRunIds.has(sessionId);
2300
+ const wasRunning = sessionId === getState().sessionId
2301
+ ? !!getState().running
2302
+ : deletePillSession && _sessionBusy.get(sessionId) === true;
2303
+ const backendClose = closeSessionBackend(sessionId, { wasRunning, context }).catch(() => {});
2304
+ if (deletePillSession) await backendClose;
2290
2305
  try { await handlePillClose(sessionId, { byUser: true }); }
2291
2306
  catch (err) { console.warn(`[ocp-v2-panel] local ${context} failed`, err); }
2292
2307
  return true;
@@ -2436,9 +2451,13 @@ async function handlePillClose(sessionId, { byUser = false } = {}) {
2436
2451
  }
2437
2452
 
2438
2453
  // Sub-agent child panel coordination ─────────────────────────────────────────
2439
- on('opencode-panel:show', async () => {
2454
+ on('opencode-panel:show', async (data) => {
2440
2455
  try {
2456
+ const requestedId = typeof data?.tabId === 'string' ? data.tabId : '';
2441
2457
  await showPrimaryOpencodePanel();
2458
+ if (requestedId && _tabSessionIds.includes(requestedId)) {
2459
+ await switchToSession(requestedId, _tabInfoCache.get(requestedId) || null);
2460
+ }
2442
2461
  } catch (err) {
2443
2462
  console.warn('[ocp-v2-panel] show request failed', err);
2444
2463
  }
@@ -2457,7 +2476,7 @@ on('opencode-panel:request-show', async () => {
2457
2476
  on('opencode-panel:request-new-session', () => { beginNewSession(); });
2458
2477
 
2459
2478
  // Whiteboard "Send to Panel" → attach image to compose footer if OCP v2 is the
2460
- // active sidepanel. Mirrors the gating used by Claude/Codex/OCP v1 so the event
2479
+ // active sidepanel. Mirrors the gating used by Claude/Codex/Antigravity so the event
2461
2480
  // is consumed by exactly one panel.
2462
2481
  on('wb:send-to-panel', async ({ dataUrl }) => {
2463
2482
  if (!dataUrl) return;
@@ -2527,6 +2546,7 @@ export async function attachOpenCodeAutomation(run, { focus = !!run?.focus, isCa
2527
2546
  && (_automationContinuedManually.has(sessionId) || _automationManualSendInFlight.has(sessionId));
2528
2547
  _automationRunIds.set(sessionId, run.runId);
2529
2548
  registerAutomationSession(sessionId, run.runId);
2549
+ syncOpenCodeWorkerQuestions(run);
2530
2550
  if (running || previousRunId !== run.runId) {
2531
2551
  _automationContinuedManually.delete(sessionId);
2532
2552
  _automationManualSendInFlight.delete(sessionId);
@@ -2595,6 +2615,7 @@ export async function detachOpenCodeAutomation(runId) {
2595
2615
  if (!entry) return false;
2596
2616
  const [sessionId] = entry;
2597
2617
  _automationRunIds.delete(sessionId);
2618
+ forgetWorkerQuestions(sessionId);
2598
2619
  _automationRunning.delete(sessionId);
2599
2620
  _automationTurn.delete(sessionId);
2600
2621
  _automationContinuedManually.delete(sessionId);
@@ -284,20 +284,29 @@ export async function rehydratePanelSession(store, api, {
284
284
  const left = () => { out.moved = true; return out; };
285
285
  if (!current()) return left();
286
286
 
287
- if (refreshInfo) {
287
+ if (refreshInfo && requireInfo) {
288
288
  let res;
289
289
  try { res = await api.sessionGet(sessionId); } catch (err) { res = { ok: false, error: err?.message || String(err) }; }
290
290
  if (!current()) return left();
291
291
  if (!replyFailed(res) && res.data) { store.setSession(sessionId, res.data); out.info = true; }
292
- else if (requireInfo) {
292
+ else {
293
293
  out.unavailable = true;
294
294
  out.error = (typeof res?.error === 'string' && res.error) || `Session ${String(sessionId).slice(0, 8)} is unavailable`;
295
295
  return out;
296
296
  }
297
- // Otherwise the transcript may still answer.
298
297
  }
298
+ const infoTask = (refreshInfo && !requireInfo)
299
+ ? (async () => {
300
+ let res;
301
+ try { res = await api.sessionGet(sessionId); } catch (err) { res = { ok: false, error: err?.message || String(err) }; }
302
+ if (!current()) return false;
303
+ if (!replyFailed(res) && res.data) { store.setSession(sessionId, res.data); out.info = true; }
304
+ return true;
305
+ })()
306
+ : null;
299
307
  const transcript = await hydrateTranscript(store, api, { sessionId, isCurrent: current });
300
- if (transcript.superseded) return left();
308
+ if (infoTask) await infoTask;
309
+ if (!current() || transcript.superseded) return left();
301
310
  out.transcript = transcript.applied;
302
311
  if (!transcript.applied) out.error = transcript.error;
303
312
  const s = store.getState();
@@ -10,7 +10,7 @@
10
10
  // ─────────────────────────────────────────────────────────────────────────────
11
11
 
12
12
  import { getDefaultStore } from './ocp-v2-state.js';
13
- import { api, supports, isDescendantSession, isKnownDescendantSession, onEvent } from './ocp-v2-ws.js';
13
+ import { hasWorkerQuestions, api, supports, isDescendantSession, isKnownDescendantSession, onEvent } from './ocp-v2-ws.js';
14
14
  import {
15
15
  permissionCardView, ALWAYS_ALLOW_SCOPE, replyToPermission, FOREIGN_REQUEST_MESSAGE,
16
16
  transcriptQuestionCard, answerQuestion, skipQuestion,
@@ -853,6 +853,14 @@ function synabunSummaryText(name, input) {
853
853
  const _expandedToolIds = new Set();
854
854
  const SYNABUN_CHEVRON_SVG = '<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>';
855
855
 
856
+ function spinRing() {
857
+ const ring = document.createElement('span');
858
+ ring.className = 'ocpv2-spin-ring';
859
+ ring.setAttribute('aria-hidden', 'true');
860
+ ring.appendChild(document.createElement('i'));
861
+ return ring;
862
+ }
863
+
856
864
  function renderSynaBunToolPart(part, toolName, stateStatus) {
857
865
  const callId = part.callID || part.id || part.toolCallId || part.tool_use_id || `sb-${toolName}`;
858
866
  const expanded = _expandedToolIds.has(callId);
@@ -861,6 +869,8 @@ function renderSynaBunToolPart(part, toolName, stateStatus) {
861
869
  wrap.className = 'ocpv2-part ocpv2-part-tool ocpv2-tool-synabun' + (expanded ? ' ocpv2-tool-expanded' : '');
862
870
  wrap.dataset.toolId = callId;
863
871
  wrap.dataset.status = stateStatus;
872
+ // The working ring (.ocpv2-spin-ring): a box the compositor turns while the call runs or waits.
873
+ wrap.appendChild(spinRing());
864
874
 
865
875
  const head = document.createElement('div');
866
876
  head.className = 'ocpv2-tool-head ocpv2-sb-head';
@@ -1001,6 +1011,12 @@ function renderToolPart(part, store) {
1001
1011
  done.textContent = 'Question answered.';
1002
1012
  return done;
1003
1013
  }
1014
+ if (hasWorkerQuestions(store.getState().sessionId)) {
1015
+ const stub = document.createElement('div');
1016
+ stub.className = 'ocpv2-part ocpv2-part-question-stub';
1017
+ stub.textContent = store.getState().pendingQuestions?.length ? 'Awaiting your answer…' : 'Question answered.';
1018
+ return stub;
1019
+ }
1004
1020
  // Dedup: if an SSE-driven QuestionRequest exists whose tool.callID matches
1005
1021
  // this tool part, let the pendingQuestions render handle it instead.
1006
1022
  const partCallId = part.callID || part.id;
@@ -211,6 +211,12 @@ export function mountCompose(rootEl, store = getDefaultStore(), opts = {}) {
211
211
  const wrap = document.createElement('div');
212
212
  wrap.className = 'ocpv2-input-wrap';
213
213
  _wrap = wrap;
214
+ // The focus ring (.ocpv2-spin-ring): a box the compositor turns while the composer has focus.
215
+ const ring = document.createElement('span');
216
+ ring.className = 'ocpv2-spin-ring';
217
+ ring.setAttribute('aria-hidden', 'true');
218
+ ring.appendChild(document.createElement('i'));
219
+ wrap.appendChild(ring);
214
220
 
215
221
  const inner = document.createElement('div');
216
222
  inner.className = 'ocpv2-input-inner';
@@ -45,6 +45,10 @@ const CSS = `
45
45
  opacity: 1;
46
46
  overflow: visible;
47
47
  }
48
+ /* Windows: the shell is 92% opaque, so the blur behind it barely shows, yet Chromium recomputes it on every
49
+ repaint inside the panel (a transcript rendering, a stream). There it goes; the colour stays. */
50
+ html.platform-win32 .ocpv2-panel,
51
+ html.desktop-titlebar--win32 .ocpv2-panel { backdrop-filter: none; -webkit-backdrop-filter: none; }
48
52
  /* Keep footer menus above focused floating terminal windows. */
49
53
  .ocpv2-panel:has(.ocpv2-dropdown.open) {
50
54
  z-index: 99999;
@@ -408,55 +412,56 @@ const CSS = `
408
412
  }
409
413
 
410
414
  /* ── Tray pill (minimize-to-pill) ───────────────────────────────────────── */
411
- @property --ocpv2-pill-angle {
412
- syntax: '<angle>';
413
- initial-value: 0deg;
414
- inherits: false;
415
- }
416
415
  .ocpv2-session-pill {
417
416
  position: relative;
418
417
  overflow: hidden;
419
418
  border-color: rgba(232, 224, 220, 0.12);
420
419
  transition: border-color 0.2s;
421
420
  }
422
- .ocpv2-session-pill::before {
423
- content: '';
421
+ /* A working pill's ring: a conic gradient turning inside the 1px border (the mask keeps only the
422
+ ring). The gradient is a square box that turns (rotate, run by the compositor) under the mask; an
423
+ animated custom property (the old --ocpv2-pill-angle) repainted the pill on the main thread every
424
+ frame for as long as the session worked. The square is wider than the pill's diagonal, so the
425
+ ring is the same conic gradient at every angle. */
426
+ .ocpv2-pill-ring {
424
427
  position: absolute; inset: 0;
428
+ display: none;
425
429
  border-radius: 8px;
426
430
  padding: 1px;
431
+ overflow: hidden;
427
432
  pointer-events: none;
428
- background: transparent;
429
433
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
430
434
  -webkit-mask-composite: xor;
431
435
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
432
436
  mask-composite: exclude;
433
- opacity: 0;
434
- }
435
- .ocpv2-session-pill.ocpv2-pill-running {
436
- border-color: transparent;
437
437
  }
438
- .ocpv2-session-pill.ocpv2-pill-running::before {
438
+ .ocpv2-pill-ring > i {
439
+ position: absolute; left: 50%; top: 50%;
440
+ width: calc(100% + 32px);
441
+ aspect-ratio: 1;
442
+ translate: -50% -50%;
439
443
  background: conic-gradient(
440
- from var(--ocpv2-pill-angle, 0deg),
441
444
  rgba(232,224,220,0.0) 0%,
442
445
  rgba(232,224,220,0.55) 25%,
443
446
  rgba(232,224,220,0.10) 50%,
444
447
  rgba(232,224,220,0.55) 75%,
445
448
  rgba(232,224,220,0.0) 100%
446
449
  );
447
- animation: ocpv2-pill-border-spin 2.4s linear infinite;
448
- opacity: 1;
450
+ animation: ocpv2-pill-ring-turn 2.4s linear infinite;
451
+ }
452
+ .ocpv2-session-pill.ocpv2-pill-running {
453
+ border-color: transparent;
449
454
  }
450
- @keyframes ocpv2-pill-border-spin {
451
- to { --ocpv2-pill-angle: 360deg; }
455
+ .ocpv2-session-pill.ocpv2-pill-running .ocpv2-pill-ring { display: block; }
456
+ @keyframes ocpv2-pill-ring-turn {
457
+ to { rotate: 360deg; }
452
458
  }
453
459
  .ocpv2-session-pill .term-minimized-pill-icon { color: rgba(232, 224, 220, 0.45); transition: color 0.2s; }
454
460
  .ocpv2-session-pill.ocpv2-pill-running .term-minimized-pill-icon { color: rgba(232, 224, 220, 1); }
455
461
  .ocpv2-session-pill:hover { border-color: rgba(232, 224, 220, 0.24); }
456
462
  .ocpv2-session-pill:hover .term-minimized-pill-icon { color: rgba(232, 224, 220, 0.85); }
457
- .ocpv2-session-pill:hover.ocpv2-pill-running::before {
463
+ .ocpv2-session-pill:hover .ocpv2-pill-ring > i {
458
464
  background: conic-gradient(
459
- from var(--ocpv2-pill-angle, 0deg),
460
465
  rgba(232,224,220,0.0) 0%,
461
466
  rgba(232,224,220,0.75) 25%,
462
467
  rgba(232,224,220,0.20) 50%,
@@ -464,6 +469,19 @@ const CSS = `
464
469
  rgba(232,224,220,0.0) 100%
465
470
  );
466
471
  }
472
+ html.platform-win32 .ocpv2-session-pill.ocpv2-pill-running,
473
+ html.desktop-titlebar--win32 .ocpv2-session-pill.ocpv2-pill-running {
474
+ border-color: rgba(232, 224, 220, 0.38);
475
+ }
476
+ html.platform-win32 .ocpv2-session-pill.ocpv2-pill-running:hover,
477
+ html.desktop-titlebar--win32 .ocpv2-session-pill.ocpv2-pill-running:hover {
478
+ border-color: rgba(232, 224, 220, 0.58);
479
+ }
480
+ html.platform-win32 .ocpv2-session-pill.ocpv2-pill-running .ocpv2-pill-ring,
481
+ html.desktop-titlebar--win32 .ocpv2-session-pill.ocpv2-pill-running .ocpv2-pill-ring {
482
+ display: none;
483
+ }
484
+ body.ui-interacting .ocpv2-pill-ring > i { animation-play-state: paused; }
467
485
  .ocpv2-session-pill.ocpv2-pill-running .term-minimized-pill-label::before {
468
486
  content: '';
469
487
  display: inline-block;
@@ -492,6 +510,12 @@ const CSS = `
492
510
  0%, 100% { opacity: 0.45; }
493
511
  50% { opacity: 1; }
494
512
  }
513
+ /* Reduced motion: the ring, the dot and the edge hold still (the working look stays). */
514
+ @media (prefers-reduced-motion: reduce) {
515
+ .ocpv2-pill-ring > i,
516
+ .ocpv2-session-pill.ocpv2-pill-running .term-minimized-pill-label::before,
517
+ .ocpv2-session-pill.ocpv2-pill-running::after { animation: none; }
518
+ }
495
519
 
496
520
  /* Parent pill marker: sub-agent attached → arrow appears after the label.
497
521
  Brightens + pulses when the child is actively running. Without this a
@@ -1292,12 +1316,44 @@ const CSS = `
1292
1316
  }
1293
1317
 
1294
1318
  /* ── SynaBun-branded tool cards (OpenCode cream palette) ───────────────── */
1295
- @property --ocpv2-sb-angle {
1296
- syntax: '<angle>';
1297
- initial-value: 0deg;
1298
- inherits: false;
1319
+ /* ── Spinning border ring (a SynaBun tool card at work, the composer with focus) ──
1320
+ A conic gradient turning inside the 1px edge, the mask keeping only the ring. The gradient is a
1321
+ square box that turns (rotate, run by the compositor) under the mask, and only while its owner's
1322
+ state is on; an animated custom property (the old --ocpv2-sb-angle / --ocpv2-border-angle,
1323
+ @property + a conic gradient from it) restyled and repainted the owner on the main thread 60 times
1324
+ a second. The ring is a size container and the square 142cqmax + 4px, wider than the owner's
1325
+ diagonal at any shape, so what the mask shows is the same conic gradient at every angle. Markup:
1326
+ <span class="ocpv2-spin-ring" aria-hidden="true"><i></i></span>, the owner's first child. */
1327
+ .ocpv2-spin-ring {
1328
+ position: absolute;
1329
+ inset: 0;
1330
+ padding: 1px;
1331
+ overflow: hidden;
1332
+ pointer-events: none;
1333
+ container-type: size;
1334
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1335
+ -webkit-mask-composite: xor;
1336
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1337
+ mask-composite: exclude;
1338
+ opacity: 0;
1339
+ transition: opacity 0.4s;
1340
+ }
1341
+ .ocpv2-spin-ring > i {
1342
+ position: absolute;
1343
+ left: 50%;
1344
+ top: 50%;
1345
+ width: calc(142cqmax + 4px);
1346
+ aspect-ratio: 1;
1347
+ translate: -50% -50%;
1348
+ }
1349
+ @keyframes ocpv2-spin-ring-turn {
1350
+ to { rotate: 360deg; }
1351
+ }
1352
+ body.ui-interacting .ocpv2-spin-ring > i { animation-play-state: paused !important; }
1353
+ /* Reduced motion: the ring holds still where the turn starts (the working / focus look stays). */
1354
+ @media (prefers-reduced-motion: reduce) {
1355
+ .ocpv2-spin-ring > i { animation: none !important; will-change: auto !important; }
1299
1356
  }
1300
- @keyframes ocpv2-sb-spin { to { --ocpv2-sb-angle: 360deg; } }
1301
1357
 
1302
1358
  .ocpv2-part-tool.ocpv2-tool-synabun {
1303
1359
  position: relative;
@@ -1312,33 +1368,27 @@ const CSS = `
1312
1368
  .ocpv2-part-tool.ocpv2-tool-synabun[data-status="error"] {
1313
1369
  border-left-color: rgba(220,140,140,0.5);
1314
1370
  }
1315
- .ocpv2-part-tool.ocpv2-tool-synabun::before {
1316
- content: '';
1317
- position: absolute;
1318
- inset: 0;
1371
+ .ocpv2-part-tool.ocpv2-tool-synabun > .ocpv2-spin-ring {
1319
1372
  border-radius: 12px;
1320
- padding: 1px;
1373
+ z-index: 1;
1374
+ }
1375
+ .ocpv2-part-tool.ocpv2-tool-synabun > .ocpv2-spin-ring > i {
1321
1376
  background: conic-gradient(
1322
- from var(--ocpv2-sb-angle, 0deg),
1323
1377
  rgba(232,224,220,0.0) 0%,
1324
1378
  rgba(232,224,220,0.35) 25%,
1325
1379
  rgba(232,224,220,0.06) 50%,
1326
1380
  rgba(232,224,220,0.35) 75%,
1327
1381
  rgba(232,224,220,0.0) 100%
1328
1382
  );
1329
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1330
- -webkit-mask-composite: xor;
1331
- mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1332
- mask-composite: exclude;
1333
- opacity: 0;
1334
- transition: opacity 0.4s;
1335
- pointer-events: none;
1336
- z-index: 1;
1337
1383
  }
1338
- .ocpv2-part-tool.ocpv2-tool-synabun[data-status="running"]::before,
1339
- .ocpv2-part-tool.ocpv2-tool-synabun[data-status="pending"]::before {
1384
+ .ocpv2-part-tool.ocpv2-tool-synabun[data-status="running"] > .ocpv2-spin-ring,
1385
+ .ocpv2-part-tool.ocpv2-tool-synabun[data-status="pending"] > .ocpv2-spin-ring {
1340
1386
  opacity: 1;
1341
- animation: ocpv2-sb-spin 3s linear infinite;
1387
+ }
1388
+ .ocpv2-part-tool.ocpv2-tool-synabun[data-status="running"] > .ocpv2-spin-ring > i,
1389
+ .ocpv2-part-tool.ocpv2-tool-synabun[data-status="pending"] > .ocpv2-spin-ring > i {
1390
+ animation: ocpv2-spin-ring-turn 3s linear infinite;
1391
+ will-change: rotate;
1342
1392
  }
1343
1393
 
1344
1394
  .ocpv2-tool-synabun .ocpv2-sb-head {
@@ -2088,15 +2138,7 @@ img.ocpv2-tool-screenshot {
2088
2138
  cursor: zoom-in;
2089
2139
  }
2090
2140
 
2091
- /* Animated conic-gradient border wrapper — cream highlight on focus */
2092
- @property --ocpv2-border-angle {
2093
- syntax: '<angle>';
2094
- initial-value: 0deg;
2095
- inherits: false;
2096
- }
2097
- @keyframes ocpv2-border-spin {
2098
- to { --ocpv2-border-angle: 360deg; }
2099
- }
2141
+ /* Composer wrapper: a cream ring turns inside its edge on focus (the shared .ocpv2-spin-ring) */
2100
2142
  .ocpv2-input-wrap {
2101
2143
  flex: 1;
2102
2144
  position: relative;
@@ -2107,30 +2149,20 @@ img.ocpv2-tool-screenshot {
2107
2149
  min-width: 0;
2108
2150
  overflow: hidden;
2109
2151
  }
2110
- .ocpv2-input-wrap::before {
2111
- content: '';
2112
- position: absolute; inset: 0;
2113
- border-radius: 14px;
2114
- padding: 1px;
2115
- pointer-events: none;
2152
+ .ocpv2-input-wrap > .ocpv2-spin-ring { border-radius: 14px; }
2153
+ .ocpv2-input-wrap > .ocpv2-spin-ring > i {
2116
2154
  background: conic-gradient(
2117
- from var(--ocpv2-border-angle, 0deg),
2118
2155
  rgba(232,224,220,0.0) 0%,
2119
2156
  rgba(232,224,220,0.45) 25%,
2120
2157
  rgba(232,224,220,0.10) 50%,
2121
2158
  rgba(232,224,220,0.45) 75%,
2122
2159
  rgba(232,224,220,0.0) 100%
2123
2160
  );
2124
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
2125
- -webkit-mask-composite: xor;
2126
- mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
2127
- mask-composite: exclude;
2128
- opacity: 0;
2129
- transition: opacity 0.4s;
2130
2161
  }
2131
- .ocpv2-input-wrap:focus-within::before {
2132
- opacity: 1;
2133
- animation: ocpv2-border-spin 3s linear infinite;
2162
+ .ocpv2-input-wrap:focus-within > .ocpv2-spin-ring { opacity: 1; }
2163
+ .ocpv2-input-wrap:focus-within > .ocpv2-spin-ring > i {
2164
+ animation: ocpv2-spin-ring-turn 3s linear infinite;
2165
+ will-change: rotate;
2134
2166
  }
2135
2167
  .ocpv2-input-wrap:focus-within {
2136
2168
  background: rgba(232,224,220,0.04);
@@ -3329,7 +3361,8 @@ const PARITY_CSS = `
3329
3361
  background: rgba(232,180,80,0.22);
3330
3362
  box-shadow: 0 0 20px rgba(232,180,80,0.04);
3331
3363
  }
3332
- .ocpv2-input-wrap.ocpv2-shell-mode::before { opacity: 0; animation: none; }
3364
+ .ocpv2-input-wrap.ocpv2-shell-mode > .ocpv2-spin-ring { opacity: 0; }
3365
+ .ocpv2-input-wrap.ocpv2-shell-mode > .ocpv2-spin-ring > i { animation: none; will-change: auto; }
3333
3366
  .ocpv2-input-wrap.ocpv2-shell-mode .ocpv2-input-inner::before {
3334
3367
  content: '!';
3335
3368
  align-self: center;