@juho0719/cckit 0.1.1
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/assets/agents/architect.md +211 -0
- package/assets/agents/build-error-resolver.md +114 -0
- package/assets/agents/ccwin-code-reviewer.md +224 -0
- package/assets/agents/database-reviewer.md +91 -0
- package/assets/agents/doc-updater.md +107 -0
- package/assets/agents/e2e-runner.md +107 -0
- package/assets/agents/planner.md +212 -0
- package/assets/agents/python-reviewer.md +98 -0
- package/assets/agents/refactor-cleaner.md +85 -0
- package/assets/agents/security-reviewer.md +108 -0
- package/assets/agents/superpower-code-reviewer.md +48 -0
- package/assets/agents/tdd-guide.md +80 -0
- package/assets/commands/build-fix.md +62 -0
- package/assets/commands/checkpoint.md +74 -0
- package/assets/commands/code-review.md +40 -0
- package/assets/commands/e2e.md +362 -0
- package/assets/commands/eval.md +120 -0
- package/assets/commands/orchestrate.md +172 -0
- package/assets/commands/plan.md +113 -0
- package/assets/commands/python-review.md +297 -0
- package/assets/commands/refactor-clean.md +80 -0
- package/assets/commands/sessions.md +305 -0
- package/assets/commands/tdd.md +326 -0
- package/assets/commands/test-coverage.md +69 -0
- package/assets/commands/update-codemaps.md +72 -0
- package/assets/commands/update-docs.md +84 -0
- package/assets/commands/verify.md +59 -0
- package/assets/hooks/post-edit-format.js +49 -0
- package/assets/hooks/post-edit-typecheck.js +96 -0
- package/assets/mcps/mcp-servers.json +92 -0
- package/assets/rules/common/agents.md +49 -0
- package/assets/rules/common/coding-style.md +48 -0
- package/assets/rules/common/git-workflow.md +45 -0
- package/assets/rules/common/hooks.md +30 -0
- package/assets/rules/common/patterns.md +31 -0
- package/assets/rules/common/performance.md +55 -0
- package/assets/rules/common/security.md +29 -0
- package/assets/rules/common/testing.md +29 -0
- package/assets/rules/python/coding-style.md +42 -0
- package/assets/rules/python/hooks.md +19 -0
- package/assets/rules/python/patterns.md +39 -0
- package/assets/rules/python/security.md +30 -0
- package/assets/rules/python/testing.md +38 -0
- package/assets/rules/typescript/coding-style.md +18 -0
- package/assets/rules/typescript/hooks.md +19 -0
- package/assets/rules/typescript/patterns.md +39 -0
- package/assets/rules/typescript/security.md +30 -0
- package/assets/rules/typescript/testing.md +38 -0
- package/assets/skills/api-design/SKILL.md +522 -0
- package/assets/skills/backend-patterns/SKILL.md +597 -0
- package/assets/skills/brainstorming/SKILL.md +96 -0
- package/assets/skills/coding-standards/SKILL.md +529 -0
- package/assets/skills/database-migrations/SKILL.md +334 -0
- package/assets/skills/deployment-patterns/SKILL.md +426 -0
- package/assets/skills/dispatching-parallel-agents/SKILL.md +180 -0
- package/assets/skills/docker-patterns/SKILL.md +363 -0
- package/assets/skills/e2e-testing/SKILL.md +325 -0
- package/assets/skills/eval-harness/SKILL.md +235 -0
- package/assets/skills/executing-plans/SKILL.md +84 -0
- package/assets/skills/finishing-a-development-branch/SKILL.md +200 -0
- package/assets/skills/frontend-patterns/SKILL.md +641 -0
- package/assets/skills/iterative-retrieval/SKILL.md +210 -0
- package/assets/skills/postgres-patterns/SKILL.md +145 -0
- package/assets/skills/python-patterns/SKILL.md +749 -0
- package/assets/skills/python-testing/SKILL.md +815 -0
- package/assets/skills/receiving-code-review/SKILL.md +213 -0
- package/assets/skills/requesting-code-review/SKILL.md +105 -0
- package/assets/skills/requesting-code-review/code-reviewer-template.md +146 -0
- package/assets/skills/subagent-driven-development/SKILL.md +242 -0
- package/assets/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
- package/assets/skills/subagent-driven-development/implementer-prompt.md +78 -0
- package/assets/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/assets/skills/systematic-debugging/CREATION-LOG.md +114 -0
- package/assets/skills/systematic-debugging/SKILL.md +296 -0
- package/assets/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/assets/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/assets/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/assets/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/assets/skills/systematic-debugging/scripts/find-polluter.sh +63 -0
- package/assets/skills/systematic-debugging/test-academic.md +14 -0
- package/assets/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/assets/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/assets/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/assets/skills/tdd-workflow/SKILL.md +409 -0
- package/assets/skills/test-driven-development/SKILL.md +371 -0
- package/assets/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/assets/skills/using-git-worktrees/SKILL.md +218 -0
- package/assets/skills/verification-before-completion/SKILL.md +139 -0
- package/assets/skills/verification-loop/SKILL.md +125 -0
- package/assets/skills/writing-plans/SKILL.md +116 -0
- package/dist/agents-AEKT67A6.js +9 -0
- package/dist/chunk-3GUKEMND.js +28 -0
- package/dist/chunk-3UNN3IBE.js +54 -0
- package/dist/chunk-3Y26YU4R.js +27 -0
- package/dist/chunk-5XOKKPAA.js +21 -0
- package/dist/chunk-6B46AIFM.js +136 -0
- package/dist/chunk-EYY2IZ7N.js +27 -0
- package/dist/chunk-K25UZZVG.js +17 -0
- package/dist/chunk-KEENFBLL.js +24 -0
- package/dist/chunk-RMUKD7CW.js +44 -0
- package/dist/chunk-W63UKEIT.js +50 -0
- package/dist/cli-VZRGF733.js +238 -0
- package/dist/commands-P5LILVZ5.js +9 -0
- package/dist/hooks-IIG2XK4I.js +9 -0
- package/dist/index.js +131 -0
- package/dist/mcps-67Q7TBGW.js +6 -0
- package/dist/paths-FT6KBIRD.js +10 -0
- package/dist/registry-EGXWYWWK.js +17 -0
- package/dist/rules-2CPBVNNJ.js +7 -0
- package/dist/skills-ULMW3UCM.js +8 -0
- package/package.json +36 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Sessions Command
|
|
2
|
+
|
|
3
|
+
Manage Claude Code session history - list, load, alias, and edit sessions stored in `~/.claude/sessions/`.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
`/sessions [list|load|alias|info|help] [options]`
|
|
8
|
+
|
|
9
|
+
## Actions
|
|
10
|
+
|
|
11
|
+
### List Sessions
|
|
12
|
+
|
|
13
|
+
Display all sessions with metadata, filtering, and pagination.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
/sessions # List all sessions (default)
|
|
17
|
+
/sessions list # Same as above
|
|
18
|
+
/sessions list --limit 10 # Show 10 sessions
|
|
19
|
+
/sessions list --date 2026-02-01 # Filter by date
|
|
20
|
+
/sessions list --search abc # Search by session ID
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Script:**
|
|
24
|
+
```bash
|
|
25
|
+
node -e "
|
|
26
|
+
const sm = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-manager');
|
|
27
|
+
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
|
|
28
|
+
|
|
29
|
+
const result = sm.getAllSessions({ limit: 20 });
|
|
30
|
+
const aliases = aa.listAliases();
|
|
31
|
+
const aliasMap = {};
|
|
32
|
+
for (const a of aliases) aliasMap[a.sessionPath] = a.name;
|
|
33
|
+
|
|
34
|
+
console.log('Sessions (showing ' + result.sessions.length + ' of ' + result.total + '):');
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log('ID Date Time Size Lines Alias');
|
|
37
|
+
console.log('────────────────────────────────────────────────────');
|
|
38
|
+
|
|
39
|
+
for (const s of result.sessions) {
|
|
40
|
+
const alias = aliasMap[s.filename] || '';
|
|
41
|
+
const size = sm.getSessionSize(s.sessionPath);
|
|
42
|
+
const stats = sm.getSessionStats(s.sessionPath);
|
|
43
|
+
const id = s.shortId === 'no-id' ? '(none)' : s.shortId.slice(0, 8);
|
|
44
|
+
const time = s.modifiedTime.toTimeString().slice(0, 5);
|
|
45
|
+
|
|
46
|
+
console.log(id.padEnd(8) + ' ' + s.date + ' ' + time + ' ' + size.padEnd(7) + ' ' + String(stats.lineCount).padEnd(5) + ' ' + alias);
|
|
47
|
+
}
|
|
48
|
+
"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Load Session
|
|
52
|
+
|
|
53
|
+
Load and display a session's content (by ID or alias).
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
/sessions load <id|alias> # Load session
|
|
57
|
+
/sessions load 2026-02-01 # By date (for no-id sessions)
|
|
58
|
+
/sessions load a1b2c3d4 # By short ID
|
|
59
|
+
/sessions load my-alias # By alias name
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Script:**
|
|
63
|
+
```bash
|
|
64
|
+
node -e "
|
|
65
|
+
const sm = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-manager');
|
|
66
|
+
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
|
|
67
|
+
const id = process.argv[1];
|
|
68
|
+
|
|
69
|
+
// First try to resolve as alias
|
|
70
|
+
const resolved = aa.resolveAlias(id);
|
|
71
|
+
const sessionId = resolved ? resolved.sessionPath : id;
|
|
72
|
+
|
|
73
|
+
const session = sm.getSessionById(sessionId, true);
|
|
74
|
+
if (!session) {
|
|
75
|
+
console.log('Session not found: ' + id);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const stats = sm.getSessionStats(session.sessionPath);
|
|
80
|
+
const size = sm.getSessionSize(session.sessionPath);
|
|
81
|
+
const aliases = aa.getAliasesForSession(session.filename);
|
|
82
|
+
|
|
83
|
+
console.log('Session: ' + session.filename);
|
|
84
|
+
console.log('Path: ~/.claude/sessions/' + session.filename);
|
|
85
|
+
console.log('');
|
|
86
|
+
console.log('Statistics:');
|
|
87
|
+
console.log(' Lines: ' + stats.lineCount);
|
|
88
|
+
console.log(' Total items: ' + stats.totalItems);
|
|
89
|
+
console.log(' Completed: ' + stats.completedItems);
|
|
90
|
+
console.log(' In progress: ' + stats.inProgressItems);
|
|
91
|
+
console.log(' Size: ' + size);
|
|
92
|
+
console.log('');
|
|
93
|
+
|
|
94
|
+
if (aliases.length > 0) {
|
|
95
|
+
console.log('Aliases: ' + aliases.map(a => a.name).join(', '));
|
|
96
|
+
console.log('');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (session.metadata.title) {
|
|
100
|
+
console.log('Title: ' + session.metadata.title);
|
|
101
|
+
console.log('');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (session.metadata.started) {
|
|
105
|
+
console.log('Started: ' + session.metadata.started);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (session.metadata.lastUpdated) {
|
|
109
|
+
console.log('Last Updated: ' + session.metadata.lastUpdated);
|
|
110
|
+
}
|
|
111
|
+
" "$ARGUMENTS"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Create Alias
|
|
115
|
+
|
|
116
|
+
Create a memorable alias for a session.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
/sessions alias <id> <name> # Create alias
|
|
120
|
+
/sessions alias 2026-02-01 today-work # Create alias named "today-work"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Script:**
|
|
124
|
+
```bash
|
|
125
|
+
node -e "
|
|
126
|
+
const sm = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-manager');
|
|
127
|
+
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
|
|
128
|
+
|
|
129
|
+
const sessionId = process.argv[1];
|
|
130
|
+
const aliasName = process.argv[2];
|
|
131
|
+
|
|
132
|
+
if (!sessionId || !aliasName) {
|
|
133
|
+
console.log('Usage: /sessions alias <id> <name>');
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Get session filename
|
|
138
|
+
const session = sm.getSessionById(sessionId);
|
|
139
|
+
if (!session) {
|
|
140
|
+
console.log('Session not found: ' + sessionId);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = aa.setAlias(aliasName, session.filename);
|
|
145
|
+
if (result.success) {
|
|
146
|
+
console.log('✓ Alias created: ' + aliasName + ' → ' + session.filename);
|
|
147
|
+
} else {
|
|
148
|
+
console.log('✗ Error: ' + result.error);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
" "$ARGUMENTS"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Remove Alias
|
|
155
|
+
|
|
156
|
+
Delete an existing alias.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
/sessions alias --remove <name> # Remove alias
|
|
160
|
+
/sessions unalias <name> # Same as above
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Script:**
|
|
164
|
+
```bash
|
|
165
|
+
node -e "
|
|
166
|
+
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
|
|
167
|
+
|
|
168
|
+
const aliasName = process.argv[1];
|
|
169
|
+
if (!aliasName) {
|
|
170
|
+
console.log('Usage: /sessions alias --remove <name>');
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const result = aa.deleteAlias(aliasName);
|
|
175
|
+
if (result.success) {
|
|
176
|
+
console.log('✓ Alias removed: ' + aliasName);
|
|
177
|
+
} else {
|
|
178
|
+
console.log('✗ Error: ' + result.error);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
" "$ARGUMENTS"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Session Info
|
|
185
|
+
|
|
186
|
+
Show detailed information about a session.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
/sessions info <id|alias> # Show session details
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Script:**
|
|
193
|
+
```bash
|
|
194
|
+
node -e "
|
|
195
|
+
const sm = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-manager');
|
|
196
|
+
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
|
|
197
|
+
|
|
198
|
+
const id = process.argv[1];
|
|
199
|
+
const resolved = aa.resolveAlias(id);
|
|
200
|
+
const sessionId = resolved ? resolved.sessionPath : id;
|
|
201
|
+
|
|
202
|
+
const session = sm.getSessionById(sessionId, true);
|
|
203
|
+
if (!session) {
|
|
204
|
+
console.log('Session not found: ' + id);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const stats = sm.getSessionStats(session.sessionPath);
|
|
209
|
+
const size = sm.getSessionSize(session.sessionPath);
|
|
210
|
+
const aliases = aa.getAliasesForSession(session.filename);
|
|
211
|
+
|
|
212
|
+
console.log('Session Information');
|
|
213
|
+
console.log('════════════════════');
|
|
214
|
+
console.log('ID: ' + (session.shortId === 'no-id' ? '(none)' : session.shortId));
|
|
215
|
+
console.log('Filename: ' + session.filename);
|
|
216
|
+
console.log('Date: ' + session.date);
|
|
217
|
+
console.log('Modified: ' + session.modifiedTime.toISOString().slice(0, 19).replace('T', ' '));
|
|
218
|
+
console.log('');
|
|
219
|
+
console.log('Content:');
|
|
220
|
+
console.log(' Lines: ' + stats.lineCount);
|
|
221
|
+
console.log(' Total items: ' + stats.totalItems);
|
|
222
|
+
console.log(' Completed: ' + stats.completedItems);
|
|
223
|
+
console.log(' In progress: ' + stats.inProgressItems);
|
|
224
|
+
console.log(' Size: ' + size);
|
|
225
|
+
if (aliases.length > 0) {
|
|
226
|
+
console.log('Aliases: ' + aliases.map(a => a.name).join(', '));
|
|
227
|
+
}
|
|
228
|
+
" "$ARGUMENTS"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### List Aliases
|
|
232
|
+
|
|
233
|
+
Show all session aliases.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
/sessions aliases # List all aliases
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Script:**
|
|
240
|
+
```bash
|
|
241
|
+
node -e "
|
|
242
|
+
const aa = require((process.env.CLAUDE_PLUGIN_ROOT||require('path').join(require('os').homedir(),'.claude'))+'/scripts/lib/session-aliases');
|
|
243
|
+
|
|
244
|
+
const aliases = aa.listAliases();
|
|
245
|
+
console.log('Session Aliases (' + aliases.length + '):');
|
|
246
|
+
console.log('');
|
|
247
|
+
|
|
248
|
+
if (aliases.length === 0) {
|
|
249
|
+
console.log('No aliases found.');
|
|
250
|
+
} else {
|
|
251
|
+
console.log('Name Session File Title');
|
|
252
|
+
console.log('─────────────────────────────────────────────────────────────');
|
|
253
|
+
for (const a of aliases) {
|
|
254
|
+
const name = a.name.padEnd(12);
|
|
255
|
+
const file = (a.sessionPath.length > 30 ? a.sessionPath.slice(0, 27) + '...' : a.sessionPath).padEnd(30);
|
|
256
|
+
const title = a.title || '';
|
|
257
|
+
console.log(name + ' ' + file + ' ' + title);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Arguments
|
|
264
|
+
|
|
265
|
+
$ARGUMENTS:
|
|
266
|
+
- `list [options]` - List sessions
|
|
267
|
+
- `--limit <n>` - Max sessions to show (default: 50)
|
|
268
|
+
- `--date <YYYY-MM-DD>` - Filter by date
|
|
269
|
+
- `--search <pattern>` - Search in session ID
|
|
270
|
+
- `load <id|alias>` - Load session content
|
|
271
|
+
- `alias <id> <name>` - Create alias for session
|
|
272
|
+
- `alias --remove <name>` - Remove alias
|
|
273
|
+
- `unalias <name>` - Same as `--remove`
|
|
274
|
+
- `info <id|alias>` - Show session statistics
|
|
275
|
+
- `aliases` - List all aliases
|
|
276
|
+
- `help` - Show this help
|
|
277
|
+
|
|
278
|
+
## Examples
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# List all sessions
|
|
282
|
+
/sessions list
|
|
283
|
+
|
|
284
|
+
# Create an alias for today's session
|
|
285
|
+
/sessions alias 2026-02-01 today
|
|
286
|
+
|
|
287
|
+
# Load session by alias
|
|
288
|
+
/sessions load today
|
|
289
|
+
|
|
290
|
+
# Show session info
|
|
291
|
+
/sessions info today
|
|
292
|
+
|
|
293
|
+
# Remove alias
|
|
294
|
+
/sessions alias --remove today
|
|
295
|
+
|
|
296
|
+
# List all aliases
|
|
297
|
+
/sessions aliases
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Notes
|
|
301
|
+
|
|
302
|
+
- Sessions are stored as markdown files in `~/.claude/sessions/`
|
|
303
|
+
- Aliases are stored in `~/.claude/session-aliases.json`
|
|
304
|
+
- Session IDs can be shortened (first 4-8 characters usually unique enough)
|
|
305
|
+
- Use aliases for frequently referenced sessions
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce test-driven development workflow. Scaffold interfaces, generate tests FIRST, then implement minimal code to pass. Ensure 80%+ coverage.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# TDD Command
|
|
6
|
+
|
|
7
|
+
This command invokes the **tdd-guide** agent to enforce test-driven development methodology.
|
|
8
|
+
|
|
9
|
+
## What This Command Does
|
|
10
|
+
|
|
11
|
+
1. **Scaffold Interfaces** - Define types/interfaces first
|
|
12
|
+
2. **Generate Tests First** - Write failing tests (RED)
|
|
13
|
+
3. **Implement Minimal Code** - Write just enough to pass (GREEN)
|
|
14
|
+
4. **Refactor** - Improve code while keeping tests green (REFACTOR)
|
|
15
|
+
5. **Verify Coverage** - Ensure 80%+ test coverage
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
Use `/tdd` when:
|
|
20
|
+
- Implementing new features
|
|
21
|
+
- Adding new functions/components
|
|
22
|
+
- Fixing bugs (write test that reproduces bug first)
|
|
23
|
+
- Refactoring existing code
|
|
24
|
+
- Building critical business logic
|
|
25
|
+
|
|
26
|
+
## How It Works
|
|
27
|
+
|
|
28
|
+
The tdd-guide agent will:
|
|
29
|
+
|
|
30
|
+
1. **Define interfaces** for inputs/outputs
|
|
31
|
+
2. **Write tests that will FAIL** (because code doesn't exist yet)
|
|
32
|
+
3. **Run tests** and verify they fail for the right reason
|
|
33
|
+
4. **Write minimal implementation** to make tests pass
|
|
34
|
+
5. **Run tests** and verify they pass
|
|
35
|
+
6. **Refactor** code while keeping tests green
|
|
36
|
+
7. **Check coverage** and add more tests if below 80%
|
|
37
|
+
|
|
38
|
+
## TDD Cycle
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
RED → GREEN → REFACTOR → REPEAT
|
|
42
|
+
|
|
43
|
+
RED: Write a failing test
|
|
44
|
+
GREEN: Write minimal code to pass
|
|
45
|
+
REFACTOR: Improve code, keep tests passing
|
|
46
|
+
REPEAT: Next feature/scenario
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Example Usage
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
User: /tdd I need a function to calculate market liquidity score
|
|
53
|
+
|
|
54
|
+
Agent (tdd-guide):
|
|
55
|
+
# TDD Session: Market Liquidity Score Calculator
|
|
56
|
+
|
|
57
|
+
## Step 1: Define Interface (SCAFFOLD)
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// lib/liquidity.ts
|
|
61
|
+
export interface MarketData {
|
|
62
|
+
totalVolume: number
|
|
63
|
+
bidAskSpread: number
|
|
64
|
+
activeTraders: number
|
|
65
|
+
lastTradeTime: Date
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function calculateLiquidityScore(market: MarketData): number {
|
|
69
|
+
// TODO: Implementation
|
|
70
|
+
throw new Error('Not implemented')
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Step 2: Write Failing Test (RED)
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// lib/liquidity.test.ts
|
|
78
|
+
import { calculateLiquidityScore } from './liquidity'
|
|
79
|
+
|
|
80
|
+
describe('calculateLiquidityScore', () => {
|
|
81
|
+
it('should return high score for liquid market', () => {
|
|
82
|
+
const market = {
|
|
83
|
+
totalVolume: 100000,
|
|
84
|
+
bidAskSpread: 0.01,
|
|
85
|
+
activeTraders: 500,
|
|
86
|
+
lastTradeTime: new Date()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const score = calculateLiquidityScore(market)
|
|
90
|
+
|
|
91
|
+
expect(score).toBeGreaterThan(80)
|
|
92
|
+
expect(score).toBeLessThanOrEqual(100)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should return low score for illiquid market', () => {
|
|
96
|
+
const market = {
|
|
97
|
+
totalVolume: 100,
|
|
98
|
+
bidAskSpread: 0.5,
|
|
99
|
+
activeTraders: 2,
|
|
100
|
+
lastTradeTime: new Date(Date.now() - 86400000) // 1 day ago
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const score = calculateLiquidityScore(market)
|
|
104
|
+
|
|
105
|
+
expect(score).toBeLessThan(30)
|
|
106
|
+
expect(score).toBeGreaterThanOrEqual(0)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should handle edge case: zero volume', () => {
|
|
110
|
+
const market = {
|
|
111
|
+
totalVolume: 0,
|
|
112
|
+
bidAskSpread: 0,
|
|
113
|
+
activeTraders: 0,
|
|
114
|
+
lastTradeTime: new Date()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const score = calculateLiquidityScore(market)
|
|
118
|
+
|
|
119
|
+
expect(score).toBe(0)
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Step 3: Run Tests - Verify FAIL
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npm test lib/liquidity.test.ts
|
|
128
|
+
|
|
129
|
+
FAIL lib/liquidity.test.ts
|
|
130
|
+
✕ should return high score for liquid market (2 ms)
|
|
131
|
+
Error: Not implemented
|
|
132
|
+
|
|
133
|
+
1 test failed, 0 passed
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
✅ Tests fail as expected. Ready to implement.
|
|
137
|
+
|
|
138
|
+
## Step 4: Implement Minimal Code (GREEN)
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// lib/liquidity.ts
|
|
142
|
+
export function calculateLiquidityScore(market: MarketData): number {
|
|
143
|
+
// Handle zero volume edge case
|
|
144
|
+
if (market.totalVolume === 0) {
|
|
145
|
+
return 0
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Calculate component scores (0-100 scale)
|
|
149
|
+
const volumeScore = Math.min(market.totalVolume / 1000, 100)
|
|
150
|
+
const spreadScore = Math.max(100 - (market.bidAskSpread * 1000), 0)
|
|
151
|
+
const traderScore = Math.min(market.activeTraders / 10, 100)
|
|
152
|
+
|
|
153
|
+
// Recent activity bonus
|
|
154
|
+
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
|
|
155
|
+
const recencyScore = Math.max(100 - (hoursSinceLastTrade * 10), 0)
|
|
156
|
+
|
|
157
|
+
// Weighted average
|
|
158
|
+
const score = (
|
|
159
|
+
volumeScore * 0.4 +
|
|
160
|
+
spreadScore * 0.3 +
|
|
161
|
+
traderScore * 0.2 +
|
|
162
|
+
recencyScore * 0.1
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
return Math.min(Math.max(score, 0), 100) // Clamp to 0-100
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Step 5: Run Tests - Verify PASS
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npm test lib/liquidity.test.ts
|
|
173
|
+
|
|
174
|
+
PASS lib/liquidity.test.ts
|
|
175
|
+
✓ should return high score for liquid market (3 ms)
|
|
176
|
+
✓ should return low score for illiquid market (2 ms)
|
|
177
|
+
✓ should handle edge case: zero volume (1 ms)
|
|
178
|
+
|
|
179
|
+
3 tests passed
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
✅ All tests passing!
|
|
183
|
+
|
|
184
|
+
## Step 6: Refactor (IMPROVE)
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// lib/liquidity.ts - Refactored with constants and better readability
|
|
188
|
+
const WEIGHTS = {
|
|
189
|
+
VOLUME: 0.4,
|
|
190
|
+
SPREAD: 0.3,
|
|
191
|
+
TRADERS: 0.2,
|
|
192
|
+
RECENCY: 0.1,
|
|
193
|
+
} as const
|
|
194
|
+
|
|
195
|
+
const SCALE_FACTORS = {
|
|
196
|
+
VOLUME: 1000,
|
|
197
|
+
SPREAD: 1000,
|
|
198
|
+
TRADERS: 10,
|
|
199
|
+
RECENCY_PENALTY: 10,
|
|
200
|
+
} as const
|
|
201
|
+
|
|
202
|
+
function clamp(value: number, min: number, max: number): number {
|
|
203
|
+
return Math.min(Math.max(value, min), max)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function calculateLiquidityScore(market: MarketData): number {
|
|
207
|
+
if (market.totalVolume === 0) return 0
|
|
208
|
+
|
|
209
|
+
const volumeScore = Math.min(market.totalVolume / SCALE_FACTORS.VOLUME, 100)
|
|
210
|
+
const spreadScore = clamp(100 - (market.bidAskSpread * SCALE_FACTORS.SPREAD), 0, 100)
|
|
211
|
+
const traderScore = Math.min(market.activeTraders / SCALE_FACTORS.TRADERS, 100)
|
|
212
|
+
|
|
213
|
+
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
|
|
214
|
+
const recencyScore = clamp(100 - (hoursSinceLastTrade * SCALE_FACTORS.RECENCY_PENALTY), 0, 100)
|
|
215
|
+
|
|
216
|
+
const weightedScore =
|
|
217
|
+
volumeScore * WEIGHTS.VOLUME +
|
|
218
|
+
spreadScore * WEIGHTS.SPREAD +
|
|
219
|
+
traderScore * WEIGHTS.TRADERS +
|
|
220
|
+
recencyScore * WEIGHTS.RECENCY
|
|
221
|
+
|
|
222
|
+
return clamp(weightedScore, 0, 100)
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Step 7: Verify Tests Still Pass
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm test lib/liquidity.test.ts
|
|
230
|
+
|
|
231
|
+
PASS lib/liquidity.test.ts
|
|
232
|
+
✓ should return high score for liquid market (3 ms)
|
|
233
|
+
✓ should return low score for illiquid market (2 ms)
|
|
234
|
+
✓ should handle edge case: zero volume (1 ms)
|
|
235
|
+
|
|
236
|
+
3 tests passed
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
✅ Refactoring complete, tests still passing!
|
|
240
|
+
|
|
241
|
+
## Step 8: Check Coverage
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npm test -- --coverage lib/liquidity.test.ts
|
|
245
|
+
|
|
246
|
+
File | % Stmts | % Branch | % Funcs | % Lines
|
|
247
|
+
---------------|---------|----------|---------|--------
|
|
248
|
+
liquidity.ts | 100 | 100 | 100 | 100
|
|
249
|
+
|
|
250
|
+
Coverage: 100% ✅ (Target: 80%)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
✅ TDD session complete!
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## TDD Best Practices
|
|
257
|
+
|
|
258
|
+
**DO:**
|
|
259
|
+
- ✅ Write the test FIRST, before any implementation
|
|
260
|
+
- ✅ Run tests and verify they FAIL before implementing
|
|
261
|
+
- ✅ Write minimal code to make tests pass
|
|
262
|
+
- ✅ Refactor only after tests are green
|
|
263
|
+
- ✅ Add edge cases and error scenarios
|
|
264
|
+
- ✅ Aim for 80%+ coverage (100% for critical code)
|
|
265
|
+
|
|
266
|
+
**DON'T:**
|
|
267
|
+
- ❌ Write implementation before tests
|
|
268
|
+
- ❌ Skip running tests after each change
|
|
269
|
+
- ❌ Write too much code at once
|
|
270
|
+
- ❌ Ignore failing tests
|
|
271
|
+
- ❌ Test implementation details (test behavior)
|
|
272
|
+
- ❌ Mock everything (prefer integration tests)
|
|
273
|
+
|
|
274
|
+
## Test Types to Include
|
|
275
|
+
|
|
276
|
+
**Unit Tests** (Function-level):
|
|
277
|
+
- Happy path scenarios
|
|
278
|
+
- Edge cases (empty, null, max values)
|
|
279
|
+
- Error conditions
|
|
280
|
+
- Boundary values
|
|
281
|
+
|
|
282
|
+
**Integration Tests** (Component-level):
|
|
283
|
+
- API endpoints
|
|
284
|
+
- Database operations
|
|
285
|
+
- External service calls
|
|
286
|
+
- React components with hooks
|
|
287
|
+
|
|
288
|
+
**E2E Tests** (use `/e2e` command):
|
|
289
|
+
- Critical user flows
|
|
290
|
+
- Multi-step processes
|
|
291
|
+
- Full stack integration
|
|
292
|
+
|
|
293
|
+
## Coverage Requirements
|
|
294
|
+
|
|
295
|
+
- **80% minimum** for all code
|
|
296
|
+
- **100% required** for:
|
|
297
|
+
- Financial calculations
|
|
298
|
+
- Authentication logic
|
|
299
|
+
- Security-critical code
|
|
300
|
+
- Core business logic
|
|
301
|
+
|
|
302
|
+
## Important Notes
|
|
303
|
+
|
|
304
|
+
**MANDATORY**: Tests must be written BEFORE implementation. The TDD cycle is:
|
|
305
|
+
|
|
306
|
+
1. **RED** - Write failing test
|
|
307
|
+
2. **GREEN** - Implement to pass
|
|
308
|
+
3. **REFACTOR** - Improve code
|
|
309
|
+
|
|
310
|
+
Never skip the RED phase. Never write code before tests.
|
|
311
|
+
|
|
312
|
+
## Integration with Other Commands
|
|
313
|
+
|
|
314
|
+
- Use `/plan` first to understand what to build
|
|
315
|
+
- Use `/tdd` to implement with tests
|
|
316
|
+
- Use `/build-fix` if build errors occur
|
|
317
|
+
- Use `/code-review` to review implementation
|
|
318
|
+
- Use `/test-coverage` to verify coverage
|
|
319
|
+
|
|
320
|
+
## Related Agents
|
|
321
|
+
|
|
322
|
+
This command invokes the `tdd-guide` agent located at:
|
|
323
|
+
`~/.claude/agents/tdd-guide.md`
|
|
324
|
+
|
|
325
|
+
And can reference the `tdd-workflow` skill at:
|
|
326
|
+
`~/.claude/skills/tdd-workflow/`
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Test Coverage
|
|
2
|
+
|
|
3
|
+
Analyze test coverage, identify gaps, and generate missing tests to reach 80%+ coverage.
|
|
4
|
+
|
|
5
|
+
## Step 1: Detect Test Framework
|
|
6
|
+
|
|
7
|
+
| Indicator | Coverage Command |
|
|
8
|
+
|-----------|-----------------|
|
|
9
|
+
| `jest.config.*` or `package.json` jest | `npx jest --coverage --coverageReporters=json-summary` |
|
|
10
|
+
| `vitest.config.*` | `npx vitest run --coverage` |
|
|
11
|
+
| `pytest.ini` / `pyproject.toml` pytest | `pytest --cov=src --cov-report=json` |
|
|
12
|
+
| `Cargo.toml` | `cargo llvm-cov --json` |
|
|
13
|
+
| `pom.xml` with JaCoCo | `mvn test jacoco:report` |
|
|
14
|
+
| `go.mod` | `go test -coverprofile=coverage.out ./...` |
|
|
15
|
+
|
|
16
|
+
## Step 2: Analyze Coverage Report
|
|
17
|
+
|
|
18
|
+
1. Run the coverage command
|
|
19
|
+
2. Parse the output (JSON summary or terminal output)
|
|
20
|
+
3. List files **below 80% coverage**, sorted worst-first
|
|
21
|
+
4. For each under-covered file, identify:
|
|
22
|
+
- Untested functions or methods
|
|
23
|
+
- Missing branch coverage (if/else, switch, error paths)
|
|
24
|
+
- Dead code that inflates the denominator
|
|
25
|
+
|
|
26
|
+
## Step 3: Generate Missing Tests
|
|
27
|
+
|
|
28
|
+
For each under-covered file, generate tests following this priority:
|
|
29
|
+
|
|
30
|
+
1. **Happy path** — Core functionality with valid inputs
|
|
31
|
+
2. **Error handling** — Invalid inputs, missing data, network failures
|
|
32
|
+
3. **Edge cases** — Empty arrays, null/undefined, boundary values (0, -1, MAX_INT)
|
|
33
|
+
4. **Branch coverage** — Each if/else, switch case, ternary
|
|
34
|
+
|
|
35
|
+
### Test Generation Rules
|
|
36
|
+
|
|
37
|
+
- Place tests adjacent to source: `foo.ts` → `foo.test.ts` (or project convention)
|
|
38
|
+
- Use existing test patterns from the project (import style, assertion library, mocking approach)
|
|
39
|
+
- Mock external dependencies (database, APIs, file system)
|
|
40
|
+
- Each test should be independent — no shared mutable state between tests
|
|
41
|
+
- Name tests descriptively: `test_create_user_with_duplicate_email_returns_409`
|
|
42
|
+
|
|
43
|
+
## Step 4: Verify
|
|
44
|
+
|
|
45
|
+
1. Run the full test suite — all tests must pass
|
|
46
|
+
2. Re-run coverage — verify improvement
|
|
47
|
+
3. If still below 80%, repeat Step 3 for remaining gaps
|
|
48
|
+
|
|
49
|
+
## Step 5: Report
|
|
50
|
+
|
|
51
|
+
Show before/after comparison:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Coverage Report
|
|
55
|
+
──────────────────────────────
|
|
56
|
+
File Before After
|
|
57
|
+
src/services/auth.ts 45% 88%
|
|
58
|
+
src/utils/validation.ts 32% 82%
|
|
59
|
+
──────────────────────────────
|
|
60
|
+
Overall: 67% 84% ✅
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Focus Areas
|
|
64
|
+
|
|
65
|
+
- Functions with complex branching (high cyclomatic complexity)
|
|
66
|
+
- Error handlers and catch blocks
|
|
67
|
+
- Utility functions used across the codebase
|
|
68
|
+
- API endpoint handlers (request → response flow)
|
|
69
|
+
- Edge cases: null, undefined, empty string, empty array, zero, negative numbers
|