tdd-claude-code 0.1.0 → 0.3.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 +8 -1
- package/bin/install.js +107 -43
- package/help.md +11 -2
- package/init.md +147 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@ Test-Led Development powered by [GSD](https://github.com/glittercowboy/get-shit-
|
|
|
4
4
|
|
|
5
5
|
**One interface. Tests happen automatically. You don't think about methodology.**
|
|
6
6
|
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="assets/terminal.svg" alt="TDD Installer" width="700">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
7
11
|
## Install
|
|
8
12
|
|
|
9
13
|
```bash
|
|
@@ -23,7 +27,9 @@ npx tdd-claude-code --local # this project only
|
|
|
23
27
|
You use `/tdd:*` commands for everything. Never touch `/gsd:*` directly.
|
|
24
28
|
|
|
25
29
|
```
|
|
26
|
-
/tdd:new-project
|
|
30
|
+
/tdd:new-project New project from scratch
|
|
31
|
+
OR
|
|
32
|
+
/tdd:init Add TDD to existing codebase
|
|
27
33
|
↓
|
|
28
34
|
/tdd:discuss 1 Shape how phase 1 gets built
|
|
29
35
|
/tdd:plan 1 Create task plans
|
|
@@ -51,6 +57,7 @@ You run one command. Tests get written before code. Automatically.
|
|
|
51
57
|
| Command | What It Does |
|
|
52
58
|
|---------|--------------|
|
|
53
59
|
| `/tdd:new-project` | Start project with test infrastructure |
|
|
60
|
+
| `/tdd:init` | Add TDD to existing codebase |
|
|
54
61
|
| `/tdd:discuss [N]` | Capture implementation preferences |
|
|
55
62
|
| `/tdd:plan [N]` | Create task plans |
|
|
56
63
|
| `/tdd:build <N>` | **Write tests → implement → verify** |
|
package/bin/install.js
CHANGED
|
@@ -5,8 +5,32 @@ const path = require('path');
|
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
6
|
const readline = require('readline');
|
|
7
7
|
|
|
8
|
+
// ANSI color codes
|
|
9
|
+
const c = {
|
|
10
|
+
reset: '\x1b[0m',
|
|
11
|
+
bold: '\x1b[1m',
|
|
12
|
+
dim: '\x1b[2m',
|
|
13
|
+
cyan: '\x1b[36m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
yellow: '\x1b[33m',
|
|
16
|
+
magenta: '\x1b[35m',
|
|
17
|
+
white: '\x1b[37m',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const LOGO = `
|
|
21
|
+
${c.cyan} ████████╗██████╗ ██████╗
|
|
22
|
+
╚══██╔══╝██╔══██╗██╔══██╗
|
|
23
|
+
██║ ██║ ██║██║ ██║
|
|
24
|
+
██║ ██║ ██║██║ ██║
|
|
25
|
+
██║ ██████╔╝██████╔╝
|
|
26
|
+
╚═╝ ╚═════╝ ╚═════╝${c.reset}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const VERSION = '0.3.0';
|
|
30
|
+
|
|
8
31
|
const COMMANDS = [
|
|
9
32
|
'new-project.md',
|
|
33
|
+
'init.md',
|
|
10
34
|
'discuss.md',
|
|
11
35
|
'plan.md',
|
|
12
36
|
'build.md',
|
|
@@ -28,27 +52,50 @@ function getLocalDir() {
|
|
|
28
52
|
return path.join(process.cwd(), '.claude', 'commands');
|
|
29
53
|
}
|
|
30
54
|
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
function printBanner() {
|
|
56
|
+
console.log(LOGO);
|
|
57
|
+
console.log(` ${c.bold}TDD Workflow${c.reset} ${c.dim}v${VERSION}${c.reset}`);
|
|
58
|
+
console.log(` ${c.white}Test-Led Development for Claude Code${c.reset}`);
|
|
59
|
+
console.log(` ${c.dim}Powered by GSD${c.reset}`);
|
|
60
|
+
console.log('');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function log(msg) {
|
|
64
|
+
console.log(` ${msg}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function success(msg) {
|
|
68
|
+
console.log(` ${c.green}✓${c.reset} ${msg}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function info(msg) {
|
|
72
|
+
console.log(` ${c.cyan}→${c.reset} ${msg}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function checkGsd(localGsdDir, installType) {
|
|
76
|
+
const globalGsdDir = path.join(getGlobalDir(), 'gsd');
|
|
77
|
+
|
|
78
|
+
// GSD can be in either location - check both
|
|
79
|
+
if (fs.existsSync(localGsdDir) || fs.existsSync(globalGsdDir)) {
|
|
80
|
+
return; // GSD found
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
log('');
|
|
84
|
+
log(`${c.yellow}GSD not found${c.reset} - installing dependency...`);
|
|
85
|
+
log('');
|
|
86
|
+
try {
|
|
87
|
+
execSync('npx --yes get-shit-done-cc@latest', { stdio: 'inherit' });
|
|
88
|
+
} catch (e) {
|
|
89
|
+
// GSD installer may exit with error but still install
|
|
90
|
+
}
|
|
91
|
+
console.log('');
|
|
92
|
+
|
|
93
|
+
// Check both locations again after install
|
|
94
|
+
if (!fs.existsSync(localGsdDir) && !fs.existsSync(globalGsdDir)) {
|
|
95
|
+
log(`${c.yellow}GSD not found after install.${c.reset}`);
|
|
96
|
+
log('Run: npx get-shit-done-cc');
|
|
97
|
+
log('Then re-run this installer.');
|
|
98
|
+
process.exit(1);
|
|
52
99
|
}
|
|
53
100
|
}
|
|
54
101
|
|
|
@@ -64,62 +111,79 @@ function install(targetDir, installType) {
|
|
|
64
111
|
|
|
65
112
|
// Copy command files
|
|
66
113
|
const sourceDir = path.join(__dirname, '..');
|
|
114
|
+
let installed = 0;
|
|
67
115
|
for (const file of COMMANDS) {
|
|
68
116
|
const src = path.join(sourceDir, file);
|
|
69
117
|
const dest = path.join(commandsDir, file);
|
|
70
118
|
if (fs.existsSync(src)) {
|
|
71
119
|
fs.copyFileSync(src, dest);
|
|
120
|
+
installed++;
|
|
72
121
|
}
|
|
73
122
|
}
|
|
74
123
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
124
|
+
success(`Installed ${installed} commands to ${c.cyan}${commandsDir}${c.reset}`);
|
|
125
|
+
log('');
|
|
126
|
+
log(`${c.green}Done!${c.reset} Restart Claude Code to load commands.`);
|
|
127
|
+
log('');
|
|
128
|
+
log(`${c.bold}Workflow:${c.reset}`);
|
|
129
|
+
log(` ${c.cyan}/tdd:new-project${c.reset} Start project with test infrastructure`);
|
|
130
|
+
log(` ${c.cyan}/tdd:discuss${c.reset} Shape implementation preferences`);
|
|
131
|
+
log(` ${c.cyan}/tdd:plan${c.reset} Create task plans`);
|
|
132
|
+
log(` ${c.cyan}/tdd:build${c.reset} Write tests → implement → verify`);
|
|
133
|
+
log(` ${c.cyan}/tdd:verify${c.reset} Human acceptance testing`);
|
|
134
|
+
log('');
|
|
135
|
+
log(`Run ${c.cyan}/tdd:help${c.reset} for full command list.`);
|
|
136
|
+
log('');
|
|
88
137
|
}
|
|
89
138
|
|
|
90
139
|
async function main() {
|
|
91
140
|
const args = process.argv.slice(2);
|
|
92
141
|
|
|
142
|
+
printBanner();
|
|
143
|
+
|
|
93
144
|
if (args.includes('--global') || args.includes('-g')) {
|
|
94
|
-
|
|
145
|
+
info(`Installing ${c.bold}globally${c.reset} to ~/.claude/commands/tdd`);
|
|
146
|
+
log('');
|
|
95
147
|
install(getGlobalDir(), 'global');
|
|
96
148
|
return;
|
|
97
149
|
}
|
|
98
150
|
|
|
99
151
|
if (args.includes('--local') || args.includes('-l')) {
|
|
100
|
-
|
|
152
|
+
info(`Installing ${c.bold}locally${c.reset} to ./.claude/commands/tdd`);
|
|
153
|
+
log('');
|
|
101
154
|
install(getLocalDir(), 'local');
|
|
102
155
|
return;
|
|
103
156
|
}
|
|
104
157
|
|
|
158
|
+
// Check if non-interactive
|
|
159
|
+
if (!process.stdin.isTTY) {
|
|
160
|
+
log(`${c.yellow}Non-interactive terminal detected, defaulting to global install${c.reset}`);
|
|
161
|
+
log('');
|
|
162
|
+
install(getGlobalDir(), 'global');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
105
166
|
// Interactive prompt
|
|
106
167
|
const rl = readline.createInterface({
|
|
107
168
|
input: process.stdin,
|
|
108
169
|
output: process.stdout
|
|
109
170
|
});
|
|
110
171
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
console.log(' 2) Local (./.claude/commands/tdd) - this project only');
|
|
116
|
-
console.log('');
|
|
172
|
+
log('Where would you like to install?');
|
|
173
|
+
log(` ${c.bold}1)${c.reset} Global ${c.dim}(~/.claude/commands/tdd)${c.reset} - available in all projects`);
|
|
174
|
+
log(` ${c.bold}2)${c.reset} Local ${c.dim}(./.claude/commands/tdd)${c.reset} - this project only`);
|
|
175
|
+
log('');
|
|
117
176
|
|
|
118
|
-
rl.question('Choice [1/2]: ', (answer) => {
|
|
177
|
+
rl.question(' Choice [1/2]: ', (answer) => {
|
|
119
178
|
rl.close();
|
|
179
|
+
console.log('');
|
|
120
180
|
if (answer === '2') {
|
|
181
|
+
info(`Installing ${c.bold}locally${c.reset}`);
|
|
182
|
+
log('');
|
|
121
183
|
install(getLocalDir(), 'local');
|
|
122
184
|
} else {
|
|
185
|
+
info(`Installing ${c.bold}globally${c.reset}`);
|
|
186
|
+
log('');
|
|
123
187
|
install(getGlobalDir(), 'global');
|
|
124
188
|
}
|
|
125
189
|
});
|
package/help.md
CHANGED
|
@@ -4,11 +4,17 @@ TDD-first workflow powered by GSD. You use `/tdd:*` for everything — tests hap
|
|
|
4
4
|
|
|
5
5
|
## Commands
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### Getting Started
|
|
8
8
|
|
|
9
9
|
| Command | What It Does |
|
|
10
10
|
|---------|--------------|
|
|
11
11
|
| `/tdd:new-project` | Start new project with test infrastructure |
|
|
12
|
+
| `/tdd:init` | Add TDD to existing codebase |
|
|
13
|
+
|
|
14
|
+
### Core Workflow
|
|
15
|
+
|
|
16
|
+
| Command | What It Does |
|
|
17
|
+
|---------|--------------|
|
|
12
18
|
| `/tdd:discuss [N]` | Capture implementation preferences for phase N |
|
|
13
19
|
| `/tdd:plan [N]` | Research and create task plans for phase N |
|
|
14
20
|
| `/tdd:build <N>` | **Write tests → implement → verify tests pass** |
|
|
@@ -38,7 +44,9 @@ TDD-first workflow powered by GSD. You use `/tdd:*` for everything — tests hap
|
|
|
38
44
|
## Workflow
|
|
39
45
|
|
|
40
46
|
```
|
|
41
|
-
/tdd:new-project
|
|
47
|
+
/tdd:new-project New project from scratch
|
|
48
|
+
OR
|
|
49
|
+
/tdd:init Existing codebase
|
|
42
50
|
↓
|
|
43
51
|
/tdd:discuss 1 Shape how phase 1 gets built
|
|
44
52
|
/tdd:plan 1 Create task plans
|
|
@@ -81,6 +89,7 @@ TDD commands call GSD internally:
|
|
|
81
89
|
| TDD Command | Calls |
|
|
82
90
|
|-------------|-------|
|
|
83
91
|
| `/tdd:new-project` | `/gsd:new-project` + test setup |
|
|
92
|
+
| `/tdd:init` | scan + test setup (no GSD call) |
|
|
84
93
|
| `/tdd:discuss` | `/gsd:discuss-phase` |
|
|
85
94
|
| `/tdd:plan` | `/gsd:plan-phase` |
|
|
86
95
|
| `/tdd:build` | write tests + `/gsd:execute-phase` |
|
package/init.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# /tdd:init - Initialize TDD in Existing Project
|
|
2
|
+
|
|
3
|
+
Add TDD workflow to an existing codebase.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- You have existing code without tests
|
|
8
|
+
- You have existing code with some tests
|
|
9
|
+
- You're joining a project mid-development
|
|
10
|
+
- You want to adopt TDD on a "vibe coded" project
|
|
11
|
+
|
|
12
|
+
For brand new projects with no code, use `/tdd:new-project` instead.
|
|
13
|
+
|
|
14
|
+
## Process
|
|
15
|
+
|
|
16
|
+
### 1. Scan for Existing Code
|
|
17
|
+
|
|
18
|
+
Check for source files:
|
|
19
|
+
- `src/`, `lib/`, `app/`, `pkg/`, or root-level code files
|
|
20
|
+
- `package.json`, `pyproject.toml`, `go.mod`, `Gemfile`, `Cargo.toml`
|
|
21
|
+
|
|
22
|
+
If no code found, suggest running `/tdd:new-project` instead.
|
|
23
|
+
|
|
24
|
+
### 2. Detect Stack
|
|
25
|
+
|
|
26
|
+
| Indicator | Stack |
|
|
27
|
+
|-----------|-------|
|
|
28
|
+
| `package.json` + React/Next deps | Next.js / React |
|
|
29
|
+
| `package.json` (no framework) | Node.js |
|
|
30
|
+
| `pyproject.toml` / `requirements.txt` | Python |
|
|
31
|
+
| `go.mod` | Go |
|
|
32
|
+
| `Gemfile` | Ruby |
|
|
33
|
+
| `Cargo.toml` | Rust |
|
|
34
|
+
|
|
35
|
+
### 3. Scan for Existing Tests
|
|
36
|
+
|
|
37
|
+
Look for test indicators:
|
|
38
|
+
|
|
39
|
+
**Directories:**
|
|
40
|
+
- `tests/`, `test/`, `__tests__/`, `spec/`
|
|
41
|
+
|
|
42
|
+
**Files:**
|
|
43
|
+
- `*_test.py`, `test_*.py`
|
|
44
|
+
- `*.test.ts`, `*.test.js`, `*.spec.ts`, `*.spec.js`
|
|
45
|
+
- `*_test.go`
|
|
46
|
+
- `*_spec.rb`
|
|
47
|
+
|
|
48
|
+
**Config files:**
|
|
49
|
+
- `vitest.config.*`, `jest.config.*`, `pytest.ini`, `pyproject.toml` [tool.pytest]
|
|
50
|
+
- `.rspec`, `spec/spec_helper.rb`
|
|
51
|
+
|
|
52
|
+
### 4. Set Up Test Framework (if missing)
|
|
53
|
+
|
|
54
|
+
If no tests found, set up based on detected stack:
|
|
55
|
+
|
|
56
|
+
| Stack | Framework | Setup |
|
|
57
|
+
|-------|-----------|-------|
|
|
58
|
+
| Next.js / React | Vitest | `npm install -D vitest @testing-library/react` |
|
|
59
|
+
| Node.js | Vitest | `npm install -D vitest` |
|
|
60
|
+
| Python | pytest | `pip install pytest` or add to pyproject.toml |
|
|
61
|
+
| Go | go test | Built-in, no setup needed |
|
|
62
|
+
| Ruby | RSpec | `gem install rspec && rspec --init` |
|
|
63
|
+
| Rust | cargo test | Built-in, no setup needed |
|
|
64
|
+
|
|
65
|
+
Create config file and test directory structure.
|
|
66
|
+
|
|
67
|
+
Add test scripts to package.json / pyproject.toml / Makefile:
|
|
68
|
+
```json
|
|
69
|
+
"scripts": {
|
|
70
|
+
"test": "vitest run",
|
|
71
|
+
"test:watch": "vitest"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 5. If Tests Already Exist
|
|
76
|
+
|
|
77
|
+
- Skip framework setup
|
|
78
|
+
- Note existing test patterns for consistency
|
|
79
|
+
- Report: "Found existing test framework: [vitest/jest/pytest/etc]"
|
|
80
|
+
- Report: "Found X existing test files"
|
|
81
|
+
|
|
82
|
+
### 6. Analyze Existing Code Structure
|
|
83
|
+
|
|
84
|
+
Scan the codebase and generate summary:
|
|
85
|
+
- Main directories and their purpose
|
|
86
|
+
- Key modules/components identified
|
|
87
|
+
- Entry points (main files, API routes, etc.)
|
|
88
|
+
- Dependencies and their roles
|
|
89
|
+
|
|
90
|
+
### 7. Create or Update PROJECT.md
|
|
91
|
+
|
|
92
|
+
If PROJECT.md doesn't exist, create it with:
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
# [Project Name]
|
|
96
|
+
|
|
97
|
+
## Overview
|
|
98
|
+
[Inferred from code structure and README if present]
|
|
99
|
+
|
|
100
|
+
## Tech Stack
|
|
101
|
+
- [Detected stack]
|
|
102
|
+
- [Key dependencies]
|
|
103
|
+
|
|
104
|
+
## Project Structure
|
|
105
|
+
[Generated from scan]
|
|
106
|
+
|
|
107
|
+
## Development Methodology: Test-Led Development
|
|
108
|
+
|
|
109
|
+
This project uses TDD. All new implementation follows Red -> Green -> Refactor:
|
|
110
|
+
|
|
111
|
+
1. **Red**: Write failing tests that define expected behavior
|
|
112
|
+
2. **Green**: Write minimum code to make tests pass
|
|
113
|
+
3. **Refactor**: Clean up while keeping tests green
|
|
114
|
+
|
|
115
|
+
Tests are written BEFORE implementation, not after.
|
|
116
|
+
|
|
117
|
+
## Test Framework
|
|
118
|
+
- Framework: [detected or installed]
|
|
119
|
+
- Run tests: `[test command]`
|
|
120
|
+
- Test directory: `[path]`
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If PROJECT.md exists, append the TDD section only.
|
|
124
|
+
|
|
125
|
+
### 8. Report Summary
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
TDD initialized for [project name]
|
|
129
|
+
|
|
130
|
+
Stack: [detected]
|
|
131
|
+
Test framework: [framework] (existing/newly configured)
|
|
132
|
+
Test directory: [path]
|
|
133
|
+
Existing tests: [count] files
|
|
134
|
+
|
|
135
|
+
Next steps:
|
|
136
|
+
- Run /tdd:status to check current test coverage
|
|
137
|
+
- Run /tdd:discuss to plan new features with TDD
|
|
138
|
+
- Run /tdd:quick for ad-hoc tasks with tests
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Usage
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
/tdd:init
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
No arguments needed. Auto-detects everything.
|