@codihaus/claude-skills 1.0.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 +167 -0
- package/bin/cli.js +58 -0
- package/package.json +46 -0
- package/skills/_quality-attributes.md +392 -0
- package/skills/_registry.md +189 -0
- package/skills/debrief/SKILL.md +647 -0
- package/skills/debrief/references/change-request-template.md +124 -0
- package/skills/debrief/references/file-patterns.md +173 -0
- package/skills/debrief/references/group-codes.md +72 -0
- package/skills/debrief/references/research-queries.md +106 -0
- package/skills/debrief/references/use-case-template.md +141 -0
- package/skills/debrief/scripts/generate_questionnaire.py +195 -0
- package/skills/dev-arch/SKILL.md +747 -0
- package/skills/dev-changelog/SKILL.md +378 -0
- package/skills/dev-coding/SKILL.md +470 -0
- package/skills/dev-coding-backend/SKILL.md +361 -0
- package/skills/dev-coding-frontend/SKILL.md +534 -0
- package/skills/dev-coding-frontend/references/nextjs.md +477 -0
- package/skills/dev-review/SKILL.md +548 -0
- package/skills/dev-scout/SKILL.md +723 -0
- package/skills/dev-scout/references/feature-patterns.md +210 -0
- package/skills/dev-scout/references/file-patterns.md +252 -0
- package/skills/dev-scout/references/tech-detection.md +211 -0
- package/skills/dev-scout/scripts/scout-analyze.sh +280 -0
- package/skills/dev-specs/SKILL.md +577 -0
- package/skills/dev-specs/references/checklist.md +176 -0
- package/skills/dev-specs/references/spec-templates.md +460 -0
- package/skills/dev-test/SKILL.md +364 -0
- package/skills/utils/diagram/SKILL.md +205 -0
- package/skills/utils/diagram/references/common-errors.md +305 -0
- package/skills/utils/diagram/references/diagram-types.md +636 -0
- package/skills/utils/docs-graph/SKILL.md +204 -0
- package/skills/utils/gemini/SKILL.md +292 -0
- package/skills/utils/gemini/scripts/gemini-scan.py +340 -0
- package/skills/utils/gemini/scripts/setup.sh +169 -0
- package/src/commands/add.js +64 -0
- package/src/commands/doctor.js +179 -0
- package/src/commands/init.js +251 -0
- package/src/commands/list.js +88 -0
- package/src/commands/remove.js +60 -0
- package/src/commands/update.js +72 -0
- package/src/index.js +26 -0
- package/src/utils/config.js +272 -0
- package/src/utils/deps.js +599 -0
- package/src/utils/skills.js +253 -0
- package/templates/CLAUDE.md.template +58 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* doctor command
|
|
3
|
+
*
|
|
4
|
+
* Check system dependencies and project setup.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
checkGlobalDeps,
|
|
15
|
+
checkProjectDeps,
|
|
16
|
+
printDepsReport,
|
|
17
|
+
installProjectDeps
|
|
18
|
+
} from '../utils/deps.js';
|
|
19
|
+
import { getInstalledSkills } from '../utils/skills.js';
|
|
20
|
+
|
|
21
|
+
export async function doctor(options) {
|
|
22
|
+
const projectPath = process.cwd();
|
|
23
|
+
|
|
24
|
+
console.log(chalk.bold('\n𩺠Claude Skills Doctor\n'));
|
|
25
|
+
console.log(chalk.gray(`Checking: ${projectPath}\n`));
|
|
26
|
+
|
|
27
|
+
let hasIssues = false;
|
|
28
|
+
|
|
29
|
+
// 1. Check global dependencies
|
|
30
|
+
console.log(chalk.cyan('1. System Dependencies'));
|
|
31
|
+
console.log('ā'.repeat(40));
|
|
32
|
+
|
|
33
|
+
const globalDeps = await checkGlobalDeps();
|
|
34
|
+
printDepsReport(globalDeps);
|
|
35
|
+
|
|
36
|
+
if (globalDeps.hasErrors) {
|
|
37
|
+
hasIssues = true;
|
|
38
|
+
console.log(chalk.red('ā Required dependencies missing'));
|
|
39
|
+
} else if (globalDeps.hasWarnings) {
|
|
40
|
+
console.log(chalk.yellow('ā ļø Some recommended dependencies missing'));
|
|
41
|
+
} else {
|
|
42
|
+
console.log(chalk.green('ā
All system dependencies OK'));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 2. Check .claude folder
|
|
46
|
+
console.log('\n' + chalk.cyan('2. Claude Code Setup'));
|
|
47
|
+
console.log('ā'.repeat(40));
|
|
48
|
+
|
|
49
|
+
const claudePath = path.join(projectPath, '.claude');
|
|
50
|
+
const skillsPath = path.join(claudePath, 'skills');
|
|
51
|
+
const settingsPath = path.join(claudePath, 'settings.local.json');
|
|
52
|
+
|
|
53
|
+
const checks = [
|
|
54
|
+
{
|
|
55
|
+
name: '.claude folder',
|
|
56
|
+
path: claudePath,
|
|
57
|
+
exists: await fs.pathExists(claudePath)
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: '.claude/skills folder',
|
|
61
|
+
path: skillsPath,
|
|
62
|
+
exists: await fs.pathExists(skillsPath)
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'settings.local.json',
|
|
66
|
+
path: settingsPath,
|
|
67
|
+
exists: await fs.pathExists(settingsPath)
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'CLAUDE.md',
|
|
71
|
+
path: path.join(projectPath, 'CLAUDE.md'),
|
|
72
|
+
exists: await fs.pathExists(path.join(projectPath, 'CLAUDE.md'))
|
|
73
|
+
}
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
for (const check of checks) {
|
|
77
|
+
const icon = check.exists ? chalk.green('ā') : chalk.red('ā');
|
|
78
|
+
console.log(` ${icon} ${check.name}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const missingSetup = checks.filter(c => !c.exists);
|
|
82
|
+
if (missingSetup.length > 0) {
|
|
83
|
+
hasIssues = true;
|
|
84
|
+
console.log(chalk.yellow('\n Run `claude-skills init` to set up missing items'));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 3. Check installed skills
|
|
88
|
+
console.log('\n' + chalk.cyan('3. Installed Skills'));
|
|
89
|
+
console.log('ā'.repeat(40));
|
|
90
|
+
|
|
91
|
+
const installed = await getInstalledSkills(projectPath);
|
|
92
|
+
|
|
93
|
+
if (installed.length === 0) {
|
|
94
|
+
console.log(chalk.yellow(' No skills installed'));
|
|
95
|
+
hasIssues = true;
|
|
96
|
+
} else {
|
|
97
|
+
const skillsOnly = installed.filter(s => s.type !== 'config');
|
|
98
|
+
console.log(` ${chalk.green('ā')} ${skillsOnly.length} skills installed`);
|
|
99
|
+
|
|
100
|
+
// Check for core skills
|
|
101
|
+
const coreSkills = ['debrief', 'dev-scout', 'dev-specs', 'dev-coding', 'dev-review'];
|
|
102
|
+
const installedNames = skillsOnly.map(s => s.name);
|
|
103
|
+
const missingCore = coreSkills.filter(s => !installedNames.includes(s));
|
|
104
|
+
|
|
105
|
+
if (missingCore.length > 0) {
|
|
106
|
+
console.log(chalk.yellow(` ā ļø Missing core skills: ${missingCore.join(', ')}`));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 4. Check project dependencies
|
|
111
|
+
console.log('\n' + chalk.cyan('4. Project Dependencies'));
|
|
112
|
+
console.log('ā'.repeat(40));
|
|
113
|
+
|
|
114
|
+
const projectDeps = await checkProjectDeps(projectPath);
|
|
115
|
+
|
|
116
|
+
if (projectDeps.noPackageJson) {
|
|
117
|
+
console.log(chalk.gray(' No package.json (not a Node.js project)'));
|
|
118
|
+
} else {
|
|
119
|
+
for (const dep of projectDeps.npm) {
|
|
120
|
+
const icon = dep.status === 'ok' ? chalk.green('ā') : chalk.yellow('ā');
|
|
121
|
+
console.log(` ${icon} ${dep.name} - ${dep.purpose}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (projectDeps.missing.length > 0 && options.fix) {
|
|
125
|
+
console.log('');
|
|
126
|
+
const { install } = await inquirer.prompt([{
|
|
127
|
+
type: 'confirm',
|
|
128
|
+
name: 'install',
|
|
129
|
+
message: 'Install missing dependencies?',
|
|
130
|
+
default: true
|
|
131
|
+
}]);
|
|
132
|
+
|
|
133
|
+
if (install) {
|
|
134
|
+
await installProjectDeps(projectPath, projectDeps.missing);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 5. Check for common issues
|
|
140
|
+
console.log('\n' + chalk.cyan('5. Common Issues'));
|
|
141
|
+
console.log('ā'.repeat(40));
|
|
142
|
+
|
|
143
|
+
// Check .gitignore
|
|
144
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
145
|
+
if (await fs.pathExists(gitignorePath)) {
|
|
146
|
+
const content = await fs.readFile(gitignorePath, 'utf-8');
|
|
147
|
+
if (content.includes('settings.local.json')) {
|
|
148
|
+
console.log(` ${chalk.green('ā')} settings.local.json in .gitignore`);
|
|
149
|
+
} else {
|
|
150
|
+
console.log(` ${chalk.yellow('ā')} settings.local.json not in .gitignore`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check for .env
|
|
155
|
+
const envPath = path.join(projectPath, '.env');
|
|
156
|
+
if (await fs.pathExists(envPath)) {
|
|
157
|
+
const content = await fs.readFile(envPath, 'utf-8');
|
|
158
|
+
if (content.includes('GEMINI_API_KEY')) {
|
|
159
|
+
console.log(` ${chalk.green('ā')} GEMINI_API_KEY configured`);
|
|
160
|
+
} else {
|
|
161
|
+
console.log(` ${chalk.gray('ā')} GEMINI_API_KEY not set (optional for large codebase scanning)`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Summary
|
|
166
|
+
console.log('\n' + 'ā'.repeat(40));
|
|
167
|
+
|
|
168
|
+
if (hasIssues) {
|
|
169
|
+
console.log(chalk.yellow('\nā ļø Some issues found. See above for details.\n'));
|
|
170
|
+
|
|
171
|
+
if (options.fix) {
|
|
172
|
+
console.log(chalk.cyan('Attempted to fix issues where possible.'));
|
|
173
|
+
} else {
|
|
174
|
+
console.log(chalk.gray('Run `claude-skills doctor --fix` to attempt automatic fixes.\n'));
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
console.log(chalk.green('\nā
Everything looks good!\n'));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* init command
|
|
3
|
+
*
|
|
4
|
+
* Initialize Claude Skills in a project.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
checkGlobalDeps,
|
|
15
|
+
checkProjectDeps,
|
|
16
|
+
printDepsReport,
|
|
17
|
+
installProjectDeps,
|
|
18
|
+
installPythonDeps
|
|
19
|
+
} from '../utils/deps.js';
|
|
20
|
+
import {
|
|
21
|
+
getAvailableSkills,
|
|
22
|
+
getInstalledSkills,
|
|
23
|
+
copySkillsToProject
|
|
24
|
+
} from '../utils/skills.js';
|
|
25
|
+
import {
|
|
26
|
+
setupSettings,
|
|
27
|
+
setupHooks,
|
|
28
|
+
setupClaudeMd,
|
|
29
|
+
updateGitignore
|
|
30
|
+
} from '../utils/config.js';
|
|
31
|
+
|
|
32
|
+
export async function init(options) {
|
|
33
|
+
const projectPath = process.cwd();
|
|
34
|
+
|
|
35
|
+
console.log(chalk.bold('\nš Claude Skills Initialization\n'));
|
|
36
|
+
console.log(chalk.gray(`Project: ${projectPath}\n`));
|
|
37
|
+
|
|
38
|
+
// Step 1: Check global dependencies
|
|
39
|
+
if (!options.noDeps) {
|
|
40
|
+
const spinner = ora('Checking system dependencies...').start();
|
|
41
|
+
const globalDeps = await checkGlobalDeps();
|
|
42
|
+
spinner.stop();
|
|
43
|
+
|
|
44
|
+
printDepsReport(globalDeps);
|
|
45
|
+
|
|
46
|
+
if (globalDeps.hasErrors) {
|
|
47
|
+
console.log(chalk.red('\nā Required dependencies missing. Please install them first.\n'));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (globalDeps.hasWarnings && !options.yes) {
|
|
52
|
+
const { proceed } = await inquirer.prompt([{
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'proceed',
|
|
55
|
+
message: 'Some recommended dependencies are missing. Continue anyway?',
|
|
56
|
+
default: true
|
|
57
|
+
}]);
|
|
58
|
+
|
|
59
|
+
if (!proceed) {
|
|
60
|
+
console.log(chalk.yellow('Initialization cancelled.'));
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Offer to install missing Python packages
|
|
66
|
+
const missingPython = globalDeps.python?.filter(p => !p.installed) || [];
|
|
67
|
+
if (missingPython.length > 0 && !options.yes) {
|
|
68
|
+
const { installPython } = await inquirer.prompt([{
|
|
69
|
+
type: 'confirm',
|
|
70
|
+
name: 'installPython',
|
|
71
|
+
message: `Install missing Python packages (${missingPython.map(p => p.name).join(', ')})?`,
|
|
72
|
+
default: true
|
|
73
|
+
}]);
|
|
74
|
+
|
|
75
|
+
if (installPython) {
|
|
76
|
+
await installPythonDeps(missingPython);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Step 2: Check if already initialized
|
|
82
|
+
const installed = await getInstalledSkills(projectPath);
|
|
83
|
+
if (installed.length > 0 && !options.yes) {
|
|
84
|
+
console.log(chalk.yellow(`\nā ļø Skills already installed (${installed.length} found)`));
|
|
85
|
+
|
|
86
|
+
const { action } = await inquirer.prompt([{
|
|
87
|
+
type: 'list',
|
|
88
|
+
name: 'action',
|
|
89
|
+
message: 'What would you like to do?',
|
|
90
|
+
choices: [
|
|
91
|
+
{ name: 'Update to latest version', value: 'update' },
|
|
92
|
+
{ name: 'Reinstall (overwrite)', value: 'reinstall' },
|
|
93
|
+
{ name: 'Cancel', value: 'cancel' }
|
|
94
|
+
]
|
|
95
|
+
}]);
|
|
96
|
+
|
|
97
|
+
if (action === 'cancel') {
|
|
98
|
+
console.log(chalk.yellow('Initialization cancelled.'));
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (action === 'update') {
|
|
103
|
+
// TODO: Implement update logic
|
|
104
|
+
console.log(chalk.cyan('Updating skills...'));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Step 3: Select skills to install
|
|
109
|
+
const available = await getAvailableSkills();
|
|
110
|
+
const skillsOnly = available.filter(s => s.type !== 'config');
|
|
111
|
+
|
|
112
|
+
let skillsToInstall = null; // null means all
|
|
113
|
+
|
|
114
|
+
if (options.skills) {
|
|
115
|
+
skillsToInstall = options.skills.split(',').map(s => s.trim());
|
|
116
|
+
console.log(chalk.cyan(`\nInstalling selected skills: ${skillsToInstall.join(', ')}`));
|
|
117
|
+
} else if (!options.all && !options.yes) {
|
|
118
|
+
const { selectSkills } = await inquirer.prompt([{
|
|
119
|
+
type: 'confirm',
|
|
120
|
+
name: 'selectSkills',
|
|
121
|
+
message: 'Install all skills? (No to select specific ones)',
|
|
122
|
+
default: true
|
|
123
|
+
}]);
|
|
124
|
+
|
|
125
|
+
if (!selectSkills) {
|
|
126
|
+
const { selected } = await inquirer.prompt([{
|
|
127
|
+
type: 'checkbox',
|
|
128
|
+
name: 'selected',
|
|
129
|
+
message: 'Select skills to install:',
|
|
130
|
+
choices: skillsOnly.map(s => ({
|
|
131
|
+
name: `${s.name} - ${s.description || 'No description'}`,
|
|
132
|
+
value: s.name,
|
|
133
|
+
checked: true
|
|
134
|
+
}))
|
|
135
|
+
}]);
|
|
136
|
+
|
|
137
|
+
skillsToInstall = selected;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Step 4: Copy skills
|
|
142
|
+
const spinner = ora('Installing skills...').start();
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const { copied, errors } = await copySkillsToProject(projectPath, skillsToInstall);
|
|
146
|
+
|
|
147
|
+
if (errors.length > 0) {
|
|
148
|
+
spinner.warn(`Installed ${copied.length} skills with ${errors.length} errors`);
|
|
149
|
+
for (const err of errors) {
|
|
150
|
+
console.log(chalk.red(` ā ${err.name}: ${err.error}`));
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
spinner.succeed(`Installed ${copied.length} skills`);
|
|
154
|
+
}
|
|
155
|
+
} catch (e) {
|
|
156
|
+
spinner.fail('Failed to install skills');
|
|
157
|
+
console.error(chalk.red(e.message));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Step 5: Set up settings
|
|
162
|
+
const settingsSpinner = ora('Setting up Claude Code configuration...').start();
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await setupSettings(projectPath);
|
|
166
|
+
settingsSpinner.succeed('Claude Code settings configured');
|
|
167
|
+
} catch (e) {
|
|
168
|
+
settingsSpinner.warn('Failed to set up settings');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Step 6: Set up hooks
|
|
172
|
+
if (!options.noHooks) {
|
|
173
|
+
const hooksSpinner = ora('Setting up hooks...').start();
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const result = await setupHooks(projectPath);
|
|
177
|
+
if (result) {
|
|
178
|
+
hooksSpinner.succeed('Hooks configured');
|
|
179
|
+
} else {
|
|
180
|
+
hooksSpinner.info('Hooks skipped');
|
|
181
|
+
}
|
|
182
|
+
} catch (e) {
|
|
183
|
+
hooksSpinner.warn('Failed to set up hooks');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Step 7: Set up CLAUDE.md
|
|
188
|
+
const claudeSpinner = ora('Setting up CLAUDE.md...').start();
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
const result = await setupClaudeMd(projectPath);
|
|
192
|
+
claudeSpinner.succeed(`CLAUDE.md ${result.action}`);
|
|
193
|
+
} catch (e) {
|
|
194
|
+
claudeSpinner.warn('Failed to set up CLAUDE.md');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Step 8: Update .gitignore
|
|
198
|
+
const gitSpinner = ora('Updating .gitignore...').start();
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const result = await updateGitignore(projectPath);
|
|
202
|
+
gitSpinner.succeed(`.gitignore ${result.action}`);
|
|
203
|
+
} catch (e) {
|
|
204
|
+
gitSpinner.warn('Failed to update .gitignore');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Step 9: Check project dependencies
|
|
208
|
+
if (!options.noDeps) {
|
|
209
|
+
console.log('');
|
|
210
|
+
const projectSpinner = ora('Checking project dependencies...').start();
|
|
211
|
+
const projectDeps = await checkProjectDeps(projectPath);
|
|
212
|
+
projectSpinner.stop();
|
|
213
|
+
|
|
214
|
+
if (projectDeps.missing.length > 0) {
|
|
215
|
+
console.log(chalk.yellow('\nā ļø Some optional dependencies are missing:\n'));
|
|
216
|
+
|
|
217
|
+
for (const dep of projectDeps.missing) {
|
|
218
|
+
const cmd = dep.type === 'pip'
|
|
219
|
+
? chalk.cyan(`pip install ${dep.name}`)
|
|
220
|
+
: chalk.cyan(`npm install -D ${dep.name}`);
|
|
221
|
+
console.log(` ${dep.name} - ${dep.purpose}`);
|
|
222
|
+
console.log(` ${cmd}\n`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!options.yes) {
|
|
226
|
+
const { install } = await inquirer.prompt([{
|
|
227
|
+
type: 'confirm',
|
|
228
|
+
name: 'install',
|
|
229
|
+
message: 'Install missing dependencies now?',
|
|
230
|
+
default: false
|
|
231
|
+
}]);
|
|
232
|
+
|
|
233
|
+
if (install) {
|
|
234
|
+
await installProjectDeps(projectPath, projectDeps.missing);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Done!
|
|
241
|
+
console.log(chalk.green('\nā
Claude Skills initialized successfully!\n'));
|
|
242
|
+
|
|
243
|
+
console.log(chalk.bold('Next steps:'));
|
|
244
|
+
console.log('');
|
|
245
|
+
console.log(' 1. Start Claude Code in this project');
|
|
246
|
+
console.log(' 2. Try a skill: ' + chalk.cyan('/debrief "your project idea"'));
|
|
247
|
+
console.log(' 3. See all skills: ' + chalk.cyan('/help'));
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log(chalk.gray('Docs: .claude/skills/_registry.md'));
|
|
250
|
+
console.log('');
|
|
251
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list command
|
|
3
|
+
*
|
|
4
|
+
* List available and installed skills.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
import { getAvailableSkills, getInstalledSkills } from '../utils/skills.js';
|
|
10
|
+
|
|
11
|
+
export async function list(options) {
|
|
12
|
+
const projectPath = process.cwd();
|
|
13
|
+
|
|
14
|
+
console.log(chalk.bold('\nš Claude Skills\n'));
|
|
15
|
+
|
|
16
|
+
const available = await getAvailableSkills();
|
|
17
|
+
const installed = await getInstalledSkills(projectPath);
|
|
18
|
+
|
|
19
|
+
const installedNames = new Set(installed.map(s => s.name));
|
|
20
|
+
|
|
21
|
+
if (options.installed) {
|
|
22
|
+
// Show only installed
|
|
23
|
+
console.log(chalk.cyan('Installed Skills:\n'));
|
|
24
|
+
|
|
25
|
+
if (installed.length === 0) {
|
|
26
|
+
console.log(chalk.gray(' No skills installed. Run `claude-skills init` to install.\n'));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const skill of installed) {
|
|
31
|
+
if (skill.type === 'config') continue;
|
|
32
|
+
|
|
33
|
+
console.log(` ${chalk.green('ā')} ${skill.name}`);
|
|
34
|
+
console.log(chalk.gray(` v${skill.version || 'unknown'} - ${skill.description || ''}`));
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
// Show all available with install status
|
|
38
|
+
console.log(chalk.cyan('Available Skills:\n'));
|
|
39
|
+
|
|
40
|
+
// Group by category
|
|
41
|
+
const mainSkills = available.filter(s => !s.category && s.type !== 'config');
|
|
42
|
+
const utilSkills = available.filter(s => s.category === 'utils');
|
|
43
|
+
const configFiles = available.filter(s => s.type === 'config');
|
|
44
|
+
|
|
45
|
+
// Main skills
|
|
46
|
+
console.log(chalk.bold(' Main Skills:'));
|
|
47
|
+
for (const skill of mainSkills) {
|
|
48
|
+
const isInstalled = installedNames.has(skill.name);
|
|
49
|
+
const icon = isInstalled ? chalk.green('ā') : chalk.gray('ā');
|
|
50
|
+
const status = isInstalled ? chalk.green(' (installed)') : '';
|
|
51
|
+
|
|
52
|
+
console.log(` ${icon} /${skill.name}${status}`);
|
|
53
|
+
console.log(chalk.gray(` v${skill.version || '?'} - ${skill.description || ''}`));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Utility skills
|
|
57
|
+
if (utilSkills.length > 0) {
|
|
58
|
+
console.log('');
|
|
59
|
+
console.log(chalk.bold(' Utility Skills:'));
|
|
60
|
+
for (const skill of utilSkills) {
|
|
61
|
+
const isInstalled = installedNames.has(skill.name);
|
|
62
|
+
const icon = isInstalled ? chalk.green('ā') : chalk.gray('ā');
|
|
63
|
+
const status = isInstalled ? chalk.green(' (installed)') : '';
|
|
64
|
+
|
|
65
|
+
console.log(` ${icon} /${skill.name}${status}`);
|
|
66
|
+
console.log(chalk.gray(` v${skill.version || '?'} - ${skill.description || ''}`));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Config files
|
|
71
|
+
console.log('');
|
|
72
|
+
console.log(chalk.bold(' Config Files:'));
|
|
73
|
+
for (const file of configFiles) {
|
|
74
|
+
const isInstalled = installedNames.has(file.name);
|
|
75
|
+
const icon = isInstalled ? chalk.green('ā') : chalk.gray('ā');
|
|
76
|
+
console.log(` ${icon} ${file.name}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log('');
|
|
81
|
+
|
|
82
|
+
// Summary
|
|
83
|
+
const skillCount = available.filter(s => s.type !== 'config').length;
|
|
84
|
+
const installedCount = installed.filter(s => s.type !== 'config').length;
|
|
85
|
+
|
|
86
|
+
console.log(chalk.gray(`${installedCount}/${skillCount} skills installed`));
|
|
87
|
+
console.log('');
|
|
88
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remove command
|
|
3
|
+
*
|
|
4
|
+
* Remove a skill from the project.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
|
|
11
|
+
import { getInstalledSkills, removeSkillFromProject } from '../utils/skills.js';
|
|
12
|
+
|
|
13
|
+
export async function remove(skillName) {
|
|
14
|
+
const projectPath = process.cwd();
|
|
15
|
+
|
|
16
|
+
console.log(chalk.bold(`\nā Removing skill: ${skillName}\n`));
|
|
17
|
+
|
|
18
|
+
// Check if skill is installed
|
|
19
|
+
const installed = await getInstalledSkills(projectPath);
|
|
20
|
+
const skill = installed.find(s => s.name === skillName);
|
|
21
|
+
|
|
22
|
+
if (!skill) {
|
|
23
|
+
console.log(chalk.yellow(`ā ļø Skill not installed: ${skillName}\n`));
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Confirm removal
|
|
28
|
+
const { confirm } = await inquirer.prompt([{
|
|
29
|
+
type: 'confirm',
|
|
30
|
+
name: 'confirm',
|
|
31
|
+
message: `Remove ${skillName}?`,
|
|
32
|
+
default: false
|
|
33
|
+
}]);
|
|
34
|
+
|
|
35
|
+
if (!confirm) {
|
|
36
|
+
console.log(chalk.yellow('Removal cancelled.\n'));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Remove the skill
|
|
41
|
+
const spinner = ora(`Removing ${skillName}...`).start();
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const result = await removeSkillFromProject(projectPath, skillName);
|
|
45
|
+
|
|
46
|
+
if (!result.success) {
|
|
47
|
+
spinner.fail(`Failed to remove ${skillName}`);
|
|
48
|
+
console.log(chalk.red(result.error));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
spinner.succeed(`Removed ${skillName}`);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
spinner.fail('Removal failed');
|
|
55
|
+
console.error(chalk.red(e.message));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(chalk.green(`\nā
${skillName} removed.\n`));
|
|
60
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update command
|
|
3
|
+
*
|
|
4
|
+
* Update installed skills to latest version.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
|
|
10
|
+
import { checkForUpdates, copySkillsToProject, getInstalledSkills } from '../utils/skills.js';
|
|
11
|
+
|
|
12
|
+
export async function update(options) {
|
|
13
|
+
const projectPath = process.cwd();
|
|
14
|
+
|
|
15
|
+
console.log(chalk.bold('\nš¦ Claude Skills Update\n'));
|
|
16
|
+
|
|
17
|
+
// Check for installed skills
|
|
18
|
+
const installed = await getInstalledSkills(projectPath);
|
|
19
|
+
|
|
20
|
+
if (installed.length === 0) {
|
|
21
|
+
console.log(chalk.yellow('No skills installed. Run `claude-skills init` first.\n'));
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log(chalk.gray(`Found ${installed.length} installed skills\n`));
|
|
26
|
+
|
|
27
|
+
// Check for updates
|
|
28
|
+
const spinner = ora('Checking for updates...').start();
|
|
29
|
+
const updates = await checkForUpdates(projectPath);
|
|
30
|
+
spinner.stop();
|
|
31
|
+
|
|
32
|
+
if (updates.length === 0) {
|
|
33
|
+
console.log(chalk.green('ā
All skills are up to date!\n'));
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log(chalk.cyan(`Found ${updates.length} update(s) available:\n`));
|
|
38
|
+
|
|
39
|
+
for (const update of updates) {
|
|
40
|
+
console.log(` ${update.name}`);
|
|
41
|
+
console.log(chalk.gray(` ${update.current} ā ${update.available}`));
|
|
42
|
+
console.log('');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (options.check) {
|
|
46
|
+
console.log(chalk.gray('Run `claude-skills update` to install updates.\n'));
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Apply updates
|
|
51
|
+
const updateSpinner = ora('Updating skills...').start();
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const skillNames = updates.map(u => u.name);
|
|
55
|
+
const { copied, errors } = await copySkillsToProject(projectPath, skillNames);
|
|
56
|
+
|
|
57
|
+
if (errors.length > 0) {
|
|
58
|
+
updateSpinner.warn(`Updated ${copied.length} skills with ${errors.length} errors`);
|
|
59
|
+
for (const err of errors) {
|
|
60
|
+
console.log(chalk.red(` ā ${err.name}: ${err.error}`));
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
updateSpinner.succeed(`Updated ${copied.length} skills`);
|
|
64
|
+
}
|
|
65
|
+
} catch (e) {
|
|
66
|
+
updateSpinner.fail('Update failed');
|
|
67
|
+
console.error(chalk.red(e.message));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(chalk.green('\nā
Update complete!\n'));
|
|
72
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Skills
|
|
3
|
+
*
|
|
4
|
+
* Programmatic API for managing Claude Code skills.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
checkGlobalDeps,
|
|
9
|
+
checkProjectDeps,
|
|
10
|
+
installProjectDeps
|
|
11
|
+
} from './utils/deps.js';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
getAvailableSkills,
|
|
15
|
+
getInstalledSkills,
|
|
16
|
+
copySkillsToProject,
|
|
17
|
+
removeSkillFromProject,
|
|
18
|
+
checkForUpdates
|
|
19
|
+
} from './utils/skills.js';
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
setupSettings,
|
|
23
|
+
setupHooks,
|
|
24
|
+
setupClaudeMd,
|
|
25
|
+
updateGitignore
|
|
26
|
+
} from './utils/config.js';
|