synabun 2.0.10 → 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.
- package/CHANGELOG.md +207 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +13 -13
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +30 -17
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +7 -6
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +302 -0
- package/lib/virustotal.mjs +203 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.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/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.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-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- 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 +18 -11
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +22 -63
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- 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/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +14 -14
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +29 -19
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- 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/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +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 +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +642 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +81 -21
- package/mcp-server/src/services/server-instructions.ts +29 -64
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +29 -20
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +592 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3953 -228
- package/neural-interface/i18n/pt-BR.json +3901 -179
- 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 +128 -28
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- 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 +81 -15
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +1073 -200
- package/neural-interface/lib/assistant-envelope.js +156 -2
- 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 +93 -19
- package/neural-interface/lib/assistant-plan-permissions.js +25 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +245 -38
- package/neural-interface/lib/assistant-runtime.js +214 -30
- package/neural-interface/lib/assistant-task-prompt.js +87 -21
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +626 -4
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +84 -0
- package/neural-interface/lib/browser-network-guard.js +476 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +198 -38
- package/neural-interface/lib/claude-agent-bridge.js +11 -2
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +163 -154
- package/neural-interface/lib/cli-resolver.js +13 -3
- package/neural-interface/lib/cli-update-planner.js +52 -41
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +191 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +13 -10
- 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/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +35 -33
- package/neural-interface/lib/mcp-external-servers.js +332 -0
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +177 -25
- package/neural-interface/lib/native-loop-providers.js +965 -66
- package/neural-interface/lib/native-loop-runtime.js +290 -42
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +53 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +793 -0
- 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 +20 -2
- package/neural-interface/lib/rulesets/api.js +7 -6
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +180 -36
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +81 -31
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +298 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +285 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +569 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +216 -0
- package/neural-interface/lib/skills/eval-confinement.js +399 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +135 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +203 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +269 -0
- package/neural-interface/lib/skills/runtime-checks.js +358 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +530 -0
- package/neural-interface/lib/skills/telemetry.js +119 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/bridge.js +6 -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 +1268 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +238 -0
- package/neural-interface/lib/worker-sandbox.js +329 -0
- package/neural-interface/package-lock.json +34 -12
- package/neural-interface/package.json +3 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +3 -3
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +125 -31
- 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 +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
- package/neural-interface/public/shared/assistant/asst-api.js +1 -1
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-control.js +205 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +445 -82
- package/neural-interface/public/shared/assistant/asst-route.js +304 -53
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
- package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
- package/neural-interface/public/shared/assistant/asst-state.js +87 -24
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
- package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
- package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +11 -12
- package/neural-interface/public/shared/cli-status.js +11 -10
- package/neural-interface/public/shared/constants.js +5 -4
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +367 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- 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/crash-notice-view.js +168 -0
- 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 +21 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- 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 +30 -15
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- 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-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +222 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +149 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- 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-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1822 -1756
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -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 +111 -140
- package/neural-interface/public/shared/ui-claude-panel.js +376 -82
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- 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-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +33 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-menubar.js +10 -20
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
- package/neural-interface/public/shared/ui-navbar.js +49 -24
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +27 -15
- package/neural-interface/public/shared/ui-settings.js +683 -526
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +270 -190
- package/neural-interface/public/shared/ui-tool-updates.js +6 -4
- package/neural-interface/public/shared/ui-tooltip.js +81 -51
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +312 -59
- package/neural-interface/public/shared/ui-worker-end.js +5 -1
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +2 -2
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +4553 -2855
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +34 -12
- package/package.json +17 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +6 -6
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Assistant brain: Google Antigravity (`agy acp`, in the brain's own Antigravity home)
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// One `agy acp` process and one ACP session per Assistant session (lib/antigravity/acp-connection.js), started in
|
|
6
|
+
// the brain's own Antigravity home (lib/antigravity/home.js: `--gemini-dir`): SynaBun's MCP server (its child gets
|
|
7
|
+
// the assistant role, the session pin, the desktop grant and the brain's credential from the agent's environment)
|
|
8
|
+
// beside the user's own servers, the user's global rules and skills, and the policy hook that asks this process
|
|
9
|
+
// about every tool call before it runs (lib/antigravity/policy.js → deps.policyCheck: the browser policy, plan mode,
|
|
10
|
+
// a remote session's read-only rules and the route gate; a refusal reaches the model with its reason and the turn
|
|
11
|
+
// goes on). The persona rides as the session's appended system prompt (_meta.antigravity.systemPrompt.append, which
|
|
12
|
+
// agy advertises in initialize). ACP session/update notifications become the unified envelope
|
|
13
|
+
// (assistant-envelope.js createAcpEnvelopeTranslator); a permission request the approval mode does not answer
|
|
14
|
+
// becomes a card (control_request), answered once (never "always": Antigravity would save it for later sessions).
|
|
15
|
+
// The model and the thinking level are the session's config options, switched per turn; images ride as ACP image
|
|
16
|
+
// blocks; Stop is session/cancel; a resumed conversation is session/resume (no replay) in the same home.
|
|
17
|
+
|
|
18
|
+
import { randomUUID } from 'node:crypto';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { acpErrorInfo, createAcpConnection, isAuthRequired } from '../antigravity/acp-connection.js';
|
|
21
|
+
import { assertSafeAntigravityProject, antigravityHomeReadPolicy, antigravityHomeSettings, homeMcpTools, policyHookCommand, prepareAntigravityHome, toAntigravityMcpEntry, userAntigravityMcpServers, userAntigravitySettings, userGeminiDir } from '../antigravity/home.js';
|
|
22
|
+
import { acpCall, acpReadOnlyKind, acpToolPaths, acpUiToolName } from '../antigravity/tool-call.js';
|
|
23
|
+
import { splitAntigravityModel } from '../antigravity/catalog.js';
|
|
24
|
+
import { acpTurnUsage } from '../antigravity/usage.js';
|
|
25
|
+
import { createAcpEnvelopeTranslator } from '../assistant-envelope.js';
|
|
26
|
+
import { planModeInstructions } from '../assistant-persona.js';
|
|
27
|
+
|
|
28
|
+
/** The hook script of every SynaBun Antigravity home. */
|
|
29
|
+
export const ANTIGRAVITY_BRAIN_POLICY_HOOK = fileURLToPath(new URL('../antigravity/policy-hook.mjs', import.meta.url));
|
|
30
|
+
const CANCEL_GRACE_MS = 8_000;
|
|
31
|
+
const MCP_WATCH_MS = 120_000;
|
|
32
|
+
const LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
|
|
33
|
+
|
|
34
|
+
/** The Assistant's Antigravity approval mode: 'auto' (every call the policy allows runs) or 'default' (cards). */
|
|
35
|
+
export function antigravityApprovalMode(mode) {
|
|
36
|
+
return mode === 'auto' || mode === 'acceptEdits' || mode === 'bypassPermissions' ? 'auto' : 'default';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Composer images ({ base64 | data, mediaType }) → ACP image blocks. */
|
|
40
|
+
export function acpImageBlocks(images = []) {
|
|
41
|
+
const blocks = [];
|
|
42
|
+
for (const image of Array.isArray(images) ? images : []) {
|
|
43
|
+
let data = image?.base64 || image?.data || null;
|
|
44
|
+
let mimeType = image?.mediaType || image?.media_type || image?.mime || image?.mimeType || 'image/png';
|
|
45
|
+
if (!data || typeof data !== 'string') continue;
|
|
46
|
+
const inline = /^data:([^;,]+);base64,(.*)$/s.exec(data);
|
|
47
|
+
if (inline) { mimeType = inline[1]; data = inline[2]; }
|
|
48
|
+
blocks.push({ type: 'image', mimeType, data });
|
|
49
|
+
}
|
|
50
|
+
return blocks;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The ACP permission option for an answer: explicit kinds only, never allow-always. */
|
|
54
|
+
function permissionOption(options, wanted) {
|
|
55
|
+
const list = Array.isArray(options) ? options.filter((option) => option && typeof option.optionId === 'string') : [];
|
|
56
|
+
for (const kind of wanted) {
|
|
57
|
+
if (kind === 'allow_always') continue;
|
|
58
|
+
const found = list.find((option) => option.kind === kind);
|
|
59
|
+
if (found) return found.optionId;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The MCP servers of a brain's home: SynaBun's own entry, then every enabled server of the user's own Antigravity
|
|
66
|
+
* configuration (a brain keeps the user's servers, as a Claude brain keeps the user's settings).
|
|
67
|
+
*/
|
|
68
|
+
export function antigravityBrainServers({ synabunMcpEntry = null, userGemini = userGeminiDir() } = {}) {
|
|
69
|
+
const servers = {};
|
|
70
|
+
const user = userAntigravityMcpServers(userGemini);
|
|
71
|
+
const own = synabunMcpEntry || user.SynaBun || null;
|
|
72
|
+
if (own) servers.SynaBun = toAntigravityMcpEntry(own);
|
|
73
|
+
for (const [name, entry] of Object.entries(user)) {
|
|
74
|
+
if (name === 'SynaBun' || entry?.disabled === true) continue;
|
|
75
|
+
servers[name] = toAntigravityMcpEntry(entry);
|
|
76
|
+
}
|
|
77
|
+
return servers;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createAntigravityBrain({ session, sink, deps = {}, persona = '' } = {}) {
|
|
81
|
+
if (typeof deps.antigravityLaunch !== 'function') throw new Error('Antigravity brain requires deps.antigravityLaunch');
|
|
82
|
+
const brain = session.brain || {};
|
|
83
|
+
const cwd = brain.cwd || deps.PACKAGE_ROOT || process.cwd();
|
|
84
|
+
const connect = typeof deps.connect === 'function' ? deps.connect : createAcpConnection;
|
|
85
|
+
const homeDir = typeof deps.antigravityHome === 'function' ? deps.antigravityHome(session.id) : null;
|
|
86
|
+
const userGemini = deps.userGemini || userGeminiDir();
|
|
87
|
+
const remoteReadOnly = deps.remoteReadOnly === true;
|
|
88
|
+
let approvalMode = antigravityApprovalMode(brain.permissionMode);
|
|
89
|
+
let planMode = brain.planMode === true || brain.permissionMode === 'plan';
|
|
90
|
+
let conn = null;
|
|
91
|
+
let sessionId = session.providerSessionId || null;
|
|
92
|
+
let resumeWanted = !!sessionId;
|
|
93
|
+
let registration = null;
|
|
94
|
+
let configOptions = [];
|
|
95
|
+
let turn = null; // { planned, cancelled, cancelTimer, model }
|
|
96
|
+
let lastSessionUsage = deps.sessionUsageBase && typeof deps.sessionUsageBase === 'object' ? deps.sessionUsageBase : null;
|
|
97
|
+
let startPromise = null;
|
|
98
|
+
let disposed = false;
|
|
99
|
+
let mcpTimer = null;
|
|
100
|
+
let mcpReported = null;
|
|
101
|
+
let replaying = false;
|
|
102
|
+
const pendingControls = new Map(); // requestId → { resolve, options }
|
|
103
|
+
|
|
104
|
+
const emit = (packet) => { if (!disposed) sink.send(packet); };
|
|
105
|
+
const note = (text) => emit({ type: 'stderr', text });
|
|
106
|
+
const optionOf = (category) => configOptions.find((o) => o?.category === category || o?.id === category) || null;
|
|
107
|
+
const valuesOf = (option) => {
|
|
108
|
+
const out = [];
|
|
109
|
+
for (const entry of option?.options || []) for (const v of Array.isArray(entry?.options) ? entry.options : [entry]) if (v && v.value !== undefined) out.push(String(v.value));
|
|
110
|
+
return out;
|
|
111
|
+
};
|
|
112
|
+
const currentValue = (category) => { const option = optionOf(category); return option?.currentValue !== undefined && option?.currentValue !== null ? String(option.currentValue) : null; };
|
|
113
|
+
|
|
114
|
+
const translator = createAcpEnvelopeTranslator({
|
|
115
|
+
emit,
|
|
116
|
+
brain: { cwd, sessionId: () => sessionId, model: () => currentValue('model') || brain.model || null },
|
|
117
|
+
planTurn: () => turn?.planned === true,
|
|
118
|
+
});
|
|
119
|
+
emit({ type: 'engine', engine: 'antigravity', brain: 'antigravity' });
|
|
120
|
+
|
|
121
|
+
function applyModes(mode, plan) {
|
|
122
|
+
if (mode === 'plan') planMode = true;
|
|
123
|
+
else if (mode) approvalMode = antigravityApprovalMode(mode);
|
|
124
|
+
if (typeof plan === 'boolean') planMode = plan;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The policy hook's question for this brain: first the runtime's checks (deps.policyCheck: browser policy, plan mode, remote read-only, route gate); then the approval
|
|
129
|
+
* mode: auto lets every call run, default lets reads and SynaBun's own tools run and asks about the rest.
|
|
130
|
+
*/
|
|
131
|
+
function policyCheck(call) {
|
|
132
|
+
let verdict = null;
|
|
133
|
+
try { verdict = typeof deps.policyCheck === 'function' ? deps.policyCheck(call) : null; } catch (error) { return { decision: 'deny', reason: `SynaBun could not check this call (${error?.message || error}).` }; }
|
|
134
|
+
if (verdict?.decision === 'deny') return verdict;
|
|
135
|
+
const homeRead = antigravityHomeReadPolicy(call, { homeDir, cwd });
|
|
136
|
+
if (homeRead) return homeRead;
|
|
137
|
+
if (remoteReadOnly || approvalMode === 'auto') return { decision: 'allow' };
|
|
138
|
+
if (acpReadOnlyKind(call.kind)) return { decision: 'allow' };
|
|
139
|
+
if (call.mcp?.server === 'SynaBun') return { decision: 'allow' };
|
|
140
|
+
return { decision: 'ask' };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function cancelControls(reason = 'turn_ended') {
|
|
144
|
+
for (const [requestId, pending] of pendingControls) {
|
|
145
|
+
pendingControls.delete(requestId);
|
|
146
|
+
emit({ type: 'control_cancelled', request_id: requestId, reason });
|
|
147
|
+
try { pending.resolve({ outcome: { outcome: 'cancelled' } }); } catch { /* answered */ }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function onPermission(params, { signal } = {}) {
|
|
152
|
+
if (disposed) return { outcome: { outcome: 'cancelled' } };
|
|
153
|
+
const call = acpCall(params);
|
|
154
|
+
const options = params?.options || [];
|
|
155
|
+
const pick = (kinds) => {
|
|
156
|
+
const optionId = permissionOption(options, kinds);
|
|
157
|
+
return optionId ? { outcome: { outcome: 'selected', optionId } } : { outcome: { outcome: 'cancelled' } };
|
|
158
|
+
};
|
|
159
|
+
const verdict = policyCheck(call);
|
|
160
|
+
// The hook asked first; a refusal reaching here (a call the hook never saw) ends the turn, as a user's would.
|
|
161
|
+
if (verdict.decision === 'deny') return pick(['reject_once', 'reject_always']);
|
|
162
|
+
if (verdict.decision === 'allow') return pick(['allow_once']);
|
|
163
|
+
const requestId = `agy-${randomUUID()}`;
|
|
164
|
+
const packet = {
|
|
165
|
+
type: 'control_request',
|
|
166
|
+
request_id: requestId,
|
|
167
|
+
request: {
|
|
168
|
+
subtype: 'can_use_tool', provider: 'antigravity', kind: 'permission',
|
|
169
|
+
tool_name: acpUiToolName(call),
|
|
170
|
+
input: call.mcp ? { ...call.mcp.args } : { ...call.args, ...(call.command ? { command: call.command } : {}) },
|
|
171
|
+
title: call.title || null,
|
|
172
|
+
brain_native: { kind: 'permission', toolCallId: call.id, sessionId: params?.sessionId || sessionId, toolCall: params?.toolCall || null },
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
return new Promise((resolveAnswer) => {
|
|
176
|
+
pendingControls.set(requestId, { resolve: resolveAnswer, options });
|
|
177
|
+
signal?.addEventListener?.('abort', () => {
|
|
178
|
+
if (!pendingControls.delete(requestId)) return;
|
|
179
|
+
emit({ type: 'control_cancelled', request_id: requestId, reason: 'withdrawn' });
|
|
180
|
+
resolveAnswer({ outcome: { outcome: 'cancelled' } });
|
|
181
|
+
}, { once: true });
|
|
182
|
+
emit(packet);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function reportMcp() {
|
|
187
|
+
if (!homeDir) return null;
|
|
188
|
+
const tools = homeMcpTools(homeDir, 'SynaBun');
|
|
189
|
+
const status = tools.length ? 'connected' : null;
|
|
190
|
+
if (status && mcpReported !== status) {
|
|
191
|
+
mcpReported = status;
|
|
192
|
+
emit({ type: 'event', event: { type: 'system', subtype: 'mcp_status', servers: [{ name: 'SynaBun', status, tools: tools.length }] } });
|
|
193
|
+
}
|
|
194
|
+
return status;
|
|
195
|
+
}
|
|
196
|
+
function watchMcp() {
|
|
197
|
+
if (!homeDir || mcpTimer) return;
|
|
198
|
+
const until = Date.now() + MCP_WATCH_MS;
|
|
199
|
+
mcpTimer = setInterval(() => {
|
|
200
|
+
if (disposed || reportMcp() || Date.now() > until) { clearInterval(mcpTimer); mcpTimer = null; }
|
|
201
|
+
}, 1000);
|
|
202
|
+
mcpTimer.unref?.();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function openSession() {
|
|
206
|
+
const meta = persona ? { antigravity: { systemPrompt: { append: persona } } } : undefined;
|
|
207
|
+
const init = await conn.initialize();
|
|
208
|
+
let answer = null;
|
|
209
|
+
if (sessionId && resumeWanted) {
|
|
210
|
+
const caps = init?.agentCapabilities?.sessionCapabilities || {};
|
|
211
|
+
// agy 1.4.12 sends the conversation's history again while it resumes (session/resume as session/load): the
|
|
212
|
+
// panel has it already, so nothing that arrives before the answer is shown.
|
|
213
|
+
replaying = true;
|
|
214
|
+
try {
|
|
215
|
+
answer = await conn.request(caps.resume ? 'session/resume' : 'session/load', { sessionId, cwd, mcpServers: [], ...(meta ? { _meta: meta } : {}) });
|
|
216
|
+
sessionId = String(answer?.sessionId || sessionId);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (isAuthRequired(error)) throw error;
|
|
219
|
+
note(`Antigravity could not resume its conversation (${acpErrorInfo(error).message}); this brain starts a new one.`);
|
|
220
|
+
answer = null;
|
|
221
|
+
sessionId = null;
|
|
222
|
+
} finally {
|
|
223
|
+
replaying = false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (!answer) {
|
|
227
|
+
answer = await conn.request('session/new', { cwd, mcpServers: [], ...(meta ? { _meta: meta } : {}) });
|
|
228
|
+
sessionId = String(answer?.sessionId || '');
|
|
229
|
+
if (!sessionId) throw new Error('Antigravity did not return a session id');
|
|
230
|
+
lastSessionUsage = null;
|
|
231
|
+
}
|
|
232
|
+
resumeWanted = false;
|
|
233
|
+
configOptions = Array.isArray(answer?.configOptions) ? answer.configOptions : [];
|
|
234
|
+
try { deps.onAntigravitySession?.(sessionId); } catch { /* bookkeeping */ }
|
|
235
|
+
reportMcp();
|
|
236
|
+
watchMcp();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function boot() {
|
|
240
|
+
if (disposed) throw new Error('Antigravity brain disposed');
|
|
241
|
+
const launch = deps.antigravityLaunch();
|
|
242
|
+
if (!launch?.command) throw new Error('The Antigravity CLI (agy) is not installed. Install it from the Antigravity side panel, sign in there, then try again — or switch the Assistant to another provider.');
|
|
243
|
+
assertSafeAntigravityProject(cwd);
|
|
244
|
+
let hookCommand = null;
|
|
245
|
+
if (homeDir) {
|
|
246
|
+
if (deps.policy?.register && deps.policyUrl) hookCommand = policyHookCommand({ script: deps.policyHookScript || ANTIGRAVITY_BRAIN_POLICY_HOOK });
|
|
247
|
+
prepareAntigravityHome({
|
|
248
|
+
dir: homeDir,
|
|
249
|
+
mcpServers: antigravityBrainServers({ synabunMcpEntry: typeof deps.synabunMcpEntry === 'function' ? deps.synabunMcpEntry() : deps.synabunMcpEntry, userGemini }),
|
|
250
|
+
hookCommand,
|
|
251
|
+
settings: antigravityHomeSettings({ userSettings: userAntigravitySettings(userGemini) }),
|
|
252
|
+
userGemini,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (hookCommand) registration = deps.policy.register((call) => (disposed ? { decision: 'deny', reason: 'This Assistant session ended.' } : policyCheck(call)), { label: `brain ${session.id}` });
|
|
256
|
+
const base = typeof deps.childEnv === 'function' ? deps.childEnv() : { ...process.env };
|
|
257
|
+
for (const key of ['SYNABUN_TOOLS', 'SYNABUN_TOOLS_PATH', 'SYNABUN_PROFILE', 'SYNABUN_RUNTIME_PROFILE_PATH', 'SYNABUN_TOOL_CATALOG_MODE', 'SYNABUN_AGY_POLICY_URL', 'SYNABUN_AGY_POLICY_TOKEN', 'SYNABUN_BROWSER_SESSION', 'SYNABUN_BROWSER_TAB']) delete base[key];
|
|
258
|
+
const env = {
|
|
259
|
+
...base,
|
|
260
|
+
// The brain's SynaBun MCP child (stdio) reads who it serves from here (mcp-server/src/services/identity.ts).
|
|
261
|
+
SYNABUN_ROLE: 'assistant',
|
|
262
|
+
SYNABUN_TERMINAL_SESSION: String(session.id),
|
|
263
|
+
...(deps.desktopGrant ? { SYNABUN_DESKTOP_GRANT: String(deps.desktopGrant) } : {}),
|
|
264
|
+
...(deps.brainCredential ? { SYNABUN_BRAIN_TOKEN: String(deps.brainCredential) } : {}),
|
|
265
|
+
...(registration ? { SYNABUN_AGY_POLICY_URL: deps.policyUrl, SYNABUN_AGY_POLICY_TOKEN: registration.token } : {}),
|
|
266
|
+
};
|
|
267
|
+
conn = connect({
|
|
268
|
+
command: launch.command,
|
|
269
|
+
args: launch.args || [],
|
|
270
|
+
acpArgs: homeDir ? ['--gemini-dir', homeDir] : [],
|
|
271
|
+
cwd,
|
|
272
|
+
env,
|
|
273
|
+
clientInfo: { name: 'synabun', title: 'SynaBun Assistant', version: '0' },
|
|
274
|
+
onUpdate: (params) => {
|
|
275
|
+
if (disposed || replaying || !params?.update || !sessionId || params.sessionId !== sessionId) return;
|
|
276
|
+
// Between turns only titles and the like count: a stray message of a turn that already ended is not shown.
|
|
277
|
+
if (!turn && params.update.sessionUpdate !== 'session_info_update') return;
|
|
278
|
+
translator.handle(params.update);
|
|
279
|
+
},
|
|
280
|
+
onPermission,
|
|
281
|
+
onExit: (info) => {
|
|
282
|
+
if (disposed) return;
|
|
283
|
+
cancelControls('agent_exited');
|
|
284
|
+
const why = info?.error || (info?.signal ? `signal ${info.signal}` : `code ${info?.code}`);
|
|
285
|
+
if (turn) finishTurn(null, new Error(`Antigravity exited (${why})${info?.stderr ? `: ${String(info.stderr).trim().split('\n').slice(-2).join(' ')}` : ''}`));
|
|
286
|
+
else note(`Antigravity exited (${why}); the next message starts it again.`);
|
|
287
|
+
conn = null;
|
|
288
|
+
startPromise = null;
|
|
289
|
+
resumeWanted = !!sessionId;
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
try {
|
|
293
|
+
await openSession();
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const auth = isAuthRequired(error);
|
|
296
|
+
const message = auth ? 'Antigravity is not signed in: open the Antigravity panel (or run `agy` in a terminal) and sign in, then try again.' : `Antigravity could not start: ${acpErrorInfo(error).message}`;
|
|
297
|
+
registration?.dispose();
|
|
298
|
+
registration = null;
|
|
299
|
+
try { await conn?.close(); } catch { /* gone */ }
|
|
300
|
+
conn = null;
|
|
301
|
+
startPromise = null;
|
|
302
|
+
throw Object.assign(new Error(message), { code: auth ? 'AUTH_REQUIRED' : 'START_FAILED' });
|
|
303
|
+
}
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
function start() {
|
|
307
|
+
if (!startPromise) startPromise = boot();
|
|
308
|
+
return startPromise;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async function setOption(category, value, label) {
|
|
312
|
+
const option = optionOf(category);
|
|
313
|
+
if (!value || !option) return;
|
|
314
|
+
if (String(option.currentValue) === String(value)) return;
|
|
315
|
+
const accepted = valuesOf(option);
|
|
316
|
+
if (accepted.length && !accepted.includes(String(value))) { note(`Antigravity offers no ${label} "${value}" here; it keeps ${option.currentValue}.`); return; }
|
|
317
|
+
try {
|
|
318
|
+
const answer = await conn.request('session/set_config_option', { sessionId, configId: option.id, value: String(value) });
|
|
319
|
+
if (Array.isArray(answer?.configOptions)) configOptions = answer.configOptions;
|
|
320
|
+
} catch (error) { note(`Antigravity kept its ${label} (${acpErrorInfo(error).message}).`); }
|
|
321
|
+
}
|
|
322
|
+
/** The turn's model and thinking level (the record may have changed since the session started; a routed turn names its own). */
|
|
323
|
+
async function applyModel(model, effort) {
|
|
324
|
+
const wanted = splitAntigravityModel(model, valuesOf(optionOf('model')));
|
|
325
|
+
if (wanted.model) await setOption('model', wanted.model, 'model');
|
|
326
|
+
const level = effort && LEVELS.has(String(effort).toLowerCase()) ? String(effort).toLowerCase() : wanted.effort;
|
|
327
|
+
if (level) await setOption('thought_level', level, 'thinking level');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function finishTurn(answer, error = null) {
|
|
331
|
+
const current = turn;
|
|
332
|
+
if (!current) return;
|
|
333
|
+
turn = null;
|
|
334
|
+
if (current.cancelTimer) clearTimeout(current.cancelTimer);
|
|
335
|
+
cancelControls('turn_ended');
|
|
336
|
+
const usage = answer?.usage ? acpTurnUsage(answer.usage, lastSessionUsage) : null;
|
|
337
|
+
if (answer?.usage) {
|
|
338
|
+
lastSessionUsage = answer.usage;
|
|
339
|
+
try { deps.onAntigravitySessionUsage?.(sessionId, answer.usage); } catch { /* bookkeeping */ }
|
|
340
|
+
}
|
|
341
|
+
if (usage) { try { deps.onAntigravityUsage?.({ usage, model: currentValue('model') || brain.model || null, sessionId }); } catch { /* metering never breaks a turn */ } }
|
|
342
|
+
const stopReason = current.cancelled ? 'cancelled' : (answer?.stopReason || 'end_turn');
|
|
343
|
+
translator.endTurn({ stopReason, usage, error: error && !current.cancelled ? (error.message || String(error)) : null, planned: current.planned === true });
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async function runPrompt(blocks, { planned = false } = {}) {
|
|
347
|
+
translator.reset();
|
|
348
|
+
turn = { planned, cancelled: false, cancelTimer: null };
|
|
349
|
+
const mine = turn;
|
|
350
|
+
conn.request('session/prompt', { sessionId, prompt: blocks }, { timeoutMs: 0 })
|
|
351
|
+
.then((answer) => { if (turn === mine) finishTurn(answer); })
|
|
352
|
+
.catch((error) => { if (turn === mine) finishTurn(null, new Error(acpErrorInfo(error).message)); });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
kind: 'antigravity',
|
|
357
|
+
start,
|
|
358
|
+
async sendUserTurn({ text, images = [], model = null, effort = null, permissionMode: mode = null, planMode: plan = null } = {}) {
|
|
359
|
+
await start();
|
|
360
|
+
if (disposed || !conn) return false;
|
|
361
|
+
if (turn) throw new Error('Antigravity is still answering the last message');
|
|
362
|
+
applyModes(mode, plan);
|
|
363
|
+
if (resumeWanted && sessionId) await openSession();
|
|
364
|
+
await applyModel(model || brain.model || null, effort || brain.effort || null);
|
|
365
|
+
// A plan turn carries what plan mode means here (a remote session's read-only brain does not).
|
|
366
|
+
const planned = planMode && !remoteReadOnly;
|
|
367
|
+
const body = planned ? `<system-reminder>\n${planModeInstructions({ provider: 'antigravity' })}\n</system-reminder>\n\n${String(text ?? '')}` : String(text ?? '');
|
|
368
|
+
await runPrompt([{ type: 'text', text: body }, ...acpImageBlocks(images)], { planned });
|
|
369
|
+
return true;
|
|
370
|
+
},
|
|
371
|
+
async abort() {
|
|
372
|
+
if (!turn) { cancelControls('stopped'); return; }
|
|
373
|
+
const current = turn;
|
|
374
|
+
current.cancelled = true;
|
|
375
|
+
cancelControls('stopped');
|
|
376
|
+
try { if (conn && sessionId) await conn.notify('session/cancel', { sessionId }); } catch { /* the answer or the grace timer ends it */ }
|
|
377
|
+
// An agent that never answers the cancelled prompt: the turn ends here anyway.
|
|
378
|
+
current.cancelTimer = setTimeout(() => { if (turn === current) finishTurn(null); }, CANCEL_GRACE_MS);
|
|
379
|
+
current.cancelTimer.unref?.();
|
|
380
|
+
},
|
|
381
|
+
async setPermissionMode(mode, { planMode: plan = null } = {}) { applyModes(mode, plan); emit({ type: 'mode_changed', mode: approvalMode, planMode }); },
|
|
382
|
+
respondControl(requestId, response = {}) {
|
|
383
|
+
const pending = pendingControls.get(String(requestId));
|
|
384
|
+
if (!pending) { emit({ type: 'error', message: `No pending Antigravity request ${requestId}` }); return; }
|
|
385
|
+
pendingControls.delete(String(requestId));
|
|
386
|
+
// Once, whatever the answer says about "always": Antigravity would save it for every later session.
|
|
387
|
+
const allow = response?.behavior === 'allow';
|
|
388
|
+
const optionId = permissionOption(pending.options, allow ? ['allow_once'] : ['reject_once', 'reject_always']);
|
|
389
|
+
pending.resolve(optionId ? { outcome: { outcome: 'selected', optionId } } : { outcome: { outcome: 'cancelled' } });
|
|
390
|
+
},
|
|
391
|
+
// Antigravity's own /compact command, as a turn of its own (busy until it ends).
|
|
392
|
+
async compact() {
|
|
393
|
+
await start();
|
|
394
|
+
if (disposed || !conn || turn) return;
|
|
395
|
+
await runPrompt([{ type: 'text', text: '/compact' }]);
|
|
396
|
+
},
|
|
397
|
+
async mcpStatus() { if (!reportMcp()) emit({ type: 'event', event: { type: 'system', subtype: 'mcp_status', servers: [] } }); },
|
|
398
|
+
// The conversation to pick up: resumed before the next message (session/resume in the brain's home).
|
|
399
|
+
async resume(id) { if (!id) return; sessionId = String(id); resumeWanted = true; lastSessionUsage = null; },
|
|
400
|
+
async listSessions() { return []; },
|
|
401
|
+
isBusy() { return !!turn || pendingControls.size > 0; },
|
|
402
|
+
// The route gate: its hook checks every call before it runs; without one (no policy wired) the runtime checks
|
|
403
|
+
// the tool starts it sees (the reactive fallback).
|
|
404
|
+
get gateMode() { return registration ? 'hook' : 'reactive'; },
|
|
405
|
+
identity() {
|
|
406
|
+
return { providerSessionId: sessionId, providerThreadId: null, accountId: null, model: currentValue('model') || brain.model || null, effort: currentValue('thought_level') || brain.effort || null, cwd, busy: !!turn, home: homeDir };
|
|
407
|
+
},
|
|
408
|
+
async dispose() {
|
|
409
|
+
if (disposed) return;
|
|
410
|
+
const wasRunning = !!turn;
|
|
411
|
+
cancelControls('brain_disposed');
|
|
412
|
+
if (wasRunning && conn && sessionId) { try { await conn.notify('session/cancel', { sessionId }); } catch { /* closing anyway */ } }
|
|
413
|
+
disposed = true;
|
|
414
|
+
if (mcpTimer) { clearInterval(mcpTimer); mcpTimer = null; }
|
|
415
|
+
if (turn?.cancelTimer) clearTimeout(turn.cancelTimer);
|
|
416
|
+
turn = null;
|
|
417
|
+
registration?.dispose();
|
|
418
|
+
registration = null;
|
|
419
|
+
try { await conn?.close(); } catch { /* gone */ }
|
|
420
|
+
conn = null;
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
}
|
|
@@ -123,10 +123,11 @@ export function createClaudeBrain({ session, sink, deps = {}, persona = '', hook
|
|
|
123
123
|
'X-Synabun-Role': 'assistant', 'X-Synabun-Terminal': session.id, 'X-Synabun-Memory-Session': session.id,
|
|
124
124
|
...(deps.desktopGrant ? { 'X-Synabun-Desktop-Grant': deps.desktopGrant } : {}),
|
|
125
125
|
...mcpHeaders,
|
|
126
|
-
//
|
|
126
|
+
// This brain launch's credential (assistant-runtime.js mintBrainCredential). The header names the variable and
|
|
127
127
|
// the CLI expands it from its own environment (below): the MCP config is on its command line, which every
|
|
128
128
|
// account of the computer can read, an environment only this user's processes. The in-process MCP server
|
|
129
|
-
// keeps the value for the request it arrived with, and sends it
|
|
129
|
+
// keeps the value for the request it arrived with, and sends it only to the routes that ask who the brain is
|
|
130
|
+
// (whatsapp_send_file, the Skills Service). Last, so nothing replaces it.
|
|
130
131
|
...(deps.brainCredential ? { 'X-Synabun-Brain-Token': '${SYNABUN_BRAIN_TOKEN}' } : {}),
|
|
131
132
|
},
|
|
132
133
|
// A remote (WhatsApp) session never pre-approves computer use: its PreToolUse hook refuses, asks or allows each call.
|
|
@@ -143,7 +144,7 @@ export function createClaudeBrain({ session, sink, deps = {}, persona = '', hook
|
|
|
143
144
|
...(typeof deps.claudeAccountEnv === 'function' ? deps.claudeAccountEnv(brain.accountId) : {}),
|
|
144
145
|
SYNABUN_ASSISTANT_SESSION: String(session.id),
|
|
145
146
|
...(deps.userContextThreads === true ? { SYNABUN_ASSISTANT_THREADS: '1' } : {}),
|
|
146
|
-
// The value of the X-Synabun-Brain-Token header above
|
|
147
|
+
// The value of the X-Synabun-Brain-Token header above.
|
|
147
148
|
...(deps.brainCredential ? { SYNABUN_BRAIN_TOKEN: deps.brainCredential } : {}),
|
|
148
149
|
},
|
|
149
150
|
maxBudgetUsd: Number(deps.maxBudgetUsd) > 0 ? Number(deps.maxBudgetUsd) : undefined,
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
// PreToolUse payload from stdin and asks lib/browser-tool-policy.js here, with
|
|
7
7
|
// no server round trip; a refusal becomes permissionDecision "deny" with the
|
|
8
8
|
// reason. Script paths resolve against the payload's cwd, else
|
|
9
|
-
// SYNABUN_BROWSER_POLICY_CWD (the run's project)
|
|
9
|
+
// SYNABUN_BROWSER_POLICY_CWD (the run's project); SYNABUN_BROWSER_POLICY_ROOTS
|
|
10
|
+
// (a JSON list, written as the run starts) names the registered code projects
|
|
11
|
+
// its test runners may also run in. An unreadable payload allows
|
|
10
12
|
// the call: the policy is a speed bump, not a sandbox. A policy module that
|
|
11
13
|
// cannot load fails closed (logged on stderr): shell commands, web search and
|
|
12
14
|
// every MCP tool but SynaBun's are denied with that reason.
|
|
@@ -25,6 +27,14 @@ function unloadedDenial(tool) {
|
|
|
25
27
|
return `SynaBun browser policy: ${tool} was refused — SynaBun's browser policy could not load (${loadError?.message || 'browserToolDenial is missing'}), so no command, web search or other server's tool can be checked for a browser launch. SynaBun's own tools still work. Stop and report this`;
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/** The registered code projects from the env (a JSON list of paths); anything unreadable is none. */
|
|
31
|
+
function policyRoots() {
|
|
32
|
+
try {
|
|
33
|
+
const list = JSON.parse(process.env.SYNABUN_BROWSER_POLICY_ROOTS || '[]');
|
|
34
|
+
return Array.isArray(list) ? list.filter((path) => typeof path === 'string') : [];
|
|
35
|
+
} catch { return []; }
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
let raw = '';
|
|
29
39
|
try { for await (const chunk of process.stdin) raw += chunk; } catch {}
|
|
30
40
|
let payload = {};
|
|
@@ -35,7 +45,7 @@ try {
|
|
|
35
45
|
const input = payload.tool_input && typeof payload.tool_input === 'object' ? payload.tool_input : {};
|
|
36
46
|
const cwd = (typeof payload.cwd === 'string' && payload.cwd) || process.env.SYNABUN_BROWSER_POLICY_CWD || process.cwd();
|
|
37
47
|
if (typeof browserToolDenial !== 'function') process.stderr.write(`[SynaBun] browser policy could not load (${loadError?.message || 'browserToolDenial is missing'}); denying shell, web search and other servers' tools\n`);
|
|
38
|
-
const reason = !tool ? null : typeof browserToolDenial === 'function' ? browserToolDenial(tool, input, { host: 'codex', cwd }) : unloadedDenial(tool);
|
|
48
|
+
const reason = !tool ? null : typeof browserToolDenial === 'function' ? browserToolDenial(tool, input, { host: 'codex', cwd, roots: policyRoots() }) : unloadedDenial(tool);
|
|
39
49
|
// Codex prints "Command blocked by PreToolUse hook: <reason>. Command: <cmd>", so
|
|
40
50
|
// the reason goes without its own final period.
|
|
41
51
|
if (reason) process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason.replace(/[.\s]+$/, '') } }));
|
|
@@ -4,9 +4,19 @@
|
|
|
4
4
|
// tool may run; a refusal becomes permissionDecision "deny" with the reason.
|
|
5
5
|
// The call's whole tool_input travels (the remote denylist reads paths from
|
|
6
6
|
// it), marked inputComplete; one too big to send goes as its command/action
|
|
7
|
-
// only, marked incomplete.
|
|
8
|
-
// allows the call — except in a WhatsApp session
|
|
9
|
-
// where a call SynaBun could not check is
|
|
7
|
+
// only, marked incomplete. No env or no answer at all (the server unreachable
|
|
8
|
+
// or slow) allows the call — except in a WhatsApp session
|
|
9
|
+
// (SYNABUN_ROUTE_GATE_REMOTE=1), where a call SynaBun could not check is
|
|
10
|
+
// denied. An answer that is not a decision (the check itself refused, such as
|
|
11
|
+
// 403 PEER_REFUSED, an error status, a body without `allow`) denies the call in
|
|
12
|
+
// every session and says what SynaBun answered: a refusal never passes for an
|
|
13
|
+
// allow.
|
|
14
|
+
//
|
|
15
|
+
// The request carries the session's pin (X-Synabun-Assistant): this hook runs
|
|
16
|
+
// under the brain's Codex app-server, an AI agent's process tree, which
|
|
17
|
+
// SynaBun's owner gate (lib/owner-authority.js) refuses unless the call says
|
|
18
|
+
// it is an agent's own. The per-session token in the body is what the route
|
|
19
|
+
// itself checks.
|
|
10
20
|
|
|
11
21
|
const url = process.env.SYNABUN_ROUTE_GATE_URL;
|
|
12
22
|
const session = process.env.SYNABUN_ROUTE_GATE_SESSION;
|
|
@@ -14,6 +24,7 @@ const token = process.env.SYNABUN_ROUTE_GATE_TOKEN;
|
|
|
14
24
|
const remote = process.env.SYNABUN_ROUTE_GATE_REMOTE === '1';
|
|
15
25
|
const MAX_INPUT_BYTES = 256 * 1024;
|
|
16
26
|
const UNCHECKED = 'SynaBun could not check this call, so a WhatsApp session does not run it.';
|
|
27
|
+
const PIN_HEADER = 'x-synabun-assistant';
|
|
17
28
|
|
|
18
29
|
let raw = '';
|
|
19
30
|
try { for await (const chunk of process.stdin) raw += chunk; } catch {}
|
|
@@ -37,20 +48,32 @@ function callArguments(toolInput) {
|
|
|
37
48
|
function deny(reason) {
|
|
38
49
|
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: String(reason).replace(/[.\s]+$/, '') } }));
|
|
39
50
|
}
|
|
51
|
+
/** The refusal of a call whose check got an answer that is not a decision: what SynaBun answered, in short. */
|
|
52
|
+
function notADecision(status, body) {
|
|
53
|
+
const code = body && typeof body === 'object' && typeof body.code === 'string' ? ` ${body.code.slice(0, 64)}` : '';
|
|
54
|
+
const said = body && typeof body === 'object' && typeof body.error === 'string' ? `: ${body.error.slice(0, 300)}` : '';
|
|
55
|
+
return `SynaBun could not check this call (its route gate answered ${status}${code}${said}), so it did not run.`;
|
|
56
|
+
}
|
|
40
57
|
|
|
41
58
|
if (url && session && token) {
|
|
59
|
+
let response = null;
|
|
42
60
|
try {
|
|
43
|
-
|
|
61
|
+
response = await fetch(url, {
|
|
44
62
|
method: 'POST',
|
|
45
|
-
|
|
63
|
+
// The session id as a header value: printable ASCII only (fetch refuses anything else before sending).
|
|
64
|
+
headers: { 'content-type': 'application/json', [PIN_HEADER]: String(session).replace(/[^\x21-\x7e]/g, '').slice(0, 200) },
|
|
46
65
|
body: JSON.stringify({ session, token, host: 'codex', tool: String(input.tool_name || input.toolName || input.tool || ''), agent: input.agent_id || null, ...callArguments(input.tool_input) }),
|
|
47
66
|
signal: AbortSignal.timeout(5000),
|
|
48
67
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
else if (remote && !(decision && decision.allow === true)) deny(UNCHECKED);
|
|
52
|
-
} catch {
|
|
68
|
+
} catch { response = null; }
|
|
69
|
+
if (!response) {
|
|
53
70
|
if (remote) deny(UNCHECKED);
|
|
71
|
+
} else {
|
|
72
|
+
let decision = null;
|
|
73
|
+
try { decision = await response.json(); } catch { decision = null; }
|
|
74
|
+
if (response.ok && decision && decision.allow === true) { /* allowed: Codex runs the call */ }
|
|
75
|
+
else if (response.ok && decision && decision.allow === false) deny(decision.reason || 'SynaBun refused this call.');
|
|
76
|
+
else deny(notADecision(response.status, decision));
|
|
54
77
|
}
|
|
55
78
|
}
|
|
56
79
|
process.exit(0);
|
|
@@ -14,6 +14,8 @@ import { createCodexEnvelopeTranslator, codexControlResponse } from '../assistan
|
|
|
14
14
|
import { baseModelId, contextVariantOf } from '../assistant-catalog.js';
|
|
15
15
|
import { codexPlanPermission, codexReadOnlyPermission, planDenyMessage, readOnlyDenyMessage } from '../assistant-plan-permissions.js';
|
|
16
16
|
import { planModeInstructions } from '../assistant-persona.js';
|
|
17
|
+
import { shouldAutoAcceptCodexMcpToolApproval } from '../codex-mcp-approvals.js';
|
|
18
|
+
import { codexMcpToolApproval } from '../../public/shared/cdx/cdx-protocol.js';
|
|
17
19
|
|
|
18
20
|
const READY_TIMEOUT_MS = 90_000;
|
|
19
21
|
// Approvals the Codex sidepanel's Auto-accept answers on its own (cdx-requests.js).
|
|
@@ -83,7 +85,7 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
|
|
|
83
85
|
}
|
|
84
86
|
if (planned) {
|
|
85
87
|
const method = packet.request?.brain_native?.method || packet.request?.method || '';
|
|
86
|
-
const tool = packet.request?.brain_native?.params?.
|
|
88
|
+
const tool = codexMcpToolApproval(packet.request?.brain_native?.params)?.fullName || packet.request?.tool_name || 'request';
|
|
87
89
|
const response = planned === 'allow'
|
|
88
90
|
? { behavior: 'allow', ...(!remoteReadOnly && approvalMode === 'auto' ? { always: true } : {}) }
|
|
89
91
|
: { behavior: 'deny', decline: true, message: remoteReadOnly ? readOnlyDenyMessage(tool) : planDenyMessage(tool, { host: 'codex' }) };
|
|
@@ -91,7 +93,9 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
|
|
|
91
93
|
sink.send({ type: 'stderr', text: `${planMode ? 'Plan mode' : 'Read-only (WhatsApp)'}: ${planned === 'allow' ? 'allowed' : 'declined'} ${String(method).split('/').slice(1, -1).join('/') || 'request'} ${tool}${planned === 'allow' ? '' : remoteReadOnly ? ' (read-only)' : ' (no code changes)'}` });
|
|
92
94
|
return;
|
|
93
95
|
}
|
|
94
|
-
|
|
96
|
+
const method = packet.request?.brain_native?.method || packet.request?.method;
|
|
97
|
+
const autoMcp = method === 'mcpServer/elicitation/request' && shouldAutoAcceptCodexMcpToolApproval(packet.request?.brain_native?.params, { autoAccept: approvalMode === 'auto', role: 'assistant' });
|
|
98
|
+
if (packet.type === 'control_request' && !planMode && !remoteReadOnly && (autoMcp || (approvalMode === 'auto' && AUTO_ACCEPT_METHODS.has(method)))) {
|
|
95
99
|
// Auto-accept: approve at once (for the session when offered), as the Codex sidepanel does.
|
|
96
100
|
send({ type: 'server_request_response', ...codexControlResponse(packet, { behavior: 'allow', always: true }) });
|
|
97
101
|
sink.send({ type: 'stderr', text: `Auto-accepted: ${String(packet.request?.brain_native?.method || packet.request?.method).split('/').slice(1, -1).join('/')}` });
|
|
@@ -119,8 +123,8 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
|
|
|
119
123
|
});
|
|
120
124
|
const socket = createVirtualSocket({
|
|
121
125
|
name: `codex-brain-${session.id}`,
|
|
122
|
-
//
|
|
123
|
-
//
|
|
126
|
+
// The brain's launch credential rides on the socket object, never in a message: the skin handler gives it to
|
|
127
|
+
// this app-server's SynaBun MCP child through its environment (whatsapp_send_file, the Skills Service).
|
|
124
128
|
credential: deps.brainCredential || null,
|
|
125
129
|
onSend: (packet) => {
|
|
126
130
|
if (disposed || !packet || typeof packet !== 'object') return;
|
|
@@ -159,7 +163,7 @@ export function createCodexBrain({ session, sink, deps = {}, persona = '' } = {}
|
|
|
159
163
|
readyResolve = () => { clearTimeout(timer); resolve(true); };
|
|
160
164
|
});
|
|
161
165
|
send({
|
|
162
|
-
type: 'bootstrap', windowId, accountId: brain.accountId || 'default',
|
|
166
|
+
type: 'bootstrap', windowId, accountId: brain.accountId || 'default',
|
|
163
167
|
cwd: brain.cwd || deps.PACKAGE_ROOT || undefined, threadId: threadId || null, role: 'assistant',
|
|
164
168
|
// Unlocks the capability-gated `computer` MCP group for this brain only.
|
|
165
169
|
desktopGrant: deps.desktopGrant || null,
|