claudekit-cli 3.5.2 → 3.6.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.
Files changed (2) hide show
  1. package/dist/index.js +333 -136
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12725,6 +12725,116 @@ var require_emoji_regex2 = __commonJS((exports, module) => {
12725
12725
  };
12726
12726
  });
12727
12727
 
12728
+ // src/utils/install-error-handler.ts
12729
+ import { existsSync as existsSync5, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "node:fs";
12730
+ import { join as join17 } from "node:path";
12731
+ function parseNameReason(str) {
12732
+ const colonIndex = str.indexOf(":");
12733
+ if (colonIndex === -1) {
12734
+ return [str.trim(), undefined];
12735
+ }
12736
+ return [str.slice(0, colonIndex).trim(), str.slice(colonIndex + 1).trim()];
12737
+ }
12738
+ function displayInstallErrors(skillsDir) {
12739
+ const summaryPath = join17(skillsDir, ".install-error-summary.json");
12740
+ if (!existsSync5(summaryPath)) {
12741
+ logger.error("Skills installation failed. Run with --verbose for details.");
12742
+ return;
12743
+ }
12744
+ let summary;
12745
+ try {
12746
+ summary = JSON.parse(readFileSync4(summaryPath, "utf-8"));
12747
+ } catch (parseError) {
12748
+ logger.error("Failed to parse error summary. File may be corrupted.");
12749
+ logger.debug(`Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
12750
+ return;
12751
+ }
12752
+ try {
12753
+ if (summary.critical_failures.length > 0) {
12754
+ logger.error("");
12755
+ logger.error("━━━ Critical Failures ━━━");
12756
+ for (const failure of summary.critical_failures) {
12757
+ const [name2, reason] = parseNameReason(failure);
12758
+ logger.error(` ✗ ${name2}`);
12759
+ if (reason)
12760
+ logger.error(` Reason: ${reason}`);
12761
+ }
12762
+ logger.error("");
12763
+ logger.error("These must be fixed before skills can work.");
12764
+ }
12765
+ if (summary.optional_failures.length > 0) {
12766
+ logger.warning("");
12767
+ logger.warning("━━━ Optional Package Failures ━━━");
12768
+ for (const failure of summary.optional_failures) {
12769
+ const [name2, reason] = parseNameReason(failure);
12770
+ logger.warning(` ! ${name2}`);
12771
+ if (reason)
12772
+ logger.info(` Reason: ${reason}`);
12773
+ }
12774
+ }
12775
+ if (summary.skipped.length > 0) {
12776
+ logger.info("");
12777
+ logger.info("━━━ Skipped (No sudo) ━━━");
12778
+ for (const skipped of summary.skipped) {
12779
+ const [name2] = parseNameReason(skipped);
12780
+ logger.info(` ~ ${name2}`);
12781
+ }
12782
+ }
12783
+ logger.info("");
12784
+ logger.info("━━━ How to Fix ━━━");
12785
+ logger.info("");
12786
+ if (summary.optional_failures.some((f3) => f3.includes("no wheel") || f3.includes("build tools") || f3.includes("build failed")) && summary.remediation.build_tools) {
12787
+ logger.info("Install build tools (one-time):");
12788
+ logger.info(` ${summary.remediation.build_tools}`);
12789
+ logger.info("");
12790
+ }
12791
+ if (summary.skipped.length > 0 && summary.remediation.sudo_packages) {
12792
+ logger.info("Install system packages:");
12793
+ logger.info(` ${summary.remediation.sudo_packages}`);
12794
+ logger.info("");
12795
+ }
12796
+ if (summary.optional_failures.length > 0 && summary.remediation.pip_retry) {
12797
+ logger.info("Then retry failed packages manually:");
12798
+ logger.info(` ${summary.remediation.pip_retry}`);
12799
+ }
12800
+ try {
12801
+ unlinkSync2(summaryPath);
12802
+ } catch (cleanupError) {
12803
+ if (cleanupError.code !== "ENOENT") {
12804
+ logger.debug(`Failed to cleanup summary file: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
12805
+ }
12806
+ }
12807
+ } catch (displayError) {
12808
+ logger.error("Failed to display error summary.");
12809
+ logger.debug(`Display error: ${displayError instanceof Error ? displayError.message : String(displayError)}`);
12810
+ }
12811
+ }
12812
+ async function checkNeedsSudoPackages() {
12813
+ if (process.platform !== "linux") {
12814
+ return false;
12815
+ }
12816
+ const { exec: exec5 } = await import("node:child_process");
12817
+ const { promisify: promisify5 } = await import("node:util");
12818
+ const execAsync5 = promisify5(exec5);
12819
+ try {
12820
+ await Promise.all([
12821
+ execAsync5("which ffmpeg", { timeout: WHICH_COMMAND_TIMEOUT_MS }),
12822
+ execAsync5("which convert", { timeout: WHICH_COMMAND_TIMEOUT_MS })
12823
+ ]);
12824
+ return false;
12825
+ } catch {
12826
+ return true;
12827
+ }
12828
+ }
12829
+ function hasInstallState(skillsDir) {
12830
+ const stateFilePath = join17(skillsDir, ".install-state.json");
12831
+ return existsSync5(stateFilePath);
12832
+ }
12833
+ var WHICH_COMMAND_TIMEOUT_MS = 5000;
12834
+ var init_install_error_handler = __esm(() => {
12835
+ init_logger();
12836
+ });
12837
+
12728
12838
  // src/utils/package-installer.ts
12729
12839
  var exports_package_installer = {};
12730
12840
  __export(exports_package_installer, {
@@ -12741,7 +12851,7 @@ __export(exports_package_installer, {
12741
12851
  getPackageVersion: () => getPackageVersion
12742
12852
  });
12743
12853
  import { exec as exec5, execFile as execFile2, spawn } from "node:child_process";
12744
- import { resolve as resolve2 } from "node:path";
12854
+ import { join as join18, resolve as resolve2 } from "node:path";
12745
12855
  import { promisify as promisify5 } from "node:util";
12746
12856
  function executeInteractiveScript(command, args, options) {
12747
12857
  return new Promise((resolve3, reject) => {
@@ -12935,9 +13045,8 @@ async function installOpenCode() {
12935
13045
  try {
12936
13046
  logger.info(`Installing ${displayName}...`);
12937
13047
  const { unlink: unlink2 } = await import("node:fs/promises");
12938
- const { join: join17 } = await import("node:path");
12939
13048
  const { tmpdir: tmpdir3 } = await import("node:os");
12940
- const tempScriptPath = join17(tmpdir3(), "opencode-install.sh");
13049
+ const tempScriptPath = join18(tmpdir3(), "opencode-install.sh");
12941
13050
  try {
12942
13051
  logger.info("Downloading OpenCode installation script...");
12943
13052
  await execFileAsync("curl", ["-fsSL", "https://opencode.ai/install", "-o", tempScriptPath], {
@@ -13047,13 +13156,12 @@ async function installSkillsDependencies(skillsDir) {
13047
13156
  };
13048
13157
  }
13049
13158
  try {
13050
- const { existsSync: existsSync5 } = await import("node:fs");
13159
+ const { existsSync: existsSync6 } = await import("node:fs");
13051
13160
  const { readFile: readFile9 } = await import("node:fs/promises");
13052
- const { join: join17 } = await import("node:path");
13053
13161
  const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
13054
13162
  const platform8 = process.platform;
13055
13163
  const scriptName = platform8 === "win32" ? "install.ps1" : "install.sh";
13056
- const scriptPath = join17(skillsDir, scriptName);
13164
+ const scriptPath = join18(skillsDir, scriptName);
13057
13165
  try {
13058
13166
  validateScriptPath(skillsDir, scriptPath);
13059
13167
  } catch (error) {
@@ -13065,11 +13173,11 @@ async function installSkillsDependencies(skillsDir) {
13065
13173
  error: `Path validation failed: ${errorMessage}`
13066
13174
  };
13067
13175
  }
13068
- if (!existsSync5(scriptPath)) {
13176
+ if (!existsSync6(scriptPath)) {
13069
13177
  logger.warning(`Skills installation script not found: ${scriptPath}`);
13070
13178
  logger.info("");
13071
13179
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
13072
- logger.info(` See: ${join17(skillsDir, "INSTALLATION.md")}`);
13180
+ logger.info(` See: ${join18(skillsDir, "INSTALLATION.md")}`);
13073
13181
  logger.info("");
13074
13182
  logger.info("Quick start:");
13075
13183
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -13113,7 +13221,7 @@ async function installSkillsDependencies(skillsDir) {
13113
13221
  logger.info(` ${platform8 === "win32" ? `powershell -File "${scriptPath}"` : `bash ${scriptPath}`}`);
13114
13222
  logger.info("");
13115
13223
  logger.info("Or see complete guide:");
13116
- logger.info(` ${join17(skillsDir, "INSTALLATION.md")}`);
13224
+ logger.info(` ${join18(skillsDir, "INSTALLATION.md")}`);
13117
13225
  return {
13118
13226
  success: false,
13119
13227
  package: displayName,
@@ -13122,6 +13230,47 @@ async function installSkillsDependencies(skillsDir) {
13122
13230
  }
13123
13231
  logger.info(`Installing ${displayName}...`);
13124
13232
  logger.info(`Running: ${scriptPath}`);
13233
+ const scriptArgs = ["--yes"];
13234
+ if (hasInstallState(skillsDir)) {
13235
+ if (isNonInteractive()) {
13236
+ logger.info("Resuming previous installation (non-interactive mode)...");
13237
+ scriptArgs.push("--resume");
13238
+ } else {
13239
+ const shouldResume = await clack.confirm({
13240
+ message: "Previous installation was interrupted. Resume?",
13241
+ initialValue: true
13242
+ });
13243
+ if (!clack.isCancel(shouldResume) && shouldResume) {
13244
+ scriptArgs.push("--resume");
13245
+ logger.info("Resuming previous installation...");
13246
+ }
13247
+ }
13248
+ }
13249
+ if (platform8 === "linux") {
13250
+ const needsSudo = await checkNeedsSudoPackages();
13251
+ if (needsSudo) {
13252
+ if (isNonInteractive()) {
13253
+ logger.info("Skipping system packages in non-interactive mode.");
13254
+ logger.info("Install manually: sudo apt-get install -y ffmpeg imagemagick");
13255
+ } else {
13256
+ logger.info("");
13257
+ logger.info("System packages (requires sudo):");
13258
+ logger.info(" • ffmpeg - Video/audio processing");
13259
+ logger.info(" • imagemagick - Image editing & conversion");
13260
+ logger.info("");
13261
+ const shouldInstallSudo = await clack.confirm({
13262
+ message: "Install these packages? (requires sudo password)",
13263
+ initialValue: true
13264
+ });
13265
+ if (!clack.isCancel(shouldInstallSudo) && shouldInstallSudo) {
13266
+ scriptArgs.push("--with-sudo");
13267
+ } else {
13268
+ logger.info("Skipping system packages. Install manually later:");
13269
+ logger.info(" sudo apt-get install -y ffmpeg imagemagick");
13270
+ }
13271
+ }
13272
+ }
13273
+ }
13125
13274
  const scriptEnv = {
13126
13275
  ...process.env,
13127
13276
  NON_INTERACTIVE: "1"
@@ -13137,7 +13286,7 @@ async function installSkillsDependencies(skillsDir) {
13137
13286
  env: scriptEnv
13138
13287
  });
13139
13288
  } else {
13140
- await executeInteractiveScript("bash", [scriptPath, "--yes"], {
13289
+ await executeInteractiveScript("bash", [scriptPath, ...scriptArgs], {
13141
13290
  timeout: 600000,
13142
13291
  cwd: skillsDir,
13143
13292
  env: scriptEnv
@@ -13150,13 +13299,34 @@ async function installSkillsDependencies(skillsDir) {
13150
13299
  };
13151
13300
  } catch (error) {
13152
13301
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
13153
- logger.error(`Failed to install ${displayName}: ${errorMessage}`);
13302
+ const exitCodeMatch = errorMessage.match(/exited with code (\d+)/);
13303
+ const exitCode = exitCodeMatch ? Number.parseInt(exitCodeMatch[1], 10) : 1;
13304
+ if (exitCode === EXIT_CODE_PARTIAL_SUCCESS) {
13305
+ displayInstallErrors(skillsDir);
13306
+ logger.info("");
13307
+ logger.success("Core functionality is available despite some package failures.");
13308
+ return {
13309
+ success: true,
13310
+ package: displayName,
13311
+ version: PARTIAL_INSTALL_VERSION
13312
+ };
13313
+ }
13314
+ if (exitCode === EXIT_CODE_CRITICAL_FAILURE) {
13315
+ displayInstallErrors(skillsDir);
13316
+ logger.error("");
13317
+ logger.error("Skills installation failed. See above for details.");
13318
+ return {
13319
+ success: false,
13320
+ package: displayName,
13321
+ error: "Critical dependencies missing"
13322
+ };
13323
+ }
13324
+ logger.error(`Unexpected error: ${errorMessage}`);
13154
13325
  logger.info("");
13155
13326
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
13156
13327
  logger.info("");
13157
13328
  logger.info("See complete guide:");
13158
- const { join: join17 } = await import("node:path");
13159
- logger.info(` cat ${join17(skillsDir, "INSTALLATION.md")}`);
13329
+ logger.info(` cat ${join18(skillsDir, "INSTALLATION.md")}`);
13160
13330
  logger.info("");
13161
13331
  logger.info("Quick start:");
13162
13332
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -13177,19 +13347,24 @@ async function handleSkillsInstallation(skillsDir) {
13177
13347
  try {
13178
13348
  const skillsResult = await installSkillsDependencies(skillsDir);
13179
13349
  if (skillsResult.success) {
13180
- logger.success("Skills dependencies installed successfully");
13350
+ if (skillsResult.version === PARTIAL_INSTALL_VERSION) {
13351
+ logger.success("Skills core dependencies installed (some optional packages skipped)");
13352
+ } else {
13353
+ logger.success("Skills dependencies installed successfully");
13354
+ }
13181
13355
  } else {
13182
- logger.warning(`Skills installation failed: ${skillsResult.error || "Unknown error"}`);
13183
- logger.info(`You can install skills dependencies manually later by running the installation script in ${skillsDir}`);
13356
+ logger.warning(`Skills installation incomplete: ${skillsResult.error || "Unknown error"}`);
13357
+ logger.info("You can install skills dependencies manually. See INSTALLATION.md");
13184
13358
  }
13185
- } catch (error) {
13186
- logger.warning(`Skills installation failed: ${error instanceof Error ? error.message : String(error)}`);
13359
+ } catch {
13360
+ logger.warning("Skills installation failed");
13187
13361
  logger.info("You can install skills dependencies manually later");
13188
13362
  }
13189
13363
  }
13190
- var execAsync5, execFileAsync, NPM_PACKAGE_REGEX;
13364
+ var execAsync5, execFileAsync, PARTIAL_INSTALL_VERSION = "partial", EXIT_CODE_CRITICAL_FAILURE = 1, EXIT_CODE_PARTIAL_SUCCESS = 2, NPM_PACKAGE_REGEX;
13191
13365
  var init_package_installer = __esm(() => {
13192
13366
  init_environment();
13367
+ init_install_error_handler();
13193
13368
  init_logger();
13194
13369
  execAsync5 = promisify5(exec5);
13195
13370
  execFileAsync = promisify5(execFile2);
@@ -14144,8 +14319,8 @@ var init_help_interceptor = __esm(() => {
14144
14319
  });
14145
14320
 
14146
14321
  // src/index.ts
14147
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
14148
- import { join as join31 } from "path";
14322
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
14323
+ import { join as join33 } from "path";
14149
14324
 
14150
14325
  // node_modules/cac/dist/index.mjs
14151
14326
  import { EventEmitter } from "events";
@@ -14750,7 +14925,7 @@ var cac = (name = "") => new CAC(name);
14750
14925
  // package.json
14751
14926
  var package_default = {
14752
14927
  name: "claudekit-cli",
14753
- version: "3.5.2",
14928
+ version: "3.6.1",
14754
14929
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
14755
14930
  type: "module",
14756
14931
  repository: {
@@ -16459,6 +16634,7 @@ Note: Do NOT use 'Paste an authentication token' - use web browser login.`);
16459
16634
  if (token && token.length > 0) {
16460
16635
  return token;
16461
16636
  }
16637
+ logger.debug("gh auth token returned empty result");
16462
16638
  return null;
16463
16639
  } catch (error) {
16464
16640
  if (error?.stderr) {
@@ -17757,7 +17933,7 @@ async function doctorCommand(options = {}) {
17757
17933
 
17758
17934
  // src/commands/init.ts
17759
17935
  var import_fs_extra17 = __toESM(require_lib(), 1);
17760
- import { join as join26, resolve as resolve4 } from "node:path";
17936
+ import { join as join28, resolve as resolve4 } from "node:path";
17761
17937
 
17762
17938
  // src/lib/commands-prefix.ts
17763
17939
  init_logger();
@@ -29012,7 +29188,7 @@ class FileMerger {
29012
29188
  const isWindows5 = process.platform === "win32";
29013
29189
  let processedContent = content;
29014
29190
  if (this.isGlobal) {
29015
- const homeVar = isWindows5 ? "%USERPROFILE%" : "$HOME";
29191
+ const homeVar = isWindows5 ? '"%USERPROFILE%"' : '"$HOME"';
29016
29192
  processedContent = this.transformClaudePaths(content, homeVar);
29017
29193
  if (processedContent !== content) {
29018
29194
  logger.debug(`Transformed .claude/ paths to ${homeVar}/.claude/ in settings.json for global installation`);
@@ -29031,12 +29207,17 @@ class FileMerger {
29031
29207
  }
29032
29208
  }
29033
29209
  transformClaudePaths(content, prefix) {
29210
+ if (/\.claude\/[^\s"']*[;`$&|><]/.test(content)) {
29211
+ logger.warning("Potentially unsafe characters detected in .claude/ paths");
29212
+ throw new Error("Settings file contains potentially unsafe path characters");
29213
+ }
29034
29214
  let transformed = content;
29035
29215
  const jsonSafePrefix = prefix.includes('"') ? prefix.replace(/"/g, "\\\"") : prefix;
29216
+ const rawPrefix = prefix.replace(/"/g, "");
29036
29217
  transformed = transformed.replace(/(node\s+)(?:\.\/)?\.claude\//g, `$1${jsonSafePrefix}/.claude/`);
29037
- if (prefix.includes("HOME") || prefix.includes("USERPROFILE")) {
29038
- transformed = transformed.replace(/\$CLAUDE_PROJECT_DIR/g, prefix);
29039
- transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%/g, prefix);
29218
+ if (rawPrefix.includes("HOME") || rawPrefix.includes("USERPROFILE")) {
29219
+ transformed = transformed.replace(/\$CLAUDE_PROJECT_DIR/g, rawPrefix);
29220
+ transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%/g, rawPrefix);
29040
29221
  }
29041
29222
  return transformed;
29042
29223
  }
@@ -29905,11 +30086,11 @@ class PromptsManager {
29905
30086
  init_dist2();
29906
30087
  init_logger();
29907
30088
  var import_fs_extra10 = __toESM(require_lib(), 1);
29908
- import { join as join18 } from "node:path";
30089
+ import { join as join20 } from "node:path";
29909
30090
 
29910
30091
  // src/lib/config-generator.ts
29911
30092
  var import_fs_extra9 = __toESM(require_lib(), 1);
29912
- import { join as join17 } from "node:path";
30093
+ import { join as join19 } from "node:path";
29913
30094
  async function generateEnvFile(targetDir, values) {
29914
30095
  const lines = [
29915
30096
  "# Generated by ClaudeKit CLI setup wizard",
@@ -29921,7 +30102,7 @@ async function generateEnvFile(targetDir, values) {
29921
30102
  lines.push(`${key}=${value}`);
29922
30103
  }
29923
30104
  }
29924
- const envPath = join17(targetDir, ".env");
30105
+ const envPath = join19(targetDir, ".env");
29925
30106
  await import_fs_extra9.writeFile(envPath, `${lines.join(`
29926
30107
  `)}
29927
30108
  `, { mode: 384 });
@@ -29992,7 +30173,7 @@ async function parseEnvFile(path9) {
29992
30173
  }
29993
30174
  }
29994
30175
  async function checkGlobalConfig() {
29995
- const globalEnvPath = join18(PathResolver.getGlobalKitDir(), ".env");
30176
+ const globalEnvPath = join20(PathResolver.getGlobalKitDir(), ".env");
29996
30177
  if (!await import_fs_extra10.pathExists(globalEnvPath))
29997
30178
  return false;
29998
30179
  const env2 = await parseEnvFile(globalEnvPath);
@@ -30008,7 +30189,7 @@ async function runSetupWizard(options) {
30008
30189
  let globalEnv = {};
30009
30190
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
30010
30191
  if (!isGlobal) {
30011
- const globalEnvPath = join18(PathResolver.getGlobalKitDir(), ".env");
30192
+ const globalEnvPath = join20(PathResolver.getGlobalKitDir(), ".env");
30012
30193
  if (await import_fs_extra10.pathExists(globalEnvPath)) {
30013
30194
  globalEnv = await parseEnvFile(globalEnvPath);
30014
30195
  }
@@ -30061,7 +30242,7 @@ async function runSetupWizard(options) {
30061
30242
  }
30062
30243
  }
30063
30244
  await generateEnvFile(targetDir, values);
30064
- f2.success(`Configuration saved to ${join18(targetDir, ".env")}`);
30245
+ f2.success(`Configuration saved to ${join20(targetDir, ".env")}`);
30065
30246
  return true;
30066
30247
  }
30067
30248
 
@@ -30069,7 +30250,7 @@ async function runSetupWizard(options) {
30069
30250
  init_logger();
30070
30251
  var import_fs_extra12 = __toESM(require_lib(), 1);
30071
30252
  import { readdir as readdir8 } from "node:fs/promises";
30072
- import { join as join20 } from "node:path";
30253
+ import { join as join22 } from "node:path";
30073
30254
 
30074
30255
  // src/lib/skills-manifest.ts
30075
30256
  init_types2();
@@ -30077,7 +30258,7 @@ init_logger();
30077
30258
  var import_fs_extra11 = __toESM(require_lib(), 1);
30078
30259
  import { createHash as createHash2 } from "node:crypto";
30079
30260
  import { readFile as readFile10, readdir as readdir7, writeFile as writeFile9 } from "node:fs/promises";
30080
- import { join as join19, relative as relative6 } from "node:path";
30261
+ import { join as join21, relative as relative6 } from "node:path";
30081
30262
 
30082
30263
  class SkillsManifestManager {
30083
30264
  static MANIFEST_FILENAME = ".skills-manifest.json";
@@ -30099,12 +30280,12 @@ class SkillsManifestManager {
30099
30280
  return manifest;
30100
30281
  }
30101
30282
  static async writeManifest(skillsDir, manifest) {
30102
- const manifestPath = join19(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30283
+ const manifestPath = join21(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30103
30284
  await writeFile9(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
30104
30285
  logger.debug(`Wrote manifest to: ${manifestPath}`);
30105
30286
  }
30106
30287
  static async readManifest(skillsDir) {
30107
- const manifestPath = join19(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30288
+ const manifestPath = join21(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30108
30289
  if (!await import_fs_extra11.pathExists(manifestPath)) {
30109
30290
  logger.debug(`No manifest found at: ${manifestPath}`);
30110
30291
  return null;
@@ -30127,7 +30308,7 @@ class SkillsManifestManager {
30127
30308
  return "flat";
30128
30309
  }
30129
30310
  for (const dir of dirs.slice(0, 3)) {
30130
- const dirPath = join19(skillsDir, dir.name);
30311
+ const dirPath = join21(skillsDir, dir.name);
30131
30312
  const subEntries = await readdir7(dirPath, { withFileTypes: true });
30132
30313
  const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
30133
30314
  if (hasSubdirs) {
@@ -30146,7 +30327,7 @@ class SkillsManifestManager {
30146
30327
  const entries = await readdir7(skillsDir, { withFileTypes: true });
30147
30328
  for (const entry of entries) {
30148
30329
  if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) {
30149
- const skillPath = join19(skillsDir, entry.name);
30330
+ const skillPath = join21(skillsDir, entry.name);
30150
30331
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
30151
30332
  skills.push({
30152
30333
  name: entry.name,
@@ -30158,11 +30339,11 @@ class SkillsManifestManager {
30158
30339
  const categories = await readdir7(skillsDir, { withFileTypes: true });
30159
30340
  for (const category of categories) {
30160
30341
  if (category.isDirectory() && category.name !== "node_modules" && !category.name.startsWith(".")) {
30161
- const categoryPath = join19(skillsDir, category.name);
30342
+ const categoryPath = join21(skillsDir, category.name);
30162
30343
  const skillEntries = await readdir7(categoryPath, { withFileTypes: true });
30163
30344
  for (const skillEntry of skillEntries) {
30164
30345
  if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
30165
- const skillPath = join19(categoryPath, skillEntry.name);
30346
+ const skillPath = join21(categoryPath, skillEntry.name);
30166
30347
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
30167
30348
  skills.push({
30168
30349
  name: skillEntry.name,
@@ -30192,7 +30373,7 @@ class SkillsManifestManager {
30192
30373
  const files = [];
30193
30374
  const entries = await readdir7(dirPath, { withFileTypes: true });
30194
30375
  for (const entry of entries) {
30195
- const fullPath = join19(dirPath, entry.name);
30376
+ const fullPath = join21(dirPath, entry.name);
30196
30377
  if (entry.name.startsWith(".") || entry.name === "node_modules") {
30197
30378
  continue;
30198
30379
  }
@@ -30435,12 +30616,12 @@ class SkillsMigrationDetector {
30435
30616
  let totalSkillLikeCount = 0;
30436
30617
  const allSkills = [];
30437
30618
  for (const dir of dirs) {
30438
- const dirPath = join20(skillsDir, dir.name);
30619
+ const dirPath = join22(skillsDir, dir.name);
30439
30620
  const subEntries = await readdir8(dirPath, { withFileTypes: true });
30440
30621
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
30441
30622
  if (subdirs.length > 0) {
30442
30623
  for (const subdir of subdirs.slice(0, 3)) {
30443
- const subdirPath = join20(dirPath, subdir.name);
30624
+ const subdirPath = join22(dirPath, subdir.name);
30444
30625
  const subdirFiles = await readdir8(subdirPath, { withFileTypes: true });
30445
30626
  const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
30446
30627
  if (hasSkillMarker) {
@@ -30479,14 +30660,14 @@ init_types2();
30479
30660
  init_logger();
30480
30661
  var import_fs_extra15 = __toESM(require_lib(), 1);
30481
30662
  import { copyFile as copyFile2, mkdir as mkdir7, readdir as readdir11, rm as rm2 } from "node:fs/promises";
30482
- import { join as join23 } from "node:path";
30663
+ import { join as join25 } from "node:path";
30483
30664
 
30484
30665
  // src/lib/skills-backup-manager.ts
30485
30666
  init_types2();
30486
30667
  init_logger();
30487
30668
  var import_fs_extra13 = __toESM(require_lib(), 1);
30488
30669
  import { copyFile, mkdir as mkdir6, readdir as readdir9, rm, stat as stat4 } from "node:fs/promises";
30489
- import { basename as basename2, join as join21, normalize as normalize2 } from "node:path";
30670
+ import { basename as basename2, join as join23, normalize as normalize2 } from "node:path";
30490
30671
  function validatePath2(path9, paramName) {
30491
30672
  if (!path9 || typeof path9 !== "string") {
30492
30673
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -30512,7 +30693,7 @@ class SkillsBackupManager {
30512
30693
  const timestamp = Date.now();
30513
30694
  const randomSuffix = Math.random().toString(36).substring(2, 8);
30514
30695
  const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
30515
- const backupDir = parentDir ? join21(parentDir, backupDirName) : join21(skillsDir, "..", backupDirName);
30696
+ const backupDir = parentDir ? join23(parentDir, backupDirName) : join23(skillsDir, "..", backupDirName);
30516
30697
  logger.info(`Creating backup at: ${backupDir}`);
30517
30698
  try {
30518
30699
  await mkdir6(backupDir, { recursive: true });
@@ -30563,7 +30744,7 @@ class SkillsBackupManager {
30563
30744
  }
30564
30745
  try {
30565
30746
  const entries = await readdir9(parentDir, { withFileTypes: true });
30566
- const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join21(parentDir, entry.name));
30747
+ const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join23(parentDir, entry.name));
30567
30748
  backups.sort().reverse();
30568
30749
  return backups;
30569
30750
  } catch (error) {
@@ -30591,8 +30772,8 @@ class SkillsBackupManager {
30591
30772
  static async copyDirectory(sourceDir, destDir) {
30592
30773
  const entries = await readdir9(sourceDir, { withFileTypes: true });
30593
30774
  for (const entry of entries) {
30594
- const sourcePath = join21(sourceDir, entry.name);
30595
- const destPath = join21(destDir, entry.name);
30775
+ const sourcePath = join23(sourceDir, entry.name);
30776
+ const destPath = join23(destDir, entry.name);
30596
30777
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30597
30778
  continue;
30598
30779
  }
@@ -30608,7 +30789,7 @@ class SkillsBackupManager {
30608
30789
  let size = 0;
30609
30790
  const entries = await readdir9(dirPath, { withFileTypes: true });
30610
30791
  for (const entry of entries) {
30611
- const fullPath = join21(dirPath, entry.name);
30792
+ const fullPath = join23(dirPath, entry.name);
30612
30793
  if (entry.isSymbolicLink()) {
30613
30794
  continue;
30614
30795
  }
@@ -30639,7 +30820,7 @@ var import_fs_extra14 = __toESM(require_lib(), 1);
30639
30820
  import { createHash as createHash3 } from "node:crypto";
30640
30821
  import { createReadStream as createReadStream2 } from "node:fs";
30641
30822
  import { readFile as readFile11, readdir as readdir10 } from "node:fs/promises";
30642
- import { join as join22, normalize as normalize3, relative as relative7 } from "node:path";
30823
+ import { join as join24, normalize as normalize3, relative as relative7 } from "node:path";
30643
30824
  function validatePath3(path9, paramName) {
30644
30825
  if (!path9 || typeof path9 !== "string") {
30645
30826
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -30786,13 +30967,13 @@ class SkillsCustomizationScanner {
30786
30967
  if (dirs.length === 0) {
30787
30968
  return ["flat", []];
30788
30969
  }
30789
- const firstDirPath = join22(skillsDir, dirs[0].name);
30970
+ const firstDirPath = join24(skillsDir, dirs[0].name);
30790
30971
  const subEntries = await readdir10(firstDirPath, { withFileTypes: true });
30791
30972
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
30792
30973
  if (subdirs.length > 0) {
30793
30974
  let skillLikeCount = 0;
30794
30975
  for (const subdir of subdirs.slice(0, 3)) {
30795
- const subdirPath = join22(firstDirPath, subdir.name);
30976
+ const subdirPath = join24(firstDirPath, subdir.name);
30796
30977
  const subdirFiles = await readdir10(subdirPath, { withFileTypes: true });
30797
30978
  const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
30798
30979
  if (hasSkillMarker) {
@@ -30802,7 +30983,7 @@ class SkillsCustomizationScanner {
30802
30983
  if (skillLikeCount > 0) {
30803
30984
  const skills = [];
30804
30985
  for (const dir of dirs) {
30805
- const categoryPath = join22(skillsDir, dir.name);
30986
+ const categoryPath = join24(skillsDir, dir.name);
30806
30987
  const skillDirs = await readdir10(categoryPath, { withFileTypes: true });
30807
30988
  skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
30808
30989
  }
@@ -30812,7 +30993,7 @@ class SkillsCustomizationScanner {
30812
30993
  return ["flat", dirs.map((dir) => dir.name)];
30813
30994
  }
30814
30995
  static async findSkillPath(skillsDir, skillName) {
30815
- const flatPath = join22(skillsDir, skillName);
30996
+ const flatPath = join24(skillsDir, skillName);
30816
30997
  if (await import_fs_extra14.pathExists(flatPath)) {
30817
30998
  return { path: flatPath, category: undefined };
30818
30999
  }
@@ -30821,8 +31002,8 @@ class SkillsCustomizationScanner {
30821
31002
  if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
30822
31003
  continue;
30823
31004
  }
30824
- const categoryPath = join22(skillsDir, entry.name);
30825
- const skillPath = join22(categoryPath, skillName);
31005
+ const categoryPath = join24(skillsDir, entry.name);
31006
+ const skillPath = join24(categoryPath, skillName);
30826
31007
  if (await import_fs_extra14.pathExists(skillPath)) {
30827
31008
  return { path: skillPath, category: entry.name };
30828
31009
  }
@@ -30833,7 +31014,7 @@ class SkillsCustomizationScanner {
30833
31014
  const files = [];
30834
31015
  const entries = await readdir10(dirPath, { withFileTypes: true });
30835
31016
  for (const entry of entries) {
30836
- const fullPath = join22(dirPath, entry.name);
31017
+ const fullPath = join24(dirPath, entry.name);
30837
31018
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30838
31019
  continue;
30839
31020
  }
@@ -31076,7 +31257,7 @@ class SkillsMigrator {
31076
31257
  }
31077
31258
  }
31078
31259
  if (options.backup && !options.dryRun) {
31079
- const claudeDir = join23(currentSkillsDir, "..");
31260
+ const claudeDir = join25(currentSkillsDir, "..");
31080
31261
  result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir);
31081
31262
  logger.success(`Backup created at: ${result.backupPath}`);
31082
31263
  }
@@ -31128,7 +31309,7 @@ class SkillsMigrator {
31128
31309
  const migrated = [];
31129
31310
  const preserved = [];
31130
31311
  const errors2 = [];
31131
- const tempDir = join23(currentSkillsDir, "..", ".skills-migration-temp");
31312
+ const tempDir = join25(currentSkillsDir, "..", ".skills-migration-temp");
31132
31313
  await mkdir7(tempDir, { recursive: true });
31133
31314
  try {
31134
31315
  for (const mapping of mappings) {
@@ -31149,9 +31330,9 @@ class SkillsMigrator {
31149
31330
  }
31150
31331
  }
31151
31332
  const category = mapping.category;
31152
- const targetPath = category ? join23(tempDir, category, skillName) : join23(tempDir, skillName);
31333
+ const targetPath = category ? join25(tempDir, category, skillName) : join25(tempDir, skillName);
31153
31334
  if (category) {
31154
- await mkdir7(join23(tempDir, category), { recursive: true });
31335
+ await mkdir7(join25(tempDir, category), { recursive: true });
31155
31336
  }
31156
31337
  await SkillsMigrator.copySkillDirectory(currentSkillPath, targetPath);
31157
31338
  migrated.push(skillName);
@@ -31185,8 +31366,8 @@ class SkillsMigrator {
31185
31366
  await mkdir7(destDir, { recursive: true });
31186
31367
  const entries = await readdir11(sourceDir, { withFileTypes: true });
31187
31368
  for (const entry of entries) {
31188
- const sourcePath = join23(sourceDir, entry.name);
31189
- const destPath = join23(destDir, entry.name);
31369
+ const sourcePath = join25(sourceDir, entry.name);
31370
+ const destPath = join25(destDir, entry.name);
31190
31371
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
31191
31372
  continue;
31192
31373
  }
@@ -31205,18 +31386,18 @@ init_types2();
31205
31386
  // src/utils/config.ts
31206
31387
  init_types2();
31207
31388
  init_logger();
31208
- import { existsSync as existsSync5 } from "node:fs";
31389
+ import { existsSync as existsSync6 } from "node:fs";
31209
31390
  import { mkdir as mkdir8, readFile as readFile12, rename as rename2, rm as rm3, writeFile as writeFile10 } from "node:fs/promises";
31210
31391
  import { chmod as chmod2 } from "node:fs/promises";
31211
31392
  import { platform as platform8 } from "node:os";
31212
- import { join as join24 } from "node:path";
31393
+ import { join as join26 } from "node:path";
31213
31394
  var PROJECT_CONFIG_FILE = ".ck.json";
31214
31395
 
31215
31396
  class ConfigManager {
31216
31397
  static config = null;
31217
31398
  static globalFlag = false;
31218
31399
  static getProjectConfigDir(projectDir, global3) {
31219
- return global3 ? projectDir : join24(projectDir, ".claude");
31400
+ return global3 ? projectDir : join26(projectDir, ".claude");
31220
31401
  }
31221
31402
  static setGlobalFlag(global3) {
31222
31403
  ConfigManager.globalFlag = global3;
@@ -31231,7 +31412,7 @@ class ConfigManager {
31231
31412
  }
31232
31413
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
31233
31414
  try {
31234
- if (existsSync5(configFile)) {
31415
+ if (existsSync6(configFile)) {
31235
31416
  const content = await readFile12(configFile, "utf-8");
31236
31417
  const data = JSON.parse(content);
31237
31418
  ConfigManager.config = ConfigSchema.parse(data);
@@ -31249,7 +31430,7 @@ class ConfigManager {
31249
31430
  const validConfig = ConfigSchema.parse(config);
31250
31431
  const configDir = PathResolver.getConfigDir(ConfigManager.globalFlag);
31251
31432
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
31252
- if (!existsSync5(configDir)) {
31433
+ if (!existsSync6(configDir)) {
31253
31434
  await mkdir8(configDir, { recursive: true });
31254
31435
  if (platform8() !== "win32") {
31255
31436
  await chmod2(configDir, 448);
@@ -31283,9 +31464,9 @@ class ConfigManager {
31283
31464
  }
31284
31465
  static async loadProjectConfig(projectDir, global3 = false) {
31285
31466
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
31286
- const configPath = join24(configDir, PROJECT_CONFIG_FILE);
31467
+ const configPath = join26(configDir, PROJECT_CONFIG_FILE);
31287
31468
  try {
31288
- if (existsSync5(configPath)) {
31469
+ if (existsSync6(configPath)) {
31289
31470
  const content = await readFile12(configPath, "utf-8");
31290
31471
  const data = JSON.parse(content);
31291
31472
  const folders = FoldersConfigSchema.parse(data.paths || data);
@@ -31299,9 +31480,9 @@ class ConfigManager {
31299
31480
  }
31300
31481
  static async saveProjectConfig(projectDir, folders, global3 = false) {
31301
31482
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
31302
- const configPath = join24(configDir, PROJECT_CONFIG_FILE);
31483
+ const configPath = join26(configDir, PROJECT_CONFIG_FILE);
31303
31484
  try {
31304
- if (!existsSync5(configDir)) {
31485
+ if (!existsSync6(configDir)) {
31305
31486
  await mkdir8(configDir, { recursive: true });
31306
31487
  }
31307
31488
  const validFolders = FoldersConfigSchema.parse(folders);
@@ -31331,21 +31512,21 @@ class ConfigManager {
31331
31512
  }
31332
31513
  static projectConfigExists(projectDir, global3 = false) {
31333
31514
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
31334
- return existsSync5(join24(configDir, PROJECT_CONFIG_FILE));
31515
+ return existsSync6(join26(configDir, PROJECT_CONFIG_FILE));
31335
31516
  }
31336
31517
  static async migrateNestedConfig(globalDir) {
31337
- const correctPath = join24(globalDir, PROJECT_CONFIG_FILE);
31338
- const incorrectPath = join24(globalDir, ".claude", PROJECT_CONFIG_FILE);
31339
- if (existsSync5(correctPath)) {
31518
+ const correctPath = join26(globalDir, PROJECT_CONFIG_FILE);
31519
+ const incorrectPath = join26(globalDir, ".claude", PROJECT_CONFIG_FILE);
31520
+ if (existsSync6(correctPath)) {
31340
31521
  logger.debug("Config already exists at correct location, skipping migration");
31341
31522
  return false;
31342
31523
  }
31343
- if (existsSync5(incorrectPath)) {
31524
+ if (existsSync6(incorrectPath)) {
31344
31525
  try {
31345
31526
  logger.info("Migrating .ck.json from nested location to correct location...");
31346
31527
  await rename2(incorrectPath, correctPath);
31347
31528
  logger.success(`Migrated ${PROJECT_CONFIG_FILE} to ${correctPath}`);
31348
- const nestedClaudeDir = join24(globalDir, ".claude");
31529
+ const nestedClaudeDir = join26(globalDir, ".claude");
31349
31530
  try {
31350
31531
  await rm3(nestedClaudeDir, { recursive: false });
31351
31532
  logger.debug("Removed empty nested .claude directory");
@@ -31368,7 +31549,7 @@ init_environment();
31368
31549
  // src/utils/file-scanner.ts
31369
31550
  init_logger();
31370
31551
  var import_fs_extra16 = __toESM(require_lib(), 1);
31371
- import { join as join25, relative as relative8, resolve as resolve3 } from "node:path";
31552
+ import { join as join27, relative as relative8, resolve as resolve3 } from "node:path";
31372
31553
  var SKIP_DIRS = [
31373
31554
  "node_modules",
31374
31555
  ".venv",
@@ -31395,7 +31576,7 @@ class FileScanner {
31395
31576
  logger.debug(`Skipping directory: ${entry}`);
31396
31577
  continue;
31397
31578
  }
31398
- const fullPath = join25(dirPath, entry);
31579
+ const fullPath = join27(dirPath, entry);
31399
31580
  if (!FileScanner.isSafePath(basePath, fullPath)) {
31400
31581
  logger.warning(`Skipping potentially unsafe path: ${entry}`);
31401
31582
  continue;
@@ -31430,14 +31611,27 @@ class FileScanner {
31430
31611
  return files;
31431
31612
  }
31432
31613
  static async findCustomFiles(destDir, sourceDir, subPath) {
31433
- const destSubDir = join25(destDir, subPath);
31434
- const sourceSubDir = join25(sourceDir, subPath);
31614
+ const destSubDir = join27(destDir, subPath);
31615
+ const sourceSubDir = join27(sourceDir, subPath);
31616
+ logger.debug(`findCustomFiles - destDir: ${destDir}`);
31617
+ logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
31618
+ logger.debug(`findCustomFiles - subPath: "${subPath}"`);
31619
+ logger.debug(`findCustomFiles - destSubDir: ${destSubDir}`);
31620
+ logger.debug(`findCustomFiles - sourceSubDir: ${sourceSubDir}`);
31435
31621
  const destFiles = await FileScanner.getFiles(destSubDir, destDir);
31436
31622
  const sourceFiles = await FileScanner.getFiles(sourceSubDir, sourceDir);
31623
+ logger.debug(`findCustomFiles - destFiles count: ${destFiles.length}`);
31624
+ logger.debug(`findCustomFiles - sourceFiles count: ${sourceFiles.length}`);
31625
+ const sourceExists = await import_fs_extra16.pathExists(sourceSubDir);
31626
+ if (sourceExists && sourceFiles.length === 0 && destFiles.length > 100) {
31627
+ logger.warning(`Source directory exists but is empty while destination has ${destFiles.length} files. This may indicate an extraction issue. Skipping custom file detection.`);
31628
+ return [];
31629
+ }
31437
31630
  const sourceFileSet = new Set(sourceFiles);
31438
31631
  const customFiles = destFiles.filter((file) => !sourceFileSet.has(file));
31439
31632
  if (customFiles.length > 0) {
31440
- logger.info(`Found ${customFiles.length} custom file(s) in ${subPath}/`);
31633
+ const displayPath = subPath || destSubDir;
31634
+ logger.info(`Found ${customFiles.length} custom file(s) in ${displayPath}`);
31441
31635
  customFiles.slice(0, 5).forEach((file) => logger.debug(` - ${file}`));
31442
31636
  if (customFiles.length > 5) {
31443
31637
  logger.debug(` ... and ${customFiles.length - 5} more`);
@@ -31472,8 +31666,11 @@ async function initCommand(options) {
31472
31666
  logger.info("Running in non-interactive mode (--yes flag)");
31473
31667
  }
31474
31668
  if (validOptions.global) {
31475
- const localSettingsPath = join26(process.cwd(), ".claude", "settings.json");
31476
- if (await import_fs_extra17.pathExists(localSettingsPath)) {
31669
+ const globalKitDir = PathResolver.getGlobalKitDir();
31670
+ const cwdResolved = resolve4(process.cwd());
31671
+ const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved === resolve4(globalKitDir, "..");
31672
+ const localSettingsPath = join28(process.cwd(), ".claude", "settings.json");
31673
+ if (!isInGlobalDir && await import_fs_extra17.pathExists(localSettingsPath)) {
31477
31674
  if (isNonInteractive2) {
31478
31675
  logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
31479
31676
  logger.warning("Consider removing local installation: rm -rf .claude");
@@ -31484,7 +31681,7 @@ async function initCommand(options) {
31484
31681
  return;
31485
31682
  }
31486
31683
  if (choice === "remove") {
31487
- const localClaudeDir = join26(process.cwd(), ".claude");
31684
+ const localClaudeDir = join28(process.cwd(), ".claude");
31488
31685
  try {
31489
31686
  await import_fs_extra17.remove(localClaudeDir);
31490
31687
  logger.success("Removed local .claude/ directory");
@@ -31543,7 +31740,7 @@ async function initCommand(options) {
31543
31740
  }
31544
31741
  if (validOptions.fresh) {
31545
31742
  const prefix = PathResolver.getPathPrefix(validOptions.global);
31546
- const claudeDir2 = prefix ? join26(resolvedDir, prefix) : resolvedDir;
31743
+ const claudeDir2 = prefix ? join28(resolvedDir, prefix) : resolvedDir;
31547
31744
  const canProceed = await handleFreshInstallation(claudeDir2, prompts);
31548
31745
  if (!canProceed) {
31549
31746
  return;
@@ -31680,7 +31877,7 @@ async function initCommand(options) {
31680
31877
  }
31681
31878
  }
31682
31879
  if (!validOptions.fresh) {
31683
- const newSkillsDir = join26(extractDir, ".claude", "skills");
31880
+ const newSkillsDir = join28(extractDir, ".claude", "skills");
31684
31881
  const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
31685
31882
  if (await import_fs_extra17.pathExists(newSkillsDir) && await import_fs_extra17.pathExists(currentSkillsDir)) {
31686
31883
  logger.info("Checking for skills directory migration...");
@@ -31705,7 +31902,7 @@ async function initCommand(options) {
31705
31902
  let customClaudeFiles = [];
31706
31903
  if (!validOptions.fresh) {
31707
31904
  logger.info("Scanning for custom .claude files...");
31708
- const scanSourceDir = validOptions.global ? join26(extractDir, ".claude") : extractDir;
31905
+ const scanSourceDir = validOptions.global ? join28(extractDir, ".claude") : extractDir;
31709
31906
  const scanTargetSubdir = validOptions.global ? "" : ".claude";
31710
31907
  customClaudeFiles = await FileScanner.findCustomFiles(resolvedDir, scanSourceDir, scanTargetSubdir);
31711
31908
  } else {
@@ -31734,7 +31931,7 @@ async function initCommand(options) {
31734
31931
  merger.addIgnorePatterns(validOptions.exclude);
31735
31932
  }
31736
31933
  merger.setGlobalFlag(validOptions.global);
31737
- const claudeDir = validOptions.global ? resolvedDir : join26(resolvedDir, ".claude");
31934
+ const claudeDir = validOptions.global ? resolvedDir : join28(resolvedDir, ".claude");
31738
31935
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
31739
31936
  if (!validOptions.fresh && await import_fs_extra17.pathExists(claudeDir)) {
31740
31937
  const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
@@ -31756,7 +31953,7 @@ async function initCommand(options) {
31756
31953
  return;
31757
31954
  }
31758
31955
  }
31759
- const sourceDir = validOptions.global ? join26(extractDir, ".claude") : extractDir;
31956
+ const sourceDir = validOptions.global ? join28(extractDir, ".claude") : extractDir;
31760
31957
  await merger.merge(sourceDir, resolvedDir, false);
31761
31958
  const manifestWriter = new ManifestWriter;
31762
31959
  const installedFiles = merger.getAllInstalledFiles();
@@ -31765,7 +31962,7 @@ async function initCommand(options) {
31765
31962
  if (!validOptions.global && !installedPath.startsWith(".claude/"))
31766
31963
  continue;
31767
31964
  const relativePath = validOptions.global ? installedPath : installedPath.replace(/^\.claude\//, "");
31768
- const filePath = join26(claudeDir, relativePath);
31965
+ const filePath = join28(claudeDir, relativePath);
31769
31966
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
31770
31967
  const ownership = manifestEntry ? "ck" : "user";
31771
31968
  filesToTrack.push({
@@ -31786,8 +31983,8 @@ async function initCommand(options) {
31786
31983
  trackingSpinner.succeed(`Tracked ${trackResult.success} files`);
31787
31984
  await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local");
31788
31985
  if (validOptions.global) {
31789
- const claudeMdSource = join26(extractDir, "CLAUDE.md");
31790
- const claudeMdDest = join26(resolvedDir, "CLAUDE.md");
31986
+ const claudeMdSource = join28(extractDir, "CLAUDE.md");
31987
+ const claudeMdDest = join28(resolvedDir, "CLAUDE.md");
31791
31988
  if (await import_fs_extra17.pathExists(claudeMdSource)) {
31792
31989
  if (!await import_fs_extra17.pathExists(claudeMdDest)) {
31793
31990
  await import_fs_extra17.copy(claudeMdSource, claudeMdDest);
@@ -31807,7 +32004,7 @@ async function initCommand(options) {
31807
32004
  await handleSkillsInstallation2(skillsDir);
31808
32005
  }
31809
32006
  if (!validOptions.skipSetup && !isNonInteractive2) {
31810
- const envPath = join26(claudeDir, ".env");
32007
+ const envPath = join28(claudeDir, ".env");
31811
32008
  if (!await import_fs_extra17.pathExists(envPath)) {
31812
32009
  const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
31813
32010
  if (shouldSetup) {
@@ -31839,7 +32036,7 @@ Protected files (.env, etc.) were not modified.`;
31839
32036
 
31840
32037
  // src/commands/new.ts
31841
32038
  var import_fs_extra18 = __toESM(require_lib(), 1);
31842
- import { join as join27, resolve as resolve5 } from "node:path";
32039
+ import { join as join29, resolve as resolve5 } from "node:path";
31843
32040
  init_types2();
31844
32041
  init_environment();
31845
32042
  init_logger();
@@ -32010,7 +32207,7 @@ async function newCommand(options) {
32010
32207
  await CommandsPrefix.cleanupCommandsDirectory(resolvedDir, false);
32011
32208
  }
32012
32209
  await merger.merge(extractDir, resolvedDir, true);
32013
- const claudeDir = join27(resolvedDir, ".claude");
32210
+ const claudeDir = join29(resolvedDir, ".claude");
32014
32211
  const manifestWriter = new ManifestWriter;
32015
32212
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
32016
32213
  const installedFiles = merger.getAllInstalledFiles();
@@ -32019,7 +32216,7 @@ async function newCommand(options) {
32019
32216
  if (!installedPath.startsWith(".claude/"))
32020
32217
  continue;
32021
32218
  const relativePath = installedPath.replace(/^\.claude\//, "");
32022
- const filePath = join27(claudeDir, relativePath);
32219
+ const filePath = join29(claudeDir, relativePath);
32023
32220
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
32024
32221
  const ownership = manifestEntry ? "ck" : "user";
32025
32222
  filesToTrack.push({
@@ -32075,7 +32272,7 @@ init_dist2();
32075
32272
  var import_fs_extra19 = __toESM(require_lib(), 1);
32076
32273
  var import_picocolors10 = __toESM(require_picocolors(), 1);
32077
32274
  import { readdirSync, rmSync } from "node:fs";
32078
- import { dirname as dirname4, join as join28 } from "node:path";
32275
+ import { dirname as dirname4, join as join30 } from "node:path";
32079
32276
  init_types2();
32080
32277
  init_logger();
32081
32278
  async function detectInstallations() {
@@ -32166,7 +32363,7 @@ async function analyzeInstallation(installation, forceOverwrite) {
32166
32363
  return result;
32167
32364
  }
32168
32365
  for (const trackedFile of metadata.files) {
32169
- const filePath = join28(installation.path, trackedFile.path);
32366
+ const filePath = join30(installation.path, trackedFile.path);
32170
32367
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
32171
32368
  if (!ownershipResult.exists)
32172
32369
  continue;
@@ -32224,7 +32421,7 @@ async function removeInstallations(installations, options) {
32224
32421
  let removedCount = 0;
32225
32422
  let cleanedDirs = 0;
32226
32423
  for (const item of analysis.toDelete) {
32227
- const filePath = join28(installation.path, item.path);
32424
+ const filePath = join30(installation.path, item.path);
32228
32425
  if (await import_fs_extra19.pathExists(filePath)) {
32229
32426
  await import_fs_extra19.remove(filePath);
32230
32427
  removedCount++;
@@ -32326,7 +32523,7 @@ import { promisify as promisify6 } from "node:util";
32326
32523
  // package.json
32327
32524
  var package_default2 = {
32328
32525
  name: "claudekit-cli",
32329
- version: "3.5.2",
32526
+ version: "3.6.1",
32330
32527
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
32331
32528
  type: "module",
32332
32529
  repository: {
@@ -32771,20 +32968,20 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
32771
32968
 
32772
32969
  // src/lib/version-cache.ts
32773
32970
  init_logger();
32774
- import { existsSync as existsSync6 } from "node:fs";
32971
+ import { existsSync as existsSync7 } from "node:fs";
32775
32972
  import { mkdir as mkdir9, readFile as readFile13, writeFile as writeFile11 } from "node:fs/promises";
32776
- import { join as join29 } from "node:path";
32973
+ import { join as join31 } from "node:path";
32777
32974
  class VersionCacheManager {
32778
32975
  static CACHE_FILENAME = "version-check.json";
32779
32976
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
32780
32977
  static getCacheFile() {
32781
32978
  const cacheDir = PathResolver.getCacheDir(false);
32782
- return join29(cacheDir, VersionCacheManager.CACHE_FILENAME);
32979
+ return join31(cacheDir, VersionCacheManager.CACHE_FILENAME);
32783
32980
  }
32784
32981
  static async load() {
32785
32982
  const cacheFile = VersionCacheManager.getCacheFile();
32786
32983
  try {
32787
- if (!existsSync6(cacheFile)) {
32984
+ if (!existsSync7(cacheFile)) {
32788
32985
  logger.debug("Version check cache not found");
32789
32986
  return null;
32790
32987
  }
@@ -32805,7 +33002,7 @@ class VersionCacheManager {
32805
33002
  const cacheFile = VersionCacheManager.getCacheFile();
32806
33003
  const cacheDir = PathResolver.getCacheDir(false);
32807
33004
  try {
32808
- if (!existsSync6(cacheDir)) {
33005
+ if (!existsSync7(cacheDir)) {
32809
33006
  await mkdir9(cacheDir, { recursive: true, mode: 448 });
32810
33007
  }
32811
33008
  await writeFile11(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
@@ -32827,7 +33024,7 @@ class VersionCacheManager {
32827
33024
  static async clear() {
32828
33025
  const cacheFile = VersionCacheManager.getCacheFile();
32829
33026
  try {
32830
- if (existsSync6(cacheFile)) {
33027
+ if (existsSync7(cacheFile)) {
32831
33028
  const fs12 = await import("node:fs/promises");
32832
33029
  await fs12.unlink(cacheFile);
32833
33030
  logger.debug("Version check cache cleared");
@@ -33255,7 +33452,7 @@ var logger2 = new Logger2;
33255
33452
 
33256
33453
  // src/utils/path-resolver.ts
33257
33454
  import { homedir as homedir2, platform as platform9 } from "node:os";
33258
- import { join as join30, normalize as normalize4 } from "node:path";
33455
+ import { join as join32, normalize as normalize4 } from "node:path";
33259
33456
 
33260
33457
  class PathResolver2 {
33261
33458
  static getTestHomeDir() {
@@ -33288,50 +33485,50 @@ class PathResolver2 {
33288
33485
  static getConfigDir(global3 = false) {
33289
33486
  const testHome = PathResolver2.getTestHomeDir();
33290
33487
  if (testHome) {
33291
- return global3 ? join30(testHome, ".config", "claude") : join30(testHome, ".claudekit");
33488
+ return global3 ? join32(testHome, ".config", "claude") : join32(testHome, ".claudekit");
33292
33489
  }
33293
33490
  if (!global3) {
33294
- return join30(homedir2(), ".claudekit");
33491
+ return join32(homedir2(), ".claudekit");
33295
33492
  }
33296
33493
  const os2 = platform9();
33297
33494
  if (os2 === "win32") {
33298
- const localAppData = process.env.LOCALAPPDATA || join30(homedir2(), "AppData", "Local");
33299
- return join30(localAppData, "claude");
33495
+ const localAppData = process.env.LOCALAPPDATA || join32(homedir2(), "AppData", "Local");
33496
+ return join32(localAppData, "claude");
33300
33497
  }
33301
33498
  const xdgConfigHome = process.env.XDG_CONFIG_HOME;
33302
33499
  if (xdgConfigHome) {
33303
- return join30(xdgConfigHome, "claude");
33500
+ return join32(xdgConfigHome, "claude");
33304
33501
  }
33305
- return join30(homedir2(), ".config", "claude");
33502
+ return join32(homedir2(), ".config", "claude");
33306
33503
  }
33307
33504
  static getConfigFile(global3 = false) {
33308
- return join30(PathResolver2.getConfigDir(global3), "config.json");
33505
+ return join32(PathResolver2.getConfigDir(global3), "config.json");
33309
33506
  }
33310
33507
  static getCacheDir(global3 = false) {
33311
33508
  const testHome = PathResolver2.getTestHomeDir();
33312
33509
  if (testHome) {
33313
- return global3 ? join30(testHome, ".cache", "claude") : join30(testHome, ".claudekit", "cache");
33510
+ return global3 ? join32(testHome, ".cache", "claude") : join32(testHome, ".claudekit", "cache");
33314
33511
  }
33315
33512
  if (!global3) {
33316
- return join30(homedir2(), ".claudekit", "cache");
33513
+ return join32(homedir2(), ".claudekit", "cache");
33317
33514
  }
33318
33515
  const os2 = platform9();
33319
33516
  if (os2 === "win32") {
33320
- const localAppData = process.env.LOCALAPPDATA || join30(homedir2(), "AppData", "Local");
33321
- return join30(localAppData, "claude", "cache");
33517
+ const localAppData = process.env.LOCALAPPDATA || join32(homedir2(), "AppData", "Local");
33518
+ return join32(localAppData, "claude", "cache");
33322
33519
  }
33323
33520
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
33324
33521
  if (xdgCacheHome) {
33325
- return join30(xdgCacheHome, "claude");
33522
+ return join32(xdgCacheHome, "claude");
33326
33523
  }
33327
- return join30(homedir2(), ".cache", "claude");
33524
+ return join32(homedir2(), ".cache", "claude");
33328
33525
  }
33329
33526
  static getGlobalKitDir() {
33330
33527
  const testHome = PathResolver2.getTestHomeDir();
33331
33528
  if (testHome) {
33332
- return join30(testHome, ".claude");
33529
+ return join32(testHome, ".claude");
33333
33530
  }
33334
- return join30(homedir2(), ".claude");
33531
+ return join32(homedir2(), ".claude");
33335
33532
  }
33336
33533
  static getPathPrefix(global3) {
33337
33534
  return global3 ? "" : ".claude";
@@ -33339,9 +33536,9 @@ class PathResolver2 {
33339
33536
  static buildSkillsPath(baseDir, global3) {
33340
33537
  const prefix = PathResolver2.getPathPrefix(global3);
33341
33538
  if (prefix) {
33342
- return join30(baseDir, prefix, "skills");
33539
+ return join32(baseDir, prefix, "skills");
33343
33540
  }
33344
- return join30(baseDir, "skills");
33541
+ return join32(baseDir, "skills");
33345
33542
  }
33346
33543
  static buildComponentPath(baseDir, component, global3) {
33347
33544
  if (!PathResolver2.isPathSafe(component)) {
@@ -33349,9 +33546,9 @@ class PathResolver2 {
33349
33546
  }
33350
33547
  const prefix = PathResolver2.getPathPrefix(global3);
33351
33548
  if (prefix) {
33352
- return join30(baseDir, prefix, component);
33549
+ return join32(baseDir, prefix, component);
33353
33550
  }
33354
- return join30(baseDir, component);
33551
+ return join32(baseDir, component);
33355
33552
  }
33356
33553
  }
33357
33554
 
@@ -33369,13 +33566,13 @@ async function displayVersion() {
33369
33566
  let localKitVersion = null;
33370
33567
  let isGlobalOnlyKit = false;
33371
33568
  const globalKitDir = PathResolver2.getGlobalKitDir();
33372
- const globalMetadataPath = join31(globalKitDir, "metadata.json");
33569
+ const globalMetadataPath = join33(globalKitDir, "metadata.json");
33373
33570
  const prefix = PathResolver2.getPathPrefix(false);
33374
- const localMetadataPath = prefix ? join31(process.cwd(), prefix, "metadata.json") : join31(process.cwd(), "metadata.json");
33571
+ const localMetadataPath = prefix ? join33(process.cwd(), prefix, "metadata.json") : join33(process.cwd(), "metadata.json");
33375
33572
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
33376
- if (!isLocalSameAsGlobal && existsSync7(localMetadataPath)) {
33573
+ if (!isLocalSameAsGlobal && existsSync8(localMetadataPath)) {
33377
33574
  try {
33378
- const rawMetadata = JSON.parse(readFileSync4(localMetadataPath, "utf-8"));
33575
+ const rawMetadata = JSON.parse(readFileSync5(localMetadataPath, "utf-8"));
33379
33576
  const metadata = MetadataSchema2.parse(rawMetadata);
33380
33577
  if (metadata.version) {
33381
33578
  const kitName = metadata.name || "ClaudeKit";
@@ -33387,9 +33584,9 @@ async function displayVersion() {
33387
33584
  logger2.verbose("Failed to parse local metadata.json", { error });
33388
33585
  }
33389
33586
  }
33390
- if (existsSync7(globalMetadataPath)) {
33587
+ if (existsSync8(globalMetadataPath)) {
33391
33588
  try {
33392
- const rawMetadata = JSON.parse(readFileSync4(globalMetadataPath, "utf-8"));
33589
+ const rawMetadata = JSON.parse(readFileSync5(globalMetadataPath, "utf-8"));
33393
33590
  const metadata = MetadataSchema2.parse(rawMetadata);
33394
33591
  if (metadata.version) {
33395
33592
  const kitName = metadata.name || "ClaudeKit";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.5.2",
3
+ "version": "3.6.1",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {