gemqq 0.5.8
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/LICENSE +21 -0
- package/README.md +74 -0
- package/index.js +304 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Charles McBrian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# gemqq
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/gemqq)
|
|
4
|
+
[](https://github.com/quadrigasoftware/gemqq/actions)
|
|
5
|
+
|
|
6
|
+
Gemini Quick Question is a one-shot wrapper for gemini-cli featuring interactive editor support, markdown rendering in terminal, and real-time token usage statistics. gemqq does not have memory nor context, it simply answers your 'quick questions' quickly.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g gemqq
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
gemqq [OPTIONS] [PROMPT...]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Options
|
|
21
|
+
|
|
22
|
+
- `-e, --edit`: Open prompt in default editor (`EDITOR` or `VISUAL`).
|
|
23
|
+
- `-r, --raw`: Output raw text (disable markdown rendering via `glow`).
|
|
24
|
+
- `-c, --copy`: Copy response to system clipboard.
|
|
25
|
+
- `-m, --model NAME`: Specify a custom model.
|
|
26
|
+
- `--style NAME`: Specify a `glow` style (e.g., `auto`, `dark`, `light`). Default is `auto`.
|
|
27
|
+
- `--no-stats`: Suppress token usage statistics and timing info.
|
|
28
|
+
- `--project`: Enable full project workspace context. By default, `gemqq` isolates file context to zero by running in a temporary directory. Use this flag when you want Gemini to see your codebase.
|
|
29
|
+
- `--pro`: Use `gemini-3-pro-preview` model.
|
|
30
|
+
- `--flash`: Use `gemini-3-flash-preview` model (Default).
|
|
31
|
+
- `--debug`: Enable debug mode.
|
|
32
|
+
- `-h, --help`: Show help message.
|
|
33
|
+
|
|
34
|
+
### Token Statistics
|
|
35
|
+
|
|
36
|
+
By default, `gemqq` displays token usage and execution time:
|
|
37
|
+
`(Done in 5.9s, 4551 tokens (4502i / 2o))`
|
|
38
|
+
|
|
39
|
+
- **i**: Input Tokens (Prompt)
|
|
40
|
+
- **o**: Output Tokens (Candidates)
|
|
41
|
+
|
|
42
|
+
Use `--no-stats` to hide this information.
|
|
43
|
+
|
|
44
|
+
### Context Isolation
|
|
45
|
+
|
|
46
|
+
By default, `gemqq` executes the Gemini CLI in a temporary directory to isolate your file context to zero. This prevents Gemini from automatically snapshotting your current directory tree, which significantly reduces token usage and improves privacy for general queries.
|
|
47
|
+
|
|
48
|
+
If you need Gemini to analyze your codebase or reference local files, use the `--project` flag to run in your current working directory with full context enabled.
|
|
49
|
+
|
|
50
|
+
### Examples
|
|
51
|
+
|
|
52
|
+
```terminaloutput
|
|
53
|
+
gemqq difference between gemini 3.0, 3.1. make a table
|
|
54
|
+
cat file.txt | gemqq summarize this
|
|
55
|
+
gemqq -e --pro
|
|
56
|
+
gemqq C++ operator precedence and keywords
|
|
57
|
+
gemqq how do I update git submodules in parent
|
|
58
|
+
gemqq --pro "Analyze the subtext of Roy's final speech in Blade Runner"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> **Note:** Prompts do not require quotes unless they contain special shell characters like `?`, `*`, `&`, `;`, or `|`. If your prompt includes these, you should either quote it or escape the characters.
|
|
62
|
+
|
|
63
|
+
## Testing
|
|
64
|
+
|
|
65
|
+
The project includes automated integration and unit tests using [Vitest](https://vitest.dev/).
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm test
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Dependencies
|
|
72
|
+
|
|
73
|
+
- [Gemini CLI](https://github.com/google/gemini-cli)
|
|
74
|
+
- [Glow](https://github.com/charmbracelet/glow) (for markdown rendering)
|
package/index.js
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copyright (c) 2026 Charles McBrian
|
|
5
|
+
* Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { program } from 'commander';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import { execa } from 'execa';
|
|
11
|
+
import clipboardy from 'clipboardy';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { tmpdir } from 'os';
|
|
16
|
+
import { spawnSync, spawn } from 'child_process';
|
|
17
|
+
|
|
18
|
+
const __filename = new URL(import.meta.url).pathname;
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
20
|
+
|
|
21
|
+
// Read version from package.json
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
|
|
23
|
+
|
|
24
|
+
// Helper to check command existence
|
|
25
|
+
function commandExists(cmd) {
|
|
26
|
+
try {
|
|
27
|
+
spawnSync(cmd, ['--version'], { stdio: 'ignore' });
|
|
28
|
+
return true;
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const hasGlow = commandExists('glow');
|
|
35
|
+
const hasGemini = commandExists('gemini');
|
|
36
|
+
|
|
37
|
+
program
|
|
38
|
+
.name('gemqq')
|
|
39
|
+
.description("Gemini Quick Question is a one-shot wrapper for gemini-cli featuring interactive editor support, markdown rendering in terminal, and real-time token usage statistics. gemqq does not have memory nor context, it simply answers your 'quick questions' quickly.")
|
|
40
|
+
.version(pkg.version)
|
|
41
|
+
.argument('[prompt...]', 'Prompt for the model')
|
|
42
|
+
.option('-e, --edit', 'Open prompt in default editor')
|
|
43
|
+
.option('-r, --raw', 'Output raw text (disable markdown rendering)')
|
|
44
|
+
.option('-c, --copy', 'Copy response to system clipboard')
|
|
45
|
+
.option('-m, --model <name>', 'Specify a custom model')
|
|
46
|
+
.option('--style <name>', 'Specify a glow style (e.g., auto, dark, light)', 'auto')
|
|
47
|
+
.option('--no-stats', 'Do not show token usage statistics')
|
|
48
|
+
.option('--project', 'Enable full project workspace context (may send more data)')
|
|
49
|
+
.option('--pro', 'Use gemini-3-pro-preview model')
|
|
50
|
+
.option('--flash', 'Use gemini-3-flash-preview model (Default)')
|
|
51
|
+
.option('--debug', 'Enable debug mode')
|
|
52
|
+
.addHelpText('after', `
|
|
53
|
+
Examples:
|
|
54
|
+
gemqq difference between gemini 3.0, 3.1. make a table
|
|
55
|
+
cat file.txt | gemqq summarize this
|
|
56
|
+
gemqq -e --pro
|
|
57
|
+
gemqq C++ operator precedence and keywords
|
|
58
|
+
gemqq how do I update git submodules in parent
|
|
59
|
+
gemqq --pro "Analyze the subtext of Roy's final speech in Blade Runner"
|
|
60
|
+
`)
|
|
61
|
+
.action(async (promptParts, options) => {
|
|
62
|
+
let currentTempDir = null;
|
|
63
|
+
let currentSpinner = null;
|
|
64
|
+
const isTest = process.env.NODE_ENV === 'test';
|
|
65
|
+
|
|
66
|
+
const cleanup = () => {
|
|
67
|
+
if (currentSpinner && !isTest) {
|
|
68
|
+
currentSpinner.stop();
|
|
69
|
+
}
|
|
70
|
+
if (currentTempDir && fs.existsSync(currentTempDir)) {
|
|
71
|
+
try {
|
|
72
|
+
fs.rmSync(currentTempDir, { recursive: true, force: true });
|
|
73
|
+
} catch (e) {}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const signalHandler = () => {
|
|
78
|
+
cleanup();
|
|
79
|
+
process.exit(130);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
process.on('SIGINT', signalHandler);
|
|
83
|
+
process.on('SIGTERM', signalHandler);
|
|
84
|
+
|
|
85
|
+
if (!hasGemini) {
|
|
86
|
+
cleanup();
|
|
87
|
+
process.off('SIGINT', signalHandler);
|
|
88
|
+
process.off('SIGTERM', signalHandler);
|
|
89
|
+
console.error(chalk.bold('Error:') + " 'gemini' CLI not found.");
|
|
90
|
+
console.error("Please install it using npm:\n");
|
|
91
|
+
console.error(chalk.bold(" npm install -g @google/gemini-cli\n"));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let initialPrompt = promptParts.join(' ');
|
|
96
|
+
let pipedInput = '';
|
|
97
|
+
|
|
98
|
+
if (!process.stdin.isTTY && (process.env.NODE_ENV !== 'test' || process.env.HAS_PIPED_INPUT)) {
|
|
99
|
+
// Read from stdin
|
|
100
|
+
const chunks = [];
|
|
101
|
+
try {
|
|
102
|
+
for await (const chunk of process.stdin) {
|
|
103
|
+
chunks.push(chunk);
|
|
104
|
+
}
|
|
105
|
+
pipedInput = Buffer.concat(chunks).toString();
|
|
106
|
+
} catch (e) {
|
|
107
|
+
if (options.debug) console.error(chalk.red('[DEBUG] Stdin read error:'), e);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!initialPrompt && !pipedInput && !options.edit) {
|
|
112
|
+
program.help();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let fullPrompt = initialPrompt;
|
|
117
|
+
if (pipedInput) {
|
|
118
|
+
if (fullPrompt) {
|
|
119
|
+
fullPrompt = `${fullPrompt}
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
${pipedInput}`;
|
|
123
|
+
} else {
|
|
124
|
+
fullPrompt = pipedInput;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (options.edit) {
|
|
129
|
+
const tmpFile = path.join(tmpdir(), `gemqq-prompt-${Date.now()}.txt`);
|
|
130
|
+
fs.writeFileSync(tmpFile, fullPrompt || '');
|
|
131
|
+
|
|
132
|
+
const editor = process.env.EDITOR || process.env.VISUAL || 'nano';
|
|
133
|
+
spawnSync(editor, [tmpFile], { stdio: 'inherit' });
|
|
134
|
+
|
|
135
|
+
const editedPrompt = fs.readFileSync(tmpFile, 'utf8').trim();
|
|
136
|
+
if (editedPrompt !== (fullPrompt || '').trim()) {
|
|
137
|
+
console.error(chalk.gray(`--- Updated Prompt ---
|
|
138
|
+
${editedPrompt}
|
|
139
|
+
----------------------
|
|
140
|
+
`));
|
|
141
|
+
}
|
|
142
|
+
fullPrompt = editedPrompt;
|
|
143
|
+
fs.unlinkSync(tmpFile);
|
|
144
|
+
} else {
|
|
145
|
+
if (fullPrompt) {
|
|
146
|
+
fullPrompt = `${fullPrompt}. Do not tell me what you are doing, only provide the answer.`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!fullPrompt && !options.edit) {
|
|
151
|
+
program.help();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const allowedTools = ['*'];
|
|
156
|
+
|
|
157
|
+
const model = options.model || (options.pro ? 'gemini-3-pro-preview' : 'gemini-3-flash-preview');
|
|
158
|
+
|
|
159
|
+
const args = ['-s', '--allowed-tools', JSON.stringify(allowedTools), '--model', model, '--output-format', 'json'];
|
|
160
|
+
if (options.debug) args.push('-d');
|
|
161
|
+
args.push(fullPrompt);
|
|
162
|
+
|
|
163
|
+
if (options.debug) {
|
|
164
|
+
console.error(chalk.bold('[DEBUG] Executing:') + ` gemini ${args.map(a => `'${a}'`).join(' ')}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
currentSpinner = isTest ? { start: () => currentSpinner, stop: () => {} } : ora('Gemini is thinking...').start();
|
|
168
|
+
const startTime = Date.now();
|
|
169
|
+
|
|
170
|
+
let sysPromptFile = null;
|
|
171
|
+
if (!options.project) {
|
|
172
|
+
try {
|
|
173
|
+
currentTempDir = fs.mkdtempSync(path.join(tmpdir(), 'gemqq-run-'));
|
|
174
|
+
sysPromptFile = path.join(currentTempDir, `gemqq-sysprompt-${Date.now()}.md`);
|
|
175
|
+
fs.writeFileSync(sysPromptFile, 'You are a helpful AI assistant. Answer the user\'s prompt concisely. Do not tell me what you are doing. Do not use this directory or any local context. Do not upload any local context.');
|
|
176
|
+
} catch (e) {
|
|
177
|
+
if (options.debug) console.error(chalk.red('[DEBUG] Failed to create isolation directory:'), e);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const execEnv = {
|
|
183
|
+
...process.env,
|
|
184
|
+
FORCE_COLOR: 'true'
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Apply the system prompt override to bypass workspace snapshotting
|
|
188
|
+
if (sysPromptFile) {
|
|
189
|
+
execEnv.GEMINI_SYSTEM_MD = sysPromptFile;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const { stdout, stderr } = await execa('gemini', args, {
|
|
193
|
+
env: execEnv,
|
|
194
|
+
cwd: currentTempDir || process.cwd()
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
cleanup();
|
|
198
|
+
|
|
199
|
+
if (stderr) {
|
|
200
|
+
const filteredStderr = stderr
|
|
201
|
+
.split('\n')
|
|
202
|
+
.filter(line => !line.match(/Loaded cached credentials|Hook registry initialized|Error executing tool/))
|
|
203
|
+
.join('\n');
|
|
204
|
+
if (filteredStderr) console.error(filteredStderr);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let modelOutput = stdout;
|
|
208
|
+
let statsString = '';
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const result = JSON.parse(stdout);
|
|
212
|
+
modelOutput = result.response || '';
|
|
213
|
+
|
|
214
|
+
if (result.stats && result.stats.models) {
|
|
215
|
+
let promptTokens = 0;
|
|
216
|
+
let candidateTokens = 0;
|
|
217
|
+
let totalTokens = 0;
|
|
218
|
+
let cachedTokens = 0;
|
|
219
|
+
|
|
220
|
+
for (const modelKey in result.stats.models) {
|
|
221
|
+
const m = result.stats.models[modelKey];
|
|
222
|
+
if (m.tokens) {
|
|
223
|
+
promptTokens += m.tokens.prompt || 0;
|
|
224
|
+
candidateTokens += m.tokens.candidates || 0;
|
|
225
|
+
totalTokens += m.tokens.total || 0;
|
|
226
|
+
cachedTokens += m.tokens.cached || 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
statsString = `, ${totalTokens} tokens (${promptTokens}i / ${candidateTokens}o`;
|
|
231
|
+
if (cachedTokens > 0) {
|
|
232
|
+
statsString += `, ${cachedTokens} cached`;
|
|
233
|
+
}
|
|
234
|
+
statsString += ')';
|
|
235
|
+
}
|
|
236
|
+
} catch (e) {
|
|
237
|
+
if (options.debug) {
|
|
238
|
+
console.error(chalk.red('[DEBUG] Failed to parse JSON output:'), e);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
243
|
+
|
|
244
|
+
let statusMsg = ` (Done in ${elapsed}s${statsString})`;
|
|
245
|
+
if (options.copy) {
|
|
246
|
+
try {
|
|
247
|
+
await clipboardy.write(modelOutput);
|
|
248
|
+
statusMsg = ` (Copied to clipboard, ${elapsed}s${statsString})`;
|
|
249
|
+
} catch (e) {
|
|
250
|
+
statusMsg = ` (Failed to copy to clipboard, ${elapsed}s${statsString})`;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (options.stats) {
|
|
255
|
+
console.error(chalk.gray(statusMsg));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (options.raw || !hasGlow) {
|
|
259
|
+
process.stdout.write(modelOutput);
|
|
260
|
+
} else {
|
|
261
|
+
// Render with glow
|
|
262
|
+
try {
|
|
263
|
+
await execa('glow', ['--style', options.style], {
|
|
264
|
+
input: modelOutput,
|
|
265
|
+
stdout: 'inherit',
|
|
266
|
+
stderr: 'inherit'
|
|
267
|
+
});
|
|
268
|
+
} catch (glowError) {
|
|
269
|
+
if (options.debug) {
|
|
270
|
+
console.error(chalk.red('[DEBUG] Glow failed:'), glowError);
|
|
271
|
+
}
|
|
272
|
+
process.stdout.write(modelOutput);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} catch (error) {
|
|
276
|
+
cleanup();
|
|
277
|
+
|
|
278
|
+
if (error.signal === 'SIGINT' || error.signal === 'SIGTERM') {
|
|
279
|
+
process.exit(130);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Filter stderr similar to bash script
|
|
283
|
+
const filteredStderr = (error.stderr || '')
|
|
284
|
+
.split('\n')
|
|
285
|
+
.filter(line => !line.match(/Loaded cached credentials|Hook registry initialized|Error executing tool/))
|
|
286
|
+
.join('\n');
|
|
287
|
+
|
|
288
|
+
const stderrLower = filteredStderr.toLowerCase();
|
|
289
|
+
// Check for common authentication error keywords
|
|
290
|
+
if (stderrLower.includes('login') || stderrLower.includes('authenticate') || stderrLower.includes('credentials')) {
|
|
291
|
+
console.error(chalk.red('\nAuthentication Error:'));
|
|
292
|
+
console.error('It appears you are not logged in or your credentials have expired.');
|
|
293
|
+
console.error('Please run the following command to log in:');
|
|
294
|
+
console.error(chalk.bold('\n gemini login\n'));
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
console.error(chalk.red('\nError calling Gemini CLI:'));
|
|
299
|
+
console.error(filteredStderr || error.message);
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gemqq",
|
|
3
|
+
"version": "0.5.8",
|
|
4
|
+
"description": "Gemini Quick Question is a one-shot CLI wrapper for Google's Gemini, featuring interactive editor support, markdown rendering, and real-time token usage statistics. gemqq does not have memory nor context, it simply answers your 'quick questions' and prompts.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gemqq": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/quadrigasoftware/gemqq.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/quadrigasoftware/gemqq/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/quadrigasoftware/gemqq#readme",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20.0.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "vitest run"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"gemini",
|
|
34
|
+
"google-gemini",
|
|
35
|
+
"cli",
|
|
36
|
+
"ai",
|
|
37
|
+
"llm",
|
|
38
|
+
"wrapper",
|
|
39
|
+
"markdown",
|
|
40
|
+
"terminal",
|
|
41
|
+
"productivity",
|
|
42
|
+
"developer-tools",
|
|
43
|
+
"one-shot"
|
|
44
|
+
],
|
|
45
|
+
"author": "Charles McBrian",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"sideEffects": false,
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"chalk": "^5.6.2",
|
|
50
|
+
"clipboardy": "^5.3.0",
|
|
51
|
+
"commander": "^14.0.3",
|
|
52
|
+
"execa": "^9.6.1",
|
|
53
|
+
"ora": "^9.3.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"vitest": "^4.0.18"
|
|
57
|
+
}
|
|
58
|
+
}
|