Skip to content

Commit c522197

Browse files
fix(cli): implement --force flag to protect existing skill files (#324)
The --force option was accepted by Commander but ignored: writeFile() always overwrote existing files silently. Users expecting protection against accidental overwrites had no way to preserve existing configs. - generatePlatformFiles: check file existence before writing; skip with a clear message when file exists and force=false - generateAllPlatformFiles / templateInstall: propagate force parameter - initCommand: pass options.force through to templateInstall Behavior change: uipro init --ai claude → skips if SKILL.md already exists uipro init --ai claude --force → overwrites regardless Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 71d02ec commit c522197

2 files changed

Lines changed: 16 additions & 7 deletions

File tree

cli/src/commands/init.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,18 @@ async function templateInstall(
101101
targetDir: string,
102102
aiType: AIType,
103103
spinner: ReturnType<typeof ora>,
104-
isGlobal = false
104+
isGlobal = false,
105+
force = false
105106
): Promise<string[]> {
106107
spinner.text = isGlobal
107108
? 'Generating skill files globally...'
108109
: 'Generating skill files from templates...';
109110

110111
if (aiType === 'all') {
111-
return generateAllPlatformFiles(targetDir, isGlobal);
112+
return generateAllPlatformFiles(targetDir, isGlobal, force);
112113
}
113114

114-
return generatePlatformFiles(targetDir, aiType, isGlobal);
115+
return generatePlatformFiles(targetDir, aiType, isGlobal, force);
115116
}
116117

117118
export async function initCommand(options: InitOptions): Promise<void> {
@@ -178,7 +179,7 @@ export async function initCommand(options: InitOptions): Promise<void> {
178179
}
179180
} else {
180181
// Use new template-based generation (default)
181-
copiedFolders = await templateInstall(cwd, aiType, spinner, isGlobal);
182+
copiedFolders = await templateInstall(cwd, aiType, spinner, isGlobal, options.force);
182183
installMethod = 'template';
183184
}
184185

cli/src/utils/template.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ async function copyDataAndScripts(targetSkillDir: string): Promise<void> {
187187
export async function generatePlatformFiles(
188188
targetDir: string,
189189
aiType: string,
190-
isGlobal = false
190+
isGlobal = false,
191+
force = false
191192
): Promise<string[]> {
192193
const config = await loadPlatformConfig(aiType);
193194
const createdFolders: string[] = [];
@@ -208,6 +209,13 @@ export async function generatePlatformFiles(
208209
// Render and write skill file (pass isGlobal to adjust paths)
209210
const skillContent = await renderSkillFile(config, isGlobal);
210211
const skillFilePath = join(skillDir, config.folderStructure.filename);
212+
213+
const fileAlreadyExists = await exists(skillFilePath);
214+
if (fileAlreadyExists && !force) {
215+
console.log(` Skipped (already exists): ${skillFilePath} — use --force to overwrite`);
216+
return [];
217+
}
218+
211219
await writeFile(skillFilePath, skillContent, 'utf-8');
212220
createdFolders.push(config.folderStructure.root);
213221

@@ -220,12 +228,12 @@ export async function generatePlatformFiles(
220228
/**
221229
* Generate files for all AI types
222230
*/
223-
export async function generateAllPlatformFiles(targetDir: string, isGlobal = false): Promise<string[]> {
231+
export async function generateAllPlatformFiles(targetDir: string, isGlobal = false, force = false): Promise<string[]> {
224232
const allFolders = new Set<string>();
225233

226234
for (const aiType of Object.keys(AI_TO_PLATFORM)) {
227235
try {
228-
const folders = await generatePlatformFiles(targetDir, aiType, isGlobal);
236+
const folders = await generatePlatformFiles(targetDir, aiType, isGlobal, force);
229237
folders.forEach(f => allFolders.add(f));
230238
} catch {
231239
// Skip if generation fails for a platform

0 commit comments

Comments
 (0)