@link-assistant/hive-mind 1.62.1 → 1.63.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.
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Gemini prompts module
3
+ * Handles building prompts for Google Gemini CLI commands
4
+ */
5
+
6
+ import { getArchitectureCareSubPrompt } from './architecture-care.prompts.lib.mjs';
7
+ import { getExperimentsExamplesSubPrompt } from './experiments-examples.prompts.lib.mjs';
8
+ import { getThinkingPromptInstruction } from './thinking-prompt.lib.mjs';
9
+
10
+ /**
11
+ * Build the user prompt for Gemini
12
+ * @param {Object} params - Parameters for building the user prompt
13
+ * @returns {string} The formatted user prompt
14
+ */
15
+ export const buildUserPrompt = params => {
16
+ const { issueUrl, issueNumber, prNumber, prUrl, branchName, tempDir, workspaceTmpDir, isContinueMode, forkedRepo, feedbackLines, forkActionsUrl, owner, repo, argv } = params;
17
+
18
+ const promptLines = [];
19
+
20
+ if (isContinueMode) {
21
+ promptLines.push(`Issue to solve: ${issueNumber ? `https://github.com/${owner}/${repo}/issues/${issueNumber}` : `Issue linked to PR #${prNumber}`}`);
22
+ } else {
23
+ promptLines.push(`Issue to solve: ${issueUrl}`);
24
+ }
25
+
26
+ promptLines.push(`Your prepared branch: ${branchName}`);
27
+ promptLines.push(`Your prepared working directory: ${tempDir}`);
28
+
29
+ if (workspaceTmpDir) {
30
+ promptLines.push(`Your prepared tmp directory for logs and downloads: ${workspaceTmpDir}`);
31
+ }
32
+
33
+ if (prUrl) {
34
+ promptLines.push(`Your prepared Pull Request: ${prUrl}`);
35
+ }
36
+
37
+ if (argv && argv.fork && forkedRepo) {
38
+ promptLines.push(`Your forked repository: ${forkedRepo}`);
39
+ promptLines.push(`Original repository (upstream): ${owner}/${repo}`);
40
+
41
+ if (branchName && forkActionsUrl) {
42
+ promptLines.push(`GitHub Actions on your fork: ${forkActionsUrl}`);
43
+ }
44
+ }
45
+
46
+ promptLines.push('');
47
+
48
+ if (isContinueMode && feedbackLines && feedbackLines.length > 0) {
49
+ feedbackLines.forEach(line => promptLines.push(line));
50
+ promptLines.push('');
51
+ }
52
+
53
+ const thinkingPromptInstruction = getThinkingPromptInstruction({ tool: 'gemini', argv });
54
+ if (thinkingPromptInstruction) {
55
+ promptLines.push(thinkingPromptInstruction);
56
+ }
57
+
58
+ promptLines.push(isContinueMode ? 'Continue.' : 'Proceed.');
59
+
60
+ return promptLines.join('\n') + '\n';
61
+ };
62
+
63
+ /**
64
+ * Build the system prompt for Gemini
65
+ * @param {Object} params - Parameters for building the prompt
66
+ * @returns {string} The formatted system prompt
67
+ */
68
+ export const buildSystemPrompt = params => {
69
+ const { owner, repo, issueNumber, prNumber, branchName, workspaceTmpDir, argv, modelSupportsVision, forkedRepo } = params;
70
+
71
+ const screenshotRepoPath = argv?.fork && forkedRepo ? forkedRepo : `${owner}/${repo}`;
72
+
73
+ let workspaceInstructions = '';
74
+ if (workspaceTmpDir) {
75
+ workspaceInstructions = `
76
+ Workspace tmp directory.
77
+ - Use ${workspaceTmpDir} for all temporary files, logs, and downloads.
78
+ - When saving command output to files, save to ${workspaceTmpDir}/command-output.log.
79
+ - When downloading CI logs, save to ${workspaceTmpDir}/ci-logs/.
80
+ - When saving diffs for review, save to ${workspaceTmpDir}/diffs/.
81
+ - When creating debug files, save to ${workspaceTmpDir}/debug/.
82
+
83
+ `;
84
+ }
85
+
86
+ let ciExamples = '';
87
+ if (workspaceTmpDir) {
88
+ ciExamples = `
89
+ CI investigation with workspace tmp directory.
90
+ - When downloading CI run logs:
91
+ gh run view RUN_ID --repo ${owner}/${repo} --log > ${workspaceTmpDir}/ci-logs/run-RUN_ID.log
92
+ - When downloading failed job logs:
93
+ gh run view RUN_ID --repo ${owner}/${repo} --log-failed > ${workspaceTmpDir}/ci-logs/run-RUN_ID-failed.log
94
+ - When listing CI runs with details:
95
+ gh run list --repo ${owner}/${repo} --branch ${branchName} --limit 5 --json databaseId,conclusion,createdAt,headSha > ${workspaceTmpDir}/ci-logs/recent-runs.json
96
+ - When saving PR diff for review:
97
+ gh pr diff ${prNumber} --repo ${owner}/${repo} > ${workspaceTmpDir}/diffs/pr-${prNumber}.diff
98
+ - When saving command output with stderr:
99
+ npm test 2>&1 | tee ${workspaceTmpDir}/test-output.log
100
+ - When investigating issue details:
101
+ gh issue view ${issueNumber} --repo ${owner}/${repo} --json body,comments > ${workspaceTmpDir}/issue-${issueNumber}.json
102
+
103
+ `;
104
+ }
105
+
106
+ return `You are an AI issue solver using Google Gemini CLI.
107
+ ${workspaceInstructions}General guidelines.
108
+ - When you execute commands and the output becomes large, save the logs to files for easier review.
109
+ - When running commands, avoid setting a timeout yourself. Let them run as long as needed. The default timeout of 2 minutes is usually enough, and once commands finish, review the logs in the file.
110
+ - When running sudo commands, especially package installations like apt-get, yum, or npm install, run them in the background to avoid timeout issues and permission errors when the process needs to be killed. Use the run_in_background parameter or append & to the command.
111
+ - When CI is failing or user reports failures, consider adding a detailed investigation protocol to your todo list with these steps:
112
+ Step 1: List recent runs with timestamps using: gh run list --repo ${owner}/${repo} --branch ${branchName} --limit 5 --json databaseId,conclusion,createdAt,headSha
113
+ Step 2: Verify runs are after the latest commit by checking timestamps and SHA
114
+ Step 3: For each non-passing run, download logs to preserve them: gh run view {run-id} --repo ${owner}/${repo} --log > ci-logs/{workflow}-{run-id}.log
115
+ Step 4: Read each downloaded log file with the Read tool to understand the actual failures
116
+ Step 5: Report findings with specific errors and line numbers from logs
117
+ This detailed investigation is especially helpful when user mentions CI failures, asks to investigate logs, you see non-passing status, or when finalizing a PR.
118
+ Note: If user says "failing" but tools show "passing", this might indicate stale data - consider downloading fresh logs and checking timestamps to resolve the discrepancy.
119
+ - When a code or log file has more than 1500 lines, read it in chunks of 1500 lines.
120
+ - When facing a complex problem, do as much tracing as possible and turn on all verbose modes.
121
+ ${getExperimentsExamplesSubPrompt(argv)}
122
+ - When you face something extremely hard, use divide and conquer.
123
+
124
+ Initial research.
125
+ - When you start, create a detailed plan for yourself and follow your todo list step by step. Add as many relevant points from these guidelines to the todo list as practical so you can track the work clearly.
126
+ - When the user mentions CI failures or asks to investigate logs, consider adding these todos to track the investigation: (1) list recent CI runs with timestamps, (2) download logs from failed runs to the ci-logs/ directory, (3) analyze error messages and identify the root cause, (4) implement a fix, (5) verify that the fix resolves the specific errors found in the logs.
127
+ - When you read the issue, read all details and comments thoroughly.
128
+ - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, download the image to a local file first, then use the Read tool to view and analyze it. Before reading downloaded images with the Read tool, verify that the file is a valid image rather than HTML by using a CLI tool such as the 'file' command. When the file command shows "HTML", "text", or "ASCII text", the download failed, so do not call Read on that file. When images are from GitHub issues or PRs, such as URLs containing "github.com/user-attachments", use: curl -L -H "Authorization: token $(gh auth token)" -o <filename> "<url>"
129
+ - When you need issue details, use gh issue view https://github.com/${owner}/${repo}/issues/${issueNumber}.
130
+ - When you need related code, use gh search code --owner ${owner} [keywords].
131
+ - When you need repo context, read files in your working directory.${
132
+ argv?.promptCheckSiblingPullRequests !== false
133
+ ? `
134
+ - When you study related work, study the most recent related pull requests.`
135
+ : ''
136
+ }${
137
+ argv && argv.promptCaseStudies
138
+ ? `
139
+ - When working on this issue, create a comprehensive case study in the ./docs/case-studies/issue-${issueNumber}/ directory with logs, analysis, timeline, root cause investigation, and proposed solutions.`
140
+ : ''
141
+ }
142
+ - When the issue is not defined clearly enough, write a comment with clarifying questions.
143
+ - When accessing GitHub Gists (especially private ones), use gh gist view command instead of direct URL fetching to ensure proper authentication.
144
+ - When you are fixing a bug, find the actual root cause first and run as many experiments as needed.
145
+ - When you are fixing a bug and the code does not have enough tracing or logs, add them and keep them in the code with the default state switched off.
146
+ - When you need comments on a pull request, note that GitHub has three different comment types with different API endpoints:
147
+ 1. PR review comments (inline code comments): gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate
148
+ 2. PR conversation comments (general discussion): gh api repos/${owner}/${repo}/issues/${prNumber}/comments --paginate
149
+ 3. PR reviews (approve/request changes): gh api repos/${owner}/${repo}/pulls/${prNumber}/reviews --paginate
150
+ Note: The command "gh pr view --json comments" only returns conversation comments and misses review comments.
151
+ - When you need the latest comments on the issue, use gh api repos/${owner}/${repo}/issues/${issueNumber}/comments --paginate.
152
+
153
+ Solution development and testing.
154
+ - When issue is solvable, first create a test that reproduces the problem, then implement the fix.
155
+ - When implementing features, search for similar existing implementations in the codebase and use them as examples instead of implementing everything from scratch.
156
+ - When coding, commit each atomic step that is useful on its own to the pull request branch so interrupted work remains preserved in the pull request.
157
+ - When you test:
158
+ start from testing of small functions using separate scripts;
159
+ write unit tests with mocks for easy and quick start.
160
+ - When you test integrations, use existing framework.
161
+ - When you test solution draft, include automated checks in pr.
162
+ - When you write or modify tests, consider setting reasonable timeouts at test, suite, and CI job levels so failures surface quickly instead of hanging.
163
+ - When you see repeated test timeout patterns in CI, investigate the root cause rather than increasing timeouts.
164
+ - When the issue is unclear, write a comment on the issue with questions.
165
+ - When you encounter any problems that you are unable to solve yourself (any human feedback or help), write a comment to the pull request asking for help.
166
+ - When you need human help, use gh pr comment ${prNumber} --body "your message" --repo ${owner}/${repo}.
167
+
168
+ Reproducible testing.
169
+ - When fixing a bug, create a test that reproduces the problem before implementing the fix. When you cannot reproduce the problem, you cannot verify the fix.
170
+ - When encountering logic bugs, write an automated test that fails due to the bug, then implement the fix to make it pass.
171
+ - When encountering UI bugs, capture a screenshot showing the problem state, then create a visual regression test or manual verification screenshot after the fix.
172
+ - When creating tests, prefer minimum reproducible examples, meaning the simplest test case that demonstrates the issue.
173
+ - When submitting a fix, include in the PR description: (1) how to reproduce the issue, (2) the automated test that verifies the fix, (3) before/after screenshots for UI issues.
174
+ - When a bug fix does not have a reproducing test, treat the fix as incomplete because regressions can occur later without notice.
175
+
176
+ Preparing pull request.
177
+ - When you code, follow contributing guidelines.
178
+ - When you commit, write clear message.
179
+ - When you need examples of style, use gh pr list --repo ${owner}/${repo} --state merged --search [keywords].
180
+ - When you open pr, describe solution draft and include tests.
181
+ - When there is a package with version and GitHub Actions workflows for automatic release, update the version (or other necessary release trigger) in your pull request to prepare for next release.
182
+ - When you update existing pr ${prNumber}, use gh pr edit ${prNumber} --repo ${owner}/${repo} to modify title and description.
183
+ - When you are about to commit or push code, run local CI checks first if they are available in contributing guidelines.
184
+ - When you finish implementation, use gh pr ready ${prNumber} --repo ${owner}/${repo}.
185
+
186
+ Workflow and collaboration.
187
+ - When you check branch, verify with git branch --show-current.
188
+ - When you push, push only to branch ${branchName}.
189
+ - When you finish, create a pull request from branch ${branchName}. If PR ${prNumber} already exists for this branch, update it instead.
190
+ - When you mention a result, include the pull request URL or comment URL.
191
+
192
+ Self review.
193
+ - When you check your solution draft, run all tests locally.
194
+ - When you check your solution draft, verify git status shows a clean working tree with no uncommitted changes.
195
+ - When you compare with repo style, use gh pr diff [number].
196
+ - When you finalize, confirm code, tests, and description are consistent.${
197
+ argv && argv.promptEnsureAllRequirementsAreMet
198
+ ? `
199
+ - When no explicit feedback or requirements are provided, ensure all changes are correct, consistent, validated, tested, logged, and aligned with all discussed requirements by checking the issue description and all comments on the issue and pull request. Check that all CI or CD checks are passing.`
200
+ : ''
201
+ }
202
+
203
+ GitHub CLI command patterns.
204
+ - When fetching lists from GitHub API, use the --paginate flag to ensure all results are returned.
205
+ - When listing PR review comments (inline code comments), use gh api repos/OWNER/REPO/pulls/NUMBER/comments --paginate.
206
+ - When listing PR conversation comments, use gh api repos/OWNER/REPO/issues/NUMBER/comments --paginate.
207
+ - When listing PR reviews, use gh api repos/OWNER/REPO/pulls/NUMBER/reviews --paginate.
208
+ - When listing issue comments, use gh api repos/OWNER/REPO/issues/NUMBER/comments --paginate.
209
+ - When adding PR comment, use gh pr comment NUMBER --body "text" --repo OWNER/REPO.
210
+ - When adding issue comment, use gh issue comment NUMBER --body "text" --repo OWNER/REPO.
211
+ - When viewing PR details, use gh pr view NUMBER --repo OWNER/REPO.
212
+ - When filtering with jq, use gh api repos/${owner}/${repo}/pulls/${prNumber}/comments --paginate --jq 'reverse | .[0:5]'.${
213
+ argv && argv.promptPlaywrightMcp
214
+ ? `
215
+
216
+ Playwright MCP usage (browser automation via MCP tools).
217
+ - When you develop frontend web applications or debug UI issues, use Playwright MCP tools to test the UI in a real browser.
218
+ - When simple fetch-based browsing is insufficient for dynamic pages, use Playwright MCP browser automation as a fallback.
219
+ - When WebSearch tool fails or returns insufficient results, use Playwright MCP browser automation as a fallback for internet search.
220
+ - When reproducing or verifying UI bugs, take before/after screenshots and close the browser when finished.`
221
+ : ''
222
+ }${
223
+ modelSupportsVision
224
+ ? `
225
+
226
+ Visual UI work and screenshots.
227
+ - When you work on visual UI changes, include a render or screenshot of the final result in the pull request description.
228
+ - When you save screenshots to the repository, use permanent links in the PR description such as https://github.com/${screenshotRepoPath}/blob/${branchName}/docs/screenshots/result.png?raw=true.`
229
+ : ''
230
+ }${ciExamples}${getArchitectureCareSubPrompt(argv)}`;
231
+ };
232
+
233
+ export default {
234
+ buildUserPrompt,
235
+ buildSystemPrompt,
236
+ };
@@ -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', 'qwen'],
50
+ choices: ['claude', 'opencode', 'codex', 'agent', 'gemini', 'qwen'],
51
51
  default: 'claude',
52
52
  },
53
53
  };
@@ -1321,7 +1321,7 @@ ${createRawJsonSection(data)}`;
1321
1321
  /**
1322
1322
  * Check if interactive mode is supported for the given tool
1323
1323
  *
1324
- * @param {string} tool - Tool name (claude, opencode, codex)
1324
+ * @param {string} tool - Tool name (claude, opencode, codex, agent, gemini)
1325
1325
  * @returns {boolean} Whether interactive mode is supported
1326
1326
  */
1327
1327
  export const isInteractiveModeSupported = tool => {
@@ -129,6 +129,19 @@ export const codexModels = {
129
129
  'gpt-4o': 'gpt-4o',
130
130
  };
131
131
 
132
+ // Gemini models (Google Gemini CLI)
133
+ // Keep aliases aligned with the Gemini CLI model aliases documented in
134
+ // docs/cli/cli-reference.md: auto, pro, flash, and flash-lite.
135
+ export const geminiModels = {
136
+ auto: 'auto',
137
+ pro: 'gemini-2.5-pro',
138
+ flash: 'gemini-2.5-flash',
139
+ 'flash-lite': 'gemini-2.5-flash-lite',
140
+ 'gemini-2.5-pro': 'gemini-2.5-pro',
141
+ 'gemini-2.5-flash': 'gemini-2.5-flash',
142
+ 'gemini-2.5-flash-lite': 'gemini-2.5-flash-lite',
143
+ };
144
+
132
145
  // Qwen Code models
133
146
  export const qwenModels = {
134
147
  qwen: 'qwen3-coder-plus',
@@ -147,6 +160,7 @@ export const defaultModels = {
147
160
  agent: 'nemotron-3-super-free', // Issue #1563: changed from qwen3.6-plus-free (free promotion ended) per agent PR #243
148
161
  opencode: 'grok-code-fast-1',
149
162
  codex: 'gpt-5.5',
163
+ gemini: 'flash',
150
164
  qwen: 'qwen3-coder-plus',
151
165
  };
152
166
 
@@ -227,6 +241,10 @@ export const CODEX_MODELS = {
227
241
  'gpt-4o': 'gpt-4o',
228
242
  };
229
243
 
244
+ export const GEMINI_MODELS = {
245
+ ...geminiModels,
246
+ };
247
+
230
248
  export const QWEN_MODELS = {
231
249
  ...qwenModels,
232
250
  'qwen3-coder': 'qwen3-coder',
@@ -257,7 +275,7 @@ export const AGENT_MODELS = {
257
275
 
258
276
  /**
259
277
  * Get the model map object for a given tool
260
- * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
278
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, gemini, qwen)
261
279
  * @returns {Object} The model mapping for the tool
262
280
  */
263
281
  export const getModelMapForTool = tool => {
@@ -270,6 +288,8 @@ export const getModelMapForTool = tool => {
270
288
  return opencodeModels;
271
289
  case 'codex':
272
290
  return codexModels;
291
+ case 'gemini':
292
+ return geminiModels;
273
293
  case 'qwen':
274
294
  return qwenModels;
275
295
  default:
@@ -279,7 +299,7 @@ export const getModelMapForTool = tool => {
279
299
 
280
300
  /**
281
301
  * Get the default model for a given tool
282
- * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
302
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, gemini, qwen)
283
303
  * @returns {string} The default model alias for the tool
284
304
  */
285
305
  export const getDefaultModelForTool = tool => {
@@ -332,7 +352,7 @@ export const resolveRuntimeDefaultModel = async (tool, options = {}) => {
332
352
 
333
353
  /**
334
354
  * Map model name to full model ID for a specific tool
335
- * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
355
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, gemini, qwen)
336
356
  * @param {string} model - The model name or alias
337
357
  * @returns {string} The full model ID
338
358
  */
@@ -346,6 +366,8 @@ export const mapModelForTool = (tool, model) => {
346
366
  return opencodeModels[model] || model;
347
367
  case 'codex':
348
368
  return codexModels[model] || model;
369
+ case 'gemini':
370
+ return geminiModels[model] || model;
349
371
  case 'qwen':
350
372
  return qwenModels[model] || model;
351
373
  default:
@@ -355,7 +377,7 @@ export const mapModelForTool = (tool, model) => {
355
377
 
356
378
  /**
357
379
  * Validate if a model is compatible with a tool
358
- * @param {string} tool - The tool name (claude, agent, opencode, codex, qwen)
380
+ * @param {string} tool - The tool name (claude, agent, opencode, codex, gemini, qwen)
359
381
  * @param {string} model - The model name or alias
360
382
  * @returns {boolean} True if the model is compatible with the tool
361
383
  */
@@ -371,6 +393,8 @@ export const isModelCompatibleWithTool = (tool, model) => {
371
393
  return mappedModel.includes('/') || Object.keys(opencodeModels).includes(model);
372
394
  case 'codex':
373
395
  return Object.keys(codexModels).includes(model) || mappedModel.startsWith('gpt-');
396
+ case 'gemini':
397
+ return Object.keys(geminiModels).includes(model) || mappedModel.startsWith('gemini-');
374
398
  case 'qwen':
375
399
  return Object.keys(qwenModels).includes(model) || mappedModel.startsWith('qwen');
376
400
  default:
@@ -393,6 +417,8 @@ export const getValidModelsForTool = tool => {
393
417
  return Object.keys(opencodeModels);
394
418
  case 'codex':
395
419
  return Object.keys(codexModels);
420
+ case 'gemini':
421
+ return Object.keys(geminiModels);
396
422
  case 'qwen':
397
423
  return Object.keys(qwenModels);
398
424
  default:
@@ -406,6 +432,7 @@ export const primaryModelNames = {
406
432
  claude: ['opus', 'sonnet', 'haiku', 'opusplan'],
407
433
  opencode: ['grok', 'gpt4o'],
408
434
  codex: ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex', 'gpt-5.3-codex-spark'],
435
+ gemini: ['flash', 'pro', 'flash-lite', 'auto'],
409
436
  agent: ['nemotron-3-super-free', 'minimax-m2.5-free', 'big-pickle', 'gpt-5-nano', 'glm-5-free', 'deepseek-r1-free'],
410
437
  qwen: ['qwen3-coder-plus', 'qwen3-coder', 'qwen3-coder-flash'],
411
438
  };
@@ -447,7 +474,7 @@ export const validateToolModelCompatibility = (tool, model) => {
447
474
 
448
475
  /**
449
476
  * Get the model map for a given tool (validation-extended version with full ID entries)
450
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
477
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'gemini', 'qwen')
451
478
  * @returns {Object} The model mapping for the tool
452
479
  */
453
480
  const getValidationModelMapForTool = tool => {
@@ -456,6 +483,8 @@ const getValidationModelMapForTool = tool => {
456
483
  return OPENCODE_MODELS;
457
484
  case 'codex':
458
485
  return CODEX_MODELS;
486
+ case 'gemini':
487
+ return GEMINI_MODELS;
459
488
  case 'agent':
460
489
  return AGENT_MODELS;
461
490
  case 'qwen':
@@ -468,7 +497,7 @@ const getValidationModelMapForTool = tool => {
468
497
 
469
498
  /**
470
499
  * Get the list of available model names for a tool (for display in help/error messages)
471
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
500
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'gemini', 'qwen')
472
501
  * @returns {string[]} Array of available model short names
473
502
  */
474
503
  export const getAvailableModelNames = tool => {
@@ -607,7 +636,7 @@ export const supports1mContext = (model, tool = 'claude') => {
607
636
  * Validate a model name against the available models for a tool
608
637
  * Supports [1m] suffix for 1 million token context (Issue #1221)
609
638
  * @param {string} model - The model name to validate (e.g., "opus", "opus[1m]", "claude-opus-4-6[1m]")
610
- * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'qwen')
639
+ * @param {string} tool - The tool name ('claude', 'opencode', 'codex', 'agent', 'gemini', 'qwen')
611
640
  * @returns {{ valid: boolean, message?: string, suggestions?: string[], mappedModel?: string, has1mSuffix?: boolean }}
612
641
  */
613
642
  export const validateModelName = (model, tool = 'claude') => {
@@ -715,7 +744,7 @@ export const formatAvailableModelsForHelp = (tool = 'claude') => {
715
744
 
716
745
  /**
717
746
  * Map tool identifier to user-friendly display name.
718
- * @param {string|null} tool - The tool identifier (claude, codex, opencode, agent, qwen)
747
+ * @param {string|null} tool - The tool identifier (claude, codex, opencode, agent, gemini, qwen)
719
748
  * @returns {string} User-friendly display name
720
749
  */
721
750
  export const getToolDisplayName = tool => {
@@ -729,6 +758,8 @@ export const getToolDisplayName = tool => {
729
758
  return 'OpenCode';
730
759
  case 'agent':
731
760
  return 'Agent CLI';
761
+ case 'gemini':
762
+ return 'Google Gemini CLI';
732
763
  case 'qwen':
733
764
  return 'Qwen Code';
734
765
  default:
@@ -327,7 +327,7 @@ export const SOLVE_OPTION_DEFINITIONS = {
327
327
  tool: {
328
328
  type: 'string',
329
329
  description: 'AI tool to use for solving issues',
330
- choices: ['claude', 'opencode', 'codex', 'agent', 'qwen'],
330
+ choices: ['claude', 'opencode', 'codex', 'agent', 'gemini', 'qwen'],
331
331
  default: 'claude',
332
332
  },
333
333
  plan: {
@@ -352,7 +352,7 @@ export const SOLVE_OPTION_DEFINITIONS = {
352
352
  },
353
353
  'enable-workspaces': {
354
354
  type: 'boolean',
355
- description: 'Use separate workspace directory structure with repository/ and tmp/ folders. Works with all tools (claude, opencode, codex, agent, qwen). Experimental feature.',
355
+ description: 'Use separate workspace directory structure with repository/ and tmp/ folders. Works with all tools (claude, opencode, codex, agent, gemini, qwen). Experimental feature.',
356
356
  default: false,
357
357
  },
358
358
  'interactive-mode': {
@@ -428,7 +428,7 @@ export const SOLVE_OPTION_DEFINITIONS = {
428
428
  },
429
429
  'prompt-playwright-mcp': {
430
430
  type: 'boolean',
431
- description: 'Enable Playwright MCP browser automation hints in system prompt (enabled by default, only takes effect if Playwright MCP is installed). Use --no-prompt-playwright-mcp to disable. Supported for --tool claude, --tool codex, --tool opencode, --tool agent, and --tool qwen.',
431
+ description: 'Enable Playwright MCP browser automation hints in system prompt (enabled by default, only takes effect if Playwright MCP is installed). Use --no-prompt-playwright-mcp to disable. Supported for --tool claude, --tool codex, --tool opencode, --tool agent, --tool gemini, and --tool qwen.',
432
432
  default: true,
433
433
  },
434
434
  'prompt-check-sibling-pull-requests': {
@@ -448,7 +448,7 @@ export const SOLVE_OPTION_DEFINITIONS = {
448
448
  },
449
449
  'playwright-mcp': {
450
450
  type: 'boolean',
451
- description: 'Enable Playwright MCP server connection for this session (enabled by default). Use --no-playwright-mcp to physically disable the Playwright MCP server without affecting the global MCP registration. When disabled, also disables --prompt-playwright-mcp and --playwright-mcp-auto-cleanup. Supported for --tool claude, --tool codex, --tool opencode, --tool agent, and --tool qwen.',
451
+ description: 'Enable Playwright MCP server connection for this session (enabled by default). Use --no-playwright-mcp to physically disable the Playwright MCP server without affecting the global MCP registration. When disabled, also disables --prompt-playwright-mcp and --playwright-mcp-auto-cleanup. Supported for --tool claude, --tool codex, --tool opencode, --tool agent, and --tool qwen; for --tool gemini this controls prompt hints and cleanup only.',
452
452
  default: true,
453
453
  },
454
454
  'playwright-mcp-auto-cleanup': {
package/src/solve.mjs CHANGED
@@ -93,6 +93,9 @@ let checkForUncommittedChanges;
93
93
  if (argv.tool === 'opencode') {
94
94
  const opencodeLib = await import('./opencode.lib.mjs');
95
95
  checkForUncommittedChanges = opencodeLib.checkForUncommittedChanges;
96
+ } else if (argv.tool === 'gemini') {
97
+ const geminiLib = await import('./gemini.lib.mjs');
98
+ checkForUncommittedChanges = geminiLib.checkForUncommittedChanges;
96
99
  } else if (argv.tool === 'codex') {
97
100
  const codexLib = await import('./codex.lib.mjs');
98
101
  checkForUncommittedChanges = codexLib.checkForUncommittedChanges;
@@ -754,6 +757,36 @@ try {
754
757
  agentPath,
755
758
  $,
756
759
  });
760
+ } else if (argv.tool === 'gemini') {
761
+ const geminiLib = await import('./gemini.lib.mjs');
762
+ const { executeGemini, checkPlaywrightMcpAvailability: checkGeminiPlaywrightMcp } = geminiLib;
763
+ const geminiPath = process.env.GEMINI_PATH || 'gemini';
764
+ await resolvePlaywrightMcp(checkGeminiPlaywrightMcp);
765
+
766
+ toolResult = await executeGemini({
767
+ issueUrl,
768
+ issueNumber,
769
+ prNumber,
770
+ prUrl,
771
+ branchName,
772
+ tempDir,
773
+ workspaceTmpDir,
774
+ isContinueMode,
775
+ mergeStateStatus,
776
+ forkedRepo,
777
+ feedbackLines,
778
+ forkActionsUrl,
779
+ owner,
780
+ repo,
781
+ argv,
782
+ log,
783
+ setLogFile,
784
+ getLogFile,
785
+ formatAligned,
786
+ getResourceSnapshot,
787
+ geminiPath,
788
+ $,
789
+ });
757
790
  } else if (argv.tool === 'qwen') {
758
791
  const qwenLib = await import('./qwen.lib.mjs');
759
792
  const { executeQwen, checkPlaywrightMcpAvailability: checkQwenPlaywrightMcp } = qwenLib;
@@ -167,7 +167,7 @@ export const getUncommittedChangesDetails = async tempDir => {
167
167
  };
168
168
 
169
169
  /**
170
- * Execute the AI tool (Claude, OpenCode, Codex, Agent, Qwen) for a restart iteration
170
+ * Execute the AI tool (Claude, OpenCode, Codex, Agent, Gemini, Qwen) for a restart iteration
171
171
  * This is the shared tool execution logic used by both watch mode and auto-restart-until-mergeable mode
172
172
  * @param {Object} params - Execution parameters
173
173
  * @returns {Promise<Object>} - Tool execution result
@@ -208,6 +208,7 @@ export const executeToolIteration = async params => {
208
208
  prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
209
209
  branchName,
210
210
  tempDir,
211
+ workspaceTmpDir,
211
212
  isContinueMode: true,
212
213
  mergeStateStatus,
213
214
  forkedRepo: argv.fork,
@@ -246,6 +247,7 @@ export const executeToolIteration = async params => {
246
247
  prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
247
248
  branchName,
248
249
  tempDir,
250
+ workspaceTmpDir,
249
251
  isContinueMode: true,
250
252
  mergeStateStatus,
251
253
  forkedRepo: argv.fork,
@@ -287,6 +289,7 @@ export const executeToolIteration = async params => {
287
289
  prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
288
290
  branchName,
289
291
  tempDir,
292
+ workspaceTmpDir,
290
293
  isContinueMode: true,
291
294
  mergeStateStatus,
292
295
  forkedRepo: argv.fork,
@@ -301,6 +304,48 @@ export const executeToolIteration = async params => {
301
304
  agentPath,
302
305
  $,
303
306
  });
307
+ } else if (argv.tool === 'gemini') {
308
+ // Use Gemini
309
+ const geminiExecLib = await import('./gemini.lib.mjs');
310
+ const { executeGemini, checkPlaywrightMcpAvailability } = geminiExecLib;
311
+ const geminiPath = argv.geminiPath || 'gemini';
312
+
313
+ if (argv.promptPlaywrightMcp) {
314
+ const playwrightMcpAvailable = await checkPlaywrightMcpAvailability();
315
+ if (playwrightMcpAvailable) {
316
+ await log('🎭 Playwright MCP detected - enabling browser automation hints', { verbose: true });
317
+ } else {
318
+ await log('â„šī¸ Playwright MCP not detected - browser automation hints will be disabled', { verbose: true });
319
+ argv.promptPlaywrightMcp = false;
320
+ }
321
+ } else {
322
+ await log('â„šī¸ Playwright MCP explicitly disabled via --no-prompt-playwright-mcp', { verbose: true });
323
+ }
324
+
325
+ toolResult = await executeGemini({
326
+ issueUrl,
327
+ issueNumber,
328
+ prNumber,
329
+ prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
330
+ branchName,
331
+ tempDir,
332
+ workspaceTmpDir,
333
+ isContinueMode: true,
334
+ mergeStateStatus,
335
+ forkedRepo: argv.fork,
336
+ feedbackLines,
337
+ forkActionsUrl: null,
338
+ owner,
339
+ repo,
340
+ argv,
341
+ log,
342
+ setLogFile: () => {},
343
+ getLogFile: () => '',
344
+ formatAligned,
345
+ getResourceSnapshot,
346
+ geminiPath,
347
+ $,
348
+ });
304
349
  } else if (argv.tool === 'qwen') {
305
350
  // Use Qwen Code
306
351
  const qwenExecLib = await import('./qwen.lib.mjs');
@@ -371,6 +416,7 @@ export const executeToolIteration = async params => {
371
416
  prUrl: `https://github.com/${owner}/${repo}/pull/${prNumber}`,
372
417
  branchName,
373
418
  tempDir,
419
+ workspaceTmpDir,
374
420
  isContinueMode: true,
375
421
  mergeStateStatus,
376
422
  forkedRepo: argv.fork,
@@ -46,7 +46,7 @@ export const { buildClaudeResumeCommand, buildClaudeInitialCommand } = claudeCom
46
46
  * @param {Object} options
47
47
  * @param {string} options.issueUrl - The issue URL passed to solve.mjs
48
48
  * @param {string} options.sessionId - The session ID to resume
49
- * @param {string|null} [options.tool] - Tool name (codex, opencode, agent)
49
+ * @param {string|null} [options.tool] - Tool name (codex, opencode, agent, gemini)
50
50
  * @param {string|null} [options.model] - Model name to preserve
51
51
  * @param {string|null} [options.fallbackModel] - Explicit fallback model to preserve
52
52
  * @param {string|null} [options.tempDir] - Working directory to preserve
@@ -303,6 +303,14 @@ export const performSystemChecks = async (minDiskSpace = 2048, skipToolConnectio
303
303
  await log('❌ Cannot proceed without OpenCode connection', { level: 'error' });
304
304
  return false;
305
305
  }
306
+ } else if (argv.tool === 'gemini') {
307
+ // Validate Gemini connection
308
+ const geminiLib = await import('./gemini.lib.mjs');
309
+ isToolConnected = await geminiLib.validateGeminiConnection(model);
310
+ if (!isToolConnected) {
311
+ await log('❌ Cannot proceed without Gemini CLI connection', { level: 'error' });
312
+ return false;
313
+ }
306
314
  } else if (argv.tool === 'codex') {
307
315
  // Validate Codex connection
308
316
  const codexLib = await import('./codex.lib.mjs');
@@ -1,7 +1,7 @@
1
1
  import { buildModelOptionDescription, defaultModels } from './models/index.mjs';
2
2
  import { parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
3
3
 
4
- export const TASK_TOOL_CHOICES = ['claude', 'codex', 'opencode', 'agent'];
4
+ export const TASK_TOOL_CHOICES = ['claude', 'codex', 'opencode', 'agent', 'gemini', 'qwen'];
5
5
 
6
6
  export function getDefaultTaskModel(tool) {
7
7
  return defaultModels[tool] || defaultModels.claude;
package/src/task.mjs CHANGED
@@ -33,7 +33,7 @@ if (earlyArgs.length === 0 || earlyArgs.includes('--help') || earlyArgs.includes
33
33
  console.log(' --only-decompose Only run decomposition mode');
34
34
  console.log(' --split Split a GitHub issue into smaller issues');
35
35
  console.log(' --split-count Number of issues to split into [default: 2]');
36
- console.log(' --tool AI tool for agent-commander read-only mode (claude, codex, opencode, agent, qwen) [default: claude]');
36
+ console.log(' --tool AI tool for agent-commander read-only mode (claude, codex, opencode, agent, gemini, qwen) [default: claude]');
37
37
  console.log(' --model, -m Model to use');
38
38
  console.log(' --isolation agent-commander isolation mode [default: screen]');
39
39
  console.log(' --dry-run Print split output without creating GitHub issues');