claude-code-pack 1.0.1 → 1.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/README.md +14 -1
- package/bin/claude-pack.mjs +2 -0
- package/claude-pack.config.json +7 -0
- package/package.json +1 -1
- package/src/install.mjs +123 -2
package/README.md
CHANGED
|
@@ -88,9 +88,21 @@ Everything is fetched fresh from GitHub, so you always get the latest version.
|
|
|
88
88
|
|
|
89
89
|
| Setting | Value |
|
|
90
90
|
|---------|-------|
|
|
91
|
-
| **Model** | `opus` |
|
|
91
|
+
| **Model (Claude Code)** | `opus` |
|
|
92
|
+
| **Model (Codex)** | `gpt-5.4` (reasoning effort: `xhigh`) |
|
|
92
93
|
| **Statusline** | Custom bash script with context window, 5h/7d rate limit bars, and color-coded usage indicators |
|
|
93
94
|
|
|
95
|
+
### Codex Integration
|
|
96
|
+
|
|
97
|
+
The installer also generates a `~/.codex/config.toml` that **reuses the same MCP servers and skills** as Claude Code — no duplicate configuration needed.
|
|
98
|
+
|
|
99
|
+
| What | How it's shared |
|
|
100
|
+
|------|----------------|
|
|
101
|
+
| **MCP servers** | Generated into `config.toml` from the same `mcpServers` in `claude-pack.config.json` |
|
|
102
|
+
| **Skills** | Codex `[[skills.config]]` points to `~/.claude/skills/` (the same directory Claude Code uses) |
|
|
103
|
+
|
|
104
|
+
This means when you add a new MCP server or skill to the pack, both Claude Code and Codex pick it up.
|
|
105
|
+
|
|
94
106
|
## Commands
|
|
95
107
|
|
|
96
108
|
```bash
|
|
@@ -103,6 +115,7 @@ claude-pack install --force # Overwrite existing installations
|
|
|
103
115
|
claude-pack install --skip-plugins # Skip plugin installation
|
|
104
116
|
claude-pack install --skip-skills # Skip skill installation
|
|
105
117
|
claude-pack install --skip-settings # Skip settings merge
|
|
118
|
+
claude-pack install --skip-codex # Skip Codex config generation
|
|
106
119
|
claude-pack install --dry-run # Preview without changes
|
|
107
120
|
```
|
|
108
121
|
|
package/bin/claude-pack.mjs
CHANGED
|
@@ -11,6 +11,7 @@ const flags = {
|
|
|
11
11
|
skipPlugins: args.includes('--skip-plugins'),
|
|
12
12
|
skipSkills: args.includes('--skip-skills'),
|
|
13
13
|
skipSettings: args.includes('--skip-settings'),
|
|
14
|
+
skipCodex: args.includes('--skip-codex'),
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
switch (command) {
|
|
@@ -44,5 +45,6 @@ Flags:
|
|
|
44
45
|
--skip-plugins Skip plugin installation
|
|
45
46
|
--skip-skills Skip skill installation
|
|
46
47
|
--skip-settings Skip settings merge
|
|
48
|
+
--skip-codex Skip Codex config generation
|
|
47
49
|
`);
|
|
48
50
|
}
|
package/claude-pack.config.json
CHANGED
|
@@ -87,5 +87,12 @@
|
|
|
87
87
|
},
|
|
88
88
|
"assets": {
|
|
89
89
|
"statusline": "assets/statusline-command.sh"
|
|
90
|
+
},
|
|
91
|
+
"codex": {
|
|
92
|
+
"enabled": true,
|
|
93
|
+
"model": "gpt-5.4",
|
|
94
|
+
"model_reasoning_effort": "xhigh",
|
|
95
|
+
"configPath": "$HOME/.codex/config.toml",
|
|
96
|
+
"skillsPath": "$HOME/.claude/skills"
|
|
90
97
|
}
|
|
91
98
|
}
|
package/package.json
CHANGED
package/src/install.mjs
CHANGED
|
@@ -361,6 +361,7 @@ async function installSettings(config, flags) {
|
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
// Merge MCP servers
|
|
364
|
+
let resolvedFsPath = null;
|
|
364
365
|
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
|
365
366
|
console.log('\n🔌 MCP Servers');
|
|
366
367
|
if (!settings.mcpServers) settings.mcpServers = {};
|
|
@@ -377,6 +378,7 @@ async function installSettings(config, flags) {
|
|
|
377
378
|
const answer = await prompt(` Use "${home}" as filesystem root? [Y/n/custom path] `);
|
|
378
379
|
|
|
379
380
|
if (answer === '' || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
381
|
+
resolvedFsPath = home;
|
|
380
382
|
const resolved = JSON.parse(JSON.stringify(serverConfig));
|
|
381
383
|
resolved.args = resolved.args.map((a) => a === '$HOME' ? home : a);
|
|
382
384
|
settings.mcpServers[name] = resolved;
|
|
@@ -392,6 +394,7 @@ async function installSettings(config, flags) {
|
|
|
392
394
|
} else {
|
|
393
395
|
// User provided a custom path
|
|
394
396
|
const customPath = answer.replace(/^~/, home);
|
|
397
|
+
resolvedFsPath = customPath;
|
|
395
398
|
const resolved = JSON.parse(JSON.stringify(serverConfig));
|
|
396
399
|
resolved.args = resolved.args.map((a) => a === '$HOME' ? customPath : a);
|
|
397
400
|
settings.mcpServers[name] = resolved;
|
|
@@ -413,6 +416,118 @@ async function installSettings(config, flags) {
|
|
|
413
416
|
if (!flags.dryRun) {
|
|
414
417
|
writeJSON(SETTINGS_PATH, settings);
|
|
415
418
|
}
|
|
419
|
+
|
|
420
|
+
return resolvedFsPath;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ─── Codex Config Generation ───────────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
function tomlValue(val) {
|
|
426
|
+
if (typeof val === 'string') return `"${val}"`;
|
|
427
|
+
if (typeof val === 'boolean') return val ? 'true' : 'false';
|
|
428
|
+
if (typeof val === 'number') return String(val);
|
|
429
|
+
if (Array.isArray(val)) {
|
|
430
|
+
const items = val.map(tomlValue);
|
|
431
|
+
// Use multiline for long arrays
|
|
432
|
+
if (items.join(', ').length > 60) {
|
|
433
|
+
return '[\n ' + items.join(',\n ') + '\n]';
|
|
434
|
+
}
|
|
435
|
+
return '[' + items.join(', ') + ']';
|
|
436
|
+
}
|
|
437
|
+
return `"${val}"`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function generateCodexToml(config, resolvedFsPath) {
|
|
441
|
+
const codex = config.codex;
|
|
442
|
+
const home = homedir();
|
|
443
|
+
const lines = [];
|
|
444
|
+
|
|
445
|
+
lines.push(`model = "${codex.model}"`);
|
|
446
|
+
if (codex.model_reasoning_effort) {
|
|
447
|
+
lines.push(`model_reasoning_effort = "${codex.model_reasoning_effort}"`);
|
|
448
|
+
}
|
|
449
|
+
lines.push('');
|
|
450
|
+
|
|
451
|
+
// Generate MCP server sections from the shared config
|
|
452
|
+
for (const [name, serverConfig] of Object.entries(config.mcpServers || {})) {
|
|
453
|
+
lines.push(`[mcp_servers.${name}]`);
|
|
454
|
+
lines.push('enabled = true');
|
|
455
|
+
|
|
456
|
+
if (serverConfig.type === 'http' || serverConfig.url) {
|
|
457
|
+
lines.push(`url = "${serverConfig.url}"`);
|
|
458
|
+
} else if (serverConfig.command) {
|
|
459
|
+
let command = serverConfig.command;
|
|
460
|
+
const args = serverConfig.args || [];
|
|
461
|
+
|
|
462
|
+
// For npx commands, resolve to full node/npx path for Codex compatibility
|
|
463
|
+
let resolvedArgs = args.map((a) => {
|
|
464
|
+
if (a === '$HOME') return resolvedFsPath || home;
|
|
465
|
+
return a;
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
lines.push(`command = "${command}"`);
|
|
469
|
+
if (resolvedArgs.length > 0) {
|
|
470
|
+
lines.push(`args = ${tomlValue(resolvedArgs)}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Environment variables
|
|
475
|
+
if (serverConfig.env && Object.keys(serverConfig.env).length > 0) {
|
|
476
|
+
lines.push('');
|
|
477
|
+
lines.push(`[mcp_servers.${name}.env]`);
|
|
478
|
+
for (const [k, v] of Object.entries(serverConfig.env)) {
|
|
479
|
+
lines.push(`${k} = "${v}"`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
lines.push('');
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Skills — point to the shared ~/.claude/skills directory
|
|
487
|
+
const skillsPath = (codex.skillsPath || '$HOME/.claude/skills').replace(/\$HOME/g, home);
|
|
488
|
+
lines.push('[[skills.config]]');
|
|
489
|
+
lines.push(`path = "${skillsPath}"`);
|
|
490
|
+
lines.push('enabled = true');
|
|
491
|
+
lines.push('');
|
|
492
|
+
|
|
493
|
+
return lines.join('\n');
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async function installCodex(config, flags, resolvedFsPath) {
|
|
497
|
+
if (!config.codex?.enabled) return;
|
|
498
|
+
|
|
499
|
+
console.log('\n🤖 Codex');
|
|
500
|
+
|
|
501
|
+
const home = homedir();
|
|
502
|
+
const configPath = (config.codex.configPath || '$HOME/.codex/config.toml').replace(/\$HOME/g, home);
|
|
503
|
+
const configDir = dirname(configPath);
|
|
504
|
+
|
|
505
|
+
if (flags.dryRun) {
|
|
506
|
+
log('○', `Would generate Codex config at ${configPath}`);
|
|
507
|
+
log('○', `Model: ${config.codex.model}`);
|
|
508
|
+
log('○', `Skills path: ~/.claude/skills (shared with Claude Code)`);
|
|
509
|
+
const mcpCount = Object.keys(config.mcpServers || {}).length;
|
|
510
|
+
log('○', `MCP servers: ${mcpCount} (same as Claude Code)`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const toml = generateCodexToml(config, resolvedFsPath);
|
|
515
|
+
ensureDir(configDir);
|
|
516
|
+
|
|
517
|
+
const exists = existsSync(configPath);
|
|
518
|
+
if (exists && !flags.force) {
|
|
519
|
+
const answer = await prompt(` Codex config exists at ${configPath}. Overwrite? [y/N] `);
|
|
520
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
521
|
+
log('⊘', 'Codex config skipped (use --force to overwrite)');
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
writeFileSync(configPath, toml);
|
|
527
|
+
log('✓', `Codex config written to ${configPath}`);
|
|
528
|
+
log('✓', `Model: ${config.codex.model}`);
|
|
529
|
+
log('✓', `Skills: ~/.claude/skills (shared with Claude Code)`);
|
|
530
|
+
log('✓', `MCP servers: ${Object.keys(config.mcpServers || {}).length} configured`);
|
|
416
531
|
}
|
|
417
532
|
|
|
418
533
|
// ─── Main Install ──────────────────────────────────────────────────────
|
|
@@ -446,13 +561,19 @@ export async function install(flags = {}) {
|
|
|
446
561
|
|
|
447
562
|
if (!flags.skipPlugins) installPlugins(config, flags);
|
|
448
563
|
if (!flags.skipSkills) installSkills(config, flags);
|
|
449
|
-
|
|
564
|
+
let resolvedFsPath = null;
|
|
565
|
+
if (!flags.skipSettings) {
|
|
566
|
+
resolvedFsPath = await installSettings(config, flags);
|
|
567
|
+
}
|
|
568
|
+
if (!flags.skipCodex) {
|
|
569
|
+
await installCodex(config, flags, resolvedFsPath);
|
|
570
|
+
}
|
|
450
571
|
|
|
451
572
|
console.log('\n────────────────────────────────────────────');
|
|
452
573
|
if (flags.dryRun) {
|
|
453
574
|
console.log(' Dry run complete. Run without --dry-run to apply.');
|
|
454
575
|
} else {
|
|
455
|
-
console.log(' ✓ All done! Restart Claude Code to pick up changes.');
|
|
576
|
+
console.log(' ✓ All done! Restart Claude Code / Codex to pick up changes.');
|
|
456
577
|
}
|
|
457
578
|
console.log('');
|
|
458
579
|
}
|