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
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Antigravity panel: the socket to /ws/antigravity (no DOM)
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// `request(type, payload)` resolves with the server's `data` or rejects with an
|
|
6
|
+
// Error carrying `code` and `authRequired`; every other message is an event for
|
|
7
|
+
// `on(type, fn)`. The socket opens on the first request, says `hello` first (with
|
|
8
|
+
// what `helloPayload()` returns: the panel's client capabilities), and opens again
|
|
9
|
+
// (1 s, 2 s, 4 s … 30 s) after it drops while anything is still listening;
|
|
10
|
+
// requests in flight when it drops reject with code 'DISCONNECTED'.
|
|
11
|
+
//
|
|
12
|
+
// A socket that never opens is not always a dropped connection: SynaBun refuses
|
|
13
|
+
// /ws/antigravity to its own automation browser, a relay and invite guests (403
|
|
14
|
+
// before the upgrade, which a page cannot see), and a server started before the
|
|
15
|
+
// panel existed does not know the path at all. After two opens in a row that fail,
|
|
16
|
+
// the client asks `probe()` (GET /api/antigravity/panel, refused or missing the same
|
|
17
|
+
// way) and, when the answer says the socket will not open, stops trying and emits
|
|
18
|
+
// `blocked { reason: 'automation' | 'refused' | 'guest' | 'restart', message }`
|
|
19
|
+
// instead of going on forever. `reconnectNow()` tries again at once.
|
|
20
|
+
// Events of its own: `connected` (hello), `disconnected`, `retrying { attempt, waitMs }`, `blocked`.
|
|
21
|
+
// `WebSocketImpl`, `url` and `probe` are injectable, so this runs under `node --test`.
|
|
22
|
+
|
|
23
|
+
const BACKOFF_MS = [1000, 2000, 4000, 8000, 15000, 30000];
|
|
24
|
+
const PROBE_AFTER_FAILURES = 2;
|
|
25
|
+
|
|
26
|
+
export function antigravitySocketUrl(location = globalThis.location) {
|
|
27
|
+
if (!location) return 'ws://127.0.0.1:3344/ws/antigravity';
|
|
28
|
+
const scheme = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
29
|
+
return `${scheme}//${location.host}/ws/antigravity`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* What GET /api/antigravity/panel says about the socket: { reason: null } (it should open: keep trying),
|
|
34
|
+
* { reason: 'offline' } (SynaBun did not answer: keep trying), or a reason that stops the retries:
|
|
35
|
+
* 'restart' (the server predates the panel), 'automation' (SynaBun's automation browser), 'guest' (an invite
|
|
36
|
+
* guest), 'refused' (any other refusal: a relay, a proxy), each with the server's words in `message`.
|
|
37
|
+
*/
|
|
38
|
+
export function probeVerdict({ status = 0, body = null, failed = false } = {}) {
|
|
39
|
+
if (failed) return { reason: 'offline', message: '' };
|
|
40
|
+
if (status >= 200 && status < 300) return { reason: null, message: '' };
|
|
41
|
+
const code = String(body?.code || '');
|
|
42
|
+
const message = typeof body?.error === 'string' ? body.error : '';
|
|
43
|
+
if (status === 404) return { reason: 'restart', message };
|
|
44
|
+
if (status === 403 || status === 401) {
|
|
45
|
+
if (code === 'WORKER_BROWSER') return { reason: 'automation', message };
|
|
46
|
+
if (/GUEST|INVITE|ADMIN/i.test(code) || /guest/i.test(message)) return { reason: 'guest', message };
|
|
47
|
+
return { reason: 'refused', message };
|
|
48
|
+
}
|
|
49
|
+
if (status >= 500) return { reason: null, message };
|
|
50
|
+
return { reason: 'refused', message };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function defaultProbe(fetchImpl = globalThis.fetch) {
|
|
54
|
+
if (typeof fetchImpl !== 'function') return probeVerdict({ failed: true });
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetchImpl('/api/antigravity/panel', { headers: { Accept: 'application/json' }, cache: 'no-store' });
|
|
57
|
+
let body = null;
|
|
58
|
+
try { body = await res.json(); } catch { body = null; }
|
|
59
|
+
return probeVerdict({ status: res.status, body });
|
|
60
|
+
} catch {
|
|
61
|
+
return probeVerdict({ failed: true });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createAntigravityClient({
|
|
66
|
+
url = antigravitySocketUrl(),
|
|
67
|
+
WebSocketImpl = globalThis.WebSocket,
|
|
68
|
+
setTimer = setTimeout,
|
|
69
|
+
clearTimer = clearTimeout,
|
|
70
|
+
requestTimeoutMs = 0,
|
|
71
|
+
helloPayload = () => ({}),
|
|
72
|
+
probe = () => defaultProbe(),
|
|
73
|
+
} = {}) {
|
|
74
|
+
let ws = null;
|
|
75
|
+
let opening = null;
|
|
76
|
+
let hello = null;
|
|
77
|
+
let seq = 0;
|
|
78
|
+
let attempt = 0;
|
|
79
|
+
let failures = 0; // opens in a row that closed before the hello
|
|
80
|
+
let reconnectTimer = null;
|
|
81
|
+
let disposed = false;
|
|
82
|
+
let blocked = null; // { reason, message } once a probe said the socket will not open
|
|
83
|
+
let probing = null;
|
|
84
|
+
const pending = new Map();
|
|
85
|
+
const listeners = new Map();
|
|
86
|
+
|
|
87
|
+
function emit(type, payload) {
|
|
88
|
+
for (const fn of [...(listeners.get(type) || [])]) {
|
|
89
|
+
try { fn(payload); } catch (error) { console.error('[antigravity] listener failed', error); }
|
|
90
|
+
}
|
|
91
|
+
for (const fn of [...(listeners.get('*') || [])]) {
|
|
92
|
+
try { fn(type, payload); } catch (error) { console.error('[antigravity] listener failed', error); }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function failPending(code, message) {
|
|
97
|
+
for (const [reqId, entry] of [...pending]) {
|
|
98
|
+
pending.delete(reqId);
|
|
99
|
+
if (entry.timer) clearTimer(entry.timer);
|
|
100
|
+
entry.reject(Object.assign(new Error(message), { code }));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function onMessage(event) {
|
|
105
|
+
let message;
|
|
106
|
+
try { message = JSON.parse(typeof event.data === 'string' ? event.data : String(event.data)); } catch { return; }
|
|
107
|
+
if (!message || typeof message.type !== 'string') return;
|
|
108
|
+
if (message.type === 'result') {
|
|
109
|
+
const entry = pending.get(message.reqId);
|
|
110
|
+
if (!entry) return;
|
|
111
|
+
pending.delete(message.reqId);
|
|
112
|
+
if (entry.timer) clearTimer(entry.timer);
|
|
113
|
+
if (message.ok) entry.resolve(message.data);
|
|
114
|
+
else entry.reject(Object.assign(new Error(message.error?.message || 'Request failed'), { code: message.error?.code, data: message.error?.data, authRequired: !!message.authRequired }));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
emit(message.type, message);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const listening = () => [...listeners.values()].some((set) => set.size);
|
|
121
|
+
|
|
122
|
+
function scheduleReconnect() {
|
|
123
|
+
if (disposed || reconnectTimer || blocked || !listening()) return;
|
|
124
|
+
const wait = BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)];
|
|
125
|
+
attempt += 1;
|
|
126
|
+
emit('retrying', { attempt, waitMs: wait });
|
|
127
|
+
reconnectTimer = setTimer(() => {
|
|
128
|
+
reconnectTimer = null;
|
|
129
|
+
// A socket that closes schedules the next try itself (onclose → afterFailure); only a socket that could not
|
|
130
|
+
// even be made needs one from here.
|
|
131
|
+
open().catch((error) => { if (error?.code !== 'DISCONNECTED' && error?.code !== 'BLOCKED') scheduleReconnect(); });
|
|
132
|
+
}, wait);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Two failed opens in a row: ask why before trying again.
|
|
136
|
+
async function afterFailure() {
|
|
137
|
+
if (failures < PROBE_AFTER_FAILURES || blocked || disposed) { scheduleReconnect(); return; }
|
|
138
|
+
if (!probing) probing = Promise.resolve().then(() => probe()).catch(() => ({ reason: 'offline', message: '' })).finally(() => { probing = null; });
|
|
139
|
+
const verdict = await probing;
|
|
140
|
+
if (disposed) return;
|
|
141
|
+
if (verdict?.reason && verdict.reason !== 'offline') {
|
|
142
|
+
blocked = { reason: verdict.reason, message: verdict.message || '' };
|
|
143
|
+
if (reconnectTimer) { clearTimer(reconnectTimer); reconnectTimer = null; }
|
|
144
|
+
emit('blocked', blocked);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (verdict?.reason === 'offline') emit('offline', {});
|
|
148
|
+
scheduleReconnect();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function rawSend(type, payload) {
|
|
152
|
+
const reqId = `q${++seq}`;
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
const entry = { resolve, reject, timer: null };
|
|
155
|
+
if (requestTimeoutMs > 0) {
|
|
156
|
+
entry.timer = setTimer(() => {
|
|
157
|
+
pending.delete(reqId);
|
|
158
|
+
reject(Object.assign(new Error(`${type} timed out`), { code: 'TIMEOUT' }));
|
|
159
|
+
}, requestTimeoutMs);
|
|
160
|
+
}
|
|
161
|
+
pending.set(reqId, entry);
|
|
162
|
+
try { ws.send(JSON.stringify({ ...payload, type, reqId })); } catch (error) {
|
|
163
|
+
pending.delete(reqId);
|
|
164
|
+
if (entry.timer) clearTimer(entry.timer);
|
|
165
|
+
reject(Object.assign(new Error(error?.message || 'Send failed'), { code: 'DISCONNECTED' }));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function open() {
|
|
171
|
+
if (disposed) return Promise.reject(Object.assign(new Error('Closed'), { code: 'DISPOSED' }));
|
|
172
|
+
if (blocked) return Promise.reject(Object.assign(new Error(blocked.message || 'The Antigravity connection was refused.'), { code: 'BLOCKED', reason: blocked.reason }));
|
|
173
|
+
if (ws && ws.readyState === 1 && hello) return Promise.resolve(hello);
|
|
174
|
+
if (opening) return opening;
|
|
175
|
+
if (typeof WebSocketImpl !== 'function') return Promise.reject(Object.assign(new Error('WebSockets are not available.'), { code: 'NO_WEBSOCKET' }));
|
|
176
|
+
opening = new Promise((resolve, reject) => {
|
|
177
|
+
let socket;
|
|
178
|
+
try { socket = new WebSocketImpl(url); } catch (error) { opening = null; reject(error); return; }
|
|
179
|
+
ws = socket;
|
|
180
|
+
let settled = false;
|
|
181
|
+
let opened = false;
|
|
182
|
+
socket.onmessage = onMessage;
|
|
183
|
+
socket.onopen = async () => {
|
|
184
|
+
opened = true;
|
|
185
|
+
try {
|
|
186
|
+
let payload = {};
|
|
187
|
+
try { payload = helloPayload() || {}; } catch { payload = {}; }
|
|
188
|
+
hello = await rawSend('hello', payload);
|
|
189
|
+
attempt = 0;
|
|
190
|
+
failures = 0;
|
|
191
|
+
settled = true;
|
|
192
|
+
opening = null;
|
|
193
|
+
emit('connected', hello);
|
|
194
|
+
resolve(hello);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
settled = true;
|
|
197
|
+
opening = null;
|
|
198
|
+
reject(error);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
socket.onclose = () => {
|
|
202
|
+
if (ws === socket) { ws = null; hello = null; }
|
|
203
|
+
failPending('DISCONNECTED', 'The connection to SynaBun dropped.');
|
|
204
|
+
if (!opened) failures += 1;
|
|
205
|
+
if (!settled) { settled = true; opening = null; reject(Object.assign(new Error('Could not connect to SynaBun.'), { code: 'DISCONNECTED' })); }
|
|
206
|
+
emit('disconnected', { opened });
|
|
207
|
+
if (listening()) afterFailure().catch(() => {});
|
|
208
|
+
};
|
|
209
|
+
socket.onerror = () => { /* onclose follows */ };
|
|
210
|
+
});
|
|
211
|
+
return opening;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function request(type, payload = {}) {
|
|
215
|
+
await open();
|
|
216
|
+
return rawSend(type, payload);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Say hello again on the open socket (new client capabilities, or after an install): the new hello is `connected`. */
|
|
220
|
+
async function refreshHello(type = 'hello', payload = null) {
|
|
221
|
+
await open();
|
|
222
|
+
let body = payload;
|
|
223
|
+
if (!body) { try { body = helloPayload() || {}; } catch { body = {}; } }
|
|
224
|
+
const answer = await rawSend(type, body);
|
|
225
|
+
hello = answer;
|
|
226
|
+
emit('connected', answer);
|
|
227
|
+
return answer;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Try again now: forget a refusal, reset the back-off and open. */
|
|
231
|
+
function reconnectNow() {
|
|
232
|
+
blocked = null;
|
|
233
|
+
failures = 0;
|
|
234
|
+
attempt = 0;
|
|
235
|
+
if (reconnectTimer) { clearTimer(reconnectTimer); reconnectTimer = null; }
|
|
236
|
+
return open();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function on(type, fn) {
|
|
240
|
+
if (!listeners.has(type)) listeners.set(type, new Set());
|
|
241
|
+
listeners.get(type).add(fn);
|
|
242
|
+
return () => listeners.get(type)?.delete(fn);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function dispose() {
|
|
246
|
+
disposed = true;
|
|
247
|
+
if (reconnectTimer) { clearTimer(reconnectTimer); reconnectTimer = null; }
|
|
248
|
+
failPending('DISPOSED', 'Closed');
|
|
249
|
+
try { ws?.close(); } catch { /* already closed */ }
|
|
250
|
+
ws = null;
|
|
251
|
+
listeners.clear();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
open,
|
|
256
|
+
request,
|
|
257
|
+
refreshHello,
|
|
258
|
+
reconnectNow,
|
|
259
|
+
on,
|
|
260
|
+
dispose,
|
|
261
|
+
get hello() { return hello; },
|
|
262
|
+
get connected() { return !!(ws && ws.readyState === 1 && hello); },
|
|
263
|
+
get blocked() { return blocked; },
|
|
264
|
+
supports: (capability) => !!hello?.capabilities?.includes(capability),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Antigravity panel: slash commands and @ mentions (no DOM)
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Two kinds of slash command meet in the composer: the agent's own (ACP
|
|
6
|
+
// `available_commands_update`: Antigravity's /plan, /goal, /compact …, sent to it
|
|
7
|
+
// as the text of a prompt) and the panel's (/new, /sessions, /rename …, run here).
|
|
8
|
+
// An agent command wins a name both have: it is Antigravity's own behaviour, and
|
|
9
|
+
// every panel action stays one click away. `@` followed by a path fragment asks
|
|
10
|
+
// for a project file; the chosen one is attached to the message (ACP resource_link)
|
|
11
|
+
// and its path stays in the text.
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The panel's commands. `key` is the agy-copy.js key of the description; `needs` names a capability the panel
|
|
15
|
+
* must have for it ('fork', 'logout', 'sessions'); `hint` is shown after the name.
|
|
16
|
+
*/
|
|
17
|
+
export const PANEL_COMMANDS = Object.freeze([
|
|
18
|
+
{ name: 'new', key: 'cmdNew' },
|
|
19
|
+
{ name: 'sessions', key: 'cmdSessions' },
|
|
20
|
+
{ name: 'rename', key: 'cmdRename', hint: 'name' },
|
|
21
|
+
{ name: 'fork', key: 'cmdFork', needs: 'fork' },
|
|
22
|
+
{ name: 'retry', key: 'cmdRetry' },
|
|
23
|
+
{ name: 'copy', key: 'cmdCopy' },
|
|
24
|
+
{ name: 'model', key: 'cmdModel' },
|
|
25
|
+
{ name: 'mode', key: 'cmdMode' },
|
|
26
|
+
{ name: 'thinking', key: 'cmdThinking' },
|
|
27
|
+
{ name: 'detail', key: 'cmdDetail', hint: 'compact | standard | verbose' },
|
|
28
|
+
{ name: 'settings', key: 'cmdSettings' },
|
|
29
|
+
{ name: 'login', key: 'cmdLogin' },
|
|
30
|
+
{ name: 'logout', key: 'cmdLogout', needs: 'logout' },
|
|
31
|
+
{ name: 'help', key: 'cmdHelp' },
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
export const DETAIL_LEVELS = Object.freeze(['compact', 'standard', 'verbose']);
|
|
35
|
+
|
|
36
|
+
/** "/name args" → { name, args } (name lower-cased), or null when the text is not one command. */
|
|
37
|
+
export function parseSlash(text) {
|
|
38
|
+
const match = /^\/([A-Za-z0-9][\w:.-]*)(?:\s+([\s\S]*))?$/.exec(String(text ?? '').trim());
|
|
39
|
+
if (!match) return null;
|
|
40
|
+
return { name: match[1].toLowerCase(), args: (match[2] || '').trim() };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* What a typed message does: { kind: 'agent' } (sent to Antigravity as typed: plain text, an agent command or an
|
|
45
|
+
* unknown one), or { kind: 'panel', name, args } for a panel command the agent does not also have.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveSlash(text, { agentCommands = [], available = () => true } = {}) {
|
|
48
|
+
const parsed = parseSlash(text);
|
|
49
|
+
if (!parsed) return { kind: 'agent' };
|
|
50
|
+
if ((agentCommands || []).some((command) => String(command?.name || '').toLowerCase() === parsed.name)) return { kind: 'agent' };
|
|
51
|
+
const panel = PANEL_COMMANDS.find((command) => command.name === parsed.name);
|
|
52
|
+
if (!panel || (panel.needs && !available(panel.needs))) return { kind: 'agent' };
|
|
53
|
+
return { kind: 'panel', name: panel.name, args: parsed.args };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The slash menu for what the composer holds: while it is "/" plus the start of one command name, the commands
|
|
58
|
+
* whose name starts with it (panel first, then the agent's; a panel command the agent also has is left out).
|
|
59
|
+
* → { query, items: [{ name, source: 'panel' | 'agent', key?, description?, hint }] } or null.
|
|
60
|
+
*/
|
|
61
|
+
export function slashMenu(text, { agentCommands = [], available = () => true, max = 80 } = {}) {
|
|
62
|
+
const match = /^\/([\w:.-]*)$/.exec(String(text ?? ''));
|
|
63
|
+
if (!match) return null;
|
|
64
|
+
const query = match[1].toLowerCase();
|
|
65
|
+
const agent = (agentCommands || []).filter((command) => command && typeof command.name === 'string');
|
|
66
|
+
const agentNames = new Set(agent.map((command) => command.name.toLowerCase()));
|
|
67
|
+
const starts = (name) => name.toLowerCase().startsWith(query);
|
|
68
|
+
const items = [
|
|
69
|
+
...PANEL_COMMANDS.filter((command) => !agentNames.has(command.name) && (!command.needs || available(command.needs)) && starts(command.name))
|
|
70
|
+
.map((command) => ({ name: command.name, source: 'panel', key: command.key, hint: command.hint || '' })),
|
|
71
|
+
...agent.filter((command) => starts(command.name))
|
|
72
|
+
.map((command) => ({ name: command.name, source: 'agent', description: command.description || '', hint: command.hint || '' })),
|
|
73
|
+
].slice(0, max);
|
|
74
|
+
return { query, items };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The text a chosen menu entry leaves in the composer: "/name " (a space, so its argument can follow). */
|
|
78
|
+
export function slashInsert(item) {
|
|
79
|
+
return `/${item?.name || ''} `;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The @ mention the caret is in: `@` at the start or after whitespace, then a path fragment up to the caret.
|
|
84
|
+
* → { start, end, query } (start: the index of '@'), or null.
|
|
85
|
+
*/
|
|
86
|
+
export function mentionAt(text, caret) {
|
|
87
|
+
const value = String(text ?? '');
|
|
88
|
+
const at = Number.isInteger(caret) ? Math.max(0, Math.min(caret, value.length)) : value.length;
|
|
89
|
+
const before = value.slice(0, at);
|
|
90
|
+
const match = /(^|\s)@([^\s@]{0,200})$/.exec(before);
|
|
91
|
+
if (!match) return null;
|
|
92
|
+
const start = at - match[2].length - 1;
|
|
93
|
+
return { start, end: at, query: match[2] };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The composer after a file was picked for a mention: "@relative/path " in place of "@query". → { text, caret }. */
|
|
97
|
+
export function applyMention(text, mention, relativePath) {
|
|
98
|
+
const value = String(text ?? '');
|
|
99
|
+
const insert = `@${relativePath} `;
|
|
100
|
+
const next = value.slice(0, mention.start) + insert + value.slice(mention.end).replace(/^\s+/, '');
|
|
101
|
+
return { text: next, caret: mention.start + insert.length };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** A project-relative path joined to the project folder (either separator; never leaves the folder). */
|
|
105
|
+
export function joinProjectPath(project, relativePath) {
|
|
106
|
+
const root = String(project || '').replace(/[\\/]+$/, '');
|
|
107
|
+
const rel = String(relativePath || '').replace(/^[\\/]+/, '');
|
|
108
|
+
if (!root || !rel || rel.split(/[\\/]/).some((part) => part === '..')) return '';
|
|
109
|
+
const sep = root.includes('\\') && !root.includes('/') ? '\\' : '/';
|
|
110
|
+
return `${root}${sep}${rel.replace(/[\\/]/g, sep)}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** A path shown relative to the project when it is inside it, else as it is. */
|
|
114
|
+
export function relativeToProject(project, path) {
|
|
115
|
+
const root = String(project || '').replace(/[\\/]+$/, '');
|
|
116
|
+
const value = String(path || '');
|
|
117
|
+
if (root && (value === root)) return '.';
|
|
118
|
+
if (root && (value.startsWith(`${root}/`) || value.startsWith(`${root}\\`))) return value.slice(root.length + 1);
|
|
119
|
+
return value;
|
|
120
|
+
}
|