skill-codex 0.2.0 → 0.7.1
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 +72 -20
- package/commands/codex-do.md +4 -3
- package/commands/codex-review.md +17 -6
- package/dist/bin/skill-codex.js +109 -17
- package/dist/bin/skill-codex.js.map +1 -1
- package/dist/index.js +510 -47
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/skills/codex-bridge/SKILL.md +217 -0
package/README.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# skill-codex
|
|
2
2
|
|
|
3
|
-

|
|
3
|
+
[](https://www.npmjs.com/package/skill-codex)
|
|
4
|
+
[](https://www.npmjs.com/package/skill-codex)
|
|
4
5
|

|
|
6
|
+
<!-- After enabling the repo on codecov.io (see DISTRIBUTION.md), uncomment:
|
|
7
|
+
[](https://codecov.io/gh/Arystos/skill-codex) -->
|
|
8
|
+

|
|
5
9
|

|
|
6
10
|

|
|
7
11
|

|
|
@@ -11,6 +15,12 @@
|
|
|
11
15
|
|
|
12
16
|
A cross-platform [Claude Code](https://code.claude.com) skill that integrates [OpenAI Codex CLI](https://github.com/openai/codex) for code review, task delegation, and consultation. Uses your existing Codex subscription -- no API key required.
|
|
13
17
|
|
|
18
|
+
> **Two models rarely make the same mistake.** skill-codex lets Claude and Codex check each other's work -- Claude plans and builds fast, Codex reviews with fresh eyes -- from a single terminal, using the Codex subscription you already pay for. No API key, no second window, no copy-paste.
|
|
19
|
+
|
|
20
|
+
<!-- Demo GIF: record a ~20s clip of `/codex-review` catching a real bug, save it to docs/demo.gif, then uncomment the next line:
|
|
21
|
+

|
|
22
|
+
-->
|
|
23
|
+
|
|
14
24
|
## Why?
|
|
15
25
|
|
|
16
26
|
Claude Code and Codex CLI have different strengths. Claude excels at reasoning, architecture, and complex refactors. Codex is fast, thorough, and great at focused execution and review. **skill-codex** lets them work together from a single terminal -- no second window, no copy-paste, no context loss.
|
|
@@ -18,10 +28,30 @@ Claude Code and Codex CLI have different strengths. Claude excels at reasoning,
|
|
|
18
28
|
* **`/codex-review`** -- Have Codex review your current changes as a second reviewer
|
|
19
29
|
* **`/codex-do`** -- Delegate well-scoped implementation tasks to Codex
|
|
20
30
|
* **`/codex-consult`** -- Get a second opinion on architecture or design decisions
|
|
31
|
+
* **`codex-bridge` agent skill** -- Auto-triggers on implementation/review/consult requests so Claude reaches for Codex without an explicit slash command
|
|
21
32
|
* **Auto-review hook** -- Smart PostToolUse hook suggests review after significant changes
|
|
33
|
+
* **Live progress** -- Streams Codex's activity (running commands, file edits, elapsed time) as MCP progress so long runs never look frozen; also mirrored to a tail-able log file (under the OS temp dir, path printed at run start -- never pollutes your repo)
|
|
22
34
|
* **Subscription-first** -- Works with `codex login`, no `OPENAI_API_KEY` needed
|
|
23
35
|
* **Edge case handling** -- Retry logic, timeout, anti-recursion, lock files, pre-flight checks
|
|
24
36
|
|
|
37
|
+
### Why not just use Claude's own subagents?
|
|
38
|
+
|
|
39
|
+
Because a subagent is the **same model**. When Claude reviews Claude, you inherit the same blind spots -- it's grading its own homework. A *different* model family was trained differently, so its mistakes don't correlate with Claude's: it catches what Claude is confidently wrong about, and Claude catches what Codex gets wrong. That uncorrelated, cross-model check is the entire point -- and skill-codex keeps Claude as the final judge, never blindly forwarding Codex's verdict.
|
|
40
|
+
|
|
41
|
+
### How it compares
|
|
42
|
+
|
|
43
|
+
| | skill-codex | Most Codex MCP bridges |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Codex **subscription** auth (no `OPENAI_API_KEY`) | ✅ | ⚠️ often require an API key |
|
|
46
|
+
| **Windows** verified in CI (not just "should work") | ✅ 9-way matrix (Windows/macOS/Linux × Node 18/20/22) | ❌ usually Linux-only CI |
|
|
47
|
+
| **Live progress** so long runs never look frozen | ✅ MCP progress + tail-able log | ⚠️ varies |
|
|
48
|
+
| **Slash commands** (`/codex-review`, `/codex-do`, `/codex-consult`) | ✅ | ⚠️ some |
|
|
49
|
+
| **Auto-review hook** (PostToolUse) | ✅ | ❌ |
|
|
50
|
+
| **Agent skill** (auto-triggers, no command needed) | ✅ | ❌ |
|
|
51
|
+
| **Guardrails**: retry, timeout, anti-recursion, lock files | ✅ | ⚠️ partial |
|
|
52
|
+
|
|
53
|
+
*A snapshot, not a leaderboard -- the Codex MCP space moves fast, so check each tool's current state. The point isn't "skill-codex wins everything"; it's that the operational details (subscription auth, real Windows support, never-frozen runs, guardrails) are where it focuses.*
|
|
54
|
+
|
|
25
55
|
## Prerequisites
|
|
26
56
|
|
|
27
57
|
* [Node.js](https://nodejs.org) >= 18
|
|
@@ -31,12 +61,14 @@ Claude Code and Codex CLI have different strengths. Claude excels at reasoning,
|
|
|
31
61
|
## Quick Start
|
|
32
62
|
|
|
33
63
|
```shell
|
|
34
|
-
#
|
|
64
|
+
# Option A: Run directly (no global install)
|
|
35
65
|
npx skill-codex setup
|
|
36
66
|
|
|
37
|
-
#
|
|
67
|
+
# Option B: Install globally, then setup
|
|
68
|
+
npm i -g skill-codex
|
|
69
|
+
skill-codex setup
|
|
38
70
|
|
|
39
|
-
#
|
|
71
|
+
# Restart Claude Code to load the MCP server, then use:
|
|
40
72
|
/codex-review # Review uncommitted changes
|
|
41
73
|
/codex-do "write tests" # Delegate a task to Codex
|
|
42
74
|
/codex-consult "approach?" # Get a second opinion
|
|
@@ -46,7 +78,8 @@ The setup command:
|
|
|
46
78
|
1. Registers the MCP server in your Claude Code config (`~/.claude.json`)
|
|
47
79
|
2. Installs slash commands globally (`~/.claude/commands/`)
|
|
48
80
|
3. Configures the auto-review PostToolUse hook
|
|
49
|
-
4.
|
|
81
|
+
4. Installs the `codex-bridge` agent skill (`~/.claude/skills/`)
|
|
82
|
+
5. Verifies everything works
|
|
50
83
|
|
|
51
84
|
> **Tip:** Add `.skill-codex.lock` to your `.gitignore`
|
|
52
85
|
|
|
@@ -55,46 +88,59 @@ The setup command:
|
|
|
55
88
|
```
|
|
56
89
|
You in Claude Code
|
|
57
90
|
|
|
|
58
|
-
|-- /codex-review --> MCP tool --> codex exec
|
|
59
|
-
|-- /codex-do "task" --> MCP tool --> codex exec --
|
|
60
|
-
+-- /codex-consult "q" --> MCP tool --> codex exec
|
|
91
|
+
|-- /codex-review --> MCP tool --> codex exec --sandbox read-only --> review findings
|
|
92
|
+
|-- /codex-do "task" --> MCP tool --> codex exec --sandbox workspace-write --> reviewed output
|
|
93
|
+
+-- /codex-consult "q" --> MCP tool --> codex exec --sandbox read-only --> synthesized opinion
|
|
61
94
|
```
|
|
62
95
|
|
|
63
96
|
The MCP server spawns `codex exec` as a subprocess, using your logged-in Codex session. Claude sees the output and critically evaluates it -- **Codex is treated as a peer, not an authority**.
|
|
64
97
|
|
|
98
|
+
### Advanced: sandbox, sessions, model & review
|
|
99
|
+
|
|
100
|
+
These `codex_exec` parameters are all optional -- omit them and Codex uses its defaults:
|
|
101
|
+
|
|
102
|
+
* **`sandbox`** -- the explicit Codex sandbox policy (`read-only`, `workspace-write`, or `danger-full-access`), overriding the `mode` default. Use `danger-full-access` only when you understand the risk.
|
|
103
|
+
* **`sessionId`** -- resume a previous Codex session for multi-round memory. Each response includes the session's thread id; pass it back so Codex retains context -- e.g. a follow-up review that checks whether *previously flagged* issues were fixed, instead of re-discovering them.
|
|
104
|
+
* **`model`** -- pick the Codex model (e.g. `gpt-5.5`, `gpt-5.4`, `gpt-5.4-mini`). Route cheap tasks to a smaller model and escalate hard ones; omit to use your configured default.
|
|
105
|
+
* **`reasoningEffort`** -- how hard Codex thinks: `minimal` | `low` | `medium` | `high` | `xhigh`. Omit for the model's default.
|
|
106
|
+
* **`review`** -- run Codex's native diff-scoped reviewer (`codex exec review`) instead of a freeform prompt, optionally targeting a branch (`reviewBase`) or commit (`reviewCommit`). The prompt becomes optional focus instructions.
|
|
107
|
+
|
|
65
108
|
### Auto-review
|
|
66
109
|
|
|
67
110
|
After significant code changes (3+ files, 100+ lines, security-related paths), the PostToolUse hook suggests running `/codex-review`. Trivial changes (docs-only, < 5 lines, whitespace) are skipped to preserve your Codex quota.
|
|
68
111
|
|
|
69
|
-
###
|
|
112
|
+
### Agent skill (auto-trigger)
|
|
70
113
|
|
|
71
|
-
|
|
72
|
-
|
|
114
|
+
The slash commands are explicit, on-demand entry points. The `codex-bridge` agent skill is the implicit one: it installs to `~/.claude/skills/` and Claude loads it automatically when your request matches a delegation, review, or consult pattern (e.g. "implement X", "generate tests for", "review this diff", "second opinion on this approach"). It maps the same three workflows -- delegate, review, consult -- onto the `codex_exec` tool, so you get Codex collaboration without remembering a command. Trivial tasks (< 50 lines, faster done directly) are explicitly out of scope.
|
|
115
|
+
|
|
116
|
+
### Example Output
|
|
73
117
|
|
|
74
|
-
|
|
118
|
+
When Codex runs, the MCP tool returns a structured plain-text response:
|
|
75
119
|
|
|
76
|
-
|
|
120
|
+
```
|
|
121
|
+
[read-only │ D:\myproject │ 21538 tok in (15744 cached) → 129 out]
|
|
122
|
+
✔ exec: powershell -Command 'git diff --cached' (ok)
|
|
77
123
|
|
|
78
124
|
CRITICAL — src/auth/login.ts:42
|
|
79
125
|
Password comparison uses == instead of timing-safe comparison.
|
|
80
|
-
Claude's assessment: Agree. Use crypto.timingSafeEqual() instead.
|
|
81
126
|
|
|
82
127
|
MEDIUM — src/api/routes.ts:18
|
|
83
128
|
Missing rate limiting on login endpoint.
|
|
84
|
-
Claude's assessment: Agree. Add rate limiter middleware.
|
|
85
|
-
|
|
86
|
-
Shall I fix these issues?
|
|
87
129
|
```
|
|
88
130
|
|
|
131
|
+
The first line shows mode, working directory, and token usage. Activity lines show commands Codex executed (with status icons: ✔ ok, ✘ blocked/failed). The response content follows after a blank line.
|
|
132
|
+
|
|
89
133
|
## Configuration
|
|
90
134
|
|
|
91
135
|
Environment variables (all optional):
|
|
92
136
|
|
|
93
137
|
| Variable | Default | Description |
|
|
94
138
|
|----------|---------|-------------|
|
|
95
|
-
| `SKILL_CODEX_TIMEOUT_MS` | `
|
|
139
|
+
| `SKILL_CODEX_TIMEOUT_MS` | `300000` (5 min) | Subprocess timeout |
|
|
96
140
|
| `SKILL_CODEX_MAX_RETRIES` | `3` | Retry count for transient errors |
|
|
141
|
+
| `SKILL_CODEX_LOG` | `<os-temp>/skill-codex/<workspace>.log` | Absolute path override for the live, tail-able per-run log |
|
|
97
142
|
| `SKILL_CODEX_DEBUG` | -- | Enable debug logging to stderr |
|
|
143
|
+
| `SKILL_CODEX_WINDOWS_SANDBOX` | `unelevated` | Windows only — Codex `windows.sandbox` mode (`unelevated`/`elevated`) |
|
|
98
144
|
|
|
99
145
|
### Smart Filter Thresholds
|
|
100
146
|
|
|
@@ -115,7 +161,7 @@ Environment variables (all optional):
|
|
|
115
161
|
| Auth expired | Advises `codex login`, no retry |
|
|
116
162
|
| Network down | Retries 3x with exponential backoff |
|
|
117
163
|
| Rate limited (429) | Retries with backoff + jitter |
|
|
118
|
-
| Codex hangs | Killed after timeout (SIGTERM
|
|
164
|
+
| Codex hangs | Killed after timeout (SIGTERM+SIGKILL on Unix, immediate kill on Windows) |
|
|
119
165
|
| Concurrent runs | Lock file prevents conflicts (stale after 15min) |
|
|
120
166
|
| Recursive calls | `SKILL_CODEX_DEPTH` limit prevents infinite loops |
|
|
121
167
|
| Trivial changes | Smart filter skips auto-review |
|
|
@@ -143,6 +189,8 @@ skill-codex/
|
|
|
143
189
|
|-- hooks/
|
|
144
190
|
| |-- post-tool-use-review.sh # Auto-review hook (macOS/Linux)
|
|
145
191
|
| +-- post-tool-use-review.ps1 # Auto-review hook (Windows)
|
|
192
|
+
|-- skills/
|
|
193
|
+
| +-- codex-bridge/SKILL.md # Agent skill (auto-triggers delegation/review/consult)
|
|
146
194
|
|-- setup/ # npx skill-codex setup installer
|
|
147
195
|
|-- bin/ # CLI entry point
|
|
148
196
|
+-- __tests__/ # vitest test suite
|
|
@@ -162,6 +210,7 @@ cd skill-codex
|
|
|
162
210
|
npm install
|
|
163
211
|
npm run build
|
|
164
212
|
npm test
|
|
213
|
+
npm run test:coverage # enforces the same 80%+ gate as CI
|
|
165
214
|
```
|
|
166
215
|
|
|
167
216
|
## Troubleshooting
|
|
@@ -176,11 +225,14 @@ Restart Claude Code after running setup. The MCP server only loads on startup.
|
|
|
176
225
|
Increase the timeout: `export SKILL_CODEX_TIMEOUT_MS=1200000` (20 min). Large codebases can take longer.
|
|
177
226
|
|
|
178
227
|
**"Auth expired" but Codex works in another terminal**
|
|
179
|
-
The MCP server runs in its own process. Run `codex login` and restart Claude Code.
|
|
228
|
+
The MCP server runs in its own process. Run `codex login` and restart Claude Code. On Windows, the auth pre-check is skipped automatically (PowerShell profile errors can cause false negatives); auth is still verified when Codex actually runs.
|
|
180
229
|
|
|
181
230
|
**Lock file blocking runs**
|
|
182
231
|
If a previous run crashed, a stale `.skill-codex.lock` may remain. It auto-cleans after 15 minutes, or delete it manually.
|
|
183
232
|
|
|
233
|
+
**Windows: "windows sandbox failed: spawn setup refresh" / Codex commands all blocked**
|
|
234
|
+
Codex's default *elevated* Windows sandbox fails to spawn shells on many setups ([openai/codex#24098](https://github.com/openai/codex/issues/24098), [#24259](https://github.com/openai/codex/issues/24259)). skill-codex works around this by pinning `windows.sandbox=unelevated`, which spawns reliably. If your machine needs the elevated sandbox instead, set `SKILL_CODEX_WINDOWS_SANDBOX=elevated`.
|
|
235
|
+
|
|
184
236
|
## Inspired By
|
|
185
237
|
|
|
186
238
|
* [Dunqing/claude-codex-bridge](https://github.com/Dunqing/claude-codex-bridge) -- retry logic, anti-recursion, output parsing
|
package/commands/codex-do.md
CHANGED
|
@@ -10,7 +10,7 @@ You are delegating an implementation task to Codex. Follow these steps:
|
|
|
10
10
|
|
|
11
11
|
2. **Evaluate if the task is suitable for delegation**:
|
|
12
12
|
- **Good for Codex**: repetitive bulk changes, boilerplate generation, test writing for existing code, migration scripts, file format conversions, well-defined single-file edits
|
|
13
|
-
- **Keep for yourself**: architectural decisions, cross-module refactoring, tasks requiring deep conversation context, ambiguous requirements,
|
|
13
|
+
- **Keep for yourself**: architectural decisions, cross-module refactoring, tasks requiring deep conversation context, ambiguous requirements, and trivial edits you'd finish faster yourself than you can write a spec for
|
|
14
14
|
- If the task is poorly scoped, explain why and suggest how to break it down.
|
|
15
15
|
|
|
16
16
|
3. **Prepare a precise, self-contained prompt** for Codex. Include:
|
|
@@ -25,7 +25,8 @@ You are delegating an implementation task to Codex. Follow these steps:
|
|
|
25
25
|
- `requireGit`: true
|
|
26
26
|
|
|
27
27
|
5. **Review Codex's output critically**:
|
|
28
|
-
- Run `git
|
|
28
|
+
- Run `git status --short` **first** to see ALL changes, including **newly-created files** (lines starting with `??`). Codex in full-auto mode often creates new files, and `git diff` alone is blind to untracked files.
|
|
29
|
+
- Run `git diff` for modifications to tracked files, and **read any new untracked files directly** to review their contents.
|
|
29
30
|
- Check for introduced bugs, regressions, or style violations
|
|
30
31
|
- Verify it matches the requested changes
|
|
31
32
|
- Verify it doesn't modify files outside the requested scope
|
|
@@ -39,6 +40,6 @@ You are delegating an implementation task to Codex. Follow these steps:
|
|
|
39
40
|
## Important
|
|
40
41
|
|
|
41
42
|
- Codex runs in **full-auto mode** — it CAN modify files in the workspace
|
|
42
|
-
- Always `git diff` after Codex runs
|
|
43
|
+
- Always run `git status --short` **and** `git diff` after Codex runs — `git status` catches new files that `git diff` misses
|
|
43
44
|
- Codex is a **peer, not an authority** — review all output before accepting
|
|
44
45
|
- For complex multi-file tasks, consider doing it yourself instead
|
package/commands/codex-review.md
CHANGED
|
@@ -7,7 +7,7 @@ Review the current changes using Codex as a second reviewer.
|
|
|
7
7
|
You are invoking Codex for a second-opinion code review. Follow these steps:
|
|
8
8
|
|
|
9
9
|
1. **Determine what to review** based on `$ARGUMENTS`:
|
|
10
|
-
- If empty or "uncommitted":
|
|
10
|
+
- If empty or "uncommitted": first run `git status --short` to see ALL changes, including **new untracked files** (lines starting with `??`). Collect tracked modifications via `git diff` and staged changes via `git diff --cached`, **and** include the full contents of any new untracked files — read them directly, or use `git diff --no-index -- /dev/null <file>`. Plain `git diff` is blind to untracked files, so a review that skips this step will miss brand-new files entirely. If there are no changes at all, inform the user and stop.
|
|
11
11
|
- If it looks like a branch name: get changes via `git diff <branch>...HEAD`
|
|
12
12
|
- If it looks like a commit SHA: get changes via `git show <sha>`
|
|
13
13
|
|
|
@@ -20,16 +20,27 @@ You are invoking Codex for a second-opinion code review. Follow these steps:
|
|
|
20
20
|
- `mode`: "exec"
|
|
21
21
|
- `requireGit`: true
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
**Option B (native Codex review):** Default to the Claude-assembled diff above, since the user prefers Claude-led review. You may instead call `codex_exec` with `review: true` to use `codex exec review`; add `reviewBase` for a branch or `reviewCommit` for a SHA. The prompt is optional focus instructions.
|
|
24
|
+
|
|
25
|
+
4. **Assign an overall verdict** from the findings (you are the final judge — weigh Codex's findings, don't just echo them):
|
|
26
|
+
- **BLOCKED** — one or more CRITICAL/HIGH issues that should be fixed before merge
|
|
27
|
+
- **WARNING** — only MEDIUM/LOW issues; safe to proceed with awareness
|
|
28
|
+
- **APPROVED** — no substantive issues
|
|
29
|
+
State it explicitly, e.g. `Verdict: BLOCKED — 2 CRITICAL, 1 MEDIUM`.
|
|
30
|
+
|
|
31
|
+
5. **Present findings** to the user:
|
|
24
32
|
- Group by severity (CRITICAL first)
|
|
25
|
-
- For each finding, add your own assessment: agree, disagree, or nuance
|
|
33
|
+
- For each finding, add your own assessment: agree, disagree (with reasoning), or add nuance
|
|
26
34
|
- Note anything Codex missed that you think is important
|
|
27
35
|
- Summarize actionable items at the end
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
6. **If BLOCKED or WARNING, offer a bounded fix loop** (only with the user's go-ahead for automated fixing):
|
|
38
|
+
- Fix the issues you agree are genuine. If you disagree with a finding, explain why instead of "fixing" it just to satisfy Codex.
|
|
39
|
+
- Re-run the review (call `codex_exec` again on the updated diff) so Codex confirms the fixes and checks for regressions.
|
|
40
|
+
- Repeat until the verdict is APPROVED or you have done **3 rounds**, then stop and summarize what remains. The hard cap keeps the loop from quietly burning your Codex quota.
|
|
30
41
|
|
|
31
42
|
## Important
|
|
32
43
|
|
|
33
44
|
- Codex runs in **read-only mode** — it cannot modify files
|
|
34
|
-
- Codex is a **peer, not an authority** — evaluate each finding critically
|
|
35
|
-
-
|
|
45
|
+
- Codex is a **peer, not an authority** — evaluate each finding critically and keep the final call yourself
|
|
46
|
+
- **Fail soft:** if `codex_exec` errors (Codex not installed, auth expired, offline), say so and fall back to your own review — a missing Codex should degrade to Claude-only review, never block the user
|
package/dist/bin/skill-codex.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// bin/skill-codex.ts
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import fs8 from "fs";
|
|
5
|
+
import path10 from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
8
|
// setup/setup.ts
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import fs7 from "fs";
|
|
10
|
+
import path9 from "path";
|
|
11
11
|
|
|
12
12
|
// setup/install-mcp.ts
|
|
13
13
|
import fs2 from "fs";
|
|
@@ -44,6 +44,9 @@ function getGlobalMcpConfigPath() {
|
|
|
44
44
|
function getGlobalCommandsDir() {
|
|
45
45
|
return path2.join(getClaudeDir(), "commands");
|
|
46
46
|
}
|
|
47
|
+
function getGlobalSkillsDir() {
|
|
48
|
+
return path2.join(getClaudeDir(), "skills");
|
|
49
|
+
}
|
|
47
50
|
|
|
48
51
|
// src/config/package-root.ts
|
|
49
52
|
import fs from "fs";
|
|
@@ -243,8 +246,79 @@ function installHook() {
|
|
|
243
246
|
};
|
|
244
247
|
}
|
|
245
248
|
|
|
246
|
-
// setup/
|
|
249
|
+
// setup/install-skill.ts
|
|
247
250
|
import fs5 from "fs";
|
|
251
|
+
import path7 from "path";
|
|
252
|
+
var SKILL_NAME = "codex-bridge";
|
|
253
|
+
function getSkillSourceDir() {
|
|
254
|
+
return path7.join(getPackageRoot(), "skills", SKILL_NAME);
|
|
255
|
+
}
|
|
256
|
+
function copyDirRecursive(source, target) {
|
|
257
|
+
const copied = [];
|
|
258
|
+
if (!fs5.existsSync(target)) {
|
|
259
|
+
fs5.mkdirSync(target, { recursive: true });
|
|
260
|
+
}
|
|
261
|
+
const entries = fs5.readdirSync(source, { withFileTypes: true });
|
|
262
|
+
for (const entry of entries) {
|
|
263
|
+
const sourcePath = path7.join(source, entry.name);
|
|
264
|
+
const targetPath = path7.join(target, entry.name);
|
|
265
|
+
if (entry.isDirectory()) {
|
|
266
|
+
copied.push(...copyDirRecursive(sourcePath, targetPath));
|
|
267
|
+
} else if (entry.isFile()) {
|
|
268
|
+
const sourceContent = fs5.readFileSync(sourcePath);
|
|
269
|
+
let shouldWrite = true;
|
|
270
|
+
if (fs5.existsSync(targetPath)) {
|
|
271
|
+
const existing = fs5.readFileSync(targetPath);
|
|
272
|
+
shouldWrite = !existing.equals(sourceContent);
|
|
273
|
+
}
|
|
274
|
+
if (shouldWrite) {
|
|
275
|
+
fs5.writeFileSync(targetPath, sourceContent);
|
|
276
|
+
copied.push(entry.name);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return copied;
|
|
281
|
+
}
|
|
282
|
+
function installSkill() {
|
|
283
|
+
const sourceDir = getSkillSourceDir();
|
|
284
|
+
const targetDir = path7.join(getGlobalSkillsDir(), SKILL_NAME);
|
|
285
|
+
if (!fs5.existsSync(sourceDir)) {
|
|
286
|
+
return {
|
|
287
|
+
installed: false,
|
|
288
|
+
targetDir,
|
|
289
|
+
copiedFiles: [],
|
|
290
|
+
message: `Skill source not found at ${sourceDir}`
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
const skillFile = path7.join(sourceDir, "SKILL.md");
|
|
294
|
+
if (!fs5.existsSync(skillFile)) {
|
|
295
|
+
return {
|
|
296
|
+
installed: false,
|
|
297
|
+
targetDir,
|
|
298
|
+
copiedFiles: [],
|
|
299
|
+
message: `SKILL.md missing in ${sourceDir}`
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const copied = copyDirRecursive(sourceDir, targetDir);
|
|
303
|
+
return {
|
|
304
|
+
installed: true,
|
|
305
|
+
targetDir,
|
|
306
|
+
copiedFiles: copied,
|
|
307
|
+
message: copied.length > 0 ? `Installed skill '${SKILL_NAME}' to ${targetDir} (${copied.length} file(s))` : `Skill '${SKILL_NAME}' already up to date`
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function uninstallSkill() {
|
|
311
|
+
const targetDir = path7.join(getGlobalSkillsDir(), SKILL_NAME);
|
|
312
|
+
if (!fs5.existsSync(targetDir)) {
|
|
313
|
+
return { removed: false, targetDir };
|
|
314
|
+
}
|
|
315
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
316
|
+
return { removed: true, targetDir };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// setup/verify.ts
|
|
320
|
+
import fs6 from "fs";
|
|
321
|
+
import path8 from "path";
|
|
248
322
|
import which from "which";
|
|
249
323
|
async function runVerification() {
|
|
250
324
|
const results = [];
|
|
@@ -264,9 +338,9 @@ async function runVerification() {
|
|
|
264
338
|
}
|
|
265
339
|
const mcpPath = getGlobalMcpConfigPath();
|
|
266
340
|
let mcpRegistered = false;
|
|
267
|
-
if (
|
|
341
|
+
if (fs6.existsSync(mcpPath)) {
|
|
268
342
|
try {
|
|
269
|
-
const raw =
|
|
343
|
+
const raw = fs6.readFileSync(mcpPath, "utf-8");
|
|
270
344
|
const config = JSON.parse(raw);
|
|
271
345
|
mcpRegistered = "skill-codex" in (config.mcpServers ?? {});
|
|
272
346
|
} catch {
|
|
@@ -280,13 +354,20 @@ async function runVerification() {
|
|
|
280
354
|
const commandsDir = getGlobalCommandsDir();
|
|
281
355
|
const expectedCommands = ["codex-review.md", "codex-do.md", "codex-consult.md"];
|
|
282
356
|
const missingCommands = expectedCommands.filter(
|
|
283
|
-
(cmd) => !
|
|
357
|
+
(cmd) => !fs6.existsSync(`${commandsDir}/${cmd}`)
|
|
284
358
|
);
|
|
285
359
|
results.push({
|
|
286
360
|
name: "Slash commands installed",
|
|
287
361
|
pass: missingCommands.length === 0,
|
|
288
362
|
detail: missingCommands.length === 0 ? `All 3 commands in ${commandsDir}` : `Missing: ${missingCommands.join(", ")}`
|
|
289
363
|
});
|
|
364
|
+
const skillFile = path8.join(getGlobalSkillsDir(), "codex-bridge", "SKILL.md");
|
|
365
|
+
const skillInstalled = fs6.existsSync(skillFile);
|
|
366
|
+
results.push({
|
|
367
|
+
name: "Agent skill installed",
|
|
368
|
+
pass: skillInstalled,
|
|
369
|
+
detail: skillInstalled ? skillFile : `Not found at ${skillFile}`
|
|
370
|
+
});
|
|
290
371
|
return {
|
|
291
372
|
results,
|
|
292
373
|
allPassed: results.every((r) => r.pass)
|
|
@@ -309,6 +390,9 @@ async function runSetup(options = {}) {
|
|
|
309
390
|
log(" ", "Registering auto-review hook...");
|
|
310
391
|
const hookResult = installHook();
|
|
311
392
|
log(hookResult.installed ? "[ok]" : "[--]", hookResult.message);
|
|
393
|
+
log(" ", "Installing agent skill...");
|
|
394
|
+
const skillResult = installSkill();
|
|
395
|
+
log(skillResult.installed ? "[ok]" : "[--]", skillResult.message);
|
|
312
396
|
log("\n ", "Verifying installation...\n");
|
|
313
397
|
const verification = await runVerification();
|
|
314
398
|
for (const check of verification.results) {
|
|
@@ -323,6 +407,8 @@ async function runSetup(options = {}) {
|
|
|
323
407
|
log(" ", " /codex-do - Delegate a task to Codex");
|
|
324
408
|
log(" ", " /codex-consult - Get a second opinion from Codex");
|
|
325
409
|
log("", "");
|
|
410
|
+
log(" ", "Agent skill installed: codex-bridge (auto-triggers on implementation/review requests)");
|
|
411
|
+
log("", "");
|
|
326
412
|
log(" ", "Tip: Add .skill-codex.lock to your .gitignore");
|
|
327
413
|
} else {
|
|
328
414
|
log("[!!]", "Setup completed with warnings. Fix the issues above and run: npx skill-codex verify\n");
|
|
@@ -333,12 +419,12 @@ async function runUninstall() {
|
|
|
333
419
|
log(">>", "skill-codex uninstall\n");
|
|
334
420
|
const mcpConfigPath = getGlobalMcpConfigPath();
|
|
335
421
|
try {
|
|
336
|
-
const raw =
|
|
422
|
+
const raw = fs7.readFileSync(mcpConfigPath, "utf-8");
|
|
337
423
|
const config = JSON.parse(raw);
|
|
338
424
|
const mcpServers = config.mcpServers;
|
|
339
425
|
if (mcpServers && "skill-codex" in mcpServers) {
|
|
340
426
|
delete mcpServers["skill-codex"];
|
|
341
|
-
|
|
427
|
+
fs7.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
342
428
|
log("[ok]", "Removed MCP server");
|
|
343
429
|
} else {
|
|
344
430
|
log("[--]", "MCP server not found");
|
|
@@ -349,17 +435,23 @@ async function runUninstall() {
|
|
|
349
435
|
const commandsDir = getGlobalCommandsDir();
|
|
350
436
|
const commandFiles = ["codex-review.md", "codex-do.md", "codex-consult.md"];
|
|
351
437
|
for (const file of commandFiles) {
|
|
352
|
-
const filePath =
|
|
438
|
+
const filePath = path9.join(commandsDir, file);
|
|
353
439
|
try {
|
|
354
|
-
|
|
440
|
+
fs7.unlinkSync(filePath);
|
|
355
441
|
log("[ok]", `Removed ${file}`);
|
|
356
442
|
} catch {
|
|
357
443
|
log("[--]", `${file} not found`);
|
|
358
444
|
}
|
|
359
445
|
}
|
|
446
|
+
const skillUninstall = uninstallSkill();
|
|
447
|
+
if (skillUninstall.removed) {
|
|
448
|
+
log("[ok]", `Removed skill: ${skillUninstall.targetDir}`);
|
|
449
|
+
} else {
|
|
450
|
+
log("[--]", "Agent skill not found");
|
|
451
|
+
}
|
|
360
452
|
const settingsPath = getClaudeSettingsPath();
|
|
361
453
|
try {
|
|
362
|
-
const raw =
|
|
454
|
+
const raw = fs7.readFileSync(settingsPath, "utf-8");
|
|
363
455
|
const settings = JSON.parse(raw);
|
|
364
456
|
const hooks = settings.hooks;
|
|
365
457
|
if (hooks) {
|
|
@@ -372,7 +464,7 @@ async function runUninstall() {
|
|
|
372
464
|
if (hooks[eventType].length < before) removed = true;
|
|
373
465
|
}
|
|
374
466
|
if (removed) {
|
|
375
|
-
|
|
467
|
+
fs7.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
376
468
|
log("[ok]", "Removed PostToolUse hook");
|
|
377
469
|
} else {
|
|
378
470
|
log("[--]", "PostToolUse hook not found");
|
|
@@ -391,10 +483,10 @@ async function runUninstall() {
|
|
|
391
483
|
var args = process.argv.slice(2);
|
|
392
484
|
var command = args[0];
|
|
393
485
|
function getVersion() {
|
|
394
|
-
const __dirname =
|
|
395
|
-
const pkgPath =
|
|
486
|
+
const __dirname = path10.dirname(fileURLToPath(import.meta.url));
|
|
487
|
+
const pkgPath = path10.resolve(__dirname, "..", "package.json");
|
|
396
488
|
try {
|
|
397
|
-
const pkg = JSON.parse(
|
|
489
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
398
490
|
return pkg.version ?? "0.0.0";
|
|
399
491
|
} catch {
|
|
400
492
|
return "0.0.0";
|