qwenproxy-cli 1.6.1 → 1.6.2

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/dist/login.js CHANGED
@@ -826,7 +826,7 @@ function addAccountsBatch(entries) {
826
826
  }
827
827
  return { added, skipped, invalid };
828
828
  }
829
- function addAccount(email, password, id) {
829
+ function addAccount(email, password = "", id) {
830
830
  if (!email || typeof email !== "string" || email.trim().length === 0) {
831
831
  throw new Error("Email is required");
832
832
  }
@@ -3182,6 +3182,7 @@ var playwright_exports = {};
3182
3182
  __export(playwright_exports, {
3183
3183
  assertAntiBotHeaders: () => assertAntiBotHeaders,
3184
3184
  buildChromiumLaunchArgs: () => buildChromiumLaunchArgs,
3185
+ cancelEmailOtpLogin: () => cancelEmailOtpLogin,
3185
3186
  captureQwenHeaders: () => captureQwenHeaders,
3186
3187
  classifyQwenAuthError: () => classifyQwenAuthError,
3187
3188
  cleanupOrphanProfiles: () => cleanupOrphanProfiles,
@@ -3222,8 +3223,10 @@ __export(playwright_exports, {
3222
3223
  removePlaywrightProfile: () => removePlaywrightProfile,
3223
3224
  saveStorageState: () => saveStorageState,
3224
3225
  schedulePlaywrightProfileReset: () => schedulePlaywrightProfileReset,
3226
+ startEmailOtpLogin: () => startEmailOtpLogin,
3225
3227
  unregisterPlaywrightAccountForTests: () => unregisterPlaywrightAccountForTests,
3226
3228
  validateAccountLogin: () => validateAccountLogin,
3229
+ verifyEmailOtpLogin: () => verifyEmailOtpLogin,
3227
3230
  withAccountPage: () => withAccountPage
3228
3231
  });
3229
3232
  import { chromium as chromium2 } from "patchright";
@@ -3565,6 +3568,10 @@ async function clearVisibleChallenge(page) {
3565
3568
  "button[aria-label*='Close' i]",
3566
3569
  "button[aria-label*='Fechar' i]",
3567
3570
  ".index-module__whats-new-modal-close",
3571
+ ".age-confirmation-modal button",
3572
+ ".age-confirmation-modal .qwen-chat-v2-btn-black",
3573
+ "button:has-text('Continuar')",
3574
+ "button:has-text('Continue')",
3568
3575
  "button:has-text('Cancel')",
3569
3576
  "button:has-text('Cancelar')",
3570
3577
  "button:has-text('I understand')",
@@ -4759,6 +4766,292 @@ async function validateAccountLogin(rawAccount, headless = true, browserType = "
4759
4766
  release();
4760
4767
  }
4761
4768
  }
4769
+ async function startEmailOtpLogin(email, options = {}) {
4770
+ const normalizedEmail = email.trim().toLowerCase();
4771
+ if (!normalizedEmail || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedEmail)) {
4772
+ return { success: false, error: "Formato de e-mail inv\xE1lido" };
4773
+ }
4774
+ const { listAccounts: listAccounts2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
4775
+ if (listAccounts2().some((a) => a.email.toLowerCase() === normalizedEmail)) {
4776
+ return {
4777
+ success: false,
4778
+ error: `Uma conta com o e-mail "${normalizedEmail}" j\xE1 est\xE1 cadastrada.`
4779
+ };
4780
+ }
4781
+ if (process.env.TEST_MOCK_QWEN_AUTH === "true" && process.env.NODE_ENV !== "production") {
4782
+ const mockSessionId = "mock-otp-" + Date.now();
4783
+ mockOtpSessions.set(mockSessionId, normalizedEmail);
4784
+ return { success: true, sessionId: mockSessionId };
4785
+ }
4786
+ const accountId = crypto3.randomUUID();
4787
+ const sessionId = accountId;
4788
+ const profilePath = getAccountProfilePath(accountId);
4789
+ const fingerprint = getFingerprintProfile(accountId);
4790
+ const browserType = options.browserType ?? config.playwright.browser;
4791
+ const { engine, channel } = resolveBrowserEngine(browserType);
4792
+ const headless = options.headless ?? config.playwright.headless;
4793
+ const launchOptions = {
4794
+ headless,
4795
+ channel,
4796
+ userAgent: fingerprint.userAgent,
4797
+ locale: fingerprint.locale,
4798
+ timezoneId: fingerprint.timezoneId,
4799
+ viewport: fingerprint.viewport,
4800
+ screen: fingerprint.viewport,
4801
+ deviceScaleFactor: 1,
4802
+ isMobile: false,
4803
+ hasTouch: false,
4804
+ colorScheme: "light",
4805
+ extraHTTPHeaders: {
4806
+ "sec-ch-ua": fingerprint.secChUa,
4807
+ "sec-ch-ua-mobile": "?0",
4808
+ "sec-ch-ua-platform": '"Windows"'
4809
+ },
4810
+ ignoreDefaultArgs: ["--enable-automation", "--enable-blink-features"],
4811
+ args: buildChromiumLaunchArgs(fingerprint.viewport)
4812
+ };
4813
+ let acctContext;
4814
+ try {
4815
+ acctContext = await withTimeout(
4816
+ engine.launchPersistentContext(profilePath, launchOptions),
4817
+ 3e4,
4818
+ `O navegador n\xE3o iniciou em 30s para a conta ${maskEmail(normalizedEmail)}.`
4819
+ );
4820
+ } catch (launchErr) {
4821
+ if (launchErr?.message?.includes("Executable doesn't exist")) {
4822
+ autoInstallPlaywrightChromium();
4823
+ acctContext = await withTimeout(
4824
+ engine.launchPersistentContext(profilePath, launchOptions),
4825
+ 3e4,
4826
+ `O navegador n\xE3o iniciou em 30s para a conta ${maskEmail(normalizedEmail)}.`
4827
+ );
4828
+ } else {
4829
+ return { success: false, error: launchErr?.message || String(launchErr) };
4830
+ }
4831
+ }
4832
+ try {
4833
+ await acctContext.addInitScript(getStealthScript(fingerprint));
4834
+ const existingPages = acctContext.pages().filter((p) => !p.isClosed());
4835
+ const acctPage = existingPages.find((p) => p.url().startsWith(qwenOrigin())) ?? existingPages[0] ?? await acctContext.newPage();
4836
+ await acctPage.goto(qwenUrl("/auth?mode=register"), {
4837
+ waitUntil: "domcontentloaded",
4838
+ timeout: Math.min(config.timeouts.navigation, 2e4)
4839
+ }).catch(() => {
4840
+ });
4841
+ await sleep2(1e3);
4842
+ await clearVisibleChallenge(acctPage);
4843
+ const requestId = crypto3.randomUUID();
4844
+ const evalRes = await acctPage.evaluate(
4845
+ async ({ email: email2, requestId: requestId2, version, timezone }) => {
4846
+ try {
4847
+ const response = await fetch("https://auth.qwen.ai/api/v2/auths/otp/email/request", {
4848
+ method: "POST",
4849
+ credentials: "include",
4850
+ headers: {
4851
+ accept: "application/json, text/plain, */*",
4852
+ "content-type": "application/json",
4853
+ source: "web",
4854
+ version,
4855
+ "x-request-origin": "https://chat.qwen.ai",
4856
+ timezone,
4857
+ "x-request-id": requestId2
4858
+ },
4859
+ body: JSON.stringify({
4860
+ identifier: email2,
4861
+ accept_terms: true,
4862
+ language: "pt-BR"
4863
+ })
4864
+ });
4865
+ const json = await response.json().catch(() => null);
4866
+ return { ok: response.ok, status: response.status, data: json };
4867
+ } catch (e) {
4868
+ return { ok: false, error: e.message };
4869
+ }
4870
+ },
4871
+ {
4872
+ email: normalizedEmail,
4873
+ requestId,
4874
+ version: getQwenWebVersion() || "0.3.12",
4875
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0]
4876
+ }
4877
+ ).catch((err) => ({ ok: false, error: err?.message || String(err) }));
4878
+ if (!evalRes.ok || evalRes.data?.success !== true) {
4879
+ const errorMsg = evalRes.data?.data?.details || evalRes.data?.data?.message || evalRes.data?.message || evalRes.error || "Falha ao solicitar c\xF3digo de verifica\xE7\xE3o";
4880
+ await closePlaywrightContextBestEffort(accountId, acctContext).catch(() => {
4881
+ });
4882
+ cleanupPlaywrightAccountState(accountId);
4883
+ return { success: false, error: errorMsg };
4884
+ }
4885
+ const timer = setTimeout(async () => {
4886
+ activeOtpSessions.delete(sessionId);
4887
+ await closePlaywrightContextBestEffort(accountId, acctContext).catch(() => {
4888
+ });
4889
+ cleanupPlaywrightAccountState(accountId);
4890
+ }, 5 * 60 * 1e3);
4891
+ timer.unref?.();
4892
+ activeOtpSessions.set(sessionId, {
4893
+ sessionId,
4894
+ accountId,
4895
+ email: normalizedEmail,
4896
+ context: acctContext,
4897
+ page: acctPage,
4898
+ fingerprint,
4899
+ createdAt: Date.now(),
4900
+ timer
4901
+ });
4902
+ return { success: true, sessionId };
4903
+ } catch (err) {
4904
+ await closePlaywrightContextBestEffort(accountId, acctContext).catch(() => {
4905
+ });
4906
+ cleanupPlaywrightAccountState(accountId);
4907
+ return { success: false, error: err?.message || String(err) };
4908
+ }
4909
+ }
4910
+ async function verifyEmailOtpLogin(sessionId, code) {
4911
+ const cleanCode = code.trim();
4912
+ if (!cleanCode) {
4913
+ return { success: false, error: "C\xF3digo de verifica\xE7\xE3o \xE9 obrigat\xF3rio" };
4914
+ }
4915
+ if (process.env.TEST_MOCK_QWEN_AUTH === "true" && process.env.NODE_ENV !== "production") {
4916
+ const mockEmail = mockOtpSessions.get(sessionId);
4917
+ if (!mockEmail) {
4918
+ return { success: false, error: "Sess\xE3o OTP inv\xE1lida ou expirada" };
4919
+ }
4920
+ if (cleanCode === "000000") {
4921
+ return { success: false, error: "C\xF3digo de verifica\xE7\xE3o incorreto ou expirado" };
4922
+ }
4923
+ const { addAccount: addAccount2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
4924
+ const mockAccId = "mock-otp-acc-" + Date.now();
4925
+ const newAccount = addAccount2(mockEmail, "", mockAccId);
4926
+ mockOtpSessions.delete(sessionId);
4927
+ return { success: true, account: newAccount };
4928
+ }
4929
+ const session = activeOtpSessions.get(sessionId);
4930
+ if (!session) {
4931
+ return { success: false, error: "Sess\xE3o OTP expirada ou n\xE3o encontrada. Solicite um novo c\xF3digo." };
4932
+ }
4933
+ if (session.page.isClosed()) {
4934
+ activeOtpSessions.delete(sessionId);
4935
+ return { success: false, error: "Navegador foi fechado. Solicite um novo c\xF3digo." };
4936
+ }
4937
+ const requestId = crypto3.randomUUID();
4938
+ const evalRes = await session.page.evaluate(
4939
+ async ({ email, code: code2, requestId: requestId2, version, timezone }) => {
4940
+ try {
4941
+ const response = await fetch("https://auth.qwen.ai/api/v2/auths/otp/email/verify", {
4942
+ method: "POST",
4943
+ credentials: "include",
4944
+ headers: {
4945
+ accept: "application/json, text/plain, */*",
4946
+ "content-type": "application/json",
4947
+ source: "web",
4948
+ version,
4949
+ "x-request-origin": "https://chat.qwen.ai",
4950
+ timezone,
4951
+ "x-request-id": requestId2
4952
+ },
4953
+ body: JSON.stringify({
4954
+ identifier: email,
4955
+ code: code2,
4956
+ name: null
4957
+ })
4958
+ });
4959
+ const json = await response.json().catch(() => null);
4960
+ return { ok: response.ok, status: response.status, data: json };
4961
+ } catch (e) {
4962
+ return { ok: false, error: e.message };
4963
+ }
4964
+ },
4965
+ {
4966
+ email: session.email,
4967
+ code: cleanCode,
4968
+ requestId,
4969
+ version: getQwenWebVersion() || "0.3.12",
4970
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0]
4971
+ }
4972
+ ).catch((err) => ({ ok: false, error: err?.message || String(err) }));
4973
+ if (!evalRes.ok || evalRes.data?.success !== true || !evalRes.data?.data) {
4974
+ const errorMsg = evalRes.data?.data?.details || evalRes.data?.data?.message || evalRes.data?.message || evalRes.error || "C\xF3digo de verifica\xE7\xE3o incorreto ou expirado";
4975
+ return { success: false, error: errorMsg };
4976
+ }
4977
+ const resData = evalRes.data.data;
4978
+ const accessToken = resData.access_token || resData.token;
4979
+ const refreshToken = resData.refresh_token;
4980
+ const userId = resData.id;
4981
+ try {
4982
+ await session.page.evaluate(({ token, rTok }) => {
4983
+ try {
4984
+ localStorage.setItem("token", token);
4985
+ localStorage.setItem("access_token", token);
4986
+ if (rTok) localStorage.setItem("refresh_token", rTok);
4987
+ document.cookie = `token=${encodeURIComponent(token)}; path=/; domain=.qwen.ai; max-age=31536000`;
4988
+ } catch {
4989
+ }
4990
+ }, { token: accessToken, rTok: refreshToken });
4991
+ await session.context.addCookies([
4992
+ {
4993
+ name: "token",
4994
+ value: accessToken,
4995
+ domain: ".qwen.ai",
4996
+ path: "/",
4997
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
4998
+ httpOnly: false,
4999
+ secure: true,
5000
+ sameSite: "Lax"
5001
+ }
5002
+ ]);
5003
+ await session.page.goto(qwenUrl("/"), {
5004
+ waitUntil: "domcontentloaded",
5005
+ timeout: Math.min(config.timeouts.navigation, 15e3)
5006
+ }).catch(() => {
5007
+ });
5008
+ await sleep2(1e3);
5009
+ await saveStorageState(session.context, session.accountId);
5010
+ const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5011
+ const { parseJwtExpiry: parseJwtExpiry2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
5012
+ const exp = parseJwtExpiry2(accessToken);
5013
+ saveAuthSession2(session.accountId, {
5014
+ cookie: `token=${accessToken}`,
5015
+ userAgent: session.fingerprint.userAgent,
5016
+ bxV: "2.5.37",
5017
+ version: getQwenWebVersion() || "0.3.12",
5018
+ userId: userId || void 0,
5019
+ tokenExpiresAt: exp || void 0,
5020
+ refreshToken: refreshToken || void 0,
5021
+ capturedAt: Date.now()
5022
+ });
5023
+ const { addAccount: addAccount2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
5024
+ const newAccount = addAccount2(session.email, "", session.accountId);
5025
+ clearTimeout(session.timer);
5026
+ activeOtpSessions.delete(sessionId);
5027
+ await closePlaywrightContextBestEffort(session.accountId, session.context).catch(() => {
5028
+ });
5029
+ cleanupPlaywrightAccountState(session.accountId);
5030
+ return { success: true, account: newAccount };
5031
+ } catch (err) {
5032
+ clearTimeout(session.timer);
5033
+ activeOtpSessions.delete(sessionId);
5034
+ await closePlaywrightContextBestEffort(session.accountId, session.context).catch(() => {
5035
+ });
5036
+ cleanupPlaywrightAccountState(session.accountId);
5037
+ return { success: false, error: err?.message || String(err) };
5038
+ }
5039
+ }
5040
+ async function cancelEmailOtpLogin(sessionId) {
5041
+ if (process.env.TEST_MOCK_QWEN_AUTH === "true" && process.env.NODE_ENV !== "production") {
5042
+ mockOtpSessions.delete(sessionId);
5043
+ return;
5044
+ }
5045
+ const session = activeOtpSessions.get(sessionId);
5046
+ if (!session) return;
5047
+ clearTimeout(session.timer);
5048
+ activeOtpSessions.delete(sessionId);
5049
+ await closePlaywrightContextBestEffort(session.accountId, session.context).catch(() => {
5050
+ });
5051
+ cleanupPlaywrightAccountState(session.accountId);
5052
+ const { wipeAccountSessionFiles: wipeAccountSessionFiles2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
5053
+ wipeAccountSessionFiles2(session.accountId);
5054
+ }
4762
5055
  function classifyQwenAuthError(code, details) {
4763
5056
  const c = (code || "").trim().toLowerCase();
4764
5057
  const d = (details || "").trim().toLowerCase();
@@ -6127,7 +6420,7 @@ async function withAccountPage(accountId, fn, timeoutMs = ACCOUNT_PAGE_OPERATION
6127
6420
  return result;
6128
6421
  } catch (error) {
6129
6422
  const message = getErrorMessage(error);
6130
- if (recoverOnTimeout && message.includes("Playwright page operation timed out")) {
6423
+ if (recoverOnTimeout && message.includes("Playwright page operation timed out") && (!page || page.isClosed())) {
6131
6424
  console.warn(
6132
6425
  `\u23F1\uFE0F [Playwright] Resetting account context after a stuck page operation: ${accountId}`
6133
6426
  );
@@ -6676,7 +6969,7 @@ async function getTokenDiagnostics(accountId) {
6676
6969
  }
6677
6970
  };
6678
6971
  }
6679
- var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, cachedUserAgents, inFlightAccountInits, sharedBrowser, sharedBrowserPromise, headerCaches, HEADER_CACHE_TTL, HEADER_REFRESH_THRESHOLD, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
6972
+ var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, cachedUserAgents, inFlightAccountInits, sharedBrowser, sharedBrowserPromise, headerCaches, HEADER_CACHE_TTL, HEADER_REFRESH_THRESHOLD, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, activeOtpSessions, mockOtpSessions, PROFILE_RESET_TIMEOUT_MS;
6680
6973
  var init_playwright = __esm({
6681
6974
  "src/services/playwright.ts"() {
6682
6975
  "use strict";
@@ -6721,11 +7014,13 @@ var init_playwright = __esm({
6721
7014
  PLAYWRIGHT_MUTEX_WAIT_MS = 6e4;
6722
7015
  ACCOUNT_PAGE_OPERATION_TIMEOUT_MS = config.timeouts.page;
6723
7016
  SESSION_PROBE_NAVIGATION_TIMEOUT_MS = 15e3;
6724
- HEADER_CAPTURE_TRIGGER_GRACE_MS = 15e3;
6725
- FIRST_TRIGGER_GRACE_MS = 8e3;
7017
+ HEADER_CAPTURE_TRIGGER_GRACE_MS = 2e4;
7018
+ FIRST_TRIGGER_GRACE_MS = 12e3;
6726
7019
  HEADER_CAPTURE_TRIGGER_ATTEMPTS = 3;
6727
7020
  CHAT_INPUT_APPEAR_TIMEOUT_MS = 15e3;
6728
7021
  CHAT_INPUT_ACTION_TIMEOUT_MS = 1e4;
7022
+ activeOtpSessions = /* @__PURE__ */ new Map();
7023
+ mockOtpSessions = /* @__PURE__ */ new Map();
6729
7024
  PROFILE_RESET_TIMEOUT_MS = Math.max(9e4, config.timeouts.headers);
6730
7025
  setWafContextResetListener((accountId) => {
6731
7026
  if (!accountPages.has(accountId)) return;
@@ -6779,7 +7074,8 @@ async function showMenu() {
6779
7074
  console.log("No accounts configured yet.\n");
6780
7075
  }
6781
7076
  console.log("\nOptions:");
6782
- console.log(" [A] Add account");
7077
+ console.log(" [A] Add account (Password)");
7078
+ console.log(" [O] Add account (Passwordless / Email OTP)");
6783
7079
  if (accounts.length > 0) {
6784
7080
  console.log(" [R] Remove an account");
6785
7081
  }
@@ -6790,7 +7086,21 @@ async function showMenu() {
6790
7086
  process.exit(0);
6791
7087
  }
6792
7088
  if (choice === "A") {
6793
- await addAccountFlow();
7089
+ clear();
7090
+ console.log("=== Add New Account ===\n");
7091
+ console.log("Authentication method:");
7092
+ console.log(" [1] Traditional Password (Email + Password)");
7093
+ console.log(" [2] Passwordless (Email Verification Code / OTP)\n");
7094
+ const method = (await askQuestion("Select method [1/2] (default 1): ")).trim();
7095
+ if (method === "2") {
7096
+ await addAccountOtpFlow();
7097
+ } else {
7098
+ await addAccountPasswordFlow();
7099
+ }
7100
+ continue;
7101
+ }
7102
+ if (choice === "O") {
7103
+ await addAccountOtpFlow();
6794
7104
  continue;
6795
7105
  }
6796
7106
  if (choice === "R" && accounts.length > 0) {
@@ -6799,9 +7109,9 @@ async function showMenu() {
6799
7109
  }
6800
7110
  }
6801
7111
  }
6802
- async function addAccountFlow() {
7112
+ async function addAccountPasswordFlow() {
6803
7113
  clear();
6804
- console.log("=== Add New Account ===\n");
7114
+ console.log("=== Add New Account (Password Login) ===\n");
6805
7115
  const email = await askQuestion("Email: ");
6806
7116
  if (!email || !email.trim()) {
6807
7117
  console.log("Email is required.");
@@ -6870,6 +7180,70 @@ async function addAccountFlow() {
6870
7180
  }
6871
7181
  await askQuestion("\nPress Enter to continue...");
6872
7182
  }
7183
+ async function addAccountOtpFlow() {
7184
+ clear();
7185
+ console.log("=== Add New Account (Passwordless / Email OTP) ===\n");
7186
+ const email = await askQuestion("Email: ");
7187
+ if (!email || !email.trim()) {
7188
+ console.log("Email is required.");
7189
+ await askQuestion("Press Enter to continue...");
7190
+ return;
7191
+ }
7192
+ const trimmedEmail = email.trim();
7193
+ const existingAccounts = listAccounts();
7194
+ if (existingAccounts.some(
7195
+ (a) => a.email.toLowerCase() === trimmedEmail.toLowerCase()
7196
+ )) {
7197
+ console.log(
7198
+ `
7199
+ \u274C Error: An account with email "${trimmedEmail}" already exists.`
7200
+ );
7201
+ await askQuestion("Press Enter to continue...");
7202
+ return;
7203
+ }
7204
+ console.log(
7205
+ `
7206
+ \u23F3 Requesting OTP verification code for ${maskEmail(trimmedEmail)}...`
7207
+ );
7208
+ const { startEmailOtpLogin: startEmailOtpLogin2, verifyEmailOtpLogin: verifyEmailOtpLogin2, cancelEmailOtpLogin: cancelEmailOtpLogin2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
7209
+ const startRes = await startEmailOtpLogin2(trimmedEmail, { headless: false });
7210
+ if (!startRes.success || !startRes.sessionId) {
7211
+ console.log(
7212
+ `
7213
+ \u274C Failed to request code: ${startRes.error || "Unknown error"}`
7214
+ );
7215
+ await askQuestion("Press Enter to continue...");
7216
+ return;
7217
+ }
7218
+ console.log(`
7219
+ \u2709\uFE0F Verification code sent to ${trimmedEmail}!`);
7220
+ console.log("Check your email inbox (and spam folder).\n");
7221
+ while (true) {
7222
+ const code = await askQuestion("Enter 6-digit code (or 'C' to cancel): ");
7223
+ if (!code || !code.trim()) continue;
7224
+ if (code.trim().toUpperCase() === "C") {
7225
+ await cancelEmailOtpLogin2(startRes.sessionId);
7226
+ console.log("\nLogin cancelled.");
7227
+ await askQuestion("Press Enter to continue...");
7228
+ return;
7229
+ }
7230
+ console.log("\n\u23F3 Verifying code and establishing 30-day session...");
7231
+ const verifyRes = await verifyEmailOtpLogin2(startRes.sessionId, code.trim());
7232
+ if (verifyRes.success && verifyRes.account) {
7233
+ console.log(
7234
+ `
7235
+ \u2705 Account verified and saved: ${maskEmail(verifyRes.account.email)} (${verifyRes.account.id})`
7236
+ );
7237
+ console.log("Passwordless 30-day session active.");
7238
+ await askQuestion("\nPress Enter to continue...");
7239
+ return;
7240
+ } else {
7241
+ console.log(`
7242
+ \u274C ${verifyRes.error || "Invalid code"}`);
7243
+ console.log("Please try again or enter 'C' to cancel.\n");
7244
+ }
7245
+ }
7246
+ }
6873
7247
  async function removeAccountFlow() {
6874
7248
  const accounts = listAccounts();
6875
7249
  if (accounts.length === 0) return;
@@ -781,7 +781,7 @@ function addAccountsBatch(entries) {
781
781
  }
782
782
  return { added, skipped, invalid };
783
783
  }
784
- function addAccount(email, password, id) {
784
+ function addAccount(email, password = "", id) {
785
785
  if (!email || typeof email !== "string" || email.trim().length === 0) {
786
786
  throw new Error("Email is required");
787
787
  }
@@ -3226,6 +3226,10 @@ async function clearVisibleChallenge(page) {
3226
3226
  "button[aria-label*='Close' i]",
3227
3227
  "button[aria-label*='Fechar' i]",
3228
3228
  ".index-module__whats-new-modal-close",
3229
+ ".age-confirmation-modal button",
3230
+ ".age-confirmation-modal .qwen-chat-v2-btn-black",
3231
+ "button:has-text('Continuar')",
3232
+ "button:has-text('Continue')",
3229
3233
  "button:has-text('Cancel')",
3230
3234
  "button:has-text('Cancelar')",
3231
3235
  "button:has-text('I understand')",
@@ -5585,8 +5589,8 @@ var init_playwright = __esm({
5585
5589
  PLAYWRIGHT_MUTEX_WAIT_MS = 6e4;
5586
5590
  ACCOUNT_PAGE_OPERATION_TIMEOUT_MS = config.timeouts.page;
5587
5591
  SESSION_PROBE_NAVIGATION_TIMEOUT_MS = 15e3;
5588
- HEADER_CAPTURE_TRIGGER_GRACE_MS = 15e3;
5589
- FIRST_TRIGGER_GRACE_MS = 8e3;
5592
+ HEADER_CAPTURE_TRIGGER_GRACE_MS = 2e4;
5593
+ FIRST_TRIGGER_GRACE_MS = 12e3;
5590
5594
  HEADER_CAPTURE_TRIGGER_ATTEMPTS = 3;
5591
5595
  CHAT_INPUT_APPEAR_TIMEOUT_MS = 15e3;
5592
5596
  CHAT_INPUT_ACTION_TIMEOUT_MS = 1e4;
@@ -5702,6 +5706,15 @@ var init_helpers = __esm({
5702
5706
  }
5703
5707
  });
5704
5708
 
5709
+ // src/utils/overload-detector.ts
5710
+ var OVERLOAD_COOLDOWN_MS;
5711
+ var init_overload_detector = __esm({
5712
+ "src/utils/overload-detector.ts"() {
5713
+ "use strict";
5714
+ OVERLOAD_COOLDOWN_MS = 5 * 60 * 1e3;
5715
+ }
5716
+ });
5717
+
5705
5718
  // src/routes/chat/retry-policy.ts
5706
5719
  var init_retry_policy = __esm({
5707
5720
  "src/routes/chat/retry-policy.ts"() {
@@ -5712,6 +5725,7 @@ var init_retry_policy = __esm({
5712
5725
  init_qwen();
5713
5726
  init_errors();
5714
5727
  init_helpers();
5728
+ init_overload_detector();
5715
5729
  init_account_manager();
5716
5730
  }
5717
5731
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwenproxy-cli",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "description": "High-performance OpenAI & Anthropic compatible API gateway for Qwen with multi-account rotation, interactive TUI, and resilient tool calling.",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -29,8 +29,8 @@
29
29
  "reset": "npx tsx src/reset-cooldowns.ts",
30
30
  "purge": "npx tsx src/delete-chats.ts",
31
31
  "test": "npm run test:mock && npm run test:live",
32
- "test:mock": "tsx --test --test-concurrency=1 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts src/tests/auth-session-refresh-preservation.test.ts src/tests/personalization-in-flight-dedup.test.ts src/tests/daily-usage.test.ts src/tests/resilience-enhancements.test.ts src/tests/pool-quota-failover.test.ts",
33
- "test:mock:fast": "tsx --test --test-concurrency=2 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts src/tests/auth-session-refresh-preservation.test.ts src/tests/personalization-in-flight-dedup.test.ts src/tests/daily-usage.test.ts src/tests/resilience-enhancements.test.ts src/tests/pool-quota-failover.test.ts",
32
+ "test:mock": "tsx --test --test-concurrency=1 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts src/tests/auth-session-refresh-preservation.test.ts src/tests/personalization-in-flight-dedup.test.ts src/tests/daily-usage.test.ts src/tests/resilience-enhancements.test.ts src/tests/pool-quota-failover.test.ts src/tests/process-guard-and-resilience.test.ts src/tests/otp-login.test.ts src/tests/overload-detector.test.ts",
33
+ "test:mock:fast": "tsx --test --test-concurrency=2 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts src/tests/auth-session-refresh-preservation.test.ts src/tests/personalization-in-flight-dedup.test.ts src/tests/daily-usage.test.ts src/tests/resilience-enhancements.test.ts src/tests/pool-quota-failover.test.ts src/tests/process-guard-and-resilience.test.ts src/tests/otp-login.test.ts src/tests/overload-detector.test.ts",
34
34
  "test:live": "tsx --test src/tests/concurrentChat.test.ts src/tests/agenticStress.test.ts",
35
35
  "test:stress": "npx tsx src/benchmarks/stress-test.ts",
36
36
  "test:stress:personalization": "npx tsx src/benchmarks/stress-test-personalization.ts",
@@ -322,7 +322,7 @@ export function addAccountsBatch(
322
322
  }
323
323
  export function addAccount(
324
324
  email: string,
325
- password: string,
325
+ password = "",
326
326
  id?: string,
327
327
  ): QwenAccount {
328
328
  if (!email || typeof email !== "string" || email.trim().length === 0) {
@@ -17,6 +17,6 @@ export function getAppVersion(): string {
17
17
  }
18
18
  }
19
19
  } catch {}
20
- cachedVersion = "v1.6.1";
20
+ cachedVersion = "v1.6.2";
21
21
  return cachedVersion;
22
22
  }