5-phase-workflow 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.
- package/README.md +332 -0
- package/bin/install.js +408 -0
- package/docs/workflow-guide.md +1024 -0
- package/package.json +34 -0
- package/src/agents/integration-agent.md +219 -0
- package/src/agents/review-processor.md +160 -0
- package/src/agents/step-executor.md +108 -0
- package/src/agents/step-fixer.md +132 -0
- package/src/agents/step-verifier.md +125 -0
- package/src/agents/verification-agent.md +411 -0
- package/src/commands/5/configure.md +309 -0
- package/src/commands/5/discuss-feature.md +393 -0
- package/src/commands/5/implement-feature.md +502 -0
- package/src/commands/5/plan-feature.md +285 -0
- package/src/commands/5/plan-implementation.md +376 -0
- package/src/commands/5/quick-implement.md +263 -0
- package/src/commands/5/review-code.md +583 -0
- package/src/commands/5/verify-implementation.md +277 -0
- package/src/hooks/statusline.js +53 -0
- package/src/settings.json +6 -0
- package/src/skills/build-project/SKILL.md +277 -0
- package/src/skills/configure-project/SKILL.md +355 -0
- package/src/skills/generate-readme/EXAMPLES.md +168 -0
- package/src/skills/generate-readme/SKILL.md +123 -0
- package/src/skills/generate-readme/TEMPLATE.md +141 -0
- package/src/skills/run-tests/SKILL.md +365 -0
- package/src/templates/ARCHITECTURE.md +64 -0
- package/src/templates/CONCERNS.md +75 -0
- package/src/templates/CONVENTIONS.md +75 -0
- package/src/templates/INTEGRATIONS.md +65 -0
- package/src/templates/STACK.md +60 -0
- package/src/templates/STRUCTURE.md +60 -0
- package/src/templates/TESTING.md +107 -0
package/bin/install.js
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
|
|
7
|
+
// ANSI colors for terminal output
|
|
8
|
+
const colors = {
|
|
9
|
+
reset: '\x1b[0m',
|
|
10
|
+
bright: '\x1b[1m',
|
|
11
|
+
green: '\x1b[32m',
|
|
12
|
+
yellow: '\x1b[33m',
|
|
13
|
+
blue: '\x1b[34m',
|
|
14
|
+
red: '\x1b[31m'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const log = {
|
|
18
|
+
info: (msg) => console.log(`${colors.blue}ℹ${colors.reset} ${msg}`),
|
|
19
|
+
success: (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`),
|
|
20
|
+
warn: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
|
|
21
|
+
error: (msg) => console.log(`${colors.red}✗${colors.reset} ${msg}`),
|
|
22
|
+
header: (msg) => console.log(`\n${colors.bright}${msg}${colors.reset}\n`)
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Parse CLI arguments
|
|
26
|
+
function parseArgs() {
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
const options = {
|
|
29
|
+
global: false,
|
|
30
|
+
local: false,
|
|
31
|
+
uninstall: false,
|
|
32
|
+
help: false
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
for (const arg of args) {
|
|
36
|
+
if (arg === '--global' || arg === '-g') options.global = true;
|
|
37
|
+
else if (arg === '--local' || arg === '-l') options.local = true;
|
|
38
|
+
else if (arg === '--uninstall' || arg === '-u') options.uninstall = true;
|
|
39
|
+
else if (arg === '--help' || arg === '-h') options.help = true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Default to local if neither specified
|
|
43
|
+
if (!options.global && !options.local && !options.uninstall) {
|
|
44
|
+
options.local = true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return options;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Show help message
|
|
51
|
+
function showHelp() {
|
|
52
|
+
console.log(`
|
|
53
|
+
${colors.bright}5-Phase Workflow Installer${colors.reset}
|
|
54
|
+
|
|
55
|
+
Usage: npx 5-phase-workflow [options]
|
|
56
|
+
|
|
57
|
+
Options:
|
|
58
|
+
--global, -g Install to ~/.claude/ (available across all projects)
|
|
59
|
+
--local, -l Install to ./.claude/ (project-specific, default)
|
|
60
|
+
--uninstall, -u Remove installation from current directory
|
|
61
|
+
--help, -h Show this help message
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
npx 5-phase-workflow # Install locally
|
|
65
|
+
npx 5-phase-workflow --global # Install globally
|
|
66
|
+
npx 5-phase-workflow --uninstall # Remove from current directory
|
|
67
|
+
`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Get installation target path
|
|
71
|
+
function getTargetPath(isGlobal) {
|
|
72
|
+
if (isGlobal) {
|
|
73
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
74
|
+
return path.join(homeDir, '.claude');
|
|
75
|
+
}
|
|
76
|
+
return path.join(process.cwd(), '.claude');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Get source path (package installation directory)
|
|
80
|
+
function getSourcePath() {
|
|
81
|
+
// When installed via npm, __dirname is <install-location>/bin
|
|
82
|
+
// Source files are in <install-location>/src
|
|
83
|
+
return path.join(__dirname, '..', 'src');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Copy directory recursively
|
|
87
|
+
function copyDir(src, dest) {
|
|
88
|
+
if (!fs.existsSync(dest)) {
|
|
89
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
93
|
+
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
const srcPath = path.join(src, entry.name);
|
|
96
|
+
const destPath = path.join(dest, entry.name);
|
|
97
|
+
|
|
98
|
+
if (entry.isDirectory()) {
|
|
99
|
+
copyDir(srcPath, destPath);
|
|
100
|
+
} else {
|
|
101
|
+
fs.copyFileSync(srcPath, destPath);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Remove directory recursively
|
|
107
|
+
function removeDir(dir) {
|
|
108
|
+
if (fs.existsSync(dir)) {
|
|
109
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
110
|
+
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
const fullPath = path.join(dir, entry.name);
|
|
113
|
+
|
|
114
|
+
if (entry.isDirectory()) {
|
|
115
|
+
removeDir(fullPath);
|
|
116
|
+
} else {
|
|
117
|
+
fs.unlinkSync(fullPath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fs.rmdirSync(dir);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Detect project type by examining files in current directory
|
|
126
|
+
function detectProjectType() {
|
|
127
|
+
const cwd = process.cwd();
|
|
128
|
+
|
|
129
|
+
if (fs.existsSync(path.join(cwd, 'package.json'))) {
|
|
130
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
131
|
+
if (pkg.dependencies?.['next'] || pkg.devDependencies?.['next']) return 'nextjs';
|
|
132
|
+
if (pkg.dependencies?.['express'] || pkg.devDependencies?.['express']) return 'express';
|
|
133
|
+
if (pkg.dependencies?.['@nestjs/core']) return 'nestjs';
|
|
134
|
+
return 'javascript';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (fs.existsSync(path.join(cwd, 'build.gradle')) || fs.existsSync(path.join(cwd, 'build.gradle.kts'))) {
|
|
138
|
+
return 'gradle-java';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (fs.existsSync(path.join(cwd, 'pom.xml'))) {
|
|
142
|
+
return 'maven-java';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (fs.existsSync(path.join(cwd, 'Cargo.toml'))) {
|
|
146
|
+
return 'rust';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (fs.existsSync(path.join(cwd, 'go.mod'))) {
|
|
150
|
+
return 'go';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (fs.existsSync(path.join(cwd, 'requirements.txt')) || fs.existsSync(path.join(cwd, 'pyproject.toml'))) {
|
|
154
|
+
const hasDjango = fs.existsSync(path.join(cwd, 'manage.py'));
|
|
155
|
+
const hasFlask = fs.existsSync(path.join(cwd, 'app.py')) || fs.existsSync(path.join(cwd, 'wsgi.py'));
|
|
156
|
+
if (hasDjango) return 'django';
|
|
157
|
+
if (hasFlask) return 'flask';
|
|
158
|
+
return 'python';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return 'unknown';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Get default config based on project type
|
|
165
|
+
function getDefaultConfig(projectType) {
|
|
166
|
+
const baseConfig = {
|
|
167
|
+
ticket: {
|
|
168
|
+
pattern: '[A-Z]+-\\d+',
|
|
169
|
+
extractFromBranch: true
|
|
170
|
+
},
|
|
171
|
+
build: {
|
|
172
|
+
command: 'auto',
|
|
173
|
+
testCommand: 'auto'
|
|
174
|
+
},
|
|
175
|
+
reviewTool: 'auto'
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Project-specific overrides
|
|
179
|
+
const overrides = {
|
|
180
|
+
'gradle-java': {
|
|
181
|
+
build: {
|
|
182
|
+
command: './gradlew build -x test -x javadoc --offline',
|
|
183
|
+
testCommand: './gradlew test --offline'
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
'maven-java': {
|
|
187
|
+
build: {
|
|
188
|
+
command: 'mvn compile',
|
|
189
|
+
testCommand: 'mvn test'
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
'javascript': {
|
|
193
|
+
build: {
|
|
194
|
+
command: 'npm run build',
|
|
195
|
+
testCommand: 'npm test'
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
'nextjs': {
|
|
199
|
+
build: {
|
|
200
|
+
command: 'npm run build',
|
|
201
|
+
testCommand: 'npm test'
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
'express': {
|
|
205
|
+
build: {
|
|
206
|
+
command: 'npm run build || tsc',
|
|
207
|
+
testCommand: 'npm test'
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
'nestjs': {
|
|
211
|
+
build: {
|
|
212
|
+
command: 'npm run build',
|
|
213
|
+
testCommand: 'npm test'
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
'rust': {
|
|
217
|
+
build: {
|
|
218
|
+
command: 'cargo build',
|
|
219
|
+
testCommand: 'cargo test'
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
'go': {
|
|
223
|
+
build: {
|
|
224
|
+
command: 'go build ./...',
|
|
225
|
+
testCommand: 'go test ./...'
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
'python': {
|
|
229
|
+
build: {
|
|
230
|
+
command: 'python -m py_compile **/*.py',
|
|
231
|
+
testCommand: 'pytest'
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
'django': {
|
|
235
|
+
build: {
|
|
236
|
+
command: 'python manage.py check',
|
|
237
|
+
testCommand: 'python manage.py test'
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
'flask': {
|
|
241
|
+
build: {
|
|
242
|
+
command: 'python -m py_compile **/*.py',
|
|
243
|
+
testCommand: 'pytest'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
...baseConfig,
|
|
250
|
+
...(overrides[projectType] || {}),
|
|
251
|
+
projectType
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Initialize config file
|
|
256
|
+
function initializeConfig(targetPath) {
|
|
257
|
+
const configDir = path.join(targetPath, '.5');
|
|
258
|
+
const configFile = path.join(configDir, 'config.json');
|
|
259
|
+
|
|
260
|
+
if (fs.existsSync(configFile)) {
|
|
261
|
+
log.info('Config file already exists, skipping initialization');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!fs.existsSync(configDir)) {
|
|
266
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const projectType = detectProjectType();
|
|
270
|
+
const config = getDefaultConfig(projectType);
|
|
271
|
+
|
|
272
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
273
|
+
log.success(`Created config file with detected project type: ${projectType}`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Merge settings.json into existing
|
|
277
|
+
function mergeSettings(targetPath, sourcePath) {
|
|
278
|
+
const targetSettings = path.join(targetPath, 'settings.json');
|
|
279
|
+
const sourceSettings = path.join(sourcePath, 'settings.json');
|
|
280
|
+
|
|
281
|
+
if (!fs.existsSync(sourceSettings)) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const newSettings = JSON.parse(fs.readFileSync(sourceSettings, 'utf8'));
|
|
286
|
+
|
|
287
|
+
if (fs.existsSync(targetSettings)) {
|
|
288
|
+
const existingSettings = JSON.parse(fs.readFileSync(targetSettings, 'utf8'));
|
|
289
|
+
const merged = { ...newSettings, ...existingSettings };
|
|
290
|
+
fs.writeFileSync(targetSettings, JSON.stringify(merged, null, 2));
|
|
291
|
+
log.info('Merged settings with existing configuration');
|
|
292
|
+
} else {
|
|
293
|
+
fs.copyFileSync(sourceSettings, targetSettings);
|
|
294
|
+
log.success('Installed settings.json');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Check if installation exists
|
|
299
|
+
function checkExistingInstallation(targetPath) {
|
|
300
|
+
const markerFile = path.join(targetPath, 'commands', '5', 'plan-feature.md');
|
|
301
|
+
return fs.existsSync(markerFile);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Perform installation
|
|
305
|
+
function install(isGlobal) {
|
|
306
|
+
const targetPath = getTargetPath(isGlobal);
|
|
307
|
+
const sourcePath = getSourcePath();
|
|
308
|
+
|
|
309
|
+
log.header('5-Phase Workflow Installation');
|
|
310
|
+
log.info(`Target: ${targetPath}`);
|
|
311
|
+
log.info(`Source: ${sourcePath}`);
|
|
312
|
+
|
|
313
|
+
// Check if already installed
|
|
314
|
+
const exists = checkExistingInstallation(targetPath);
|
|
315
|
+
if (exists) {
|
|
316
|
+
log.warn('Installation already exists at this location');
|
|
317
|
+
log.info('To upgrade, run with --uninstall first, then reinstall');
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Create target directory if it doesn't exist
|
|
322
|
+
if (!fs.existsSync(targetPath)) {
|
|
323
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
324
|
+
log.success(`Created ${targetPath}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Copy directories
|
|
328
|
+
const dirs = ['commands', 'agents', 'skills', 'hooks', 'templates'];
|
|
329
|
+
for (const dir of dirs) {
|
|
330
|
+
const src = path.join(sourcePath, dir);
|
|
331
|
+
const dest = path.join(targetPath, dir);
|
|
332
|
+
|
|
333
|
+
if (fs.existsSync(src)) {
|
|
334
|
+
copyDir(src, dest);
|
|
335
|
+
log.success(`Installed ${dir}/`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Merge settings
|
|
340
|
+
mergeSettings(targetPath, sourcePath);
|
|
341
|
+
|
|
342
|
+
// Initialize config
|
|
343
|
+
if (!isGlobal) {
|
|
344
|
+
initializeConfig(targetPath);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
log.header('Installation Complete!');
|
|
348
|
+
log.info('Available commands:');
|
|
349
|
+
log.info(' /5:plan-feature - Start feature planning (Phase 1)');
|
|
350
|
+
log.info(' /5:plan-implementation - Create implementation plan (Phase 2)');
|
|
351
|
+
log.info(' /5:implement-feature - Execute implementation (Phase 3)');
|
|
352
|
+
log.info(' /5:verify-implementation - Verify implementation (Phase 4)');
|
|
353
|
+
log.info(' /5:review-code - Code review (Phase 5)');
|
|
354
|
+
log.info(' /5:configure - Interactive project setup');
|
|
355
|
+
log.info('');
|
|
356
|
+
log.info(`Config file: ${path.join(targetPath, '.5', 'config.json')}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Perform uninstallation
|
|
360
|
+
function uninstall() {
|
|
361
|
+
const targetPath = getTargetPath(false); // Always local for uninstall
|
|
362
|
+
|
|
363
|
+
log.header('5-Phase Workflow Uninstallation');
|
|
364
|
+
log.info(`Target: ${targetPath}`);
|
|
365
|
+
|
|
366
|
+
if (!checkExistingInstallation(targetPath)) {
|
|
367
|
+
log.warn('No installation found at this location');
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Remove directories
|
|
372
|
+
const dirs = ['commands/5', 'agents', 'skills', 'hooks', 'templates'];
|
|
373
|
+
for (const dir of dirs) {
|
|
374
|
+
const fullPath = path.join(targetPath, dir);
|
|
375
|
+
if (fs.existsSync(fullPath)) {
|
|
376
|
+
removeDir(fullPath);
|
|
377
|
+
log.success(`Removed ${dir}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Remove config
|
|
382
|
+
const configDir = path.join(targetPath, '.5');
|
|
383
|
+
if (fs.existsSync(configDir)) {
|
|
384
|
+
removeDir(configDir);
|
|
385
|
+
log.success('Removed .5/ config directory');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
log.header('Uninstallation Complete!');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Main
|
|
392
|
+
function main() {
|
|
393
|
+
const options = parseArgs();
|
|
394
|
+
|
|
395
|
+
if (options.help) {
|
|
396
|
+
showHelp();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (options.uninstall) {
|
|
401
|
+
uninstall();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
install(options.global);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
main();
|