synabun 2.0.10 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +207 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +13 -13
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +30 -17
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +7 -6
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +302 -0
- package/lib/virustotal.mjs +203 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +18 -11
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +22 -63
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +14 -14
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +29 -19
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +642 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +81 -21
- package/mcp-server/src/services/server-instructions.ts +29 -64
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +29 -20
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +592 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3953 -228
- package/neural-interface/i18n/pt-BR.json +3901 -179
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +128 -28
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +81 -15
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +1073 -200
- package/neural-interface/lib/assistant-envelope.js +156 -2
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +93 -19
- package/neural-interface/lib/assistant-plan-permissions.js +25 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +245 -38
- package/neural-interface/lib/assistant-runtime.js +214 -30
- package/neural-interface/lib/assistant-task-prompt.js +87 -21
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +626 -4
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +84 -0
- package/neural-interface/lib/browser-network-guard.js +476 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +198 -38
- package/neural-interface/lib/claude-agent-bridge.js +11 -2
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +163 -154
- package/neural-interface/lib/cli-resolver.js +13 -3
- package/neural-interface/lib/cli-update-planner.js +52 -41
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +191 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +13 -10
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +35 -33
- package/neural-interface/lib/mcp-external-servers.js +332 -0
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +177 -25
- package/neural-interface/lib/native-loop-providers.js +965 -66
- package/neural-interface/lib/native-loop-runtime.js +290 -42
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +53 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +793 -0
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +20 -2
- package/neural-interface/lib/rulesets/api.js +7 -6
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +180 -36
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +81 -31
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +298 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +285 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +569 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +216 -0
- package/neural-interface/lib/skills/eval-confinement.js +399 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +135 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +203 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +269 -0
- package/neural-interface/lib/skills/runtime-checks.js +358 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +530 -0
- package/neural-interface/lib/skills/telemetry.js +119 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +1268 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +238 -0
- package/neural-interface/lib/worker-sandbox.js +329 -0
- package/neural-interface/package-lock.json +34 -12
- package/neural-interface/package.json +3 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +3 -3
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +125 -31
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
- package/neural-interface/public/shared/assistant/asst-api.js +1 -1
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-control.js +205 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +445 -82
- package/neural-interface/public/shared/assistant/asst-route.js +304 -53
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
- package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
- package/neural-interface/public/shared/assistant/asst-state.js +87 -24
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
- package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
- package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +11 -12
- package/neural-interface/public/shared/cli-status.js +11 -10
- package/neural-interface/public/shared/constants.js +5 -4
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +367 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +21 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +30 -15
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +222 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +149 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1822 -1756
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +111 -140
- package/neural-interface/public/shared/ui-claude-panel.js +376 -82
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +33 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-menubar.js +10 -20
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
- package/neural-interface/public/shared/ui-navbar.js +49 -24
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +27 -15
- package/neural-interface/public/shared/ui-settings.js +683 -526
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +270 -190
- package/neural-interface/public/shared/ui-tool-updates.js +6 -4
- package/neural-interface/public/shared/ui-tooltip.js +81 -51
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +312 -59
- package/neural-interface/public/shared/ui-worker-end.js +5 -1
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +2 -2
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +4553 -2855
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +34 -12
- package/package.json +17 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +6 -6
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// `footer`: items under the list that stay in view while the list scrolls.
|
|
18
18
|
// Every menu is measured at the width it is shown at, never wider than its box less the margins,
|
|
19
19
|
// and opens where that box has room (the list scrolls inside it). The box is the Assistant
|
|
20
|
-
// panel or root around the anchor, else the window.
|
|
20
|
+
// panel or root around the anchor, else the app frame (app-frame.js; the window on a page without it).
|
|
21
21
|
// `bounds`: an element (or () => DOMRect) to use as that box instead: the menu is then exactly
|
|
22
22
|
// `width` wide (or the box's room) and follows the box on resize.
|
|
23
23
|
// `onEscape`: returns true when it handled Esc (e.g. went back a view): the menu stays open.
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
// any group left empty. The handle's update({ title, items, footer, focus }) redraws
|
|
45
45
|
// an open menu in place (focus: the data-id to land on; the filter's text still applies).
|
|
46
46
|
|
|
47
|
+
import { frameRect } from '../app-frame.js';
|
|
48
|
+
|
|
47
49
|
let _open = null;
|
|
48
50
|
let _uid = 0;
|
|
49
51
|
let _lastDown = null;
|
|
@@ -290,14 +292,13 @@ const BOUNDED_MIN_WIDTH = 248;
|
|
|
290
292
|
const MENU_MIN_HEIGHT = 96;
|
|
291
293
|
const BOUNDED_MIN_HEIGHT = 140;
|
|
292
294
|
|
|
293
|
-
/** The box a menu stays inside: its bounds clipped to the
|
|
295
|
+
/** The box a menu stays inside: its bounds clipped to the app frame (the frame when it has none). */
|
|
294
296
|
function boundsBox(bounds) {
|
|
295
|
-
const
|
|
296
|
-
const vh = window.innerHeight;
|
|
297
|
+
const f = frameRect();
|
|
297
298
|
let r = null;
|
|
298
299
|
try { r = typeof bounds === 'function' ? bounds() : bounds?.getBoundingClientRect?.(); } catch { r = null; }
|
|
299
|
-
if (!r || !(r.width > 0) || !(r.height > 0)) return { left:
|
|
300
|
-
return { left: Math.max(
|
|
300
|
+
if (!r || !(r.width > 0) || !(r.height > 0)) return { left: f.left, top: f.top, right: f.right, bottom: f.bottom };
|
|
301
|
+
return { left: Math.max(f.left, r.left), top: Math.max(f.top, r.top), right: Math.min(f.right, r.right), bottom: Math.min(f.bottom, r.bottom) };
|
|
301
302
|
}
|
|
302
303
|
|
|
303
304
|
/** Where a menu without `bounds` stays: the Assistant around its anchor (the sidepanel, or a tab's own root). */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fetchToolCatalog } from '../agent-runtime-options.js';
|
|
1
2
|
// ═══════════════════════════════════════════
|
|
2
3
|
// SynaBun Assistant — panel (mount / lifecycle)
|
|
3
4
|
// ═══════════════════════════════════════════
|
|
@@ -34,12 +35,12 @@ import { t } from '../i18n.js';
|
|
|
34
35
|
import '../account-i18n.js';
|
|
35
36
|
import { forgetGreeting, mountGreeting } from '../greeting/greeting-card.js';
|
|
36
37
|
import { notify, NOTIF_TYPE } from '../ui-notifications.js';
|
|
37
|
-
import { getProviderMeta } from '../provider-icons.js';
|
|
38
38
|
import { isGuest, hasPermission } from '../ui-sync.js';
|
|
39
39
|
import { getWhiteboardElementById } from '../ui-whiteboard.js';
|
|
40
40
|
import { focusNativeLoopRun } from '../ui-native-loop-router.js';
|
|
41
41
|
import { wireFileLinks } from '../ui-file-links.js';
|
|
42
42
|
import { injectAssistantStyles } from './asst-styles.js';
|
|
43
|
+
import { tipsSeen, tourOffered } from '../tour/tour-state.js';
|
|
43
44
|
import { createAssistantSocket } from './asst-ws.js';
|
|
44
45
|
import { createRenderer, ICON_ASSISTANT, mdInto } from './asst-render.js';
|
|
45
46
|
import { createMascotDirector, MASCOT_TIMING, turnEndPose } from './asst-mascot.js';
|
|
@@ -47,7 +48,9 @@ import { lastInputAt, onKey, onPointer } from '../synabun-ticker.js';
|
|
|
47
48
|
import { buildControlResponse, closedControlState, normalizeControlRequest, renderControlCard } from './asst-control.js';
|
|
48
49
|
import { buildPromptText, createComposer } from './asst-composer.js';
|
|
49
50
|
import { buildDispatchSpec, parseSlashCommand, slashHelpMarkdown } from './asst-slash.js';
|
|
50
|
-
import {
|
|
51
|
+
import { resolveStopTarget } from './asst-stop.js';
|
|
52
|
+
import { plural } from './asst-tool-kinds.js';
|
|
53
|
+
import { cachedProjects, createBrainPicker, openModelMenu, testDensityLabel } from './asst-brain-picker.js';
|
|
51
54
|
import { createRovingToolbar } from './asst-roving.js';
|
|
52
55
|
import { openAccountsManager } from './asst-accounts.js';
|
|
53
56
|
import { createAgentsDock } from './asst-agents-dock.js';
|
|
@@ -58,8 +61,8 @@ import { createRouteModeControl, openModelsManager, openRoutesEditor, refreshMod
|
|
|
58
61
|
import { budgetChipText, budgetSpendText, budgetTone, closeBudgetEditor, createBudgetController, mountBudgetChip, openBudgetEditor } from './asst-budget.js';
|
|
59
62
|
import { computerRemoteView, createComputerPanel, createComputerToggle, normalizeComputerRemote, openFrameLightbox, closeFrameLightbox, requestDesktopStop } from './asst-computer.js';
|
|
60
63
|
import {
|
|
61
|
-
applyLimit, applyLimitPacket, applyUsagePacket, brainLabel, createRenameWriter, createTabState, DEFAULT_ROUTE_MODE, deserializeTabState, fmtCost, fmtRunLine, limitExpiresIn, limitNoticeText, modelShortName,
|
|
62
|
-
brainModePatch, normalizeBrain, normalizeComputerMode, permissionModeLabel, normalizeRouteMode, normalizeTestDensity, projectLabel, providerShortLabel, readStoredBrain, runFromPayload,
|
|
64
|
+
applyLimit, applyLimitPacket, applyUsagePacket, BRAIN_PROVIDERS, brainLabel, createRenameWriter, createTabState, DEFAULT_ROUTE_MODE, deserializeTabState, fmtCost, fmtRunLine, limitExpiresIn, limitNoticeText, modelShortName,
|
|
65
|
+
brainModePatch, isBrainProvider, normalizeBrain, normalizeComputerMode, permissionModeLabel, normalizeRouteMode, normalizeTestDensity, projectLabel, providerMeta, providerShortLabel, readStoredBrain, runFromPayload,
|
|
63
66
|
serializeTabState, sessionStatus, tabStorageKey, userSessionTitle,
|
|
64
67
|
} from './asst-state.js';
|
|
65
68
|
import {
|
|
@@ -240,9 +243,27 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
240
243
|
if (host.toolbarSlot) host.toolbarSlot.appendChild(barEl);
|
|
241
244
|
|
|
242
245
|
// ── Helpers ──
|
|
243
|
-
|
|
244
|
-
const
|
|
246
|
+
// A worker-only provider provider-icons.js does not know yet keeps its own name (asst-state.js providerMeta).
|
|
247
|
+
const providerIcon = (p) => providerMeta(p).icon;
|
|
248
|
+
const providerColor = (p) => providerMeta(p).color;
|
|
245
249
|
const visible = () => { try { return host.isVisible ? !!host.isVisible() : true; } catch { return true; } };
|
|
250
|
+
|
|
251
|
+
// ── Just-in-time tips (../tour/tour-tips.js): once each, ever; never in a replay or while the tour runs ──
|
|
252
|
+
function tip(id, targetOf) {
|
|
253
|
+
if (destroyed || replaying || !visible() || guestBlocked() || tipsSeen(storage).has(id)) return;
|
|
254
|
+
requestAnimationFrame(() => {
|
|
255
|
+
if (destroyed) return;
|
|
256
|
+
let target = null;
|
|
257
|
+
try { target = targetOf(); } catch { target = null; }
|
|
258
|
+
if (!target?.isConnected) return;
|
|
259
|
+
import('../tour/tour-tips.js')
|
|
260
|
+
.then(async ({ ensureTourStyles, showTip }) => {
|
|
261
|
+
await ensureTourStyles();
|
|
262
|
+
if (!destroyed && target.isConnected) showTip(id, { storage, tr: (key) => t(key), root, target, renderer, reduced: () => matchMedia('(prefers-reduced-motion: reduce)').matches });
|
|
263
|
+
})
|
|
264
|
+
.catch(() => { /* a tip is never worth an error */ });
|
|
265
|
+
});
|
|
266
|
+
}
|
|
246
267
|
const hostId = host.id || null; // routing only (assistant:new / resume / focused) — never a feature switch
|
|
247
268
|
|
|
248
269
|
function persist() {
|
|
@@ -506,7 +527,19 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
506
527
|
emptyBudgetChip?.destroy();
|
|
507
528
|
emptyBudgetChip = null;
|
|
508
529
|
},
|
|
509
|
-
|
|
530
|
+
// The first-visit row asks for the Workspace tour on this panel (ui-tutorial.js); the others fill the composer.
|
|
531
|
+
onSuggestion: (template, s) => {
|
|
532
|
+
if (s?.action === 'tour') { emit('tour:open', { host: controller.tourHost(), from: 'starter' }); return; }
|
|
533
|
+
composer.fillTemplate(template);
|
|
534
|
+
},
|
|
535
|
+
// A follow-up under a finished message, or Retry now on a usage-limit card: sent as the user's next
|
|
536
|
+
// message (queued while a turn runs, like a typed one). "Something else…" is the composer.
|
|
537
|
+
onFollowup: (text) => { submit(clickPayload(text)); },
|
|
538
|
+
onFollowupOther: () => composer.focus(),
|
|
539
|
+
onLimitRetry: (text) => { submit(clickPayload(text)); },
|
|
540
|
+
onSwitchProvider: (anchor, meta) => continueOnAnotherProvider(anchor, meta),
|
|
541
|
+
limitInfo: () => st.limit,
|
|
542
|
+
brainProvider: () => st.brain.provider,
|
|
510
543
|
heroOrigin: () => { try { return host.takeHeroOrigin?.() || null; } catch { return null; } },
|
|
511
544
|
onMascotChange: () => director?.retarget(),
|
|
512
545
|
onInit: (ev) => {
|
|
@@ -536,12 +569,20 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
536
569
|
},
|
|
537
570
|
});
|
|
538
571
|
|
|
572
|
+
/** What a click sends: the text alone, shaped like a typed message with nothing attached. */
|
|
573
|
+
function clickPayload(text) {
|
|
574
|
+
return { text: String(text ?? ''), images: [], files: [], uploads: [], memories: [] };
|
|
575
|
+
}
|
|
576
|
+
|
|
539
577
|
function emptySuggestions() {
|
|
540
578
|
const project = projectLabel(st.brain.project, cachedProjects()) || tt('assistant.empty.thisProject', 'this project');
|
|
541
579
|
const list = [];
|
|
580
|
+
// Until the Workspace tour is completed or skipped, its starter comes first. It never opens by itself.
|
|
581
|
+
if (tourOffered(storage) && !guestBlocked()) list.push({ id: 'tour', action: 'tour', kind: 'ask', label: tt('tour.starter', 'Show me the workspace'), meta: tt('tour.starterTime', '2 min') });
|
|
542
582
|
if (computerAvailable()) list.push({ id: 'computer', label: tt('assistant.empty.suggestComputer', 'Use my Mac to…'), template: tt('assistant.empty.templateComputer', 'Use my Mac to {caret}') });
|
|
543
583
|
list.push({ id: 'web', label: tt('assistant.empty.suggestWeb', 'Look up … on the web'), template: tt('assistant.empty.templateWeb', 'Look up {caret} on the web') });
|
|
544
584
|
list.push({ id: 'fix', label: tt('assistant.empty.suggestFix', 'Fix … in {project}', { project }), template: tt('assistant.empty.templateFix', 'Fix {caret} in {project}', { project }) });
|
|
585
|
+
list.push({ id: 'skill', label: tt('assistant.empty.suggestSkill', 'Create Skill'), template: tt('assistant.empty.templateSkill', 'Create a skill that {caret}') });
|
|
545
586
|
list.push({ id: 'schedule', label: tt('assistant.empty.suggestSchedule', 'Schedule …'), template: tt('assistant.empty.templateSchedule', 'Schedule {caret}') });
|
|
546
587
|
list.push({ id: 'remember', label: tt('assistant.empty.suggestRemember', 'Remember …'), template: tt('assistant.empty.templateRemember', 'Remember {caret}') });
|
|
547
588
|
return list;
|
|
@@ -553,7 +594,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
553
594
|
describeSlash: (cmd) => tt(cmd.descKey, cmd.desc),
|
|
554
595
|
resolveMemory: (id) => appState.allNodes?.find(n => n.id === id) || null,
|
|
555
596
|
resolveWhiteboardImage: (id) => { const wb = getWhiteboardElementById(id); return wb?.type === 'image' && wb.dataUrl ? { dataUrl: wb.dataUrl } : null; },
|
|
556
|
-
onDraftChange: (text) => { st.draft = text; persist(); director?.type(!!String(text || '').trim()); },
|
|
597
|
+
onDraftChange: (text) => { st.draft = text; persist(); director?.type(!!String(text || '').trim()); renderer.setDrafting?.(!!String(text || '').trim()); },
|
|
557
598
|
onFocusChange: (focused) => { if (focused) director?.touch(); else director?.stopTyping(); },
|
|
558
599
|
onAbort: () => abort(),
|
|
559
600
|
onToast: toast,
|
|
@@ -591,6 +632,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
591
632
|
const accountHooks = () => ({ t, onChanged: () => picker.refresh(true), onSelect: (id) => applyBrain({ ...st.brain, accountId: id }, { requiresSwitch: true, field: 'account' }) });
|
|
592
633
|
// Model · effort · permission mode · account sit in the composer row next to attach; project and MCP in the toolbar.
|
|
593
634
|
const picker = createBrainPicker({ brain: composer.el.querySelector('.asst-composer-brain'), context: barGroups.context }, {
|
|
635
|
+
getSessionId: () => st.sessionId,
|
|
594
636
|
t,
|
|
595
637
|
mascot: () => director,
|
|
596
638
|
getBrain: () => st.brain,
|
|
@@ -677,6 +719,17 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
677
719
|
agentsBtn.setAttribute('aria-pressed', st.dockOpen ? 'true' : 'false');
|
|
678
720
|
|
|
679
721
|
const usage = createUsageGauge(root.querySelector('.asst-usage-host'), { t, sessionId });
|
|
722
|
+
// The first usage strip on screen gets its tip (once, ever).
|
|
723
|
+
const usageHostEl = root.querySelector('.asst-usage-host');
|
|
724
|
+
if (typeof MutationObserver === 'function' && !tipsSeen(storage).has('usage')) {
|
|
725
|
+
const usageTipWatch = new MutationObserver(() => {
|
|
726
|
+
if (usageHostEl.hidden) return;
|
|
727
|
+
usageTipWatch.disconnect();
|
|
728
|
+
tip('usage', () => usageHostEl.querySelector('.asst-usage-strip') || usageHostEl);
|
|
729
|
+
});
|
|
730
|
+
usageTipWatch.observe(usageHostEl, { attributes: true, attributeFilter: ['hidden'] });
|
|
731
|
+
unsubs.push(() => usageTipWatch.disconnect());
|
|
732
|
+
}
|
|
680
733
|
if (st.usageView) { usage.apply({ type: 'assistant:usage', ...st.usageView }); usage.setConnection('reconnecting'); }
|
|
681
734
|
let usageFetchSeq = 0;
|
|
682
735
|
let usageSocketOpened = false;
|
|
@@ -721,6 +774,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
721
774
|
clearTimeout(limitTimer);
|
|
722
775
|
limitTimer = null;
|
|
723
776
|
const limit = st.limit;
|
|
777
|
+
renderer.noteLimit(limit); // the waiting card of this turn's limit error counts to the reported reset
|
|
724
778
|
limitEl.hidden = !limit;
|
|
725
779
|
limitEl.dataset.status = limit?.status || '';
|
|
726
780
|
const text = limitNoticeText(limit, tt);
|
|
@@ -870,7 +924,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
870
924
|
return;
|
|
871
925
|
case 'assistant:dispatch': {
|
|
872
926
|
const run = runFromPayload(packet);
|
|
873
|
-
if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); }
|
|
927
|
+
if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); tip('run', () => renderer.getRunCard(run.runId)); }
|
|
874
928
|
return;
|
|
875
929
|
}
|
|
876
930
|
case 'assistant:permission-request':
|
|
@@ -914,7 +968,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
914
968
|
switch (ev.type) {
|
|
915
969
|
case 'synabun.dispatch': {
|
|
916
970
|
const run = runFromPayload(ev);
|
|
917
|
-
if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); }
|
|
971
|
+
if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); tip('run', () => renderer.getRunCard(run.runId)); }
|
|
918
972
|
return;
|
|
919
973
|
}
|
|
920
974
|
case 'synabun.dispatch_result': {
|
|
@@ -972,7 +1026,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
972
1026
|
const next = normalizeBrain({ ...st.brain, ...meta.brain, provider: meta.brain.provider || meta.brain.brain || st.brain.provider });
|
|
973
1027
|
if (JSON.stringify(next) !== JSON.stringify(st.brain)) { st.brain = next; picker.render(); host.setBrain?.(next); persist(); }
|
|
974
1028
|
} else if (typeof meta.brain === 'string') {
|
|
975
|
-
const next = normalizeBrain({ ...st.brain, provider: meta.brain, model: meta.model ?? st.brain.model, effort: meta.effort ?? st.brain.effort, accountId: meta.accountId ?? st.brain.accountId,
|
|
1029
|
+
const next = normalizeBrain({ ...st.brain, provider: meta.brain, model: meta.model ?? st.brain.model, effort: meta.effort ?? st.brain.effort, accountId: meta.accountId ?? st.brain.accountId, tools: meta.tools ?? st.brain.tools, project: meta.cwd ?? st.brain.project });
|
|
976
1030
|
if (JSON.stringify(next) !== JSON.stringify(st.brain)) { st.brain = next; picker.render(); host.setBrain?.(next); persist(); }
|
|
977
1031
|
}
|
|
978
1032
|
if (meta.budget && typeof meta.budget === 'object') budgetController.receiveSession(meta.budget);
|
|
@@ -1156,6 +1210,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1156
1210
|
if (st.computerRemote) { explainRemoteComputer(); return; }
|
|
1157
1211
|
const next = enabled === true;
|
|
1158
1212
|
const wasActive = st.desktopActive;
|
|
1213
|
+
if (next && !st.computerEffective) tip('computer', () => (isRendered(computerToggle.el) ? computerToggle.el : moreBtn));
|
|
1159
1214
|
st.computerUse = next;
|
|
1160
1215
|
st.computerEffective = next;
|
|
1161
1216
|
persist();
|
|
@@ -1181,7 +1236,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1181
1236
|
elapsedMs: st.turnStartedAt ? Date.now() - st.turnStartedAt : 0,
|
|
1182
1237
|
}) : null;
|
|
1183
1238
|
const answer = wasRunning && !aborted ? renderer.turnAnswer() : '';
|
|
1184
|
-
renderer.finishTurn({ holdMs: pose ? MASCOT_TIMING.oneShotMs[pose] : 0 });
|
|
1239
|
+
renderer.finishTurn({ holdMs: pose ? MASCOT_TIMING.oneShotMs[pose] : 0, guess: !aborted && !errored });
|
|
1185
1240
|
if (wasRunning) director.turnEnded(pose);
|
|
1186
1241
|
if (answer && !silent) announce(tt('assistant.announce.replied', 'SynaBun replied: {text}', { text: answer }));
|
|
1187
1242
|
st.running = false;
|
|
@@ -1221,6 +1276,8 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1221
1276
|
providerIcon,
|
|
1222
1277
|
scrollEnd: () => renderer.scrollEnd(),
|
|
1223
1278
|
onRespond: (n, decision) => respondControl(n, decision),
|
|
1279
|
+
// A question card's Esc, and its answer when focus was in it: back to the message box.
|
|
1280
|
+
focusComposer: () => composer.focus(),
|
|
1224
1281
|
renderRoute: (_container, n) => mountRouteCard(n),
|
|
1225
1282
|
});
|
|
1226
1283
|
if (!entry) return;
|
|
@@ -1262,6 +1319,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1262
1319
|
renderer.appendNode(card.el);
|
|
1263
1320
|
routeCards.set(card.routeId, card);
|
|
1264
1321
|
routeChip.render();
|
|
1322
|
+
tip('route', () => card.el);
|
|
1265
1323
|
requestAnimationFrame(() => { if (!destroyed && !card.collapsed) card.focusIfIdle(); });
|
|
1266
1324
|
return card;
|
|
1267
1325
|
}
|
|
@@ -1423,6 +1481,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1423
1481
|
compact();
|
|
1424
1482
|
return true;
|
|
1425
1483
|
case 'new':
|
|
1484
|
+
if (parsed.error === 'not_brain') { toast(notBrainText(parsed.provider)); return false; }
|
|
1426
1485
|
newSession(parsed.provider || null);
|
|
1427
1486
|
return true;
|
|
1428
1487
|
case 'resume':
|
|
@@ -1430,8 +1489,9 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1430
1489
|
else renames.settled().then(() => { if (!destroyed) sock.send({ type: 'list_sessions' }); }); // a rename on its way is in the list
|
|
1431
1490
|
return true;
|
|
1432
1491
|
case 'stop':
|
|
1492
|
+
// /stop all: every run of the session, at once. /stop <target>: the one run it names, or nothing.
|
|
1433
1493
|
if (parsed.all) await stopAll();
|
|
1434
|
-
else if (parsed.target) await
|
|
1494
|
+
else if (parsed.target) await stopNamedRun(parsed.target);
|
|
1435
1495
|
else abort();
|
|
1436
1496
|
return true;
|
|
1437
1497
|
case 'agents': {
|
|
@@ -1449,6 +1509,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1449
1509
|
if (parsed.error) { toast(tt('assistant.slash.needsText', 'Usage: /remember <text>')); return false; }
|
|
1450
1510
|
return queueOrSend({ ...payload, display: payload.text, text: tt('assistant.prompts.remember', 'Store this in SynaBun memory with the remember tool (pick a fitting category, project, tags and importance): {text}', { text: parsed.text }) });
|
|
1451
1511
|
case 'model': {
|
|
1512
|
+
if (parsed.error === 'not_brain') { toast(notBrainText(parsed.provider)); return false; }
|
|
1452
1513
|
if (!parsed.model && !parsed.provider) { picker.openField('model'); return true; }
|
|
1453
1514
|
const next = { ...st.brain };
|
|
1454
1515
|
let requiresSwitch = false;
|
|
@@ -1497,10 +1558,15 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1497
1558
|
}
|
|
1498
1559
|
}
|
|
1499
1560
|
|
|
1561
|
+
/** /model or /new naming a provider that runs dispatched work only (none today: all four can be the brain). */
|
|
1562
|
+
function notBrainText(provider) {
|
|
1563
|
+
return tt('assistant.slash.notBrain', '{provider} runs dispatched work only, never the Assistant itself. Send it a task with /dispatch {id} <task>.', { provider: providerShortLabel(provider), id: provider });
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1500
1566
|
function dispatchErrorText(parsed) {
|
|
1501
1567
|
switch (parsed.error) {
|
|
1502
|
-
case 'missing_provider': return tt('assistant.slash.dispatchProvider', 'Usage: /dispatch <claude|codex|opencode> [flags] <task>');
|
|
1503
|
-
case 'invalid_provider': return tt('assistant.slash.dispatchInvalidProvider', 'Unknown provider "{provider}". Use claude, codex or
|
|
1568
|
+
case 'missing_provider': return tt('assistant.slash.dispatchProvider', 'Usage: /dispatch <claude|codex|opencode|antigravity> [flags] <task>');
|
|
1569
|
+
case 'invalid_provider': return tt('assistant.slash.dispatchInvalidProvider', 'Unknown provider "{provider}". Use claude, codex, opencode or antigravity.', { provider: parsed.provider });
|
|
1504
1570
|
case 'unknown_flag': return tt('assistant.slash.dispatchUnknownFlag', 'Unknown flag --{flag}', { flag: parsed.flag });
|
|
1505
1571
|
case 'missing_flag_value': return tt('assistant.slash.dispatchFlagValue', 'Flag --{flag} needs a value', { flag: parsed.flag });
|
|
1506
1572
|
case 'missing_task': return tt('assistant.slash.dispatchTask', 'Add the task text after the flags');
|
|
@@ -1514,7 +1580,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1514
1580
|
}
|
|
1515
1581
|
|
|
1516
1582
|
async function dispatch(parsed, payload) {
|
|
1517
|
-
const spec = buildDispatchSpec(parsed, st.brain, { assistantSessionId: sessionId });
|
|
1583
|
+
const spec = buildDispatchSpec(parsed, st.brain, { assistantSessionId: sessionId, toolCatalog: await fetchToolCatalog() });
|
|
1518
1584
|
renderer.appendUser(payload.text);
|
|
1519
1585
|
try {
|
|
1520
1586
|
const res = await dispatchAssistantRun(spec);
|
|
@@ -1549,6 +1615,8 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1549
1615
|
}
|
|
1550
1616
|
|
|
1551
1617
|
function newSession(provider) {
|
|
1618
|
+
// Only a brain provider names a new session's brain (Claude Code, Codex, OpenCode or Antigravity).
|
|
1619
|
+
if (provider && !isBrainProvider(provider)) provider = null;
|
|
1552
1620
|
const b = provider ? normalizeBrain({ ...st.brain, provider, model: '', effort: null, agent: null, accountId: null }) : st.brain;
|
|
1553
1621
|
// This one is still empty: it is the new session (the server keeps one draft, not a pile of them).
|
|
1554
1622
|
// /new <provider> switches its brain as the picker does; what only this page showed (/help) is cleared.
|
|
@@ -1585,7 +1653,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1585
1653
|
if (meta.silent) return;
|
|
1586
1654
|
if (meta.requiresSwitch) {
|
|
1587
1655
|
const b = st.brain;
|
|
1588
|
-
if (!meta.restartBrain) sock.send({ type: 'switch_brain', brain: b.provider, model: b.model || undefined, effort: b.effort || undefined, accountId: b.accountId || undefined,
|
|
1656
|
+
if (!meta.restartBrain) sock.send({ type: 'switch_brain', brain: b.provider, model: b.model || undefined, effort: b.effort || undefined, accountId: b.accountId || undefined, tools: b.tools ?? undefined, cwd: b.project || undefined, agent: b.agent || undefined, permissionMode: b.permissionMode, planMode: b.planMode === true });
|
|
1589
1657
|
renderer.appendDivider(`${tt('assistant.status.brain', 'brain')} → ${brainLabel(b)}`);
|
|
1590
1658
|
renderer.forgetSeen(); // the new brain's ids start over
|
|
1591
1659
|
} else if (before.permissionMode !== st.brain.permissionMode || !!before.planMode !== !!st.brain.planMode) {
|
|
@@ -1605,6 +1673,33 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1605
1673
|
});
|
|
1606
1674
|
}
|
|
1607
1675
|
|
|
1676
|
+
// "Continue with another provider" on the Assistant's own limit-wait card: the same model menu
|
|
1677
|
+
// the toolbar's model field opens (never a native select), minus the limited provider, then the
|
|
1678
|
+
// existing switch (applyBrain → switch_brain) and, where the blocked prompt is known, Retry now's
|
|
1679
|
+
// own resend (submit) — in that order, so the server sees the switch before the retried prompt.
|
|
1680
|
+
function continueOnAnotherProvider(anchor, { excludeProvider = '', retryText = '' } = {}) {
|
|
1681
|
+
if (!anchor) return;
|
|
1682
|
+
const providers = BRAIN_PROVIDERS.filter((p) => p !== excludeProvider);
|
|
1683
|
+
if (!providers.length) return;
|
|
1684
|
+
openModelMenu(anchor, {
|
|
1685
|
+
brain: st.brain,
|
|
1686
|
+
t,
|
|
1687
|
+
providers,
|
|
1688
|
+
title: tt('assistant.limitWait.switchProvider', 'Continue with another provider'),
|
|
1689
|
+
warnSwitch: true,
|
|
1690
|
+
allowCustom: false, // a custom id here would resolve to the (still limited) current provider
|
|
1691
|
+
onToast: toast,
|
|
1692
|
+
onManageModels: () => openModels(),
|
|
1693
|
+
onSelect: async (target) => {
|
|
1694
|
+
if (!target?.provider) return;
|
|
1695
|
+
await picker.switchProvider(target.provider, target.model || '');
|
|
1696
|
+
if (destroyed) return;
|
|
1697
|
+
renderer.clearLimitWait();
|
|
1698
|
+
if (retryText) submit(clickPayload(retryText));
|
|
1699
|
+
},
|
|
1700
|
+
}).catch(() => {});
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1608
1703
|
// ── Runs ──
|
|
1609
1704
|
async function focusRun(runId) {
|
|
1610
1705
|
if (!runId) return;
|
|
@@ -1638,9 +1733,29 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1638
1733
|
}
|
|
1639
1734
|
}
|
|
1640
1735
|
|
|
1736
|
+
/**
|
|
1737
|
+
* /stop <target>: the run of this session it names (its id or the start of it, its title, the words
|
|
1738
|
+
* of its title: asst-stop.js), and only that one. A target that fits none, or more than one, stops nothing.
|
|
1739
|
+
*/
|
|
1740
|
+
async function stopNamedRun(target) {
|
|
1741
|
+
const found = resolveStopTarget(target, dock.getRuns());
|
|
1742
|
+
if (found.run && !found.error) return stopRun(found.run.runId);
|
|
1743
|
+
if (found.passthrough) return stopRun(found.passthrough); // a full id the tray has not loaded: the server knows
|
|
1744
|
+
const name = (run) => `${run.title || run.runId}${run.title ? ` (${String(run.runId).slice(0, 8)})` : ''}`;
|
|
1745
|
+
const message = found.error === 'ambiguous'
|
|
1746
|
+
? tt('assistant.slash.stopAmbiguous', '"{target}" matches {count} agents: {list}. Nothing was stopped; name one of them.', { target, count: found.matches.length, list: found.matches.map(name).join(', ') })
|
|
1747
|
+
: found.error === 'finished'
|
|
1748
|
+
? tt('assistant.slash.stopFinished', '{name} has already finished.', { name: name(found.run) })
|
|
1749
|
+
: tt('assistant.slash.stopNoMatch', 'No agent of this session matches "{target}". Nothing was stopped; /agents lists them.', { target });
|
|
1750
|
+
renderer.appendStatus(message);
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1641
1753
|
async function stopAll() {
|
|
1642
|
-
try {
|
|
1643
|
-
|
|
1754
|
+
try {
|
|
1755
|
+
const res = await killAllAssistantRuns(sessionId);
|
|
1756
|
+
const count = Array.isArray(res?.stopped) ? res.stopped.length : null;
|
|
1757
|
+
toast(count === null ? tt('assistant.status.stopAllRequested', 'Stopping all dispatched agents…') : plural(tt, 'assistant.status.stopAllDone', count, 'Stopped {count} agent.', 'Stopped {count} agents.'));
|
|
1758
|
+
} catch (err) { renderer.appendError(`${tt('assistant.status.stopFailed', 'Stop failed')}: ${err?.message || err}`); }
|
|
1644
1759
|
}
|
|
1645
1760
|
|
|
1646
1761
|
async function escalateRun(runId, target) {
|
|
@@ -1852,6 +1967,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
1852
1967
|
items.push({ kind: 'info', label: tt('assistant.topbar.cost', 'Session cost'), value: fmtCost(totalCost()) || '$0.00' });
|
|
1853
1968
|
if (Number(st.dispatchUsd) > 0) items.push({ kind: 'info', label: tt('assistant.topbar.agentsCost', 'Agents'), value: fmtCost(st.dispatchUsd) });
|
|
1854
1969
|
openMenu(moreBtn, { label: tt('assistant.toolbar.more', 'More options'), items, role: 'menu', placement: 'below', width: 280 });
|
|
1970
|
+
tip('more', () => document.querySelector('.asst-dd-menu'));
|
|
1855
1971
|
}
|
|
1856
1972
|
|
|
1857
1973
|
// Assistant → Models: switch models off (hidden from routing, dispatch and every model menu).
|
|
@@ -2145,6 +2261,22 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
|
|
|
2145
2261
|
resume,
|
|
2146
2262
|
setRouteMode: (mode) => setRouteMode(mode),
|
|
2147
2263
|
setComputerUse: (enabled) => setComputerUse(enabled),
|
|
2264
|
+
/**
|
|
2265
|
+
* What the Workspace tour presents on (public/shared/tour/): this panel's own board,
|
|
2266
|
+
* its controls and its director, while the empty state shows its character and nothing
|
|
2267
|
+
* runs. null otherwise (the tour then uses a session-free preview).
|
|
2268
|
+
*/
|
|
2269
|
+
tourHost() {
|
|
2270
|
+
const hero = renderer.mascot();
|
|
2271
|
+
if (destroyed || st.running || hero?.kind !== 'hero' || hero.parked?.()) return null;
|
|
2272
|
+
return {
|
|
2273
|
+
root, transcript: transcriptEl, announcer, bar: barEl, renderer, director, composer,
|
|
2274
|
+
live: true,
|
|
2275
|
+
computer: computerAvailable(),
|
|
2276
|
+
refreshStarters: () => renderer.refreshEmpty(),
|
|
2277
|
+
focusComposer: () => composer.focus(),
|
|
2278
|
+
};
|
|
2279
|
+
},
|
|
2148
2280
|
attachMemory: (node) => composer.addMemory(node),
|
|
2149
2281
|
attachImageDataUrl: (dataUrl, name) => composer.addImageDataUrl(dataUrl, name),
|
|
2150
2282
|
insertText: (text) => composer.insertText(text),
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
// mascot stands over its task class's scene (asst-scenes.js; the motion is
|
|
9
9
|
// asst-scene-styles.js): one column, as wide as the scene.
|
|
10
10
|
//
|
|
11
|
-
// Rules: gold only means live (the awake row's ring and tick, the
|
|
12
|
-
// sweep); a rack a card holds (data-state="waiting") drops its gold:
|
|
13
|
-
// for you" in the warn tone with ◆,
|
|
11
|
+
// Rules: gold only means live (the awake row's ring and tick, the bubble's
|
|
12
|
+
// verb, the sweep); a rack a card holds (data-state="waiting") drops its gold:
|
|
13
|
+
// "Waiting for you" in the warn tone with ◆, stopped clocks. Motion answers
|
|
14
14
|
// events and stays under 300 ms; infinite animations run only on the live
|
|
15
15
|
// rack, pause while the UI is dragged (body.ui-interacting) and everything is
|
|
16
16
|
// static under prefers-reduced-motion (the sweep is not drawn at all). No
|
|
@@ -117,6 +117,7 @@ export const RACK_CSS = `
|
|
|
117
117
|
grid-area: caption;
|
|
118
118
|
align-self: end;
|
|
119
119
|
min-width: 0;
|
|
120
|
+
margin-left: 8px; /* flush with the bubble's body (its notch takes the first 8px) */
|
|
120
121
|
margin-bottom: 6px; /* the gap over the bubble: an empty caption takes no room */
|
|
121
122
|
overflow: hidden;
|
|
122
123
|
display: -webkit-box;
|
|
@@ -128,95 +129,107 @@ export const RACK_CSS = `
|
|
|
128
129
|
}
|
|
129
130
|
.asst-rack-caption:empty { display: none; }
|
|
130
131
|
|
|
132
|
+
/* ── The bubble: one 18px line (verb · subject · clock), 32px tall at one line, the ledger row's height.
|
|
133
|
+
The verb is gold only while the call runs; the mascot (and the sweep) carry the motion, the bubble
|
|
134
|
+
carries the words and, at the end of the line in the quietest tone, the numbers. Opaque fill (the
|
|
135
|
+
card under the panel tint), so the notch can cover the ring where it meets the edge: no seam. */
|
|
131
136
|
.asst-bubble {
|
|
137
|
+
--rk-bubble-bg: linear-gradient(var(--rk-fill-1), var(--rk-fill-1)), var(--rk-card);
|
|
132
138
|
grid-area: bubble;
|
|
133
139
|
position: relative;
|
|
134
140
|
justify-self: start;
|
|
135
141
|
align-self: start;
|
|
136
|
-
display:
|
|
137
|
-
grid-template-columns: auto minmax(0, 1fr);
|
|
138
|
-
align-items: baseline;
|
|
139
|
-
column-gap: 7px;
|
|
140
|
-
row-gap: 1px;
|
|
142
|
+
display: block; /* a block, not a flex column: a flex item's -webkit-box is blockified and loses its line clamp */
|
|
141
143
|
max-width: calc(100% - 8px);
|
|
142
144
|
min-width: 0;
|
|
143
145
|
margin-left: 8px;
|
|
144
|
-
padding:
|
|
145
|
-
border-radius: 3px
|
|
146
|
-
background: var(--rk-
|
|
146
|
+
padding: 7px 10px;
|
|
147
|
+
border-radius: 3px 10px 10px 10px;
|
|
148
|
+
background: var(--rk-bubble-bg);
|
|
147
149
|
box-shadow: inset 0 0 0 1px var(--rk-line);
|
|
148
150
|
}
|
|
149
|
-
/* The tail:
|
|
151
|
+
/* The tail: a 7px notch pointing at the mascot (left beside it, up under it), centred on the first line and
|
|
152
|
+
on the mascot's eyes. An 11px square turned 45° and cut to a triangle, 1px into the bubble so it paints
|
|
153
|
+
over the ring: the ring stops at the notch's legs, no double edge. */
|
|
150
154
|
.asst-bubble::before {
|
|
151
155
|
content: '';
|
|
152
156
|
position: absolute;
|
|
153
|
-
left: -
|
|
154
|
-
top:
|
|
157
|
+
left: -4.5px;
|
|
158
|
+
top: 10.5px;
|
|
155
159
|
width: 11px;
|
|
156
160
|
height: 11px;
|
|
157
|
-
background: var(--rk-
|
|
161
|
+
background: var(--rk-bubble-bg);
|
|
158
162
|
box-shadow: inset 1px -1px 0 var(--rk-line);
|
|
159
163
|
clip-path: polygon(0 0, 0 100%, 100% 100%);
|
|
160
164
|
transform: rotate(45deg);
|
|
161
165
|
pointer-events: none;
|
|
162
166
|
}
|
|
163
|
-
|
|
167
|
+
/* The line: one text flow, two lines at most (six opened), of the verb, the subject (cut by asst-render.js
|
|
168
|
+
until nothing is clamped) and the numbers, which take the end of the subject's last line and wrap
|
|
169
|
+
under it as a unit when they are long (a computer action and its clock). 2px of room around it for
|
|
170
|
+
the subject's focus ring. */
|
|
171
|
+
.asst-bubble-line {
|
|
172
|
+
display: -webkit-box;
|
|
173
|
+
-webkit-box-orient: vertical;
|
|
174
|
+
-webkit-line-clamp: 2;
|
|
175
|
+
min-width: 0;
|
|
176
|
+
margin: -2px -3px;
|
|
177
|
+
padding: 2px 3px;
|
|
178
|
+
overflow: hidden;
|
|
179
|
+
/* The strut sets the 18px pitch; the words inside sit at line-height 1, so no mix of sizes or fonts grows a line. */
|
|
180
|
+
font-size: 12px;
|
|
181
|
+
line-height: 18px;
|
|
182
|
+
overflow-wrap: anywhere;
|
|
183
|
+
}
|
|
184
|
+
.asst-bubble-line:has(> .asst-bubble-subject[aria-expanded="true"]) { -webkit-line-clamp: 6; }
|
|
185
|
+
.asst-bubble-verb { color: var(--rk-text-2); font-size: 12px; font-weight: 500; line-height: 1; white-space: nowrap; }
|
|
186
|
+
.asst-bubble-verb:not(:empty) { margin-right: 7px; }
|
|
164
187
|
.asst-bubble[data-state="running"] .asst-bubble-verb { color: var(--rk-gold); }
|
|
165
|
-
/* A card holds the call: no gold,
|
|
188
|
+
/* A card holds the call: no gold, the clock stopped (asst-render.js), "◆ Waiting for you". */
|
|
166
189
|
.asst-bubble[data-state="waiting"] .asst-bubble-verb { color: var(--rk-warn); }
|
|
167
190
|
.asst-bubble[data-state="waiting"] .asst-bubble-verb::before { content: '◆'; margin-right: 5px; font-size: 9px; vertical-align: 1px; }
|
|
168
191
|
.asst-bubble-subject {
|
|
169
192
|
--rk-cut: middle; /* where asst-render.js cuts a long subject: the middle; the head on a narrow stage */
|
|
170
193
|
position: relative;
|
|
171
|
-
min-width: 0;
|
|
172
|
-
overflow: hidden;
|
|
173
|
-
display: -webkit-box;
|
|
174
|
-
-webkit-box-orient: vertical;
|
|
175
|
-
-webkit-line-clamp: 2;
|
|
176
194
|
border-radius: 4px;
|
|
177
195
|
color: var(--rk-text);
|
|
178
196
|
font-size: 12px;
|
|
179
|
-
line-height: 1
|
|
180
|
-
overflow-wrap: anywhere;
|
|
197
|
+
line-height: 1;
|
|
181
198
|
cursor: pointer;
|
|
182
199
|
}
|
|
183
200
|
.asst-bubble-subject.is-mono { font-family: var(--rk-mono); font-size: 11.5px; }
|
|
184
201
|
.asst-bubble-subject.is-muted { color: var(--rk-text-3); }
|
|
185
|
-
.asst-bubble-subject[aria-expanded="true"] {
|
|
202
|
+
.asst-bubble-subject[aria-expanded="true"] { cursor: text; user-select: text; }
|
|
186
203
|
.asst-bubble-subject .is-dim { color: var(--rk-text-3); }
|
|
187
204
|
.asst-bubble-subject .is-strong { color: var(--rk-text); font-weight: 600; }
|
|
188
|
-
/*
|
|
189
|
-
|
|
205
|
+
/* A URL or path: one piece per span, a <wbr> between them (asst-render.js writeSubject), so it wraps after "/"
|
|
206
|
+
and at its other separators, never mid-word; a piece wider than its line is cut instead (fitSubject). The
|
|
207
|
+
rest of the subject wraps as the line says. Opened, the whole literal shows: a piece may break again. */
|
|
208
|
+
.asst-bubble-piece { white-space: nowrap; }
|
|
209
|
+
.asst-bubble-subject[aria-expanded="true"] .asst-bubble-piece { white-space: normal; }
|
|
210
|
+
/* Streaming thinking cut from its head ("…the end of the thought") fades in from the cut; whole text is left alone. */
|
|
211
|
+
.asst-bubble[data-kind="think"][data-state="running"] .asst-bubble-subject.is-cut {
|
|
190
212
|
-webkit-mask-image: linear-gradient(90deg, transparent, #000 12px);
|
|
191
213
|
mask-image: linear-gradient(90deg, transparent, #000 12px);
|
|
192
214
|
}
|
|
193
|
-
.asst-bubble-caret {
|
|
194
|
-
display: none;
|
|
195
|
-
width: 6px;
|
|
196
|
-
height: 12px;
|
|
197
|
-
margin-left: 3px;
|
|
198
|
-
vertical-align: -2px;
|
|
199
|
-
background: var(--rk-gold);
|
|
200
|
-
}
|
|
201
|
-
.asst-bubble[data-state="running"] .asst-bubble-caret { display: inline-block; animation: asst-rk-caret 1.06s steps(1) infinite; }
|
|
202
215
|
.asst-bubble-meta {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
gap: 2px 12px;
|
|
216
|
+
display: inline-flex;
|
|
217
|
+
gap: 0 8px;
|
|
218
|
+
margin-left: 7px;
|
|
207
219
|
color: var(--rk-text-3);
|
|
208
220
|
font-size: 11px;
|
|
209
|
-
line-height: 1
|
|
221
|
+
line-height: 1; /* inside the 18px strut: the smaller type never grows the line */
|
|
222
|
+
white-space: nowrap;
|
|
210
223
|
font-variant-numeric: tabular-nums;
|
|
211
224
|
}
|
|
212
225
|
.asst-bubble-meta:empty { display: none; }
|
|
213
226
|
.asst-bubble-num { white-space: nowrap; }
|
|
214
227
|
.asst-bubble-err {
|
|
215
|
-
grid-column: 1 / -1;
|
|
216
228
|
display: -webkit-box;
|
|
217
229
|
-webkit-box-orient: vertical;
|
|
218
230
|
-webkit-line-clamp: 2;
|
|
219
231
|
min-width: 0;
|
|
232
|
+
margin-top: 2px;
|
|
220
233
|
overflow: hidden;
|
|
221
234
|
color: var(--rk-red);
|
|
222
235
|
font-family: var(--rk-mono);
|
|
@@ -228,8 +241,8 @@ export const RACK_CSS = `
|
|
|
228
241
|
.asst-bubble-copy {
|
|
229
242
|
position: relative;
|
|
230
243
|
isolation: isolate;
|
|
231
|
-
|
|
232
|
-
|
|
244
|
+
display: inline-flex;
|
|
245
|
+
align-items: center;
|
|
233
246
|
height: var(--rk-pill-h);
|
|
234
247
|
margin-top: 4px;
|
|
235
248
|
padding: 0 var(--rk-pill-px);
|
|
@@ -242,7 +255,9 @@ export const RACK_CSS = `
|
|
|
242
255
|
cursor: pointer;
|
|
243
256
|
}
|
|
244
257
|
.asst-bubble-copy:hover { color: var(--rk-text); }
|
|
245
|
-
|
|
258
|
+
/* The clock: tabular digits that roll in place (asst-render.js); its cell keeps "59 s" of room, right-aligned, so
|
|
259
|
+
"9 s" → "10 s" moves nothing. */
|
|
260
|
+
.asst-odo { display: inline-flex; justify-content: flex-end; min-width: 2.4em; font-variant-numeric: tabular-nums; white-space: pre; }
|
|
246
261
|
.asst-odo-d { display: inline-block; }
|
|
247
262
|
|
|
248
263
|
.asst-rack-sweep { position: absolute; left: 0; right: 0; bottom: 0; height: 1.5px; overflow: hidden; pointer-events: none; }
|
|
@@ -553,9 +568,9 @@ export const RACK_CSS = `
|
|
|
553
568
|
.asst-rack-stage { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "face caption" "bubble bubble"; column-gap: 8px; row-gap: 6px; }
|
|
554
569
|
.asst-rack-set { align-self: center; flex-direction: row; }
|
|
555
570
|
.asst-rack.is-staged > .asst-rack-stage { padding: 10px 10px 10px; }
|
|
556
|
-
.asst-rack-caption { align-self: center; margin-bottom: 0; }
|
|
557
|
-
.asst-bubble { justify-self: stretch; max-width: 100%; margin: 4px 0 0; border-radius: 3px
|
|
558
|
-
.asst-bubble::before { left: 30px; top: -
|
|
571
|
+
.asst-rack-caption { align-self: center; margin-left: 0; margin-bottom: 0; }
|
|
572
|
+
.asst-bubble { justify-self: stretch; max-width: 100%; margin: 4px 0 0; border-radius: 3px 10px 10px 10px; }
|
|
573
|
+
.asst-bubble::before { left: 30px; top: -4.5px; box-shadow: inset 1px 1px 0 var(--rk-line); clip-path: polygon(0 100%, 0 0, 100% 0); }
|
|
559
574
|
.asst-station-hdr { gap: 8px; padding: 0 6px; }
|
|
560
575
|
.asst-station-time { display: none; }
|
|
561
576
|
.asst-tick.is-old { display: none; }
|
|
@@ -565,7 +580,8 @@ export const RACK_CSS = `
|
|
|
565
580
|
.asst-station-sub { margin-left: 12px; }
|
|
566
581
|
}
|
|
567
582
|
@container asst (max-width: 320px) {
|
|
568
|
-
.asst-bubble { padding:
|
|
583
|
+
.asst-bubble { padding: 6px 9px; }
|
|
584
|
+
.asst-bubble::before { top: -4.5px; }
|
|
569
585
|
.asst-bubble-subject { --rk-cut: head; }
|
|
570
586
|
.asst-bubble-meta { display: none; }
|
|
571
587
|
}
|
|
@@ -576,6 +592,7 @@ export const RACK_CSS = `
|
|
|
576
592
|
}
|
|
577
593
|
|
|
578
594
|
/* ── Motion ─────────────────────────────────────────────────────── */
|
|
595
|
+
/* The caret blink belongs to the scenes' code caret (asst-scene-styles.js); the bubble has none. */
|
|
579
596
|
@keyframes asst-rk-caret { 0% { opacity: 1; } 50% { opacity: 0; } }
|
|
580
597
|
@keyframes asst-rk-sweep { from { transform: translateX(-100%); } to { transform: translateX(270%); } }
|
|
581
598
|
@keyframes asst-rk-tick { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
|