swayrouter 1.0.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/.env.example +43 -0
- package/CHANGELOG.md +132 -0
- package/LICENSE +30 -0
- package/README.id.md +633 -0
- package/README.md +628 -0
- package/cli/cli.js +388 -0
- package/cli/package.json +4 -0
- package/cli/src/cli/commands/xaiVideo.js +280 -0
- package/cli/src/cli/tray/SwayAvatar.svg +20 -0
- package/cli/src/cli/tray/autostart.js +351 -0
- package/cli/src/cli/tray/icon.ico +0 -0
- package/cli/src/cli/tray/icon.png +0 -0
- package/cli/src/cli/tray/tray.js +258 -0
- package/cli/src/cli/tray/tray.ps1 +129 -0
- package/cli/src/cli/tray/trayHost.js +157 -0
- package/cli/src/cli/tray/trayWin.js +83 -0
- package/cli/src/cli/utils/display.js +123 -0
- package/cli/src/cli/utils/input.js +138 -0
- package/cli/src/runtime/discover.js +153 -0
- package/cli/src/runtime/lifecycle.js +333 -0
- package/cli/src/runtime/runMenu.js +250 -0
- package/cli/src/runtime/uiAdapters.js +12 -0
- package/cli/src/runtime/update.js +130 -0
- package/dashboard/dist/assets/CliTools-Ch3gKuNw.js +24 -0
- package/dashboard/dist/assets/Combo-BBCldjWi.js +1 -0
- package/dashboard/dist/assets/ConsoleLog-wywAYcPT.js +6 -0
- package/dashboard/dist/assets/Dashboard-DxzyF41b.js +1 -0
- package/dashboard/dist/assets/Header-C_9Su9BF.js +1 -0
- package/dashboard/dist/assets/Keys-D0ufgcsc.js +1 -0
- package/dashboard/dist/assets/Login-BeKpipS_.js +1 -0
- package/dashboard/dist/assets/ManageApiKey-CVXsmW2B.js +1 -0
- package/dashboard/dist/assets/OAuthCallback-D_UZYcF6.js +1 -0
- package/dashboard/dist/assets/Provider-BU7JfTqm.js +4 -0
- package/dashboard/dist/assets/ProviderModelAccordion-BAifkfVR.js +1 -0
- package/dashboard/dist/assets/Proxy-CU15VJ--.js +1 -0
- package/dashboard/dist/assets/QuotaMonitor-HzGK7bcc.js +1 -0
- package/dashboard/dist/assets/Settings-Dt4y2dC0.js +1 -0
- package/dashboard/dist/assets/Setup-DSDUwU7N.js +1 -0
- package/dashboard/dist/assets/StatusBadge-1nAOyHU2.js +1 -0
- package/dashboard/dist/assets/SwayChat-Bup7up6D.js +10 -0
- package/dashboard/dist/assets/Usage-eWnrPQ_v.js +4 -0
- package/dashboard/dist/assets/accordion-DOOPDDgt.js +1 -0
- package/dashboard/dist/assets/admin-extras-api-CCdu5TFM.js +1 -0
- package/dashboard/dist/assets/api-keys-api-ifAC2Ok3.js +1 -0
- package/dashboard/dist/assets/card-CC0Omjcv.js +1 -0
- package/dashboard/dist/assets/chatStudio-C0zPz_Z_.js +2 -0
- package/dashboard/dist/assets/checkbox-7SZBrmbN.js +1 -0
- package/dashboard/dist/assets/connections-api-_N54UD3S.js +1 -0
- package/dashboard/dist/assets/copy-button-qBvM6H9z.js +1 -0
- package/dashboard/dist/assets/currency-api-SV9CBf5e.js +1 -0
- package/dashboard/dist/assets/flip-button-BGgkjtl0.js +1 -0
- package/dashboard/dist/assets/frame-cUiti6Lq.js +1 -0
- package/dashboard/dist/assets/icons-vendor-CUx7SB5V.js +541 -0
- package/dashboard/dist/assets/index-B6j-9zHy.js +10 -0
- package/dashboard/dist/assets/index-C-_l0yYz.css +1 -0
- package/dashboard/dist/assets/live-mode-CHShLY4E.js +1 -0
- package/dashboard/dist/assets/markdown-vendor-BY8e1gQ8.js +29 -0
- package/dashboard/dist/assets/motion-vendor-g5fpGzmJ.js +9 -0
- package/dashboard/dist/assets/oauth-callback-CqYQzyd7.js +1 -0
- package/dashboard/dist/assets/query-vendor-DVevaSVS.js +1 -0
- package/dashboard/dist/assets/react-vendor-xnYrwzsL.js +61 -0
- package/dashboard/dist/assets/ripple-button-l8aMiVVG.js +1 -0
- package/dashboard/dist/assets/segmented-CqmEnQjZ.js +1 -0
- package/dashboard/dist/assets/select-D8pUtMXp.js +1 -0
- package/dashboard/dist/assets/skeleton-7uJDiIXe.js +1 -0
- package/dashboard/dist/assets/table-D0M60Tu1.js +1 -0
- package/dashboard/dist/assets/tabs-C6YkuulG.js +1 -0
- package/dashboard/dist/assets/tunnel-api-DDPsBaDV.js +1 -0
- package/dashboard/dist/assets/ui-vendor-BuM9f2NY.js +17 -0
- package/dashboard/dist/image2/SwayAvatar.svg +20 -0
- package/dashboard/dist/index.html +32 -0
- package/dashboard/dist/logo/avatar.svg +1 -0
- package/dashboard/dist/logo/sway.svg +20 -0
- package/dashboard/dist/logo/swaychat.svg +20 -0
- package/dashboard/dist/providers/SwayCustom.svg +19 -0
- package/dashboard/dist/providers/alicode.svg +12 -0
- package/dashboard/dist/providers/anthropic.svg +11 -0
- package/dashboard/dist/providers/antigravity.svg +3 -0
- package/dashboard/dist/providers/azure.svg +5 -0
- package/dashboard/dist/providers/baidu.svg +3 -0
- package/dashboard/dist/providers/blackbox.svg +5 -0
- package/dashboard/dist/providers/byteplus.svg +3 -0
- package/dashboard/dist/providers/cerebras.svg +4 -0
- package/dashboard/dist/providers/chutes.svg +4 -0
- package/dashboard/dist/providers/claude.svg +3 -0
- package/dashboard/dist/providers/cline.svg +11 -0
- package/dashboard/dist/providers/cloudflare-ai.svg +4 -0
- package/dashboard/dist/providers/codebuddy.svg +11 -0
- package/dashboard/dist/providers/codex.svg +10 -0
- package/dashboard/dist/providers/commandcode.svg +3 -0
- package/dashboard/dist/providers/cursor.svg +3 -0
- package/dashboard/dist/providers/deepseek.svg +10 -0
- package/dashboard/dist/providers/featherless.svg +3 -0
- package/dashboard/dist/providers/fireworks.svg +3 -0
- package/dashboard/dist/providers/gemini.svg +3 -0
- package/dashboard/dist/providers/geminicli.svg +11 -0
- package/dashboard/dist/providers/github.svg +3 -0
- package/dashboard/dist/providers/grok.svg +3 -0
- package/dashboard/dist/providers/groq.svg +3 -0
- package/dashboard/dist/providers/hermesagent.svg +1 -0
- package/dashboard/dist/providers/kilocode.svg +15 -0
- package/dashboard/dist/providers/kimchi.svg +3 -0
- package/dashboard/dist/providers/kimi.svg +4 -0
- package/dashboard/dist/providers/kiro.svg +10 -0
- package/dashboard/dist/providers/meta.svg +3 -0
- package/dashboard/dist/providers/mimo.svg +10 -0
- package/dashboard/dist/providers/minimax.svg +3 -0
- package/dashboard/dist/providers/mistral.svg +3 -0
- package/dashboard/dist/providers/morph.svg +3 -0
- package/dashboard/dist/providers/nebius.svg +4 -0
- package/dashboard/dist/providers/nvidia.svg +3 -0
- package/dashboard/dist/providers/ollama.svg +3 -0
- package/dashboard/dist/providers/omp.svg +5 -0
- package/dashboard/dist/providers/openai.svg +3 -0
- package/dashboard/dist/providers/opencode.svg +3 -0
- package/dashboard/dist/providers/openrouter.svg +3 -0
- package/dashboard/dist/providers/perplexity.svg +3 -0
- package/dashboard/dist/providers/poolside.svg +36 -0
- package/dashboard/dist/providers/qoder.svg +11 -0
- package/dashboard/dist/providers/sumopod.svg +3 -0
- package/dashboard/dist/providers/tencent.svg +5 -0
- package/dashboard/dist/providers/together.svg +12 -0
- package/dashboard/dist/providers/trae.svg +3 -0
- package/dashboard/dist/providers/venice.svg +4 -0
- package/dashboard/dist/providers/vercel.svg +3 -0
- package/dashboard/dist/providers/vertex.svg +17 -0
- package/dashboard/dist/providers/windsurf.svg +10 -0
- package/dashboard/dist/providers/zai.svg +3 -0
- package/dashboard/tsconfig.json +13 -0
- package/package.json +87 -0
- package/src/config/appConstants.js +153 -0
- package/src/config/defaultThinkingSignature.js +7 -0
- package/src/config/errorConfig.js +117 -0
- package/src/config/grokCli.js +9 -0
- package/src/config/kiroConstants.js +235 -0
- package/src/config/mediaConfig.js +20 -0
- package/src/config/ollamaModels.js +18 -0
- package/src/config/providerModels.js +109 -0
- package/src/config/providers.js +17 -0
- package/src/config/runtimeConfig.js +84 -0
- package/src/dashboardGuard.js +254 -0
- package/src/executors/antigravity.js +389 -0
- package/src/executors/azure.js +49 -0
- package/src/executors/base.js +225 -0
- package/src/executors/codebuddy-cn.js +23 -0
- package/src/executors/codebuddy-intl.js +60 -0
- package/src/executors/codex.js +436 -0
- package/src/executors/commandcode.js +83 -0
- package/src/executors/cursor.js +1075 -0
- package/src/executors/default.js +294 -0
- package/src/executors/gemini-cli.js +88 -0
- package/src/executors/github.js +393 -0
- package/src/executors/grok-cli.js +510 -0
- package/src/executors/grok-web.js +342 -0
- package/src/executors/index.js +86 -0
- package/src/executors/kimchi.js +116 -0
- package/src/executors/kiro.js +1155 -0
- package/src/executors/ollama-local.js +14 -0
- package/src/executors/opencode-go.js +47 -0
- package/src/executors/opencode.js +31 -0
- package/src/executors/qoder.js +433 -0
- package/src/executors/trae.js +318 -0
- package/src/executors/vertex.js +151 -0
- package/src/executors/windsurf.js +555 -0
- package/src/executors/xiaomi-tokenplan.js +16 -0
- package/src/handlers/chatCore/nonStreamingHandler.js +370 -0
- package/src/handlers/chatCore/requestDetail.js +130 -0
- package/src/handlers/chatCore/sseToJsonHandler.js +318 -0
- package/src/handlers/chatCore/streamingHandler.js +250 -0
- package/src/handlers/chatCore.js +652 -0
- package/src/lib/auth/dashboardSession.js +83 -0
- package/src/lib/auth/loginLimiter.js +99 -0
- package/src/lib/cache/ttlCache.js +153 -0
- package/src/lib/consoleLogBuffer.js +127 -0
- package/src/lib/dataDir.js +45 -0
- package/src/lib/db/adapters/betterSqliteAdapter.js +36 -0
- package/src/lib/db/adapters/bunSqliteAdapter.js +47 -0
- package/src/lib/db/adapters/nodeSqliteAdapter.js +65 -0
- package/src/lib/db/adapters/runtimeHelpers.js +23 -0
- package/src/lib/db/adapters/sqljsAdapter.js +103 -0
- package/src/lib/db/backup.js +75 -0
- package/src/lib/db/driver.js +110 -0
- package/src/lib/db/helpers/jsonCol.js +18 -0
- package/src/lib/db/helpers/kvStore.js +48 -0
- package/src/lib/db/helpers/metaStore.js +32 -0
- package/src/lib/db/index.js +473 -0
- package/src/lib/db/migrate.js +267 -0
- package/src/lib/db/migrations/001-initial.js +12 -0
- package/src/lib/db/migrations/002-prune-headroom-pxpipe-settings.js +32 -0
- package/src/lib/db/migrations/004-request-details-trace-id.js +12 -0
- package/src/lib/db/migrations/005-request-details-payload-capture.js +11 -0
- package/src/lib/db/migrations/007-headroom-readd-settings.js +35 -0
- package/src/lib/db/migrations/008-account-model-locks.js +22 -0
- package/src/lib/db/migrations/009-warp-pool-lifecycle.js +5 -0
- package/src/lib/db/migrations/010-api-key-file-permissions.js +7 -0
- package/src/lib/db/migrations/011-remove-upstream-user-agent-profile.js +41 -0
- package/src/lib/db/migrations/012-remove-headroom-settings.js +33 -0
- package/src/lib/db/migrations/013-default-fill-first-routing.js +20 -0
- package/src/lib/db/migrations/014-normalize-fill-first-routing.js +37 -0
- package/src/lib/db/migrations/015-remove-ip-ban-tables.js +8 -0
- package/src/lib/db/migrations/016-prune-legacy-codebuddy-intl-models.js +25 -0
- package/src/lib/db/migrations/index.js +20 -0
- package/src/lib/db/nineRouterMigration.js +785 -0
- package/src/lib/db/paths.js +23 -0
- package/src/lib/db/repos/accountModelLocksRepo.js +74 -0
- package/src/lib/db/repos/aliasRepo.js +108 -0
- package/src/lib/db/repos/apiKeysRepo.js +204 -0
- package/src/lib/db/repos/combosRepo.js +85 -0
- package/src/lib/db/repos/connectionsRepo.js +522 -0
- package/src/lib/db/repos/disabledModelsRepo.js +63 -0
- package/src/lib/db/repos/nodesRepo.js +127 -0
- package/src/lib/db/repos/pricingRepo.js +108 -0
- package/src/lib/db/repos/proxyPoolsRepo.js +104 -0
- package/src/lib/db/repos/requestDetailsRepo.js +345 -0
- package/src/lib/db/repos/settingsRepo.js +135 -0
- package/src/lib/db/repos/usageRepo.js +1335 -0
- package/src/lib/db/schema.js +179 -0
- package/src/lib/db/version.js +32 -0
- package/src/lib/db/writeBehind.js +174 -0
- package/src/lib/disabledModelsDb.js +3 -0
- package/src/lib/env.ts +175 -0
- package/src/lib/errors/publicError.js +18 -0
- package/src/lib/grokBuildConfig.js +243 -0
- package/src/lib/guardRequest.js +51 -0
- package/src/lib/localDb.js +21 -0
- package/src/lib/mcp/stdioSseBridge.js +174 -0
- package/src/lib/network/connectionProxy.js +200 -0
- package/src/lib/network/proxyTest.js +158 -0
- package/src/lib/network/proxyUrl.js +76 -0
- package/src/lib/network/relay.js +71 -0
- package/src/lib/oauth/constants/oauth.js +152 -0
- package/src/lib/oauth/constants/xai.js +43 -0
- package/src/lib/oauth/kiroExternalIdp.js +167 -0
- package/src/lib/oauth/providerHelpers.js +90 -0
- package/src/lib/oauth/providers/_shared.js +12 -0
- package/src/lib/oauth/providers/antigravity.js +126 -0
- package/src/lib/oauth/providers/claude.js +60 -0
- package/src/lib/oauth/providers/cline.js +62 -0
- package/src/lib/oauth/providers/clinepass.js +62 -0
- package/src/lib/oauth/providers/codebuddy-cn.js +75 -0
- package/src/lib/oauth/providers/codebuddy-intl.js +73 -0
- package/src/lib/oauth/providers/codex.js +72 -0
- package/src/lib/oauth/providers/cursor.js +18 -0
- package/src/lib/oauth/providers/gemini-cli.js +84 -0
- package/src/lib/oauth/providers/github.js +96 -0
- package/src/lib/oauth/providers/grok-cli.js +123 -0
- package/src/lib/oauth/providers/index.js +233 -0
- package/src/lib/oauth/providers/kilocode.js +60 -0
- package/src/lib/oauth/providers/kimchi.js +79 -0
- package/src/lib/oauth/providers/kimi.js +79 -0
- package/src/lib/oauth/providers/kiro.js +147 -0
- package/src/lib/oauth/providers/qoder.js +90 -0
- package/src/lib/oauth/providers/trae.js +244 -0
- package/src/lib/oauth/providers/windsurf.js +123 -0
- package/src/lib/oauth/providers/xai.js +95 -0
- package/src/lib/oauth/providers.js +16 -0
- package/src/lib/oauth/services/cursor.js +132 -0
- package/src/lib/oauth/services/kiro.js +351 -0
- package/src/lib/oauth/services/oauth.js +135 -0
- package/src/lib/oauth/services/qoder.js +151 -0
- package/src/lib/oauth/services/xai.js +204 -0
- package/src/lib/oauth/utils/ideDetect.js +55 -0
- package/src/lib/oauth/utils/pkce.js +25 -0
- package/src/lib/oauth/utils/server.js +732 -0
- package/src/lib/oauth/utils/ui.js +43 -0
- package/src/lib/providerNormalization.js +40 -0
- package/src/lib/qoder/constants.js +1 -0
- package/src/lib/requestDetailsDb.js +3 -0
- package/src/lib/resourceProfile.ts +124 -0
- package/src/lib/runtimeSecrets.ts +130 -0
- package/src/lib/security/payloadCapture.js +87 -0
- package/src/lib/tunnel/cloudflare/cloudflared.js +436 -0
- package/src/lib/tunnel/cloudflare/config.js +8 -0
- package/src/lib/tunnel/cloudflare/healthCheck.js +37 -0
- package/src/lib/tunnel/cloudflare/manager.js +149 -0
- package/src/lib/tunnel/cloudflare/pid.js +31 -0
- package/src/lib/tunnel/cloudflare/publicUrl.js +41 -0
- package/src/lib/tunnel/cloudflare/requirements.js +12 -0
- package/src/lib/tunnel/index.js +26 -0
- package/src/lib/tunnel/shared/dnsResolver.js +16 -0
- package/src/lib/tunnel/shared/internetCheck.js +30 -0
- package/src/lib/tunnel/shared/state.js +45 -0
- package/src/lib/tunnel/shared/watchdogConfig.js +6 -0
- package/src/lib/update/installer.js +52 -0
- package/src/lib/update/version.js +116 -0
- package/src/lib/usageDb.js +6 -0
- package/src/lib/usageRefresh.js +88 -0
- package/src/lifecycle/appLifecycle.ts +99 -0
- package/src/models.js +36 -0
- package/src/next/headers.js +12 -0
- package/src/next/server.js +74 -0
- package/src/observability/metrics.js +439 -0
- package/src/observability/tracing.js +107 -0
- package/src/open-sse-index.js +70 -0
- package/src/providers/capabilities.js +299 -0
- package/src/providers/display.ts +142 -0
- package/src/providers/index.js +27 -0
- package/src/providers/models/helpers.js +19 -0
- package/src/providers/models/namePatterns.js +27 -0
- package/src/providers/models/schema.js +32 -0
- package/src/providers/pricing.js +248 -0
- package/src/providers/registry/agentrouter.js +52 -0
- package/src/providers/registry/alicode-intl.js +32 -0
- package/src/providers/registry/alicode.js +33 -0
- package/src/providers/registry/alims-intl.js +30 -0
- package/src/providers/registry/anthropic.js +29 -0
- package/src/providers/registry/antigravity.js +139 -0
- package/src/providers/registry/azure.js +23 -0
- package/src/providers/registry/baidu.js +35 -0
- package/src/providers/registry/blackbox.js +41 -0
- package/src/providers/registry/byteplus.js +36 -0
- package/src/providers/registry/cerebras.js +33 -0
- package/src/providers/registry/chutes.js +26 -0
- package/src/providers/registry/claude.js +80 -0
- package/src/providers/registry/cline.js +53 -0
- package/src/providers/registry/clinepass.js +62 -0
- package/src/providers/registry/cloudflare-ai.js +84 -0
- package/src/providers/registry/codebuddy-cn.js +95 -0
- package/src/providers/registry/codebuddy-intl.js +91 -0
- package/src/providers/registry/codex.js +145 -0
- package/src/providers/registry/commandcode.js +45 -0
- package/src/providers/registry/cursor.js +61 -0
- package/src/providers/registry/deepseek.js +55 -0
- package/src/providers/registry/featherless.js +36 -0
- package/src/providers/registry/fireworks.js +34 -0
- package/src/providers/registry/gemini-cli.js +59 -0
- package/src/providers/registry/gemini.js +76 -0
- package/src/providers/registry/github.js +131 -0
- package/src/providers/registry/glm-cn.js +35 -0
- package/src/providers/registry/glm.js +58 -0
- package/src/providers/registry/grok-cli.js +87 -0
- package/src/providers/registry/grok-web.js +41 -0
- package/src/providers/registry/groq.js +38 -0
- package/src/providers/registry/index.js +77 -0
- package/src/providers/registry/kilo-gateway.js +34 -0
- package/src/providers/registry/kilocode.js +48 -0
- package/src/providers/registry/kimchi.js +49 -0
- package/src/providers/registry/kimi.js +82 -0
- package/src/providers/registry/kiro.js +132 -0
- package/src/providers/registry/meta.js +34 -0
- package/src/providers/registry/minimax-cn.js +90 -0
- package/src/providers/registry/minimax.js +90 -0
- package/src/providers/registry/mistral.js +36 -0
- package/src/providers/registry/morph.js +31 -0
- package/src/providers/registry/nebius.js +26 -0
- package/src/providers/registry/nvidia.js +55 -0
- package/src/providers/registry/ollama-local.js +18 -0
- package/src/providers/registry/ollama.js +38 -0
- package/src/providers/registry/openai.js +114 -0
- package/src/providers/registry/opencode-go.js +41 -0
- package/src/providers/registry/opencode.js +26 -0
- package/src/providers/registry/openrouter.js +36 -0
- package/src/providers/registry/perplexity.js +56 -0
- package/src/providers/registry/poolside.js +30 -0
- package/src/providers/registry/qoder.js +58 -0
- package/src/providers/registry/sumopod.js +84 -0
- package/src/providers/registry/tencent.js +29 -0
- package/src/providers/registry/together.js +38 -0
- package/src/providers/registry/trae.js +71 -0
- package/src/providers/registry/venice.js +69 -0
- package/src/providers/registry/vercel-ai-gateway.js +37 -0
- package/src/providers/registry/vertex-partner.js +31 -0
- package/src/providers/registry/vertex.js +33 -0
- package/src/providers/registry/windsurf.js +129 -0
- package/src/providers/registry/xai.js +46 -0
- package/src/providers/registry/xiaomi-mimo.js +66 -0
- package/src/providers/registry/xiaomi-tokenplan.js +58 -0
- package/src/providers/registryEntry.js +3 -0
- package/src/providers/schema.js +33 -0
- package/src/providers/shared.js +114 -0
- package/src/providers/thinkingLevels.js +49 -0
- package/src/routes/api/auth/login/route.js +82 -0
- package/src/routes/api/auth/logout/route.js +9 -0
- package/src/routes/api/auth/reset-password/route.js +12 -0
- package/src/routes/api/auth/status/route.js +33 -0
- package/src/routes/api/auth/verify-password/route.js +39 -0
- package/src/routes/api/chat/tools/curl/route.js +100 -0
- package/src/routes/api/chat/tools/router/route.js +215 -0
- package/src/routes/api/chat/tools/search/route.js +362 -0
- package/src/routes/api/chat/tools/shell/route.js +228 -0
- package/src/routes/api/cli-tools/all-statuses/route.js +37 -0
- package/src/routes/api/cli-tools/claude-settings/route.js +261 -0
- package/src/routes/api/cli-tools/codex-settings/route.js +220 -0
- package/src/routes/api/cli-tools/cowork-mcp-registry/route.js +80 -0
- package/src/routes/api/cli-tools/cowork-mcp-tools/route.js +96 -0
- package/src/routes/api/cli-tools/cowork-settings/route.js +380 -0
- package/src/routes/api/cli-tools/grok-build-settings/route.js +152 -0
- package/src/routes/api/cli-tools/hermes-settings/route.js +169 -0
- package/src/routes/api/cli-tools/kilo-settings/route.js +131 -0
- package/src/routes/api/cli-tools/model-mappings/route.js +43 -0
- package/src/routes/api/cli-tools/omp-settings/route.js +266 -0
- package/src/routes/api/cli-tools/opencode-settings/route.js +243 -0
- package/src/routes/api/combos/[id]/route.js +73 -0
- package/src/routes/api/combos/route.js +43 -0
- package/src/routes/api/health/live/route.js +7 -0
- package/src/routes/api/health/ready/route.js +19 -0
- package/src/routes/api/health/route.js +17 -0
- package/src/routes/api/inflight/stream/route.js +24 -0
- package/src/routes/api/init/route.js +3 -0
- package/src/routes/api/keys/[id]/route.js +71 -0
- package/src/routes/api/keys/route.js +41 -0
- package/src/routes/api/logs/route.js +19 -0
- package/src/routes/api/mcp/[plugin]/message/route.js +23 -0
- package/src/routes/api/mcp/[plugin]/sse/route.js +35 -0
- package/src/routes/api/models/availability/route.js +104 -0
- package/src/routes/api/models/custom/route.js +58 -0
- package/src/routes/api/models/disabled/route.js +47 -0
- package/src/routes/api/models/route.js +64 -0
- package/src/routes/api/models/test/ping.js +236 -0
- package/src/routes/api/models/test/route.js +14 -0
- package/src/routes/api/oauth/[provider]/[action]/route.js +491 -0
- package/src/routes/api/oauth/codex/bulk-import/route.js +105 -0
- package/src/routes/api/oauth/codex/import-token/route.js +82 -0
- package/src/routes/api/oauth/cursor/auto-import/route.js +250 -0
- package/src/routes/api/oauth/cursor/import/route.js +86 -0
- package/src/routes/api/oauth/kiro/api-key/route.js +60 -0
- package/src/routes/api/oauth/kiro/auto-import/route.js +120 -0
- package/src/routes/api/oauth/kiro/import/route.js +72 -0
- package/src/routes/api/oauth/kiro/import-cli-proxy/route.js +42 -0
- package/src/routes/api/oauth/kiro/social-authorize/route.js +40 -0
- package/src/routes/api/oauth/kiro/social-exchange/route.js +62 -0
- package/src/routes/api/pricing/route.js +96 -0
- package/src/routes/api/provider-nodes/[id]/route.js +106 -0
- package/src/routes/api/provider-nodes/route.js +110 -0
- package/src/routes/api/provider-nodes/validate/route.js +197 -0
- package/src/routes/api/providers/[id]/models/route.js +716 -0
- package/src/routes/api/providers/[id]/route.js +195 -0
- package/src/routes/api/providers/[id]/test/route.js +27 -0
- package/src/routes/api/providers/[id]/test/testUtils.js +912 -0
- package/src/routes/api/providers/[id]/test-models/route.js +211 -0
- package/src/routes/api/providers/catalog/route.js +58 -0
- package/src/routes/api/providers/client/route.js +133 -0
- package/src/routes/api/providers/counts/route.js +43 -0
- package/src/routes/api/providers/kilo/free-models/route.js +58 -0
- package/src/routes/api/providers/route.js +361 -0
- package/src/routes/api/providers/suggested-models/filters.js +24 -0
- package/src/routes/api/providers/suggested-models/route.js +34 -0
- package/src/routes/api/providers/test-batch/route.js +145 -0
- package/src/routes/api/providers/validate/route.js +633 -0
- package/src/routes/api/proxy-pools/[id]/route.js +129 -0
- package/src/routes/api/proxy-pools/[id]/test/route.js +64 -0
- package/src/routes/api/proxy-pools/cloudflare-deploy/route.js +183 -0
- package/src/routes/api/proxy-pools/route.js +85 -0
- package/src/routes/api/proxy-pools/vercel-deploy/route.js +181 -0
- package/src/routes/api/settings/currency/route.js +29 -0
- package/src/routes/api/settings/database/path/route.js +8 -0
- package/src/routes/api/settings/database/route.js +89 -0
- package/src/routes/api/settings/migrate-9router/route.js +81 -0
- package/src/routes/api/settings/require-login/route.js +14 -0
- package/src/routes/api/settings/route.js +186 -0
- package/src/routes/api/shutdown/route.js +25 -0
- package/src/routes/api/tags/route.js +17 -0
- package/src/routes/api/translator/console-logs/route.js +28 -0
- package/src/routes/api/translator/console-logs/stream/route.js +95 -0
- package/src/routes/api/tunnel/disable/route.js +18 -0
- package/src/routes/api/tunnel/enable/route.js +32 -0
- package/src/routes/api/tunnel/status/route.js +23 -0
- package/src/routes/api/update/route.js +42 -0
- package/src/routes/api/usage/[connectionId]/codex-reset-credits/route.js +169 -0
- package/src/routes/api/usage/[connectionId]/route.js +222 -0
- package/src/routes/api/usage/chart/route.js +27 -0
- package/src/routes/api/usage/history/route.js +94 -0
- package/src/routes/api/usage/logs/route.js +14 -0
- package/src/routes/api/usage/providers/route.js +36 -0
- package/src/routes/api/usage/request-details/route.js +61 -0
- package/src/routes/api/usage/request-logs/route.js +15 -0
- package/src/routes/api/usage/stats/route.js +23 -0
- package/src/routes/api/usage/stream/route.js +78 -0
- package/src/routes/api/v1/api/chat/route.js +36 -0
- package/src/routes/api/v1/chat/completions/route.js +28 -0
- package/src/routes/api/v1/images/edits/route.js +70 -0
- package/src/routes/api/v1/images/generations/route.js +50 -0
- package/src/routes/api/v1/images/imageValidation.js +45 -0
- package/src/routes/api/v1/messages/count_tokens/route.js +87 -0
- package/src/routes/api/v1/messages/route.js +26 -0
- package/src/routes/api/v1/models/route.js +440 -0
- package/src/routes/api/v1/responses/compact/route.js +34 -0
- package/src/routes/api/v1/responses/route.js +26 -0
- package/src/routes/api/v1/route.js +1 -0
- package/src/routes/api/version/route.js +11 -0
- package/src/routes/table.js +1141 -0
- package/src/rtk/applyFilter.js +13 -0
- package/src/rtk/autodetect.js +104 -0
- package/src/rtk/caveman.js +6 -0
- package/src/rtk/cavemanPrompts.js +107 -0
- package/src/rtk/constants.js +51 -0
- package/src/rtk/filters/buildOutput.js +120 -0
- package/src/rtk/filters/dedupLog.js +43 -0
- package/src/rtk/filters/find.js +47 -0
- package/src/rtk/filters/gitDiff.js +90 -0
- package/src/rtk/filters/gitLog.js +88 -0
- package/src/rtk/filters/gitStatus.js +101 -0
- package/src/rtk/filters/grep.js +45 -0
- package/src/rtk/filters/ls.js +73 -0
- package/src/rtk/filters/readNumbered.js +22 -0
- package/src/rtk/filters/searchList.js +49 -0
- package/src/rtk/filters/smartTruncate.js +13 -0
- package/src/rtk/filters/tree.js +28 -0
- package/src/rtk/index.js +143 -0
- package/src/rtk/ponytail.js +6 -0
- package/src/rtk/ponytailPrompt.js +49 -0
- package/src/rtk/systemInject.js +89 -0
- package/src/server.ts +474 -0
- package/src/services/accountFallback.js +241 -0
- package/src/services/accountPool.js +389 -0
- package/src/services/capacityAdapter.js +140 -0
- package/src/services/cliModelMapping.js +84 -0
- package/src/services/clinepassModels.js +60 -0
- package/src/services/codebuddyModels.js +250 -0
- package/src/services/combo.js +482 -0
- package/src/services/copilotModels.js +126 -0
- package/src/services/currencyRate.js +56 -0
- package/src/services/cursorModels.js +197 -0
- package/src/services/grokCliModels.js +130 -0
- package/src/services/kimchiModels.js +175 -0
- package/src/services/kiroModels.js +246 -0
- package/src/services/model.js +83 -0
- package/src/services/oauthCredentialManager.js +153 -0
- package/src/services/projectId.js +240 -0
- package/src/services/provider.js +145 -0
- package/src/services/qoderModels.js +274 -0
- package/src/services/tokenRefresh/dedup.js +70 -0
- package/src/services/tokenRefresh/providers.js +626 -0
- package/src/services/tokenRefresh.js +274 -0
- package/src/services/usage/claude.js +134 -0
- package/src/services/usage/codebuddy-cn.js +212 -0
- package/src/services/usage/codex.js +193 -0
- package/src/services/usage/deepseek.js +103 -0
- package/src/services/usage/github.js +94 -0
- package/src/services/usage/google.js +218 -0
- package/src/services/usage/grok-cli.js +368 -0
- package/src/services/usage/grokCliQuotaFrame.js +170 -0
- package/src/services/usage/kimi.js +185 -0
- package/src/services/usage/kiro.js +172 -0
- package/src/services/usage/minimax.js +215 -0
- package/src/services/usage/misc.js +264 -0
- package/src/services/usage/shared.js +59 -0
- package/src/services/usage.js +56 -0
- package/src/shared/clineAuth.js +37 -0
- package/src/shared/constants/config.js +80 -0
- package/src/shared/constants/coworkPlugins.js +69 -0
- package/src/shared/constants/models.js +41 -0
- package/src/shared/constants/providers.js +128 -0
- package/src/shared/constants/providersDisplay.js +1 -0
- package/src/shared/qoder/constants.js +50 -0
- package/src/shared/qoder/cosy.js +134 -0
- package/src/shared/qoder/encoding.js +36 -0
- package/src/shared/services/initializeApp.js +226 -0
- package/src/shared/services/quotaAutoPing.js +310 -0
- package/src/shared/utils/apiKey.js +65 -0
- package/src/shared/utils/clineAuth.js +1 -0
- package/src/shared/utils/index.js +3 -0
- package/src/shared/utils/machineId.js +60 -0
- package/src/shared/utils/ssrfGuard.js +280 -0
- package/src/sse/handlers/chat.js +426 -0
- package/src/sse/oauthLease.js +32 -0
- package/src/sse/recovery.js +235 -0
- package/src/sse/services/auth.js +489 -0
- package/src/sse/services/backgroundTokenRefresh.js +173 -0
- package/src/sse/services/model.js +129 -0
- package/src/sse/services/requestCancellation.js +4 -0
- package/src/sse/services/tokenRefresh.js +264 -0
- package/src/sse/utils/logger.js +142 -0
- package/src/staticServe.ts +95 -0
- package/src/transformer/streamToJsonConverter.js +87 -0
- package/src/translator/canonical.js +81 -0
- package/src/translator/concerns/chunk.js +9 -0
- package/src/translator/concerns/compatFallback.js +147 -0
- package/src/translator/concerns/finishReason.js +59 -0
- package/src/translator/concerns/image.js +105 -0
- package/src/translator/concerns/json.js +4 -0
- package/src/translator/concerns/kiroConversation.js +428 -0
- package/src/translator/concerns/message.js +5 -0
- package/src/translator/concerns/modality.js +134 -0
- package/src/translator/concerns/paramSupport.js +97 -0
- package/src/translator/concerns/prefetch.js +86 -0
- package/src/translator/concerns/reasoning.js +18 -0
- package/src/translator/concerns/thinking.js +40 -0
- package/src/translator/concerns/thinkingUnified.js +319 -0
- package/src/translator/concerns/toolCall.js +134 -0
- package/src/translator/concerns/usage.js +61 -0
- package/src/translator/detection.js +42 -0
- package/src/translator/formats/claude.js +323 -0
- package/src/translator/formats/gemini.js +366 -0
- package/src/translator/formats/maxTokens.js +19 -0
- package/src/translator/formats/openai.js +116 -0
- package/src/translator/formats/responsesApi.js +117 -0
- package/src/translator/formats.js +28 -0
- package/src/translator/index.js +237 -0
- package/src/translator/request/antigravity-to-openai.js +217 -0
- package/src/translator/request/claude-to-kiro.js +288 -0
- package/src/translator/request/claude-to-openai.js +199 -0
- package/src/translator/request/gemini-to-openai.js +142 -0
- package/src/translator/request/openai-responses.js +373 -0
- package/src/translator/request/openai-to-claude.js +260 -0
- package/src/translator/request/openai-to-commandcode.js +161 -0
- package/src/translator/request/openai-to-cursor.js +175 -0
- package/src/translator/request/openai-to-gemini.js +422 -0
- package/src/translator/request/openai-to-kiro.js +360 -0
- package/src/translator/request/openai-to-ollama.js +152 -0
- package/src/translator/request/openai-to-vertex.js +36 -0
- package/src/translator/response/claude-to-openai.js +185 -0
- package/src/translator/response/commandcode-to-openai.js +164 -0
- package/src/translator/response/cursor-to-openai.js +18 -0
- package/src/translator/response/gemini-to-openai.js +127 -0
- package/src/translator/response/kiro-to-claude.js +230 -0
- package/src/translator/response/kiro-to-openai.js +136 -0
- package/src/translator/response/ollama-to-openai.js +106 -0
- package/src/translator/response/openai-responses.js +534 -0
- package/src/translator/response/openai-to-antigravity.js +107 -0
- package/src/translator/response/openai-to-claude.js +231 -0
- package/src/translator/schema/blocks.js +40 -0
- package/src/translator/schema/defaults.js +3 -0
- package/src/translator/schema/finishReasons.js +22 -0
- package/src/translator/schema/index.js +7 -0
- package/src/translator/schema/roles.js +12 -0
- package/src/transport/requestBoundary.ts +223 -0
- package/src/transport/routerAdmission.ts +380 -0
- package/src/types/provider.ts +59 -0
- package/src/utils/bypassHandler.js +272 -0
- package/src/utils/claudeCloaking.js +10 -0
- package/src/utils/claudeSignature.js +35 -0
- package/src/utils/clientDetector.js +183 -0
- package/src/utils/cursorChecksum.js +104 -0
- package/src/utils/cursorProtobuf.js +801 -0
- package/src/utils/debugLog.js +12 -0
- package/src/utils/error.js +120 -0
- package/src/utils/inflight.js +127 -0
- package/src/utils/kiroSessionReplay.js +139 -0
- package/src/utils/ollamaTransform.js +83 -0
- package/src/utils/proxyFetch.js +308 -0
- package/src/utils/reasoningContentInjector.js +71 -0
- package/src/utils/requestLogger.js +272 -0
- package/src/utils/responsesStreamHelpers.js +46 -0
- package/src/utils/sessionManager.js +205 -0
- package/src/utils/sse.js +13 -0
- package/src/utils/sseConstants.js +21 -0
- package/src/utils/stream.js +511 -0
- package/src/utils/streamHandler.js +256 -0
- package/src/utils/streamHelpers.js +113 -0
- package/src/utils/toolDeduper.js +44 -0
- package/src/utils/usageTracking.js +329 -0
- package/tsconfig.json +45 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
const fs = require("node:fs");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const { spawn } = require("node:child_process");
|
|
4
|
+
const { selectMenu, pause } = require("../cli/utils/input");
|
|
5
|
+
const { showStatus, withProgress } = require("../cli/utils/display");
|
|
6
|
+
const { openBrowser } = require("./uiAdapters");
|
|
7
|
+
const { installPackageVersion } = require("./update");
|
|
8
|
+
const lifecycle = require("./lifecycle");
|
|
9
|
+
const { initTray, killTray } = require("../cli/tray/tray");
|
|
10
|
+
const { acquireTrayLock, stopLegacyTrayHosts, stopTrayHost } = require("../cli/tray/trayHost");
|
|
11
|
+
const pkg = require("../../../package.json");
|
|
12
|
+
|
|
13
|
+
function trayOptions(installation, port) {
|
|
14
|
+
return {
|
|
15
|
+
port,
|
|
16
|
+
onOpenDashboard: () => openBrowser(dashboardUrl(installation, port)),
|
|
17
|
+
onQuit: () => {
|
|
18
|
+
try { lifecycle.stop(installation); } catch {}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function initializeTray(installation, port) {
|
|
24
|
+
try { return initTray(trayOptions(installation, port)); } catch { return null; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function trayHostArgs(installation, port) {
|
|
28
|
+
const cliEntry = path.resolve(__dirname, "..", "..", "cli.js");
|
|
29
|
+
const args = [];
|
|
30
|
+
if (fs.existsSync(cliEntry)) args.push(cliEntry);
|
|
31
|
+
args.push("--tray", "--skip-update", "--dir", installation.installDir, "--port", String(port));
|
|
32
|
+
if (installation.host) args.push("--host", installation.host);
|
|
33
|
+
return args;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function startTrayHost(installation, port) {
|
|
37
|
+
try {
|
|
38
|
+
stopLegacyTrayHosts(installation);
|
|
39
|
+
const child = spawn(process.execPath, trayHostArgs(installation, port), {
|
|
40
|
+
detached: true,
|
|
41
|
+
windowsHide: true,
|
|
42
|
+
stdio: "ignore",
|
|
43
|
+
});
|
|
44
|
+
child.unref();
|
|
45
|
+
return child.pid || true;
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function runTrayHost(installation, options = {}) {
|
|
52
|
+
const port = Number(options.port || installation.port || 14045);
|
|
53
|
+
const trayLock = acquireTrayLock(installation, port);
|
|
54
|
+
if (!trayLock) return;
|
|
55
|
+
|
|
56
|
+
let running = lifecycle.status(installation).running;
|
|
57
|
+
if (!running) {
|
|
58
|
+
running = await lifecycle.waitForReady(port, {
|
|
59
|
+
host: options.host || installation.host,
|
|
60
|
+
timeoutMs: 3000,
|
|
61
|
+
intervalMs: 100,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (!running) {
|
|
65
|
+
await withProgress("Starting Sway Router", (progress) => {
|
|
66
|
+
progress.update(35, "Starting Sway Router");
|
|
67
|
+
return lifecycle.start(installation, {
|
|
68
|
+
background: true,
|
|
69
|
+
showLog: options.showLog,
|
|
70
|
+
port,
|
|
71
|
+
host: options.host,
|
|
72
|
+
});
|
|
73
|
+
}, { doneMessage: "Sway Router started" });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const tray = initializeTray(installation, port);
|
|
77
|
+
if (!tray) {
|
|
78
|
+
trayLock.release();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const shutdown = () => {
|
|
83
|
+
try { lifecycle.stop(installation); } catch {}
|
|
84
|
+
try { void killTray(); } catch {}
|
|
85
|
+
trayLock.release();
|
|
86
|
+
};
|
|
87
|
+
process.once("SIGINT", shutdown);
|
|
88
|
+
process.once("SIGTERM", shutdown);
|
|
89
|
+
await new Promise(() => {});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isHeadless() {
|
|
93
|
+
return process.platform === "linux" && !process.env.DISPLAY;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function backgroundStatusMessage(installation, port) {
|
|
97
|
+
const suffix = isHeadless() ? " (headless mode; no system tray)" : "";
|
|
98
|
+
return `Sway Router is running in background at ${dashboardUrl(installation, port)}${suffix}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function startTrayForMenu(installation, port) {
|
|
102
|
+
return startTrayHost(installation, port);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function dashboardUrl(installation, port) {
|
|
106
|
+
return `http://localhost:${port || installation.port || 14045}/dashboard`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function startAndShow(installation, options, background) {
|
|
110
|
+
try {
|
|
111
|
+
const result = await withProgress("Starting Sway Router", (progress) => {
|
|
112
|
+
progress.update(35, "Starting Sway Router");
|
|
113
|
+
return lifecycle.start(installation, { ...options, background });
|
|
114
|
+
}, { doneMessage: "Sway Router started" });
|
|
115
|
+
if (background) {
|
|
116
|
+
const tray = startTrayForMenu(installation, result.port);
|
|
117
|
+
showStatus(`${backgroundStatusMessage(installation, result.port)}${tray ? " with the tray enabled" : ""}`, "success");
|
|
118
|
+
} else {
|
|
119
|
+
showStatus(`Sway Router is ready at ${dashboardUrl(installation, result.port)}`, "success");
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
showStatus(error.message, "error");
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function closeTray(installation) {
|
|
129
|
+
try { await killTray(); } catch {}
|
|
130
|
+
try { await stopTrayHost(installation); } catch {}
|
|
131
|
+
try { stopLegacyTrayHosts(installation); } catch {}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function disableTray(installation) {
|
|
135
|
+
await closeTray(installation);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function menuItems(updateInfo = null) {
|
|
139
|
+
const items = [
|
|
140
|
+
{ id: "background", label: "Run in Background / Tray" },
|
|
141
|
+
{ id: "restart", label: "Restart Sway Router" },
|
|
142
|
+
{ id: "stop", label: "Stop Sway Router" },
|
|
143
|
+
];
|
|
144
|
+
if (updateInfo?.updateAvailable && updateInfo.updateSupported && updateInfo.latestVersion) {
|
|
145
|
+
items.push({ id: "update", label: `Update to v${updateInfo.latestVersion}` });
|
|
146
|
+
}
|
|
147
|
+
items.push({ id: "exit", label: "Exit & Stop Router" });
|
|
148
|
+
return items;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function stopManaged(installation) {
|
|
152
|
+
const result = await withProgress("Stopping Sway Router", () => lifecycle.stop(installation), {
|
|
153
|
+
doneMessage: "Sway Router stopped",
|
|
154
|
+
});
|
|
155
|
+
await disableTray(installation);
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function currentStatus(installation) {
|
|
160
|
+
return lifecycle.status(installation);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function menuStatusText(status, version = pkg.version) {
|
|
164
|
+
return `Status: ${status.running ? "running" : "stopped"}\nCurrent Version: v${version}`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function stopWithMessage(installation) {
|
|
168
|
+
const result = await stopManaged(installation);
|
|
169
|
+
showStatus(result.stopped ? "Sway Router stopped." : "Sway Router was not running.", result.stopped ? "success" : "info");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function updateAndRestart(installation, options, updateInfo) {
|
|
173
|
+
const wasRunning = currentStatus(installation).running;
|
|
174
|
+
if (wasRunning) await stopManaged(installation);
|
|
175
|
+
try {
|
|
176
|
+
await installPackageVersion(updateInfo.latestVersion);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (wasRunning) await startAndShow(installation, options, true);
|
|
179
|
+
showStatus(error.message, "error");
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (wasRunning) {
|
|
184
|
+
const restarted = await startAndShow(installation, options, true);
|
|
185
|
+
if (!restarted) return false;
|
|
186
|
+
}
|
|
187
|
+
showStatus(`Updated to v${updateInfo.latestVersion}. Closing menu.`, "success");
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function runMenu(installation, options = {}) {
|
|
192
|
+
const port = Number(options.port || installation.port || 14045);
|
|
193
|
+
const updateInfo = options.updateInfo || null;
|
|
194
|
+
while (true) {
|
|
195
|
+
const current = currentStatus(installation);
|
|
196
|
+
const items = menuItems(updateInfo);
|
|
197
|
+
const selected = await selectMenu(
|
|
198
|
+
"Sway Router",
|
|
199
|
+
items,
|
|
200
|
+
0,
|
|
201
|
+
menuStatusText(current),
|
|
202
|
+
`Dashboard: ${dashboardUrl(installation, port)}`,
|
|
203
|
+
);
|
|
204
|
+
if (selected === null) return 0;
|
|
205
|
+
const selectedItem = items[selected];
|
|
206
|
+
if (!selectedItem || selectedItem.id === "exit" || selected < 0) {
|
|
207
|
+
await stopWithMessage(installation);
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
if (selectedItem.id === "background") {
|
|
211
|
+
if (current.running) {
|
|
212
|
+
const tray = startTrayForMenu(installation, port);
|
|
213
|
+
showStatus(`Sway Router will keep running in the background${tray ? " with the tray enabled" : ""}. Closing menu.`, "success");
|
|
214
|
+
} else {
|
|
215
|
+
const started = await startAndShow(installation, options, true);
|
|
216
|
+
if (!started) {
|
|
217
|
+
await pause("Press Enter to return to the menu...");
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
223
|
+
if (selectedItem.id === "restart") {
|
|
224
|
+
if (!currentStatus(installation).running) {
|
|
225
|
+
showStatus("Sway Router is stopped. Start it with `swayrouter start` first.", "warning");
|
|
226
|
+
} else {
|
|
227
|
+
await stopManaged(installation);
|
|
228
|
+
await startAndShow(installation, options, true);
|
|
229
|
+
}
|
|
230
|
+
await pause("Press Enter to return to the menu...");
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (selectedItem.id === "stop") {
|
|
234
|
+
if (!currentStatus(installation).running) {
|
|
235
|
+
showStatus("Sway Router is already stopped.", "info");
|
|
236
|
+
} else {
|
|
237
|
+
await stopWithMessage(installation);
|
|
238
|
+
}
|
|
239
|
+
await pause("Press Enter to return to the menu...");
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (selectedItem.id === "update") {
|
|
243
|
+
const updated = await updateAndRestart(installation, options, updateInfo);
|
|
244
|
+
if (updated) return 0;
|
|
245
|
+
await pause("Press Enter to return to the menu...");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
module.exports = { runMenu, dashboardUrl, menuItems, menuStatusText, runTrayHost, startTrayHost };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const { exec } = require("node:child_process");
|
|
2
|
+
|
|
3
|
+
function openBrowser(url) {
|
|
4
|
+
const command = process.platform === "win32"
|
|
5
|
+
? `start "" "${url.replaceAll('"', '')}"`
|
|
6
|
+
: process.platform === "darwin"
|
|
7
|
+
? `open "${url.replaceAll('"', '')}"`
|
|
8
|
+
: `xdg-open "${url.replaceAll('"', '')}"`;
|
|
9
|
+
exec(command, { windowsHide: true }, () => {});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = { openBrowser };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const { spawn } = require("node:child_process");
|
|
2
|
+
const pkg = require("../../../package.json");
|
|
3
|
+
const { withProgress } = require("../cli/utils/display");
|
|
4
|
+
|
|
5
|
+
const REQUEST_TIMEOUT_MS = 2500;
|
|
6
|
+
|
|
7
|
+
function normalizeVersion(value) {
|
|
8
|
+
const match = String(value || "").trim().replace(/^v/i, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
|
|
9
|
+
if (!match) return null;
|
|
10
|
+
return {
|
|
11
|
+
major: Number(match[1]),
|
|
12
|
+
minor: Number(match[2]),
|
|
13
|
+
patch: Number(match[3]),
|
|
14
|
+
prerelease: match[4] ? match[4].split(".") : [],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function compareVersions(left, right) {
|
|
19
|
+
const a = normalizeVersion(left);
|
|
20
|
+
const b = normalizeVersion(right);
|
|
21
|
+
if (!a || !b) return 0;
|
|
22
|
+
if (a.major !== b.major) return a.major - b.major;
|
|
23
|
+
if (a.minor !== b.minor) return a.minor - b.minor;
|
|
24
|
+
if (a.patch !== b.patch) return a.patch - b.patch;
|
|
25
|
+
if (!a.prerelease.length && !b.prerelease.length) return 0;
|
|
26
|
+
if (!a.prerelease.length) return 1;
|
|
27
|
+
if (!b.prerelease.length) return -1;
|
|
28
|
+
const length = Math.max(a.prerelease.length, b.prerelease.length);
|
|
29
|
+
for (let index = 0; index < length; index += 1) {
|
|
30
|
+
const leftPart = a.prerelease[index];
|
|
31
|
+
const rightPart = b.prerelease[index];
|
|
32
|
+
if (leftPart === undefined) return -1;
|
|
33
|
+
if (rightPart === undefined) return 1;
|
|
34
|
+
if (leftPart === rightPart) continue;
|
|
35
|
+
const leftNumber = /^\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
36
|
+
const rightNumber = /^\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
37
|
+
if (leftNumber !== null && rightNumber !== null) return leftNumber - rightNumber;
|
|
38
|
+
if (leftNumber !== null) return -1;
|
|
39
|
+
if (rightNumber !== null) return 1;
|
|
40
|
+
return leftPart < rightPart ? -1 : 1;
|
|
41
|
+
}
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isNewerVersion(currentVersion, latestVersion) {
|
|
46
|
+
return Boolean(normalizeVersion(currentVersion) && normalizeVersion(latestVersion)
|
|
47
|
+
&& compareVersions(latestVersion, currentVersion) > 0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function registryUrl() {
|
|
51
|
+
return String(process.env.SWAYROUTER_NPM_REGISTRY || "https://registry.npmjs.org").replace(/\/+$/, "");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function checkForUpdate(fetchImpl = globalThis.fetch) {
|
|
55
|
+
const currentVersion = String(pkg.version || "0.0.0");
|
|
56
|
+
const packageName = process.env.SWAYROUTER_PACKAGE_NAME || pkg.name || "swayrouter";
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
59
|
+
let latestVersion = null;
|
|
60
|
+
let checkError = null;
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetchImpl(
|
|
63
|
+
`${registryUrl()}/${encodeURIComponent(packageName)}/latest`,
|
|
64
|
+
{ headers: { accept: "application/json" }, signal: controller.signal },
|
|
65
|
+
);
|
|
66
|
+
if (response.ok) {
|
|
67
|
+
const body = await response.json();
|
|
68
|
+
latestVersion = typeof body?.version === "string" ? body.version.trim() : null;
|
|
69
|
+
} else if (response.status !== 404) {
|
|
70
|
+
checkError = `registry returned ${response.status}`;
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
checkError = error instanceof Error ? error.message : String(error);
|
|
74
|
+
} finally {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
packageName,
|
|
80
|
+
currentVersion,
|
|
81
|
+
latestVersion,
|
|
82
|
+
updateAvailable: isNewerVersion(currentVersion, latestVersion),
|
|
83
|
+
updateSupported: pkg.private !== true && Boolean(latestVersion),
|
|
84
|
+
checkedAt: new Date().toISOString(),
|
|
85
|
+
checkError,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function packageManager() {
|
|
90
|
+
const customCommand = String(process.env.SWAYROUTER_PACKAGE_MANAGER_PATH || "").trim();
|
|
91
|
+
if (customCommand) return { command: customCommand, args: ["install", "--global"] };
|
|
92
|
+
|
|
93
|
+
const preferred = String(process.env.SWAYROUTER_PACKAGE_MANAGER || "").trim().toLowerCase();
|
|
94
|
+
if (preferred === "npm") return { command: "npm", args: ["install", "--global"] };
|
|
95
|
+
return { command: "bun", args: ["install", "--global"] };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function installPackageVersion(version) {
|
|
99
|
+
if (pkg.private === true) {
|
|
100
|
+
return Promise.reject(new Error("Package updates are unavailable for this private checkout"));
|
|
101
|
+
}
|
|
102
|
+
const manager = packageManager();
|
|
103
|
+
const spec = `${process.env.SWAYROUTER_PACKAGE_NAME || pkg.name || "swayrouter"}@${version}`;
|
|
104
|
+
return withProgress(`Updating Sway Router to v${version}`, (progress) => new Promise((resolve, reject) => {
|
|
105
|
+
progress.update(35, "Preparing update");
|
|
106
|
+
let child;
|
|
107
|
+
try {
|
|
108
|
+
child = spawn(manager.command, [...manager.args, spec], {
|
|
109
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
110
|
+
windowsHide: true,
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
reject(error);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
progress.update(55, `Installing v${version}`);
|
|
117
|
+
child.once("error", reject);
|
|
118
|
+
child.once("close", (code) => {
|
|
119
|
+
if (code === 0) resolve({ manager: manager.command, version });
|
|
120
|
+
else reject(new Error(`${manager.command} install failed with exit code ${code ?? "unknown"}`));
|
|
121
|
+
});
|
|
122
|
+
}), { indeterminate: true, doneMessage: `Sway Router updated to v${version}` });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
checkForUpdate,
|
|
127
|
+
compareVersions,
|
|
128
|
+
installPackageVersion,
|
|
129
|
+
isNewerVersion,
|
|
130
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{r as p,j as e}from"./react-vendor-xnYrwzsL.js";import{u as Xe,a as ee}from"./query-vendor-DVevaSVS.js";import{m as ce,A as Ke}from"./motion-vendor-g5fpGzmJ.js";import{H as Ze}from"./Header-C_9Su9BF.js";import{R as I}from"./ripple-button-l8aMiVVG.js";import{a as de,P as De}from"./ProviderModelAccordion-BAifkfVR.js";import{S as ke}from"./StatusBadge-1nAOyHU2.js";import{F as Me,a as Se,c as Ae}from"./frame-cUiti6Lq.js";import{y as be,J as et,I as B,S as ue,c as O,D as me,m as fe,n as pe,o as he,s as xe,F as Ue,e as z,q as ge,g as te,t as se}from"./index-B6j-9zHy.js";import{C as ne}from"./copy-button-qBvM6H9z.js";import{S as tt}from"./skeleton-7uJDiIXe.js";import{S as st,a as nt,b as ot,c as at}from"./select-D8pUtMXp.js";import{p as oe}from"./live-mode-CHShLY4E.js";import{b as rt,g as lt,d as Oe,l as it}from"./api-keys-api-ifAC2Ok3.js";import{aa as ae,q as ve,ax as ct,ay as Ee,a8 as dt,a9 as ut,D as mt,r as ft,i as pt,ag as Fe,ac as Ie,az as _e,X as ht}from"./icons-vendor-CUx7SB5V.js";import"./accordion-DOOPDDgt.js";import"./ui-vendor-BuM9f2NY.js";const D={claude:{name:"Claude Code",tier:"config"},codex:{name:"Codex CLI",tier:"config"},opencode:{name:"OpenCode",tier:"config"},hermes:{name:"Hermes Agent",tier:"config"},cowork:{name:"Claude Cowork",tier:"config"},kilo:{name:"Kilo Code",tier:"config"},"grok-build":{name:"Grok Build",tier:"config"},omp:{name:"OMP (oh-my-pi)",tier:"config"}},xt=Object.keys(D);function gt(s,...n){return n.some(r=>s[r]===!0)}function yt(s,n){var r,l,o;if(n){if(s==="claude"){const i=(r=n.settings)==null?void 0:r.env,f=["FABLE","OPUS","SONNET","HAIKU"].map(h=>i==null?void 0:i[`ANTHROPIC_DEFAULT_${h}_MODEL`]).filter(h=>typeof h=="string"&&h.length>0);return f.length?f:void 0}if(s==="hermes"){const i=(o=(l=n.settings)==null?void 0:l.model)==null?void 0:o.default;return typeof i=="string"&&i?[i]:void 0}if(s==="codex"){const c=(typeof n.config=="string"?n.config:"").match(/^model\s*=\s*["']([^"'\r\n]+)["']/m);return c?[c[1].trim()]:void 0}if(Array.isArray(n.models))return n.models.filter(i=>typeof i=="string")}}async function bt(){const{data:s}=await be.get("/cli-tools/all-statuses");return{tools:xt.map(r=>{const l=(s==null?void 0:s[r])??null,o=D[r];if(!l)return{id:r,name:o.name,tier:o.tier,installed:!1,connected:!1,available:!1,detail:"Status unavailable"};const i=l.installed!==!1,c=gt(l,"hasSwayRouter","connected");return{id:r,name:o.name,tier:o.tier,installed:i,connected:c,available:!0,configPath:et(typeof l.settingsPath=="string"?l.settingsPath:typeof l.configPath=="string"?l.configPath:void 0),detail:typeof l.message=="string"?l.message:void 0,version:typeof l.version=="string"?l.version:void 0,models:yt(r,l),raw:l}}),origin:typeof window<"u"?window.location.origin:"",apiKey:""}}function vt(s){return s.trim().replace(/\/$/,"")}function jt(s){return s==="claude"?"claude/claude-sonnet-5":s==="codex"?"openai/gpt-5":""}function Nt(s,n){var i;const r=vt(n.baseUrl||""),l=((i=n.models)==null?void 0:i.filter(Boolean))??[],o=n.primaryModel||l[0]||jt(s);switch(s){case"claude":return{env:{ANTHROPIC_BASE_URL:r,ANTHROPIC_AUTH_TOKEN:n.apiKey||"",ANTHROPIC_DEFAULT_FABLE_MODEL:n.fableModel||o,ANTHROPIC_DEFAULT_OPUS_MODEL:n.opusModel||o,ANTHROPIC_DEFAULT_SONNET_MODEL:n.sonnetModel||o,ANTHROPIC_DEFAULT_HAIKU_MODEL:n.haikuModel||o,API_TIMEOUT_MS:"600000"},exaMcpEnabled:n.exaMcpEnabled!==!1};case"codex":return{baseUrl:r,apiKey:n.apiKey||"",model:o,subagentModel:n.subagentModel||o};case"opencode":return{baseUrl:r,apiKey:n.apiKey||"",models:l.length?l:[o],activeModel:o,subagentModel:n.subagentModel||o};case"omp":return{baseUrl:r,apiKey:n.apiKey||"",models:l,primaryModel:n.primaryModel||o};case"cowork":return{baseUrl:r,apiKey:n.apiKey||"",models:l.length?l:[o]};case"grok-build":return{baseUrl:r,apiKey:n.apiKey||"",model:o};default:return{baseUrl:r,apiKey:n.apiKey||"",model:o}}}async function wt(s,n){var l,o;const{data:r}=await be.post(`/cli-tools/${encodeURIComponent(s)}-settings`,Nt(s,n));if(r.success===!1)throw new Error(r.message||"Configuration failed");return{id:s,name:((l=D[s])==null?void 0:l.name)??s,tier:((o=D[s])==null?void 0:o.tier)??"config",installed:!0,connected:!0,available:!0,detail:r.message}}async function Ct(s){return $e(s)}async function $e(s){var r,l;const{data:n}=await be.delete(`/cli-tools/${encodeURIComponent(s)}-settings`);if(n.success===!1)throw new Error(n.message||"Reset failed");return{id:s,name:((r=D[s])==null?void 0:r.name)??s,tier:((l=D[s])==null?void 0:l.tier)??"config",installed:!0,connected:!1,available:!0,detail:n.message}}async function kt(){const s=await rt().catch(()=>""),n={Accept:"application/json"};s&&(n.Authorization=`Bearer ${s}`);const r=await fetch("/v1/models",{credentials:"include",headers:n});return r.ok?((await r.json()).data??[]).flatMap(o=>{var f;const i=typeof o.id=="string"?o.id.trim():"";if(!i)return[];const c=typeof o.owned_by=="string"&&o.owned_by?o.owned_by:i.includes("/")?i.split("/",1)[0]:"other";return[{id:i,name:((f=o.name)==null?void 0:f.trim())||i,provider:c,capabilities:o.capabilities}]}):[]}function ye(s){const n=s.trim().replace(/\/$/,"");return!n||n==="—"?"":n.endsWith("/v1")?n:`${n}/v1`}function Mt(s){return[...new Set((s.models??[]).filter(n=>!!(n!=null&&n.trim())).map(n=>n.trim()))]}function He(s,n){var r;return((r=s.primaryModel)==null?void 0:r.trim())||n[0]||""}function re(s){return JSON.stringify(s,null,2)}function F(s){return JSON.stringify(s)}function St(s,n,r){var c;const l=He(s,r),o=((c=s.subagentModel)==null?void 0:c.trim())||l,i={provider:{swayrouter:{npm:"@ai-sdk/openai-compatible",options:{baseURL:ye(s.baseUrl),apiKey:n},...r.length?{models:Object.fromEntries(r.map(f=>[f,{name:f,modalities:{input:["text","image"],output:["text"]}}]))}:{}}}};return l&&(i.model=`swayrouter/${l}`),o&&(i.agent={explorer:{description:"Fast explorer subagent for codebase exploration",mode:"subagent",model:`swayrouter/${o}`}}),i}function At(s){return s?s.length<=8?"•".repeat(s.length):`${s.slice(0,4)}${"•".repeat(Math.min(16,s.length-4))}`:""}function Ot(s,n=!1){var h,w,N,k,x,M;const r=Mt(s),l=n?s.apiKey:At(s.apiKey),o=ye(s.baseUrl),i=He(s,r),c=s.toolId==="omp"?!!o:!!(o&&s.apiKey),f=c?void 0:s.toolId==="omp"?"Ensure the OMP gateway endpoint is available.":"Ensure an endpoint and API key are available.";switch(s.toolId){case"opencode":return{format:"json",fileName:"opencode.json",content:re(St(s,l,r)),modelCount:r.length,complete:c,message:f};case"omp":{const d=r.length?` models:
|
|
2
|
+
${r.map(g=>` - id: ${JSON.stringify(g)}
|
|
3
|
+
name: ${JSON.stringify(g)}`).join(`
|
|
4
|
+
`)}
|
|
5
|
+
`:"",u=s.apiKey?` apiKey: ${JSON.stringify(l)}
|
|
6
|
+
`:` auth: none
|
|
7
|
+
`;return{format:"yaml",fileName:"~/.omp/agent/models.yml",content:`providers:
|
|
8
|
+
swayrouter:
|
|
9
|
+
baseUrl: ${ye(s.baseUrl)}
|
|
10
|
+
api: openai-completions
|
|
11
|
+
${u} discovery:
|
|
12
|
+
type: openai-models-list
|
|
13
|
+
${d}`,modelCount:r.length,complete:c,message:f}}case"claude":{const d={ANTHROPIC_BASE_URL:o.replace(/\/v1$/,""),ANTHROPIC_AUTH_TOKEN:l,API_TIMEOUT_MS:"600000"},u={ANTHROPIC_DEFAULT_FABLE_MODEL:((h=s.fableModel)==null?void 0:h.trim())||i,ANTHROPIC_DEFAULT_OPUS_MODEL:((w=s.opusModel)==null?void 0:w.trim())||i,ANTHROPIC_DEFAULT_SONNET_MODEL:((N=s.sonnetModel)==null?void 0:N.trim())||i,ANTHROPIC_DEFAULT_HAIKU_MODEL:((k=s.haikuModel)==null?void 0:k.trim())||i};for(const[g,j]of Object.entries(u))j&&(d[g]=j);return{format:"env",fileName:".env",content:Object.entries(d).map(([g,j])=>`${g}=${F(j)}`).join(`
|
|
14
|
+
`)+`
|
|
15
|
+
`,modelCount:r.length,complete:c,message:f}}case"codex":{const d=[...i?[`model = ${F(i)}`]:[],'model_provider = "swayrouter"',"","[model_providers.swayrouter]",'name = "Sway Router"',`base_url = ${F(o)}`,'wire_api = "responses"'],u=((x=s.subagentModel)==null?void 0:x.trim())||i;return u&&d.push("","[agents.subagent]",`model = ${F(u)}`),d.push("","# Write this credential to auth.json (Codex reads it separately):",re({OPENAI_API_KEY:l,auth_mode:"apikey"})),{format:"toml",fileName:"config.toml + auth.json",content:d.join(`
|
|
16
|
+
`)+`
|
|
17
|
+
`,modelCount:r.length,complete:c,message:f}}case"hermes":return{format:"yaml",fileName:"config.yaml + .env",content:`model:
|
|
18
|
+
default: ${JSON.stringify(i)}
|
|
19
|
+
provider: "custom"
|
|
20
|
+
base_url: ${JSON.stringify(o)}
|
|
21
|
+
|
|
22
|
+
# Add to .env
|
|
23
|
+
OPENAI_API_KEY=${F(l)}
|
|
24
|
+
`,modelCount:r.length,complete:c,message:f};default:return{format:"json",fileName:`${s.toolId}.json`,content:re({baseUrl:o,apiKey:l,model:i,subagentModel:((M=s.subagentModel)==null?void 0:M.trim())||i}),modelCount:r.length,complete:c,message:f}}}const Et={claude:"Anthropic Claude Code CLI",codex:"OpenAI Codex CLI",hermes:"Nous Research agent",opencode:"OpenCode terminal assistant",cowork:"Claude Desktop third-party inference",kilo:"Kilo Code assistant","grok-build":"Grok Build coding agent",omp:"oh-my-pi — Rust coding agent (local gateway)"},It={claude:"/providers/claude.svg",cowork:"/providers/claude.svg",codex:"/providers/codex.svg","grok-build":"/providers/grok.svg",hermes:"/providers/hermesagent.svg",kilo:"/providers/kilocode.svg",omp:"/providers/omp.svg",opencode:"/providers/opencode.svg"},_t=new Set(["kilo","hermes","grok-build"]),Lt=new Set(["codex","opencode"]),H=new Set(["opencode","omp"]),Rt="/v1";function le(s){return s==="claude"}function ie(s,n){return n?s==="claude"?n:`${n}${Rt}`:"—"}function G(s){return s.tier==="config"}function Le(s){return G(s)}const Tt=[{key:"fable",label:"Fable",hint:"Claude Fable"},{key:"opus",label:"Opus",hint:"Claude Opus"},{key:"sonnet",label:"Sonnet",hint:"Claude Sonnet"},{key:"haiku",label:"Haiku",hint:"Claude Haiku"}];function Pt(s){return s?`${s.slice(0,Math.min(10,s.length))}${"•".repeat(8)}`:"key unavailable"}function q(s){return s&&typeof s=="object"&&!Array.isArray(s)?s:{}}function $(s){return typeof s=="string"?s:""}function Re(s){return Array.isArray(s)?s.filter(n=>typeof n=="string"&&n.length>0):[]}function Be(){return{primary:"",subagent:"",models:[],active:"",fable:"",opus:"",sonnet:"",haiku:""}}function Q(s){var c;const n=Be();if(s.id==="claude"){const f=q((c=s.raw)==null?void 0:c.settings),h=q(f.env);if(Object.keys(h).some(N=>N.startsWith("ANTHROPIC_DEFAULT_")))return{...n,fable:$(h.ANTHROPIC_DEFAULT_FABLE_MODEL),opus:$(h.ANTHROPIC_DEFAULT_OPUS_MODEL),sonnet:$(h.ANTHROPIC_DEFAULT_SONNET_MODEL),haiku:$(h.ANTHROPIC_DEFAULT_HAIKU_MODEL)}}const r=q(s.raw),l=q(r[s.id]),o=Re(l.models).length?Re(l.models):s.models??[],i=$(l.activeModel);return H.has(s.id)?{...n,models:o,active:o.includes(i)?i:o[0]||""}:{...n,primary:o[0]||""}}function Kt(s,n){const r=n.trim().toLowerCase(),l=r?s.filter(c=>c.id.toLowerCase().includes(r)||c.name.toLowerCase().includes(r)||c.provider.toLowerCase().includes(r)):s,o=new Map;for(const c of l){const f=c.provider||"other",h=o.get(f);h?h.push(c):o.set(f,[c])}return[...o.keys()].sort((c,f)=>c.localeCompare(f)).map(c=>({provider:c,items:o.get(c)}))}function ss(){const s=Xe(),n="nr-cli-selected-tool",[r,l]=p.useState({}),[o,i]=p.useState(null),[c,f]=p.useState(""),[h,w]=p.useState(!1),[N,k]=p.useState(!1),[x,M]=p.useState(null),[d,u]=p.useState(()=>{try{return localStorage.getItem(n)}catch{return null}}),[g,j]=p.useState("");function L(t){u(t);try{t?localStorage.setItem(n,t):localStorage.removeItem(n)}catch{}}const R=ee({queryKey:["cli-tools"],queryFn:bt,enabled:oe(),retry:!1}),C=ee({queryKey:["api-keys-for-cli"],queryFn:()=>it(),enabled:oe(),retry:!1}),T=ee({queryKey:["cli-tools","models"],queryFn:kt,enabled:oe(),retry:!1}),y=R.data??{tools:[],origin:"",apiKey:""},P=R.isLoading,ze=R.isError,J=T.data??[],W=p.useMemo(()=>{const t=y.origin||"";return(t.includes("127.0.0.1")||t.includes("localhost"))&&typeof window<"u"?window.location.origin:t},[y.origin]),Y=p.useMemo(()=>{const t=g.trim().toLowerCase();let a=[...y.tools];return t&&(a=a.filter(m=>m.name.toLowerCase().includes(t)||m.id.toLowerCase().includes(t)||(Et[m.id]||"").toLowerCase().includes(t))),a.sort((m,b)=>(m.connected?1:0)!=(b.connected?1:0)?(b.connected?1:0)-(m.connected?1:0):(m.name||m.id).localeCompare(b.name||b.id)),a},[y.tools,g]);p.useEffect(()=>{if(y.tools.length===0||d&&y.tools.some(a=>a.id===d))return;let t=null;try{t=localStorage.getItem(n)}catch{t=null}t&&y.tools.some(a=>a.id===t)&&u(t)},[y.tools,d]);const V=Y.find(t=>t.id===d)||null,je=V&&y.tools.find(t=>t.id===V.id)||V,_=C.data??[],[K,Ne]=p.useState(""),X=_.find(t=>t.id===K);p.useEffect(()=>{_.length>0&&!K&&Ne(_[0].id)},[_,K]),p.useEffect(()=>{const t=_.find(a=>a.id===K);if(!t){f("");return}lt(t.id).then(f).catch(()=>f(""))},[_,y.apiKey,K]),p.useEffect(()=>{l(t=>{let a=!1;const m={...t};for(const b of y.tools)m[b.id]||(m[b.id]=Q(b),a=!0);return a?m:t})},[y.tools]);function E(t,a="default"){a==="success"?se.success(t):a==="error"?se.error(t):se(t)}function U(t,a){l(m=>({...m,[t]:{...m[t]??Q({id:t}),...a}}))}function qe(t,a,m=!1){const b=le(t.id)?[a.fable,a.opus,a.sonnet,a.haiku].filter(Boolean):H.has(t.id)?a.models:[a.primary].filter(Boolean);return Ot({toolId:t.id,baseUrl:ie(t.id,W),apiKey:c||y.apiKey,models:b,primaryModel:H.has(t.id)?a.active:a.primary,subagentModel:a.subagent,fableModel:a.fable,opusModel:a.opus,sonnetModel:a.sonnet,haikuModel:a.haiku},m)}function Qe(t,a){const m=new Blob([t],{type:"text/plain;charset=utf-8"}),b=URL.createObjectURL(m),S=document.createElement("a");S.href=b,S.download=a.split(" + ")[0],S.click(),URL.revokeObjectURL(b)}function Ge(t,a){const m={baseUrl:ie(t.id,W),apiKey:c,models:[a.primary],primaryModel:a.primary,subagentModel:a.subagent};if(le(t.id))return{...m,models:[a.fable,a.opus,a.sonnet,a.haiku],fableModel:a.fable,opusModel:a.opus,sonnetModel:a.sonnet,haikuModel:a.haiku};if(H.has(t.id)){const b=a.models.filter(Boolean),S=a.active||b[b.length-1]||"";return{...m,models:b,primaryModel:S,activeModel:S}}return Lt.has(t.id)?m:_t.has(t.id)?{...m,models:[a.primary]}:m}async function Je(t){if(!G(t))return E(`${t.name} is detection-only`,"error");if(!c&&t.id!=="hermes"&&t.id!=="grok-build"&&t.id!=="omp")return E("Select an API key first","error");const a=r[t.id]??Q(t);i({id:t.id,kind:"apply"});try{await wt(t.id,Ge(t,a)),await s.invalidateQueries({queryKey:["cli-tools"]}),E(`${t.name} connected`,"success")}catch(m){E(te(m,"Connect failed"),"error")}finally{i(null)}}async function We(t){if(Le(t)){i({id:t.id,kind:"disconnect"});try{await Ct(t.id),await s.invalidateQueries({queryKey:["cli-tools"]}),E(`${t.name} disconnected`,"success")}catch(a){E(te(a,"Disconnect failed"),"error")}finally{i(null)}}}async function Ye(t){if(G(t)){M(null),i({id:t.id,kind:"reset"});try{await $e(t.id),l(a=>({...a,[t.id]:Be()})),w(!1),k(!1),await s.invalidateQueries({queryKey:["cli-tools"]}),E(`${t.name} reset`,"success")}catch(a){E(te(a,"Reset failed"),"error")}finally{i(null)}}}async function Ve(){await s.invalidateQueries({queryKey:["cli-tools"]}),E("Refreshed","success")}function we(t){return t.available?t.tier==="detection"?"Detection only":t.connected?"Connected":t.installed?"Not configured":"Not installed":"Unavailable"}function Ce(t){return t.available?t.connected?"ok":t.installed?"warn":"muted":"err"}return e.jsxs("div",{className:O("flex w-full flex-col gap-2 overflow-hidden sm:gap-3 lg:gap-4","h-[calc(100dvh-4.5rem)] max-h-[calc(100dvh-4.5rem)]","lg:h-full lg:max-h-none"),children:[e.jsx(Ze,{className:"mb-0 sm:mb-0 shrink-0",title:"CLI Tools",description:"Detect and configure CLI tools on the machine running Sway Router.",actions:e.jsx(e.Fragment,{children:e.jsxs(I,{size:"sm",variant:"outline",onClick:()=>void Ve(),children:[e.jsx(ae,{className:"h-3.5 w-3.5"}),"Refresh"]})})}),ze?e.jsx("div",{className:"rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:"Unable to load CLI tools. Check your session and backend connection."}):null,e.jsxs("div",{className:"flex min-h-0 flex-1 flex-col gap-2 overflow-hidden sm:gap-3 lg:flex-row lg:gap-4",children:[e.jsxs(Me,{className:O("flex shrink-0 flex-col overflow-hidden","w-full h-[26dvh] max-h-[26dvh] min-h-0 sm:h-[30dvh] sm:max-h-[30dvh] lg:h-full lg:max-h-none lg:min-h-0 lg:w-[280px] xl:w-[320px]"),children:[e.jsx(Se,{className:"space-y-2 border-b border-border p-4",children:e.jsxs("div",{className:"relative",children:[e.jsx(ve,{className:"pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),e.jsx(B,{className:"pl-8",placeholder:"Search tools…",value:g,onChange:t=>j(t.target.value)})]})}),e.jsx(Ae,{className:"flex min-h-0 flex-1 flex-col overflow-hidden p-0",children:e.jsx(ue,{overscrollContain:!0,scrollFade:!0,scrollbarGutter:!0,className:"min-h-0 flex-1",children:e.jsx("div",{className:"p-2",children:P?e.jsx("div",{className:"space-y-2 p-1",children:Array.from({length:6}).map((t,a)=>e.jsx(tt,{className:"h-14 w-full rounded-lg"},a))}):Y.length===0?e.jsx("p",{className:"p-6 text-center text-sm text-muted-foreground",children:g.trim()?"No tools match":"No CLI tools available"}):e.jsx("ul",{className:"space-y-1",children:Y.map(t=>e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>L(t.id),className:O("relative flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors duration-100","outline-none focus-visible:ring-1 focus-visible:ring-white/20",d===t.id?"text-foreground":"hover:bg-surface-hover/70"),children:[d===t.id?e.jsx(ce.span,{layoutId:"cli-tool-highlight",className:"absolute inset-0 rounded-lg bg-surface-hover",transition:{type:"spring",stiffness:420,damping:34,mass:.55}}):null,e.jsx(Te,{toolId:t.id,className:"size-9"}),e.jsxs("div",{className:"relative z-10 min-w-0 flex-1",children:[e.jsx("div",{className:"flex min-w-0 items-center gap-1.5",children:e.jsx("span",{className:"truncate text-sm font-medium",children:t.name})}),e.jsxs("div",{className:"mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5 text-[11px] text-muted-foreground",children:[e.jsx(ke,{tone:Ce(t),className:"text-[10px]",children:we(t)}),t.configPath?e.jsx("code",{className:"truncate font-mono text-muted-foreground/60",children:t.configPath}):null]})]})]})},t.id))})})})})]}),e.jsx(Me,{className:"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden",children:je?(()=>{const t=je,a=r[t.id]??Q(t),m=(o==null?void 0:o.id)===t.id&&o.kind==="apply",b=(o==null?void 0:o.id)===t.id&&o.kind==="disconnect",S=(o==null?void 0:o.id)===t.id&&o.kind==="reset",A=qe(t,a,N);return e.jsxs(Ke,{mode:"wait",initial:!1,children:[e.jsxs(ce.div,{initial:{opacity:0,x:10},animate:{opacity:1,x:0},exit:{opacity:0,x:-10},transition:{type:"spring",stiffness:380,damping:32,mass:.55},className:"flex min-h-0 flex-1 flex-col overflow-hidden",children:[e.jsxs(Se,{className:"flex shrink-0 flex-row flex-wrap items-start justify-between gap-3 border-b border-border p-4 sm:p-5",children:[e.jsxs("div",{className:"flex min-w-0 items-start gap-3",children:[e.jsx(Te,{toolId:t.id,className:"size-10 rounded-xl"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h2",{className:"truncate text-lg font-semibold",children:t.name}),e.jsxs("div",{className:"mt-1 flex flex-wrap items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(ke,{tone:Ce(t),children:we(t)}),e.jsx("span",{className:"font-mono text-xs",children:t.id}),t.configPath?e.jsx("code",{className:"truncate text-xs",children:t.configPath}):null]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[t.connected&&Le(t)?e.jsx(I,{size:"sm",variant:"outline",onClick:()=>void We(t),disabled:b||m||S,children:b?"…":"Disconnect"}):null,G(t)?e.jsxs(e.Fragment,{children:[e.jsxs(I,{size:"sm",variant:"outline",onClick:()=>{k(!1),w(!0)},disabled:!t.available||!t.installed||m||b||S,children:[e.jsx(ct,{className:"h-3.5 w-3.5"}),"Manual config"]}),e.jsx(I,{size:"sm",onClick:()=>void Je(t),disabled:!t.available||!t.installed||m||b||S,className:"min-w-[5.5rem]",children:m?e.jsxs(e.Fragment,{children:[e.jsx(ae,{className:"h-3.5 w-3.5 animate-spin"}),"Applying…"]}):t.connected?"Re-apply":"Apply"}),e.jsxs(I,{size:"sm",variant:"outline",onClick:()=>M(t),disabled:!t.available||!t.installed||m||b||S,className:"text-destructive hover:border-destructive/50 hover:bg-destructive/10 hover:text-destructive",children:[e.jsx(Ee,{className:"h-3.5 w-3.5"}),"Reset"]})]}):null]})]}),e.jsx(Ae,{className:"min-h-0 flex-1 space-y-4 overflow-hidden p-4 sm:p-5",children:e.jsx(ue,{overscrollContain:!0,scrollFade:!0,scrollbarGutter:!0,className:"h-full",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Endpoint"}),e.jsx(B,{readOnly:!0,value:ie(t.id,W),className:"h-8 font-mono text-[11px]"})]}),e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"API key"}),e.jsx("div",{className:"flex items-center gap-1.5",children:_.length>0?e.jsxs(e.Fragment,{children:[e.jsxs(st,{value:K,onValueChange:v=>Ne(v??""),children:[e.jsx(nt,{size:"sm",className:"min-w-0 flex-1 font-mono text-xs",children:e.jsx("span",{className:"truncate",children:X?`${X.name} (${Oe(X)})`:"Select API key"})}),e.jsx(ot,{children:_.map(v=>e.jsxs(at,{value:v.id,children:[v.name," (",Oe(v),")"]},v.id))})]}),e.jsx(ne,{value:c||y.apiKey,className:"h-8 shrink-0 px-2",label:""})]}):e.jsxs(e.Fragment,{children:[e.jsx(B,{readOnly:!0,value:Pt(y.apiKey),className:"h-8 min-w-0 flex-1 font-mono text-[11px]"}),e.jsx(ne,{value:c||y.apiKey,className:"h-8 shrink-0 px-2",label:""})]})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Model aliases"}),le(t.id)?e.jsx("div",{className:"grid gap-3 sm:grid-cols-2",children:Tt.map(v=>e.jsx(Pe,{label:v.label,value:a[v.key],models:J,onChange:Z=>U(t.id,{[v.key]:Z})},v.key))}):H.has(t.id)?e.jsx(Dt,{value:a.models,active:a.active,models:J,label:t.id==="omp"?"Models (optional; live discovery stays enabled)":"Models",onAdd:v=>U(t.id,{models:v.filter(Boolean),active:v.length?a.active:""}),onRemove:v=>U(t.id,{models:a.models.filter(Z=>Z!==v),active:a.active===v?"":a.active}),onSetActive:v=>U(t.id,{active:v})}):e.jsx(Pe,{label:"Model",value:a.primary,models:J,onChange:v=>U(t.id,{primary:v})})]})]})})})]},t.id),e.jsx(me,{open:h,onOpenChange:w,children:e.jsxs(fe,{className:"max-w-3xl",children:[e.jsxs(pe,{children:[e.jsxs(he,{children:["Manual config · ",t.name]}),e.jsxs(xe,{children:["Copy this snapshot into ",e.jsx("code",{className:"font-mono",children:A.fileName}),", or apply it directly to the native config."]})]}),e.jsxs(Ue,{className:"space-y-3 px-6 pb-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 rounded-lg border border-border bg-muted/30 px-3 py-2 text-xs text-muted-foreground",children:[e.jsxs("span",{children:[A.modelCount," model",A.modelCount===1?"":"s"," · ",A.format.toUpperCase()]}),e.jsx("span",{children:"Generated from the current model selections."})]}),A.complete?null:e.jsx("p",{className:"rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning-foreground",children:A.message}),e.jsxs("div",{className:"relative",children:[e.jsx("pre",{className:"max-h-[50dvh] overflow-auto rounded-xl border border-border bg-background p-3 pr-12 font-mono text-[11px] leading-relaxed text-foreground whitespace-pre-wrap break-words",children:A.content}),e.jsx(z,{label:N?"Mask API key":"Reveal API key",children:e.jsx("button",{type:"button",onClick:()=>k(v=>!v),className:"absolute right-2 top-2 rounded-md border border-border bg-card p-1.5 text-muted-foreground transition-colors hover:text-foreground","aria-label":N?"Mask API key":"Reveal API key",children:N?e.jsx(dt,{className:"h-3.5 w-3.5"}):e.jsx(ut,{className:"h-3.5 w-3.5"})})})]})]}),e.jsxs(ge,{variant:"bare",className:"flex-row justify-end",children:[e.jsx(ne,{value:A.content,label:"Copy config"}),e.jsxs(I,{size:"sm",variant:"outline",onClick:()=>Qe(A.content,A.fileName),children:[e.jsx(mt,{className:"h-3.5 w-3.5"}),"Download"]})]})]})})]})})():e.jsx("div",{className:"flex flex-1 items-center justify-center p-6 text-sm text-muted-foreground",children:"Select a CLI tool"})})]}),e.jsx(me,{open:!!x,onOpenChange:t=>!t&&M(null),children:e.jsxs(fe,{className:"sm:max-w-md",children:[e.jsxs(pe,{children:[e.jsxs(he,{children:["Reset ",x==null?void 0:x.name,"?"]}),e.jsxs(xe,{children:["This removes Sway Router settings from ",x==null?void 0:x.name,". All selected models will be cleared, while the CLI installation and unrelated settings stay untouched."]})]}),e.jsxs(ge,{children:[e.jsx(I,{variant:"outline",onClick:()=>M(null),disabled:!!(x&&(o==null?void 0:o.id)===x.id&&o.kind==="reset"),children:"Cancel"}),e.jsx(I,{variant:"destructive",onClick:()=>x&&void Ye(x),disabled:!!(x&&(o==null?void 0:o.id)===x.id&&o.kind==="reset"),children:x&&(o==null?void 0:o.id)===x.id&&o.kind==="reset"?e.jsxs(e.Fragment,{children:[e.jsx(ae,{className:"h-3.5 w-3.5 animate-spin"}),"Resetting…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Ee,{className:"h-3.5 w-3.5"}),"Reset"]})})]})]})})]})}function Te({toolId:s,className:n}){const r=It[s];return e.jsx("span",{"aria-hidden":"true",className:O("relative z-10 flex shrink-0 items-center justify-center rounded-lg bg-white p-1.5 outline outline-1 outline-white/30 outline-offset-2",n),children:r?e.jsx("span",{className:"block size-full bg-background",style:{WebkitMaskImage:`url(${r})`,maskImage:`url(${r})`,WebkitMaskPosition:"center",maskPosition:"center",WebkitMaskRepeat:"no-repeat",maskRepeat:"no-repeat",WebkitMaskSize:"contain",maskSize:"contain"}}):e.jsx(ft,{className:"size-4 text-muted-foreground"})})}function Pe({label:s,value:n,models:r,onChange:l}){const[o,i]=p.useState(!1),[c,f]=p.useState(""),h=p.useRef(null),w=p.useRef(null),N=r,k=p.useMemo(()=>Kt(N,c),[N,c]),x=N.find(u=>u.id===n),M=n||"";p.useEffect(()=>{if(!o)return;function u(j){var L;(L=h.current)!=null&&L.contains(j.target)||i(!1)}function g(j){j.key==="Escape"&&i(!1)}return document.addEventListener("mousedown",u),document.addEventListener("keydown",g),()=>{document.removeEventListener("mousedown",u),document.removeEventListener("keydown",g)}},[o]),p.useEffect(()=>{o&&(f(""),requestAnimationFrame(()=>{var u;return(u=w.current)==null?void 0:u.focus()}))},[o]);function d(u){l(u),i(!1)}return e.jsxs("div",{className:"space-y-1",ref:h,children:[e.jsx("label",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:s}),e.jsxs("div",{className:"relative",children:[e.jsx(z,{label:M||"Select a model",children:e.jsxs("button",{type:"button",onClick:()=>i(u=>!u),className:O("flex h-8 w-full items-center gap-1.5 rounded-md border border-border bg-card px-2 text-left text-xs","outline-none transition-colors hover:bg-surface-hover","focus-visible:border-white/25 focus-visible:ring-1 focus-visible:ring-white/15",o&&"border-white/25"),"aria-label":"Select a model",children:[e.jsx(de,{provider:M.split("/")[0]||"other",className:"h-4 w-4"}),e.jsx("span",{className:"min-w-0 flex-1 truncate font-mono text-[11px] text-foreground",children:M||"Select a model"}),e.jsx(pt,{className:O("h-3.5 w-3.5 shrink-0 text-muted-foreground transition-transform",o&&"rotate-180")})]})}),e.jsx(Ke,{children:o?e.jsx(ce.div,{initial:{opacity:0,scale:.95,y:6},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.97,y:4},transition:{type:"spring",stiffness:420,damping:30,mass:.5},className:"absolute left-0 right-0 z-40 mt-1 w-full min-w-72",children:e.jsxs("div",{className:"flex h-72 flex-col overflow-hidden rounded-xl border border-border bg-card",children:[e.jsx("div",{className:"shrink-0 border-b border-border bg-card p-1.5",children:e.jsxs("div",{className:"relative",children:[e.jsx(ve,{className:"pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground"}),e.jsx(B,{ref:w,value:c,onChange:u=>f(u.target.value),placeholder:"Search models…",className:"h-8 pl-7 text-xs"})]})}),e.jsx(ue,{overscrollContain:!0,scrollFade:!0,className:"min-h-0 flex-1",children:e.jsx(De,{groups:k,query:c,empty:e.jsx("p",{className:"px-3 py-4 text-center text-xs text-muted-foreground",children:r.length===0?"No providers connected yet":"No models match"}),renderItem:(u,g)=>{const j=u.id===((x==null?void 0:x.id)??n);return e.jsxs("button",{type:"button",onClick:()=>d(u.id),className:O("flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left transition-colors",j?"bg-primary/10 text-foreground":"text-foreground hover:bg-surface-hover"),children:[e.jsx(de,{provider:g,className:"h-5 w-5 shrink-0"}),e.jsx(z,{label:u.id,children:e.jsx("span",{className:"min-w-0 flex-1 truncate font-mono text-[11px]",children:u.name||u.id})}),j?e.jsx(Fe,{className:"h-3.5 w-3.5 shrink-0 text-primary"}):null]})}})})]})}):null})]})]})}function Dt({value:s,active:n,models:r,label:l="Models",onAdd:o,onRemove:i,onSetActive:c}){const[f,h]=p.useState(!1),[w,N]=p.useState(""),k=p.useMemo(()=>new Set(s),[s]),x=p.useMemo(()=>{const d=w.trim().toLowerCase(),u=d?r.filter(C=>C.id.toLowerCase().includes(d)||C.name.toLowerCase().includes(d)||C.provider.toLowerCase().includes(d)):r,g=[],j=new Map;for(const C of u)if(C.provider==="combo")g.push(C);else{const y=C.provider||"other",P=j.get(y);P?P.push(C):j.set(y,[C])}const L=C=>[...C].sort((T,y)=>Number(k.has(y.id))-Number(k.has(T.id))||T.name.localeCompare(y.name)),R=[];g.length&&R.push({provider:"Combo",items:L(g)});for(const[C,T]of[...j.entries()].sort((y,P)=>y[0].localeCompare(P[0])))R.push({provider:C,items:L(T)});return{groups:R,isEmpty:u.length===0,hasNone:r.length===0}},[r,w,k]);p.useEffect(()=>{n&&!k.has(n)&&c("")},[s,n]);function M(d){const u=s.includes(d)?s.filter(g=>g!==d):[...s,d];o(u)}return e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:l}),s.length===0?e.jsxs("div",{className:"flex h-8 items-center justify-between rounded-md border border-dashed border-border px-2.5 text-xs text-muted-foreground",children:[e.jsx("span",{children:"No models selected"}),e.jsxs("button",{type:"button",onClick:()=>h(!0),className:"flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] font-medium text-foreground transition-colors hover:bg-surface-hover",children:[e.jsx(Ie,{className:"h-3.5 w-3.5"}),"Select models to add"]})]}):e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("div",{className:"flex flex-wrap gap-1.5",children:s.map(d=>{const u=d===n;return e.jsx(z,{label:u?"Active model":d,children:e.jsxs("span",{className:O("group inline-flex h-7 items-center gap-1 rounded-full border pl-1.5 pr-1 text-[11px] font-mono",u?"border-primary/40 bg-primary/10 text-foreground":"border-border bg-card text-muted-foreground"),children:[e.jsx("button",{type:"button",onClick:()=>c(d),className:"grid h-5 w-5 place-items-center rounded-full transition-colors hover:bg-surface-hover","aria-label":u?"Active model":"Set active",children:e.jsx(_e,{className:O("h-3 w-3",u?"fill-amber-400 text-amber-400":"text-muted-foreground")})}),e.jsx("span",{className:"max-w-32 truncate",children:d}),e.jsx("button",{type:"button",onClick:()=>i(d),className:"grid h-5 w-5 place-items-center rounded-full transition-colors hover:bg-surface-hover","aria-label":"Remove model",children:e.jsx(ht,{className:"h-3 w-3"})})]})},d)})}),n&&e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Active: ",e.jsx("span",{className:"font-mono",children:n})]}),e.jsxs("button",{type:"button",onClick:()=>h(!0),className:"flex items-center gap-1 text-[11px] font-medium text-foreground transition-colors hover:text-primary",children:[e.jsx(Ie,{className:"h-3.5 w-3.5"}),"Add Model"]})]}),e.jsx(me,{open:f,onOpenChange:d=>{h(d),d||N("")},children:e.jsxs(fe,{className:"flex max-h-[min(80dvh,560px)] flex-col p-0",children:[e.jsxs(pe,{children:[e.jsx(he,{children:"Select models"}),e.jsx(xe,{children:"Click a model to add or remove it. Starred model is the active one."})]}),e.jsx("div",{className:"px-6 pb-3",children:e.jsxs("div",{className:"relative",children:[e.jsx(ve,{className:"pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground"}),e.jsx(B,{autoFocus:!0,value:w,onChange:d=>N(d.target.value),placeholder:"Search models…",className:"h-8 pl-7 text-xs"})]})}),e.jsx(Ue,{scrollFade:!0,className:"flex-1 overflow-hidden px-6 pb-6",children:x.hasNone?e.jsx("p",{className:"px-1 py-3 text-center text-xs text-muted-foreground",children:"No providers connected yet"}):x.isEmpty?e.jsx("p",{className:"px-1 py-3 text-center text-xs text-muted-foreground",children:"No models match"}):e.jsx(De,{groups:x.groups,query:w,renderItem:(d,u)=>{const g=k.has(d.id),j=d.id===n;return e.jsxs("button",{type:"button",onClick:()=>M(d.id),className:O("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left transition-colors",g?"bg-primary/10 text-foreground":"text-foreground hover:bg-surface-hover"),children:[e.jsx(de,{provider:u,className:"h-5 w-5 shrink-0"}),e.jsx(z,{label:d.id,children:e.jsx("span",{className:"min-w-0 flex-1 truncate font-mono text-[11px]",children:d.name||d.id})}),j?e.jsx(_e,{className:"h-3.5 w-3.5 shrink-0 fill-amber-400 text-amber-400"}):null,g&&!j?e.jsx(Fe,{className:"h-3.5 w-3.5 shrink-0 text-primary"}):null,g&&j?e.jsx("span",{className:"h-3.5 shrink-0 text-[10px] text-primary",children:"Active"}):null]})}})}),e.jsx(ge,{variant:"bare",children:e.jsx(I,{size:"sm",onClick:()=>{h(!1),N("")},children:"Done"})})]})})]})}export{ss as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as i,j as e,a as de}from"./react-vendor-xnYrwzsL.js";import{u as me,a as B}from"./query-vendor-DVevaSVS.js";import{H as ue}from"./Header-C_9Su9BF.js";import{R as P}from"./ripple-button-l8aMiVVG.js";import{P as xe,a as pe}from"./ProviderModelAccordion-BAifkfVR.js";import{I as O,h as U,e as z,D as V,m as W,n as X,o as Y,F as fe,q as Z,s as he,g as G,a as ee,S as be,t as $,E as ge}from"./index-B6j-9zHy.js";import{F as je,c as ve}from"./frame-cUiti6Lq.js";import{S as ye}from"./segmented-CqmEnQjZ.js";import{S as Ne}from"./skeleton-7uJDiIXe.js";import{T as we,a as Se,b as te,c as K,d as ke,e as T}from"./table-D0M60Tu1.js";import{b as Ce,e as Me,f as De,g as Ee}from"./admin-extras-api-CCdu5TFM.js";import{g as qe}from"./chatStudio-C0zPz_Z_.js";import{b as Pe}from"./api-keys-api-ifAC2Ok3.js";import{p as se}from"./live-mode-CHShLY4E.js";import{ac as ae,q as le,h as re,af as oe,i as ze,X as Ae,a as Fe,ag as Le}from"./icons-vendor-CUx7SB5V.js";import"./accordion-DOOPDDgt.js";import"./ui-vendor-BuM9f2NY.js";import"./motion-vendor-g5fpGzmJ.js";async function Re(){const u=await Pe().catch(()=>""),c={Accept:"application/json"};u&&(c.Authorization=`Bearer ${u}`);const h=await fetch("/v1/models",{credentials:"include",headers:c});if(!h.ok){const n=await h.json().catch(()=>null),l=n==null?void 0:n.error,p=typeof l=="string"?l:(l==null?void 0:l.message)||(n==null?void 0:n.message)||`Models request failed (${h.status})`;throw new Error(p)}return((await h.json()).data??[]).flatMap(n=>{var m;const l=typeof n.id=="string"?n.id.trim():"";if(!l)return[];const p=typeof n.owned_by=="string"&&n.owned_by?n.owned_by:l.includes("/")?l.split("/",1)[0]:"other";return[{id:l,name:((m=n.name)==null?void 0:m.trim())||l,provider:p}]})}function ne({models:u,selected:c,onChange:h,loading:A=!1,error:n,multiple:l=!0,placeholder:p="Select models"}){const[m,g]=i.useState(!1),[f,N]=i.useState(""),w=i.useRef(null),S=i.useRef(null),F=i.useRef(null),[b,v]=i.useState(null);function k(){const s=S.current;if(!s)return;const o=s.getBoundingClientRect(),r=12,x=6,C=window.innerHeight-o.bottom-r,M=o.top-r,D=C<230&&M>C,j=Math.max(144,D?M:C),E=Math.max(120,Math.min(256,j-54)),q=o.width,R=Math.min(Math.max(r,o.left),Math.max(r,window.innerWidth-q-r));v(D?{left:R,bottom:window.innerHeight-o.top+x,width:q,listHeight:E}:{left:R,top:o.bottom+x,width:q,listHeight:E})}i.useEffect(()=>{if(!m)return;function s(o){var x;const r=o.target;w.current&&!w.current.contains(r)&&!((x=F.current)!=null&&x.contains(r))&&g(!1)}return document.addEventListener("mousedown",s),()=>document.removeEventListener("mousedown",s)},[m]),i.useEffect(()=>{if(!m){v(null);return}k();const s=()=>k();return window.addEventListener("resize",s),window.addEventListener("scroll",s,!0),()=>{window.removeEventListener("resize",s),window.removeEventListener("scroll",s,!0)}},[m]);const y=i.useMemo(()=>{const s=new Set(u.map(r=>r.id)),o=c.filter(r=>r&&!s.has(r)).map(r=>{const x=r.split("/").filter(Boolean);return{id:r,name:x[x.length-1]||r,provider:x.length>1?x[0]:"other"}});return[...u,...o]},[u,c]),L=i.useMemo(()=>qe(y,f),[y,f]);function Q(s){if(!l){h([s]),g(!1);return}h(c.includes(s)?c.filter(o=>o!==s):[...c,s])}return e.jsxs("div",{ref:w,className:"relative",children:[e.jsxs("button",{ref:S,type:"button",onClick:()=>g(s=>!s),className:"flex min-h-9 w-full items-center gap-2 rounded-md border border-input bg-surface px-2.5 py-1.5 text-left text-sm transition-colors hover:bg-surface-hover","aria-haspopup":"listbox","aria-expanded":m,children:[e.jsx("span",{className:"min-w-0 flex-1 truncate text-xs text-foreground",children:c.length===0?p:l?`${c.length} model${c.length===1?"":"s"} selected`:c[0]}),e.jsx(ze,{className:`size-4 shrink-0 text-muted-foreground transition-transform ${m?"rotate-180":""}`})]}),c.length>0?e.jsx("div",{className:"mt-2 flex flex-wrap gap-1.5",children:c.map(s=>e.jsxs("span",{className:"inline-flex max-w-full items-center gap-1 rounded-md border border-border bg-muted/45 px-2 py-1 text-[11px] text-foreground",children:[e.jsx(z,{label:s,children:e.jsx("span",{className:"max-w-[15rem] truncate font-mono",children:s})}),e.jsx("button",{type:"button",onClick:()=>h(c.filter(o=>o!==s)),className:"shrink-0 rounded p-0.5 text-muted-foreground hover:bg-surface-hover hover:text-foreground","aria-label":`Remove ${s}`,children:e.jsx(Ae,{className:"size-3"})})]},s))}):null,m&&b?de.createPortal(e.jsxs("div",{ref:F,className:"fixed z-[100] overflow-hidden rounded-xl border border-border bg-card",style:{left:b.left,top:b.top,bottom:b.bottom,width:b.width},children:[e.jsx("div",{className:"border-b border-border p-1.5",children:e.jsxs("div",{className:"relative",children:[e.jsx(le,{className:"pointer-events-none absolute left-2 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground"}),e.jsx(O,{autoFocus:!0,value:f,onChange:s=>N(s.target.value),placeholder:"Search models…","aria-label":"Search models",className:"h-8 pl-7 text-xs"})]})}),A?e.jsx("p",{className:"px-3 py-5 text-center text-xs text-muted-foreground",children:"Loading models…"}):n?e.jsxs("div",{className:"flex items-start gap-2 px-3 py-4 text-xs text-destructive",children:[e.jsx(Fe,{className:"mt-0.5 size-3.5 shrink-0"}),e.jsx("span",{children:G(n,"Unable to load models")})]}):e.jsx(be,{className:"min-h-0",style:{height:b.listHeight},overscrollContain:!0,children:e.jsx("div",{role:"listbox","aria-multiselectable":l,className:"py-1",children:e.jsx(xe,{groups:L,query:f,empty:e.jsx("p",{className:"px-3 py-5 text-center text-xs text-muted-foreground",children:y.length?"No models match":"No provider models available"}),renderItem:(s,o)=>{const r=c.includes(s.id);return e.jsxs("button",{type:"button",role:"option","aria-selected":r,onClick:()=>Q(s.id),className:"flex w-full items-start gap-2 rounded-md px-2.5 py-1.5 text-left text-foreground transition-colors hover:bg-surface-hover",children:[e.jsx(pe,{provider:o,className:"mt-0.5 size-5"}),e.jsx(z,{label:s.id,children:e.jsx("span",{className:"min-w-0 flex-1 break-all font-mono text-[11px] leading-4",children:s.id})}),r?e.jsx(Le,{className:"mt-0.5 size-3.5 shrink-0 text-primary"}):null]})}})})})]}),document.body):null]})}function tt(){var _;const u=me(),[c,h]=i.useState(""),[A,n]=i.useState(!1),[l,p]=i.useState(null),[m,g]=i.useState(null),[f,N]=i.useState(!1),[w,S]=i.useState(""),[F,b]=i.useState([]),[v,k]=i.useState("fallback"),[y,L]=i.useState(""),Q=B({queryKey:["combos"],queryFn:Ee,enabled:se(),retry:!1}),s=B({queryKey:["settings"],queryFn:ge,enabled:se(),retry:!1}),o=B({queryKey:["combos","models"],queryFn:Re,enabled:A,retry:1}),r=Q.data??[],x=Q.isLoading,C=i.useMemo(()=>(o.data??[]).filter(t=>t.provider!=="combo"),[o.data]),M=((_=s.data)==null?void 0:_.comboStrategies)??{},D=i.useMemo(()=>{const t=c.trim().toLowerCase();return t?r.filter(a=>a.name.toLowerCase().includes(t)||a.models.some(d=>d.toLowerCase().includes(t))):r},[r,c]);function j(t,a="default"){a==="success"?$.success(t):a==="error"?$.error(t):$(t)}function E(){S(""),b([]),k("fallback"),L("")}function q(){E(),p(null),n(!0)}function R(t){p(t),S(t.name),b(t.models);const a=M[t.name]||{};k(a.fallbackStrategy==="round-robin"||a.fallbackStrategy==="fusion"||a.fallbackStrategy==="fallback"?a.fallbackStrategy:"fallback"),L(a.judgeModel||""),n(!0)}async function I(t,a,d){const J=(d||s.data||{}).comboStrategies||{};await ee({comboStrategies:{...J,[t]:{...J[t],...a}}}),await u.invalidateQueries({queryKey:["settings"]})}async function ie(){const t=w.trim(),a=F;if(!t)return j("Name required","error");if(!a.length)return j("Add at least one model","error");N(!0);try{const d={fallbackStrategy:v,judgeModel:v==="fusion"&&y.trim()||void 0};l?(await Ce(l.id||l.name,{models:a,name:t!==l.name?t:void 0}),await I(t,d,s.data),await u.invalidateQueries({queryKey:["combos"]}),j("Combo updated","success")):(await Me({name:t,models:a}),await I(t,d,s.data),await u.invalidateQueries({queryKey:["combos"]}),j("Combo created","success")),n(!1),p(null),E()}catch(d){j(G(d,"Save failed"),"error")}finally{N(!1)}}async function ce(){const t=m;if(t){N(!0);try{await De(t.id||t.name);const d=(s.data||{}).comboStrategies||{};if(d[t.name]){const H={...d};delete H[t.name],await ee({comboStrategies:H}),await u.invalidateQueries({queryKey:["settings"]})}await u.invalidateQueries({queryKey:["combos"]}),j("Combo deleted","success"),g(null)}catch(a){j(G(a,"Delete failed"),"error")}finally{N(!1)}}}return e.jsxs("div",{className:"space-y-4",children:[e.jsx(ue,{title:"Combos",actions:r.length>0?e.jsxs(P,{size:"sm",onClick:q,children:[e.jsx(ae,{className:"h-4 w-4"}),"Add combo"]}):null}),e.jsxs("div",{className:"relative max-w-md",children:[e.jsx(le,{className:"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),e.jsx(O,{value:c,onChange:t=>h(t.target.value),placeholder:"Search combos…",className:"pl-9"})]}),e.jsx(je,{className:"overflow-hidden",children:e.jsx(ve,{className:"p-0",children:x?e.jsx("div",{className:"space-y-2 p-4",children:Array.from({length:3}).map((t,a)=>e.jsx(Ne,{className:"h-12 w-full"},a))}):r.length===0?e.jsxs("div",{className:"flex flex-col items-center gap-2 px-4 py-16 text-center",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"No combos yet"}),e.jsxs(P,{size:"sm",onClick:q,children:[e.jsx(ae,{className:"h-4 w-4"}),"Create first combo"]})]}):D.length===0?e.jsx("div",{className:"px-4 py-16 text-center text-sm text-muted-foreground",children:"No combos match your search."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"divide-y divide-border/70 rounded-xl border border-border/70 bg-card sm:hidden",children:D.map(t=>{const a=M[t.name]||{},d=a.fallbackStrategy||"fallback";return e.jsxs("article",{className:"min-w-0 space-y-2.5 p-3",children:[e.jsxs("div",{className:"flex min-w-0 items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"truncate text-sm font-medium",children:t.name}),e.jsx(U,{variant:"outline",className:"mt-1 text-[10px]",children:d})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-1.5",children:[e.jsx(z,{label:"Edit",children:e.jsx("button",{type:"button",className:"inline-flex h-8 w-8 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-surface-hover hover:text-foreground",onClick:()=>R(t),"aria-label":"Edit combo",children:e.jsx(re,{className:"h-3.5 w-3.5"})})}),e.jsx(z,{label:"Delete",children:e.jsx("button",{type:"button",className:"inline-flex h-8 w-8 items-center justify-center rounded-md border border-border text-muted-foreground hover:border-destructive/40 hover:bg-destructive/10 hover:text-destructive",onClick:()=>g(t),"aria-label":"Delete combo",children:e.jsx(oe,{className:"h-3.5 w-3.5"})})})]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Models"}),e.jsx("p",{className:"mt-1 break-words font-mono text-[11px] leading-4 text-muted-foreground",children:t.models.join(" → ")}),d==="fusion"&&a.judgeModel?e.jsxs("p",{className:"mt-1 break-words text-[10px] text-muted-foreground",children:["Judge: ",a.judgeModel]}):null]})]},t.id||t.name)})}),e.jsx("div",{className:"hidden sm:block",children:e.jsxs(we,{className:"min-w-[40rem] text-[13px]",children:[e.jsx(Se,{className:"sticky top-0 z-10 bg-background text-[10px] uppercase text-muted-foreground",children:e.jsxs(te,{className:"border-b border-border/80",children:[e.jsx(K,{className:"px-4 py-2 font-medium",children:"Name"}),e.jsx(K,{className:"px-2 py-2 font-medium",children:"Strategy"}),e.jsx(K,{className:"px-2 py-2 font-medium",children:"Models"}),e.jsx(K,{className:"px-4 py-2 font-medium text-right",children:"Actions"})]})}),e.jsx(ke,{children:D.map(t=>{const a=M[t.name]||{},d=a.fallbackStrategy||"fallback";return e.jsxs(te,{className:"border-b border-border/60 last:border-0 hover:bg-muted/30",children:[e.jsx(T,{className:"max-w-[12rem] truncate px-4 py-2 font-medium",children:t.name}),e.jsx(T,{className:"px-2 py-2",children:e.jsx(U,{variant:"outline",className:"text-[10px]",children:d})}),e.jsx(T,{className:"px-2 py-2",children:e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"max-w-[24rem] truncate font-mono text-[11px] text-muted-foreground",children:t.models.join(" → ")}),d==="fusion"&&a.judgeModel?e.jsxs("p",{className:"mt-0.5 text-[10px] text-muted-foreground",children:["judge: ",a.judgeModel]}):null]})}),e.jsx(T,{className:"px-4 py-2",children:e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsx(z,{label:"Edit",children:e.jsx("button",{type:"button",className:"inline-flex h-7 w-7 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-surface-hover hover:text-foreground",onClick:()=>R(t),"aria-label":"Edit combo",children:e.jsx(re,{className:"h-3.5 w-3.5"})})}),e.jsx(z,{label:"Delete",children:e.jsx("button",{type:"button",className:"inline-flex h-7 w-7 items-center justify-center rounded-md border border-border text-muted-foreground hover:border-destructive/40 hover:bg-destructive/10 hover:text-destructive",onClick:()=>g(t),"aria-label":"Delete combo",children:e.jsx(oe,{className:"h-3.5 w-3.5"})})})]})})]},t.id||t.name)})})]})})]})})}),e.jsx(V,{open:A,onOpenChange:t=>{t||(n(!1),p(null),E())},children:e.jsxs(W,{className:"max-h-[90vh]",children:[e.jsx(X,{children:e.jsx(Y,{children:l?"Edit combo":"Create combo"})}),e.jsxs(fe,{className:"space-y-4",children:[e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Name"}),e.jsx(O,{value:w,onChange:t=>S(t.target.value),placeholder:"smart"})]}),e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Models"}),e.jsx(ne,{models:C,selected:F,onChange:b,loading:o.isLoading,error:o.error,placeholder:"Select provider models"})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Strategy"}),e.jsx(ye,{size:"sm",value:v,onChange:k,options:[{value:"fallback",label:"Fallback"},{value:"round-robin",label:"Round-robin"},{value:"fusion",label:"Fusion"}]})]}),v==="fusion"?e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Judge model"}),e.jsx(ne,{models:C,selected:y?[y]:[],onChange:t=>L(t[0]||""),loading:o.isLoading,error:o.error,multiple:!1,placeholder:"Select judge model"})]}):null]}),e.jsxs(Z,{children:[e.jsx(P,{variant:"outline",onClick:()=>{n(!1),p(null)},disabled:f,children:"Cancel"}),e.jsx(P,{onClick:ie,disabled:f,children:f?"Saving…":l?"Save":"Create"})]})]})}),e.jsx(V,{open:!!m,onOpenChange:t=>{t||g(null)},children:e.jsxs(W,{children:[e.jsxs(X,{children:[e.jsx(Y,{children:"Delete combo?"}),e.jsxs(he,{children:[e.jsx("span",{className:"font-medium text-foreground",children:m==null?void 0:m.name})," ","and its strategy override will be removed."]})]}),e.jsxs(Z,{children:[e.jsx(P,{variant:"outline",onClick:()=>g(null),disabled:f,children:"Cancel"}),e.jsx(P,{variant:"destructive",onClick:ce,disabled:f,children:f?"Deleting…":"Delete"})]})]})})]})}export{tt as default};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{j as s,r as d}from"./react-vendor-xnYrwzsL.js";import{H as Te}from"./Header-C_9Su9BF.js";import{c as E,I as Ne,e as V,S as Ce,h as Ae,D as ve,m as we,n as ye,o as Oe,s as Le,q as je,y as Fe,t as M,g as Z}from"./index-B6j-9zHy.js";import{R as y}from"./ripple-button-l8aMiVVG.js";import{F as De,a as _e,c as Y}from"./frame-cUiti6Lq.js";import{af as Me,q as ke,aI as Pe,ag as Ue,ad as Be}from"./icons-vendor-CUx7SB5V.js";import"./query-vendor-DVevaSVS.js";import"./ui-vendor-BuM9f2NY.js";import"./motion-vendor-g5fpGzmJ.js";const J={healthy:"bg-success",active:"bg-success",degraded:"bg-warning",down:"bg-destructive",inactive:"bg-muted-foreground",unknown:"bg-muted-foreground"};function Ie({status:t="unknown",className:e,pulse:r=!0}){return s.jsxs("span",{className:E("relative inline-flex h-2.5 w-2.5",e),children:[r&&(t==="healthy"||t==="active")&&s.jsx("span",{className:E("absolute inline-flex h-full w-full animate-ping rounded-full opacity-40",J[t])}),s.jsx("span",{className:E("relative inline-flex h-2.5 w-2.5 rounded-full",J[t])})]})}const Q={AUTH:"Account routing",Auth:"Authentication",API:"API request",A4_3:"Compatibility retry",A4_4:"Compatibility retry",AutoPing:"Quota monitor",BG_TOKEN_REFRESH:"Token refresh",CHAT:"Chat request",CLIENT:"Client detection",CODEX:"Codex",COMBO:"Model fallback",CTRL:"Connection",DATA_DIR:"Data directory",DB:"Database",FETCH:"Provider",FORMAT:"Format conversion",FUSION:"Model fusion",InitApp:"Server startup",LOCK:"Account",MODALITY:"Input processing",NetworkMonitor:"Network monitor",PASSTHROUGH:"Provider passthrough",ProjectId:"Project setup",PROTOBUF:"Data encoding",ProxyFetch:"Proxy connection",RESPONSE:"Provider",RTK:"Token optimization",SSE:"Streaming",STREAM:"Streaming",TLS:"Secure connection",TOKEN:"Token refresh",TOKEN_REFRESH:"Token refresh",TOOLDEDUP:"Tool processing",Tunnel:"Cloudflare tunnel"},He={DEBUG:"Details",DONE:"Request",ERROR:"Error",FALLBACK:"Fallback",FETCH:"Provider",LOCK:"Account",REQUEST:"HTTP request",RESPONSE:"Provider",RETRY:"Retry",START:"Request",STREAM:"Streaming",WARN:"Warning"};function Ke(t){return t.replace(/\r\n/g,`
|
|
2
|
+
`).split(`
|
|
3
|
+
`).map(e=>e.replace(/[ \t]+/g," ").trim()).join(`
|
|
4
|
+
`).trim()}function O(t){if(!t.includes("@"))return t;const[e,r]=t.split("@",2);return!e||!r?t:`${e.slice(0,3)}…@${r}`}function u(t){const e=Number(t.replace(/,/g,""));return Number.isFinite(e)?e.toLocaleString("en-US"):t}function v(t){const e=Number(t.replace(/,/g,"").replace(/B$/i,""));return Number.isFinite(e)?e<1024?`${e} bytes`:e<1024*1024?`${(e/1024).toFixed(e<10*1024?1:0)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`:t}function x(t){const e=Number(t.replace(/,/g,""));return Number.isFinite(e)?e>=1e3?`${(e/1e3).toFixed(2).replace(/\.00$/,"")}s`:`${e}ms`:t}function Ge(t,e){return e.toLowerCase().includes("account")||e.toLowerCase()==="acc"?O(t):/^(?:in|out|input|output|active|due|excluded|emitted|recvLines|chunks|messages|tools)$/i.test(e)?u(t):/^(?:body|bytes|size)$/i.test(e)&&/^\d+(?:B)?$/i.test(t)?v(t):/^(?:dur|duration|ttft|connectTimeout|stallTimeout)$/i.test(e)&&/^(?:\d+)(?:ms)?$/i.test(t)?x(t.replace(/ms$/i,"")):t}function ue(t){return t.replace(new RegExp("(?<![?&/:])\\b([A-Za-z][A-Za-z0-9_-]*)=([^ |·,]+)(?=\\s*(?:\\||·|,|$))","g"),(e,r,n)=>`${r}: ${Ge(n,r)}`)}function b(t){return t.split(/\s+·\s+|\s*\|\s*/).map(e=>e.trim()).filter(Boolean).map(e=>{if(/^FMT:\s*/i.test(e))return e.replace(/^FMT:\s*/i,"Format: ").replace(/→/g," → ");if(/^THINK:/i.test(e))return e.replace(/^THINK:/i,"Reasoning: ");if(/^ACC:/i.test(e))return`Account: ${O(e.replace(/^ACC:/i,"").trim())}`;if(/^(?:STREAM|stream)$/i.test(e))return"Streaming response";if(/^JSON$/i.test(e))return"JSON response";const r=e.match(/^(\d+)\s+MSG$/i);if(r)return`${u(r[1])} messages`;const n=e.match(/^(\d+)\s+TOOL$/i);if(n)return`${u(n[1])} tools`;if(/^attempt=/i.test(e))return e.replace(/^attempt=/i,"Attempt: ");if(/^reason=/i.test(e)){const l=e.replace(/^reason=/i,"").trim();return`Reason: ${l==="initial"?"initial request":l}`}if(/^TTFT\s+\d+ms$/i.test(e))return e.replace(/^TTFT\s+/i,"First token: ").replace(/^(First token:\s*)(\d+)ms$/i,(l,g,S)=>`${g}${x(S)}`);const a=e.match(/^IN\s+(\d+)$/i);if(a)return`Input tokens: ${u(a[1])}`;const c=e.match(/^OUT\s+(\d+)$/i);return c?`Output tokens: ${u(c[1])}`:/^\d+ms$/i.test(e)?`Duration: ${x(e.slice(0,-2))}`:ue(e).replace(/\bttft:/gi,"First token:").replace(/\bct:/gi,"Content type:").replace(/\bcl:/gi,"Content length:").replace(/\bdur:/gi,"Duration:").replace(/\bchunks:/gi,"Chunks:").replace(/\bbytes:/gi,"Bytes:").replace(/\bstallTimeout:/gi,"Stall timeout:").replace(/\bconnectTimeout:/gi,"Connection timeout:")}).join(" · ")}function X(t){var l,g,S;const e=t.match(/^POST\s+(.+?)\s+→\s+(.+?)(?:\s+·\s+([\s\S]+))?$/i);if(!e)return b(t);const a=`${((S=(g=(l=e[3])==null?void 0:l.match(/\b(?:STREAM|JSON)\b/i))==null?void 0:g[0])==null?void 0:S.toLowerCase())==="stream"?"Sent streaming request":"Sent request"}: ${e[1]} → ${e[2]}`,c=e[3]?b(e[3]):"";return c?`${a} · ${c}`:a}function qe(t){const e=t.match(/^([A-Z0-9_-]+)\s+→\s+([^·|]+)(?:\s+(?:·|\|)\s+([\s\S]+))?$/i);if(!e)return b(t);const r=e[3]?b(e[3]):"";return`Connecting to ${e[1]} at ${e[2].trim()}${r?` · ${r}`:""}`}function ze(t){const e=t.match(/^([A-Z0-9_-]+)\s+(\d{3})(?:\s+·\s+([\s\S]+))?$/i);if(!e)return b(t);const r=e[3]?b(e[3]):"";return`Provider response: ${e[1]} returned ${e[2]}${r?` · ${r}`:""}`}function We(t){const e=t.split(/\s+·\s+/).map(a=>a.trim()).filter(Boolean);if(!e.length||!/^\d+ms$/i.test(e[0]))return b(t);const[r,...n]=e;return`Request completed in ${x(r.slice(0,-2))}${n.length?` · ${b(n.join(" · "))}`:""}`}function de(t){const e=t.match(/^A4\.[34](?:\s+)?(?:·\s+)?(.+)$/i);return e?`Compatibility retry · ${e[1].replace(/^pre-content\s+/i,"before response content: ").replace(/\bauth-error\b/gi,"provider authentication failed").replace(/socket close/gi,"connection closed").replace(/^reactive refresh\s*/i,"refreshing provider credentials: ").replace(/^without\s+/i,"without unsupported field ").replace(/socket retry succeeded/i,"connection retry succeeded").replace(/retry succeeded/i,"retry succeeded")}`:/^TOKEN REFRESHED/i.test(t)?t.replace(/^TOKEN REFRESHED/i,"Provider credentials refreshed"):/^pre-stripped\s+\(cached\)/i.test(t)?t.replace(/^pre-stripped\s+\(cached\)\s*/i,"Compatibility settings applied · removed ").replace(/:\s*/," fields: "):/^retry after strip/i.test(t)?t.replace(/^retry after strip/i,"Compatibility retry failed after removing"):/^preview failed/i.test(t)?t.replace(/^preview failed/i,"Response preview failed").replace(/\s*\(non-fatal\)/i,""):/^FALLBACK/i.test(t)?b(t.replace(/^FALLBACK\s*/i,"")):b(t)}function Ve(t){const e=t.match(/^⇄\s*ACC:([^\s]+)\s+UNAVAILABLE\s+\((\d{3})\)\s+→\s+NEXT ACCOUNT/i);return e?`Account ${O(e[1])} is unavailable (${e[2]}); trying the next account`:de(t)}function Ze(t){let e=t.match(/^([^|]+)\|\s*total connections:\s*(\d+),\s*(?:excludeIds|excluded accounts):\s*([^,]+),\s*model:\s*(.+)$/i);return e?`${e[1].trim()} has ${u(e[2])} accounts · excluded: ${e[3].trim()} · model: ${e[4].trim()}`:(e=t.match(/^([^|]+)\|\s*available:\s*(\d+)\/(\d+)$/i),e?`${e[1].trim()} account availability: ${u(e[2])} of ${u(e[3])}`:(e=t.match(/^([^|]+)\|\s*pinned to\s+([^\s]+)\s+\(([^)]+)\)/i),e?`${e[1].trim()} is using account ${e[3]} (${e[2]})`:(e=t.match(/^([^|]+)\|\s*cache-affine\(([^)]+)\)\s+→\s+(.+)$/i),e?`${e[1].trim()} selected a sticky account (${e[2]}) · ${e[3]}`:(e=t.match(/^([^|]+)\|\s*all\s+(\d+)\s+accounts locked for\s+(.+?)\s+\(([^)]+)\)/i),e?`${e[1].trim()}: all ${u(e[2])} accounts are locked for ${e[3]} · available ${e[4]}`:(e=t.match(/^([^|]+)\|\s*account pool busy\s+\((\d+) candidates,\s*queue=(\d+)\)/i),e?`${e[1].trim()}: account pool is busy · ${u(e[2])} candidates · queue limit ${u(e[3])}`:/^No credentials for/i.test(t)?t.replace(/^No credentials for/i,"No credentials are configured for"):/^No active credentials for provider:/i.test(t)?t.replace(/^No active credentials for provider:/i,"No active credentials are available for provider:"):P(t))))))}function ee(t){let e=t.match(/^flush\s*·\s*provider=([^·]+)\s*·\s*model=([^·]+)\s*·\s*recvLines=(\d+)\s*·\s*emitted=(\d+)\s*·\s*events=\[([^\]]*)\]/i);return e?`Stream summary: ${e[1].trim()} · model ${e[2].trim()} · received ${u(e[3])} lines · emitted ${u(e[4])} events · events: ${e[5]||"none"}`:(e=t.match(/^pipe start\s*·\s*stallTimeout=(\d+)ms/i),e?`Stream started · stall timeout: ${x(e[1])}`:(e=t.match(/^chunk\s+#(\d+)\s*·\s*size=(\d+)B\s*·\s*gap=(\d+)ms\s*·\s*total=(\d+)B/i),e?`Received stream chunk ${e[1]} · ${v(e[2])} · ${x(e[3])} since previous · ${v(e[4])} total`:(e=t.match(/^upstream EOF\s*·\s*chunks=(\d+)\s*·\s*bytes=(\d+)\s*·\s*dur=(\d+)ms/i),e?`Provider stream ended · ${u(e[1])} chunks · ${v(e[2])} · ${x(e[3])}`:(e=t.match(/^STALL TIMEOUT\s+(\d+)ms\s+\|\s+chunks=(\d+)\s+\|\s+bytes=(\d+)\s+\|\s+sinceLast=(\d+)ms/i),e?`Stream stalled for ${x(e[4])} · timeout ${x(e[1])} · ${u(e[2])} chunks · ${v(e[3])}`:(e=t.match(/^(complete|error|disconnect)(?::\s*)?(.+)$/i),e?`Stream ${e[1].toLowerCase()}: ${b(e[2])}`:b(t))))))}function Ye(t){const e=t.match(/^TRANSFORM\s*·\s*(.*)$/i);return e?`Token optimization applied · ${e[1].split(/\s+·\s+/).map(n=>n.replace(/^CAVEMAN:/i,"Caveman prompt: ").replace(/^PONYTAIL:/i,"Ponytail prompt: ")).join(" · ")}`:b(t)}function P(t){return ue(t).replace(/^RESPONSE_ERROR\s+(\d{3})/i,"Provider response failed with status $1").replace(/^REQUEST\s+/i,"Received request ").replace(/\bFMT:/gi,"Format:").replace(/\bTHINK:/gi,"Reasoning:").replace(/\bACC:/gi,"Account:").replace(/\bTTFT\s+(\d+)ms/gi,(e,r)=>`First token: ${x(r)}`).replace(/\bIN\s+(\d+)\b/gi,(e,r)=>`Input tokens: ${u(r)}`).replace(/\bOUT\s+(\d+)\b/gi,(e,r)=>`Output tokens: ${u(r)}`).replace(/\bCAVEMAN:/gi,"Caveman prompt:").replace(/\bPONYTAIL:/gi,"Ponytail prompt:").replace(/\bSSE overloaded\b/gi,"Provider temporarily overloaded").replace(/\b(?:cache-affine|cache affinity)\b/gi,"sticky cache routing").replace(/\bmodelLocked\b/gi,"model temporarily locked").replace(/\bexcludeIds\b/gi,"excluded accounts").replace(/\binputItems\b/gi,"input items").replace(/\bprefetchImages\b/gi,"image preparation").replace(/\bstraggler\/timeout\b/gi,"slow or timed-out response").replace(/\bpanel=/gi,"panel: ").replace(/\bjudge=/gi,"reviewer: ").replace(/\bquorum=/gi,"minimum responses: ").replace(/\bsticky=/gi,"sticky limit: ").replace(/\bstrategy:/gi,"routing strategy:").replace(/\bfan-out collected\b/gi,"parallel model responses collected").replace(/\breturned empty content\b/gi,"returned an empty response").replace(/\bpanicked\b/gi,"failed").replace(/\bSTREAM\b/gi,"Streaming response").replace(/\b(\d+)\s+MSG\b/gi,(e,r)=>`${u(r)} messages`).replace(/\b(\d+)\s+TOOL\b/gi,(e,r)=>`${u(r)} tools`).replace(/\s{2,}/g," ").replace(/(Account:\s+)([^\s·|]+@[^\s·|]+)/gi,(e,r,n)=>`${r}${O(n)}`).trim()}function te(t,e={}){var l,g;const r=Ke(t);if(!r)return"";const n=((l=e.label)==null?void 0:l.toUpperCase())||"",a=((g=e.source)==null?void 0:g.toUpperCase())||"";if(n==="START")return X(r);if(n==="FETCH"||a==="FETCH")return qe(r);if(n==="RESPONSE"||a==="RESPONSE")return ze(r);if(n==="DONE")return We(r);if(n==="REQUEST")return P(r);const c=a.replace(/\./g,"_");return n==="RETRY"||c==="A4_3"||c==="A4_4"?de(r):n==="FALLBACK"||a==="FALLBACK"?Ve(r):a==="AUTH"?Ze(r):n==="STREAM"||a==="SSE"||a==="STREAM"||a==="CTRL"?ee(r):/^POST\s+/i.test(r)?X(r):/^TRANSFORM\s*·/i.test(r)?Ye(r):/^(?:flush|pipe start|chunk\s+#|upstream EOF|STALL TIMEOUT|complete|error|disconnect)/i.test(r)?ee(r):P(r)}function Je(t){const e=t.trim();return e?He[e.toUpperCase()]||Q[e]||Q[e.toUpperCase().replace(/\./g,"_")]||e.replace(/[_:-]+/g," ").replace(/\b\w/g,r=>r.toUpperCase()):"Runtime"}const re=1e3,pe=["LOG","INFO","SUCCESS","WARN","ERROR","DEBUG"],Qe=/^\s*\[([A-Za-z]+)\]/,Xe=/^\s*([A-Za-z]+)\b/,se=/(?:\bERROR\b|\b(?:Reference|Type|Syntax|Range|URI)Error\b|\b(?:Error|Exception):|\bstatus\s*[=:]\s*5\d\d\b|\bHTTP\s+5\d\d\b)/i,et=/(?:\bWARN(?:ING)?\b|\bstatus\s*[=:]\s*4\d\d\b|\bHTTP\s+4\d\d\b)/i,tt=/(?:\b(?:HTTP\s*)?2\d\d\b|\bstatus\s*[=:]\s*2\d\d\b|\b(?:OK|SUCCESS|PASSED|HEALTHY)\b)/i,rt=/[\p{Emoji_Presentation}\p{Extended_Pictographic}�️]/gu,st=/(?:[A-Za-z]:[\\/]|\/)[^|]*?\.swayrouter[\\/]+db[\\/]+data\.sqlite/gi,nt=/^(?:(\w[\w-]*)\s+)?(START|FETCH|RESPONSE|RETRY|DONE|WARN|ERROR|FALLBACK|LOCK|REQUEST|STREAM)\s+([\s\S]+)$/i,it=/^(?:(\w[\w-]*)\s+)?DEBUG\s+([A-Z][A-Z0-9_-]*)\s*(?:·\s*)?([\s\S]*)$/i;function me(t){return t.split(/\r?\n/).map(e=>e.replace(/[ \t]+/g," ").trimEnd()).filter((e,r,n)=>e.length>0||r<n.length-1).join(`
|
|
5
|
+
`).trim()}function ne(t){return me(t.replace(rt,"").replace(st,".swayrouter\\db\\data.sqlite").replace(/^\s*\[\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?\]\s*/,""))}function L(t){const e=t.match(/^\s*\[(?:LOG|INFO|WARN|ERROR|DEBUG)\]\s*/i);if(e)return t.slice(e[0].length);const r=t.match(/^\s*(?:LOG|INFO|WARN|ERROR|DEBUG)\b\s*/i);return r?t.slice(r[0].length):t}function U(t){const e=L(t).trim(),r=e.match(it);if(r)return{tag:r[1]??null,label:r[2].toUpperCase(),message:r[3].trim()};const n=e.match(nt);return n?{tag:n[1]??null,label:n[2].toUpperCase(),message:n[3]}:null}function ie(t){const e=me(t),r=e.match(/^(.*?)(?:\s+)(\{[\s\S]*\})$/);if(!r)return e;try{const n=JSON.parse(r[2]);if(!n||typeof n!="object"||Array.isArray(n))return e;const a=Object.entries(n).map(([c,l])=>{if(typeof l=="string")return`${c}=${l}`;if(l===null)return`${c}=null`;try{return`${c}=${JSON.stringify(l)}`}catch{return`${c}=${String(l)}`}});return a.length?`${r[1].trim()} · ${a.join(" · ")}`:r[1].trim()}catch{return e}}function oe(t){var c;const e=U(t);if(se.test(t))return"ERROR";if(tt.test(t)||(e==null?void 0:e.label)==="DONE")return"SUCCESS";const r=t.match(Qe),a=(r?r[1]:((c=t.match(Xe))==null?void 0:c[1])??"").toUpperCase();return pe.includes(a)?a:/^(?:\w[\w-]*\s+)?DEBUG\b/i.test(L(t).trim())?"DEBUG":e?e.label==="ERROR"?"ERROR":["WARN","RETRY","FALLBACK"].includes(e.label)?"WARN":"INFO":se.test(t)?"ERROR":et.test(t)?"WARN":"LOG"}function ot(t){var n;const e=U(t);if(e)return e.label;const r=(n=L(t).match(/^\s*(?:\[([^\]]+)\]\s*)+/))==null?void 0:n[1];return r?r.trim().slice(0,32):"runtime"}function at(t){return Je(t)}function ct(t){var c;const e=U(t);if(e)return te(ie(e.message),{label:e.label,source:e.label});const r=L(t),n=((c=r.match(/^\s*(?:\[([^\]]+)\]\s*)+/))==null?void 0:c[1])||"",a=r.replace(/^\s*(?:\[[^\]]+\]\s*)+/,"");return te(ie(a),{source:n})}function k(t){return t.length>re?t.slice(-re):t}function lt(t){const e=Date.now();return t.map(r=>({line:r,ts:e}))}function ae(t){const e=Date.now();return t.filter(r=>typeof(r==null?void 0:r.line)=="string").map(r=>({line:r.line,ts:r.ts>0&&Number.isFinite(r.ts)?r.ts:e}))}function ce(t){const e=new Date(t),r=n=>String(n).padStart(2,"0");return`${r(e.getHours())}:${r(e.getMinutes())}:${r(e.getSeconds())}`}function fe(t){switch(t){case"SUCCESS":return"bg-success";case"ERROR":return"bg-destructive";case"WARN":return"bg-warning";case"INFO":return"bg-info";case"DEBUG":return"bg-debug";default:return"bg-muted-foreground/55"}}function ut(t){switch(t){case"SUCCESS":return"success";case"ERROR":return"error";case"WARN":return"warning";case"INFO":return"info";case"DEBUG":return"debug";default:return"outline"}}function le({label:t,value:e,count:r,active:n,onClick:a}){const c=e==="all"?null:e;return s.jsxs("button",{type:"button","aria-pressed":n,onClick:()=>a(e),className:E("inline-flex shrink-0 items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs transition-colors",n?"border-border bg-white/[0.08] text-foreground":"border-transparent text-muted-foreground hover:border-border/70 hover:bg-white/[0.04] hover:text-foreground"),children:[s.jsx("span",{"aria-hidden":"true",className:E("size-1.5 rounded-full",c?fe(c):"bg-foreground/80")}),s.jsx("span",{children:t}),s.jsx("span",{className:"tabular-nums text-[11px] text-muted-foreground",children:r})]})}function St(){const[t,e]=d.useState(!1),[r,n]=d.useState(!1),[a,c]=d.useState(!1),[l,g]=d.useState([]),[S,he]=d.useState(""),[T,B]=d.useState("all"),[N,ge]=d.useState(!0),[I,be]=d.useState(!0),[j,H]=d.useState(!1),F=d.useRef(null),C=d.useRef(null),K=d.useDeferredValue(S);d.useEffect(()=>{let i=!1,o=null,p=null,m=null,f=1e3,$=0;const q=25e3*2+5e3,D=()=>{m&&clearTimeout(m),m=null},z=()=>{if(i||p)return;const R=Math.floor(Math.random()*Math.min(500,f/2));p=setTimeout(()=>{p=null,W()},f+R),f=Math.min(f*2,1e4)},w=()=>{D(),m=setTimeout(()=>{if(!(i||!o)){if(Date.now()-$<q){w();return}o.close(),o=null,e(!1),z()}},q)},W=()=>{if(i||o)return;const R=new EventSource("/api/translator/console-logs/stream");o=R,$=Date.now(),w(),R.onopen=()=>{i||o!==R||(f=1e3,$=Date.now(),e(!0),w())},R.onerror=()=>{o===R&&(D(),e(!1),R.close(),o=null,z())},R.onmessage=Se=>{if(i||o!==R)return;$=Date.now(),w();let h;try{h=JSON.parse(Se.data)}catch{return}if(h.type==="init")g(k(ae(h.entries)));else if(h.type==="line")g(_=>k([..._,{line:h.line,ts:typeof h.ts=="number"&&Number.isFinite(h.ts)?h.ts:Date.now()}]));else if(h.type==="lines"){const _=Array.isArray(h.lines)&&typeof h.lines[0]=="object"?ae(h.lines):lt(h.lines);g($e=>k([...$e,..._]))}else h.type==="clear"&&g([])}};return W(),()=>{i=!0,p&&clearTimeout(p),p=null,D(),o==null||o.close(),o=null}},[]),d.useEffect(()=>{const i=F.current;if(!i)return;const o=()=>{const p=i.scrollHeight-i.scrollTop-i.clientHeight;be(p<28)};return i.addEventListener("scroll",o,{passive:!0}),o(),()=>i.removeEventListener("scroll",o)},[]),d.useEffect(()=>{if(!I)return;const i=F.current;i&&(i.scrollTop=i.scrollHeight)},[l,I]),d.useEffect(()=>()=>{C.current&&clearTimeout(C.current)},[]);async function Ee(){c(!1),n(!0);try{await Fe.delete("/translator/console-logs"),g([]),M.success("Console logs cleared")}catch(i){M.error(Z(i,"Clear failed"))}finally{n(!1)}}const Re=d.useMemo(()=>{const i={LOG:0,INFO:0,SUCCESS:0,WARN:0,ERROR:0,DEBUG:0};for(const o of l)i[oe(ne(o.line))]+=1;return i},[l]),A=d.useMemo(()=>{const i=K.trim().toLowerCase();return l.map(({line:o,ts:p},m)=>{const f=ne(o);return{raw:f,message:ct(f),source:at(ot(f)),level:oe(f),ts:p,index:m}}).filter(({level:o})=>T==="all"||T===o).filter(({raw:o,message:p,source:m})=>!i||`${o} ${p} ${m}`.toLowerCase().includes(i))},[T,K,l]);async function xe(){const i=A.map(({message:o,source:p,level:m,ts:f})=>`${ce(f)} ${m} ${p} — ${o}`).join(`
|
|
6
|
+
`);try{await navigator.clipboard.writeText(i),H(!0),C.current&&clearTimeout(C.current),C.current=setTimeout(()=>H(!1),1600)}catch(o){M.error(Z(o,"Copy failed"))}}const G=A.length;return s.jsxs("div",{className:"space-y-4",children:[s.jsx(Te,{title:"Console Logs",actions:s.jsxs(y,{size:"sm",variant:"outline",onClick:()=>c(!0),disabled:r,children:[s.jsx(Me,{className:"h-3.5 w-3.5"}),r?"Clearing…":"Clear"]})}),s.jsxs(De,{className:"overflow-hidden",children:[s.jsx(_e,{className:"gap-3 border-b border-border px-3 py-3 sm:px-4",children:s.jsxs("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(Ie,{status:t?"active":"down",pulse:t}),s.jsx("span",{className:E("text-xs font-medium",t?"text-emerald-400":"text-destructive"),children:t?"Live":"Reconnecting"}),s.jsxs("span",{className:"text-xs text-muted-foreground",children:[l.length.toLocaleString()," ",l.length===1?"event":"events"]}),G!==l.length?s.jsxs("span",{className:"text-xs text-muted-foreground/70",children:[G.toLocaleString()," shown"]}):null]}),s.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-2",children:[s.jsxs("div",{className:"relative min-w-0 flex-1 sm:w-56 sm:flex-none",children:[s.jsx(ke,{className:"pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground"}),s.jsx(Ne,{value:S,onChange:i=>he(i.target.value),placeholder:"Search logs","aria-label":"Search console logs",className:"h-8 w-full pl-8 text-xs"})]}),s.jsx(V,{label:N?"Long lines wrap":"Long lines scroll horizontally",children:s.jsx("button",{type:"button","aria-pressed":N,onClick:()=>ge(i=>!i),"aria-label":"Toggle line wrapping",className:E("inline-flex size-8 items-center justify-center rounded-md border transition-colors",N?"border-border bg-white/[0.08] text-foreground":"border-border text-muted-foreground hover:bg-white/[0.04] hover:text-foreground"),children:s.jsx(Pe,{className:"h-3.5 w-3.5"})})}),s.jsx(V,{label:j?"Copied":"Copy visible logs",children:s.jsxs(y,{size:"sm",variant:"outline",onClick:()=>void xe(),disabled:A.length===0,"aria-label":"Copy visible logs",children:[j?s.jsx(Ue,{className:"h-3.5 w-3.5"}):s.jsx(Be,{className:"h-3.5 w-3.5"}),s.jsx("span",{className:"hidden sm:inline",children:j?"Copied":"Copy"})]})})]})]})}),s.jsx(Y,{className:"border-b border-border p-2",children:s.jsxs("div",{className:"flex gap-1 overflow-x-auto",role:"group","aria-label":"Filter logs by level",children:[s.jsx(le,{label:"All",value:"all",count:l.length,active:T==="all",onClick:B}),pe.map(i=>s.jsx(le,{label:i,value:i,count:Re[i],active:T===i,onClick:B},i))]})}),s.jsx(Y,{className:"min-h-0 p-0",children:s.jsx(Ce,{overscrollContain:!0,scrollFade:!0,scrollbarGutter:!0,viewportRef:F,className:"h-[calc(100dvh-285px)] min-h-[24rem]",children:s.jsx("div",{className:"font-mono text-xs leading-relaxed",children:A.length===0?s.jsx("div",{className:"flex min-h-[20rem] items-center justify-center px-6 text-center",children:s.jsxs("div",{children:[s.jsx("div",{className:"text-sm font-medium text-foreground",children:l.length===0?"No logs yet":"No matching logs"}),s.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:l.length===0?"New runtime logs will appear here.":"Try another level or search term."})]})}):s.jsx("div",{className:"divide-y divide-border/45",children:A.map(({raw:i,message:o,source:p,level:m,ts:f,index:$})=>s.jsxs("div",{className:E("grid min-w-0 grid-cols-[4rem_3.75rem_5rem_minmax(0,1fr)] items-start gap-x-2 px-3 py-2.5 transition-colors hover:bg-white/[0.035] sm:grid-cols-[4.5rem_4rem_6rem_minmax(0,1fr)] sm:gap-x-3 sm:px-4",m==="ERROR"&&"bg-destructive/[0.035]"),children:[s.jsx("span",{className:"pt-1 text-[10px] tabular-nums text-muted-foreground/70",children:ce(f)}),s.jsxs(Ae,{variant:ut(m),size:"sm",className:"w-fit font-sans",children:[s.jsx("span",{"aria-hidden":"true",className:E("mr-1 inline-block size-1.5 rounded-full",fe(m))}),m]}),s.jsx("span",{className:E("min-w-0 pt-1 text-[10px] text-muted-foreground",N?"break-words whitespace-normal [overflow-wrap:anywhere]":"overflow-x-auto whitespace-nowrap"),title:p,children:p}),s.jsx("span",{className:E("min-w-0 text-foreground/90 [overflow-wrap:anywhere]",N?"whitespace-pre-wrap break-words":"overflow-x-auto whitespace-pre"),title:o||i,children:o||i})]},`${$}-${f}-${i}`))})})})})]}),s.jsx(ve,{open:a,onOpenChange:c,children:s.jsxs(we,{children:[s.jsxs(ye,{children:[s.jsx(Oe,{children:"Clear console logs?"}),s.jsx(Le,{children:"This removes the current in-memory log buffer. New logs will continue to appear."})]}),s.jsxs(je,{children:[s.jsx(y,{variant:"outline",onClick:()=>c(!1),children:"Cancel"}),s.jsx(y,{variant:"destructive",onClick:()=>void Ee(),children:"Clear logs"})]})]})})]})}export{St as default};
|