@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,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Management Utilities
|
|
3
|
+
*
|
|
4
|
+
* Copy, list, and manage skills in projects.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
|
|
14
|
+
// Path to bundled skills (in npm package)
|
|
15
|
+
const SKILLS_SOURCE = path.join(__dirname, '../../skills');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get list of all available skills
|
|
19
|
+
*/
|
|
20
|
+
export async function getAvailableSkills() {
|
|
21
|
+
const skills = [];
|
|
22
|
+
|
|
23
|
+
// Read main skills
|
|
24
|
+
const mainSkills = await fs.readdir(SKILLS_SOURCE);
|
|
25
|
+
|
|
26
|
+
for (const name of mainSkills) {
|
|
27
|
+
const skillPath = path.join(SKILLS_SOURCE, name);
|
|
28
|
+
const stat = await fs.stat(skillPath);
|
|
29
|
+
|
|
30
|
+
if (!stat.isDirectory()) continue;
|
|
31
|
+
|
|
32
|
+
// Check if it's a skill (has SKILL.md) or a category folder (like utils/)
|
|
33
|
+
const skillMd = path.join(skillPath, 'SKILL.md');
|
|
34
|
+
|
|
35
|
+
if (await fs.pathExists(skillMd)) {
|
|
36
|
+
// It's a skill
|
|
37
|
+
const metadata = await parseSkillMetadata(skillMd);
|
|
38
|
+
skills.push({
|
|
39
|
+
name,
|
|
40
|
+
path: skillPath,
|
|
41
|
+
...metadata
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
// It's a category folder (like utils/), check subdirectories
|
|
45
|
+
const subItems = await fs.readdir(skillPath);
|
|
46
|
+
|
|
47
|
+
for (const subName of subItems) {
|
|
48
|
+
const subPath = path.join(skillPath, subName);
|
|
49
|
+
const subStat = await fs.stat(subPath);
|
|
50
|
+
|
|
51
|
+
if (!subStat.isDirectory()) continue;
|
|
52
|
+
|
|
53
|
+
const subSkillMd = path.join(subPath, 'SKILL.md');
|
|
54
|
+
if (await fs.pathExists(subSkillMd)) {
|
|
55
|
+
const metadata = await parseSkillMetadata(subSkillMd);
|
|
56
|
+
skills.push({
|
|
57
|
+
name: `${name}/${subName}`,
|
|
58
|
+
path: subPath,
|
|
59
|
+
category: name,
|
|
60
|
+
...metadata
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Also include special files
|
|
68
|
+
const specialFiles = ['_registry.md', '_quality-attributes.md'];
|
|
69
|
+
for (const file of specialFiles) {
|
|
70
|
+
const filePath = path.join(SKILLS_SOURCE, file);
|
|
71
|
+
if (await fs.pathExists(filePath)) {
|
|
72
|
+
skills.push({
|
|
73
|
+
name: file,
|
|
74
|
+
path: filePath,
|
|
75
|
+
type: 'config'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return skills;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Parse skill metadata from SKILL.md frontmatter
|
|
85
|
+
*/
|
|
86
|
+
async function parseSkillMetadata(skillMdPath) {
|
|
87
|
+
try {
|
|
88
|
+
const content = await fs.readFile(skillMdPath, 'utf-8');
|
|
89
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
90
|
+
|
|
91
|
+
if (!frontmatterMatch) {
|
|
92
|
+
return { version: 'unknown', description: '' };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const frontmatter = frontmatterMatch[1];
|
|
96
|
+
const metadata = {};
|
|
97
|
+
|
|
98
|
+
// Parse YAML-like frontmatter
|
|
99
|
+
const lines = frontmatter.split('\n');
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
102
|
+
if (match) {
|
|
103
|
+
metadata[match[1]] = match[2].trim();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return metadata;
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return { version: 'unknown', description: '' };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get installed skills in a project
|
|
115
|
+
*/
|
|
116
|
+
export async function getInstalledSkills(projectPath) {
|
|
117
|
+
const skillsPath = path.join(projectPath, '.claude', 'skills');
|
|
118
|
+
|
|
119
|
+
if (!await fs.pathExists(skillsPath)) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const skills = [];
|
|
124
|
+
const items = await fs.readdir(skillsPath);
|
|
125
|
+
|
|
126
|
+
for (const name of items) {
|
|
127
|
+
const itemPath = path.join(skillsPath, name);
|
|
128
|
+
const stat = await fs.stat(itemPath);
|
|
129
|
+
|
|
130
|
+
if (!stat.isDirectory()) {
|
|
131
|
+
// Config files like _registry.md
|
|
132
|
+
if (name.endsWith('.md')) {
|
|
133
|
+
skills.push({ name, type: 'config' });
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const skillMd = path.join(itemPath, 'SKILL.md');
|
|
139
|
+
if (await fs.pathExists(skillMd)) {
|
|
140
|
+
const metadata = await parseSkillMetadata(skillMd);
|
|
141
|
+
skills.push({
|
|
142
|
+
name,
|
|
143
|
+
path: itemPath,
|
|
144
|
+
...metadata
|
|
145
|
+
});
|
|
146
|
+
} else {
|
|
147
|
+
// Check for nested skills (like utils/)
|
|
148
|
+
const subItems = await fs.readdir(itemPath);
|
|
149
|
+
for (const subName of subItems) {
|
|
150
|
+
const subPath = path.join(itemPath, subName);
|
|
151
|
+
const subStat = await fs.stat(subPath);
|
|
152
|
+
|
|
153
|
+
if (!subStat.isDirectory()) continue;
|
|
154
|
+
|
|
155
|
+
const subSkillMd = path.join(subPath, 'SKILL.md');
|
|
156
|
+
if (await fs.pathExists(subSkillMd)) {
|
|
157
|
+
const metadata = await parseSkillMetadata(subSkillMd);
|
|
158
|
+
skills.push({
|
|
159
|
+
name: `${name}/${subName}`,
|
|
160
|
+
path: subPath,
|
|
161
|
+
category: name,
|
|
162
|
+
...metadata
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return skills;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Copy skills to project
|
|
174
|
+
*/
|
|
175
|
+
export async function copySkillsToProject(projectPath, skillNames = null) {
|
|
176
|
+
const targetPath = path.join(projectPath, '.claude', 'skills');
|
|
177
|
+
|
|
178
|
+
// Ensure target directory exists
|
|
179
|
+
await fs.ensureDir(targetPath);
|
|
180
|
+
|
|
181
|
+
const available = await getAvailableSkills();
|
|
182
|
+
const toCopy = skillNames
|
|
183
|
+
? available.filter(s => skillNames.includes(s.name) || s.type === 'config')
|
|
184
|
+
: available;
|
|
185
|
+
|
|
186
|
+
const copied = [];
|
|
187
|
+
const errors = [];
|
|
188
|
+
|
|
189
|
+
for (const skill of toCopy) {
|
|
190
|
+
try {
|
|
191
|
+
const targetSkillPath = path.join(targetPath, skill.name);
|
|
192
|
+
|
|
193
|
+
if (skill.type === 'config') {
|
|
194
|
+
// Copy single file
|
|
195
|
+
await fs.copy(skill.path, path.join(targetPath, skill.name));
|
|
196
|
+
} else {
|
|
197
|
+
// Copy directory
|
|
198
|
+
await fs.copy(skill.path, targetSkillPath);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
copied.push(skill.name);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
errors.push({ name: skill.name, error: e.message });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { copied, errors };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Remove a skill from project
|
|
212
|
+
*/
|
|
213
|
+
export async function removeSkillFromProject(projectPath, skillName) {
|
|
214
|
+
const targetPath = path.join(projectPath, '.claude', 'skills', skillName);
|
|
215
|
+
|
|
216
|
+
if (!await fs.pathExists(targetPath)) {
|
|
217
|
+
return { success: false, error: 'Skill not found' };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
await fs.remove(targetPath);
|
|
222
|
+
return { success: true };
|
|
223
|
+
} catch (e) {
|
|
224
|
+
return { success: false, error: e.message };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Check if skills need updating
|
|
230
|
+
*/
|
|
231
|
+
export async function checkForUpdates(projectPath) {
|
|
232
|
+
const installed = await getInstalledSkills(projectPath);
|
|
233
|
+
const available = await getAvailableSkills();
|
|
234
|
+
|
|
235
|
+
const updates = [];
|
|
236
|
+
|
|
237
|
+
for (const installedSkill of installed) {
|
|
238
|
+
if (installedSkill.type === 'config') continue;
|
|
239
|
+
|
|
240
|
+
const availableSkill = available.find(a => a.name === installedSkill.name);
|
|
241
|
+
if (!availableSkill) continue;
|
|
242
|
+
|
|
243
|
+
if (installedSkill.version !== availableSkill.version) {
|
|
244
|
+
updates.push({
|
|
245
|
+
name: installedSkill.name,
|
|
246
|
+
current: installedSkill.version,
|
|
247
|
+
available: availableSkill.version
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return updates;
|
|
253
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Project-specific instructions for Claude Code.
|
|
4
|
+
|
|
5
|
+
## Skills
|
|
6
|
+
|
|
7
|
+
This project uses CodiHaus Claude Skills. Available skills:
|
|
8
|
+
|
|
9
|
+
| Skill | Purpose |
|
|
10
|
+
|-------|---------|
|
|
11
|
+
| `/debrief` | Create BRD and use cases from requirements |
|
|
12
|
+
| `/dev-scout` | Explore and document existing codebase |
|
|
13
|
+
| `/dev-arch` | Make architecture decisions |
|
|
14
|
+
| `/dev-specs` | Create implementation specifications |
|
|
15
|
+
| `/dev-coding` | Implement features from specs |
|
|
16
|
+
| `/dev-test` | Automated UI testing |
|
|
17
|
+
| `/dev-review` | Code review with quality checks |
|
|
18
|
+
| `/dev-changelog` | Document what was implemented |
|
|
19
|
+
|
|
20
|
+
### Utility Skills (called by other skills)
|
|
21
|
+
|
|
22
|
+
| Skill | Purpose |
|
|
23
|
+
|-------|---------|
|
|
24
|
+
| `/utils/diagram` | Mermaid diagram validation |
|
|
25
|
+
| `/utils/docs-graph` | Documentation relationship viewer |
|
|
26
|
+
| `/utils/gemini` | Large codebase scanning |
|
|
27
|
+
|
|
28
|
+
See `.claude/skills/_registry.md` for full documentation.
|
|
29
|
+
|
|
30
|
+
## Project Overview
|
|
31
|
+
|
|
32
|
+
{Add your project description here}
|
|
33
|
+
|
|
34
|
+
## Tech Stack
|
|
35
|
+
|
|
36
|
+
{List your technologies here}
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
|
|
40
|
+
### Getting Started
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Install dependencies
|
|
44
|
+
npm install
|
|
45
|
+
|
|
46
|
+
# Start development server
|
|
47
|
+
npm run dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Testing
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm test
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Conventions
|
|
57
|
+
|
|
58
|
+
{Add any project-specific conventions here}
|