qwenproxy-cli 1.3.4 → 1.3.6

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.4",
3
+ "version": "1.3.6",
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": {
@@ -2490,23 +2490,21 @@ export async function captureQwenHeaders(
2490
2490
  // picking a sibling textarea/contenteditable), then fall back to generic.
2491
2491
  // Mirrors upstream 5b3fd3e (robust account header capture).
2492
2492
  const inputSelector =
2493
- 'textarea.message-input-textarea:visible, textarea:visible, [contenteditable="true"]:visible';
2493
+ "textarea.message-input-textarea, textarea[placeholder*='Ask' i], textarea[placeholder*='Pergunte' i], textarea";
2494
2494
  // Bound the appearance wait: a page that never renders the chat input is
2495
2495
  // blocked (WAF interstitial, punish document, or failed SPA hydration).
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,19 +2524,18 @@ 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 });
2530
- if (settled || page.isClosed()) return;
2531
- await page.fill(inputSelector, "a", { timeout: inputActionTimeoutMs });
2532
- // Dispatch native React input events and keyboard stroke to guarantee React updates state
2533
- if (typeof page.keyboard?.press === "function") {
2534
- await page.keyboard.press("End").catch(() => {});
2535
- }
2536
- if (typeof (page.keyboard as any)?.type === "function") {
2537
- await (page.keyboard as any).type(" ").catch(() => {});
2527
+ if (typeof (inputLocator as any).focus === "function") {
2528
+ await (inputLocator as any).focus({ timeout: inputActionTimeoutMs }).catch(() => {});
2529
+ } else {
2530
+ await page.focus(inputSelector, { timeout: inputActionTimeoutMs }).catch(() => {});
2538
2531
  }
2539
- if (typeof page.keyboard?.press === "function") {
2540
- await page.keyboard.press("Backspace").catch(() => {});
2532
+ if (settled || page.isClosed()) return;
2533
+ if (typeof (inputLocator as any).fill === "function") {
2534
+ await (inputLocator as any).fill("a", { timeout: inputActionTimeoutMs }).catch(() => {});
2535
+ } else {
2536
+ await page.fill(inputSelector, "a", { timeout: inputActionTimeoutMs }).catch(() => {});
2541
2537
  }
2538
+
2542
2539
  if (typeof page.evaluate === "function") {
2543
2540
  await page.evaluate((sel) => {
2544
2541
  const el = document.querySelector(sel) as HTMLTextAreaElement | null;
@@ -2585,17 +2582,18 @@ export async function captureQwenHeaders(
2585
2582
  try {
2586
2583
  await page.waitForFunction(() => {
2587
2584
  const btn = document.querySelector(
2588
- ".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"
2585
+ ".message-input-right-button-send .send-button, .message-input-right-button-send button, .chat-prompt-send-button, button.send-button, button[aria-label*='Send' i], button[aria-label*='Enviar' i], .send-button-container button"
2589
2586
  ) as HTMLButtonElement | null;
2590
2587
  return btn && !btn.disabled && !btn.classList.contains("disabled") && btn.getAttribute("aria-disabled") !== "true";
2591
2588
  }, { timeout: 3000 });
2592
2589
  } catch {
2593
- await sleep(1000);
2590
+ await sleep(500);
2594
2591
  }
2595
2592
  if (settled || page.isClosed()) return;
2596
2593
 
2597
2594
  const sendSelectors = [
2598
2595
  ".message-input-right-button-send .send-button",
2596
+ ".message-input-right-button-send button",
2599
2597
  ".chat-prompt-send-button",
2600
2598
  "button.send-button",
2601
2599
  "button[aria-label*='Send' i]",
@@ -2618,16 +2616,7 @@ export async function captureQwenHeaders(
2618
2616
  );
2619
2617
  }, btn);
2620
2618
  if (!isDisabled) {
2621
- await page.evaluate((sel) => {
2622
- const element = document.querySelector(sel) as HTMLElement;
2623
- if (element) {
2624
- element.focus();
2625
- element.click();
2626
- }
2627
- }, selector);
2628
- if (!settled && !page.isClosed()) {
2629
- await btn.click({ force: true, delay: 50 }).catch(() => {});
2630
- }
2619
+ await btn.click({ delay: 50 }).catch(() => {});
2631
2620
  clicked = true;
2632
2621
  break;
2633
2622
  }