oh-my-customcode 0.157.1 → 0.159.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/README.md +4 -4
- package/dist/cli/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/rules/MUST-agent-design.md +1 -1
- package/templates/.claude/rules/MUST-agent-teams.md +1 -16
- package/templates/.claude/skills/de-lead-routing/SKILL.md +1 -21
- package/templates/.claude/skills/dev-lead-routing/SKILL.md +1 -21
- package/templates/.claude/skills/intent-detection/SKILL.md +3 -9
- package/templates/.claude/skills/intent-detection/patterns/agent-triggers.yaml +3 -12
- package/templates/.claude/skills/research/SKILL.md +8 -35
- package/templates/.claude/skills/roundtable-debate/SKILL.md +6 -7
- package/templates/.claude/skills/structured-dev-cycle/SKILL.md +1 -12
- package/templates/CLAUDE.md +3 -2
- package/templates/guides/agent-design/google-agents-cli-patterns.md +1 -2
- package/templates/guides/multi-agent-debate-patterns/README.md +1 -10
- package/templates/guides/multi-provider-exec/README.md +2 -15
- package/templates/manifest.json +2 -2
- package/templates/.claude/skills/agora/SKILL.md +0 -288
- package/templates/.claude/skills/codex-exec/SKILL.md +0 -259
- package/templates/.claude/skills/codex-exec/scripts/codex-wrapper.cjs +0 -430
- package/templates/.claude/skills/gemini-exec/SKILL.md +0 -215
- package/templates/.claude/skills/gemini-exec/scripts/gemini-wrapper.cjs +0 -485
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* codex-wrapper.js
|
|
5
|
-
*
|
|
6
|
-
* Node.js wrapper for OpenAI Codex CLI (non-interactive execution).
|
|
7
|
-
* Executes codex in ephemeral mode with structured JSON output.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* node codex-wrapper.js --prompt "your prompt" [options]
|
|
11
|
-
*
|
|
12
|
-
* Options:
|
|
13
|
-
* --prompt <text> Required: prompt to execute
|
|
14
|
-
* --json Enable JSON Lines output from codex
|
|
15
|
-
* --output <path> Save final message to file
|
|
16
|
-
* --model <name> Specify model (default: o3)
|
|
17
|
-
* --timeout <ms> Execution timeout in milliseconds (default: 120000, max: 600000)
|
|
18
|
-
* --full-auto Use full-auto approval mode (default: -a never)
|
|
19
|
-
* --working-dir <dir> Set working directory for execution
|
|
20
|
-
*
|
|
21
|
-
* Output (JSON to stdout):
|
|
22
|
-
* Success: { "success": true, "output": "...", "duration_ms": 1234, ... }
|
|
23
|
-
* Failure: { "success": false, "error": "...", "stderr": "...", ... }
|
|
24
|
-
*
|
|
25
|
-
* Exit codes:
|
|
26
|
-
* 0 = success
|
|
27
|
-
* 1 = execution error
|
|
28
|
-
* 2 = validation error (missing binary/auth)
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
const { spawn, execFileSync } = require('child_process');
|
|
32
|
-
const fs = require('fs');
|
|
33
|
-
const path = require('path');
|
|
34
|
-
const os = require('os');
|
|
35
|
-
|
|
36
|
-
// Configuration
|
|
37
|
-
const DEFAULT_TIMEOUT_MS = 120000; // 2 minutes
|
|
38
|
-
const MAX_TIMEOUT_MS = 600000; // 10 minutes
|
|
39
|
-
const KILL_GRACE_PERIOD_MS = 5000; // 5 seconds for graceful shutdown
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Parse command line arguments
|
|
43
|
-
* @returns {Object} Parsed arguments
|
|
44
|
-
*/
|
|
45
|
-
function parseArgs() {
|
|
46
|
-
const args = {
|
|
47
|
-
prompt: null,
|
|
48
|
-
json: false,
|
|
49
|
-
output: null,
|
|
50
|
-
model: null,
|
|
51
|
-
timeout: DEFAULT_TIMEOUT_MS,
|
|
52
|
-
fullAuto: false,
|
|
53
|
-
workingDir: null,
|
|
54
|
-
effort: null,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
for (let i = 2; i < process.argv.length; i++) {
|
|
58
|
-
const arg = process.argv[i];
|
|
59
|
-
|
|
60
|
-
switch (arg) {
|
|
61
|
-
case '--prompt':
|
|
62
|
-
if (i + 1 < process.argv.length) {
|
|
63
|
-
args.prompt = process.argv[++i];
|
|
64
|
-
}
|
|
65
|
-
break;
|
|
66
|
-
case '--json':
|
|
67
|
-
args.json = true;
|
|
68
|
-
break;
|
|
69
|
-
case '--output':
|
|
70
|
-
if (i + 1 < process.argv.length) {
|
|
71
|
-
args.output = process.argv[++i];
|
|
72
|
-
}
|
|
73
|
-
break;
|
|
74
|
-
case '--model':
|
|
75
|
-
if (i + 1 < process.argv.length) {
|
|
76
|
-
args.model = process.argv[++i];
|
|
77
|
-
}
|
|
78
|
-
break;
|
|
79
|
-
case '--timeout':
|
|
80
|
-
if (i + 1 < process.argv.length) {
|
|
81
|
-
const timeoutValue = parseInt(process.argv[++i], 10);
|
|
82
|
-
if (!isNaN(timeoutValue)) {
|
|
83
|
-
args.timeout = Math.min(timeoutValue, MAX_TIMEOUT_MS);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
break;
|
|
87
|
-
case '--full-auto':
|
|
88
|
-
args.fullAuto = true;
|
|
89
|
-
break;
|
|
90
|
-
case '--working-dir':
|
|
91
|
-
if (i + 1 < process.argv.length) {
|
|
92
|
-
args.workingDir = process.argv[++i];
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
case '--effort':
|
|
96
|
-
case '--reasoning-effort':
|
|
97
|
-
if (i + 1 < process.argv.length) {
|
|
98
|
-
args.effort = process.argv[++i];
|
|
99
|
-
}
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return args;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Validate environment for codex execution
|
|
109
|
-
* @returns {Object} Validation result { valid: boolean, errors: string[] }
|
|
110
|
-
*/
|
|
111
|
-
function validateEnvironment() {
|
|
112
|
-
const errors = [];
|
|
113
|
-
|
|
114
|
-
// Check for codex binary
|
|
115
|
-
try {
|
|
116
|
-
execFileSync('which', ['codex'], { stdio: 'pipe' });
|
|
117
|
-
} catch (error) {
|
|
118
|
-
// Try common installation paths
|
|
119
|
-
const commonPaths = [
|
|
120
|
-
'/usr/local/bin/codex',
|
|
121
|
-
path.join(os.homedir(), '.local', 'bin', 'codex'),
|
|
122
|
-
path.join(os.homedir(), 'bin', 'codex'),
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
const codexExists = commonPaths.some(p => fs.existsSync(p));
|
|
126
|
-
if (!codexExists) {
|
|
127
|
-
errors.push('codex binary not found in PATH or common locations');
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Note: OPENAI_API_KEY is optional if codex has its own stored auth (via `codex auth`)
|
|
132
|
-
if (!process.env.OPENAI_API_KEY) {
|
|
133
|
-
console.error('[codex-wrapper] Note: OPENAI_API_KEY not set, relying on codex built-in auth');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
valid: errors.length === 0,
|
|
138
|
-
errors,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Build codex command array
|
|
144
|
-
* @param {Object} options - Command options
|
|
145
|
-
* @returns {Object} Command structure { binary: string, args: string[] }
|
|
146
|
-
*/
|
|
147
|
-
function buildCommand(options) {
|
|
148
|
-
const args = ['exec', '--ephemeral'];
|
|
149
|
-
|
|
150
|
-
// Approval mode (default: normal, --full-auto: automatic execution)
|
|
151
|
-
if (options.fullAuto) {
|
|
152
|
-
args.push('--full-auto');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// JSON output
|
|
156
|
-
if (options.json) {
|
|
157
|
-
args.push('--json');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Model selection
|
|
161
|
-
if (options.model) {
|
|
162
|
-
args.push('--model', options.model);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Working directory
|
|
166
|
-
if (options.workingDir) {
|
|
167
|
-
args.push('-C', options.workingDir);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Reasoning effort (maps to -c model_reasoning_effort="value")
|
|
171
|
-
if (options.effort) {
|
|
172
|
-
const validEfforts = ['minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
173
|
-
if (validEfforts.includes(options.effort)) {
|
|
174
|
-
args.push('-c', `model_reasoning_effort="${options.effort}"`);
|
|
175
|
-
} else {
|
|
176
|
-
process.stderr.write(`Warning: Invalid effort level "${options.effort}". Valid: ${validEfforts.join(', ')}\n`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Add prompt as last argument
|
|
181
|
-
args.push(options.prompt);
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
binary: 'codex',
|
|
185
|
-
args,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Execute codex command
|
|
191
|
-
* @param {string} binary - Binary to execute
|
|
192
|
-
* @param {string[]} args - Command arguments
|
|
193
|
-
* @param {number} timeout - Timeout in milliseconds
|
|
194
|
-
* @param {string|null} workingDir - Working directory
|
|
195
|
-
* @returns {Promise<Object>} Execution result
|
|
196
|
-
*/
|
|
197
|
-
function executeCodex(binary, args, timeout, workingDir = null) {
|
|
198
|
-
return new Promise((resolve) => {
|
|
199
|
-
const startTime = Date.now();
|
|
200
|
-
let stdout = '';
|
|
201
|
-
let stderr = '';
|
|
202
|
-
let timedOut = false;
|
|
203
|
-
|
|
204
|
-
const spawnOptions = {
|
|
205
|
-
cwd: workingDir || process.cwd(),
|
|
206
|
-
env: process.env,
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const child = spawn(binary, args, spawnOptions);
|
|
210
|
-
|
|
211
|
-
// Collect output
|
|
212
|
-
child.stdout.on('data', (data) => {
|
|
213
|
-
stdout += data.toString();
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
child.stderr.on('data', (data) => {
|
|
217
|
-
stderr += data.toString();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Set timeout
|
|
221
|
-
const timeoutHandle = setTimeout(() => {
|
|
222
|
-
timedOut = true;
|
|
223
|
-
console.error('[codex-wrapper] Timeout reached, terminating process...', { file: 'stderr' });
|
|
224
|
-
|
|
225
|
-
// Graceful termination attempt
|
|
226
|
-
child.kill('SIGTERM');
|
|
227
|
-
|
|
228
|
-
// Force kill after grace period
|
|
229
|
-
setTimeout(() => {
|
|
230
|
-
if (!child.killed) {
|
|
231
|
-
console.error('[codex-wrapper] Force killing process...', { file: 'stderr' });
|
|
232
|
-
child.kill('SIGKILL');
|
|
233
|
-
}
|
|
234
|
-
}, KILL_GRACE_PERIOD_MS);
|
|
235
|
-
}, timeout);
|
|
236
|
-
|
|
237
|
-
// Handle process exit
|
|
238
|
-
child.on('close', (exitCode) => {
|
|
239
|
-
clearTimeout(timeoutHandle);
|
|
240
|
-
const durationMs = Date.now() - startTime;
|
|
241
|
-
|
|
242
|
-
resolve({
|
|
243
|
-
exitCode: exitCode !== null ? exitCode : 1,
|
|
244
|
-
stdout,
|
|
245
|
-
stderr,
|
|
246
|
-
timedOut,
|
|
247
|
-
durationMs,
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// Handle spawn errors
|
|
252
|
-
child.on('error', (error) => {
|
|
253
|
-
clearTimeout(timeoutHandle);
|
|
254
|
-
const durationMs = Date.now() - startTime;
|
|
255
|
-
|
|
256
|
-
resolve({
|
|
257
|
-
exitCode: 1,
|
|
258
|
-
stdout,
|
|
259
|
-
stderr: stderr + '\nSpawn error: ' + error.message,
|
|
260
|
-
timedOut: false,
|
|
261
|
-
durationMs,
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Parse JSON Lines output from codex
|
|
269
|
-
* @param {string} output - Raw output string
|
|
270
|
-
* @returns {Object} Parsed result { events: object[], finalMessage: string|null, parseErrors: string[] }
|
|
271
|
-
*/
|
|
272
|
-
function parseJsonLines(output) {
|
|
273
|
-
const lines = output.split('\n').filter(line => line.trim().length > 0);
|
|
274
|
-
const events = [];
|
|
275
|
-
const parseErrors = [];
|
|
276
|
-
let finalMessage = null;
|
|
277
|
-
|
|
278
|
-
for (const line of lines) {
|
|
279
|
-
try {
|
|
280
|
-
const event = JSON.parse(line);
|
|
281
|
-
events.push(event);
|
|
282
|
-
|
|
283
|
-
// Codex CLI v0.99.0 format: item.completed events with agent_message type
|
|
284
|
-
if (event.type === 'item.completed' && event.item) {
|
|
285
|
-
if (event.item.type === 'agent_message' && event.item.text) {
|
|
286
|
-
finalMessage = event.item.text;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
// Look for assistant message in various event structures (fallback for future API changes)
|
|
290
|
-
else if (event.type === 'assistant_message' && event.content) {
|
|
291
|
-
finalMessage = event.content;
|
|
292
|
-
} else if (event.message && event.message.role === 'assistant') {
|
|
293
|
-
finalMessage = event.message.content || event.message.text;
|
|
294
|
-
} else if (event.role === 'assistant' && event.content) {
|
|
295
|
-
finalMessage = event.content;
|
|
296
|
-
}
|
|
297
|
-
} catch (error) {
|
|
298
|
-
parseErrors.push(`Failed to parse line: ${error.message}`);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
events,
|
|
304
|
-
finalMessage,
|
|
305
|
-
parseErrors,
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Main execution function
|
|
311
|
-
*/
|
|
312
|
-
async function main() {
|
|
313
|
-
const args = parseArgs();
|
|
314
|
-
|
|
315
|
-
// Validate required arguments
|
|
316
|
-
if (!args.prompt) {
|
|
317
|
-
const result = {
|
|
318
|
-
success: false,
|
|
319
|
-
error: 'Missing required argument: --prompt',
|
|
320
|
-
exit_code: 2,
|
|
321
|
-
};
|
|
322
|
-
console.log(JSON.stringify(result, null, 2));
|
|
323
|
-
process.exit(2);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Validate environment
|
|
327
|
-
const validation = validateEnvironment();
|
|
328
|
-
if (!validation.valid) {
|
|
329
|
-
const result = {
|
|
330
|
-
success: false,
|
|
331
|
-
error: 'Environment validation failed',
|
|
332
|
-
validation_errors: validation.errors,
|
|
333
|
-
exit_code: 2,
|
|
334
|
-
};
|
|
335
|
-
console.log(JSON.stringify(result, null, 2));
|
|
336
|
-
process.exit(2);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
console.error(`[codex-wrapper] Executing codex with timeout: ${args.timeout}ms`);
|
|
340
|
-
if (args.workingDir) {
|
|
341
|
-
console.error(`[codex-wrapper] Working directory: ${args.workingDir}`);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Build command
|
|
345
|
-
const command = buildCommand(args);
|
|
346
|
-
console.error(`[codex-wrapper] Command: ${command.binary} ${command.args.join(' ')}`);
|
|
347
|
-
|
|
348
|
-
// Execute
|
|
349
|
-
const execResult = await executeCodex(
|
|
350
|
-
command.binary,
|
|
351
|
-
command.args,
|
|
352
|
-
args.timeout,
|
|
353
|
-
args.workingDir
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
// Process result
|
|
357
|
-
let output = null;
|
|
358
|
-
let eventsCount = 0;
|
|
359
|
-
|
|
360
|
-
if (args.json && execResult.stdout) {
|
|
361
|
-
const parsed = parseJsonLines(execResult.stdout);
|
|
362
|
-
eventsCount = parsed.events.length;
|
|
363
|
-
output = parsed.finalMessage;
|
|
364
|
-
|
|
365
|
-
if (parsed.parseErrors.length > 0) {
|
|
366
|
-
console.error('[codex-wrapper] JSON parse errors:', parsed.parseErrors.join('; '));
|
|
367
|
-
}
|
|
368
|
-
} else {
|
|
369
|
-
output = execResult.stdout.trim();
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Determine success
|
|
373
|
-
const success = execResult.exitCode === 0 && !execResult.timedOut;
|
|
374
|
-
|
|
375
|
-
// Build result object
|
|
376
|
-
const result = {
|
|
377
|
-
success,
|
|
378
|
-
duration_ms: execResult.durationMs,
|
|
379
|
-
exit_code: execResult.exitCode,
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
if (success) {
|
|
383
|
-
result.output = output || execResult.stdout;
|
|
384
|
-
result.model = args.model || 'o3';
|
|
385
|
-
if (args.json) {
|
|
386
|
-
result.events_count = eventsCount;
|
|
387
|
-
}
|
|
388
|
-
} else {
|
|
389
|
-
if (execResult.timedOut) {
|
|
390
|
-
result.error = `Execution timed out after ${args.timeout}ms`;
|
|
391
|
-
} else {
|
|
392
|
-
result.error = 'Execution failed';
|
|
393
|
-
}
|
|
394
|
-
if (execResult.stderr) {
|
|
395
|
-
result.stderr = execResult.stderr.trim();
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// Write output file if requested
|
|
400
|
-
if (args.output && output) {
|
|
401
|
-
try {
|
|
402
|
-
const outputDir = path.dirname(args.output);
|
|
403
|
-
if (!fs.existsSync(outputDir)) {
|
|
404
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
405
|
-
}
|
|
406
|
-
fs.writeFileSync(args.output, output, 'utf-8');
|
|
407
|
-
console.error(`[codex-wrapper] Output written to: ${args.output}`);
|
|
408
|
-
} catch (error) {
|
|
409
|
-
console.error(`[codex-wrapper] Failed to write output file: ${error.message}`);
|
|
410
|
-
result.output_file_error = error.message;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// Output JSON result to stdout
|
|
415
|
-
console.log(JSON.stringify(result, null, 2));
|
|
416
|
-
|
|
417
|
-
process.exit(result.exit_code);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Run
|
|
421
|
-
main().catch(error => {
|
|
422
|
-
const result = {
|
|
423
|
-
success: false,
|
|
424
|
-
error: 'Unexpected error: ' + error.message,
|
|
425
|
-
stack: error.stack,
|
|
426
|
-
exit_code: 1,
|
|
427
|
-
};
|
|
428
|
-
console.log(JSON.stringify(result, null, 2));
|
|
429
|
-
process.exit(1);
|
|
430
|
-
});
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gemini-exec
|
|
3
|
-
description: Execute Gemini CLI prompts and return results
|
|
4
|
-
scope: core
|
|
5
|
-
argument-hint: "<prompt> [--json] [--stream-json] [--output <path>] [--model <name>] [--timeout <ms>] [--sandbox] [--plan]"
|
|
6
|
-
user-invocable: true
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Gemini Exec Skill
|
|
10
|
-
|
|
11
|
-
Execute Google Gemini CLI prompts in non-interactive mode and return structured results. Enables Claude + Gemini hybrid workflows.
|
|
12
|
-
|
|
13
|
-
## Options
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
<prompt> Required. The prompt to send to Gemini CLI
|
|
17
|
-
--json Return structured JSON output (-o json)
|
|
18
|
-
--stream-json Return streaming JSON events (-o stream-json)
|
|
19
|
-
--output <path> Save response to file
|
|
20
|
-
--model <name> Model override (default: Gemini CLI default)
|
|
21
|
-
--timeout <ms> Execution timeout (default: 120000, max: 600000)
|
|
22
|
-
--yolo Enable auto-approval mode (gemini -y)
|
|
23
|
-
--sandbox Run in sandbox mode (gemini -s)
|
|
24
|
-
--plan Use plan approval mode (--approval-mode plan)
|
|
25
|
-
--working-dir Working directory for Gemini execution
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Workflow
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
1. Pre-checks
|
|
32
|
-
- Verify `gemini` binary is installed (which gemini)
|
|
33
|
-
- Verify authentication (GOOGLE_API_KEY, GEMINI_API_KEY, or gcloud auth)
|
|
34
|
-
2. Build command
|
|
35
|
-
- Base: gemini -p "<prompt>"
|
|
36
|
-
- Apply options: -o json, -m <model>, -y, -s, --approval-mode plan
|
|
37
|
-
3. Execute
|
|
38
|
-
- Run via Bash tool with timeout (default 2min, max 10min)
|
|
39
|
-
- Or use helper script: node .claude/skills/gemini-exec/scripts/gemini-wrapper.cjs
|
|
40
|
-
4. Parse output
|
|
41
|
-
- Text mode: return raw stdout
|
|
42
|
-
- JSON mode: parse single JSON object, extract response field
|
|
43
|
-
- Stream-JSON mode: parse event stream, extract final assistant message
|
|
44
|
-
5. Report results
|
|
45
|
-
- Format output with execution metadata
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Safety Defaults
|
|
49
|
-
|
|
50
|
-
- `-p` flag: Non-interactive prompt mode (no session persistence)
|
|
51
|
-
- Default mode: Normal approval (Gemini prompts for confirmation)
|
|
52
|
-
- Override with `--yolo` only when explicitly requested
|
|
53
|
-
- Sandbox mode (`-s`) available for isolated execution
|
|
54
|
-
|
|
55
|
-
## Output Format
|
|
56
|
-
|
|
57
|
-
### Success (Text Mode)
|
|
58
|
-
```
|
|
59
|
-
[Gemini Exec] Completed
|
|
60
|
-
|
|
61
|
-
Model: (default)
|
|
62
|
-
Duration: 23.4s
|
|
63
|
-
Working Dir: /path/to/project
|
|
64
|
-
|
|
65
|
-
--- Output ---
|
|
66
|
-
{gemini response text}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Success (JSON Mode)
|
|
70
|
-
```
|
|
71
|
-
[Gemini Exec] Completed (JSON)
|
|
72
|
-
|
|
73
|
-
Model: (default)
|
|
74
|
-
Duration: 23.4s
|
|
75
|
-
|
|
76
|
-
--- Response ---
|
|
77
|
-
{extracted response from JSON}
|
|
78
|
-
|
|
79
|
-
--- Stats ---
|
|
80
|
-
{token usage and other stats}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Success (Stream-JSON Mode)
|
|
84
|
-
```
|
|
85
|
-
[Gemini Exec] Completed (Stream-JSON)
|
|
86
|
-
|
|
87
|
-
Model: (default)
|
|
88
|
-
Duration: 23.4s
|
|
89
|
-
Events: 12
|
|
90
|
-
|
|
91
|
-
--- Final Message ---
|
|
92
|
-
{extracted final assistant message}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Failure
|
|
96
|
-
```
|
|
97
|
-
[Gemini Exec] Failed
|
|
98
|
-
|
|
99
|
-
Error: {error_message}
|
|
100
|
-
Exit Code: {code}
|
|
101
|
-
Suggested Fix: {suggestion}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Helper Script
|
|
105
|
-
|
|
106
|
-
For complex executions, use the wrapper script:
|
|
107
|
-
```bash
|
|
108
|
-
node .claude/skills/gemini-exec/scripts/gemini-wrapper.cjs --prompt "your prompt" [options]
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
The wrapper provides:
|
|
112
|
-
- Environment validation (binary + auth checks)
|
|
113
|
-
- Safe command construction
|
|
114
|
-
- JSON and stream-JSON parsing with response extraction
|
|
115
|
-
- Structured JSON output
|
|
116
|
-
- Timeout handling with graceful termination
|
|
117
|
-
|
|
118
|
-
## Examples
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
# Simple text prompt
|
|
122
|
-
gemini-exec "explain what this project does"
|
|
123
|
-
|
|
124
|
-
# JSON output with model override
|
|
125
|
-
gemini-exec "list all TODO items" --json --model gemini-2.5-pro
|
|
126
|
-
|
|
127
|
-
# Stream-JSON for detailed event tracking
|
|
128
|
-
gemini-exec "analyze the codebase" --stream-json
|
|
129
|
-
|
|
130
|
-
# Save output to file
|
|
131
|
-
gemini-exec "generate a README" --output ./README.md
|
|
132
|
-
|
|
133
|
-
# Sandbox mode with auto-approval
|
|
134
|
-
gemini-exec "fix the failing tests" --yolo --sandbox
|
|
135
|
-
|
|
136
|
-
# Plan mode for careful execution
|
|
137
|
-
gemini-exec "refactor the auth module" --plan
|
|
138
|
-
|
|
139
|
-
# Specify working directory
|
|
140
|
-
gemini-exec "analyze the codebase" --working-dir /path/to/project
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Integration
|
|
144
|
-
|
|
145
|
-
Works with the orchestrator pattern:
|
|
146
|
-
- Main conversation delegates Gemini execution via this skill
|
|
147
|
-
- Results are returned to the main conversation for further processing
|
|
148
|
-
- Can be chained with other skills (e.g., dev-review after Gemini generates code)
|
|
149
|
-
|
|
150
|
-
## Availability Check
|
|
151
|
-
|
|
152
|
-
gemini-exec requires the Gemini CLI binary to be installed and authenticated. The skill is only usable when:
|
|
153
|
-
|
|
154
|
-
1. `gemini` binary is found in PATH (`which gemini` succeeds)
|
|
155
|
-
2. Authentication is valid (GOOGLE_API_KEY, GEMINI_API_KEY set, or gcloud auth active)
|
|
156
|
-
|
|
157
|
-
If either check fails, this skill cannot be used. Fall back to Claude agents for the task.
|
|
158
|
-
|
|
159
|
-
> **Note**: This skill is invoked via `/gemini-exec` command, delegated by the orchestrator, or suggested by routing skills when gemini is available. The intent-detection system can trigger it for research and code generation hybrid workflows.
|
|
160
|
-
|
|
161
|
-
## Agent Teams Integration
|
|
162
|
-
|
|
163
|
-
When used within Agent Teams (requires explicit invocation):
|
|
164
|
-
|
|
165
|
-
1. **As delegated task**: orchestrator explicitly delegates gemini-exec for code generation
|
|
166
|
-
2. **Hybrid workflow**: Claude team member analyzes → orchestrator invokes gemini-exec → Claude reviews
|
|
167
|
-
3. **Iteration**: Team messaging enables review-fix cycles between Claude and Gemini outputs
|
|
168
|
-
|
|
169
|
-
```
|
|
170
|
-
Orchestrator delegates generation task
|
|
171
|
-
→ /gemini-exec invoked explicitly
|
|
172
|
-
→ Output returned to orchestrator
|
|
173
|
-
→ Reviewer validates quality
|
|
174
|
-
→ Iterate if needed
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Research Workflow
|
|
178
|
-
|
|
179
|
-
When the orchestrator or intent-detection detects a research request:
|
|
180
|
-
|
|
181
|
-
1. **Check Gemini availability**: Verify `gemini` binary and auth
|
|
182
|
-
2. **If available**: Execute prompt for research
|
|
183
|
-
3. **If unavailable**: Fall back to Claude's WebFetch/WebSearch
|
|
184
|
-
|
|
185
|
-
### Research Command Pattern
|
|
186
|
-
```
|
|
187
|
-
/gemini-exec "Research and analyze: {topic}. Provide structured findings with sources." --json
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## Code Generation Workflow
|
|
191
|
-
|
|
192
|
-
When routing skills detect a code generation task and gemini is available:
|
|
193
|
-
|
|
194
|
-
1. **Check availability**: Verify gemini CLI via `/tmp/.claude-env-status-*`
|
|
195
|
-
2. **If available + new file creation**: Suggest hybrid workflow
|
|
196
|
-
3. **Hybrid pattern**:
|
|
197
|
-
- gemini-exec generates initial code (fast, broad generation)
|
|
198
|
-
- Claude expert reviews for quality, patterns, best practices
|
|
199
|
-
- Iterate if needed
|
|
200
|
-
|
|
201
|
-
### Suitable Tasks
|
|
202
|
-
- New file scaffolding
|
|
203
|
-
- Boilerplate generation
|
|
204
|
-
- Test stub creation
|
|
205
|
-
- Documentation generation
|
|
206
|
-
|
|
207
|
-
### Unsuitable Tasks
|
|
208
|
-
- Modifying existing code (Claude expert better at understanding context)
|
|
209
|
-
- Architecture decisions (requires reasoning, not generation)
|
|
210
|
-
- Bug fixes (requires deep code understanding)
|
|
211
|
-
|
|
212
|
-
### Code Generation Command Pattern
|
|
213
|
-
```
|
|
214
|
-
/gemini-exec "Generate {description} following {framework} best practices" --yolo
|
|
215
|
-
```
|