tdd-claude-code 0.1.0 → 0.2.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 +4 -0
- package/bin/install.js +106 -43
- 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
|
package/bin/install.js
CHANGED
|
@@ -5,6 +5,29 @@ 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.2.0';
|
|
30
|
+
|
|
8
31
|
const COMMANDS = [
|
|
9
32
|
'new-project.md',
|
|
10
33
|
'discuss.md',
|
|
@@ -28,27 +51,50 @@ function getLocalDir() {
|
|
|
28
51
|
return path.join(process.cwd(), '.claude', 'commands');
|
|
29
52
|
}
|
|
30
53
|
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
function printBanner() {
|
|
55
|
+
console.log(LOGO);
|
|
56
|
+
console.log(` ${c.bold}TDD Workflow${c.reset} ${c.dim}v${VERSION}${c.reset}`);
|
|
57
|
+
console.log(` ${c.white}Test-Led Development for Claude Code${c.reset}`);
|
|
58
|
+
console.log(` ${c.dim}Powered by GSD${c.reset}`);
|
|
59
|
+
console.log('');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function log(msg) {
|
|
63
|
+
console.log(` ${msg}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function success(msg) {
|
|
67
|
+
console.log(` ${c.green}✓${c.reset} ${msg}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function info(msg) {
|
|
71
|
+
console.log(` ${c.cyan}→${c.reset} ${msg}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function checkGsd(localGsdDir, installType) {
|
|
75
|
+
const globalGsdDir = path.join(getGlobalDir(), 'gsd');
|
|
76
|
+
|
|
77
|
+
// GSD can be in either location - check both
|
|
78
|
+
if (fs.existsSync(localGsdDir) || fs.existsSync(globalGsdDir)) {
|
|
79
|
+
return; // GSD found
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
log('');
|
|
83
|
+
log(`${c.yellow}GSD not found${c.reset} - installing dependency...`);
|
|
84
|
+
log('');
|
|
85
|
+
try {
|
|
86
|
+
execSync('npx --yes get-shit-done-cc@latest', { stdio: 'inherit' });
|
|
87
|
+
} catch (e) {
|
|
88
|
+
// GSD installer may exit with error but still install
|
|
89
|
+
}
|
|
90
|
+
console.log('');
|
|
91
|
+
|
|
92
|
+
// Check both locations again after install
|
|
93
|
+
if (!fs.existsSync(localGsdDir) && !fs.existsSync(globalGsdDir)) {
|
|
94
|
+
log(`${c.yellow}GSD not found after install.${c.reset}`);
|
|
95
|
+
log('Run: npx get-shit-done-cc');
|
|
96
|
+
log('Then re-run this installer.');
|
|
97
|
+
process.exit(1);
|
|
52
98
|
}
|
|
53
99
|
}
|
|
54
100
|
|
|
@@ -64,62 +110,79 @@ function install(targetDir, installType) {
|
|
|
64
110
|
|
|
65
111
|
// Copy command files
|
|
66
112
|
const sourceDir = path.join(__dirname, '..');
|
|
113
|
+
let installed = 0;
|
|
67
114
|
for (const file of COMMANDS) {
|
|
68
115
|
const src = path.join(sourceDir, file);
|
|
69
116
|
const dest = path.join(commandsDir, file);
|
|
70
117
|
if (fs.existsSync(src)) {
|
|
71
118
|
fs.copyFileSync(src, dest);
|
|
119
|
+
installed++;
|
|
72
120
|
}
|
|
73
121
|
}
|
|
74
122
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
123
|
+
success(`Installed ${installed} commands to ${c.cyan}${commandsDir}${c.reset}`);
|
|
124
|
+
log('');
|
|
125
|
+
log(`${c.green}Done!${c.reset} Restart Claude Code to load commands.`);
|
|
126
|
+
log('');
|
|
127
|
+
log(`${c.bold}Workflow:${c.reset}`);
|
|
128
|
+
log(` ${c.cyan}/tdd:new-project${c.reset} Start project with test infrastructure`);
|
|
129
|
+
log(` ${c.cyan}/tdd:discuss${c.reset} Shape implementation preferences`);
|
|
130
|
+
log(` ${c.cyan}/tdd:plan${c.reset} Create task plans`);
|
|
131
|
+
log(` ${c.cyan}/tdd:build${c.reset} Write tests → implement → verify`);
|
|
132
|
+
log(` ${c.cyan}/tdd:verify${c.reset} Human acceptance testing`);
|
|
133
|
+
log('');
|
|
134
|
+
log(`Run ${c.cyan}/tdd:help${c.reset} for full command list.`);
|
|
135
|
+
log('');
|
|
88
136
|
}
|
|
89
137
|
|
|
90
138
|
async function main() {
|
|
91
139
|
const args = process.argv.slice(2);
|
|
92
140
|
|
|
141
|
+
printBanner();
|
|
142
|
+
|
|
93
143
|
if (args.includes('--global') || args.includes('-g')) {
|
|
94
|
-
|
|
144
|
+
info(`Installing ${c.bold}globally${c.reset} to ~/.claude/commands/tdd`);
|
|
145
|
+
log('');
|
|
95
146
|
install(getGlobalDir(), 'global');
|
|
96
147
|
return;
|
|
97
148
|
}
|
|
98
149
|
|
|
99
150
|
if (args.includes('--local') || args.includes('-l')) {
|
|
100
|
-
|
|
151
|
+
info(`Installing ${c.bold}locally${c.reset} to ./.claude/commands/tdd`);
|
|
152
|
+
log('');
|
|
101
153
|
install(getLocalDir(), 'local');
|
|
102
154
|
return;
|
|
103
155
|
}
|
|
104
156
|
|
|
157
|
+
// Check if non-interactive
|
|
158
|
+
if (!process.stdin.isTTY) {
|
|
159
|
+
log(`${c.yellow}Non-interactive terminal detected, defaulting to global install${c.reset}`);
|
|
160
|
+
log('');
|
|
161
|
+
install(getGlobalDir(), 'global');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
105
165
|
// Interactive prompt
|
|
106
166
|
const rl = readline.createInterface({
|
|
107
167
|
input: process.stdin,
|
|
108
168
|
output: process.stdout
|
|
109
169
|
});
|
|
110
170
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
console.log(' 2) Local (./.claude/commands/tdd) - this project only');
|
|
116
|
-
console.log('');
|
|
171
|
+
log('Where would you like to install?');
|
|
172
|
+
log(` ${c.bold}1)${c.reset} Global ${c.dim}(~/.claude/commands/tdd)${c.reset} - available in all projects`);
|
|
173
|
+
log(` ${c.bold}2)${c.reset} Local ${c.dim}(./.claude/commands/tdd)${c.reset} - this project only`);
|
|
174
|
+
log('');
|
|
117
175
|
|
|
118
|
-
rl.question('Choice [1/2]: ', (answer) => {
|
|
176
|
+
rl.question(' Choice [1/2]: ', (answer) => {
|
|
119
177
|
rl.close();
|
|
178
|
+
console.log('');
|
|
120
179
|
if (answer === '2') {
|
|
180
|
+
info(`Installing ${c.bold}locally${c.reset}`);
|
|
181
|
+
log('');
|
|
121
182
|
install(getLocalDir(), 'local');
|
|
122
183
|
} else {
|
|
184
|
+
info(`Installing ${c.bold}globally${c.reset}`);
|
|
185
|
+
log('');
|
|
123
186
|
install(getGlobalDir(), 'global');
|
|
124
187
|
}
|
|
125
188
|
});
|