zevairouter 1.0.83 → 1.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/cli/app/.next-cli-build/BUILD_ID +1 -1
- package/cli/app/.next-cli-build/app-path-routes-manifest.json +5 -5
- package/cli/app/.next-cli-build/build-manifest.json +2 -2
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/automation/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/automation/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/context/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/context/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/terminal/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/terminal/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.html +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.html +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/api/auth/login/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/auth/oidc/start/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/auth/oidc/test/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/auth/status/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/claude-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/cline-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/codex-gateway/accounts/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/codex-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-registry/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-tools/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/deepseek-tui-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/droid-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/hermes-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/jcode-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/kilo-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/openclaw-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/cli-tools/opencode-settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/combos/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/combos/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/context/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/context/bulk/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/context/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/dashboard/chat/completions/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/headroom/extras/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/headroom/proxy/[...path]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/headroom/restart/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/headroom/start/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/headroom/status/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/headroom/stop/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/health/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/init/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/keys/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/keys/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/locale/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/mcp/[plugin]/message/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/mcp/[plugin]/sse/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/media-providers/tts/voices/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/alias/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/availability/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/custom/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/disabled/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/test/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/test/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/antigravity/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/antigravity/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/antigravity/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/antigravity/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/antigravity/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/autoclaw/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/autoclaw/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/autoclaw/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/autoclaw/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/autoclaw/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/bulk-token/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy/quota-cookie/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-token/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/quota-cookie/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/cursor/auto-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/grok-cli/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/grok-cli/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/grok-cli/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/grok-cli/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/grok-cli/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/auto-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/social-authorize/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/qoder/bulk-import/[jobId]/cancel/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/qoder/bulk-import/[jobId]/manual/[workerId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/qoder/bulk-import/[jobId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/qoder/bulk-import/latest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/oauth/qoder/bulk-import/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pricing/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/provider-nodes/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/provider-nodes/validate/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/bulk-delete/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/client/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/kilo/free-models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/suggested-models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/test-batch/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/validate/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/validate/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/health/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/install/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/restart/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/start/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/stats/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/status/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/pxpipe/stop/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/settings/database/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/settings/proxy-test/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/settings/proxy-test/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/settings/require-login/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/settings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/shutdown/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tags/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/auth/setup/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/auth/status/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/auth/unlock/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/input/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/resize/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/stream/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/terminal/session/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/console-logs/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/load/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/save/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/send/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/translate/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/disable/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/enable/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/status/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/tailscale-check/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/aggregate/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/chart/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/history/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/providers/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/request-details/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/request-logs/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/stats/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/usage/stream/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/api/chat/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/audio/speech/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/audio/voices/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/embeddings/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/images/generations/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/messages/count_tokens/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/messages/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/models/info/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/responses/compact/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/responses/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/search/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1/web/fetch/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/v1beta/models/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/shutdown/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/update/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/callback/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/callback.html +1 -1
- package/cli/app/.next-cli-build/server/app/callback.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/callback.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/callback.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/callback.segments/callback.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.html +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/quota.rsc +6 -6
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/index.html +1 -1
- package/cli/app/.next-cli-build/server/app/index.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/index.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/index.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/landing.html +1 -1
- package/cli/app/.next-cli-build/server/app/landing.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/landing.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing.segments/landing.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/login/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/login.html +1 -1
- package/cli/app/.next-cli-build/server/app/login.rsc +4 -4
- package/cli/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +4 -4
- package/cli/app/.next-cli-build/server/app/login.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/login.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/login.segments/login.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/page.js.nft.json +1 -1
- package/cli/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app-paths-manifest.json +5 -5
- package/cli/app/.next-cli-build/server/chunks/1396.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/2130.js +1 -0
- package/cli/app/.next-cli-build/server/chunks/3155.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/3407.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/3487.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/4746.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/5000.js +2 -2
- package/cli/app/.next-cli-build/server/chunks/6896.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/7774.js +2 -2
- package/cli/app/.next-cli-build/server/chunks/8157.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/8371.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/8590.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/891.js +1 -1
- package/cli/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/pages/404.html +1 -1
- package/cli/app/.next-cli-build/server/pages/500.html +1 -1
- package/cli/app/.next-cli-build/static/chunks/{3702-790d0c6b750c193e.js → 3702-c33199d84eed99f9.js} +1 -1
- package/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/src/lib/terminal/ptyBridge.py +163 -0
- package/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/cli/app/src/lib/terminal/ptyBridge.py +163 -0
- package/cli/app/package.json +1 -1
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/src/lib/oauth/services/grokCliBulkImportManager.js +110 -59
- package/src/lib/oauth/services/grokXaiEmailAutomation.js +428 -34
- package/src/lib/oauth/services/kiroGoogleAutomation.js +629 -164
- package/src/lib/oauth/services/tempmailClient.js +146 -18
- /package/cli/app/.next-cli-build/static/{FlRjqQtzHVNvcFcCzVDTM → R1kyWZTqGzBl4VyH_Yizr}/_buildManifest.js +0 -0
- /package/cli/app/.next-cli-build/static/{FlRjqQtzHVNvcFcCzVDTM → R1kyWZTqGzBl4VyH_Yizr}/_ssgManifest.js +0 -0
|
@@ -96,14 +96,28 @@ const GOOGLE_LOGIN_BUTTON_SELECTORS = [
|
|
|
96
96
|
'a#social-google',
|
|
97
97
|
'a:has-text("Sign up with Google")',
|
|
98
98
|
'a:has-text("Log in with Google")',
|
|
99
|
+
'a:has-text("Login with Google")',
|
|
100
|
+
'a:has-text("Continue with Google")',
|
|
101
|
+
'a:has-text("Sign in with Google")',
|
|
99
102
|
'button:has-text("Sign up with Google")',
|
|
100
103
|
'button:has-text("Log in with Google")',
|
|
104
|
+
'button:has-text("Login with Google")',
|
|
105
|
+
'button:has-text("Continue with Google")',
|
|
106
|
+
'button:has-text("Sign in with Google")',
|
|
101
107
|
'button:has-text("Google")',
|
|
102
108
|
'a:has-text("Google")',
|
|
109
|
+
'div[role="button"]:has-text("Continue with Google")',
|
|
110
|
+
'div[role="button"]:has-text("Login with Google")',
|
|
103
111
|
'div[role="button"]:has-text("Google")',
|
|
112
|
+
'span:has-text("Continue with Google")',
|
|
113
|
+
'span:has-text("Login with Google")',
|
|
104
114
|
'span:has-text("Google")',
|
|
105
115
|
'[aria-label*="Google"]',
|
|
106
116
|
'[data-provider*="google" i]',
|
|
117
|
+
// xAI / Grok device + account pages
|
|
118
|
+
'button:has-text("Login with Google")',
|
|
119
|
+
'button:has-text("Continue with Google")',
|
|
120
|
+
'[data-testid*="google" i]',
|
|
107
121
|
];
|
|
108
122
|
|
|
109
123
|
const TERMS_CHECKBOX_SELECTORS = [
|
|
@@ -398,7 +412,7 @@ async function getFirstVisibleLocator(page, selector) {
|
|
|
398
412
|
return null;
|
|
399
413
|
}
|
|
400
414
|
|
|
401
|
-
async function waitForFirstVisibleLocator(page, selector, { timeout = 15_000, pollInterval =
|
|
415
|
+
async function waitForFirstVisibleLocator(page, selector, { timeout = 15_000, pollInterval = 150 } = {}) {
|
|
402
416
|
const deadline = Date.now() + timeout;
|
|
403
417
|
while (Date.now() < deadline) {
|
|
404
418
|
const found = await getFirstVisibleLocator(page, selector);
|
|
@@ -410,58 +424,99 @@ async function waitForFirstVisibleLocator(page, selector, { timeout = 15_000, po
|
|
|
410
424
|
return null;
|
|
411
425
|
}
|
|
412
426
|
|
|
413
|
-
|
|
414
|
-
|
|
427
|
+
/** Tiny yield only — never use multi-second sleeps for “maybe page will load”. */
|
|
428
|
+
function yieldMs(ms = 50) {
|
|
429
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
430
|
+
}
|
|
415
431
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
try {
|
|
424
|
-
await locator.fill("", { timeout: 3_000 });
|
|
425
|
-
} catch {
|
|
426
|
-
/* noop */
|
|
427
|
-
}
|
|
428
|
-
try {
|
|
429
|
-
const delay = Math.floor(40 + Math.random() * 80); // 40-120ms per keystroke
|
|
430
|
-
await locator.type(value, { delay, timeout });
|
|
431
|
-
} catch {
|
|
432
|
-
// If type() fails, fall back to fill()
|
|
432
|
+
/**
|
|
433
|
+
* Wait until a condition is true, polling fast. Replaces fixed sleep after clicks.
|
|
434
|
+
* @returns {Promise<boolean>} true if condition met before timeout
|
|
435
|
+
*/
|
|
436
|
+
async function waitUntil(checkFn, { timeout = 8_000, interval = 100 } = {}) {
|
|
437
|
+
const deadline = Date.now() + timeout;
|
|
438
|
+
while (Date.now() < deadline) {
|
|
433
439
|
try {
|
|
434
|
-
await
|
|
440
|
+
if (await checkFn()) return true;
|
|
435
441
|
} catch {
|
|
436
|
-
|
|
442
|
+
/* retry */
|
|
437
443
|
}
|
|
444
|
+
await yieldMs(interval);
|
|
438
445
|
}
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
439
448
|
|
|
440
|
-
|
|
449
|
+
function isGoogleHostname(url) {
|
|
441
450
|
try {
|
|
442
|
-
|
|
451
|
+
const host = new URL(url).hostname;
|
|
452
|
+
return host === "accounts.google.com"
|
|
453
|
+
|| host.endsWith(".accounts.google.com")
|
|
454
|
+
|| /^accounts\.google\./i.test(host);
|
|
443
455
|
} catch {
|
|
444
|
-
|
|
456
|
+
return false;
|
|
445
457
|
}
|
|
446
|
-
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** After navigation/click: wait for URL change or next UI, not a fixed sleep. */
|
|
461
|
+
async function waitForPageAdvance(page, {
|
|
462
|
+
fromUrl = "",
|
|
463
|
+
urlMatch = null,
|
|
464
|
+
selector = null,
|
|
465
|
+
timeout = 8_000,
|
|
466
|
+
} = {}) {
|
|
467
|
+
const startUrl = fromUrl || page.url?.() || "";
|
|
468
|
+
return waitUntil(async () => {
|
|
469
|
+
const url = page.url?.() || "";
|
|
470
|
+
if (urlMatch) {
|
|
471
|
+
if (typeof urlMatch === "function" && urlMatch(url)) return true;
|
|
472
|
+
if (urlMatch instanceof RegExp && urlMatch.test(url)) return true;
|
|
473
|
+
}
|
|
474
|
+
if (url && url !== startUrl && !url.startsWith("about:")) return true;
|
|
475
|
+
if (selector) {
|
|
476
|
+
const found = await getFirstVisibleLocator(page, selector);
|
|
477
|
+
if (found) return true;
|
|
478
|
+
}
|
|
479
|
+
return false;
|
|
480
|
+
}, { timeout, interval: 80 });
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function fillInputResilient(locator, value, { timeout = 15_000 } = {}) {
|
|
484
|
+
if (!locator || value == null) return false;
|
|
447
485
|
|
|
448
|
-
//
|
|
486
|
+
// Prefer fill() first (fast). CloakBrowser already spoofs input events well
|
|
487
|
+
// enough for Google in practice; slow type is only a fallback for React
|
|
488
|
+
// controlled fields that reject programmatic fill.
|
|
449
489
|
try {
|
|
450
|
-
await locator.click({ timeout:
|
|
490
|
+
await locator.click({ timeout: 3_000 });
|
|
451
491
|
} catch {
|
|
452
492
|
/* noop */
|
|
453
493
|
}
|
|
454
494
|
try {
|
|
455
|
-
await locator.fill(
|
|
495
|
+
await locator.fill(String(value), { timeout: Math.min(timeout, 8_000) });
|
|
496
|
+
const observed = await locator.inputValue().catch(() => "");
|
|
497
|
+
if (observed === value) return true;
|
|
498
|
+
} catch {
|
|
499
|
+
/* fall through to typed input */
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
try {
|
|
503
|
+
await locator.fill("", { timeout: 2_000 });
|
|
456
504
|
} catch {
|
|
457
505
|
/* noop */
|
|
458
506
|
}
|
|
459
507
|
try {
|
|
460
|
-
|
|
508
|
+
// Light humanization only if fill failed — 15–35ms/key (was 40–120ms).
|
|
509
|
+
const delay = Math.floor(15 + Math.random() * 20);
|
|
510
|
+
await locator.type(String(value), { delay, timeout });
|
|
461
511
|
} catch {
|
|
462
|
-
|
|
512
|
+
try {
|
|
513
|
+
await locator.fill(String(value), { timeout });
|
|
514
|
+
} catch {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
463
517
|
}
|
|
464
518
|
|
|
519
|
+
let observed = "";
|
|
465
520
|
try {
|
|
466
521
|
observed = await locator.inputValue();
|
|
467
522
|
} catch {
|
|
@@ -497,12 +552,18 @@ function includesAny(text, markers) {
|
|
|
497
552
|
function isGoogleAuthPage(page) {
|
|
498
553
|
try {
|
|
499
554
|
const url = new URL(page.url());
|
|
500
|
-
return url.hostname === "accounts.google.com"
|
|
555
|
+
return url.hostname === "accounts.google.com"
|
|
556
|
+
|| url.hostname.endsWith(".accounts.google.com")
|
|
557
|
+
|| /^accounts\.google\./i.test(url.hostname);
|
|
501
558
|
} catch {
|
|
502
559
|
return false;
|
|
503
560
|
}
|
|
504
561
|
}
|
|
505
562
|
|
|
563
|
+
function isGrokish(serviceLabel) {
|
|
564
|
+
return /grok/i.test(String(serviceLabel || ""));
|
|
565
|
+
}
|
|
566
|
+
|
|
506
567
|
// Google bounces flagged (headless) browsers:
|
|
507
568
|
// - myaccount.google.com/not-supported
|
|
508
569
|
// - accounts.google.com/v3/signin/rejected ("This browser or app may not be secure")
|
|
@@ -602,14 +663,15 @@ async function waitThroughGoogleInterstitials(page, reportStep, { maxWaitMs = 20
|
|
|
602
663
|
]);
|
|
603
664
|
if (clicked) {
|
|
604
665
|
reportStep?.("selecting_google_account", "Selected account from Google AccountChooser");
|
|
605
|
-
await page
|
|
666
|
+
await waitForPageAdvance(page, { timeout: 5_000 });
|
|
606
667
|
continue;
|
|
607
668
|
}
|
|
608
669
|
}
|
|
609
670
|
|
|
610
671
|
const waiters = [
|
|
611
|
-
page.waitForNavigation({ waitUntil: "domcontentloaded", timeout:
|
|
612
|
-
|
|
672
|
+
page.waitForNavigation({ waitUntil: "domcontentloaded", timeout: 3_000 }).catch(() => null),
|
|
673
|
+
// Cap idle wait low — exit as soon as URL/body changes or success settles.
|
|
674
|
+
yieldMs(400),
|
|
613
675
|
];
|
|
614
676
|
if (successPromise && !isSuccessSettled(successPromise)) {
|
|
615
677
|
waiters.push(successPromise.then(() => null).catch(() => null));
|
|
@@ -622,9 +684,16 @@ async function waitThroughGoogleInterstitials(page, reportStep, { maxWaitMs = 20
|
|
|
622
684
|
function isProviderPage(page) {
|
|
623
685
|
try {
|
|
624
686
|
const url = new URL(page.url());
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
||
|
|
687
|
+
const host = url.hostname || "";
|
|
688
|
+
return /codebuddy\.(ai|cn)$/.test(host)
|
|
689
|
+
|| host.endsWith(".codebuddy.ai")
|
|
690
|
+
|| host.endsWith(".codebuddy.cn")
|
|
691
|
+
// xAI / Grok CLI device authorization + account host
|
|
692
|
+
|| host === "accounts.x.ai"
|
|
693
|
+
|| host === "auth.x.ai"
|
|
694
|
+
|| host.endsWith(".x.ai")
|
|
695
|
+
|| host === "grok.com"
|
|
696
|
+
|| host.endsWith(".grok.com");
|
|
628
697
|
} catch {
|
|
629
698
|
return false;
|
|
630
699
|
}
|
|
@@ -1188,6 +1257,38 @@ async function handleCodeBuddyStartedAuthorization(page, reportStep) {
|
|
|
1188
1257
|
return true;
|
|
1189
1258
|
}
|
|
1190
1259
|
|
|
1260
|
+
async function providerHasGoogleLogin(page) {
|
|
1261
|
+
try {
|
|
1262
|
+
for (const name of [/continue with google/i, /sign in with google/i, /sign up with google/i, /^google$/i]) {
|
|
1263
|
+
const btn = page.getByRole("button", { name }).first();
|
|
1264
|
+
if (await btn.isVisible({ timeout: 300 }).catch(() => false)) return true;
|
|
1265
|
+
const link = page.getByRole("link", { name }).first();
|
|
1266
|
+
if (await link.isVisible({ timeout: 200 }).catch(() => false)) return true;
|
|
1267
|
+
}
|
|
1268
|
+
} catch {
|
|
1269
|
+
/* ignore */
|
|
1270
|
+
}
|
|
1271
|
+
for (const selector of GOOGLE_LOGIN_BUTTON_SELECTORS) {
|
|
1272
|
+
try {
|
|
1273
|
+
const loc = page.locator(selector).first();
|
|
1274
|
+
if (await loc.isVisible({ timeout: 200 }).catch(() => false)) return true;
|
|
1275
|
+
} catch {
|
|
1276
|
+
/* next */
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
return false;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function isXaiProviderPage(page) {
|
|
1283
|
+
try {
|
|
1284
|
+
const host = new URL(page.url()).hostname || "";
|
|
1285
|
+
return host === "accounts.x.ai" || host === "auth.x.ai" || host.endsWith(".x.ai")
|
|
1286
|
+
|| host === "grok.com" || host.endsWith(".grok.com");
|
|
1287
|
+
} catch {
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1191
1292
|
async function handleProviderOnboarding(page, reportStep, serviceLabel) {
|
|
1192
1293
|
if (!isProviderPage(page) || isGoogleAuthPage(page)) return false;
|
|
1193
1294
|
|
|
@@ -1208,37 +1309,53 @@ async function handleProviderOnboarding(page, reportStep, serviceLabel) {
|
|
|
1208
1309
|
return true;
|
|
1209
1310
|
}
|
|
1210
1311
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
await page
|
|
1215
|
-
|
|
1216
|
-
|
|
1312
|
+
// Region / workspace defaults are CodeBuddy-style — not xAI device approve.
|
|
1313
|
+
// False-positive select matches on xAI wasted the session into "Invalid action".
|
|
1314
|
+
if (!isXaiProviderPage(page)) {
|
|
1315
|
+
const selectedNativeRegion = await selectNativeRegionOption(page);
|
|
1316
|
+
if (selectedNativeRegion) {
|
|
1317
|
+
reportStep("selecting_provider_region", `Selected ${serviceLabel} region`);
|
|
1318
|
+
await page.waitForTimeout(700);
|
|
1319
|
+
return true;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
const openedRegionMenu = await clickFirstActionable(page, PROVIDER_REGION_TRIGGER_SELECTORS);
|
|
1323
|
+
if (openedRegionMenu) {
|
|
1324
|
+
reportStep("opening_provider_region_selector", `Opening ${serviceLabel} region selector`);
|
|
1325
|
+
await page.waitForTimeout(500);
|
|
1326
|
+
const selectedRegion = await clickFirstActionable(page, PROVIDER_REGION_OPTION_SELECTORS);
|
|
1327
|
+
if (selectedRegion) {
|
|
1328
|
+
reportStep("selecting_provider_region", `Selected ${serviceLabel} region`);
|
|
1329
|
+
await page.waitForTimeout(700);
|
|
1330
|
+
}
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1217
1333
|
|
|
1218
|
-
const openedRegionMenu = await clickFirstActionable(page, PROVIDER_REGION_TRIGGER_SELECTORS);
|
|
1219
|
-
if (openedRegionMenu) {
|
|
1220
|
-
reportStep("opening_provider_region_selector", `Opening ${serviceLabel} region selector`);
|
|
1221
|
-
await page.waitForTimeout(500);
|
|
1222
1334
|
const selectedRegion = await clickFirstActionable(page, PROVIDER_REGION_OPTION_SELECTORS);
|
|
1223
1335
|
if (selectedRegion) {
|
|
1224
1336
|
reportStep("selecting_provider_region", `Selected ${serviceLabel} region`);
|
|
1225
1337
|
await page.waitForTimeout(700);
|
|
1338
|
+
return true;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
const filledDefaults = await fillProviderOnboardingDefaults(page);
|
|
1342
|
+
if (filledDefaults) {
|
|
1343
|
+
reportStep("filling_provider_onboarding", `Filled ${serviceLabel} onboarding defaults`);
|
|
1344
|
+
await page.waitForTimeout(500);
|
|
1345
|
+
return true;
|
|
1226
1346
|
}
|
|
1227
|
-
return true;
|
|
1228
1347
|
}
|
|
1229
1348
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
return
|
|
1349
|
+
// xAI device pages: never click generic Continue/Next/Confirm. Those submit
|
|
1350
|
+
// the device form without a session → "Invalid action" and burn 1–3 minutes.
|
|
1351
|
+
// Only Google SSO (login gate) + Allow/Authorize (clickXaiDeviceAuthorize).
|
|
1352
|
+
if (isXaiProviderPage(page)) {
|
|
1353
|
+
return false;
|
|
1235
1354
|
}
|
|
1236
1355
|
|
|
1237
|
-
|
|
1238
|
-
if (
|
|
1239
|
-
|
|
1240
|
-
await page.waitForTimeout(500);
|
|
1241
|
-
return true;
|
|
1356
|
+
// If Google SSO is still offered, do not mash generic Continue.
|
|
1357
|
+
if (await providerHasGoogleLogin(page)) {
|
|
1358
|
+
return false;
|
|
1242
1359
|
}
|
|
1243
1360
|
|
|
1244
1361
|
const clickedAction = await clickFirstActionable(page, PROVIDER_ONBOARDING_ACTION_SELECTORS);
|
|
@@ -1251,36 +1368,226 @@ async function handleProviderOnboarding(page, reportStep, serviceLabel) {
|
|
|
1251
1368
|
return false;
|
|
1252
1369
|
}
|
|
1253
1370
|
|
|
1254
|
-
|
|
1371
|
+
/**
|
|
1372
|
+
* xAI device step 1: "Enter the code shown in your terminal" → Continue.
|
|
1373
|
+
* Only after this do we land on sign-in with "Login with Google".
|
|
1374
|
+
* Never run this after Google login — that re-submits Continue into Invalid action.
|
|
1375
|
+
*/
|
|
1376
|
+
async function handleXaiDeviceCodeConfirm(page, reportStep, { alreadyAuthed = false } = {}) {
|
|
1377
|
+
if (!isXaiProviderPage(page)) return false;
|
|
1378
|
+
if (alreadyAuthed) return false;
|
|
1379
|
+
// Already on Google SSO wall — past this step.
|
|
1380
|
+
if (await providerHasGoogleLogin(page)) return false;
|
|
1381
|
+
|
|
1382
|
+
const text = await readPageText(page).catch(() => "");
|
|
1383
|
+
// Logged-in device/approve screens — do not re-click Continue.
|
|
1384
|
+
if (/sign out|log out|device authorized|you can close|invalid action/i.test(text)) {
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
const isCodeConfirm =
|
|
1389
|
+
/enter the code shown in your terminal/i.test(text)
|
|
1390
|
+
|| /only enter this code if you just initiated/i.test(text)
|
|
1391
|
+
|| (/sign in to grok/i.test(text) && /continue/i.test(text) && !/login with/i.test(text));
|
|
1392
|
+
if (!isCodeConfirm) return false;
|
|
1393
|
+
|
|
1394
|
+
const fromUrl = page.url?.() || "";
|
|
1395
|
+
let clicked = false;
|
|
1396
|
+
try {
|
|
1397
|
+
const btn = page.getByRole("button", { name: /^Continue$/i }).first();
|
|
1398
|
+
if (await btn.isVisible({ timeout: 300 }).catch(() => false)) {
|
|
1399
|
+
await btn.click({ timeout: 5_000 });
|
|
1400
|
+
clicked = true;
|
|
1401
|
+
}
|
|
1402
|
+
} catch {
|
|
1403
|
+
/* fall through */
|
|
1404
|
+
}
|
|
1405
|
+
if (!clicked) {
|
|
1406
|
+
clicked = await clickFirstActionable(page, [
|
|
1407
|
+
'button[type="submit"]:has-text("Continue")',
|
|
1408
|
+
'button:has-text("Continue")',
|
|
1409
|
+
]);
|
|
1410
|
+
}
|
|
1411
|
+
if (!clicked) return false;
|
|
1412
|
+
|
|
1413
|
+
reportStep?.("confirming_device_code", "Confirmed device user code on xAI");
|
|
1414
|
+
// Event-driven: next screen is Login with Google or URL change — no fixed 1.2s sleep.
|
|
1415
|
+
await waitForPageAdvance(page, {
|
|
1416
|
+
fromUrl,
|
|
1417
|
+
urlMatch: (u) => /sign-in|login|oauth/i.test(u) && u !== fromUrl,
|
|
1418
|
+
selector: [
|
|
1419
|
+
...GOOGLE_LOGIN_BUTTON_SELECTORS.split(", ").slice(0, 8),
|
|
1420
|
+
'button:has-text("Login with Google")',
|
|
1421
|
+
'button:has-text("Login with email")',
|
|
1422
|
+
].join(", "),
|
|
1423
|
+
timeout: 10_000,
|
|
1424
|
+
});
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
async function clickGoogleLoginRole(page) {
|
|
1429
|
+
// Role-based matches are more reliable on SPA auth shells (xAI, etc.)
|
|
1430
|
+
// than CSS :has-text alone — especially when the label is nested.
|
|
1431
|
+
const roleNames = [
|
|
1432
|
+
/login with google/i,
|
|
1433
|
+
/log in with google/i,
|
|
1434
|
+
/continue with google/i,
|
|
1435
|
+
/sign up with google/i,
|
|
1436
|
+
/sign in with google/i,
|
|
1437
|
+
/^google$/i,
|
|
1438
|
+
];
|
|
1439
|
+
for (const name of roleNames) {
|
|
1440
|
+
try {
|
|
1441
|
+
const btn = page.getByRole("button", { name }).first();
|
|
1442
|
+
if (await btn.isVisible({ timeout: 250 }).catch(() => false)) {
|
|
1443
|
+
const enabled = await btn.isEnabled().catch(() => true);
|
|
1444
|
+
if (!enabled) continue;
|
|
1445
|
+
await btn.click({ timeout: 5_000 });
|
|
1446
|
+
return true;
|
|
1447
|
+
}
|
|
1448
|
+
} catch {
|
|
1449
|
+
/* next */
|
|
1450
|
+
}
|
|
1451
|
+
try {
|
|
1452
|
+
const link = page.getByRole("link", { name }).first();
|
|
1453
|
+
if (await link.isVisible({ timeout: 200 }).catch(() => false)) {
|
|
1454
|
+
await link.click({ timeout: 5_000 });
|
|
1455
|
+
return true;
|
|
1456
|
+
}
|
|
1457
|
+
} catch {
|
|
1458
|
+
/* next */
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return false;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
async function ensureProviderTermsChecked(page, reportStep) {
|
|
1465
|
+
// Returns true only when we newly checked a box (not when already checked).
|
|
1466
|
+
for (const scope of getInteractionScopes(page)) {
|
|
1467
|
+
for (const selector of TERMS_CHECKBOX_SELECTORS) {
|
|
1468
|
+
try {
|
|
1469
|
+
const locator = scope.locator(selector).first();
|
|
1470
|
+
const count = await locator.count().catch(() => 0);
|
|
1471
|
+
if (!count) continue;
|
|
1472
|
+
const visible = await locator.isVisible().catch(() => false);
|
|
1473
|
+
if (!visible) continue;
|
|
1474
|
+
const already = await locator.isChecked().catch(() => false);
|
|
1475
|
+
if (already) return false;
|
|
1476
|
+
const did = await locator.check({ force: true, timeout: 3_000 }).then(() => true).catch(() => false)
|
|
1477
|
+
|| await locator.click({ force: true, timeout: 3_000 }).then(() => true).catch(() => false);
|
|
1478
|
+
if (did) {
|
|
1479
|
+
reportStep?.("accepting_provider_terms", "Accepted provider terms for Google login");
|
|
1480
|
+
// Wait until Google button enables — not a blind sleep.
|
|
1481
|
+
await waitUntil(
|
|
1482
|
+
async () => {
|
|
1483
|
+
try {
|
|
1484
|
+
const btn = page.getByRole("button", { name: /google/i }).first();
|
|
1485
|
+
return (await btn.isVisible().catch(() => false))
|
|
1486
|
+
&& (await btn.isEnabled().catch(() => true));
|
|
1487
|
+
} catch {
|
|
1488
|
+
return true;
|
|
1489
|
+
}
|
|
1490
|
+
},
|
|
1491
|
+
{ timeout: 2_000, interval: 80 },
|
|
1492
|
+
);
|
|
1493
|
+
return true;
|
|
1494
|
+
}
|
|
1495
|
+
} catch {
|
|
1496
|
+
/* next */
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return false;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
async function handleProviderLoginGate(page, reportStep, { allowGoogleClick = true } = {}) {
|
|
1255
1504
|
if (isGoogleAuthPage(page)) return false;
|
|
1256
1505
|
|
|
1257
1506
|
const confirmedExistingDialog = await clickFirstActionable(page, PRIVACY_CONFIRM_BUTTON_SELECTORS);
|
|
1258
1507
|
if (confirmedExistingDialog) {
|
|
1259
1508
|
reportStep("accepting_provider_privacy_dialog", "Confirmed provider privacy agreement dialog");
|
|
1260
|
-
await page.waitForTimeout(1000);
|
|
1261
1509
|
return true;
|
|
1262
1510
|
}
|
|
1263
1511
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1512
|
+
// Always try terms first — but do NOT treat "already checked" as progress.
|
|
1513
|
+
// Returning true every loop on an already-checked box blocked Google re-click
|
|
1514
|
+
// for ~30–60s after a failed first SSO attempt.
|
|
1515
|
+
const newlyCheckedTerms = await ensureProviderTermsChecked(page, reportStep);
|
|
1516
|
+
|
|
1517
|
+
if (!allowGoogleClick) {
|
|
1518
|
+
return newlyCheckedTerms;
|
|
1268
1519
|
}
|
|
1269
1520
|
|
|
1270
|
-
|
|
1521
|
+
// Prefer explicit Google SSO over generic Continue (device code pages
|
|
1522
|
+
// often have both — clicking Continue without a session yields invalid_code).
|
|
1523
|
+
const clickedGoogleRole = await clickGoogleLoginRole(page);
|
|
1524
|
+
const clickedGoogle = clickedGoogleRole || await clickFirstActionable(page, GOOGLE_LOGIN_BUTTON_SELECTORS);
|
|
1271
1525
|
if (clickedGoogle) {
|
|
1272
1526
|
reportStep("selecting_google_login", "Selecting Google login");
|
|
1273
|
-
await page.waitForTimeout(1000);
|
|
1274
1527
|
|
|
1275
1528
|
const confirmedDialog = await clickFirstActionable(page, PRIVACY_CONFIRM_BUTTON_SELECTORS);
|
|
1276
1529
|
if (confirmedDialog) {
|
|
1277
1530
|
reportStep("accepting_provider_privacy_dialog", "Confirmed provider privacy agreement dialog");
|
|
1278
|
-
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// Wait for OAuth redirect to Google (or email field) — event-driven.
|
|
1534
|
+
const reached = await waitForPageAdvance(page, {
|
|
1535
|
+
urlMatch: (u) => isGoogleHostname(u),
|
|
1536
|
+
selector: EMAIL_INPUT_SELECTOR,
|
|
1537
|
+
timeout: 12_000,
|
|
1538
|
+
});
|
|
1539
|
+
if (reached || isGoogleAuthPage(page)) {
|
|
1540
|
+
reportStep("google_login_page", "Reached Google sign-in after provider SSO");
|
|
1541
|
+
} else {
|
|
1542
|
+
// Popup-based Google SSO
|
|
1543
|
+
try {
|
|
1544
|
+
const ctx = page.context?.();
|
|
1545
|
+
const pages = ctx?.pages?.() || [];
|
|
1546
|
+
for (let i = pages.length - 1; i >= 0; i -= 1) {
|
|
1547
|
+
const p = pages[i];
|
|
1548
|
+
const u = p.url?.() || "";
|
|
1549
|
+
if (isGoogleHostname(u)) {
|
|
1550
|
+
reportStep("google_login_popup", "Google sign-in opened in a popup");
|
|
1551
|
+
break;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
} catch {
|
|
1555
|
+
/* ignore */
|
|
1556
|
+
}
|
|
1279
1557
|
}
|
|
1280
1558
|
|
|
1281
1559
|
return true;
|
|
1282
1560
|
}
|
|
1283
1561
|
|
|
1562
|
+
return newlyCheckedTerms;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
/** Fast path for xAI device approve after Google session exists. */
|
|
1566
|
+
async function clickXaiDeviceAuthorize(page, reportStep) {
|
|
1567
|
+
if (!isXaiProviderPage(page)) return false;
|
|
1568
|
+
// Never approve while Google SSO is still on the page — that was thrashing
|
|
1569
|
+
// Continue / Allow before login and landing on "Invalid action".
|
|
1570
|
+
if (await providerHasGoogleLogin(page)) return false;
|
|
1571
|
+
|
|
1572
|
+
// Prefer exact authorize verbs — avoid bare "Continue" (too many false hits).
|
|
1573
|
+
const roles = [
|
|
1574
|
+
/^(Allow|Authorize|Approve|Confirm)$/i,
|
|
1575
|
+
/^(Allow|Authorize|Approve)\b/i,
|
|
1576
|
+
];
|
|
1577
|
+
for (const re of roles) {
|
|
1578
|
+
try {
|
|
1579
|
+
const btn = page.getByRole("button", { name: re }).first();
|
|
1580
|
+
if (await btn.isVisible({ timeout: 200 }).catch(() => false)) {
|
|
1581
|
+
const label = (await btn.innerText().catch(() => "")) || "";
|
|
1582
|
+
if (/google/i.test(label)) continue;
|
|
1583
|
+
await btn.click({ timeout: 3_000 });
|
|
1584
|
+
reportStep?.("approving_consent", "Approving xAI device authorization");
|
|
1585
|
+
return true;
|
|
1586
|
+
}
|
|
1587
|
+
} catch {
|
|
1588
|
+
/* next */
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1284
1591
|
return false;
|
|
1285
1592
|
}
|
|
1286
1593
|
|
|
@@ -1578,39 +1885,101 @@ export async function runGoogleAccountAutomation({
|
|
|
1578
1885
|
// (pwd page stays mounted ~1–3s after Next; re-fill aborts the OAuth chain).
|
|
1579
1886
|
let passwordSubmittedAt = 0;
|
|
1580
1887
|
let emailSubmittedAt = 0;
|
|
1581
|
-
|
|
1582
|
-
|
|
1888
|
+
let googleLoginSelectedAt = 0;
|
|
1889
|
+
let seenGoogleAuth = false;
|
|
1890
|
+
let deviceApproveAt = 0;
|
|
1891
|
+
let deviceInvalidReopenAt = 0;
|
|
1892
|
+
let deviceInvalidReopenCount = 0;
|
|
1893
|
+
// Cooldowns prevent double-submit only — not artificial pacing.
|
|
1894
|
+
const PASSWORD_RESUBMIT_COOLDOWN_MS = isGrokish(serviceLabel) ? 6_000 : 18_000;
|
|
1895
|
+
const EMAIL_RESUBMIT_COOLDOWN_MS = isGrokish(serviceLabel) ? 3_000 : 8_000;
|
|
1896
|
+
const GOOGLE_SSO_COOLDOWN_MS = isGrokish(serviceLabel) ? 3_000 : 8_000;
|
|
1897
|
+
// Don't hammer Allow — xAI rate_limits rapid device posts.
|
|
1898
|
+
const DEVICE_APPROVE_COOLDOWN_MS = 3_000;
|
|
1899
|
+
const DEVICE_INVALID_REOPEN_COOLDOWN_MS = 4_000;
|
|
1900
|
+
const DEVICE_INVALID_REOPEN_MAX = 3;
|
|
1901
|
+
const isGrokFlow = isGrokish(serviceLabel);
|
|
1902
|
+
// Grok does not need the long Kiro SetSID / kiro:// interstitial window.
|
|
1903
|
+
const postPasswordInterstitialMs = isGrokFlow ? 4_000 : 25_000;
|
|
1904
|
+
// Loop poll: race successPromise — keep tiny so fast networks aren't stalled.
|
|
1905
|
+
const loopTickMs = isGrokFlow ? 120 : 500;
|
|
1583
1906
|
|
|
1584
1907
|
reportStep(openingStep, openingMessage);
|
|
1585
1908
|
await page.goto(authUrl, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
|
1586
|
-
|
|
1587
|
-
await
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1909
|
+
// Wait for interactive UI (Continue / Google / email), not a fixed sleep.
|
|
1910
|
+
await waitUntil(
|
|
1911
|
+
async () =>
|
|
1912
|
+
isGoogleAuthPage(page)
|
|
1913
|
+
|| (await getFirstVisibleLocator(page, 'button:has-text("Continue"), button:has-text("Login with Google"), button:has-text("Google")'))
|
|
1914
|
+
|| (await getFirstVisibleLocator(page, EMAIL_INPUT_SELECTOR)),
|
|
1915
|
+
{ timeout: isGrokFlow ? 6_000 : 12_000, interval: 80 },
|
|
1916
|
+
);
|
|
1917
|
+
if (!isGrokFlow) {
|
|
1918
|
+
await waitThroughGoogleInterstitials(page, reportStep, interstitialOpts(8_000));
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// Provider shells (xAI device, CodeBuddy, …) must pick Google SSO first.
|
|
1922
|
+
// Never type credentials into provider user_code / email fields.
|
|
1923
|
+
// xAI: confirm device user_code first, then Google SSO — event-driven retries.
|
|
1924
|
+
for (let attempt = 0; attempt < (isGrokFlow ? 6 : 2); attempt += 1) {
|
|
1925
|
+
if (isGoogleAuthPage(page)) break;
|
|
1926
|
+
if (await handleXaiDeviceCodeConfirm(page, reportStep)) {
|
|
1927
|
+
continue;
|
|
1928
|
+
}
|
|
1929
|
+
if (await handleProviderLoginGate(page, reportStep)) {
|
|
1930
|
+
googleLoginSelectedAt = Date.now();
|
|
1931
|
+
if (isGoogleAuthPage(page)) break;
|
|
1932
|
+
// Gate already waited for Google URL; only brief yield if still on provider.
|
|
1933
|
+
await yieldMs(50);
|
|
1934
|
+
continue;
|
|
1607
1935
|
}
|
|
1936
|
+
// SPA not ready — poll for buttons, don't sleep 600ms blindly.
|
|
1937
|
+
const ready = await waitUntil(
|
|
1938
|
+
async () =>
|
|
1939
|
+
(await providerHasGoogleLogin(page))
|
|
1940
|
+
|| /enter the code|login with google|continue/i.test(await readPageText(page).catch(() => "")),
|
|
1941
|
+
{ timeout: 800, interval: 80 },
|
|
1942
|
+
);
|
|
1943
|
+
if (!ready) await yieldMs(100);
|
|
1944
|
+
}
|
|
1945
|
+
if (!isGrokFlow) {
|
|
1946
|
+
await waitThroughGoogleInterstitials(page, reportStep, interstitialOpts(6_000));
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// Only fill Google email once we are actually on accounts.google.com.
|
|
1950
|
+
if (isGoogleAuthPage(page)) {
|
|
1951
|
+
seenGoogleAuth = true;
|
|
1952
|
+
const emailInput = await waitForFirstVisibleLocator(page, EMAIL_INPUT_SELECTOR, { timeout: 10_000 });
|
|
1953
|
+
if (emailInput) {
|
|
1954
|
+
reportStep("entering_email", "Entering Google email");
|
|
1955
|
+
const filled = await fillInputResilient(emailInput, email);
|
|
1956
|
+
if (!filled) {
|
|
1957
|
+
reportStep("email_fill_failed", "Could not fill the Google email field; will retry in the polling loop");
|
|
1958
|
+
} else {
|
|
1959
|
+
reportStep("submitting_email", "Submitting email");
|
|
1960
|
+
await clickFirstVisible(page, NEXT_BUTTON_SELECTORS);
|
|
1961
|
+
emailSubmittedAt = Date.now();
|
|
1962
|
+
// Wait for password field (or leave email step) — not fixed sleep.
|
|
1963
|
+
await waitForPageAdvance(page, {
|
|
1964
|
+
selector: PASSWORD_INPUT_SELECTOR,
|
|
1965
|
+
timeout: isGrokFlow ? 8_000 : 12_000,
|
|
1966
|
+
});
|
|
1967
|
+
if (!isGrokFlow) {
|
|
1968
|
+
await waitThroughGoogleInterstitials(page, reportStep, interstitialOpts(8_000));
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
} else if (isProviderPage(page)) {
|
|
1973
|
+
reportStep(
|
|
1974
|
+
"waiting_for_google_sso",
|
|
1975
|
+
`Provider page still open (${(page.url?.() || "").slice(0, 80)}) — will keep selecting Google login`,
|
|
1976
|
+
);
|
|
1608
1977
|
}
|
|
1609
1978
|
|
|
1610
1979
|
while (Date.now() - startTime < shortTimeoutMs) {
|
|
1611
1980
|
const successResult = await Promise.race([
|
|
1612
1981
|
successPromise.then((result) => ({ kind: "success", result })).catch((error) => ({ kind: "success_error", error })),
|
|
1613
|
-
new Promise((resolve) => setTimeout(() => resolve(null),
|
|
1982
|
+
new Promise((resolve) => setTimeout(() => resolve(null), loopTickMs)),
|
|
1614
1983
|
]);
|
|
1615
1984
|
|
|
1616
1985
|
if (successResult?.kind === "success") {
|
|
@@ -1630,14 +1999,22 @@ export async function runGoogleAccountAutomation({
|
|
|
1630
1999
|
}
|
|
1631
2000
|
|
|
1632
2001
|
// Unblock SetSID / empty Google interstitials before other handlers
|
|
1633
|
-
const waited = await waitThroughGoogleInterstitials(
|
|
2002
|
+
const waited = await waitThroughGoogleInterstitials(
|
|
2003
|
+
page,
|
|
2004
|
+
reportStep,
|
|
2005
|
+
interstitialOpts(isGrokFlow ? 2_500 : 8_000),
|
|
2006
|
+
);
|
|
1634
2007
|
if (waited) {
|
|
1635
2008
|
continue;
|
|
1636
2009
|
}
|
|
1637
2010
|
|
|
1638
2011
|
const handledGoogleConsent = await handleGoogleConsent(page, reportStep);
|
|
1639
2012
|
if (handledGoogleConsent) {
|
|
1640
|
-
|
|
2013
|
+
if (!isGrokFlow) {
|
|
2014
|
+
await waitThroughGoogleInterstitials(page, reportStep, interstitialOpts(12_000));
|
|
2015
|
+
} else {
|
|
2016
|
+
await waitForPageAdvance(page, { timeout: 4_000 });
|
|
2017
|
+
}
|
|
1641
2018
|
continue;
|
|
1642
2019
|
}
|
|
1643
2020
|
|
|
@@ -1696,92 +2073,179 @@ export async function runGoogleAccountAutomation({
|
|
|
1696
2073
|
continue;
|
|
1697
2074
|
}
|
|
1698
2075
|
|
|
1699
|
-
|
|
1700
|
-
if (
|
|
1701
|
-
|
|
2076
|
+
// xAI rate-limits device authorize after rapid retries — fail fast.
|
|
2077
|
+
if (
|
|
2078
|
+
isProviderPage(page)
|
|
2079
|
+
&& (/rate[_ ]?limit/i.test(text) || /error=rate_limited/i.test(page.url?.() || ""))
|
|
2080
|
+
) {
|
|
2081
|
+
reportStep("device_rate_limited", "xAI device authorization rate-limited");
|
|
2082
|
+
return {
|
|
2083
|
+
status: "failed",
|
|
2084
|
+
error: "xAI rate-limited device authorization. Wait a few minutes and retry (too many rapid device-code attempts).",
|
|
2085
|
+
};
|
|
1702
2086
|
}
|
|
1703
2087
|
|
|
1704
|
-
//
|
|
1705
|
-
//
|
|
1706
|
-
//
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
// Give Google time to leave the password challenge before the next
|
|
1730
|
-
// loop iteration can re-detect the still-mounted password field.
|
|
1731
|
-
await Promise.race([
|
|
1732
|
-
page.waitForNavigation({ waitUntil: "domcontentloaded", timeout: 8_000 }).catch(() => null),
|
|
1733
|
-
page.waitForTimeout(2_500),
|
|
1734
|
-
]);
|
|
1735
|
-
// Password submit often lands on empty SetSID while network completes
|
|
1736
|
-
// consent→idpresponse→kiro://. Callback monitor (CDP) settles successPromise.
|
|
1737
|
-
await waitThroughGoogleInterstitials(page, reportStep, interstitialOpts(25_000));
|
|
1738
|
-
} else {
|
|
1739
|
-
reportStep("password_fill_failed", "Could not fill the Google password field; retrying loop");
|
|
1740
|
-
await page.waitForTimeout(700);
|
|
1741
|
-
}
|
|
2088
|
+
// xAI often lands on /oauth2/device/approve with "Invalid action" after
|
|
2089
|
+
// Google consent when the approve form was double-submitted. Re-open the
|
|
2090
|
+
// original device URL (with user_code) a few times — not every loop tick.
|
|
2091
|
+
if (
|
|
2092
|
+
isProviderPage(page)
|
|
2093
|
+
&& /invalid action|invalid[_ ]?code|code (has )?expired|expired code/i.test(text)
|
|
2094
|
+
&& authUrl
|
|
2095
|
+
&& seenGoogleAuth
|
|
2096
|
+
&& deviceInvalidReopenCount < DEVICE_INVALID_REOPEN_MAX
|
|
2097
|
+
&& Date.now() - deviceInvalidReopenAt > DEVICE_INVALID_REOPEN_COOLDOWN_MS
|
|
2098
|
+
) {
|
|
2099
|
+
deviceInvalidReopenCount += 1;
|
|
2100
|
+
deviceInvalidReopenAt = Date.now();
|
|
2101
|
+
deviceApproveAt = 0;
|
|
2102
|
+
reportStep(
|
|
2103
|
+
"device_invalid_reopen",
|
|
2104
|
+
`Device page error — reopening auth URL (${deviceInvalidReopenCount}/${DEVICE_INVALID_REOPEN_MAX})`,
|
|
2105
|
+
);
|
|
2106
|
+
await page.goto(authUrl, { waitUntil: "domcontentloaded", timeout: 60_000 }).catch(() => null);
|
|
2107
|
+
await waitUntil(
|
|
2108
|
+
async () =>
|
|
2109
|
+
(await getFirstVisibleLocator(page, 'button:has-text("Continue"), button:has-text("Allow"), button:has-text("Authorize")'))
|
|
2110
|
+
|| (await providerHasGoogleLogin(page)),
|
|
2111
|
+
{ timeout: 4_000, interval: 80 },
|
|
2112
|
+
);
|
|
1742
2113
|
continue;
|
|
1743
2114
|
}
|
|
1744
2115
|
|
|
1745
|
-
const
|
|
1746
|
-
if (nextEmailInput) {
|
|
1747
|
-
const sinceEmail = Date.now() - emailSubmittedAt;
|
|
1748
|
-
if (emailSubmittedAt && sinceEmail < EMAIL_RESUBMIT_COOLDOWN_MS) {
|
|
1749
|
-
reportStep(
|
|
1750
|
-
"waiting_after_email",
|
|
1751
|
-
`Email already submitted ${Math.round(sinceEmail / 1000)}s ago — waiting for password/next screen`,
|
|
1752
|
-
);
|
|
1753
|
-
await page.waitForTimeout(800);
|
|
1754
|
-
continue;
|
|
1755
|
-
}
|
|
2116
|
+
const googleAuthed = Boolean(seenGoogleAuth && passwordSubmittedAt);
|
|
1756
2117
|
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
if (filled) {
|
|
1760
|
-
reportStep("submitting_email", "Submitting email");
|
|
1761
|
-
await clickFirstVisible(page, NEXT_BUTTON_SELECTORS);
|
|
1762
|
-
emailSubmittedAt = Date.now();
|
|
1763
|
-
await page.waitForTimeout(1_500);
|
|
1764
|
-
} else {
|
|
1765
|
-
reportStep("email_fill_failed", "Could not fill the Google email field; retrying loop");
|
|
1766
|
-
}
|
|
1767
|
-
await page.waitForTimeout(700);
|
|
2118
|
+
// xAI device user_code confirm (Continue) — only before Google login.
|
|
2119
|
+
if (await handleXaiDeviceCodeConfirm(page, reportStep, { alreadyAuthed: googleAuthed })) {
|
|
1768
2120
|
continue;
|
|
1769
2121
|
}
|
|
1770
2122
|
|
|
1771
|
-
|
|
2123
|
+
// Provider Google SSO BEFORE generic onboarding Continues.
|
|
2124
|
+
// Cooldown: re-clicking Google mid-redirect restarts OAuth and wastes time.
|
|
2125
|
+
const allowGoogleClick =
|
|
2126
|
+
!googleAuthed
|
|
2127
|
+
&& (!googleLoginSelectedAt || Date.now() - googleLoginSelectedAt > GOOGLE_SSO_COOLDOWN_MS);
|
|
2128
|
+
const handledProviderGate = await handleProviderLoginGate(page, reportStep, { allowGoogleClick });
|
|
1772
2129
|
if (handledProviderGate) {
|
|
2130
|
+
if (allowGoogleClick) googleLoginSelectedAt = Date.now();
|
|
1773
2131
|
continue;
|
|
1774
2132
|
}
|
|
1775
2133
|
|
|
1776
|
-
|
|
1777
|
-
if (
|
|
1778
|
-
|
|
1779
|
-
|
|
2134
|
+
// xAI device approve ONLY after Google password submitted.
|
|
2135
|
+
if (
|
|
2136
|
+
googleAuthed
|
|
2137
|
+
&& Date.now() - deviceApproveAt > DEVICE_APPROVE_COOLDOWN_MS
|
|
2138
|
+
&& await clickXaiDeviceAuthorize(page, reportStep)
|
|
2139
|
+
) {
|
|
2140
|
+
deviceApproveAt = Date.now();
|
|
1780
2141
|
continue;
|
|
1781
2142
|
}
|
|
1782
2143
|
|
|
2144
|
+
const handledProviderOnboarding = await handleProviderOnboarding(page, reportStep, serviceLabel);
|
|
2145
|
+
if (handledProviderOnboarding) {
|
|
2146
|
+
continue;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// Credentials only on accounts.google.com — never into provider shells.
|
|
2150
|
+
if (isGoogleAuthPage(page)) {
|
|
2151
|
+
seenGoogleAuth = true;
|
|
2152
|
+
// Check password BEFORE email — after submitting the email the password
|
|
2153
|
+
// page loads and during the transition the old email input can briefly
|
|
2154
|
+
// remain visible; if we checked email first we'd re-type the email
|
|
2155
|
+
// address into whatever field is focused (often the password input).
|
|
2156
|
+
const passwordInput = await getFirstVisibleLocator(page, PASSWORD_INPUT_SELECTOR);
|
|
2157
|
+
if (passwordInput) {
|
|
2158
|
+
const sincePw = Date.now() - passwordSubmittedAt;
|
|
2159
|
+
if (passwordSubmittedAt && sincePw < PASSWORD_RESUBMIT_COOLDOWN_MS) {
|
|
2160
|
+
// Still on (or animating off) the password form after a recent submit —
|
|
2161
|
+
// do NOT re-fill; wait for SetSID/consent/callback instead.
|
|
2162
|
+
reportStep(
|
|
2163
|
+
"waiting_after_password",
|
|
2164
|
+
`Password already submitted ${Math.round(sincePw / 1000)}s ago — waiting for Google redirect`,
|
|
2165
|
+
);
|
|
2166
|
+
await waitThroughGoogleInterstitials(
|
|
2167
|
+
page,
|
|
2168
|
+
reportStep,
|
|
2169
|
+
interstitialOpts(isGrokFlow ? 2_000 : 6_000),
|
|
2170
|
+
);
|
|
2171
|
+
continue;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
reportStep("entering_password", "Entering Google password");
|
|
2175
|
+
const filled = await fillInputResilient(passwordInput, password);
|
|
2176
|
+
if (filled) {
|
|
2177
|
+
reportStep("submitting_password", "Submitting password");
|
|
2178
|
+
const prePwUrl = page.url?.() || "";
|
|
2179
|
+
await clickFirstVisible(page, NEXT_BUTTON_SELECTORS);
|
|
2180
|
+
passwordSubmittedAt = Date.now();
|
|
2181
|
+
// Leave password challenge via navigation / URL change / success — no 2.5s sleep.
|
|
2182
|
+
await Promise.race([
|
|
2183
|
+
page.waitForNavigation({ waitUntil: "domcontentloaded", timeout: isGrokFlow ? 6_000 : 10_000 }).catch(() => null),
|
|
2184
|
+
waitForPageAdvance(page, { fromUrl: prePwUrl, timeout: isGrokFlow ? 6_000 : 10_000 }),
|
|
2185
|
+
successPromise.then(() => null).catch(() => null),
|
|
2186
|
+
]);
|
|
2187
|
+
await waitThroughGoogleInterstitials(
|
|
2188
|
+
page,
|
|
2189
|
+
reportStep,
|
|
2190
|
+
interstitialOpts(postPasswordInterstitialMs),
|
|
2191
|
+
);
|
|
2192
|
+
} else {
|
|
2193
|
+
reportStep("password_fill_failed", "Could not fill the Google password field; retrying loop");
|
|
2194
|
+
await yieldMs(100);
|
|
2195
|
+
}
|
|
2196
|
+
continue;
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
const nextEmailInput = await getFirstVisibleLocator(page, EMAIL_INPUT_SELECTOR);
|
|
2200
|
+
if (nextEmailInput) {
|
|
2201
|
+
const sinceEmail = Date.now() - emailSubmittedAt;
|
|
2202
|
+
if (emailSubmittedAt && sinceEmail < EMAIL_RESUBMIT_COOLDOWN_MS) {
|
|
2203
|
+
reportStep(
|
|
2204
|
+
"waiting_after_email",
|
|
2205
|
+
`Email already submitted ${Math.round(sinceEmail / 1000)}s ago — waiting for password/next screen`,
|
|
2206
|
+
);
|
|
2207
|
+
await waitForPageAdvance(page, {
|
|
2208
|
+
selector: PASSWORD_INPUT_SELECTOR,
|
|
2209
|
+
timeout: Math.max(200, EMAIL_RESUBMIT_COOLDOWN_MS - sinceEmail),
|
|
2210
|
+
});
|
|
2211
|
+
continue;
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
reportStep("entering_email", "Entering Google email");
|
|
2215
|
+
const filled = await fillInputResilient(nextEmailInput, email);
|
|
2216
|
+
if (filled) {
|
|
2217
|
+
reportStep("submitting_email", "Submitting email");
|
|
2218
|
+
await clickFirstVisible(page, NEXT_BUTTON_SELECTORS);
|
|
2219
|
+
emailSubmittedAt = Date.now();
|
|
2220
|
+
await waitForPageAdvance(page, {
|
|
2221
|
+
selector: PASSWORD_INPUT_SELECTOR,
|
|
2222
|
+
timeout: isGrokFlow ? 6_000 : 10_000,
|
|
2223
|
+
});
|
|
2224
|
+
} else {
|
|
2225
|
+
reportStep("email_fill_failed", "Could not fill the Google email field; retrying loop");
|
|
2226
|
+
await yieldMs(80);
|
|
2227
|
+
}
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
// On xAI before Google login, APPROVE selectors match "Continue with Google"
|
|
2233
|
+
// via :has-text("Continue") and wreck the device code → Invalid action loop.
|
|
2234
|
+
const mayGenericApprove =
|
|
2235
|
+
isGoogleAuthPage(page)
|
|
2236
|
+
|| (seenGoogleAuth && passwordSubmittedAt && !(await providerHasGoogleLogin(page)));
|
|
2237
|
+
if (mayGenericApprove) {
|
|
2238
|
+
const clickedApprove = await clickFirstVisible(page, APPROVE_BUTTON_SELECTORS);
|
|
2239
|
+
if (clickedApprove) {
|
|
2240
|
+
reportStep("approving_consent", `Approving Google or ${serviceLabel} consent`);
|
|
2241
|
+
deviceApproveAt = Date.now();
|
|
2242
|
+
await waitForPageAdvance(page, { timeout: isGrokFlow ? 2_000 : 4_000 });
|
|
2243
|
+
continue;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
|
|
1783
2247
|
// Periodic diagnostics so jobs aren't opaque "waiting" spam
|
|
1784
|
-
if (Math.floor((Date.now() - startTime) / 5000) !== Math.floor((Date.now() - startTime -
|
|
2248
|
+
if (Math.floor((Date.now() - startTime) / 5000) !== Math.floor((Date.now() - startTime - loopTickMs) / 5000)) {
|
|
1785
2249
|
const url = page.url?.() || "";
|
|
1786
2250
|
const snippet = String(text || (await readPageText(page).catch(() => ""))).slice(0, 100).replace(/\s+/g, " ");
|
|
1787
2251
|
reportStep(
|
|
@@ -1791,7 +2255,8 @@ export async function runGoogleAccountAutomation({
|
|
|
1791
2255
|
} else {
|
|
1792
2256
|
reportStep("waiting_for_next_screen", `Waiting for the next Google or ${serviceLabel} screen`);
|
|
1793
2257
|
}
|
|
1794
|
-
|
|
2258
|
+
// Only yield — next loop races successPromise + handlers. Fast net = fast exit.
|
|
2259
|
+
await yieldMs(loopTickMs);
|
|
1795
2260
|
}
|
|
1796
2261
|
|
|
1797
2262
|
// Final blocked check before generic needs_manual
|