@link-assistant/hive-mind 1.61.0 → 1.62.0

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.62.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add direct Qwen Code CLI support for solve and hive workflows.
8
+
3
9
  ## 1.61.0
4
10
 
5
11
  ### Minor Changes
package/README.hi.md CHANGED
@@ -343,7 +343,7 @@ solve <issue-url> [options]
343
343
 
344
344
  | विकल्प | संक्षिप्त | विवरण | डिफ़ॉल्ट |
345
345
  | ------------------------ | --------- | ----------------------------------------------------------- | -------- |
346
- | `--tool` | | AI टूल (claude, opencode, codex, agent) | claude |
346
+ | `--tool` | | AI टूल (claude, opencode, codex, agent, qwen) | claude |
347
347
  | `--verbose` | `-v` | विस्तृत लॉगिंग सक्षम करें | false |
348
348
  | `--attach-logs` | | PR में लॉग संलग्न करें (⚠️ संवेदनशील डेटा उजागर हो सकता है) | false |
349
349
  | `--auto-init-repository` | | खाली रेपो स्वतः-आरंभ करें (README.md बनाता है) | false |
@@ -370,7 +370,7 @@ hive <github-url> [options]
370
370
 
371
371
  | विकल्प | संक्षिप्त | विवरण | डिफ़ॉल्ट |
372
372
  | ------------------------ | --------- | ----------------------------------------------------------- | -------- |
373
- | `--tool` | | AI टूल (claude, opencode, agent) | claude |
373
+ | `--tool` | | AI टूल (claude, opencode, codex, agent, qwen) | claude |
374
374
  | `--concurrency` | `-c` | समानांतर वर्कर की संख्या | 2 |
375
375
  | `--skip-issues-with-prs` | `-s` | मौजूदा PR वाले इश्यू छोड़ें | false |
376
376
  | `--verbose` | `-v` | विस्तृत लॉगिंग सक्षम करें | false |
@@ -462,11 +462,13 @@ Aliases:
462
462
  /codex /solve --tool codex के बराबर है
463
463
  /opencode /solve --tool opencode के बराबर है
464
464
  /agent /solve --tool agent के बराबर है
465
+ /qwen /solve --tool qwen के बराबर है
465
466
 
466
467
  Tool alias examples:
467
468
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
468
469
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
469
470
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
471
+ /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
470
472
 
471
473
  Free Models (with --tool agent):
472
474
  /solve https://github.com/owner/repo/issues/123 --tool agent --model nemotron-3-super-free
package/README.md CHANGED
@@ -352,7 +352,7 @@ solve <issue-url> [options]
352
352
 
353
353
  | Option | Alias | Description | Default |
354
354
  | ------------------------ | ----- | ------------------------------------------------ | ------- |
355
- | `--tool` | | AI tool (claude, opencode, codex, agent) | claude |
355
+ | `--tool` | | AI tool (claude, opencode, codex, agent, qwen) | claude |
356
356
  | `--verbose` | `-v` | Enable verbose logging | false |
357
357
  | `--attach-logs` | | Attach logs to PR (⚠️ may expose sensitive data) | false |
358
358
  | `--auto-init-repository` | | Auto-initialize empty repos (creates README.md) | false |
@@ -379,7 +379,7 @@ hive <github-url> [options]
379
379
 
380
380
  | Option | Alias | Description | Default |
381
381
  | ------------------------ | ----- | ------------------------------------------------- | ------- |
382
- | `--tool` | | AI tool (claude, opencode, agent) | claude |
382
+ | `--tool` | | AI tool (claude, opencode, codex, agent, qwen) | claude |
383
383
  | `--concurrency` | `-c` | Number of parallel workers | 2 |
384
384
  | `--skip-issues-with-prs` | `-s` | Skip issues with existing PRs | false |
385
385
  | `--verbose` | `-v` | Enable verbose logging | false |
@@ -469,11 +469,13 @@ Aliases:
469
469
  /codex is equivalent to /solve --tool codex
470
470
  /opencode is equivalent to /solve --tool opencode
471
471
  /agent is equivalent to /solve --tool agent
472
+ /qwen is equivalent to /solve --tool qwen
472
473
 
473
474
  Tool alias examples:
474
475
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
475
476
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
476
477
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
478
+ /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
477
479
 
478
480
  Free Models (with --tool agent):
479
481
  /solve https://github.com/owner/repo/issues/123 --tool agent --model nemotron-3-super-free
@@ -495,6 +497,7 @@ Current tool defaults in Hive Mind:
495
497
  | `codex` | `gpt-5.5` preferred, with runtime fallback to local catalog | Codex runs with `reasoning_effort=none` unless you pass `--think` or `--thinking-budget` |
496
498
  | `opencode` | `grok-code-fast-1` | No extra thinking prompt is added for the default model |
497
499
  | `agent` | `nemotron-3-super-free` | No extra thinking prompt is added for the default model |
500
+ | `qwen` | `qwen3-coder-plus` | No extra thinking prompt is added for the default model |
498
501
 
499
502
  See [docs/CONFIGURATION.md](./docs/CONFIGURATION.md) for the full per-tool defaults and reasoning mappings.
500
503
 
package/README.ru.md CHANGED
@@ -343,7 +343,7 @@ solve <issue-url> [options]
343
343
 
344
344
  | Параметр | Сокр. | Описание | По умолчанию |
345
345
  | ------------------------ | ----- | --------------------------------------------------------------------- | ------------ |
346
- | `--tool` | | Инструмент ИИ (claude, opencode, codex, agent) | claude |
346
+ | `--tool` | | Инструмент ИИ (claude, opencode, codex, agent, qwen) | claude |
347
347
  | `--verbose` | `-v` | Включить подробное логирование | false |
348
348
  | `--attach-logs` | | Прикрепить логи к PR (⚠️ может раскрыть конфиденциальные данные) | false |
349
349
  | `--auto-init-repository` | | Автоматически инициализировать пустые репозитории (создаёт README.md) | false |
@@ -370,7 +370,7 @@ hive <github-url> [options]
370
370
 
371
371
  | Параметр | Сокр. | Описание | По умолчанию |
372
372
  | ------------------------ | ----- | ----------------------------------------------------------------- | ------------ |
373
- | `--tool` | | Инструмент ИИ (claude, opencode, agent) | claude |
373
+ | `--tool` | | Инструмент ИИ (claude, opencode, codex, agent, qwen) | claude |
374
374
  | `--concurrency` | `-c` | Количество параллельных воркеров | 2 |
375
375
  | `--skip-issues-with-prs` | `-s` | Пропускать задачи с существующими PR | false |
376
376
  | `--verbose` | `-v` | Включить подробное логирование | false |
@@ -463,11 +463,13 @@ Aliases:
463
463
  /codex эквивалентна /solve --tool codex
464
464
  /opencode эквивалентна /solve --tool opencode
465
465
  /agent эквивалентна /solve --tool agent
466
+ /qwen эквивалентна /solve --tool qwen
466
467
 
467
468
  Tool alias examples:
468
469
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
469
470
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
470
471
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
472
+ /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
471
473
 
472
474
  Free Models (with --tool agent):
473
475
  /solve https://github.com/owner/repo/issues/123 --tool agent --model nemotron-3-super-free
package/README.zh.md CHANGED
@@ -341,13 +341,13 @@ solve <issue-url> [options]
341
341
 
342
342
  **其他常用选项:**
343
343
 
344
- | 选项 | 简写 | 描述 | 默认值 |
345
- | ------------------------ | ---- | ----------------------------------------- | ------ |
346
- | `--tool` | | AI 工具(claude、opencode、codex、agent) | claude |
347
- | `--verbose` | `-v` | 启用详细日志 | false |
348
- | `--attach-logs` | | 将日志附加到 PR(⚠️ 可能暴露敏感数据) | false |
349
- | `--auto-init-repository` | | 自动初始化空仓库(创建 README.md) | false |
350
- | `--help` | `-h` | 显示所有可用选项 | - |
344
+ | 选项 | 简写 | 描述 | 默认值 |
345
+ | ------------------------ | ---- | ----------------------------------------------- | ------ |
346
+ | `--tool` | | AI 工具(claude、opencode、codex、agent、qwen) | claude |
347
+ | `--verbose` | `-v` | 启用详细日志 | false |
348
+ | `--attach-logs` | | 将日志附加到 PR(⚠️ 可能暴露敏感数据) | false |
349
+ | `--auto-init-repository` | | 自动初始化空仓库(创建 README.md) | false |
350
+ | `--help` | `-h` | 显示所有可用选项 | - |
351
351
 
352
352
  > **📖 完整选项列表**:包含 Fork、自动续行、监视模式及实验性功能在内的所有可用选项,请参见 [docs/CONFIGURATION.zh.md](./docs/CONFIGURATION.zh.md#solve-options)。
353
353
 
@@ -368,14 +368,14 @@ hive <github-url> [options]
368
368
 
369
369
  **其他常用选项:**
370
370
 
371
- | 选项 | 简写 | 描述 | 默认值 |
372
- | ------------------------ | ---- | -------------------------------------- | ------ |
373
- | `--tool` | | AI 工具(claude、opencode、agent) | claude |
374
- | `--concurrency` | `-c` | 并行工作进程数量 | 2 |
375
- | `--skip-issues-with-prs` | `-s` | 跳过已有 PR 的 Issue | false |
376
- | `--verbose` | `-v` | 启用详细日志 | false |
377
- | `--attach-logs` | | 将日志附加到 PR(⚠️ 可能暴露敏感数据) | false |
378
- | `--help` | `-h` | 显示所有可用选项 | - |
371
+ | 选项 | 简写 | 描述 | 默认值 |
372
+ | ------------------------ | ---- | ----------------------------------------------- | ------ |
373
+ | `--tool` | | AI 工具(claude、opencode、codex、agent、qwen | claude |
374
+ | `--concurrency` | `-c` | 并行工作进程数量 | 2 |
375
+ | `--skip-issues-with-prs` | `-s` | 跳过已有 PR 的 Issue | false |
376
+ | `--verbose` | `-v` | 启用详细日志 | false |
377
+ | `--attach-logs` | | 将日志附加到 PR(⚠️ 可能暴露敏感数据) | false |
378
+ | `--help` | `-h` | 显示所有可用选项 | - |
379
379
 
380
380
  > **📖 完整选项列表**:包含项目监控、YouTrack 集成及实验性功能在内的所有可用选项,请参见 [docs/CONFIGURATION.zh.md](./docs/CONFIGURATION.zh.md#hive-options)。
381
381
 
@@ -459,11 +459,13 @@ Aliases:
459
459
  /codex 等同于 /solve --tool codex
460
460
  /opencode 等同于 /solve --tool opencode
461
461
  /agent 等同于 /solve --tool agent
462
+ /qwen 等同于 /solve --tool qwen
462
463
 
463
464
  Tool alias examples:
464
465
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
465
466
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
466
467
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
468
+ /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
467
469
 
468
470
  Free Models (with --tool agent):
469
471
  /solve https://github.com/owner/repo/issues/123 --tool agent --model nemotron-3-super-free
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.61.0",
3
+ "version": "1.62.0",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -294,13 +294,13 @@ Plan sub-agent usage.
294
294
 
295
295
  Agent Commander usage (unified subagent delegation).
296
296
  - When you need to delegate tasks to subagents, use the agent-commander CLI tool (start-agent) instead of the native Task tool.
297
- - Agent Commander provides a unified API for different agent types (claude, opencode, codex, agent) and supports various isolation modes.
297
+ - Agent Commander provides a unified API for different agent types (claude, opencode, codex, agent, qwen) and supports various isolation modes.
298
298
  - To delegate a task, use the Bash tool to run start-agent with appropriate parameters:
299
299
  \`\`\`bash
300
300
  start-agent --tool claude --working-directory "$(pwd)" --prompt "Your task description here"
301
301
  \`\`\`
302
302
  - Common start-agent parameters:
303
- --tool <name>: Agent to use (claude, opencode, codex, agent)
303
+ --tool <name>: Agent to use (claude, opencode, codex, agent, qwen)
304
304
  --working-directory <path>: Execution directory (use current directory for context)
305
305
  --prompt <text>: The task to delegate
306
306
  --model <name>: Model to use (${[...new Set(Object.values(primaryModelNames).flat())].slice(0, 5).join(', ')}, etc.)
@@ -277,13 +277,13 @@ Planning workflow usage.
277
277
 
278
278
  Agent Commander usage (unified subagent delegation).
279
279
  - When you need to delegate tasks to subagents, use the agent-commander CLI tool (start-agent) instead of relying only on native Codex collaboration.
280
- - Agent Commander provides a unified API for different agent types (claude, opencode, codex, agent) and supports various isolation modes.
280
+ - Agent Commander provides a unified API for different agent types (claude, opencode, codex, agent, qwen) and supports various isolation modes.
281
281
  - To delegate a task, use a command like:
282
282
  \`\`\`bash
283
283
  start-agent --tool codex --working-directory "$(pwd)" --prompt "Your task description here"
284
284
  \`\`\`
285
285
  - Common start-agent parameters:
286
- --tool <name>: Agent to use (claude, opencode, codex, agent)
286
+ --tool <name>: Agent to use (claude, opencode, codex, agent, qwen)
287
287
  --working-directory <path>: Execution directory (use the current directory for context)
288
288
  --prompt <text>: The task to delegate
289
289
  --model <name>: Model to use
@@ -52,6 +52,7 @@ export const timeouts = {
52
52
  claudeCli: parseIntWithDefault('HIVE_MIND_CLAUDE_TIMEOUT_SECONDS', 60) * 1000,
53
53
  opencodeCli: parseIntWithDefault('HIVE_MIND_OPENCODE_TIMEOUT_SECONDS', 60) * 1000,
54
54
  codexCli: parseIntWithDefault('HIVE_MIND_CODEX_TIMEOUT_SECONDS', 60) * 1000,
55
+ qwenCli: parseIntWithDefault('HIVE_MIND_QWEN_TIMEOUT_SECONDS', 60) * 1000,
55
56
  githubApiDelay: parseIntWithDefault('HIVE_MIND_GITHUB_API_DELAY_MS', 5000),
56
57
  githubRepoDelay: parseIntWithDefault('HIVE_MIND_GITHUB_REPO_DELAY_MS', 2000),
57
58
  retryBaseDelay: parseIntWithDefault('HIVE_MIND_RETRY_BASE_DELAY_MS', 5000),
@@ -47,7 +47,7 @@ const HIVE_CUSTOM_SOLVE_OPTIONS = {
47
47
  tool: {
48
48
  type: 'string',
49
49
  description: 'AI tool to use for solving issues',
50
- choices: ['claude', 'opencode', 'codex', 'agent'],
50
+ choices: ['claude', 'opencode', 'codex', 'agent', 'qwen'],
51
51
  default: 'claude',
52
52
  },
53
53
  };
package/src/hive.mjs CHANGED
@@ -97,6 +97,8 @@ if (isRunningDirectly) {
97
97
  const { listSolutionDrafts } = solutionDraftsLib;
98
98
  const recheckLib = await import('./hive.recheck.lib.mjs');
99
99
  const { recheckIssueConditions } = recheckLib;
100
+ const toolConnectionValidationLib = await import('./tool-connection-validation.lib.mjs');
101
+ const { validateToolConnection } = toolConnectionValidationLib;
100
102
  const commandName = process.argv[1] ? process.argv[1].split('/').pop() : '';
101
103
  const isLocalScript = commandName.endsWith('.mjs');
102
104
  const solveCommand = isLocalScript ? './solve.mjs' : 'solve';
@@ -1426,8 +1428,6 @@ if (isRunningDirectly) {
1426
1428
  await safeExit(0, 'Process completed');
1427
1429
  }
1428
1430
 
1429
- // validateClaudeConnection is imported from lib.mjs
1430
-
1431
1431
  // Handle graceful shutdown
1432
1432
  process.on('SIGINT', () => gracefulShutdown('interrupt'));
1433
1433
  process.on('SIGTERM', () => gracefulShutdown('termination'));
@@ -1437,7 +1437,7 @@ if (isRunningDirectly) {
1437
1437
  await log('⏩ Skipping system resource check (dry-run mode or skip-tool-connection-check enabled)', {
1438
1438
  verbose: true,
1439
1439
  });
1440
- await log('⏩ Skipping Claude CLI connection check (dry-run mode or skip-tool-connection-check enabled)', {
1440
+ await log('⏩ Skipping AI tool connection check (dry-run mode or skip-tool-connection-check enabled)', {
1441
1441
  verbose: true,
1442
1442
  });
1443
1443
  } else {
@@ -1454,10 +1454,10 @@ if (isRunningDirectly) {
1454
1454
  await safeExit(1, 'Error occurred');
1455
1455
  }
1456
1456
 
1457
- // Validate Claude CLI connection before starting monitoring with the same model that will be used
1458
- const isClaudeConnected = await validateClaudeConnection(argv.model);
1459
- if (!isClaudeConnected) {
1460
- await log('❌ Cannot start monitoring without Claude CLI connection', { level: 'error' });
1457
+ // Validate the selected AI tool connection before starting monitoring with the same model that will be used
1458
+ const isToolConnected = await validateToolConnection({ tool: argv.tool, model: argv.model, verbose: argv.verbose, validateClaudeConnection });
1459
+ if (!isToolConnected) {
1460
+ await log(`❌ Cannot start monitoring without ${argv.tool || 'claude'} connection`, { level: 'error' });
1461
1461
  await safeExit(1, 'Error occurred');
1462
1462
  }
1463
1463
  }
@@ -129,12 +129,25 @@ export const codexModels = {
129
129
  'gpt-4o': 'gpt-4o',
130
130
  };
131
131
 
132
+ // Qwen Code models
133
+ export const qwenModels = {
134
+ qwen: 'qwen3-coder-plus',
135
+ 'qwen-coder': 'qwen3-coder-plus',
136
+ qwen3: 'qwen3-coder-plus',
137
+ 'qwen3-coder': 'qwen3-coder',
138
+ 'qwen3-coder-plus': 'qwen3-coder-plus',
139
+ 'qwen3-coder-flash': 'qwen3-coder-flash',
140
+ 'qwen3.6-plus': 'qwen3.6-plus',
141
+ 'qwen3.6-coder-plus': 'qwen3.6-coder-plus',
142
+ };
143
+
132
144
  // Default model for each tool (Issue #1473: centralized to avoid scattered hardcoded defaults)
133
145
  export const defaultModels = {
134
146
  claude: 'sonnet',
135
147
  agent: 'nemotron-3-super-free', // Issue #1563: changed from qwen3.6-plus-free (free promotion ended) per agent PR #243
136
148
  opencode: 'grok-code-fast-1',
137
149
  codex: 'gpt-5.5',
150
+ qwen: 'qwen3-coder-plus',
138
151
  };
139
152
 
140
153
  // Models that support 1M token context window via [1m] suffix (Issue #1221, Issue #1238, Issue #1329)
@@ -214,6 +227,15 @@ export const CODEX_MODELS = {
214
227
  'gpt-4o': 'gpt-4o',
215
228
  };
216
229
 
230
+ export const QWEN_MODELS = {
231
+ ...qwenModels,
232
+ 'qwen3-coder': 'qwen3-coder',
233
+ 'qwen3-coder-plus': 'qwen3-coder-plus',
234
+ 'qwen3-coder-flash': 'qwen3-coder-flash',
235
+ 'qwen3.6-plus': 'qwen3.6-plus',
236
+ 'qwen3.6-coder-plus': 'qwen3.6-coder-plus',
237
+ };
238
+
217
239
  export const AGENT_MODELS = {
218
240
  ...agentModels,
219
241
  'opencode/grok-code': 'opencode/grok-code',
@@ -235,7 +257,7 @@ export const AGENT_MODELS = {
235
257
 
236
258
  /**
237
259
  * Get the model map object for a given tool
238
- * @param {string} tool - The tool name (claude, agent, opencode, codex)
260
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
239
261
  * @returns {Object} The model mapping for the tool
240
262
  */
241
263
  export const getModelMapForTool = tool => {
@@ -248,6 +270,8 @@ export const getModelMapForTool = tool => {
248
270
  return opencodeModels;
249
271
  case 'codex':
250
272
  return codexModels;
273
+ case 'qwen':
274
+ return qwenModels;
251
275
  default:
252
276
  return claudeModels;
253
277
  }
@@ -255,7 +279,7 @@ export const getModelMapForTool = tool => {
255
279
 
256
280
  /**
257
281
  * Get the default model for a given tool
258
- * @param {string} tool - The tool name (claude, agent, opencode, codex)
282
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
259
283
  * @returns {string} The default model alias for the tool
260
284
  */
261
285
  export const getDefaultModelForTool = tool => {
@@ -308,7 +332,7 @@ export const resolveRuntimeDefaultModel = async (tool, options = {}) => {
308
332
 
309
333
  /**
310
334
  * Map model name to full model ID for a specific tool
311
- * @param {string} tool - The tool name (claude, agent, opencode, codex)
335
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
312
336
  * @param {string} model - The model name or alias
313
337
  * @returns {string} The full model ID
314
338
  */
@@ -322,6 +346,8 @@ export const mapModelForTool = (tool, model) => {
322
346
  return opencodeModels[model] || model;
323
347
  case 'codex':
324
348
  return codexModels[model] || model;
349
+ case 'qwen':
350
+ return qwenModels[model] || model;
325
351
  default:
326
352
  return model;
327
353
  }
@@ -329,7 +355,7 @@ export const mapModelForTool = (tool, model) => {
329
355
 
330
356
  /**
331
357
  * Validate if a model is compatible with a tool
332
- * @param {string} tool - The tool name (claude, agent, opencode, codex)
358
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
333
359
  * @param {string} model - The model name or alias
334
360
  * @returns {boolean} True if the model is compatible with the tool
335
361
  */
@@ -345,6 +371,8 @@ export const isModelCompatibleWithTool = (tool, model) => {
345
371
  return mappedModel.includes('/') || Object.keys(opencodeModels).includes(model);
346
372
  case 'codex':
347
373
  return Object.keys(codexModels).includes(model) || mappedModel.startsWith('gpt-');
374
+ case 'qwen':
375
+ return Object.keys(qwenModels).includes(model) || mappedModel.startsWith('qwen');
348
376
  default:
349
377
  return true;
350
378
  }
@@ -365,6 +393,8 @@ export const getValidModelsForTool = tool => {
365
393
  return Object.keys(opencodeModels);
366
394
  case 'codex':
367
395
  return Object.keys(codexModels);
396
+ case 'qwen':
397
+ return Object.keys(qwenModels);
368
398
  default:
369
399
  return [];
370
400
  }
@@ -377,6 +407,7 @@ export const primaryModelNames = {
377
407
  opencode: ['grok', 'gpt4o'],
378
408
  codex: ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex', 'gpt-5.3-codex-spark'],
379
409
  agent: ['nemotron-3-super-free', 'minimax-m2.5-free', 'big-pickle', 'gpt-5-nano', 'glm-5-free', 'deepseek-r1-free'],
410
+ qwen: ['qwen3-coder-plus', 'qwen3-coder', 'qwen3-coder-flash'],
380
411
  };
381
412
 
382
413
  /**
@@ -416,7 +447,7 @@ export const validateToolModelCompatibility = (tool, model) => {
416
447
 
417
448
  /**
418
449
  * Get the model map for a given tool (validation-extended version with full ID entries)
419
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent')
450
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
420
451
  * @returns {Object} The model mapping for the tool
421
452
  */
422
453
  const getValidationModelMapForTool = tool => {
@@ -427,6 +458,8 @@ const getValidationModelMapForTool = tool => {
427
458
  return CODEX_MODELS;
428
459
  case 'agent':
429
460
  return AGENT_MODELS;
461
+ case 'qwen':
462
+ return QWEN_MODELS;
430
463
  case 'claude':
431
464
  default:
432
465
  return CLAUDE_MODELS;
@@ -435,7 +468,7 @@ const getValidationModelMapForTool = tool => {
435
468
 
436
469
  /**
437
470
  * Get the list of available model names for a tool (for display in help/error messages)
438
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent')
471
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
439
472
  * @returns {string[]} Array of available model short names
440
473
  */
441
474
  export const getAvailableModelNames = tool => {
@@ -574,7 +607,7 @@ export const supports1mContext = (model, tool = 'claude') => {
574
607
  * Validate a model name against the available models for a tool
575
608
  * Supports [1m] suffix for 1 million token context (Issue #1221)
576
609
  * @param {string} model - The model name to validate (e.g., "opus", "opus[1m]", "claude-opus-4-6[1m]")
577
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex')
610
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
578
611
  * @returns {{ valid: boolean, message?: string, suggestions?: string[], mappedModel?: string, has1mSuffix?: boolean }}
579
612
  */
580
613
  export const validateModelName = (model, tool = 'claude') => {
@@ -647,7 +680,7 @@ export const validateModelName = (model, tool = 'claude') => {
647
680
  * Validate model name and exit with error if invalid
648
681
  * This is the main entry point for model validation in solve.mjs, hive.mjs, etc.
649
682
  * @param {string} model - The model name to validate
650
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex')
683
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
651
684
  * @param {Function} exitFn - Function to call for exiting (default: process.exit)
652
685
  * @returns {Promise<boolean>} True if valid, exits process if invalid
653
686
  */
@@ -682,7 +715,7 @@ export const formatAvailableModelsForHelp = (tool = 'claude') => {
682
715
 
683
716
  /**
684
717
  * Map tool identifier to user-friendly display name.
685
- * @param {string|null} tool - The tool identifier (claude, codex, opencode, agent)
718
+ * @param {string|null} tool - The tool identifier (claude, codex, opencode, agent, qwen)
686
719
  * @returns {string} User-friendly display name
687
720
  */
688
721
  export const getToolDisplayName = tool => {
@@ -696,6 +729,8 @@ export const getToolDisplayName = tool => {
696
729
  return 'OpenCode';
697
730
  case 'agent':
698
731
  return 'Agent CLI';
732
+ case 'qwen':
733
+ return 'Qwen Code';
699
734
  default:
700
735
  return 'AI tool';
701
736
  }
@@ -817,7 +852,7 @@ const doesRequestedMatchActual = (requestedModel, actualModelId, tool) => {
817
852
  *
818
853
  * @param {Object} options - Model info options
819
854
  * @param {string|null} options.requestedModel - The model requested via --model flag
820
- * @param {string|null} options.tool - The tool used (claude, agent, opencode, codex)
855
+ * @param {string|null} options.tool - The tool used (claude, agent, opencode, codex, qwen)
821
856
  * @param {Object|null} options.pricingInfo - Pricing info from tool result
822
857
  * @param {Object|null} options.modelInfo - Pre-fetched model metadata from models.dev
823
858
  * @param {Array<{modelId: string, modelInfo: Object|null}>|null} options.modelsUsed - Actual models used from CLI JSON output
@@ -928,7 +963,7 @@ export const resolveDefaultFallbackModel = (tool, model) => {
928
963
  *
929
964
  * @param {Object} options
930
965
  * @param {string|null} options.requestedModel - The --model flag value
931
- * @param {string|null} options.tool - The tool used (claude, agent, opencode, codex)
966
+ * @param {string|null} options.tool - The tool used (claude, agent, opencode, codex, qwen)
932
967
  * @param {Object|null} options.pricingInfo - Pricing info from tool result
933
968
  * @param {Array<string>|null} options.actualModelIds - Actual model IDs from CLI JSON output
934
969
  * @returns {Promise<string>} Formatted markdown model info section