@link-assistant/hive-mind 1.62.0 â 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.
- package/CHANGELOG.md +12 -0
- package/README.hi.md +4 -2
- package/README.md +18 -15
- package/README.ru.md +4 -2
- package/README.zh.md +17 -15
- package/package.json +1 -1
- package/src/bidirectional-interactive.lib.mjs +1 -1
- package/src/claude.budget-stats.lib.mjs +49 -30
- package/src/claude.lib.mjs +11 -15
- package/src/config.lib.mjs +1 -0
- package/src/gemini.lib.mjs +611 -0
- package/src/gemini.prompts.lib.mjs +236 -0
- package/src/hive.config.lib.mjs +1 -1
- package/src/interactive-mode.lib.mjs +1 -1
- package/src/models/index.mjs +39 -8
- package/src/solve.config.lib.mjs +4 -4
- package/src/solve.mjs +33 -0
- package/src/solve.restart-shared.lib.mjs +47 -1
- package/src/solve.results.lib.mjs +1 -1
- package/src/solve.validation.lib.mjs +8 -0
- package/src/task.config.lib.mjs +1 -1
- package/src/task.mjs +1 -1
- package/src/telegram-bot.mjs +4 -4
- package/src/telegram-solve-command.lib.mjs +1 -0
- package/src/telegram-solve-queue-command.lib.mjs +1 -1
- package/src/telegram-solve-queue.helpers.lib.mjs +12 -1
- package/src/telegram-solve-queue.lib.mjs +37 -20
- package/src/usage-limit.lib.mjs +1 -1
|
@@ -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
|
+
};
|
package/src/hive.config.lib.mjs
CHANGED
|
@@ -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 => {
|
package/src/models/index.mjs
CHANGED
|
@@ -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:
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -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');
|
package/src/task.config.lib.mjs
CHANGED
|
@@ -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');
|