skill-codex 0.2.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/LICENSE +21 -0
- package/README.md +202 -0
- package/commands/codex-consult.md +36 -0
- package/commands/codex-do.md +44 -0
- package/commands/codex-review.md +35 -0
- package/dist/bin/skill-codex.js +467 -0
- package/dist/bin/skill-codex.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +722 -0
- package/dist/index.js.map +1 -0
- package/hooks/post-tool-use-review.ps1 +50 -0
- package/hooks/post-tool-use-review.sh +49 -0
- package/package.json +81 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// bin/skill-codex.ts
|
|
4
|
+
import fs7 from "fs";
|
|
5
|
+
import path8 from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
// setup/setup.ts
|
|
9
|
+
import fs6 from "fs";
|
|
10
|
+
import path7 from "path";
|
|
11
|
+
|
|
12
|
+
// setup/install-mcp.ts
|
|
13
|
+
import fs2 from "fs";
|
|
14
|
+
import path4 from "path";
|
|
15
|
+
|
|
16
|
+
// src/config/paths.ts
|
|
17
|
+
import path2 from "path";
|
|
18
|
+
|
|
19
|
+
// src/util/platform.ts
|
|
20
|
+
import os from "os";
|
|
21
|
+
import path from "path";
|
|
22
|
+
function getPlatform() {
|
|
23
|
+
const p = os.platform();
|
|
24
|
+
if (p === "win32" || p === "darwin" || p === "linux") return p;
|
|
25
|
+
return "linux";
|
|
26
|
+
}
|
|
27
|
+
function isWindows() {
|
|
28
|
+
return getPlatform() === "win32";
|
|
29
|
+
}
|
|
30
|
+
function getHomeDir() {
|
|
31
|
+
return os.homedir();
|
|
32
|
+
}
|
|
33
|
+
function getClaudeDir() {
|
|
34
|
+
return path.join(getHomeDir(), ".claude");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/config/paths.ts
|
|
38
|
+
function getClaudeSettingsPath() {
|
|
39
|
+
return path2.join(getClaudeDir(), "settings.json");
|
|
40
|
+
}
|
|
41
|
+
function getGlobalMcpConfigPath() {
|
|
42
|
+
return path2.join(getHomeDir(), ".claude.json");
|
|
43
|
+
}
|
|
44
|
+
function getGlobalCommandsDir() {
|
|
45
|
+
return path2.join(getClaudeDir(), "commands");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/config/package-root.ts
|
|
49
|
+
import fs from "fs";
|
|
50
|
+
import path3 from "path";
|
|
51
|
+
function getPackageRoot() {
|
|
52
|
+
const thisFile = new URL(import.meta.url).pathname;
|
|
53
|
+
const normalized = process.platform === "win32" && thisFile.startsWith("/") ? thisFile.slice(1) : thisFile;
|
|
54
|
+
let dir = path3.dirname(normalized);
|
|
55
|
+
for (let i = 0; i < 10; i++) {
|
|
56
|
+
if (fs.existsSync(path3.join(dir, "package.json"))) {
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
const parent = path3.dirname(dir);
|
|
60
|
+
if (parent === dir) break;
|
|
61
|
+
dir = parent;
|
|
62
|
+
}
|
|
63
|
+
return path3.resolve(path3.dirname(normalized), "..", "..");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// setup/install-mcp.ts
|
|
67
|
+
function getServerEntryPath() {
|
|
68
|
+
return path4.join(getPackageRoot(), "dist", "index.js");
|
|
69
|
+
}
|
|
70
|
+
function installMcp(options = {}) {
|
|
71
|
+
const configPath = getGlobalMcpConfigPath();
|
|
72
|
+
let config = {};
|
|
73
|
+
if (fs2.existsSync(configPath)) {
|
|
74
|
+
try {
|
|
75
|
+
const raw = fs2.readFileSync(configPath, "utf-8");
|
|
76
|
+
config = JSON.parse(raw);
|
|
77
|
+
} catch {
|
|
78
|
+
return {
|
|
79
|
+
installed: false,
|
|
80
|
+
configPath,
|
|
81
|
+
message: `Failed to parse ${configPath}. Back it up and try again.`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const servers = config.mcpServers ?? {};
|
|
86
|
+
if ("skill-codex" in servers && !options.force) {
|
|
87
|
+
return {
|
|
88
|
+
installed: false,
|
|
89
|
+
configPath,
|
|
90
|
+
message: "skill-codex MCP server already registered. Use --force to overwrite."
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const entryPath = getServerEntryPath();
|
|
94
|
+
const updatedConfig = {
|
|
95
|
+
...config,
|
|
96
|
+
mcpServers: {
|
|
97
|
+
...servers,
|
|
98
|
+
"skill-codex": {
|
|
99
|
+
command: "node",
|
|
100
|
+
args: [entryPath],
|
|
101
|
+
env: {}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const dir = path4.dirname(configPath);
|
|
106
|
+
if (!fs2.existsSync(dir)) {
|
|
107
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
const tmpPath = configPath + ".tmp";
|
|
110
|
+
fs2.writeFileSync(tmpPath, JSON.stringify(updatedConfig, null, 2) + "\n", "utf-8");
|
|
111
|
+
fs2.renameSync(tmpPath, configPath);
|
|
112
|
+
return {
|
|
113
|
+
installed: true,
|
|
114
|
+
configPath,
|
|
115
|
+
message: `MCP server registered in ${configPath}`
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// setup/install-commands.ts
|
|
120
|
+
import fs3 from "fs";
|
|
121
|
+
import path5 from "path";
|
|
122
|
+
var COMMAND_FILES = ["codex-review.md", "codex-do.md", "codex-consult.md"];
|
|
123
|
+
function getCommandsSourceDir() {
|
|
124
|
+
return path5.join(getPackageRoot(), "commands");
|
|
125
|
+
}
|
|
126
|
+
function installCommands(options = {}) {
|
|
127
|
+
const targetDir = options.global !== false ? getGlobalCommandsDir() : path5.join(options.projectDir ?? process.cwd(), ".claude", "commands");
|
|
128
|
+
const sourceDir = getCommandsSourceDir();
|
|
129
|
+
if (!fs3.existsSync(targetDir)) {
|
|
130
|
+
fs3.mkdirSync(targetDir, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
const installed = [];
|
|
133
|
+
const skipped = [];
|
|
134
|
+
for (const file of COMMAND_FILES) {
|
|
135
|
+
const sourcePath = path5.join(sourceDir, file);
|
|
136
|
+
const targetPath = path5.join(targetDir, file);
|
|
137
|
+
if (!fs3.existsSync(sourcePath)) {
|
|
138
|
+
skipped.push(file);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const sourceContent = fs3.readFileSync(sourcePath, "utf-8");
|
|
142
|
+
if (fs3.existsSync(targetPath)) {
|
|
143
|
+
const existingContent = fs3.readFileSync(targetPath, "utf-8");
|
|
144
|
+
if (existingContent === sourceContent) {
|
|
145
|
+
skipped.push(file);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
fs3.writeFileSync(targetPath, sourceContent, "utf-8");
|
|
150
|
+
installed.push(file);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
installed,
|
|
154
|
+
skipped,
|
|
155
|
+
targetDir,
|
|
156
|
+
message: installed.length > 0 ? `Installed ${installed.length} command(s) to ${targetDir}` : "All commands already up to date"
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// setup/install-hook.ts
|
|
161
|
+
import fs4 from "fs";
|
|
162
|
+
import path6 from "path";
|
|
163
|
+
function getHookScriptPath() {
|
|
164
|
+
const hooksDir = path6.join(getPackageRoot(), "hooks");
|
|
165
|
+
return isWindows() ? path6.join(hooksDir, "post-tool-use-review.ps1") : path6.join(hooksDir, "post-tool-use-review.sh");
|
|
166
|
+
}
|
|
167
|
+
function buildHookCommand() {
|
|
168
|
+
const scriptPath = getHookScriptPath();
|
|
169
|
+
if (!fs4.existsSync(scriptPath)) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
const command2 = isWindows() ? `powershell -ExecutionPolicy Bypass -File "${scriptPath}"` : `bash "${scriptPath}"`;
|
|
173
|
+
return { command: command2, scriptPath };
|
|
174
|
+
}
|
|
175
|
+
function installHook() {
|
|
176
|
+
const settingsPath = getClaudeSettingsPath();
|
|
177
|
+
let settings = {};
|
|
178
|
+
if (fs4.existsSync(settingsPath)) {
|
|
179
|
+
try {
|
|
180
|
+
const raw = fs4.readFileSync(settingsPath, "utf-8");
|
|
181
|
+
settings = JSON.parse(raw);
|
|
182
|
+
} catch {
|
|
183
|
+
return {
|
|
184
|
+
installed: false,
|
|
185
|
+
settingsPath,
|
|
186
|
+
message: `Failed to parse ${settingsPath}. Back it up and fix manually.`
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const hookResult = buildHookCommand();
|
|
191
|
+
if (!hookResult) {
|
|
192
|
+
return {
|
|
193
|
+
installed: false,
|
|
194
|
+
settingsPath,
|
|
195
|
+
message: "Hook script not found. Run `npm run build` first."
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const hookEntry = {
|
|
199
|
+
matcher: "Write|Edit|MultiEdit|NotebookEdit",
|
|
200
|
+
hooks: [
|
|
201
|
+
{
|
|
202
|
+
type: "command",
|
|
203
|
+
command: hookResult.command
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
};
|
|
207
|
+
const existingHooks = settings.hooks?.PostToolUse ?? [];
|
|
208
|
+
const alreadyExists = existingHooks.some(
|
|
209
|
+
(h) => h.hooks?.some((inner) => inner.command.includes("skill-codex"))
|
|
210
|
+
);
|
|
211
|
+
if (alreadyExists) {
|
|
212
|
+
return {
|
|
213
|
+
installed: false,
|
|
214
|
+
settingsPath,
|
|
215
|
+
message: "skill-codex hook already registered."
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const updatedSettings = {
|
|
219
|
+
...settings,
|
|
220
|
+
hooks: {
|
|
221
|
+
...settings.hooks,
|
|
222
|
+
PostToolUse: [...existingHooks, hookEntry]
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const dir = path6.dirname(settingsPath);
|
|
226
|
+
if (!fs4.existsSync(dir)) {
|
|
227
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
228
|
+
}
|
|
229
|
+
const tmpPath = settingsPath + ".tmp";
|
|
230
|
+
fs4.writeFileSync(tmpPath, JSON.stringify(updatedSettings, null, 2) + "\n", "utf-8");
|
|
231
|
+
fs4.renameSync(tmpPath, settingsPath);
|
|
232
|
+
if (!isWindows()) {
|
|
233
|
+
const shPath = path6.resolve(path6.dirname(getHookScriptPath()), "post-tool-use-review.sh");
|
|
234
|
+
try {
|
|
235
|
+
fs4.chmodSync(shPath, 493);
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
installed: true,
|
|
241
|
+
settingsPath,
|
|
242
|
+
message: `PostToolUse hook registered in ${settingsPath}`
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// setup/verify.ts
|
|
247
|
+
import fs5 from "fs";
|
|
248
|
+
import which from "which";
|
|
249
|
+
async function runVerification() {
|
|
250
|
+
const results = [];
|
|
251
|
+
const nodeVersion = process.versions.node;
|
|
252
|
+
const nodeMajor = parseInt(nodeVersion.split(".")[0] ?? "0", 10);
|
|
253
|
+
results.push({
|
|
254
|
+
name: "Node.js >= 18",
|
|
255
|
+
pass: nodeMajor >= 18,
|
|
256
|
+
detail: `v${nodeVersion}`
|
|
257
|
+
});
|
|
258
|
+
let codexPath = null;
|
|
259
|
+
try {
|
|
260
|
+
codexPath = await which("codex");
|
|
261
|
+
results.push({ name: "Codex CLI found", pass: true, detail: codexPath });
|
|
262
|
+
} catch {
|
|
263
|
+
results.push({ name: "Codex CLI found", pass: false, detail: "Not found. Run: npm i -g @openai/codex" });
|
|
264
|
+
}
|
|
265
|
+
const mcpPath = getGlobalMcpConfigPath();
|
|
266
|
+
let mcpRegistered = false;
|
|
267
|
+
if (fs5.existsSync(mcpPath)) {
|
|
268
|
+
try {
|
|
269
|
+
const raw = fs5.readFileSync(mcpPath, "utf-8");
|
|
270
|
+
const config = JSON.parse(raw);
|
|
271
|
+
mcpRegistered = "skill-codex" in (config.mcpServers ?? {});
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
results.push({
|
|
276
|
+
name: "MCP server registered",
|
|
277
|
+
pass: mcpRegistered,
|
|
278
|
+
detail: mcpRegistered ? mcpPath : `Not found in ${mcpPath}`
|
|
279
|
+
});
|
|
280
|
+
const commandsDir = getGlobalCommandsDir();
|
|
281
|
+
const expectedCommands = ["codex-review.md", "codex-do.md", "codex-consult.md"];
|
|
282
|
+
const missingCommands = expectedCommands.filter(
|
|
283
|
+
(cmd) => !fs5.existsSync(`${commandsDir}/${cmd}`)
|
|
284
|
+
);
|
|
285
|
+
results.push({
|
|
286
|
+
name: "Slash commands installed",
|
|
287
|
+
pass: missingCommands.length === 0,
|
|
288
|
+
detail: missingCommands.length === 0 ? `All 3 commands in ${commandsDir}` : `Missing: ${missingCommands.join(", ")}`
|
|
289
|
+
});
|
|
290
|
+
return {
|
|
291
|
+
results,
|
|
292
|
+
allPassed: results.every((r) => r.pass)
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// setup/setup.ts
|
|
297
|
+
function log(icon, message) {
|
|
298
|
+
process.stdout.write(`${icon} ${message}
|
|
299
|
+
`);
|
|
300
|
+
}
|
|
301
|
+
async function runSetup(options = {}) {
|
|
302
|
+
log(">>", "skill-codex setup\n");
|
|
303
|
+
log(" ", "Registering MCP server...");
|
|
304
|
+
const mcpResult = installMcp({ force: options.force });
|
|
305
|
+
log(mcpResult.installed ? "[ok]" : "[--]", mcpResult.message);
|
|
306
|
+
log(" ", "Installing slash commands...");
|
|
307
|
+
const cmdResult = installCommands({ global: true });
|
|
308
|
+
log(cmdResult.installed.length > 0 ? "[ok]" : "[--]", cmdResult.message);
|
|
309
|
+
log(" ", "Registering auto-review hook...");
|
|
310
|
+
const hookResult = installHook();
|
|
311
|
+
log(hookResult.installed ? "[ok]" : "[--]", hookResult.message);
|
|
312
|
+
log("\n ", "Verifying installation...\n");
|
|
313
|
+
const verification = await runVerification();
|
|
314
|
+
for (const check of verification.results) {
|
|
315
|
+
const icon = check.pass ? "[ok]" : "[!!]";
|
|
316
|
+
log(` ${icon}`, `${check.name}: ${check.detail}`);
|
|
317
|
+
}
|
|
318
|
+
log("", "");
|
|
319
|
+
if (verification.allPassed) {
|
|
320
|
+
log("[ok]", "Setup complete! Restart Claude Code to activate.\n");
|
|
321
|
+
log(" ", "Available commands:");
|
|
322
|
+
log(" ", " /codex-review - Code review by Codex");
|
|
323
|
+
log(" ", " /codex-do - Delegate a task to Codex");
|
|
324
|
+
log(" ", " /codex-consult - Get a second opinion from Codex");
|
|
325
|
+
log("", "");
|
|
326
|
+
log(" ", "Tip: Add .skill-codex.lock to your .gitignore");
|
|
327
|
+
} else {
|
|
328
|
+
log("[!!]", "Setup completed with warnings. Fix the issues above and run: npx skill-codex verify\n");
|
|
329
|
+
}
|
|
330
|
+
return verification.allPassed;
|
|
331
|
+
}
|
|
332
|
+
async function runUninstall() {
|
|
333
|
+
log(">>", "skill-codex uninstall\n");
|
|
334
|
+
const mcpConfigPath = getGlobalMcpConfigPath();
|
|
335
|
+
try {
|
|
336
|
+
const raw = fs6.readFileSync(mcpConfigPath, "utf-8");
|
|
337
|
+
const config = JSON.parse(raw);
|
|
338
|
+
const mcpServers = config.mcpServers;
|
|
339
|
+
if (mcpServers && "skill-codex" in mcpServers) {
|
|
340
|
+
delete mcpServers["skill-codex"];
|
|
341
|
+
fs6.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
342
|
+
log("[ok]", "Removed MCP server");
|
|
343
|
+
} else {
|
|
344
|
+
log("[--]", "MCP server not found");
|
|
345
|
+
}
|
|
346
|
+
} catch {
|
|
347
|
+
log("[--]", "MCP server not found (could not read ~/.claude.json)");
|
|
348
|
+
}
|
|
349
|
+
const commandsDir = getGlobalCommandsDir();
|
|
350
|
+
const commandFiles = ["codex-review.md", "codex-do.md", "codex-consult.md"];
|
|
351
|
+
for (const file of commandFiles) {
|
|
352
|
+
const filePath = path7.join(commandsDir, file);
|
|
353
|
+
try {
|
|
354
|
+
fs6.unlinkSync(filePath);
|
|
355
|
+
log("[ok]", `Removed ${file}`);
|
|
356
|
+
} catch {
|
|
357
|
+
log("[--]", `${file} not found`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const settingsPath = getClaudeSettingsPath();
|
|
361
|
+
try {
|
|
362
|
+
const raw = fs6.readFileSync(settingsPath, "utf-8");
|
|
363
|
+
const settings = JSON.parse(raw);
|
|
364
|
+
const hooks = settings.hooks;
|
|
365
|
+
if (hooks) {
|
|
366
|
+
let removed = false;
|
|
367
|
+
for (const eventType of Object.keys(hooks)) {
|
|
368
|
+
const before = hooks[eventType].length;
|
|
369
|
+
hooks[eventType] = hooks[eventType].filter(
|
|
370
|
+
(entry) => !(entry.command ?? "").includes("skill-codex")
|
|
371
|
+
);
|
|
372
|
+
if (hooks[eventType].length < before) removed = true;
|
|
373
|
+
}
|
|
374
|
+
if (removed) {
|
|
375
|
+
fs6.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
376
|
+
log("[ok]", "Removed PostToolUse hook");
|
|
377
|
+
} else {
|
|
378
|
+
log("[--]", "PostToolUse hook not found");
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
log("[--]", "PostToolUse hook not found");
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
log("[--]", "Could not read ~/.claude/settings.json");
|
|
385
|
+
}
|
|
386
|
+
log("", "");
|
|
387
|
+
log("[ok]", "Uninstall complete. Restart Claude Code to apply changes.");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// bin/skill-codex.ts
|
|
391
|
+
var args = process.argv.slice(2);
|
|
392
|
+
var command = args[0];
|
|
393
|
+
function getVersion() {
|
|
394
|
+
const __dirname = path8.dirname(fileURLToPath(import.meta.url));
|
|
395
|
+
const pkgPath = path8.resolve(__dirname, "..", "package.json");
|
|
396
|
+
try {
|
|
397
|
+
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
398
|
+
return pkg.version ?? "0.0.0";
|
|
399
|
+
} catch {
|
|
400
|
+
return "0.0.0";
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async function main() {
|
|
404
|
+
if (command === "--help" || command === "-h") {
|
|
405
|
+
const version = getVersion();
|
|
406
|
+
process.stdout.write(`skill-codex v${version}
|
|
407
|
+
|
|
408
|
+
Usage:
|
|
409
|
+
skill-codex setup Install MCP server, commands, and hook
|
|
410
|
+
skill-codex setup --force Overwrite existing configuration
|
|
411
|
+
skill-codex verify Check installation status
|
|
412
|
+
skill-codex uninstall Show uninstall instructions
|
|
413
|
+
skill-codex --help, -h Show this help message
|
|
414
|
+
skill-codex --version, -v Show version
|
|
415
|
+
`);
|
|
416
|
+
process.exit(0);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (command === "--version" || command === "-v") {
|
|
420
|
+
process.stdout.write(`${getVersion()}
|
|
421
|
+
`);
|
|
422
|
+
process.exit(0);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
switch (command) {
|
|
426
|
+
case "setup": {
|
|
427
|
+
const force = args.includes("--force");
|
|
428
|
+
const success = await runSetup({ force });
|
|
429
|
+
process.exit(success ? 0 : 1);
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
case "verify": {
|
|
433
|
+
const { results, allPassed } = await runVerification();
|
|
434
|
+
for (const check of results) {
|
|
435
|
+
const icon = check.pass ? "[ok]" : "[!!]";
|
|
436
|
+
process.stdout.write(`${icon} ${check.name}: ${check.detail}
|
|
437
|
+
`);
|
|
438
|
+
}
|
|
439
|
+
process.exit(allPassed ? 0 : 1);
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
case "uninstall": {
|
|
443
|
+
await runUninstall();
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
default: {
|
|
447
|
+
const version = getVersion();
|
|
448
|
+
process.stdout.write(`skill-codex v${version}
|
|
449
|
+
|
|
450
|
+
Usage:
|
|
451
|
+
skill-codex setup Install MCP server, commands, and hook
|
|
452
|
+
skill-codex setup --force Overwrite existing configuration
|
|
453
|
+
skill-codex verify Check installation status
|
|
454
|
+
skill-codex uninstall Show uninstall instructions
|
|
455
|
+
skill-codex --help, -h Show this help message
|
|
456
|
+
skill-codex --version, -v Show version
|
|
457
|
+
`);
|
|
458
|
+
process.exit(command ? 1 : 0);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
main().catch((err) => {
|
|
463
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
|
|
464
|
+
`);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
});
|
|
467
|
+
//# sourceMappingURL=skill-codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../bin/skill-codex.ts","../../setup/setup.ts","../../setup/install-mcp.ts","../../src/config/paths.ts","../../src/util/platform.ts","../../src/config/package-root.ts","../../setup/install-commands.ts","../../setup/install-hook.ts","../../setup/verify.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { runSetup, runUninstall } from \"../setup/setup.js\";\nimport { runVerification } from \"../setup/verify.js\";\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction getVersion(): string {\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const pkgPath = path.resolve(__dirname, \"..\", \"package.json\");\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n return pkg.version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nasync function main(): Promise<void> {\n if (command === \"--help\" || command === \"-h\") {\n const version = getVersion();\n process.stdout.write(`skill-codex v${version}\n\nUsage:\n skill-codex setup Install MCP server, commands, and hook\n skill-codex setup --force Overwrite existing configuration\n skill-codex verify Check installation status\n skill-codex uninstall Show uninstall instructions\n skill-codex --help, -h Show this help message\n skill-codex --version, -v Show version\n`);\n process.exit(0);\n return;\n }\n\n if (command === \"--version\" || command === \"-v\") {\n process.stdout.write(`${getVersion()}\\n`);\n process.exit(0);\n return;\n }\n\n switch (command) {\n case \"setup\": {\n const force = args.includes(\"--force\");\n const success = await runSetup({ force });\n process.exit(success ? 0 : 1);\n break;\n }\n\n case \"verify\": {\n const { results, allPassed } = await runVerification();\n for (const check of results) {\n const icon = check.pass ? \"[ok]\" : \"[!!]\";\n process.stdout.write(`${icon} ${check.name}: ${check.detail}\\n`);\n }\n process.exit(allPassed ? 0 : 1);\n break;\n }\n\n case \"uninstall\": {\n await runUninstall();\n break;\n }\n\n default: {\n const version = getVersion();\n process.stdout.write(`skill-codex v${version}\n\nUsage:\n skill-codex setup Install MCP server, commands, and hook\n skill-codex setup --force Overwrite existing configuration\n skill-codex verify Check installation status\n skill-codex uninstall Show uninstall instructions\n skill-codex --help, -h Show this help message\n skill-codex --version, -v Show version\n`);\n process.exit(command ? 1 : 0);\n }\n }\n}\n\nmain().catch((err) => {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { installMcp } from \"./install-mcp.js\";\nimport { installCommands } from \"./install-commands.js\";\nimport { installHook } from \"./install-hook.js\";\nimport { runVerification } from \"./verify.js\";\nimport {\n getGlobalMcpConfigPath,\n getGlobalCommandsDir,\n getClaudeSettingsPath,\n} from \"../src/config/paths.js\";\n\nfunction log(icon: string, message: string): void {\n process.stdout.write(`${icon} ${message}\\n`);\n}\n\nexport async function runSetup(options: { force?: boolean } = {}): Promise<boolean> {\n log(\">>\", \"skill-codex setup\\n\");\n\n // Step 1: Install MCP server\n log(\" \", \"Registering MCP server...\");\n const mcpResult = installMcp({ force: options.force });\n log(mcpResult.installed ? \"[ok]\" : \"[--]\", mcpResult.message);\n\n // Step 2: Install slash commands\n log(\" \", \"Installing slash commands...\");\n const cmdResult = installCommands({ global: true });\n log(cmdResult.installed.length > 0 ? \"[ok]\" : \"[--]\", cmdResult.message);\n\n // Step 3: Install hook\n log(\" \", \"Registering auto-review hook...\");\n const hookResult = installHook();\n log(hookResult.installed ? \"[ok]\" : \"[--]\", hookResult.message);\n\n // Step 4: Verify\n log(\"\\n \", \"Verifying installation...\\n\");\n const verification = await runVerification();\n\n for (const check of verification.results) {\n const icon = check.pass ? \"[ok]\" : \"[!!]\";\n log(` ${icon}`, `${check.name}: ${check.detail}`);\n }\n\n // Summary\n log(\"\", \"\");\n if (verification.allPassed) {\n log(\"[ok]\", \"Setup complete! Restart Claude Code to activate.\\n\");\n log(\" \", \"Available commands:\");\n log(\" \", \" /codex-review - Code review by Codex\");\n log(\" \", \" /codex-do - Delegate a task to Codex\");\n log(\" \", \" /codex-consult - Get a second opinion from Codex\");\n log(\"\", \"\");\n log(\" \", \"Tip: Add .skill-codex.lock to your .gitignore\");\n } else {\n log(\"[!!]\", \"Setup completed with warnings. Fix the issues above and run: npx skill-codex verify\\n\");\n }\n\n return verification.allPassed;\n}\n\nexport async function runUninstall(): Promise<void> {\n log(\">>\", \"skill-codex uninstall\\n\");\n\n // Step 1: Remove MCP server from ~/.claude.json\n const mcpConfigPath = getGlobalMcpConfigPath();\n try {\n const raw = fs.readFileSync(mcpConfigPath, \"utf-8\");\n const config = JSON.parse(raw) as Record<string, unknown>;\n const mcpServers = (config as { mcpServers?: Record<string, unknown> }).mcpServers;\n if (mcpServers && \"skill-codex\" in mcpServers) {\n delete mcpServers[\"skill-codex\"];\n fs.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n log(\"[ok]\", \"Removed MCP server\");\n } else {\n log(\"[--]\", \"MCP server not found\");\n }\n } catch {\n log(\"[--]\", \"MCP server not found (could not read ~/.claude.json)\");\n }\n\n // Step 2: Remove slash commands from ~/.claude/commands/\n const commandsDir = getGlobalCommandsDir();\n const commandFiles = [\"codex-review.md\", \"codex-do.md\", \"codex-consult.md\"];\n for (const file of commandFiles) {\n const filePath = path.join(commandsDir, file);\n try {\n fs.unlinkSync(filePath);\n log(\"[ok]\", `Removed ${file}`);\n } catch {\n log(\"[--]\", `${file} not found`);\n }\n }\n\n // Step 3: Remove PostToolUse hook from ~/.claude/settings.json\n const settingsPath = getClaudeSettingsPath();\n try {\n const raw = fs.readFileSync(settingsPath, \"utf-8\");\n const settings = JSON.parse(raw) as Record<string, unknown>;\n type HookEntry = { command?: string; hooks?: HookEntry[] };\n type HooksMap = Record<string, HookEntry[]>;\n const hooks = settings.hooks as HooksMap | undefined;\n if (hooks) {\n let removed = false;\n for (const eventType of Object.keys(hooks)) {\n const before = hooks[eventType].length;\n hooks[eventType] = hooks[eventType].filter(\n (entry) => !(entry.command ?? \"\").includes(\"skill-codex\")\n );\n if (hooks[eventType].length < before) removed = true;\n }\n if (removed) {\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + \"\\n\", \"utf-8\");\n log(\"[ok]\", \"Removed PostToolUse hook\");\n } else {\n log(\"[--]\", \"PostToolUse hook not found\");\n }\n } else {\n log(\"[--]\", \"PostToolUse hook not found\");\n }\n } catch {\n log(\"[--]\", \"Could not read ~/.claude/settings.json\");\n }\n\n log(\"\", \"\");\n log(\"[ok]\", \"Uninstall complete. Restart Claude Code to apply changes.\");\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getGlobalMcpConfigPath } from \"../src/config/paths.js\";\nimport { getPackageRoot } from \"../src/config/package-root.js\";\n\ninterface McpConfig {\n mcpServers?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nfunction getServerEntryPath(): string {\n return path.join(getPackageRoot(), \"dist\", \"index.js\");\n}\n\nexport function installMcp(options: { force?: boolean } = {}): {\n installed: boolean;\n configPath: string;\n message: string;\n} {\n const configPath = getGlobalMcpConfigPath();\n let config: McpConfig = {};\n\n // Read existing config\n if (fs.existsSync(configPath)) {\n try {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n config = JSON.parse(raw) as McpConfig;\n } catch {\n return {\n installed: false,\n configPath,\n message: `Failed to parse ${configPath}. Back it up and try again.`,\n };\n }\n }\n\n // Check if already registered\n const servers = config.mcpServers ?? {};\n if (\"skill-codex\" in servers && !options.force) {\n return {\n installed: false,\n configPath,\n message: \"skill-codex MCP server already registered. Use --force to overwrite.\",\n };\n }\n\n const entryPath = getServerEntryPath();\n\n // Create new config with merged MCP server\n const updatedConfig: McpConfig = {\n ...config,\n mcpServers: {\n ...servers,\n \"skill-codex\": {\n command: \"node\",\n args: [entryPath],\n env: {},\n },\n },\n };\n\n // Ensure directory exists\n const dir = path.dirname(configPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Atomic write: write to temp file then rename to prevent corruption\n const tmpPath = configPath + \".tmp\";\n fs.writeFileSync(tmpPath, JSON.stringify(updatedConfig, null, 2) + \"\\n\", \"utf-8\");\n fs.renameSync(tmpPath, configPath);\n\n return {\n installed: true,\n configPath,\n message: `MCP server registered in ${configPath}`,\n };\n}\n","import path from \"node:path\";\nimport { getClaudeDir, getHomeDir } from \"../util/platform.js\";\n\nexport function getClaudeSettingsPath(): string {\n return path.join(getClaudeDir(), \"settings.json\");\n}\n\nexport function getGlobalMcpConfigPath(): string {\n return path.join(getHomeDir(), \".claude.json\");\n}\n\nexport function getGlobalCommandsDir(): string {\n return path.join(getClaudeDir(), \"commands\");\n}\n\nexport function getProjectCommandsDir(cwd: string): string {\n return path.join(cwd, \".claude\", \"commands\");\n}\n\nexport function getProjectMcpConfigPath(cwd: string): string {\n return path.join(cwd, \".mcp.json\");\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\n\nexport type Platform = \"win32\" | \"darwin\" | \"linux\";\n\nexport function getPlatform(): Platform {\n const p = os.platform();\n if (p === \"win32\" || p === \"darwin\" || p === \"linux\") return p;\n return \"linux\"; // default fallback for other unix-like\n}\n\nexport function isWindows(): boolean {\n return getPlatform() === \"win32\";\n}\n\nexport function normalizePath(p: string): string {\n return p.replace(/\\\\/g, \"/\");\n}\n\nexport function getHomeDir(): string {\n return os.homedir();\n}\n\nexport function getClaudeDir(): string {\n return path.join(getHomeDir(), \".claude\");\n}\n\nexport function getTempDir(): string {\n return os.tmpdir();\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Resolves the package root directory by walking up from the current file\n * until we find package.json. Works both in dev (src/) and after bundling (dist/).\n */\nexport function getPackageRoot(): string {\n const thisFile = new URL(import.meta.url).pathname;\n const normalized = process.platform === \"win32\" && thisFile.startsWith(\"/\")\n ? thisFile.slice(1)\n : thisFile;\n\n let dir = path.dirname(normalized);\n for (let i = 0; i < 10; i++) {\n if (fs.existsSync(path.join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = path.dirname(dir);\n if (parent === dir) break; // reached filesystem root\n dir = parent;\n }\n\n // Fallback: assume 2 levels up from dist/bin/\n return path.resolve(path.dirname(normalized), \"..\", \"..\");\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getGlobalCommandsDir } from \"../src/config/paths.js\";\nimport { getPackageRoot } from \"../src/config/package-root.js\";\n\nconst COMMAND_FILES = [\"codex-review.md\", \"codex-do.md\", \"codex-consult.md\"];\n\nfunction getCommandsSourceDir(): string {\n return path.join(getPackageRoot(), \"commands\");\n}\n\nexport function installCommands(options: { global?: boolean; projectDir?: string } = {}): {\n installed: string[];\n skipped: string[];\n targetDir: string;\n message: string;\n} {\n const targetDir = options.global !== false\n ? getGlobalCommandsDir()\n : path.join(options.projectDir ?? process.cwd(), \".claude\", \"commands\");\n\n const sourceDir = getCommandsSourceDir();\n\n // Ensure target directory exists\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n }\n\n const installed: string[] = [];\n const skipped: string[] = [];\n\n for (const file of COMMAND_FILES) {\n const sourcePath = path.join(sourceDir, file);\n const targetPath = path.join(targetDir, file);\n\n if (!fs.existsSync(sourcePath)) {\n skipped.push(file);\n continue;\n }\n\n const sourceContent = fs.readFileSync(sourcePath, \"utf-8\");\n\n // Skip if identical content already exists\n if (fs.existsSync(targetPath)) {\n const existingContent = fs.readFileSync(targetPath, \"utf-8\");\n if (existingContent === sourceContent) {\n skipped.push(file);\n continue;\n }\n }\n\n fs.writeFileSync(targetPath, sourceContent, \"utf-8\");\n installed.push(file);\n }\n\n return {\n installed,\n skipped,\n targetDir,\n message: installed.length > 0\n ? `Installed ${installed.length} command(s) to ${targetDir}`\n : \"All commands already up to date\",\n };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getClaudeSettingsPath } from \"../src/config/paths.js\";\nimport { isWindows } from \"../src/util/platform.js\";\nimport { getPackageRoot } from \"../src/config/package-root.js\";\n\ninterface HookCommand {\n type: \"command\";\n command: string;\n}\n\ninterface HookEntry {\n matcher: string;\n hooks: HookCommand[];\n}\n\ninterface ClaudeSettings {\n hooks?: {\n PostToolUse?: HookEntry[];\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nfunction getHookScriptPath(): string {\n const hooksDir = path.join(getPackageRoot(), \"hooks\");\n return isWindows()\n ? path.join(hooksDir, \"post-tool-use-review.ps1\")\n : path.join(hooksDir, \"post-tool-use-review.sh\");\n}\n\nfunction buildHookCommand(): { command: string; scriptPath: string } | null {\n const scriptPath = getHookScriptPath();\n if (!fs.existsSync(scriptPath)) {\n return null;\n }\n const command = isWindows()\n ? `powershell -ExecutionPolicy Bypass -File \"${scriptPath}\"`\n : `bash \"${scriptPath}\"`;\n return { command, scriptPath };\n}\n\nexport function installHook(): {\n installed: boolean;\n settingsPath: string;\n message: string;\n} {\n const settingsPath = getClaudeSettingsPath();\n let settings: ClaudeSettings = {};\n\n if (fs.existsSync(settingsPath)) {\n try {\n const raw = fs.readFileSync(settingsPath, \"utf-8\");\n settings = JSON.parse(raw) as ClaudeSettings;\n } catch {\n return {\n installed: false,\n settingsPath,\n message: `Failed to parse ${settingsPath}. Back it up and fix manually.`,\n };\n }\n }\n\n const hookResult = buildHookCommand();\n if (!hookResult) {\n return {\n installed: false,\n settingsPath,\n message: \"Hook script not found. Run `npm run build` first.\",\n };\n }\n\n // Correct Claude Code hook format: matcher + hooks array\n const hookEntry: HookEntry = {\n matcher: \"Write|Edit|MultiEdit|NotebookEdit\",\n hooks: [\n {\n type: \"command\",\n command: hookResult.command,\n },\n ],\n };\n\n const existingHooks = settings.hooks?.PostToolUse ?? [];\n\n // Check if already registered (search in nested hooks array)\n const alreadyExists = existingHooks.some((h) =>\n h.hooks?.some((inner) => inner.command.includes(\"skill-codex\")),\n );\n if (alreadyExists) {\n return {\n installed: false,\n settingsPath,\n message: \"skill-codex hook already registered.\",\n };\n }\n\n const updatedSettings: ClaudeSettings = {\n ...settings,\n hooks: {\n ...settings.hooks,\n PostToolUse: [...existingHooks, hookEntry],\n },\n };\n\n const dir = path.dirname(settingsPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Atomic write: temp file then rename\n const tmpPath = settingsPath + \".tmp\";\n fs.writeFileSync(tmpPath, JSON.stringify(updatedSettings, null, 2) + \"\\n\", \"utf-8\");\n fs.renameSync(tmpPath, settingsPath);\n\n // Ensure bash script is executable on unix\n if (!isWindows()) {\n const shPath = path.resolve(path.dirname(getHookScriptPath()), \"post-tool-use-review.sh\");\n try {\n fs.chmodSync(shPath, 0o755);\n } catch {\n // Best effort\n }\n }\n\n return {\n installed: true,\n settingsPath,\n message: `PostToolUse hook registered in ${settingsPath}`,\n };\n}\n","import fs from \"node:fs\";\nimport which from \"which\";\nimport { getGlobalMcpConfigPath, getGlobalCommandsDir } from \"../src/config/paths.js\";\n\ninterface CheckResult {\n readonly name: string;\n readonly pass: boolean;\n readonly detail: string;\n}\n\nexport async function runVerification(): Promise<{\n results: CheckResult[];\n allPassed: boolean;\n}> {\n const results: CheckResult[] = [];\n\n // 1. Node.js version\n const nodeVersion = process.versions.node;\n const nodeMajor = parseInt(nodeVersion.split(\".\")[0] ?? \"0\", 10);\n results.push({\n name: \"Node.js >= 18\",\n pass: nodeMajor >= 18,\n detail: `v${nodeVersion}`,\n });\n\n // 2. Codex CLI on PATH\n let codexPath: string | null = null;\n try {\n codexPath = await which(\"codex\");\n results.push({ name: \"Codex CLI found\", pass: true, detail: codexPath });\n } catch {\n results.push({ name: \"Codex CLI found\", pass: false, detail: \"Not found. Run: npm i -g @openai/codex\" });\n }\n\n // 3. MCP server registered\n const mcpPath = getGlobalMcpConfigPath();\n let mcpRegistered = false;\n if (fs.existsSync(mcpPath)) {\n try {\n const raw = fs.readFileSync(mcpPath, \"utf-8\");\n const config = JSON.parse(raw);\n mcpRegistered = \"skill-codex\" in (config.mcpServers ?? {});\n } catch {\n // Parse error\n }\n }\n results.push({\n name: \"MCP server registered\",\n pass: mcpRegistered,\n detail: mcpRegistered ? mcpPath : `Not found in ${mcpPath}`,\n });\n\n // 4. Slash commands installed\n const commandsDir = getGlobalCommandsDir();\n const expectedCommands = [\"codex-review.md\", \"codex-do.md\", \"codex-consult.md\"];\n const missingCommands = expectedCommands.filter(\n (cmd) => !fs.existsSync(`${commandsDir}/${cmd}`),\n );\n results.push({\n name: \"Slash commands installed\",\n pass: missingCommands.length === 0,\n detail: missingCommands.length === 0\n ? `All 3 commands in ${commandsDir}`\n : `Missing: ${missingCommands.join(\", \")}`,\n });\n\n return {\n results,\n allPassed: results.every((r) => r.pass),\n };\n}\n"],"mappings":"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","names":["fs","path","fs","path","fs","path","path","path","path","path","fs","fs","path","path","fs","fs","path","path","fs","command","fs","fs","fs","path","path","fs"]}
|
package/dist/index.d.ts
ADDED