synabun 2.1.0 → 2.2.0

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 (317) hide show
  1. package/CHANGELOG.md +121 -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 +501 -39
  71. package/neural-interface/i18n/pt-BR.json +501 -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-budget-planner.js +7 -3
  88. package/neural-interface/lib/assistant-budget-split.js +42 -15
  89. package/neural-interface/lib/assistant-catalog.js +76 -9
  90. package/neural-interface/lib/assistant-config.js +6 -3
  91. package/neural-interface/lib/assistant-dispatch.js +207 -49
  92. package/neural-interface/lib/assistant-envelope.js +153 -1
  93. package/neural-interface/lib/assistant-evidence.js +80 -0
  94. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  95. package/neural-interface/lib/assistant-persona.js +16 -11
  96. package/neural-interface/lib/assistant-plan-permissions.js +15 -0
  97. package/neural-interface/lib/assistant-router.js +237 -35
  98. package/neural-interface/lib/assistant-runtime.js +158 -12
  99. package/neural-interface/lib/assistant-task-prompt.js +10 -8
  100. package/neural-interface/lib/assistant-tools.js +2 -2
  101. package/neural-interface/lib/assistant-usage.js +29 -0
  102. package/neural-interface/lib/backup-service.js +6 -1
  103. package/neural-interface/lib/browser-guard-cdp.js +5 -4
  104. package/neural-interface/lib/browser-network-guard.js +274 -82
  105. package/neural-interface/lib/browser-tool-policy.js +12 -7
  106. package/neural-interface/lib/claude-agent-bridge.js +7 -0
  107. package/neural-interface/lib/claude-history-cache.js +210 -0
  108. package/neural-interface/lib/claude-model-catalog.js +5 -1
  109. package/neural-interface/lib/cli-install-api.js +1 -1
  110. package/neural-interface/lib/cli-install.js +160 -31
  111. package/neural-interface/lib/cli-resolver.js +9 -2
  112. package/neural-interface/lib/cli-update-planner.js +25 -15
  113. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  114. package/neural-interface/lib/codex-worker-app-server.js +25 -6
  115. package/neural-interface/lib/editor-git-api.js +3 -20
  116. package/neural-interface/lib/exec-loop-command.js +9 -2
  117. package/neural-interface/lib/file-explorer-api.js +74 -40
  118. package/neural-interface/lib/file-explorer-watch.js +9 -3
  119. package/neural-interface/lib/git-bash/install.js +52 -6
  120. package/neural-interface/lib/git-bash/manager.js +59 -17
  121. package/neural-interface/lib/git-bash/pins.js +12 -0
  122. package/neural-interface/lib/git-read.js +2 -2
  123. package/neural-interface/lib/git-status-runner.js +390 -0
  124. package/neural-interface/lib/git-status-watchdog.js +40 -0
  125. package/neural-interface/lib/greeting/budgets.js +1 -0
  126. package/neural-interface/lib/greeting/engine.js +2 -2
  127. package/neural-interface/lib/greeting/sources.js +10 -12
  128. package/neural-interface/lib/greeting/writer.js +1 -1
  129. package/neural-interface/lib/mcp-client-config.js +37 -6
  130. package/neural-interface/lib/mcp-external-servers.js +13 -4
  131. package/neural-interface/lib/mcp-installer.js +2 -1
  132. package/neural-interface/lib/memory-session-capture.js +17 -3
  133. package/neural-interface/lib/morelogin.js +147 -25
  134. package/neural-interface/lib/native-loop-providers.js +420 -21
  135. package/neural-interface/lib/native-loop-runtime.js +23 -2
  136. package/neural-interface/lib/opencode-native-boundary.js +11 -2
  137. package/neural-interface/lib/owner-authority.js +1 -1
  138. package/neural-interface/lib/path-confine.js +12 -9
  139. package/neural-interface/lib/peer-identity.js +32 -2
  140. package/neural-interface/lib/pty-host/core.js +28 -1
  141. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  142. package/neural-interface/lib/pty-host/manager.js +12 -1
  143. package/neural-interface/lib/remote-policy.js +1 -1
  144. package/neural-interface/lib/request-gate.js +3 -0
  145. package/neural-interface/lib/rulesets/api.js +6 -5
  146. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  147. package/neural-interface/lib/rulesets/installer.js +89 -10
  148. package/neural-interface/lib/rulesets/render.js +1 -1
  149. package/neural-interface/lib/session-cache-builder.js +64 -1
  150. package/neural-interface/lib/skills/catalog.js +5 -1
  151. package/neural-interface/lib/skills/creation-brief.js +1 -1
  152. package/neural-interface/lib/skills/creation-sources.js +19 -1
  153. package/neural-interface/lib/skills/deploy.js +9 -4
  154. package/neural-interface/lib/skills/draft-confinement.js +3 -1
  155. package/neural-interface/lib/skills/eval-confinement.js +3 -1
  156. package/neural-interface/lib/skills/eval-trace.js +16 -0
  157. package/neural-interface/lib/skills/export.js +5 -2
  158. package/neural-interface/lib/skills/known-bridge-digests.json +58 -4
  159. package/neural-interface/lib/skills/ownership.js +1 -1
  160. package/neural-interface/lib/skills/roots.js +10 -3
  161. package/neural-interface/lib/skills/runtime-checks.js +6 -3
  162. package/neural-interface/lib/skills/service.js +15 -7
  163. package/neural-interface/lib/skills/telemetry.js +6 -0
  164. package/neural-interface/lib/synabun-version.js +1 -1
  165. package/neural-interface/lib/system-activity.js +1 -1
  166. package/neural-interface/lib/whatsapp/brain.js +7 -3
  167. package/neural-interface/lib/whatsapp/cards.js +22 -9
  168. package/neural-interface/lib/whatsapp/config.js +1 -1
  169. package/neural-interface/lib/worker-confinement.js +77 -1
  170. package/neural-interface/lib/worker-question.js +74 -0
  171. package/neural-interface/lib/worker-resume.js +13 -4
  172. package/neural-interface/lib/worker-sandbox.js +46 -16
  173. package/neural-interface/package-lock.json +18 -2
  174. package/neural-interface/package.json +2 -1
  175. package/neural-interface/public/onboarding.html +1 -1
  176. package/neural-interface/public/shared/agent-runtime-options.js +89 -11
  177. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  178. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  179. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  180. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  181. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  182. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  183. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  184. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  185. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  186. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  187. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  188. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  189. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  190. package/neural-interface/public/shared/api.js +4 -4
  191. package/neural-interface/public/shared/assistant/asst-agents-dock.js +3 -4
  192. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  193. package/neural-interface/public/shared/assistant/asst-brain-picker.js +56 -9
  194. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  195. package/neural-interface/public/shared/assistant/asst-control.js +48 -0
  196. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  197. package/neural-interface/public/shared/assistant/asst-limit-dock.js +6 -1
  198. package/neural-interface/public/shared/assistant/asst-limit-wait.js +38 -5
  199. package/neural-interface/public/shared/assistant/asst-panel.js +45 -8
  200. package/neural-interface/public/shared/assistant/asst-render.js +51 -12
  201. package/neural-interface/public/shared/assistant/asst-route.js +237 -57
  202. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  203. package/neural-interface/public/shared/assistant/asst-scenes.js +54 -1
  204. package/neural-interface/public/shared/assistant/asst-sidepanel.js +51 -7
  205. package/neural-interface/public/shared/assistant/asst-slash.js +8 -2
  206. package/neural-interface/public/shared/assistant/asst-state.js +76 -9
  207. package/neural-interface/public/shared/assistant/asst-styles.js +34 -0
  208. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +34 -7
  209. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  210. package/neural-interface/public/shared/cdx/cdx-output.js +26 -3
  211. package/neural-interface/public/shared/cdx/cdx-panel.js +14 -2
  212. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  213. package/neural-interface/public/shared/cdx/cdx-protocol.js +11 -10
  214. package/neural-interface/public/shared/cdx/cdx-render.js +10 -9
  215. package/neural-interface/public/shared/cdx/cdx-requests.js +11 -1
  216. package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
  217. package/neural-interface/public/shared/cdx/cdx-tabs.js +75 -5
  218. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  219. package/neural-interface/public/shared/cli-install-view.js +7 -4
  220. package/neural-interface/public/shared/cli-status.js +9 -8
  221. package/neural-interface/public/shared/constants.js +3 -2
  222. package/neural-interface/public/shared/context-menu-model.js +1 -0
  223. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  224. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  225. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  226. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  227. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  228. package/neural-interface/public/shared/desktop-update-view.js +1 -0
  229. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  230. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  231. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  232. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  233. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  234. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  235. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  236. package/neural-interface/public/shared/html-shell.js +21 -4
  237. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +27 -7
  238. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  239. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
  240. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -0
  241. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +46 -3
  242. package/neural-interface/public/shared/provider-icons.js +4 -2
  243. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  244. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +1 -1
  245. package/neural-interface/public/shared/settings/settings-skill-folders.js +2 -2
  246. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  247. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  248. package/neural-interface/public/shared/skills/ss-creation.js +6 -3
  249. package/neural-interface/public/shared/skills/ss-dialog.js +5 -2
  250. package/neural-interface/public/shared/skills/ss-lint.js +9 -1
  251. package/neural-interface/public/shared/skills/ss-profiles.js +44 -6
  252. package/neural-interface/public/shared/skills/ss-review-view.js +2 -2
  253. package/neural-interface/public/shared/skills/studio/sx-actions.js +1 -1
  254. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +1 -1
  255. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +2 -1
  256. package/neural-interface/public/shared/skills/studio/sx-dom.js +2 -1
  257. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  258. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  259. package/neural-interface/public/shared/skills/studio/sx-inspector.js +1 -1
  260. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +9 -6
  261. package/neural-interface/public/shared/skills/studio/sx-install.js +20 -3
  262. package/neural-interface/public/shared/skills/studio/sx-library-view.js +144 -35
  263. package/neural-interface/public/shared/skills/studio/sx-library.js +6 -2
  264. package/neural-interface/public/shared/skills/studio/sx-main.js +11 -2
  265. package/neural-interface/public/shared/skills/studio/sx-review-view.js +1 -1
  266. package/neural-interface/public/shared/skills/studio/sx-subject.js +7 -6
  267. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +6 -5
  268. package/neural-interface/public/shared/state.js +1 -1
  269. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  270. package/neural-interface/public/shared/styles.css +354 -34
  271. package/neural-interface/public/shared/text-cache.js +29 -0
  272. package/neural-interface/public/shared/tool-list-picker.js +2 -2
  273. package/neural-interface/public/shared/tool-list-view.js +2 -2
  274. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  275. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  276. package/neural-interface/public/shared/ui-assistant.js +2 -0
  277. package/neural-interface/public/shared/ui-automation-studio.js +20 -12
  278. package/neural-interface/public/shared/ui-claude-panel.js +299 -77
  279. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  280. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  281. package/neural-interface/public/shared/ui-file-links.js +2 -2
  282. package/neural-interface/public/shared/ui-games.js +2 -2
  283. package/neural-interface/public/shared/ui-judgments.js +1 -1
  284. package/neural-interface/public/shared/ui-keybinds.js +8 -2
  285. package/neural-interface/public/shared/ui-link.js +3 -3
  286. package/neural-interface/public/shared/ui-menubar.js +2 -2
  287. package/neural-interface/public/shared/ui-native-loop-router.js +4 -0
  288. package/neural-interface/public/shared/ui-navbar.js +45 -0
  289. package/neural-interface/public/shared/ui-notifications.js +1 -0
  290. package/neural-interface/public/shared/ui-resume.js +9 -7
  291. package/neural-interface/public/shared/ui-schedules-studio.js +41 -10
  292. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  293. package/neural-interface/public/shared/ui-sessions.js +22 -12
  294. package/neural-interface/public/shared/ui-settings.js +90 -65
  295. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  296. package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -3
  297. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  298. package/neural-interface/public/shared/ui-sidepanel-windows.js +3 -3
  299. package/neural-interface/public/shared/ui-terminal.js +146 -10
  300. package/neural-interface/public/shared/ui-tool-updates.js +3 -3
  301. package/neural-interface/public/shared/ui-tooltip.js +71 -46
  302. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  303. package/neural-interface/public/shared/ui-whiteboard.js +1 -1
  304. package/neural-interface/public/shared/ui-worker-end.js +1 -1
  305. package/neural-interface/public/shared/whatsapp/wa-view.js +2 -2
  306. package/neural-interface/public/shared/worker-questions.js +34 -0
  307. package/neural-interface/public/sidepanel-session.html +1 -1
  308. package/neural-interface/server.js +644 -426
  309. package/neural-interface/templates/rulesets/README.md +1 -1
  310. package/neural-interface/templates/rulesets/legacy-hashes.json +5 -5
  311. package/neural-interface/templates/rulesets/manifest.json +1 -1
  312. package/npm-shrinkwrap.json +18 -2
  313. package/package.json +2 -1
  314. package/skills/skill-forge/SKILL.md +4 -4
  315. package/skills/synabun/SKILL.md +1 -1
  316. package/skills/synabun/modules/schedule.md +3 -3
  317. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -0,0 +1,299 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — one Antigravity agent process, spoken to over ACP
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Google Antigravity's CLI (`agy`) has no Node SDK. What it offers a program
6
+ // is the Agent Client Protocol: `agy acp` is Google's "Antigravity ACP Server",
7
+ // JSON-RPC 2.0 over stdio, one JSON message per line (initialize, authenticate,
8
+ // session/new|load|list|resume|close|prompt|cancel|set_mode|set_model|
9
+ // set_config_option, and the agent's own session/update notifications and
10
+ // session/request_permission requests). This module starts that process and
11
+ // speaks the protocol through the protocol's official TypeScript SDK
12
+ // (@agentclientprotocol/sdk, its `unstable` surface: session/set_model and the
13
+ // per-turn `usage` of a prompt answer are not in the stable one yet).
14
+ //
15
+ // createAcpConnection(spec) starts `<command> ...args acp ...acpArgs`, answers at once
16
+ // .initialize(extra?) the agent's capabilities, auth methods, version
17
+ // .request(method, params) any agent method; rejects with the agent's error
18
+ // .notify(method, params) session/cancel and the like
19
+ // .close() ends the process (SIGTERM, then SIGKILL)
20
+ // .exited resolves { code, signal } once the process is gone
21
+ // .stderrTail() the last few KB the agent wrote to stderr, redacted
22
+ //
23
+ // By default the client offers the agent no file system and no terminal (`fs`
24
+ // false, `terminal` false): Antigravity reads, writes and runs commands itself,
25
+ // and asks the client before each one it wants approved
26
+ // (session/request_permission). What the client answers is the caller's
27
+ // (`onPermission`); a caller that has none cancels every request, which the
28
+ // agent reads as "not approved". A caller that offers more says so in
29
+ // `initialize({ clientCapabilities })` and answers what it offered: the file and
30
+ // terminal methods through `onClientRequest`, elicitation/create through
31
+ // `onElicitation` (elicitation/complete arrives at `onNotification`). A method
32
+ // nobody answers is refused as "method not found".
33
+ //
34
+ // Nothing here throws at construction. A spawn that fails, or a process that
35
+ // ends, rejects every request in flight and every later one.
36
+
37
+ import { spawn as nodeSpawn } from 'node:child_process';
38
+ import { Readable, Writable } from 'node:stream';
39
+ import { client as acpClient, ndJsonStream, PROTOCOL_VERSION, RequestError } from '@agentclientprotocol/sdk/unstable';
40
+
41
+ export const ACP_PROTOCOL_VERSION = PROTOCOL_VERSION;
42
+ /** What `initialize()` offers when the caller says nothing: no file system, no terminal. */
43
+ export const DEFAULT_CLIENT_CAPABILITIES = Object.freeze({ fs: Object.freeze({ readTextFile: false, writeTextFile: false }), terminal: false });
44
+ /** The client methods an agent may call once the client offered them (`fs`, `terminal`): `onClientRequest` answers them. */
45
+ export const ACP_CLIENT_METHODS = Object.freeze([
46
+ 'fs/read_text_file', 'fs/write_text_file',
47
+ 'terminal/create', 'terminal/output', 'terminal/wait_for_exit', 'terminal/kill', 'terminal/release',
48
+ ]);
49
+ const STDERR_KEEP = 8 * 1024;
50
+ const KILL_GRACE_MS = 2_000;
51
+ const DEFAULT_TIMEOUT_MS = 120_000;
52
+
53
+ /** Credentials an agent might echo on stderr: never kept, never forwarded. */
54
+ export function redactSecrets(text) {
55
+ return String(text ?? '')
56
+ .replace(/(\bauthorization["'=:\s]+(?:bearer|basic)\s+)[^\s"',;}]+/gi, '$1[redacted]')
57
+ .replace(/\bya29\.[A-Za-z0-9._-]{10,}/g, 'ya29.[redacted]')
58
+ .replace(/\bAIza[0-9A-Za-z_-]{20,}/g, 'AIza[redacted]')
59
+ .replace(/\b(1\/\/[0-9A-Za-z_-]{20,})/g, '[redacted-refresh-token]')
60
+ .replace(/((?:api[_-]?key|token|secret|password|authorization)["'=:\s]+)("?)[^\s"',}]{8,}/gi, '$1$2[redacted]');
61
+ }
62
+
63
+ /** The error an ACP request rejected with, as one plain object (message, JSON-RPC code, data). */
64
+ export function acpErrorInfo(error) {
65
+ if (!error) return { message: 'Unknown error' };
66
+ const message = typeof error.message === 'string' && error.message ? error.message : String(error);
67
+ const info = { message: redactSecrets(message) };
68
+ if (Number.isInteger(error.code)) info.code = error.code;
69
+ if (error.data !== undefined) {
70
+ try { info.data = JSON.parse(redactSecrets(JSON.stringify(error.data))); } catch { /* not JSON: left out */ }
71
+ }
72
+ return info;
73
+ }
74
+
75
+ /** ACP's "authentication required" error (-32000), which every session method answers before a sign-in. */
76
+ export function isAuthRequired(error) {
77
+ return Number(error?.code) === -32000 || /authentication required/i.test(String(error?.message || ''));
78
+ }
79
+
80
+ function withTimeout(promise, ms, what, onTimeout) {
81
+ if (!ms || ms <= 0) return promise;
82
+ let timer;
83
+ return Promise.race([
84
+ promise,
85
+ new Promise((_, reject) => {
86
+ timer = setTimeout(() => {
87
+ try { onTimeout?.(); } catch { /* the timeout is reported either way */ }
88
+ reject(Object.assign(new Error(`${what} timed out after ${Math.round(ms / 1000)} s`), { code: 'ETIMEDOUT' }));
89
+ }, ms);
90
+ timer.unref?.();
91
+ }),
92
+ ]).finally(() => clearTimeout(timer));
93
+ }
94
+
95
+ /**
96
+ * Start `agy acp` and connect to it.
97
+ *
98
+ * `command` / `args`: what starts the CLI (a resolved launch spec: the file, and the words
99
+ * before `acp`, such as `node cli.js` for a script). `acpArgs`: flags of the `acp` subcommand itself,
100
+ * after it (`--gemini-dir <dir>`: a SynaBun home, lib/antigravity/home.js). `env` / `cwd`: the process's own.
101
+ * `onUpdate(params)`: every session/update notification, as the agent sent it.
102
+ * `onPermission(params, { signal })`: answers session/request_permission
103
+ * ({ outcome: { outcome: 'selected', optionId } } or { outcome: { outcome: 'cancelled' } }).
104
+ * `onClientRequest(method, params, { signal })`: answers the client methods of ACP_CLIENT_METHODS
105
+ * (fs/read_text_file … terminal/release) with their result, or throws (a RequestError keeps its code).
106
+ * `onElicitation(params, { signal })`: answers elicitation/create ({ action, content? }); one that
107
+ * throws or answers nothing counts as { action: 'cancel' }.
108
+ * `onNotification(method, params)` / `onRequest(method, params)`: anything else the agent
109
+ * sends (elicitation/complete, extension methods; the client methods above too when their own
110
+ * handler is missing); an unanswered request is refused as "method not found".
111
+ * `onExit({ code, signal, stderr })`: once, when the process is gone.
112
+ */
113
+ export function createAcpConnection({
114
+ command,
115
+ args = [],
116
+ acpArgs = [],
117
+ cwd = process.cwd(),
118
+ env = process.env,
119
+ spawnImpl = nodeSpawn,
120
+ clientInfo = { name: 'synabun', title: 'SynaBun', version: '0' },
121
+ onUpdate = () => {},
122
+ onPermission = null,
123
+ onClientRequest = null,
124
+ onElicitation = null,
125
+ onNotification = null,
126
+ onRequest = null,
127
+ onExit = null,
128
+ onLog = null,
129
+ requestTimeoutMs = DEFAULT_TIMEOUT_MS,
130
+ } = {}) {
131
+ let stderr = '';
132
+ let exitInfo = null;
133
+ let closing = false;
134
+ let child = null;
135
+ let connection = null;
136
+ let resolveExited;
137
+ const exited = new Promise((resolve) => { resolveExited = resolve; });
138
+ const log = (line) => { try { onLog?.(line); } catch { /* logging never breaks the session */ } };
139
+
140
+ const finish = (info) => {
141
+ if (exitInfo) return;
142
+ exitInfo = { code: info?.code ?? null, signal: info?.signal ?? null, error: info?.error ? redactSecrets(info.error) : undefined, stderr: stderrTail() };
143
+ try { connection?.close(new Error(exitInfo.error || `Antigravity exited (${exitInfo.signal || exitInfo.code})`)); } catch { /* already closed */ }
144
+ resolveExited(exitInfo);
145
+ try { onExit?.(exitInfo); } catch { /* the exit is recorded either way */ }
146
+ };
147
+ function stderrTail() { return redactSecrets(stderr); }
148
+
149
+ if (typeof command !== 'string' || !command) {
150
+ queueMicrotask(() => finish({ error: 'Antigravity CLI (agy) is not installed or could not be resolved.' }));
151
+ } else {
152
+ try {
153
+ child = spawnImpl(command, [...args, 'acp', ...(Array.isArray(acpArgs) ? acpArgs.map(String) : [])], { cwd, env, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true, detached: process.platform !== 'win32' });
154
+ } catch (error) {
155
+ queueMicrotask(() => finish({ error: error?.message || String(error) }));
156
+ }
157
+ }
158
+
159
+ if (child) {
160
+ child.on('error', (error) => finish({ error: error?.message || String(error) }));
161
+ child.on('exit', (code, signal) => finish({ code, signal }));
162
+ child.stderr?.setEncoding?.('utf8');
163
+ child.stderr?.on('data', (chunk) => {
164
+ stderr = (stderr + chunk).slice(-STDERR_KEEP);
165
+ });
166
+ child.stdin?.on?.('error', () => { /* a closed pipe ends in the exit above */ });
167
+ // A client method without its own handler goes where every unknown request goes.
168
+ const unhandled = (method, params) => {
169
+ if (typeof onRequest === 'function') return onRequest(method, params);
170
+ throw RequestError.methodNotFound(method);
171
+ };
172
+ const app = acpClient()
173
+ .onNotification('session/update', (ctx) => { onUpdate(ctx.params); })
174
+ .onRequest('session/request_permission', async (ctx) => {
175
+ if (typeof onPermission !== 'function') return { outcome: { outcome: 'cancelled' } };
176
+ try {
177
+ const answer = await onPermission(ctx.params, { signal: ctx.signal });
178
+ return answer?.outcome ? answer : { outcome: { outcome: 'cancelled' } };
179
+ } catch (error) {
180
+ log(`permission handler failed: ${error?.message || error}`);
181
+ return { outcome: { outcome: 'cancelled' } };
182
+ }
183
+ })
184
+ .onRequest('elicitation/create', async (ctx) => {
185
+ if (typeof onElicitation !== 'function') return unhandled('elicitation/create', ctx.params);
186
+ try {
187
+ const answer = await onElicitation(ctx.params, { signal: ctx.signal });
188
+ return typeof answer?.action === 'string' ? answer : { action: 'cancel' };
189
+ } catch (error) {
190
+ log(`elicitation handler failed: ${error?.message || error}`);
191
+ return { action: 'cancel' };
192
+ }
193
+ })
194
+ .onNotification('elicitation/complete', (ctx) => { try { onNotification?.('elicitation/complete', ctx.params); } catch { /* informational */ } });
195
+ for (const method of ACP_CLIENT_METHODS) {
196
+ app.onRequest(method, async (ctx) => {
197
+ if (typeof onClientRequest !== 'function') return unhandled(method, ctx.params);
198
+ return onClientRequest(method, ctx.params, { signal: ctx.signal });
199
+ });
200
+ }
201
+ app
202
+ .onNotification('*', (ctx) => { try { onNotification?.(ctx.method, ctx.params); } catch { /* informational */ } })
203
+ .onRequest('*', async (ctx) => unhandled(ctx.method, ctx.params));
204
+ try {
205
+ connection = app.connect(ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout)));
206
+ connection.closed.catch?.(() => {});
207
+ } catch (error) {
208
+ queueMicrotask(() => finish({ error: error?.message || String(error) }));
209
+ }
210
+ }
211
+
212
+ function gone() {
213
+ return Object.assign(new Error(exitInfo?.error || 'The Antigravity agent is not running.'), { code: 'AGENT_EXITED', stderr: stderrTail() });
214
+ }
215
+
216
+ async function request(method, params = {}, { timeoutMs = requestTimeoutMs, signal } = {}) {
217
+ if (exitInfo || !connection) throw gone();
218
+ const pending = connection.agent.request(method, params, signal ? { signal } : undefined);
219
+ return withTimeout(pending, timeoutMs, `Antigravity ${method}`);
220
+ }
221
+
222
+ async function notify(method, params = {}) {
223
+ if (exitInfo || !connection) throw gone();
224
+ return connection.agent.notify(method, params);
225
+ }
226
+
227
+ // One initialize per process: a second call shares the first answer, whatever it asks.
228
+ // `clientCapabilities`: what the client offers the agent (DEFAULT_CLIENT_CAPABILITIES when not given).
229
+ let initialized = null;
230
+ function initialize({ clientCapabilities, ...extra } = {}) {
231
+ if (!initialized) {
232
+ initialized = request('initialize', {
233
+ protocolVersion: ACP_PROTOCOL_VERSION,
234
+ clientCapabilities: clientCapabilities && typeof clientCapabilities === 'object'
235
+ ? clientCapabilities
236
+ : { fs: { ...DEFAULT_CLIENT_CAPABILITIES.fs }, terminal: DEFAULT_CLIENT_CAPABILITIES.terminal },
237
+ clientInfo,
238
+ ...extra,
239
+ }, { timeoutMs: 30_000 }).catch((error) => { initialized = null; throw error; });
240
+ }
241
+ return initialized;
242
+ }
243
+
244
+ let closePromise = null;
245
+ function close() {
246
+ if (closePromise) return closePromise;
247
+ closing = true;
248
+ closePromise = (async () => {
249
+ try { connection?.close(); } catch { /* already closed */ }
250
+ if (!child) return exited;
251
+ try { child.stdin?.end?.(); } catch { /* already closed */ }
252
+ const grouped = process.platform !== 'win32' && Number.isInteger(child.pid) && child.pid > 0;
253
+ const signal = (name) => {
254
+ try { if (grouped) process.kill(-child.pid, name); else child.kill(name); } catch { /* gone */ }
255
+ };
256
+ const groupAlive = () => {
257
+ if (!grouped) return !exitInfo;
258
+ try { process.kill(-child.pid, 0); return true; } catch (error) { return error.code !== 'ESRCH'; }
259
+ };
260
+ if (process.platform === 'win32' && child.pid) {
261
+ // taskkill must capture the tree while its parent still exists. Killing the parent first loses it.
262
+ await new Promise((resolve) => {
263
+ let timer;
264
+ let killer;
265
+ const done = () => { clearTimeout(timer); resolve(); };
266
+ try {
267
+ killer = nodeSpawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true });
268
+ timer = setTimeout(() => { try { killer.kill('SIGKILL'); } catch {} done(); }, KILL_GRACE_MS);
269
+ killer.on('exit', done);
270
+ killer.on('error', done);
271
+ } catch { done(); }
272
+ });
273
+ if (!exitInfo) signal('SIGKILL');
274
+ } else signal('SIGTERM');
275
+ const deadline = Date.now() + KILL_GRACE_MS;
276
+ while (groupAlive() && Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, 25));
277
+ // The parent can exit before an MCP child. Always signal the process group, even after `exited`.
278
+ if (groupAlive()) {
279
+ signal('SIGKILL');
280
+ }
281
+ const hardDeadline = Date.now() + 500;
282
+ while (groupAlive() && Date.now() < hardDeadline) await new Promise((resolve) => setTimeout(resolve, 25));
283
+ if (!exitInfo) finish({ error: 'Antigravity shutdown exceeded its hard timeout', signal: 'SIGKILL' });
284
+ return exited;
285
+ })();
286
+ return closePromise;
287
+ }
288
+
289
+ return {
290
+ get pid() { return child?.pid ?? null; },
291
+ get running() { return !exitInfo && !!connection; },
292
+ exited,
293
+ initialize,
294
+ request,
295
+ notify,
296
+ close,
297
+ stderrTail,
298
+ };
299
+ }
@@ -0,0 +1,100 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Bypass in the Antigravity side panel: what an auto-approved permission request still meets
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Antigravity has no per-session way to skip its approvals: `agy acp --dangerously-skip-permissions` is a flag of
6
+ // the whole process (one per panel window, every tab), and an ACP session offers no permission mode or config
7
+ // option (agy 1.4.12). So Bypass is the bridge's: a tab in Bypass gets every session/request_permission answered
8
+ // at once with the agent's own "allow once" option (never "always", which agy would save in ~/.gemini for later
9
+ // sessions), and the request still reaches SynaBun, so these hard rails stay in force:
10
+ //
11
+ // browser lib/browser-tool-policy.js: Antigravity's own web search, URL reading and browser, a shell that starts a
12
+ // browser or browser automation code, another server's browser tools (pages go through SynaBun's browser)
13
+ // protected a path or a command line that reaches one of SynaBun's protected home folders
14
+ // (lib/worker-confinement.js PROTECTED_HOME_DIRS: SynaBun's data home, ~/.claude, ~/.codex, ~/.gemini,
15
+ // ~/.ssh, ~/.aws, …: credentials and the runtimes' own settings)
16
+ //
17
+ // A call a rail catches is refused (the agent's reject option, else cancelled) and the page is told why. A request
18
+ // with no allow-once option is left to the owner's card. Lexical, like the rest of SynaBun's guards: a speed bump
19
+ // for an agent, not a sandbox.
20
+
21
+ import { homedir } from 'node:os';
22
+ import { isAbsolute, join, relative, resolve } from 'node:path';
23
+ import { browserToolDenial } from '../browser-tool-policy.js';
24
+ import { PROTECTED_HOME_DIRS } from '../worker-confinement.js';
25
+ import { acpCall, acpPolicyInput, acpToolName, acpToolPaths, acpWebTool } from './tool-call.js';
26
+
27
+ export const BYPASS_RAILS = Object.freeze(['browser', 'protected']);
28
+
29
+ function inside(dir, path) {
30
+ const rel = relative(dir, path);
31
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
32
+ }
33
+
34
+ function placeOf(raw, { cwd, home }) {
35
+ const text = String(raw || '').trim();
36
+ if (!text) return null;
37
+ if (text === '~' || text.startsWith('~/')) return resolve(home, text.slice(2));
38
+ if (/^\$\{?HOME\}?(\/|$)/.test(text)) return resolve(home, text.replace(/^\$\{?HOME\}?\/?/, ''));
39
+ if (isAbsolute(text)) return resolve(text);
40
+ return cwd ? resolve(cwd, text) : null;
41
+ }
42
+
43
+ /** The protected folder a path or a command line reaches, else null. */
44
+ export function protectedTarget(call, { cwd = null, home = homedir() } = {}) {
45
+ const dirs = PROTECTED_HOME_DIRS.map((d) => join(home, d));
46
+ for (const raw of acpToolPaths(call)) {
47
+ const place = placeOf(raw, { cwd, home });
48
+ if (place) for (const dir of dirs) if (inside(dir, place)) return place;
49
+ }
50
+ const command = typeof call.command === 'string' ? call.command
51
+ : typeof call.args?.command === 'string' ? call.args.command
52
+ : Array.isArray(call.args?.command) ? call.args.command.join(' ')
53
+ : typeof call.args?.CommandLine === 'string' ? call.args.CommandLine : '';
54
+ if (command) {
55
+ const words = command.split(/[\s'"`;|&<>()=]+/).filter(Boolean);
56
+ for (const word of words) {
57
+ const place = /^(~|\$\{?HOME\}?)(\/|$)/.test(word) || isAbsolute(word) ? placeOf(word, { cwd, home }) : null;
58
+ if (place) for (const dir of dirs) if (inside(dir, place)) return place;
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+
64
+ /** The rail one permission request meets under Bypass: { rule, reason } or null when it may be approved. */
65
+ export function bypassRail(toolCall, { cwd = null, home = homedir(), roots = [] } = {}) {
66
+ let call;
67
+ try { call = acpCall(toolCall && typeof toolCall === 'object' ? toolCall : {}); } catch { return { rule: 'check-failed', reason: 'SynaBun could not read this request, so Bypass did not approve it.' }; }
68
+ try {
69
+ if ((!call.name && !call.title && call.kind === 'other')
70
+ || (call.kind === 'mcp' && !call.mcp)
71
+ || (call.kind === 'execute' && !call.command)
72
+ || (['read', 'search', 'edit', 'delete', 'move'].includes(call.kind) && !acpToolPaths(call).length)) {
73
+ return { rule: 'check-failed', reason: 'SynaBun could not read a complete tool call in this request, so Bypass did not approve it.' };
74
+ }
75
+ // A permission request often names no tool (only a title such as "Run `ls`"): a command is read as one.
76
+ const name = !call.mcp && call.kind === 'execute' && call.command ? 'run_command' : acpToolName(call);
77
+ const input = acpPolicyInput(call);
78
+ const browser = browserToolDenial(acpWebTool(call) && !name.startsWith('mcp__') ? (call.name || 'search_web') : name, input, { host: 'antigravity', cwd, roots });
79
+ if (browser) return { rule: 'browser', reason: browser };
80
+ const place = protectedTarget(call, { cwd, home });
81
+ if (place) return { rule: 'protected', reason: `${place} is inside one of SynaBun's protected folders (credentials and the runtimes' own settings): Bypass never approves it.`, target: place };
82
+ return null;
83
+ } catch (error) {
84
+ return { rule: 'check-failed', reason: `SynaBun could not check this request (${String(error?.message || error).slice(0, 200)}), so Bypass did not approve it.` };
85
+ }
86
+ }
87
+
88
+ /** The option Bypass answers with: the agent's allow-once option, never an "always" one; null when there is none. */
89
+ export function allowOnceOption(options) {
90
+ const list = Array.isArray(options) ? options.filter((o) => o && typeof o.optionId === 'string') : [];
91
+ return list.find((o) => o.kind === 'allow_once')
92
+ || list.find((o) => !o.kind && /^allow(?!.*always)/i.test(`${o.optionId} ${o.name || ''}`) && !/always/i.test(`${o.optionId} ${o.name || ''}`))
93
+ || null;
94
+ }
95
+
96
+ /** The option a refusal answers with: reject-once first, else null (then the request is cancelled). */
97
+ export function rejectOnceOption(options) {
98
+ const list = Array.isArray(options) ? options.filter((o) => o && typeof o.optionId === 'string') : [];
99
+ return list.find((o) => o.kind === 'reject_once') || null;
100
+ }