qwen-api-proxy 1.0.10 → 1.0.12

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.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # FreeQwenApi
2
2
 
3
+ [![npm version](https://badge.fury.io/js/qwen-api-proxy.svg)](https://badge.fury.io/js/qwen-api-proxy)
4
+ [![npm downloads](https://img.shields.io/npm/dm/qwen-api-proxy.svg)](https://www.npmjs.com/package/qwen-api-proxy)
5
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
6
+
7
+ > **📦 npm:** `npx qwen-api-proxy` или `npm install -g qwen-api-proxy`
3
8
  > **🐳 Docker Hub:** https://hub.docker.com/r/endykaufman/qwen-api-proxy
4
9
  > **🔧 Форк:** https://github.com/EndyKaufman/FreeQwenApi
5
10
  > **🌐 Оригинал:** https://github.com/y13sint/FreeQwenApi
@@ -109,11 +114,12 @@ curl http://localhost:3264/api/chat/completions \
109
114
  ## Содержание
110
115
 
111
116
  1. [Быстрый старт](#быстрый-старт)
112
- 2. [Docker Hub](#docker-hub) 🆕
113
- 3. [Docker](#docker)
114
- 4. [Управление аккаунтами](#управление-аккаунтами)
115
- 5. [Авторизация API-ключами](#авторизация-api-ключами)
116
- 6. [API Reference](#api-reference)
117
+ 2. [CLI команды](#-cli-команды) 🆕
118
+ 3. [Docker Hub](#docker-hub) 🆕
119
+ 4. [Docker](#docker)
120
+ 5. [Управление аккаунтами](#управление-аккаунтами)
121
+ 6. [Авторизация API-ключами](#авторизация-api-ключами)
122
+ 7. [API Reference](#api-reference)
117
123
  - [POST /api/chat](#post-apichat)
118
124
  - [POST /api/chat/completions](#post-apichatcompletions)
119
125
  - [GET /api/models](#get-apimodels)
@@ -122,19 +128,60 @@ curl http://localhost:3264/api/chat/completions \
122
128
  - [POST /api/files/upload](#post-apifilesupload)
123
129
  - [POST /api/files/getstsToken](#post-apifilesgetststoken)
124
130
  - [POST /api/images/generations](#post-apiimagesgenerations)
125
- 7. [Работа с контекстом (API v2)](#работа-с-контекстом-api-v2)
126
- 8. [Работа с изображениями](#работа-с-изображениями)
127
- 9. [Генерация изображений](#генерация-изображений) 🆕
128
- 10. [OpenAI SDK](#openai-sdk)
129
- 11. [Python](#python-альтернативная-реализация)
130
- 12. [Доступные модели](#доступные-модели)
131
- 13. [Переменные окружения](#переменные-окружения)
132
- 14. [Структура проекта](#структура-проекта)
131
+ 8. [Работа с контекстом (API v2)](#работа-с-контекстом-api-v2)
132
+ 9. [Работа с изображениями](#работа-с-изображениями)
133
+ 10. [Генерация изображений](#генерация-изображений) 🆕
134
+ 11. [OpenAI SDK](#openai-sdk)
135
+ 12. [Python](#python-альтернативная-реализация)
136
+ 13. [Доступные модели](#доступные-модели)
137
+ 14. [Переменные окружения](#переменные-окружения)
138
+ 15. [Структура проекта](#структура-проекта)
133
139
 
134
140
  ---
135
141
 
136
142
  ## Быстрый старт
137
143
 
144
+ > 🆕 **Новые пользователи?** Начните с [QUICK_START.md](QUICK_START.md) - пошаговое руководство с устранением常见ных ошибок
145
+
146
+ ### 🌍 Кросс-платформенная поддержка
147
+
148
+ Этот проект полностью поддерживает работу на:
149
+ - ✅ **Windows** (10/11, Server 2019+)
150
+ - ✅ **Linux** (Ubuntu 18.04+, Debian 10+, CentOS 8+)
151
+ - ✅ **macOS** (10.15+, включая Apple Silicon)
152
+
153
+ **Требования:**
154
+ - Node.js >= 18.0.0 (рекомендуется 20.x или 22.x LTS)
155
+ - Для команды `archive`: `zip` (Linux/macOS) или `zip`/`7-Zip`/PowerShell (Windows)
156
+
157
+ > 📖 **Полное руководство:** [CROSS_PLATFORM.md](CROSS_PLATFORM.md)
158
+
159
+ ### 📦 Через npm (Рекомендуется)
160
+
161
+ **Без установки (npx):**
162
+ ```bash
163
+ # Инициализация директории
164
+ npx qwen-api-proxy init
165
+
166
+ # Запуск сервера
167
+ npx qwen-api-proxy
168
+ ```
169
+
170
+ **Глобальная установка:**
171
+ ```bash
172
+ npm install -g qwen-api-proxy
173
+
174
+ # Инициализация
175
+ qwen-api-proxy init
176
+
177
+ # Запуск сервера
178
+ qwen-api-proxy
179
+ ```
180
+
181
+ > 💡 **Подробнее:** [README_NPM.md](README_NPM.md) - полное руководство по npm пакету
182
+
183
+ ### 💻 Ручная установка
184
+
138
185
  ```bash
139
186
  # Node.js (Основной)
140
187
  git clone https://github.com/y13sint/FreeQwenApi
@@ -186,6 +233,62 @@ python main.py
186
233
 
187
234
  ---
188
235
 
236
+ ## 🛠️ CLI команды
237
+
238
+ Все команды можно запускать через `npx` (без установки) или после глобальной установки:
239
+
240
+ ```bash
241
+ # Без установки (рекомендуется для редкого использования)
242
+ npx qwen-api-proxy <command>
243
+
244
+ # После глобальной установки (для частого использования)
245
+ qwen-api-proxy <command>
246
+ ```
247
+
248
+ ### Основные команды
249
+
250
+ | Команда | Описание |
251
+ |---------|----------|
252
+ | `npx qwen-api-proxy` | Запуск сервера |
253
+ | `npx qwen-api-proxy init` | Инициализация директории (без запуска) |
254
+ | `npx qwen-api-proxy archive` | Создание архива сессии |
255
+ | `npx qwen-api-proxy extend` | Продление сессий |
256
+ | `npx qwen-api-proxy doctor` | Проверка здоровья системы |
257
+
258
+ ### Примеры использования
259
+
260
+ ```bash
261
+ # Инициализация проекта
262
+ npx qwen-api-proxy init
263
+
264
+ # Создание архива сессии для backup
265
+ npx qwen-api-proxy archive
266
+
267
+ # Продление всех сессий
268
+ npx qwen-api-proxy extend
269
+
270
+ # Продление конкретного аккаунта
271
+ npx qwen-api-proxy extend --account-id acc_1234567890
272
+
273
+ # Проверка здоровья системы
274
+ npx qwen-api-proxy doctor
275
+
276
+ # С пользовательской директорией
277
+ npx qwen-api-proxy archive --dir=/path/to/project
278
+ ```
279
+
280
+ ### 🔧 NPM Scripts (для разработчиков)
281
+
282
+ ```bash
283
+ npm start # Запуск сервера
284
+ npm run archive # Создание архива
285
+ npm run auth # Добавить аккаунт
286
+ npm run rebuild-tokens # Перестроить tokens.json
287
+ npm run check-sessions # Проверить сессии
288
+ ```
289
+
290
+ ---
291
+
189
292
  ## Docker Hub
190
293
 
191
294
  Готовый Docker образ доступен на Docker Hub:
@@ -208,7 +311,7 @@ docker run -d \
208
311
  -v $(pwd)/logs:/app/logs \
209
312
  -v $(pwd)/uploads:/app/uploads \
210
313
  -v $(pwd)/temp:/app/temp \
211
- endykaufman/qwen-api-proxy:1.0.10
314
+ endykaufman/qwen-api-proxy:1.0.12
212
315
 
213
316
  # 3. Смотрим логи
214
317
  docker logs -f qwen-proxy
@@ -217,7 +320,7 @@ docker logs -f qwen-proxy
217
320
  ### Доступные теги
218
321
 
219
322
  - `latest` - последняя стабильная версия
220
- - `1.0.10` - текущая версия
323
+ - `1.0.12` - текущая версия
221
324
  - `1.0.x` - предыдущие версии
222
325
 
223
326
  > **💡 Важно:** Перед первым запуском добавьте аккаунт через `npm run auth` или загрузите сессию через Telegram бота.
@@ -238,7 +341,7 @@ docker logs -f qwen-proxy
238
341
  ```yaml
239
342
  services:
240
343
  qwen-proxy:
241
- image: endykaufman/qwen-api-proxy:1.0.10
344
+ image: endykaufman/qwen-api-proxy:1.0.12
242
345
  container_name: qwen-proxy
243
346
  env_file:
244
347
  - .env
@@ -293,7 +396,7 @@ docker run -d \
293
396
  -v $(pwd)/logs:/app/logs \
294
397
  -v $(pwd)/uploads:/app/uploads \
295
398
  -v $(pwd)/temp:/app/temp \
296
- endykaufman/qwen-api-proxy:1.0.10
399
+ endykaufman/qwen-api-proxy:1.0.12
297
400
  ```
298
401
 
299
402
  Файл `docker-compose.yml`:
@@ -302,7 +405,7 @@ docker run -d \
302
405
  services:
303
406
  qwen-proxy:
304
407
  build: .
305
- image: endykaufman/qwen-api-proxy:1.0.10
408
+ image: endykaufman/qwen-api-proxy:1.0.12
306
409
  container_name: qwen-proxy
307
410
  env_file:
308
411
  - .env # Автоматическая загрузка переменных
@@ -10,7 +10,7 @@
10
10
  * 4. Passes control to the main index.js
11
11
  */
12
12
 
13
- import { fileURLToPath } from 'url';
13
+ import { fileURLToPath, pathToFileURL } from 'url';
14
14
  import path from 'path';
15
15
  import fs from 'fs';
16
16
  import { execSync } from 'child_process';
@@ -151,15 +151,40 @@ npm-debug.log*
151
151
  }
152
152
 
153
153
  /**
154
- * Check if zip is available
154
+ * Check if zip is available (cross-platform)
155
155
  */
156
156
  function checkDependencies() {
157
+ const isWindows = process.platform === 'win32';
158
+
157
159
  try {
158
- execSync('zip --version', { stdio: 'ignore' });
159
- console.log(' ✓ zip command available');
160
+ // On Windows, check for zip.exe or 7z.exe
161
+ if (isWindows) {
162
+ try {
163
+ execSync('zip --version', { stdio: 'ignore' });
164
+ console.log(' ✓ zip command available');
165
+ return;
166
+ } catch (e) {
167
+ // Try 7z as alternative
168
+ try {
169
+ execSync('7z --help', { stdio: 'ignore' });
170
+ console.log(' ✓ 7z command available (alternative to zip)');
171
+ return;
172
+ } catch (e2) {
173
+ // Neither available
174
+ }
175
+ }
176
+ console.warn(' ⚠️ zip/7z command not found (required for archive command)');
177
+ console.warn(' Install with: choco install zip or download 7-Zip from 7-zip.org');
178
+ } else {
179
+ // Unix-like systems (Linux, macOS)
180
+ execSync('zip --version', { stdio: 'ignore' });
181
+ console.log(' ✓ zip command available');
182
+ }
160
183
  } catch (error) {
161
- console.warn(' ⚠️ zip command not found (required for archive command)');
162
- console.warn(' Install with: sudo apt install zip (Ubuntu) or brew install zip (macOS)');
184
+ if (!isWindows) {
185
+ console.warn(' ⚠️ zip command not found (required for archive command)');
186
+ console.warn(' Install with: sudo apt install zip (Ubuntu) or brew install zip (macOS)');
187
+ }
163
188
  }
164
189
  }
165
190
 
@@ -184,6 +209,17 @@ function setup() {
184
209
  checkDependencies();
185
210
 
186
211
  console.log('\n✅ Working directory setup complete!\n');
212
+ console.log('📝 Next steps for first-time users:');
213
+ console.log(' 1. Add an account: qwen-api-proxy (or npx qwen-api-proxy)');
214
+ console.log(' - Select "1 - Add new account"');
215
+ console.log(' - Browser will open for authentication');
216
+ console.log(' - Login to Qwen and press ENTER in console');
217
+ console.log(' 2. Create archive: qwen-api-proxy archive');
218
+ console.log(' 3. Start server: qwen-api-proxy');
219
+ console.log('\n💡 Alternative: Use Telegram bot to upload session files');
220
+ console.log(' - Configure TELEGRAM_BOT_TOKEN in .env file');
221
+ console.log(' - Send session archive to the bot');
222
+ console.log('\n');
187
223
 
188
224
  // Show warnings for missing .gitignore entries
189
225
  if (missingGitignoreDirs.length > 0) {
@@ -256,12 +292,34 @@ if (command === 'doctor') {
256
292
  issues.push(`Node.js ${nodeVersion} (✗ requires >= 18)`);
257
293
  }
258
294
 
259
- // Check zip command
295
+ // Check zip command (cross-platform)
296
+ const isWindows = process.platform === 'win32';
297
+ let zipAvailable = false;
260
298
  try {
261
- execSync('zip --version', { stdio: 'ignore' });
262
- ok.push('zip command available');
299
+ if (isWindows) {
300
+ try {
301
+ execSync('zip --version', { stdio: 'ignore' });
302
+ zipAvailable = true;
303
+ } catch (e) {
304
+ try {
305
+ execSync('7z --help', { stdio: 'ignore' });
306
+ zipAvailable = true; // 7z can work as alternative
307
+ } catch (e2) {
308
+ // Neither available
309
+ }
310
+ }
311
+ } else {
312
+ execSync('zip --version', { stdio: 'ignore' });
313
+ zipAvailable = true;
314
+ }
263
315
  } catch (error) {
264
- warnings.push('zip command not found (required for archive command)');
316
+ // zip not available
317
+ }
318
+
319
+ if (zipAvailable) {
320
+ ok.push('zip/7z command available');
321
+ } else {
322
+ warnings.push('zip/7z command not found (required for archive command)');
265
323
  }
266
324
 
267
325
  // Check working directory structure
@@ -358,22 +416,56 @@ if (command === 'doctor') {
358
416
  warnings.push('No accounts configured yet');
359
417
  }
360
418
 
361
- // Check disk space
419
+ // Check disk space (cross-platform)
362
420
  try {
363
- const dfOutput = execSync('df -k .', { encoding: 'utf8' });
364
- const lines = dfOutput.split('\n');
365
- if (lines.length >= 2) {
366
- const parts = lines[1].split(/\s+/);
367
- const availableKB = parseInt(parts[3]);
368
- const availableGB = (availableKB / 1024 / 1024).toFixed(2);
369
- if (availableGB > 1) {
370
- ok.push(`Disk space: ${availableGB} GB available`);
371
- } else {
372
- warnings.push(`Low disk space: ${availableGB} GB available`);
421
+ if (isWindows) {
422
+ // Use PowerShell or wmic on Windows
423
+ try {
424
+ const wmicOutput = execSync('wmic logicaldisk where "DeviceID=\'C:\'" get FreeSpace /value', { encoding: 'utf8' });
425
+ const match = wmicOutput.match(/FreeSpace=(\d+)/);
426
+ if (match) {
427
+ const availableBytes = parseInt(match[1]);
428
+ const availableGB = (availableBytes / 1024 / 1024 / 1024).toFixed(2);
429
+ if (availableGB > 1) {
430
+ ok.push(`Disk space: ${availableGB} GB available`);
431
+ } else {
432
+ warnings.push(`Low disk space: ${availableGB} GB available`);
433
+ }
434
+ }
435
+ } catch (e) {
436
+ // wmic might not be available, try PowerShell
437
+ try {
438
+ const psOutput = execSync('powershell -Command "(Get-PSDrive C).Free"', { encoding: 'utf8' });
439
+ const freeBytes = parseInt(psOutput.trim());
440
+ if (!isNaN(freeBytes)) {
441
+ const availableGB = (freeBytes / 1024 / 1024 / 1024).toFixed(2);
442
+ if (availableGB > 1) {
443
+ ok.push(`Disk space: ${availableGB} GB available`);
444
+ } else {
445
+ warnings.push(`Low disk space: ${availableGB} GB available`);
446
+ }
447
+ }
448
+ } catch (e2) {
449
+ // Skip disk check on Windows if commands fail
450
+ }
451
+ }
452
+ } else {
453
+ // Unix-like systems
454
+ const dfOutput = execSync('df -k .', { encoding: 'utf8' });
455
+ const lines = dfOutput.split('\n');
456
+ if (lines.length >= 2) {
457
+ const parts = lines[1].split(/\s+/);
458
+ const availableKB = parseInt(parts[3]);
459
+ const availableGB = (availableKB / 1024 / 1024).toFixed(2);
460
+ if (availableGB > 1) {
461
+ ok.push(`Disk space: ${availableGB} GB available`);
462
+ } else {
463
+ warnings.push(`Low disk space: ${availableGB} GB available`);
464
+ }
373
465
  }
374
466
  }
375
467
  } catch (error) {
376
- // df not available, skip
468
+ // df/wmic not available, skip
377
469
  }
378
470
 
379
471
  // Print results
@@ -411,4 +503,7 @@ if (needsSetup) {
411
503
  process.env.QWEN_API_PROXY_GLOBAL = 'true';
412
504
 
413
505
  // Import and run the main application
414
- await import(path.join(PACKAGE_ROOT, 'index.js'));
506
+ // Convert path to file:// URL for cross-platform ESM compatibility
507
+ const indexPath = path.join(PACKAGE_ROOT, 'index.js');
508
+ const indexUrl = pathToFileURL(indexPath).href;
509
+ await import(indexUrl);
package/index.js CHANGED
@@ -108,13 +108,14 @@ async function handleShutdown() {
108
108
  }
109
109
 
110
110
  /**
111
- * Создает ZIP архив папки session/
111
+ * Создает ZIP архив папки session/ (cross-platform)
112
112
  */
113
113
  function createSessionArchive() {
114
114
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
115
115
  const archiveName = `session_backup_${timestamp}.zip`;
116
116
  const archivePath = path.resolve(process.cwd(), archiveName);
117
117
  const sessionPath = path.resolve(process.cwd(), SESSION_DIR);
118
+ const isWindows = process.platform === 'win32';
118
119
 
119
120
  console.log('\n📦 Создание архива сессии...');
120
121
  console.log(`📂 Путь к сессии: ${sessionPath}`);
@@ -132,10 +133,52 @@ function createSessionArchive() {
132
133
  throw new Error('Папка сессии пуста. Сначала выполните авторизацию.');
133
134
  }
134
135
 
135
- // Создаем ZIP архив
136
- const command = `cd "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}/"`;
137
- logInfo(`Выполнение команды: ${command}`);
138
- execSync(command, { stdio: 'inherit' });
136
+ // Проверяем, есть ли реальные данные (accounts, tokens.json, и т.д.)
137
+ const hasAccounts = fs.existsSync(path.join(sessionPath, 'accounts')) &&
138
+ fs.readdirSync(path.join(sessionPath, 'accounts')).length > 0;
139
+ const hasTokens = fs.existsSync(path.join(sessionPath, 'tokens.json'));
140
+
141
+ if (!hasAccounts && !hasTokens) {
142
+ throw new Error('Папка сессии не содержит данных аккаунтов.');
143
+ }
144
+
145
+ // Показываем статистику
146
+ console.log('\n📊 Найденные данные:');
147
+ if (hasAccounts) {
148
+ const accounts = fs.readdirSync(path.join(sessionPath, 'accounts'));
149
+ console.log(` ✓ Аккаунты: ${accounts.length} (${accounts.join(', ')})`);
150
+ }
151
+ if (hasTokens) {
152
+ try {
153
+ const tokens = JSON.parse(fs.readFileSync(path.join(sessionPath, 'tokens.json'), 'utf8'));
154
+ console.log(` ✓ Токены: ${Array.isArray(tokens) ? tokens.length : 0} записей`);
155
+ } catch (e) {
156
+ console.log(' ⚠ tokens.json не удалось прочитать');
157
+ }
158
+ }
159
+
160
+ // Создаем ZIP архив (cross-platform)
161
+ let command;
162
+ if (isWindows) {
163
+ // Try zip first, fallback to PowerShell Compress-Archive
164
+ try {
165
+ command = `cd /d "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}"`;
166
+ logInfo(`Выполнение команды: ${command}`);
167
+ execSync(command, { stdio: 'inherit' });
168
+ } catch (zipError) {
169
+ // Fallback to PowerShell Compress-Archive
170
+ logInfo('zip не найден, используем PowerShell Compress-Archive');
171
+ const psCommand = `Compress-Archive -Path "${sessionPath}" -DestinationPath "${archivePath}" -Force`;
172
+ command = `powershell -Command "${psCommand}"`;
173
+ logInfo(`Выполнение команды: ${command}`);
174
+ execSync(command, { stdio: 'inherit' });
175
+ }
176
+ } else {
177
+ // Unix-like systems (Linux, macOS)
178
+ command = `cd "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}/"`;
179
+ logInfo(`Выполнение команды: ${command}`);
180
+ execSync(command, { stdio: 'inherit' });
181
+ }
139
182
 
140
183
  // Проверяем создание архива
141
184
  if (!fs.existsSync(archivePath)) {
@@ -215,6 +258,68 @@ async function handleCLICommand() {
215
258
  console.log('╚══════════════════════════════════════════════════════════╝\n');
216
259
 
217
260
  try {
261
+ // Проверяем, есть ли уже аккаунты
262
+ const tokensPath = path.join(process.cwd(), SESSION_DIR, 'tokens.json');
263
+ const accountsPath = path.join(process.cwd(), SESSION_DIR, ACCOUNTS_DIR);
264
+
265
+ let hasAccounts = false;
266
+
267
+ if (fs.existsSync(tokensPath)) {
268
+ try {
269
+ const tokens = JSON.parse(fs.readFileSync(tokensPath, 'utf8'));
270
+ if (Array.isArray(tokens) && tokens.length > 0) {
271
+ hasAccounts = true;
272
+ }
273
+ } catch (e) {
274
+ // tokens.json corrupted
275
+ }
276
+ }
277
+
278
+ if (!hasAccounts && fs.existsSync(accountsPath)) {
279
+ const accounts = fs.readdirSync(accountsPath);
280
+ if (accounts.length > 0) {
281
+ hasAccounts = true;
282
+ }
283
+ }
284
+
285
+ // Если аккаунтов нет, предлагаем добавить
286
+ if (!hasAccounts) {
287
+ console.log('📝 Аккаунты не найдены. Необходимо добавить аккаунт перед созданием архива.\n');
288
+ console.log('🔹 Вариант 1: Добавить аккаунт сейчас (откроется браузер)');
289
+ console.log('🔹 Вариант 2: Отправить файл сессии через Telegram бота');
290
+ console.log('🔹 Вариант 3: Выйти и запустить вручную: npx qwen-api-proxy\n');
291
+
292
+ const { prompt } = await import('./src/utils/prompt.js');
293
+ const choice = await prompt('Ваш выбор (1/2/3, Enter = 1): ');
294
+
295
+ if (choice === '2') {
296
+ console.log('\n💡 Для использования Telegram бота:');
297
+ console.log(' 1. Добавьте TELEGRAM_BOT_TOKEN в .env файл');
298
+ console.log(' 2. Запустите: npx qwen-api-proxy');
299
+ console.log(' 3. Отправьте файл сессии боту\n');
300
+ process.exit(0);
301
+ } else if (choice === '3') {
302
+ console.log('\n👋 Выход. Запустите "npx qwen-api-proxy" для добавления аккаунта.\n');
303
+ process.exit(0);
304
+ }
305
+
306
+ // choice === '1' или Enter - добавляем аккаунт
307
+ console.log('\n🔐 Запуск браузера для добавления аккаунта...\n');
308
+
309
+ const { addAccountInteractive } = await import('./src/utils/accountSetup.js');
310
+ const accountId = await addAccountInteractive();
311
+
312
+ if (!accountId) {
313
+ console.log('\n❌ Аккаунт не был добавлен. Архив не создан.\n');
314
+ process.exit(1);
315
+ }
316
+
317
+ console.log(`\n✅ Аккаунт ${accountId} успешно добавлен!\n`);
318
+ } else {
319
+ console.log('✅ Найден существующий аккаунт\n');
320
+ }
321
+
322
+ // Теперь создаем архив
218
323
  const archivePath = createSessionArchive();
219
324
  console.log('\n🎉 ГОТОВО!');
220
325
  console.log(`📄 Архив: ${archivePath}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwen-api-proxy",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Proxy server for accessing Qwen API through browser emulation with OpenAI-compatible API and Telegram bot",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -45,6 +45,7 @@
45
45
  "start": "node index.js",
46
46
  "archive": "node index.js archive",
47
47
  "test": "echo \"Error: no test specified\" && exit 1",
48
+ "test:cross-platform": "node test-cross-platform.js",
48
49
  "check-permissions": "node scripts/checkPermissions.js",
49
50
  "fix-permissions": "bash fix-permissions.sh",
50
51
  "rebuild-tokens": "node scripts/rebuildTokens.js",