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
@@ -65,12 +65,15 @@ export function resumeSandboxPlan(current, previous, channelPort) {
65
65
  */
66
66
  export function resumeRefusal(entry, { now = Date.now(), workLeftMs = Infinity, atShutdown = false, isDirectory = () => true, accountUnusable = () => '' } = {}) {
67
67
  if (!entry) return 'the run is not known';
68
- if (!['claude-code', 'codex', 'opencode'].includes(entry.provider)) return 'this provider cannot continue after a restart';
68
+ if (!['claude-code', 'codex', 'opencode', 'antigravity'].includes(entry.provider)) return 'this provider cannot continue after a restart';
69
69
  if (entry.confinement?.kind === 'skill-eval') return 'a skill evaluation run is a measurement and starts over instead';
70
70
  if (entry.confinement) return 'a skill drafting run is not resumed';
71
71
  if (entry.removedAt) return 'the run was removed';
72
- if (!(entry.provider === 'codex' ? entry.providerThreadId : entry.providerSessionId)) return `its ${entry.provider === 'codex' ? 'Codex thread' : entry.provider === 'opencode' ? 'OpenCode session' : 'Claude session'} had not started yet`;
72
+ if (!(entry.provider === 'codex' ? entry.providerThreadId : entry.providerSessionId)) return `its ${entry.provider === 'codex' ? 'Codex thread' : entry.provider === 'opencode' ? 'OpenCode session' : entry.provider === 'antigravity' ? 'Antigravity session' : 'Claude session'} had not started yet`;
73
73
  if (entry.provider === 'opencode' && !entry.resumeInfo?.persistentOpenCode) return 'its OpenCode session has no durable run data';
74
+ // Antigravity keeps the conversation in the run's own home (lib/antigravity/home.js): a run started before homes
75
+ // existed has its session in the user's own ~/.gemini, which a resume does not use.
76
+ if (entry.provider === 'antigravity' && !entry.resumeInfo?.antigravityHome) return 'its Antigravity session has no SynaBun home to resume from';
74
77
  const resumes = Number(entry.resumes) || 0;
75
78
  if (resumes >= MAX_RESUMES) return `it was resumed ${resumes} times already`;
76
79
  if (!(workLeftMs > 0)) return entry.maxMinutes ? `its ${entry.maxMinutes} minutes of work time are used up` : 'its work time is used up';
@@ -79,7 +82,8 @@ export function resumeRefusal(entry, { now = Date.now(), workLeftMs = Infinity,
79
82
  if (since && now - since > RESUME_WINDOW_MS) return `the server was back ${Math.round((now - since) / 60_000)} minutes later (more than ${Math.round(RESUME_WINDOW_MS / 60_000)})`;
80
83
  if (!entry.cwd || !isDirectory(entry.cwd)) return `its working directory is gone (${entry.cwd || 'none'})`;
81
84
  let unusable = '';
82
- try { unusable = entry.provider === 'opencode' ? '' : String(accountUnusable((entry.provider === 'codex' ? entry.codexAccountId : entry.claudeAccountId) || 'default', entry.provider, entry) || ''); } catch (error) { unusable = error?.message || 'it could not be read'; }
85
+ // OpenCode and Antigravity sign in inside their own CLI: SynaBun keeps no account of theirs.
86
+ try { unusable = entry.provider === 'opencode' || entry.provider === 'antigravity' ? '' : String(accountUnusable((entry.provider === 'codex' ? entry.codexAccountId : entry.claudeAccountId) || 'default', entry.provider, entry) || ''); } catch (error) { unusable = error?.message || 'it could not be read'; }
83
87
  if (unusable) return `its ${entry.provider === 'codex' ? 'Codex' : 'Claude'} account (${entry.codexAccountId || entry.claudeAccountId || 'default'}) cannot be used: ${unusable}`;
84
88
  return null;
85
89
  }
@@ -184,7 +188,12 @@ export function processCommandLine(pid, { platform = process.platform, run = exe
184
188
  */
185
189
  export function isRunCliCommand(command, runId) {
186
190
  const text = String(command || '');
187
- return !!runId && text.includes(String(runId)) && ((text.includes('--input-format') && text.includes('stream-json')) || (text.includes('app-server') && text.includes('synabun_worker_run=')));
191
+ return !!runId && text.includes(String(runId)) && (
192
+ (text.includes('--input-format') && text.includes('stream-json'))
193
+ || (text.includes('app-server') && text.includes('synabun_worker_run='))
194
+ // Antigravity: `agy acp --gemini-dir <data home>/runtime/antigravity/homes/run-<run id>-…` (lib/antigravity/home.js).
195
+ || (/\sacp(?:\s|$)/.test(text) && text.includes('--gemini-dir') && /[\\/]antigravity[\\/]homes[\\/]run-/.test(text))
196
+ );
188
197
  }
189
198
 
190
199
  /** Windows: end a process and every process it started (taskkill /T /F, as the server's own shutdown does). */
@@ -19,13 +19,32 @@
19
19
  // interface IPs and its hostname — while a different port and the public internet stay open. The earlier
20
20
  // `localhost:<port>` literal did NOT cover [::ffff:127.0.0.1] (a verified full bypass of the whole layer on the
21
21
  // dual-stack listener): Seatbelt's `localhost` resolves to 127.0.0.1 + ::1 only. The host literal must be `*`
22
- // or `localhost` (a numeric IP literal is rejected by the parser); `*` is the only form that is address-proof.
22
+ // or `localhost` (a numeric IP literal, with or without a CIDR suffix, is rejected by the parser: "host must be
23
+ // * or localhost in network address"); `*` is the only form that is address-proof.
23
24
  // Seatbelt has no port-range syntax (`*:4120-4400` is rejected), so a reserved range is emitted one port a line.
24
25
  // • `(deny file-read* file-write* (subpath "<canonical>"))` blocks reads AND writes under a path; a later
25
26
  // `(allow file-read* file-write* (subpath "<canonical>"))` wins (Seatbelt is last-match-wins within a filter),
26
27
  // so SynaBun's whole data home can be denied and the run's own scratch / cwd / config folder allowed back after
27
28
  // it. Seatbelt matches the RESOLVED path, so every literal must be canonicalised (/tmp is a symlink to
28
29
  // /private/tmp; an un-resolved literal never matches, and an allow-back must resolve the same way as its deny).
30
+ // • macOS 27 (27.2 / 26B123, confirmed with scratch sandbox-exec probes outside the repo, 2026-11-01): a
31
+ // `(deny network-outbound (remote ip …))` rule placed textually AFTER an `(allow network-outbound (remote ip
32
+ // …))` rule silently defeats that allow — even when the deny's port is completely unrelated to the allow's
33
+ // (e.g. a later `deny *:4096` broke an earlier `allow localhost:9` for a different, unrelated port 9). This
34
+ // held on every literal form tried (`localhost` and `*` alike), so it is not about the host literal at all —
35
+ // it is purely textual position. A deny is never undone by what comes after it, and a later allow for one port
36
+ // never reopens a different, already-denied port — only "deny AFTER allow, different port" misbehaves. A
37
+ // same-port pair (a broad `*:<port>` allow immediately followed by a narrower `localhost:<port>` deny, the
38
+ // INTERNET_PORTS local-redeny below) still narrows correctly on 27.2: last-match-wins for an overlapping
39
+ // filter is unaffected, confirmed by direct probe. The fix is purely about ORDER, so buildWorkerSandboxProfile
40
+ // emits every plain port/range deny FIRST, then the strict profile's own allow-then-narrow pair for
41
+ // INTERNET_PORTS, then the worker-channel allow(s) dead last among network-outbound rules — nothing (deny)
42
+ // ever follows them, on macOS 26 or 27. This does not widen anything: the channel allow keeps the narrow
43
+ // `localhost:<port>` literal (still local-only on both macOS versions), and the reorder also fixes a second,
44
+ // previously-undetected collateral regression — the strict profile's own INTERNET_PORTS allow-back (meant to
45
+ // keep DNS/SSH/HTTP/HTTPS reachable on real remote hosts) was equally defeated by the later control-port and
46
+ // reserved-range denies that used to sit between it and nothing; a guarded worker in the strict fallback had
47
+ // silently lost the public internet too.
29
48
  // • The sandbox is inherited by detached / nohup grandchildren, so a worker cannot escape it by backgrounding.
30
49
  // • A same-user `KERN_PROCARGS2` read (ps -E / a tiny C program) CANNOT be blocked by Seatbelt (it is a same-uid
31
50
  // kernel allowance, not a sandbox-governed operation). So a worker inside the sandbox can still read another
@@ -166,6 +185,10 @@ function metadataAncestors(allowPaths, denyPaths) {
166
185
  * spelling (the IPv4-mapped one included); Seatbelt's `localhost` misses [::ffff:…],
167
186
  * and mixing `ip6` rules with `localhost` ones silently re-opens IPv4 loopback (verified
168
187
  * on macOS 26), so this is written as deny-all-then-allow, never as a loopback deny.
188
+ * On macOS 27 a later deny for an unrelated port defeats an earlier allow (see the
189
+ * module header), so every network-outbound ALLOW rule this emits — the strict
190
+ * profile's INTERNET_PORTS allow-back and the channel allow(s) — is placed after
191
+ * every plain port/range deny, with the channel allow(s) last of all.
169
192
  * @param {string} [o.note] a short comment line (the run id), for readability in a log.
170
193
  * @returns {string} the profile text (ends with a newline).
171
194
  */
@@ -177,34 +200,41 @@ export function buildWorkerSandboxProfile({ denyPorts = [], denyLocalPorts = [],
177
200
  ? { from: Math.max(1, Number(denyPortRange.from)), to: Math.min(65535, Number(denyPortRange.to)) } : null;
178
201
  const denies = [...new Set((denyPaths || []).filter((p) => typeof p === 'string' && p).map(canonicalPath))];
179
202
  const allows = [...new Set((allowPaths || []).filter((p) => typeof p === 'string' && p).map(canonicalPath))];
203
+ const channelPorts = strictLocal ? cleanPorts(strictLocal.allowPorts) : [];
180
204
  const lines = ['(version 1)'];
181
205
  if (note) lines.push(`; ${String(note).replace(/[\r\n]+/g, ' ').slice(0, 200)}`);
182
206
  lines.push('(allow default)');
183
207
  if (strictLocal) {
184
208
  // Detection failed: nothing local is known to be safe, so nothing local is reachable but the worker channel.
185
- // Deny every outbound IP connection, allow the internet's ports back on every host, take them away again on this
186
- // computer's own addresses, and allow the channel last (last match wins).
187
209
  lines.push('; strict: the relay detection failed for this run, so no local port is reachable but the worker channel');
188
210
  lines.push(`(deny network-outbound (remote ip ${sexpr('*:*')}))`);
189
- for (const port of INTERNET_PORTS) lines.push(`(allow network-outbound (remote ip ${sexpr(`*:${port}`)}))`);
190
- for (const port of INTERNET_PORTS) if (port !== 53) localOnly.add(port); // a local DNS resolver stays reachable
191
- for (const port of cleanPorts(strictLocal.allowPorts)) {
192
- localOnly.delete(port);
193
- lines.push(`(allow network-outbound (remote ip ${sexpr(`localhost:${port}`)}))`);
194
- }
195
211
  }
196
- // The control ports: a worker's own programs may not open them (its MCP tools are the way in). `*:<port>` blocks
197
- // the port on every address (127.0.0.1, ::1, [::ffff:127.0.0.1], 0.0.0.0, the LAN IPs, the hostname); the public
198
- // internet and every other port stay open.
212
+ // The control ports and the reserved relay range FIRST, before any allow rule below: on macOS 27 a later deny
213
+ // here would defeat an earlier allow for an unrelated port (module header). A plain deny is never undone by
214
+ // what follows it, so their own position relative to each other never matters.
199
215
  const seen = new Set();
200
216
  for (const port of ports) { seen.add(port); lines.push(`(deny network-outbound (remote ip ${sexpr(`*:${port}`)}))`); }
201
- // Local-only denies (an internet port a relay holds here, local SSH): this computer's own addresses, never the internet.
217
+ // The reserved relay range in full: every isolated OpenCode serve, whether it started before or after this profile.
218
+ if (range) for (let p = range.from; p <= range.to; p++) { if (!seen.has(p)) { seen.add(p); lines.push(`(deny network-outbound (remote ip ${sexpr(`*:${p}`)}))`); } }
219
+ if (strictLocal) {
220
+ // Allow the internet's ports back on every host, then narrow them to this computer's own addresses right
221
+ // after (same port: last-match-wins narrows it locally, unaffected by the macOS 27 ordering issue above,
222
+ // which is about an unrelated port's deny, not a same-port narrowing pair).
223
+ for (const port of INTERNET_PORTS) if (port !== 53) localOnly.add(port); // a local DNS resolver stays reachable
224
+ for (const port of channelPorts) localOnly.delete(port);
225
+ for (const port of INTERNET_PORTS) lines.push(`(allow network-outbound (remote ip ${sexpr(`*:${port}`)}))`);
226
+ }
227
+ // Local-only denies (an internet port a relay holds here, local SSH): this computer's own addresses, never the
228
+ // internet. In strict mode these sit right after the INTERNET_PORTS allow-back above (the same-port narrowing
229
+ // pair); otherwise there is no preceding allow to narrow and the position carries no ordering requirement.
202
230
  for (const port of [...new Set([...localOnly, ...ALWAYS_LOCAL_DENY_PORTS])].sort((x, y) => x - y)) {
203
- if (strictLocal && cleanPorts(strictLocal.allowPorts).includes(port)) continue;
231
+ if (channelPorts.includes(port)) continue;
204
232
  lines.push(`(deny network-outbound (remote ip ${sexpr(`localhost:${port}`)}))`);
205
233
  }
206
- // The reserved relay range in full: every isolated OpenCode serve, whether it started before or after this profile.
207
- if (range) for (let p = range.from; p <= range.to; p++) { if (!seen.has(p)) { seen.add(p); lines.push(`(deny network-outbound (remote ip ${sexpr(`*:${p}`)}))`); } }
234
+ // The worker channel, allowed dead last among every network-outbound rule above: on macOS 27 any later deny —
235
+ // even for a wholly unrelated port — would silently defeat this allow (module header). Kept local-only
236
+ // (`localhost:<port>`, not `*:<port>`): still unreachable from a remote host on this exact port, on macOS 26 and 27.
237
+ for (const port of channelPorts) lines.push(`(allow network-outbound (remote ip ${sexpr(`localhost:${port}`)}))`);
208
238
  // SynaBun's whole data home (its auth secrets, other runs' task text, the memory DB) and other runtimes' creds:
209
239
  // a worker neither reads nor writes them.
210
240
  for (const path of denies) lines.push(`(deny file-read* file-write* (subpath ${sexpr(path)}))`);
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "neural-memory-interface",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "neural-memory-interface",
9
- "version": "2.1.0",
9
+ "version": "2.2.1",
10
10
  "hasInstallScript": true,
11
11
  "license": "Apache-2.0",
12
12
  "dependencies": {
13
+ "@agentclientprotocol/sdk": "2.2.0",
13
14
  "@anthropic-ai/claude-agent-sdk": "0.3.288",
14
15
  "@huggingface/transformers": "^3.0.0",
15
16
  "@openai/codex-sdk": "^0.160.0",
@@ -57,6 +58,21 @@
57
58
  "node": ">=22.19.0"
58
59
  }
59
60
  },
61
+ "node_modules/@agentclientprotocol/sdk": {
62
+ "version": "2.2.0",
63
+ "resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-2.2.0.tgz",
64
+ "integrity": "sha512-o1+eDQVb05yzPY+5v54awHyONU1oeLsbLVavkwrMQaZDuJDh/38pQiXJS4ix4d6QA3Y4bU0lHFRjwg99KKKSaQ==",
65
+ "license": "Apache-2.0",
66
+ "peerDependencies": {
67
+ "@modelcontextprotocol/server": "^2.4.0",
68
+ "zod": "^3.25.76 || ^4.0.0"
69
+ },
70
+ "peerDependenciesMeta": {
71
+ "@modelcontextprotocol/server": {
72
+ "optional": true
73
+ }
74
+ }
75
+ },
60
76
  "node_modules/@antfu/install-pkg": {
61
77
  "version": "2.1.0",
62
78
  "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-2.1.0.tgz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neural-memory-interface",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "private": true,
5
5
  "description": "Private local SynaBun interface for memory visualization and multi-agent workflows",
6
6
  "license": "Apache-2.0",
@@ -21,6 +21,7 @@
21
21
  "postinstall": "node scripts/rebuild-pty.js && node scripts/build-vendor.mjs"
22
22
  },
23
23
  "dependencies": {
24
+ "@agentclientprotocol/sdk": "2.2.0",
24
25
  "@anthropic-ai/claude-agent-sdk": "0.3.288",
25
26
  "@huggingface/transformers": "^3.0.0",
26
27
  "@openai/codex-sdk": "^0.160.0",
@@ -1489,7 +1489,7 @@ const wizardState = {
1489
1489
  // `id` is also the host name of the rules API (/api/setup/rules/:host).
1490
1490
  const TOOLS = [
1491
1491
  { id: 'claude', name: 'Claude Code', api: '/api/claude-code/mcp', configPath: '~/.claude.json' },
1492
- { id: 'gemini', name: 'Gemini CLI', api: '/api/setup/gemini/mcp', configPath: '~/.gemini/settings.json' },
1492
+ { id: 'antigravity', name: 'Antigravity CLI', api: '/api/setup/antigravity/mcp', configPath: '~/.gemini/config/mcp_config.json' },
1493
1493
  { id: 'codex', name: 'Codex CLI', api: '/api/setup/codex/mcp', configPath: '~/.codex/config.toml' },
1494
1494
  { id: 'opencode', name: 'OpenCode', api: '/api/opencode/mcp', configPath: '~/.config/opencode/opencode.json' },
1495
1495
  ];
@@ -6,16 +6,36 @@ import { fetchOpencodeProviders, opencodeProviders } from './opencode-providers.
6
6
  export const CLI_PROFILES = [
7
7
  { id: 'claude-code', label: 'Claude Code', desc: 'Anthropic' },
8
8
  { id: 'codex', label: 'Codex CLI', desc: 'OpenAI' },
9
- { id: 'gemini', label: 'Gemini CLI', desc: 'Google' },
9
+ { id: 'antigravity', label: 'Antigravity CLI', desc: 'Google' },
10
10
  { id: 'opencode', label: 'OpenCode CLI', desc: 'Multi-provider' },
11
11
  ];
12
12
 
13
- const STATIC_MODELS = {
14
- gemini: [
15
- { id: 'gemini-2.5-pro', label: '2.5 Pro', desc: 'Most capable', tier: 'default' },
16
- { id: 'gemini-2.5-flash', label: '2.5 Flash', desc: 'Lightweight' },
17
- ],
18
- };
13
+ // Google Antigravity replaced the Gemini CLI (provider id `gemini` → `antigravity`). What was saved before
14
+ // (a launch profile, a resume tab, a template's CLI or icon) can still say `gemini`: it reads as Antigravity.
15
+ // The server moves its own files the same way (lib/antigravity/migrate-gemini.js).
16
+ export function migrateProviderId(id) { return id === 'gemini' ? 'antigravity' : id; }
17
+
18
+ // The Gemini CLI's own model ids (gemini-1.x, gemini-2.x) are not Antigravity's: one saved for it reads as
19
+ // none, so Antigravity's default runs (the same rule as isGeminiCliModel in lib/antigravity/migrate-gemini.js).
20
+ const GEMINI_CLI_MODEL_RE = /^gemini-[12](?:[.-]|$)/i;
21
+ export function migrateProviderModel(profileId, model) {
22
+ return migrateProviderId(profileId) === 'antigravity' && typeof model === 'string' && GEMINI_CLI_MODEL_RE.test(model.trim()) ? null : model;
23
+ }
24
+
25
+ /** Saved launch records (loop templates, schedules, groups, timers) with a Gemini CLI profile or icon read as Antigravity's. */
26
+ export function migrateLaunchRecords(list) {
27
+ if (!Array.isArray(list)) return list;
28
+ return list.map((record) => {
29
+ if (!record || typeof record !== 'object' || (record.profile !== 'gemini' && record.icon !== 'gemini')) return record;
30
+ const next = { ...record };
31
+ if (next.icon === 'gemini') next.icon = migrateProviderId(next.icon);
32
+ if (next.profile === 'gemini') {
33
+ next.profile = migrateProviderId(next.profile);
34
+ if (migrateProviderModel(next.profile, next.model) !== next.model) next.model = null;
35
+ }
36
+ return next;
37
+ });
38
+ }
19
39
 
20
40
  // Claude Code models are discovered live from the installed CLI via
21
41
  // /api/claude/models (see lib/claude-model-catalog.js) — the CLI is the only
@@ -59,6 +79,15 @@ export const EFFORT_LEVELS_BY_PROFILE = {
59
79
  { id: 'max', label: 'Max', desc: 'Maximum' },
60
80
  { id: 'ultra', label: 'Ultra', desc: 'Maximum, with delegation', tier: 'top' },
61
81
  ],
82
+ // The levels `agy --effort` takes; `off` passes none, so Antigravity uses its own default.
83
+ antigravity: [
84
+ { id: 'off', label: 'Default', desc: 'Model default' },
85
+ { id: 'low', label: 'Low', desc: 'Light' },
86
+ { id: 'medium', label: 'Med', desc: 'Balanced' },
87
+ { id: 'high', label: 'High', desc: 'Deep' },
88
+ { id: 'xhigh', label: 'XHigh', desc: 'Very deep' },
89
+ { id: 'max', label: 'Max', desc: 'Maximum', tier: 'top' },
90
+ ],
62
91
  };
63
92
 
64
93
  // One effort vocabulary, lowest first (the server keeps the same table in
@@ -145,14 +174,16 @@ let _opencodeModelsCache = null;
145
174
  let _opencodeModelsLoading = null;
146
175
  let _claudeModelsCache = null;
147
176
  let _claudeModelsLoading = null;
177
+ let _antigravityModelsCache = null;
178
+ let _antigravityModelsLoading = null;
148
179
  let _toolCatalog = null;
149
180
  const _toolCatalogLoads = new Map();
150
181
  const _toolCatalogByCwd = new Map();
151
182
  const _toolCatalogAt = new Map();
152
183
  let _toolCatalogEpoch = 0;
153
184
 
154
- // The verified Claude and Codex lists are also kept in sessionStorage (this tab only): after a reload the
155
- // pickers paint from them at once (a list read back is due, so the first load still asks the server).
185
+ // The verified Claude, Codex and Antigravity lists are also kept in sessionStorage (this tab only): after a reload
186
+ // the pickers paint from them at once (a list read back is due, so the first load still asks the server).
156
187
  const LIST_STORE_PREFIX = 'synabun:runtime-models:v1:';
157
188
  function keepList(key, list) {
158
189
  try { if (typeof sessionStorage !== 'undefined') sessionStorage.setItem(LIST_STORE_PREFIX + key, JSON.stringify(list)); } catch { /* full or unavailable */ }
@@ -169,6 +200,8 @@ function keptList(key) {
169
200
  if (claude && !_claudeModelsCache) _claudeModelsCache = claude;
170
201
  const codex = keptList('codex:default');
171
202
  if (codex && !_codexModelsCache.has('default')) _codexModelsCache.set('default', codex);
203
+ const antigravity = keptList('antigravity');
204
+ if (antigravity && !_antigravityModelsCache) _antigravityModelsCache = antigravity;
172
205
  })();
173
206
 
174
207
  function localJsonArray(key) {
@@ -538,16 +571,59 @@ export async function fetchClaudeModels(force = false) {
538
571
  return _claudeModelsLoading;
539
572
  }
540
573
 
574
+ // GET /api/antigravity/models answers { models: [{ id, label, description?, default? }], source: 'live' | 'unavailable' }.
575
+ function antigravityModelOption(model) {
576
+ const id = String(model?.id || '').trim();
577
+ if (!id) return null;
578
+ return {
579
+ id,
580
+ provider: 'antigravity',
581
+ cliReady: true,
582
+ label: String(model.label || id),
583
+ desc: String(model.description || ''),
584
+ ...(model.default === true ? { tier: 'default', isDefault: true } : {}),
585
+ };
586
+ }
587
+
588
+ // Antigravity's models come only from the installed `agy`: there is no list of SynaBun's own to fall back on,
589
+ // so until it answers the pickers are empty and a launch runs Antigravity's default. A list it gave once is
590
+ // kept through a failed or unavailable answer.
591
+ export async function fetchAntigravityModels(force = false) {
592
+ if (!force && _antigravityModelsCache?.length && modelListIsFresh('antigravity')) return _antigravityModelsCache;
593
+ if (_antigravityModelsLoading) return _antigravityModelsLoading;
594
+ _antigravityModelsLoading = (async () => {
595
+ try {
596
+ const resp = await fetch('/api/antigravity/models');
597
+ const data = await resp.json().catch(() => ({}));
598
+ const models = resp.ok && data?.source !== 'unavailable' && Array.isArray(data?.models)
599
+ ? data.models.map(antigravityModelOption).filter(Boolean)
600
+ : [];
601
+ if (models.length) {
602
+ _antigravityModelsCache = models;
603
+ _modelListAt.set('antigravity', Date.now());
604
+ keepList('antigravity', models);
605
+ }
606
+ return _antigravityModelsCache || [];
607
+ } catch {
608
+ return _antigravityModelsCache || [];
609
+ } finally {
610
+ _antigravityModelsLoading = null;
611
+ }
612
+ })();
613
+ return _antigravityModelsLoading;
614
+ }
615
+
541
616
  // Profiles whose model list is fetched at runtime rather than baked in. Callers use
542
617
  // this to decide whether to kick off an async load and re-render when it lands.
543
618
  export function isDynamicModelProfile(profileId) {
544
- return profileId === 'opencode' || profileId === 'codex' || profileId === 'claude-code';
619
+ return profileId === 'opencode' || profileId === 'codex' || profileId === 'claude-code' || profileId === 'antigravity';
545
620
  }
546
621
 
547
622
  export async function ensureModelsForProfile(profileId, force = false, accountId = 'default') {
548
623
  if (profileId === 'codex') return fetchCodexModels(force, accountId);
549
624
  if (profileId === 'opencode') return fetchOpencodeModels(force);
550
625
  if (profileId === 'claude-code') return fetchClaudeModels(force);
626
+ if (profileId === 'antigravity') return fetchAntigravityModels(force);
551
627
  return getModelsForProfile(profileId, accountId);
552
628
  }
553
629
 
@@ -565,7 +641,8 @@ export function getModelsForProfile(profileId, accountId = 'default') {
565
641
  if (profileId === 'codex') return _codexModelsCache.get(String(accountId || 'default')) || [];
566
642
  if (profileId === 'opencode') return _opencodeModelsCache || keptOpencodeModels() || [];
567
643
  if (profileId === 'claude-code') return _claudeModelsCache || [];
568
- return STATIC_MODELS[profileId] || [];
644
+ if (profileId === 'antigravity') return _antigravityModelsCache || [];
645
+ return [];
569
646
  }
570
647
 
571
648
  // Live Claude and Codex options are spawn-ready ids. Only legacy Claude options
@@ -678,6 +755,7 @@ export function clearRuntimeOptionCaches() {
678
755
  _opencodeModelsCache = null;
679
756
  opencodeProviders.invalidate('');
680
757
  _claudeModelsCache = null;
758
+ _antigravityModelsCache = null;
681
759
  _modelListAt.clear();
682
760
  invalidateToolCatalog(); _toolCatalog = null; _toolCatalogByCwd.clear(); _toolCatalogAt.clear();
683
761
  _claudeAccountsCache = null;
@@ -0,0 +1,47 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Antigravity panel: a tab's Bypass (no DOM)
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Bypass is a tab's choice, like the Claude Code panel's: off by default, turned on only by the owner in the
6
+ // permissions picker (after one confirm each time), saved with the tab, and stated to the bridge with every session
7
+ // the tab opens (`bypass` on session:new / load / resume) and at once for a running one (session:bypass). The bridge
8
+ // answers each permission request of that session "allow once" itself, except what SynaBun's hard rails refuse
9
+ // (lib/antigravity/bypass.js: the browser policy and the protected folders). A server without the `bypass`
10
+ // capability cannot run it: the pick waits there, shown as unavailable, and the tab asks as before.
11
+
12
+ export const PERMISSION_DEFAULT = 'default';
13
+ export const PERMISSION_BYPASS = 'bypass';
14
+
15
+ /** The permissions picker of a tab: its entries, the state the control is styled by and its tooltip. */
16
+ export function bypassControl({ bypass = false, supported = true } = {}, T = (key) => key) {
17
+ const on = bypass === true;
18
+ const entries = [
19
+ { value: PERMISSION_DEFAULT, label: T('permDefault'), title: T('permDefaultHint'), selected: !on },
20
+ { value: PERMISSION_BYPASS, label: T('permBypass'), title: supported ? T('permBypassHint') : T('permBypassRestart'), selected: on, disabled: !supported && !on },
21
+ ];
22
+ if (on && !supported) return { entries, state: 'bypass', waiting: true, title: T('permBypassWaiting') };
23
+ if (on) return { entries, state: 'bypass', waiting: false, title: T('permBypassOnTitle') };
24
+ return { entries, state: '', waiting: false, title: supported ? T('permDefaultHint') : T('permBypassRestart') };
25
+ }
26
+
27
+ /** What a pick in the picker does: { confirm: true } to ask first, { set: boolean } to apply, or null for no change. */
28
+ export function pickPermission(value, { bypass = false, supported = true } = {}) {
29
+ const want = value === PERMISSION_BYPASS;
30
+ if (want === (bypass === true)) return null;
31
+ if (want && !supported) return null;
32
+ return want ? { confirm: true } : { set: false };
33
+ }
34
+
35
+ /** A saved tab's Bypass: only a literal true counts (anything else in storage is off). */
36
+ export function restoredBypass(value) {
37
+ return value === true;
38
+ }
39
+
40
+ /** A permission:auto event as one transcript row: { severity, text }. */
41
+ export function autoAnswerRow(message, T = (key) => key) {
42
+ const tool = String(message?.toolCall?.title || message?.toolCall?.kind || T('permTool')).slice(0, 160);
43
+ if (message?.decision === 'refused') {
44
+ return { severity: 'error', text: T('permAutoRefused', { tool, reason: String(message.reason || '').slice(0, 400) }) };
45
+ }
46
+ return { severity: 'info', text: T('permAutoAllowed', { tool }) };
47
+ }