ccsetup 1.0.5 → 1.0.6
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/create-project.js +190 -27
- package/package.json +1 -1
package/bin/create-project.js
CHANGED
|
@@ -2,44 +2,207 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
5
6
|
|
|
6
7
|
const projectName = process.argv[2] || '.';
|
|
7
8
|
const targetDir = path.resolve(process.cwd(), projectName);
|
|
8
9
|
const templateDir = path.join(__dirname, '..', 'template');
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
const rl = readline.createInterface({
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
output: process.stdout
|
|
14
|
+
});
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
function prompt(question) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
rl.question(question, (answer) => {
|
|
19
|
+
resolve(answer.toLowerCase().trim());
|
|
20
|
+
});
|
|
21
|
+
});
|
|
16
22
|
}
|
|
17
23
|
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
function normalizeConflictStrategy(input) {
|
|
25
|
+
const normalized = input.toLowerCase().trim();
|
|
26
|
+
|
|
27
|
+
// Accept abbreviations and variations
|
|
28
|
+
if (normalized === 's' || normalized === 'skip' || normalized === '1') return 'skip';
|
|
29
|
+
if (normalized === 'r' || normalized === 'rename' || normalized === '2') return 'rename';
|
|
30
|
+
if (normalized === 'o' || normalized === 'overwrite' || normalized === '3') return 'overwrite';
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function main() {
|
|
36
|
+
console.log(`Creating Claude Code project in ${targetDir}...`);
|
|
37
|
+
|
|
38
|
+
if (projectName !== '.') {
|
|
39
|
+
if (!fs.existsSync(targetDir)) {
|
|
40
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const fileConflicts = [];
|
|
45
|
+
const dirConflicts = [];
|
|
46
|
+
const allItems = [];
|
|
47
|
+
|
|
48
|
+
function scanTemplate(src, dest, relativePath = '') {
|
|
49
|
+
const exists = fs.existsSync(src);
|
|
50
|
+
const stats = exists && fs.statSync(src);
|
|
51
|
+
const isDirectory = exists && stats.isDirectory();
|
|
52
|
+
|
|
53
|
+
if (isDirectory) {
|
|
54
|
+
allItems.push({
|
|
55
|
+
src,
|
|
56
|
+
dest,
|
|
57
|
+
type: 'directory',
|
|
58
|
+
relativePath,
|
|
59
|
+
exists: fs.existsSync(dest)
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (fs.existsSync(dest)) {
|
|
63
|
+
dirConflicts.push(relativePath || '.');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fs.readdirSync(src).forEach(childItem => {
|
|
67
|
+
scanTemplate(
|
|
68
|
+
path.join(src, childItem),
|
|
69
|
+
path.join(dest, childItem),
|
|
70
|
+
path.join(relativePath, childItem)
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
} else {
|
|
74
|
+
allItems.push({
|
|
75
|
+
src,
|
|
76
|
+
dest,
|
|
77
|
+
type: 'file',
|
|
78
|
+
relativePath,
|
|
79
|
+
exists: fs.existsSync(dest)
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (fs.existsSync(dest)) {
|
|
83
|
+
fileConflicts.push(relativePath);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
scanTemplate(templateDir, targetDir);
|
|
89
|
+
|
|
90
|
+
let conflictStrategy = 'skip';
|
|
91
|
+
|
|
92
|
+
if (dirConflicts.length > 0) {
|
|
93
|
+
console.log('\n⚠️ The following directories already exist:');
|
|
94
|
+
dirConflicts.forEach(dir => console.log(` - ${dir}/`));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (fileConflicts.length > 0) {
|
|
98
|
+
console.log('\n⚠️ The following files already exist:');
|
|
99
|
+
fileConflicts.forEach(file => console.log(` - ${file}`));
|
|
100
|
+
|
|
101
|
+
console.log('\n📋 This choice will apply to ALL conflicting files listed above.');
|
|
102
|
+
console.log('\nConflict resolution options:');
|
|
103
|
+
console.log(' 1) skip (s) - Keep your existing files, only copy new files');
|
|
104
|
+
console.log(' 2) rename (r) - Keep your files, save template files with -ccsetup suffix');
|
|
105
|
+
console.log(' 3) overwrite (o) - Replace ALL existing files with template versions');
|
|
106
|
+
console.log('\nExamples: type "skip", "s", or "1" for the first option');
|
|
107
|
+
|
|
108
|
+
const userInput = await prompt('\nYour choice [skip/rename/overwrite or s/r/o]: ');
|
|
109
|
+
conflictStrategy = normalizeConflictStrategy(userInput);
|
|
110
|
+
|
|
111
|
+
if (!conflictStrategy) {
|
|
112
|
+
console.log(`\n❌ Invalid option: "${userInput}". Please use: skip/s/1, rename/r/2, or overwrite/o/3`);
|
|
113
|
+
rl.close();
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (conflictStrategy === 'overwrite') {
|
|
118
|
+
const confirm = await prompt('⚠️ Are you sure you want to overwrite existing files? This cannot be undone! (yes/no): ');
|
|
119
|
+
if (confirm !== 'yes') {
|
|
120
|
+
console.log('Operation cancelled.');
|
|
121
|
+
rl.close();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
}
|
|
26
124
|
}
|
|
27
|
-
fs.readdirSync(src).forEach(childItem => {
|
|
28
|
-
copyRecursive(path.join(src, childItem), path.join(dest, childItem));
|
|
29
|
-
});
|
|
30
|
-
} else {
|
|
31
|
-
fs.copyFileSync(src, dest);
|
|
32
125
|
}
|
|
33
|
-
}
|
|
34
126
|
|
|
35
|
-
|
|
127
|
+
const strategyDescriptions = {
|
|
128
|
+
skip: 'Keeping all existing files, copying only new files',
|
|
129
|
+
rename: 'Keeping existing files, saving templates with -ccsetup suffix',
|
|
130
|
+
overwrite: 'Replacing existing files with template versions'
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
console.log(`\n✨ ${strategyDescriptions[conflictStrategy]}...`);
|
|
134
|
+
|
|
135
|
+
let skippedCount = 0;
|
|
136
|
+
let copiedCount = 0;
|
|
137
|
+
let renamedCount = 0;
|
|
138
|
+
let overwrittenCount = 0;
|
|
139
|
+
|
|
140
|
+
for (const item of allItems) {
|
|
141
|
+
if (item.type === 'directory') {
|
|
142
|
+
if (!item.exists && !fs.existsSync(item.dest)) {
|
|
143
|
+
fs.mkdirSync(item.dest, { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
if (item.exists) {
|
|
147
|
+
if (conflictStrategy === 'skip') {
|
|
148
|
+
skippedCount++;
|
|
149
|
+
continue;
|
|
150
|
+
} else if (conflictStrategy === 'rename') {
|
|
151
|
+
const ext = path.extname(item.dest);
|
|
152
|
+
const baseName = path.basename(item.dest, ext);
|
|
153
|
+
const dirName = path.dirname(item.dest);
|
|
154
|
+
let newDest = path.join(dirName, `${baseName}-ccsetup${ext}`);
|
|
155
|
+
let counter = 1;
|
|
156
|
+
while (fs.existsSync(newDest)) {
|
|
157
|
+
newDest = path.join(dirName, `${baseName}-ccsetup-${counter}${ext}`);
|
|
158
|
+
counter++;
|
|
159
|
+
}
|
|
160
|
+
fs.copyFileSync(item.src, newDest);
|
|
161
|
+
renamedCount++;
|
|
162
|
+
console.log(` 📄 Created: ${path.relative(targetDir, newDest)}`);
|
|
163
|
+
} else if (conflictStrategy === 'overwrite') {
|
|
164
|
+
fs.copyFileSync(item.src, item.dest);
|
|
165
|
+
overwrittenCount++;
|
|
166
|
+
console.log(` ♻️ Replaced: ${item.relativePath}`);
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
fs.copyFileSync(item.src, item.dest);
|
|
170
|
+
copiedCount++;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
36
174
|
|
|
37
|
-
console.log('\n✅ Claude Code project created successfully!');
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
175
|
+
console.log('\n✅ Claude Code project created successfully!');
|
|
176
|
+
|
|
177
|
+
// Show summary of what happened
|
|
178
|
+
if (fileConflicts.length > 0 || copiedCount > 0) {
|
|
179
|
+
console.log('\n📊 Summary:');
|
|
180
|
+
if (copiedCount > 0) console.log(` ✨ ${copiedCount} new files copied`);
|
|
181
|
+
if (skippedCount > 0) console.log(` ⏭️ ${skippedCount} existing files kept unchanged`);
|
|
182
|
+
if (renamedCount > 0) console.log(` 📄 ${renamedCount} template files saved with -ccsetup suffix`);
|
|
183
|
+
if (overwrittenCount > 0) console.log(` ♻️ ${overwrittenCount} files replaced with template versions`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log('\nNext steps:');
|
|
187
|
+
if (projectName !== '.') {
|
|
188
|
+
console.log(` cd ${projectName}`);
|
|
189
|
+
}
|
|
190
|
+
console.log(' 1. Edit CLAUDE.md to add your project-specific instructions');
|
|
191
|
+
console.log(' 2. Update docs/ROADMAP.md with your project goals');
|
|
192
|
+
console.log(' 3. Start creating tickets in the tickets/ directory');
|
|
193
|
+
|
|
194
|
+
if (fileConflicts.length > 0 && conflictStrategy === 'rename') {
|
|
195
|
+
console.log('\n💡 Tip: Review the -ccsetup files to see template examples');
|
|
196
|
+
console.log(' You can compare them with your existing files or copy sections you need');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log('\nHappy coding with Claude! 🎉');
|
|
200
|
+
|
|
201
|
+
rl.close();
|
|
41
202
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
console.
|
|
45
|
-
|
|
203
|
+
|
|
204
|
+
main().catch(err => {
|
|
205
|
+
console.error('Error:', err);
|
|
206
|
+
rl.close();
|
|
207
|
+
process.exit(1);
|
|
208
|
+
});
|