mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-10 03:14:32 +08:00
optimize codex skills
This commit is contained in:
@@ -18,11 +18,18 @@ Execute Codex CLI commands and parse structured JSON responses. Supports file re
|
||||
|
||||
## Usage
|
||||
|
||||
通过 Bash tool 调用:
|
||||
```bash
|
||||
bash scripts/codex.sh "<task>" [model] [working_dir]
|
||||
node ~/.claude/skills/codex/scripts/codex.js "<task>" [model] [working_dir]
|
||||
```
|
||||
|
||||
**Timeout**: Set `timeout: 7200000` (2 hours) in Bash tool for long tasks.
|
||||
## Timeout Control
|
||||
|
||||
- **Built-in**: Script enforces 2-hour timeout by default
|
||||
- **Override**: Set `CODEX_TIMEOUT` environment variable (in milliseconds, e.g., `CODEX_TIMEOUT=3600000` for 1 hour)
|
||||
- **Behavior**: On timeout, sends SIGTERM, then SIGKILL after 5s if process doesn't exit
|
||||
- **Exit code**: Returns 124 on timeout (consistent with GNU timeout)
|
||||
- **Bash tool**: Always set `timeout: 7200000` parameter for double protection
|
||||
|
||||
### Parameters
|
||||
|
||||
@@ -47,26 +54,41 @@ Error format:
|
||||
ERROR: Error message
|
||||
```
|
||||
|
||||
### Invocation Pattern
|
||||
|
||||
When calling via Bash tool, always include the timeout parameter:
|
||||
```
|
||||
Bash tool parameters:
|
||||
- command: node ~/.claude/skills/codex/scripts/codex.js "<task>" [model] [working_dir]
|
||||
- timeout: 7200000
|
||||
- description: <brief description of the task>
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
**Basic code analysis:**
|
||||
```bash
|
||||
bash scripts/codex.sh "explain @src/main.ts"
|
||||
# Via Bash tool with timeout parameter
|
||||
node ~/.claude/skills/codex/scripts/codex.js "explain @src/main.ts"
|
||||
# timeout: 7200000
|
||||
```
|
||||
|
||||
**Refactoring with specific model:**
|
||||
```bash
|
||||
bash scripts/codex.sh "refactor @src/utils for performance" "gpt-5"
|
||||
node ~/.claude/skills/codex/scripts/codex.js "refactor @src/utils for performance" "gpt-5"
|
||||
# timeout: 7200000
|
||||
```
|
||||
|
||||
**Multi-file analysis:**
|
||||
```bash
|
||||
bash scripts/codex.sh "analyze @. and find security issues" "gpt-5-codex" "/path/to/project"
|
||||
node ~/.claude/skills/codex/scripts/codex.js "analyze @. and find security issues" "gpt-5-codex" "/path/to/project"
|
||||
# timeout: 7200000
|
||||
```
|
||||
|
||||
**Quick task:**
|
||||
```bash
|
||||
bash scripts/codex.sh "add comments to @utils.js" "gpt-5-codex"
|
||||
node ~/.claude/skills/codex/scripts/codex.js "add comments to @utils.js" "gpt-5-codex"
|
||||
# timeout: 7200000
|
||||
```
|
||||
|
||||
## Notes
|
||||
@@ -75,4 +97,3 @@ bash scripts/codex.sh "add comments to @utils.js" "gpt-5-codex"
|
||||
- Uses `--skip-git-repo-check` to work in any directory
|
||||
- Streams progress, returns only final agent message
|
||||
- Requires Codex CLI installed and authenticated
|
||||
- Use `timeout: 7200000` (2 hours) for complex tasks that may take longer
|
||||
178
skills/codex/scripts/codex.js
Executable file
178
skills/codex/scripts/codex.js
Executable file
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
const DEFAULT_MODEL = 'gpt-5-codex';
|
||||
const DEFAULT_WORKDIR = '.';
|
||||
const DEFAULT_TIMEOUT_MS = 7_200_000; // 2 hours
|
||||
const FORCE_KILL_DELAY_MS = 5_000;
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const [task, modelArg, workdirArg] = args;
|
||||
|
||||
const logError = (message) => {
|
||||
process.stderr.write(`ERROR: ${message}\n`);
|
||||
};
|
||||
|
||||
const logWarn = (message) => {
|
||||
process.stderr.write(`WARN: ${message}\n`);
|
||||
};
|
||||
|
||||
if (!task) {
|
||||
logError('Task required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const model = modelArg || DEFAULT_MODEL;
|
||||
const workdir = workdirArg || DEFAULT_WORKDIR;
|
||||
|
||||
const resolveTimeout = () => {
|
||||
const raw = process.env.CODEX_TIMEOUT;
|
||||
if (raw == null || raw === '') {
|
||||
return DEFAULT_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
const parsed = Number(raw);
|
||||
if (!Number.isFinite(parsed) || parsed <= 0) {
|
||||
logWarn(`Invalid CODEX_TIMEOUT "${raw}", falling back to ${DEFAULT_TIMEOUT_MS}ms`);
|
||||
return DEFAULT_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
};
|
||||
|
||||
const codexArgs = [
|
||||
'e',
|
||||
'-m',
|
||||
model,
|
||||
'--dangerously-bypass-approvals-and-sandbox',
|
||||
'--skip-git-repo-check',
|
||||
'-C',
|
||||
workdir,
|
||||
'--json',
|
||||
task,
|
||||
];
|
||||
|
||||
const child = spawn('codex', codexArgs, {
|
||||
stdio: ['ignore', 'pipe', 'inherit'],
|
||||
});
|
||||
|
||||
let timedOut = false;
|
||||
let lastAgentMessage = null;
|
||||
let stdoutBuffer = '';
|
||||
let forceKillTimer = null;
|
||||
|
||||
const timeoutMs = resolveTimeout();
|
||||
|
||||
const forceTerminate = () => {
|
||||
if (!child.killed) {
|
||||
child.kill('SIGTERM');
|
||||
forceKillTimer = setTimeout(() => {
|
||||
if (!child.killed) {
|
||||
child.kill('SIGKILL');
|
||||
}
|
||||
}, FORCE_KILL_DELAY_MS);
|
||||
}
|
||||
};
|
||||
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
timedOut = true;
|
||||
logError('Codex execution timeout');
|
||||
forceTerminate();
|
||||
}, timeoutMs);
|
||||
|
||||
const normalizeText = (text) => {
|
||||
if (typeof text === 'string') {
|
||||
return text;
|
||||
}
|
||||
if (Array.isArray(text)) {
|
||||
return text.join('');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const handleJsonLine = (line) => {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let event;
|
||||
try {
|
||||
event = JSON.parse(trimmed);
|
||||
} catch (err) {
|
||||
logWarn(`Failed to parse Codex output line: ${trimmed}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
event &&
|
||||
event.type === 'item.completed' &&
|
||||
event.item &&
|
||||
event.item.type === 'agent_message'
|
||||
) {
|
||||
const text = normalizeText(event.item.text);
|
||||
if (text != null) {
|
||||
lastAgentMessage = text;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
child.stdout.on('data', (chunk) => {
|
||||
stdoutBuffer += chunk.toString('utf8');
|
||||
let newlineIndex = stdoutBuffer.indexOf('\n');
|
||||
|
||||
while (newlineIndex !== -1) {
|
||||
const line = stdoutBuffer.slice(0, newlineIndex);
|
||||
stdoutBuffer = stdoutBuffer.slice(newlineIndex + 1);
|
||||
handleJsonLine(line);
|
||||
newlineIndex = stdoutBuffer.indexOf('\n');
|
||||
}
|
||||
});
|
||||
|
||||
child.stdout.on('end', () => {
|
||||
if (stdoutBuffer) {
|
||||
handleJsonLine(stdoutBuffer);
|
||||
stdoutBuffer = '';
|
||||
}
|
||||
});
|
||||
|
||||
child.on('error', (err) => {
|
||||
clearTimeout(timeoutHandle);
|
||||
if (forceKillTimer) {
|
||||
clearTimeout(forceKillTimer);
|
||||
}
|
||||
logError(`Failed to start Codex CLI: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
child.on('close', (code, signal) => {
|
||||
clearTimeout(timeoutHandle);
|
||||
if (forceKillTimer) {
|
||||
clearTimeout(forceKillTimer);
|
||||
}
|
||||
|
||||
if (timedOut) {
|
||||
process.exit(124);
|
||||
return;
|
||||
}
|
||||
|
||||
if (code === 0) {
|
||||
if (lastAgentMessage != null) {
|
||||
process.stdout.write(`${lastAgentMessage}\n`);
|
||||
process.exit(0);
|
||||
} else {
|
||||
logError('Codex completed without an agent_message output');
|
||||
process.exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
logError(`Codex terminated with signal ${signal}`);
|
||||
process.exit(code ?? 1);
|
||||
return;
|
||||
}
|
||||
|
||||
logError(`Codex exited with status ${code}`);
|
||||
process.exit(code ?? 1);
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
TASK="${1:-}"
|
||||
MODEL="${2:-gpt-5-codex}"
|
||||
WORKDIR="${3:-.}"
|
||||
|
||||
if [ -z "$TASK" ]; then
|
||||
echo "ERROR: Task required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
codex e -m "$MODEL" --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check -C "$WORKDIR" --json "$TASK" 2>/dev/null | \
|
||||
jq -r 'select(.type == "item.completed" and .item.type == "agent_message") | .item.text' | \
|
||||
tail -n 1
|
||||
Reference in New Issue
Block a user