5-phase-workflow 1.4.4 → 1.5.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 +18 -10
- package/bin/install.js +96 -30
- package/docs/workflow-guide.md +4 -4
- package/package.json +1 -1
- package/src/commands/5/configure.md +6 -6
- package/src/commands/5/implement-feature.md +7 -1
- package/src/commands/5/plan-feature.md +13 -0
- package/src/commands/5/plan-implementation.md +14 -0
- package/src/commands/5/quick-implement.md +7 -1
- package/src/commands/5/review-code.md +2 -2
- package/src/commands/5/unlock.md +23 -0
- package/src/commands/5/update.md +41 -4
- package/src/commands/5/verify-implementation.md +2 -2
- package/src/hooks/check-updates.js +1 -1
- package/src/hooks/config-guard.js +1 -1
- package/src/hooks/plan-guard.js +32 -9
- package/src/hooks/statusline.js +1 -1
- package/src/skills/build-project/SKILL.md +2 -2
- package/src/skills/run-tests/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -126,10 +126,11 @@ All commands are available under the `/5:` namespace:
|
|
|
126
126
|
| `/5:verify-implementation` | 4 | Verify completeness and correctness |
|
|
127
127
|
| `/5:review-code` | 5 | AI-powered code review (CodeRabbit) |
|
|
128
128
|
| `/5:quick-implement` | Fast | Streamlined workflow for small tasks |
|
|
129
|
+
| `/5:unlock` | Utility | Remove planning guard lock |
|
|
129
130
|
|
|
130
131
|
## Configuration
|
|
131
132
|
|
|
132
|
-
The workflow is configured via `.
|
|
133
|
+
The workflow is configured via `.5/config.json`. Here's an example:
|
|
133
134
|
|
|
134
135
|
```json
|
|
135
136
|
{
|
|
@@ -181,7 +182,7 @@ Claude asks 5-10 clarifying questions to understand your requirements:
|
|
|
181
182
|
- How will we verify it works?
|
|
182
183
|
- Are there simpler alternatives?
|
|
183
184
|
|
|
184
|
-
The output is a comprehensive feature spec at `.
|
|
185
|
+
The output is a comprehensive feature spec at `.5/features/{ticket-id}/feature.md`.
|
|
185
186
|
|
|
186
187
|
### Phase 2: Implementation Planning
|
|
187
188
|
|
|
@@ -207,7 +208,7 @@ Claude executes the plan using specialized agents:
|
|
|
207
208
|
- **step-verifier**: Compiles and checks for errors after each step
|
|
208
209
|
- **integration-agent**: Wires components and registers routes
|
|
209
210
|
|
|
210
|
-
State is tracked in `.
|
|
211
|
+
State is tracked in `.5/features/{ticket-id}/state.json` for resumability.
|
|
211
212
|
|
|
212
213
|
### Phase 4: Verify Implementation
|
|
213
214
|
|
|
@@ -234,9 +235,12 @@ Automated review using CodeRabbit (if installed):
|
|
|
234
235
|
After installation, your `.claude/` directory will contain:
|
|
235
236
|
|
|
236
237
|
```
|
|
238
|
+
.5/
|
|
239
|
+
├── config.json # Project configuration
|
|
240
|
+
├── version.json # Version tracking
|
|
241
|
+
└── features/ # Feature tracking
|
|
242
|
+
|
|
237
243
|
.claude/
|
|
238
|
-
├── .5/
|
|
239
|
-
│ └── config.json # Project configuration
|
|
240
244
|
├── commands/5/ # Workflow commands
|
|
241
245
|
│ ├── plan-feature.md
|
|
242
246
|
│ ├── plan-implementation.md
|
|
@@ -245,13 +249,17 @@ After installation, your `.claude/` directory will contain:
|
|
|
245
249
|
│ ├── review-code.md
|
|
246
250
|
│ ├── discuss-feature.md
|
|
247
251
|
│ ├── quick-implement.md
|
|
248
|
-
│
|
|
252
|
+
│ ├── configure.md
|
|
253
|
+
│ └── unlock.md
|
|
249
254
|
├── skills/ # Atomic operations
|
|
250
255
|
│ ├── build-project/
|
|
251
256
|
│ ├── run-tests/
|
|
252
257
|
│ └── generate-readme/
|
|
253
258
|
├── hooks/
|
|
254
|
-
│
|
|
259
|
+
│ ├── statusline.js # Status line integration
|
|
260
|
+
│ ├── check-updates.js # Update notifications
|
|
261
|
+
│ ├── plan-guard.js # Planning phase edit guard
|
|
262
|
+
│ └── config-guard.js # Configuration guard
|
|
255
263
|
└── settings.json # Claude Code settings
|
|
256
264
|
```
|
|
257
265
|
|
|
@@ -293,7 +301,7 @@ After installation, your `.claude/` directory will contain:
|
|
|
293
301
|
|
|
294
302
|
1. Run `/5:configure` to verify configuration
|
|
295
303
|
2. Test commands manually in terminal
|
|
296
|
-
3. Update `.
|
|
304
|
+
3. Update `.5/config.json` with correct commands
|
|
297
305
|
|
|
298
306
|
### "Cannot find project type"
|
|
299
307
|
|
|
@@ -303,7 +311,7 @@ The auto-detection failed. Run `/5:configure` and manually select your project t
|
|
|
303
311
|
|
|
304
312
|
If implementation gets stuck:
|
|
305
313
|
|
|
306
|
-
1. Check `.
|
|
314
|
+
1. Check `.5/features/{ticket-id}/state.json`
|
|
307
315
|
2. Note the `currentStep` value
|
|
308
316
|
3. Run `/5:implement-feature` again - it will resume from that step
|
|
309
317
|
|
|
@@ -338,7 +346,7 @@ npx 5-phase-workflow
|
|
|
338
346
|
```
|
|
339
347
|
|
|
340
348
|
**Note:** During updates:
|
|
341
|
-
- Config files in `.
|
|
349
|
+
- Config files in `.5/` are preserved
|
|
342
350
|
- User-created commands, agents, skills, hooks, and templates are preserved
|
|
343
351
|
- Only workflow-managed files are updated
|
|
344
352
|
|
package/bin/install.js
CHANGED
|
@@ -35,8 +35,8 @@ function compareVersions(v1, v2) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Get installed version from .5/version.json
|
|
38
|
-
function getInstalledVersion(
|
|
39
|
-
const versionFile = path.join(
|
|
38
|
+
function getInstalledVersion(isGlobal) {
|
|
39
|
+
const versionFile = path.join(getDataPath(isGlobal), 'version.json');
|
|
40
40
|
if (!fs.existsSync(versionFile)) return null;
|
|
41
41
|
|
|
42
42
|
try {
|
|
@@ -55,13 +55,13 @@ function getPackageVersion() {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
// Get full version info
|
|
58
|
-
function getVersionInfo(targetPath) {
|
|
58
|
+
function getVersionInfo(targetPath, isGlobal) {
|
|
59
59
|
const exists = checkExistingInstallation(targetPath);
|
|
60
60
|
if (!exists) {
|
|
61
61
|
return { exists: false };
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const installed = getInstalledVersion(
|
|
64
|
+
const installed = getInstalledVersion(isGlobal);
|
|
65
65
|
const available = getPackageVersion();
|
|
66
66
|
|
|
67
67
|
if (!installed) {
|
|
@@ -139,7 +139,7 @@ Examples:
|
|
|
139
139
|
`);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
// Get installation target path
|
|
142
|
+
// Get installation target path (.claude/ directory)
|
|
143
143
|
function getTargetPath(isGlobal) {
|
|
144
144
|
if (isGlobal) {
|
|
145
145
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
@@ -148,6 +148,60 @@ function getTargetPath(isGlobal) {
|
|
|
148
148
|
return path.join(process.cwd(), '.claude');
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
// Get data path (.5/ directory for config, version, features)
|
|
152
|
+
// Local installs: <project>/.5 (project root)
|
|
153
|
+
// Global installs: ~/.claude/.5 (alongside global install)
|
|
154
|
+
function getDataPath(isGlobal) {
|
|
155
|
+
if (isGlobal) {
|
|
156
|
+
return path.join(getTargetPath(true), '.5');
|
|
157
|
+
}
|
|
158
|
+
return path.join(process.cwd(), '.5');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Migrate data from old .claude/.5/ to new .5/ location (local installs only)
|
|
162
|
+
// This runs during upgrades so existing users don't lose config/features/version data.
|
|
163
|
+
function migrateDataDir(isGlobal) {
|
|
164
|
+
// Global installs: old and new paths are both ~/.claude/.5 — no migration needed
|
|
165
|
+
if (isGlobal) return;
|
|
166
|
+
|
|
167
|
+
const oldDir = path.join(process.cwd(), '.claude', '.5');
|
|
168
|
+
const newDir = getDataPath(false); // <project>/.5
|
|
169
|
+
|
|
170
|
+
if (!fs.existsSync(oldDir)) return;
|
|
171
|
+
|
|
172
|
+
// If new dir doesn't exist, move everything over
|
|
173
|
+
if (!fs.existsSync(newDir)) {
|
|
174
|
+
fs.mkdirSync(newDir, { recursive: true });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Copy all files/dirs from old to new (skip files that already exist in new)
|
|
178
|
+
copyDirMerge(oldDir, newDir);
|
|
179
|
+
|
|
180
|
+
// Remove old directory
|
|
181
|
+
removeDir(oldDir);
|
|
182
|
+
log.success('Migrated .claude/.5/ → .5/');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Copy directory recursively, skipping files that already exist at destination
|
|
186
|
+
function copyDirMerge(src, dest) {
|
|
187
|
+
if (!fs.existsSync(dest)) {
|
|
188
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
192
|
+
|
|
193
|
+
for (const entry of entries) {
|
|
194
|
+
const srcPath = path.join(src, entry.name);
|
|
195
|
+
const destPath = path.join(dest, entry.name);
|
|
196
|
+
|
|
197
|
+
if (entry.isDirectory()) {
|
|
198
|
+
copyDirMerge(srcPath, destPath);
|
|
199
|
+
} else if (!fs.existsSync(destPath)) {
|
|
200
|
+
fs.copyFileSync(srcPath, destPath);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
151
205
|
// Get source path (package installation directory)
|
|
152
206
|
function getSourcePath() {
|
|
153
207
|
// When installed via npm, __dirname is <install-location>/bin
|
|
@@ -328,12 +382,12 @@ function selectiveUpdate(targetPath, sourcePath) {
|
|
|
328
382
|
}
|
|
329
383
|
|
|
330
384
|
// Initialize version.json after successful install
|
|
331
|
-
function initializeVersionJson(
|
|
332
|
-
const
|
|
333
|
-
const versionFile = path.join(
|
|
385
|
+
function initializeVersionJson(isGlobal) {
|
|
386
|
+
const dataDir = getDataPath(isGlobal);
|
|
387
|
+
const versionFile = path.join(dataDir, 'version.json');
|
|
334
388
|
|
|
335
|
-
if (!fs.existsSync(
|
|
336
|
-
fs.mkdirSync(
|
|
389
|
+
if (!fs.existsSync(dataDir)) {
|
|
390
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
337
391
|
}
|
|
338
392
|
|
|
339
393
|
const version = getPackageVersion();
|
|
@@ -427,7 +481,7 @@ function checkExistingInstallation(targetPath) {
|
|
|
427
481
|
}
|
|
428
482
|
|
|
429
483
|
// Helper to show commands
|
|
430
|
-
function showCommandsHelp(
|
|
484
|
+
function showCommandsHelp(isGlobal) {
|
|
431
485
|
log.info('Available commands:');
|
|
432
486
|
log.info(' /5:plan-feature - Start feature planning (Phase 1)');
|
|
433
487
|
log.info(' /5:plan-implementation - Create implementation plan (Phase 2)');
|
|
@@ -435,8 +489,9 @@ function showCommandsHelp(targetPath) {
|
|
|
435
489
|
log.info(' /5:verify-implementation - Verify implementation (Phase 4)');
|
|
436
490
|
log.info(' /5:review-code - Code review (Phase 5)');
|
|
437
491
|
log.info(' /5:configure - Interactive project setup');
|
|
492
|
+
log.info(' /5:unlock - Remove planning guard lock');
|
|
438
493
|
log.info('');
|
|
439
|
-
log.info(`Config file: ${path.join(
|
|
494
|
+
log.info(`Config file: ${path.join(getDataPath(isGlobal), 'config.json')}`);
|
|
440
495
|
}
|
|
441
496
|
|
|
442
497
|
// Fresh installation
|
|
@@ -463,7 +518,7 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
|
|
|
463
518
|
mergeSettings(targetPath, sourcePath);
|
|
464
519
|
|
|
465
520
|
// Initialize version tracking
|
|
466
|
-
initializeVersionJson(
|
|
521
|
+
initializeVersionJson(isGlobal);
|
|
467
522
|
|
|
468
523
|
log.header('Installation Complete!');
|
|
469
524
|
log.info('');
|
|
@@ -477,10 +532,10 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
|
|
|
477
532
|
log.info(' • Create project-specific skills');
|
|
478
533
|
log.info('');
|
|
479
534
|
|
|
480
|
-
showCommandsHelp(
|
|
535
|
+
showCommandsHelp(isGlobal);
|
|
481
536
|
}
|
|
482
537
|
|
|
483
|
-
// Perform update (preserves .5/ directory
|
|
538
|
+
// Perform update (preserves user-created files, updates .5/ data directory)
|
|
484
539
|
function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
485
540
|
log.header(`Updating from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
|
|
486
541
|
log.info('Preserving user-created commands, agents, skills, and hooks');
|
|
@@ -492,8 +547,8 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
492
547
|
mergeSettings(targetPath, sourcePath);
|
|
493
548
|
|
|
494
549
|
// Update version.json
|
|
495
|
-
const
|
|
496
|
-
const versionFile = path.join(
|
|
550
|
+
const dataDir = getDataPath(isGlobal);
|
|
551
|
+
const versionFile = path.join(dataDir, 'version.json');
|
|
497
552
|
|
|
498
553
|
let versionData;
|
|
499
554
|
if (fs.existsSync(versionFile)) {
|
|
@@ -511,22 +566,22 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
511
566
|
versionData.installedVersion = versionInfo.available;
|
|
512
567
|
versionData.lastUpdated = new Date().toISOString();
|
|
513
568
|
|
|
514
|
-
if (!fs.existsSync(
|
|
515
|
-
fs.mkdirSync(
|
|
569
|
+
if (!fs.existsSync(dataDir)) {
|
|
570
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
516
571
|
}
|
|
517
572
|
fs.writeFileSync(versionFile, JSON.stringify(versionData, null, 2));
|
|
518
573
|
|
|
519
574
|
// Create features directory if it doesn't exist
|
|
520
|
-
const featuresDir = path.join(
|
|
575
|
+
const featuresDir = path.join(dataDir, 'features');
|
|
521
576
|
if (!fs.existsSync(featuresDir)) {
|
|
522
577
|
fs.mkdirSync(featuresDir, { recursive: true });
|
|
523
|
-
log.info('
|
|
524
|
-
log.info('
|
|
578
|
+
log.info('Feature folders nest under .5/features/');
|
|
579
|
+
log.info('See RELEASE_NOTES.md for migration if you have in-progress features');
|
|
525
580
|
}
|
|
526
581
|
|
|
527
582
|
log.header('Update Complete!');
|
|
528
583
|
log.success(`Now running version ${versionInfo.available}`);
|
|
529
|
-
showCommandsHelp(
|
|
584
|
+
showCommandsHelp(isGlobal);
|
|
530
585
|
}
|
|
531
586
|
|
|
532
587
|
// Perform installation
|
|
@@ -538,8 +593,11 @@ function install(isGlobal, forceUpgrade = false) {
|
|
|
538
593
|
log.info(`Target: ${targetPath}`);
|
|
539
594
|
log.info(`Source: ${sourcePath}`);
|
|
540
595
|
|
|
596
|
+
// Migrate data from old .claude/.5/ to new .5/ location
|
|
597
|
+
migrateDataDir(isGlobal);
|
|
598
|
+
|
|
541
599
|
// Check for existing installation and version
|
|
542
|
-
const versionInfo = getVersionInfo(targetPath);
|
|
600
|
+
const versionInfo = getVersionInfo(targetPath, isGlobal);
|
|
543
601
|
|
|
544
602
|
if (versionInfo.exists) {
|
|
545
603
|
if (versionInfo.legacy) {
|
|
@@ -630,11 +688,18 @@ function uninstall() {
|
|
|
630
688
|
}
|
|
631
689
|
log.success('Removed workflow templates (preserved user-created templates)');
|
|
632
690
|
|
|
633
|
-
// Remove
|
|
634
|
-
const
|
|
635
|
-
if (fs.existsSync(
|
|
636
|
-
removeDir(
|
|
637
|
-
log.success('Removed .5/
|
|
691
|
+
// Remove data directory (.5/)
|
|
692
|
+
const dataDir = getDataPath(false);
|
|
693
|
+
if (fs.existsSync(dataDir)) {
|
|
694
|
+
removeDir(dataDir);
|
|
695
|
+
log.success('Removed .5/ data directory');
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Also clean up old .claude/.5/ if it still exists
|
|
699
|
+
const oldDataDir = path.join(targetPath, '.5');
|
|
700
|
+
if (fs.existsSync(oldDataDir)) {
|
|
701
|
+
removeDir(oldDataDir);
|
|
702
|
+
log.success('Removed legacy .claude/.5/ directory');
|
|
638
703
|
}
|
|
639
704
|
|
|
640
705
|
log.header('Uninstallation Complete!');
|
|
@@ -651,7 +716,8 @@ function main() {
|
|
|
651
716
|
|
|
652
717
|
if (options.check) {
|
|
653
718
|
const targetPath = getTargetPath(options.global);
|
|
654
|
-
|
|
719
|
+
migrateDataDir(options.global);
|
|
720
|
+
const versionInfo = getVersionInfo(targetPath, options.global);
|
|
655
721
|
|
|
656
722
|
if (!versionInfo.exists) {
|
|
657
723
|
log.info('Not installed');
|
package/docs/workflow-guide.md
CHANGED
|
@@ -72,7 +72,7 @@ The installer copies workflow files to `.claude/` directory. **It does NOT creat
|
|
|
72
72
|
4. **Phase 4** (`/5:verify-implementation`): Verifies configuration
|
|
73
73
|
|
|
74
74
|
After completing these steps, you have:
|
|
75
|
-
- `.
|
|
75
|
+
- `.5/config.json` with your project settings
|
|
76
76
|
- `CLAUDE.md` with comprehensive project documentation
|
|
77
77
|
- `.5/STRUCTURE.md`, `.5/STACK.md`, etc. with modular documentation
|
|
78
78
|
- Project-specific skills in `.claude/skills/`
|
|
@@ -295,7 +295,7 @@ Map feature requirements to technical components, skills, and dependency steps.
|
|
|
295
295
|
- **Step 2 (Logic)**: Business logic, services, handlers (sequential if needed)
|
|
296
296
|
- **Step 3 (Integration)**: API routes, wiring, tests (sequential for integration)
|
|
297
297
|
|
|
298
|
-
Note: Step count and organization is configurable in `.
|
|
298
|
+
Note: Step count and organization is configurable in `.5/config.json`
|
|
299
299
|
|
|
300
300
|
6. **Implementation Plan Creation**: Claude writes an **atomic plan structure** to:
|
|
301
301
|
```
|
|
@@ -997,7 +997,7 @@ If working on multiple features:
|
|
|
997
997
|
|
|
998
998
|
## Configuring for Different Tech Stacks
|
|
999
999
|
|
|
1000
|
-
The 5-phase workflow is designed to work with any technology stack. Configuration is stored in `.
|
|
1000
|
+
The 5-phase workflow is designed to work with any technology stack. Configuration is stored in `.5/config.json` and can be customized using the `/5:configure` command.
|
|
1001
1001
|
|
|
1002
1002
|
### Quick Setup
|
|
1003
1003
|
|
|
@@ -1096,7 +1096,7 @@ You can override auto-detected values in the config file.
|
|
|
1096
1096
|
|
|
1097
1097
|
### Further Customization
|
|
1098
1098
|
|
|
1099
|
-
See the `/5:configure` command for interactive configuration, or manually edit `.
|
|
1099
|
+
See the `/5:configure` command for interactive configuration, or manually edit `.5/config.json` to customize:
|
|
1100
1100
|
- Ticket ID patterns
|
|
1101
1101
|
- Branch naming conventions
|
|
1102
1102
|
- Build and test commands
|
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@ After running this command, proceed through the standard phases:
|
|
|
26
26
|
Your job in this command:
|
|
27
27
|
✅ Analyze project (detect type, build commands, etc.)
|
|
28
28
|
✅ Gather user preferences via questions
|
|
29
|
-
✅ Write `.
|
|
29
|
+
✅ Write `.5/config.json` directly
|
|
30
30
|
✅ Create feature spec at `.5/features/CONFIGURE/feature.md` for remaining work
|
|
31
31
|
✅ Tell user to run /5:plan-implementation CONFIGURE
|
|
32
32
|
|
|
@@ -49,7 +49,7 @@ Perform all detection silently, collecting results for Step 2.
|
|
|
49
49
|
|
|
50
50
|
**1a. Check for existing config:**
|
|
51
51
|
```bash
|
|
52
|
-
if [ -f ".
|
|
52
|
+
if [ -f ".5/config.json" ]; then
|
|
53
53
|
# Config exists - will ask user in Step 2 what to do
|
|
54
54
|
config_exists=true
|
|
55
55
|
else
|
|
@@ -155,7 +155,7 @@ For each command found: record exact syntax, note variants (e.g., `test:unit`, `
|
|
|
155
155
|
|
|
156
156
|
If "Start fresh" selected:
|
|
157
157
|
- Confirm: "This will delete existing config. Are you sure?"
|
|
158
|
-
- If confirmed: delete .
|
|
158
|
+
- If confirmed: delete .5/config.json
|
|
159
159
|
- Proceed to detection and questions
|
|
160
160
|
|
|
161
161
|
If "Update existing configuration":
|
|
@@ -281,14 +281,14 @@ If no patterns/commands detected:
|
|
|
281
281
|
|
|
282
282
|
### Step 2.5: Write config.json
|
|
283
283
|
|
|
284
|
-
Using the values gathered from Steps 1 and 2, write `.
|
|
284
|
+
Using the values gathered from Steps 1 and 2, write `.5/config.json` directly.
|
|
285
285
|
|
|
286
286
|
**If "Update existing" flow:** Read current config, merge updated values.
|
|
287
287
|
**If "Start fresh" or new install:** Write new config.
|
|
288
288
|
|
|
289
289
|
**Ensure directory exists:**
|
|
290
290
|
```bash
|
|
291
|
-
mkdir -p .
|
|
291
|
+
mkdir -p .5
|
|
292
292
|
```
|
|
293
293
|
|
|
294
294
|
**Schema:**
|
|
@@ -413,7 +413,7 @@ Include only patterns/commands where user selected "Generate".
|
|
|
413
413
|
|
|
414
414
|
Tell the user:
|
|
415
415
|
|
|
416
|
-
1. "Configuration saved to `.
|
|
416
|
+
1. "Configuration saved to `.5/config.json`"
|
|
417
417
|
2. "Configuration feature planned at `.5/features/CONFIGURE/feature.md`"
|
|
418
418
|
3. "Next steps:"
|
|
419
419
|
- "Run `/clear` to reset context"
|
|
@@ -39,7 +39,7 @@ Parse:
|
|
|
39
39
|
|
|
40
40
|
If the plan doesn't exist, tell the user to run `/5:plan-implementation` first.
|
|
41
41
|
|
|
42
|
-
Also read `.
|
|
42
|
+
Also read `.5/config.json` and extract:
|
|
43
43
|
- `git.autoCommit` (boolean, default `false`)
|
|
44
44
|
- `git.commitMessage.pattern` (string, default `{ticket-id} {short-description}`)
|
|
45
45
|
|
|
@@ -59,6 +59,12 @@ Create `.5/features/{feature-name}/state.json`:
|
|
|
59
59
|
}
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
Then remove the planning guard marker (planning is over, implementation is starting):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
rm -f .5/.planning-active
|
|
66
|
+
```
|
|
67
|
+
|
|
62
68
|
### Step 3: Execute Steps
|
|
63
69
|
|
|
64
70
|
Group components by step number from the plan. For each step:
|
|
@@ -37,6 +37,19 @@ After creating the spec, you are DONE.
|
|
|
37
37
|
|
|
38
38
|
## Process
|
|
39
39
|
|
|
40
|
+
### Step 0: Activate Planning Guard
|
|
41
|
+
|
|
42
|
+
Write the planning guard marker to `.5/.planning-active` using the Write tool:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"phase": "plan-feature",
|
|
47
|
+
"startedAt": "{ISO-timestamp}"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This activates the plan-guard hook which prevents accidental source file edits during planning. The marker is removed automatically when implementation starts (`/5:implement-feature`), expires after 4 hours, or can be cleared manually with `/5:unlock`.
|
|
52
|
+
|
|
40
53
|
### Step 1: Gather Feature Description
|
|
41
54
|
|
|
42
55
|
Ask the developer for the feature description using AskUserQuestion:
|
|
@@ -66,6 +66,20 @@ Add emergency schedule tracking to products with date validation.
|
|
|
66
66
|
|
|
67
67
|
## Process
|
|
68
68
|
|
|
69
|
+
### Step 0: Activate Planning Guard
|
|
70
|
+
|
|
71
|
+
Write (or refresh) the planning guard marker to `.5/.planning-active` using the Write tool:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"phase": "plan-implementation",
|
|
76
|
+
"feature": "{feature-name}",
|
|
77
|
+
"startedAt": "{ISO-timestamp}"
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This activates (or refreshes) the plan-guard hook which prevents accidental source file edits during planning. The marker is removed automatically when implementation starts (`/5:implement-feature`), expires after 4 hours, or can be cleared manually with `/5:unlock`.
|
|
82
|
+
|
|
69
83
|
### Step 1: Load Feature Spec
|
|
70
84
|
|
|
71
85
|
Read `.5/features/{feature-name}/feature.md` (where `{feature-name}` is the argument provided).
|
|
@@ -51,7 +51,7 @@ Extract ticket ID using configurable pattern from config (e.g., `PROJ-\d+` or `\
|
|
|
51
51
|
|
|
52
52
|
**Sanitize the ticket ID:** Only allow alphanumeric characters, dashes (`-`), and underscores (`_`). Strip any other characters (especially `/`, `..`, `~`, spaces). If the sanitized result is empty, ask the user for a valid ticket ID.
|
|
53
53
|
|
|
54
|
-
Also read `.
|
|
54
|
+
Also read `.5/config.json` and extract:
|
|
55
55
|
- `git.autoCommit` (boolean, default `false`)
|
|
56
56
|
- `git.commitMessage.pattern` (string, default `{ticket-id} {short-description}`)
|
|
57
57
|
|
|
@@ -128,6 +128,12 @@ Create state file at `.5/features/${feature_name}/state.json` with fields: `tick
|
|
|
128
128
|
|
|
129
129
|
Verify the file was written correctly with Read tool. If creation fails, stop and report error.
|
|
130
130
|
|
|
131
|
+
Then remove the planning guard marker (implementation is starting):
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
rm -f .5/.planning-active
|
|
135
|
+
```
|
|
136
|
+
|
|
131
137
|
### Step 8: Execute Implementation
|
|
132
138
|
|
|
133
139
|
**Decision criteria for execution approach:**
|
|
@@ -20,7 +20,7 @@ After saving the review report, you are DONE.
|
|
|
20
20
|
|
|
21
21
|
## Review Tools
|
|
22
22
|
|
|
23
|
-
Two review tools are supported (configured in `.
|
|
23
|
+
Two review tools are supported (configured in `.5/config.json` field `reviewTool`):
|
|
24
24
|
|
|
25
25
|
- **Claude** (default) — Built-in, zero setup. A fresh-context agent reviews code blind.
|
|
26
26
|
- **CodeRabbit** — External CLI. Requires `coderabbit` installed and authenticated.
|
|
@@ -31,7 +31,7 @@ Both produce the same structured output format.
|
|
|
31
31
|
|
|
32
32
|
### Step 1: Determine Review Tool
|
|
33
33
|
|
|
34
|
-
Read `.
|
|
34
|
+
Read `.5/config.json` and check the `reviewTool` field.
|
|
35
35
|
|
|
36
36
|
- If not set or missing, default to `"claude"`
|
|
37
37
|
- If `"none"`, inform user that automated review is disabled and STOP
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 5:unlock
|
|
3
|
+
description: Remove the planning guard lock to allow edits outside the workflow
|
|
4
|
+
allowed-tools: Bash
|
|
5
|
+
context: inherit
|
|
6
|
+
user-invocable: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Unlock Planning Guard
|
|
10
|
+
|
|
11
|
+
Remove the `.planning-active` marker file that restricts Write/Edit operations during planning phases.
|
|
12
|
+
|
|
13
|
+
## Process
|
|
14
|
+
|
|
15
|
+
Run this bash command to check and remove the marker in one step:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
if [ -f .5/.planning-active ]; then rm .5/.planning-active && echo "REMOVED"; else echo "ABSENT"; fi
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Based on the output, confirm to the user:
|
|
22
|
+
- If output contains "REMOVED": "Planning guard removed. You can now edit files freely."
|
|
23
|
+
- If output contains "ABSENT": "No planning guard was active. You're already free to edit files."
|
package/src/commands/5/update.md
CHANGED
|
@@ -1,17 +1,54 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: 5:update
|
|
3
3
|
description: Update the 5-Phase Workflow to the latest version
|
|
4
|
-
allowed-tools: Bash
|
|
4
|
+
allowed-tools: Bash, Read, AskUserQuestion
|
|
5
5
|
context: inherit
|
|
6
6
|
user-invocable: true
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Update 5-Phase Workflow
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Step 1: Check Current Version
|
|
12
|
+
|
|
13
|
+
Read `.5/version.json` and note the current `installedVersion`.
|
|
14
|
+
|
|
15
|
+
## Step 2: Run Upgrade
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
|
-
npx 5-phase-workflow --upgrade
|
|
18
|
+
npx 5-phase-workflow@latest --upgrade
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
## Step 3: Confirm Upgrade
|
|
22
|
+
|
|
23
|
+
Read `.5/version.json` again. Compare the new `installedVersion` to the previous one.
|
|
24
|
+
|
|
25
|
+
- If the version **did not change**: tell the user they're already on the latest version. Stop here.
|
|
26
|
+
- If the version **changed**: continue to Step 4.
|
|
27
|
+
|
|
28
|
+
## Step 4: Show What Changed
|
|
29
|
+
|
|
30
|
+
Run `git status` to show the files modified by the upgrade. Summarize the changes for the user (e.g., "Updated 12 files in `.claude/commands/5/`, `.claude/skills/`, `.claude/hooks/`").
|
|
31
|
+
|
|
32
|
+
## Step 5: Ask to Commit
|
|
33
|
+
|
|
34
|
+
Ask the user: "Would you like to commit the upgraded workflow files?"
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
1. **Yes** - commit the changes
|
|
38
|
+
2. **No** - leave changes uncommitted
|
|
39
|
+
|
|
40
|
+
If the user chooses **No**, stop here.
|
|
41
|
+
|
|
42
|
+
## Step 6: Commit
|
|
43
|
+
|
|
44
|
+
Read `.5/config.json` if it exists and extract `git.commitMessage.pattern` (default: `{ticket-id} {short-description}`).
|
|
45
|
+
|
|
46
|
+
Build the commit message by applying the pattern:
|
|
47
|
+
- Replace `{ticket-id}` with an empty string (no ticket for upgrades) and trim any leading/trailing whitespace
|
|
48
|
+
- Replace `{short-description}` with `update 5-Phase Workflow to {new-version}`
|
|
49
|
+
- If the pattern is the conventional format (`feat({ticket-id}): {short-description}`), use: `chore: update 5-Phase Workflow to {new-version}`
|
|
50
|
+
- If no config or no pattern, use: `update 5-Phase Workflow to {new-version}`
|
|
51
|
+
|
|
52
|
+
Stage **only** the workflow-managed files shown in `git status` (inside `.claude/commands/5/`, `.claude/skills/`, `.claude/hooks/`, `.claude/templates/`, `.claude/settings.json`, and `.5/version.json`). Never use `git add .` or `git add -A`.
|
|
53
|
+
|
|
54
|
+
Create the commit. Report success to the user.
|
|
@@ -49,7 +49,7 @@ Note: feature.md not found — skipping feature completeness checks.
|
|
|
49
49
|
This is normal for quick-implement workflows. Infrastructure and quality checks will still run.
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Also read `.
|
|
52
|
+
Also read `.5/config.json` and extract:
|
|
53
53
|
- `git.autoCommit` (boolean, default `false`)
|
|
54
54
|
- `git.commitMessage.pattern` (string, default `{ticket-id} {short-description}`)
|
|
55
55
|
|
|
@@ -70,7 +70,7 @@ For each component in the plan:
|
|
|
70
70
|
|
|
71
71
|
#### 2b. Run Build
|
|
72
72
|
|
|
73
|
-
Execute the build command from the plan (or auto-detect from `.
|
|
73
|
+
Execute the build command from the plan (or auto-detect from `.5/config.json`):
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
76
|
{build-command}
|
|
@@ -23,7 +23,7 @@ process.stdin.on('end', () => {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
async function checkForUpdates(workspaceDir) {
|
|
26
|
-
const versionFile = path.join(workspaceDir, '.
|
|
26
|
+
const versionFile = path.join(workspaceDir, '.5', 'version.json');
|
|
27
27
|
|
|
28
28
|
// Check if version.json exists
|
|
29
29
|
if (!fs.existsSync(versionFile)) {
|
|
@@ -9,7 +9,7 @@ process.stdin.on('end', () => {
|
|
|
9
9
|
try {
|
|
10
10
|
const data = JSON.parse(input);
|
|
11
11
|
const cwd = data.cwd || process.cwd();
|
|
12
|
-
const configFile = path.join(cwd, '.
|
|
12
|
+
const configFile = path.join(cwd, '.5', 'config.json');
|
|
13
13
|
|
|
14
14
|
if (fs.existsSync(configFile)) {
|
|
15
15
|
process.exit(0);
|
package/src/hooks/plan-guard.js
CHANGED
|
@@ -26,6 +26,12 @@ process.stdin.on('end', () => {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const workspaceDir = data.cwd || data.workspace?.current_dir || process.cwd();
|
|
29
|
+
|
|
30
|
+
// If no planning phase is active, allow all tools
|
|
31
|
+
if (!isPlanningActive(workspaceDir)) {
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
const toolInput = data.tool_input || {};
|
|
30
36
|
|
|
31
37
|
// Determine which feature is being targeted and check its state
|
|
@@ -41,7 +47,8 @@ process.stdin.on('end', () => {
|
|
|
41
47
|
process.stderr.write(
|
|
42
48
|
`BLOCKED: Only Explore agents are allowed during planning phases. ` +
|
|
43
49
|
`Attempted: subagent_type="${agentType}". ` +
|
|
44
|
-
`To use other agent types, start implementation with /5:implement-feature
|
|
50
|
+
`To use other agent types, start implementation with /5:implement-feature. ` +
|
|
51
|
+
`If you're not in a planning phase, run /5:unlock to clear the planning lock.`
|
|
45
52
|
);
|
|
46
53
|
process.exit(2);
|
|
47
54
|
}
|
|
@@ -54,7 +61,8 @@ process.stdin.on('end', () => {
|
|
|
54
61
|
`BLOCKED: ${toolName} outside .5/ is not allowed during planning phases. ` +
|
|
55
62
|
`Attempted: "${filePath}". ` +
|
|
56
63
|
`Planning commands may only write to .5/features/. ` +
|
|
57
|
-
`To modify source files, start implementation with /5:implement-feature
|
|
64
|
+
`To modify source files, start implementation with /5:implement-feature. ` +
|
|
65
|
+
`If you're not in a planning phase, run /5:unlock to clear the planning lock.`
|
|
58
66
|
);
|
|
59
67
|
process.exit(2);
|
|
60
68
|
}
|
|
@@ -70,23 +78,20 @@ process.stdin.on('end', () => {
|
|
|
70
78
|
function isInsideDotFive(filePath, workspaceDir) {
|
|
71
79
|
const resolved = path.resolve(workspaceDir, filePath);
|
|
72
80
|
const dotFiveDir = path.join(workspaceDir, '.5');
|
|
73
|
-
const claudeDotFiveDir = path.join(workspaceDir, '.claude', '.5');
|
|
74
81
|
return resolved.startsWith(dotFiveDir + path.sep) ||
|
|
75
|
-
resolved
|
|
76
|
-
resolved === dotFiveDir ||
|
|
77
|
-
resolved === claudeDotFiveDir;
|
|
82
|
+
resolved === dotFiveDir;
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
function getTargetFeature(toolName, toolInput, workspaceDir) {
|
|
81
86
|
// Extract the feature name from the tool input context
|
|
82
|
-
const featuresDir = path.join(workspaceDir, '.
|
|
87
|
+
const featuresDir = path.join(workspaceDir, '.5', 'features');
|
|
83
88
|
|
|
84
89
|
if (toolName === 'Write' || toolName === 'Edit') {
|
|
85
90
|
// Check if the file path is inside a feature directory
|
|
86
91
|
const filePath = toolInput.file_path || '';
|
|
87
92
|
const resolved = path.resolve(workspaceDir, filePath);
|
|
88
93
|
if (resolved.startsWith(featuresDir + path.sep)) {
|
|
89
|
-
// Extract feature name: .
|
|
94
|
+
// Extract feature name: .5/features/{feature-name}/...
|
|
90
95
|
const relative = resolved.slice(featuresDir.length + 1);
|
|
91
96
|
const featureName = relative.split(path.sep)[0];
|
|
92
97
|
if (featureName) return featureName;
|
|
@@ -118,10 +123,28 @@ function getTargetFeature(toolName, toolInput, workspaceDir) {
|
|
|
118
123
|
return null;
|
|
119
124
|
}
|
|
120
125
|
|
|
126
|
+
function isPlanningActive(workspaceDir) {
|
|
127
|
+
const markerPath = path.join(workspaceDir, '.5', '.planning-active');
|
|
128
|
+
if (!fs.existsSync(markerPath)) return false;
|
|
129
|
+
try {
|
|
130
|
+
const marker = JSON.parse(fs.readFileSync(markerPath, 'utf8'));
|
|
131
|
+
if (marker.startedAt) {
|
|
132
|
+
const elapsed = Date.now() - new Date(marker.startedAt).getTime();
|
|
133
|
+
if (elapsed > 4 * 60 * 60 * 1000) {
|
|
134
|
+
try { fs.unlinkSync(markerPath); } catch (e) {}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
} catch (e) {
|
|
140
|
+
return true; // Unreadable marker → fail-safe, assume active
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
121
144
|
function isFeatureInImplementationMode(workspaceDir, featureName) {
|
|
122
145
|
// Check if this specific feature has a state.json (created in Phase 3)
|
|
123
146
|
const stateFile = path.join(
|
|
124
|
-
workspaceDir, '.
|
|
147
|
+
workspaceDir, '.5', 'features', featureName, 'state.json'
|
|
125
148
|
);
|
|
126
149
|
return fs.existsSync(stateFile);
|
|
127
150
|
}
|
package/src/hooks/statusline.js
CHANGED
|
@@ -46,7 +46,7 @@ process.stdin.on('end', () => {
|
|
|
46
46
|
// Check for available update
|
|
47
47
|
let updateIndicator = '';
|
|
48
48
|
try {
|
|
49
|
-
const versionFile = path.join(dir, '.
|
|
49
|
+
const versionFile = path.join(dir, '.5', 'version.json');
|
|
50
50
|
const versionData = JSON.parse(fs.readFileSync(versionFile, 'utf8'));
|
|
51
51
|
const latest = versionData.latestAvailableVersion;
|
|
52
52
|
const installed = versionData.installedVersion;
|
|
@@ -17,7 +17,7 @@ This skill executes build tasks with auto-detection of the build system and suff
|
|
|
17
17
|
|
|
18
18
|
The skill automatically detects the build system using:
|
|
19
19
|
|
|
20
|
-
1. **Config file** (`.
|
|
20
|
+
1. **Config file** (`.5/config.json`) - if `build.command` is specified
|
|
21
21
|
2. **Auto-detection** - by examining project files:
|
|
22
22
|
- `package.json` → npm/yarn/pnpm
|
|
23
23
|
- `build.gradle` or `build.gradle.kts` → Gradle
|
|
@@ -46,7 +46,7 @@ When invoked, the skill expects:
|
|
|
46
46
|
|
|
47
47
|
### 1. Load Configuration
|
|
48
48
|
|
|
49
|
-
Read `.
|
|
49
|
+
Read `.5/config.json` if it exists:
|
|
50
50
|
|
|
51
51
|
```json
|
|
52
52
|
{
|
|
@@ -17,7 +17,7 @@ This skill executes test tasks with auto-detection of the test runner and suffic
|
|
|
17
17
|
|
|
18
18
|
The skill automatically detects the test runner using:
|
|
19
19
|
|
|
20
|
-
1. **Config file** (`.
|
|
20
|
+
1. **Config file** (`.5/config.json`) - if `build.testCommand` is specified
|
|
21
21
|
2. **Auto-detection** - by examining project files and package.json scripts:
|
|
22
22
|
- `package.json` with jest/vitest/mocha → npm test
|
|
23
23
|
- `pytest.ini` or test files → pytest
|
|
@@ -49,7 +49,7 @@ When invoked, the skill expects:
|
|
|
49
49
|
|
|
50
50
|
### 1. Load Configuration
|
|
51
51
|
|
|
52
|
-
Read `.
|
|
52
|
+
Read `.5/config.json` if it exists:
|
|
53
53
|
|
|
54
54
|
```json
|
|
55
55
|
{
|