create-claude-rails 0.4.0 → 0.4.1
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 +12 -3
- package/lib/copy.js +18 -6
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -183,10 +183,12 @@ async function run() {
|
|
|
183
183
|
// --- Directory detection ---
|
|
184
184
|
const dirState = detectProjectState(projectDir);
|
|
185
185
|
|
|
186
|
+
let existingManifest = {};
|
|
186
187
|
if (dirState === 'existing-install') {
|
|
187
188
|
const existing = readMetadata(projectDir);
|
|
189
|
+
existingManifest = existing.manifest || {};
|
|
188
190
|
console.log(` Found existing installation (v${existing.version}, installed ${existing.installedAt.split('T')[0]})`);
|
|
189
|
-
console.log('
|
|
191
|
+
console.log(' Updating upstream-managed files and adding new files.');
|
|
190
192
|
if (!flags.yes && !flags.lean) {
|
|
191
193
|
const { proceed } = await prompts({
|
|
192
194
|
type: 'confirm',
|
|
@@ -401,6 +403,7 @@ async function run() {
|
|
|
401
403
|
skipConflicts: flags.yes || dirState === 'existing-install',
|
|
402
404
|
skipPhases: isSkill,
|
|
403
405
|
projectRoot: projectDir,
|
|
406
|
+
existingManifest,
|
|
404
407
|
});
|
|
405
408
|
totalCopied += results.copied.length;
|
|
406
409
|
totalSkipped += results.skipped.length;
|
|
@@ -429,8 +432,14 @@ async function run() {
|
|
|
429
432
|
}
|
|
430
433
|
|
|
431
434
|
if (flags.yes || dirState === 'existing-install') {
|
|
432
|
-
//
|
|
433
|
-
|
|
435
|
+
// If file is in the old manifest, it's upstream-managed — overwrite.
|
|
436
|
+
// If not, it's project-created — skip.
|
|
437
|
+
if (existingManifest[mPath]) {
|
|
438
|
+
if (!flags.dryRun) fs.copyFileSync(srcPath, destPath);
|
|
439
|
+
totalOverwritten++;
|
|
440
|
+
} else {
|
|
441
|
+
totalSkipped++;
|
|
442
|
+
}
|
|
434
443
|
allManifest[mPath] = incomingHash;
|
|
435
444
|
} else {
|
|
436
445
|
const response = await prompts({
|
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 } = {}) {
|
|
14
|
+
async function copyTemplates(src, dest, { dryRun = false, skipConflicts = false, skipPhases = false, projectRoot = null, existingManifest = {} } = {}) {
|
|
15
15
|
const results = { copied: [], skipped: [], overwritten: [], manifest: {} };
|
|
16
|
-
await walkAndCopy(src, dest, src, results, dryRun, skipConflicts, skipPhases, projectRoot);
|
|
16
|
+
await walkAndCopy(src, dest, src, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest);
|
|
17
17
|
return results;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipConflicts, skipPhases, projectRoot) {
|
|
20
|
+
async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest) {
|
|
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);
|
|
40
|
+
await walkAndCopy(srcRoot, destRoot, srcPath, results, dryRun, skipConflicts, skipPhases, projectRoot, existingManifest);
|
|
41
41
|
} else {
|
|
42
42
|
const incoming = fs.readFileSync(srcPath, 'utf8');
|
|
43
43
|
const incomingHash = hashContent(incoming);
|
|
@@ -52,8 +52,20 @@ async function walkAndCopy(srcRoot, destRoot, currentSrc, results, dryRun, skipC
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (skipConflicts) {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
// Check if file is upstream-managed (in the old manifest).
|
|
56
|
+
// If so, overwrite — it can't be customized (hook enforces this).
|
|
57
|
+
// If not, skip — it's project-created content.
|
|
58
|
+
const manifestKey = projectRoot
|
|
59
|
+
? path.relative(projectRoot, destPath)
|
|
60
|
+
: relPath;
|
|
61
|
+
if (existingManifest[manifestKey]) {
|
|
62
|
+
if (!dryRun) fs.copyFileSync(srcPath, destPath);
|
|
63
|
+
results.overwritten.push(relPath);
|
|
64
|
+
results.manifest[relPath] = incomingHash;
|
|
65
|
+
} else {
|
|
66
|
+
results.skipped.push(relPath);
|
|
67
|
+
results.manifest[relPath] = incomingHash;
|
|
68
|
+
}
|
|
57
69
|
continue;
|
|
58
70
|
}
|
|
59
71
|
|