5-phase-workflow 1.4.3 → 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 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 `.claude/.5/config.json`. Here's an example:
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 `.claude/.features/{ticket-id}.md`.
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 `.claude/.implementations/state/{ticket-id}.json` for resumability.
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
- └── configure.md
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
- └── statusline.js # Status line integration
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 `.claude/.5/config.json` with correct commands
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 `.claude/.implementations/state/{ticket-id}.json`
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 `.claude/.5/` are preserved
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
@@ -23,9 +23,10 @@ const log = {
23
23
  };
24
24
 
25
25
  // Version comparison (semver)
26
+ // Uses parseInt to handle pre-release tags (e.g., "2-beta" → 2)
26
27
  function compareVersions(v1, v2) {
27
- const parts1 = v1.split('.').map(Number);
28
- const parts2 = v2.split('.').map(Number);
28
+ const parts1 = v1.split('.').map(p => parseInt(p, 10) || 0);
29
+ const parts2 = v2.split('.').map(p => parseInt(p, 10) || 0);
29
30
  for (let i = 0; i < 3; i++) {
30
31
  if (parts1[i] > parts2[i]) return 1;
31
32
  if (parts1[i] < parts2[i]) return -1;
@@ -34,8 +35,8 @@ function compareVersions(v1, v2) {
34
35
  }
35
36
 
36
37
  // Get installed version from .5/version.json
37
- function getInstalledVersion(targetPath) {
38
- const versionFile = path.join(targetPath, '.5', 'version.json');
38
+ function getInstalledVersion(isGlobal) {
39
+ const versionFile = path.join(getDataPath(isGlobal), 'version.json');
39
40
  if (!fs.existsSync(versionFile)) return null;
40
41
 
41
42
  try {
@@ -54,13 +55,13 @@ function getPackageVersion() {
54
55
  }
55
56
 
56
57
  // Get full version info
57
- function getVersionInfo(targetPath) {
58
+ function getVersionInfo(targetPath, isGlobal) {
58
59
  const exists = checkExistingInstallation(targetPath);
59
60
  if (!exists) {
60
61
  return { exists: false };
61
62
  }
62
63
 
63
- const installed = getInstalledVersion(targetPath);
64
+ const installed = getInstalledVersion(isGlobal);
64
65
  const available = getPackageVersion();
65
66
 
66
67
  if (!installed) {
@@ -138,7 +139,7 @@ Examples:
138
139
  `);
139
140
  }
140
141
 
141
- // Get installation target path
142
+ // Get installation target path (.claude/ directory)
142
143
  function getTargetPath(isGlobal) {
143
144
  if (isGlobal) {
144
145
  const homeDir = process.env.HOME || process.env.USERPROFILE;
@@ -147,6 +148,60 @@ function getTargetPath(isGlobal) {
147
148
  return path.join(process.cwd(), '.claude');
148
149
  }
149
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
+
150
205
  // Get source path (package installation directory)
151
206
  function getSourcePath() {
152
207
  // When installed via npm, __dirname is <install-location>/bin
@@ -214,7 +269,8 @@ function getWorkflowManagedFiles() {
214
269
  hooks: [
215
270
  'statusline.js',
216
271
  'check-updates.js',
217
- 'plan-guard.js'
272
+ 'plan-guard.js',
273
+ 'config-guard.js'
218
274
  ],
219
275
 
220
276
  // Templates: specific template files
@@ -234,7 +290,6 @@ function getWorkflowManagedFiles() {
234
290
  'workflow/VERIFICATION-REPORT.md',
235
291
  'workflow/REVIEW-FINDINGS.md',
236
292
  'workflow/REVIEW-SUMMARY.md',
237
- 'workflow/QUICK-PLAN.md',
238
293
  'workflow/FIX-PLAN.md'
239
294
  ]
240
295
  };
@@ -255,20 +310,22 @@ function selectiveUpdate(targetPath, sourcePath) {
255
310
  log.success('Updated commands/5/');
256
311
  }
257
312
 
258
- // Update specific agents
259
- const agentsSrc = path.join(sourcePath, 'agents');
260
- const agentsDest = path.join(targetPath, 'agents');
261
- if (!fs.existsSync(agentsDest)) {
262
- fs.mkdirSync(agentsDest, { recursive: true });
263
- }
264
- for (const agent of managed.agents) {
265
- const src = path.join(agentsSrc, agent);
266
- const dest = path.join(agentsDest, agent);
267
- if (fs.existsSync(src)) {
268
- fs.copyFileSync(src, dest);
313
+ // Update specific agents (currently none — instructions are embedded inline in commands)
314
+ if (managed.agents.length > 0) {
315
+ const agentsSrc = path.join(sourcePath, 'agents');
316
+ const agentsDest = path.join(targetPath, 'agents');
317
+ if (!fs.existsSync(agentsDest)) {
318
+ fs.mkdirSync(agentsDest, { recursive: true });
269
319
  }
320
+ for (const agent of managed.agents) {
321
+ const src = path.join(agentsSrc, agent);
322
+ const dest = path.join(agentsDest, agent);
323
+ if (fs.existsSync(src)) {
324
+ fs.copyFileSync(src, dest);
325
+ }
326
+ }
327
+ log.success('Updated agents/ (workflow files only)');
270
328
  }
271
- log.success('Updated agents/ (workflow files only)');
272
329
 
273
330
  // Update specific skills
274
331
  const skillsSrc = path.join(sourcePath, 'skills');
@@ -324,175 +381,13 @@ function selectiveUpdate(targetPath, sourcePath) {
324
381
  log.success('Updated templates/ (workflow files only)');
325
382
  }
326
383
 
327
- // Detect project type by examining files in current directory
328
- function detectProjectType() {
329
- const cwd = process.cwd();
330
-
331
- if (fs.existsSync(path.join(cwd, 'package.json'))) {
332
- const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
333
- if (pkg.dependencies?.['next'] || pkg.devDependencies?.['next']) return 'nextjs';
334
- if (pkg.dependencies?.['express'] || pkg.devDependencies?.['express']) return 'express';
335
- if (pkg.dependencies?.['@nestjs/core']) return 'nestjs';
336
- return 'javascript';
337
- }
338
-
339
- if (fs.existsSync(path.join(cwd, 'build.gradle')) || fs.existsSync(path.join(cwd, 'build.gradle.kts'))) {
340
- return 'gradle-java';
341
- }
342
-
343
- if (fs.existsSync(path.join(cwd, 'pom.xml'))) {
344
- return 'maven-java';
345
- }
346
-
347
- if (fs.existsSync(path.join(cwd, 'Cargo.toml'))) {
348
- return 'rust';
349
- }
350
-
351
- if (fs.existsSync(path.join(cwd, 'go.mod'))) {
352
- return 'go';
353
- }
354
-
355
- if (fs.existsSync(path.join(cwd, 'requirements.txt')) || fs.existsSync(path.join(cwd, 'pyproject.toml'))) {
356
- const hasDjango = fs.existsSync(path.join(cwd, 'manage.py'));
357
- const hasFlask = fs.existsSync(path.join(cwd, 'app.py')) || fs.existsSync(path.join(cwd, 'wsgi.py'));
358
- if (hasDjango) return 'django';
359
- if (hasFlask) return 'flask';
360
- return 'python';
361
- }
362
-
363
- return 'unknown';
364
- }
365
-
366
- // Get default config based on project type
367
- function getDefaultConfig(projectType) {
368
- const baseConfig = {
369
- ticket: {
370
- pattern: '[A-Z]+-\\d+',
371
- extractFromBranch: true
372
- },
373
- build: {
374
- command: 'auto',
375
- testCommand: 'auto'
376
- },
377
- reviewTool: 'claude',
378
- git: {
379
- autoCommit: false,
380
- commitMessage: { pattern: '{ticket-id} {short-description}' }
381
- }
382
- };
383
-
384
- // Project-specific overrides
385
- const overrides = {
386
- 'gradle-java': {
387
- build: {
388
- command: './gradlew build -x test -x javadoc --offline',
389
- testCommand: './gradlew test --offline'
390
- }
391
- },
392
- 'maven-java': {
393
- build: {
394
- command: 'mvn compile',
395
- testCommand: 'mvn test'
396
- }
397
- },
398
- 'javascript': {
399
- build: {
400
- command: 'npm run build',
401
- testCommand: 'npm test'
402
- }
403
- },
404
- 'nextjs': {
405
- build: {
406
- command: 'npm run build',
407
- testCommand: 'npm test'
408
- }
409
- },
410
- 'express': {
411
- build: {
412
- command: 'npm run build || tsc',
413
- testCommand: 'npm test'
414
- }
415
- },
416
- 'nestjs': {
417
- build: {
418
- command: 'npm run build',
419
- testCommand: 'npm test'
420
- }
421
- },
422
- 'rust': {
423
- build: {
424
- command: 'cargo build',
425
- testCommand: 'cargo test'
426
- }
427
- },
428
- 'go': {
429
- build: {
430
- command: 'go build ./...',
431
- testCommand: 'go test ./...'
432
- }
433
- },
434
- 'python': {
435
- build: {
436
- command: 'python -m py_compile **/*.py',
437
- testCommand: 'pytest'
438
- }
439
- },
440
- 'django': {
441
- build: {
442
- command: 'python manage.py check',
443
- testCommand: 'python manage.py test'
444
- }
445
- },
446
- 'flask': {
447
- build: {
448
- command: 'python -m py_compile **/*.py',
449
- testCommand: 'pytest'
450
- }
451
- }
452
- };
453
-
454
- return {
455
- ...baseConfig,
456
- ...(overrides[projectType] || {}),
457
- projectType
458
- };
459
- }
460
-
461
- // Initialize config file
462
- function initializeConfig(targetPath) {
463
- const configDir = path.join(targetPath, '.5');
464
- const configFile = path.join(configDir, 'config.json');
465
-
466
- if (fs.existsSync(configFile)) {
467
- log.info('Config file already exists, skipping initialization');
468
- return;
469
- }
470
-
471
- if (!fs.existsSync(configDir)) {
472
- fs.mkdirSync(configDir, { recursive: true });
473
- }
474
-
475
- // Create features subdirectory
476
- const featuresDir = path.join(configDir, 'features');
477
- if (!fs.existsSync(featuresDir)) {
478
- fs.mkdirSync(featuresDir, { recursive: true });
479
- log.success('Created .5/features/ directory');
480
- }
481
-
482
- const projectType = detectProjectType();
483
- const config = getDefaultConfig(projectType);
484
-
485
- fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
486
- log.success(`Created config file with detected project type: ${projectType}`);
487
- }
488
-
489
384
  // Initialize version.json after successful install
490
- function initializeVersionJson(targetPath, isGlobal) {
491
- const configDir = path.join(targetPath, '.5');
492
- const versionFile = path.join(configDir, 'version.json');
385
+ function initializeVersionJson(isGlobal) {
386
+ const dataDir = getDataPath(isGlobal);
387
+ const versionFile = path.join(dataDir, 'version.json');
493
388
 
494
- if (!fs.existsSync(configDir)) {
495
- fs.mkdirSync(configDir, { recursive: true });
389
+ if (!fs.existsSync(dataDir)) {
390
+ fs.mkdirSync(dataDir, { recursive: true });
496
391
  }
497
392
 
498
393
  const version = getPackageVersion();
@@ -512,16 +407,42 @@ function initializeVersionJson(targetPath, isGlobal) {
512
407
  log.success('Initialized version tracking');
513
408
  }
514
409
 
410
+ // Merge hook arrays by matching on the command path.
411
+ // Keeps user overrides for existing hooks, adds new hooks from source.
412
+ function mergeHookArrays(targetArr, sourceArr) {
413
+ const result = [...targetArr];
414
+ for (const sourceEntry of sourceArr) {
415
+ const sourceCmd = sourceEntry.hooks?.[0]?.command || '';
416
+ const exists = result.some(entry => {
417
+ const cmd = entry.hooks?.[0]?.command || '';
418
+ return cmd === sourceCmd;
419
+ });
420
+ if (!exists) {
421
+ result.push(sourceEntry);
422
+ }
423
+ }
424
+ return result;
425
+ }
426
+
427
+ // Hook event keys that contain arrays of hook entries
428
+ const HOOK_ARRAY_KEYS = new Set([
429
+ 'PreToolUse', 'PostToolUse', 'SessionStart', 'SessionEnd',
430
+ 'PreCompact', 'PostCompact'
431
+ ]);
432
+
515
433
  // Deep merge for settings.json
516
- function deepMerge(target, source) {
434
+ function deepMerge(target, source, parentKey) {
517
435
  const result = { ...target };
518
436
 
519
437
  for (const key in source) {
520
438
  if (source[key] !== null && typeof source[key] === 'object' && !Array.isArray(source[key])) {
521
439
  // Recursively merge nested objects
522
- result[key] = deepMerge(result[key] || {}, source[key]);
440
+ result[key] = deepMerge(result[key] || {}, source[key], key);
441
+ } else if (Array.isArray(source[key]) && Array.isArray(result[key]) && HOOK_ARRAY_KEYS.has(key)) {
442
+ // Hook arrays: merge by command path to add new hooks
443
+ result[key] = mergeHookArrays(result[key], source[key]);
523
444
  } else {
524
- // For primitives and arrays: use source if target doesn't have it
445
+ // For primitives and non-hook arrays: use source if target doesn't have it
525
446
  if (!(key in result)) {
526
447
  result[key] = source[key];
527
448
  }
@@ -560,7 +481,7 @@ function checkExistingInstallation(targetPath) {
560
481
  }
561
482
 
562
483
  // Helper to show commands
563
- function showCommandsHelp(targetPath) {
484
+ function showCommandsHelp(isGlobal) {
564
485
  log.info('Available commands:');
565
486
  log.info(' /5:plan-feature - Start feature planning (Phase 1)');
566
487
  log.info(' /5:plan-implementation - Create implementation plan (Phase 2)');
@@ -568,8 +489,9 @@ function showCommandsHelp(targetPath) {
568
489
  log.info(' /5:verify-implementation - Verify implementation (Phase 4)');
569
490
  log.info(' /5:review-code - Code review (Phase 5)');
570
491
  log.info(' /5:configure - Interactive project setup');
492
+ log.info(' /5:unlock - Remove planning guard lock');
571
493
  log.info('');
572
- log.info(`Config file: ${path.join(targetPath, '.5', 'config.json')}`);
494
+ log.info(`Config file: ${path.join(getDataPath(isGlobal), 'config.json')}`);
573
495
  }
574
496
 
575
497
  // Fresh installation
@@ -596,7 +518,7 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
596
518
  mergeSettings(targetPath, sourcePath);
597
519
 
598
520
  // Initialize version tracking
599
- initializeVersionJson(targetPath, isGlobal);
521
+ initializeVersionJson(isGlobal);
600
522
 
601
523
  log.header('Installation Complete!');
602
524
  log.info('');
@@ -610,10 +532,10 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
610
532
  log.info(' • Create project-specific skills');
611
533
  log.info('');
612
534
 
613
- showCommandsHelp(targetPath);
535
+ showCommandsHelp(isGlobal);
614
536
  }
615
537
 
616
- // Perform update (preserves .5/ directory and user-created files)
538
+ // Perform update (preserves user-created files, updates .5/ data directory)
617
539
  function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
618
540
  log.header(`Updating from ${versionInfo.installed || 'legacy'} to ${versionInfo.available}`);
619
541
  log.info('Preserving user-created commands, agents, skills, and hooks');
@@ -625,8 +547,8 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
625
547
  mergeSettings(targetPath, sourcePath);
626
548
 
627
549
  // Update version.json
628
- const configDir = path.join(targetPath, '.5');
629
- const versionFile = path.join(configDir, 'version.json');
550
+ const dataDir = getDataPath(isGlobal);
551
+ const versionFile = path.join(dataDir, 'version.json');
630
552
 
631
553
  let versionData;
632
554
  if (fs.existsSync(versionFile)) {
@@ -644,22 +566,22 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
644
566
  versionData.installedVersion = versionInfo.available;
645
567
  versionData.lastUpdated = new Date().toISOString();
646
568
 
647
- if (!fs.existsSync(configDir)) {
648
- fs.mkdirSync(configDir, { recursive: true });
569
+ if (!fs.existsSync(dataDir)) {
570
+ fs.mkdirSync(dataDir, { recursive: true });
649
571
  }
650
572
  fs.writeFileSync(versionFile, JSON.stringify(versionData, null, 2));
651
573
 
652
574
  // Create features directory if it doesn't exist
653
- const featuresDir = path.join(configDir, 'features');
575
+ const featuresDir = path.join(dataDir, 'features');
654
576
  if (!fs.existsSync(featuresDir)) {
655
577
  fs.mkdirSync(featuresDir, { recursive: true });
656
- log.info('📁 Feature folders now nest under .5/features/');
657
- log.info('📋 See RELEASE_NOTES.md for migration if you have in-progress features');
578
+ log.info('Feature folders nest under .5/features/');
579
+ log.info('See RELEASE_NOTES.md for migration if you have in-progress features');
658
580
  }
659
581
 
660
582
  log.header('Update Complete!');
661
583
  log.success(`Now running version ${versionInfo.available}`);
662
- showCommandsHelp(targetPath);
584
+ showCommandsHelp(isGlobal);
663
585
  }
664
586
 
665
587
  // Perform installation
@@ -671,8 +593,11 @@ function install(isGlobal, forceUpgrade = false) {
671
593
  log.info(`Target: ${targetPath}`);
672
594
  log.info(`Source: ${sourcePath}`);
673
595
 
596
+ // Migrate data from old .claude/.5/ to new .5/ location
597
+ migrateDataDir(isGlobal);
598
+
674
599
  // Check for existing installation and version
675
- const versionInfo = getVersionInfo(targetPath);
600
+ const versionInfo = getVersionInfo(targetPath, isGlobal);
676
601
 
677
602
  if (versionInfo.exists) {
678
603
  if (versionInfo.legacy) {
@@ -727,21 +652,54 @@ function uninstall() {
727
652
  return;
728
653
  }
729
654
 
730
- // Remove directories
731
- const dirs = ['commands/5', 'agents', 'skills', 'hooks', 'templates'];
732
- for (const dir of dirs) {
733
- const fullPath = path.join(targetPath, dir);
734
- if (fs.existsSync(fullPath)) {
735
- removeDir(fullPath);
736
- log.success(`Removed ${dir}`);
655
+ const managed = getWorkflowManagedFiles();
656
+
657
+ // Remove commands/5/ (workflow namespace only)
658
+ const commands5 = path.join(targetPath, 'commands', '5');
659
+ if (fs.existsSync(commands5)) {
660
+ removeDir(commands5);
661
+ log.success('Removed commands/5/');
662
+ }
663
+
664
+ // Remove only workflow-managed skills
665
+ for (const skill of managed.skills) {
666
+ const skillPath = path.join(targetPath, 'skills', skill);
667
+ if (fs.existsSync(skillPath)) {
668
+ removeDir(skillPath);
669
+ }
670
+ }
671
+ log.success('Removed workflow skills (preserved user-created skills)');
672
+
673
+ // Remove only workflow-managed hooks
674
+ for (const hook of managed.hooks) {
675
+ const hookPath = path.join(targetPath, 'hooks', hook);
676
+ if (fs.existsSync(hookPath)) {
677
+ fs.unlinkSync(hookPath);
737
678
  }
738
679
  }
680
+ log.success('Removed workflow hooks (preserved user-created hooks)');
681
+
682
+ // Remove only workflow-managed templates
683
+ for (const template of managed.templates) {
684
+ const templatePath = path.join(targetPath, 'templates', template);
685
+ if (fs.existsSync(templatePath)) {
686
+ fs.unlinkSync(templatePath);
687
+ }
688
+ }
689
+ log.success('Removed workflow templates (preserved user-created templates)');
690
+
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
+ }
739
697
 
740
- // Remove config
741
- const configDir = path.join(targetPath, '.5');
742
- if (fs.existsSync(configDir)) {
743
- removeDir(configDir);
744
- log.success('Removed .5/ config directory');
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');
745
703
  }
746
704
 
747
705
  log.header('Uninstallation Complete!');
@@ -758,7 +716,8 @@ function main() {
758
716
 
759
717
  if (options.check) {
760
718
  const targetPath = getTargetPath(options.global);
761
- const versionInfo = getVersionInfo(targetPath);
719
+ migrateDataDir(options.global);
720
+ const versionInfo = getVersionInfo(targetPath, options.global);
762
721
 
763
722
  if (!versionInfo.exists) {
764
723
  log.info('Not installed');
@@ -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
- - `.claude/.5/config.json` with your project settings
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 `.claude/.5/config.json`
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 `.claude/.5/config.json` and can be customized using the `/5:configure` command.
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 `.claude/.5/config.json` to customize:
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "5-phase-workflow",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "A 5-phase feature development workflow for Claude Code",
5
5
  "bin": {
6
6
  "5-phase-workflow": "bin/install.js"