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
|
@@ -7,7 +7,7 @@ import { FRAMED_CLASS, frameRect } from './app-frame.js';
|
|
|
7
7
|
|
|
8
8
|
const STORAGE_PREFIX = 'synabun-sidepanel-layout-';
|
|
9
9
|
const surfaces = new Map();
|
|
10
|
-
const LABELS = { claude: 'Claude', codex: 'Codex', opencode: 'OpenCode', assistant: 'SynaBun Assistant' };
|
|
10
|
+
const LABELS = { claude: 'Claude', codex: 'Codex', opencode: 'OpenCode', antigravity: 'Antigravity', assistant: 'SynaBun Assistant' };
|
|
11
11
|
const DETACH_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="3" y="7" width="14" height="14" rx="2"/><path d="M13 3h8v8M21 3l-9 9"/></svg>';
|
|
12
12
|
const DOCK_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16M6 12h6m-3-3 3 3-3 3"/></svg>';
|
|
13
13
|
const MOVE_ICON = '<svg viewBox="0 0 16 16" fill="currentColor"><circle cx="5" cy="4" r="1"/><circle cx="11" cy="4" r="1"/><circle cx="5" cy="8" r="1"/><circle cx="11" cy="8" r="1"/><circle cx="5" cy="12" r="1"/><circle cx="11" cy="12" r="1"/></svg>';
|
|
@@ -59,10 +59,10 @@ function injectStyles() {
|
|
|
59
59
|
transform: none !important; transition: opacity .15s ease;
|
|
60
60
|
}
|
|
61
61
|
.sp-sidepanel.sp-floating.sp-window-focused { border-color: rgba(148,163,184,.38); }
|
|
62
|
-
.sp-sidepanel.sp-floating > :is(.cp-resize-handle,.cxp-resize-handle,.ocpv2-resize-handle,.asp-resize-handle) { display: none; }
|
|
62
|
+
.sp-sidepanel.sp-floating > :is(.cp-resize-handle,.cxp-resize-handle,.ocpv2-resize-handle,.agy-resize-handle,.asp-resize-handle) { display: none; }
|
|
63
63
|
.sp-window-move { display: none !important; }
|
|
64
64
|
.sp-floating .sp-window-move { display: inline-flex !important; cursor: move; flex-shrink: 0; }
|
|
65
|
-
.sp-floating > :is(.cp-header,.cxp-header,.ocpv2-header,.asp-header) { cursor: move; touch-action: none; }
|
|
65
|
+
.sp-floating > :is(.cp-header,.cxp-header,.ocpv2-header,.agy-header,.asp-header) { cursor: move; touch-action: none; }
|
|
66
66
|
.sp-window-toggle svg, .sp-window-move svg { width: 13px; height: 13px; pointer-events: none; }
|
|
67
67
|
.sp-window-resize { display: none; position: absolute; z-index: 20; touch-action: none; }
|
|
68
68
|
.sp-floating > .sp-window-resize { display: block; }
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// ═══════════════════════════════════════════
|
|
5
5
|
//
|
|
6
6
|
// Provides a docked bottom terminal panel with tabbed sessions.
|
|
7
|
-
// Profiles: Claude Code, Codex CLI,
|
|
7
|
+
// Profiles: Claude Code, Codex CLI, Antigravity CLI, OpenCode, Shell.
|
|
8
8
|
|
|
9
9
|
import { state, emit, on } from './state.js';
|
|
10
10
|
import { KEYS } from './constants.js';
|
|
@@ -23,12 +23,12 @@ import { mountAssistant } from './assistant/asst-panel.js';
|
|
|
23
23
|
import { getAssistantSession } from './assistant/asst-api.js';
|
|
24
24
|
import { mascotCameoSvg } from './synabun-mascot.js';
|
|
25
25
|
import { brainLabel, normalizeBrain, readStoredBrain, restoredSessionName, sessionNameGivenUp } from './assistant/asst-state.js';
|
|
26
|
-
import { initAssistant, registerAssistantHost, openAssistant, assistantOwnerOf,
|
|
26
|
+
import { initAssistant, registerAssistantHost, openAssistant, assistantOwnerOf, readLiveAssistantSessions, assistantBlocked, isAssistantSessionLive } from './ui-assistant.js';
|
|
27
27
|
|
|
28
28
|
const $ = (id) => document.getElementById(id);
|
|
29
|
-
const CLI_PROFILES = new Set(['claude-code', 'codex', '
|
|
30
|
-
const NOTIF_TRACKED_CLI_PROFILES = new Set(['claude-code', 'codex', '
|
|
31
|
-
const CLI_PROFILES_NEED_RECALL = new Set(['claude-code', 'codex', '
|
|
29
|
+
const CLI_PROFILES = new Set(['claude-code', 'codex', 'antigravity', 'opencode']);
|
|
30
|
+
const NOTIF_TRACKED_CLI_PROFILES = new Set(['claude-code', 'codex', 'antigravity', 'opencode']);
|
|
31
|
+
const CLI_PROFILES_NEED_RECALL = new Set(['claude-code', 'codex', 'antigravity', 'opencode']);
|
|
32
32
|
|
|
33
33
|
// ── Platform ──
|
|
34
34
|
// macOS gets Terminal.app keys (Cmd shortcuts, Option word-jumps, Ctrl keys
|
|
@@ -144,7 +144,7 @@ function _injectPathIntoTerm(term, ws, path) {
|
|
|
144
144
|
|
|
145
145
|
const SVG_CLAUDE = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z"/></svg>';
|
|
146
146
|
const SVG_OPENAI = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"/></svg>';
|
|
147
|
-
const
|
|
147
|
+
const SVG_ANTIGRAVITY = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 20 12 4l7.5 16"/><path d="M8.2 20a3.8 3.8 0 0 1 7.6 0"/></svg>';
|
|
148
148
|
const SVG_OPENCODE = '<svg viewBox="0 0 240 300" fill="currentColor"><path fill-rule="evenodd" d="M0 0h240v300H0V0zm60 60v180h120V60H60z"/><rect x="60" y="120" width="120" height="120" opacity=".45"/></svg>';
|
|
149
149
|
const SVG_SHELL = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>';
|
|
150
150
|
const SVG_GIT = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>';
|
|
@@ -156,7 +156,7 @@ const PROFILES = [
|
|
|
156
156
|
{ id: 'assistant', label: 'Assistant', svg: SVG_ASSISTANT, color: '#FFD23C' }, // non-PTY: hosts assistant/asst-panel.js
|
|
157
157
|
{ id: 'claude-code', label: 'Claude Code', svg: SVG_CLAUDE, color: '#D4A27F' },
|
|
158
158
|
{ id: 'codex', label: 'Codex CLI', svg: SVG_OPENAI, color: '#74c7a5' },
|
|
159
|
-
{ id: '
|
|
159
|
+
{ id: 'antigravity', label: 'Antigravity CLI', svg: SVG_ANTIGRAVITY, color: '#669DF6' },
|
|
160
160
|
{ id: 'opencode', label: 'OpenCode', svg: SVG_OPENCODE, color: '#E8E0DC' },
|
|
161
161
|
{ id: 'shell', label: 'Shell', svg: SVG_SHELL, color: '#aaaaaa' },
|
|
162
162
|
{ id: 'browser', label: 'Browser', svg: SVG_BROWSER, color: '#4fc3f7' },
|
|
@@ -248,6 +248,12 @@ let _closingIds = new Set(); // session IDs currently being closed (prevents r
|
|
|
248
248
|
let _opening = false; // true while openSession/openBrowserSession is in progress
|
|
249
249
|
let _openingAt = 0; // timestamp when _opening was set true (auto-reset after 15s)
|
|
250
250
|
let _restoringLayout = false; // true during reconnect+layout restore (suppresses layout saves)
|
|
251
|
+
// Saved Assistant tabs whose session list could not be read yet (server still starting).
|
|
252
|
+
// Kept in the registry on every save until a read succeeds; never pruned on a failed read.
|
|
253
|
+
let _waitingAssistant = [];
|
|
254
|
+
let _waitingAssistantTimer = null;
|
|
255
|
+
const _waitingPlace = new Map(); // waiting Assistant tab id → { float, order, pane, paneActive, switches } from the saved layout
|
|
256
|
+
const ASSISTANT_RESTORE_RETRY_MS = [500, 1000, 2000, 4000, 8000, 15_000];
|
|
251
257
|
let _windowResizeTimer = null; // debounce handle for window resize clamping
|
|
252
258
|
|
|
253
259
|
// ── Split pane state ──
|
|
@@ -256,6 +262,7 @@ let _focusedPane = 0; // 0=left, 1=right — which pane has keyboard
|
|
|
256
262
|
let _paneAssignments = new Map(); // sessionId → 0|1 (which pane a session belongs to)
|
|
257
263
|
let _activePaneIdx = [-1, -1]; // per-pane active session index (into _sessions)
|
|
258
264
|
let _splitRatio = 0.5; // left pane width fraction (0.3–0.7)
|
|
265
|
+
let _paneSwitches = [0, 0]; // per-pane count of tab switches outside a restore
|
|
259
266
|
|
|
260
267
|
const DEFAULT_HEIGHT = 320;
|
|
261
268
|
const MIN_HEIGHT = 120;
|
|
@@ -1610,6 +1617,7 @@ function saveSessionRegistry() {
|
|
|
1610
1617
|
brain: s._isAssistant ? (s._brain || prev?.brain || null) : null,
|
|
1611
1618
|
});
|
|
1612
1619
|
}
|
|
1620
|
+
for (const w of _waitingAssistant) if (!seen.has(w.id)) seen.set(w.id, w);
|
|
1613
1621
|
storage.setItem(KEYS.TERMINAL_SESSIONS, JSON.stringify([...seen.values()]));
|
|
1614
1622
|
}
|
|
1615
1623
|
|
|
@@ -1646,6 +1654,14 @@ function saveTerminalLayout() {
|
|
|
1646
1654
|
if (_restoringLayout) return; // don't overwrite saved layout during reconnect
|
|
1647
1655
|
try {
|
|
1648
1656
|
const snap = getTerminalSnapshot();
|
|
1657
|
+
// A float still waiting for its session keeps its saved place.
|
|
1658
|
+
for (const w of _waitingAssistant) {
|
|
1659
|
+
const float = _waitingPlace.get(w.id)?.float;
|
|
1660
|
+
if (float && !snap.detachedTabs.some(dt => dt.sessionId === w.id)) snap.detachedTabs.push(float);
|
|
1661
|
+
// …and a docked one its split pane.
|
|
1662
|
+
const pane = _waitingPlace.get(w.id)?.pane;
|
|
1663
|
+
if (snap.splitMode && pane != null && !(w.id in snap.paneAssignments)) snap.paneAssignments[w.id] = pane;
|
|
1664
|
+
}
|
|
1649
1665
|
storage.setItem(KEYS.TERMINAL_SESSIONS + '-layout', JSON.stringify(snap));
|
|
1650
1666
|
} catch {}
|
|
1651
1667
|
}
|
|
@@ -3530,6 +3546,107 @@ function _assistantOwnedElsewhere(sessionId) {
|
|
|
3530
3546
|
}
|
|
3531
3547
|
|
|
3532
3548
|
/** Reconnect a saved assistant tab (registry / workspace) to its live server session. */
|
|
3549
|
+
/** Keep saved Assistant tabs while the session list cannot be read, and retry the read. */
|
|
3550
|
+
function _waitAssistantRestore(entries, { layout = null, order = [] } = {}) {
|
|
3551
|
+
const known = new Set(_waitingAssistant.map(w => w.id));
|
|
3552
|
+
for (const e of entries) {
|
|
3553
|
+
if (!known.has(e.id)) _waitingAssistant.push(e);
|
|
3554
|
+
// Where the tab was: its float (position, size) from the saved layout, or its docked place.
|
|
3555
|
+
const float = (layout?.detachedTabs || []).find(dt => dt?.sessionId === e.id) || null;
|
|
3556
|
+
// In split mode, its pane and whether it was that pane's active tab.
|
|
3557
|
+
const p = layout?.splitMode ? layout.paneAssignments?.[e.id] : null;
|
|
3558
|
+
const pane = p === 0 || p === 1 ? p : null;
|
|
3559
|
+
const paneActive = pane != null && (layout.sessions || [])[layout.activePaneIdx?.[pane]]?.id === e.id;
|
|
3560
|
+
_waitingPlace.set(e.id, { float, order: order.map(o => o.id), pane, paneActive, switches: null });
|
|
3561
|
+
}
|
|
3562
|
+
if (_waitingAssistantTimer) return;
|
|
3563
|
+
const attempt = async (n) => {
|
|
3564
|
+
_waitingAssistantTimer = null;
|
|
3565
|
+
if (!_waitingAssistant.length || assistantBlocked()) return;
|
|
3566
|
+
const live = await readLiveAssistantSessions();
|
|
3567
|
+
if (!live) {
|
|
3568
|
+
// Out of retries: the entries stay saved for the next page load.
|
|
3569
|
+
if (n < ASSISTANT_RESTORE_RETRY_MS.length) _waitingAssistantTimer = setTimeout(() => attempt(n + 1), ASSISTANT_RESTORE_RETRY_MS[n]);
|
|
3570
|
+
return;
|
|
3571
|
+
}
|
|
3572
|
+
const waiting = _waitingAssistant;
|
|
3573
|
+
_waitingAssistant = [];
|
|
3574
|
+
// A late restore is silent: no panel opened, the active tab kept, each tab back where it was saved.
|
|
3575
|
+
const active = _sessions[_activeIdx] || null;
|
|
3576
|
+
const restored = [];
|
|
3577
|
+
_restoringLayout = true;
|
|
3578
|
+
try {
|
|
3579
|
+
for (const saved of waiting) {
|
|
3580
|
+
if (!live.has(saved.id) || _sessions.some(s => s.id === saved.id)) continue;
|
|
3581
|
+
try { const s = await reconnectAssistantSession(saved.id, live.get(saved.id), saved); if (s) restored.push(s); }
|
|
3582
|
+
catch (err) { console.warn('[assistant] reconnect failed:', saved.id, err); }
|
|
3583
|
+
}
|
|
3584
|
+
} finally { _restoringLayout = false; }
|
|
3585
|
+
if (active) _activeIdx = _sessions.indexOf(active);
|
|
3586
|
+
for (const s of restored) _placeLateAssistant(s, _waitingPlace.get(s.id));
|
|
3587
|
+
_waitingPlace.clear();
|
|
3588
|
+
if (active) _activeIdx = _sessions.indexOf(active);
|
|
3589
|
+
else {
|
|
3590
|
+
// Nothing was active: the first docked tab is, unhidden for when the panel is opened.
|
|
3591
|
+
_activeIdx = _sessions.findIndex(s => !_detachedTabs.has(s.id));
|
|
3592
|
+
const first = _sessions[_activeIdx];
|
|
3593
|
+
if (first?.viewport) first.viewport.style.display = '';
|
|
3594
|
+
}
|
|
3595
|
+
renderTabBar();
|
|
3596
|
+
saveSessionRegistry(); // prunes the ones whose sessions are really gone
|
|
3597
|
+
saveTerminalLayout();
|
|
3598
|
+
};
|
|
3599
|
+
_waitingAssistantTimer = setTimeout(() => attempt(1), ASSISTANT_RESTORE_RETRY_MS[0]);
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
/** The restore that started the wait is done: pane switches from now on are the user's. */
|
|
3603
|
+
function _markLatePaneSwitches() {
|
|
3604
|
+
for (const place of _waitingPlace.values()) if (!place.switches) place.switches = [..._paneSwitches];
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
/** A tab a late restore mounted goes where it was saved: its float, or its docked place in the saved order (and split pane). */
|
|
3608
|
+
function _placeLateAssistant(session, place) {
|
|
3609
|
+
if (place?.float) {
|
|
3610
|
+
if (session.viewport) session.viewport.style.display = '';
|
|
3611
|
+
applyTerminalLayout({ detachedTabs: [place.float] });
|
|
3612
|
+
return;
|
|
3613
|
+
}
|
|
3614
|
+
if (!_splitMode) { _orderLateAssistant(session, place?.order || []); return; }
|
|
3615
|
+
// Split is on, so both panes exist: its saved pane, else its neighbour's. The user's layout stays as it is.
|
|
3616
|
+
const paneActiveIds = _activePaneIdx.map(i => _sessions[i]?.id ?? null);
|
|
3617
|
+
const pane = place?.pane ?? null;
|
|
3618
|
+
let order = place?.order || [];
|
|
3619
|
+
if (pane != null) order = order.filter(id => id === session.id || _paneAssignments.get(id) === pane);
|
|
3620
|
+
const neighbour = _orderLateAssistant(session, order);
|
|
3621
|
+
const target = pane ?? _paneAssignments.get(neighbour?.id) ?? _focusedPane;
|
|
3622
|
+
_paneAssignments.set(session.id, target);
|
|
3623
|
+
_panel?.querySelector(`.term-pane[data-pane="${target}"] .term-pane-body`)?.appendChild(session.viewport);
|
|
3624
|
+
_activePaneIdx = paneActiveIds.map(id => _sessions.findIndex(s => s.id === id));
|
|
3625
|
+
// It was the pane's active tab and nobody switched tabs there since: it is again.
|
|
3626
|
+
const untouched = place?.switches && place.switches[target] === _paneSwitches[target];
|
|
3627
|
+
if (pane != null && place.paneActive && untouched) switchToSessionInPane(_sessions.indexOf(session), target);
|
|
3628
|
+
else if (session.viewport) session.viewport.style.display = 'none';
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
/** Move a late tab next to its nearest neighbour in `order`; returns that neighbour (or null). */
|
|
3632
|
+
function _orderLateAssistant(session, order) {
|
|
3633
|
+
const at = order.indexOf(session.id);
|
|
3634
|
+
if (at < 0) return null; // not in the saved order: it stays last
|
|
3635
|
+
const from = _sessions.indexOf(session);
|
|
3636
|
+
_sessions.splice(from, 1);
|
|
3637
|
+
// After the nearest tab saved before it, else before the nearest saved after it, else last.
|
|
3638
|
+
let to = _sessions.length;
|
|
3639
|
+
const before = order.slice(0, at).reverse().map(id => _sessions.findIndex(s => s.id === id)).find(i => i >= 0);
|
|
3640
|
+
if (before !== undefined) to = before + 1;
|
|
3641
|
+
else {
|
|
3642
|
+
const after = order.slice(at + 1).map(id => _sessions.findIndex(s => s.id === id)).find(i => i >= 0);
|
|
3643
|
+
if (after !== undefined) to = after;
|
|
3644
|
+
}
|
|
3645
|
+
const neighbour = _sessions[to] || _sessions[to - 1] || null;
|
|
3646
|
+
_sessions.splice(to, 0, session);
|
|
3647
|
+
return neighbour;
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3533
3650
|
async function reconnectAssistantSession(sessionId, live, saved) {
|
|
3534
3651
|
if (_assistantOwnedElsewhere(sessionId)) return null;
|
|
3535
3652
|
let meta = live || null;
|
|
@@ -5996,7 +6113,7 @@ export async function initTerminal() {
|
|
|
5996
6113
|
// Register CLI launch keybind actions (open as detached floating tab)
|
|
5997
6114
|
registerAction('launch-claude', () => launchDetached('claude-code'));
|
|
5998
6115
|
registerAction('launch-codex', () => launchDetached('codex'));
|
|
5999
|
-
registerAction('launch-
|
|
6116
|
+
registerAction('launch-antigravity', () => launchDetached('antigravity'));
|
|
6000
6117
|
registerAction('launch-opencode', () => launchDetached('opencode'));
|
|
6001
6118
|
registerAction('launch-browser', () => openBrowserSession());
|
|
6002
6119
|
registerAction('launch-youtube', () => openBrowserSession('https://www.youtube.com'));
|
|
@@ -6125,7 +6242,17 @@ export async function initTerminal() {
|
|
|
6125
6242
|
const liveBrowserMap = _streamDisabled ? new Map() : new Map(liveBrowserSessions.map(s => [s.id, s]));
|
|
6126
6243
|
|
|
6127
6244
|
// Fetch live assistant sessions (only when the registry has assistant tabs)
|
|
6128
|
-
|
|
6245
|
+
// A failed read is not an empty list: keep those tabs waiting and retry.
|
|
6246
|
+
let liveAssistantMap = new Map();
|
|
6247
|
+
if (registry.some(r => r.profile === 'assistant')) {
|
|
6248
|
+
const read = await readLiveAssistantSessions();
|
|
6249
|
+
if (read) liveAssistantMap = read;
|
|
6250
|
+
else {
|
|
6251
|
+
let layout = null;
|
|
6252
|
+
try { layout = JSON.parse(storage.getItem(KEYS.TERMINAL_SESSIONS + '-layout') || 'null'); } catch {}
|
|
6253
|
+
_waitAssistantRestore(registry.filter(r => r.profile === 'assistant'), { layout, order: registry });
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6129
6256
|
|
|
6130
6257
|
const liveIds = new Set([...liveMap.keys(), ...liveBrowserMap.keys(), ...liveAssistantMap.keys()]);
|
|
6131
6258
|
|
|
@@ -6190,6 +6317,8 @@ export async function initTerminal() {
|
|
|
6190
6317
|
_syncRenderers();
|
|
6191
6318
|
}
|
|
6192
6319
|
|
|
6320
|
+
_markLatePaneSwitches();
|
|
6321
|
+
|
|
6193
6322
|
// Clean up dead sessions from registry
|
|
6194
6323
|
if (toReconnect.length !== registry.length) {
|
|
6195
6324
|
saveSessionRegistry();
|
|
@@ -6708,7 +6837,12 @@ export async function restoreTerminalSnapshot(snap) {
|
|
|
6708
6837
|
} catch {}
|
|
6709
6838
|
const liveMap = new Map(liveSessions.map(s => [s.id, s]));
|
|
6710
6839
|
const liveIds = new Set(liveMap.keys());
|
|
6711
|
-
|
|
6840
|
+
let liveAssistantMap = new Map();
|
|
6841
|
+
if (snap.sessions.some(s => s.profile === 'assistant')) {
|
|
6842
|
+
const read = await readLiveAssistantSessions();
|
|
6843
|
+
if (read) liveAssistantMap = read;
|
|
6844
|
+
else _waitAssistantRestore(snap.sessions.filter(s => s.profile === 'assistant'), { layout: snap, order: snap.sessions });
|
|
6845
|
+
}
|
|
6712
6846
|
|
|
6713
6847
|
// Disconnect current sessions without killing server PTY
|
|
6714
6848
|
disconnectAllSessions();
|
|
@@ -6745,6 +6879,7 @@ export async function restoreTerminalSnapshot(snap) {
|
|
|
6745
6879
|
const firstDocked = _sessions.findIndex(s => !_detachedTabs.has(s.id));
|
|
6746
6880
|
if (firstDocked >= 0 && !_splitMode) switchToSession(firstDocked, { force: true });
|
|
6747
6881
|
_syncRenderers();
|
|
6882
|
+
_markLatePaneSwitches();
|
|
6748
6883
|
}
|
|
6749
6884
|
|
|
6750
6885
|
// ══════════════════════════════════════════
|
|
@@ -7650,6 +7785,7 @@ function initSplitDivider() {
|
|
|
7650
7785
|
function switchToSessionInPane(idx, pane) {
|
|
7651
7786
|
if (idx < 0 || idx >= _sessions.length) return;
|
|
7652
7787
|
_activePaneIdx[pane] = idx;
|
|
7788
|
+
if (!_restoringLayout) _paneSwitches[pane]++;
|
|
7653
7789
|
|
|
7654
7790
|
// Show/hide viewports within this pane only
|
|
7655
7791
|
const paneBody = _panel?.querySelector(`.term-pane[data-pane="${pane}"] .term-pane-body`);
|
|
@@ -14,7 +14,7 @@ const TOOL_ELEMENTS = {
|
|
|
14
14
|
'claude-code': { toolbar: 'claude-update-badge', menu: 'claude-menu-update-badge' },
|
|
15
15
|
'codex': { toolbar: 'codex-update-badge', menu: 'codex-menu-update-badge' },
|
|
16
16
|
'opencode': { toolbar: 'opencode-update-badge', menu: 'opencode-menu-update-badge' },
|
|
17
|
-
'
|
|
17
|
+
'antigravity': { toolbar: 'antigravity-update-badge', menu: 'antigravity-menu-update-badge' },
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
// Parent elements whose tooltips are updated when an update badge is visible.
|
|
@@ -22,14 +22,14 @@ const PARENT_ELEMENTS = {
|
|
|
22
22
|
'claude-code': { toolbar: 'topright-claude-panel-btn', menu: 'menu-terminal-claude' },
|
|
23
23
|
'codex': { toolbar: 'topright-codex-panel-btn', menu: 'menu-terminal-codex' },
|
|
24
24
|
'opencode': { toolbar: 'topright-opencode-panel-btn', menu: 'menu-terminal-opencode' },
|
|
25
|
-
'
|
|
25
|
+
'antigravity': { toolbar: 'topright-antigravity-panel-btn', menu: 'menu-terminal-antigravity' },
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
const TOOL_LABELS = {
|
|
29
29
|
'claude-code': 'Claude Code',
|
|
30
30
|
'codex': 'Codex',
|
|
31
31
|
'opencode': 'OpenCode',
|
|
32
|
-
'
|
|
32
|
+
'antigravity': 'Antigravity CLI',
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
// Cached server response so click handlers can read per-tool updateCommand
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// ═══════════════════════════════════════════
|
|
5
5
|
|
|
6
6
|
import { boundsForPoint, frameRect } from './app-frame.js';
|
|
7
|
+
import { isWindowsPlatform } from './desktop-bridge.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Initialize the tooltip system.
|
|
@@ -11,9 +12,16 @@ import { boundsForPoint, frameRect } from './app-frame.js';
|
|
|
11
12
|
* mouseover/mouseout on any [data-tooltip] elements.
|
|
12
13
|
*/
|
|
13
14
|
export function initTooltip() {
|
|
15
|
+
if (document.documentElement?.classList) {
|
|
16
|
+
document.documentElement.classList.toggle('platform-win32', isWindowsPlatform(globalThis.window));
|
|
17
|
+
}
|
|
14
18
|
const tip = document.createElement('div');
|
|
15
19
|
tip.className = 'ui-tooltip';
|
|
16
|
-
|
|
20
|
+
const arrowEl = document.createElement('span');
|
|
21
|
+
arrowEl.className = 'ui-tooltip-arrow';
|
|
22
|
+
const textEl = document.createElement('span');
|
|
23
|
+
textEl.className = 'ui-tooltip-text';
|
|
24
|
+
tip.append(arrowEl, textEl);
|
|
17
25
|
document.body.appendChild(tip);
|
|
18
26
|
|
|
19
27
|
let showTimer = null;
|
|
@@ -29,7 +37,12 @@ export function initTooltip() {
|
|
|
29
37
|
// control's tooltip over the open menu: while one is open, the control stays
|
|
30
38
|
// quiet.
|
|
31
39
|
const OPEN_MENU_INSIDE = '.cp-dropdown.open > .cp-dd-menu, .cxp-dropdown.open > .cxp-dd-menu, .ocpv2-dropdown.open > .ocpv2-dd-menu';
|
|
32
|
-
function openMenuInside(el) {
|
|
40
|
+
function openMenuInside(el) {
|
|
41
|
+
if (el.classList?.contains('term-minimized-pill') || el.classList?.contains('term-minimized-pill-close')) return false;
|
|
42
|
+
return !!el.querySelector(OPEN_MENU_INSIDE);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const rectKey = (r) => r.left + ',' + r.top + ',' + r.width + ',' + r.height;
|
|
33
46
|
|
|
34
47
|
// Swap the placement class only: a reposition (the follow loop below) must keep .visible.
|
|
35
48
|
function setPlacement(placement) {
|
|
@@ -37,8 +50,8 @@ export function initTooltip() {
|
|
|
37
50
|
tip.classList.add(placement);
|
|
38
51
|
}
|
|
39
52
|
|
|
40
|
-
function positionTip(el) {
|
|
41
|
-
const r = el.getBoundingClientRect();
|
|
53
|
+
function positionTip(el, knownRect = null) {
|
|
54
|
+
const r = knownRect || el.getBoundingClientRect();
|
|
42
55
|
const tw = tip.offsetWidth;
|
|
43
56
|
const th = tip.offsetHeight;
|
|
44
57
|
const gap = 8;
|
|
@@ -50,14 +63,14 @@ export function initTooltip() {
|
|
|
50
63
|
// Left-side placement (session dropdowns in sidepanels)
|
|
51
64
|
// Anchor to the left edge of the containing sidepanel so tooltip always appears fully outside
|
|
52
65
|
if (preferred === 'left') {
|
|
53
|
-
const panel = el.closest('.claude-panel, .codex-panel, .ocp-panel, .assistant-panel, .menubar-dropdown--resume');
|
|
66
|
+
const panel = el.closest('.claude-panel, .codex-panel, .ocp-panel, .agy-panel, .assistant-panel, .menubar-dropdown--resume');
|
|
54
67
|
const anchorLeft = panel ? panel.getBoundingClientRect().left : r.left;
|
|
55
68
|
if (anchorLeft - gap - tw > b.left + 4) {
|
|
56
69
|
setPlacement('left');
|
|
57
70
|
tip.style.top = (r.top + r.height / 2 - th / 2) + 'px';
|
|
58
71
|
tip.style.left = (anchorLeft - gap - tw) + 'px';
|
|
59
72
|
tip.style.setProperty('--arrow-y', (th / 2) + 'px');
|
|
60
|
-
return;
|
|
73
|
+
return { rect: r, width: tw };
|
|
61
74
|
}
|
|
62
75
|
}
|
|
63
76
|
|
|
@@ -70,7 +83,7 @@ export function initTooltip() {
|
|
|
70
83
|
tip.style.top = (r.top + r.height / 2 - th / 2) + 'px';
|
|
71
84
|
tip.style.left = (anchorRight + gap) + 'px';
|
|
72
85
|
tip.style.setProperty('--arrow-y', (th / 2) + 'px');
|
|
73
|
-
return;
|
|
86
|
+
return { rect: r, width: tw };
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
// Elements near the top (title bar) → force below
|
|
@@ -90,6 +103,7 @@ export function initTooltip() {
|
|
|
90
103
|
const arrowLeft = r.left + r.width / 2 - left;
|
|
91
104
|
tip.style.setProperty('--arrow-x', arrowLeft + 'px');
|
|
92
105
|
tip.style.setProperty('--arrow-y', '');
|
|
106
|
+
return { rect: r, width: tw };
|
|
93
107
|
}
|
|
94
108
|
|
|
95
109
|
function suppressTitle(el) {
|
|
@@ -98,10 +112,16 @@ export function initTooltip() {
|
|
|
98
112
|
el._savedTitle = el.getAttribute('title');
|
|
99
113
|
el.removeAttribute('title');
|
|
100
114
|
}
|
|
101
|
-
el.querySelectorAll('[title]')
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
const titledChildren = [...el.querySelectorAll('[title]')];
|
|
116
|
+
if (titledChildren.length) {
|
|
117
|
+
el._savedTitleNodes = titledChildren;
|
|
118
|
+
for (const child of titledChildren) {
|
|
119
|
+
child._savedTitle = child.getAttribute('title');
|
|
120
|
+
child.removeAttribute('title');
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
delete el._savedTitleNodes;
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
126
|
|
|
107
127
|
function restoreTitle(el) {
|
|
@@ -109,12 +129,15 @@ export function initTooltip() {
|
|
|
109
129
|
el.setAttribute('title', el._savedTitle);
|
|
110
130
|
delete el._savedTitle;
|
|
111
131
|
}
|
|
112
|
-
el.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
132
|
+
if (el._savedTitleNodes) {
|
|
133
|
+
for (const child of el._savedTitleNodes) {
|
|
134
|
+
if (child._savedTitle !== undefined) {
|
|
135
|
+
child.setAttribute('title', child._savedTitle);
|
|
136
|
+
delete child._savedTitle;
|
|
137
|
+
}
|
|
116
138
|
}
|
|
117
|
-
|
|
139
|
+
delete el._savedTitleNodes;
|
|
140
|
+
}
|
|
118
141
|
}
|
|
119
142
|
|
|
120
143
|
function show(el) {
|
|
@@ -122,7 +145,6 @@ export function initTooltip() {
|
|
|
122
145
|
if (!text || openMenuInside(el)) return;
|
|
123
146
|
clearTimeout(hideTimer);
|
|
124
147
|
suppressTitle(el);
|
|
125
|
-
const textEl = tip.querySelector('.ui-tooltip-text');
|
|
126
148
|
const nlIdx = text.indexOf('\n');
|
|
127
149
|
if (nlIdx !== -1) {
|
|
128
150
|
let main = text.slice(0, nlIdx);
|
|
@@ -141,37 +163,22 @@ export function initTooltip() {
|
|
|
141
163
|
}
|
|
142
164
|
currentTarget = el;
|
|
143
165
|
tip.style.display = 'block';
|
|
144
|
-
|
|
145
|
-
positionTip(el);
|
|
166
|
+
const { rect: initialRect, width: initialWidth } = positionTip(el);
|
|
146
167
|
tip.classList.add('visible');
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
// Some targets resize on hover (e.g. tray pill label expands max-width
|
|
155
|
-
// 100→300px over ~300ms). Without follow-up positioning, the tooltip
|
|
156
|
-
// stays anchored to the un-expanded rect and the pill grows leftward
|
|
157
|
-
// over it. Drive a rAF loop for the duration of any size/position
|
|
158
|
-
// transition so the tooltip tracks the target.
|
|
159
|
-
const followFor = 360; // ms — upper bound, slightly longer than the longest pill transition
|
|
160
|
-
const stopAt = performance.now() + followFor;
|
|
161
|
-
// Self-terminate once the target stops moving: a static target (the vast
|
|
162
|
-
// majority of tooltips) settles in ~2 frames instead of running the full
|
|
163
|
-
// 360ms rAF/getBoundingClientRect loop, while an animating pill keeps being
|
|
164
|
-
// followed until it settles or the cap is hit.
|
|
165
|
-
let lastRectKey = '';
|
|
168
|
+
|
|
169
|
+
// Follow targets that actually animate their geometry on hover (via transitionrun),
|
|
170
|
+
// without polling static targets across multiple rAFs.
|
|
171
|
+
const followFor = 360;
|
|
172
|
+
let stopAt = 0;
|
|
173
|
+
let lastRectKey = rectKey(initialRect);
|
|
166
174
|
let stableTicks = 0;
|
|
167
175
|
const tick = () => {
|
|
168
176
|
repositionRafId = 0;
|
|
169
177
|
if (currentTarget !== el) return;
|
|
170
|
-
positionTip(el);
|
|
171
|
-
const
|
|
172
|
-
const key = r.left + ',' + r.top + ',' + r.width + ',' + r.height;
|
|
178
|
+
const { rect: r } = positionTip(el);
|
|
179
|
+
const key = rectKey(r);
|
|
173
180
|
if (key === lastRectKey) {
|
|
174
|
-
if (++stableTicks >= 2) return;
|
|
181
|
+
if (++stableTicks >= 2) return;
|
|
175
182
|
} else {
|
|
176
183
|
stableTicks = 0;
|
|
177
184
|
lastRectKey = key;
|
|
@@ -184,6 +191,8 @@ export function initTooltip() {
|
|
|
184
191
|
if (currentTarget !== el) return;
|
|
185
192
|
if (event.target !== el && !el.contains(event.target)) return;
|
|
186
193
|
if (!/width|max-width|transform|margin|padding|left|right|top|bottom/.test(event.propertyName || '')) return;
|
|
194
|
+
stopAt = performance.now() + followFor;
|
|
195
|
+
stableTicks = 0;
|
|
187
196
|
if (!repositionRafId) repositionRafId = requestAnimationFrame(tick);
|
|
188
197
|
};
|
|
189
198
|
repositionEndHandler = (event) => {
|
|
@@ -193,9 +202,25 @@ export function initTooltip() {
|
|
|
193
202
|
};
|
|
194
203
|
el.addEventListener('transitionrun', repositionRunHandler);
|
|
195
204
|
el.addEventListener('transitionend', repositionEndHandler);
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
|
|
205
|
+
|
|
206
|
+
// One check on the next frame (a single rect read): metrics that settle after display:none, or a
|
|
207
|
+
// hover transition that began before the listeners above were attached (the 16-20 ms show delay).
|
|
208
|
+
if (!repositionRafId) {
|
|
209
|
+
repositionRafId = requestAnimationFrame(() => {
|
|
210
|
+
repositionRafId = 0;
|
|
211
|
+
if (currentTarget !== el) return;
|
|
212
|
+
const r = el.getBoundingClientRect();
|
|
213
|
+
const key = rectKey(r);
|
|
214
|
+
if (key !== lastRectKey || tip.offsetWidth !== initialWidth) {
|
|
215
|
+
lastRectKey = key;
|
|
216
|
+
positionTip(el, r);
|
|
217
|
+
if (key !== rectKey(initialRect)) {
|
|
218
|
+
stopAt = performance.now() + followFor;
|
|
219
|
+
repositionRafId = requestAnimationFrame(tick);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
199
224
|
}
|
|
200
225
|
|
|
201
226
|
function hide() {
|
|
@@ -230,7 +255,7 @@ export function initTooltip() {
|
|
|
230
255
|
clearTimeout(hideTimer);
|
|
231
256
|
if (currentTarget) {
|
|
232
257
|
hide();
|
|
233
|
-
show(el);
|
|
258
|
+
showTimer = setTimeout(() => show(el), 16);
|
|
234
259
|
} else {
|
|
235
260
|
showTimer = setTimeout(() => show(el), 20);
|
|
236
261
|
}
|