5-phase-workflow 1.8.1 → 1.8.2
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/bin/install.js +114 -3
- package/package.json +1 -1
package/bin/install.js
CHANGED
|
@@ -248,6 +248,19 @@ function removeDir(dir) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
// Files removed from the package before manifest tracking existed.
|
|
252
|
+
// This list is frozen — future removals are handled by manifest diffing.
|
|
253
|
+
const LEGACY_REMOVED_FILES = [
|
|
254
|
+
'agents/feature-planner.md',
|
|
255
|
+
'agents/implementation-planner.md',
|
|
256
|
+
'agents/review-processor.md',
|
|
257
|
+
'agents/step-executor.md',
|
|
258
|
+
'agents/integration-agent.md',
|
|
259
|
+
'agents/step-fixer.md',
|
|
260
|
+
'agents/step-verifier.md',
|
|
261
|
+
'agents/verification-agent.md'
|
|
262
|
+
];
|
|
263
|
+
|
|
251
264
|
// Get list of workflow-owned files/directories (not user-created)
|
|
252
265
|
function getWorkflowManagedFiles() {
|
|
253
266
|
return {
|
|
@@ -303,6 +316,46 @@ function getWorkflowManagedFiles() {
|
|
|
303
316
|
};
|
|
304
317
|
}
|
|
305
318
|
|
|
319
|
+
// Flatten getWorkflowManagedFiles() into a list of relative paths (relative to .claude/)
|
|
320
|
+
function getFileManifest() {
|
|
321
|
+
const managed = getWorkflowManagedFiles();
|
|
322
|
+
const manifest = [];
|
|
323
|
+
|
|
324
|
+
// Commands are directories
|
|
325
|
+
for (const cmd of managed.commands) {
|
|
326
|
+
manifest.push(`commands/${cmd}`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Agents are files
|
|
330
|
+
for (const agent of managed.agents) {
|
|
331
|
+
manifest.push(`agents/${agent}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Skills are directories
|
|
335
|
+
for (const skill of managed.skills) {
|
|
336
|
+
manifest.push(`skills/${skill}`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Hooks are files
|
|
340
|
+
for (const hook of managed.hooks) {
|
|
341
|
+
manifest.push(`hooks/${hook}`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Templates are files (may include nested paths like workflow/FEATURE-SPEC.md)
|
|
345
|
+
for (const template of managed.templates) {
|
|
346
|
+
manifest.push(`templates/${template}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// References are files
|
|
350
|
+
if (managed.references) {
|
|
351
|
+
for (const ref of managed.references) {
|
|
352
|
+
manifest.push(`references/${ref}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return manifest;
|
|
357
|
+
}
|
|
358
|
+
|
|
306
359
|
// Selectively update only workflow-managed files, preserve user content
|
|
307
360
|
function selectiveUpdate(targetPath, sourcePath) {
|
|
308
361
|
const managed = getWorkflowManagedFiles();
|
|
@@ -406,6 +459,50 @@ function selectiveUpdate(targetPath, sourcePath) {
|
|
|
406
459
|
}
|
|
407
460
|
}
|
|
408
461
|
|
|
462
|
+
// Clean up files that were previously installed but are no longer managed
|
|
463
|
+
function cleanupOrphanedFiles(targetPath, dataDir) {
|
|
464
|
+
const versionFile = path.join(dataDir, 'version.json');
|
|
465
|
+
const currentManifest = getFileManifest();
|
|
466
|
+
const currentSet = new Set(currentManifest);
|
|
467
|
+
|
|
468
|
+
let oldManifest = null;
|
|
469
|
+
if (fs.existsSync(versionFile)) {
|
|
470
|
+
try {
|
|
471
|
+
const data = JSON.parse(fs.readFileSync(versionFile, 'utf8'));
|
|
472
|
+
oldManifest = data.manifest || null;
|
|
473
|
+
} catch (e) {
|
|
474
|
+
// Corrupted file, treat as no manifest
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (oldManifest) {
|
|
479
|
+
// Manifest exists: diff old vs current, delete orphans
|
|
480
|
+
for (const entry of oldManifest) {
|
|
481
|
+
if (!currentSet.has(entry)) {
|
|
482
|
+
const fullPath = path.join(targetPath, entry);
|
|
483
|
+
if (fs.existsSync(fullPath)) {
|
|
484
|
+
const stat = fs.statSync(fullPath);
|
|
485
|
+
if (stat.isDirectory()) {
|
|
486
|
+
removeDir(fullPath);
|
|
487
|
+
} else {
|
|
488
|
+
fs.unlinkSync(fullPath);
|
|
489
|
+
}
|
|
490
|
+
log.info(`Removed orphaned: ${entry}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
// No manifest (legacy upgrade): use static legacy removals list
|
|
496
|
+
for (const entry of LEGACY_REMOVED_FILES) {
|
|
497
|
+
const fullPath = path.join(targetPath, entry);
|
|
498
|
+
if (fs.existsSync(fullPath)) {
|
|
499
|
+
fs.unlinkSync(fullPath);
|
|
500
|
+
log.info(`Removed legacy orphan: ${entry}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
409
506
|
// Ensure .5/.gitignore exists and contains .update-cache.json
|
|
410
507
|
function ensureDotFiveGitignore(dataDir) {
|
|
411
508
|
const gitignorePath = path.join(dataDir, '.gitignore');
|
|
@@ -436,7 +533,8 @@ function initializeVersionJson(isGlobal) {
|
|
|
436
533
|
packageVersion: version,
|
|
437
534
|
installedAt: now,
|
|
438
535
|
lastUpdated: now,
|
|
439
|
-
installationType: isGlobal ? 'global' : 'local'
|
|
536
|
+
installationType: isGlobal ? 'global' : 'local',
|
|
537
|
+
manifest: getFileManifest()
|
|
440
538
|
};
|
|
441
539
|
|
|
442
540
|
fs.writeFileSync(versionFile, JSON.stringify(versionData, null, 2));
|
|
@@ -583,11 +681,14 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
583
681
|
// Selectively update only workflow-managed files (preserves user content)
|
|
584
682
|
selectiveUpdate(targetPath, sourcePath);
|
|
585
683
|
|
|
684
|
+
// Clean up orphaned files from previous versions
|
|
685
|
+
const dataDir = getDataPath(isGlobal);
|
|
686
|
+
cleanupOrphanedFiles(targetPath, dataDir);
|
|
687
|
+
|
|
586
688
|
// Merge settings (deep merge preserves user customizations)
|
|
587
689
|
mergeSettings(targetPath, sourcePath);
|
|
588
690
|
|
|
589
691
|
// Update version.json
|
|
590
|
-
const dataDir = getDataPath(isGlobal);
|
|
591
692
|
const versionFile = path.join(dataDir, 'version.json');
|
|
592
693
|
const now = new Date().toISOString();
|
|
593
694
|
|
|
@@ -598,7 +699,8 @@ function performUpdate(targetPath, sourcePath, isGlobal, versionInfo) {
|
|
|
598
699
|
packageVersion: versionInfo.available,
|
|
599
700
|
installedAt: existing.installedAt || now,
|
|
600
701
|
lastUpdated: now,
|
|
601
|
-
installationType: existing.installationType || (isGlobal ? 'global' : 'local')
|
|
702
|
+
installationType: existing.installationType || (isGlobal ? 'global' : 'local'),
|
|
703
|
+
manifest: getFileManifest()
|
|
602
704
|
};
|
|
603
705
|
|
|
604
706
|
if (!fs.existsSync(dataDir)) {
|
|
@@ -690,6 +792,15 @@ function uninstall() {
|
|
|
690
792
|
|
|
691
793
|
const managed = getWorkflowManagedFiles();
|
|
692
794
|
|
|
795
|
+
// Remove legacy orphaned files that may still exist from older versions
|
|
796
|
+
for (const entry of LEGACY_REMOVED_FILES) {
|
|
797
|
+
const fullPath = path.join(targetPath, entry);
|
|
798
|
+
if (fs.existsSync(fullPath)) {
|
|
799
|
+
fs.unlinkSync(fullPath);
|
|
800
|
+
log.info(`Removed legacy orphan: ${entry}`);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
693
804
|
// Remove commands/5/ (workflow namespace only)
|
|
694
805
|
const commands5 = path.join(targetPath, 'commands', '5');
|
|
695
806
|
if (fs.existsSync(commands5)) {
|