@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.
Files changed (46) hide show
  1. package/README.md +167 -0
  2. package/bin/cli.js +58 -0
  3. package/package.json +46 -0
  4. package/skills/_quality-attributes.md +392 -0
  5. package/skills/_registry.md +189 -0
  6. package/skills/debrief/SKILL.md +647 -0
  7. package/skills/debrief/references/change-request-template.md +124 -0
  8. package/skills/debrief/references/file-patterns.md +173 -0
  9. package/skills/debrief/references/group-codes.md +72 -0
  10. package/skills/debrief/references/research-queries.md +106 -0
  11. package/skills/debrief/references/use-case-template.md +141 -0
  12. package/skills/debrief/scripts/generate_questionnaire.py +195 -0
  13. package/skills/dev-arch/SKILL.md +747 -0
  14. package/skills/dev-changelog/SKILL.md +378 -0
  15. package/skills/dev-coding/SKILL.md +470 -0
  16. package/skills/dev-coding-backend/SKILL.md +361 -0
  17. package/skills/dev-coding-frontend/SKILL.md +534 -0
  18. package/skills/dev-coding-frontend/references/nextjs.md +477 -0
  19. package/skills/dev-review/SKILL.md +548 -0
  20. package/skills/dev-scout/SKILL.md +723 -0
  21. package/skills/dev-scout/references/feature-patterns.md +210 -0
  22. package/skills/dev-scout/references/file-patterns.md +252 -0
  23. package/skills/dev-scout/references/tech-detection.md +211 -0
  24. package/skills/dev-scout/scripts/scout-analyze.sh +280 -0
  25. package/skills/dev-specs/SKILL.md +577 -0
  26. package/skills/dev-specs/references/checklist.md +176 -0
  27. package/skills/dev-specs/references/spec-templates.md +460 -0
  28. package/skills/dev-test/SKILL.md +364 -0
  29. package/skills/utils/diagram/SKILL.md +205 -0
  30. package/skills/utils/diagram/references/common-errors.md +305 -0
  31. package/skills/utils/diagram/references/diagram-types.md +636 -0
  32. package/skills/utils/docs-graph/SKILL.md +204 -0
  33. package/skills/utils/gemini/SKILL.md +292 -0
  34. package/skills/utils/gemini/scripts/gemini-scan.py +340 -0
  35. package/skills/utils/gemini/scripts/setup.sh +169 -0
  36. package/src/commands/add.js +64 -0
  37. package/src/commands/doctor.js +179 -0
  38. package/src/commands/init.js +251 -0
  39. package/src/commands/list.js +88 -0
  40. package/src/commands/remove.js +60 -0
  41. package/src/commands/update.js +72 -0
  42. package/src/index.js +26 -0
  43. package/src/utils/config.js +272 -0
  44. package/src/utils/deps.js +599 -0
  45. package/src/utils/skills.js +253 -0
  46. package/templates/CLAUDE.md.template +58 -0
@@ -0,0 +1,340 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Gemini Codebase Scanner
4
+
5
+ Scans a codebase using Gemini Flash's large context window
6
+ and produces a structured summary for Claude Code to use.
7
+
8
+ Usage:
9
+ python gemini-scan.py --path /path/to/project --output summary.md
10
+ """
11
+
12
+ import os
13
+ import sys
14
+ import argparse
15
+ from pathlib import Path
16
+ from typing import List, Set
17
+
18
+ # Check for google-generativeai
19
+ try:
20
+ import google.generativeai as genai
21
+ except ImportError:
22
+ print("Error: google-generativeai not installed")
23
+ print("Run: pip install google-generativeai")
24
+ sys.exit(1)
25
+
26
+
27
+ # Default file extensions to include
28
+ DEFAULT_EXTENSIONS = {
29
+ # JavaScript/TypeScript
30
+ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
31
+ # Python
32
+ '.py',
33
+ # Web
34
+ '.html', '.css', '.scss', '.sass', '.less',
35
+ # Config
36
+ '.json', '.yaml', '.yml', '.toml', '.env.example',
37
+ # Docs
38
+ '.md', '.mdx',
39
+ # Other
40
+ '.sql', '.graphql', '.prisma',
41
+ # Config files (no extension)
42
+ }
43
+
44
+ # Files to always include (by name)
45
+ INCLUDE_FILES = {
46
+ 'package.json', 'tsconfig.json', 'next.config.js', 'next.config.mjs',
47
+ 'vite.config.ts', 'vite.config.js', 'tailwind.config.js', 'tailwind.config.ts',
48
+ 'prisma/schema.prisma', '.env.example', 'docker-compose.yml', 'Dockerfile',
49
+ 'requirements.txt', 'pyproject.toml', 'Cargo.toml', 'go.mod',
50
+ 'README.md', 'CLAUDE.md',
51
+ }
52
+
53
+ # Default ignore patterns
54
+ DEFAULT_IGNORE = {
55
+ 'node_modules', '.git', '.next', '.nuxt', 'dist', 'build', 'out',
56
+ '__pycache__', '.pytest_cache', '.mypy_cache', 'venv', '.venv',
57
+ 'coverage', '.coverage', 'htmlcov', '.nyc_output',
58
+ '.idea', '.vscode', '*.log', '*.lock',
59
+ 'vendor', 'target', 'bin', 'obj',
60
+ }
61
+
62
+ DEFAULT_PROMPT = """Analyze this codebase and provide a structured summary:
63
+
64
+ 1. **Project Overview**
65
+ - What does this project do? (1-2 sentences)
66
+ - Main technologies/frameworks used
67
+
68
+ 2. **File Organization**
69
+ - Key directories and their purposes
70
+ - Entry points (main files)
71
+ - Configuration files
72
+
73
+ 3. **Architecture Patterns**
74
+ - Overall architecture (MVC, component-based, microservices, etc.)
75
+ - Coding conventions observed
76
+ - State management approach (if frontend)
77
+
78
+ 4. **Key Files** (most important files to understand the project)
79
+ - Entry points
80
+ - Core business logic
81
+ - API/route definitions
82
+ - Database models/schema
83
+
84
+ 5. **Dependencies**
85
+ - Key external packages and their purpose
86
+ - Internal module structure
87
+
88
+ 6. **For Scout** (recommendations for deeper analysis)
89
+ - Which files/folders need closer inspection
90
+ - Potential complexity areas
91
+ - Suggested focus areas
92
+
93
+ Be concise but comprehensive. Use markdown formatting with headers and tables where appropriate.
94
+ """
95
+
96
+
97
+ def load_gitignore(path: Path) -> Set[str]:
98
+ """Load patterns from .gitignore file."""
99
+ gitignore_path = path / '.gitignore'
100
+ patterns = set()
101
+
102
+ if gitignore_path.exists():
103
+ with open(gitignore_path, 'r') as f:
104
+ for line in f:
105
+ line = line.strip()
106
+ if line and not line.startswith('#'):
107
+ # Simple pattern handling
108
+ patterns.add(line.rstrip('/'))
109
+
110
+ return patterns
111
+
112
+
113
+ def should_ignore(path: Path, ignore_patterns: Set[str]) -> bool:
114
+ """Check if path should be ignored."""
115
+ name = path.name
116
+
117
+ # Check against ignore patterns
118
+ for pattern in ignore_patterns:
119
+ if pattern.startswith('*'):
120
+ if name.endswith(pattern[1:]):
121
+ return True
122
+ elif name == pattern or pattern in str(path):
123
+ return True
124
+
125
+ return False
126
+
127
+
128
+ def collect_files(
129
+ root_path: Path,
130
+ extensions: Set[str],
131
+ ignore_patterns: Set[str],
132
+ max_files: int
133
+ ) -> List[Path]:
134
+ """Collect files from the directory."""
135
+ files = []
136
+
137
+ for path in root_path.rglob('*'):
138
+ if len(files) >= max_files:
139
+ break
140
+
141
+ if not path.is_file():
142
+ continue
143
+
144
+ if should_ignore(path, ignore_patterns):
145
+ continue
146
+
147
+ # Check if it's in INCLUDE_FILES or has valid extension
148
+ rel_path = str(path.relative_to(root_path))
149
+ if rel_path in INCLUDE_FILES or path.name in INCLUDE_FILES:
150
+ files.append(path)
151
+ elif path.suffix.lower() in extensions:
152
+ files.append(path)
153
+
154
+ return sorted(files)
155
+
156
+
157
+ def read_file_content(path: Path, max_lines: int = 500) -> str:
158
+ """Read file content with line limit."""
159
+ try:
160
+ with open(path, 'r', encoding='utf-8', errors='ignore') as f:
161
+ lines = f.readlines()
162
+
163
+ if len(lines) > max_lines:
164
+ content = ''.join(lines[:max_lines])
165
+ content += f"\n... (truncated, {len(lines) - max_lines} more lines)"
166
+ else:
167
+ content = ''.join(lines)
168
+
169
+ return content
170
+ except Exception as e:
171
+ return f"Error reading file: {e}"
172
+
173
+
174
+ def build_codebase_content(root_path: Path, files: List[Path]) -> str:
175
+ """Build the codebase content string."""
176
+ parts = []
177
+
178
+ # Add file tree first
179
+ parts.append("# File Structure\n")
180
+ parts.append("```")
181
+
182
+ # Build simple tree
183
+ for f in files[:100]: # Limit tree display
184
+ rel_path = f.relative_to(root_path)
185
+ parts.append(str(rel_path))
186
+
187
+ if len(files) > 100:
188
+ parts.append(f"... and {len(files) - 100} more files")
189
+
190
+ parts.append("```\n")
191
+
192
+ # Add file contents
193
+ parts.append("# File Contents\n")
194
+
195
+ for f in files:
196
+ rel_path = f.relative_to(root_path)
197
+ content = read_file_content(f)
198
+
199
+ parts.append(f"\n## {rel_path}\n")
200
+ parts.append(f"```{f.suffix[1:] if f.suffix else ''}")
201
+ parts.append(content)
202
+ parts.append("```\n")
203
+
204
+ return '\n'.join(parts)
205
+
206
+
207
+ def scan_with_gemini(content: str, prompt: str, api_key: str) -> str:
208
+ """Send content to Gemini and get summary."""
209
+ genai.configure(api_key=api_key)
210
+
211
+ model = genai.GenerativeModel(
212
+ model_name="gemini-1.5-flash",
213
+ generation_config={
214
+ "temperature": 0.3,
215
+ "max_output_tokens": 8192,
216
+ }
217
+ )
218
+
219
+ full_prompt = f"{prompt}\n\n---\n\n{content}"
220
+
221
+ print(f"Sending to Gemini ({len(full_prompt):,} characters)...")
222
+
223
+ response = model.generate_content(full_prompt)
224
+
225
+ return response.text
226
+
227
+
228
+ def main():
229
+ parser = argparse.ArgumentParser(
230
+ description='Scan codebase with Gemini Flash'
231
+ )
232
+ parser.add_argument(
233
+ '--path', '-p',
234
+ type=str,
235
+ default='.',
236
+ help='Path to scan (default: current directory)'
237
+ )
238
+ parser.add_argument(
239
+ '--output', '-o',
240
+ type=str,
241
+ help='Output file path (default: stdout)'
242
+ )
243
+ parser.add_argument(
244
+ '--prompt',
245
+ type=str,
246
+ default=DEFAULT_PROMPT,
247
+ help='Custom prompt for Gemini'
248
+ )
249
+ parser.add_argument(
250
+ '--extensions', '-e',
251
+ type=str,
252
+ nargs='+',
253
+ help='File extensions to include (e.g., .py .js)'
254
+ )
255
+ parser.add_argument(
256
+ '--max-files', '-m',
257
+ type=int,
258
+ default=500,
259
+ help='Maximum files to process (default: 500)'
260
+ )
261
+ parser.add_argument(
262
+ '--ignore', '-i',
263
+ type=str,
264
+ nargs='+',
265
+ help='Additional patterns to ignore'
266
+ )
267
+
268
+ args = parser.parse_args()
269
+
270
+ # Check API key
271
+ api_key = os.environ.get('GEMINI_API_KEY')
272
+ if not api_key:
273
+ print("Error: GEMINI_API_KEY environment variable not set")
274
+ print("Run the setup script: ./scripts/setup.sh")
275
+ sys.exit(1)
276
+
277
+ # Setup paths
278
+ root_path = Path(args.path).resolve()
279
+ if not root_path.exists():
280
+ print(f"Error: Path does not exist: {root_path}")
281
+ sys.exit(1)
282
+
283
+ print(f"Scanning: {root_path}")
284
+
285
+ # Setup extensions
286
+ extensions = set(args.extensions) if args.extensions else DEFAULT_EXTENSIONS
287
+
288
+ # Setup ignore patterns
289
+ ignore_patterns = DEFAULT_IGNORE.copy()
290
+ ignore_patterns.update(load_gitignore(root_path))
291
+ if args.ignore:
292
+ ignore_patterns.update(args.ignore)
293
+
294
+ # Collect files
295
+ print("Collecting files...")
296
+ files = collect_files(root_path, extensions, ignore_patterns, args.max_files)
297
+ print(f"Found {len(files)} files")
298
+
299
+ if not files:
300
+ print("No files found to scan")
301
+ sys.exit(1)
302
+
303
+ # Build content
304
+ print("Building content...")
305
+ content = build_codebase_content(root_path, files)
306
+
307
+ # Scan with Gemini
308
+ try:
309
+ result = scan_with_gemini(content, args.prompt, api_key)
310
+ except Exception as e:
311
+ print(f"Error calling Gemini API: {e}")
312
+ sys.exit(1)
313
+
314
+ # Add metadata header
315
+ output = f"""# Gemini Codebase Summary
316
+
317
+ > Generated by: gemini-scan.py
318
+ > Path: {root_path}
319
+ > Files scanned: {len(files)}
320
+ > Model: gemini-1.5-flash
321
+
322
+ ---
323
+
324
+ {result}
325
+ """
326
+
327
+ # Output
328
+ if args.output:
329
+ output_path = Path(args.output)
330
+ output_path.parent.mkdir(parents=True, exist_ok=True)
331
+ with open(output_path, 'w') as f:
332
+ f.write(output)
333
+ print(f"Output written to: {output_path}")
334
+ else:
335
+ print("\n" + "="*60 + "\n")
336
+ print(output)
337
+
338
+
339
+ if __name__ == '__main__':
340
+ main()
@@ -0,0 +1,169 @@
1
+ #!/bin/bash
2
+
3
+ # Gemini Setup Script
4
+ # Sets up API key and verifies connection
5
+
6
+ echo "========================================"
7
+ echo " Gemini Flash Setup for Claude Code"
8
+ echo "========================================"
9
+ echo ""
10
+
11
+ # Colors
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ NC='\033[0m' # No Color
16
+
17
+ # Check if API key already exists
18
+ if [ -n "$GEMINI_API_KEY" ]; then
19
+ echo -e "${GREEN}[OK]${NC} GEMINI_API_KEY found in environment"
20
+ EXISTING_KEY=true
21
+ else
22
+ echo -e "${YELLOW}[!]${NC} GEMINI_API_KEY not found"
23
+ EXISTING_KEY=false
24
+ fi
25
+
26
+ # Check .env file
27
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
29
+ ENV_FILE="$PROJECT_ROOT/.env"
30
+
31
+ if [ -f "$ENV_FILE" ]; then
32
+ if grep -q "GEMINI_API_KEY" "$ENV_FILE"; then
33
+ echo -e "${GREEN}[OK]${NC} GEMINI_API_KEY found in .env file"
34
+ # Source it
35
+ export $(grep "GEMINI_API_KEY" "$ENV_FILE" | xargs)
36
+ EXISTING_KEY=true
37
+ fi
38
+ fi
39
+
40
+ echo ""
41
+
42
+ if [ "$EXISTING_KEY" = false ]; then
43
+ echo "To get a Gemini API key:"
44
+ echo ""
45
+ echo "1. Go to: https://aistudio.google.com/app/apikey"
46
+ echo "2. Click 'Create API key'"
47
+ echo "3. Copy the key"
48
+ echo ""
49
+ read -p "Enter your Gemini API key: " API_KEY
50
+
51
+ if [ -z "$API_KEY" ]; then
52
+ echo -e "${RED}[ERROR]${NC} No API key provided"
53
+ exit 1
54
+ fi
55
+
56
+ # Save to .env file
57
+ echo ""
58
+ echo "Where to save the API key?"
59
+ echo "1. Project .env file (recommended)"
60
+ echo "2. Shell profile (~/.bashrc or ~/.zshrc)"
61
+ echo "3. Both"
62
+ read -p "Choice [1]: " SAVE_CHOICE
63
+ SAVE_CHOICE=${SAVE_CHOICE:-1}
64
+
65
+ case $SAVE_CHOICE in
66
+ 1)
67
+ echo "GEMINI_API_KEY=$API_KEY" >> "$ENV_FILE"
68
+ echo -e "${GREEN}[OK]${NC} Saved to $ENV_FILE"
69
+ ;;
70
+ 2)
71
+ SHELL_PROFILE="$HOME/.bashrc"
72
+ if [ -f "$HOME/.zshrc" ]; then
73
+ SHELL_PROFILE="$HOME/.zshrc"
74
+ fi
75
+ echo "export GEMINI_API_KEY=$API_KEY" >> "$SHELL_PROFILE"
76
+ echo -e "${GREEN}[OK]${NC} Saved to $SHELL_PROFILE"
77
+ echo -e "${YELLOW}[!]${NC} Run: source $SHELL_PROFILE"
78
+ ;;
79
+ 3)
80
+ echo "GEMINI_API_KEY=$API_KEY" >> "$ENV_FILE"
81
+ SHELL_PROFILE="$HOME/.bashrc"
82
+ if [ -f "$HOME/.zshrc" ]; then
83
+ SHELL_PROFILE="$HOME/.zshrc"
84
+ fi
85
+ echo "export GEMINI_API_KEY=$API_KEY" >> "$SHELL_PROFILE"
86
+ echo -e "${GREEN}[OK]${NC} Saved to both"
87
+ ;;
88
+ esac
89
+
90
+ export GEMINI_API_KEY="$API_KEY"
91
+ fi
92
+
93
+ echo ""
94
+ echo "Checking Python dependencies..."
95
+
96
+ # Check Python
97
+ if ! command -v python3 &> /dev/null; then
98
+ echo -e "${RED}[ERROR]${NC} Python 3 not found"
99
+ echo "Install Python 3 first: https://www.python.org/downloads/"
100
+ exit 1
101
+ fi
102
+ echo -e "${GREEN}[OK]${NC} Python 3 found"
103
+
104
+ # Check google-generativeai
105
+ if python3 -c "import google.generativeai" 2>/dev/null; then
106
+ echo -e "${GREEN}[OK]${NC} google-generativeai installed"
107
+ else
108
+ echo -e "${YELLOW}[!]${NC} google-generativeai not installed"
109
+ read -p "Install now? [Y/n]: " INSTALL
110
+ INSTALL=${INSTALL:-Y}
111
+ if [[ $INSTALL =~ ^[Yy]$ ]]; then
112
+ pip install google-generativeai
113
+ if [ $? -eq 0 ]; then
114
+ echo -e "${GREEN}[OK]${NC} Installed successfully"
115
+ else
116
+ echo -e "${RED}[ERROR]${NC} Installation failed"
117
+ exit 1
118
+ fi
119
+ else
120
+ echo "Please run: pip install google-generativeai"
121
+ exit 1
122
+ fi
123
+ fi
124
+
125
+ echo ""
126
+ echo "Testing connection..."
127
+
128
+ # Test API
129
+ python3 << 'EOF'
130
+ import os
131
+ import sys
132
+
133
+ try:
134
+ import google.generativeai as genai
135
+ except ImportError:
136
+ print("ERROR: google-generativeai not installed")
137
+ sys.exit(1)
138
+
139
+ api_key = os.environ.get("GEMINI_API_KEY")
140
+ if not api_key:
141
+ print("ERROR: GEMINI_API_KEY not set")
142
+ sys.exit(1)
143
+
144
+ try:
145
+ genai.configure(api_key=api_key)
146
+ model = genai.GenerativeModel("gemini-1.5-flash")
147
+ response = model.generate_content("Say 'Hello from Gemini!' in exactly those words.")
148
+ print(f"Response: {response.text.strip()}")
149
+ print("SUCCESS: Gemini API working!")
150
+ except Exception as e:
151
+ print(f"ERROR: {e}")
152
+ sys.exit(1)
153
+ EOF
154
+
155
+ if [ $? -eq 0 ]; then
156
+ echo ""
157
+ echo -e "${GREEN}========================================"
158
+ echo " Setup Complete!"
159
+ echo "========================================${NC}"
160
+ echo ""
161
+ echo "You can now use Gemini for codebase scanning:"
162
+ echo ""
163
+ echo " python scripts/gemini-scan.py --path /your/project"
164
+ echo ""
165
+ else
166
+ echo ""
167
+ echo -e "${RED}Setup failed. Check errors above.${NC}"
168
+ exit 1
169
+ fi
@@ -0,0 +1,64 @@
1
+ /**
2
+ * add command
3
+ *
4
+ * Add a specific skill to the project.
5
+ */
6
+
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+
10
+ import { getAvailableSkills, getInstalledSkills, copySkillsToProject } from '../utils/skills.js';
11
+
12
+ export async function add(skillName) {
13
+ const projectPath = process.cwd();
14
+
15
+ console.log(chalk.bold(`\n➕ Adding skill: ${skillName}\n`));
16
+
17
+ // Check if skill exists
18
+ const available = await getAvailableSkills();
19
+ const skill = available.find(s => s.name === skillName);
20
+
21
+ if (!skill) {
22
+ console.log(chalk.red(`❌ Skill not found: ${skillName}\n`));
23
+ console.log('Available skills:');
24
+
25
+ for (const s of available.filter(s => s.type !== 'config')) {
26
+ console.log(` - ${s.name}`);
27
+ }
28
+
29
+ console.log('');
30
+ process.exit(1);
31
+ }
32
+
33
+ // Check if already installed
34
+ const installed = await getInstalledSkills(projectPath);
35
+ const alreadyInstalled = installed.find(s => s.name === skillName);
36
+
37
+ if (alreadyInstalled) {
38
+ console.log(chalk.yellow(`⚠️ Skill already installed: ${skillName}\n`));
39
+ console.log(chalk.gray('Use `claude-skills update` to update to latest version.\n'));
40
+ process.exit(0);
41
+ }
42
+
43
+ // Install the skill
44
+ const spinner = ora(`Installing ${skillName}...`).start();
45
+
46
+ try {
47
+ const { copied, errors } = await copySkillsToProject(projectPath, [skillName]);
48
+
49
+ if (errors.length > 0) {
50
+ spinner.fail(`Failed to install ${skillName}`);
51
+ console.log(chalk.red(errors[0].error));
52
+ process.exit(1);
53
+ }
54
+
55
+ spinner.succeed(`Installed ${skillName}`);
56
+ } catch (e) {
57
+ spinner.fail('Installation failed');
58
+ console.error(chalk.red(e.message));
59
+ process.exit(1);
60
+ }
61
+
62
+ console.log(chalk.green(`\n✅ ${skillName} added successfully!\n`));
63
+ console.log(`Try it: ${chalk.cyan(`/${skillName}`)}\n`);
64
+ }