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
@@ -20,7 +20,7 @@ import { createTunnelCard, drawInto, mcpKeyNeededText, readTunnel } from './ui-t
20
20
  import { remoteMcpAddress } from './tunnel-view.js';
21
21
  import { recheckCliStatus, getCliStatus, addCliToPath } from './cli-status.js';
22
22
  import { cliInstallText, setCliInstallTranslator } from './cli-install-view.js';
23
- import { dropdownHTML, wireDropdowns } from './cc-dropdown.js';
23
+ import { dropdownHTML, wireDropdowns, setDropdownItems, setDropdownValue } from './cc-dropdown.js';
24
24
  setCliInstallTranslator((key, params) => kit.tx(`cliInstall.${key}`, params));
25
25
  import { setGitBashTranslator } from './git-bash-view.js';
26
26
  import { gitBashRowHtml, wireGitBashRow } from './ui-git-bash.js';
@@ -98,7 +98,8 @@ const TAB_ICONS = {
98
98
  const COPY_ICON = '<svg viewBox="0 0 24 24"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
99
99
  const CHEVRON_ICON = '<svg class="cc-section-chevron" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>';
100
100
  const ANTHROPIC_ICON = '<svg viewBox="0 0 24 24" class="cc-provider-icon"><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" fill="currentColor"/></svg>';
101
- const GEMINI_ICON = '<svg viewBox="0 0 24 24" class="cc-provider-icon"><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" fill="currentColor"/></svg>';
101
+ // A line drawing: its paths carry fill="none" themselves, because `.cli-path-icon svg` fills every icon it holds.
102
+ const ANTIGRAVITY_ICON = '<svg viewBox="0 0 24 24" class="cc-provider-icon" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 20 12 4l7.5 16" fill="none"/><path d="M8.2 20a3.8 3.8 0 0 1 7.6 0" fill="none"/></svg>';
102
103
  const OPENAI_ICON = '<svg viewBox="0 0 24 24" class="cc-provider-icon"><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" fill="currentColor"/></svg>';
103
104
  const OPENCODE_ICON = '<svg viewBox="0 0 24 30" class="cc-provider-icon" fill="currentColor"><path d="M18 6H6V24H18V6ZM24 30H0V0H24V30Z"/></svg>';
104
105
  const BROWSER_ICON = '<svg viewBox="0 0 24 24" class="cc-provider-icon"><circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="1.5"/><ellipse cx="12" cy="12" rx="4" ry="10" fill="none" stroke="currentColor" stroke-width="1.5"/><line x1="2" y1="12" x2="22" y2="12" stroke="currentColor" stroke-width="1.5"/><path d="M4.5 7h15M4.5 17h15" fill="none" stroke="currentColor" stroke-width="1"/></svg>';
@@ -531,21 +532,29 @@ function buildNavHTML(activeId) {
531
532
  return html;
532
533
  }
533
534
 
534
- /** The nav rail's stand-in on a narrow panel: one labelled select that lists every page. */
535
+ /** The nav rail's stand-in on a narrow panel: one labelled dropdown that lists every page. */
535
536
  function buildPagePickerHTML(activeId) {
536
537
  const groups = SETTINGS_GROUPS.map(group => {
537
538
  const options = SETTINGS_PAGES.filter(p => p.group === group.id).map(page => {
538
539
  const keys = pageKeys(page);
539
- return `<option value="${page.id}"${page.id === activeId ? ' selected' : ''}>${kit.te(keys.navLabel)} — ${kit.te(keys.navHelp)}</option>`;
540
- }).join('');
541
- return options ? `<optgroup label="${kit.te(group.labelKey)}">${options}</optgroup>` : '';
542
- }).join('');
540
+ return { value: page.id, label: `${kit.tx(keys.navLabel)} — ${kit.tx(keys.navHelp)}`, selected: page.id === activeId };
541
+ });
542
+ return options.length ? { group: kit.tx(group.labelKey), options } : null;
543
+ }).filter(Boolean);
544
+ // dropdownHTML escapes the labels itself.
543
545
  return `<div class="stg-page-picker">
544
- <label for="stg-page-select">${kit.te('settings.redesign.common.allPages')}</label>
545
- <select id="stg-page-select">${groups}</select>
546
+ <label id="stg-page-select-label" for="stg-page-select-trigger">${kit.te('settings.redesign.common.allPages')}</label>
547
+ ${dropdownHTML('stg-page-select', groups, { classes: 'stg-page-dropdown', labelledBy: 'stg-page-select-label' })}
546
548
  </div>`;
547
549
  }
548
550
 
551
+ /** A settings field whose control is a styled dropdown: the id stays on its hidden input, the label and help point at its button. */
552
+ function dropdownField(invId, id, entries, { classes = '' } = {}) {
553
+ const control = dropdownHTML(id, entries, { classes, labelledBy: `${id}-label` })
554
+ .replace('role="combobox"', `role="combobox" aria-describedby="${id}-help"`);
555
+ return kit.field(invId, control, { forId: id }).replace(`<label for="${id}">`, `<label id="${id}-label" for="${id}-trigger">`);
556
+ }
557
+
549
558
  /** The search field above the page list, and the results list that takes the list's place while it holds a query. */
550
559
  function buildSearchHTML() {
551
560
  return `<div class="stg-search" role="search">
@@ -815,9 +824,9 @@ function buildBrowserTab() {
815
824
  ${kit.field('BRW011', dd('BRW011', 'bc-connectMode', 'connect', ['mirror', 'attach', 'morelogin']))}
816
825
  ${kit.field('BRW012', dd('BRW012', 'bc-attachSeed', 'seed', ['real', 'fresh']), { attrs: 'id="bc-attachSeed-row" style="display:none"' })}
817
826
  <div class="stg-field bc-card-row" id="bc-morelogin-row" ${kit.inv('BRW013')} style="display:none">
818
- <label for="bc-morelogin-env-id">${kit.L('BRW013')}</label>
827
+ <label id="bc-morelogin-env-id-label" for="bc-morelogin-env-id-trigger">${kit.L('BRW013')}</label>
819
828
  <div class="browser-cfg-input-row">
820
- <select class="browser-cfg-input" id="bc-morelogin-env-id" style="flex:1" aria-describedby="bc-morelogin-env-id-help"></select>
829
+ ${dropdownHTML('bc-morelogin-env-id', [{ value: '', label: kit.tx('settings.redesign.browser.loadingProfiles') }], { classes: 'bc-ml-dropdown', labelledBy: 'bc-morelogin-env-id-label', attrs: 'style="flex:1;min-width:0"' }).replace('role="combobox"', 'role="combobox" aria-describedby="bc-morelogin-env-id-help"')}
821
830
  <button type="button" class="cli-detect-btn" id="bc-morelogin-refresh" ${kit.inv('BRW014')} title="${kit.H('BRW014')}">${REFRESH}${kit.L('BRW014')}</button>
822
831
  </div>
823
832
  <div class="stg-help" id="bc-morelogin-env-id-help">${kit.H('BRW013')}</div>
@@ -965,7 +974,7 @@ function buildSetupTab(setupStatus) {
965
974
  // primary,remove,view,copy,text}, and the header badge (#setup-<id> .gfx-group-title .setup-status-badge).
966
975
  const providers = [
967
976
  { id: 'claude', name: 'Claude', icon: ANTHROPIC_ICON, file: '~/.claude.json', ids: { toggle: 'SET004', cli: 'SET005', primary: 'SET006', remove: 'SET007', view: 'SET008', copy: 'SET009' } },
968
- { id: 'gemini', name: 'Gemini', icon: GEMINI_ICON, file: '~/.gemini/settings.json', ids: { toggle: 'SET010', config: 'SET011', primary: 'SET012', remove: 'SET013', view: 'SET014', copy: 'SET015' } },
977
+ { id: 'antigravity', name: 'Antigravity', icon: ANTIGRAVITY_ICON, file: '~/.gemini/config/mcp_config.json', ids: { toggle: 'SET010', config: 'SET011', primary: 'SET012', remove: 'SET013', view: 'SET014', copy: 'SET015' } },
969
978
  { id: 'codex', name: 'Codex', icon: OPENAI_ICON, file: '~/.codex/config.toml', ids: { toggle: 'SET016', cli: 'SET017', config: 'SET018', primary: 'SET019', remove: 'SET020', view: 'SET021', copy: 'SET022' } },
970
979
  { id: 'opencode', name: 'OpenCode', icon: OPENCODE_ICON, file: '~/.config/opencode/opencode.json', ids: { toggle: 'SET023', config: 'SET024', primary: 'SET025', remove: 'SET026', view: 'SET027', copy: 'SET028' } },
971
980
  ].map((p) => ({ ...p, on: setupStatus[p.id]?.connected || false }));
@@ -1105,7 +1114,7 @@ function buildTerminalTab(cliConfig) {
1105
1114
  const cliProfiles = [
1106
1115
  { id: 'claude-code', name: 'Claude Code', icon: ANTHROPIC_ICON, color: '#D4A27F', default: 'claude', inv: 'CLI001' },
1107
1116
  { id: 'codex', name: 'Codex', icon: OPENAI_ICON, color: '#74c7a5', default: 'codex', inv: 'CLI003' },
1108
- { id: 'gemini', name: 'Gemini', icon: GEMINI_ICON, color: '#669DF6', default: 'gemini', inv: 'CLI004' },
1117
+ { id: 'antigravity', name: 'Antigravity', icon: ANTIGRAVITY_ICON, color: '#669DF6', default: 'agy', inv: 'CLI004' },
1109
1118
  { id: 'opencode', name: 'OpenCode', icon: OPENCODE_ICON, color: '#E8E0DC', default: 'opencode', inv: 'CLI005' },
1110
1119
  ];
1111
1120
 
@@ -1128,7 +1137,7 @@ function buildTerminalTab(cliConfig) {
1128
1137
  <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
1129
1138
  ${kit.L('CLI002')}
1130
1139
  </button>
1131
- ${p.id === 'gemini' ? '' : `<button type="button" class="cli-detect-btn" data-cli-add-path="${p.id}" hidden>${escapeHtml(cliInstallText('addPath'))}</button>`}
1140
+ <button type="button" class="cli-detect-btn" data-cli-add-path="${p.id}" hidden>${escapeHtml(cliInstallText('addPath'))}</button>
1132
1141
  <span class="cli-path-status${isDefault ? '' : ' custom'}" id="cli-status-${p.id}" ${kit.inv('CLI007')}>${kit.te(isDefault ? 'settings.redesign.terminal.cliStatus.default' : 'settings.redesign.terminal.cliStatus.custom')}</span>
1133
1142
  </div>
1134
1143
  <div class="stg-help" id="cli-path-${p.id}-help">${kit.H(p.inv)}</div>
@@ -1141,7 +1150,7 @@ function buildTerminalTab(cliConfig) {
1141
1150
  { code: 'C:\\Users\\me\\.npm\\claude', key: 'exWindows' },
1142
1151
  { code: '/opt/homebrew/bin/claude', key: 'exUnix' },
1143
1152
  { code: 'wsl claude', key: 'exWsl' },
1144
- { code: 'wsl -d Ubuntu gemini', key: 'exWslDistro' },
1153
+ { code: 'wsl -d Ubuntu claude', key: 'exWslDistro' },
1145
1154
  ];
1146
1155
 
1147
1156
  return `
@@ -1251,12 +1260,7 @@ function buildMcpTab() {
1251
1260
  </div>
1252
1261
  <div class="stg-mcp-form-grid" style="margin-top:10px">
1253
1262
  ${kit.field('MCP012', input('stg-mcp-srv-name', { ph: m('ph.name') }), { forId: 'stg-mcp-srv-name' })}
1254
- ${kit.field('MCP013', `
1255
- <select class="stg-input stg-input-sm" id="stg-mcp-srv-type" aria-describedby="stg-mcp-srv-type-help">
1256
- <option value="stdio">${m('type.stdio')}</option>
1257
- <option value="sse">${m('type.sse')}</option>
1258
- <option value="http">${m('type.http')}</option>
1259
- </select>`, { forId: 'stg-mcp-srv-type' })}
1263
+ ${dropdownField('MCP013', 'stg-mcp-srv-type', ['stdio', 'sse', 'http'].map(t => ({ value: t, label: kit.tx(`settings.redesign.mcp.type.${t}`), selected: t === 'stdio' })))}
1260
1264
  ${kit.field('MCP014', input('stg-mcp-srv-cmd', { ph: 'node' }), { forId: 'stg-mcp-srv-cmd', className: 'stg-mcp-field-wide stg-mcp-field-stdio', attrs: 'data-stg-shown-by="#stg-mcp-srv-type"' })}
1261
1265
  ${kit.field('MCP015', `
1262
1266
  <div class="stg-mcp-arg-chips" id="stg-mcp-arg-chips" ${kit.inv('MCP027')}>
@@ -1282,7 +1286,7 @@ function buildMcpTab() {
1282
1286
  ${platform('claudeCode', true)}
1283
1287
  ${platform('opencode', true)}
1284
1288
  ${platform('codex', true)}
1285
- ${platform('gemini', false)}
1289
+ ${platform('antigravity', false)}
1286
1290
  </div>
1287
1291
  <div class="stg-action-row stg-mcp-form-actions" style="margin-top:10px">
1288
1292
  <button type="button" class="stg-action-btn compact" id="stg-mcp-srv-save" ${kit.inv('MCP020')} title="${kit.H('MCP020')}">${kit.L('MCP020')}</button>
@@ -1613,11 +1617,10 @@ function buildYoutubeTab(yt) {
1613
1617
  ${key('YT008', 'STEAM_API_KEY', 'xxxx', 'password')}
1614
1618
 
1615
1619
  ${kit.subhead(y('pipelineTitle'))}
1616
- ${kit.field('YT009', `
1617
- <select id="yt-upload-transport" class="stg-input" aria-describedby="yt-upload-transport-help">
1618
- <option value="browser"${p.uploadTransport !== 'api' ? ' selected' : ''}>${y('transport.browser')}</option>
1619
- <option value="api"${p.uploadTransport === 'api' ? ' selected' : ''}>${y('transport.api')}</option>
1620
- </select>`, { forId: 'yt-upload-transport' })}
1620
+ ${dropdownField('YT009', 'yt-upload-transport', [
1621
+ { value: 'browser', label: kit.tx('settings.redesign.youtube.transport.browser'), selected: p.uploadTransport !== 'api' },
1622
+ { value: 'api', label: kit.tx('settings.redesign.youtube.transport.api'), selected: p.uploadTransport === 'api' },
1623
+ ])}
1621
1624
  ${kit.field('YT010', `
1622
1625
  <div class="settings-key-row">
1623
1626
  <input id="yt-quality" type="text" value="${esc(dl.quality || 'bestvideo[height<=1080]+bestaudio/best[height<=1080]')}" autocomplete="off" spellcheck="false" aria-describedby="yt-quality-help">
@@ -1671,13 +1674,17 @@ function buildSocialTab(toolCategories, toolPermissions) {
1671
1674
 
1672
1675
  function buildSkillsTab(ccSkills) {
1673
1676
  const skills = ccSkills || [];
1677
+ // Antigravity reads ~/.gemini/config/skills: its chip shows once the server lists that target for the skills (an
1678
+ // older server installs to Claude Code, Codex and OpenCode only, and would refuse the chip's request).
1679
+ const antigravity = skills.some(s => s?.targetStates?.antigravity || (s?.installedTargets && Object.hasOwn(s.installedTargets, 'antigravity')));
1674
1680
  const targets = [
1675
1681
  { id: 'claude', label: kit.te('settings.redesign.product.claude') },
1676
1682
  { id: 'codex', label: kit.te('settings.redesign.product.codex') },
1677
1683
  { id: 'opencode', label: kit.te('settings.redesign.product.opencode') },
1684
+ ...(antigravity ? [{ id: 'antigravity', label: kit.te('settings.redesign.product.antigravity') }] : []),
1678
1685
  ];
1679
1686
  const row = (skill) => {
1680
- const installed = skill.installedTargets || { claude: !!skill.installed, codex: false, opencode: false };
1687
+ const installed = skill.installedTargets || { claude: !!skill.installed, codex: false, opencode: false, antigravity: false };
1681
1688
  const anyOn = targets.some(t => installed[t.id]);
1682
1689
  // What each runtime has of it: a native skill folder, an old bridge not moved yet, or a folder of that name
1683
1690
  // SynaBun did not install (settings/settings-skill-folders.js chipState).
@@ -2008,10 +2015,8 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
2008
2015
  { label: 'Claude Web', on: !!compat.web, note: compat.webNote },
2009
2016
  { label: 'Claude Cowork', on: !!compat.cowork },
2010
2017
  ];
2011
- const geminiItems = [
2012
- { label: 'Gemini CLI', on: false },
2013
- { label: 'Gemini Code Assist', on: false },
2014
- { label: 'Gemini Web', on: false },
2018
+ const antigravityItems = [
2019
+ { label: 'Antigravity CLI', on: false },
2015
2020
  ];
2016
2021
  const openaiItems = [
2017
2022
  { label: 'Codex CLI', on: compat.codex !== false },
@@ -2040,7 +2045,7 @@ function buildConnectionsTab(ccIntegrations, ccSkills, tunnelStatus, mcpKeyInfo,
2040
2045
  };
2041
2046
  return `<div class="cc-provider-badges" data-stg-nostatus onclick="event.stopPropagation()" ${kit.inv('AUT046')}>
2042
2047
  ${badge('anthropic', ANTHROPIC_ICON, 'compat.claude', anthropicItems, false)}
2043
- ${badge('google', GEMINI_ICON, 'compat.gemini', geminiItems, true)}
2048
+ ${badge('google', ANTIGRAVITY_ICON, 'compat.antigravity', antigravityItems, true)}
2044
2049
  ${badge('openai', OPENAI_ICON, 'compat.openai', openaiItems, true)}
2045
2050
  </div>`;
2046
2051
  };
@@ -2494,6 +2499,7 @@ function buildMoreLoginTab() {
2494
2499
  <span class="settings-status-dot disconnected" id="ml-status-dot"></span>
2495
2500
  <span id="ml-status-line">${m('checking')}</span>
2496
2501
  </div>
2502
+ <div class="stg-help" id="ml-path-hint" hidden style="margin:8px 0 0">${m('customPathHint')}</div>
2497
2503
  <div class="stg-help" style="margin:8px 0 12px">${kit.th('settings.redesign.morelogin.intro', {
2498
2504
  link: '<a href="https://www.morelogin.com" target="_blank" rel="noopener">morelogin.com</a>',
2499
2505
  path: `<strong>${m('apiPath')}</strong>`,
@@ -2570,7 +2576,10 @@ function wireMoreLoginTab(overlay) {
2570
2576
  const dot = $('ml-status-dot'), line = $('ml-status-line'), conn = $('ml-conn-status');
2571
2577
  if (!s.installed) { dot.className = 'settings-status-dot disconnected'; line.textContent = kit.tx('settings.redesign.morelogin.moreloginNotInstalled'); if (conn) conn.textContent = kit.tx('settings.redesign.morelogin.notInstalled'); }
2572
2578
  else if (!s.running) { dot.className = 'settings-status-dot disconnected'; line.textContent = kit.tx('settings.redesign.morelogin.installedApiNotRunningPort', { port: s.port }); if (conn) conn.textContent = kit.tx('settings.redesign.morelogin.appClosed'); }
2579
+ else if (s.apiError) { dot.className = 'settings-status-dot disconnected'; line.textContent = kit.tx('settings.redesign.morelogin.runningApiRejected', { port: s.port, reason: String(s.apiError) }); if (conn) conn.textContent = kit.tx('settings.redesign.morelogin.apiError'); }
2573
2580
  else { dot.className = 'settings-status-dot connected'; line.textContent = kit.tx('settings.redesign.morelogin.connectedProfileSPort', { profileCount: s.profileCount, port: s.port }); if (conn) conn.textContent = kit.tx('settings.redesign.morelogin.connected'); }
2581
+ const hint = $('ml-path-hint');
2582
+ if (hint) hint.hidden = !!(s.installed && s.running);
2574
2583
  _defaultEnvId = s.defaultEnvId || null;
2575
2584
  const ds = $('ml-default-status');
2576
2585
  if (ds) ds.textContent = (s.isDefault && s.defaultEnvId) ? kit.tx('settings.redesign.morelogin.defaultAiBrowserSet') : kit.tx('settings.redesign.morelogin.noDefaultSet');
@@ -2616,6 +2625,11 @@ function wireMoreLoginTab(overlay) {
2616
2625
  if ($('ml-api-id') && !$('ml-api-id').value) $('ml-api-id').value = cfg.config.apiId || '';
2617
2626
  }
2618
2627
  const p = await jget('/api/morelogin/profiles');
2628
+ if (p.ok === false && p.error) {
2629
+ const list = $('ml-profile-list');
2630
+ if (list) list.innerHTML = '<div class="settings-hint" role="status">' + escapeHtml(String(p.error)) + '</div>';
2631
+ return;
2632
+ }
2619
2633
  renderProfiles(p.envs || []);
2620
2634
  }
2621
2635
 
@@ -3063,7 +3077,7 @@ function activateSettingsTab(overlay, tabId = DEFAULT_SETTINGS_PAGE, { remember
3063
3077
  nav.setAttribute('aria-current', 'page');
3064
3078
  body.classList.add('active');
3065
3079
  const picker = overlay.querySelector('#stg-page-select');
3066
- if (picker) picker.value = pageId;
3080
+ if (picker) setDropdownValue(picker, pageId);
3067
3081
  if (changed) {
3068
3082
  const content = overlay.querySelector('.settings-content');
3069
3083
  if (content) content.scrollTop = 0;
@@ -3346,7 +3360,7 @@ async function openSettingsModalNow(options = {}) {
3346
3360
  let _bridgeResult = null;
3347
3361
  // The greeting (lib/greeting/): what its endpoint answered, as a reading (no answer is a reading too).
3348
3362
  let greetingReading = readGreetingStatus({ status: 0 });
3349
- let setupStatus = { claude: {}, gemini: {}, codex: {}, opencode: {}, paths: {} };
3363
+ let setupStatus = { claude: {}, antigravity: {}, codex: {}, opencode: {}, paths: {} };
3350
3364
  let cliConfig = {};
3351
3365
  let toolPermissions = {};
3352
3366
  let toolCategories = [];
@@ -3497,7 +3511,7 @@ async function openSettingsModalNow(options = {}) {
3497
3511
 
3498
3512
  // ── Nav status dots (Judgments and WhatsApp update theirs as they wire) ──
3499
3513
  kit.setNavStatus(overlay, 'server', settings.storage === 'sqlite' ? 'connected' : 'disconnected');
3500
- kit.setNavStatus(overlay, 'setup', (setupStatus.claude?.connected || setupStatus.gemini?.connected || setupStatus.codex?.connected || setupStatus.opencode?.connected) ? 'connected' : 'disconnected');
3514
+ kit.setNavStatus(overlay, 'setup', (setupStatus.claude?.connected || setupStatus.antigravity?.connected || setupStatus.codex?.connected || setupStatus.opencode?.connected) ? 'connected' : 'disconnected');
3501
3515
  kit.setNavStatus(overlay, 'discord', discordConfig.botToken ? 'connected' : 'disconnected');
3502
3516
  kit.setNavStatus(overlay, 'judgments', (typesafeConfig && typesafeConfig.enabled) ? 'connected' : 'disconnected');
3503
3517
 
@@ -4714,7 +4728,7 @@ async function openSettingsModalNow(options = {}) {
4714
4728
  // Must stay in sync with CLI_DEFAULTS in server.js and the cliProfiles
4715
4729
  // list that renders the inputs — opencode was previously missing here, so
4716
4730
  // its input rendered but its value was never sent to the server.
4717
- const cliDefaults = { 'claude-code': 'claude', 'codex': 'codex', 'gemini': 'gemini', 'opencode': 'opencode' };
4731
+ const cliDefaults = { 'claude-code': 'claude', 'codex': 'codex', 'antigravity': 'agy', 'opencode': 'opencode' };
4718
4732
  const cliProfileIds = Object.keys(cliDefaults);
4719
4733
 
4720
4734
  const pathButtons = overlay.querySelectorAll('[data-cli-add-path]');
@@ -5407,8 +5421,8 @@ async function openSettingsModalNow(options = {}) {
5407
5421
  emit('skills:open', { place: 'library' });
5408
5422
  });
5409
5423
 
5410
- // Skill target chips — one skill can be installed independently into Claude / Codex / OpenCode
5411
- const runtimeLabels = { claude: 'Claude Code', codex: 'Codex CLI', opencode: 'OpenCode CLI' };
5424
+ // Skill target chips — one skill can be installed independently into Claude / Codex / OpenCode / Antigravity
5425
+ const runtimeLabels = { claude: 'Claude Code', codex: 'Codex CLI', opencode: 'OpenCode CLI', antigravity: 'Antigravity CLI' };
5412
5426
  overlay.querySelectorAll('.cc-skill-target[data-cc-skill]').forEach(chip => {
5413
5427
  chip.addEventListener('click', async () => {
5414
5428
  const skillName = chip.dataset.ccSkill;
@@ -5635,7 +5649,7 @@ async function openSettingsModalNow(options = {}) {
5635
5649
  const message = overlay.querySelector('#setup-rules-message');
5636
5650
  const legacyBox = overlay.querySelector('#setup-rules-legacy');
5637
5651
  const versionBadge = overlay.querySelector('#setup-rules-version');
5638
- const hostOf = { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', gemini: 'Gemini' };
5652
+ const hostOf = { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', antigravity: 'Antigravity' };
5639
5653
 
5640
5654
  if (autoToggle && installAllBtn && legacyBox) {
5641
5655
  rulesRenderers.push(() => {
@@ -5708,26 +5722,26 @@ async function openSettingsModalNow(options = {}) {
5708
5722
  : { command: 'node', args: [paths.mcpIndexPath || '<path-to>/mcp-server/run.mjs'] };
5709
5723
  };
5710
5724
 
5711
- // ── Gemini ──
5712
- wireSetupMcpToggle('gemini', '/api/setup/gemini/mcp', '~/.gemini/settings.json');
5713
- // Config preview
5725
+ // ── Antigravity ──
5726
+ wireSetupMcpToggle('antigravity', '/api/setup/antigravity/mcp', '~/.gemini/config/mcp_config.json');
5727
+ // Config preview (mcp_config.json: `disabled`, no `trust`)
5714
5728
  {
5715
- const preview = overlay.querySelector('#setup-gemini-config-preview');
5729
+ const preview = overlay.querySelector('#setup-antigravity-config-preview');
5716
5730
  let cachedConfig = '';
5717
5731
  if (preview) {
5718
- fetch('/api/setup/gemini/mcp').then(r => r.json()).then(data => {
5732
+ fetch('/api/setup/antigravity/mcp').then(r => r.json()).then(data => {
5719
5733
  if (data.ok && data.config) {
5720
5734
  cachedConfig = JSON.stringify(data.config, null, 2);
5721
5735
  preview.textContent = cachedConfig;
5722
5736
  } else if (data.ok) {
5723
- cachedConfig = JSON.stringify({ mcpServers: { SynaBun: { ...mcpLaunch(), env: { DOTENV_PATH: setupStatus.paths?.envPath || '<path-to>/synabun/.env' } } } }, null, 2);
5737
+ cachedConfig = JSON.stringify({ mcpServers: { SynaBun: { ...mcpLaunch(), env: { DOTENV_PATH: setupStatus.paths?.envPath || '<path-to>/synabun/.env' }, disabled: false } } }, null, 2);
5724
5738
  preview.textContent = cachedConfig;
5725
5739
  } else { preview.textContent = kit.tx('settings.redesign.setup.couldNotLoadConfig'); }
5726
5740
  }).catch(() => { preview.textContent = kit.tx('settings.redesign.setup.failedToLoad'); });
5727
5741
  }
5728
- wireCopyBtn('setup-gemini-config-copy', () => cachedConfig, kit.tx('settings.redesign.setup.copyJsonConfig'));
5742
+ wireCopyBtn('setup-antigravity-config-copy', () => cachedConfig, kit.tx('settings.redesign.setup.copyJsonConfig'));
5729
5743
  }
5730
- wireRulesControls('gemini', 'gemini');
5744
+ wireRulesControls('antigravity', 'antigravity');
5731
5745
 
5732
5746
  // ── Codex ──
5733
5747
  wireSetupMcpToggle('codex', '/api/setup/codex/mcp', '~/.codex/config.toml');
@@ -6048,16 +6062,18 @@ async function openSettingsModalNow(options = {}) {
6048
6062
  let _moreloginDesiredEnvId = '';
6049
6063
  async function loadMoreLoginEnvs() {
6050
6064
  const sel = overlay.querySelector('#bc-morelogin-env-id');
6065
+ // A placeholder choice (loading / error / not running) keeps its reason visible in the closed dropdown.
6066
+ const only = (key) => setDropdownItems(sel, [{ value: '', label: kit.tx(key), selected: true }]);
6051
6067
  const statusEl = overlay.querySelector('#bc-morelogin-status-text');
6052
6068
  if (!sel) return;
6053
6069
  try {
6054
6070
  const r = await fetch('/api/browser/morelogin-envs');
6055
6071
  const d = await r.json();
6056
- if (!d || d.ok === false) { sel.innerHTML = '<option value="">' + kit.te('settings.redesign.browser.error') + '</option>'; if (statusEl) statusEl.textContent = (d && d.error) || kit.tx('settings.redesign.browser.failedToLoadMoreloginProfiles'); return; }
6057
- if (!d.installed) { sel.innerHTML = '<option value="">' + kit.te('settings.redesign.browser.moreloginNotInstalled') + '</option>'; if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.moreloginDesktopAppIsNotInstalled'); return; }
6058
- if (!d.running) { sel.innerHTML = '<option value="">' + kit.te('settings.redesign.browser.startMorelogin') + '</option>'; if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.moreloginNotRunningOpenTheApp', { port: d.port }); return; }
6072
+ if (!d || d.ok === false) { only('settings.redesign.browser.error'); if (statusEl) statusEl.textContent = (d && d.error) || kit.tx('settings.redesign.browser.failedToLoadMoreloginProfiles'); return; }
6073
+ if (!d.installed) { only('settings.redesign.browser.moreloginNotInstalled'); if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.moreloginDesktopAppIsNotInstalled') + ' ' + kit.tx('settings.redesign.browser.moreloginCustomPathHint'); return; }
6074
+ if (!d.running) { only('settings.redesign.browser.startMorelogin'); if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.moreloginNotRunningOpenTheApp', { port: d.port }) + (d.error ? ' ' + String(d.error) : ''); return; }
6059
6075
  const envs = d.envs || [];
6060
- if (!envs.length) { sel.innerHTML = '<option value="">' + kit.te('settings.redesign.browser.noProfiles') + '</option>'; if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.noMoreloginProfilesYetOneIs'); return; }
6076
+ if (!envs.length) { only('settings.redesign.browser.noProfiles'); if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.noMoreloginProfilesYetOneIs'); return; }
6061
6077
  const want = _moreloginDesiredEnvId || sel.value || '';
6062
6078
  // Show each env's proxy — without it there is no way to tell from SynaBun
6063
6079
  // whether a profile's traffic leaves the machine.
@@ -6066,8 +6082,9 @@ async function openSettingsModalNow(options = {}) {
6066
6082
  const where = [p.host, p.port].filter(Boolean).join(':');
6067
6083
  return ` · ${[p.type, where, p.country].filter(Boolean).join(' ')}`;
6068
6084
  };
6069
- sel.innerHTML = envs.map(e => `<option value="${escapeHtml(String(e.id))}">${escapeHtml(e.name)}${e.status ? ` (${escapeHtml(String(e.status))})` : ''}${escapeHtml(proxyLabel(e.proxy))}</option>`).join('');
6070
- if (want && envs.some(e => String(e.id) === String(want))) sel.value = String(want);
6085
+ // dropdownHTML escapes the labels itself.
6086
+ setDropdownItems(sel, envs.map(e => ({ value: String(e.id), label: `${e.name ?? ''}${e.status ? ` (${String(e.status)})` : ''}${proxyLabel(e.proxy)}` })));
6087
+ if (want && envs.some(e => String(e.id) === String(want))) setDropdownValue(sel, String(want));
6071
6088
  if (statusEl) {
6072
6089
  let msg = kit.tx('settings.redesign.browser.profileSApiPort', { count: envs.length, port: d.port });
6073
6090
  // MoreLogin silently redirects a navigation it refuses to its stop page: a
@@ -6082,7 +6099,7 @@ async function openSettingsModalNow(options = {}) {
6082
6099
  statusEl.textContent = msg;
6083
6100
  }
6084
6101
  } catch {
6085
- sel.innerHTML = '<option value="">' + kit.te('settings.redesign.browser.error') + '</option>';
6102
+ only('settings.redesign.browser.error');
6086
6103
  if (statusEl) statusEl.textContent = kit.tx('settings.redesign.browser.failedToReachMorelogin');
6087
6104
  }
6088
6105
  }
@@ -6130,6 +6147,7 @@ async function openSettingsModalNow(options = {}) {
6130
6147
  item.addEventListener('click', refreshAttachSeedRow);
6131
6148
  });
6132
6149
  }
6150
+ { const mlRow = overlay.querySelector('#bc-morelogin-row'); if (mlRow) wireDropdowns(mlRow, { signal: panelLife.signal }); }
6133
6151
  overlay.querySelector('#bc-morelogin-refresh')?.addEventListener('click', (e) => { e.preventDefault(); loadMoreLoginEnvs(); });
6134
6152
  const attachSeedDd = overlay.querySelector('.bc-dropdown[data-for="bc-attachSeed"]');
6135
6153
  if (attachSeedDd) {
@@ -7270,7 +7288,7 @@ async function openSettingsModalNow(options = {}) {
7270
7288
 
7271
7289
  // Explore project
7272
7290
  function openExploreModal(projectPath, projectLabel) {
7273
- const EXPLORE_CLI_IDS = ['claude-code', 'codex', 'gemini'];
7291
+ const EXPLORE_CLI_IDS = ['claude-code', 'codex', 'antigravity'];
7274
7292
  const CLI_OPTIONS = CLI_PROFILES
7275
7293
  .filter(p => EXPLORE_CLI_IDS.includes(p.id))
7276
7294
  .map(p => ({ id: p.id, label: p.label }));
@@ -7350,7 +7368,7 @@ async function openSettingsModalNow(options = {}) {
7350
7368
  selectedCli = cli;
7351
7369
  selectedModel = getExploreModels(cli)[0]?.id || '';
7352
7370
  renderModal();
7353
- if (cli === 'codex') {
7371
+ if (cli === 'codex' || cli === 'antigravity') {
7354
7372
  ensureModelsForProfile(cli).then(() => {
7355
7373
  if (exploreOverlay.isConnected && selectedCli === cli) renderModal();
7356
7374
  });
@@ -8701,7 +8719,7 @@ async function openSettingsModalNow(options = {}) {
8701
8719
  claudeCode: { label: 'CC', title: 'Claude Code (~/.claude.json)' },
8702
8720
  opencode: { label: 'OC', title: 'OpenCode' },
8703
8721
  codex: { label: 'CX', title: 'Codex (~/.codex/config.toml)' },
8704
- gemini: { label: 'GE', title: 'Gemini (~/.gemini/settings.json)' },
8722
+ antigravity: { label: 'AG', title: 'Antigravity (~/.gemini/config/mcp_config.json)' },
8705
8723
  };
8706
8724
 
8707
8725
  async function renderInstalledAll() {
@@ -8972,13 +8990,18 @@ async function openSettingsModalNow(options = {}) {
8972
8990
  const platformsEl = overlay.querySelector('#stg-mcp-platforms');
8973
8991
  const feedbackEl = overlay.querySelector('#stg-mcp-sync-feedback');
8974
8992
 
8993
+ // The type is a styled dropdown: filled from code it fires no change, so the form's transport follows here too.
8994
+ function setServerType(type) {
8995
+ if (typeEl) setDropdownValue(typeEl, type);
8996
+ if (addForm) addForm.dataset.transport = typeEl?.value || type;
8997
+ }
8998
+
8975
8999
  function resetAddForm() {
8976
9000
  if (pasteZone) pasteZone.value = '';
8977
9001
  if (nameEl) nameEl.value = '';
8978
9002
  if (cmdEl) cmdEl.value = '';
8979
9003
  if (urlEl) urlEl.value = '';
8980
- if (typeEl) typeEl.value = 'stdio';
8981
- if (addForm) addForm.dataset.transport = 'stdio';
9004
+ setServerType('stdio');
8982
9005
  // Clear arg chips
8983
9006
  if (argChips) argChips.querySelectorAll('.stg-mcp-arg-chip').forEach(c => c.remove());
8984
9007
  // Clear env + header rows
@@ -9062,10 +9085,7 @@ async function openSettingsModalNow(options = {}) {
9062
9085
  function populateAddForm(parsed) {
9063
9086
  if (!parsed) return;
9064
9087
  if (parsed.name && nameEl) nameEl.value = parsed.name;
9065
- if (parsed.type && typeEl) {
9066
- typeEl.value = parsed.type;
9067
- if (addForm) addForm.dataset.transport = parsed.type;
9068
- }
9088
+ if (parsed.type) setServerType(parsed.type);
9069
9089
  if (parsed.command && cmdEl) cmdEl.value = parsed.command;
9070
9090
  if (parsed.url && urlEl) urlEl.value = parsed.url;
9071
9091
  if (parsed.args && parsed.args.length) {
@@ -9172,7 +9192,7 @@ async function openSettingsModalNow(options = {}) {
9172
9192
  function applyDetected(name, detected) {
9173
9193
  if (!detected) return;
9174
9194
  if (nameEl && name) nameEl.value = name;
9175
- if (typeEl) typeEl.value = detected.type || 'stdio';
9195
+ setServerType(detected.type || 'stdio');
9176
9196
  if (cmdEl) cmdEl.value = detected.command || '';
9177
9197
  // Rebuild arg chips
9178
9198
  if (argChips && argInput) {
@@ -9550,6 +9570,11 @@ async function openSettingsModalNow(options = {}) {
9550
9570
  }
9551
9571
 
9552
9572
  // ── Shell behaviours: jump lists, keyboard disclosure, page picker ──
9573
+ // The three styled dropdowns of the shell and the panes (page picker, MCP server type, YouTube upload transport).
9574
+ for (const id of ['stg-page-select', 'stg-mcp-srv-type', 'yt-upload-transport']) {
9575
+ const box = overlay.querySelector(`.cc-dropdown[data-for="${id}"]`)?.parentElement;
9576
+ if (box) wireDropdowns(box, { signal: panelLife.signal });
9577
+ }
9553
9578
  wireSettingsShell(overlay, { activate: (pageId) => activateSettingsTab(overlay, pageId) });
9554
9579
  // ── Search: the index is built from the strings of the active locale; what the panes load is read at query time ──
9555
9580
  // In another locale the English names are searched too (someone who learned the settings in English still finds
@@ -27,9 +27,16 @@ if (hostedSidepanelId && host) {
27
27
  receivePath = panel.attachPathToOpencode;
28
28
  end = panel.endHostedOpenCodeSessions;
29
29
  defaults = () => ({ project: store.getState().cwd || '' });
30
+ } else if (provider === 'antigravity') {
31
+ const panel = await import('./ui-antigravity-panel.js');
32
+ await panel.toggleAntigravityPanel();
33
+ receivePath = panel.attachPathToAntigravity;
34
+ end = panel.endHostedAntigravitySessions;
35
+ // The active tab's project (the picker's hidden input holds '' until the project list has loaded).
36
+ defaults = panel.antigravityPanelDefaults;
30
37
  } else throw new Error('Unknown session provider');
31
- const focus = () => document.querySelector('#cp-input, #cxp-input, .ocpv2-compose textarea')?.focus();
32
- const title = document.querySelector('.cp-session-label, .cxp-session-label, .ocpv2-session-label');
38
+ const focus = () => document.querySelector('#cp-input, #cxp-input, .ocpv2-compose textarea, .agy-input')?.focus();
39
+ const title = document.querySelector('.cp-session-label, .cxp-session-label, .ocpv2-session-label, .agy-session-btn span');
33
40
  const syncTitle = () => host.title(hostedSidepanelId, title?.textContent?.trim());
34
41
  if (title) new MutationObserver(syncTitle).observe(title, { childList: true, subtree: true, characterData: true });
35
42
  syncTitle();
@@ -7,9 +7,9 @@ import { normalizeSessionWindowStatus } from './sidepanel-session-status.js';
7
7
  import { savedTabsStatus } from './ui-sidepanel-tray.js';
8
8
 
9
9
  let manifestKey;
10
- const PROVIDERS = { claude: 'Claude', codex: 'Codex', opencode: 'OpenCode' };
10
+ const PROVIDERS = { claude: 'Claude', codex: 'Codex', opencode: 'OpenCode', antigravity: 'Antigravity' };
11
11
  // provider-icons.js ids: the window's pill wears its provider's icon and colour.
12
- const PROVIDER_IDS = { claude: 'claude-code', codex: 'codex', opencode: 'opencode' };
12
+ const PROVIDER_IDS = { claude: 'claude-code', codex: 'codex', opencode: 'opencode', antigravity: 'antigravity' };
13
13
  const STATUS_WORDS = { working: 'working', action: 'needs you' };
14
14
  const entries = new Map();
15
15
  const editorOwners = new Map();
@@ -22,7 +22,7 @@ function save() {
22
22
  function storageFor(id) {
23
23
  // Session lists/registries share one live cache. Unscoped defaults and legacy
24
24
  // session pointers belong to the individual document, never another session.
25
- const scoped = key => /^(synabun-(claude|codex)-panel-(session|thread|title|project|model|effort|autoaccept|default-model|permission-mode)|opencode-v2-project)$/.test(key);
25
+ const scoped = key => /^(synabun-(claude|codex|antigravity)-panel-(session|thread|title|project|model|effort|autoaccept|default-model|permission-mode)|opencode-v2-project)$/.test(key);
26
26
  const keyFor = key => scoped(key) ? `synabun-session-pref-${id}:${key}` : key;
27
27
  return {
28
28
  getItem(key) {
@@ -11,6 +11,7 @@ import { getProviderMeta } from './provider-icons.js';
11
11
  import { toggleClaudePanel, isClaudePanelOpen, bootClaudePanel } from './ui-claude-panel.js';
12
12
  import { toggleCodexPanel, isCodexPanelOpen, bootCodexPanel } from './ui-codex-panel.js';
13
13
  import { toggleOpencodePanel, isOpencodePanelOpen, bootOpencodePanel } from './ui-opencode-panel-v2.js';
14
+ import { toggleAntigravityPanel, isAntigravityPanelOpen, bootAntigravityPanel } from './ui-antigravity-panel.js';
14
15
  import { nativeLoopWindowId } from './ui-native-window-id.js';
15
16
 
16
17
  const PLACEHOLDER_CLASS = 'sidepanel-tray-placeholder';
@@ -52,6 +53,15 @@ const PROVIDERS = {
52
53
  pillClass: 'ocpv2-session-pill',
53
54
  eventName: 'opencode-panel:show',
54
55
  },
56
+ antigravity: {
57
+ providerId: 'antigravity',
58
+ windowKey: 'agy-window-id',
59
+ tabsKeyPrefix: 'synabun-antigravity-panel-tabs',
60
+ pillClass: 'agy-session-pill',
61
+ // A tab saved while a permission card waited on the user (agy-panel.js renderPills).
62
+ attentionClass: 'agy-pill-attention',
63
+ eventName: 'antigravity-panel:show',
64
+ },
55
65
  };
56
66
 
57
67
  // How each panel boots without showing itself, and whether it should: OpenCode only
@@ -60,6 +70,9 @@ const PROVIDERS = {
60
70
  const BOOT_HIDDEN = {
61
71
  claude: { boot: () => bootClaudePanel() },
62
72
  codex: { boot: () => bootCodexPanel() },
73
+ // An Antigravity turn ends with the page that ran it (its `agy acp` belongs to the panel socket), so a saved tab is
74
+ // never working after a reload: booting would only start Antigravity to say so.
75
+ antigravity: { boot: () => bootAntigravityPanel(), ready: async () => false },
63
76
  opencode: {
64
77
  boot: () => bootOpencodePanel(),
65
78
  ready: async () => (await (await fetch('/api/opencode-v2/status')).json())?.running === true,
@@ -152,8 +165,24 @@ function hasOpenCodeState(tab) {
152
165
  );
153
166
  }
154
167
 
168
+ function hasAntigravityState(tab) {
169
+ const label = normalizeLabel(tab.title || tab.label);
170
+ return !!(
171
+ tab.sessionId
172
+ || tab.running
173
+ || tab.automationRunId
174
+ || normalizeLabel(tab.draft)
175
+ || !isDefaultLabel(label, ['new session', 'antigravity'])
176
+ );
177
+ }
178
+
155
179
  function tabLabel(provider, tab) {
156
180
  if (provider === 'claude') return normalizeLabel(tab.label) || 'New chat';
181
+ if (provider === 'antigravity') {
182
+ const title = normalizeLabel(tab.title || tab.label);
183
+ if (title && !isDefaultLabel(title, ['new session'])) return title;
184
+ return tab.sessionId ? `Antigravity · ${String(tab.sessionId).slice(0, 8)}` : 'New session';
185
+ }
157
186
  if (provider === 'codex') return normalizeLabel(tab.pendingSessionLabel || tab.title || tab.sessionLabel) || 'New session';
158
187
  const title = normalizeLabel(tab.sessionTitle || tab.title);
159
188
  if (title) return title;
@@ -169,6 +198,7 @@ function tabId(provider, tab, index) {
169
198
  if (provider === 'claude' && tab.sessionId) return String(tab.sessionId);
170
199
  if (provider === 'codex' && tab.threadId) return String(tab.threadId);
171
200
  if (provider === 'opencode' && tab.sessionId) return String(tab.sessionId);
201
+ if (provider === 'antigravity' && tab.sessionId) return String(tab.sessionId);
172
202
  return `${provider}-${index}`;
173
203
  }
174
204
 
@@ -338,12 +368,14 @@ function cleanupLegacyV1Once(meta) {
338
368
  function statePredicate(provider) {
339
369
  if (provider === 'claude') return hasClaudeState;
340
370
  if (provider === 'codex') return hasCodexState;
371
+ if (provider === 'antigravity') return hasAntigravityState;
341
372
  return hasOpenCodeState;
342
373
  }
343
374
 
344
375
  function dedupeKeyForTab(provider, tab) {
345
376
  if (provider === 'claude') return tab.sessionId ? `cp:${tab.sessionId}` : null;
346
377
  if (provider === 'codex') return tab.threadId ? `cxp:${tab.threadId}` : null;
378
+ if (provider === 'antigravity') return tab.sessionId ? `agy:${tab.sessionId}` : null;
347
379
  return tab.sessionId ? `ocp:${tab.sessionId}` : null;
348
380
  }
349
381
 
@@ -505,14 +537,23 @@ function migrateSourceToCurrentWindow(provider, sourceKey) {
505
537
 
506
538
  async function openProvider(provider, tabIdValue, sourceKey) {
507
539
  migrateSourceToCurrentWindow(provider, sourceKey);
508
- if (provider === 'claude') {
509
- if (!isClaudePanelOpen()) await toggleClaudePanel();
510
- } else if (provider === 'codex') {
511
- if (!isCodexPanelOpen()) await toggleCodexPanel();
512
- } else if (provider === 'opencode') {
513
- if (!isOpencodePanelOpen()) await toggleOpencodePanel();
540
+ if (tabIdValue) globalThis.__synabunPendingTab = { provider, tabId: String(tabIdValue) };
541
+ try {
542
+ if (provider === 'claude') {
543
+ if (!isClaudePanelOpen()) await toggleClaudePanel();
544
+ } else if (provider === 'codex') {
545
+ if (!isCodexPanelOpen()) await toggleCodexPanel();
546
+ } else if (provider === 'opencode') {
547
+ if (!isOpencodePanelOpen()) await toggleOpencodePanel();
548
+ } else if (provider === 'antigravity') {
549
+ if (!isAntigravityPanelOpen()) await toggleAntigravityPanel();
550
+ }
551
+ emit(PROVIDERS[provider]?.eventName, { tabId: tabIdValue });
552
+ } finally {
553
+ if (globalThis.__synabunPendingTab?.provider === provider) {
554
+ globalThis.__synabunPendingTab = null;
555
+ }
514
556
  }
515
- emit(PROVIDERS[provider]?.eventName, { tabId: tabIdValue });
516
557
  }
517
558
 
518
559
  function createPlaceholder(provider, payload, tab, index) {