@link-assistant/hive-mind 1.62.1 → 1.64.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,17 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.64.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2ffb808: Add experimental `--use-agent-commander` option to delegate supported tool execution to the agent-commander library, including Claude, Codex, OpenCode, Agent, Qwen, and Gemini.
8
+
9
+ ## 1.63.0
10
+
11
+ ### Minor Changes
12
+
13
+ - b7b0721: Add direct Google Gemini CLI support for solve, hive, queueing, model validation, structured stream JSON parsing, and Telegram `/gemini` aliases.
14
+
3
15
  ## 1.62.1
4
16
 
5
17
  ### Patch 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, qwen) | claude |
346
+ | `--tool` | | AI टूल (claude, opencode, codex, agent, qwen, gemini) | 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, codex, agent, qwen) | claude |
373
+ | `--tool` | | AI टूल (claude, opencode, codex, agent, qwen, gemini) | claude |
374
374
  | `--concurrency` | `-c` | समानांतर वर्कर की संख्या | 2 |
375
375
  | `--skip-issues-with-prs` | `-s` | मौजूदा PR वाले इश्यू छोड़ें | false |
376
376
  | `--verbose` | `-v` | विस्तृत लॉगिंग सक्षम करें | false |
@@ -463,12 +463,15 @@ Aliases:
463
463
  /opencode /solve --tool opencode के बराबर है
464
464
  /agent /solve --tool agent के बराबर है
465
465
  /qwen /solve --tool qwen के बराबर है
466
+ /gemini /solve --tool gemini के बराबर है
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
+ /gemini https://github.com/owner/repo/issues/123 --model flash
471
473
  /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
474
+ /gemini https://github.com/owner/repo/issues/123 --model gemini-2.5-flash
472
475
 
473
476
  Free Models (with --tool agent):
474
477
  /solve https://github.com/owner/repo/issues/123 --tool agent --model nemotron-3-super-free
package/README.md CHANGED
@@ -350,13 +350,13 @@ solve <issue-url> [options]
350
350
 
351
351
  **Other useful options:**
352
352
 
353
- | Option | Alias | Description | Default |
354
- | ------------------------ | ----- | ------------------------------------------------ | ------- |
355
- | `--tool` | | AI tool (claude, opencode, codex, agent, qwen) | claude |
356
- | `--verbose` | `-v` | Enable verbose logging | false |
357
- | `--attach-logs` | | Attach logs to PR (⚠️ may expose sensitive data) | false |
358
- | `--auto-init-repository` | | Auto-initialize empty repos (creates README.md) | false |
359
- | `--help` | `-h` | Show all available options | - |
353
+ | Option | Alias | Description | Default |
354
+ | ------------------------ | ----- | ------------------------------------------------------ | ------- |
355
+ | `--tool` | | AI tool (claude, opencode, codex, agent, qwen, gemini) | claude |
356
+ | `--verbose` | `-v` | Enable verbose logging | false |
357
+ | `--attach-logs` | | Attach logs to PR (⚠️ may expose sensitive data) | false |
358
+ | `--auto-init-repository` | | Auto-initialize empty repos (creates README.md) | false |
359
+ | `--help` | `-h` | Show all available options | - |
360
360
 
361
361
  > **📖 Full options list**: See [docs/CONFIGURATION.md](./docs/CONFIGURATION.md#solve-options) for all available options including forking, auto-continue, watch mode, and experimental features.
362
362
 
@@ -377,14 +377,14 @@ hive <github-url> [options]
377
377
 
378
378
  **Other useful options:**
379
379
 
380
- | Option | Alias | Description | Default |
381
- | ------------------------ | ----- | ------------------------------------------------- | ------- |
382
- | `--tool` | | AI tool (claude, opencode, codex, agent, qwen) | claude |
383
- | `--concurrency` | `-c` | Number of parallel workers | 2 |
384
- | `--skip-issues-with-prs` | `-s` | Skip issues with existing PRs | false |
385
- | `--verbose` | `-v` | Enable verbose logging | false |
386
- | `--attach-logs` | | Attach logs to PRs (⚠️ may expose sensitive data) | false |
387
- | `--help` | `-h` | Show all available options | - |
380
+ | Option | Alias | Description | Default |
381
+ | ------------------------ | ----- | ------------------------------------------------------ | ------- |
382
+ | `--tool` | | AI tool (claude, opencode, codex, agent, qwen, gemini) | claude |
383
+ | `--concurrency` | `-c` | Number of parallel workers | 2 |
384
+ | `--skip-issues-with-prs` | `-s` | Skip issues with existing PRs | false |
385
+ | `--verbose` | `-v` | Enable verbose logging | false |
386
+ | `--attach-logs` | | Attach logs to PRs (⚠️ may expose sensitive data) | false |
387
+ | `--help` | `-h` | Show all available options | - |
388
388
 
389
389
  > **📖 Full options list**: See [docs/CONFIGURATION.md](./docs/CONFIGURATION.md#hive-options) for all available options including project monitoring, YouTrack integration, and experimental features.
390
390
 
@@ -470,12 +470,15 @@ Aliases:
470
470
  /opencode is equivalent to /solve --tool opencode
471
471
  /agent is equivalent to /solve --tool agent
472
472
  /qwen is equivalent to /solve --tool qwen
473
+ /gemini is equivalent to /solve --tool gemini
473
474
 
474
475
  Tool alias examples:
475
476
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
476
477
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
477
478
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
479
+ /gemini https://github.com/owner/repo/issues/123 --model flash
478
480
  /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
481
+ /gemini https://github.com/owner/repo/issues/123 --model gemini-2.5-flash
479
482
 
480
483
  Free Models (with --tool agent):
481
484
  /solve https://github.com/owner/repo/issues/123 --tool agent --model nemotron-3-super-free
@@ -497,7 +500,9 @@ Current tool defaults in Hive Mind:
497
500
  | `codex` | `gpt-5.5` preferred, with runtime fallback to local catalog | Codex runs with `reasoning_effort=none` unless you pass `--think` or `--thinking-budget` |
498
501
  | `opencode` | `grok-code-fast-1` | No extra thinking prompt is added for the default model |
499
502
  | `agent` | `nemotron-3-super-free` | No extra thinking prompt is added for the default model |
503
+ | `gemini` | `flash` | No extra thinking prompt is added for the default model |
500
504
  | `qwen` | `qwen3-coder-plus` | No extra thinking prompt is added for the default model |
505
+ | `gemini` | `gemini-2.5-flash` | No extra thinking prompt is added for the default model |
501
506
 
502
507
  See [docs/CONFIGURATION.md](./docs/CONFIGURATION.md) for the full per-tool defaults and reasoning mappings.
503
508
 
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, qwen) | claude |
346
+ | `--tool` | | Инструмент ИИ (claude, opencode, codex, agent, qwen, gemini) | 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, codex, agent, qwen) | claude |
373
+ | `--tool` | | Инструмент ИИ (claude, opencode, codex, agent, qwen, gemini) | claude |
374
374
  | `--concurrency` | `-c` | Количество параллельных воркеров | 2 |
375
375
  | `--skip-issues-with-prs` | `-s` | Пропускать задачи с существующими PR | false |
376
376
  | `--verbose` | `-v` | Включить подробное логирование | false |
@@ -464,12 +464,15 @@ Aliases:
464
464
  /opencode эквивалентна /solve --tool opencode
465
465
  /agent эквивалентна /solve --tool agent
466
466
  /qwen эквивалентна /solve --tool qwen
467
+ /gemini эквивалентна /solve --tool gemini
467
468
 
468
469
  Tool alias examples:
469
470
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
470
471
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
471
472
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
473
+ /gemini https://github.com/owner/repo/issues/123 --model flash
472
474
  /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
475
+ /gemini https://github.com/owner/repo/issues/123 --model gemini-2.5-flash
473
476
 
474
477
  Free Models (with --tool agent):
475
478
  /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、qwen) | 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、gemini) | 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、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` | 显示所有可用选项 | - |
371
+ | 选项 | 简写 | 描述 | 默认值 |
372
+ | ------------------------ | ---- | ------------------------------------------------------- | ------ |
373
+ | `--tool` | | AI 工具(claude、opencode、codex、agent、qwen、gemini) | 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
 
@@ -460,12 +460,15 @@ Aliases:
460
460
  /opencode 等同于 /solve --tool opencode
461
461
  /agent 等同于 /solve --tool agent
462
462
  /qwen 等同于 /solve --tool qwen
463
+ /gemini 等同于 /solve --tool gemini
463
464
 
464
465
  Tool alias examples:
465
466
  /codex https://github.com/owner/repo/issues/123 --model gpt-5.5
466
467
  /opencode https://github.com/owner/repo/issues/123 --model grok-code-fast-1
467
468
  /agent https://github.com/owner/repo/issues/123 --model nemotron-3-super-free
469
+ /gemini https://github.com/owner/repo/issues/123 --model flash
468
470
  /qwen https://github.com/owner/repo/issues/123 --model qwen3-coder-plus
471
+ /gemini https://github.com/owner/repo/issues/123 --model gemini-2.5-flash
469
472
 
470
473
  Free Models (with --tool agent):
471
474
  /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.62.1",
3
+ "version": "1.64.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",
@@ -72,7 +72,7 @@
72
72
  "@secretlint/secretlint-rule-preset-recommend": "^11.2.5",
73
73
  "@sentry/node": "^10.15.0",
74
74
  "@sentry/profiling-node": "^10.15.0",
75
- "agent-commander": "^0.4.2",
75
+ "agent-commander": "^0.6.1",
76
76
  "dayjs": "^1.11.19",
77
77
  "decimal.js-light": "^2.5.1",
78
78
  "lino-arguments": "^0.3.0",
@@ -0,0 +1,361 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Experimental agent-commander execution adapter.
4
+ *
5
+ * This module is only used when solve is called with --use-agent-commander.
6
+ * Default tool execution remains in claude.lib.mjs, codex.lib.mjs,
7
+ * opencode.lib.mjs, and agent.lib.mjs.
8
+ */
9
+
10
+ import { resolveCodexReasoningEffort } from './codex.options.lib.mjs';
11
+ import { mapModelForTool } from './models/index.mjs';
12
+ import { buildCodexDisable1mContextConfigArgs, buildCodexSubSessionSizeConfigArgs, parseSubSessionSize } from './sub-session-size.lib.mjs';
13
+ import { detectUsageLimit } from './usage-limit.lib.mjs';
14
+
15
+ export const AGENT_COMMANDER_TOOLS = new Set(['claude', 'codex', 'opencode', 'agent', 'qwen', 'gemini']);
16
+
17
+ const TOOL_EXECUTABLE_CONFIG = {
18
+ claude: { argvKey: 'claudePath', envKey: 'CLAUDE_PATH' },
19
+ codex: { argvKey: 'codexPath', envKey: 'CODEX_PATH' },
20
+ opencode: { argvKey: 'opencodePath', envKey: 'OPENCODE_PATH' },
21
+ agent: { argvKey: 'agentPath', envKey: 'AGENT_PATH' },
22
+ qwen: { argvKey: 'qwenPath', envKey: 'QWEN_PATH' },
23
+ gemini: { argvKey: 'geminiPath', envKey: 'GEMINI_PATH' },
24
+ };
25
+
26
+ const getConfiguredExecutable = (argv = {}, tool) => {
27
+ const config = TOOL_EXECUTABLE_CONFIG[tool];
28
+ if (!config) return null;
29
+ return argv[config.argvKey] || process.env[config.envKey] || null;
30
+ };
31
+
32
+ const appendExtraArgs = (options, args) => {
33
+ if (!Array.isArray(args) || args.length === 0) return;
34
+ options.extraArgs = [...(options.extraArgs || []), ...args];
35
+ };
36
+
37
+ const appendExtraEnv = (options, env) => {
38
+ const entries = Object.entries(env || {}).filter(([, value]) => value !== undefined && value !== null && value !== false);
39
+ if (entries.length === 0) return;
40
+ options.extraEnv = {
41
+ ...(options.extraEnv || {}),
42
+ ...Object.fromEntries(entries.map(([key, value]) => [key, String(value)])),
43
+ };
44
+ };
45
+
46
+ const buildClaudeToolOptions = (argv = {}) => {
47
+ const options = {};
48
+ options.verbose = !!argv.verbose;
49
+ if (argv.fallbackModel) options.fallbackModel = argv.fallbackModel;
50
+
51
+ const extraEnv = {};
52
+ if (argv.thinkingBudget !== undefined) extraEnv.MAX_THINKING_TOKENS = argv.thinkingBudget;
53
+ if (argv.disable1mContext) extraEnv.CLAUDE_CODE_DISABLE_1M_CONTEXT = '1';
54
+ if (argv.showThinkingContent) extraEnv.CLAUDE_CODE_SHOW_THINKING = '1';
55
+ if (argv.planModel) extraEnv.ANTHROPIC_DEFAULT_OPUS_MODEL = argv.planModel;
56
+ appendExtraEnv(options, extraEnv);
57
+
58
+ return options;
59
+ };
60
+
61
+ const buildCodexToolOptions = (argv = {}) => {
62
+ const options = {};
63
+ const { reasoningEffort } = resolveCodexReasoningEffort(argv);
64
+ appendExtraArgs(options, ['-c', `model_reasoning_effort=${reasoningEffort}`, '-c', 'model_reasoning_summary=auto']);
65
+
66
+ appendExtraArgs(options, buildCodexDisable1mContextConfigArgs(!!argv.disable1mContext));
67
+ try {
68
+ appendExtraArgs(options, buildCodexSubSessionSizeConfigArgs(parseSubSessionSize(argv.subSessionSize)));
69
+ } catch {
70
+ // The embedded Codex path logs parse warnings later. Keep agent-commander
71
+ // command construction permissive so validation can still run.
72
+ }
73
+
74
+ return options;
75
+ };
76
+
77
+ const defaultLog = async (message, options = {}) => {
78
+ if (options.verbose && !global.verboseMode) return;
79
+ if (options.level === 'error') {
80
+ console.error(message);
81
+ } else if (options.level === 'warning' || options.level === 'warn') {
82
+ console.warn(message);
83
+ } else {
84
+ console.log(message);
85
+ }
86
+ };
87
+
88
+ const getAgentCommander = async () => {
89
+ try {
90
+ return await import('agent-commander');
91
+ } catch (error) {
92
+ throw new Error(`agent-commander is not installed or cannot be loaded. Install it with: npm install agent-commander\nOriginal error: ${error.message}`);
93
+ }
94
+ };
95
+
96
+ export const isAgentCommanderAvailable = async () => {
97
+ try {
98
+ await getAgentCommander();
99
+ return true;
100
+ } catch {
101
+ return false;
102
+ }
103
+ };
104
+
105
+ export const getAgentCommanderToolName = (argv = {}) => argv.tool || 'claude';
106
+
107
+ const resolveAgentCommanderModel = (tool, model) => (model ? mapModelForTool(tool, model) : model);
108
+
109
+ export const buildAgentCommanderToolOptions = (argv = {}, tool = getAgentCommanderToolName(argv)) => {
110
+ const options = tool === 'claude' ? buildClaudeToolOptions(argv) : tool === 'codex' ? buildCodexToolOptions(argv) : {};
111
+
112
+ const executable = getConfiguredExecutable(argv, tool);
113
+ if (executable) {
114
+ options.executable = executable;
115
+ }
116
+
117
+ if (tool === 'gemini' && argv.verbose) options.debug = true;
118
+
119
+ return options;
120
+ };
121
+
122
+ export const buildAgentCommanderControllerOptions = ({ tool, tempDir, prompt, systemPrompt, argv = {} }) => ({
123
+ tool,
124
+ workingDirectory: tempDir,
125
+ prompt,
126
+ systemPrompt,
127
+ model: resolveAgentCommanderModel(tool, argv.model),
128
+ json: tool !== 'agent',
129
+ resume: argv.resume,
130
+ toolOptions: buildAgentCommanderToolOptions(argv, tool),
131
+ });
132
+
133
+ export const validateAgentCommanderConnection = async ({ tool, model, log = defaultLog, agentCommanderModule = null }) => {
134
+ try {
135
+ const module = agentCommanderModule || (await getAgentCommander());
136
+ const { agent, isToolSupported } = module;
137
+ const toolName = tool || 'claude';
138
+
139
+ if (!AGENT_COMMANDER_TOOLS.has(toolName) || !isToolSupported({ toolName })) {
140
+ await log(`[agent-commander] Tool '${toolName}' is not supported`, { level: 'error' });
141
+ return false;
142
+ }
143
+
144
+ const controller = agent({
145
+ tool: toolName,
146
+ workingDirectory: process.cwd(),
147
+ prompt: 'connection check',
148
+ model: resolveAgentCommanderModel(toolName, model),
149
+ json: toolName !== 'agent',
150
+ toolOptions: buildAgentCommanderToolOptions({ model }, toolName),
151
+ });
152
+ await controller.start({ dryRun: true, attached: false });
153
+ await log(`[agent-commander] ${toolName} command construction validated`, { verbose: true });
154
+ return true;
155
+ } catch (error) {
156
+ await log(`[agent-commander] Connection validation failed: ${error.message}`, { level: 'error' });
157
+ return false;
158
+ }
159
+ };
160
+
161
+ const getPromptModule = async tool => {
162
+ if (tool === 'claude') return await import('./claude.prompts.lib.mjs');
163
+ if (tool === 'codex') return await import('./codex.prompts.lib.mjs');
164
+ if (tool === 'opencode') return await import('./opencode.prompts.lib.mjs');
165
+ if (tool === 'agent') return await import('./agent.prompts.lib.mjs');
166
+ if (tool === 'qwen') return await import('./qwen.prompts.lib.mjs');
167
+ if (tool === 'gemini') return await import('./gemini.prompts.lib.mjs');
168
+ throw new Error(`Unsupported tool for agent-commander: ${tool}`);
169
+ };
170
+
171
+ export const getPlaywrightMcpAvailabilityCheck = async tool => {
172
+ if (tool === 'opencode') return (await import('./opencode.lib.mjs')).checkPlaywrightMcpAvailability;
173
+ if (tool === 'codex') return (await import('./codex.lib.mjs')).checkPlaywrightMcpAvailability;
174
+ if (tool === 'agent') return (await import('./agent.lib.mjs')).checkPlaywrightMcpAvailability;
175
+ if (tool === 'qwen') return (await import('./qwen.lib.mjs')).checkPlaywrightMcpAvailability;
176
+ if (tool === 'gemini') return (await import('./gemini.lib.mjs')).checkPlaywrightMcpAvailability;
177
+ return (await import('./claude.lib.mjs')).checkPlaywrightMcpAvailability;
178
+ };
179
+
180
+ export const resolvePlaywrightMcpForAgentCommander = async ({ argv, log = defaultLog, tool = getAgentCommanderToolName(argv) }) => {
181
+ if (argv.playwrightMcp === false) return;
182
+ if (!argv.promptPlaywrightMcp) {
183
+ await log('ℹ️ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
184
+ return;
185
+ }
186
+
187
+ const checkFn = await getPlaywrightMcpAvailabilityCheck(tool);
188
+ const available = await checkFn();
189
+ if (available) {
190
+ await log('🎭 Playwright MCP detected - enabling browser automation hints', { verbose: true });
191
+ } else {
192
+ await log('ℹ️ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
193
+ argv.promptPlaywrightMcp = false;
194
+ }
195
+ };
196
+
197
+ const getParsedMessages = result => {
198
+ const parsed = result?.output?.parsed;
199
+ if (Array.isArray(parsed)) return parsed;
200
+ if (parsed && typeof parsed === 'object') return [parsed];
201
+ return [];
202
+ };
203
+
204
+ const extractResultSummary = (messages, plainOutput) => {
205
+ for (const message of [...messages].reverse()) {
206
+ if (typeof message?.result === 'string' && message.result.trim()) return message.result.trim();
207
+ if (typeof message?.summary === 'string' && message.summary.trim()) return message.summary.trim();
208
+ if (typeof message?.text === 'string' && message.text.trim()) return message.text.trim();
209
+ if (typeof message?.message === 'string' && message.message.trim()) return message.message.trim();
210
+ if (typeof message?.item?.content === 'string' && message.item.content.trim()) return message.item.content.trim();
211
+ if (Array.isArray(message?.item?.content)) {
212
+ const text = message.item.content
213
+ .map(part => part?.text || '')
214
+ .join('')
215
+ .trim();
216
+ if (text) return text;
217
+ }
218
+ }
219
+
220
+ return plainOutput?.trim() ? plainOutput.trim().slice(-4000) : null;
221
+ };
222
+
223
+ const hasErrorMessage = messages => messages.some(message => message?.is_error === true || message?.type === 'error' || message?.type === 'step_error' || message?.error);
224
+
225
+ export const summarizeAgentCommanderResult = ({ result, tool }) => {
226
+ const plainOutput = result?.output?.plain || '';
227
+ if (result?.metadata && typeof result.metadata === 'object') {
228
+ const metadata = result.metadata;
229
+ return {
230
+ success: metadata.success === true,
231
+ sessionId: metadata.sessionId || result.sessionId || null,
232
+ limitReached: !!metadata.limitReached,
233
+ limitResetTime: metadata.limitResetTime || null,
234
+ limitTimezone: metadata.limitTimezone || null,
235
+ anthropicTotalCostUSD: metadata.anthropicTotalCostUSD ?? null,
236
+ publicPricingEstimate: metadata.publicPricingEstimate ?? metadata.pricingInfo?.totalCostUSD ?? null,
237
+ pricingInfo: metadata.pricingInfo || null,
238
+ resultSummary: metadata.resultSummary || null,
239
+ resultModelUsage: metadata.resultModelUsage || null,
240
+ streamTokenUsage: metadata.streamTokenUsage || result.usage || null,
241
+ subAgentCalls: metadata.subAgentCalls || null,
242
+ errorDuringExecution: metadata.errorDuringExecution === true || result?.exitCode !== 0,
243
+ result: plainOutput,
244
+ };
245
+ }
246
+
247
+ const messages = getParsedMessages(result);
248
+ const usageLimit = detectUsageLimit(plainOutput);
249
+ const usage = result?.usage || null;
250
+ const resultMessage = [...messages].reverse().find(message => message?.type === 'result') || null;
251
+ const totalCost = typeof resultMessage?.total_cost_usd === 'number' ? resultMessage.total_cost_usd : null;
252
+ const publicPricingEstimate = tool === 'agent' && typeof usage?.totalCost === 'number' ? usage.totalCost : null;
253
+
254
+ return {
255
+ success: result?.exitCode === 0 && !usageLimit.isUsageLimit && !hasErrorMessage(messages),
256
+ sessionId: result?.sessionId || resultMessage?.session_id || null,
257
+ limitReached: usageLimit.isUsageLimit,
258
+ limitResetTime: usageLimit.resetTime,
259
+ limitTimezone: usageLimit.timezone,
260
+ anthropicTotalCostUSD: tool === 'claude' ? totalCost : null,
261
+ publicPricingEstimate,
262
+ pricingInfo: publicPricingEstimate !== null ? { totalCostUSD: publicPricingEstimate, source: 'agent-commander' } : null,
263
+ resultSummary: extractResultSummary(messages, plainOutput),
264
+ resultModelUsage: null,
265
+ streamTokenUsage: usage,
266
+ subAgentCalls: null,
267
+ errorDuringExecution: result?.exitCode !== 0 || hasErrorMessage(messages),
268
+ result: plainOutput,
269
+ };
270
+ };
271
+
272
+ export const executeWithAgentCommander = async params => {
273
+ const { agentCommanderModule = null, promptModule = null, log = defaultLog, argv, tempDir, workspaceTmpDir, ...promptParams } = params;
274
+ const tool = getAgentCommanderToolName(argv);
275
+ const module = agentCommanderModule || (await getAgentCommander());
276
+
277
+ if (!AGENT_COMMANDER_TOOLS.has(tool) || !module.isToolSupported({ toolName: tool })) {
278
+ throw new Error(`agent-commander does not support tool '${tool}'`);
279
+ }
280
+
281
+ const prompts = promptModule || (await getPromptModule(tool));
282
+ const promptBuilderParams = { ...promptParams, tempDir, workspaceTmpDir, argv };
283
+ const prompt = prompts.buildUserPrompt(promptBuilderParams);
284
+ const systemPrompt = prompts.buildSystemPrompt(promptBuilderParams);
285
+ const controllerOptions = buildAgentCommanderControllerOptions({ tool, tempDir, prompt, systemPrompt, argv });
286
+
287
+ if (argv.verbose) {
288
+ await log('\n[agent-commander] Final prompt structure:', { verbose: true });
289
+ await log(` Tool: ${tool}`, { verbose: true });
290
+ await log(` User prompt characters: ${prompt.length}`, { verbose: true });
291
+ await log(` System prompt characters: ${systemPrompt.length}`, { verbose: true });
292
+ }
293
+
294
+ const controller = module.agent(controllerOptions);
295
+ const dryRun = !!(argv.dryRun || argv.onlyPrepareCommand);
296
+ await log(`\n[agent-commander] Starting ${tool} execution${dryRun ? ' (dry-run)' : ''}...`);
297
+ await controller.start({
298
+ dryRun,
299
+ attached: true,
300
+ onOutput: chunk => {
301
+ if (chunk.type === 'stderr') process.stderr.write(chunk.data);
302
+ else process.stdout.write(chunk.data);
303
+ },
304
+ });
305
+
306
+ if (dryRun) {
307
+ return {
308
+ success: true,
309
+ sessionId: null,
310
+ limitReached: false,
311
+ limitResetTime: null,
312
+ limitTimezone: null,
313
+ anthropicTotalCostUSD: null,
314
+ publicPricingEstimate: null,
315
+ pricingInfo: null,
316
+ resultSummary: null,
317
+ };
318
+ }
319
+
320
+ const result = await controller.stop();
321
+ await log(`[agent-commander] ${tool} exited with code ${result.exitCode}`);
322
+ return summarizeAgentCommanderResult({ result, tool });
323
+ };
324
+
325
+ export const checkForUncommittedChanges = async (tempDir, owner, repo, branchName, $, log = defaultLog, autoCommit = false, autoRestartEnabled = true) => {
326
+ await log('\n🔍 Checking for uncommitted changes...');
327
+ const gitStatusResult = await $({ cwd: tempDir })`git status --porcelain 2>&1`;
328
+ const statusOutput = gitStatusResult.stdout?.toString().trim() || '';
329
+
330
+ if (!statusOutput) {
331
+ await log('✅ No uncommitted changes found');
332
+ return false;
333
+ }
334
+
335
+ await log('📝 Found uncommitted changes');
336
+ await log('Changes:');
337
+ for (const line of statusOutput.split('\n')) await log(` ${line}`);
338
+
339
+ if (autoCommit) {
340
+ await log('💾 Auto-committing changes (--auto-commit-uncommitted-changes is enabled)...');
341
+ const addResult = await $({ cwd: tempDir })`git add -A`;
342
+ if (addResult.code === 0) {
343
+ const commitResult = await $({ cwd: tempDir })`git commit -m ${'Auto-commit: Changes made through agent-commander during problem-solving session'}`;
344
+ if (commitResult.code === 0) {
345
+ const pushResult = await $({ cwd: tempDir })`git push origin ${branchName} 2>&1`;
346
+ await log(pushResult.code === 0 ? '✅ Changes pushed successfully' : `⚠️ Warning: Could not push changes: ${pushResult.stderr?.toString().trim() || pushResult.stdout?.toString().trim()}`, { level: pushResult.code === 0 ? 'info' : 'warning' });
347
+ }
348
+ }
349
+ return false;
350
+ }
351
+
352
+ if (autoRestartEnabled) {
353
+ await log('\n⚠️ IMPORTANT: Uncommitted changes detected!');
354
+ await log(' The agent-commander controlled tool made changes that were not committed.');
355
+ await log('\n🔄 AUTO-RESTART: Restarting the tool to handle uncommitted changes...\n');
356
+ return true;
357
+ }
358
+
359
+ await log('\n⚠️ Uncommitted changes detected but auto-restart is disabled.');
360
+ return false;
361
+ };
@@ -851,7 +851,7 @@ export const createBidirectionalHandler = options => {
851
851
  /**
852
852
  * Check if bidirectional interactive mode is supported for the given tool
853
853
  *
854
- * @param {string} tool - Tool name (claude, opencode, codex)
854
+ * @param {string} tool - Tool name (claude, opencode, codex, agent, gemini)
855
855
  * @returns {boolean} Whether bidirectional interactive mode is supported
856
856
  */
857
857
  export const isBidirectionalModeSupported = tool => {
@@ -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, qwen) and supports various isolation modes.
297
+ - Agent Commander provides a unified API for different agent types (claude, opencode, codex, agent, qwen, gemini) 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, qwen)
303
+ --tool <name>: Agent to use (claude, opencode, codex, agent, qwen, gemini)
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, qwen) and supports various isolation modes.
280
+ - Agent Commander provides a unified API for different agent types (claude, opencode, codex, agent, qwen, gemini) 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, qwen)
286
+ --tool <name>: Agent to use (claude, opencode, codex, agent, qwen, gemini)
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
@@ -51,6 +51,7 @@ const parseFloatWithDefault = (envVar, defaultValue) => {
51
51
  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
+ geminiCli: parseIntWithDefault('HIVE_MIND_GEMINI_TIMEOUT_SECONDS', 60) * 1000,
54
55
  codexCli: parseIntWithDefault('HIVE_MIND_CODEX_TIMEOUT_SECONDS', 60) * 1000,
55
56
  qwenCli: parseIntWithDefault('HIVE_MIND_QWEN_TIMEOUT_SECONDS', 60) * 1000,
56
57
  githubApiDelay: parseIntWithDefault('HIVE_MIND_GITHUB_API_DELAY_MS', 5000),