qwenproxy-cli 1.3.3 → 1.3.5

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/README.es.md CHANGED
@@ -141,6 +141,12 @@ QwenProxy iniciará el servidor proxy en segundo plano y abrirá el panel intera
141
141
 
142
142
  ### 3. Añadir Cuentas de Qwen
143
143
 
144
+ > 🌐 **¿Dónde crear las cuentas?**
145
+ > Crea tus cuentas gratuitas directamente en el portal oficial de Qwen: **[https://chat.qwen.ai](https://chat.qwen.ai)**
146
+ > 1. Ingresa a **[chat.qwen.ai](https://chat.qwen.ai)** y haz clic en **Sign up** (Registrarse).
147
+ > 2. Regístrate con tu correo y contraseña (o inicia sesión con Google).
148
+ > 3. *Consejo:* Crea de 3 a 10 cuentas gratuitas. QwenProxy rotará automáticamente entre ellas cuando alcancen la cuota diaria, brindándote uso continuo e ininterrumpido en tus agentes de código.
149
+
144
150
  Dentro de la TUI, dirígete a la pestaña **`[5] Contas`** para gestionar credenciales:
145
151
 
146
152
  - **Importación por Lotes (`B`):** Pulsa **`B`** (o haz clic en `[ B ] Em Lote`). Pega tus credenciales en masa (`email:contraseña` por línea, formato `.env` con comas o copiado de hojas de cálculo). El sistema calcula las cuentas válidas en tiempo real, respeta caracteres especiales en contraseñas, omite duplicadas y guarda todo cifrado en SQLite en una sola transacción (<10ms).
package/README.md CHANGED
@@ -141,6 +141,12 @@ QwenProxy launches the high-performance proxy server in the background and opens
141
141
 
142
142
  ### 3. Add Qwen Accounts
143
143
 
144
+ > 🌐 **Where to create accounts?**
145
+ > Create your free accounts directly on the official Qwen Web portal: **[https://chat.qwen.ai](https://chat.qwen.ai)**
146
+ > 1. Go to **[chat.qwen.ai](https://chat.qwen.ai)** and click **Sign up**.
147
+ > 2. Register with your email and password (or Google login).
148
+ > 3. *Pro Tip:* Create 3 to 10 accounts so QwenProxy can automatically rotate between them when daily quotas are reached, giving you continuous uninterrupted coding!
149
+
144
150
  Inside the TUI, navigate to tab **`[5] Accounts`** to manage credentials:
145
151
 
146
152
  - **Batch Import (`B`):** Press **`B`** (or click `[ B ] Em Lote`). Paste your account credentials in bulk (`email:password` per line, raw `.env` string with commas, or spreadsheet paste). The parser calculates valid accounts in real time, handles special password characters safely, skips duplicates, and commits encrypted credentials to SQLite in a single transaction (<10ms).
package/README.pt-BR.md CHANGED
@@ -300,6 +300,12 @@ O QwenProxy inicializa o servidor de alta performance em segundo plano e abre a
300
300
 
301
301
  ### 3. Adicionar Contas Qwen
302
302
 
303
+ > 🌐 **Onde criar as contas?**
304
+ > Crie suas contas gratuitas diretamente no portal oficial do Qwen: **[https://chat.qwen.ai](https://chat.qwen.ai)**
305
+ > 1. Acesse **[chat.qwen.ai](https://chat.qwen.ai)** e clique no botão **Sign up** (Cadastrar-se).
306
+ > 2. Cadastre-se com seu e-mail e defina uma senha (ou use login via Google).
307
+ > 3. *Dica de Ouro:* Crie de 3 a 10 contas gratuitas. O QwenProxy rotaciona automaticamente entre elas quando a cota diária de uma atinge o limite, garantindo uso contínuo e sem pausas no seu fluxo de desenvolvimento!
308
+
303
309
  Na TUI, você pode gerenciar suas contas na aba **`[5] Contas`** de duas formas simples:
304
310
 
305
311
  - **Importação em Lote (`B`):** Pressione a tecla **`B`** (ou clique em `[ B ] Em Lote`). Cole suas contas de uma só vez (aceita formato `email:senha`, formato bruto do `.env` com vírgulas ou copiado de planilhas). O sistema calcula a contagem em tempo real, valida duplicatas e grava tudo no SQLite criptografado em milissegundos.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwenproxy-cli",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
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": {
@@ -80,7 +80,7 @@ const envSchema = z
80
80
  CHAT_TIMEOUT: z.string().default("180000"),
81
81
  NAVIGATION_TIMEOUT: z.string().default("60000"),
82
82
  PAGE_TIMEOUT: z.string().default("60000"),
83
- HEADERS_TIMEOUT: z.string().default("90000"),
83
+ HEADERS_TIMEOUT: z.string().default("120000"),
84
84
  TIME_TO_FIRST_BYTE: z.string().default("60000"),
85
85
  IDLE_STREAM_TIMEOUT: z.string().default("60000"),
86
86
  // Deadline for the FIRST upstream chunk on thinking models (the reasoning
@@ -2496,17 +2496,15 @@ export async function captureQwenHeaders(
2496
2496
  // Unbounded, page.focus would burn its 60s default timeout on every
2497
2497
  // attempt, freezing the whole capture and cooling a healthy account with
2498
2498
  // AuthInitFailed. A miss marks the attempt for a reload instead.
2499
+ const inputLocator = page.locator(inputSelector).first();
2499
2500
  try {
2500
- await page
2501
- .locator(inputSelector)
2502
- .first()
2503
- .waitFor({
2504
- state: "visible",
2505
- timeout: Math.max(
2506
- 1,
2507
- Math.min(CHAT_INPUT_APPEAR_TIMEOUT_MS, remainingBudgetMs()),
2508
- ),
2509
- });
2501
+ await inputLocator.waitFor({
2502
+ state: "visible",
2503
+ timeout: Math.max(
2504
+ 1,
2505
+ Math.min(CHAT_INPUT_APPEAR_TIMEOUT_MS, remainingBudgetMs()),
2506
+ ),
2507
+ });
2510
2508
  } catch {
2511
2509
  if (settled || page.isClosed()) return;
2512
2510
  console.warn(
@@ -2526,9 +2524,27 @@ export async function captureQwenHeaders(
2526
2524
  for (let interactionTry = 1; interactionTry <= 2; interactionTry++) {
2527
2525
  if (settled || page.isClosed()) return;
2528
2526
  try {
2529
- await page.focus(inputSelector, { timeout: inputActionTimeoutMs });
2527
+ if (typeof (inputLocator as any).focus === "function") {
2528
+ await (inputLocator as any).focus({ timeout: inputActionTimeoutMs });
2529
+ } else {
2530
+ await page.focus(inputSelector, { timeout: inputActionTimeoutMs });
2531
+ }
2530
2532
  if (settled || page.isClosed()) return;
2531
- await page.fill(inputSelector, "a", { timeout: inputActionTimeoutMs });
2533
+ if (typeof (inputLocator as any).fill === "function") {
2534
+ await (inputLocator as any).fill("a", { timeout: inputActionTimeoutMs });
2535
+ } else {
2536
+ await page.fill(inputSelector, "a", { timeout: inputActionTimeoutMs });
2537
+ }
2538
+ // Dispatch native React input events and keyboard stroke to guarantee React updates state
2539
+ if (typeof page.keyboard?.press === "function") {
2540
+ await page.keyboard.press("End").catch(() => {});
2541
+ }
2542
+ if (typeof (page.keyboard as any)?.type === "function") {
2543
+ await (page.keyboard as any).type(" ").catch(() => {});
2544
+ }
2545
+ if (typeof page.keyboard?.press === "function") {
2546
+ await page.keyboard.press("Backspace").catch(() => {});
2547
+ }
2532
2548
  if (typeof page.evaluate === "function") {
2533
2549
  await page.evaluate((sel) => {
2534
2550
  const el = document.querySelector(sel) as HTMLTextAreaElement | null;
@@ -2570,7 +2586,18 @@ export async function captureQwenHeaders(
2570
2586
  return;
2571
2587
  }
2572
2588
  if (settled || page.isClosed()) return;
2573
- await sleep(2000);
2589
+
2590
+ // Wait up to 3s for React to enable the send button after typing
2591
+ try {
2592
+ await page.waitForFunction(() => {
2593
+ const btn = document.querySelector(
2594
+ ".message-input-right-button-send .send-button, .chat-prompt-send-button, button.send-button, button[aria-label*='Send' i], button[aria-label*='Enviar' i], .send-button-container button"
2595
+ ) as HTMLButtonElement | null;
2596
+ return btn && !btn.disabled && !btn.classList.contains("disabled") && btn.getAttribute("aria-disabled") !== "true";
2597
+ }, { timeout: 3000 });
2598
+ } catch {
2599
+ await sleep(1000);
2600
+ }
2574
2601
  if (settled || page.isClosed()) return;
2575
2602
 
2576
2603
  const sendSelectors = [