cli-ai-skills 1.7.3 → 1.7.6
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/bin/cli.js +7 -6
- package/lib/codex.js +61 -23
- package/lib/detector.js +65 -5
- package/lib/interactive.js +23 -12
- package/lib/ui/table.js +14 -9
- package/lib/utils/path-resolver.js +20 -1
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -96,7 +96,7 @@ async function main() {
|
|
|
96
96
|
displayToolsTable(detected);
|
|
97
97
|
|
|
98
98
|
const hasAny = detected.copilot.installed || detected.claude.installed ||
|
|
99
|
-
detected.
|
|
99
|
+
detected.codex_cli.installed || detected.codex_app.installed || detected.opencode.installed ||
|
|
100
100
|
detected.gemini.installed;
|
|
101
101
|
|
|
102
102
|
if (!hasAny) {
|
|
@@ -112,7 +112,7 @@ async function main() {
|
|
|
112
112
|
platforms = [];
|
|
113
113
|
if (detected.copilot.installed) platforms.push('copilot');
|
|
114
114
|
if (detected.claude.installed) platforms.push('claude');
|
|
115
|
-
if (detected.
|
|
115
|
+
if (detected.codex_cli.installed) platforms.push('codex_cli');
|
|
116
116
|
if (detected.opencode.installed) platforms.push('opencode');
|
|
117
117
|
if (detected.gemini.installed) platforms.push('gemini');
|
|
118
118
|
} else {
|
|
@@ -140,7 +140,7 @@ async function main() {
|
|
|
140
140
|
if (platforms.includes('claude')) {
|
|
141
141
|
installClaudeSkills(repoPath, [skill], quiet);
|
|
142
142
|
}
|
|
143
|
-
if (platforms.includes('codex')) {
|
|
143
|
+
if (platforms.includes('codex') || platforms.includes('codex_cli') || platforms.includes('codex_app')) {
|
|
144
144
|
installCodexSkills(repoPath, [skill], quiet);
|
|
145
145
|
}
|
|
146
146
|
if (platforms.includes('opencode')) {
|
|
@@ -167,7 +167,7 @@ async function main() {
|
|
|
167
167
|
displayToolsTable(detected);
|
|
168
168
|
|
|
169
169
|
const hasAny = detected.copilot.installed || detected.claude.installed ||
|
|
170
|
-
detected.
|
|
170
|
+
detected.codex_cli.installed || detected.codex_app.installed || detected.opencode.installed ||
|
|
171
171
|
detected.gemini.installed;
|
|
172
172
|
|
|
173
173
|
if (!hasAny) {
|
|
@@ -227,7 +227,8 @@ async function main() {
|
|
|
227
227
|
platforms = [];
|
|
228
228
|
if (detected.copilot.installed) platforms.push('copilot');
|
|
229
229
|
if (detected.claude.installed) platforms.push('claude');
|
|
230
|
-
if (detected.
|
|
230
|
+
if (detected.codex_cli.installed) platforms.push('codex_cli');
|
|
231
|
+
if (detected.codex_app.installed) platforms.push('codex_app');
|
|
231
232
|
if (detected.opencode.installed) platforms.push('opencode');
|
|
232
233
|
if (detected.gemini.installed) platforms.push('gemini');
|
|
233
234
|
} else {
|
|
@@ -254,7 +255,7 @@ async function main() {
|
|
|
254
255
|
installClaudeSkills(repoPath, null, quiet);
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
if (platforms.includes('codex')) {
|
|
258
|
+
if (platforms.includes('codex') || platforms.includes('codex_cli') || platforms.includes('codex_app')) {
|
|
258
259
|
installCodexSkills(repoPath, null, quiet);
|
|
259
260
|
}
|
|
260
261
|
|
package/lib/codex.js
CHANGED
|
@@ -1,45 +1,70 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
|
+
const chalk = require('chalk');
|
|
4
5
|
const { getSkillsSourcePath, getUserSkillsPath } = require('./utils/path-resolver');
|
|
5
6
|
|
|
6
|
-
const CODEX_SKILLS_DIR = getUserSkillsPath('codex');
|
|
7
|
-
|
|
8
7
|
/**
|
|
9
8
|
* Instala skills para OpenAI Codex
|
|
9
|
+
* Solução robusta com multi-path fallback e logging detalhado
|
|
10
10
|
* @param {string} repoPath - Caminho para o repositório cli-ai-skills
|
|
11
|
+
* @param {Array<string>|null} skills - Skills to install (null = all)
|
|
12
|
+
* @param {boolean} quiet - Suppress output
|
|
11
13
|
*/
|
|
12
|
-
function install(repoPath) {
|
|
13
|
-
|
|
14
|
+
function install(repoPath, skills = null, quiet = false) {
|
|
15
|
+
const targetDir = getUserSkillsPath('codex');
|
|
16
|
+
|
|
17
|
+
if (!quiet) {
|
|
18
|
+
console.log(chalk.cyan('\n📦 Instalando skills para OpenAI Codex...'));
|
|
19
|
+
console.log(chalk.gray(` Destino: ${targetDir}`));
|
|
20
|
+
}
|
|
14
21
|
|
|
15
|
-
const
|
|
22
|
+
const sourceDir = getSkillsSourcePath(repoPath, 'codex');
|
|
16
23
|
|
|
17
|
-
if (!fs.existsSync(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
if (!fs.existsSync(sourceDir)) {
|
|
25
|
+
if (!quiet) {
|
|
26
|
+
console.log(chalk.red('❌ Diretório .codex/skills não encontrado no repositório'));
|
|
27
|
+
console.log(chalk.gray(` Esperado: ${sourceDir}`));
|
|
28
|
+
}
|
|
29
|
+
return { installed: 0, failed: 0 };
|
|
21
30
|
}
|
|
22
31
|
|
|
23
|
-
// Criar
|
|
24
|
-
if (!fs.existsSync(
|
|
25
|
-
fs.mkdirSync(
|
|
26
|
-
|
|
32
|
+
// Criar diretório de destino se não existir
|
|
33
|
+
if (!fs.existsSync(targetDir)) {
|
|
34
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
35
|
+
if (!quiet) {
|
|
36
|
+
console.log(chalk.green(` ✓ Criado: ${targetDir}`));
|
|
37
|
+
}
|
|
27
38
|
}
|
|
28
39
|
|
|
29
40
|
// Listar skills disponíveis
|
|
30
|
-
const
|
|
41
|
+
const availableSkills = fs.readdirSync(sourceDir, { withFileTypes: true })
|
|
31
42
|
.filter(d => d.isDirectory() && d.name !== 'node_modules' && !d.name.startsWith('.'))
|
|
32
43
|
.map(d => d.name);
|
|
33
44
|
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
if (availableSkills.length === 0) {
|
|
46
|
+
if (!quiet) {
|
|
47
|
+
console.log(chalk.yellow(' ⚠️ Nenhum skill encontrado em .codex/skills/'));
|
|
48
|
+
}
|
|
49
|
+
return { installed: 0, failed: 0 };
|
|
37
50
|
}
|
|
51
|
+
|
|
52
|
+
const skillsToInstall = skills || availableSkills;
|
|
53
|
+
let installed = 0;
|
|
54
|
+
let failed = 0;
|
|
38
55
|
|
|
39
56
|
// Criar symlinks
|
|
40
|
-
|
|
41
|
-
const src = path.join(
|
|
42
|
-
const dest = path.join(
|
|
57
|
+
skillsToInstall.forEach(skill => {
|
|
58
|
+
const src = path.join(sourceDir, skill);
|
|
59
|
+
const dest = path.join(targetDir, skill);
|
|
60
|
+
|
|
61
|
+
if (!fs.existsSync(src)) {
|
|
62
|
+
if (!quiet) {
|
|
63
|
+
console.log(chalk.yellow(` ⚠️ Skill não encontrada: ${skill}`));
|
|
64
|
+
}
|
|
65
|
+
failed++;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
43
68
|
|
|
44
69
|
// Remover symlink antigo se existir
|
|
45
70
|
if (fs.existsSync(dest) || fs.lstatSync(dest, {throwIfNoEntry: false})) {
|
|
@@ -53,13 +78,26 @@ function install(repoPath) {
|
|
|
53
78
|
// Criar novo symlink
|
|
54
79
|
try {
|
|
55
80
|
fs.symlinkSync(src, dest);
|
|
56
|
-
|
|
81
|
+
if (!quiet) {
|
|
82
|
+
console.log(chalk.green(` ✓ Codex: ${skill}`));
|
|
83
|
+
}
|
|
84
|
+
installed++;
|
|
57
85
|
} catch (error) {
|
|
58
|
-
|
|
86
|
+
if (!quiet) {
|
|
87
|
+
console.log(chalk.red(` ✗ Erro ao instalar ${skill}: ${error.message}`));
|
|
88
|
+
}
|
|
89
|
+
failed++;
|
|
59
90
|
}
|
|
60
91
|
});
|
|
61
92
|
|
|
62
|
-
|
|
93
|
+
if (!quiet) {
|
|
94
|
+
console.log(chalk.green(`\n✅ ${installed} Codex skill(s) instalado(s)`));
|
|
95
|
+
if (failed > 0) {
|
|
96
|
+
console.log(chalk.yellow(`⚠️ ${failed} skill(s) falharam`));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { installed, failed };
|
|
63
101
|
}
|
|
64
102
|
|
|
65
103
|
module.exports = { install };
|
package/lib/detector.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Detecta ferramentas AI CLI instaladas no sistema
|
|
5
|
-
* @returns {Object} { copilot: {installed, version, path}, claude: {...}, ... }
|
|
8
|
+
* @returns {Object} { copilot: {installed, version, path}, claude: {...}, codex_cli: {...}, codex_app: {...}, ... }
|
|
6
9
|
*/
|
|
7
10
|
function detectTools() {
|
|
8
11
|
const tools = {
|
|
9
12
|
copilot: detectCopilot(),
|
|
10
13
|
claude: detectClaude(),
|
|
11
|
-
|
|
14
|
+
codex_cli: detectCodexCli(),
|
|
15
|
+
codex_app: detectCodexApp(),
|
|
12
16
|
opencode: detectOpenCode(),
|
|
13
17
|
gemini: detectGemini()
|
|
14
18
|
};
|
|
@@ -43,9 +47,9 @@ function detectClaude() {
|
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
/**
|
|
46
|
-
* Detecta OpenAI Codex
|
|
50
|
+
* Detecta OpenAI Codex CLI
|
|
47
51
|
*/
|
|
48
|
-
function
|
|
52
|
+
function detectCodexCli() {
|
|
49
53
|
try {
|
|
50
54
|
const version = execSync('codex --version', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
|
|
51
55
|
const path = execSync('which codex', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
|
|
@@ -55,6 +59,62 @@ function detectCodex() {
|
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Detecta OpenAI Codex App (Desktop)
|
|
64
|
+
*/
|
|
65
|
+
function detectCodexApp() {
|
|
66
|
+
// Check macOS
|
|
67
|
+
if (os.platform() === 'darwin') {
|
|
68
|
+
const appPath = '/Applications/Codex.app';
|
|
69
|
+
if (fs.existsSync(appPath)) {
|
|
70
|
+
try {
|
|
71
|
+
// Try to get version from Info.plist
|
|
72
|
+
const plistPath = path.join(appPath, 'Contents', 'Info.plist');
|
|
73
|
+
const version = 'Codex Desktop'; // Could parse plist for exact version
|
|
74
|
+
return { installed: true, version, path: appPath };
|
|
75
|
+
} catch (e) {
|
|
76
|
+
return { installed: true, version: 'unknown', path: appPath };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check Linux (if applicable)
|
|
82
|
+
if (os.platform() === 'linux') {
|
|
83
|
+
// Could check for ~/.local/share/applications or similar
|
|
84
|
+
const homeDir = os.homedir();
|
|
85
|
+
const possiblePaths = [
|
|
86
|
+
path.join(homeDir, '.local', 'share', 'codex'),
|
|
87
|
+
'/opt/Codex',
|
|
88
|
+
'/usr/local/bin/Codex'
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
for (const appPath of possiblePaths) {
|
|
92
|
+
if (fs.existsSync(appPath)) {
|
|
93
|
+
return { installed: true, version: 'Codex Desktop', path: appPath };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check Windows
|
|
99
|
+
if (os.platform() === 'win32') {
|
|
100
|
+
const programFiles = process.env['ProgramFiles'] || 'C:\\Program Files';
|
|
101
|
+
const appPath = path.join(programFiles, 'Codex', 'Codex.exe');
|
|
102
|
+
if (fs.existsSync(appPath)) {
|
|
103
|
+
return { installed: true, version: 'Codex Desktop', path: appPath };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { installed: false, version: null, path: null };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @deprecated Use detectCodexCli() and detectCodexApp() instead
|
|
112
|
+
* Detecta OpenAI Codex (mantido para backward compatibility)
|
|
113
|
+
*/
|
|
114
|
+
function detectCodex() {
|
|
115
|
+
return detectCodexCli();
|
|
116
|
+
}
|
|
117
|
+
|
|
58
118
|
/**
|
|
59
119
|
* Detecta OpenCode
|
|
60
120
|
*/
|
|
@@ -123,5 +183,5 @@ Após instalar, execute novamente: npx cli-ai-skills
|
|
|
123
183
|
`;
|
|
124
184
|
}
|
|
125
185
|
|
|
126
|
-
module.exports = { detectTools, getInstallInstructions };
|
|
186
|
+
module.exports = { detectTools, getInstallInstructions, detectCodex, detectCodexCli, detectCodexApp };
|
|
127
187
|
|
package/lib/interactive.js
CHANGED
|
@@ -50,47 +50,58 @@ async function confirmCancel() {
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Pergunta ao usuário para quais plataformas instalar
|
|
53
|
-
*
|
|
53
|
+
* Codex CLI e Codex App são mostrados SEMPRE separadamente
|
|
54
|
+
* @param {Object} detected - Ferramentas detectadas { copilot, claude, codex_cli, codex_app, opencode, gemini }
|
|
54
55
|
* @returns {Promise<Array>} Plataformas escolhidas
|
|
55
56
|
*/
|
|
56
57
|
async function promptPlatforms(detected) {
|
|
57
58
|
const choices = [];
|
|
58
59
|
|
|
59
|
-
if (detected.copilot) {
|
|
60
|
+
if (detected.copilot && detected.copilot.installed) {
|
|
60
61
|
choices.push({
|
|
61
|
-
name: '✅ GitHub Copilot CLI (
|
|
62
|
+
name: '✅ GitHub Copilot CLI (~/.github/skills/)',
|
|
62
63
|
value: 'copilot',
|
|
63
64
|
checked: true
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
if (detected.claude) {
|
|
68
|
+
if (detected.claude && detected.claude.installed) {
|
|
68
69
|
choices.push({
|
|
69
|
-
name: '✅ Claude Code (
|
|
70
|
+
name: '✅ Claude Code (~/.claude/skills/)',
|
|
70
71
|
value: 'claude',
|
|
71
72
|
checked: true
|
|
72
73
|
});
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
// Codex CLI - sempre separado
|
|
77
|
+
if (detected.codex_cli && detected.codex_cli.installed) {
|
|
76
78
|
choices.push({
|
|
77
|
-
name: '✅ OpenAI Codex (
|
|
78
|
-
value: '
|
|
79
|
+
name: '✅ OpenAI Codex CLI (~/.codex/vendor_imports/skills/skills/.curated/)',
|
|
80
|
+
value: 'codex_cli',
|
|
79
81
|
checked: true
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
// Codex App - sempre separado
|
|
86
|
+
if (detected.codex_app && detected.codex_app.installed) {
|
|
84
87
|
choices.push({
|
|
85
|
-
name: '✅
|
|
88
|
+
name: '✅ OpenAI Codex App (~/.codex/vendor_imports/skills/skills/.curated/)',
|
|
89
|
+
value: 'codex_app',
|
|
90
|
+
checked: true
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (detected.opencode && detected.opencode.installed) {
|
|
95
|
+
choices.push({
|
|
96
|
+
name: '✅ OpenCode (~/.opencode/skills/)',
|
|
86
97
|
value: 'opencode',
|
|
87
98
|
checked: true
|
|
88
99
|
});
|
|
89
100
|
}
|
|
90
101
|
|
|
91
|
-
if (detected.gemini) {
|
|
102
|
+
if (detected.gemini && detected.gemini.installed) {
|
|
92
103
|
choices.push({
|
|
93
|
-
name: '✅ Gemini CLI (
|
|
104
|
+
name: '✅ Gemini CLI (~/.gemini/skills/)',
|
|
94
105
|
value: 'gemini',
|
|
95
106
|
checked: true
|
|
96
107
|
});
|
package/lib/ui/table.js
CHANGED
|
@@ -2,36 +2,40 @@ const chalk = require('chalk');
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Exibe tabela formatada de ferramentas detectadas
|
|
5
|
+
* Agora com Codex CLI e Codex App separados
|
|
5
6
|
* @param {Object} tools - Objeto retornado por detectTools()
|
|
6
7
|
*/
|
|
7
8
|
function displayToolsTable(tools) {
|
|
8
|
-
console.log('\n
|
|
9
|
-
console.log('│ Ferramenta │ Status │ Versão
|
|
10
|
-
console.log('
|
|
9
|
+
console.log('\n┌──────────────────────────────────────────────────────────────────┐');
|
|
10
|
+
console.log('│ Ferramenta │ Status │ Versão │');
|
|
11
|
+
console.log('├──────────────────────────────────────────────────────────────────┤');
|
|
11
12
|
|
|
12
13
|
const toolNames = {
|
|
13
14
|
copilot: 'GitHub Copilot CLI',
|
|
14
15
|
claude: 'Claude Code',
|
|
15
|
-
|
|
16
|
+
codex_cli: 'OpenAI Codex CLI',
|
|
17
|
+
codex_app: 'OpenAI Codex App',
|
|
16
18
|
opencode: 'OpenCode',
|
|
17
19
|
gemini: 'Gemini CLI'
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
for (const [key, name] of Object.entries(toolNames)) {
|
|
21
23
|
const tool = tools[key];
|
|
24
|
+
if (!tool) continue; // Skip if tool not in detected object
|
|
25
|
+
|
|
22
26
|
const status = tool.installed ? chalk.green('✓') : chalk.red('✗');
|
|
23
27
|
const version = tool.version || chalk.gray('-');
|
|
24
28
|
|
|
25
29
|
// Formatar linha com espaçamento fixo
|
|
26
30
|
const namePadded = name.padEnd(21);
|
|
27
31
|
const statusPadded = ' ' + status + ' ';
|
|
28
|
-
const versionStr = String(version).substring(0,
|
|
29
|
-
const versionPadded = versionStr.padEnd(
|
|
32
|
+
const versionStr = String(version).substring(0, 26);
|
|
33
|
+
const versionPadded = versionStr.padEnd(26);
|
|
30
34
|
|
|
31
35
|
console.log(`│ ${namePadded} │${statusPadded}│ ${versionPadded}│`);
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
console.log('
|
|
38
|
+
console.log('└──────────────────────────────────────────────────────────────────┘\n');
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/**
|
|
@@ -44,12 +48,13 @@ function getToolsSummary(tools) {
|
|
|
44
48
|
|
|
45
49
|
if (tools.copilot && tools.copilot.installed) installed.push('copilot');
|
|
46
50
|
if (tools.claude && tools.claude.installed) installed.push('claude');
|
|
47
|
-
if (tools.
|
|
51
|
+
if (tools.codex_cli && tools.codex_cli.installed) installed.push('codex_cli');
|
|
52
|
+
if (tools.codex_app && tools.codex_app.installed) installed.push('codex_app');
|
|
48
53
|
if (tools.opencode && tools.opencode.installed) installed.push('opencode');
|
|
49
54
|
if (tools.gemini && tools.gemini.installed) installed.push('gemini');
|
|
50
55
|
|
|
51
56
|
return {
|
|
52
|
-
total:
|
|
57
|
+
total: 6,
|
|
53
58
|
installed: installed.length,
|
|
54
59
|
names: installed
|
|
55
60
|
};
|
|
@@ -63,16 +63,35 @@ function getSkillsSourcePath(basePath, platform) {
|
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* Get user home directory skills path for a platform
|
|
66
|
+
* Includes multi-path fallback for Codex (robust solution)
|
|
66
67
|
* @param {string} platform - Platform name
|
|
67
68
|
* @returns {string} Path to user's skills directory
|
|
68
69
|
*/
|
|
69
70
|
function getUserSkillsPath(platform) {
|
|
70
71
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
71
72
|
|
|
73
|
+
// Special handling for Codex with multi-path fallback
|
|
74
|
+
if (platform === 'codex') {
|
|
75
|
+
const codexPaths = [
|
|
76
|
+
path.join(home, '.codex', 'vendor_imports', 'skills', 'skills', '.curated'), // Real path (primary)
|
|
77
|
+
path.join(home, '.codex', 'vendor_imports', 'skills', 'skills', '.custom'), // Alternative
|
|
78
|
+
path.join(home, '.codex', 'skills') // Documented path (fallback)
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// Return first existing path, or primary path if none exist (will be created)
|
|
82
|
+
for (const codexPath of codexPaths) {
|
|
83
|
+
if (fs.existsSync(codexPath)) {
|
|
84
|
+
return codexPath;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Return primary path (will be created during install)
|
|
89
|
+
return codexPaths[0];
|
|
90
|
+
}
|
|
91
|
+
|
|
72
92
|
const platformDirs = {
|
|
73
93
|
'copilot': path.join(home, '.github', 'skills'),
|
|
74
94
|
'claude': path.join(home, '.claude', 'skills'),
|
|
75
|
-
'codex': path.join(home, '.codex', 'skills'),
|
|
76
95
|
'opencode': path.join(home, '.opencode', 'skills'),
|
|
77
96
|
'gemini': path.join(home, '.gemini', 'skills')
|
|
78
97
|
};
|