synabun 2.0.7 → 2.0.10
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 +67 -0
- package/README.md +1 -1
- package/THIRD-PARTY-LICENSES.md +46 -4
- package/hooks/claude-code/post-plan.mjs +6 -30
- package/hooks/claude-code/session-start.mjs +1 -4
- package/hooks/claude-code/shared.mjs +106 -72
- package/launcher.mjs +9 -3
- package/lib/package-processes.js +670 -0
- package/lib/runtime-dependencies.js +225 -0
- package/lib/start-launcher.js +6 -1
- package/mcp-server/dist/services/browser-bench.d.ts +1 -1
- package/mcp-server/dist/services/browser-bench.d.ts.map +1 -1
- package/mcp-server/dist/services/browser-bench.js +1 -1
- package/mcp-server/dist/services/browser-bench.js.map +1 -1
- package/mcp-server/dist/services/categories.d.ts +35 -2
- package/mcp-server/dist/services/categories.d.ts.map +1 -1
- package/mcp-server/dist/services/categories.js +77 -33
- package/mcp-server/dist/services/categories.js.map +1 -1
- package/mcp-server/dist/services/desktop-bench.d.ts +7 -7
- package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -1
- package/mcp-server/dist/services/desktop-bench.js +1 -1
- package/mcp-server/dist/services/desktop-bench.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +1 -1
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +1 -1
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/bluesky.js +1 -1
- package/mcp-server/dist/tools/bluesky.js.map +1 -1
- package/mcp-server/dist/tools/browser-advanced.d.ts +1 -1
- package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-advanced.js +1 -1
- package/mcp-server/dist/tools/browser-advanced.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-batch.js +1 -1
- package/mcp-server/dist/tools/browser-batch.js.map +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.js +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -1
- package/mcp-server/dist/tools/browser-interact.d.ts +1 -1
- package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-interact.js +1 -1
- package/mcp-server/dist/tools/browser-interact.js.map +1 -1
- package/mcp-server/dist/tools/browser-navigate.d.ts +1 -1
- package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-navigate.js +1 -1
- package/mcp-server/dist/tools/browser-navigate.js.map +1 -1
- package/mcp-server/dist/tools/browser-observe.d.ts +1 -1
- package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-observe.js +1 -1
- package/mcp-server/dist/tools/browser-observe.js.map +1 -1
- package/mcp-server/dist/tools/card-tools.d.ts +1 -1
- package/mcp-server/dist/tools/card-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/card-tools.js +1 -1
- package/mcp-server/dist/tools/card-tools.js.map +1 -1
- package/mcp-server/dist/tools/category.d.ts +1 -1
- package/mcp-server/dist/tools/category.d.ts.map +1 -1
- package/mcp-server/dist/tools/category.js +5 -1
- package/mcp-server/dist/tools/category.js.map +1 -1
- package/mcp-server/dist/tools/choice.d.ts +1 -1
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +1 -1
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/computer.d.ts +1 -1
- package/mcp-server/dist/tools/computer.d.ts.map +1 -1
- package/mcp-server/dist/tools/computer.js +1 -1
- package/mcp-server/dist/tools/computer.js.map +1 -1
- package/mcp-server/dist/tools/discord-channel.d.ts +1 -1
- package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-channel.js +1 -1
- package/mcp-server/dist/tools/discord-channel.js.map +1 -1
- package/mcp-server/dist/tools/discord-guild.d.ts +1 -1
- package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-guild.js +1 -1
- package/mcp-server/dist/tools/discord-guild.js.map +1 -1
- package/mcp-server/dist/tools/discord-member.d.ts +1 -1
- package/mcp-server/dist/tools/discord-member.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-member.js +1 -1
- package/mcp-server/dist/tools/discord-member.js.map +1 -1
- package/mcp-server/dist/tools/discord-message.d.ts +1 -1
- package/mcp-server/dist/tools/discord-message.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-message.js +1 -1
- package/mcp-server/dist/tools/discord-message.js.map +1 -1
- package/mcp-server/dist/tools/discord-onboarding.d.ts +1 -1
- package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-onboarding.js +1 -1
- package/mcp-server/dist/tools/discord-onboarding.js.map +1 -1
- package/mcp-server/dist/tools/discord-role.d.ts +1 -1
- package/mcp-server/dist/tools/discord-role.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-role.js +1 -1
- package/mcp-server/dist/tools/discord-role.js.map +1 -1
- package/mcp-server/dist/tools/discord-thread.d.ts +1 -1
- package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-thread.js +1 -1
- package/mcp-server/dist/tools/discord-thread.js.map +1 -1
- package/mcp-server/dist/tools/discord-webhook.d.ts +1 -1
- package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-webhook.js +1 -1
- package/mcp-server/dist/tools/discord-webhook.js.map +1 -1
- package/mcp-server/dist/tools/fb-groups.d.ts +1 -1
- package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -1
- package/mcp-server/dist/tools/fb-groups.js +1 -1
- package/mcp-server/dist/tools/fb-groups.js.map +1 -1
- package/mcp-server/dist/tools/forget.d.ts +1 -1
- package/mcp-server/dist/tools/forget.d.ts.map +1 -1
- package/mcp-server/dist/tools/forget.js +1 -1
- package/mcp-server/dist/tools/forget.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.d.ts +1 -1
- package/mcp-server/dist/tools/git-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +1 -1
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/gsc/experience.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/experience.js +1 -1
- package/mcp-server/dist/tools/gsc/experience.js.map +1 -1
- package/mcp-server/dist/tools/gsc/indexing.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/indexing.js +1 -1
- package/mcp-server/dist/tools/gsc/indexing.js.map +1 -1
- package/mcp-server/dist/tools/gsc/inspect.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/inspect.js +1 -1
- package/mcp-server/dist/tools/gsc/inspect.js.map +1 -1
- package/mcp-server/dist/tools/gsc/navigate.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/navigate.js +1 -1
- package/mcp-server/dist/tools/gsc/navigate.js.map +1 -1
- package/mcp-server/dist/tools/gsc/performance.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/performance.js +1 -1
- package/mcp-server/dist/tools/gsc/performance.js.map +1 -1
- package/mcp-server/dist/tools/gsc/settings.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/settings.js +1 -1
- package/mcp-server/dist/tools/gsc/settings.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/image-tools.js.map +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -1
- package/mcp-server/dist/tools/loop.d.ts +1 -1
- package/mcp-server/dist/tools/loop.d.ts.map +1 -1
- package/mcp-server/dist/tools/loop.js +1 -1
- package/mcp-server/dist/tools/loop.js.map +1 -1
- package/mcp-server/dist/tools/memories.d.ts +1 -1
- package/mcp-server/dist/tools/memories.d.ts.map +1 -1
- package/mcp-server/dist/tools/memories.js +1 -1
- package/mcp-server/dist/tools/memories.js.map +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +1 -1
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/profile.d.ts +1 -1
- package/mcp-server/dist/tools/profile.d.ts.map +1 -1
- package/mcp-server/dist/tools/profile.js +1 -1
- package/mcp-server/dist/tools/profile.js.map +1 -1
- package/mcp-server/dist/tools/recall.d.ts +1 -1
- package/mcp-server/dist/tools/recall.d.ts.map +1 -1
- package/mcp-server/dist/tools/recall.js +1 -1
- package/mcp-server/dist/tools/recall.js.map +1 -1
- package/mcp-server/dist/tools/reflect.d.ts +1 -1
- package/mcp-server/dist/tools/reflect.d.ts.map +1 -1
- package/mcp-server/dist/tools/reflect.js +1 -1
- package/mcp-server/dist/tools/reflect.js.map +1 -1
- package/mcp-server/dist/tools/remember.d.ts +1 -1
- package/mcp-server/dist/tools/remember.d.ts.map +1 -1
- package/mcp-server/dist/tools/remember.js +13 -11
- package/mcp-server/dist/tools/remember.js.map +1 -1
- package/mcp-server/dist/tools/restore.d.ts +1 -1
- package/mcp-server/dist/tools/restore.d.ts.map +1 -1
- package/mcp-server/dist/tools/restore.js +1 -1
- package/mcp-server/dist/tools/restore.js.map +1 -1
- package/mcp-server/dist/tools/style-guide-tools.d.ts +1 -1
- package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/style-guide-tools.js +1 -1
- package/mcp-server/dist/tools/style-guide-tools.js.map +1 -1
- package/mcp-server/dist/tools/sync.d.ts +1 -1
- package/mcp-server/dist/tools/sync.d.ts.map +1 -1
- package/mcp-server/dist/tools/sync.js +1 -1
- package/mcp-server/dist/tools/sync.js.map +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.d.ts +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.js +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -1
- package/mcp-server/dist/tools/utils.d.ts +1 -1
- package/mcp-server/dist/tools/utils.d.ts.map +1 -1
- package/mcp-server/dist/tools/utils.js +1 -1
- package/mcp-server/dist/tools/utils.js.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.js +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +3 -3
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/dist/tools/youtube/analytics.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/analytics.js +1 -1
- package/mcp-server/dist/tools/youtube/analytics.js.map +1 -1
- package/mcp-server/dist/tools/youtube/download.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/download.js +1 -1
- package/mcp-server/dist/tools/youtube/download.js.map +1 -1
- package/mcp-server/dist/tools/youtube/media.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/media.js +1 -1
- package/mcp-server/dist/tools/youtube/media.js.map +1 -1
- package/mcp-server/dist/tools/youtube/metadata.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/metadata.js +1 -1
- package/mcp-server/dist/tools/youtube/metadata.js.map +1 -1
- package/mcp-server/dist/tools/youtube/navigate.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/navigate.js +1 -1
- package/mcp-server/dist/tools/youtube/navigate.js.map +1 -1
- package/mcp-server/dist/tools/youtube/playlist.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/playlist.js +1 -1
- package/mcp-server/dist/tools/youtube/playlist.js.map +1 -1
- package/mcp-server/dist/tools/youtube/schedule.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/schedule.js +1 -1
- package/mcp-server/dist/tools/youtube/schedule.js.map +1 -1
- package/mcp-server/dist/tools/youtube/source.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/source.js +1 -1
- package/mcp-server/dist/tools/youtube/source.js.map +1 -1
- package/mcp-server/dist/tools/youtube/upload.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/upload.js +4 -9
- package/mcp-server/dist/tools/youtube/upload.js.map +1 -1
- package/mcp-server/dist/tui.js +16 -4
- package/mcp-server/dist/tui.js.map +1 -1
- package/mcp-server/package-lock.json +3 -3
- package/mcp-server/package.json +3 -3
- package/mcp-server/src/services/browser-bench.ts +1 -1
- package/mcp-server/src/services/categories.ts +77 -32
- package/mcp-server/src/services/desktop-bench.ts +1 -1
- package/mcp-server/src/tools/agents.ts +1 -1
- package/mcp-server/src/tools/bluesky.ts +1 -1
- package/mcp-server/src/tools/browser-advanced.ts +1 -1
- package/mcp-server/src/tools/browser-batch.ts +1 -1
- package/mcp-server/src/tools/browser-cheatsheet.ts +1 -1
- package/mcp-server/src/tools/browser-interact.ts +1 -1
- package/mcp-server/src/tools/browser-navigate.ts +1 -1
- package/mcp-server/src/tools/browser-observe.ts +1 -1
- package/mcp-server/src/tools/card-tools.ts +1 -1
- package/mcp-server/src/tools/category.ts +6 -1
- package/mcp-server/src/tools/choice.ts +1 -1
- package/mcp-server/src/tools/computer.ts +1 -1
- package/mcp-server/src/tools/discord-channel.ts +1 -1
- package/mcp-server/src/tools/discord-guild.ts +1 -1
- package/mcp-server/src/tools/discord-member.ts +1 -1
- package/mcp-server/src/tools/discord-message.ts +1 -1
- package/mcp-server/src/tools/discord-onboarding.ts +1 -1
- package/mcp-server/src/tools/discord-role.ts +1 -1
- package/mcp-server/src/tools/discord-thread.ts +1 -1
- package/mcp-server/src/tools/discord-webhook.ts +1 -1
- package/mcp-server/src/tools/fb-groups.ts +1 -1
- package/mcp-server/src/tools/forget.ts +1 -1
- package/mcp-server/src/tools/git-tools.ts +1 -1
- package/mcp-server/src/tools/gsc/experience.ts +1 -1
- package/mcp-server/src/tools/gsc/indexing.ts +1 -1
- package/mcp-server/src/tools/gsc/inspect.ts +1 -1
- package/mcp-server/src/tools/gsc/navigate.ts +1 -1
- package/mcp-server/src/tools/gsc/performance.ts +1 -1
- package/mcp-server/src/tools/gsc/settings.ts +1 -1
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/leonardo-browser-tools.ts +1 -1
- package/mcp-server/src/tools/loop.ts +1 -1
- package/mcp-server/src/tools/memories.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +1 -1
- package/mcp-server/src/tools/profile.ts +1 -1
- package/mcp-server/src/tools/recall.ts +1 -1
- package/mcp-server/src/tools/reflect.ts +1 -1
- package/mcp-server/src/tools/remember.ts +13 -12
- package/mcp-server/src/tools/restore.ts +1 -1
- package/mcp-server/src/tools/style-guide-tools.ts +1 -1
- package/mcp-server/src/tools/sync.ts +1 -1
- package/mcp-server/src/tools/tictactoe-tools.ts +1 -1
- package/mcp-server/src/tools/utils.ts +1 -1
- package/mcp-server/src/tools/whatsapp-send-file.ts +1 -1
- package/mcp-server/src/tools/whiteboard-tools.ts +1 -1
- package/mcp-server/src/tools/youtube/analytics.ts +1 -1
- package/mcp-server/src/tools/youtube/download.ts +1 -1
- package/mcp-server/src/tools/youtube/media.ts +1 -1
- package/mcp-server/src/tools/youtube/metadata.ts +1 -1
- package/mcp-server/src/tools/youtube/navigate.ts +1 -1
- package/mcp-server/src/tools/youtube/playlist.ts +1 -1
- package/mcp-server/src/tools/youtube/schedule.ts +1 -1
- package/mcp-server/src/tools/youtube/source.ts +1 -1
- package/mcp-server/src/tools/youtube/upload.ts +4 -12
- package/mcp-server/src/tui.ts +22 -9
- package/neural-interface/i18n/en.json +236 -7
- package/neural-interface/i18n/pt-BR.json +238 -9
- package/neural-interface/lib/account-usage.js +5 -3
- package/neural-interface/lib/agent-sandbox-elevation.js +102 -0
- package/neural-interface/lib/agent-sandbox-setting.js +57 -0
- package/neural-interface/lib/app-controls-api.js +161 -0
- package/neural-interface/lib/assistant-api.js +40 -7
- package/neural-interface/lib/assistant-brains/opencode.js +13 -1
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +44 -0
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +57 -0
- package/neural-interface/lib/assistant-catalog.js +17 -2
- package/neural-interface/lib/assistant-dispatch.js +3 -0
- package/neural-interface/lib/assistant-envelope.js +19 -1
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
- package/neural-interface/lib/assistant-runtime.js +131 -8
- package/neural-interface/lib/claude-model-catalog.js +64 -14
- package/neural-interface/lib/codex-account-auth.js +4 -2
- package/neural-interface/lib/codex-accounts.js +14 -1
- package/neural-interface/lib/codex-settings-schema.js +111 -47
- package/neural-interface/lib/editor-completion-opencode.js +132 -35
- package/neural-interface/lib/exec-loop-command.js +11 -2
- package/neural-interface/lib/install-details.js +23 -5
- package/neural-interface/lib/launch-cache.js +293 -0
- package/neural-interface/lib/login-start.js +524 -0
- package/neural-interface/lib/native-loop-providers.js +24 -4
- package/neural-interface/lib/native-loop-runtime.js +19 -0
- package/neural-interface/lib/opencode-db-schema.js +75 -0
- package/neural-interface/lib/opencode-history.js +16 -1
- package/neural-interface/lib/opencode-protocol.js +173 -0
- package/neural-interface/lib/opencode-provider-view.js +81 -0
- package/neural-interface/lib/opencode-runtime-config.js +10 -3
- package/neural-interface/lib/opencode-serve-records.js +606 -0
- package/neural-interface/lib/opencode-v2-client.js +33 -6
- package/neural-interface/lib/opencode-v2-ws-requests.js +19 -5
- package/neural-interface/lib/opencode-worker-activity.js +229 -0
- package/neural-interface/lib/opencode2-client.js +760 -0
- package/neural-interface/lib/opencode2-proxy.js +116 -0
- package/neural-interface/lib/opencode2-translate.js +1008 -0
- package/neural-interface/lib/process-identity.js +361 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +3 -2
- package/neural-interface/lib/session-cache-builder.js +26 -5
- package/neural-interface/lib/session-indexer.js +3 -1
- package/neural-interface/lib/session-title-generator.js +20 -0
- package/neural-interface/lib/style-guide/api.js +4 -3
- package/neural-interface/lib/untrusted-file-headers.js +27 -0
- package/neural-interface/package-lock.json +1342 -44
- package/neural-interface/package.json +5 -1
- package/neural-interface/public/index.html +2 -2
- package/neural-interface/public/shared/account-menu.js +4 -1
- package/neural-interface/public/shared/account-usage.js +62 -2
- package/neural-interface/public/shared/account-view.js +2 -1
- package/neural-interface/public/shared/agent-runtime-options.js +55 -11
- package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +172 -17
- package/neural-interface/public/shared/assistant/asst-api.js +18 -3
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +424 -152
- package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
- package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
- package/neural-interface/public/shared/assistant/asst-menu.js +275 -77
- package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +236 -35
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +28 -10
- package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
- package/neural-interface/public/shared/assistant/asst-render.js +382 -36
- package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
- package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
- package/neural-interface/public/shared/assistant/asst-scenes.js +528 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
- package/neural-interface/public/shared/assistant/asst-state.js +14 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +109 -17
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +13 -1
- package/neural-interface/public/shared/cc-dropdown.js +480 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +14 -2
- package/neural-interface/public/shared/cdx/cdx-render.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-styles.js +49 -5
- package/neural-interface/public/shared/cdx/cdx-tabs.js +152 -35
- package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
- package/neural-interface/public/shared/data-cache.js +223 -0
- package/neural-interface/public/shared/desktop-bridge.js +11 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
- package/neural-interface/public/shared/desktop-titlebar.js +214 -28
- package/neural-interface/public/shared/desktop-update-view.js +15 -5
- package/neural-interface/public/shared/file-links.js +73 -8
- package/neural-interface/public/shared/html-shell.js +74 -80
- package/neural-interface/public/shared/launch-prefetch.js +59 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +11 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +97 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +3 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +16 -9
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +60 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +83 -5
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +195 -19
- package/neural-interface/public/shared/opencode-providers.js +39 -0
- package/neural-interface/public/shared/schedules-view.js +318 -0
- package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
- package/neural-interface/public/shared/settings/settings-app.js +243 -0
- package/neural-interface/public/shared/settings/settings-data.js +88 -0
- package/neural-interface/public/shared/settings/settings-ia.js +17 -0
- package/neural-interface/public/shared/showcase-privacy.js +2 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
- package/neural-interface/public/shared/styles.css +543 -372
- package/neural-interface/public/shared/ui-assistant.js +27 -5
- package/neural-interface/public/shared/ui-automation-studio.js +67 -27
- package/neural-interface/public/shared/ui-bookmarks.js +2 -1
- package/neural-interface/public/shared/ui-claude-panel.js +126 -12
- package/neural-interface/public/shared/ui-codex-panel.js +1 -0
- package/neural-interface/public/shared/ui-detail.js +6 -6
- package/neural-interface/public/shared/ui-explorer.js +2 -0
- package/neural-interface/public/shared/ui-file-links.js +1 -0
- package/neural-interface/public/shared/ui-image-gallery.js +6 -5
- package/neural-interface/public/shared/ui-invite.js +18 -2
- package/neural-interface/public/shared/ui-link.js +9 -9
- package/neural-interface/public/shared/ui-menubar.js +232 -33
- package/neural-interface/public/shared/ui-native-loop-router.js +2 -0
- package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
- package/neural-interface/public/shared/ui-schedules-studio.js +2099 -869
- package/neural-interface/public/shared/ui-sessions.js +15 -4
- package/neural-interface/public/shared/ui-settings.js +87 -36
- package/neural-interface/public/shared/ui-sidebar.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +55 -4
- package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
- package/neural-interface/public/shared/ui-skills.js +70 -12
- package/neural-interface/public/shared/ui-sync.js +9 -0
- package/neural-interface/public/shared/ui-terminal.js +36 -20
- package/neural-interface/public/shared/ui-trash.js +8 -1
- package/neural-interface/public/shared/ui-tutorial-steps.js +7 -3
- package/neural-interface/public/shared/ui-tutorial.js +15 -5
- package/neural-interface/public/shared/ui-update.js +87 -16
- package/neural-interface/public/shared/ui-whiteboard.js +2 -1
- package/neural-interface/public/variant/2d/main.js +4 -1
- package/neural-interface/public/variant/3d/main.js +3 -0
- package/neural-interface/public/vendor/highlight/LICENSE +29 -0
- package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
- package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
- package/neural-interface/public/vendor/highlight/manifest.json +5 -0
- package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
- package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
- package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
- package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
- package/neural-interface/public/vendor/marked/manifest.json +4 -0
- package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
- package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
- package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
- package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
- package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
- package/neural-interface/scripts/build-vendor.mjs +84 -3
- package/neural-interface/scripts/rebuild-pty.js +14 -2
- package/neural-interface/server.js +1279 -372
- package/npm-shrinkwrap.json +4424 -0
- package/package.json +54 -2
- package/postinstall.js +61 -47
- package/preuninstall.js +8 -35
- package/setup.js +76 -44
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/schedule.md +2 -2
- package/updater.cmd +2 -2
- package/updater.mjs +97 -3
|
@@ -29,11 +29,14 @@ import {
|
|
|
29
29
|
import { getHiddenModels, HIDDEN_MODELS_EVENT, hiddenModelMatch } from '../ocp-hidden-models.js';
|
|
30
30
|
import { getProviderMeta } from '../provider-icons.js';
|
|
31
31
|
import { on } from '../state.js';
|
|
32
|
+
import { registerLaunchPrefetch } from '../launch-prefetch.js';
|
|
32
33
|
import { fetchAssistantCatalog, fetchProjects, patchClaudeAccount, patchCodexAccount, setClaudeWorkerAccount, setCodexWorkerAccount } from './asst-api.js';
|
|
33
|
-
import { accountBadge,
|
|
34
|
-
import {
|
|
34
|
+
import { accountBadge, accountIdentity, accountName, accountText } from '../account-view.js';
|
|
35
|
+
import { autoAccountLabel } from '../account-usage.js';
|
|
36
|
+
import { accountChoiceItems, accountManageItem, accountMenuRow, accountModeItem, openAccountMenu } from './asst-account-menu.js';
|
|
35
37
|
import { closeMenu, currentMenu, isMenuOpen, openMenu } from './asst-menu.js';
|
|
36
38
|
import { createMascotControl } from './asst-mascot.js';
|
|
39
|
+
import { modelChipForms, modelChipName, modelChipTag } from './asst-model-chip.js';
|
|
37
40
|
import {
|
|
38
41
|
ACCOUNT_PROVIDERS,
|
|
39
42
|
brainRequiresSwitch,
|
|
@@ -52,6 +55,9 @@ import {
|
|
|
52
55
|
} from './asst-state.js';
|
|
53
56
|
|
|
54
57
|
let _projectsCache = null;
|
|
58
|
+
// Providers whose field menus have everything they read loaded once (models, catalog, accounts or agents,
|
|
59
|
+
// presets, projects): their menus open from it at once and read it again in the background.
|
|
60
|
+
const _warmProviders = new Set();
|
|
55
61
|
|
|
56
62
|
/** SynaBun's registered projects as the last load saw them ([{ path, label }]; [] before the first). */
|
|
57
63
|
export function cachedProjects() { return _projectsCache || []; }
|
|
@@ -79,6 +85,10 @@ const TEST_DENSITY_COPY = {
|
|
|
79
85
|
thorough: ['Thorough', 'Full coverage, whole suite, live checks.'],
|
|
80
86
|
};
|
|
81
87
|
|
|
88
|
+
// English copy of the Admin sandbox row (i18n: assistant.adminSandbox.hint). Names only Codex: the
|
|
89
|
+
// one provider it changes (lib/agent-sandbox-elevation.js; Claude Code and OpenCode are no-ops).
|
|
90
|
+
export const ADMIN_SANDBOX_HINT = 'Only changes anything when SynaBun runs on Windows. On: Codex can set up its strongest sandbox, which asks for administrator approval once per account. Off: no admin prompt; Codex uses a sandbox that needs no admin, with weaker isolation.';
|
|
91
|
+
|
|
82
92
|
/** "Light" — the level's name (a missing or unknown level is the default one). */
|
|
83
93
|
export function testDensityLabel(level, t) {
|
|
84
94
|
const id = normalizeTestDensity(level);
|
|
@@ -315,11 +325,41 @@ export async function loadModelCatalog({ force = false } = {}) {
|
|
|
315
325
|
// while it loaded: the next open asks again.
|
|
316
326
|
_catalogAt = remote && epoch === _catalogEpoch ? Date.now() : 0;
|
|
317
327
|
_catalogPartial = !remote;
|
|
328
|
+
if (_catalogAt) keepCatalog(out, sets);
|
|
318
329
|
return out;
|
|
319
330
|
})().finally(() => { _catalogLoading = null; });
|
|
320
331
|
return _catalogLoading;
|
|
321
332
|
}
|
|
322
333
|
|
|
334
|
+
// The last complete catalog is also kept in sessionStorage (this tab only): after a reload the model menus
|
|
335
|
+
// paint from it at once. Read back, it is due: the first load asks the server again.
|
|
336
|
+
const CATALOG_STORE_KEY = 'synabun:assistant-model-catalog:v1';
|
|
337
|
+
function keepCatalog(catalog, sets) {
|
|
338
|
+
try {
|
|
339
|
+
if (typeof sessionStorage === 'undefined') return;
|
|
340
|
+
const hidden = {};
|
|
341
|
+
for (const provider of PROVIDERS) hidden[provider] = [...(sets?.[provider] || [])];
|
|
342
|
+
const rowOnly = {};
|
|
343
|
+
for (const provider of PROVIDERS) rowOnly[provider] = [...(sets?.rowOnly?.[provider] || [])];
|
|
344
|
+
sessionStorage.setItem(CATALOG_STORE_KEY, JSON.stringify({ catalog, hidden, rowOnly }));
|
|
345
|
+
} catch { /* full or unavailable */ }
|
|
346
|
+
}
|
|
347
|
+
(() => {
|
|
348
|
+
try {
|
|
349
|
+
if (typeof sessionStorage === 'undefined' || _catalog) return;
|
|
350
|
+
const kept = JSON.parse(sessionStorage.getItem(CATALOG_STORE_KEY) || 'null');
|
|
351
|
+
if (!kept?.catalog || typeof kept.catalog !== 'object') return;
|
|
352
|
+
_catalog = kept.catalog;
|
|
353
|
+
_catalogAt = 0;
|
|
354
|
+
const sets = { rowOnly: {} };
|
|
355
|
+
for (const provider of PROVIDERS) {
|
|
356
|
+
sets[provider] = new Set(Array.isArray(kept.hidden?.[provider]) ? kept.hidden[provider] : []);
|
|
357
|
+
sets.rowOnly[provider] = new Set(Array.isArray(kept.rowOnly?.[provider]) ? kept.rowOnly[provider] : []);
|
|
358
|
+
}
|
|
359
|
+
_hidden = sets;
|
|
360
|
+
} catch { /* unreadable: the first load builds it */ }
|
|
361
|
+
})();
|
|
362
|
+
|
|
323
363
|
/** The last loadModelCatalog() result, synchronously (null before the first load). */
|
|
324
364
|
export function cachedModelCatalog() { return _catalog; }
|
|
325
365
|
|
|
@@ -340,6 +380,8 @@ export function invalidateModelCatalog() {
|
|
|
340
380
|
_catalogAt = 0;
|
|
341
381
|
_catalogPartial = false;
|
|
342
382
|
_catalogEpoch += 1;
|
|
383
|
+
// A reload must not paint the lists this replaced.
|
|
384
|
+
try { if (typeof sessionStorage !== 'undefined') sessionStorage.removeItem(CATALOG_STORE_KEY); } catch { /* unavailable */ }
|
|
343
385
|
}
|
|
344
386
|
|
|
345
387
|
/**
|
|
@@ -360,6 +402,15 @@ function modelListsChanged() {
|
|
|
360
402
|
for (const listener of [..._catalogListeners]) {
|
|
361
403
|
try { listener(); } catch { /* a listener's failure is its own */ }
|
|
362
404
|
}
|
|
405
|
+
scheduleCatalogReload();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// In a page: the new lists are read right away, so the next menu opens from them (an open that comes
|
|
409
|
+
// first joins this read).
|
|
410
|
+
let _catalogReloadTimer = null;
|
|
411
|
+
function scheduleCatalogReload() {
|
|
412
|
+
if (typeof document === 'undefined' || _catalogReloadTimer) return;
|
|
413
|
+
_catalogReloadTimer = setTimeout(() => { _catalogReloadTimer = null; loadModelCatalog().catch(() => {}); }, 250);
|
|
363
414
|
}
|
|
364
415
|
|
|
365
416
|
/**
|
|
@@ -391,6 +442,12 @@ on('sync:opencode:hidden-models-changed', modelListsChanged);
|
|
|
391
442
|
on('sync:assistant:hidden-models-changed', modelListsChanged);
|
|
392
443
|
on('sync:assistant:catalog-changed', modelListsChanged);
|
|
393
444
|
|
|
445
|
+
// Launch: the menus' lists are read once the page has painted, so the first model menu opens from them.
|
|
446
|
+
if (typeof document !== 'undefined') {
|
|
447
|
+
registerLaunchPrefetch('assistant-model-catalog', () => loadModelCatalog(), { order: 10, owner: true });
|
|
448
|
+
registerLaunchPrefetch('assistant-accounts', () => Promise.allSettled([fetchClaudeAccounts(), fetchCodexAccounts(), fetchMcpProfilePresets(), fetchOpencodeAgents()]), { order: 14, owner: true });
|
|
449
|
+
}
|
|
450
|
+
|
|
394
451
|
function sameModel(selected, m) {
|
|
395
452
|
if (!selected) return false;
|
|
396
453
|
return selected === m.id || selected === m.selector;
|
|
@@ -416,7 +473,8 @@ function tierTag(m, tr) {
|
|
|
416
473
|
* opts: { brain, onSelect(target), includeHere, hereLabel, title, t, placement,
|
|
417
474
|
* current:{provider, model}|null, warnSwitch, providers, onToast(text),
|
|
418
475
|
* accept(provider, model) → bool (only those models), emptyLabel (when none
|
|
419
|
-
* passes), allowCustom (default true), zIndex (see asst-menu.js)
|
|
476
|
+
* passes), allowCustom (default true), zIndex (see asst-menu.js),
|
|
477
|
+
* accountItems (menu items listed first, under accountTitle) }
|
|
420
478
|
* target: { provider, model, label, tier, vision, outputs, efforts, price } | { here: true }
|
|
421
479
|
*/
|
|
422
480
|
export async function openModelMenu(anchor, opts = {}) {
|
|
@@ -428,74 +486,28 @@ export async function openModelMenu(anchor, opts = {}) {
|
|
|
428
486
|
if (!anchor) return null;
|
|
429
487
|
const tr = tf(t);
|
|
430
488
|
const b = normalizeBrain(brain);
|
|
431
|
-
|
|
432
|
-
//
|
|
433
|
-
const
|
|
434
|
-
title, className: 'asst-model-menu asst-route-model-menu',
|
|
435
|
-
items: [{ kind: 'info', label: tr('assistant.routes.editorState.loadingModels', 'Loading models…') }],
|
|
436
|
-
width: 380, zIndex: opts.zIndex ?? null, repositionOnResize: true,
|
|
437
|
-
}) : null;
|
|
438
|
-
if (loading) loading.el.setAttribute('aria-busy', 'true');
|
|
439
|
-
if (loading) { loading.el.setAttribute('role', 'dialog'); anchor.setAttribute('aria-haspopup', 'dialog'); }
|
|
489
|
+
// The kept catalog paints the menu at once (it is read again in the background below, and an open menu
|
|
490
|
+
// follows it in place); only a first open, or a reload the user asked for, waits for the lists.
|
|
491
|
+
const kept = opts.forceReload === true ? null : cachedModelCatalog();
|
|
440
492
|
let catalog = {};
|
|
441
493
|
let failed = false;
|
|
442
|
-
|
|
443
|
-
if (
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
if (!
|
|
457
|
-
listed += models.length;
|
|
458
|
-
const meta = getProviderMeta(provider);
|
|
459
|
-
const hiddenCount = metadata.hiddenCounts[provider] || 0;
|
|
460
|
-
const note = opts.routingEditor ? tr('assistant.routes.menu.hiddenCount', '{count} hidden in Models', { count: hiddenCount }) : warnSwitch && provider !== b.provider ? tr('assistant.brain.newConversation', 'starts a new conversation') : '';
|
|
461
|
-
items.push({ kind: 'header', label: meta.label, icon: meta.icon, color: meta.color, note });
|
|
462
|
-
for (const m of models) {
|
|
463
|
-
items.push({
|
|
464
|
-
kind: 'radio',
|
|
465
|
-
id: `${provider}:${m.id}`,
|
|
466
|
-
label: m.label,
|
|
467
|
-
desc: modelDesc(m, tr, opts.routingEditor),
|
|
468
|
-
title: `${m.label || m.id} · ${m.id}`,
|
|
469
|
-
tag: tierTag(m, tr),
|
|
470
|
-
keywords: `${meta.label} ${m.id}`,
|
|
471
|
-
selected: !!current && current.provider === provider && sameModel(current.model, m),
|
|
472
|
-
onSelect: () => onSelect?.({ provider, model: m.id, label: m.label, tier: m.tier || null, vision: m.vision ?? null, outputs: m.outputs || null, efforts: m.efforts || null, price: m.price || null }),
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
if (opts.routingEditor && !models.length) items.push({ kind: 'info', label: typeof accept === 'function' ? tr('assistant.routes.menu.noCompatible', 'No compatible models shown for this provider.') : tr('assistant.routes.menu.providerEmpty', 'No models shown for this provider.') });
|
|
476
|
-
}
|
|
477
|
-
// Nothing passes the filter (e.g. no model makes video yet): say so instead of an empty list.
|
|
478
|
-
if (!listed && typeof accept === 'function' && emptyLabel) items.push({ kind: 'info', label: emptyLabel });
|
|
479
|
-
if (opts.routingEditor && !listed && typeof accept !== 'function') items.push({ kind: 'info', label: tr('assistant.routes.editorState.modelsEmpty', 'No models are available. Check Models or connect a provider, then reload.') });
|
|
480
|
-
if (allowCustom) {
|
|
481
|
-
items.push({ kind: 'separator' });
|
|
482
|
-
items.push({
|
|
483
|
-
kind: 'input',
|
|
484
|
-
placeholder: tr('assistant.brain.modelCustom', 'Custom model id…'),
|
|
485
|
-
onSubmit: (v) => {
|
|
486
|
-
const provider = current?.provider || b.provider;
|
|
487
|
-
const disabled = hiddenModelFor(provider, v);
|
|
488
|
-
if (disabled) {
|
|
489
|
-
onToast?.(tr('assistant.brain.modelDisabled', "{model} is disabled in the Assistant's Models list.", { model: disabled }));
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
onSelect?.({ provider, model: v, label: modelShortName(v), custom: true });
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
if (!opts.routingEditor && typeof opts.onManageModels === 'function') {
|
|
497
|
-
items.push({ id: '__manage_models', label: tr('assistant.models.manage', 'Manage models…'), onSelect: () => opts.onManageModels() });
|
|
494
|
+
let loading = null;
|
|
495
|
+
if (kept) {
|
|
496
|
+
catalog = kept;
|
|
497
|
+
} else {
|
|
498
|
+
anchor.setAttribute('aria-busy', 'true');
|
|
499
|
+
// Open immediately: a slow provider still has a visible, cancellable state.
|
|
500
|
+
loading = opts.routingEditor ? openMenu(anchor, {
|
|
501
|
+
title, className: 'asst-model-menu asst-route-model-menu',
|
|
502
|
+
items: [{ kind: 'info', label: tr('assistant.routes.editorState.loadingModels', 'Loading models…') }],
|
|
503
|
+
width: 380, zIndex: opts.zIndex ?? null, repositionOnResize: true,
|
|
504
|
+
}) : null;
|
|
505
|
+
if (loading) loading.el.setAttribute('aria-busy', 'true');
|
|
506
|
+
if (loading) { loading.el.setAttribute('role', 'dialog'); anchor.setAttribute('aria-haspopup', 'dialog'); }
|
|
507
|
+
try { catalog = await loadModelCatalog({ force: opts.forceReload === true }); } catch { failed = true; } finally { anchor.removeAttribute('aria-busy'); }
|
|
508
|
+
if (!anchor.isConnected || (loading && currentMenu() !== loading.el)) return null;
|
|
498
509
|
}
|
|
510
|
+
const items = buildModelMenuItems(catalog);
|
|
499
511
|
const menu = openMenu(anchor, {
|
|
500
512
|
title: title || tr('assistant.brain.model', 'Model'),
|
|
501
513
|
items,
|
|
@@ -509,7 +521,79 @@ export async function openModelMenu(anchor, opts = {}) {
|
|
|
509
521
|
repositionOnResize: true,
|
|
510
522
|
filterEmptyLabel: tr('assistant.routes.menu.noMatches', 'No matching models. Check Models for hidden choices.'),
|
|
511
523
|
});
|
|
512
|
-
if (opts.routingEditor && menu)
|
|
524
|
+
if (opts.routingEditor && menu) decorateRouteMenu(menu, failed);
|
|
525
|
+
// Painted from the kept catalog: read it again (fresh within its minute, else a background request) and
|
|
526
|
+
// redraw the open menu in place when the lists changed, leaving the filter, the scroll and the focus alone.
|
|
527
|
+
if (kept && menu && !opts.routingEditor) {
|
|
528
|
+
loadModelCatalog().then((next) => {
|
|
529
|
+
if (!next || next === kept || currentMenu() !== menu.el || !anchor.isConnected) return;
|
|
530
|
+
const nextItems = buildModelMenuItems(next);
|
|
531
|
+
if (menuItemsSignature(nextItems) !== menuItemsSignature(items)) menu.update({ items: nextItems, keepPlace: true });
|
|
532
|
+
}).catch(() => { /* the kept list stays */ });
|
|
533
|
+
}
|
|
534
|
+
return menu;
|
|
535
|
+
|
|
536
|
+
function buildModelMenuItems(catalog) {
|
|
537
|
+
const metadata = modelCatalogStatus();
|
|
538
|
+
const items = [];
|
|
539
|
+
if (Array.isArray(opts.accountItems) && opts.accountItems.length) {
|
|
540
|
+
items.push({ kind: 'header', label: opts.accountTitle || tr('assistant.brain.account', 'Account profile') }, ...opts.accountItems, { kind: 'separator' });
|
|
541
|
+
}
|
|
542
|
+
if (includeHere) {
|
|
543
|
+
items.push({ kind: 'radio', id: '__here', label: hereLabel || tr('assistant.routes.brainDecides', 'Let the brain decide'), selected: !current, onSelect: () => onSelect?.({ here: true }) });
|
|
544
|
+
}
|
|
545
|
+
const list = Array.isArray(providers) && providers.length ? PROVIDERS.filter(p => providers.includes(p)) : PROVIDERS;
|
|
546
|
+
let listed = 0;
|
|
547
|
+
for (const provider of list) {
|
|
548
|
+
const models = (catalog[provider] || []).filter(m => typeof accept !== 'function' || accept(provider, m));
|
|
549
|
+
if (!models.length && !opts.routingEditor) continue;
|
|
550
|
+
listed += models.length;
|
|
551
|
+
const meta = getProviderMeta(provider);
|
|
552
|
+
const hiddenCount = metadata.hiddenCounts[provider] || 0;
|
|
553
|
+
const note = opts.routingEditor ? tr('assistant.routes.menu.hiddenCount', '{count} hidden in Models', { count: hiddenCount }) : warnSwitch && provider !== b.provider ? tr('assistant.brain.newConversation', 'starts a new conversation') : '';
|
|
554
|
+
items.push({ kind: 'header', label: meta.label, icon: meta.icon, color: meta.color, note });
|
|
555
|
+
for (const m of models) {
|
|
556
|
+
items.push({
|
|
557
|
+
kind: 'radio',
|
|
558
|
+
id: `${provider}:${m.id}`,
|
|
559
|
+
label: m.label,
|
|
560
|
+
desc: modelDesc(m, tr, opts.routingEditor),
|
|
561
|
+
title: `${m.label || m.id} · ${m.id}`,
|
|
562
|
+
tag: tierTag(m, tr),
|
|
563
|
+
keywords: `${meta.label} ${m.id}`,
|
|
564
|
+
selected: !!current && current.provider === provider && sameModel(current.model, m),
|
|
565
|
+
onSelect: () => onSelect?.({ provider, model: m.id, label: m.label, tier: m.tier || null, vision: m.vision ?? null, outputs: m.outputs || null, efforts: m.efforts || null, price: m.price || null }),
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
if (opts.routingEditor && !models.length) items.push({ kind: 'info', label: typeof accept === 'function' ? tr('assistant.routes.menu.noCompatible', 'No compatible models shown for this provider.') : tr('assistant.routes.menu.providerEmpty', 'No models shown for this provider.') });
|
|
569
|
+
}
|
|
570
|
+
// Nothing passes the filter (e.g. no model makes video yet): say so instead of an empty list.
|
|
571
|
+
if (!listed && typeof accept === 'function' && emptyLabel) items.push({ kind: 'info', label: emptyLabel });
|
|
572
|
+
if (opts.routingEditor && !listed && typeof accept !== 'function') items.push({ kind: 'info', label: tr('assistant.routes.editorState.modelsEmpty', 'No models are available. Check Models or connect a provider, then reload.') });
|
|
573
|
+
if (allowCustom) {
|
|
574
|
+
items.push({ kind: 'separator' });
|
|
575
|
+
items.push({
|
|
576
|
+
kind: 'input',
|
|
577
|
+
placeholder: tr('assistant.brain.modelCustom', 'Custom model id…'),
|
|
578
|
+
onSubmit: (v) => {
|
|
579
|
+
const provider = current?.provider || b.provider;
|
|
580
|
+
const disabled = hiddenModelFor(provider, v);
|
|
581
|
+
if (disabled) {
|
|
582
|
+
onToast?.(tr('assistant.brain.modelDisabled', "{model} is disabled in the Assistant's Models list.", { model: disabled }));
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
onSelect?.({ provider, model: v, label: modelShortName(v), custom: true });
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
if (!opts.routingEditor && typeof opts.onManageModels === 'function') {
|
|
590
|
+
items.push({ id: '__manage_models', label: tr('assistant.models.manage', 'Manage models…'), onSelect: () => opts.onManageModels() });
|
|
591
|
+
}
|
|
592
|
+
return items;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function decorateRouteMenu(menu, failed) {
|
|
596
|
+
const metadata = modelCatalogStatus();
|
|
513
597
|
// Search and a custom-id input belong to a dialog; choices are a radio group.
|
|
514
598
|
// A menu role cannot contain these form fields or recovery buttons.
|
|
515
599
|
menu.el.setAttribute('role', 'dialog');
|
|
@@ -539,7 +623,11 @@ export async function openModelMenu(anchor, opts = {}) {
|
|
|
539
623
|
}
|
|
540
624
|
menu.el.append(footer); menu.reposition();
|
|
541
625
|
}
|
|
542
|
-
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** What a model menu lists, for telling a fresher read from the one on screen. */
|
|
629
|
+
function menuItemsSignature(items) {
|
|
630
|
+
return JSON.stringify((items || []).map((item) => [item.kind || '', item.id ?? '', item.label || '', item.desc || '', item.tag || '', item.note || '', !!item.selected]));
|
|
543
631
|
}
|
|
544
632
|
|
|
545
633
|
// ── Picker ──────────────────────────────────────────────────────────────────
|
|
@@ -642,11 +730,39 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
642
730
|
return name;
|
|
643
731
|
}
|
|
644
732
|
|
|
733
|
+
// The "⋯" item's value, in the account menu's words: the name and its plan, "API key" or "Signed out" ("Default · Max").
|
|
734
|
+
function accountValue(brain) {
|
|
735
|
+
const acc = accountOf(brain);
|
|
736
|
+
if (!acc) return brain.accountId === 'auto' ? autoAccountLabel(hooks.t) : (brain.accountId || t('assistant.brain.accountDefault', 'Default'));
|
|
737
|
+
const row = accountMenuRow(acc, { provider: accountProvider(brain), t: hooks.t });
|
|
738
|
+
return [row.name, row.badge.text].filter(Boolean).join(' · ');
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// The model menu's own row first: it also names the "[1m]" / "[extended]" variants the provider list lacks.
|
|
742
|
+
function modelRow(brain) {
|
|
743
|
+
return catalogModelRow(brain.provider, brain.model) || modelOf(brain);
|
|
744
|
+
}
|
|
745
|
+
|
|
645
746
|
function modelLabel(brain = currentBrain()) {
|
|
646
|
-
const model =
|
|
747
|
+
const model = modelRow(brain);
|
|
647
748
|
return model ? (model.label || modelShortName(model.id)) : (brain.model ? modelShortName(brain.model) : t('assistant.brain.modelDefault', 'Default model'));
|
|
648
749
|
}
|
|
649
750
|
|
|
751
|
+
// The composer chip's account cue: the account menu's initial avatar when the provider has more than one
|
|
752
|
+
// account (or the account is signed out), "Auto" for Auto; null otherwise. Its full words are the tooltip's.
|
|
753
|
+
function accountCue(brain) {
|
|
754
|
+
if (!ACCOUNT_PROVIDERS.has(brain.provider)) return null;
|
|
755
|
+
if (brain.accountId === 'auto') return { text: t('assistant.brain.accountAutoShort', 'Auto'), tone: 'muted' };
|
|
756
|
+
const accounts = brain.provider === 'codex' ? getCachedCodexAccounts() : getCachedClaudeAccounts();
|
|
757
|
+
const acc = accountOf(brain);
|
|
758
|
+
const signedOut = acc?.signedIn === false;
|
|
759
|
+
if (accounts.length < 2 && !signedOut) return null;
|
|
760
|
+
const initial = acc
|
|
761
|
+
? accountMenuRow(acc, { provider: accountProvider(brain), t: hooks.t }).initial
|
|
762
|
+
: Array.from(String(brain.accountId || t('assistant.brain.accountDefault', 'Default')).trim())[0]?.toLocaleUpperCase();
|
|
763
|
+
return { text: initial || '?', tone: signedOut ? 'warn' : 'muted' };
|
|
764
|
+
}
|
|
765
|
+
|
|
650
766
|
function values(brain = currentBrain()) {
|
|
651
767
|
const meta = getProviderMeta(brain.provider);
|
|
652
768
|
const efforts = effortsFor(brain);
|
|
@@ -669,6 +785,26 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
669
785
|
};
|
|
670
786
|
}
|
|
671
787
|
|
|
788
|
+
/**
|
|
789
|
+
* The permission menu's Admin sandbox row (a check: the global setting, every agent SynaBun starts),
|
|
790
|
+
* or null while the host has none to show (a server that does not serve it). Its tooltip and
|
|
791
|
+
* aria-label say the value in effect.
|
|
792
|
+
*/
|
|
793
|
+
function adminSandboxItem() {
|
|
794
|
+
const on = typeof hooks.getAdminSandbox === 'function' ? hooks.getAdminSandbox() : null;
|
|
795
|
+
if (typeof on !== 'boolean') return null;
|
|
796
|
+
const label = t('assistant.adminSandbox.label', 'Admin sandbox');
|
|
797
|
+
const value = on ? t('assistant.adminSandbox.on', 'On') : t('assistant.adminSandbox.off', 'Off');
|
|
798
|
+
const hint = t('assistant.adminSandbox.hint', ADMIN_SANDBOX_HINT);
|
|
799
|
+
return {
|
|
800
|
+
kind: 'check', id: 'admin-sandbox', label, desc: hint, checked: on,
|
|
801
|
+
className: 'asst-admin-sandbox-item',
|
|
802
|
+
title: `${label}: ${value}. ${hint}`,
|
|
803
|
+
ariaLabel: t('assistant.adminSandbox.aria', '{label}: {value}. Only changes anything when SynaBun runs on Windows.', { label, value }),
|
|
804
|
+
onSelect: () => hooks.onAdminSandbox?.(!on),
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
|
|
672
808
|
/** The session's Test density, or null while the host has none to show (a server that does not know it). */
|
|
673
809
|
function testDensity() {
|
|
674
810
|
const level = typeof hooks.getTestDensity === 'function' ? hooks.getTestDensity() : null;
|
|
@@ -689,21 +825,117 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
689
825
|
btn.setAttribute('aria-label', aria || tooltip || label || field);
|
|
690
826
|
}
|
|
691
827
|
|
|
828
|
+
// The composer's model chip (asst-model-chip.js): the model's short name, a context tag for a variant,
|
|
829
|
+
// the account cue and "API" on an API key, never the credential's name (the provider icon says it).
|
|
830
|
+
// Model label, id, account, who it is and what it runs on are the tooltip and aria-label.
|
|
831
|
+
// fitModelChip() draws the longest form that fits the row.
|
|
832
|
+
let chipForms = [];
|
|
833
|
+
let chipParts = null;
|
|
834
|
+
let chipCatalog = null;
|
|
835
|
+
function renderModelChip(brain, v) {
|
|
836
|
+
const btn = buttons.model;
|
|
837
|
+
// The catalog was dropped (a model hidden, a provider's list changed): read it again, then the label.
|
|
838
|
+
if (!cachedModelCatalog() && !chipCatalog) {
|
|
839
|
+
chipCatalog = loadModelCatalog().catch(() => null).then(() => {
|
|
840
|
+
chipCatalog = null;
|
|
841
|
+
if (!destroyed && cachedModelCatalog()) render();
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
const row = modelRow(brain);
|
|
845
|
+
const id = brain.model || row?.id || '';
|
|
846
|
+
const { name, raw } = id ? modelChipName(row?.label, id) : { name: v.model, raw: false };
|
|
847
|
+
const tag = modelChipTag(id, { contextWindow: row?.contextWindow, label: row?.label });
|
|
848
|
+
const cue = accountCue(brain);
|
|
849
|
+
const p = accountProvider(brain);
|
|
850
|
+
const acc = ACCOUNT_PROVIDERS.has(brain.provider) ? accountOf(brain) : null;
|
|
851
|
+
const api = acc && acc.signedIn !== false && acc.mode === 'apiKey' ? accountText('apiShort', {}, p) : '';
|
|
852
|
+
const names = (cachedModelCatalog()?.[brain.provider] || []).map(m => modelChipName(m.label, m.id).name);
|
|
853
|
+
chipForms = modelChipForms({ name, names, tag: !!tag, cue: !!cue, api: !!api });
|
|
854
|
+
|
|
855
|
+
const who = !ACCOUNT_PROVIDERS.has(brain.provider) ? ''
|
|
856
|
+
: brain.accountId === 'auto' ? autoAccountLabel(hooks.t)
|
|
857
|
+
: acc ? accountName(acc, p) : (brain.accountId || t('assistant.brain.accountDefault', 'Default'));
|
|
858
|
+
const model = brain.model && v.model !== brain.model ? `${v.model} · ${brain.model}` : (brain.model || v.model);
|
|
859
|
+
const tip = [
|
|
860
|
+
v.meta.label, model, who ? t('assistant.brain.asAccount', 'as {account}', { account: who }) : '',
|
|
861
|
+
acc ? accountIdentity(acc) : '', acc ? accountBadge(acc, p).text : '',
|
|
862
|
+
].filter(Boolean).join(' · ');
|
|
863
|
+
setBtn('model', { label: '', icon: v.meta.icon, color: v.meta.color, tooltip: tip, aria: `${t('assistant.brain.model', 'Model')}: ${tip}` });
|
|
864
|
+
|
|
865
|
+
const label = btn.querySelector('.asst-dd-label');
|
|
866
|
+
label.classList.add('asst-model-label');
|
|
867
|
+
chipParts = {
|
|
868
|
+
name: el('span', 'asst-model-name', name),
|
|
869
|
+
tag: el('span', 'asst-model-tag', tag),
|
|
870
|
+
cue: el('span', 'asst-acct-avatar asst-model-cue', cue?.text || ''),
|
|
871
|
+
api: el('span', 'asst-acct-badge asst-model-api', api),
|
|
872
|
+
};
|
|
873
|
+
if (cue) chipParts.cue.dataset.tone = cue.tone;
|
|
874
|
+
label.replaceChildren(chipParts.name, chipParts.tag, chipParts.cue, chipParts.api);
|
|
875
|
+
// A display name ("Sonnet 5") reads in sans; a raw id nothing names ("opus") stays mono.
|
|
876
|
+
btn.toggleAttribute('data-raw', raw);
|
|
877
|
+
fitModelChip();
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
function drawChipForm(form) {
|
|
881
|
+
chipParts.name.textContent = form.name;
|
|
882
|
+
chipParts.tag.hidden = !form.tag;
|
|
883
|
+
chipParts.cue.hidden = !form.cue;
|
|
884
|
+
chipParts.api.hidden = !form.api;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// The first form, longest first, that leaves the row as the shortest one does: no part cut, no other
|
|
888
|
+
// field narrower, the row no taller (it wraps below 320px). None does: the shortest, its name squeezed.
|
|
889
|
+
function fitModelChip() {
|
|
890
|
+
const btn = buttons.model;
|
|
891
|
+
if (destroyed || !btn || !chipParts || !chipForms.length) return;
|
|
892
|
+
btn.removeAttribute('data-squeezed');
|
|
893
|
+
const label = btn.querySelector('.asst-dd-label');
|
|
894
|
+
const slot = btn.parentElement;
|
|
895
|
+
// Nothing to measure (not on screen, no layout): the whole chip, until the row has a width.
|
|
896
|
+
if (chipForms.length === 1 || !isRendered(btn) || !slot || typeof label?.getBoundingClientRect !== 'function') { drawChipForm(chipForms[0]); return; }
|
|
897
|
+
const row = slot.parentElement || null;
|
|
898
|
+
const others = [...slot.querySelectorAll('.asst-dd-label')].filter(n => n !== label && n.getClientRects().length > 0);
|
|
899
|
+
const width = n => n.getBoundingClientRect().width;
|
|
900
|
+
const cut = () => {
|
|
901
|
+
const right = label.getBoundingClientRect().right + 0.5;
|
|
902
|
+
return Object.values(chipParts).some(n => !n.hidden && n.getBoundingClientRect().right > right);
|
|
903
|
+
};
|
|
904
|
+
const shortest = chipForms[chipForms.length - 1];
|
|
905
|
+
drawChipForm(shortest);
|
|
906
|
+
const base = { height: row?.offsetHeight || 0, widths: others.map(width) };
|
|
907
|
+
const fits = () => !cut()
|
|
908
|
+
&& (row?.offsetHeight || 0) <= base.height + 0.5
|
|
909
|
+
&& others.every((n, i) => width(n) >= base.widths[i] - 0.5)
|
|
910
|
+
&& !(slot.scrollWidth > slot.clientWidth + 1);
|
|
911
|
+
for (const form of chipForms.slice(0, -1)) {
|
|
912
|
+
drawChipForm(form);
|
|
913
|
+
if (fits()) return;
|
|
914
|
+
}
|
|
915
|
+
drawChipForm(shortest);
|
|
916
|
+
btn.toggleAttribute('data-squeezed', cut());
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// The row's width decides the form (a panel resized, a tab shown, the fields that collapse to glyphs).
|
|
920
|
+
const fitHost = buttons.model.parentElement?.parentElement || buttons.model.parentElement;
|
|
921
|
+
let fitFrame = 0;
|
|
922
|
+
let fitWidth = -1;
|
|
923
|
+
const scheduleFit = () => {
|
|
924
|
+
if (fitFrame || destroyed || typeof requestAnimationFrame !== 'function') return;
|
|
925
|
+
fitFrame = requestAnimationFrame(() => { fitFrame = 0; fitModelChip(); });
|
|
926
|
+
};
|
|
927
|
+
const fitObserver = typeof ResizeObserver === 'function' && fitHost ? new ResizeObserver((entries) => {
|
|
928
|
+
const w = Math.round(entries[entries.length - 1]?.contentRect?.width || 0);
|
|
929
|
+
if (w !== fitWidth) { fitWidth = w; scheduleFit(); }
|
|
930
|
+
}) : null;
|
|
931
|
+
fitObserver?.observe(fitHost);
|
|
932
|
+
if (typeof document !== 'undefined') document.fonts?.ready?.then(scheduleFit).catch(() => {});
|
|
933
|
+
|
|
692
934
|
function render() {
|
|
693
935
|
if (destroyed) return;
|
|
694
936
|
const brain = currentBrain();
|
|
695
937
|
const v = values(brain);
|
|
696
|
-
|
|
697
|
-
setBtn('model', { label: v.model, icon: v.meta.icon, color: v.meta.color, tooltip: modelTip, aria: `${t('assistant.brain.model', 'Model')}: ${modelTip}` });
|
|
698
|
-
if (ACCOUNT_PROVIDERS.has(brain.provider)) {
|
|
699
|
-
const acc = accountOf(brain);
|
|
700
|
-
const label = buttons.model.querySelector('.asst-dd-label');
|
|
701
|
-
label.classList.add('asst-model-account-label');
|
|
702
|
-
const mode = acc ? accountCompactMode(acc, accountProvider(brain)) : t('accounts.checking', 'Checking…');
|
|
703
|
-
label.replaceChildren(el('span', 'asst-model-name', v.model), el('span', '', '·'), el('span', 'asst-model-account', acc ? accountName(acc, accountProvider(brain)) : brain.accountId || t('assistant.brain.accountDefault', 'Default')), el('span', '', '·'), el('span', 'asst-model-mode', mode));
|
|
704
|
-
} else buttons.model.querySelector('.asst-dd-label').classList.remove('asst-model-account-label');
|
|
705
|
-
// A display name ("Sonnet 5") reads in sans; a raw id nothing names ("opus[1m]") stays mono.
|
|
706
|
-
buttons.model?.toggleAttribute('data-raw', /^[a-z0-9][\w.\-[\]:/]*$/.test(String(v.model || '')));
|
|
938
|
+
renderModelChip(brain, v);
|
|
707
939
|
|
|
708
940
|
if (brain.provider === 'opencode') {
|
|
709
941
|
setBtn('effort', { label: v.effort, icon: ICON_AGENT, tooltip: `${t('assistant.brain.agent', 'OpenCode agent')}: ${v.effort}` });
|
|
@@ -791,7 +1023,7 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
791
1023
|
{ field: 'mode', label: t('assistant.brain.mode', 'Permission mode'), value: v.mode, icon: ICON_SHIELD, hidden: false },
|
|
792
1024
|
{ field: 'tests', label: t('assistant.tests.title', 'Test density'), value: testDensity() ? testDensityLabel(testDensity(), hooks.t) : '', icon: testsIcon(testDensityBars(testDensity())), hidden: !testDensity() },
|
|
793
1025
|
{ field: 'mcp', label: t('assistant.brain.mcp', 'MCP tool profile'), value: v.mcp, icon: ICON_PLUG, hidden: false },
|
|
794
|
-
{ field: 'account', label: t('assistant.brain.
|
|
1026
|
+
{ field: 'account', label: t('assistant.brain.accountShort', 'Account'), value: accountValue(brain), icon: ICON_ACCOUNT, hidden: !ACCOUNT_PROVIDERS.has(brain.provider) },
|
|
795
1027
|
];
|
|
796
1028
|
}
|
|
797
1029
|
|
|
@@ -817,6 +1049,7 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
817
1049
|
}).catch(() => { _projectsCache = _projectsCache || []; }));
|
|
818
1050
|
}
|
|
819
1051
|
await Promise.allSettled(jobs);
|
|
1052
|
+
if (cachedModelCatalog()) _warmProviders.add(provider);
|
|
820
1053
|
}
|
|
821
1054
|
|
|
822
1055
|
async function refresh(force = false) {
|
|
@@ -848,14 +1081,19 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
848
1081
|
const anchor = anchorFor(field, anchorOverride);
|
|
849
1082
|
const brain = currentBrain();
|
|
850
1083
|
if (field === 'model') {
|
|
851
|
-
|
|
1084
|
+
// The account rows come from the kept lists; they are read again in the background once loaded.
|
|
1085
|
+
if (ACCOUNT_PROVIDERS.has(brain.provider)) {
|
|
1086
|
+
if (_warmProviders.has(brain.provider)) ensureLoaded(brain.provider).catch(() => {});
|
|
1087
|
+
else await ensureLoaded(brain.provider);
|
|
1088
|
+
}
|
|
852
1089
|
await openModelMenu(anchor, {
|
|
853
1090
|
brain,
|
|
854
1091
|
t: hooks.t,
|
|
855
1092
|
placement,
|
|
856
1093
|
current: { provider: brain.provider, model: brain.model },
|
|
857
1094
|
warnSwitch: true,
|
|
858
|
-
accountItems: ACCOUNT_PROVIDERS.has(brain.provider) ? accountItems(brain
|
|
1095
|
+
accountItems: ACCOUNT_PROVIDERS.has(brain.provider) ? accountItems(brain) : [],
|
|
1096
|
+
accountTitle: accountText('menuTitle', {}, accountProvider(brain)),
|
|
859
1097
|
onToast: hooks.onToast,
|
|
860
1098
|
onManageModels: hooks.onManageModels,
|
|
861
1099
|
onSelect: (target) => {
|
|
@@ -882,12 +1120,48 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
882
1120
|
});
|
|
883
1121
|
return;
|
|
884
1122
|
}
|
|
885
|
-
//
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1123
|
+
// The account menu reads the kept rows and asks again by itself (asst-account-menu.js).
|
|
1124
|
+
if (field === 'account') {
|
|
1125
|
+
if (!ACCOUNT_PROVIDERS.has(brain.provider)) return;
|
|
1126
|
+
if (!_warmProviders.has(brain.provider)) {
|
|
1127
|
+
anchor.setAttribute('aria-busy', 'true');
|
|
1128
|
+
try { await ensureLoaded(brain.provider); } finally { anchor.removeAttribute('aria-busy'); }
|
|
1129
|
+
if (destroyed || !anchor.isConnected) return;
|
|
1130
|
+
} else {
|
|
1131
|
+
ensureLoaded(brain.provider).catch(() => {});
|
|
1132
|
+
}
|
|
1133
|
+
// Kept inside the panel that holds the anchor (the sidepanel, or the tab's own root).
|
|
1134
|
+
openAccountMenu(anchor, accountMenu(brain, anchor.closest?.('.assistant-panel') || anchor.closest?.('.asst-root') || null));
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
// Everything else needs the provider catalog — load it lazily on first open. Once it is loaded the menu
|
|
1138
|
+
// opens from what is kept, the lists are read again in the background, and an open menu they change is
|
|
1139
|
+
// redrawn in place (the filter, the scroll and the focus stay).
|
|
1140
|
+
const warm = _warmProviders.has(brain.provider);
|
|
1141
|
+
if (!warm) {
|
|
1142
|
+
anchor.setAttribute('aria-busy', 'true');
|
|
1143
|
+
try { await ensureLoaded(brain.provider); } finally { anchor.removeAttribute('aria-busy'); }
|
|
1144
|
+
if (destroyed || !anchor.isConnected) return;
|
|
1145
|
+
}
|
|
1146
|
+
let shown = null;
|
|
1147
|
+
drawField(field, brain, (title, items, extra = {}) => {
|
|
1148
|
+
const opened = openMenu(anchor, { title, items, placement, role: 'menu', ...extra });
|
|
1149
|
+
shown = opened ? { opened, items } : null;
|
|
1150
|
+
return opened;
|
|
1151
|
+
}, { anchor, restoreFocus });
|
|
1152
|
+
if (warm && shown) {
|
|
1153
|
+
ensureLoaded(brain.provider).then(() => {
|
|
1154
|
+
if (destroyed || !shown || currentMenu() !== shown.opened.el || !anchor.isConnected) return;
|
|
1155
|
+
let fresh = null;
|
|
1156
|
+
drawField(field, currentBrain(), (_title, items) => { fresh = items; return null; }, { anchor, restoreFocus });
|
|
1157
|
+
if (fresh && menuItemsSignature(fresh) !== menuItemsSignature(shown.items)) shown.opened.update({ items: fresh, keepPlace: true });
|
|
1158
|
+
}).catch(() => {});
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
890
1161
|
|
|
1162
|
+
// The menu of one field, from the lists as they are kept now: `menu(title, items, extra)` opens it (or, for a
|
|
1163
|
+
// redraw, only takes the items).
|
|
1164
|
+
function drawField(field, brain, menu, { anchor, restoreFocus = false } = {}) {
|
|
891
1165
|
if (field === 'effort') {
|
|
892
1166
|
if (brain.provider === 'opencode') {
|
|
893
1167
|
const agents = getCachedOpencodeAgents();
|
|
@@ -918,12 +1192,6 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
918
1192
|
return;
|
|
919
1193
|
}
|
|
920
1194
|
|
|
921
|
-
if (field === 'account') {
|
|
922
|
-
if (!ACCOUNT_PROVIDERS.has(brain.provider)) return;
|
|
923
|
-
menu(t('assistant.brain.account', 'Account profile'), accountItems(brain), { width: 300 });
|
|
924
|
-
return;
|
|
925
|
-
}
|
|
926
|
-
|
|
927
1195
|
if (field === 'project') {
|
|
928
1196
|
const actor = anchor === heroProject ? heroProjectMascot : null;
|
|
929
1197
|
const pick = project => {
|
|
@@ -975,70 +1243,74 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
975
1243
|
onSelect: () => commit({ permissionMode: m.id }, 'mode'),
|
|
976
1244
|
});
|
|
977
1245
|
}
|
|
1246
|
+
// The global Admin sandbox switch (every agent SynaBun starts, not this conversation), under its own header.
|
|
1247
|
+
const adminSandbox = adminSandboxItem();
|
|
1248
|
+
if (adminSandbox) items.push({ kind: 'separator' }, { kind: 'header', label: t('assistant.adminSandbox.group', 'Every agent') }, adminSandbox);
|
|
978
1249
|
menu(t('assistant.brain.mode', 'Permission mode'), items);
|
|
979
1250
|
}
|
|
980
1251
|
}
|
|
981
1252
|
|
|
982
|
-
// The
|
|
983
|
-
//
|
|
984
|
-
|
|
985
|
-
|
|
1253
|
+
// The cog's account menu (asst-account-menu.js): every account once, the conversation's and the
|
|
1254
|
+
// workers' choice, kept inside `bounds`. What each choice does is the same as the composer's.
|
|
1255
|
+
function accountMenu(brain, bounds) {
|
|
1256
|
+
const codex = brain.provider === 'codex';
|
|
1257
|
+
const refetch = () => (codex ? fetchCodexAccounts(true) : fetchClaudeAccounts(true));
|
|
1258
|
+
return {
|
|
1259
|
+
provider: codex ? 'codex' : 'claude',
|
|
1260
|
+
t: hooks.t,
|
|
1261
|
+
placement,
|
|
1262
|
+
bounds,
|
|
1263
|
+
read: () => ({
|
|
1264
|
+
accounts: codex ? getCachedCodexAccounts() : getCachedClaudeAccounts(),
|
|
1265
|
+
currentId: currentBrain().accountId,
|
|
1266
|
+
workerId: codex ? getCodexWorkerAccountId() : getClaudeWorkerAccountId(),
|
|
1267
|
+
running: hooks.getRunning?.() === true,
|
|
1268
|
+
}),
|
|
1269
|
+
onAuto: () => commit({ accountId: 'auto' }, 'account'),
|
|
1270
|
+
onPick: (id) => commit({ accountId: id }, 'account'),
|
|
1271
|
+
onSetWorker: async (id) => { await (codex ? setCodexWorkerAccount : setClaudeWorkerAccount)(id); await refetch(); render(); },
|
|
1272
|
+
onSetMode: async (id, mode) => {
|
|
1273
|
+
const before = currentBrain();
|
|
1274
|
+
try {
|
|
1275
|
+
await (codex ? patchCodexAccount : patchClaudeAccount)(id, { mode }); await refetch();
|
|
1276
|
+
hooks.onChange?.(currentBrain(), { requiresSwitch: true, restartBrain: true, field: 'accountMode', previous: before }); render();
|
|
1277
|
+
}
|
|
1278
|
+
catch (err) { hooks.onToast?.(err?.message || String(err)); }
|
|
1279
|
+
},
|
|
1280
|
+
onAdd: () => hooks.onAddAccount?.(brain.provider),
|
|
1281
|
+
onManage: (id) => (id ? hooks.onManageAccounts?.(brain.provider, id) : hooks.onManageAccounts?.(brain.provider)),
|
|
1282
|
+
onError: (err) => hooks.onToast?.(err?.message || String(err)),
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// The composer's Model menu lists the brain's accounts too (Claude or Codex), as the cog's account menu
|
|
1287
|
+
// does (asst-account-menu.js): Auto, every account once (a signed-out one opens its sign-in), the Uses
|
|
1288
|
+
// switch of an account holding both credentials, Add account… and Manage….
|
|
1289
|
+
function accountItems(brain) {
|
|
986
1290
|
const codex = brain.provider === 'codex';
|
|
987
1291
|
const p = codex ? 'codex' : 'claude';
|
|
988
1292
|
const accounts = codex ? getCachedCodexAccounts() : getCachedClaudeAccounts();
|
|
989
1293
|
const refetch = () => (codex ? fetchCodexAccounts(true) : fetchClaudeAccounts(true));
|
|
990
|
-
const items =
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
selected: a.id === brain.accountId,
|
|
998
|
-
onSelect: () => commit({ accountId: a.id }, 'account'),
|
|
999
|
-
};
|
|
1294
|
+
const items = accountChoiceItems({
|
|
1295
|
+
t: hooks.t,
|
|
1296
|
+
rows: accounts.map((a) => accountMenuRow(a, { provider: p, t: hooks.t })),
|
|
1297
|
+
currentId: brain.accountId,
|
|
1298
|
+
onAuto: () => commit({ accountId: 'auto' }, 'account'),
|
|
1299
|
+
onPick: (id) => commit({ accountId: id }, 'account'),
|
|
1300
|
+
onSignIn: (id) => hooks.onManageAccounts?.(brain.provider, id),
|
|
1000
1301
|
});
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
try {
|
|
1014
|
-
await (codex ? patchCodexAccount : patchClaudeAccount)(current.id, { mode: m.mode }); await refetch();
|
|
1015
|
-
hooks.onChange?.(currentBrain(), { requiresSwitch: true, restartBrain: true, field: 'accountMode', previous: brain }); render();
|
|
1016
|
-
}
|
|
1017
|
-
catch (err) { hooks.onToast?.(err?.message || String(err)); }
|
|
1018
|
-
},
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
const worker = codex ? getCodexWorkerAccountId() : getClaudeWorkerAccountId();
|
|
1023
|
-
if (!composer) {
|
|
1024
|
-
items.push({ kind: 'separator' });
|
|
1025
|
-
items.push({ kind: 'header', label: codex ? t('assistant.accounts.codexWorkersHeader', 'Codex workers use') : t('assistant.accounts.workersHeader', 'Claude Code workers use') });
|
|
1026
|
-
for (const a of accounts) {
|
|
1027
|
-
const usable = accountUsable(a);
|
|
1028
|
-
items.push({
|
|
1029
|
-
kind: 'radio', id: `worker:${a.id}`, label: accountName(a, p), tag: accountBadge(a, p).text,
|
|
1030
|
-
disabled: !usable && a.id !== worker, selected: a.id === worker,
|
|
1031
|
-
onSelect: async () => {
|
|
1032
|
-
if (a.id === worker) return;
|
|
1033
|
-
try { await (codex ? setCodexWorkerAccount : setClaudeWorkerAccount)(a.id); await refetch(); render(); }
|
|
1034
|
-
catch (err) { hooks.onToast?.(err?.message || String(err)); }
|
|
1035
|
-
},
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
items.push({ kind: 'separator' });
|
|
1040
|
-
items.push({ id: '__add', label: t('assistant.accounts.add', 'Add account…'), onSelect: () => hooks.onAddAccount?.(brain.provider) });
|
|
1041
|
-
items.push({ id: '__manage', label: t('assistant.accounts.manage', 'Manage…'), onSelect: () => hooks.onManageAccounts?.(brain.provider) });
|
|
1302
|
+
const uses = accountModeItem({
|
|
1303
|
+
provider: p, t: hooks.t, account: accounts.find((a) => a.id === brain.accountId), running: hooks.getRunning?.() === true,
|
|
1304
|
+
onSetMode: async (id, mode) => {
|
|
1305
|
+
try {
|
|
1306
|
+
await (codex ? patchCodexAccount : patchClaudeAccount)(id, { mode }); await refetch();
|
|
1307
|
+
hooks.onChange?.(currentBrain(), { requiresSwitch: true, restartBrain: true, field: 'accountMode', previous: brain }); render();
|
|
1308
|
+
}
|
|
1309
|
+
catch (err) { hooks.onToast?.(err?.message || String(err)); }
|
|
1310
|
+
},
|
|
1311
|
+
});
|
|
1312
|
+
if (uses) items.push(uses);
|
|
1313
|
+
items.push(accountManageItem({ t: hooks.t, onAdd: () => hooks.onAddAccount?.(brain.provider), onManage: () => hooks.onManageAccounts?.(brain.provider) }));
|
|
1042
1314
|
return items;
|
|
1043
1315
|
}
|
|
1044
1316
|
|
|
@@ -1088,6 +1360,6 @@ export function createBrainPicker(host, hooks = {}) {
|
|
|
1088
1360
|
mountEmptyProject,
|
|
1089
1361
|
setBrain() { render(); },
|
|
1090
1362
|
close: closeMenu,
|
|
1091
|
-
destroy() { destroyed = true; for (const off of offAccounts) { try { off?.(); } catch {} } closeMenu(); heroProjectMascot?.destroy(); Object.values(buttons).forEach((b) => b.remove()); heroProject?.remove(); heroProject = null; root.remove(); },
|
|
1363
|
+
destroy() { destroyed = true; fitObserver?.disconnect(); if (fitFrame && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(fitFrame); for (const off of offAccounts) { try { off?.(); } catch {} } closeMenu(); heroProjectMascot?.destroy(); Object.values(buttons).forEach((b) => b.remove()); heroProject?.remove(); heroProject = null; root.remove(); },
|
|
1092
1364
|
};
|
|
1093
1365
|
}
|