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.
- package/CHANGELOG.md +139 -0
- package/README.md +1 -1
- package/docs/whatsapp.md +11 -11
- package/lib/client-config-repair.js +13 -9
- package/lib/external-tools.js +6 -5
- package/lib/update-snapshot.js +77 -3
- package/lib/virustotal.mjs +12 -1
- package/mcp-server/dist/index.js +1 -1
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +2 -1
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +2 -1
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.js +1 -1
- package/mcp-server/dist/services/tool-catalog.js.map +1 -1
- package/mcp-server/dist/services/tool-list.d.ts +1 -1
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -1
- package/mcp-server/dist/services/tool-runtime.d.ts +2 -2
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -1
- package/mcp-server/dist/services/tool-runtime.js +1 -1
- package/mcp-server/dist/services/tool-runtime.js.map +1 -1
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +8 -8
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +10 -9
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +8 -8
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/skill-tools.js +11 -8
- package/mcp-server/dist/tools/skill-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/index.ts +1 -1
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +2 -1
- package/mcp-server/src/services/server-instructions.ts +2 -1
- package/mcp-server/src/services/tool-catalog.ts +1 -1
- package/mcp-server/src/services/tool-list.ts +1 -1
- package/mcp-server/src/services/tool-runtime.ts +2 -2
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/tools/agents.ts +10 -9
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +11 -8
- package/neural-interface/i18n/en.json +504 -39
- package/neural-interface/i18n/pt-BR.json +504 -39
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +1 -0
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/codex.js +6 -1
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +76 -9
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +211 -50
- package/neural-interface/lib/assistant-envelope.js +153 -1
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +16 -11
- package/neural-interface/lib/assistant-plan-permissions.js +15 -0
- package/neural-interface/lib/assistant-router.js +237 -35
- package/neural-interface/lib/assistant-runtime.js +158 -12
- package/neural-interface/lib/assistant-task-prompt.js +10 -8
- package/neural-interface/lib/assistant-tools.js +2 -2
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +6 -1
- package/neural-interface/lib/browser-guard-cdp.js +5 -4
- package/neural-interface/lib/browser-network-guard.js +274 -82
- package/neural-interface/lib/browser-tool-policy.js +12 -7
- package/neural-interface/lib/claude-agent-bridge.js +7 -0
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +160 -31
- package/neural-interface/lib/cli-resolver.js +9 -2
- package/neural-interface/lib/cli-update-planner.js +25 -15
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +25 -6
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +9 -2
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/mcp-client-config.js +37 -6
- package/neural-interface/lib/mcp-external-servers.js +40 -7
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +147 -25
- package/neural-interface/lib/native-loop-providers.js +423 -23
- package/neural-interface/lib/native-loop-runtime.js +23 -2
- package/neural-interface/lib/opencode-native-boundary.js +165 -22
- package/neural-interface/lib/owner-authority.js +1 -1
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +80 -6
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +3 -0
- package/neural-interface/lib/rulesets/api.js +6 -5
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +89 -10
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +64 -1
- package/neural-interface/lib/skills/catalog.js +5 -1
- package/neural-interface/lib/skills/creation-brief.js +1 -1
- package/neural-interface/lib/skills/creation-sources.js +19 -1
- package/neural-interface/lib/skills/deploy.js +9 -4
- package/neural-interface/lib/skills/draft-confinement.js +3 -1
- package/neural-interface/lib/skills/eval-confinement.js +3 -1
- package/neural-interface/lib/skills/eval-trace.js +16 -0
- package/neural-interface/lib/skills/export.js +5 -2
- package/neural-interface/lib/skills/known-bridge-digests.json +58 -4
- package/neural-interface/lib/skills/ownership.js +1 -1
- package/neural-interface/lib/skills/roots.js +10 -3
- package/neural-interface/lib/skills/runtime-checks.js +6 -3
- package/neural-interface/lib/skills/service.js +15 -7
- package/neural-interface/lib/skills/telemetry.js +6 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +77 -1
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-resume.js +13 -4
- package/neural-interface/lib/worker-sandbox.js +46 -16
- package/neural-interface/package-lock.json +18 -2
- package/neural-interface/package.json +2 -1
- package/neural-interface/public/onboarding.html +1 -1
- package/neural-interface/public/shared/agent-runtime-options.js +89 -11
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +4 -4
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +3 -4
- package/neural-interface/public/shared/assistant/asst-api.js +15 -3
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +56 -9
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-computer.js +26 -2
- package/neural-interface/public/shared/assistant/asst-control.js +48 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +6 -1
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +38 -5
- package/neural-interface/public/shared/assistant/asst-motion-gate.js +80 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +46 -9
- package/neural-interface/public/shared/assistant/asst-render.js +112 -18
- package/neural-interface/public/shared/assistant/asst-route.js +237 -57
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scene-styles.js +55 -23
- package/neural-interface/public/shared/assistant/asst-scenes.js +279 -80
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +4 -4
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +51 -7
- package/neural-interface/public/shared/assistant/asst-slash.js +8 -2
- package/neural-interface/public/shared/assistant/asst-state.js +76 -9
- package/neural-interface/public/shared/assistant/asst-style-cache.js +44 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +58 -4
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +34 -7
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +26 -3
- package/neural-interface/public/shared/cdx/cdx-panel.js +14 -2
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +11 -10
- package/neural-interface/public/shared/cdx/cdx-render.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-requests.js +11 -1
- package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
- package/neural-interface/public/shared/cdx/cdx-tabs.js +75 -5
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +7 -4
- package/neural-interface/public/shared/cli-status.js +9 -8
- package/neural-interface/public/shared/constants.js +3 -2
- package/neural-interface/public/shared/context-menu-model.js +1 -0
- package/neural-interface/public/shared/cp/cp-permissions.js +12 -0
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +1 -0
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +21 -4
- package/neural-interface/public/shared/loading-teardown.js +34 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +6 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +28 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +17 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +6 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +101 -68
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +46 -3
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +1 -1
- package/neural-interface/public/shared/settings/settings-skill-folders.js +2 -2
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-creation.js +6 -3
- package/neural-interface/public/shared/skills/ss-dialog.js +5 -2
- package/neural-interface/public/shared/skills/ss-lint.js +9 -1
- package/neural-interface/public/shared/skills/ss-profiles.js +44 -6
- package/neural-interface/public/shared/skills/ss-review-view.js +2 -2
- package/neural-interface/public/shared/skills/studio/sx-actions.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +2 -1
- package/neural-interface/public/shared/skills/studio/sx-dom.js +2 -1
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +9 -6
- package/neural-interface/public/shared/skills/studio/sx-install.js +20 -3
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +144 -35
- package/neural-interface/public/shared/skills/studio/sx-library.js +6 -2
- package/neural-interface/public/shared/skills/studio/sx-main.js +11 -2
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-subject.js +7 -6
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +6 -5
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/storage-retry.js +47 -0
- package/neural-interface/public/shared/storage.js +25 -4
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styles.css +362 -35
- package/neural-interface/public/shared/synabun-mascot.js +27 -8
- package/neural-interface/public/shared/synabun-ticker.js +147 -12
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +2 -2
- package/neural-interface/public/shared/tool-list-view.js +2 -2
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +20 -12
- package/neural-interface/public/shared/ui-claude-panel.js +374 -134
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +8 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-loading.js +5 -4
- package/neural-interface/public/shared/ui-menubar.js +2 -2
- package/neural-interface/public/shared/ui-native-loop-router.js +4 -0
- package/neural-interface/public/shared/ui-navbar.js +45 -0
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +41 -10
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +22 -12
- package/neural-interface/public/shared/ui-settings.js +90 -65
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -3
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +3 -3
- package/neural-interface/public/shared/ui-terminal.js +146 -10
- package/neural-interface/public/shared/ui-tool-updates.js +3 -3
- package/neural-interface/public/shared/ui-tooltip.js +71 -46
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-whiteboard.js +1 -1
- package/neural-interface/public/shared/ui-worker-end.js +1 -1
- package/neural-interface/public/shared/whatsapp/wa-view.js +2 -2
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/sidepanel-session.html +1 -1
- package/neural-interface/server.js +731 -466
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +5 -5
- package/neural-interface/templates/rulesets/manifest.json +1 -1
- package/npm-shrinkwrap.json +18 -2
- package/package.json +2 -1
- package/skills/skill-forge/SKILL.md +4 -4
- package/skills/synabun/SKILL.md +1 -1
- package/skills/synabun/modules/schedule.md +3 -3
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { codexWorkerReply, CODEX_QUESTIONS, elicitationReply, openCodeAnswers, workerQuestions } from './worker-question.js';
|
|
1
2
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
2
3
|
import { tmpdir } from 'node:os';
|
|
3
|
-
import { externalServerInventory, selectExternalServers, codexMcpEnabledOverride, referenceClaudeMap, waitForClaudeMcpScope, redactMcpValues, writePrivateMcpConfig,
|
|
4
|
+
import { externalServerInventory, selectExternalServers, codexMcpEnabledOverride, referenceClaudeMap, waitForClaudeMcpScope, redactMcpValues, writePrivateMcpConfig, mcpSecretValues } from './mcp-external-servers.js';
|
|
4
5
|
import { resolveStoredTools, runtimeToolsValue, readDefaultTools } from './tool-lists.js';
|
|
5
6
|
import { waitForSynabunTools, synabunToolsTimeoutText } from './opencode-mcp-ready.js';
|
|
6
7
|
import { config as memoryConfig, detectProject as memoryProject } from '../../mcp-server/dist/config.js';
|
|
@@ -21,7 +22,13 @@ import { CODEX_BROWSER_POLICY_UNTRUSTED_NOTE, codexBrowserPolicyHook } from './a
|
|
|
21
22
|
import { codexWindowsSandbox, codexWindowsSandboxConfig } from './agent-sandbox-elevation.js';
|
|
22
23
|
import { DRAFT_DISALLOWED_TOOLS, DRAFT_TOOLS, codexDraftOptions, draftOpenCodeDecision, draftPreToolUseHook, draftToolDecision, openCodeDraftConfig, resolveDraftConfinement } from './skills/draft-confinement.js';
|
|
23
24
|
import { EVAL_CONFINEMENT, codexEvalOptions, evalClaudeOptions, evalGitSafetyEnv, evalOpenCodeDecision, evalPreToolUseHook, evalToolDecision, openCodeEvalConfig, openCodeEvalEnv, placeOpenCodeEvalSkill, resolveEvalConfinement } from './skills/eval-confinement.js';
|
|
24
|
-
import { WORKER_GUARD_DEFAULT, codexSandboxFor, confinementEvent, openCodeCodeModeDecision, openCodeCodeModeNote, openCodePermissionDecision, openCodePermissionsFor, resolveWorkerConfinement, workerShellDecision, workerToolDecision } from './worker-confinement.js';
|
|
25
|
+
import { WORKER_GUARD_DEFAULT, acpPermissionDecision, codexSandboxFor, confinementEvent, openCodeCodeModeDecision, openCodeCodeModeNote, openCodePermissionDecision, openCodePermissionsFor, resolveWorkerConfinement, workerShellDecision, workerToolDecision } from './worker-confinement.js';
|
|
26
|
+
import { createAcpConnection } from './antigravity/acp-connection.js';
|
|
27
|
+
import { acpTurnUsage } from './antigravity/usage.js';
|
|
28
|
+
import { assertSafeAntigravityProject, antigravityHomeReadPolicy, antigravityHomeSettings, policyHookCommand, prepareAntigravityHome, toAntigravityMcpEntry, userAntigravityMcpServers, userAntigravitySettings, userGeminiDir } from './antigravity/home.js';
|
|
29
|
+
import { acpCall, acpPolicyInput, acpReadOnlyKind, acpToolName, acpToolPaths, acpWebTool } from './antigravity/tool-call.js';
|
|
30
|
+
import { splitAntigravityModel } from './antigravity/catalog.js';
|
|
31
|
+
import { fileURLToPath } from 'node:url';
|
|
25
32
|
|
|
26
33
|
function nativeToolSelection(options, provider) { return resolveStoredTools(options, { source: options.runMode === 'task' ? 'dispatch' : 'launch', provider, defaultTools: options.runMode === 'task' ? undefined : readDefaultTools(memoryConfig.dataHome) }); }
|
|
27
34
|
|
|
@@ -355,7 +362,7 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
355
362
|
runId, cwd, model, effort, codexHome, codexPath, browserSessionId,
|
|
356
363
|
browserTabId, onIdentity = () => {}, onEvent = () => {},
|
|
357
364
|
CodexClass = Codex,
|
|
358
|
-
extraEnv = {}, permissionPolicy: rawPolicy = 'auto', capability: rawCapability = 'full',
|
|
365
|
+
extraEnv = {}, permissionPolicy: rawPolicy = 'auto', permissionBroker = null, capability: rawCapability = 'full',
|
|
359
366
|
outputSchema = null, desktopGrantProvider = null, modelContextWindow = null, contextMode = null,
|
|
360
367
|
// Image creation runs (assistant dispatch): 'image' → each turn returns the images it generated.
|
|
361
368
|
collectMedia = null,
|
|
@@ -400,10 +407,8 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
400
407
|
const extended = contextMode === 'extended' || legacyExtended;
|
|
401
408
|
const runModel = legacyExtended ? String(model).replace(/\[extended\]$/i, '') : model;
|
|
402
409
|
if (extended && !(Number(modelContextWindow) > 0)) throw new Error(`Extended context is unavailable for ${runModel}.`);
|
|
403
|
-
//
|
|
404
|
-
|
|
405
|
-
// offer 'restricted' instead.
|
|
406
|
-
if (permissionPolicy === 'ask') throw policyUnsupportedError('Codex', permissionPolicy);
|
|
410
|
+
// Legacy exec loops have no approval channel. Task workers use an app-server.
|
|
411
|
+
if (permissionPolicy === 'ask' && runMode !== 'task') throw policyUnsupportedError('Codex', permissionPolicy);
|
|
407
412
|
// Assistant task runs: SynaBun's browser policy as a PreToolUse hook the
|
|
408
413
|
// user's Codex trusts (the brain's route-gate mechanism), and no web search
|
|
409
414
|
// of Codex's own. Without a trusted hook the policy is instructions only
|
|
@@ -416,6 +421,7 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
416
421
|
}
|
|
417
422
|
const pins = stringEnv({
|
|
418
423
|
SYNABUN_TERMINAL_SESSION: runId,
|
|
424
|
+
SYNABUN_RUN_MODE: options.runMode === 'task' ? 'task' : undefined,
|
|
419
425
|
SYNABUN_PROJECT: cwd ? memoryProject(cwd) : 'global',
|
|
420
426
|
SYNABUN_BROWSER_SESSION: browserSessionId,
|
|
421
427
|
SYNABUN_BROWSER_TAB: browserTabId,
|
|
@@ -436,7 +442,7 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
436
442
|
const policyEnv = browserPolicy ? { SYNABUN_BROWSER_POLICY_CWD: cwd || process.cwd(), SYNABUN_BROWSER_POLICY_ROOTS: JSON.stringify(Array.isArray(policyRoots) ? policyRoots : []) } : {};
|
|
437
443
|
const env = withServeEnv(stringEnv({ ...inherited, ...pins, CODEX_HOME: codexHome, ...policyEnv, ...stringEnv(extraEnv) }), evaluated ? evalGitSafetyEnv(evaluated.held.root) : null);
|
|
438
444
|
const config = { ...codexWindowsSandboxConfig(adminSandbox) };
|
|
439
|
-
if (Object.keys(pins).length) config.mcp_servers = { SynaBun: { env: pins } };
|
|
445
|
+
if (Object.keys(pins).length) config.mcp_servers = { SynaBun: { env: pins, ...(task ? { tool_timeout_sec: Math.ceil((options.questionTimeoutMs || 30 * 60_000) / 1000) + 30 } : {}) } };
|
|
440
446
|
if (!boxed) {
|
|
441
447
|
const inventory = externalServerInventory({ provider: 'codex', cwd, codexHome, env, home: env.HOME, dataHome: memoryConfig.dataHome, ...options.externalMcpContext });
|
|
442
448
|
const list = nativeToolSelection(options, 'codex');
|
|
@@ -462,6 +468,13 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
462
468
|
}
|
|
463
469
|
const WorkerCodex = task && !boxed && CodexClass === Codex ? CodexWorkerAppServer : CodexClass;
|
|
464
470
|
const codex = new WorkerCodex({
|
|
471
|
+
permissionPolicy,
|
|
472
|
+
onRequest: permissionBroker && !boxed ? async (packet, signal) => {
|
|
473
|
+
const question = CODEX_QUESTIONS.has(packet.method);
|
|
474
|
+
if (!question && permissionPolicy !== 'ask') return { error: { code: -32601, message: 'Unexpected worker approval request' } };
|
|
475
|
+
const reply = await permissionBroker.request({ kind: question ? 'ask' : 'tool', toolName: packet.method, input: packet.params, questions: workerQuestions(packet.params), protocol: { provider: 'codex', method: packet.method, id: packet.id }, signal });
|
|
476
|
+
return codexWorkerReply(packet, reply);
|
|
477
|
+
} : null,
|
|
465
478
|
onProcess: options.onProcess, signal: options.signal, apiKey: options.apiKey, configArgs: options.configArgs,
|
|
466
479
|
...(codexPath ? { codexPathOverride: codexPath } : {}),
|
|
467
480
|
env,
|
|
@@ -694,10 +707,10 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
694
707
|
const ownEnv = stringEnv({
|
|
695
708
|
...inherited,
|
|
696
709
|
SYNABUN_TERMINAL_SESSION: runId,
|
|
710
|
+
SYNABUN_RUN_MODE: options.runMode === 'task' ? 'task' : undefined,
|
|
697
711
|
SYNABUN_PROJECT: cwd ? memoryProject(cwd) : 'global',
|
|
698
712
|
SYNABUN_BROWSER_SESSION: browserSessionId,
|
|
699
713
|
SYNABUN_BROWSER_TAB: browserTabId,
|
|
700
|
-
SYNABUN_RUN_MODE: runMode === 'task' ? 'task' : undefined,
|
|
701
714
|
...stringEnv(extraEnv),
|
|
702
715
|
});
|
|
703
716
|
// Apply after every inherited/child environment overlay: drop ALL GIT_* first, then SynaBun's own safety entries.
|
|
@@ -722,13 +735,11 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
722
735
|
// Computer-use workers: the grant unlocks the `computer` MCP group.
|
|
723
736
|
'X-Synabun-Desktop-Grant': typeof desktopGrantProvider === 'function' ? desktopGrantProvider() || undefined : undefined,
|
|
724
737
|
});
|
|
725
|
-
//
|
|
726
|
-
//
|
|
727
|
-
|
|
728
|
-
const denyMatcher =
|
|
729
|
-
const denyMessage =
|
|
730
|
-
? 'Dispatched workers do not use plan mode.'
|
|
731
|
-
: 'This unattended automation cannot wait for interactive input.';
|
|
738
|
+
// Questions use the broker under every policy, independently of tool approvals.
|
|
739
|
+
// ExitPlanMode stays denied: asking does not need a separate plan turn.
|
|
740
|
+
const questionMode = !held && typeof permissionBroker?.request === 'function';
|
|
741
|
+
const denyMatcher = questionMode ? 'ExitPlanMode' : 'AskUserQuestion|ExitPlanMode';
|
|
742
|
+
const denyMessage = 'Dispatched workers do not use plan mode; questions use the live run sidepanel.';
|
|
732
743
|
// A confined run asks canUseTool for every write (permission mode 'default') on top of its PreToolUse hook, and
|
|
733
744
|
// loads no settings file: no user hooks (they would ask it for memories it has no tool to write), no allow rules.
|
|
734
745
|
const bypass = !askMode && !held;
|
|
@@ -767,6 +778,7 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
767
778
|
},
|
|
768
779
|
})],
|
|
769
780
|
},
|
|
781
|
+
...(questionMode ? [{ matcher: 'AskUserQuestion', hooks: [async () => ({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'ask', permissionDecisionReason: 'The user answers in this run’s sidepanel.' } })] }] : []),
|
|
770
782
|
// Assistant task runs: SynaBun's browser policy (browser-tool-policy.js)
|
|
771
783
|
// on every call, subagents' included, before the bypass and canUseTool.
|
|
772
784
|
...(runMode === 'task' ? [{
|
|
@@ -789,7 +801,7 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
789
801
|
}
|
|
790
802
|
if (toolName === 'ExitPlanMode') return { behavior: 'deny', message: denyMessage };
|
|
791
803
|
if (toolName === 'AskUserQuestion') {
|
|
792
|
-
if (!
|
|
804
|
+
if (!questionMode) return { behavior: 'deny', message: denyMessage };
|
|
793
805
|
const reply = await brokerRequest({ kind: 'ask', toolName, input: toolInput, questions: toolInput?.questions || [] });
|
|
794
806
|
if (reply.behavior === 'allow') {
|
|
795
807
|
const answers = reply.answers || reply.updatedInput?.answers || {};
|
|
@@ -797,6 +809,8 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
797
809
|
}
|
|
798
810
|
return { behavior: 'deny', message: reply.message || 'The question was not answered.' };
|
|
799
811
|
}
|
|
812
|
+
// Loading a deferred question schema is a read, never a permission decision.
|
|
813
|
+
if (toolName === 'ToolSearch') return { behavior: 'allow', updatedInput: toolInput };
|
|
800
814
|
// Computer use is fully autonomous: its guards live in the desktop service,
|
|
801
815
|
// so the orchestrator is never asked to approve individual actions.
|
|
802
816
|
if (askMode && /^mcp__SynaBun__computer(_apps|_ax|_status)?$/.test(String(toolName))) return { behavior: 'allow', updatedInput: toolInput };
|
|
@@ -850,7 +864,8 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
850
864
|
if (definition.oauth) privateMcpServers[name].oauth = structuredClone(definition.oauth);
|
|
851
865
|
if (definition.headersHelper) privateMcpServers[name].headersHelper = definition.headersHelper;
|
|
852
866
|
}
|
|
853
|
-
|
|
867
|
+
// Only the external servers' secrets (expanded through the CLI's env); SynaBun's own headers are not secrets.
|
|
868
|
+
externalValues = mcpSecretValues(definitions, { env });
|
|
854
869
|
externalScopeNames = Object.keys(definitions);
|
|
855
870
|
}
|
|
856
871
|
if (model) queryOptions.model = model;
|
|
@@ -1293,6 +1308,7 @@ export async function createOpenCodeNativeLoopAdapter(options = {}) {
|
|
|
1293
1308
|
} catch {}
|
|
1294
1309
|
return '';
|
|
1295
1310
|
};
|
|
1311
|
+
const pendingQuestions = new Set();
|
|
1296
1312
|
const brokerRequest = async (request) => {
|
|
1297
1313
|
try {
|
|
1298
1314
|
const reply = await permissionBroker.request({ runId, provider: 'opencode', signal: activeAbort?.signal, ...request });
|
|
@@ -1310,6 +1326,7 @@ export async function createOpenCodeNativeLoopAdapter(options = {}) {
|
|
|
1310
1326
|
};
|
|
1311
1327
|
const finishTurnWithText = () => {
|
|
1312
1328
|
const turn = activeTurn;
|
|
1329
|
+
if (pendingQuestions.size) return;
|
|
1313
1330
|
if (!turn || turn.mode !== 'async' || turn.sent === false || turn.settled || turn.finishing) return;
|
|
1314
1331
|
turn.finishing = true;
|
|
1315
1332
|
fetchAssistantText()
|
|
@@ -1336,15 +1353,23 @@ export async function createOpenCodeNativeLoopAdapter(options = {}) {
|
|
|
1336
1353
|
if (/^message[.:]part[.:]delta$/i.test(eventType)) rememberDelta(event);
|
|
1337
1354
|
if (/question\.asked/i.test(eventType)) {
|
|
1338
1355
|
const requestID = event.id || event.requestID;
|
|
1339
|
-
if (requestID &&
|
|
1340
|
-
|
|
1356
|
+
if (requestID && !held && permissionBroker?.request && client.question?.reply) {
|
|
1357
|
+
if (pendingQuestions.has(requestID)) return;
|
|
1358
|
+
pendingQuestions.add(requestID);
|
|
1359
|
+
brokerRequest({ kind: 'ask', toolName: 'question', input: event, questions: event.questions || [], protocol: { provider: 'opencode', id: requestID } })
|
|
1341
1360
|
.then((reply) => {
|
|
1361
|
+
// The tool is now answered; an idle SSE arriving before the HTTP ack is valid.
|
|
1362
|
+
pendingQuestions.delete(requestID);
|
|
1342
1363
|
if (reply.behavior === 'allow') {
|
|
1343
|
-
return client.question.reply({ requestID, answers:
|
|
1364
|
+
return client.question.reply({ requestID, answers: openCodeAnswers(event.questions || [], reply.answers), directory: cwd || undefined });
|
|
1344
1365
|
}
|
|
1345
1366
|
return client.question?.reject?.({ requestID, directory: cwd || undefined });
|
|
1346
1367
|
})
|
|
1347
|
-
.catch(() => {
|
|
1368
|
+
.catch(async (error) => {
|
|
1369
|
+
try { await client.question?.reject?.({ requestID, directory: cwd || undefined }); } catch {}
|
|
1370
|
+
settleActiveTurn(new Error(`OpenCode question reply failed: ${providerErrorMessage(error)}`));
|
|
1371
|
+
})
|
|
1372
|
+
.finally(() => pendingQuestions.delete(requestID));
|
|
1348
1373
|
} else if (requestID && client.question?.reject) {
|
|
1349
1374
|
client.question.reject({ requestID, directory: cwd || undefined }).catch(() => {});
|
|
1350
1375
|
}
|
|
@@ -1383,7 +1408,8 @@ export async function createOpenCodeNativeLoopAdapter(options = {}) {
|
|
|
1383
1408
|
}) || (() => {});
|
|
1384
1409
|
// The rules of a confined run ride the session too (lib/opencode2-client.js session.create sends them as the
|
|
1385
1410
|
// session's own `permissions`), on top of the serve's config.
|
|
1386
|
-
|
|
1411
|
+
let sessionRules = confined ? openCodeDraftConfig().permissions : evaluated ? openCodeEvalConfig(evaluated).permissions : guard ? openCodePermissionsFor(guard) : null;
|
|
1412
|
+
if (runMode === 'task' && !held) sessionRules = [...(sessionRules || []), { action: 'question', resource: '*', effect: 'allow' }];
|
|
1387
1413
|
try {
|
|
1388
1414
|
await client.waitUntilConnected?.(10_000);
|
|
1389
1415
|
const created = options.resumeSessionId
|
|
@@ -1538,3 +1564,377 @@ export async function createOpenCodeNativeLoopAdapter(options = {}) {
|
|
|
1538
1564
|
},
|
|
1539
1565
|
};
|
|
1540
1566
|
}
|
|
1567
|
+
|
|
1568
|
+
// ── Antigravity (Google's `agy` CLI, over ACP) ──────────────────────────────
|
|
1569
|
+
//
|
|
1570
|
+
// One `agy acp` process and one ACP session per run (lib/antigravity/acp-connection.js), every turn a session/prompt,
|
|
1571
|
+
// in the run's own Antigravity home (`--gemini-dir`, lib/antigravity/home.js): its MCP servers are exactly SynaBun's
|
|
1572
|
+
// and the external servers its tool list names, and its PreToolUse hook asks SynaBun about every call before it runs
|
|
1573
|
+
// (lib/antigravity/policy.js → antigravityRunPolicy: the browser policy, the run's MCP scope, the worker's
|
|
1574
|
+
// confinement). A refusal reaches the model with its reason ("tool call denied by pre-tool hook: …") and the turn goes
|
|
1575
|
+
// on; an ACP permission refusal would end the turn without one. Approvals stay with ACP's session/request_permission:
|
|
1576
|
+
// the Assistant's broker answers them under 'ask', else they are allowed once. Never "always": Antigravity would save
|
|
1577
|
+
// it for later sessions. The model and thinking level are the session's own config options (set only to a value the
|
|
1578
|
+
// session offers). The home keeps the conversation, so a run resumes after a restart (session/resume, no replay).
|
|
1579
|
+
// SynaBun's MCP child gets the run's pins from the agent's environment, which agy's MCP children inherit.
|
|
1580
|
+
|
|
1581
|
+
/** The hook script every SynaBun home runs before a tool call. */
|
|
1582
|
+
export const ANTIGRAVITY_POLICY_HOOK = fileURLToPath(new URL('./antigravity/policy-hook.mjs', import.meta.url));
|
|
1583
|
+
|
|
1584
|
+
/** The ACP permission option for an answer: explicit kinds only, never allow-always. */
|
|
1585
|
+
export function acpPermissionOption(options, wanted) {
|
|
1586
|
+
const list = Array.isArray(options) ? options.filter((option) => option && typeof option.optionId === 'string') : [];
|
|
1587
|
+
for (const kind of wanted) {
|
|
1588
|
+
if (kind === 'allow_always') continue;
|
|
1589
|
+
const found = list.find((option) => option.kind === kind);
|
|
1590
|
+
if (found) return found.optionId;
|
|
1591
|
+
}
|
|
1592
|
+
return null;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
/** The last JSON object in a reply (an output schema's answer, which ACP has no channel for), or null. */
|
|
1596
|
+
export function lastJsonObject(text) {
|
|
1597
|
+
const source = String(text || '');
|
|
1598
|
+
const fenced = [...source.matchAll(/```(?:json)?\s*([\s\S]*?)```/g)].map((m) => m[1]).reverse();
|
|
1599
|
+
for (const candidate of [...fenced, source]) {
|
|
1600
|
+
const trimmed = candidate.trim();
|
|
1601
|
+
for (let start = trimmed.lastIndexOf('{'); start >= 0; start = trimmed.lastIndexOf('{', start - 1)) {
|
|
1602
|
+
const end = trimmed.lastIndexOf('}');
|
|
1603
|
+
if (end <= start) continue;
|
|
1604
|
+
try {
|
|
1605
|
+
const value = JSON.parse(trimmed.slice(start, end + 1));
|
|
1606
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) return value;
|
|
1607
|
+
} catch { /* try an earlier brace */ }
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
return null;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* One Antigravity run's policy for one tool call (acpCall's shape): what its hook answers, and what a permission
|
|
1615
|
+
* request is checked against again. { decision: 'deny', reason, event? } | { decision: 'ask' | 'allow', event? }.
|
|
1616
|
+
* - MCP tool schemas in the run's home may be read; home configuration is refused;
|
|
1617
|
+
* - the browser policy (lib/browser-tool-policy.js: Antigravity's own web search, URL reading and browser, a shell
|
|
1618
|
+
* that starts a browser or browser code, another server's browser tools);
|
|
1619
|
+
* - the run's MCP scope (`allowedServers`: SynaBun and the external servers its tool list names;
|
|
1620
|
+
* enabled project MCP servers are refused before agy starts);
|
|
1621
|
+
* - the worker's confinement (lib/worker-confinement.js acpPermissionDecision; warn mode reports and allows);
|
|
1622
|
+
* - then the approval: 'ask' for anything but a read under the 'ask' policy, else 'allow'.
|
|
1623
|
+
*/
|
|
1624
|
+
export function antigravityRunPolicy(call, { homeDir = null, cwd = null, allowedServers = null, guard = null, askMode = false, policyRoots = [] } = {}) {
|
|
1625
|
+
if (!call || (!call.name && !call.title && (!call.kind || call.kind === 'other'))) return { decision: 'deny', reason: 'SynaBun received no valid tool call, so it is refused.' };
|
|
1626
|
+
const approval = () => (askMode && !acpReadOnlyKind(call.kind) ? 'ask' : 'allow');
|
|
1627
|
+
const name = acpToolName(call);
|
|
1628
|
+
const input = acpPolicyInput(call);
|
|
1629
|
+
const browser = browserToolDenial(acpWebTool(call) && !name.startsWith('mcp__') ? (call.name || 'search_web') : name, input, { host: 'antigravity', cwd, roots: policyRoots });
|
|
1630
|
+
if (browser) return { decision: 'deny', reason: browser, event: { type: 'synabun.browser_policy', action: 'refused', tool: name, reason: browser } };
|
|
1631
|
+
if (call.mcp && allowedServers && !allowedServers.has(call.mcp.server)) {
|
|
1632
|
+
const reason = `SynaBun: the MCP server ${call.mcp.server} is not one of this run's servers (${[...allowedServers].join(', ') || 'none'}), so ${call.mcp.tool} is refused. Use the tools this run was given.`;
|
|
1633
|
+
return { decision: 'deny', reason, event: { type: 'synabun.mcp_scope', action: 'refused', server: call.mcp.server, tool: call.mcp.tool, reason } };
|
|
1634
|
+
}
|
|
1635
|
+
const homeRead = antigravityHomeReadPolicy(call, { homeDir, cwd });
|
|
1636
|
+
if (homeRead) return homeRead;
|
|
1637
|
+
if (guard) {
|
|
1638
|
+
const decision = acpPermissionDecision(call, guard);
|
|
1639
|
+
if (decision) {
|
|
1640
|
+
const event = confinementEvent(decision, { tool: call.title || name, confinement: guard, provider: 'antigravity' });
|
|
1641
|
+
if (guard.enforced) return { decision: 'deny', reason: decision.reason, event };
|
|
1642
|
+
return { decision: approval(), event };
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
return { decision: approval() };
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
/** The MCP servers of a run's home: SynaBun's own entry, then the external servers its tool list names. */
|
|
1649
|
+
function antigravityRunServers({ tools, synabunMcpEntry, userGemini, onNote }) {
|
|
1650
|
+
const servers = {};
|
|
1651
|
+
let inventory = null;
|
|
1652
|
+
let names = [];
|
|
1653
|
+
try {
|
|
1654
|
+
inventory = externalServerInventory({ provider: 'antigravity', antigravityConfigPath: join(userGemini, 'config', 'mcp_config.json'), dataHome: memoryConfig.dataHome });
|
|
1655
|
+
names = selectExternalServers(tools.items, inventory).names;
|
|
1656
|
+
} catch (error) {
|
|
1657
|
+
if (error?.code === 'TOOLS_INVALID') throw error;
|
|
1658
|
+
onNote?.(`Antigravity: the external MCP servers could not be read (${error?.message || error}); this run has SynaBun's tools only.`);
|
|
1659
|
+
}
|
|
1660
|
+
const own = synabunMcpEntry || userAntigravityMcpServers(userGemini).SynaBun || null;
|
|
1661
|
+
if (own) servers.SynaBun = toAntigravityMcpEntry(own);
|
|
1662
|
+
for (const name of names) {
|
|
1663
|
+
const definition = inventory?.definitionFor(name);
|
|
1664
|
+
if (definition && name !== 'SynaBun') servers[name] = toAntigravityMcpEntry(definition);
|
|
1665
|
+
}
|
|
1666
|
+
return servers;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
export async function createAntigravityNativeLoopAdapter(options = {}) {
|
|
1670
|
+
const {
|
|
1671
|
+
runId, cwd, model = null, effort = null, launch = null,
|
|
1672
|
+
onIdentity = () => {}, onEvent = () => {}, onProcess = null, onNote = null,
|
|
1673
|
+
permissionPolicy: rawPolicy = 'auto', permissionBroker = null,
|
|
1674
|
+
capability: rawCapability = 'full', outputSchema = null, runMode = 'loop',
|
|
1675
|
+
browserSessionId = null, browserTabId = null, desktopGrantProvider = null,
|
|
1676
|
+
extraEnv = {}, unsetEnv = [], resumeSessionId = null,
|
|
1677
|
+
confinement = null,
|
|
1678
|
+
guardMode = WORKER_GUARD_DEFAULT, scratchDir = null, serverPort = null, localPortRange = null,
|
|
1679
|
+
connect = createAcpConnection,
|
|
1680
|
+
// The run's Antigravity home (lib/antigravity/home.js). null: agy runs in the user's own ~/.gemini, with every
|
|
1681
|
+
// server of theirs and no hook (an older server's wiring, a test of the bare protocol).
|
|
1682
|
+
homeDir = null, synabunMcpEntry = null, userGemini = userGeminiDir(),
|
|
1683
|
+
// The hook's way back (lib/antigravity/policy.js): the registry, the loopback address of POST /api/antigravity/policy.
|
|
1684
|
+
policy = null, policyUrl = null, policyHookScript = ANTIGRAVITY_POLICY_HOOK, policyRoots = [],
|
|
1685
|
+
// ACP counts tokens per session: what the session had counted when the run was suspended (a resume books only
|
|
1686
|
+
// what follows), and where each turn's count is kept for the next resume.
|
|
1687
|
+
sessionUsageBase = null, onSessionUsage = null,
|
|
1688
|
+
} = options;
|
|
1689
|
+
if (!launch?.command) {
|
|
1690
|
+
const error = new Error('The Antigravity CLI (agy) is not installed or could not be resolved.');
|
|
1691
|
+
error.code = 'CLI_MISSING';
|
|
1692
|
+
throw error;
|
|
1693
|
+
}
|
|
1694
|
+
// Skill drafting and evaluation runs hold their own confinement; Antigravity has no setup for one, and a confined
|
|
1695
|
+
// run never starts unconfined.
|
|
1696
|
+
if (confinement) throw confinementUnsupportedError('Antigravity', 'skill drafting and evaluation run on Claude Code, Codex and OpenCode', confinement?.kind === EVAL_CONFINEMENT ? 'an evaluation folder' : 'a drafting folder');
|
|
1697
|
+
assertSafeAntigravityProject(cwd);
|
|
1698
|
+
const permissionPolicy = normalizePermissionPolicy(rawPolicy);
|
|
1699
|
+
const capability = normalizeCapability(rawCapability);
|
|
1700
|
+
const guard = workerGuardFor({ capability, cwd, guardMode, scratchDir, confinement: null, serverPort, localPortRange });
|
|
1701
|
+
const askMode = permissionPolicy === 'ask' && typeof permissionBroker?.request === 'function';
|
|
1702
|
+
const tools = nativeToolSelection(options, 'antigravity');
|
|
1703
|
+
|
|
1704
|
+
// The run's home: its servers, its hook, its settings, the user's rules and skills.
|
|
1705
|
+
let allowedServers = null;
|
|
1706
|
+
let hookCommand = null;
|
|
1707
|
+
if (homeDir) {
|
|
1708
|
+
const servers = antigravityRunServers({ tools, synabunMcpEntry, userGemini, onNote });
|
|
1709
|
+
allowedServers = new Set(Object.keys(servers));
|
|
1710
|
+
if (typeof policy?.register === 'function' && policyUrl) hookCommand = policyHookCommand({ script: policyHookScript });
|
|
1711
|
+
else onNote?.('Antigravity: SynaBun\'s tool-call hook is not available in this server, so the browser policy and the run\'s MCP scope are checked only when Antigravity asks for approval.');
|
|
1712
|
+
prepareAntigravityHome({ dir: homeDir, mcpServers: servers, hookCommand, settings: antigravityHomeSettings({ userSettings: userAntigravitySettings(userGemini) }), userGemini });
|
|
1713
|
+
}
|
|
1714
|
+
const policyOptions = { homeDir, cwd, allowedServers, guard, askMode, policyRoots };
|
|
1715
|
+
|
|
1716
|
+
const pins = stringEnv({
|
|
1717
|
+
SYNABUN_TERMINAL_SESSION: runId,
|
|
1718
|
+
SYNABUN_RUN_MODE: options.runMode === 'task' ? 'task' : undefined,
|
|
1719
|
+
SYNABUN_PROJECT: cwd ? memoryProject(cwd) : 'global',
|
|
1720
|
+
SYNABUN_BROWSER_SESSION: browserSessionId,
|
|
1721
|
+
SYNABUN_BROWSER_TAB: browserTabId,
|
|
1722
|
+
SYNABUN_TOOLS: runtimeToolsValue(tools.items.includes('all') ? tools.items : [...tools.groups, ...tools.servers]),
|
|
1723
|
+
SYNABUN_DESKTOP_GRANT: typeof desktopGrantProvider === 'function' ? desktopGrantProvider() || undefined : undefined,
|
|
1724
|
+
});
|
|
1725
|
+
const inherited = { ...process.env };
|
|
1726
|
+
for (const key of ['SYNABUN_PROFILE', 'SYNABUN_RUNTIME_PROFILE_PATH', 'SYNABUN_TOOLS', 'SYNABUN_TOOLS_PATH', 'SYNABUN_TOOL_CATALOG_MODE', 'SYNABUN_ROLE', 'SYNABUN_AGY_POLICY_URL', 'SYNABUN_AGY_POLICY_TOKEN']) delete inherited[key];
|
|
1727
|
+
for (const key of Array.isArray(unsetEnv) ? unsetEnv : []) delete inherited[key];
|
|
1728
|
+
delete inherited.SYNABUN_BRAIN_TOKEN;
|
|
1729
|
+
for (const key of LIVE_DATA_ENV) delete inherited[key];
|
|
1730
|
+
|
|
1731
|
+
let alive = true;
|
|
1732
|
+
let sessionId = null;
|
|
1733
|
+
let providerTurn = Number(options.providerTurnBase) || 0;
|
|
1734
|
+
let activeTurn = null; // { iteration, providerTurn, text, controller }
|
|
1735
|
+
let lastSessionUsage = sessionUsageBase && typeof sessionUsageBase === 'object' ? sessionUsageBase : null;
|
|
1736
|
+
const openPermissions = new Set(); // resolvers of permission answers still waiting
|
|
1737
|
+
const startedAt = Date.now();
|
|
1738
|
+
|
|
1739
|
+
const emit = (eventType, event, extra = {}) => {
|
|
1740
|
+
try { onEvent({ provider: 'antigravity', runId, eventType, event, ...extra }); } catch { /* observers never break a run */ }
|
|
1741
|
+
};
|
|
1742
|
+
const turnMeta = () => (activeTurn ? { iteration: activeTurn.iteration, providerTurn: activeTurn.providerTurn } : {});
|
|
1743
|
+
// The hook's question (and, without a hook, the permission request's): the answer, its event in the run's events.
|
|
1744
|
+
const checkCall = (call) => {
|
|
1745
|
+
const answer = antigravityRunPolicy(call, policyOptions);
|
|
1746
|
+
if (answer.event) emit(answer.event.type, answer.event, turnMeta());
|
|
1747
|
+
return answer;
|
|
1748
|
+
};
|
|
1749
|
+
const registration = hookCommand ? policy.register((call) => (alive ? checkCall(call) : { decision: 'deny', reason: 'This run has ended.' }), { label: `run ${runId}` }) : null;
|
|
1750
|
+
const env = stringEnv({
|
|
1751
|
+
...inherited, ...pins, ...stringEnv(extraEnv),
|
|
1752
|
+
...(registration ? { SYNABUN_AGY_POLICY_URL: policyUrl, SYNABUN_AGY_POLICY_TOKEN: registration.token } : {}),
|
|
1753
|
+
});
|
|
1754
|
+
|
|
1755
|
+
const decidePermission = async (params, signal) => {
|
|
1756
|
+
const call = acpCall(params);
|
|
1757
|
+
const options = params?.options || [];
|
|
1758
|
+
const allowOnce = () => ({ outcome: { outcome: 'selected', optionId: acpPermissionOption(options, ['allow_once']) } });
|
|
1759
|
+
const rejectOnce = () => ({ outcome: { outcome: 'selected', optionId: acpPermissionOption(options, ['reject_once', 'reject_always']) } });
|
|
1760
|
+
const settle = (answer) => (answer.outcome.optionId ? answer : { outcome: { outcome: 'cancelled' } });
|
|
1761
|
+
if (!alive) return { outcome: { outcome: 'cancelled' } };
|
|
1762
|
+
// With the hook the call was checked before Antigravity asked: checked again here without reporting it twice
|
|
1763
|
+
// (a refusal here ends the turn, which only a call the hook never saw can earn).
|
|
1764
|
+
const verdict = registration ? antigravityRunPolicy(call, policyOptions) : checkCall(call);
|
|
1765
|
+
if (verdict.decision === 'deny') return settle(rejectOnce());
|
|
1766
|
+
if (askMode && !acpReadOnlyKind(call.kind)) {
|
|
1767
|
+
try {
|
|
1768
|
+
// Allowed once whatever the answer said about "always": Antigravity would save an "always" for every later
|
|
1769
|
+
// session of the user's, outside this run (the dispatcher drops it for Antigravity too).
|
|
1770
|
+
const reply = await permissionBroker.request({ runId, provider: 'antigravity', signal, kind: 'tool', toolName: call.mcp ? `${call.mcp.server}_${call.mcp.tool}` : (call.title || call.name || call.kind || 'tool'), input: params?.toolCall || {} });
|
|
1771
|
+
if (reply?.behavior === 'allow') return settle(allowOnce());
|
|
1772
|
+
return settle(rejectOnce());
|
|
1773
|
+
} catch {
|
|
1774
|
+
return settle(rejectOnce());
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
return settle(allowOnce());
|
|
1778
|
+
};
|
|
1779
|
+
|
|
1780
|
+
const conn = connect({
|
|
1781
|
+
command: launch.command,
|
|
1782
|
+
args: launch.args || [],
|
|
1783
|
+
acpArgs: homeDir ? ['--gemini-dir', homeDir] : [],
|
|
1784
|
+
cwd: cwd || undefined,
|
|
1785
|
+
env,
|
|
1786
|
+
clientInfo: { name: 'synabun', title: 'SynaBun', version: '0' },
|
|
1787
|
+
onUpdate: (params) => {
|
|
1788
|
+
if (!params || params.sessionId !== sessionId || !params.update) return;
|
|
1789
|
+
const update = params.update;
|
|
1790
|
+
if (activeTurn && update.sessionUpdate === 'agent_message_chunk' && update.content?.type === 'text') activeTurn.text += update.content.text || '';
|
|
1791
|
+
emit(update.sessionUpdate || 'session/update', update, turnMeta());
|
|
1792
|
+
},
|
|
1793
|
+
onElicitation: async (params, { signal } = {}) => {
|
|
1794
|
+
if (!alive || !activeTurn || params.sessionId !== sessionId || !permissionBroker?.request) return { action: 'cancel' };
|
|
1795
|
+
const reply = await permissionBroker.request({ runId, provider: 'antigravity', signal: AbortSignal.any([activeTurn?.controller?.signal, signal].filter(Boolean)), kind: 'ask', toolName: 'choice', input: params, questions: workerQuestions(params), protocol: { provider: 'antigravity', method: 'elicitation/create' } });
|
|
1796
|
+
return elicitationReply(params, reply);
|
|
1797
|
+
},
|
|
1798
|
+
onPermission: (params, { signal } = {}) => new Promise((resolve) => {
|
|
1799
|
+
const done = (answer) => { openPermissions.delete(done); resolve(answer); };
|
|
1800
|
+
openPermissions.add(done);
|
|
1801
|
+
decidePermission(params, signal).then(done, () => done({ outcome: { outcome: 'cancelled' } }));
|
|
1802
|
+
}),
|
|
1803
|
+
onExit: (info) => {
|
|
1804
|
+
alive = false;
|
|
1805
|
+
for (const done of [...openPermissions]) done({ outcome: { outcome: 'cancelled' } });
|
|
1806
|
+
if (info?.error || (info?.code && info.code !== 0)) emit('synabun.provider_exit', { type: 'synabun.provider_exit', code: info.code, signal: info.signal, error: info.error || null });
|
|
1807
|
+
},
|
|
1808
|
+
});
|
|
1809
|
+
try { onProcess?.({ pid: conn.pid, startedAt, home: homeDir || null }); } catch { /* informational */ }
|
|
1810
|
+
|
|
1811
|
+
const fail = async (error) => {
|
|
1812
|
+
alive = false;
|
|
1813
|
+
registration?.dispose();
|
|
1814
|
+
try { await conn.close(); } catch { /* gone */ }
|
|
1815
|
+
throw error;
|
|
1816
|
+
};
|
|
1817
|
+
let session;
|
|
1818
|
+
try {
|
|
1819
|
+
const init = await conn.initialize({ clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false, elicitation: { form: {} } } });
|
|
1820
|
+
if (resumeSessionId) {
|
|
1821
|
+
// session/resume picks the conversation up without replaying it; an agent without it replays (session/load),
|
|
1822
|
+
// which onUpdate drops (sessionId is set only once the load answered).
|
|
1823
|
+
const caps = init?.agentCapabilities?.sessionCapabilities || {};
|
|
1824
|
+
const method = caps.resume ? 'session/resume' : 'session/load';
|
|
1825
|
+
session = await conn.request(method, { sessionId: String(resumeSessionId), cwd, mcpServers: [] });
|
|
1826
|
+
sessionId = String(session?.sessionId || resumeSessionId);
|
|
1827
|
+
} else {
|
|
1828
|
+
session = await conn.request('session/new', { cwd, mcpServers: [] });
|
|
1829
|
+
sessionId = session.sessionId;
|
|
1830
|
+
}
|
|
1831
|
+
} catch (error) {
|
|
1832
|
+
const message = Number(error?.code) === -32000
|
|
1833
|
+
? 'Antigravity is not signed in: open the Antigravity panel (or run `agy` in a terminal) and sign in, then try again.'
|
|
1834
|
+
: providerErrorMessage(error, resumeSessionId ? 'Antigravity could not resume the run\'s session' : 'Antigravity could not start a session');
|
|
1835
|
+
return fail(Object.assign(new Error(message), { code: Number(error?.code) === -32000 ? 'AUTH_REQUIRED' : (error?.code || 'START_FAILED') }));
|
|
1836
|
+
}
|
|
1837
|
+
onIdentity({ providerSessionId: sessionId, ...(homeDir ? { antigravityHome: homeDir } : {}) });
|
|
1838
|
+
|
|
1839
|
+
// The model and the thinking level, as the session's own config options name them. A model id with its level
|
|
1840
|
+
// (gemini-4-argon-high, as `agy models` and ACP's model list spell it) is that model at that level.
|
|
1841
|
+
let configOptions = Array.isArray(session?.configOptions) ? session.configOptions : [];
|
|
1842
|
+
const offered = (category) => {
|
|
1843
|
+
const option = configOptions.find((o) => o?.category === category);
|
|
1844
|
+
const accepted = [];
|
|
1845
|
+
for (const entry of option?.options || []) for (const v of Array.isArray(entry?.options) ? entry.options : [entry]) if (v && v.value !== undefined) accepted.push(String(v.value));
|
|
1846
|
+
return { option, accepted };
|
|
1847
|
+
};
|
|
1848
|
+
const setOption = async (category, value, label) => {
|
|
1849
|
+
if (!value) return;
|
|
1850
|
+
const { option, accepted } = offered(category);
|
|
1851
|
+
if (!option) {
|
|
1852
|
+
if (category === 'model') {
|
|
1853
|
+
try { await conn.request('session/set_model', { sessionId, modelId: String(value) }); } catch (error) { onNote?.(`Antigravity kept its default model: ${providerErrorMessage(error, 'set_model failed')}`); }
|
|
1854
|
+
}
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
if (!accepted.includes(String(value))) {
|
|
1858
|
+
if (category === 'model') throw Object.assign(new Error(`Antigravity does not offer the model ${value} (it offers ${accepted.join(', ') || 'none'}).`), { code: 'MODEL_UNAVAILABLE' });
|
|
1859
|
+
onNote?.(`Antigravity has no ${label} "${value}" for this model; it keeps ${option.currentValue}.`);
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
if (String(option.currentValue) === String(value)) return;
|
|
1863
|
+
const answer = await conn.request('session/set_config_option', { sessionId, configId: option.id, value: String(value) });
|
|
1864
|
+
if (Array.isArray(answer?.configOptions)) configOptions = answer.configOptions;
|
|
1865
|
+
};
|
|
1866
|
+
const wanted = splitAntigravityModel(model, offered('model').accepted);
|
|
1867
|
+
const level = effort && !['off', 'default', 'auto', 'none'].includes(String(effort).toLowerCase()) ? String(effort) : wanted.effort;
|
|
1868
|
+
try {
|
|
1869
|
+
await setOption('model', wanted.model, 'model');
|
|
1870
|
+
await setOption('thought_level', level, 'thinking level');
|
|
1871
|
+
} catch (error) {
|
|
1872
|
+
return fail(error);
|
|
1873
|
+
}
|
|
1874
|
+
const optionValue = (category) => configOptions.find((o) => o?.category === category)?.currentValue ?? null;
|
|
1875
|
+
|
|
1876
|
+
return {
|
|
1877
|
+
identity: () => ({ providerSessionId: sessionId, ...(homeDir ? { antigravityHome: homeDir } : {}) }),
|
|
1878
|
+
isAlive: () => alive && conn.running,
|
|
1879
|
+
processInfo: () => ({ pid: conn.pid, startedAt, home: homeDir || null }),
|
|
1880
|
+
describe: () => ({
|
|
1881
|
+
provider: 'antigravity', permissionPolicy, capability, askMode, model: optionValue('model'), effort: optionValue('thought_level'),
|
|
1882
|
+
...(homeDir ? { home: homeDir, servers: [...(allowedServers || [])], hook: !!registration } : {}),
|
|
1883
|
+
...(guard ? { guard: { mode: guard.mode, capability: guard.capability, writable: [...guard.writable] } } : {}),
|
|
1884
|
+
}),
|
|
1885
|
+
async runTurn(prompt, meta = {}) {
|
|
1886
|
+
if (!alive || !conn.running) throw new Error('Antigravity native loop is closed');
|
|
1887
|
+
if (activeTurn) throw new Error('Antigravity native loop already has an active turn');
|
|
1888
|
+
providerTurn += 1;
|
|
1889
|
+
const turn = { iteration: meta.iteration, providerTurn, text: '', cancelled: false, controller: new AbortController() };
|
|
1890
|
+
activeTurn = turn;
|
|
1891
|
+
emit('synabun.user_prompt', { type: 'synabun.user_prompt', text: String(prompt || '') }, { iteration: meta.iteration, providerTurn });
|
|
1892
|
+
const schema = meta.outputSchema || outputSchema;
|
|
1893
|
+
const body = schema && typeof schema === 'object'
|
|
1894
|
+
? `${String(prompt || '')}\n\nEnd your reply with one JSON object (in a \`\`\`json block) that matches this JSON Schema:\n${JSON.stringify(schema)}`
|
|
1895
|
+
: String(prompt || '');
|
|
1896
|
+
try {
|
|
1897
|
+
const answer = await conn.request('session/prompt', { sessionId, prompt: [{ type: 'text', text: body }] }, { timeoutMs: 0 });
|
|
1898
|
+
// The turn's own tokens, whatever its end (a stopped turn spent them too).
|
|
1899
|
+
const usage = acpTurnUsage(answer?.usage, lastSessionUsage);
|
|
1900
|
+
if (answer?.usage) {
|
|
1901
|
+
lastSessionUsage = answer.usage;
|
|
1902
|
+
try { onSessionUsage?.(answer.usage); } catch { /* bookkeeping */ }
|
|
1903
|
+
}
|
|
1904
|
+
if (answer?.stopReason === 'cancelled' || turn.cancelled) throw Object.assign(asAbortError('aborted'), { usage, sessionUsage: answer?.usage || null, providerSessionId: sessionId });
|
|
1905
|
+
const text = turn.text;
|
|
1906
|
+
const result = { providerSessionId: sessionId, text, usage, sessionUsage: answer?.usage || null, stopReason: answer?.stopReason || 'end_turn', result: { text, usage } };
|
|
1907
|
+
if (answer?.stopReason === 'refusal') result.refused = true;
|
|
1908
|
+
if (schema && typeof schema === 'object') {
|
|
1909
|
+
const structured = lastJsonObject(text);
|
|
1910
|
+
if (structured) result.structured = structured;
|
|
1911
|
+
}
|
|
1912
|
+
return result;
|
|
1913
|
+
} catch (error) {
|
|
1914
|
+
if (error?.name === 'AbortError') throw error;
|
|
1915
|
+
if (!alive || !conn.running) throw new Error(`Antigravity stopped during the turn${conn.stderrTail() ? `: ${conn.stderrTail().slice(-400)}` : ''}`);
|
|
1916
|
+
throw new Error(providerErrorMessage(error, 'Antigravity turn failed'));
|
|
1917
|
+
} finally {
|
|
1918
|
+
turn.controller.abort();
|
|
1919
|
+
if (activeTurn === turn) activeTurn = null;
|
|
1920
|
+
}
|
|
1921
|
+
},
|
|
1922
|
+
async abort() {
|
|
1923
|
+
if (activeTurn) { activeTurn.cancelled = true; activeTurn.controller.abort(); }
|
|
1924
|
+
for (const done of [...openPermissions]) done({ outcome: { outcome: 'cancelled' } });
|
|
1925
|
+
try { if (sessionId && conn.running) await settleWithin(conn.notify('session/cancel', { sessionId })); } catch {}
|
|
1926
|
+
return true;
|
|
1927
|
+
},
|
|
1928
|
+
// The process is the run's own: it always ends with the run. Its conversation stays in the run's home, where a
|
|
1929
|
+
// resume after a restart finds it (the dispatcher's prune removes the home once the run is gone).
|
|
1930
|
+
async dispose() {
|
|
1931
|
+
const wasAlive = alive;
|
|
1932
|
+
alive = false;
|
|
1933
|
+
activeTurn?.controller.abort();
|
|
1934
|
+
for (const done of [...openPermissions]) done({ outcome: { outcome: 'cancelled' } });
|
|
1935
|
+
if (wasAlive && activeTurn && sessionId && conn.running) { try { await settleWithin(conn.notify('session/cancel', { sessionId })); } catch {} }
|
|
1936
|
+
await settleWithin(conn.close(), 3000);
|
|
1937
|
+
registration?.dispose();
|
|
1938
|
+
},
|
|
1939
|
+
};
|
|
1940
|
+
}
|