@acmecloud/core 1.0.5 → 1.0.7
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/dist/skills/builtin/code-concise.md +84 -0
- package/dist/skills/builtin/frontend-design.md +137 -0
- package/dist/skills/builtin/systematic-debugging.md +156 -0
- package/dist/skills/builtin/tdd.md +157 -0
- package/dist/skills/builtin/windows-shell-guide.md +119 -0
- package/dist/skills/index.js +56 -11
- package/package.json +5 -3
- package/src/skills/builtin/code-concise.md +84 -0
- package/src/skills/builtin/frontend-design.md +137 -0
- package/src/skills/builtin/systematic-debugging.md +156 -0
- package/src/skills/builtin/tdd.md +157 -0
- package/src/skills/builtin/windows-shell-guide.md +119 -0
- package/src/skills/index.ts +141 -86
package/dist/skills/index.js
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
|
-
import * as fs from
|
|
2
|
-
import path from
|
|
3
|
-
import os from
|
|
1
|
+
import * as fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { dirname } from "path";
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
/**
|
|
9
|
+
* Load built-in skills from the builtin directory
|
|
10
|
+
*/
|
|
11
|
+
async function loadBuiltinSkills() {
|
|
12
|
+
const builtinSkillsDir = path.join(__dirname, "builtin");
|
|
13
|
+
const skills = [];
|
|
14
|
+
try {
|
|
15
|
+
const files = await fs.readdir(builtinSkillsDir);
|
|
16
|
+
for (const file of files) {
|
|
17
|
+
if (file.endsWith(".md")) {
|
|
18
|
+
const filePath = path.join(builtinSkillsDir, file);
|
|
19
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
20
|
+
let name = file.replace(".md", "");
|
|
21
|
+
let description = `Skill ${name}`;
|
|
22
|
+
// Extract name from frontmatter
|
|
23
|
+
const nameMatch = content.match(/^---[\r\n]+name:\s*(.*)/m);
|
|
24
|
+
if (nameMatch) {
|
|
25
|
+
name = nameMatch[1].trim();
|
|
26
|
+
}
|
|
27
|
+
// Extract description from frontmatter
|
|
28
|
+
const descriptionMatch = content.match(/^description:\s*(.*)/m);
|
|
29
|
+
if (descriptionMatch) {
|
|
30
|
+
description = descriptionMatch[1].trim();
|
|
31
|
+
}
|
|
32
|
+
skills.push({ name, description, content });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err.code !== "ENOENT") {
|
|
38
|
+
console.warn(`Could not read builtin skills: ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return skills;
|
|
42
|
+
}
|
|
4
43
|
/**
|
|
5
44
|
* Searches upward from startDir for the given targets.
|
|
6
45
|
*/
|
|
@@ -28,12 +67,12 @@ async function findUpDirectories(startDir, targets) {
|
|
|
28
67
|
return results;
|
|
29
68
|
}
|
|
30
69
|
export async function loadSkills() {
|
|
31
|
-
const globalSkillsPath = path.join(os.homedir(),
|
|
70
|
+
const globalSkillsPath = path.join(os.homedir(), ".acmecode", "skills");
|
|
32
71
|
// OpenCode patterns: .agents/skills, .claude/skills, .acmecode/skills
|
|
33
72
|
const searchTargets = [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
73
|
+
".acmecode/skills",
|
|
74
|
+
".agents/skills",
|
|
75
|
+
".claude/skills",
|
|
37
76
|
];
|
|
38
77
|
const localSkillDirs = await findUpDirectories(process.cwd(), searchTargets);
|
|
39
78
|
// Priority: Lower directories in the tree (closer to project root) are processed first,
|
|
@@ -41,13 +80,19 @@ export async function loadSkills() {
|
|
|
41
80
|
// Global is processed first of all.
|
|
42
81
|
const allDirs = [globalSkillsPath, ...localSkillDirs.reverse()];
|
|
43
82
|
const skillsMap = new Map();
|
|
83
|
+
// First, load built-in skills
|
|
84
|
+
const builtinSkills = await loadBuiltinSkills();
|
|
85
|
+
for (const skill of builtinSkills) {
|
|
86
|
+
skillsMap.set(skill.name, skill);
|
|
87
|
+
}
|
|
88
|
+
// Then load user skills (can override built-ins)
|
|
44
89
|
for (const dir of allDirs) {
|
|
45
90
|
try {
|
|
46
91
|
const files = await fs.readdir(dir);
|
|
47
92
|
for (const file of files) {
|
|
48
|
-
if (file.endsWith(
|
|
49
|
-
const content = await fs.readFile(path.join(dir, file),
|
|
50
|
-
let name = file.replace(
|
|
93
|
+
if (file.endsWith(".md")) {
|
|
94
|
+
const content = await fs.readFile(path.join(dir, file), "utf8");
|
|
95
|
+
let name = file.replace(".md", "");
|
|
51
96
|
// Improved parsing: Look for name and description in YAML frontmatter or content
|
|
52
97
|
let description = `Skill ${name}`;
|
|
53
98
|
// Try to extract name from frontmatter
|
|
@@ -63,7 +108,7 @@ export async function loadSkills() {
|
|
|
63
108
|
}
|
|
64
109
|
}
|
|
65
110
|
catch (err) {
|
|
66
|
-
if (err.code !==
|
|
111
|
+
if (err.code !== "ENOENT") {
|
|
67
112
|
console.warn(`Could not read skills directory ${dir}: ${err.message}`);
|
|
68
113
|
}
|
|
69
114
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acmecloud/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsc"
|
|
13
|
+
"build": "tsc && cpx \"src/skills/builtin/*.md\" dist/skills/builtin/",
|
|
14
|
+
"postbuild": "cpx \"src/skills/builtin/*.md\" dist/skills/builtin/"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
17
|
"@ai-sdk/anthropic": "^3.0.46",
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/diff": "^7.0.2",
|
|
39
|
-
"@types/turndown": "^5.0.6"
|
|
40
|
+
"@types/turndown": "^5.0.6",
|
|
41
|
+
"cpx": "^1.5.0"
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-concise
|
|
3
|
+
description: Code review and optimization based on Clean Code principles
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Clean Code Review & Optimization Skill
|
|
7
|
+
|
|
8
|
+
This skill provides automated code review and intelligent optimization recommendations based on "Clean Code" principles.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Apply when:
|
|
13
|
+
|
|
14
|
+
- Reviewing code for issues
|
|
15
|
+
- Analyzing code quality
|
|
16
|
+
- Providing improvement suggestions
|
|
17
|
+
- Optimizing existing code
|
|
18
|
+
|
|
19
|
+
## Core Rules
|
|
20
|
+
|
|
21
|
+
### Priority Levels
|
|
22
|
+
|
|
23
|
+
**CRITICAL** - Must fix immediately:
|
|
24
|
+
|
|
25
|
+
- Security vulnerabilities
|
|
26
|
+
- Data loss risks
|
|
27
|
+
- Performance disasters
|
|
28
|
+
- Logic errors
|
|
29
|
+
- Null pointer exceptions
|
|
30
|
+
|
|
31
|
+
**HIGH** - Should fix soon:
|
|
32
|
+
|
|
33
|
+
- Code duplication > 10 lines
|
|
34
|
+
- Functions > 50 lines
|
|
35
|
+
- Cyclomatic complexity > 10
|
|
36
|
+
- Missing error handling
|
|
37
|
+
|
|
38
|
+
**MEDIUM** - Should fix eventually:
|
|
39
|
+
|
|
40
|
+
- Non-meaningful names
|
|
41
|
+
- Inconsistent naming
|
|
42
|
+
- Missing documentation
|
|
43
|
+
|
|
44
|
+
**LOW** - Nice to have:
|
|
45
|
+
|
|
46
|
+
- Formatting issues
|
|
47
|
+
- Minor style violations
|
|
48
|
+
|
|
49
|
+
### Naming Issues
|
|
50
|
+
|
|
51
|
+
**Bad:** `d`, `temp`, `data`, `process()`, `handle()`
|
|
52
|
+
**Good:** `days`, `dailyRate`, `calculateTotalCost()`
|
|
53
|
+
|
|
54
|
+
### Function Issues
|
|
55
|
+
|
|
56
|
+
- Functions should be < 20 lines (WARNING if > 20, HIGH if > 50)
|
|
57
|
+
- Parameters should be ≤ 3 (use objects for more)
|
|
58
|
+
- No boolean flags that change behavior
|
|
59
|
+
- Separate side effects from return values
|
|
60
|
+
|
|
61
|
+
### Code Duplication
|
|
62
|
+
|
|
63
|
+
- Extract repeated blocks (>10 lines) to functions
|
|
64
|
+
- Use parameterization for similar logic
|
|
65
|
+
|
|
66
|
+
### Error Handling
|
|
67
|
+
|
|
68
|
+
- Never ignore errors (empty catch blocks)
|
|
69
|
+
- Don't return null - throw exceptions or use Optional
|
|
70
|
+
- Don't use magic error codes - use exceptions
|
|
71
|
+
|
|
72
|
+
### Code Structure
|
|
73
|
+
|
|
74
|
+
- Max 3 levels of nesting (use guard clauses)
|
|
75
|
+
- No magic numbers (use named constants)
|
|
76
|
+
- Classes should be < 200 lines
|
|
77
|
+
|
|
78
|
+
## Review Workflow
|
|
79
|
+
|
|
80
|
+
1. **Quick Scan**: Identify top 3-5 critical issues
|
|
81
|
+
2. **Detailed Review**: Expand on specific issues when asked
|
|
82
|
+
3. **Optimization**: Provide refactoring suggestions when requested
|
|
83
|
+
|
|
84
|
+
Provide actionable fixes with before/after code examples.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: Create distinctive, production-grade frontend interfaces
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Frontend Design
|
|
7
|
+
|
|
8
|
+
Create distinctive, production-grade frontend interfaces with high design quality.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use when building:
|
|
13
|
+
|
|
14
|
+
- Web components
|
|
15
|
+
- Landing pages
|
|
16
|
+
- Dashboards
|
|
17
|
+
- React/Vue components
|
|
18
|
+
- HTML/CSS layouts
|
|
19
|
+
- Any web UI
|
|
20
|
+
|
|
21
|
+
## Design Principles
|
|
22
|
+
|
|
23
|
+
### 1. Choose a Bold Direction
|
|
24
|
+
|
|
25
|
+
Before coding, understand:
|
|
26
|
+
|
|
27
|
+
- **Purpose**: What problem does this solve?
|
|
28
|
+
- **Tone**: Pick an extreme (minimalist, maximalist, retro, futuristic, etc.)
|
|
29
|
+
- **Constraints**: Technical requirements
|
|
30
|
+
- **Differentiation**: What makes this UNFORGETTABLE?
|
|
31
|
+
|
|
32
|
+
### 2. Typography Matters
|
|
33
|
+
|
|
34
|
+
**Do:**
|
|
35
|
+
|
|
36
|
+
- Choose distinctive fonts
|
|
37
|
+
- Pair display fonts with body fonts
|
|
38
|
+
- Use font weights intentionally
|
|
39
|
+
|
|
40
|
+
**Avoid:**
|
|
41
|
+
|
|
42
|
+
- Generic fonts (Arial, Inter, Roboto) as defaults
|
|
43
|
+
- System fonts for distinctive designs
|
|
44
|
+
|
|
45
|
+
### 3. Color & Theme
|
|
46
|
+
|
|
47
|
+
- Commit to a cohesive palette
|
|
48
|
+
- Use CSS variables for consistency
|
|
49
|
+
- Dominant colors with sharp accents
|
|
50
|
+
- Avoid timid, evenly-distributed palettes
|
|
51
|
+
|
|
52
|
+
### 4. Motion & Animation
|
|
53
|
+
|
|
54
|
+
- Use CSS animations for polish
|
|
55
|
+
- Staggered reveals (animation-delay)
|
|
56
|
+
- Scroll-triggered effects
|
|
57
|
+
- Hover states that surprise
|
|
58
|
+
- One well-orchestrated page load > many micro-interactions
|
|
59
|
+
|
|
60
|
+
### 5. Spatial Composition
|
|
61
|
+
|
|
62
|
+
- Unexpected layouts
|
|
63
|
+
- Asymmetry
|
|
64
|
+
- Diagonal flow
|
|
65
|
+
- Grid-breaking elements
|
|
66
|
+
- Generous negative space OR controlled density
|
|
67
|
+
|
|
68
|
+
### 6. Visual Details
|
|
69
|
+
|
|
70
|
+
Create atmosphere with:
|
|
71
|
+
|
|
72
|
+
- Gradient meshes
|
|
73
|
+
- Noise textures
|
|
74
|
+
- Geometric patterns
|
|
75
|
+
- Layered transparencies
|
|
76
|
+
- Dramatic shadows
|
|
77
|
+
- Custom cursors
|
|
78
|
+
- Grain overlays
|
|
79
|
+
|
|
80
|
+
## Avoid Generic AI Aesthetics
|
|
81
|
+
|
|
82
|
+
❌ Generic fonts (Inter, Roboto, Arial)
|
|
83
|
+
❌ Purple gradients on white
|
|
84
|
+
❌ Predictable layouts
|
|
85
|
+
❌ Cookie-cutter components
|
|
86
|
+
|
|
87
|
+
✅ Distinctive font choices
|
|
88
|
+
✅ Unexpected color combinations
|
|
89
|
+
✅ Creative layouts
|
|
90
|
+
✅ Contextual design decisions
|
|
91
|
+
|
|
92
|
+
## Implementation Guidelines
|
|
93
|
+
|
|
94
|
+
### Maximalist Design
|
|
95
|
+
|
|
96
|
+
Needs elaborate code with:
|
|
97
|
+
|
|
98
|
+
- Extensive animations
|
|
99
|
+
- Multiple effects
|
|
100
|
+
- Layered elements
|
|
101
|
+
- Rich interactions
|
|
102
|
+
|
|
103
|
+
### Minimalist Design
|
|
104
|
+
|
|
105
|
+
Needs restraint with:
|
|
106
|
+
|
|
107
|
+
- Precise spacing
|
|
108
|
+
- Careful typography
|
|
109
|
+
- Subtle details
|
|
110
|
+
- Perfect proportions
|
|
111
|
+
|
|
112
|
+
## Code Quality
|
|
113
|
+
|
|
114
|
+
Your code should be:
|
|
115
|
+
|
|
116
|
+
- Production-grade
|
|
117
|
+
- Functional
|
|
118
|
+
- Visually striking
|
|
119
|
+
- Meticulously refined
|
|
120
|
+
|
|
121
|
+
Match implementation complexity to aesthetic vision.
|
|
122
|
+
|
|
123
|
+
## Quick Reference
|
|
124
|
+
|
|
125
|
+
**Before coding:**
|
|
126
|
+
|
|
127
|
+
1. What's the purpose?
|
|
128
|
+
2. What's the tone?
|
|
129
|
+
3. What makes it memorable?
|
|
130
|
+
|
|
131
|
+
**While coding:**
|
|
132
|
+
|
|
133
|
+
1. Is this distinctive or generic?
|
|
134
|
+
2. Are details refined?
|
|
135
|
+
3. Does it match the vision?
|
|
136
|
+
|
|
137
|
+
**Remember:** Claude is capable of extraordinary creative work. Don't settle for generic.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: systematic-debugging
|
|
3
|
+
description: Systematic debugging - find root cause before proposing fixes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Systematic Debugging
|
|
7
|
+
|
|
8
|
+
**Core principle:** ALWAYS find root cause before attempting fixes. Symptom fixes are failure.
|
|
9
|
+
|
|
10
|
+
**The Iron Law:** NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
|
|
11
|
+
|
|
12
|
+
If you haven't completed Phase 1, you cannot propose fixes.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
Use for ANY technical issue:
|
|
17
|
+
|
|
18
|
+
- Test failures
|
|
19
|
+
- Bugs in production
|
|
20
|
+
- Unexpected behavior
|
|
21
|
+
- Performance problems
|
|
22
|
+
- Build failures
|
|
23
|
+
- Integration issues
|
|
24
|
+
|
|
25
|
+
**Use ESPECIALLY when:**
|
|
26
|
+
|
|
27
|
+
- Under time pressure (emergencies make guessing tempting)
|
|
28
|
+
- "Just one quick fix" seems obvious
|
|
29
|
+
- You've already tried multiple fixes
|
|
30
|
+
- You don't fully understand the issue
|
|
31
|
+
|
|
32
|
+
## Phase 1: Root Cause Investigation
|
|
33
|
+
|
|
34
|
+
### Step 1: Read Error Messages Carefully
|
|
35
|
+
|
|
36
|
+
- Don't skip past errors or warnings
|
|
37
|
+
- Read stack traces completely
|
|
38
|
+
- Note line numbers, file paths, error codes
|
|
39
|
+
- They often contain the exact solution
|
|
40
|
+
|
|
41
|
+
### Step 2: Reproduce Consistently
|
|
42
|
+
|
|
43
|
+
Ask:
|
|
44
|
+
|
|
45
|
+
- Can you trigger it reliably?
|
|
46
|
+
- What are the exact steps?
|
|
47
|
+
- Does it happen every time?
|
|
48
|
+
- If not reproducible → gather more data, don't guess
|
|
49
|
+
|
|
50
|
+
### Step 3: Check Recent Changes
|
|
51
|
+
|
|
52
|
+
- What changed that could cause this?
|
|
53
|
+
- Git diff, recent commits
|
|
54
|
+
- New dependencies, config changes
|
|
55
|
+
- Environmental differences
|
|
56
|
+
|
|
57
|
+
### Step 4: Gather Evidence
|
|
58
|
+
|
|
59
|
+
In multi-component systems:
|
|
60
|
+
|
|
61
|
+
- Log what data enters each component
|
|
62
|
+
- Log what data exits each component
|
|
63
|
+
- Verify environment/config propagation
|
|
64
|
+
- Check state at each layer
|
|
65
|
+
|
|
66
|
+
**Example diagnostic approach:**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Check each layer
|
|
70
|
+
echo "=== Layer 1: Input ==="
|
|
71
|
+
# Check input data
|
|
72
|
+
|
|
73
|
+
echo "=== Layer 2: Processing ==="
|
|
74
|
+
# Check processing state
|
|
75
|
+
|
|
76
|
+
echo "=== Layer 3: Output ==="
|
|
77
|
+
# Check output data
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Phase 2: Hypothesis Formation
|
|
81
|
+
|
|
82
|
+
After gathering evidence:
|
|
83
|
+
|
|
84
|
+
1. **List observed symptoms**
|
|
85
|
+
- What exactly is happening?
|
|
86
|
+
- What should happen instead?
|
|
87
|
+
|
|
88
|
+
2. **Form hypotheses**
|
|
89
|
+
- What could cause these symptoms?
|
|
90
|
+
- Rank by likelihood
|
|
91
|
+
|
|
92
|
+
3. **Test hypotheses systematically**
|
|
93
|
+
- Start with most likely
|
|
94
|
+
- Design tests that prove/disprove
|
|
95
|
+
|
|
96
|
+
## Phase 3: Fix Implementation
|
|
97
|
+
|
|
98
|
+
Only after root cause is found:
|
|
99
|
+
|
|
100
|
+
1. **Propose minimal fix**
|
|
101
|
+
- Address root cause, not symptoms
|
|
102
|
+
- Smallest change possible
|
|
103
|
+
|
|
104
|
+
2. **Verify fix**
|
|
105
|
+
- Run all tests
|
|
106
|
+
- Check for regressions
|
|
107
|
+
- Verify root cause is resolved
|
|
108
|
+
|
|
109
|
+
3. **Document learnings**
|
|
110
|
+
- What caused the bug?
|
|
111
|
+
- How can we prevent this?
|
|
112
|
+
- Add tests if missing
|
|
113
|
+
|
|
114
|
+
## Red Flags
|
|
115
|
+
|
|
116
|
+
**STOP if you're about to:**
|
|
117
|
+
|
|
118
|
+
- Change random things hoping it works
|
|
119
|
+
- Apply fixes without understanding
|
|
120
|
+
- Say "let me just try this"
|
|
121
|
+
- Skip error messages
|
|
122
|
+
- Assume you know without checking
|
|
123
|
+
|
|
124
|
+
## Common Mistakes
|
|
125
|
+
|
|
126
|
+
❌ **Random fixes** - Changing code without understanding
|
|
127
|
+
❌ **Assumption-based debugging** - "It should work because..."
|
|
128
|
+
❌ **Ignoring error messages** - Skipping past crucial clues
|
|
129
|
+
❌ **Fixing symptoms** - Not addressing root cause
|
|
130
|
+
❌ **Multiple changes** - Can't tell what fixed it
|
|
131
|
+
|
|
132
|
+
## Debugging Checklist
|
|
133
|
+
|
|
134
|
+
Before proposing any fix:
|
|
135
|
+
|
|
136
|
+
- [ ] I have reproduced the issue consistently
|
|
137
|
+
- [ ] I have read the full error message
|
|
138
|
+
- [ ] I have checked recent changes
|
|
139
|
+
- [ ] I have gathered evidence from the system
|
|
140
|
+
- [ ] I understand the root cause
|
|
141
|
+
- [ ] I can explain why my fix will work
|
|
142
|
+
|
|
143
|
+
## Quick Reference
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
1. READ errors carefully
|
|
147
|
+
2. REPRODUCE consistently
|
|
148
|
+
3. CHECK recent changes
|
|
149
|
+
4. GATHER evidence
|
|
150
|
+
5. FORM hypotheses
|
|
151
|
+
6. TEST systematically
|
|
152
|
+
7. FIX root cause
|
|
153
|
+
8. VERIFY fix works
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Remember:** Systematic debugging is faster than random fixes.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Test-Driven Development - write failing tests first, then minimal code to pass
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test-Driven Development (TDD)
|
|
7
|
+
|
|
8
|
+
**Core principle:** Write the test first. Watch it fail. Write minimal code to pass.
|
|
9
|
+
|
|
10
|
+
If you didn't watch the test fail, you don't know if it tests the right thing.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
**Always use for:**
|
|
15
|
+
|
|
16
|
+
- New features
|
|
17
|
+
- Bug fixes
|
|
18
|
+
- Refactoring
|
|
19
|
+
- Behavior changes
|
|
20
|
+
|
|
21
|
+
**Exceptions (ask first):**
|
|
22
|
+
|
|
23
|
+
- Throwaway prototypes
|
|
24
|
+
- Generated code
|
|
25
|
+
- Configuration files
|
|
26
|
+
|
|
27
|
+
## The Iron Law
|
|
28
|
+
|
|
29
|
+
**NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST**
|
|
30
|
+
|
|
31
|
+
Write code before the test? Delete it. Start fresh from tests.
|
|
32
|
+
|
|
33
|
+
## Red-Green-Refactor Cycle
|
|
34
|
+
|
|
35
|
+
### 1. RED - Write Failing Test
|
|
36
|
+
|
|
37
|
+
Write ONE minimal test that demonstrates what should happen:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
test("retries failed operations 3 times", async () => {
|
|
41
|
+
let attempts = 0;
|
|
42
|
+
const operation = () => {
|
|
43
|
+
attempts++;
|
|
44
|
+
if (attempts < 3) throw new Error("fail");
|
|
45
|
+
return "success";
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const result = await retryOperation(operation);
|
|
49
|
+
|
|
50
|
+
expect(result).toBe("success");
|
|
51
|
+
expect(attempts).toBe(3);
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Test qualities:**
|
|
56
|
+
|
|
57
|
+
- Clear, specific name
|
|
58
|
+
- Tests real behavior
|
|
59
|
+
- One thing only
|
|
60
|
+
|
|
61
|
+
### 2. GREEN - Minimal Code to Pass
|
|
62
|
+
|
|
63
|
+
Write the simplest code that makes the test pass:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
async function retryOperation(operation: () => any, maxRetries: number = 3) {
|
|
67
|
+
let attempts = 0;
|
|
68
|
+
while (attempts < maxRetries) {
|
|
69
|
+
try {
|
|
70
|
+
return await operation();
|
|
71
|
+
} catch (e) {
|
|
72
|
+
attempts++;
|
|
73
|
+
if (attempts >= maxRetries) throw e;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Don't:**
|
|
80
|
+
|
|
81
|
+
- Add extra features "just in case"
|
|
82
|
+
- Make it perfect
|
|
83
|
+
- Over-engineer
|
|
84
|
+
|
|
85
|
+
**Do:**
|
|
86
|
+
|
|
87
|
+
- Make it work
|
|
88
|
+
- Keep it simple
|
|
89
|
+
- Stay focused on the test
|
|
90
|
+
|
|
91
|
+
### 3. REFACTOR - Clean Up
|
|
92
|
+
|
|
93
|
+
Now improve the code while keeping tests green:
|
|
94
|
+
|
|
95
|
+
- Remove duplication
|
|
96
|
+
- Improve names
|
|
97
|
+
- Extract functions
|
|
98
|
+
- Apply patterns
|
|
99
|
+
|
|
100
|
+
Then repeat for the next test.
|
|
101
|
+
|
|
102
|
+
## Test Writing Guidelines
|
|
103
|
+
|
|
104
|
+
### Good Test Names
|
|
105
|
+
|
|
106
|
+
✅ `returnsZeroForEmptyArray()`
|
|
107
|
+
✅ `throwsErrorForInvalidInput()`
|
|
108
|
+
✅ `calculatesTotalWithDiscount()`
|
|
109
|
+
|
|
110
|
+
❌ `test1()`, `test2()`
|
|
111
|
+
❌ `test()`, `check()`
|
|
112
|
+
❌ `works()`, `fails()`
|
|
113
|
+
|
|
114
|
+
### Test Real Behavior
|
|
115
|
+
|
|
116
|
+
✅ Tests actual API usage
|
|
117
|
+
✅ Uses real dependencies when possible
|
|
118
|
+
✅ Clear expected outcome
|
|
119
|
+
|
|
120
|
+
❌ Mocks everything
|
|
121
|
+
❌ Tests the mock, not behavior
|
|
122
|
+
❌ Vague assertions
|
|
123
|
+
|
|
124
|
+
### One Thing Only
|
|
125
|
+
|
|
126
|
+
✅ One assertion per concept
|
|
127
|
+
✅ Clear setup, action, result
|
|
128
|
+
|
|
129
|
+
❌ Testing multiple behaviors
|
|
130
|
+
❌ Complex setup logic
|
|
131
|
+
|
|
132
|
+
## Common Anti-patterns
|
|
133
|
+
|
|
134
|
+
### Skipping the Red
|
|
135
|
+
|
|
136
|
+
Writing implementation first, then tests. This defeats TDD entirely.
|
|
137
|
+
|
|
138
|
+
### Too Big Steps
|
|
139
|
+
|
|
140
|
+
Writing a test that does too much. Break into smaller tests.
|
|
141
|
+
|
|
142
|
+
### Premature Optimization
|
|
143
|
+
|
|
144
|
+
Adding features "just in case". Add only what tests require.
|
|
145
|
+
|
|
146
|
+
### Ignoring Failures
|
|
147
|
+
|
|
148
|
+
Not verifying the test actually fails. Always watch it fail first.
|
|
149
|
+
|
|
150
|
+
## Quick Reference
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
RED: Write test → Run → See it fail
|
|
154
|
+
GREEN: Write minimal code → Run → See it pass
|
|
155
|
+
REFACTOR: Clean up → Run → Ensure still passes
|
|
156
|
+
Repeat.
|
|
157
|
+
```
|