create-claude-cabinet 0.27.2 → 0.27.3
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/lib/cli.js +22 -3
- package/lib/copy.js +14 -10
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -697,8 +697,13 @@ async function run() {
|
|
|
697
697
|
if (dirState === 'existing-install') {
|
|
698
698
|
const existing = readMetadata(projectDir);
|
|
699
699
|
existingManifest = existing.manifest || {};
|
|
700
|
-
|
|
701
|
-
|
|
700
|
+
if (existing.version) {
|
|
701
|
+
const installedDate = existing.installedAt ? existing.installedAt.split('T')[0] : 'unknown';
|
|
702
|
+
console.log(` Found existing installation (v${existing.version}, installed ${installedDate})`);
|
|
703
|
+
console.log(' Updating upstream-managed files and adding new files.');
|
|
704
|
+
} else {
|
|
705
|
+
console.log(' Found .ccrc.json (migration-only, no prior install). Installing fresh.');
|
|
706
|
+
}
|
|
702
707
|
if (!flags.yes && !flags.lean) {
|
|
703
708
|
const { proceed } = await prompts({
|
|
704
709
|
type: 'confirm',
|
|
@@ -948,12 +953,23 @@ async function run() {
|
|
|
948
953
|
'skills/verify',
|
|
949
954
|
];
|
|
950
955
|
const isSkill = tmpl.startsWith('skills/') && !alwaysCopyPhases.some(p => tmpl.startsWith(p));
|
|
956
|
+
// Instruction phases listed in MODULES as explicit file paths
|
|
957
|
+
// under this skill dir must bypass the phase-file guard in copy.js.
|
|
958
|
+
const instrPhases = new Set();
|
|
959
|
+
for (const mod of Object.values(MODULES)) {
|
|
960
|
+
for (const t of (mod.templates || [])) {
|
|
961
|
+
if (t.startsWith(tmpl + '/') && t.includes('/phases/')) {
|
|
962
|
+
instrPhases.add(t.slice(tmpl.length + 1));
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
951
966
|
const results = await copyTemplates(srcPath, destPath, {
|
|
952
967
|
dryRun: flags.dryRun,
|
|
953
968
|
skipConflicts: flags.yes || dirState === 'existing-install',
|
|
954
969
|
skipPhases: isSkill,
|
|
955
970
|
projectRoot: projectDir,
|
|
956
971
|
existingManifest,
|
|
972
|
+
instructionPhases: instrPhases,
|
|
957
973
|
});
|
|
958
974
|
totalCopied += results.copied.length;
|
|
959
975
|
totalSkipped += results.skipped.length;
|
|
@@ -986,8 +1002,11 @@ async function run() {
|
|
|
986
1002
|
// file and the on-disk content differs from upstream (operator
|
|
987
1003
|
// edited it), preserve it. This keeps the documented "customize
|
|
988
1004
|
// by editing the phase file" affordance intact across upgrades.
|
|
1005
|
+
// Exception: instruction phases explicitly listed in MODULES are
|
|
1006
|
+
// CC-owned and must always overwrite (they're not customizable).
|
|
989
1007
|
const isPhaseFile = tmpl.includes('/phases/') || tmpl.includes('\\phases\\');
|
|
990
|
-
|
|
1008
|
+
const isInstructionPhase = isPhaseFile && mod.templates.includes(tmpl);
|
|
1009
|
+
if (isPhaseFile && !isInstructionPhase && existingContent.trim() !== '' && existingContent.trim() !== incoming.trim()) {
|
|
991
1010
|
console.log(` Preserved customized phase: ${tmpl}`);
|
|
992
1011
|
totalSkipped++;
|
|
993
1012
|
allManifest[mPath] = hashContent(existingContent);
|
package/lib/copy.js
CHANGED
|
@@ -11,13 +11,13 @@ function hashContent(content) {
|
|
|
11
11
|
* Recursively copy files from src to dest, surfacing conflicts.
|
|
12
12
|
* Returns { copied: string[], skipped: string[], overwritten: string[] }
|
|
13
13
|
*/
|
|
14
|
-
async function copyTemplates(src, dest, { dryRun = false, skipConflicts = false, skipPhases = false, projectRoot = null, existingManifest = {} } = {}) {
|
|
14
|
+
async function copyTemplates(src, dest, { dryRun = false, skipConflicts = false, skipPhases = false, projectRoot = null, existingManifest = {}, instructionPhases = new Set() } = {}) {
|
|
15
15
|
const results = { copied: [], skipped: [], overwritten: [], manifest: {} };
|
|
16
|
-
await walkAndCopy(src, dest, src, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest);
|
|
16
|
+
await walkAndCopy(src, dest, src, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest, instructionPhases);
|
|
17
17
|
return results;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest) {
|
|
20
|
+
async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest, instructionPhases) {
|
|
21
21
|
const entries = fs.readdirSync(currentSrc, { withFileTypes: true });
|
|
22
22
|
|
|
23
23
|
for (const entry of entries) {
|
|
@@ -37,7 +37,7 @@ async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipC
|
|
|
37
37
|
if (!dryRun && !fs.existsSync(destPath)) {
|
|
38
38
|
fs.mkdirSync(destPath, { recursive: true });
|
|
39
39
|
}
|
|
40
|
-
await walkAndCopy(srcRoot, destRoot, srcPath, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest);
|
|
40
|
+
await walkAndCopy(srcRoot, destRoot, srcPath, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest, instructionPhases);
|
|
41
41
|
} else {
|
|
42
42
|
const incoming = fs.readFileSync(srcPath, 'utf8');
|
|
43
43
|
const incomingHash = hashContent(incoming);
|
|
@@ -48,13 +48,17 @@ async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipC
|
|
|
48
48
|
// Phase file guard (act:98d74381) — independent of skipPhases flag.
|
|
49
49
|
// If a phase file on disk has been customized (differs from template
|
|
50
50
|
// and isn't empty), never overwrite it regardless of other flags.
|
|
51
|
+
// Exception: instruction phases (CC-owned, always overwrite) are
|
|
52
|
+
// exempt — they ship updated content that consumers must receive.
|
|
51
53
|
if (relPath.includes('phases' + path.sep) || relPath.includes('phases/')) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
if (!instructionPhases.has(relPath)) {
|
|
55
|
+
const trimmedExisting = existing.trim();
|
|
56
|
+
if (trimmedExisting !== '' && trimmedExisting !== incoming.trim()) {
|
|
57
|
+
results.skipped.push(relPath);
|
|
58
|
+
results.manifest[relPath] = hashContent(existing);
|
|
59
|
+
console.log(` Preserved customized phase: ${displayPath}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
|
package/package.json
CHANGED