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
@@ -90,9 +90,10 @@
90
90
  * - `paintMascot(svg, frame)` — draw a frame on any `mascotSvg()`. A still
91
91
  * frame (`stillFrame`, or a rig that is not looping) draws its prop at
92
92
  * ≥ .7 opacity with strokes of ≥ 1.5 CSS px, so it reads at 28×14.
93
- * - `mascotCameoSvg()` — two 3×7 px pill eyes (`syna-cameo` /
94
- * `syna-cameo-eye`) for running pills, leaning −12° like the two-pill mark
95
- * (never a pause glyph); the host's CSS animates them.
93
+ * - `mascotCameoSvg()` — two 3×7 px pill eyes (`syna-cameo` >
94
+ * `syna-cameo-eyes` > svg > `syna-cameo-eye` ×2) for running pills,
95
+ * leaning −12° like the two-pill mark (never a pause glyph); the host's CSS
96
+ * moves the `syna-cameo-eyes` box (an HTML element, so the compositor runs it).
96
97
  * - `mascotPropSvg(kind, { width, height })` + `paintMascotProp(svg, kind)`
97
98
  * — a kind's prop alone, framed to its own box: the ledger's row glyphs.
98
99
  * - `mascotBounds(pose)` — the face-unit box a pose can draw in (the eyes over
@@ -167,14 +168,18 @@ export function blinkAmount(elapsed) {
167
168
  /**
168
169
  * Two 3×7 px pill eyes for a running pill; the host's CSS moves them. The
169
170
  * pair leans −12° like the two-pill mark (the right eye sits higher), so it
170
- * never reads as a pause glyph. The eyes stay untransformed for the CSS glance.
171
+ * never reads as a pause glyph. What moves is the HTML box around the eyes
172
+ * (`syna-cameo-eyes`), never a part of the SVG: a box's transform runs on
173
+ * the compositor and, when the page draws a frame anyway, restyles one
174
+ * element without laying the SVG out again.
171
175
  */
172
176
  export function mascotCameoSvg({ className = '' } = {}) {
173
- return `<svg class="syna-cameo${className ? ` ${className}` : ''}" viewBox="0 0 10 7" width="10" height="7" style="overflow:visible" aria-hidden="true" focusable="false">`
177
+ return `<span class="syna-cameo${className ? ` ${className}` : ''}" aria-hidden="true"><span class="syna-cameo-eyes">`
178
+ + '<svg viewBox="0 0 10 7" width="10" height="7" style="display:block;overflow:visible" focusable="false">'
174
179
  + '<g class="syna-cameo-pair" transform="rotate(-12 5 3.5)">'
175
180
  + '<rect class="syna-cameo-eye" x="0" y="0" width="3" height="7" rx="1.5" fill="currentColor"/>'
176
181
  + '<rect class="syna-cameo-eye" x="7" y="0" width="3" height="7" rx="1.5" fill="currentColor"/>'
177
- + '</g></svg>';
182
+ + '</g></svg></span></span>';
178
183
  }
179
184
 
180
185
  /** Each prop's own box in face units, to draw it alone (a ledger row's glyph, a suggestion's). */
@@ -1842,6 +1847,14 @@ function createPainter(svg, uid) {
1842
1847
  if (value == null) el.removeAttribute(attr);
1843
1848
  else el.setAttribute(attr, value);
1844
1849
  };
1850
+ /** A prop's writes for this frame: the last value per attribute wins, put() writes it once (paint). */
1851
+ const staged = new Map();
1852
+ const stage = (el, attr, value) => {
1853
+ if (!el) return;
1854
+ let attrs = staged.get(el);
1855
+ if (!attrs) { attrs = new Map(); staged.set(el, attrs); }
1856
+ attrs.set(attr, value);
1857
+ };
1845
1858
  /** CSS px per face unit: the SVG's box over its viewBox (xMidYMid meet: the tighter axis). */
1846
1859
  const unitPx = () => {
1847
1860
  const w = Number(svg.getAttribute?.('width'));
@@ -1898,8 +1911,14 @@ function createPainter(svg, uid) {
1898
1911
  put(entry.g, 'display', null);
1899
1912
  put(entry.g, 'opacity', op < 0.999 ? n(op) : null);
1900
1913
  put(entry.g, 'transform', p.dx || p.dy ? `translate(${n(p.dx || 0)},${n(p.dy || 0)})` : null);
1901
- if (!f.still) for (const b of entry.base) put(b.el, b.attr, b.value); // live: the drawn values
1902
- PROPS[name].update(entry.r, p, put);
1914
+ // Live: the drawn values, then the frame's own over them. Both are staged and each attribute is
1915
+ // written once with its final value, so a frame that changes nothing writes nothing (an attribute
1916
+ // written twice a frame, back to its base and on again, restyles and re-lays the SVG out every frame).
1917
+ staged.clear();
1918
+ if (!f.still) for (const b of entry.base) stage(b.el, b.attr, b.value);
1919
+ PROPS[name].update(entry.r, p, stage);
1920
+ for (const [el, attrs] of staged) for (const [attr, value] of attrs) put(el, attr, value);
1921
+ staged.clear();
1903
1922
  if (f.still) legible(entry);
1904
1923
  }
1905
1924
  }
@@ -9,6 +9,18 @@
9
9
  // requestFrames(ms) lifts the animation subscribers (≥ 24 fps) to 60 fps for a
10
10
  // moment: a pose blend, a hop.
11
11
  //
12
+ // A frame is only requested for the vsync a subscriber is due on: a 30 fps
13
+ // rig costs 30 frames a second, not one per vsync. Every frame the page draws
14
+ // makes the browser restyle each running CSS animation on the main thread
15
+ // (composited or not), so a frame nobody needs is never free. Between due
16
+ // frames the loop sleeps on a timer that wakes half a frame before the vsync
17
+ // it wants; the frame interval is learnt from back-to-back frames (60 Hz,
18
+ // 120 Hz displays).
19
+ //
20
+ // A subscriber may name a `target` element: it runs only while that element
21
+ // is on screen (one shared IntersectionObserver), and a loop whose every
22
+ // subscriber is off screen requests nothing at all until one comes back.
23
+ //
12
24
  // The loop stops while the tab is hidden (document.hidden, body.app-hidden)
13
25
  // and freezes while the UI is dragged (body.ui-interacting): subscribers are
14
26
  // skipped, and the first frame after either hands each one a dt of at most
@@ -20,7 +32,7 @@
20
32
  // pointermove listener and one keydown listener (both capture phase, so a
21
33
  // handler that stops propagation cannot hide input from them).
22
34
  //
23
- // subscribe(fn(now, dt), { fps }) → unsubscribe() (unsubscribe.setFps(n) re-caps)
35
+ // subscribe(fn(now, dt), { fps, target }) → unsubscribe() (unsubscribe.setFps(n) re-caps)
24
36
  // requestFrames(ms) 60 fps for the next ms
25
37
  // isReducedMotion() live prefers-reduced-motion
26
38
  // onReducedMotionChange(fn(on)) → unsubscribe()
@@ -41,8 +53,10 @@
41
53
  const FRAME_60 = 1000 / 60;
42
54
  const SLOP = 4; // ms of rAF jitter a capped subscriber tolerates before it skips a frame
43
55
  const RESUME_DT = 50; // the first dt after a stop or a freeze is at most this
44
- const SLEEP_OVER = 48; // a wait longer than this sleeps on a timer instead of frames
45
56
  const POLL_MS = 250; // how often a stopped loop re-checks when no MutationObserver exists
57
+ const PHASE_MS = 1500; // a frame newer than this still tells where the vsyncs fall
58
+ const MIN_FRAME = 4; // ms: the shortest frame interval believed (240 Hz)
59
+ const MAX_FRAME = 34; // ms: the longest (30 Hz)
46
60
  const MAX_BOOST = 5000;
47
61
  const LISTEN = { passive: true, capture: true };
48
62
 
@@ -84,10 +98,73 @@ let pollId = 0;
84
98
  let boostUntil = -Infinity;
85
99
  let watching = false;
86
100
  let observer = null;
101
+ let frameMs = FRAME_60; // the display's frame interval, as back-to-back frames show it
102
+ let lastTs = -Infinity; // the last frame's timestamp: where the vsyncs fall
103
+ let inFrame = false; // frame() is running
104
+ let chained = false; // the frame in flight was requested by the previous one, with no wait between
105
+ const counts = { frames: 0, requests: 0, sleeps: 0 }; // for tests and the idle-CPU suite
87
106
 
88
107
  const capFps = fps => Math.max(1, Math.min(60, Number(fps) > 0 ? Number(fps) : 30));
89
108
  const boosted = (sub, t) => t < boostUntil && sub.fps >= 24;
90
109
  const intervalOf = (sub, t) => (boosted(sub, t) ? FRAME_60 : 1000 / sub.fps);
110
+ /** A subscriber with a target off screen is parked: it is neither called nor waited for. */
111
+ const parked = sub => sub.target && !sub.seen;
112
+
113
+ // ── Targets: one IntersectionObserver for every subscriber that names an element ──
114
+
115
+ let targetIo = null; // undefined while unavailable
116
+ const targetSubs = new Map(); // element → Set of subs
117
+ const targetSeen = new Map(); // element → on screen as last reported (absent until the first report)
118
+
119
+ function targetObserver() {
120
+ if (targetIo !== null) return targetIo;
121
+ const IO = env ? env.IntersectionObserver : globalThis.IntersectionObserver;
122
+ if (typeof IO !== 'function') { targetIo = undefined; return targetIo; }
123
+ try {
124
+ targetIo = new IO((entries) => {
125
+ let woke = false;
126
+ for (const entry of entries) {
127
+ const set = targetSubs.get(entry.target);
128
+ if (!set) continue;
129
+ const on = !!entry.isIntersecting;
130
+ targetSeen.set(entry.target, on);
131
+ for (const sub of set) {
132
+ if (sub.seen === on) continue;
133
+ sub.seen = on;
134
+ if (on) { sub.resume = true; woke = true; }
135
+ }
136
+ }
137
+ if (woke && subs.size) wakeNow();
138
+ });
139
+ } catch { targetIo = undefined; }
140
+ return targetIo;
141
+ }
142
+
143
+ function watchTarget(sub) {
144
+ const el = sub.target;
145
+ const io = targetObserver();
146
+ if (!io) { sub.target = null; return; } // no observer: the target counts as on screen
147
+ let set = targetSubs.get(el);
148
+ if (!set) {
149
+ set = new Set();
150
+ targetSubs.set(el, set);
151
+ try { io.observe(el); } catch { targetSubs.delete(el); sub.target = null; return; }
152
+ }
153
+ set.add(sub);
154
+ // Until the observer's first report the target counts as on screen (it draws at once, as before).
155
+ sub.seen = targetSeen.has(el) ? targetSeen.get(el) : true;
156
+ }
157
+
158
+ function unwatchTarget(sub) {
159
+ const el = sub.target;
160
+ const set = el ? targetSubs.get(el) : null;
161
+ if (!set) return;
162
+ set.delete(sub);
163
+ if (set.size) return;
164
+ targetSubs.delete(el);
165
+ targetSeen.delete(el);
166
+ try { targetIo?.unobserve(el); } catch { /* already gone */ }
167
+ }
91
168
 
92
169
  /** Why the loop is not running: '' (it runs), 'hidden' or 'interacting'. */
93
170
  export function tickerPaused() {
@@ -102,17 +179,20 @@ export function tickerPaused() {
102
179
 
103
180
  /**
104
181
  * Call `fn(now, dt)` from the shared loop, at most `fps` times a second
105
- * (1-60, default 30). Returns unsubscribe(); unsubscribe.setFps(n) changes the
106
- * cap in place.
182
+ * (1-60, default 30). With `target` (an element) it is called only while that
183
+ * element is on screen. Returns unsubscribe(); unsubscribe.setFps(n) changes
184
+ * the cap in place.
107
185
  */
108
- export function subscribe(fn, { fps = 30 } = {}) {
186
+ export function subscribe(fn, { fps = 30, target = null } = {}) {
109
187
  if (typeof fn !== 'function') return Object.assign(() => {}, { setFps() {} });
110
- const sub = { fn, fps: capFps(fps), last: -1, born: now(), resume: false };
188
+ const sub = { fn, fps: capFps(fps), last: -1, born: now(), resume: false, target: target && typeof target === 'object' ? target : null, seen: true };
111
189
  subs.add(sub);
190
+ if (sub.target) watchTarget(sub);
112
191
  watch();
113
192
  wakeNow();
114
193
  const unsubscribe = () => {
115
194
  if (!subs.delete(sub)) return;
195
+ unwatchTarget(sub);
116
196
  if (!subs.size) halt();
117
197
  };
118
198
  unsubscribe.setFps = (next) => {
@@ -138,31 +218,71 @@ function wakeNow() {
138
218
  schedule();
139
219
  }
140
220
 
221
+ /**
222
+ * Request the next frame a subscriber is due on, and no other: when the next
223
+ * vsync serves it, at once; otherwise a timer wakes half a frame before the
224
+ * vsync it wants. Nothing at all while every subscriber is parked.
225
+ */
141
226
  function schedule() {
142
227
  if (rafId || timerId || !subs.size) return;
143
228
  const raf = rafFn();
144
229
  if (!raf) return;
145
230
  if (tickerPaused()) { stopped(); return; }
146
231
  const t = now();
147
- let wait = Infinity;
232
+ let due = Infinity;
148
233
  for (const sub of subs) {
149
- const due = sub.last < 0 ? 0 : sub.last + intervalOf(sub, t) - SLOP - t;
150
- if (due < wait) wait = due;
234
+ if (parked(sub)) continue;
235
+ const at = sub.last < 0 ? t : sub.last + intervalOf(sub, t) - SLOP;
236
+ if (at < due) due = at;
151
237
  }
152
- if (wait > SLEEP_OVER) {
153
- timerId = later(() => { timerId = 0; schedule(); }, wait - FRAME_60);
238
+ if (!Number.isFinite(due)) return; // every subscriber is off screen: the observer wakes the loop
239
+ const phase = lastTs > -Infinity && t - lastTs < PHASE_MS ? lastTs : null;
240
+ let lead;
241
+ if (due <= t) lead = 0;
242
+ else if (phase === null) lead = due - t - frameMs; // no recent vsync to count from: the frame before `due`
243
+ else {
244
+ const k = Math.max(1, Math.ceil((due - phase) / frameMs - 1e-6));
245
+ lead = k === 1 ? 0 : phase + (k - 0.5) * frameMs - t; // half a frame before the vsync that serves `due`
246
+ }
247
+ if (lead > 1) {
248
+ counts.sleeps += 1;
249
+ timerId = later(() => { timerId = 0; schedule(); }, lead);
154
250
  return;
155
251
  }
252
+ counts.requests += 1;
253
+ chained = inFrame;
156
254
  rafId = raf(frame);
157
255
  }
158
256
 
257
+ /** Learn the display's frame interval from two frames requested back to back. */
258
+ function learnInterval(ts) {
259
+ if (!chained || !(lastTs > -Infinity)) return;
260
+ const d = ts - lastTs;
261
+ if (!(d >= MIN_FRAME && d <= MAX_FRAME)) return;
262
+ // Snap down to the shortest seen; drift back up slowly (a dropped frame is two, not a slower display).
263
+ frameMs = Math.min(d, Math.min(MAX_FRAME, frameMs + 0.05));
264
+ }
265
+
159
266
  function frame(ts) {
160
267
  rafId = 0;
161
268
  if (!subs.size) return;
162
269
  if (tickerPaused()) { stopped(); return; }
163
270
  const t = typeof ts === 'number' && Number.isFinite(ts) ? ts : now();
271
+ counts.frames += 1;
272
+ learnInterval(t);
273
+ lastTs = t;
274
+ chained = false;
275
+ inFrame = true;
276
+ try {
277
+ runSubscribers(t);
278
+ schedule(); // inside the frame: a frame requested from here is the next vsync's (it teaches the interval)
279
+ } finally { inFrame = false; }
280
+ }
281
+
282
+ function runSubscribers(t) {
164
283
  for (const sub of Array.from(subs)) {
165
284
  if (!subs.has(sub)) continue; // unsubscribed by an earlier subscriber this frame
285
+ if (parked(sub)) continue;
166
286
  const interval = intervalOf(sub, t);
167
287
  if (sub.last >= 0 && t - sub.last < interval - SLOP) continue;
168
288
  let dt = t - (sub.last >= 0 ? sub.last : sub.born);
@@ -172,7 +292,6 @@ function frame(ts) {
172
292
  sub.last = t;
173
293
  try { sub.fn(t, dt); } catch (err) { report(err); }
174
294
  }
175
- schedule();
176
295
  }
177
296
 
178
297
  /** The loop stopped (hidden) or froze (drag): mark the jump, wait for the watchers. */
@@ -334,6 +453,17 @@ function reset() {
334
453
  halt();
335
454
  subs.clear();
336
455
  boostUntil = -Infinity;
456
+ try { targetIo?.disconnect(); } catch { /* gone */ }
457
+ targetIo = null;
458
+ targetSubs.clear();
459
+ targetSeen.clear();
460
+ frameMs = FRAME_60;
461
+ lastTs = -Infinity;
462
+ inFrame = false;
463
+ chained = false;
464
+ counts.frames = 0;
465
+ counts.requests = 0;
466
+ counts.sleeps = 0;
337
467
  const q = motionQuery;
338
468
  if (q && motionFns.size) {
339
469
  if (q.removeEventListener) q.removeEventListener('change', onMotionQuery);
@@ -372,5 +502,10 @@ export const __ticker = {
372
502
  keyListeners: keyFns.size,
373
503
  keyAttached: keyOn,
374
504
  motionListeners: motionFns.size,
505
+ parked: Array.from(subs).filter(parked).length,
506
+ targets: targetSubs.size,
507
+ frameMs,
375
508
  }),
509
+ /** Frames run, frames requested and timer sleeps since the last reset (the idle-CPU suite reads them). */
510
+ counts: () => ({ ...counts }),
376
511
  };
@@ -0,0 +1,29 @@
1
+ // String caches need a size budget as well as an entry count: streaming
2
+ // revisions are different keys and may each hold a nearly complete transcript.
3
+ export function createTextCache({ maxEntries = 512, maxChars = 1_000_000, maxEntryChars = 64_000 } = {}) {
4
+ const entries = new Map();
5
+ let chars = 0;
6
+ const drop = key => {
7
+ const value = entries.get(key);
8
+ if (value === undefined) return;
9
+ chars -= key.length + value.length;
10
+ entries.delete(key);
11
+ };
12
+ return {
13
+ get(key) {
14
+ const value = entries.get(key);
15
+ if (value !== undefined) { entries.delete(key); entries.set(key, value); }
16
+ return value;
17
+ },
18
+ set(key, value) {
19
+ drop(key);
20
+ const size = key.length + value.length;
21
+ if (size > Math.min(maxChars, maxEntryChars) || maxEntries < 1) return;
22
+ while (entries.size && (entries.size >= maxEntries || chars + size > maxChars)) drop(entries.keys().next().value);
23
+ entries.set(key, value);
24
+ chars += size;
25
+ },
26
+ clear() { entries.clear(); chars = 0; },
27
+ stats: () => ({ entries: entries.size, chars }),
28
+ };
29
+ }
@@ -11,7 +11,7 @@ export function toolPickerHTML(id, tools, options = {}) {
11
11
  if (!catalog) return '';
12
12
  const view = toolListView(catalog, tools, { translate, ...options });
13
13
  return dropdownHTML(id, view.entries, { multiple: true, label: toolWord('label'), classes: 'tool-list-picker',
14
- summary: view.summary, ...options, classes: `tool-list-picker ${options.classes || ''}`.trim(), attrs: `data-tool-options="${encodeURIComponent(JSON.stringify({ inheritLabel: options.inheritLabel, usesBrowser: options.usesBrowser, taskClass: options.taskClass, cwd: options.cwd, provider: options.provider, includeServers: options.includeServers, externalSelection: catalog.externalServersVersion >= 2 && options.includeServers !== false && options.provider !== 'gemini', externalRefs: (tools ?? catalog.defaultTools ?? []).filter(id => id.startsWith('mcp:')) }))}"` });
14
+ summary: view.summary, ...options, classes: `tool-list-picker ${options.classes || ''}`.trim(), attrs: `data-tool-options="${encodeURIComponent(JSON.stringify({ inheritLabel: options.inheritLabel, usesBrowser: options.usesBrowser, taskClass: options.taskClass, cwd: options.cwd, provider: options.provider, includeServers: options.includeServers, externalSelection: catalog.externalServersVersion >= 2 && options.includeServers !== false && options.provider !== 'antigravity', externalRefs: (tools ?? catalog.defaultTools ?? []).filter(id => id.startsWith('mcp:')) }))}"` });
15
15
  }
16
16
  export function updateToolPicker(input, tools, options = {}) {
17
17
  options = { ...JSON.parse(decodeURIComponent(dropdownOf(input)?.dataset.toolOptions || '%7B%7D')), ...options };
@@ -20,7 +20,7 @@ export function updateToolPicker(input, tools, options = {}) {
20
20
  const view = toolListView(catalog, tools, { translate, ...options });
21
21
  setDropdownItems(input, view.entries);
22
22
  const dd = dropdownOf(input);
23
- if (dd) dd.dataset.toolOptions = encodeURIComponent(JSON.stringify({ inheritLabel: options.inheritLabel, usesBrowser: options.usesBrowser, taskClass: options.taskClass, cwd: options.cwd, provider: options.provider, includeServers: options.includeServers, externalSelection: catalog.externalServersVersion >= 2 && options.includeServers !== false && options.provider !== 'gemini', externalRefs: (tools ?? catalog.defaultTools ?? []).filter(id => id.startsWith('mcp:')) }));
23
+ if (dd) dd.dataset.toolOptions = encodeURIComponent(JSON.stringify({ inheritLabel: options.inheritLabel, usesBrowser: options.usesBrowser, taskClass: options.taskClass, cwd: options.cwd, provider: options.provider, includeServers: options.includeServers, externalSelection: catalog.externalServersVersion >= 2 && options.includeServers !== false && options.provider !== 'antigravity', externalRefs: (tools ?? catalog.defaultTools ?? []).filter(id => id.startsWith('mcp:')) }));
24
24
  const label = dropdownOf(input)?.querySelector('.cc-dropdown-value');
25
25
  if (label) { label.textContent = view.summary; label.title = view.summary; }
26
26
  }
@@ -45,7 +45,7 @@ function groupWord(group, field, translate) {
45
45
  return group[field];
46
46
  }
47
47
 
48
- export const strictToolHost = provider => provider === 'opencode' || provider === 'gemini';
48
+ export const strictToolHost = provider => provider === 'opencode' || provider === 'antigravity';
49
49
  export const taskToolHost = provider => strictToolHost(provider) || provider === 'claude-code' || provider === 'codex';
50
50
 
51
51
  /** Hidden-input encoding: inheritance differs from an explicit empty group list. */
@@ -87,7 +87,7 @@ export function toolListView(catalog, tools, { inheritLabel = null, usesBrowser,
87
87
  });
88
88
  if (options.length) entries.push({ group: word(section), options });
89
89
  }
90
- if (includeServers && provider !== 'gemini' && catalog?.externalServersVersion >= 2) {
90
+ if (includeServers && provider !== 'antigravity' && catalog?.externalServersVersion >= 2) {
91
91
  const wildcard = refs.includes('mcp:*');
92
92
  const rows = (catalog.servers || []).filter(row => row.selectable !== false);
93
93
  // A saved unavailable ref stays visible and round-trips; loading a catalog never silently clears it.
@@ -0,0 +1,54 @@
1
+ // The top-right toolbar's overflow, what decides (no DOM, no imports: node --test loads it).
2
+ // The page side is ui-topright-overflow.js.
3
+
4
+ // Lowest priority first: the first entries are the first to leave the row for the ⋯ menu.
5
+ export const OVERFLOW_ORDER = [
6
+ 'topright-keybinds-btn',
7
+ 'invite-overlay',
8
+ 'topright-trash-btn',
9
+ 'topright-bookmarks-btn',
10
+ 'topright-antigravity-panel-btn',
11
+ 'topright-opencode-panel-btn',
12
+ 'topright-file-explorer-btn',
13
+ 'topright-memory-explorer-btn',
14
+ 'topright-codex-panel-btn',
15
+ 'topright-update-btn',
16
+ 'topright-claude-panel-btn',
17
+ 'topright-assistant-panel-btn',
18
+ // the very last resort, a band of about 120 px: the toggle too (its entry in the menu shows and hides the tools)
19
+ 'topright-tools-btn',
20
+ ];
21
+
22
+ /**
23
+ * Which entries of OVERFLOW_ORDER leave the row: the fewest, in order, that bring the row's width within `available`.
24
+ * `total` is the row with everything in it and no ⋯; `widths[i]` what entry i takes in the row (its width and the gap
25
+ * before it; 0 when it is not shown at all, and then never listed); `menuWidth` what the ⋯ adds once anything
26
+ * overflows. Pinned entries never leave.
27
+ */
28
+ export function overflowCount({ total, available, widths, menuWidth, pinned = [] }) {
29
+ if (total <= available) return { count: 0, hidden: [] };
30
+ let need = total + menuWidth;
31
+ const hidden = [];
32
+ for (let i = 0; i < widths.length && need > available; i++) {
33
+ if (pinned.includes(i) || !widths[i]) continue;
34
+ need -= widths[i];
35
+ hidden.push(i);
36
+ }
37
+ return { count: hidden.length, hidden };
38
+ }
39
+
40
+ /**
41
+ * Where a dropdown of the bar (workspaces, bookmarks, share) goes across: kept within [minLeft, maxRight] (the band's
42
+ * clip on the left, which already clears the Focus Mode rail and the left panels; the viewport on the right).
43
+ * `left` / `width` are its box as the stylesheet hangs it. Returns the `shift` (px, + is to the right) and the
44
+ * `maxWidth` it may take (null when it fits as it is). Too wide for the room: as wide as the room, flush with minLeft.
45
+ */
46
+ export function clampDropdownX({ left, width, minLeft, maxRight }) {
47
+ const room = Math.max(0, maxRight - minLeft);
48
+ const w = Math.min(width, room);
49
+ const maxWidth = width > room ? room : null;
50
+ let x = left;
51
+ if (x + w > maxRight) x = maxRight - w;
52
+ if (x < minLeft) x = minLeft;
53
+ return { shift: Math.round(x - left), maxWidth };
54
+ }
@@ -0,0 +1,19 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Antigravity Panel (barrel re-export)
3
+ // The Antigravity side panel's entry point: one stable surface for the shared
4
+ // UI modules (navbar, tray, detached session windows, the native-loop router,
5
+ // the File Explorer's Send to). Implementation lives in ./agy/.
6
+ // ═══════════════════════════════════════════
7
+
8
+ export {
9
+ toggleAntigravityPanel,
10
+ isAntigravityPanelOpen,
11
+ bootAntigravityPanel,
12
+ openAntigravityWithPrompt,
13
+ attachPathToAntigravity,
14
+ attachAntigravityAutomation,
15
+ detachAntigravityAutomation,
16
+ handleAntigravityAutomationEvent,
17
+ antigravityPanelDefaults,
18
+ endHostedAntigravitySessions,
19
+ } from './agy/agy-panel.js';
@@ -41,6 +41,8 @@ const hosts = createAssistantHosts({
41
41
  export const registerAssistantHost = (adapter) => hosts.register(adapter);
42
42
  export const assistantOwnerOf = (sessionId) => hosts.ownerOf(sessionId);
43
43
  export const fetchLiveAssistantSessions = () => hosts.fetchLive();
44
+ /** The same, or null when the list could not be read (the server is starting): saved tabs are kept then. */
45
+ export const readLiveAssistantSessions = () => hosts.readLive();
44
46
  export const isAssistantSessionLive = (meta) => hosts.isLive(meta);
45
47
  /** opts: { host, brain, resume, label, floating, prompt } */
46
48
  export const openAssistant = (opts = {}) => hosts.open(opts);
@@ -28,6 +28,9 @@ import {
28
28
  getEffortLevelsForProfile,
29
29
  getModelsForProfile,
30
30
  isDynamicModelProfile,
31
+ migrateLaunchRecords,
32
+ migrateProviderId,
33
+ migrateProviderModel,
31
34
  modelSelectorValue,
32
35
  modelMatchesSelector,
33
36
  normalizeEffortForProfile,
@@ -184,7 +187,7 @@ const AS_ICONS = {
184
187
  // External SVG logos (fill-based, from public/ directory)
185
188
  claude: `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" fill-rule="evenodd"><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"/></svg>`,
186
189
  openai: `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" fill-rule="evenodd"><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>`,
187
- gemini: `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" fill-rule="evenodd"><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>`,
190
+ antigravity: `<svg viewBox="0 0 24 24" width="14" height="14" 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>`,
188
191
  pin: _s('<path d="M8 14v-3"/><path d="M4 11h8"/><path d="M10.5 2.5l3 3-2 2 .5 2-4.5.5.5-4.5 2-.5z"/>'),
189
192
 
190
193
  // UI chrome
@@ -195,8 +198,8 @@ const AS_ICONS = {
195
198
  export: _s('<path d="M8 2v8M4 6l4-4 4 4"/><path d="M2 11v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-2"/>'),
196
199
  };
197
200
 
198
- /** Resolve icon key → SVG HTML. Falls back to refresh icon for unknown keys. */
199
- function icon(key) { return AS_ICONS[key] || AS_ICONS.refresh; }
201
+ /** Resolve icon key → SVG HTML. Falls back to refresh icon for unknown keys ('gemini' reads as 'antigravity'). */
202
+ function icon(key) { return AS_ICONS[migrateProviderId(key)] || AS_ICONS.refresh; }
200
203
 
201
204
  /** Icon keys available for template selection (excludes UI-only icons). */
202
205
  const ICON_KEYS = Object.keys(AS_ICONS).filter(k => !['back','forward','down','close','export','plus','bolt','blank'].includes(k));
@@ -205,10 +208,10 @@ const _modelLoadRequests = new Set();
205
208
  const _modelLoadAttempts = new Set();
206
209
 
207
210
  // Persistent launch preferences (remembered across launches in session)
208
- let _launchProfile = storage.getItem('as-launch-profile') || 'claude-code';
211
+ let _launchProfile = migrateProviderId(storage.getItem('as-launch-profile') || 'claude-code');
209
212
  const _initialLaunchSelection = normalizeAutomationSelection(
210
- storage.getItem('as-launch-profile') || 'claude-code',
211
- storage.getItem('as-launch-model'), storage.getItem('as-launch-context-mode'),
213
+ _launchProfile,
214
+ migrateProviderModel(_launchProfile, storage.getItem('as-launch-model')), storage.getItem('as-launch-context-mode'),
212
215
  );
213
216
  let _launchModel = _initialLaunchSelection.model;
214
217
  let _launchContextMode = _initialLaunchSelection.contextMode || 'default';
@@ -1114,6 +1117,11 @@ function dynamicModelEmptyText(profileId) {
1114
1117
  ? 'No Claude Code models found — check the Claude CLI install in Settings → Terminal.'
1115
1118
  : 'Loading Claude Code models...';
1116
1119
  }
1120
+ if (profileId === 'antigravity') {
1121
+ return loaded
1122
+ ? 'No Antigravity models found — check the Antigravity CLI install in Settings → Terminal.'
1123
+ : 'Loading Antigravity models...';
1124
+ }
1117
1125
  return 'No model selection available';
1118
1126
  }
1119
1127
 
@@ -2338,7 +2346,7 @@ async function loadData() {
2338
2346
  await fetchToolCatalog();
2339
2347
  // One round trip for the three lists (they were asked one after another), then the agents.
2340
2348
  const [templates, folders, active] = await Promise.allSettled([fetchLoopTemplates(), fetchLoopFolders(), fetchActiveLoop()]);
2341
- _templates = templates.status === 'fulfilled' ? templates.value : [];
2349
+ _templates = templates.status === 'fulfilled' ? migrateLaunchRecords(templates.value) : [];
2342
2350
  _folders = folders.status === 'fulfilled' ? folders.value : [];
2343
2351
  _activeLoop = active.status === 'fulfilled' ? active.value : null;
2344
2352
  await refreshAgents();
@@ -3153,7 +3161,7 @@ async function saveCurrentTemplate() {
3153
3161
  try {
3154
3162
  if (_selected.id) { await updateLoopTemplate(_selected.id, payload); }
3155
3163
  else { const result = await createLoopTemplate(payload); if (result?.id) _selected.id = result.id; }
3156
- _templates = await fetchLoopTemplates();
3164
+ _templates = migrateLaunchRecords(await fetchLoopTemplates());
3157
3165
  const updated = _templates.find(t => t.id === _selected.id);
3158
3166
  if (updated) _selected = updated;
3159
3167
  _originalContent = task;
@@ -3259,7 +3267,7 @@ async function customizePreset(preset) {
3259
3267
  };
3260
3268
  const result = await createLoopTemplate(payload);
3261
3269
  if (result?.id) {
3262
- _templates = await fetchLoopTemplates();
3270
+ _templates = migrateLaunchRecords(await fetchLoopTemplates());
3263
3271
  const newTpl = _templates.find(t => t.id === result.id);
3264
3272
  if (newTpl) {
3265
3273
  showToast('Customized \u2014 edit and save your copy');
@@ -4574,9 +4582,9 @@ function wireInputSync(container) {
4574
4582
  // ═══════════════════════════════════════════
4575
4583
 
4576
4584
  async function loadScheduleData() {
4577
- try { _schedules = await fetchSchedules(); } catch { _schedules = []; }
4585
+ try { _schedules = migrateLaunchRecords(await fetchSchedules()); } catch { _schedules = []; }
4578
4586
  try { _scheduleTimerData = await fetchScheduleTimers(); } catch { _scheduleTimerData = {}; }
4579
- try { _quickTimers = await fetchQuickTimers(); } catch { _quickTimers = []; }
4587
+ try { _quickTimers = migrateLaunchRecords(await fetchQuickTimers()); } catch { _quickTimers = []; }
4580
4588
  }
4581
4589
 
4582
4590
  const CRON_PRESET_GROUPS = [
@@ -5095,7 +5103,7 @@ function triggerImport() {
5095
5103
  showToast('Invalid file format'); return;
5096
5104
  }
5097
5105
  const result = await importLoopTemplates(data);
5098
- _templates = await fetchLoopTemplates();
5106
+ _templates = migrateLaunchRecords(await fetchLoopTemplates());
5099
5107
  renderView();
5100
5108
  showToast(`Imported: ${result.added} added, ${result.updated} updated`);
5101
5109
  } catch (err) { showToast('Import failed: ' + err.message); }