claudekit-cli 3.7.1 → 3.8.0

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.
Files changed (2) hide show
  1. package/dist/index.js +292 -87
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6324,6 +6324,7 @@ var init_types2 = __esm(() => {
6324
6324
  beta: exports_external.boolean().default(false),
6325
6325
  dryRun: exports_external.boolean().default(false),
6326
6326
  forceOverwrite: exports_external.boolean().default(false),
6327
+ forceOverwriteSettings: exports_external.boolean().default(false),
6327
6328
  skipSetup: exports_external.boolean().default(false),
6328
6329
  refresh: exports_external.boolean().default(false),
6329
6330
  docsDir: exports_external.string().optional(),
@@ -13157,7 +13158,7 @@ async function installSkillsDependencies(skillsDir) {
13157
13158
  }
13158
13159
  try {
13159
13160
  const { existsSync: existsSync6 } = await import("node:fs");
13160
- const { readFile: readFile11 } = await import("node:fs/promises");
13161
+ const { readFile: readFile12 } = await import("node:fs/promises");
13161
13162
  const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
13162
13163
  const platform9 = process.platform;
13163
13164
  const scriptName = platform9 === "win32" ? "install.ps1" : "install.sh";
@@ -13193,7 +13194,7 @@ async function installSkillsDependencies(skillsDir) {
13193
13194
  logger.info(` Platform: ${platform9 === "win32" ? "Windows (PowerShell)" : "Unix (bash)"}`);
13194
13195
  logger.info("");
13195
13196
  try {
13196
- const scriptContent = await readFile11(scriptPath, "utf-8");
13197
+ const scriptContent = await readFile12(scriptPath, "utf-8");
13197
13198
  const previewLines = scriptContent.split(`
13198
13199
  `).slice(0, 20);
13199
13200
  logger.info("Script preview (first 20 lines):");
@@ -14925,7 +14926,7 @@ var cac = (name = "") => new CAC(name);
14925
14926
  // package.json
14926
14927
  var package_default = {
14927
14928
  name: "claudekit-cli",
14928
- version: "3.7.1",
14929
+ version: "3.8.0",
14929
14930
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
14930
14931
  type: "module",
14931
14932
  repository: {
@@ -18765,7 +18766,7 @@ async function doctorCommand(options = {}) {
18765
18766
  }
18766
18767
 
18767
18768
  // src/commands/init.ts
18768
- var import_fs_extra17 = __toESM(require_lib(), 1);
18769
+ var import_fs_extra18 = __toESM(require_lib(), 1);
18769
18770
  import { join as join29, resolve as resolve5 } from "node:path";
18770
18771
 
18771
18772
  // src/lib/commands-prefix.ts
@@ -28492,7 +28493,7 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
28492
28493
 
28493
28494
  // src/lib/merge.ts
28494
28495
  init_dist2();
28495
- var import_fs_extra6 = __toESM(require_lib(), 1);
28496
+ var import_fs_extra7 = __toESM(require_lib(), 1);
28496
28497
  var import_ignore2 = __toESM(require_ignore(), 1);
28497
28498
  import { dirname as dirname4, join as join15, relative as relative4 } from "node:path";
28498
28499
 
@@ -29934,11 +29935,168 @@ minimatch.unescape = unescape;
29934
29935
  init_types2();
29935
29936
  init_logger();
29936
29937
 
29938
+ // src/lib/settings-merger.ts
29939
+ init_logger();
29940
+ var import_fs_extra6 = __toESM(require_lib(), 1);
29941
+
29942
+ class SettingsMerger {
29943
+ static merge(source, destination) {
29944
+ const result = {
29945
+ merged: { ...destination },
29946
+ hooksAdded: 0,
29947
+ hooksPreserved: 0,
29948
+ mcpServersPreserved: 0,
29949
+ conflictsDetected: []
29950
+ };
29951
+ if (source.hooks) {
29952
+ result.merged.hooks = SettingsMerger.mergeHooks(source.hooks, destination.hooks || {}, result);
29953
+ }
29954
+ if (source.mcp) {
29955
+ result.merged.mcp = SettingsMerger.mergeMcp(source.mcp, destination.mcp || {}, result);
29956
+ }
29957
+ for (const key of Object.keys(source)) {
29958
+ if (key !== "hooks" && key !== "mcp" && !(key in destination)) {
29959
+ result.merged[key] = source[key];
29960
+ }
29961
+ }
29962
+ return result;
29963
+ }
29964
+ static mergeHooks(sourceHooks, destHooks, result) {
29965
+ const merged = { ...destHooks };
29966
+ for (const [eventName, sourceEntries] of Object.entries(sourceHooks)) {
29967
+ const destEntries = destHooks[eventName] || [];
29968
+ merged[eventName] = SettingsMerger.mergeHookEntries(sourceEntries, destEntries, eventName, result);
29969
+ }
29970
+ return merged;
29971
+ }
29972
+ static mergeHookEntries(sourceEntries, destEntries, eventName, result) {
29973
+ const existingCommands = new Set;
29974
+ SettingsMerger.extractCommands(destEntries, existingCommands);
29975
+ if (destEntries.length > 0) {
29976
+ result.hooksPreserved += destEntries.length;
29977
+ }
29978
+ const merged = [...destEntries];
29979
+ for (const entry of sourceEntries) {
29980
+ const commands = SettingsMerger.getEntryCommands(entry);
29981
+ const isFullyDuplicated = commands.length > 0 && commands.every((cmd) => existingCommands.has(cmd));
29982
+ const duplicateCommands = commands.filter((cmd) => existingCommands.has(cmd));
29983
+ if (duplicateCommands.length > 0) {
29984
+ const summary = duplicateCommands.length === 1 ? `"${SettingsMerger.truncateCommand(duplicateCommands[0])}"` : `${duplicateCommands.length} commands`;
29985
+ result.conflictsDetected.push(`${eventName}: duplicate ${summary}`);
29986
+ }
29987
+ if (!isFullyDuplicated) {
29988
+ merged.push(entry);
29989
+ result.hooksAdded++;
29990
+ for (const cmd of commands) {
29991
+ existingCommands.add(cmd);
29992
+ }
29993
+ }
29994
+ }
29995
+ return merged;
29996
+ }
29997
+ static extractCommands(entries, commands) {
29998
+ for (const entry of entries) {
29999
+ if ("command" in entry && entry.command) {
30000
+ commands.add(entry.command);
30001
+ }
30002
+ if ("hooks" in entry && entry.hooks) {
30003
+ for (const hook of entry.hooks) {
30004
+ if (hook.command) {
30005
+ commands.add(hook.command);
30006
+ }
30007
+ }
30008
+ }
30009
+ }
30010
+ }
30011
+ static getEntryCommands(entry) {
30012
+ const commands = [];
30013
+ if ("command" in entry && entry.command) {
30014
+ commands.push(entry.command);
30015
+ }
30016
+ if ("hooks" in entry && entry.hooks) {
30017
+ for (const hook of entry.hooks) {
30018
+ if (hook.command) {
30019
+ commands.push(hook.command);
30020
+ }
30021
+ }
30022
+ }
30023
+ return commands;
30024
+ }
30025
+ static truncateCommand(cmd, maxLen = 50) {
30026
+ if (cmd.length <= maxLen)
30027
+ return cmd;
30028
+ return `${cmd.slice(0, maxLen - 3)}...`;
30029
+ }
30030
+ static mergeMcp(sourceMcp, destMcp, result) {
30031
+ if (!sourceMcp)
30032
+ return destMcp;
30033
+ if (!destMcp)
30034
+ return sourceMcp;
30035
+ const merged = { ...destMcp };
30036
+ if (sourceMcp.servers) {
30037
+ const destServers = destMcp.servers || {};
30038
+ merged.servers = { ...destServers };
30039
+ for (const [serverName, serverConfig] of Object.entries(sourceMcp.servers)) {
30040
+ if (serverName in destServers) {
30041
+ result.mcpServersPreserved++;
30042
+ logger.debug(`Preserved user MCP server: ${serverName}`);
30043
+ } else {
30044
+ merged.servers[serverName] = serverConfig;
30045
+ logger.debug(`Added ClaudeKit MCP server: ${serverName}`);
30046
+ }
30047
+ }
30048
+ }
30049
+ for (const key of Object.keys(sourceMcp)) {
30050
+ if (key !== "servers" && !(key in merged)) {
30051
+ merged[key] = sourceMcp[key];
30052
+ }
30053
+ }
30054
+ return merged;
30055
+ }
30056
+ static async readSettingsFile(filePath) {
30057
+ try {
30058
+ if (!await import_fs_extra6.pathExists(filePath)) {
30059
+ return null;
30060
+ }
30061
+ const content = await import_fs_extra6.readFile(filePath, "utf-8");
30062
+ const parsed = JSON.parse(content);
30063
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
30064
+ logger.warning(`Invalid settings file format (expected object): ${filePath}`);
30065
+ return null;
30066
+ }
30067
+ return parsed;
30068
+ } catch (error) {
30069
+ logger.warning(`Failed to parse settings file: ${filePath} - ${error}`);
30070
+ return null;
30071
+ }
30072
+ }
30073
+ static async writeSettingsFile(filePath, settings) {
30074
+ const content = JSON.stringify(settings, null, "\t");
30075
+ await import_fs_extra6.writeFile(filePath, content, "utf-8");
30076
+ }
30077
+ static async createBackup(filePath) {
30078
+ try {
30079
+ if (!await import_fs_extra6.pathExists(filePath)) {
30080
+ return null;
30081
+ }
30082
+ const backupPath = `${filePath}.backup`;
30083
+ const content = await import_fs_extra6.readFile(filePath, "utf-8");
30084
+ await import_fs_extra6.writeFile(backupPath, content, "utf-8");
30085
+ return backupPath;
30086
+ } catch (error) {
30087
+ logger.warning(`Failed to create backup: ${error}`);
30088
+ return null;
30089
+ }
30090
+ }
30091
+ }
30092
+
30093
+ // src/lib/merge.ts
29937
30094
  class FileMerger {
29938
30095
  neverCopyChecker = import_ignore2.default().add(NEVER_COPY_PATTERNS);
29939
30096
  userConfigChecker = import_ignore2.default().add(USER_CONFIG_PATTERNS);
29940
30097
  includePatterns = [];
29941
30098
  isGlobal = false;
30099
+ forceOverwriteSettings = false;
29942
30100
  installedFiles = new Set;
29943
30101
  installedDirectories = new Set;
29944
30102
  setIncludePatterns(patterns) {
@@ -29947,6 +30105,9 @@ class FileMerger {
29947
30105
  setGlobalFlag(isGlobal) {
29948
30106
  this.isGlobal = isGlobal;
29949
30107
  }
30108
+ setForceOverwriteSettings(force) {
30109
+ this.forceOverwriteSettings = force;
30110
+ }
29950
30111
  async merge(sourceDir, destDir, skipConfirmation = false) {
29951
30112
  const conflicts = await this.detectConflicts(sourceDir, destDir);
29952
30113
  if (conflicts.length > 0 && !skipConfirmation) {
@@ -29971,7 +30132,7 @@ class FileMerger {
29971
30132
  const relativePath = relative4(sourceDir, file);
29972
30133
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
29973
30134
  const destPath = join15(destDir, relativePath);
29974
- if (await import_fs_extra6.pathExists(destPath)) {
30135
+ if (await import_fs_extra7.pathExists(destPath)) {
29975
30136
  if (this.neverCopyChecker.ignores(normalizedRelativePath)) {
29976
30137
  logger.debug(`Security-sensitive file exists but won't be overwritten: ${normalizedRelativePath}`);
29977
30138
  continue;
@@ -29999,7 +30160,7 @@ class FileMerger {
29999
30160
  continue;
30000
30161
  }
30001
30162
  if (this.userConfigChecker.ignores(normalizedRelativePath)) {
30002
- const fileExists = await import_fs_extra6.pathExists(destPath);
30163
+ const fileExists = await import_fs_extra7.pathExists(destPath);
30003
30164
  if (fileExists) {
30004
30165
  logger.debug(`Skipping existing user config file: ${normalizedRelativePath}`);
30005
30166
  skippedCount++;
@@ -30013,7 +30174,7 @@ class FileMerger {
30013
30174
  copiedCount++;
30014
30175
  continue;
30015
30176
  }
30016
- await import_fs_extra6.copy(file, destPath, { overwrite: true });
30177
+ await import_fs_extra7.copy(file, destPath, { overwrite: true });
30017
30178
  this.trackInstalledFile(normalizedRelativePath);
30018
30179
  copiedCount++;
30019
30180
  }
@@ -30021,27 +30182,69 @@ class FileMerger {
30021
30182
  }
30022
30183
  async processSettingsJson(sourceFile, destFile) {
30023
30184
  try {
30024
- const content = await import_fs_extra6.readFile(sourceFile, "utf-8");
30185
+ const sourceContent = await import_fs_extra7.readFile(sourceFile, "utf-8");
30025
30186
  const isWindows5 = process.platform === "win32";
30026
- let processedContent = content;
30187
+ let transformedSource = sourceContent;
30027
30188
  if (this.isGlobal) {
30028
30189
  const homeVar = isWindows5 ? '"%USERPROFILE%"' : '"$HOME"';
30029
- processedContent = this.transformClaudePaths(content, homeVar);
30030
- if (processedContent !== content) {
30190
+ transformedSource = this.transformClaudePaths(sourceContent, homeVar);
30191
+ if (transformedSource !== sourceContent) {
30031
30192
  logger.debug(`Transformed .claude/ paths to ${homeVar}/.claude/ in settings.json for global installation`);
30032
30193
  }
30033
30194
  } else {
30034
30195
  const projectDirVar = isWindows5 ? '"%CLAUDE_PROJECT_DIR%"' : '"$CLAUDE_PROJECT_DIR"';
30035
- processedContent = this.transformClaudePaths(content, projectDirVar);
30036
- if (processedContent !== content) {
30196
+ transformedSource = this.transformClaudePaths(sourceContent, projectDirVar);
30197
+ if (transformedSource !== sourceContent) {
30037
30198
  logger.debug(`Transformed .claude/ paths to ${projectDirVar}/.claude/ in settings.json for local installation`);
30038
30199
  }
30039
30200
  }
30040
- await import_fs_extra6.writeFile(destFile, processedContent, "utf-8");
30201
+ const destExists = await import_fs_extra7.pathExists(destFile);
30202
+ if (destExists && !this.forceOverwriteSettings) {
30203
+ await this.selectiveMergeSettings(transformedSource, destFile);
30204
+ } else {
30205
+ await import_fs_extra7.writeFile(destFile, transformedSource, "utf-8");
30206
+ if (this.forceOverwriteSettings && destExists) {
30207
+ logger.debug("Force overwrite enabled, replaced settings.json completely");
30208
+ }
30209
+ }
30041
30210
  } catch (error) {
30042
30211
  logger.error(`Failed to process settings.json: ${error}`);
30043
- await import_fs_extra6.copy(sourceFile, destFile, { overwrite: true });
30212
+ await import_fs_extra7.copy(sourceFile, destFile, { overwrite: true });
30213
+ }
30214
+ }
30215
+ async selectiveMergeSettings(transformedSourceContent, destFile) {
30216
+ let sourceSettings;
30217
+ try {
30218
+ sourceSettings = JSON.parse(transformedSourceContent);
30219
+ } catch {
30220
+ logger.warning("Failed to parse source settings.json, falling back to overwrite");
30221
+ await import_fs_extra7.writeFile(destFile, transformedSourceContent, "utf-8");
30222
+ return;
30223
+ }
30224
+ const destSettings = await SettingsMerger.readSettingsFile(destFile);
30225
+ if (!destSettings) {
30226
+ await import_fs_extra7.writeFile(destFile, transformedSourceContent, "utf-8");
30227
+ return;
30228
+ }
30229
+ const backupPath = await SettingsMerger.createBackup(destFile);
30230
+ if (backupPath) {
30231
+ logger.debug(`Created settings backup: ${backupPath}`);
30232
+ }
30233
+ const mergeResult = SettingsMerger.merge(sourceSettings, destSettings);
30234
+ if (mergeResult.hooksAdded > 0) {
30235
+ logger.debug(`Added ${mergeResult.hooksAdded} new hook(s)`);
30044
30236
  }
30237
+ if (mergeResult.hooksPreserved > 0) {
30238
+ logger.debug(`Preserved ${mergeResult.hooksPreserved} existing hook(s)`);
30239
+ }
30240
+ if (mergeResult.mcpServersPreserved > 0) {
30241
+ logger.debug(`Preserved ${mergeResult.mcpServersPreserved} MCP server(s)`);
30242
+ }
30243
+ if (mergeResult.conflictsDetected.length > 0) {
30244
+ logger.warning(`Duplicate hooks detected (skipped): ${mergeResult.conflictsDetected.join(", ")}`);
30245
+ }
30246
+ await SettingsMerger.writeSettingsFile(destFile, mergeResult.merged);
30247
+ logger.success("Merged settings.json (user customizations preserved)");
30045
30248
  }
30046
30249
  transformClaudePaths(content, prefix) {
30047
30250
  if (/\.claude\/[^\s"']*[;`$&|><]/.test(content)) {
@@ -30060,12 +30263,12 @@ class FileMerger {
30060
30263
  }
30061
30264
  async getFiles(dir, baseDir = dir) {
30062
30265
  const files = [];
30063
- const entries = await import_fs_extra6.readdir(dir, { encoding: "utf8" });
30266
+ const entries = await import_fs_extra7.readdir(dir, { encoding: "utf8" });
30064
30267
  for (const entry of entries) {
30065
30268
  const fullPath = join15(dir, entry);
30066
30269
  const relativePath = relative4(baseDir, fullPath);
30067
30270
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
30068
- const stats = await import_fs_extra6.lstat(fullPath);
30271
+ const stats = await import_fs_extra7.lstat(fullPath);
30069
30272
  if (stats.isSymbolicLink()) {
30070
30273
  logger.warning(`Skipping symbolic link: ${normalizedRelativePath}`);
30071
30274
  continue;
@@ -30123,14 +30326,14 @@ class FileMerger {
30123
30326
 
30124
30327
  // src/lib/migration/legacy-migration.ts
30125
30328
  init_logger();
30126
- var import_fs_extra8 = __toESM(require_lib(), 1);
30329
+ var import_fs_extra9 = __toESM(require_lib(), 1);
30127
30330
  import { readdir as readdir7, stat as stat3 } from "node:fs/promises";
30128
30331
  import { join as join17, relative as relative5 } from "node:path";
30129
30332
 
30130
30333
  // src/lib/migration/release-manifest.ts
30131
30334
  init_zod();
30132
30335
  init_logger();
30133
- var import_fs_extra7 = __toESM(require_lib(), 1);
30336
+ var import_fs_extra8 = __toESM(require_lib(), 1);
30134
30337
  import { join as join16 } from "node:path";
30135
30338
  var ReleaseManifestFileSchema = exports_external.object({
30136
30339
  path: exports_external.string(),
@@ -30147,7 +30350,7 @@ class ReleaseManifestLoader {
30147
30350
  static async load(extractDir) {
30148
30351
  const manifestPath = join16(extractDir, "release-manifest.json");
30149
30352
  try {
30150
- const content = await import_fs_extra7.readFile(manifestPath, "utf-8");
30353
+ const content = await import_fs_extra8.readFile(manifestPath, "utf-8");
30151
30354
  const parsed = JSON.parse(content);
30152
30355
  return ReleaseManifestSchema.parse(parsed);
30153
30356
  } catch (error) {
@@ -30315,7 +30518,7 @@ User-created files (sample):`);
30315
30518
  files: trackedFiles
30316
30519
  };
30317
30520
  const metadataPath = join17(claudeDir, "metadata.json");
30318
- await import_fs_extra8.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
30521
+ await import_fs_extra9.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
30319
30522
  logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
30320
30523
  return true;
30321
30524
  }
@@ -30894,11 +31097,11 @@ class PromptsManager {
30894
31097
  // src/lib/setup-wizard.ts
30895
31098
  init_dist2();
30896
31099
  init_logger();
30897
- var import_fs_extra10 = __toESM(require_lib(), 1);
31100
+ var import_fs_extra11 = __toESM(require_lib(), 1);
30898
31101
  import { join as join21 } from "node:path";
30899
31102
 
30900
31103
  // src/lib/config-generator.ts
30901
- var import_fs_extra9 = __toESM(require_lib(), 1);
31104
+ var import_fs_extra10 = __toESM(require_lib(), 1);
30902
31105
  import { join as join20 } from "node:path";
30903
31106
  async function generateEnvFile(targetDir, values) {
30904
31107
  const lines = [
@@ -30912,7 +31115,7 @@ async function generateEnvFile(targetDir, values) {
30912
31115
  }
30913
31116
  }
30914
31117
  const envPath = join20(targetDir, ".env");
30915
- await import_fs_extra9.writeFile(envPath, `${lines.join(`
31118
+ await import_fs_extra10.writeFile(envPath, `${lines.join(`
30916
31119
  `)}
30917
31120
  `, { mode: 384 });
30918
31121
  }
@@ -30956,7 +31159,7 @@ var ESSENTIAL_CONFIGS = [
30956
31159
  ];
30957
31160
  async function parseEnvFile(path9) {
30958
31161
  try {
30959
- const content = await import_fs_extra10.readFile(path9, "utf-8");
31162
+ const content = await import_fs_extra11.readFile(path9, "utf-8");
30960
31163
  const env2 = {};
30961
31164
  for (const line of content.split(`
30962
31165
  `)) {
@@ -30983,7 +31186,7 @@ async function parseEnvFile(path9) {
30983
31186
  }
30984
31187
  async function checkGlobalConfig() {
30985
31188
  const globalEnvPath = join21(PathResolver.getGlobalKitDir(), ".env");
30986
- if (!await import_fs_extra10.pathExists(globalEnvPath))
31189
+ if (!await import_fs_extra11.pathExists(globalEnvPath))
30987
31190
  return false;
30988
31191
  const env2 = await parseEnvFile(globalEnvPath);
30989
31192
  return Object.keys(env2).length > 0;
@@ -30999,7 +31202,7 @@ async function runSetupWizard(options) {
30999
31202
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
31000
31203
  if (!isGlobal) {
31001
31204
  const globalEnvPath = join21(PathResolver.getGlobalKitDir(), ".env");
31002
- if (await import_fs_extra10.pathExists(globalEnvPath)) {
31205
+ if (await import_fs_extra11.pathExists(globalEnvPath)) {
31003
31206
  globalEnv = await parseEnvFile(globalEnvPath);
31004
31207
  }
31005
31208
  }
@@ -31057,16 +31260,16 @@ async function runSetupWizard(options) {
31057
31260
 
31058
31261
  // src/lib/skills-detector.ts
31059
31262
  init_logger();
31060
- var import_fs_extra12 = __toESM(require_lib(), 1);
31263
+ var import_fs_extra13 = __toESM(require_lib(), 1);
31061
31264
  import { readdir as readdir9 } from "node:fs/promises";
31062
31265
  import { join as join23 } from "node:path";
31063
31266
 
31064
31267
  // src/lib/skills-manifest.ts
31065
31268
  init_types2();
31066
31269
  init_logger();
31067
- var import_fs_extra11 = __toESM(require_lib(), 1);
31270
+ var import_fs_extra12 = __toESM(require_lib(), 1);
31068
31271
  import { createHash as createHash2 } from "node:crypto";
31069
- import { readFile as readFile12, readdir as readdir8, writeFile as writeFile11 } from "node:fs/promises";
31272
+ import { readFile as readFile13, readdir as readdir8, writeFile as writeFile12 } from "node:fs/promises";
31070
31273
  import { join as join22, relative as relative6 } from "node:path";
31071
31274
 
31072
31275
  class SkillsManifestManager {
@@ -31074,7 +31277,7 @@ class SkillsManifestManager {
31074
31277
  static MANIFEST_VERSION = "1.0.0";
31075
31278
  static async generateManifest(skillsDir) {
31076
31279
  logger.debug(`Generating manifest for: ${skillsDir}`);
31077
- if (!await import_fs_extra11.pathExists(skillsDir)) {
31280
+ if (!await import_fs_extra12.pathExists(skillsDir)) {
31078
31281
  throw new SkillsMigrationError(`Skills directory does not exist: ${skillsDir}`);
31079
31282
  }
31080
31283
  const structure = await SkillsManifestManager.detectStructure(skillsDir);
@@ -31090,17 +31293,17 @@ class SkillsManifestManager {
31090
31293
  }
31091
31294
  static async writeManifest(skillsDir, manifest) {
31092
31295
  const manifestPath = join22(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
31093
- await writeFile11(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
31296
+ await writeFile12(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
31094
31297
  logger.debug(`Wrote manifest to: ${manifestPath}`);
31095
31298
  }
31096
31299
  static async readManifest(skillsDir) {
31097
31300
  const manifestPath = join22(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
31098
- if (!await import_fs_extra11.pathExists(manifestPath)) {
31301
+ if (!await import_fs_extra12.pathExists(manifestPath)) {
31099
31302
  logger.debug(`No manifest found at: ${manifestPath}`);
31100
31303
  return null;
31101
31304
  }
31102
31305
  try {
31103
- const content = await readFile12(manifestPath, "utf-8");
31306
+ const content = await readFile13(manifestPath, "utf-8");
31104
31307
  const data = JSON.parse(content);
31105
31308
  const manifest = SkillsManifestSchema.parse(data);
31106
31309
  logger.debug(`Read manifest from: ${manifestPath}`);
@@ -31172,7 +31375,7 @@ class SkillsManifestManager {
31172
31375
  files.sort();
31173
31376
  for (const file of files) {
31174
31377
  const relativePath = relative6(dirPath, file);
31175
- const content = await readFile12(file);
31378
+ const content = await readFile13(file);
31176
31379
  hash.update(relativePath);
31177
31380
  hash.update(content);
31178
31381
  }
@@ -31302,8 +31505,8 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
31302
31505
  class SkillsMigrationDetector {
31303
31506
  static async detectMigration(oldSkillsDir, currentSkillsDir) {
31304
31507
  logger.debug("Detecting skills migration need...");
31305
- const oldExists = await import_fs_extra12.pathExists(oldSkillsDir);
31306
- const currentExists = await import_fs_extra12.pathExists(currentSkillsDir);
31508
+ const oldExists = await import_fs_extra13.pathExists(oldSkillsDir);
31509
+ const currentExists = await import_fs_extra13.pathExists(currentSkillsDir);
31307
31510
  if (!oldExists && !currentExists) {
31308
31511
  logger.debug("No skills directories found, migration not needed");
31309
31512
  return {
@@ -31414,7 +31617,7 @@ class SkillsMigrationDetector {
31414
31617
  };
31415
31618
  }
31416
31619
  static async scanDirectory(skillsDir) {
31417
- if (!await import_fs_extra12.pathExists(skillsDir)) {
31620
+ if (!await import_fs_extra13.pathExists(skillsDir)) {
31418
31621
  return ["flat", []];
31419
31622
  }
31420
31623
  const entries = await readdir9(skillsDir, { withFileTypes: true });
@@ -31467,14 +31670,14 @@ class SkillsMigrationDetector {
31467
31670
  // src/lib/skills-migrator.ts
31468
31671
  init_types2();
31469
31672
  init_logger();
31470
- var import_fs_extra15 = __toESM(require_lib(), 1);
31673
+ var import_fs_extra16 = __toESM(require_lib(), 1);
31471
31674
  import { copyFile as copyFile2, mkdir as mkdir8, readdir as readdir12, rm as rm2 } from "node:fs/promises";
31472
31675
  import { join as join26 } from "node:path";
31473
31676
 
31474
31677
  // src/lib/skills-backup-manager.ts
31475
31678
  init_types2();
31476
31679
  init_logger();
31477
- var import_fs_extra13 = __toESM(require_lib(), 1);
31680
+ var import_fs_extra14 = __toESM(require_lib(), 1);
31478
31681
  import { copyFile, mkdir as mkdir7, readdir as readdir10, rm, stat as stat4 } from "node:fs/promises";
31479
31682
  import { basename as basename2, join as join24, normalize as normalize4 } from "node:path";
31480
31683
  function validatePath2(path9, paramName) {
@@ -31496,7 +31699,7 @@ class SkillsBackupManager {
31496
31699
  if (parentDir) {
31497
31700
  validatePath2(parentDir, "parentDir");
31498
31701
  }
31499
- if (!await import_fs_extra13.pathExists(skillsDir)) {
31702
+ if (!await import_fs_extra14.pathExists(skillsDir)) {
31500
31703
  throw new SkillsMigrationError(`Cannot create backup: Skills directory does not exist: ${skillsDir}`);
31501
31704
  }
31502
31705
  const timestamp = Date.now();
@@ -31519,12 +31722,12 @@ class SkillsBackupManager {
31519
31722
  static async restoreBackup(backupDir, targetDir) {
31520
31723
  validatePath2(backupDir, "backupDir");
31521
31724
  validatePath2(targetDir, "targetDir");
31522
- if (!await import_fs_extra13.pathExists(backupDir)) {
31725
+ if (!await import_fs_extra14.pathExists(backupDir)) {
31523
31726
  throw new SkillsMigrationError(`Cannot restore: Backup directory does not exist: ${backupDir}`);
31524
31727
  }
31525
31728
  logger.info(`Restoring from backup: ${backupDir}`);
31526
31729
  try {
31527
- if (await import_fs_extra13.pathExists(targetDir)) {
31730
+ if (await import_fs_extra14.pathExists(targetDir)) {
31528
31731
  await rm(targetDir, { recursive: true, force: true });
31529
31732
  }
31530
31733
  await mkdir7(targetDir, { recursive: true });
@@ -31535,7 +31738,7 @@ class SkillsBackupManager {
31535
31738
  }
31536
31739
  }
31537
31740
  static async deleteBackup(backupDir) {
31538
- if (!await import_fs_extra13.pathExists(backupDir)) {
31741
+ if (!await import_fs_extra14.pathExists(backupDir)) {
31539
31742
  logger.warning(`Backup directory does not exist: ${backupDir}`);
31540
31743
  return;
31541
31744
  }
@@ -31548,7 +31751,7 @@ class SkillsBackupManager {
31548
31751
  }
31549
31752
  }
31550
31753
  static async listBackups(parentDir) {
31551
- if (!await import_fs_extra13.pathExists(parentDir)) {
31754
+ if (!await import_fs_extra14.pathExists(parentDir)) {
31552
31755
  return [];
31553
31756
  }
31554
31757
  try {
@@ -31573,7 +31776,7 @@ class SkillsBackupManager {
31573
31776
  }
31574
31777
  }
31575
31778
  static async getBackupSize(backupDir) {
31576
- if (!await import_fs_extra13.pathExists(backupDir)) {
31779
+ if (!await import_fs_extra14.pathExists(backupDir)) {
31577
31780
  return 0;
31578
31781
  }
31579
31782
  return await SkillsBackupManager.getDirectorySize(backupDir);
@@ -31625,10 +31828,10 @@ class SkillsBackupManager {
31625
31828
  // src/lib/skills-customization-scanner.ts
31626
31829
  init_types2();
31627
31830
  init_logger();
31628
- var import_fs_extra14 = __toESM(require_lib(), 1);
31831
+ var import_fs_extra15 = __toESM(require_lib(), 1);
31629
31832
  import { createHash as createHash3 } from "node:crypto";
31630
31833
  import { createReadStream as createReadStream2 } from "node:fs";
31631
- import { readFile as readFile13, readdir as readdir11 } from "node:fs/promises";
31834
+ import { readFile as readFile14, readdir as readdir11 } from "node:fs/promises";
31632
31835
  import { join as join25, normalize as normalize5, relative as relative7 } from "node:path";
31633
31836
  function validatePath3(path9, paramName) {
31634
31837
  if (!path9 || typeof path9 !== "string") {
@@ -31708,7 +31911,7 @@ class SkillsCustomizationScanner {
31708
31911
  static async detectFileChanges(currentSkillPath, baselineSkillPath) {
31709
31912
  const changes = [];
31710
31913
  const currentFiles = await SkillsCustomizationScanner.getAllFiles(currentSkillPath);
31711
- const baselineFiles = await import_fs_extra14.pathExists(baselineSkillPath) ? await SkillsCustomizationScanner.getAllFiles(baselineSkillPath) : [];
31914
+ const baselineFiles = await import_fs_extra15.pathExists(baselineSkillPath) ? await SkillsCustomizationScanner.getAllFiles(baselineSkillPath) : [];
31712
31915
  const currentFileMap = new Map(await Promise.all(currentFiles.map(async (f3) => {
31713
31916
  const relPath = relative7(currentSkillPath, f3);
31714
31917
  const hash = await SkillsCustomizationScanner.hashFile(f3);
@@ -31768,7 +31971,7 @@ class SkillsCustomizationScanner {
31768
31971
  return false;
31769
31972
  }
31770
31973
  static async scanSkillsDirectory(skillsDir) {
31771
- if (!await import_fs_extra14.pathExists(skillsDir)) {
31974
+ if (!await import_fs_extra15.pathExists(skillsDir)) {
31772
31975
  return ["flat", []];
31773
31976
  }
31774
31977
  const entries = await readdir11(skillsDir, { withFileTypes: true });
@@ -31803,7 +32006,7 @@ class SkillsCustomizationScanner {
31803
32006
  }
31804
32007
  static async findSkillPath(skillsDir, skillName) {
31805
32008
  const flatPath = join25(skillsDir, skillName);
31806
- if (await import_fs_extra14.pathExists(flatPath)) {
32009
+ if (await import_fs_extra15.pathExists(flatPath)) {
31807
32010
  return { path: flatPath, category: undefined };
31808
32011
  }
31809
32012
  const entries = await readdir11(skillsDir, { withFileTypes: true });
@@ -31813,7 +32016,7 @@ class SkillsCustomizationScanner {
31813
32016
  }
31814
32017
  const categoryPath = join25(skillsDir, entry.name);
31815
32018
  const skillPath = join25(categoryPath, skillName);
31816
- if (await import_fs_extra14.pathExists(skillPath)) {
32019
+ if (await import_fs_extra15.pathExists(skillPath)) {
31817
32020
  return { path: skillPath, category: entry.name };
31818
32021
  }
31819
32022
  }
@@ -31856,7 +32059,7 @@ class SkillsCustomizationScanner {
31856
32059
  files.sort();
31857
32060
  for (const file of files) {
31858
32061
  const relativePath = relative7(dirPath, file);
31859
- const content = await readFile13(file);
32062
+ const content = await readFile14(file);
31860
32063
  hash.update(relativePath);
31861
32064
  hash.update(content);
31862
32065
  }
@@ -32125,7 +32328,7 @@ class SkillsMigrator {
32125
32328
  try {
32126
32329
  const skillName = mapping.skillName;
32127
32330
  const currentSkillPath = mapping.oldPath;
32128
- if (!await import_fs_extra15.pathExists(currentSkillPath)) {
32331
+ if (!await import_fs_extra16.pathExists(currentSkillPath)) {
32129
32332
  logger.warning(`Skill not found, skipping: ${skillName}`);
32130
32333
  continue;
32131
32334
  }
@@ -32196,7 +32399,7 @@ init_types2();
32196
32399
  init_types2();
32197
32400
  init_logger();
32198
32401
  import { existsSync as existsSync6 } from "node:fs";
32199
- import { mkdir as mkdir9, readFile as readFile14, rename as rename2, rm as rm3, writeFile as writeFile12 } from "node:fs/promises";
32402
+ import { mkdir as mkdir9, readFile as readFile15, rename as rename2, rm as rm3, writeFile as writeFile13 } from "node:fs/promises";
32200
32403
  import { chmod as chmod2 } from "node:fs/promises";
32201
32404
  import { platform as platform9 } from "node:os";
32202
32405
  import { join as join27 } from "node:path";
@@ -32222,7 +32425,7 @@ class ConfigManager {
32222
32425
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
32223
32426
  try {
32224
32427
  if (existsSync6(configFile)) {
32225
- const content = await readFile14(configFile, "utf-8");
32428
+ const content = await readFile15(configFile, "utf-8");
32226
32429
  const data = JSON.parse(content);
32227
32430
  ConfigManager.config = ConfigSchema.parse(data);
32228
32431
  logger.debug(`Config loaded from ${configFile}`);
@@ -32245,7 +32448,7 @@ class ConfigManager {
32245
32448
  await chmod2(configDir, 448);
32246
32449
  }
32247
32450
  }
32248
- await writeFile12(configFile, JSON.stringify(validConfig, null, 2), "utf-8");
32451
+ await writeFile13(configFile, JSON.stringify(validConfig, null, 2), "utf-8");
32249
32452
  if (platform9() !== "win32") {
32250
32453
  await chmod2(configFile, 384);
32251
32454
  }
@@ -32276,7 +32479,7 @@ class ConfigManager {
32276
32479
  const configPath = join27(configDir, PROJECT_CONFIG_FILE);
32277
32480
  try {
32278
32481
  if (existsSync6(configPath)) {
32279
- const content = await readFile14(configPath, "utf-8");
32482
+ const content = await readFile15(configPath, "utf-8");
32280
32483
  const data = JSON.parse(content);
32281
32484
  const folders = FoldersConfigSchema.parse(data.paths || data);
32282
32485
  logger.debug(`Project config loaded from ${configPath}`);
@@ -32295,7 +32498,7 @@ class ConfigManager {
32295
32498
  await mkdir9(configDir, { recursive: true });
32296
32499
  }
32297
32500
  const validFolders = FoldersConfigSchema.parse(folders);
32298
- await writeFile12(configPath, JSON.stringify({ paths: validFolders }, null, 2), "utf-8");
32501
+ await writeFile13(configPath, JSON.stringify({ paths: validFolders }, null, 2), "utf-8");
32299
32502
  logger.debug(`Project config saved to ${configPath}`);
32300
32503
  } catch (error) {
32301
32504
  throw new Error(`Failed to save project config: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -32357,7 +32560,7 @@ init_environment();
32357
32560
 
32358
32561
  // src/utils/file-scanner.ts
32359
32562
  init_logger();
32360
- var import_fs_extra16 = __toESM(require_lib(), 1);
32563
+ var import_fs_extra17 = __toESM(require_lib(), 1);
32361
32564
  import { join as join28, relative as relative8, resolve as resolve4 } from "node:path";
32362
32565
  var SKIP_DIRS2 = [
32363
32566
  "node_modules",
@@ -32383,11 +32586,11 @@ class FileScanner {
32383
32586
  static async getFiles(dirPath, relativeTo) {
32384
32587
  const basePath = relativeTo || dirPath;
32385
32588
  const files = [];
32386
- if (!await import_fs_extra16.pathExists(dirPath)) {
32589
+ if (!await import_fs_extra17.pathExists(dirPath)) {
32387
32590
  return files;
32388
32591
  }
32389
32592
  try {
32390
- const entries = await import_fs_extra16.readdir(dirPath, { encoding: "utf8" });
32593
+ const entries = await import_fs_extra17.readdir(dirPath, { encoding: "utf8" });
32391
32594
  for (const entry of entries) {
32392
32595
  if (SKIP_DIRS2.includes(entry)) {
32393
32596
  logger.debug(`Skipping directory: ${entry}`);
@@ -32400,7 +32603,7 @@ class FileScanner {
32400
32603
  }
32401
32604
  let stats;
32402
32605
  try {
32403
- stats = await import_fs_extra16.lstat(fullPath);
32606
+ stats = await import_fs_extra17.lstat(fullPath);
32404
32607
  } catch (error) {
32405
32608
  if (error instanceof Error && "code" in error && (error.code === "EACCES" || error.code === "EPERM")) {
32406
32609
  logger.warning(`Skipping inaccessible path: ${entry}`);
@@ -32439,7 +32642,7 @@ class FileScanner {
32439
32642
  const sourceFiles = await FileScanner.getFiles(sourceSubDir, sourceDir);
32440
32643
  logger.debug(`findCustomFiles - destFiles count: ${destFiles.length}`);
32441
32644
  logger.debug(`findCustomFiles - sourceFiles count: ${sourceFiles.length}`);
32442
- const sourceExists = await import_fs_extra16.pathExists(sourceSubDir);
32645
+ const sourceExists = await import_fs_extra17.pathExists(sourceSubDir);
32443
32646
  if (sourceExists && sourceFiles.length === 0 && destFiles.length > 100) {
32444
32647
  logger.warning(`Source directory exists but is empty while destination has ${destFiles.length} files. This may indicate an extraction issue. Skipping custom file detection.`);
32445
32648
  return [];
@@ -32487,7 +32690,7 @@ async function initCommand(options) {
32487
32690
  const cwdResolved = resolve5(process.cwd());
32488
32691
  const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved === resolve5(globalKitDir, "..");
32489
32692
  const localSettingsPath = join29(process.cwd(), ".claude", "settings.json");
32490
- if (!isInGlobalDir && await import_fs_extra17.pathExists(localSettingsPath)) {
32693
+ if (!isInGlobalDir && await import_fs_extra18.pathExists(localSettingsPath)) {
32491
32694
  if (isNonInteractive2) {
32492
32695
  logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
32493
32696
  logger.warning("Consider removing local installation: rm -rf .claude");
@@ -32500,7 +32703,7 @@ async function initCommand(options) {
32500
32703
  if (choice === "remove") {
32501
32704
  const localClaudeDir = join29(process.cwd(), ".claude");
32502
32705
  try {
32503
- await import_fs_extra17.remove(localClaudeDir);
32706
+ await import_fs_extra18.remove(localClaudeDir);
32504
32707
  logger.success("Removed local .claude/ directory");
32505
32708
  } catch (error) {
32506
32709
  logger.error(`Failed to remove local installation: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -32544,7 +32747,7 @@ async function initCommand(options) {
32544
32747
  }
32545
32748
  const resolvedDir = resolve5(targetDir);
32546
32749
  logger.info(`Target directory: ${resolvedDir}`);
32547
- if (!await import_fs_extra17.pathExists(resolvedDir)) {
32750
+ if (!await import_fs_extra18.pathExists(resolvedDir)) {
32548
32751
  if (validOptions.global) {
32549
32752
  const { mkdir: mkdir10 } = await import("node:fs/promises");
32550
32753
  await mkdir10(resolvedDir, { recursive: true });
@@ -32696,7 +32899,7 @@ async function initCommand(options) {
32696
32899
  if (!validOptions.fresh) {
32697
32900
  const newSkillsDir = join29(extractDir, ".claude", "skills");
32698
32901
  const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
32699
- if (await import_fs_extra17.pathExists(newSkillsDir) && await import_fs_extra17.pathExists(currentSkillsDir)) {
32902
+ if (await import_fs_extra18.pathExists(newSkillsDir) && await import_fs_extra18.pathExists(currentSkillsDir)) {
32700
32903
  logger.info("Checking for skills directory migration...");
32701
32904
  const migrationDetection = await SkillsMigrationDetector.detectMigration(newSkillsDir, currentSkillsDir);
32702
32905
  if (migrationDetection.status === "recommended" || migrationDetection.status === "required") {
@@ -32748,9 +32951,10 @@ async function initCommand(options) {
32748
32951
  merger.addIgnorePatterns(validOptions.exclude);
32749
32952
  }
32750
32953
  merger.setGlobalFlag(validOptions.global);
32954
+ merger.setForceOverwriteSettings(validOptions.forceOverwriteSettings);
32751
32955
  const claudeDir = validOptions.global ? resolvedDir : join29(resolvedDir, ".claude");
32752
32956
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
32753
- if (!validOptions.fresh && await import_fs_extra17.pathExists(claudeDir)) {
32957
+ if (!validOptions.fresh && await import_fs_extra18.pathExists(claudeDir)) {
32754
32958
  const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
32755
32959
  if (legacyDetection.isLegacy && releaseManifest) {
32756
32960
  logger.info("Legacy installation detected - migrating to ownership tracking...");
@@ -32802,9 +33006,9 @@ async function initCommand(options) {
32802
33006
  if (validOptions.global) {
32803
33007
  const claudeMdSource = join29(extractDir, "CLAUDE.md");
32804
33008
  const claudeMdDest = join29(resolvedDir, "CLAUDE.md");
32805
- if (await import_fs_extra17.pathExists(claudeMdSource)) {
32806
- if (!await import_fs_extra17.pathExists(claudeMdDest)) {
32807
- await import_fs_extra17.copy(claudeMdSource, claudeMdDest);
33009
+ if (await import_fs_extra18.pathExists(claudeMdSource)) {
33010
+ if (!await import_fs_extra18.pathExists(claudeMdDest)) {
33011
+ await import_fs_extra18.copy(claudeMdSource, claudeMdDest);
32808
33012
  logger.success("Copied CLAUDE.md to global directory");
32809
33013
  } else {
32810
33014
  logger.debug("CLAUDE.md already exists in global directory (preserved)");
@@ -32822,7 +33026,7 @@ async function initCommand(options) {
32822
33026
  }
32823
33027
  if (!validOptions.skipSetup && !isNonInteractive2) {
32824
33028
  const envPath = join29(claudeDir, ".env");
32825
- if (!await import_fs_extra17.pathExists(envPath)) {
33029
+ if (!await import_fs_extra18.pathExists(envPath)) {
32826
33030
  const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
32827
33031
  if (shouldSetup) {
32828
33032
  await runSetupWizard({
@@ -32852,7 +33056,7 @@ Protected files (.env, etc.) were not modified.`;
32852
33056
  }
32853
33057
 
32854
33058
  // src/commands/new.ts
32855
- var import_fs_extra18 = __toESM(require_lib(), 1);
33059
+ var import_fs_extra19 = __toESM(require_lib(), 1);
32856
33060
  import { join as join30, resolve as resolve6 } from "node:path";
32857
33061
  init_types2();
32858
33062
  init_environment();
@@ -32884,8 +33088,8 @@ async function newCommand(options) {
32884
33088
  }
32885
33089
  const resolvedDir = resolve6(targetDir);
32886
33090
  logger.info(`Target directory: ${resolvedDir}`);
32887
- if (await import_fs_extra18.pathExists(resolvedDir)) {
32888
- const files = await import_fs_extra18.readdir(resolvedDir);
33091
+ if (await import_fs_extra19.pathExists(resolvedDir)) {
33092
+ const files = await import_fs_extra19.readdir(resolvedDir);
32889
33093
  const isEmpty = files.length === 0;
32890
33094
  if (!isEmpty) {
32891
33095
  if (isNonInteractive2) {
@@ -33085,7 +33289,7 @@ async function newCommand(options) {
33085
33289
  }
33086
33290
 
33087
33291
  // src/commands/uninstall.ts
33088
- var import_fs_extra19 = __toESM(require_lib(), 1);
33292
+ var import_fs_extra20 = __toESM(require_lib(), 1);
33089
33293
  var import_picocolors10 = __toESM(require_picocolors(), 1);
33090
33294
  import { readdirSync, rmSync } from "node:fs";
33091
33295
  import { dirname as dirname5, join as join31 } from "node:path";
@@ -33098,14 +33302,14 @@ async function detectInstallations() {
33098
33302
  installations.push({
33099
33303
  type: "local",
33100
33304
  path: setup.project.path,
33101
- exists: await import_fs_extra19.pathExists(setup.project.path)
33305
+ exists: await import_fs_extra20.pathExists(setup.project.path)
33102
33306
  });
33103
33307
  }
33104
33308
  if (setup.global.path && setup.global.metadata) {
33105
33309
  installations.push({
33106
33310
  type: "global",
33107
33311
  path: setup.global.path,
33108
- exists: await import_fs_extra19.pathExists(setup.global.path)
33312
+ exists: await import_fs_extra20.pathExists(setup.global.path)
33109
33313
  });
33110
33314
  }
33111
33315
  return installations.filter((i) => i.exists);
@@ -33238,8 +33442,8 @@ async function removeInstallations(installations, options) {
33238
33442
  let cleanedDirs = 0;
33239
33443
  for (const item of analysis.toDelete) {
33240
33444
  const filePath = join31(installation.path, item.path);
33241
- if (await import_fs_extra19.pathExists(filePath)) {
33242
- await import_fs_extra19.remove(filePath);
33445
+ if (await import_fs_extra20.pathExists(filePath)) {
33446
+ await import_fs_extra20.remove(filePath);
33243
33447
  removedCount++;
33244
33448
  logger.debug(`Removed: ${item.path}`);
33245
33449
  cleanedDirs += await cleanupEmptyDirectories(filePath, installation.path);
@@ -33338,7 +33542,7 @@ import { promisify as promisify6 } from "node:util";
33338
33542
  // package.json
33339
33543
  var package_default2 = {
33340
33544
  name: "claudekit-cli",
33341
- version: "3.7.1",
33545
+ version: "3.8.0",
33342
33546
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
33343
33547
  type: "module",
33344
33548
  repository: {
@@ -33784,7 +33988,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
33784
33988
  // src/lib/version-cache.ts
33785
33989
  init_logger();
33786
33990
  import { existsSync as existsSync7 } from "node:fs";
33787
- import { mkdir as mkdir10, readFile as readFile15, writeFile as writeFile13 } from "node:fs/promises";
33991
+ import { mkdir as mkdir10, readFile as readFile16, writeFile as writeFile14 } from "node:fs/promises";
33788
33992
  import { join as join32 } from "node:path";
33789
33993
  class VersionCacheManager {
33790
33994
  static CACHE_FILENAME = "version-check.json";
@@ -33800,7 +34004,7 @@ class VersionCacheManager {
33800
34004
  logger.debug("Version check cache not found");
33801
34005
  return null;
33802
34006
  }
33803
- const content = await readFile15(cacheFile, "utf-8");
34007
+ const content = await readFile16(cacheFile, "utf-8");
33804
34008
  const cache2 = JSON.parse(content);
33805
34009
  if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
33806
34010
  logger.debug("Invalid cache structure, ignoring");
@@ -33820,7 +34024,7 @@ class VersionCacheManager {
33820
34024
  if (!existsSync7(cacheDir)) {
33821
34025
  await mkdir10(cacheDir, { recursive: true, mode: 448 });
33822
34026
  }
33823
- await writeFile13(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
34027
+ await writeFile14(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
33824
34028
  logger.debug(`Version check cache saved to ${cacheFile}`);
33825
34029
  } catch (error) {
33826
34030
  logger.debug(`Failed to save version check cache: ${error}`);
@@ -34064,6 +34268,7 @@ var UpdateCommandOptionsSchema2 = exports_external.object({
34064
34268
  beta: exports_external.boolean().default(false),
34065
34269
  dryRun: exports_external.boolean().default(false),
34066
34270
  forceOverwrite: exports_external.boolean().default(false),
34271
+ forceOverwriteSettings: exports_external.boolean().default(false),
34067
34272
  skipSetup: exports_external.boolean().default(false),
34068
34273
  refresh: exports_external.boolean().default(false),
34069
34274
  docsDir: exports_external.string().optional(),
@@ -34447,7 +34652,7 @@ cli.command("new", "Bootstrap a new ClaudeKit project (with interactive version
34447
34652
  }
34448
34653
  await newCommand(options);
34449
34654
  });
34450
- cli.command("init", "Initialize or update ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer, marketing)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Completely remove .claude directory before downloading (requires confirmation)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").action(async (options) => {
34655
+ cli.command("init", "Initialize or update ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer, marketing)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Completely remove .claude directory before downloading (requires confirmation)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").action(async (options) => {
34451
34656
  if (options.exclude && !Array.isArray(options.exclude)) {
34452
34657
  options.exclude = [options.exclude];
34453
34658
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.7.1",
3
+ "version": "3.8.0",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {