synabun 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +139 -0
- package/README.md +1 -1
- package/docs/whatsapp.md +11 -11
- package/lib/client-config-repair.js +13 -9
- package/lib/external-tools.js +6 -5
- package/lib/update-snapshot.js +77 -3
- package/lib/virustotal.mjs +12 -1
- package/mcp-server/dist/index.js +1 -1
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +2 -1
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +2 -1
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.js +1 -1
- package/mcp-server/dist/services/tool-catalog.js.map +1 -1
- package/mcp-server/dist/services/tool-list.d.ts +1 -1
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -1
- package/mcp-server/dist/services/tool-runtime.d.ts +2 -2
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -1
- package/mcp-server/dist/services/tool-runtime.js +1 -1
- package/mcp-server/dist/services/tool-runtime.js.map +1 -1
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +8 -8
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +10 -9
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +8 -8
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/skill-tools.js +11 -8
- package/mcp-server/dist/tools/skill-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/index.ts +1 -1
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +2 -1
- package/mcp-server/src/services/server-instructions.ts +2 -1
- package/mcp-server/src/services/tool-catalog.ts +1 -1
- package/mcp-server/src/services/tool-list.ts +1 -1
- package/mcp-server/src/services/tool-runtime.ts +2 -2
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/tools/agents.ts +10 -9
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +11 -8
- package/neural-interface/i18n/en.json +504 -39
- package/neural-interface/i18n/pt-BR.json +504 -39
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +1 -0
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/codex.js +6 -1
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +76 -9
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +211 -50
- package/neural-interface/lib/assistant-envelope.js +153 -1
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +16 -11
- package/neural-interface/lib/assistant-plan-permissions.js +15 -0
- package/neural-interface/lib/assistant-router.js +237 -35
- package/neural-interface/lib/assistant-runtime.js +158 -12
- package/neural-interface/lib/assistant-task-prompt.js +10 -8
- package/neural-interface/lib/assistant-tools.js +2 -2
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +6 -1
- package/neural-interface/lib/browser-guard-cdp.js +5 -4
- package/neural-interface/lib/browser-network-guard.js +274 -82
- package/neural-interface/lib/browser-tool-policy.js +12 -7
- package/neural-interface/lib/claude-agent-bridge.js +7 -0
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +160 -31
- package/neural-interface/lib/cli-resolver.js +9 -2
- package/neural-interface/lib/cli-update-planner.js +25 -15
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +25 -6
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +9 -2
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/mcp-client-config.js +37 -6
- package/neural-interface/lib/mcp-external-servers.js +40 -7
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +147 -25
- package/neural-interface/lib/native-loop-providers.js +423 -23
- package/neural-interface/lib/native-loop-runtime.js +23 -2
- package/neural-interface/lib/opencode-native-boundary.js +165 -22
- package/neural-interface/lib/owner-authority.js +1 -1
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +80 -6
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +3 -0
- package/neural-interface/lib/rulesets/api.js +6 -5
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +89 -10
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +64 -1
- package/neural-interface/lib/skills/catalog.js +5 -1
- package/neural-interface/lib/skills/creation-brief.js +1 -1
- package/neural-interface/lib/skills/creation-sources.js +19 -1
- package/neural-interface/lib/skills/deploy.js +9 -4
- package/neural-interface/lib/skills/draft-confinement.js +3 -1
- package/neural-interface/lib/skills/eval-confinement.js +3 -1
- package/neural-interface/lib/skills/eval-trace.js +16 -0
- package/neural-interface/lib/skills/export.js +5 -2
- package/neural-interface/lib/skills/known-bridge-digests.json +58 -4
- package/neural-interface/lib/skills/ownership.js +1 -1
- package/neural-interface/lib/skills/roots.js +10 -3
- package/neural-interface/lib/skills/runtime-checks.js +6 -3
- package/neural-interface/lib/skills/service.js +15 -7
- package/neural-interface/lib/skills/telemetry.js +6 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +77 -1
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-resume.js +13 -4
- package/neural-interface/lib/worker-sandbox.js +46 -16
- package/neural-interface/package-lock.json +18 -2
- package/neural-interface/package.json +2 -1
- package/neural-interface/public/onboarding.html +1 -1
- package/neural-interface/public/shared/agent-runtime-options.js +89 -11
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +4 -4
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +3 -4
- package/neural-interface/public/shared/assistant/asst-api.js +15 -3
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +56 -9
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-computer.js +26 -2
- package/neural-interface/public/shared/assistant/asst-control.js +48 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +6 -1
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +38 -5
- package/neural-interface/public/shared/assistant/asst-motion-gate.js +80 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +46 -9
- package/neural-interface/public/shared/assistant/asst-render.js +112 -18
- package/neural-interface/public/shared/assistant/asst-route.js +237 -57
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scene-styles.js +55 -23
- package/neural-interface/public/shared/assistant/asst-scenes.js +279 -80
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +4 -4
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +51 -7
- package/neural-interface/public/shared/assistant/asst-slash.js +8 -2
- package/neural-interface/public/shared/assistant/asst-state.js +76 -9
- package/neural-interface/public/shared/assistant/asst-style-cache.js +44 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +58 -4
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +34 -7
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +26 -3
- package/neural-interface/public/shared/cdx/cdx-panel.js +14 -2
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +11 -10
- package/neural-interface/public/shared/cdx/cdx-render.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-requests.js +11 -1
- package/neural-interface/public/shared/cdx/cdx-styles.js +4 -0
- package/neural-interface/public/shared/cdx/cdx-tabs.js +75 -5
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +7 -4
- package/neural-interface/public/shared/cli-status.js +9 -8
- package/neural-interface/public/shared/constants.js +3 -2
- package/neural-interface/public/shared/context-menu-model.js +1 -0
- package/neural-interface/public/shared/cp/cp-permissions.js +12 -0
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +1 -0
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +21 -4
- package/neural-interface/public/shared/loading-teardown.js +34 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +6 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +28 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +17 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +6 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +101 -68
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +46 -3
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +1 -1
- package/neural-interface/public/shared/settings/settings-skill-folders.js +2 -2
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-creation.js +6 -3
- package/neural-interface/public/shared/skills/ss-dialog.js +5 -2
- package/neural-interface/public/shared/skills/ss-lint.js +9 -1
- package/neural-interface/public/shared/skills/ss-profiles.js +44 -6
- package/neural-interface/public/shared/skills/ss-review-view.js +2 -2
- package/neural-interface/public/shared/skills/studio/sx-actions.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +2 -1
- package/neural-interface/public/shared/skills/studio/sx-dom.js +2 -1
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +9 -6
- package/neural-interface/public/shared/skills/studio/sx-install.js +20 -3
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +144 -35
- package/neural-interface/public/shared/skills/studio/sx-library.js +6 -2
- package/neural-interface/public/shared/skills/studio/sx-main.js +11 -2
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +1 -1
- package/neural-interface/public/shared/skills/studio/sx-subject.js +7 -6
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +6 -5
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/storage-retry.js +47 -0
- package/neural-interface/public/shared/storage.js +25 -4
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styles.css +362 -35
- package/neural-interface/public/shared/synabun-mascot.js +27 -8
- package/neural-interface/public/shared/synabun-ticker.js +147 -12
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +2 -2
- package/neural-interface/public/shared/tool-list-view.js +2 -2
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +20 -12
- package/neural-interface/public/shared/ui-claude-panel.js +374 -134
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +8 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-loading.js +5 -4
- package/neural-interface/public/shared/ui-menubar.js +2 -2
- package/neural-interface/public/shared/ui-native-loop-router.js +4 -0
- package/neural-interface/public/shared/ui-navbar.js +45 -0
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +41 -10
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +22 -12
- package/neural-interface/public/shared/ui-settings.js +90 -65
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -3
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +3 -3
- package/neural-interface/public/shared/ui-terminal.js +146 -10
- package/neural-interface/public/shared/ui-tool-updates.js +3 -3
- package/neural-interface/public/shared/ui-tooltip.js +71 -46
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-whiteboard.js +1 -1
- package/neural-interface/public/shared/ui-worker-end.js +1 -1
- package/neural-interface/public/shared/whatsapp/wa-view.js +2 -2
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/sidepanel-session.html +1 -1
- package/neural-interface/server.js +731 -466
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +5 -5
- package/neural-interface/templates/rulesets/manifest.json +1 -1
- package/npm-shrinkwrap.json +18 -2
- package/package.json +2 -1
- package/skills/skill-forge/SKILL.md +4 -4
- package/skills/synabun/SKILL.md +1 -1
- package/skills/synabun/modules/schedule.md +3 -3
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { t } from '../i18n.js';
|
|
2
|
+
import { answerWorkerQuestion } from '../worker-questions.js';
|
|
1
3
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
4
|
// OpenCode V2 — WebSocket client (multi-panel)
|
|
3
5
|
// One WS connection serves every OCP v2 panel on the page. Panels register a
|
|
@@ -27,6 +29,12 @@ const _outcomes = createOutcomeNotifications();
|
|
|
27
29
|
|
|
28
30
|
function _fireOutcomeNotify(store, type) {
|
|
29
31
|
const s = store.getState();
|
|
32
|
+
// A sub-agent finishing is an intermediate step of its parent's task, not
|
|
33
|
+
// news on its own: ensureChildSpawn gives every Task/subagent call its own
|
|
34
|
+
// panel and store, so without this a multi-step turn popped one "done" per
|
|
35
|
+
// sub-agent plus one for the task itself. Its own errors still surface —
|
|
36
|
+
// those need attention wherever they happen.
|
|
37
|
+
if (type !== NOTIF_TYPE.ERROR && s.parentSessionId) return;
|
|
30
38
|
if (!_outcomes.take(s, type === NOTIF_TYPE.ERROR ? 'error' : 'done')) return;
|
|
31
39
|
const baseLabel = s.sessionInfo?.title || s.sessionInfo?.info?.title || 'OpenCode';
|
|
32
40
|
const label = s.parentSessionId ? `↳ ${baseLabel}` : baseLabel;
|
|
@@ -627,6 +635,41 @@ function request(payload, timeoutMs = 30000, { turnOf = '' } = {}) {
|
|
|
627
635
|
});
|
|
628
636
|
}
|
|
629
637
|
|
|
638
|
+
const workerQuestionRuns = new Map();
|
|
639
|
+
export const hasWorkerQuestions = (sessionId) => workerQuestionRuns.has(sessionId);
|
|
640
|
+
export const forgetWorkerQuestions = (sessionId) => workerQuestionRuns.delete(sessionId);
|
|
641
|
+
const workerQuestions = (run) => (run?.pending || []).filter((p) => p.kind === 'question').map((p) => ({ ...p.input, id: p.protocol?.id, sessionID: run.providerSessionId, _workerRequestId: p.requestId }));
|
|
642
|
+
|
|
643
|
+
export function syncOpenCodeWorkerQuestions(run) {
|
|
644
|
+
if (run.runMode !== 'task') return;
|
|
645
|
+
const sid = run.providerSessionId;
|
|
646
|
+
const previous = workerQuestions(workerQuestionRuns.get(sid));
|
|
647
|
+
workerQuestionRuns.set(sid, run);
|
|
648
|
+
const next = workerQuestions(run);
|
|
649
|
+
for (const req of previous) if (!next.some((n) => n.id === req.id)) _asks.note('question.replied', { id: req.id, sessionID: sid });
|
|
650
|
+
for (const req of next) _asks.note('question.asked', req);
|
|
651
|
+
for (const store of _storesBySession.get(sid) || []) {
|
|
652
|
+
for (const req of previous) if (!next.some((n) => n.id === req.id)) store.removePendingQuestion(req.id);
|
|
653
|
+
for (const req of next) store.addPendingQuestion(req);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
async function answerOpenCodeWorker({ sessionId, requestId, answers }, reject = false) {
|
|
658
|
+
let run = workerQuestionRuns.get(sessionId);
|
|
659
|
+
let pending = workerQuestions(run).find((q) => q.id === requestId);
|
|
660
|
+
// An SSE question can precede the run update. Read the authoritative pending request before answering.
|
|
661
|
+
if (!pending) {
|
|
662
|
+
const res = await fetch(`/api/assistant/runs/${encodeURIComponent(run.runId)}`);
|
|
663
|
+
if (!res.ok) throw new Error(t('workerQuestion.deliveryFailed'));
|
|
664
|
+
const body = await res.json();
|
|
665
|
+
if (!body.run) throw new Error(t('workerQuestion.deliveryFailed'));
|
|
666
|
+
run = body.run; pending = workerQuestions(run).find((q) => q.id === requestId);
|
|
667
|
+
}
|
|
668
|
+
if (pending) await answerWorkerQuestion(run.runId, pending._workerRequestId, { decision: reject ? 'deny' : 'answer', answers });
|
|
669
|
+
for (const store of _storesBySession.get(sessionId) || []) store.removePendingQuestion(requestId);
|
|
670
|
+
return { ok: true, data: true };
|
|
671
|
+
}
|
|
672
|
+
|
|
630
673
|
export const api = {
|
|
631
674
|
init: () => request({ type: 'init', windowId: nativeLoopWindowId }),
|
|
632
675
|
// options: { search, archived, roots, limit }. A server without
|
|
@@ -645,9 +688,9 @@ export const api = {
|
|
|
645
688
|
compact: ({ sessionId, cwd, tools } = {}) => request({ type: 'session:compact', sessionId, cwd, tools }, 5 * 60 * 1000),
|
|
646
689
|
permissionReply: ({ sessionId, permissionId, response, cwd, message }) =>
|
|
647
690
|
request({ type: 'permission:reply', sessionId, permissionId, response, cwd, message }),
|
|
648
|
-
questionList: ({ cwd, sessionId } = {}) => request({ type: 'question:list', cwd, sessionId }),
|
|
649
|
-
questionReply: ({ requestId, answers, cwd, sessionId }) => request({ type: 'question:reply', requestId, answers, cwd, sessionId }),
|
|
650
|
-
questionReject: ({ requestId, sessionId }) => request({ type: 'question:reject', requestId, sessionId }),
|
|
691
|
+
questionList: ({ cwd, sessionId } = {}) => workerQuestionRuns.has(sessionId) ? Promise.resolve({ data: workerQuestions(workerQuestionRuns.get(sessionId)) }) : request({ type: 'question:list', cwd, sessionId }),
|
|
692
|
+
questionReply: ({ requestId, answers, cwd, sessionId }) => workerQuestionRuns.has(sessionId) ? answerOpenCodeWorker({ requestId, answers, sessionId }) : request({ type: 'question:reply', requestId, answers, cwd, sessionId }),
|
|
693
|
+
questionReject: ({ requestId, sessionId }) => workerQuestionRuns.has(sessionId) ? answerOpenCodeWorker({ requestId, sessionId }, true) : request({ type: 'question:reject', requestId, sessionId }),
|
|
651
694
|
toolsGet: (sessionId) => gated({ type: 'mcp:tools:get', sessionId }),
|
|
652
695
|
toolsSet: (sessionId, tools) => gated({ type: 'mcp:tools:set', sessionId, tools }, 45_000),
|
|
653
696
|
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
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>';
|
|
6
6
|
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 0 0-.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 0 1 .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 0 1 4.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 0 1-.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 0 0 5.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 0 0 10.205 0a5.947 5.947 0 0 0-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 0 0 4.162 1.713z"/></svg>';
|
|
7
|
-
|
|
7
|
+
// A line drawing: its paths carry fill="none" themselves, because some places fill every icon they hold
|
|
8
|
+
// (`.resume-provider-icon svg { fill: currentColor }`), which would turn the strokes into a solid triangle.
|
|
9
|
+
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" fill="none"/><path d="M8.2 20a3.8 3.8 0 0 1 7.6 0" fill="none"/></svg>';
|
|
8
10
|
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>';
|
|
9
11
|
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>';
|
|
10
12
|
const SVG_BROWSER = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>';
|
|
@@ -15,7 +17,7 @@ const PROVIDER_META = {
|
|
|
15
17
|
'claude-code': { id: 'claude-code', label: 'Claude Code', shortLabel: 'Claude', icon: SVG_CLAUDE, color: '#D4A27F' },
|
|
16
18
|
codex: { id: 'codex', label: 'Codex', shortLabel: 'Codex', icon: SVG_OPENAI, color: '#74C7A5' },
|
|
17
19
|
opencode: { id: 'opencode', label: 'OpenCode', shortLabel: 'OpenCode', icon: SVG_OPENCODE, color: '#E8E0DC' },
|
|
18
|
-
|
|
20
|
+
antigravity: { id: 'antigravity', label: 'Antigravity', shortLabel: 'Antigravity', icon: SVG_ANTIGRAVITY, color: '#669DF6' },
|
|
19
21
|
synabun: { id: 'synabun', label: 'SynaBun', shortLabel: 'SynaBun', icon: SVG_SYNABUN, color: '#FFD23C' },
|
|
20
22
|
shell: { id: 'shell', label: 'Shell', shortLabel: 'Shell', icon: SVG_SHELL, color: '#AAAAAA' },
|
|
21
23
|
browser: { id: 'browser', label: 'Browser', shortLabel: 'Browser', icon: SVG_BROWSER, color: '#4FC3F7' },
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
// `tx` in Settings; the wizard reads the same catalogue, i18n/en.json).
|
|
21
21
|
|
|
22
22
|
/** The tools SynaBun installs rules for, in the order both surfaces list them. Cursor is copy-only. */
|
|
23
|
-
export const RULES_INSTALL_HOSTS = Object.freeze(['claude', '
|
|
23
|
+
export const RULES_INSTALL_HOSTS = Object.freeze(['claude', 'antigravity', 'codex', 'opencode']);
|
|
24
24
|
|
|
25
|
-
export const RULES_HOST_LABELS = Object.freeze({ claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode',
|
|
25
|
+
export const RULES_HOST_LABELS = Object.freeze({ claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', antigravity: 'Antigravity', cursor: 'Cursor', coexistence: 'coexistence' });
|
|
26
26
|
|
|
27
27
|
/** The states that count as "the rules are in place". `shadowed` is installed too, only not loaded (Codex's override file). */
|
|
28
28
|
export const RULES_IN_PLACE = Object.freeze(['installed', 'newer', 'shadowed']);
|
|
@@ -66,7 +66,7 @@ export async function refreshSkillChips(root) {
|
|
|
66
66
|
const skill = byDir.get(chip.dataset.ccSkill);
|
|
67
67
|
if (!skill || chip.style.pointerEvents === 'none') continue;
|
|
68
68
|
const target = chip.dataset.ccTarget;
|
|
69
|
-
const installed = skill.installedTargets || { claude: !!skill.installed, codex: false, opencode: false };
|
|
69
|
+
const installed = skill.installedTargets || { claude: !!skill.installed, codex: false, opencode: false, antigravity: false };
|
|
70
70
|
const now = chipState(skill.targetStates?.[target], !!installed[target]);
|
|
71
71
|
chip.classList.toggle('on', now.on);
|
|
72
72
|
chip.dataset.state = now.on ? 'on' : 'off';
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// each runtime chip's state (a native folder, an old bridge, someone else's folder). Every sentence is a
|
|
9
9
|
// settings.redesign.skills.* key; the pane (settings-skill-folders-pane.js) draws it.
|
|
10
10
|
|
|
11
|
-
const RUNTIME = { claude: 'settings.redesign.product.claude', codex: 'settings.redesign.product.codex', opencode: 'settings.redesign.product.opencode' };
|
|
11
|
+
const RUNTIME = { claude: 'settings.redesign.product.claude', codex: 'settings.redesign.product.codex', opencode: 'settings.redesign.product.opencode', antigravity: 'settings.redesign.product.antigravity' };
|
|
12
12
|
|
|
13
13
|
/** What the status answer says, or that the server cannot say it yet (one from before the Skills Service). */
|
|
14
14
|
export function readFoldersStatus(answer) {
|
|
@@ -26,7 +26,7 @@ export function readFoldersStatus(answer) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const ASSISTANTS = ['claude', 'codex', 'opencode'];
|
|
29
|
+
const ASSISTANTS = ['claude', 'codex', 'opencode', 'antigravity'];
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* The owner's assistants (GET /v2/config `assistants`: chosen, detected, effective): one chip per runtime, on when
|
|
@@ -55,13 +55,18 @@ export const WHOLESALE_SELECTORS = [
|
|
|
55
55
|
// OpenCode side panel transcript
|
|
56
56
|
'.ocpv2-part-text', '.ocpv2-reasoning-body', '.ocpv2-tc-summary', '.ocpv2-tc-meta', '.ocpv2-tc-body',
|
|
57
57
|
'.ocpv2-tool-input', '.ocpv2-tool-output', '.ocpv2-sb-summary',
|
|
58
|
+
// Antigravity side panel: session names, the transcript, tool and request cards, the plan, what waits to be sent
|
|
59
|
+
'.agy-session-label', '.agy-tab-label', '.agy-sess-list .agy-pop-item-title', '.agy-sess-list .agy-pop-item-meta',
|
|
60
|
+
'.agy-msg-text', '.agy-msg .agy-md', '.agy-msg-image', '.agy-thought-body',
|
|
61
|
+
'.agy-card-title', '.agy-card-subtitle', '.agy-card-text', '.agy-card-body', '.agy-card-error', '.agy-plan-text',
|
|
62
|
+
'.agy-queue-text', '.agy-chip', '.agy-folder-chip',
|
|
58
63
|
// Assistant transcript, run and worker cards
|
|
59
64
|
'.asst-msg-text', '.asst-md', '.asst-thinking-content', '.asst-run-title', '.asst-run-summary', '.asst-run-escalate-reason',
|
|
60
65
|
'.asst-tool-detail', '.asst-tool-body', '.asst-tool-section', '.asst-tl-said', '.asst-tl-subject', '.asst-bubble-text',
|
|
61
66
|
'.asst-station-sub', '.asst-station-log', '.asst-auto-title', '.asst-auto-summary', '.asst-auto-detail',
|
|
62
67
|
// Composers, once they hold text (an empty one keeps its placeholder sharp)
|
|
63
68
|
'#cp-input:not(:placeholder-shown)', '#cxp-input:not(:placeholder-shown)', '.ocpv2-compose-input:not(:placeholder-shown)',
|
|
64
|
-
'.asst-input:not(:placeholder-shown)',
|
|
69
|
+
'.asst-input:not(:placeholder-shown)', '.agy-input:not(:placeholder-shown)',
|
|
65
70
|
// Terminal output (the WebGL canvas and the DOM renderer alike) and the terminal's browser tab
|
|
66
71
|
'.term-viewport .xterm-screen', '.term-float-tab-body .xterm', '.browser-canvas', '.browser-url-input', '.browser-title-label',
|
|
67
72
|
// Resume results
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
// Assistant (sessionStatus). The same source as the tray pills, never a second
|
|
9
9
|
// guess. DOM-free.
|
|
10
10
|
|
|
11
|
-
const WORKING = /^(cp|cxp|ocpv2|asp)-pill-running$/;
|
|
12
|
-
const NEEDS_YOU = /^((cp|cxp|asp)-pill-attention|ocpv2-pill-waiting)$/;
|
|
11
|
+
const WORKING = /^(cp|cxp|ocpv2|agy|asp)-pill-running$/;
|
|
12
|
+
const NEEDS_YOU = /^((cp|cxp|agy|asp)-pill-attention|ocpv2-pill-waiting)$/;
|
|
13
13
|
|
|
14
14
|
/** The states a detached window's pill shows: a session in it needs you > one works > none. */
|
|
15
15
|
export const SESSION_WINDOW_STATES = Object.freeze(['action', 'working', 'idle']);
|
|
@@ -44,6 +44,6 @@ export function normalizeSessionWindowStatus(status) {
|
|
|
44
44
|
*/
|
|
45
45
|
export function runAwaitsAnswer(run) {
|
|
46
46
|
if (run?.status !== 'starting' && run?.status !== 'running') return false;
|
|
47
|
-
if (run.turnState === 'needs_input') return true;
|
|
47
|
+
if (run.turnState === 'needs_input' || run.turnState === 'awaiting_permission' || run.pending?.some((p) => p.kind === 'question')) return true;
|
|
48
48
|
return run.turnState === 'idle' && (run.outcome || run.lastResult?.status) === 'needs_input';
|
|
49
49
|
}
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
// one reading of a request for the page and the server. No DOM and no imports.
|
|
9
9
|
//
|
|
10
10
|
// describe the owner's words only
|
|
11
|
-
// conversation one session transcript of Claude Code, Codex or
|
|
11
|
+
// conversation one session transcript of Claude Code, Codex, OpenCode or Antigravity (read by the server, as data)
|
|
12
12
|
// url a web page, read by the server with the SynaBun browser before the worker starts (as data)
|
|
13
13
|
// repo a registered project, read by the server: its file tree, docs, manifests and the files named
|
|
14
14
|
// memory a recall over SynaBun's memory
|
|
15
15
|
// import an imported skill (a staged import), or a skill of the catalog or the library, as the starting point
|
|
16
16
|
|
|
17
17
|
export const SOURCE_KINDS = Object.freeze(['describe', 'conversation', 'url', 'repo', 'memory', 'import']);
|
|
18
|
-
export const CONVERSATION_PROVIDERS = Object.freeze(['claude-code', 'codex', 'opencode']);
|
|
18
|
+
export const CONVERSATION_PROVIDERS = Object.freeze(['claude-code', 'codex', 'opencode', 'antigravity']);
|
|
19
19
|
/**
|
|
20
20
|
* Who drafts: Claude Code only. A drafting worker reads hostile sources, so it is held to its folder with file tools
|
|
21
21
|
* only (lib/skills/draft-confinement.js), which Claude Code enforces before any permission mode; Codex starts MCP
|
|
@@ -23,7 +23,8 @@ export const CONVERSATION_PROVIDERS = Object.freeze(['claude-code', 'codex', 'op
|
|
|
23
23
|
*/
|
|
24
24
|
/** The providers a drafting run can be held to its folder on (lib/skills/draft-confinement.js draftConfinementSupport). */
|
|
25
25
|
export const DRAFT_PROVIDERS = Object.freeze(['claude-code', 'codex', 'opencode']);
|
|
26
|
-
|
|
26
|
+
/** Where a drafted skill may be installed later (a deploy.js target): Antigravity too, though no Antigravity worker drafts. */
|
|
27
|
+
export const CREATION_TARGET_RUNTIMES = Object.freeze(['claude', 'codex', 'opencode', 'antigravity', 'agents']);
|
|
27
28
|
|
|
28
29
|
/** The stages of a creation, in order; the last four end it. */
|
|
29
30
|
export const CREATION_STAGES = Object.freeze(['queued', 'gathering', 'drafting', 'checking', 'submitting', 'done', 'failed', 'cancelled', 'interrupted']);
|
|
@@ -184,6 +185,8 @@ export function normalizeCreationRequest(body, { submitDefault = true } = {}) {
|
|
|
184
185
|
const scope = t.scope === undefined || t.scope === null || t.scope === '' ? 'user' : t.scope;
|
|
185
186
|
if (scope !== 'user' && scope !== 'project') { problems.push({ field: `${at}.scope`, code: 'targets-scope' }); return; }
|
|
186
187
|
if (t.runtime === 'agents' && scope !== 'user') { problems.push({ field: `${at}.scope`, code: 'targets-agents-scope' }); return; }
|
|
188
|
+
// Antigravity reads a project's .agents/skills, which is the codex target with scope project.
|
|
189
|
+
if (t.runtime === 'antigravity' && scope !== 'user') { problems.push({ field: `${at}.scope`, code: 'targets-antigravity-scope' }); return; }
|
|
187
190
|
const accountId = t.accountId === undefined || t.accountId === null || t.accountId === '' ? 'default' : t.accountId;
|
|
188
191
|
if (typeof accountId !== 'string' || !ACCOUNT_RE.test(accountId)) { problems.push({ field: `${at}.accountId`, code: 'targets-account' }); return; }
|
|
189
192
|
let projectPath = null;
|
|
@@ -30,9 +30,11 @@ export function closeDialog() { _open?.giveUp(); }
|
|
|
30
30
|
* @param {string|null} [o.cancelId] what Escape and a click outside answer; null: they answer null
|
|
31
31
|
* @param {HTMLElement|null} [o.extra] more content after the text (a checkbox, a list)
|
|
32
32
|
* @param {(answer: string, ui: object) => boolean} [o.accept] called before the answer is given: false keeps it open
|
|
33
|
+
* @param {(ui: object) => void} [o.onOpen] called once it is drawn, with { box, body, bar, byId, setDisabled, done }
|
|
34
|
+
* @param {string} [o.className] one more class on the dialog (a variant: `ss-dlg--confirm`)
|
|
33
35
|
* @returns {Promise<string|null>} the id of the button, or `cancelId` / null
|
|
34
36
|
*/
|
|
35
|
-
export function askInPanel({ host, title, lines = [], buttons, focus = null, cancelId = 'cancel', extra = null, accept = null, wide = false }) {
|
|
37
|
+
export function askInPanel({ host, title, lines = [], buttons, focus = null, cancelId = 'cancel', extra = null, accept = null, wide = false, onOpen = null, className = '' }) {
|
|
36
38
|
return new Promise((resolve) => {
|
|
37
39
|
_open?.giveUp();
|
|
38
40
|
const before = document.activeElement;
|
|
@@ -41,7 +43,7 @@ export function askInPanel({ host, title, lines = [], buttons, focus = null, can
|
|
|
41
43
|
const backdrop = document.createElement('div');
|
|
42
44
|
backdrop.className = 'ss-fd-backdrop';
|
|
43
45
|
const box = document.createElement('div');
|
|
44
|
-
box.className = `ss-file-dialog ss-dlg${wide ? ' ss-dlg--wide' : ''}`;
|
|
46
|
+
box.className = `ss-file-dialog ss-dlg${wide ? ' ss-dlg--wide' : ''}${className ? ` ${className}` : ''}`;
|
|
45
47
|
const uid = `ss-dlg-${Math.random().toString(36).slice(2, 8)}`;
|
|
46
48
|
box.setAttribute('role', 'alertdialog');
|
|
47
49
|
box.setAttribute('aria-modal', 'true');
|
|
@@ -126,5 +128,6 @@ export function askInPanel({ host, title, lines = [], buttons, focus = null, can
|
|
|
126
128
|
const start = (focus && byId.get(focus)) || [...buttons].reverse().map((b) => byId.get(b.id)).find((n) => n && !n.disabled && !n.classList.contains('ss-dlg-btn--danger')) || enabled()[0];
|
|
127
129
|
start?.focus({ preventScroll: true });
|
|
128
130
|
ui.done = done;
|
|
131
|
+
if (typeof onOpen === 'function') onOpen(ui);
|
|
129
132
|
});
|
|
130
133
|
}
|
|
@@ -81,7 +81,12 @@ export function lintArtifact({ type, parsed, folderName = '', knownNames = [] })
|
|
|
81
81
|
if (typeof desc !== 'string') add('description-type', 'error', `"description" must be text; it is ${kindOf(desc)}.`, lineOf('description'));
|
|
82
82
|
else if (!desc.trim()) add('description-empty', 'error', '"description" is empty.', lineOf('description'));
|
|
83
83
|
else {
|
|
84
|
-
|
|
84
|
+
// The 1024-character limit is the skill format's (Claude Code, Codex and the portable format refuse a longer
|
|
85
|
+
// SKILL.md). An agent or a command has none: a long description only costs context, which is no error.
|
|
86
|
+
if (desc.length > DESCRIPTION_MAX) {
|
|
87
|
+
if (type === 'skill') add('description-length', 'error', `"description" is ${desc.length} characters; the limit is ${DESCRIPTION_MAX}.`, lineOf('description'));
|
|
88
|
+
else add('description-length', 'info', `"description" is ${desc.length} characters: every session carries it, so a shorter one leaves more room.`, lineOf('description'));
|
|
89
|
+
}
|
|
85
90
|
const hidden = findHiddenChars(desc);
|
|
86
91
|
if (hidden.length) add('description-hidden-chars', 'error', `"description" holds characters nobody can see: ${hidden.slice(0, 5).map((h) => h.label).join(', ')}${hidden.length > 5 ? '…' : ''}.`, lineOf('description'));
|
|
87
92
|
}
|
|
@@ -99,6 +104,9 @@ export function lintArtifact({ type, parsed, folderName = '', knownNames = [] })
|
|
|
99
104
|
if (has(key) && typeof data[key] !== 'boolean') add(`${key}-type`, 'error', `"${key}" must be true or false; it is ${kindOf(data[key])}.`, lineOf(key));
|
|
100
105
|
}
|
|
101
106
|
for (const key of STRING_KEYS) {
|
|
107
|
+
// `argument-hint: [message]` is the form Claude Code's own documentation writes: YAML reads the brackets as a
|
|
108
|
+
// list of text and Claude Code shows it as written. Only another kind of value is an error.
|
|
109
|
+
if (key === 'argument-hint' && Array.isArray(data[key]) && data[key].every((v) => typeof v === 'string' || typeof v === 'number')) continue;
|
|
102
110
|
if (has(key) && data[key] !== null && typeof data[key] !== 'string') add(`${key}-type`, 'error', `"${key}" must be text; it is ${kindOf(data[key])}.`, lineOf(key));
|
|
103
111
|
}
|
|
104
112
|
for (const key of TOOL_KEYS) {
|
|
@@ -11,14 +11,15 @@
|
|
|
11
11
|
//
|
|
12
12
|
// Invocation is kept as intent, apart from any one runtime's spelling of it: who may start the skill (the user
|
|
13
13
|
// by name, the model on its own), read from every dialect a folder carries (Claude Code fields, Codex's
|
|
14
|
-
// agents/openai.yaml, OpenCode's metadata) and compared with what a target
|
|
15
|
-
// so an install never lets a model start a skill its author kept
|
|
14
|
+
// agents/openai.yaml, OpenCode's metadata, Antigravity's disable-slash-command) and compared with what a target
|
|
15
|
+
// would read from the exported bytes, so an install never lets a model start a skill its author kept
|
|
16
|
+
// explicit-only (invocationPlan).
|
|
16
17
|
//
|
|
17
18
|
// No DOM, no I/O: the page and the server load it; YAML is parsed by the caller.
|
|
18
19
|
|
|
19
20
|
import { findHiddenChars } from './ss-unicode.js';
|
|
20
21
|
|
|
21
|
-
export const PROFILE_SET_VERSION = '2026-10-
|
|
22
|
+
export const PROFILE_SET_VERSION = '2026-10-30';
|
|
22
23
|
|
|
23
24
|
const RETRIEVED = '2026-10-21';
|
|
24
25
|
const SOURCES = Object.freeze({
|
|
@@ -29,6 +30,7 @@ const SOURCES = Object.freeze({
|
|
|
29
30
|
codexPrompts: { title: 'Codex custom prompts (deprecated)', url: 'https://learn.chatgpt.com/docs/custom-prompts', retrieved: RETRIEVED },
|
|
30
31
|
opencode: { title: 'OpenCode skills', url: 'https://opencode.ai/docs/skills/', retrieved: RETRIEVED },
|
|
31
32
|
opencodeCommands: { title: 'OpenCode commands', url: 'https://opencode.ai/docs/commands/', retrieved: RETRIEVED },
|
|
33
|
+
antigravity: { title: 'Antigravity CLI reference', url: 'https://antigravity.google/docs/cli/reference', retrieved: '2026-10-30' },
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
export const PORTABLE_FIELDS = Object.freeze(['name', 'description', 'license', 'compatibility', 'metadata', 'allowed-tools']);
|
|
@@ -39,6 +41,9 @@ export const CLAUDE_FIELDS = Object.freeze([
|
|
|
39
41
|
]);
|
|
40
42
|
const OPENCODE_FIELDS = Object.freeze(['name', 'description', 'license', 'compatibility', 'metadata', 'disable-model-invocation']);
|
|
41
43
|
const CODEX_FIELDS = Object.freeze(['name', 'description', 'metadata']);
|
|
44
|
+
const ANTIGRAVITY_FIELDS = Object.freeze(['name', 'description', 'disable-slash-command']);
|
|
45
|
+
/** The most of a SKILL.md body Antigravity reads (UTF-8 bytes after the frontmatter). */
|
|
46
|
+
export const ANTIGRAVITY_BODY_BYTES = 24 * 1024;
|
|
42
47
|
|
|
43
48
|
export const PORTABLE_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
44
49
|
export const CODEX_SIDECAR = 'agents/openai.yaml';
|
|
@@ -121,6 +126,19 @@ export const PROFILES = Object.freeze({
|
|
|
121
126
|
],
|
|
122
127
|
reload: { file: 'new-session', newRoot: 'new-session', note: 'A running OpenCode may not see a new skill; start a new session (or restart the server) to be sure.' },
|
|
123
128
|
}),
|
|
129
|
+
'antigravity-native': Object.freeze({
|
|
130
|
+
id: 'antigravity-native', version: '2026-10-30', title: 'Antigravity', runtime: 'antigravity', status: 'current',
|
|
131
|
+
sources: [SOURCES.antigravity], verified: null,
|
|
132
|
+
fields: { recognized: ANTIGRAVITY_FIELDS, required: ['name', 'description'], strictTopLevel: false },
|
|
133
|
+
limits: { nameChars: 64, descriptionChars: 1024, bodyBytes: ANTIGRAVITY_BODY_BYTES },
|
|
134
|
+
invocation: { model: 'chosen by its description; no field keeps the model from starting it', user: '/name; `disable-slash-command: true` hides it' },
|
|
135
|
+
substitutions: null,
|
|
136
|
+
roots: [
|
|
137
|
+
{ scope: 'user', path: '~/.gemini/config/skills', note: 'where SynaBun installs' },
|
|
138
|
+
{ scope: 'project', path: '<project>/.agents/skills', note: 'the Codex project folder, which Antigravity reads too' },
|
|
139
|
+
],
|
|
140
|
+
reload: { file: 'automatic', newRoot: 'automatic', note: 'Antigravity reads its skill folders again by itself; there is no command to run.' },
|
|
141
|
+
}),
|
|
124
142
|
'codex-prompt': Object.freeze({
|
|
125
143
|
id: 'codex-prompt', version: '2026-10-21', title: 'Codex custom prompt (deprecated)', runtime: 'codex', status: 'legacy',
|
|
126
144
|
sources: [SOURCES.codexPrompts], verified: null,
|
|
@@ -144,7 +162,7 @@ export const PROFILES = Object.freeze({
|
|
|
144
162
|
});
|
|
145
163
|
|
|
146
164
|
/** The profile an install into a runtime is checked against. */
|
|
147
|
-
export const TARGET_PROFILE = Object.freeze({ claude: 'claude-code', codex: 'codex-native', opencode: 'opencode-native', agents: 'portable-six-field' });
|
|
165
|
+
export const TARGET_PROFILE = Object.freeze({ claude: 'claude-code', codex: 'codex-native', opencode: 'opencode-native', antigravity: 'antigravity-native', agents: 'portable-six-field' });
|
|
148
166
|
|
|
149
167
|
export function getProfile(id) {
|
|
150
168
|
return Object.prototype.hasOwnProperty.call(PROFILES, id) ? PROFILES[id] : null;
|
|
@@ -162,6 +180,11 @@ export function profileList() {
|
|
|
162
180
|
|
|
163
181
|
const has = (data, key) => !!data && Object.prototype.hasOwnProperty.call(data, key);
|
|
164
182
|
const isMap = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
183
|
+
const ENCODER = new TextEncoder();
|
|
184
|
+
/** A text's length in UTF-8 bytes (0 for anything else). */
|
|
185
|
+
const utf8Length = (text) => (typeof text === 'string' ? ENCODER.encode(text).length : 0);
|
|
186
|
+
/** "24 KB", "25.3 KB", "812 bytes". */
|
|
187
|
+
const kb = (bytes) => (bytes < 1024 ? `${bytes} bytes` : `${Math.round((bytes / 1024) * 10) / 10} KB`);
|
|
165
188
|
const kindOf = (value) => {
|
|
166
189
|
if (value === undefined) return 'absent';
|
|
167
190
|
if (value === null) return 'empty';
|
|
@@ -202,9 +225,11 @@ export function readInvocationIntent({ data, sidecar = null }) {
|
|
|
202
225
|
const meta = isMap(data?.metadata) ? data.metadata : null;
|
|
203
226
|
if (meta && has(meta, 'opencode/autoinvoke')) said.opencodeModel = openSwitch(meta['opencode/autoinvoke']);
|
|
204
227
|
if (meta && has(meta, 'opencode/slash')) said.opencodeSlash = openSwitch(meta['opencode/slash']);
|
|
228
|
+
// Antigravity's `disable-slash-command: true` keeps /name from the person, as Claude Code's user-invocable: false does.
|
|
229
|
+
if (has(data, 'disable-slash-command')) said.antigravityUser = claudeBoolean(data['disable-slash-command']) === true ? false : (claudeBoolean(data['disable-slash-command']) === false ? true : null);
|
|
205
230
|
const modelSays = [said.claudeModel, said.codexModel, said.opencodeModel].filter((v) => v === true || v === false);
|
|
206
231
|
const model = !modelSays.includes(false);
|
|
207
|
-
const user = said.claudeUser !== false;
|
|
232
|
+
const user = said.claudeUser !== false && said.antigravityUser !== false;
|
|
208
233
|
const conflicts = [];
|
|
209
234
|
if (modelSays.includes(false) && modelSays.includes(true)) conflicts.push('model');
|
|
210
235
|
return { user, model, slash: said.opencodeSlash ?? null, said, conflicts };
|
|
@@ -228,6 +253,10 @@ export function effectiveInvocation(profileId, { data, sidecar = null }) {
|
|
|
228
253
|
const claudeOff = claudeBoolean(data?.['disable-model-invocation']) === true;
|
|
229
254
|
return { model: !(openSwitch(meta?.['opencode/autoinvoke']) === false || claudeOff), user: true, slash: openSwitch(meta?.['opencode/slash']) === true };
|
|
230
255
|
}
|
|
256
|
+
if (runtime === 'antigravity') {
|
|
257
|
+
// Only a YAML true is taken as hiding /name (anything else is not counted on); nothing keeps its model from starting a skill.
|
|
258
|
+
return { model: true, user: data?.['disable-slash-command'] !== true };
|
|
259
|
+
}
|
|
231
260
|
return { model: true, user: true };
|
|
232
261
|
}
|
|
233
262
|
|
|
@@ -254,6 +283,7 @@ export function invocationPlan(profileId, { intent, data, sidecar = null }) {
|
|
|
254
283
|
}
|
|
255
284
|
if (!intent.user && now.user) {
|
|
256
285
|
if (runtime === 'claude') transforms.push({ file: 'SKILL.md', op: 'frontmatter', key: 'user-invocable', value: false, reason: 'Keeps /name hidden in Claude Code, as the skill\'s other settings say.' });
|
|
286
|
+
else if (runtime === 'antigravity') transforms.push({ file: 'SKILL.md', op: 'frontmatter', key: 'disable-slash-command', value: true, reason: 'Keeps /name hidden in Antigravity, as the skill\'s other settings say.' });
|
|
257
287
|
else diagnostics.push({ ruleId: 'L-08-user-invocation-broader', severity: 'warning', message: `${profile.title} has no setting that hides a skill from the person: there it can still be started by name.`, file: 'SKILL.md', line: null });
|
|
258
288
|
}
|
|
259
289
|
return { transforms, diagnostics };
|
|
@@ -306,7 +336,7 @@ export function lintForProfile(profileId, { parsed, folderName = '', headPath =
|
|
|
306
336
|
if (hidden.length || /[<>]/.test(name)) add('L-03-name-chars', 'error', `"name" holds characters ${profile.title} refuses (${hidden.length ? hidden.map((h) => h.label).join(', ') : 'an angle bracket'}).`, lineOf('name'));
|
|
307
337
|
const portableName = PORTABLE_NAME_RE.test(name);
|
|
308
338
|
if (!portableName) {
|
|
309
|
-
if (strictPortable || runtime === 'opencode') add('L-03-name-format', 'error', `"name" must be lowercase letters, digits and single hyphens for ${profile.title}.`, lineOf('name'));
|
|
339
|
+
if (strictPortable || runtime === 'opencode' || runtime === 'antigravity') add('L-03-name-format', 'error', `"name" must be lowercase letters, digits and single hyphens for ${profile.title}.`, lineOf('name'));
|
|
310
340
|
else add('L-03-name-format', 'warning', `"name" is not lowercase letters, digits and single hyphens: other runtimes may refuse it.`, lineOf('name'));
|
|
311
341
|
}
|
|
312
342
|
if (folderName && name !== folderName) {
|
|
@@ -398,6 +428,14 @@ export function lintForProfile(profileId, { parsed, folderName = '', headPath =
|
|
|
398
428
|
if (has(data, 'hooks') && !isMap(data.hooks)) add('L-04-hooks-type', 'error', `"hooks" must be a mapping of events; it is ${kindOf(data.hooks)}.`, lineOf('hooks'));
|
|
399
429
|
}
|
|
400
430
|
|
|
431
|
+
// Antigravity's own field and limit
|
|
432
|
+
if (runtime === 'antigravity') {
|
|
433
|
+
if (has(data, 'disable-slash-command') && typeof data['disable-slash-command'] !== 'boolean') add('L-04-disable-slash-command-type', 'error', `"disable-slash-command" must be true or false; it is ${kindOf(data['disable-slash-command'])}.`, lineOf('disable-slash-command'));
|
|
434
|
+
const bytes = utf8Length(parsed?.body);
|
|
435
|
+
const max = profile.limits.bodyBytes || ANTIGRAVITY_BODY_BYTES;
|
|
436
|
+
if (bytes > max) add('L-03-body-size', 'error', `The body is ${kb(bytes)}; ${profile.title} reads ${kb(max)} at most. Move detail into files the skill points to.`, parsed?.bodyLine || null);
|
|
437
|
+
}
|
|
438
|
+
|
|
401
439
|
// Keys the profile does not read
|
|
402
440
|
for (const key of Object.keys(data)) {
|
|
403
441
|
if (profile.fields.recognized.includes(key)) continue;
|
|
@@ -20,7 +20,7 @@ export const REVIEW_STATE_LABEL = Object.freeze({
|
|
|
20
20
|
withdrawn: 'Withdrawn',
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
export const RUNTIME_LABEL = Object.freeze({ claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', agents: 'Shared (~/.agents/skills)' });
|
|
23
|
+
export const RUNTIME_LABEL = Object.freeze({ claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', antigravity: 'Antigravity', agents: 'Shared (~/.agents/skills)' });
|
|
24
24
|
|
|
25
25
|
/** A target as a person reads it: the runtime, and the project or the account when it is not the default one. */
|
|
26
26
|
export function targetLabel(t) {
|
|
@@ -123,7 +123,7 @@ export function targetChoices({ sharedAgentsRoot = false } = {}, suggested = [])
|
|
|
123
123
|
choices.push({ key, runtime: target.runtime, target, label: targetLabel(target), on: true });
|
|
124
124
|
}
|
|
125
125
|
const plainAsked = new Set(asked.filter(plainTarget).map((t) => t.runtime));
|
|
126
|
-
for (const runtime of ['claude', 'codex', 'opencode', ...(sharedAgentsRoot ? ['agents'] : [])]) {
|
|
126
|
+
for (const runtime of ['claude', 'codex', 'opencode', 'antigravity', ...(sharedAgentsRoot ? ['agents'] : [])]) {
|
|
127
127
|
if (plainAsked.has(runtime)) continue;
|
|
128
128
|
const target = { runtime };
|
|
129
129
|
choices.push({ key: JSON.stringify(target), runtime, target, label: targetLabel(target), on: !asked.length && runtime === 'claude' });
|
|
@@ -165,7 +165,7 @@ export async function deleteFromLibrary(ctx, ws) {
|
|
|
165
165
|
if (!ctx.alive(gen)) return;
|
|
166
166
|
const installs = skill.installations || [];
|
|
167
167
|
if (installs.length) {
|
|
168
|
-
const where = installs.slice(0, 6).map((i) => `• ${t(`skillsStudio.runtime.${['claude', 'codex', 'opencode', 'agents'].includes(i.runtime) ? i.runtime : 'claude'}`)} · ${i.destination || ''}`);
|
|
168
|
+
const where = installs.slice(0, 6).map((i) => `• ${t(`skillsStudio.runtime.${['claude', 'codex', 'opencode', 'antigravity', 'agents'].includes(i.runtime) ? i.runtime : 'claude'}`)} · ${i.destination || ''}`);
|
|
169
169
|
const answer = await ctx.ask({
|
|
170
170
|
title: t('skillsStudio.ws.libraryDeleteInstalledTitle', { name: ws.label }),
|
|
171
171
|
lines: [tp('skillsStudio.ws.libraryDeleteInstalled', installs.length), ...where],
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
|
|
26
26
|
const PROMPT_KEY = 'skills-studio-create-prompt';
|
|
27
27
|
const SCAN_COUNTED = ['blocked', 'incomplete', 'review', 'findings'];
|
|
28
|
-
const PROVIDER_RUNTIME = new Map([['claude-code', 'claude'], ['codex', 'codex'], ['opencode', 'opencode']]);
|
|
28
|
+
const PROVIDER_RUNTIME = new Map([['claude-code', 'claude'], ['codex', 'codex'], ['opencode', 'opencode'], ['antigravity', 'antigravity']]);
|
|
29
29
|
|
|
30
30
|
// What the box keeps between drawings of the place (the form itself is kept in storage).
|
|
31
31
|
const AI = {
|
|
@@ -13,7 +13,8 @@ import { CREATION_LIMITS, DRAFT_PROVIDERS, isActiveCreation, normalizeCreationRe
|
|
|
13
13
|
export const AI_FORM_KEY = 'skills-studio-create-ai';
|
|
14
14
|
/** The places a source is added from (describe is the prompt itself). */
|
|
15
15
|
export const AI_SOURCE_KINDS = Object.freeze(['conversation', 'url', 'repo', 'memory', 'import']);
|
|
16
|
-
|
|
16
|
+
/** The runtimes a drafted skill is meant for (its install targets, ss-creation.js CREATION_TARGET_RUNTIMES), not who drafts it. */
|
|
17
|
+
export const DRAFT_RUNTIMES = Object.freeze(['claude', 'codex', 'opencode', 'antigravity']);
|
|
17
18
|
export const WORK_MINUTES = Object.freeze([20, 30, 45, 60, 90]);
|
|
18
19
|
/** The steps a creation shows, in order. */
|
|
19
20
|
export const CREATION_STEPS = Object.freeze(['sources', 'drafting', 'checking', 'review']);
|
|
@@ -97,7 +97,8 @@ export function healthIcon(code) {
|
|
|
97
97
|
case 'invalid': case 'not-text': return ICONS.err;
|
|
98
98
|
case 'warnings': return ICONS.warn;
|
|
99
99
|
case 'update': return ICONS.update;
|
|
100
|
-
case 'shadowed': case 'twice': case 'same-description': return ICONS.flag;
|
|
100
|
+
case 'shadowed': case 'twice': case 'same-description': case 'duplicate-record': return ICONS.flag;
|
|
101
|
+
case 'stale-install': return ICONS.update;
|
|
101
102
|
case 'bridge': return ICONS.bridge;
|
|
102
103
|
case 'readonly': return ICONS.lock;
|
|
103
104
|
case 'draft': return ICONS.draft;
|