claudekit-cli 3.5.2 → 3.6.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 +314 -134
  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.0",
14754
14929
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
14755
14930
  type: "module",
14756
14931
  repository: {
@@ -17757,7 +17932,7 @@ async function doctorCommand(options = {}) {
17757
17932
 
17758
17933
  // src/commands/init.ts
17759
17934
  var import_fs_extra17 = __toESM(require_lib(), 1);
17760
- import { join as join26, resolve as resolve4 } from "node:path";
17935
+ import { join as join28, resolve as resolve4 } from "node:path";
17761
17936
 
17762
17937
  // src/lib/commands-prefix.ts
17763
17938
  init_logger();
@@ -29012,7 +29187,7 @@ class FileMerger {
29012
29187
  const isWindows5 = process.platform === "win32";
29013
29188
  let processedContent = content;
29014
29189
  if (this.isGlobal) {
29015
- const homeVar = isWindows5 ? "%USERPROFILE%" : "$HOME";
29190
+ const homeVar = isWindows5 ? '"%USERPROFILE%"' : '"$HOME"';
29016
29191
  processedContent = this.transformClaudePaths(content, homeVar);
29017
29192
  if (processedContent !== content) {
29018
29193
  logger.debug(`Transformed .claude/ paths to ${homeVar}/.claude/ in settings.json for global installation`);
@@ -29031,12 +29206,17 @@ class FileMerger {
29031
29206
  }
29032
29207
  }
29033
29208
  transformClaudePaths(content, prefix) {
29209
+ if (/\.claude\/[^\s"']*[;`$&|><]/.test(content)) {
29210
+ logger.warning("Potentially unsafe characters detected in .claude/ paths");
29211
+ throw new Error("Settings file contains potentially unsafe path characters");
29212
+ }
29034
29213
  let transformed = content;
29035
29214
  const jsonSafePrefix = prefix.includes('"') ? prefix.replace(/"/g, "\\\"") : prefix;
29215
+ const rawPrefix = prefix.replace(/"/g, "");
29036
29216
  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);
29217
+ if (rawPrefix.includes("HOME") || rawPrefix.includes("USERPROFILE")) {
29218
+ transformed = transformed.replace(/\$CLAUDE_PROJECT_DIR/g, rawPrefix);
29219
+ transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%/g, rawPrefix);
29040
29220
  }
29041
29221
  return transformed;
29042
29222
  }
@@ -29905,11 +30085,11 @@ class PromptsManager {
29905
30085
  init_dist2();
29906
30086
  init_logger();
29907
30087
  var import_fs_extra10 = __toESM(require_lib(), 1);
29908
- import { join as join18 } from "node:path";
30088
+ import { join as join20 } from "node:path";
29909
30089
 
29910
30090
  // src/lib/config-generator.ts
29911
30091
  var import_fs_extra9 = __toESM(require_lib(), 1);
29912
- import { join as join17 } from "node:path";
30092
+ import { join as join19 } from "node:path";
29913
30093
  async function generateEnvFile(targetDir, values) {
29914
30094
  const lines = [
29915
30095
  "# Generated by ClaudeKit CLI setup wizard",
@@ -29921,7 +30101,7 @@ async function generateEnvFile(targetDir, values) {
29921
30101
  lines.push(`${key}=${value}`);
29922
30102
  }
29923
30103
  }
29924
- const envPath = join17(targetDir, ".env");
30104
+ const envPath = join19(targetDir, ".env");
29925
30105
  await import_fs_extra9.writeFile(envPath, `${lines.join(`
29926
30106
  `)}
29927
30107
  `, { mode: 384 });
@@ -29992,7 +30172,7 @@ async function parseEnvFile(path9) {
29992
30172
  }
29993
30173
  }
29994
30174
  async function checkGlobalConfig() {
29995
- const globalEnvPath = join18(PathResolver.getGlobalKitDir(), ".env");
30175
+ const globalEnvPath = join20(PathResolver.getGlobalKitDir(), ".env");
29996
30176
  if (!await import_fs_extra10.pathExists(globalEnvPath))
29997
30177
  return false;
29998
30178
  const env2 = await parseEnvFile(globalEnvPath);
@@ -30008,7 +30188,7 @@ async function runSetupWizard(options) {
30008
30188
  let globalEnv = {};
30009
30189
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
30010
30190
  if (!isGlobal) {
30011
- const globalEnvPath = join18(PathResolver.getGlobalKitDir(), ".env");
30191
+ const globalEnvPath = join20(PathResolver.getGlobalKitDir(), ".env");
30012
30192
  if (await import_fs_extra10.pathExists(globalEnvPath)) {
30013
30193
  globalEnv = await parseEnvFile(globalEnvPath);
30014
30194
  }
@@ -30061,7 +30241,7 @@ async function runSetupWizard(options) {
30061
30241
  }
30062
30242
  }
30063
30243
  await generateEnvFile(targetDir, values);
30064
- f2.success(`Configuration saved to ${join18(targetDir, ".env")}`);
30244
+ f2.success(`Configuration saved to ${join20(targetDir, ".env")}`);
30065
30245
  return true;
30066
30246
  }
30067
30247
 
@@ -30069,7 +30249,7 @@ async function runSetupWizard(options) {
30069
30249
  init_logger();
30070
30250
  var import_fs_extra12 = __toESM(require_lib(), 1);
30071
30251
  import { readdir as readdir8 } from "node:fs/promises";
30072
- import { join as join20 } from "node:path";
30252
+ import { join as join22 } from "node:path";
30073
30253
 
30074
30254
  // src/lib/skills-manifest.ts
30075
30255
  init_types2();
@@ -30077,7 +30257,7 @@ init_logger();
30077
30257
  var import_fs_extra11 = __toESM(require_lib(), 1);
30078
30258
  import { createHash as createHash2 } from "node:crypto";
30079
30259
  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";
30260
+ import { join as join21, relative as relative6 } from "node:path";
30081
30261
 
30082
30262
  class SkillsManifestManager {
30083
30263
  static MANIFEST_FILENAME = ".skills-manifest.json";
@@ -30099,12 +30279,12 @@ class SkillsManifestManager {
30099
30279
  return manifest;
30100
30280
  }
30101
30281
  static async writeManifest(skillsDir, manifest) {
30102
- const manifestPath = join19(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30282
+ const manifestPath = join21(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30103
30283
  await writeFile9(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
30104
30284
  logger.debug(`Wrote manifest to: ${manifestPath}`);
30105
30285
  }
30106
30286
  static async readManifest(skillsDir) {
30107
- const manifestPath = join19(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30287
+ const manifestPath = join21(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
30108
30288
  if (!await import_fs_extra11.pathExists(manifestPath)) {
30109
30289
  logger.debug(`No manifest found at: ${manifestPath}`);
30110
30290
  return null;
@@ -30127,7 +30307,7 @@ class SkillsManifestManager {
30127
30307
  return "flat";
30128
30308
  }
30129
30309
  for (const dir of dirs.slice(0, 3)) {
30130
- const dirPath = join19(skillsDir, dir.name);
30310
+ const dirPath = join21(skillsDir, dir.name);
30131
30311
  const subEntries = await readdir7(dirPath, { withFileTypes: true });
30132
30312
  const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
30133
30313
  if (hasSubdirs) {
@@ -30146,7 +30326,7 @@ class SkillsManifestManager {
30146
30326
  const entries = await readdir7(skillsDir, { withFileTypes: true });
30147
30327
  for (const entry of entries) {
30148
30328
  if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) {
30149
- const skillPath = join19(skillsDir, entry.name);
30329
+ const skillPath = join21(skillsDir, entry.name);
30150
30330
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
30151
30331
  skills.push({
30152
30332
  name: entry.name,
@@ -30158,11 +30338,11 @@ class SkillsManifestManager {
30158
30338
  const categories = await readdir7(skillsDir, { withFileTypes: true });
30159
30339
  for (const category of categories) {
30160
30340
  if (category.isDirectory() && category.name !== "node_modules" && !category.name.startsWith(".")) {
30161
- const categoryPath = join19(skillsDir, category.name);
30341
+ const categoryPath = join21(skillsDir, category.name);
30162
30342
  const skillEntries = await readdir7(categoryPath, { withFileTypes: true });
30163
30343
  for (const skillEntry of skillEntries) {
30164
30344
  if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
30165
- const skillPath = join19(categoryPath, skillEntry.name);
30345
+ const skillPath = join21(categoryPath, skillEntry.name);
30166
30346
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
30167
30347
  skills.push({
30168
30348
  name: skillEntry.name,
@@ -30192,7 +30372,7 @@ class SkillsManifestManager {
30192
30372
  const files = [];
30193
30373
  const entries = await readdir7(dirPath, { withFileTypes: true });
30194
30374
  for (const entry of entries) {
30195
- const fullPath = join19(dirPath, entry.name);
30375
+ const fullPath = join21(dirPath, entry.name);
30196
30376
  if (entry.name.startsWith(".") || entry.name === "node_modules") {
30197
30377
  continue;
30198
30378
  }
@@ -30435,12 +30615,12 @@ class SkillsMigrationDetector {
30435
30615
  let totalSkillLikeCount = 0;
30436
30616
  const allSkills = [];
30437
30617
  for (const dir of dirs) {
30438
- const dirPath = join20(skillsDir, dir.name);
30618
+ const dirPath = join22(skillsDir, dir.name);
30439
30619
  const subEntries = await readdir8(dirPath, { withFileTypes: true });
30440
30620
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
30441
30621
  if (subdirs.length > 0) {
30442
30622
  for (const subdir of subdirs.slice(0, 3)) {
30443
- const subdirPath = join20(dirPath, subdir.name);
30623
+ const subdirPath = join22(dirPath, subdir.name);
30444
30624
  const subdirFiles = await readdir8(subdirPath, { withFileTypes: true });
30445
30625
  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
30626
  if (hasSkillMarker) {
@@ -30479,14 +30659,14 @@ init_types2();
30479
30659
  init_logger();
30480
30660
  var import_fs_extra15 = __toESM(require_lib(), 1);
30481
30661
  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";
30662
+ import { join as join25 } from "node:path";
30483
30663
 
30484
30664
  // src/lib/skills-backup-manager.ts
30485
30665
  init_types2();
30486
30666
  init_logger();
30487
30667
  var import_fs_extra13 = __toESM(require_lib(), 1);
30488
30668
  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";
30669
+ import { basename as basename2, join as join23, normalize as normalize2 } from "node:path";
30490
30670
  function validatePath2(path9, paramName) {
30491
30671
  if (!path9 || typeof path9 !== "string") {
30492
30672
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -30512,7 +30692,7 @@ class SkillsBackupManager {
30512
30692
  const timestamp = Date.now();
30513
30693
  const randomSuffix = Math.random().toString(36).substring(2, 8);
30514
30694
  const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
30515
- const backupDir = parentDir ? join21(parentDir, backupDirName) : join21(skillsDir, "..", backupDirName);
30695
+ const backupDir = parentDir ? join23(parentDir, backupDirName) : join23(skillsDir, "..", backupDirName);
30516
30696
  logger.info(`Creating backup at: ${backupDir}`);
30517
30697
  try {
30518
30698
  await mkdir6(backupDir, { recursive: true });
@@ -30563,7 +30743,7 @@ class SkillsBackupManager {
30563
30743
  }
30564
30744
  try {
30565
30745
  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));
30746
+ const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join23(parentDir, entry.name));
30567
30747
  backups.sort().reverse();
30568
30748
  return backups;
30569
30749
  } catch (error) {
@@ -30591,8 +30771,8 @@ class SkillsBackupManager {
30591
30771
  static async copyDirectory(sourceDir, destDir) {
30592
30772
  const entries = await readdir9(sourceDir, { withFileTypes: true });
30593
30773
  for (const entry of entries) {
30594
- const sourcePath = join21(sourceDir, entry.name);
30595
- const destPath = join21(destDir, entry.name);
30774
+ const sourcePath = join23(sourceDir, entry.name);
30775
+ const destPath = join23(destDir, entry.name);
30596
30776
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30597
30777
  continue;
30598
30778
  }
@@ -30608,7 +30788,7 @@ class SkillsBackupManager {
30608
30788
  let size = 0;
30609
30789
  const entries = await readdir9(dirPath, { withFileTypes: true });
30610
30790
  for (const entry of entries) {
30611
- const fullPath = join21(dirPath, entry.name);
30791
+ const fullPath = join23(dirPath, entry.name);
30612
30792
  if (entry.isSymbolicLink()) {
30613
30793
  continue;
30614
30794
  }
@@ -30639,7 +30819,7 @@ var import_fs_extra14 = __toESM(require_lib(), 1);
30639
30819
  import { createHash as createHash3 } from "node:crypto";
30640
30820
  import { createReadStream as createReadStream2 } from "node:fs";
30641
30821
  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";
30822
+ import { join as join24, normalize as normalize3, relative as relative7 } from "node:path";
30643
30823
  function validatePath3(path9, paramName) {
30644
30824
  if (!path9 || typeof path9 !== "string") {
30645
30825
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -30786,13 +30966,13 @@ class SkillsCustomizationScanner {
30786
30966
  if (dirs.length === 0) {
30787
30967
  return ["flat", []];
30788
30968
  }
30789
- const firstDirPath = join22(skillsDir, dirs[0].name);
30969
+ const firstDirPath = join24(skillsDir, dirs[0].name);
30790
30970
  const subEntries = await readdir10(firstDirPath, { withFileTypes: true });
30791
30971
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
30792
30972
  if (subdirs.length > 0) {
30793
30973
  let skillLikeCount = 0;
30794
30974
  for (const subdir of subdirs.slice(0, 3)) {
30795
- const subdirPath = join22(firstDirPath, subdir.name);
30975
+ const subdirPath = join24(firstDirPath, subdir.name);
30796
30976
  const subdirFiles = await readdir10(subdirPath, { withFileTypes: true });
30797
30977
  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
30978
  if (hasSkillMarker) {
@@ -30802,7 +30982,7 @@ class SkillsCustomizationScanner {
30802
30982
  if (skillLikeCount > 0) {
30803
30983
  const skills = [];
30804
30984
  for (const dir of dirs) {
30805
- const categoryPath = join22(skillsDir, dir.name);
30985
+ const categoryPath = join24(skillsDir, dir.name);
30806
30986
  const skillDirs = await readdir10(categoryPath, { withFileTypes: true });
30807
30987
  skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
30808
30988
  }
@@ -30812,7 +30992,7 @@ class SkillsCustomizationScanner {
30812
30992
  return ["flat", dirs.map((dir) => dir.name)];
30813
30993
  }
30814
30994
  static async findSkillPath(skillsDir, skillName) {
30815
- const flatPath = join22(skillsDir, skillName);
30995
+ const flatPath = join24(skillsDir, skillName);
30816
30996
  if (await import_fs_extra14.pathExists(flatPath)) {
30817
30997
  return { path: flatPath, category: undefined };
30818
30998
  }
@@ -30821,8 +31001,8 @@ class SkillsCustomizationScanner {
30821
31001
  if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
30822
31002
  continue;
30823
31003
  }
30824
- const categoryPath = join22(skillsDir, entry.name);
30825
- const skillPath = join22(categoryPath, skillName);
31004
+ const categoryPath = join24(skillsDir, entry.name);
31005
+ const skillPath = join24(categoryPath, skillName);
30826
31006
  if (await import_fs_extra14.pathExists(skillPath)) {
30827
31007
  return { path: skillPath, category: entry.name };
30828
31008
  }
@@ -30833,7 +31013,7 @@ class SkillsCustomizationScanner {
30833
31013
  const files = [];
30834
31014
  const entries = await readdir10(dirPath, { withFileTypes: true });
30835
31015
  for (const entry of entries) {
30836
- const fullPath = join22(dirPath, entry.name);
31016
+ const fullPath = join24(dirPath, entry.name);
30837
31017
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30838
31018
  continue;
30839
31019
  }
@@ -31076,7 +31256,7 @@ class SkillsMigrator {
31076
31256
  }
31077
31257
  }
31078
31258
  if (options.backup && !options.dryRun) {
31079
- const claudeDir = join23(currentSkillsDir, "..");
31259
+ const claudeDir = join25(currentSkillsDir, "..");
31080
31260
  result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir);
31081
31261
  logger.success(`Backup created at: ${result.backupPath}`);
31082
31262
  }
@@ -31128,7 +31308,7 @@ class SkillsMigrator {
31128
31308
  const migrated = [];
31129
31309
  const preserved = [];
31130
31310
  const errors2 = [];
31131
- const tempDir = join23(currentSkillsDir, "..", ".skills-migration-temp");
31311
+ const tempDir = join25(currentSkillsDir, "..", ".skills-migration-temp");
31132
31312
  await mkdir7(tempDir, { recursive: true });
31133
31313
  try {
31134
31314
  for (const mapping of mappings) {
@@ -31149,9 +31329,9 @@ class SkillsMigrator {
31149
31329
  }
31150
31330
  }
31151
31331
  const category = mapping.category;
31152
- const targetPath = category ? join23(tempDir, category, skillName) : join23(tempDir, skillName);
31332
+ const targetPath = category ? join25(tempDir, category, skillName) : join25(tempDir, skillName);
31153
31333
  if (category) {
31154
- await mkdir7(join23(tempDir, category), { recursive: true });
31334
+ await mkdir7(join25(tempDir, category), { recursive: true });
31155
31335
  }
31156
31336
  await SkillsMigrator.copySkillDirectory(currentSkillPath, targetPath);
31157
31337
  migrated.push(skillName);
@@ -31185,8 +31365,8 @@ class SkillsMigrator {
31185
31365
  await mkdir7(destDir, { recursive: true });
31186
31366
  const entries = await readdir11(sourceDir, { withFileTypes: true });
31187
31367
  for (const entry of entries) {
31188
- const sourcePath = join23(sourceDir, entry.name);
31189
- const destPath = join23(destDir, entry.name);
31368
+ const sourcePath = join25(sourceDir, entry.name);
31369
+ const destPath = join25(destDir, entry.name);
31190
31370
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
31191
31371
  continue;
31192
31372
  }
@@ -31205,18 +31385,18 @@ init_types2();
31205
31385
  // src/utils/config.ts
31206
31386
  init_types2();
31207
31387
  init_logger();
31208
- import { existsSync as existsSync5 } from "node:fs";
31388
+ import { existsSync as existsSync6 } from "node:fs";
31209
31389
  import { mkdir as mkdir8, readFile as readFile12, rename as rename2, rm as rm3, writeFile as writeFile10 } from "node:fs/promises";
31210
31390
  import { chmod as chmod2 } from "node:fs/promises";
31211
31391
  import { platform as platform8 } from "node:os";
31212
- import { join as join24 } from "node:path";
31392
+ import { join as join26 } from "node:path";
31213
31393
  var PROJECT_CONFIG_FILE = ".ck.json";
31214
31394
 
31215
31395
  class ConfigManager {
31216
31396
  static config = null;
31217
31397
  static globalFlag = false;
31218
31398
  static getProjectConfigDir(projectDir, global3) {
31219
- return global3 ? projectDir : join24(projectDir, ".claude");
31399
+ return global3 ? projectDir : join26(projectDir, ".claude");
31220
31400
  }
31221
31401
  static setGlobalFlag(global3) {
31222
31402
  ConfigManager.globalFlag = global3;
@@ -31231,7 +31411,7 @@ class ConfigManager {
31231
31411
  }
31232
31412
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
31233
31413
  try {
31234
- if (existsSync5(configFile)) {
31414
+ if (existsSync6(configFile)) {
31235
31415
  const content = await readFile12(configFile, "utf-8");
31236
31416
  const data = JSON.parse(content);
31237
31417
  ConfigManager.config = ConfigSchema.parse(data);
@@ -31249,7 +31429,7 @@ class ConfigManager {
31249
31429
  const validConfig = ConfigSchema.parse(config);
31250
31430
  const configDir = PathResolver.getConfigDir(ConfigManager.globalFlag);
31251
31431
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
31252
- if (!existsSync5(configDir)) {
31432
+ if (!existsSync6(configDir)) {
31253
31433
  await mkdir8(configDir, { recursive: true });
31254
31434
  if (platform8() !== "win32") {
31255
31435
  await chmod2(configDir, 448);
@@ -31283,9 +31463,9 @@ class ConfigManager {
31283
31463
  }
31284
31464
  static async loadProjectConfig(projectDir, global3 = false) {
31285
31465
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
31286
- const configPath = join24(configDir, PROJECT_CONFIG_FILE);
31466
+ const configPath = join26(configDir, PROJECT_CONFIG_FILE);
31287
31467
  try {
31288
- if (existsSync5(configPath)) {
31468
+ if (existsSync6(configPath)) {
31289
31469
  const content = await readFile12(configPath, "utf-8");
31290
31470
  const data = JSON.parse(content);
31291
31471
  const folders = FoldersConfigSchema.parse(data.paths || data);
@@ -31299,9 +31479,9 @@ class ConfigManager {
31299
31479
  }
31300
31480
  static async saveProjectConfig(projectDir, folders, global3 = false) {
31301
31481
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
31302
- const configPath = join24(configDir, PROJECT_CONFIG_FILE);
31482
+ const configPath = join26(configDir, PROJECT_CONFIG_FILE);
31303
31483
  try {
31304
- if (!existsSync5(configDir)) {
31484
+ if (!existsSync6(configDir)) {
31305
31485
  await mkdir8(configDir, { recursive: true });
31306
31486
  }
31307
31487
  const validFolders = FoldersConfigSchema.parse(folders);
@@ -31331,21 +31511,21 @@ class ConfigManager {
31331
31511
  }
31332
31512
  static projectConfigExists(projectDir, global3 = false) {
31333
31513
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
31334
- return existsSync5(join24(configDir, PROJECT_CONFIG_FILE));
31514
+ return existsSync6(join26(configDir, PROJECT_CONFIG_FILE));
31335
31515
  }
31336
31516
  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)) {
31517
+ const correctPath = join26(globalDir, PROJECT_CONFIG_FILE);
31518
+ const incorrectPath = join26(globalDir, ".claude", PROJECT_CONFIG_FILE);
31519
+ if (existsSync6(correctPath)) {
31340
31520
  logger.debug("Config already exists at correct location, skipping migration");
31341
31521
  return false;
31342
31522
  }
31343
- if (existsSync5(incorrectPath)) {
31523
+ if (existsSync6(incorrectPath)) {
31344
31524
  try {
31345
31525
  logger.info("Migrating .ck.json from nested location to correct location...");
31346
31526
  await rename2(incorrectPath, correctPath);
31347
31527
  logger.success(`Migrated ${PROJECT_CONFIG_FILE} to ${correctPath}`);
31348
- const nestedClaudeDir = join24(globalDir, ".claude");
31528
+ const nestedClaudeDir = join26(globalDir, ".claude");
31349
31529
  try {
31350
31530
  await rm3(nestedClaudeDir, { recursive: false });
31351
31531
  logger.debug("Removed empty nested .claude directory");
@@ -31368,7 +31548,7 @@ init_environment();
31368
31548
  // src/utils/file-scanner.ts
31369
31549
  init_logger();
31370
31550
  var import_fs_extra16 = __toESM(require_lib(), 1);
31371
- import { join as join25, relative as relative8, resolve as resolve3 } from "node:path";
31551
+ import { join as join27, relative as relative8, resolve as resolve3 } from "node:path";
31372
31552
  var SKIP_DIRS = [
31373
31553
  "node_modules",
31374
31554
  ".venv",
@@ -31395,7 +31575,7 @@ class FileScanner {
31395
31575
  logger.debug(`Skipping directory: ${entry}`);
31396
31576
  continue;
31397
31577
  }
31398
- const fullPath = join25(dirPath, entry);
31578
+ const fullPath = join27(dirPath, entry);
31399
31579
  if (!FileScanner.isSafePath(basePath, fullPath)) {
31400
31580
  logger.warning(`Skipping potentially unsafe path: ${entry}`);
31401
31581
  continue;
@@ -31430,8 +31610,8 @@ class FileScanner {
31430
31610
  return files;
31431
31611
  }
31432
31612
  static async findCustomFiles(destDir, sourceDir, subPath) {
31433
- const destSubDir = join25(destDir, subPath);
31434
- const sourceSubDir = join25(sourceDir, subPath);
31613
+ const destSubDir = join27(destDir, subPath);
31614
+ const sourceSubDir = join27(sourceDir, subPath);
31435
31615
  const destFiles = await FileScanner.getFiles(destSubDir, destDir);
31436
31616
  const sourceFiles = await FileScanner.getFiles(sourceSubDir, sourceDir);
31437
31617
  const sourceFileSet = new Set(sourceFiles);
@@ -31472,7 +31652,7 @@ async function initCommand(options) {
31472
31652
  logger.info("Running in non-interactive mode (--yes flag)");
31473
31653
  }
31474
31654
  if (validOptions.global) {
31475
- const localSettingsPath = join26(process.cwd(), ".claude", "settings.json");
31655
+ const localSettingsPath = join28(process.cwd(), ".claude", "settings.json");
31476
31656
  if (await import_fs_extra17.pathExists(localSettingsPath)) {
31477
31657
  if (isNonInteractive2) {
31478
31658
  logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
@@ -31484,7 +31664,7 @@ async function initCommand(options) {
31484
31664
  return;
31485
31665
  }
31486
31666
  if (choice === "remove") {
31487
- const localClaudeDir = join26(process.cwd(), ".claude");
31667
+ const localClaudeDir = join28(process.cwd(), ".claude");
31488
31668
  try {
31489
31669
  await import_fs_extra17.remove(localClaudeDir);
31490
31670
  logger.success("Removed local .claude/ directory");
@@ -31543,7 +31723,7 @@ async function initCommand(options) {
31543
31723
  }
31544
31724
  if (validOptions.fresh) {
31545
31725
  const prefix = PathResolver.getPathPrefix(validOptions.global);
31546
- const claudeDir2 = prefix ? join26(resolvedDir, prefix) : resolvedDir;
31726
+ const claudeDir2 = prefix ? join28(resolvedDir, prefix) : resolvedDir;
31547
31727
  const canProceed = await handleFreshInstallation(claudeDir2, prompts);
31548
31728
  if (!canProceed) {
31549
31729
  return;
@@ -31680,7 +31860,7 @@ async function initCommand(options) {
31680
31860
  }
31681
31861
  }
31682
31862
  if (!validOptions.fresh) {
31683
- const newSkillsDir = join26(extractDir, ".claude", "skills");
31863
+ const newSkillsDir = join28(extractDir, ".claude", "skills");
31684
31864
  const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
31685
31865
  if (await import_fs_extra17.pathExists(newSkillsDir) && await import_fs_extra17.pathExists(currentSkillsDir)) {
31686
31866
  logger.info("Checking for skills directory migration...");
@@ -31705,7 +31885,7 @@ async function initCommand(options) {
31705
31885
  let customClaudeFiles = [];
31706
31886
  if (!validOptions.fresh) {
31707
31887
  logger.info("Scanning for custom .claude files...");
31708
- const scanSourceDir = validOptions.global ? join26(extractDir, ".claude") : extractDir;
31888
+ const scanSourceDir = validOptions.global ? join28(extractDir, ".claude") : extractDir;
31709
31889
  const scanTargetSubdir = validOptions.global ? "" : ".claude";
31710
31890
  customClaudeFiles = await FileScanner.findCustomFiles(resolvedDir, scanSourceDir, scanTargetSubdir);
31711
31891
  } else {
@@ -31734,7 +31914,7 @@ async function initCommand(options) {
31734
31914
  merger.addIgnorePatterns(validOptions.exclude);
31735
31915
  }
31736
31916
  merger.setGlobalFlag(validOptions.global);
31737
- const claudeDir = validOptions.global ? resolvedDir : join26(resolvedDir, ".claude");
31917
+ const claudeDir = validOptions.global ? resolvedDir : join28(resolvedDir, ".claude");
31738
31918
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
31739
31919
  if (!validOptions.fresh && await import_fs_extra17.pathExists(claudeDir)) {
31740
31920
  const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
@@ -31756,7 +31936,7 @@ async function initCommand(options) {
31756
31936
  return;
31757
31937
  }
31758
31938
  }
31759
- const sourceDir = validOptions.global ? join26(extractDir, ".claude") : extractDir;
31939
+ const sourceDir = validOptions.global ? join28(extractDir, ".claude") : extractDir;
31760
31940
  await merger.merge(sourceDir, resolvedDir, false);
31761
31941
  const manifestWriter = new ManifestWriter;
31762
31942
  const installedFiles = merger.getAllInstalledFiles();
@@ -31765,7 +31945,7 @@ async function initCommand(options) {
31765
31945
  if (!validOptions.global && !installedPath.startsWith(".claude/"))
31766
31946
  continue;
31767
31947
  const relativePath = validOptions.global ? installedPath : installedPath.replace(/^\.claude\//, "");
31768
- const filePath = join26(claudeDir, relativePath);
31948
+ const filePath = join28(claudeDir, relativePath);
31769
31949
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
31770
31950
  const ownership = manifestEntry ? "ck" : "user";
31771
31951
  filesToTrack.push({
@@ -31786,8 +31966,8 @@ async function initCommand(options) {
31786
31966
  trackingSpinner.succeed(`Tracked ${trackResult.success} files`);
31787
31967
  await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local");
31788
31968
  if (validOptions.global) {
31789
- const claudeMdSource = join26(extractDir, "CLAUDE.md");
31790
- const claudeMdDest = join26(resolvedDir, "CLAUDE.md");
31969
+ const claudeMdSource = join28(extractDir, "CLAUDE.md");
31970
+ const claudeMdDest = join28(resolvedDir, "CLAUDE.md");
31791
31971
  if (await import_fs_extra17.pathExists(claudeMdSource)) {
31792
31972
  if (!await import_fs_extra17.pathExists(claudeMdDest)) {
31793
31973
  await import_fs_extra17.copy(claudeMdSource, claudeMdDest);
@@ -31807,7 +31987,7 @@ async function initCommand(options) {
31807
31987
  await handleSkillsInstallation2(skillsDir);
31808
31988
  }
31809
31989
  if (!validOptions.skipSetup && !isNonInteractive2) {
31810
- const envPath = join26(claudeDir, ".env");
31990
+ const envPath = join28(claudeDir, ".env");
31811
31991
  if (!await import_fs_extra17.pathExists(envPath)) {
31812
31992
  const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
31813
31993
  if (shouldSetup) {
@@ -31839,7 +32019,7 @@ Protected files (.env, etc.) were not modified.`;
31839
32019
 
31840
32020
  // src/commands/new.ts
31841
32021
  var import_fs_extra18 = __toESM(require_lib(), 1);
31842
- import { join as join27, resolve as resolve5 } from "node:path";
32022
+ import { join as join29, resolve as resolve5 } from "node:path";
31843
32023
  init_types2();
31844
32024
  init_environment();
31845
32025
  init_logger();
@@ -32010,7 +32190,7 @@ async function newCommand(options) {
32010
32190
  await CommandsPrefix.cleanupCommandsDirectory(resolvedDir, false);
32011
32191
  }
32012
32192
  await merger.merge(extractDir, resolvedDir, true);
32013
- const claudeDir = join27(resolvedDir, ".claude");
32193
+ const claudeDir = join29(resolvedDir, ".claude");
32014
32194
  const manifestWriter = new ManifestWriter;
32015
32195
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
32016
32196
  const installedFiles = merger.getAllInstalledFiles();
@@ -32019,7 +32199,7 @@ async function newCommand(options) {
32019
32199
  if (!installedPath.startsWith(".claude/"))
32020
32200
  continue;
32021
32201
  const relativePath = installedPath.replace(/^\.claude\//, "");
32022
- const filePath = join27(claudeDir, relativePath);
32202
+ const filePath = join29(claudeDir, relativePath);
32023
32203
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
32024
32204
  const ownership = manifestEntry ? "ck" : "user";
32025
32205
  filesToTrack.push({
@@ -32075,7 +32255,7 @@ init_dist2();
32075
32255
  var import_fs_extra19 = __toESM(require_lib(), 1);
32076
32256
  var import_picocolors10 = __toESM(require_picocolors(), 1);
32077
32257
  import { readdirSync, rmSync } from "node:fs";
32078
- import { dirname as dirname4, join as join28 } from "node:path";
32258
+ import { dirname as dirname4, join as join30 } from "node:path";
32079
32259
  init_types2();
32080
32260
  init_logger();
32081
32261
  async function detectInstallations() {
@@ -32166,7 +32346,7 @@ async function analyzeInstallation(installation, forceOverwrite) {
32166
32346
  return result;
32167
32347
  }
32168
32348
  for (const trackedFile of metadata.files) {
32169
- const filePath = join28(installation.path, trackedFile.path);
32349
+ const filePath = join30(installation.path, trackedFile.path);
32170
32350
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
32171
32351
  if (!ownershipResult.exists)
32172
32352
  continue;
@@ -32224,7 +32404,7 @@ async function removeInstallations(installations, options) {
32224
32404
  let removedCount = 0;
32225
32405
  let cleanedDirs = 0;
32226
32406
  for (const item of analysis.toDelete) {
32227
- const filePath = join28(installation.path, item.path);
32407
+ const filePath = join30(installation.path, item.path);
32228
32408
  if (await import_fs_extra19.pathExists(filePath)) {
32229
32409
  await import_fs_extra19.remove(filePath);
32230
32410
  removedCount++;
@@ -32326,7 +32506,7 @@ import { promisify as promisify6 } from "node:util";
32326
32506
  // package.json
32327
32507
  var package_default2 = {
32328
32508
  name: "claudekit-cli",
32329
- version: "3.5.2",
32509
+ version: "3.6.0",
32330
32510
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
32331
32511
  type: "module",
32332
32512
  repository: {
@@ -32771,20 +32951,20 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
32771
32951
 
32772
32952
  // src/lib/version-cache.ts
32773
32953
  init_logger();
32774
- import { existsSync as existsSync6 } from "node:fs";
32954
+ import { existsSync as existsSync7 } from "node:fs";
32775
32955
  import { mkdir as mkdir9, readFile as readFile13, writeFile as writeFile11 } from "node:fs/promises";
32776
- import { join as join29 } from "node:path";
32956
+ import { join as join31 } from "node:path";
32777
32957
  class VersionCacheManager {
32778
32958
  static CACHE_FILENAME = "version-check.json";
32779
32959
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
32780
32960
  static getCacheFile() {
32781
32961
  const cacheDir = PathResolver.getCacheDir(false);
32782
- return join29(cacheDir, VersionCacheManager.CACHE_FILENAME);
32962
+ return join31(cacheDir, VersionCacheManager.CACHE_FILENAME);
32783
32963
  }
32784
32964
  static async load() {
32785
32965
  const cacheFile = VersionCacheManager.getCacheFile();
32786
32966
  try {
32787
- if (!existsSync6(cacheFile)) {
32967
+ if (!existsSync7(cacheFile)) {
32788
32968
  logger.debug("Version check cache not found");
32789
32969
  return null;
32790
32970
  }
@@ -32805,7 +32985,7 @@ class VersionCacheManager {
32805
32985
  const cacheFile = VersionCacheManager.getCacheFile();
32806
32986
  const cacheDir = PathResolver.getCacheDir(false);
32807
32987
  try {
32808
- if (!existsSync6(cacheDir)) {
32988
+ if (!existsSync7(cacheDir)) {
32809
32989
  await mkdir9(cacheDir, { recursive: true, mode: 448 });
32810
32990
  }
32811
32991
  await writeFile11(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
@@ -32827,7 +33007,7 @@ class VersionCacheManager {
32827
33007
  static async clear() {
32828
33008
  const cacheFile = VersionCacheManager.getCacheFile();
32829
33009
  try {
32830
- if (existsSync6(cacheFile)) {
33010
+ if (existsSync7(cacheFile)) {
32831
33011
  const fs12 = await import("node:fs/promises");
32832
33012
  await fs12.unlink(cacheFile);
32833
33013
  logger.debug("Version check cache cleared");
@@ -33255,7 +33435,7 @@ var logger2 = new Logger2;
33255
33435
 
33256
33436
  // src/utils/path-resolver.ts
33257
33437
  import { homedir as homedir2, platform as platform9 } from "node:os";
33258
- import { join as join30, normalize as normalize4 } from "node:path";
33438
+ import { join as join32, normalize as normalize4 } from "node:path";
33259
33439
 
33260
33440
  class PathResolver2 {
33261
33441
  static getTestHomeDir() {
@@ -33288,50 +33468,50 @@ class PathResolver2 {
33288
33468
  static getConfigDir(global3 = false) {
33289
33469
  const testHome = PathResolver2.getTestHomeDir();
33290
33470
  if (testHome) {
33291
- return global3 ? join30(testHome, ".config", "claude") : join30(testHome, ".claudekit");
33471
+ return global3 ? join32(testHome, ".config", "claude") : join32(testHome, ".claudekit");
33292
33472
  }
33293
33473
  if (!global3) {
33294
- return join30(homedir2(), ".claudekit");
33474
+ return join32(homedir2(), ".claudekit");
33295
33475
  }
33296
33476
  const os2 = platform9();
33297
33477
  if (os2 === "win32") {
33298
- const localAppData = process.env.LOCALAPPDATA || join30(homedir2(), "AppData", "Local");
33299
- return join30(localAppData, "claude");
33478
+ const localAppData = process.env.LOCALAPPDATA || join32(homedir2(), "AppData", "Local");
33479
+ return join32(localAppData, "claude");
33300
33480
  }
33301
33481
  const xdgConfigHome = process.env.XDG_CONFIG_HOME;
33302
33482
  if (xdgConfigHome) {
33303
- return join30(xdgConfigHome, "claude");
33483
+ return join32(xdgConfigHome, "claude");
33304
33484
  }
33305
- return join30(homedir2(), ".config", "claude");
33485
+ return join32(homedir2(), ".config", "claude");
33306
33486
  }
33307
33487
  static getConfigFile(global3 = false) {
33308
- return join30(PathResolver2.getConfigDir(global3), "config.json");
33488
+ return join32(PathResolver2.getConfigDir(global3), "config.json");
33309
33489
  }
33310
33490
  static getCacheDir(global3 = false) {
33311
33491
  const testHome = PathResolver2.getTestHomeDir();
33312
33492
  if (testHome) {
33313
- return global3 ? join30(testHome, ".cache", "claude") : join30(testHome, ".claudekit", "cache");
33493
+ return global3 ? join32(testHome, ".cache", "claude") : join32(testHome, ".claudekit", "cache");
33314
33494
  }
33315
33495
  if (!global3) {
33316
- return join30(homedir2(), ".claudekit", "cache");
33496
+ return join32(homedir2(), ".claudekit", "cache");
33317
33497
  }
33318
33498
  const os2 = platform9();
33319
33499
  if (os2 === "win32") {
33320
- const localAppData = process.env.LOCALAPPDATA || join30(homedir2(), "AppData", "Local");
33321
- return join30(localAppData, "claude", "cache");
33500
+ const localAppData = process.env.LOCALAPPDATA || join32(homedir2(), "AppData", "Local");
33501
+ return join32(localAppData, "claude", "cache");
33322
33502
  }
33323
33503
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
33324
33504
  if (xdgCacheHome) {
33325
- return join30(xdgCacheHome, "claude");
33505
+ return join32(xdgCacheHome, "claude");
33326
33506
  }
33327
- return join30(homedir2(), ".cache", "claude");
33507
+ return join32(homedir2(), ".cache", "claude");
33328
33508
  }
33329
33509
  static getGlobalKitDir() {
33330
33510
  const testHome = PathResolver2.getTestHomeDir();
33331
33511
  if (testHome) {
33332
- return join30(testHome, ".claude");
33512
+ return join32(testHome, ".claude");
33333
33513
  }
33334
- return join30(homedir2(), ".claude");
33514
+ return join32(homedir2(), ".claude");
33335
33515
  }
33336
33516
  static getPathPrefix(global3) {
33337
33517
  return global3 ? "" : ".claude";
@@ -33339,9 +33519,9 @@ class PathResolver2 {
33339
33519
  static buildSkillsPath(baseDir, global3) {
33340
33520
  const prefix = PathResolver2.getPathPrefix(global3);
33341
33521
  if (prefix) {
33342
- return join30(baseDir, prefix, "skills");
33522
+ return join32(baseDir, prefix, "skills");
33343
33523
  }
33344
- return join30(baseDir, "skills");
33524
+ return join32(baseDir, "skills");
33345
33525
  }
33346
33526
  static buildComponentPath(baseDir, component, global3) {
33347
33527
  if (!PathResolver2.isPathSafe(component)) {
@@ -33349,9 +33529,9 @@ class PathResolver2 {
33349
33529
  }
33350
33530
  const prefix = PathResolver2.getPathPrefix(global3);
33351
33531
  if (prefix) {
33352
- return join30(baseDir, prefix, component);
33532
+ return join32(baseDir, prefix, component);
33353
33533
  }
33354
- return join30(baseDir, component);
33534
+ return join32(baseDir, component);
33355
33535
  }
33356
33536
  }
33357
33537
 
@@ -33369,13 +33549,13 @@ async function displayVersion() {
33369
33549
  let localKitVersion = null;
33370
33550
  let isGlobalOnlyKit = false;
33371
33551
  const globalKitDir = PathResolver2.getGlobalKitDir();
33372
- const globalMetadataPath = join31(globalKitDir, "metadata.json");
33552
+ const globalMetadataPath = join33(globalKitDir, "metadata.json");
33373
33553
  const prefix = PathResolver2.getPathPrefix(false);
33374
- const localMetadataPath = prefix ? join31(process.cwd(), prefix, "metadata.json") : join31(process.cwd(), "metadata.json");
33554
+ const localMetadataPath = prefix ? join33(process.cwd(), prefix, "metadata.json") : join33(process.cwd(), "metadata.json");
33375
33555
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
33376
- if (!isLocalSameAsGlobal && existsSync7(localMetadataPath)) {
33556
+ if (!isLocalSameAsGlobal && existsSync8(localMetadataPath)) {
33377
33557
  try {
33378
- const rawMetadata = JSON.parse(readFileSync4(localMetadataPath, "utf-8"));
33558
+ const rawMetadata = JSON.parse(readFileSync5(localMetadataPath, "utf-8"));
33379
33559
  const metadata = MetadataSchema2.parse(rawMetadata);
33380
33560
  if (metadata.version) {
33381
33561
  const kitName = metadata.name || "ClaudeKit";
@@ -33387,9 +33567,9 @@ async function displayVersion() {
33387
33567
  logger2.verbose("Failed to parse local metadata.json", { error });
33388
33568
  }
33389
33569
  }
33390
- if (existsSync7(globalMetadataPath)) {
33570
+ if (existsSync8(globalMetadataPath)) {
33391
33571
  try {
33392
- const rawMetadata = JSON.parse(readFileSync4(globalMetadataPath, "utf-8"));
33572
+ const rawMetadata = JSON.parse(readFileSync5(globalMetadataPath, "utf-8"));
33393
33573
  const metadata = MetadataSchema2.parse(rawMetadata);
33394
33574
  if (metadata.version) {
33395
33575
  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.0",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {