claudekit-cli 3.1.0 → 3.3.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 (3) hide show
  1. package/bin/ck.js +6 -1
  2. package/dist/index.js +692 -260
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7159,19 +7159,29 @@ __export(exports_types, {
7159
7159
  GitHubReleaseSchema: () => GitHubReleaseSchema,
7160
7160
  GitHubReleaseAssetSchema: () => GitHubReleaseAssetSchema,
7161
7161
  GitHubError: () => GitHubError,
7162
+ FoldersConfigSchema: () => FoldersConfigSchema,
7162
7163
  ExtractionError: () => ExtractionError,
7163
7164
  ExcludePatternSchema: () => ExcludePatternSchema,
7164
7165
  DownloadError: () => DownloadError,
7166
+ DEFAULT_FOLDERS: () => DEFAULT_FOLDERS,
7165
7167
  ConfigSchema: () => ConfigSchema,
7166
7168
  ClaudeKitError: () => ClaudeKitError,
7167
7169
  AuthenticationError: () => AuthenticationError,
7168
7170
  AVAILABLE_KITS: () => AVAILABLE_KITS
7169
7171
  });
7170
- var KitType, ExcludePatternSchema, NewCommandOptionsSchema, UpdateCommandOptionsSchema, VersionCommandOptionsSchema, UninstallCommandOptionsSchema, UpdateCliOptionsSchema, TrackedFileSchema, MetadataSchema, ConfigSchema, GitHubReleaseAssetSchema, GitHubReleaseSchema, KitConfigSchema, AVAILABLE_KITS, NEVER_COPY_PATTERNS, USER_CONFIG_PATTERNS, PROTECTED_PATTERNS, ClaudeKitError, AuthenticationError, GitHubError, DownloadError, ExtractionError, SkillsManifestSchema, SkillsMigrationError;
7172
+ var KitType, ExcludePatternSchema, FoldersConfigSchema, DEFAULT_FOLDERS, NewCommandOptionsSchema, UpdateCommandOptionsSchema, VersionCommandOptionsSchema, UninstallCommandOptionsSchema, UpdateCliOptionsSchema, TrackedFileSchema, MetadataSchema, ConfigSchema, GitHubReleaseAssetSchema, GitHubReleaseSchema, KitConfigSchema, AVAILABLE_KITS, NEVER_COPY_PATTERNS, USER_CONFIG_PATTERNS, PROTECTED_PATTERNS, ClaudeKitError, AuthenticationError, GitHubError, DownloadError, ExtractionError, SkillsManifestSchema, SkillsMigrationError;
7171
7173
  var init_types2 = __esm(() => {
7172
7174
  init_zod();
7173
7175
  KitType = exports_external.enum(["engineer", "marketing"]);
7174
7176
  ExcludePatternSchema = exports_external.string().trim().min(1, "Exclude pattern cannot be empty").max(500, "Exclude pattern too long").refine((val) => !val.startsWith("/"), "Absolute paths not allowed in exclude patterns").refine((val) => !val.includes(".."), "Path traversal not allowed in exclude patterns");
7177
+ FoldersConfigSchema = exports_external.object({
7178
+ docs: exports_external.string().optional(),
7179
+ plans: exports_external.string().optional()
7180
+ });
7181
+ DEFAULT_FOLDERS = {
7182
+ docs: "docs",
7183
+ plans: "plans"
7184
+ };
7175
7185
  NewCommandOptionsSchema = exports_external.object({
7176
7186
  dir: exports_external.string().default("."),
7177
7187
  kit: KitType.optional(),
@@ -7184,7 +7194,9 @@ var init_types2 = __esm(() => {
7184
7194
  prefix: exports_external.boolean().default(false),
7185
7195
  beta: exports_external.boolean().default(false),
7186
7196
  dryRun: exports_external.boolean().default(false),
7187
- refresh: exports_external.boolean().default(false)
7197
+ refresh: exports_external.boolean().default(false),
7198
+ docsDir: exports_external.string().optional(),
7199
+ plansDir: exports_external.string().optional()
7188
7200
  });
7189
7201
  UpdateCommandOptionsSchema = exports_external.object({
7190
7202
  dir: exports_external.string().default("."),
@@ -7200,7 +7212,9 @@ var init_types2 = __esm(() => {
7200
7212
  dryRun: exports_external.boolean().default(false),
7201
7213
  forceOverwrite: exports_external.boolean().default(false),
7202
7214
  skipSetup: exports_external.boolean().default(false),
7203
- refresh: exports_external.boolean().default(false)
7215
+ refresh: exports_external.boolean().default(false),
7216
+ docsDir: exports_external.string().optional(),
7217
+ plansDir: exports_external.string().optional()
7204
7218
  });
7205
7219
  VersionCommandOptionsSchema = exports_external.object({
7206
7220
  kit: KitType.optional(),
@@ -7241,7 +7255,8 @@ var init_types2 = __esm(() => {
7241
7255
  defaults: exports_external.object({
7242
7256
  kit: KitType.optional(),
7243
7257
  dir: exports_external.string().optional()
7244
- }).optional()
7258
+ }).optional(),
7259
+ folders: FoldersConfigSchema.optional()
7245
7260
  });
7246
7261
  GitHubReleaseAssetSchema = exports_external.object({
7247
7262
  id: exports_external.number(),
@@ -11390,9 +11405,9 @@ async function installOpenCode() {
11390
11405
  try {
11391
11406
  logger.info(`Installing ${displayName}...`);
11392
11407
  const { unlink: unlink2 } = await import("node:fs/promises");
11393
- const { join: join24 } = await import("node:path");
11408
+ const { join: join26 } = await import("node:path");
11394
11409
  const { tmpdir: tmpdir3 } = await import("node:os");
11395
- const tempScriptPath = join24(tmpdir3(), "opencode-install.sh");
11410
+ const tempScriptPath = join26(tmpdir3(), "opencode-install.sh");
11396
11411
  try {
11397
11412
  logger.info("Downloading OpenCode installation script...");
11398
11413
  await execFileAsync("curl", ["-fsSL", "https://opencode.ai/install", "-o", tempScriptPath], {
@@ -11506,12 +11521,12 @@ async function installSkillsDependencies(skillsDir) {
11506
11521
  }
11507
11522
  try {
11508
11523
  const { existsSync: existsSync6 } = await import("node:fs");
11509
- const { readFile: readFile12 } = await import("node:fs/promises");
11510
- const { join: join24 } = await import("node:path");
11524
+ const { readFile: readFile13 } = await import("node:fs/promises");
11525
+ const { join: join26 } = await import("node:path");
11511
11526
  const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
11512
11527
  const platform9 = process.platform;
11513
11528
  const scriptName = platform9 === "win32" ? "install.ps1" : "install.sh";
11514
- const scriptPath = join24(skillsDir, scriptName);
11529
+ const scriptPath = join26(skillsDir, scriptName);
11515
11530
  try {
11516
11531
  validateScriptPath(skillsDir, scriptPath);
11517
11532
  } catch (error2) {
@@ -11527,7 +11542,7 @@ async function installSkillsDependencies(skillsDir) {
11527
11542
  logger.warning(`Skills installation script not found: ${scriptPath}`);
11528
11543
  logger.info("");
11529
11544
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
11530
- logger.info(` See: ${join24(skillsDir, "INSTALLATION.md")}`);
11545
+ logger.info(` See: ${join26(skillsDir, "INSTALLATION.md")}`);
11531
11546
  logger.info("");
11532
11547
  logger.info("Quick start:");
11533
11548
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -11543,7 +11558,7 @@ async function installSkillsDependencies(skillsDir) {
11543
11558
  logger.info(` Platform: ${platform9 === "win32" ? "Windows (PowerShell)" : "Unix (bash)"}`);
11544
11559
  logger.info("");
11545
11560
  try {
11546
- const scriptContent = await readFile12(scriptPath, "utf-8");
11561
+ const scriptContent = await readFile13(scriptPath, "utf-8");
11547
11562
  const previewLines = scriptContent.split(`
11548
11563
  `).slice(0, 20);
11549
11564
  logger.info("Script preview (first 20 lines):");
@@ -11571,7 +11586,7 @@ async function installSkillsDependencies(skillsDir) {
11571
11586
  logger.info(` ${platform9 === "win32" ? `powershell -File "${scriptPath}"` : `bash ${scriptPath}`}`);
11572
11587
  logger.info("");
11573
11588
  logger.info("Or see complete guide:");
11574
- logger.info(` ${join24(skillsDir, "INSTALLATION.md")}`);
11589
+ logger.info(` ${join26(skillsDir, "INSTALLATION.md")}`);
11575
11590
  return {
11576
11591
  success: false,
11577
11592
  package: displayName,
@@ -11613,8 +11628,8 @@ async function installSkillsDependencies(skillsDir) {
11613
11628
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
11614
11629
  logger.info("");
11615
11630
  logger.info("See complete guide:");
11616
- const { join: join24 } = await import("node:path");
11617
- logger.info(` cat ${join24(skillsDir, "INSTALLATION.md")}`);
11631
+ const { join: join26 } = await import("node:path");
11632
+ logger.info(` cat ${join26(skillsDir, "INSTALLATION.md")}`);
11618
11633
  logger.info("");
11619
11634
  logger.info("Quick start:");
11620
11635
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -11734,6 +11749,21 @@ var init_help_commands = __esm(() => {
11734
11749
  description: "Add /ck: prefix to all slash commands"
11735
11750
  }
11736
11751
  ]
11752
+ },
11753
+ {
11754
+ title: "Folder Options",
11755
+ options: [
11756
+ {
11757
+ flags: "--docs-dir <name>",
11758
+ description: "Custom docs folder name to avoid conflicts with existing folders",
11759
+ defaultValue: "docs"
11760
+ },
11761
+ {
11762
+ flags: "--plans-dir <name>",
11763
+ description: "Custom plans folder name to avoid conflicts with existing folders",
11764
+ defaultValue: "plans"
11765
+ }
11766
+ ]
11737
11767
  }
11738
11768
  ]
11739
11769
  };
@@ -11819,6 +11849,21 @@ var init_help_commands = __esm(() => {
11819
11849
  description: "Override ownership protections and delete user-modified files"
11820
11850
  }
11821
11851
  ]
11852
+ },
11853
+ {
11854
+ title: "Folder Options",
11855
+ options: [
11856
+ {
11857
+ flags: "--docs-dir <name>",
11858
+ description: "Custom docs folder name to avoid conflicts with existing folders",
11859
+ defaultValue: "docs"
11860
+ },
11861
+ {
11862
+ flags: "--plans-dir <name>",
11863
+ description: "Custom plans folder name to avoid conflicts with existing folders",
11864
+ defaultValue: "plans"
11865
+ }
11866
+ ]
11822
11867
  }
11823
11868
  ]
11824
11869
  };
@@ -12149,7 +12194,7 @@ async function basicPager(content) {
12149
12194
  });
12150
12195
  rl.on("SIGINT", () => {
12151
12196
  rl.close();
12152
- process.exit(0);
12197
+ process.exitCode = 0;
12153
12198
  });
12154
12199
  while (currentLine < lines.length) {
12155
12200
  const pageLines = lines.slice(currentLine, currentLine + pageSize);
@@ -12164,7 +12209,9 @@ async function basicPager(content) {
12164
12209
  rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
12165
12210
  if (answer.toLowerCase() === "q") {
12166
12211
  rl.close();
12167
- process.exit(0);
12212
+ process.exitCode = 0;
12213
+ resolve6();
12214
+ return;
12168
12215
  }
12169
12216
  process.stdout.write("\x1B[1A\x1B[2K");
12170
12217
  resolve6();
@@ -12413,7 +12460,7 @@ async function handleHelp(_args) {
12413
12460
  console.error("Error rendering help:", error2);
12414
12461
  return;
12415
12462
  }
12416
- process.exit(0);
12463
+ process.exitCode = 0;
12417
12464
  }
12418
12465
  function isHelpRequested(argv) {
12419
12466
  return argv.includes("--help") || argv.includes("-h");
@@ -12426,7 +12473,7 @@ var init_help_interceptor = __esm(() => {
12426
12473
 
12427
12474
  // src/index.ts
12428
12475
  import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
12429
- import { join as join29 } from "path";
12476
+ import { join as join31 } from "path";
12430
12477
 
12431
12478
  // node_modules/cac/dist/index.mjs
12432
12479
  import { EventEmitter } from "events";
@@ -13031,7 +13078,7 @@ var cac = (name = "") => new CAC(name);
13031
13078
  // package.json
13032
13079
  var package_default = {
13033
13080
  name: "claudekit-cli",
13034
- version: "3.1.0",
13081
+ version: "3.3.0",
13035
13082
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
13036
13083
  type: "module",
13037
13084
  repository: {
@@ -15850,8 +15897,8 @@ async function doctorCommand(options = {}) {
15850
15897
  }
15851
15898
 
15852
15899
  // src/commands/init.ts
15853
- var import_fs_extra16 = __toESM(require_lib(), 1);
15854
- import { join as join24, resolve as resolve4 } from "node:path";
15900
+ var import_fs_extra17 = __toESM(require_lib(), 1);
15901
+ import { join as join26, resolve as resolve4 } from "node:path";
15855
15902
 
15856
15903
  // src/lib/commands-prefix.ts
15857
15904
  init_logger();
@@ -26439,6 +26486,7 @@ class DownloadManager {
26439
26486
  "Thumbs.db",
26440
26487
  "*.log"
26441
26488
  ];
26489
+ static tempDirCounter = 0;
26442
26490
  totalExtractedSize = 0;
26443
26491
  ig;
26444
26492
  userExcludePatterns = [];
@@ -26876,7 +26924,8 @@ class DownloadManager {
26876
26924
  }
26877
26925
  async createTempDir() {
26878
26926
  const timestamp = Date.now();
26879
- const primaryTempDir = join10(tmpdir2(), `claudekit-${timestamp}`);
26927
+ const counter = DownloadManager.tempDirCounter++;
26928
+ const primaryTempDir = join10(tmpdir2(), `claudekit-${timestamp}-${counter}`);
26880
26929
  try {
26881
26930
  await mkdir5(primaryTempDir, { recursive: true });
26882
26931
  logger.debug(`Created temp directory: ${primaryTempDir}`);
@@ -26892,7 +26941,7 @@ Solutions:
26892
26941
  2. Set HOME environment variable
26893
26942
  3. Try running from a different directory`);
26894
26943
  }
26895
- const fallbackTempDir = join10(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}`);
26944
+ const fallbackTempDir = join10(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
26896
26945
  try {
26897
26946
  await mkdir5(fallbackTempDir, { recursive: true });
26898
26947
  logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
@@ -26925,13 +26974,235 @@ Solutions:
26925
26974
  }
26926
26975
  }
26927
26976
 
26928
- // src/lib/fresh-installer.ts
26977
+ // src/lib/folder-path-transformer.ts
26978
+ init_types2();
26929
26979
  init_logger();
26930
26980
  var import_fs_extra4 = __toESM(require_lib(), 1);
26931
- import { join as join11 } from "node:path";
26981
+ import { readFile as readFile5, readdir as readdir3, rename, writeFile as writeFile4 } from "node:fs/promises";
26982
+ import { join as join11, relative as relative3 } from "node:path";
26983
+ var TRANSFORMABLE_FILE_PATTERNS = [
26984
+ ".md",
26985
+ ".txt",
26986
+ ".json",
26987
+ ".yaml",
26988
+ ".yml",
26989
+ ".toml",
26990
+ ".sh",
26991
+ ".bash",
26992
+ ".zsh",
26993
+ ".ps1",
26994
+ ".ts",
26995
+ ".js",
26996
+ ".mjs",
26997
+ ".cjs"
26998
+ ];
26999
+ async function transformFolderPaths(extractDir, folders, options = {}) {
27000
+ const result = {
27001
+ foldersRenamed: 0,
27002
+ filesTransformed: 0,
27003
+ totalReferences: 0
27004
+ };
27005
+ const needsTransform = folders.docs !== DEFAULT_FOLDERS.docs || folders.plans !== DEFAULT_FOLDERS.plans;
27006
+ if (!needsTransform) {
27007
+ logger.debug("No folder transformation needed (using defaults)");
27008
+ return result;
27009
+ }
27010
+ logger.info("Transforming folder paths...");
27011
+ const replacements = new Map;
27012
+ if (folders.docs !== DEFAULT_FOLDERS.docs) {
27013
+ replacements.set(`${DEFAULT_FOLDERS.docs}/`, `${folders.docs}/`);
27014
+ replacements.set(`"${DEFAULT_FOLDERS.docs}"`, `"${folders.docs}"`);
27015
+ replacements.set(`'${DEFAULT_FOLDERS.docs}'`, `'${folders.docs}'`);
27016
+ replacements.set(`/${DEFAULT_FOLDERS.docs}`, `/${folders.docs}`);
27017
+ replacements.set(`./${DEFAULT_FOLDERS.docs}`, `./${folders.docs}`);
27018
+ }
27019
+ if (folders.plans !== DEFAULT_FOLDERS.plans) {
27020
+ replacements.set(`${DEFAULT_FOLDERS.plans}/`, `${folders.plans}/`);
27021
+ replacements.set(`"${DEFAULT_FOLDERS.plans}"`, `"${folders.plans}"`);
27022
+ replacements.set(`'${DEFAULT_FOLDERS.plans}'`, `'${folders.plans}'`);
27023
+ replacements.set(`/${DEFAULT_FOLDERS.plans}`, `/${folders.plans}`);
27024
+ replacements.set(`./${DEFAULT_FOLDERS.plans}`, `./${folders.plans}`);
27025
+ }
27026
+ const dirsToRename = [];
27027
+ if (folders.docs !== DEFAULT_FOLDERS.docs) {
27028
+ const docsPath = join11(extractDir, DEFAULT_FOLDERS.docs);
27029
+ if (await import_fs_extra4.pathExists(docsPath)) {
27030
+ dirsToRename.push({
27031
+ from: docsPath,
27032
+ to: join11(extractDir, folders.docs)
27033
+ });
27034
+ }
27035
+ const claudeDocsPath = join11(extractDir, ".claude", DEFAULT_FOLDERS.docs);
27036
+ if (await import_fs_extra4.pathExists(claudeDocsPath)) {
27037
+ dirsToRename.push({
27038
+ from: claudeDocsPath,
27039
+ to: join11(extractDir, ".claude", folders.docs)
27040
+ });
27041
+ }
27042
+ }
27043
+ if (folders.plans !== DEFAULT_FOLDERS.plans) {
27044
+ const plansPath = join11(extractDir, DEFAULT_FOLDERS.plans);
27045
+ if (await import_fs_extra4.pathExists(plansPath)) {
27046
+ dirsToRename.push({
27047
+ from: plansPath,
27048
+ to: join11(extractDir, folders.plans)
27049
+ });
27050
+ }
27051
+ const claudePlansPath = join11(extractDir, ".claude", DEFAULT_FOLDERS.plans);
27052
+ if (await import_fs_extra4.pathExists(claudePlansPath)) {
27053
+ dirsToRename.push({
27054
+ from: claudePlansPath,
27055
+ to: join11(extractDir, ".claude", folders.plans)
27056
+ });
27057
+ }
27058
+ }
27059
+ for (const { from, to } of dirsToRename) {
27060
+ if (options.dryRun) {
27061
+ logger.info(`[dry-run] Would rename: ${relative3(extractDir, from)} → ${relative3(extractDir, to)}`);
27062
+ } else {
27063
+ try {
27064
+ await rename(from, to);
27065
+ logger.debug(`Renamed: ${relative3(extractDir, from)} → ${relative3(extractDir, to)}`);
27066
+ result.foldersRenamed++;
27067
+ } catch (error2) {
27068
+ logger.warning(`Failed to rename ${from}: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
27069
+ }
27070
+ }
27071
+ }
27072
+ const compiledReplacements = [];
27073
+ for (const [search, replace3] of replacements) {
27074
+ compiledReplacements.push({
27075
+ regex: new RegExp(escapeRegExp(search), "g"),
27076
+ replacement: replace3
27077
+ });
27078
+ }
27079
+ const transformedFiles = await transformFileContents(extractDir, compiledReplacements, options);
27080
+ result.filesTransformed = transformedFiles.filesChanged;
27081
+ result.totalReferences = transformedFiles.replacementsCount;
27082
+ if (options.verbose) {
27083
+ logger.info(`Folder transformation complete: ${result.foldersRenamed} folders renamed, ` + `${result.filesTransformed} files updated, ${result.totalReferences} references changed`);
27084
+ }
27085
+ return result;
27086
+ }
27087
+ async function transformFileContents(dir, compiledReplacements, options) {
27088
+ let filesChanged = 0;
27089
+ let replacementsCount = 0;
27090
+ const entries = await readdir3(dir, { withFileTypes: true });
27091
+ for (const entry of entries) {
27092
+ const fullPath = join11(dir, entry.name);
27093
+ if (entry.isDirectory()) {
27094
+ if (entry.name === "node_modules" || entry.name === ".git") {
27095
+ continue;
27096
+ }
27097
+ const subResult = await transformFileContents(fullPath, compiledReplacements, options);
27098
+ filesChanged += subResult.filesChanged;
27099
+ replacementsCount += subResult.replacementsCount;
27100
+ } else if (entry.isFile()) {
27101
+ const shouldTransform = TRANSFORMABLE_FILE_PATTERNS.some((ext) => entry.name.toLowerCase().endsWith(ext));
27102
+ if (!shouldTransform)
27103
+ continue;
27104
+ try {
27105
+ const content = await readFile5(fullPath, "utf-8");
27106
+ let newContent = content;
27107
+ let changeCount = 0;
27108
+ for (const { regex: regex2, replacement } of compiledReplacements) {
27109
+ regex2.lastIndex = 0;
27110
+ const matches = newContent.match(regex2);
27111
+ if (matches) {
27112
+ changeCount += matches.length;
27113
+ regex2.lastIndex = 0;
27114
+ newContent = newContent.replace(regex2, replacement);
27115
+ }
27116
+ }
27117
+ if (changeCount > 0) {
27118
+ if (options.dryRun) {
27119
+ logger.debug(`[dry-run] Would update ${relative3(dir, fullPath)}: ${changeCount} replacement(s)`);
27120
+ } else {
27121
+ await writeFile4(fullPath, newContent, "utf-8");
27122
+ logger.debug(`Updated ${relative3(dir, fullPath)}: ${changeCount} replacement(s)`);
27123
+ }
27124
+ filesChanged++;
27125
+ replacementsCount += changeCount;
27126
+ }
27127
+ } catch (error2) {
27128
+ if (error2.code !== "ENOENT") {
27129
+ logger.debug(`Skipped ${entry.name}: ${error2 instanceof Error ? error2.message : "Unknown"}`);
27130
+ }
27131
+ }
27132
+ }
27133
+ }
27134
+ return { filesChanged, replacementsCount };
27135
+ }
27136
+ function escapeRegExp(string) {
27137
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27138
+ }
27139
+ function validateFolderOptions(options) {
27140
+ if (options.docsDir) {
27141
+ const docsError = validateFolderName(options.docsDir);
27142
+ if (docsError) {
27143
+ logger.error(`Invalid --docs-dir value: ${docsError}`);
27144
+ process.exit(1);
27145
+ }
27146
+ }
27147
+ if (options.plansDir) {
27148
+ const plansError = validateFolderName(options.plansDir);
27149
+ if (plansError) {
27150
+ logger.error(`Invalid --plans-dir value: ${plansError}`);
27151
+ process.exit(1);
27152
+ }
27153
+ }
27154
+ }
27155
+ function validateFolderName(name2) {
27156
+ if (!name2 || name2.trim().length === 0) {
27157
+ return "Folder name cannot be empty";
27158
+ }
27159
+ if (name2.includes("..") || name2.includes("/") || name2.includes("\\")) {
27160
+ return "Folder name cannot contain path separators or parent references";
27161
+ }
27162
+ const invalidChars = /[<>:"|?*\x00-\x1f]/;
27163
+ if (invalidChars.test(name2)) {
27164
+ return "Folder name contains invalid characters";
27165
+ }
27166
+ const reservedNames = [
27167
+ "CON",
27168
+ "PRN",
27169
+ "AUX",
27170
+ "NUL",
27171
+ "COM1",
27172
+ "COM2",
27173
+ "COM3",
27174
+ "COM4",
27175
+ "COM5",
27176
+ "COM6",
27177
+ "COM7",
27178
+ "COM8",
27179
+ "COM9",
27180
+ "LPT1",
27181
+ "LPT2",
27182
+ "LPT3",
27183
+ "LPT4",
27184
+ "LPT5",
27185
+ "LPT6",
27186
+ "LPT7",
27187
+ "LPT8",
27188
+ "LPT9"
27189
+ ];
27190
+ if (reservedNames.includes(name2.toUpperCase())) {
27191
+ return "Folder name is a reserved system name";
27192
+ }
27193
+ if (name2.length > 255) {
27194
+ return "Folder name is too long (max 255 characters)";
27195
+ }
27196
+ return null;
27197
+ }
27198
+
27199
+ // src/lib/fresh-installer.ts
27200
+ init_logger();
27201
+ var import_fs_extra5 = __toESM(require_lib(), 1);
27202
+ import { join as join12 } from "node:path";
26932
27203
  var CLAUDEKIT_SUBDIRECTORIES = ["commands", "agents", "skills", "workflows", "hooks"];
26933
27204
  async function handleFreshInstallation(claudeDir, prompts) {
26934
- if (!await import_fs_extra4.pathExists(claudeDir)) {
27205
+ if (!await import_fs_extra5.pathExists(claudeDir)) {
26935
27206
  logger.info(".claude directory does not exist, proceeding with fresh installation");
26936
27207
  return true;
26937
27208
  }
@@ -26946,8 +27217,8 @@ async function handleFreshInstallation(claudeDir, prompts) {
26946
27217
  const { rmSync } = await import("node:fs");
26947
27218
  let removedCount = 0;
26948
27219
  for (const subdir of CLAUDEKIT_SUBDIRECTORIES) {
26949
- const subdirPath = join11(claudeDir, subdir);
26950
- if (await import_fs_extra4.pathExists(subdirPath)) {
27220
+ const subdirPath = join12(claudeDir, subdir);
27221
+ if (await import_fs_extra5.pathExists(subdirPath)) {
26951
27222
  rmSync(subdirPath, { recursive: true, force: true });
26952
27223
  removedCount++;
26953
27224
  logger.debug(`Removed subdirectory: ${subdir}/`);
@@ -26963,9 +27234,9 @@ async function handleFreshInstallation(claudeDir, prompts) {
26963
27234
 
26964
27235
  // src/lib/global-path-transformer.ts
26965
27236
  init_logger();
26966
- import { readFile as readFile5, readdir as readdir3, writeFile as writeFile4 } from "node:fs/promises";
27237
+ import { readFile as readFile6, readdir as readdir4, writeFile as writeFile5 } from "node:fs/promises";
26967
27238
  import { platform as platform7 } from "node:os";
26968
- import { extname, join as join12 } from "node:path";
27239
+ import { extname, join as join13 } from "node:path";
26969
27240
  var IS_WINDOWS = platform7() === "win32";
26970
27241
  var HOME_PREFIX = IS_WINDOWS ? "%USERPROFILE%" : "$HOME";
26971
27242
  function getHomeDirPrefix() {
@@ -27055,9 +27326,9 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
27055
27326
  let filesSkipped = 0;
27056
27327
  const skippedFiles = [];
27057
27328
  async function processDirectory(dir) {
27058
- const entries = await readdir3(dir, { withFileTypes: true });
27329
+ const entries = await readdir4(dir, { withFileTypes: true });
27059
27330
  for (const entry of entries) {
27060
- const fullPath = join12(dir, entry.name);
27331
+ const fullPath = join13(dir, entry.name);
27061
27332
  if (entry.isDirectory()) {
27062
27333
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
27063
27334
  continue;
@@ -27065,10 +27336,10 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
27065
27336
  await processDirectory(fullPath);
27066
27337
  } else if (entry.isFile() && shouldTransformFile(entry.name)) {
27067
27338
  try {
27068
- const content = await readFile5(fullPath, "utf-8");
27339
+ const content = await readFile6(fullPath, "utf-8");
27069
27340
  const { transformed, changes } = transformContent(content);
27070
27341
  if (changes > 0) {
27071
- await writeFile4(fullPath, transformed, "utf-8");
27342
+ await writeFile5(fullPath, transformed, "utf-8");
27072
27343
  filesTransformed++;
27073
27344
  totalChanges += changes;
27074
27345
  if (options.verbose) {
@@ -27096,9 +27367,9 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
27096
27367
 
27097
27368
  // src/lib/merge.ts
27098
27369
  init_dist2();
27099
- var import_fs_extra5 = __toESM(require_lib(), 1);
27370
+ var import_fs_extra6 = __toESM(require_lib(), 1);
27100
27371
  var import_ignore2 = __toESM(require_ignore(), 1);
27101
- import { dirname as dirname3, join as join13, relative as relative3 } from "node:path";
27372
+ import { dirname as dirname3, join as join14, relative as relative4 } from "node:path";
27102
27373
 
27103
27374
  // node_modules/@isaacs/balanced-match/dist/esm/index.js
27104
27375
  var balanced = (a3, b3, str) => {
@@ -28572,10 +28843,10 @@ class FileMerger {
28572
28843
  const conflicts = [];
28573
28844
  const files = await this.getFiles(sourceDir, sourceDir);
28574
28845
  for (const file of files) {
28575
- const relativePath = relative3(sourceDir, file);
28846
+ const relativePath = relative4(sourceDir, file);
28576
28847
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
28577
- const destPath = join13(destDir, relativePath);
28578
- if (await import_fs_extra5.pathExists(destPath)) {
28848
+ const destPath = join14(destDir, relativePath);
28849
+ if (await import_fs_extra6.pathExists(destPath)) {
28579
28850
  if (this.neverCopyChecker.ignores(normalizedRelativePath)) {
28580
28851
  logger.debug(`Security-sensitive file exists but won't be overwritten: ${normalizedRelativePath}`);
28581
28852
  continue;
@@ -28594,16 +28865,16 @@ class FileMerger {
28594
28865
  let copiedCount = 0;
28595
28866
  let skippedCount = 0;
28596
28867
  for (const file of files) {
28597
- const relativePath = relative3(sourceDir, file);
28868
+ const relativePath = relative4(sourceDir, file);
28598
28869
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
28599
- const destPath = join13(destDir, relativePath);
28870
+ const destPath = join14(destDir, relativePath);
28600
28871
  if (this.neverCopyChecker.ignores(normalizedRelativePath)) {
28601
28872
  logger.debug(`Skipping security-sensitive file: ${normalizedRelativePath}`);
28602
28873
  skippedCount++;
28603
28874
  continue;
28604
28875
  }
28605
28876
  if (this.userConfigChecker.ignores(normalizedRelativePath)) {
28606
- const fileExists = await import_fs_extra5.pathExists(destPath);
28877
+ const fileExists = await import_fs_extra6.pathExists(destPath);
28607
28878
  if (fileExists) {
28608
28879
  logger.debug(`Skipping existing user config file: ${normalizedRelativePath}`);
28609
28880
  skippedCount++;
@@ -28617,7 +28888,7 @@ class FileMerger {
28617
28888
  copiedCount++;
28618
28889
  continue;
28619
28890
  }
28620
- await import_fs_extra5.copy(file, destPath, { overwrite: true });
28891
+ await import_fs_extra6.copy(file, destPath, { overwrite: true });
28621
28892
  this.trackInstalledFile(normalizedRelativePath);
28622
28893
  copiedCount++;
28623
28894
  }
@@ -28625,7 +28896,7 @@ class FileMerger {
28625
28896
  }
28626
28897
  async processSettingsJson(sourceFile, destFile) {
28627
28898
  try {
28628
- const content = await import_fs_extra5.readFile(sourceFile, "utf-8");
28899
+ const content = await import_fs_extra6.readFile(sourceFile, "utf-8");
28629
28900
  const isWindows5 = process.platform === "win32";
28630
28901
  let processedContent = content;
28631
28902
  if (this.isGlobal) {
@@ -28640,20 +28911,20 @@ class FileMerger {
28640
28911
  logger.debug("Converted Unix env var syntax to Windows syntax in settings.json");
28641
28912
  }
28642
28913
  }
28643
- await import_fs_extra5.writeFile(destFile, processedContent, "utf-8");
28914
+ await import_fs_extra6.writeFile(destFile, processedContent, "utf-8");
28644
28915
  } catch (error2) {
28645
28916
  logger.error(`Failed to process settings.json: ${error2}`);
28646
- await import_fs_extra5.copy(sourceFile, destFile, { overwrite: true });
28917
+ await import_fs_extra6.copy(sourceFile, destFile, { overwrite: true });
28647
28918
  }
28648
28919
  }
28649
28920
  async getFiles(dir, baseDir = dir) {
28650
28921
  const files = [];
28651
- const entries = await import_fs_extra5.readdir(dir, { encoding: "utf8" });
28922
+ const entries = await import_fs_extra6.readdir(dir, { encoding: "utf8" });
28652
28923
  for (const entry of entries) {
28653
- const fullPath = join13(dir, entry);
28654
- const relativePath = relative3(baseDir, fullPath);
28924
+ const fullPath = join14(dir, entry);
28925
+ const relativePath = relative4(baseDir, fullPath);
28655
28926
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
28656
- const stats = await import_fs_extra5.lstat(fullPath);
28927
+ const stats = await import_fs_extra6.lstat(fullPath);
28657
28928
  if (stats.isSymbolicLink()) {
28658
28929
  logger.warning(`Skipping symbolic link: ${normalizedRelativePath}`);
28659
28930
  continue;
@@ -28711,15 +28982,15 @@ class FileMerger {
28711
28982
 
28712
28983
  // src/lib/migration/legacy-migration.ts
28713
28984
  init_logger();
28714
- var import_fs_extra7 = __toESM(require_lib(), 1);
28715
- import { readdir as readdir5, stat as stat3 } from "node:fs/promises";
28716
- import { join as join15, relative as relative4 } from "node:path";
28985
+ var import_fs_extra8 = __toESM(require_lib(), 1);
28986
+ import { readdir as readdir6, stat as stat3 } from "node:fs/promises";
28987
+ import { join as join16, relative as relative5 } from "node:path";
28717
28988
 
28718
28989
  // src/lib/migration/release-manifest.ts
28719
28990
  init_zod();
28720
28991
  init_logger();
28721
- var import_fs_extra6 = __toESM(require_lib(), 1);
28722
- import { join as join14 } from "node:path";
28992
+ var import_fs_extra7 = __toESM(require_lib(), 1);
28993
+ import { join as join15 } from "node:path";
28723
28994
  var ReleaseManifestFileSchema = exports_external.object({
28724
28995
  path: exports_external.string(),
28725
28996
  checksum: exports_external.string().regex(/^[a-f0-9]{64}$/),
@@ -28733,9 +29004,9 @@ var ReleaseManifestSchema = exports_external.object({
28733
29004
 
28734
29005
  class ReleaseManifestLoader {
28735
29006
  static async load(extractDir) {
28736
- const manifestPath = join14(extractDir, "release-manifest.json");
29007
+ const manifestPath = join15(extractDir, "release-manifest.json");
28737
29008
  try {
28738
- const content = await import_fs_extra6.readFile(manifestPath, "utf-8");
29009
+ const content = await import_fs_extra7.readFile(manifestPath, "utf-8");
28739
29010
  const parsed = JSON.parse(content);
28740
29011
  return ReleaseManifestSchema.parse(parsed);
28741
29012
  } catch (error2) {
@@ -28764,7 +29035,7 @@ class LegacyMigration {
28764
29035
  const files = [];
28765
29036
  let entries;
28766
29037
  try {
28767
- entries = await readdir5(dir);
29038
+ entries = await readdir6(dir);
28768
29039
  } catch (err) {
28769
29040
  const error2 = err;
28770
29041
  if (error2.code === "ENOENT") {
@@ -28779,7 +29050,7 @@ class LegacyMigration {
28779
29050
  for (const entry of entries) {
28780
29051
  if (entry === "metadata.json")
28781
29052
  continue;
28782
- const fullPath = join15(dir, entry);
29053
+ const fullPath = join16(dir, entry);
28783
29054
  let stats;
28784
29055
  try {
28785
29056
  stats = await stat3(fullPath);
@@ -28812,7 +29083,7 @@ class LegacyMigration {
28812
29083
  };
28813
29084
  const filesInManifest = [];
28814
29085
  for (const file of files) {
28815
- const relativePath = relative4(claudeDir, file).replace(/\\/g, "/");
29086
+ const relativePath = relative5(claudeDir, file).replace(/\\/g, "/");
28816
29087
  const manifestEntry = ReleaseManifestLoader.findFile(manifest, relativePath);
28817
29088
  if (!manifestEntry) {
28818
29089
  preview.userCreated.push(relativePath);
@@ -28881,7 +29152,7 @@ User-created files (sample):`);
28881
29152
  ];
28882
29153
  if (filesToChecksum.length > 0) {
28883
29154
  const checksumResults = await Promise.all(filesToChecksum.map(async ({ relativePath, ownership }) => {
28884
- const fullPath = join15(claudeDir, relativePath);
29155
+ const fullPath = join16(claudeDir, relativePath);
28885
29156
  const checksum = await OwnershipChecker.calculateChecksum(fullPath);
28886
29157
  return { relativePath, checksum, ownership };
28887
29158
  }));
@@ -28902,8 +29173,8 @@ User-created files (sample):`);
28902
29173
  installedAt: new Date().toISOString(),
28903
29174
  files: trackedFiles
28904
29175
  };
28905
- const metadataPath = join15(claudeDir, "metadata.json");
28906
- await import_fs_extra7.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
29176
+ const metadataPath = join16(claudeDir, "metadata.json");
29177
+ await import_fs_extra8.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
28907
29178
  logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
28908
29179
  return true;
28909
29180
  }
@@ -29435,6 +29706,28 @@ class PromptsManager {
29435
29706
  }
29436
29707
  return updateEverything;
29437
29708
  }
29709
+ async promptLocalMigration() {
29710
+ const result = await ie({
29711
+ message: "Local ClaudeKit installation detected. Local settings take precedence over global.",
29712
+ options: [
29713
+ {
29714
+ value: "remove",
29715
+ label: "Remove local installation",
29716
+ hint: "Delete .claude/ and use global only"
29717
+ },
29718
+ {
29719
+ value: "keep",
29720
+ label: "Keep both installations",
29721
+ hint: "Local will take precedence"
29722
+ },
29723
+ { value: "cancel", label: "Cancel", hint: "Abort global installation" }
29724
+ ]
29725
+ });
29726
+ if (lD(result)) {
29727
+ return "cancel";
29728
+ }
29729
+ return result;
29730
+ }
29438
29731
  async promptDirectorySelection(global3 = false) {
29439
29732
  f2.step("Select directories to update");
29440
29733
  const prefix = PathResolver.getPathPrefix(global3);
@@ -29471,12 +29764,12 @@ class PromptsManager {
29471
29764
  // src/lib/setup-wizard.ts
29472
29765
  init_dist2();
29473
29766
  init_logger();
29474
- var import_fs_extra9 = __toESM(require_lib(), 1);
29475
- import { join as join17 } from "node:path";
29767
+ var import_fs_extra10 = __toESM(require_lib(), 1);
29768
+ import { join as join18 } from "node:path";
29476
29769
 
29477
29770
  // src/lib/config-generator.ts
29478
- var import_fs_extra8 = __toESM(require_lib(), 1);
29479
- import { join as join16 } from "node:path";
29771
+ var import_fs_extra9 = __toESM(require_lib(), 1);
29772
+ import { join as join17 } from "node:path";
29480
29773
  async function generateEnvFile(targetDir, values) {
29481
29774
  const lines = [
29482
29775
  "# Generated by ClaudeKit CLI setup wizard",
@@ -29488,8 +29781,8 @@ async function generateEnvFile(targetDir, values) {
29488
29781
  lines.push(`${key}=${value}`);
29489
29782
  }
29490
29783
  }
29491
- const envPath = join16(targetDir, ".env");
29492
- await import_fs_extra8.writeFile(envPath, `${lines.join(`
29784
+ const envPath = join17(targetDir, ".env");
29785
+ await import_fs_extra9.writeFile(envPath, `${lines.join(`
29493
29786
  `)}
29494
29787
  `, { mode: 384 });
29495
29788
  }
@@ -29533,7 +29826,7 @@ var ESSENTIAL_CONFIGS = [
29533
29826
  ];
29534
29827
  async function parseEnvFile(path9) {
29535
29828
  try {
29536
- const content = await import_fs_extra9.readFile(path9, "utf-8");
29829
+ const content = await import_fs_extra10.readFile(path9, "utf-8");
29537
29830
  const env2 = {};
29538
29831
  for (const line of content.split(`
29539
29832
  `)) {
@@ -29559,8 +29852,8 @@ async function parseEnvFile(path9) {
29559
29852
  }
29560
29853
  }
29561
29854
  async function checkGlobalConfig() {
29562
- const globalEnvPath = join17(PathResolver.getGlobalKitDir(), ".env");
29563
- if (!await import_fs_extra9.pathExists(globalEnvPath))
29855
+ const globalEnvPath = join18(PathResolver.getGlobalKitDir(), ".env");
29856
+ if (!await import_fs_extra10.pathExists(globalEnvPath))
29564
29857
  return false;
29565
29858
  const env2 = await parseEnvFile(globalEnvPath);
29566
29859
  return Object.keys(env2).length > 0;
@@ -29575,8 +29868,8 @@ async function runSetupWizard(options) {
29575
29868
  let globalEnv = {};
29576
29869
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
29577
29870
  if (!isGlobal) {
29578
- const globalEnvPath = join17(PathResolver.getGlobalKitDir(), ".env");
29579
- if (await import_fs_extra9.pathExists(globalEnvPath)) {
29871
+ const globalEnvPath = join18(PathResolver.getGlobalKitDir(), ".env");
29872
+ if (await import_fs_extra10.pathExists(globalEnvPath)) {
29580
29873
  globalEnv = await parseEnvFile(globalEnvPath);
29581
29874
  }
29582
29875
  }
@@ -29628,30 +29921,30 @@ async function runSetupWizard(options) {
29628
29921
  }
29629
29922
  }
29630
29923
  await generateEnvFile(targetDir, values);
29631
- f2.success(`Configuration saved to ${join17(targetDir, ".env")}`);
29924
+ f2.success(`Configuration saved to ${join18(targetDir, ".env")}`);
29632
29925
  return true;
29633
29926
  }
29634
29927
 
29635
29928
  // src/lib/skills-detector.ts
29636
29929
  init_logger();
29637
- var import_fs_extra11 = __toESM(require_lib(), 1);
29638
- import { readdir as readdir7 } from "node:fs/promises";
29639
- import { join as join19 } from "node:path";
29930
+ var import_fs_extra12 = __toESM(require_lib(), 1);
29931
+ import { readdir as readdir8 } from "node:fs/promises";
29932
+ import { join as join20 } from "node:path";
29640
29933
 
29641
29934
  // src/lib/skills-manifest.ts
29642
29935
  init_types2();
29643
29936
  init_logger();
29644
- var import_fs_extra10 = __toESM(require_lib(), 1);
29937
+ var import_fs_extra11 = __toESM(require_lib(), 1);
29645
29938
  import { createHash as createHash2 } from "node:crypto";
29646
- import { readFile as readFile9, readdir as readdir6, writeFile as writeFile8 } from "node:fs/promises";
29647
- import { join as join18, relative as relative5 } from "node:path";
29939
+ import { readFile as readFile10, readdir as readdir7, writeFile as writeFile9 } from "node:fs/promises";
29940
+ import { join as join19, relative as relative6 } from "node:path";
29648
29941
 
29649
29942
  class SkillsManifestManager {
29650
29943
  static MANIFEST_FILENAME = ".skills-manifest.json";
29651
29944
  static MANIFEST_VERSION = "1.0.0";
29652
29945
  static async generateManifest(skillsDir) {
29653
29946
  logger.debug(`Generating manifest for: ${skillsDir}`);
29654
- if (!await import_fs_extra10.pathExists(skillsDir)) {
29947
+ if (!await import_fs_extra11.pathExists(skillsDir)) {
29655
29948
  throw new SkillsMigrationError(`Skills directory does not exist: ${skillsDir}`);
29656
29949
  }
29657
29950
  const structure = await SkillsManifestManager.detectStructure(skillsDir);
@@ -29666,18 +29959,18 @@ class SkillsManifestManager {
29666
29959
  return manifest;
29667
29960
  }
29668
29961
  static async writeManifest(skillsDir, manifest) {
29669
- const manifestPath = join18(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
29670
- await writeFile8(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
29962
+ const manifestPath = join19(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
29963
+ await writeFile9(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
29671
29964
  logger.debug(`Wrote manifest to: ${manifestPath}`);
29672
29965
  }
29673
29966
  static async readManifest(skillsDir) {
29674
- const manifestPath = join18(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
29675
- if (!await import_fs_extra10.pathExists(manifestPath)) {
29967
+ const manifestPath = join19(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
29968
+ if (!await import_fs_extra11.pathExists(manifestPath)) {
29676
29969
  logger.debug(`No manifest found at: ${manifestPath}`);
29677
29970
  return null;
29678
29971
  }
29679
29972
  try {
29680
- const content = await readFile9(manifestPath, "utf-8");
29973
+ const content = await readFile10(manifestPath, "utf-8");
29681
29974
  const data = JSON.parse(content);
29682
29975
  const manifest = SkillsManifestSchema.parse(data);
29683
29976
  logger.debug(`Read manifest from: ${manifestPath}`);
@@ -29688,14 +29981,14 @@ class SkillsManifestManager {
29688
29981
  }
29689
29982
  }
29690
29983
  static async detectStructure(skillsDir) {
29691
- const entries = await readdir6(skillsDir, { withFileTypes: true });
29984
+ const entries = await readdir7(skillsDir, { withFileTypes: true });
29692
29985
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith("."));
29693
29986
  if (dirs.length === 0) {
29694
29987
  return "flat";
29695
29988
  }
29696
29989
  for (const dir of dirs.slice(0, 3)) {
29697
- const dirPath = join18(skillsDir, dir.name);
29698
- const subEntries = await readdir6(dirPath, { withFileTypes: true });
29990
+ const dirPath = join19(skillsDir, dir.name);
29991
+ const subEntries = await readdir7(dirPath, { withFileTypes: true });
29699
29992
  const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
29700
29993
  if (hasSubdirs) {
29701
29994
  return "categorized";
@@ -29710,10 +30003,10 @@ class SkillsManifestManager {
29710
30003
  static async scanSkills(skillsDir, structure) {
29711
30004
  const skills = [];
29712
30005
  if (structure === "flat") {
29713
- const entries = await readdir6(skillsDir, { withFileTypes: true });
30006
+ const entries = await readdir7(skillsDir, { withFileTypes: true });
29714
30007
  for (const entry of entries) {
29715
30008
  if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) {
29716
- const skillPath = join18(skillsDir, entry.name);
30009
+ const skillPath = join19(skillsDir, entry.name);
29717
30010
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
29718
30011
  skills.push({
29719
30012
  name: entry.name,
@@ -29722,14 +30015,14 @@ class SkillsManifestManager {
29722
30015
  }
29723
30016
  }
29724
30017
  } else {
29725
- const categories = await readdir6(skillsDir, { withFileTypes: true });
30018
+ const categories = await readdir7(skillsDir, { withFileTypes: true });
29726
30019
  for (const category of categories) {
29727
30020
  if (category.isDirectory() && category.name !== "node_modules" && !category.name.startsWith(".")) {
29728
- const categoryPath = join18(skillsDir, category.name);
29729
- const skillEntries = await readdir6(categoryPath, { withFileTypes: true });
30021
+ const categoryPath = join19(skillsDir, category.name);
30022
+ const skillEntries = await readdir7(categoryPath, { withFileTypes: true });
29730
30023
  for (const skillEntry of skillEntries) {
29731
30024
  if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
29732
- const skillPath = join18(categoryPath, skillEntry.name);
30025
+ const skillPath = join19(categoryPath, skillEntry.name);
29733
30026
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
29734
30027
  skills.push({
29735
30028
  name: skillEntry.name,
@@ -29748,8 +30041,8 @@ class SkillsManifestManager {
29748
30041
  const files = await SkillsManifestManager.getAllFiles(dirPath);
29749
30042
  files.sort();
29750
30043
  for (const file of files) {
29751
- const relativePath = relative5(dirPath, file);
29752
- const content = await readFile9(file);
30044
+ const relativePath = relative6(dirPath, file);
30045
+ const content = await readFile10(file);
29753
30046
  hash.update(relativePath);
29754
30047
  hash.update(content);
29755
30048
  }
@@ -29757,9 +30050,9 @@ class SkillsManifestManager {
29757
30050
  }
29758
30051
  static async getAllFiles(dirPath) {
29759
30052
  const files = [];
29760
- const entries = await readdir6(dirPath, { withFileTypes: true });
30053
+ const entries = await readdir7(dirPath, { withFileTypes: true });
29761
30054
  for (const entry of entries) {
29762
- const fullPath = join18(dirPath, entry.name);
30055
+ const fullPath = join19(dirPath, entry.name);
29763
30056
  if (entry.name.startsWith(".") || entry.name === "node_modules") {
29764
30057
  continue;
29765
30058
  }
@@ -29879,8 +30172,8 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
29879
30172
  class SkillsMigrationDetector {
29880
30173
  static async detectMigration(oldSkillsDir, currentSkillsDir) {
29881
30174
  logger.debug("Detecting skills migration need...");
29882
- const oldExists = await import_fs_extra11.pathExists(oldSkillsDir);
29883
- const currentExists = await import_fs_extra11.pathExists(currentSkillsDir);
30175
+ const oldExists = await import_fs_extra12.pathExists(oldSkillsDir);
30176
+ const currentExists = await import_fs_extra12.pathExists(currentSkillsDir);
29884
30177
  if (!oldExists && !currentExists) {
29885
30178
  logger.debug("No skills directories found, migration not needed");
29886
30179
  return {
@@ -29991,10 +30284,10 @@ class SkillsMigrationDetector {
29991
30284
  };
29992
30285
  }
29993
30286
  static async scanDirectory(skillsDir) {
29994
- if (!await import_fs_extra11.pathExists(skillsDir)) {
30287
+ if (!await import_fs_extra12.pathExists(skillsDir)) {
29995
30288
  return ["flat", []];
29996
30289
  }
29997
- const entries = await readdir7(skillsDir, { withFileTypes: true });
30290
+ const entries = await readdir8(skillsDir, { withFileTypes: true });
29998
30291
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith("."));
29999
30292
  if (dirs.length === 0) {
30000
30293
  return ["flat", []];
@@ -30002,13 +30295,13 @@ class SkillsMigrationDetector {
30002
30295
  let totalSkillLikeCount = 0;
30003
30296
  const allSkills = [];
30004
30297
  for (const dir of dirs) {
30005
- const dirPath = join19(skillsDir, dir.name);
30006
- const subEntries = await readdir7(dirPath, { withFileTypes: true });
30298
+ const dirPath = join20(skillsDir, dir.name);
30299
+ const subEntries = await readdir8(dirPath, { withFileTypes: true });
30007
30300
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
30008
30301
  if (subdirs.length > 0) {
30009
30302
  for (const subdir of subdirs.slice(0, 3)) {
30010
- const subdirPath = join19(dirPath, subdir.name);
30011
- const subdirFiles = await readdir7(subdirPath, { withFileTypes: true });
30303
+ const subdirPath = join20(dirPath, subdir.name);
30304
+ const subdirFiles = await readdir8(subdirPath, { withFileTypes: true });
30012
30305
  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"));
30013
30306
  if (hasSkillMarker) {
30014
30307
  totalSkillLikeCount++;
@@ -30044,16 +30337,16 @@ class SkillsMigrationDetector {
30044
30337
  // src/lib/skills-migrator.ts
30045
30338
  init_types2();
30046
30339
  init_logger();
30047
- var import_fs_extra14 = __toESM(require_lib(), 1);
30048
- import { copyFile as copyFile2, mkdir as mkdir7, readdir as readdir10, rm as rm2 } from "node:fs/promises";
30049
- import { join as join22 } from "node:path";
30340
+ var import_fs_extra15 = __toESM(require_lib(), 1);
30341
+ import { copyFile as copyFile2, mkdir as mkdir7, readdir as readdir11, rm as rm2 } from "node:fs/promises";
30342
+ import { join as join23 } from "node:path";
30050
30343
 
30051
30344
  // src/lib/skills-backup-manager.ts
30052
30345
  init_types2();
30053
30346
  init_logger();
30054
- var import_fs_extra12 = __toESM(require_lib(), 1);
30055
- import { copyFile, mkdir as mkdir6, readdir as readdir8, rm, stat as stat4 } from "node:fs/promises";
30056
- import { basename as basename2, join as join20, normalize as normalize2 } from "node:path";
30347
+ var import_fs_extra13 = __toESM(require_lib(), 1);
30348
+ import { copyFile, mkdir as mkdir6, readdir as readdir9, rm, stat as stat4 } from "node:fs/promises";
30349
+ import { basename as basename2, join as join21, normalize as normalize2 } from "node:path";
30057
30350
  function validatePath2(path9, paramName) {
30058
30351
  if (!path9 || typeof path9 !== "string") {
30059
30352
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -30073,13 +30366,13 @@ class SkillsBackupManager {
30073
30366
  if (parentDir) {
30074
30367
  validatePath2(parentDir, "parentDir");
30075
30368
  }
30076
- if (!await import_fs_extra12.pathExists(skillsDir)) {
30369
+ if (!await import_fs_extra13.pathExists(skillsDir)) {
30077
30370
  throw new SkillsMigrationError(`Cannot create backup: Skills directory does not exist: ${skillsDir}`);
30078
30371
  }
30079
30372
  const timestamp = Date.now();
30080
30373
  const randomSuffix = Math.random().toString(36).substring(2, 8);
30081
30374
  const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
30082
- const backupDir = parentDir ? join20(parentDir, backupDirName) : join20(skillsDir, "..", backupDirName);
30375
+ const backupDir = parentDir ? join21(parentDir, backupDirName) : join21(skillsDir, "..", backupDirName);
30083
30376
  logger.info(`Creating backup at: ${backupDir}`);
30084
30377
  try {
30085
30378
  await mkdir6(backupDir, { recursive: true });
@@ -30096,12 +30389,12 @@ class SkillsBackupManager {
30096
30389
  static async restoreBackup(backupDir, targetDir) {
30097
30390
  validatePath2(backupDir, "backupDir");
30098
30391
  validatePath2(targetDir, "targetDir");
30099
- if (!await import_fs_extra12.pathExists(backupDir)) {
30392
+ if (!await import_fs_extra13.pathExists(backupDir)) {
30100
30393
  throw new SkillsMigrationError(`Cannot restore: Backup directory does not exist: ${backupDir}`);
30101
30394
  }
30102
30395
  logger.info(`Restoring from backup: ${backupDir}`);
30103
30396
  try {
30104
- if (await import_fs_extra12.pathExists(targetDir)) {
30397
+ if (await import_fs_extra13.pathExists(targetDir)) {
30105
30398
  await rm(targetDir, { recursive: true, force: true });
30106
30399
  }
30107
30400
  await mkdir6(targetDir, { recursive: true });
@@ -30112,7 +30405,7 @@ class SkillsBackupManager {
30112
30405
  }
30113
30406
  }
30114
30407
  static async deleteBackup(backupDir) {
30115
- if (!await import_fs_extra12.pathExists(backupDir)) {
30408
+ if (!await import_fs_extra13.pathExists(backupDir)) {
30116
30409
  logger.warning(`Backup directory does not exist: ${backupDir}`);
30117
30410
  return;
30118
30411
  }
@@ -30125,12 +30418,12 @@ class SkillsBackupManager {
30125
30418
  }
30126
30419
  }
30127
30420
  static async listBackups(parentDir) {
30128
- if (!await import_fs_extra12.pathExists(parentDir)) {
30421
+ if (!await import_fs_extra13.pathExists(parentDir)) {
30129
30422
  return [];
30130
30423
  }
30131
30424
  try {
30132
- const entries = await readdir8(parentDir, { withFileTypes: true });
30133
- const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join20(parentDir, entry.name));
30425
+ const entries = await readdir9(parentDir, { withFileTypes: true });
30426
+ const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join21(parentDir, entry.name));
30134
30427
  backups.sort().reverse();
30135
30428
  return backups;
30136
30429
  } catch (error2) {
@@ -30150,16 +30443,16 @@ class SkillsBackupManager {
30150
30443
  }
30151
30444
  }
30152
30445
  static async getBackupSize(backupDir) {
30153
- if (!await import_fs_extra12.pathExists(backupDir)) {
30446
+ if (!await import_fs_extra13.pathExists(backupDir)) {
30154
30447
  return 0;
30155
30448
  }
30156
30449
  return await SkillsBackupManager.getDirectorySize(backupDir);
30157
30450
  }
30158
30451
  static async copyDirectory(sourceDir, destDir) {
30159
- const entries = await readdir8(sourceDir, { withFileTypes: true });
30452
+ const entries = await readdir9(sourceDir, { withFileTypes: true });
30160
30453
  for (const entry of entries) {
30161
- const sourcePath = join20(sourceDir, entry.name);
30162
- const destPath = join20(destDir, entry.name);
30454
+ const sourcePath = join21(sourceDir, entry.name);
30455
+ const destPath = join21(destDir, entry.name);
30163
30456
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30164
30457
  continue;
30165
30458
  }
@@ -30173,9 +30466,9 @@ class SkillsBackupManager {
30173
30466
  }
30174
30467
  static async getDirectorySize(dirPath) {
30175
30468
  let size = 0;
30176
- const entries = await readdir8(dirPath, { withFileTypes: true });
30469
+ const entries = await readdir9(dirPath, { withFileTypes: true });
30177
30470
  for (const entry of entries) {
30178
- const fullPath = join20(dirPath, entry.name);
30471
+ const fullPath = join21(dirPath, entry.name);
30179
30472
  if (entry.isSymbolicLink()) {
30180
30473
  continue;
30181
30474
  }
@@ -30202,11 +30495,11 @@ class SkillsBackupManager {
30202
30495
  // src/lib/skills-customization-scanner.ts
30203
30496
  init_types2();
30204
30497
  init_logger();
30205
- var import_fs_extra13 = __toESM(require_lib(), 1);
30498
+ var import_fs_extra14 = __toESM(require_lib(), 1);
30206
30499
  import { createHash as createHash3 } from "node:crypto";
30207
30500
  import { createReadStream as createReadStream2 } from "node:fs";
30208
- import { readFile as readFile10, readdir as readdir9 } from "node:fs/promises";
30209
- import { join as join21, normalize as normalize3, relative as relative6 } from "node:path";
30501
+ import { readFile as readFile11, readdir as readdir10 } from "node:fs/promises";
30502
+ import { join as join22, normalize as normalize3, relative as relative7 } from "node:path";
30210
30503
  function validatePath3(path9, paramName) {
30211
30504
  if (!path9 || typeof path9 !== "string") {
30212
30505
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -30285,14 +30578,14 @@ class SkillsCustomizationScanner {
30285
30578
  static async detectFileChanges(currentSkillPath, baselineSkillPath) {
30286
30579
  const changes = [];
30287
30580
  const currentFiles = await SkillsCustomizationScanner.getAllFiles(currentSkillPath);
30288
- const baselineFiles = await import_fs_extra13.pathExists(baselineSkillPath) ? await SkillsCustomizationScanner.getAllFiles(baselineSkillPath) : [];
30581
+ const baselineFiles = await import_fs_extra14.pathExists(baselineSkillPath) ? await SkillsCustomizationScanner.getAllFiles(baselineSkillPath) : [];
30289
30582
  const currentFileMap = new Map(await Promise.all(currentFiles.map(async (f3) => {
30290
- const relPath = relative6(currentSkillPath, f3);
30583
+ const relPath = relative7(currentSkillPath, f3);
30291
30584
  const hash = await SkillsCustomizationScanner.hashFile(f3);
30292
30585
  return [relPath, hash];
30293
30586
  })));
30294
30587
  const baselineFileMap = new Map(await Promise.all(baselineFiles.map(async (f3) => {
30295
- const relPath = relative6(baselineSkillPath, f3);
30588
+ const relPath = relative7(baselineSkillPath, f3);
30296
30589
  const hash = await SkillsCustomizationScanner.hashFile(f3);
30297
30590
  return [relPath, hash];
30298
30591
  })));
@@ -30330,8 +30623,8 @@ class SkillsCustomizationScanner {
30330
30623
  if (files1.length !== files2.length) {
30331
30624
  return true;
30332
30625
  }
30333
- const relFiles1 = files1.map((f3) => relative6(dir1, f3)).sort();
30334
- const relFiles2 = files2.map((f3) => relative6(dir2, f3)).sort();
30626
+ const relFiles1 = files1.map((f3) => relative7(dir1, f3)).sort();
30627
+ const relFiles2 = files2.map((f3) => relative7(dir2, f3)).sort();
30335
30628
  if (JSON.stringify(relFiles1) !== JSON.stringify(relFiles2)) {
30336
30629
  return true;
30337
30630
  }
@@ -30345,22 +30638,22 @@ class SkillsCustomizationScanner {
30345
30638
  return false;
30346
30639
  }
30347
30640
  static async scanSkillsDirectory(skillsDir) {
30348
- if (!await import_fs_extra13.pathExists(skillsDir)) {
30641
+ if (!await import_fs_extra14.pathExists(skillsDir)) {
30349
30642
  return ["flat", []];
30350
30643
  }
30351
- const entries = await readdir9(skillsDir, { withFileTypes: true });
30644
+ const entries = await readdir10(skillsDir, { withFileTypes: true });
30352
30645
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith("."));
30353
30646
  if (dirs.length === 0) {
30354
30647
  return ["flat", []];
30355
30648
  }
30356
- const firstDirPath = join21(skillsDir, dirs[0].name);
30357
- const subEntries = await readdir9(firstDirPath, { withFileTypes: true });
30649
+ const firstDirPath = join22(skillsDir, dirs[0].name);
30650
+ const subEntries = await readdir10(firstDirPath, { withFileTypes: true });
30358
30651
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
30359
30652
  if (subdirs.length > 0) {
30360
30653
  let skillLikeCount = 0;
30361
30654
  for (const subdir of subdirs.slice(0, 3)) {
30362
- const subdirPath = join21(firstDirPath, subdir.name);
30363
- const subdirFiles = await readdir9(subdirPath, { withFileTypes: true });
30655
+ const subdirPath = join22(firstDirPath, subdir.name);
30656
+ const subdirFiles = await readdir10(subdirPath, { withFileTypes: true });
30364
30657
  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"));
30365
30658
  if (hasSkillMarker) {
30366
30659
  skillLikeCount++;
@@ -30369,8 +30662,8 @@ class SkillsCustomizationScanner {
30369
30662
  if (skillLikeCount > 0) {
30370
30663
  const skills = [];
30371
30664
  for (const dir of dirs) {
30372
- const categoryPath = join21(skillsDir, dir.name);
30373
- const skillDirs = await readdir9(categoryPath, { withFileTypes: true });
30665
+ const categoryPath = join22(skillsDir, dir.name);
30666
+ const skillDirs = await readdir10(categoryPath, { withFileTypes: true });
30374
30667
  skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
30375
30668
  }
30376
30669
  return ["categorized", skills];
@@ -30379,18 +30672,18 @@ class SkillsCustomizationScanner {
30379
30672
  return ["flat", dirs.map((dir) => dir.name)];
30380
30673
  }
30381
30674
  static async findSkillPath(skillsDir, skillName) {
30382
- const flatPath = join21(skillsDir, skillName);
30383
- if (await import_fs_extra13.pathExists(flatPath)) {
30675
+ const flatPath = join22(skillsDir, skillName);
30676
+ if (await import_fs_extra14.pathExists(flatPath)) {
30384
30677
  return { path: flatPath, category: undefined };
30385
30678
  }
30386
- const entries = await readdir9(skillsDir, { withFileTypes: true });
30679
+ const entries = await readdir10(skillsDir, { withFileTypes: true });
30387
30680
  for (const entry of entries) {
30388
30681
  if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
30389
30682
  continue;
30390
30683
  }
30391
- const categoryPath = join21(skillsDir, entry.name);
30392
- const skillPath = join21(categoryPath, skillName);
30393
- if (await import_fs_extra13.pathExists(skillPath)) {
30684
+ const categoryPath = join22(skillsDir, entry.name);
30685
+ const skillPath = join22(categoryPath, skillName);
30686
+ if (await import_fs_extra14.pathExists(skillPath)) {
30394
30687
  return { path: skillPath, category: entry.name };
30395
30688
  }
30396
30689
  }
@@ -30398,9 +30691,9 @@ class SkillsCustomizationScanner {
30398
30691
  }
30399
30692
  static async getAllFiles(dirPath) {
30400
30693
  const files = [];
30401
- const entries = await readdir9(dirPath, { withFileTypes: true });
30694
+ const entries = await readdir10(dirPath, { withFileTypes: true });
30402
30695
  for (const entry of entries) {
30403
- const fullPath = join21(dirPath, entry.name);
30696
+ const fullPath = join22(dirPath, entry.name);
30404
30697
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30405
30698
  continue;
30406
30699
  }
@@ -30432,8 +30725,8 @@ class SkillsCustomizationScanner {
30432
30725
  const files = await SkillsCustomizationScanner.getAllFiles(dirPath);
30433
30726
  files.sort();
30434
30727
  for (const file of files) {
30435
- const relativePath = relative6(dirPath, file);
30436
- const content = await readFile10(file);
30728
+ const relativePath = relative7(dirPath, file);
30729
+ const content = await readFile11(file);
30437
30730
  hash.update(relativePath);
30438
30731
  hash.update(content);
30439
30732
  }
@@ -30643,7 +30936,7 @@ class SkillsMigrator {
30643
30936
  }
30644
30937
  }
30645
30938
  if (options.backup && !options.dryRun) {
30646
- const claudeDir = join22(currentSkillsDir, "..");
30939
+ const claudeDir = join23(currentSkillsDir, "..");
30647
30940
  result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir);
30648
30941
  logger.success(`Backup created at: ${result.backupPath}`);
30649
30942
  }
@@ -30695,14 +30988,14 @@ class SkillsMigrator {
30695
30988
  const migrated = [];
30696
30989
  const preserved = [];
30697
30990
  const errors2 = [];
30698
- const tempDir = join22(currentSkillsDir, "..", ".skills-migration-temp");
30991
+ const tempDir = join23(currentSkillsDir, "..", ".skills-migration-temp");
30699
30992
  await mkdir7(tempDir, { recursive: true });
30700
30993
  try {
30701
30994
  for (const mapping of mappings) {
30702
30995
  try {
30703
30996
  const skillName = mapping.skillName;
30704
30997
  const currentSkillPath = mapping.oldPath;
30705
- if (!await import_fs_extra14.pathExists(currentSkillPath)) {
30998
+ if (!await import_fs_extra15.pathExists(currentSkillPath)) {
30706
30999
  logger.warning(`Skill not found, skipping: ${skillName}`);
30707
31000
  continue;
30708
31001
  }
@@ -30716,9 +31009,9 @@ class SkillsMigrator {
30716
31009
  }
30717
31010
  }
30718
31011
  const category = mapping.category;
30719
- const targetPath = category ? join22(tempDir, category, skillName) : join22(tempDir, skillName);
31012
+ const targetPath = category ? join23(tempDir, category, skillName) : join23(tempDir, skillName);
30720
31013
  if (category) {
30721
- await mkdir7(join22(tempDir, category), { recursive: true });
31014
+ await mkdir7(join23(tempDir, category), { recursive: true });
30722
31015
  }
30723
31016
  await SkillsMigrator.copySkillDirectory(currentSkillPath, targetPath);
30724
31017
  migrated.push(skillName);
@@ -30750,10 +31043,10 @@ class SkillsMigrator {
30750
31043
  }
30751
31044
  static async copySkillDirectory(sourceDir, destDir) {
30752
31045
  await mkdir7(destDir, { recursive: true });
30753
- const entries = await readdir10(sourceDir, { withFileTypes: true });
31046
+ const entries = await readdir11(sourceDir, { withFileTypes: true });
30754
31047
  for (const entry of entries) {
30755
- const sourcePath = join22(sourceDir, entry.name);
30756
- const destPath = join22(destDir, entry.name);
31048
+ const sourcePath = join23(sourceDir, entry.name);
31049
+ const destPath = join23(destDir, entry.name);
30757
31050
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
30758
31051
  continue;
30759
31052
  }
@@ -30773,9 +31066,12 @@ init_types2();
30773
31066
  init_types2();
30774
31067
  init_logger();
30775
31068
  import { existsSync as existsSync5 } from "node:fs";
30776
- import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile9 } from "node:fs/promises";
31069
+ import { mkdir as mkdir8, readFile as readFile12, writeFile as writeFile10 } from "node:fs/promises";
30777
31070
  import { chmod as chmod2 } from "node:fs/promises";
30778
31071
  import { platform as platform8 } from "node:os";
31072
+ import { join as join24 } from "node:path";
31073
+ var PROJECT_CONFIG_FILE = ".ck.json";
31074
+
30779
31075
  class ConfigManager {
30780
31076
  static config = null;
30781
31077
  static globalFlag = false;
@@ -30793,7 +31089,7 @@ class ConfigManager {
30793
31089
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
30794
31090
  try {
30795
31091
  if (existsSync5(configFile)) {
30796
- const content = await readFile11(configFile, "utf-8");
31092
+ const content = await readFile12(configFile, "utf-8");
30797
31093
  const data = JSON.parse(content);
30798
31094
  ConfigManager.config = ConfigSchema.parse(data);
30799
31095
  logger.debug(`Config loaded from ${configFile}`);
@@ -30816,7 +31112,7 @@ class ConfigManager {
30816
31112
  await chmod2(configDir, 448);
30817
31113
  }
30818
31114
  }
30819
- await writeFile9(configFile, JSON.stringify(validConfig, null, 2), "utf-8");
31115
+ await writeFile10(configFile, JSON.stringify(validConfig, null, 2), "utf-8");
30820
31116
  if (platform8() !== "win32") {
30821
31117
  await chmod2(configFile, 384);
30822
31118
  }
@@ -30842,6 +31138,56 @@ class ConfigManager {
30842
31138
  current[keys[keys.length - 1]] = value;
30843
31139
  await ConfigManager.save(config);
30844
31140
  }
31141
+ static async loadProjectConfig(projectDir) {
31142
+ const configPath = join24(projectDir, ".claude", PROJECT_CONFIG_FILE);
31143
+ try {
31144
+ if (existsSync5(configPath)) {
31145
+ const content = await readFile12(configPath, "utf-8");
31146
+ const data = JSON.parse(content);
31147
+ const folders = FoldersConfigSchema.parse(data.paths || data);
31148
+ logger.debug(`Project config loaded from ${configPath}`);
31149
+ return folders;
31150
+ }
31151
+ } catch (error2) {
31152
+ logger.warning(`Failed to load project config from ${configPath}: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
31153
+ }
31154
+ return null;
31155
+ }
31156
+ static async saveProjectConfig(projectDir, folders) {
31157
+ const claudeDir = join24(projectDir, ".claude");
31158
+ const configPath = join24(claudeDir, PROJECT_CONFIG_FILE);
31159
+ try {
31160
+ if (!existsSync5(claudeDir)) {
31161
+ await mkdir8(claudeDir, { recursive: true });
31162
+ }
31163
+ const validFolders = FoldersConfigSchema.parse(folders);
31164
+ await writeFile10(configPath, JSON.stringify({ paths: validFolders }, null, 2), "utf-8");
31165
+ logger.debug(`Project config saved to ${configPath}`);
31166
+ } catch (error2) {
31167
+ throw new Error(`Failed to save project config: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
31168
+ }
31169
+ }
31170
+ static async resolveFoldersConfig(projectDir, cliOptions) {
31171
+ const result = { ...DEFAULT_FOLDERS };
31172
+ const globalConfig = await ConfigManager.load();
31173
+ if (globalConfig.folders?.docs)
31174
+ result.docs = globalConfig.folders.docs;
31175
+ if (globalConfig.folders?.plans)
31176
+ result.plans = globalConfig.folders.plans;
31177
+ const projectConfig = await ConfigManager.loadProjectConfig(projectDir);
31178
+ if (projectConfig?.docs)
31179
+ result.docs = projectConfig.docs;
31180
+ if (projectConfig?.plans)
31181
+ result.plans = projectConfig.plans;
31182
+ if (cliOptions?.docsDir)
31183
+ result.docs = cliOptions.docsDir;
31184
+ if (cliOptions?.plansDir)
31185
+ result.plans = cliOptions.plansDir;
31186
+ return result;
31187
+ }
31188
+ static projectConfigExists(projectDir) {
31189
+ return existsSync5(join24(projectDir, ".claude", PROJECT_CONFIG_FILE));
31190
+ }
30845
31191
  }
30846
31192
 
30847
31193
  // src/commands/init.ts
@@ -30849,8 +31195,8 @@ init_environment();
30849
31195
 
30850
31196
  // src/utils/file-scanner.ts
30851
31197
  init_logger();
30852
- var import_fs_extra15 = __toESM(require_lib(), 1);
30853
- import { join as join23, relative as relative7, resolve as resolve2 } from "node:path";
31198
+ var import_fs_extra16 = __toESM(require_lib(), 1);
31199
+ import { join as join25, relative as relative8, resolve as resolve2 } from "node:path";
30854
31200
  var SKIP_DIRS = [
30855
31201
  "node_modules",
30856
31202
  ".venv",
@@ -30867,24 +31213,24 @@ class FileScanner {
30867
31213
  static async getFiles(dirPath, relativeTo) {
30868
31214
  const basePath = relativeTo || dirPath;
30869
31215
  const files = [];
30870
- if (!await import_fs_extra15.pathExists(dirPath)) {
31216
+ if (!await import_fs_extra16.pathExists(dirPath)) {
30871
31217
  return files;
30872
31218
  }
30873
31219
  try {
30874
- const entries = await import_fs_extra15.readdir(dirPath, { encoding: "utf8" });
31220
+ const entries = await import_fs_extra16.readdir(dirPath, { encoding: "utf8" });
30875
31221
  for (const entry of entries) {
30876
31222
  if (SKIP_DIRS.includes(entry)) {
30877
31223
  logger.debug(`Skipping directory: ${entry}`);
30878
31224
  continue;
30879
31225
  }
30880
- const fullPath = join23(dirPath, entry);
31226
+ const fullPath = join25(dirPath, entry);
30881
31227
  if (!FileScanner.isSafePath(basePath, fullPath)) {
30882
31228
  logger.warning(`Skipping potentially unsafe path: ${entry}`);
30883
31229
  continue;
30884
31230
  }
30885
31231
  let stats;
30886
31232
  try {
30887
- stats = await import_fs_extra15.lstat(fullPath);
31233
+ stats = await import_fs_extra16.lstat(fullPath);
30888
31234
  } catch (error2) {
30889
31235
  if (error2 instanceof Error && "code" in error2 && (error2.code === "EACCES" || error2.code === "EPERM")) {
30890
31236
  logger.warning(`Skipping inaccessible path: ${entry}`);
@@ -30900,7 +31246,7 @@ class FileScanner {
30900
31246
  const subFiles = await FileScanner.getFiles(fullPath, basePath);
30901
31247
  files.push(...subFiles);
30902
31248
  } else if (stats.isFile()) {
30903
- const relativePath = relative7(basePath, fullPath);
31249
+ const relativePath = relative8(basePath, fullPath);
30904
31250
  files.push(FileScanner.toPosixPath(relativePath));
30905
31251
  }
30906
31252
  }
@@ -30912,8 +31258,8 @@ class FileScanner {
30912
31258
  return files;
30913
31259
  }
30914
31260
  static async findCustomFiles(destDir, sourceDir, subPath) {
30915
- const destSubDir = join23(destDir, subPath);
30916
- const sourceSubDir = join23(sourceDir, subPath);
31261
+ const destSubDir = join25(destDir, subPath);
31262
+ const sourceSubDir = join25(sourceDir, subPath);
30917
31263
  const destFiles = await FileScanner.getFiles(destSubDir, destDir);
30918
31264
  const sourceFiles = await FileScanner.getFiles(sourceSubDir, sourceDir);
30919
31265
  const sourceFileSet = new Set(sourceFiles);
@@ -30950,6 +31296,34 @@ async function initCommand(options) {
30950
31296
  logger.info("Global mode enabled - using platform-specific user configuration");
30951
31297
  }
30952
31298
  const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
31299
+ if (validOptions.global) {
31300
+ const localSettingsPath = join26(process.cwd(), ".claude", "settings.json");
31301
+ if (await import_fs_extra17.pathExists(localSettingsPath)) {
31302
+ if (isNonInteractive2) {
31303
+ logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
31304
+ logger.warning("Consider removing local installation: rm -rf .claude");
31305
+ } else {
31306
+ const choice = await prompts.promptLocalMigration();
31307
+ if (choice === "cancel") {
31308
+ prompts.outro("Installation cancelled.");
31309
+ return;
31310
+ }
31311
+ if (choice === "remove") {
31312
+ const localClaudeDir = join26(process.cwd(), ".claude");
31313
+ try {
31314
+ await import_fs_extra17.remove(localClaudeDir);
31315
+ logger.success("Removed local .claude/ directory");
31316
+ } catch (error2) {
31317
+ logger.error(`Failed to remove local installation: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
31318
+ logger.warning("Proceeding with global installation anyway.");
31319
+ }
31320
+ }
31321
+ if (choice === "keep") {
31322
+ logger.warning("Proceeding with global installation. Local settings will take precedence.");
31323
+ }
31324
+ }
31325
+ }
31326
+ }
30953
31327
  const config = await ConfigManager.get();
30954
31328
  let kit = validOptions.kit || config.defaults?.kit;
30955
31329
  if (!kit) {
@@ -30972,7 +31346,7 @@ async function initCommand(options) {
30972
31346
  }
30973
31347
  const resolvedDir = resolve4(targetDir);
30974
31348
  logger.info(`Target directory: ${resolvedDir}`);
30975
- if (!await import_fs_extra16.pathExists(resolvedDir)) {
31349
+ if (!await import_fs_extra17.pathExists(resolvedDir)) {
30976
31350
  if (validOptions.global) {
30977
31351
  const { mkdir: mkdir9 } = await import("node:fs/promises");
30978
31352
  await mkdir9(resolvedDir, { recursive: true });
@@ -30985,7 +31359,7 @@ async function initCommand(options) {
30985
31359
  }
30986
31360
  if (validOptions.fresh) {
30987
31361
  const prefix = PathResolver.getPathPrefix(validOptions.global);
30988
- const claudeDir2 = prefix ? join24(resolvedDir, prefix) : resolvedDir;
31362
+ const claudeDir2 = prefix ? join26(resolvedDir, prefix) : resolvedDir;
30989
31363
  const canProceed = await handleFreshInstallation(claudeDir2, prompts);
30990
31364
  if (!canProceed) {
30991
31365
  return;
@@ -31095,10 +31469,30 @@ async function initCommand(options) {
31095
31469
  });
31096
31470
  logger.success(`Transformed ${transformResult.totalChanges} path(s) in ${transformResult.filesTransformed} file(s)`);
31097
31471
  }
31472
+ const foldersConfig = await ConfigManager.resolveFoldersConfig(resolvedDir, {
31473
+ docsDir: validOptions.docsDir,
31474
+ plansDir: validOptions.plansDir
31475
+ });
31476
+ validateFolderOptions(validOptions);
31477
+ const hasCustomFolders = foldersConfig.docs !== DEFAULT_FOLDERS.docs || foldersConfig.plans !== DEFAULT_FOLDERS.plans;
31478
+ if (hasCustomFolders) {
31479
+ logger.info(`Using custom folder names: docs=${foldersConfig.docs}, plans=${foldersConfig.plans}`);
31480
+ const folderTransformResult = await transformFolderPaths(extractDir, foldersConfig, {
31481
+ verbose: logger.isVerbose()
31482
+ });
31483
+ logger.success(`Transformed ${folderTransformResult.foldersRenamed} folder(s), ${folderTransformResult.totalReferences} reference(s) in ${folderTransformResult.filesTransformed} file(s)`);
31484
+ if (validOptions.docsDir || validOptions.plansDir) {
31485
+ await ConfigManager.saveProjectConfig(resolvedDir, {
31486
+ docs: foldersConfig.docs,
31487
+ plans: foldersConfig.plans
31488
+ });
31489
+ logger.debug("Saved folder configuration to .claude/.ck.json");
31490
+ }
31491
+ }
31098
31492
  if (!validOptions.fresh) {
31099
- const newSkillsDir = join24(extractDir, ".claude", "skills");
31493
+ const newSkillsDir = join26(extractDir, ".claude", "skills");
31100
31494
  const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
31101
- if (await import_fs_extra16.pathExists(newSkillsDir) && await import_fs_extra16.pathExists(currentSkillsDir)) {
31495
+ if (await import_fs_extra17.pathExists(newSkillsDir) && await import_fs_extra17.pathExists(currentSkillsDir)) {
31102
31496
  logger.info("Checking for skills directory migration...");
31103
31497
  const migrationDetection = await SkillsMigrationDetector.detectMigration(newSkillsDir, currentSkillsDir);
31104
31498
  if (migrationDetection.status === "recommended" || migrationDetection.status === "required") {
@@ -31121,7 +31515,7 @@ async function initCommand(options) {
31121
31515
  let customClaudeFiles = [];
31122
31516
  if (!validOptions.fresh) {
31123
31517
  logger.info("Scanning for custom .claude files...");
31124
- const scanSourceDir = validOptions.global ? join24(extractDir, ".claude") : extractDir;
31518
+ const scanSourceDir = validOptions.global ? join26(extractDir, ".claude") : extractDir;
31125
31519
  const scanTargetSubdir = validOptions.global ? "" : ".claude";
31126
31520
  customClaudeFiles = await FileScanner.findCustomFiles(resolvedDir, scanSourceDir, scanTargetSubdir);
31127
31521
  } else {
@@ -31150,9 +31544,9 @@ async function initCommand(options) {
31150
31544
  merger.addIgnorePatterns(validOptions.exclude);
31151
31545
  }
31152
31546
  merger.setGlobalFlag(validOptions.global);
31153
- const claudeDir = validOptions.global ? resolvedDir : join24(resolvedDir, ".claude");
31547
+ const claudeDir = validOptions.global ? resolvedDir : join26(resolvedDir, ".claude");
31154
31548
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
31155
- if (!validOptions.fresh && await import_fs_extra16.pathExists(claudeDir)) {
31549
+ if (!validOptions.fresh && await import_fs_extra17.pathExists(claudeDir)) {
31156
31550
  const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
31157
31551
  if (legacyDetection.isLegacy && releaseManifest) {
31158
31552
  logger.info("Legacy installation detected - migrating to ownership tracking...");
@@ -31172,7 +31566,7 @@ async function initCommand(options) {
31172
31566
  return;
31173
31567
  }
31174
31568
  }
31175
- const sourceDir = validOptions.global ? join24(extractDir, ".claude") : extractDir;
31569
+ const sourceDir = validOptions.global ? join26(extractDir, ".claude") : extractDir;
31176
31570
  await merger.merge(sourceDir, resolvedDir, false);
31177
31571
  const manifestWriter = new ManifestWriter;
31178
31572
  const installedFiles = merger.getAllInstalledFiles();
@@ -31181,7 +31575,7 @@ async function initCommand(options) {
31181
31575
  if (!validOptions.global && !installedPath.startsWith(".claude/"))
31182
31576
  continue;
31183
31577
  const relativePath = validOptions.global ? installedPath : installedPath.replace(/^\.claude\//, "");
31184
- const filePath = join24(claudeDir, relativePath);
31578
+ const filePath = join26(claudeDir, relativePath);
31185
31579
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
31186
31580
  const ownership = manifestEntry ? "ck" : "user";
31187
31581
  filesToTrack.push({
@@ -31202,11 +31596,11 @@ async function initCommand(options) {
31202
31596
  trackingSpinner.succeed(`Tracked ${trackResult.success} files`);
31203
31597
  await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local");
31204
31598
  if (validOptions.global) {
31205
- const claudeMdSource = join24(extractDir, "CLAUDE.md");
31206
- const claudeMdDest = join24(resolvedDir, "CLAUDE.md");
31207
- if (await import_fs_extra16.pathExists(claudeMdSource)) {
31208
- if (!await import_fs_extra16.pathExists(claudeMdDest)) {
31209
- await import_fs_extra16.copy(claudeMdSource, claudeMdDest);
31599
+ const claudeMdSource = join26(extractDir, "CLAUDE.md");
31600
+ const claudeMdDest = join26(resolvedDir, "CLAUDE.md");
31601
+ if (await import_fs_extra17.pathExists(claudeMdSource)) {
31602
+ if (!await import_fs_extra17.pathExists(claudeMdDest)) {
31603
+ await import_fs_extra17.copy(claudeMdSource, claudeMdDest);
31210
31604
  logger.success("Copied CLAUDE.md to global directory");
31211
31605
  } else {
31212
31606
  logger.debug("CLAUDE.md already exists in global directory (preserved)");
@@ -31223,8 +31617,8 @@ async function initCommand(options) {
31223
31617
  await handleSkillsInstallation2(skillsDir);
31224
31618
  }
31225
31619
  if (!validOptions.skipSetup && !isNonInteractive2) {
31226
- const envPath = join24(claudeDir, ".env");
31227
- if (!await import_fs_extra16.pathExists(envPath)) {
31620
+ const envPath = join26(claudeDir, ".env");
31621
+ if (!await import_fs_extra17.pathExists(envPath)) {
31228
31622
  const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
31229
31623
  if (shouldSetup) {
31230
31624
  await runSetupWizard({
@@ -31254,8 +31648,8 @@ Protected files (.env, etc.) were not modified.`;
31254
31648
  }
31255
31649
 
31256
31650
  // src/commands/new.ts
31257
- var import_fs_extra17 = __toESM(require_lib(), 1);
31258
- import { join as join25, resolve as resolve5 } from "node:path";
31651
+ var import_fs_extra18 = __toESM(require_lib(), 1);
31652
+ import { join as join27, resolve as resolve5 } from "node:path";
31259
31653
  init_types2();
31260
31654
  init_environment();
31261
31655
  init_logger();
@@ -31286,8 +31680,8 @@ async function newCommand(options) {
31286
31680
  }
31287
31681
  const resolvedDir = resolve5(targetDir);
31288
31682
  logger.info(`Target directory: ${resolvedDir}`);
31289
- if (await import_fs_extra17.pathExists(resolvedDir)) {
31290
- const files = await import_fs_extra17.readdir(resolvedDir);
31683
+ if (await import_fs_extra18.pathExists(resolvedDir)) {
31684
+ const files = await import_fs_extra18.readdir(resolvedDir);
31291
31685
  const isEmpty = files.length === 0;
31292
31686
  if (!isEmpty) {
31293
31687
  if (isNonInteractive2) {
@@ -31401,6 +31795,23 @@ async function newCommand(options) {
31401
31795
  if (CommandsPrefix.shouldApplyPrefix(validOptions)) {
31402
31796
  await CommandsPrefix.applyPrefix(extractDir);
31403
31797
  }
31798
+ const foldersConfig = await ConfigManager.resolveFoldersConfig(resolvedDir, {
31799
+ docsDir: validOptions.docsDir,
31800
+ plansDir: validOptions.plansDir
31801
+ });
31802
+ validateFolderOptions(validOptions);
31803
+ const hasCustomFolders = foldersConfig.docs !== DEFAULT_FOLDERS.docs || foldersConfig.plans !== DEFAULT_FOLDERS.plans;
31804
+ if (hasCustomFolders) {
31805
+ const transformResult = await transformFolderPaths(extractDir, foldersConfig, {
31806
+ verbose: logger.isVerbose()
31807
+ });
31808
+ logger.success(`Transformed ${transformResult.foldersRenamed} folder(s), ` + `${transformResult.totalReferences} reference(s) in ${transformResult.filesTransformed} file(s)`);
31809
+ await ConfigManager.saveProjectConfig(resolvedDir, {
31810
+ docs: foldersConfig.docs,
31811
+ plans: foldersConfig.plans
31812
+ });
31813
+ logger.debug("Saved folder configuration to .claude/.ck.json");
31814
+ }
31404
31815
  const merger = new FileMerger;
31405
31816
  if (validOptions.exclude && validOptions.exclude.length > 0) {
31406
31817
  merger.addIgnorePatterns(validOptions.exclude);
@@ -31409,7 +31820,7 @@ async function newCommand(options) {
31409
31820
  await CommandsPrefix.cleanupCommandsDirectory(resolvedDir, false);
31410
31821
  }
31411
31822
  await merger.merge(extractDir, resolvedDir, true);
31412
- const claudeDir = join25(resolvedDir, ".claude");
31823
+ const claudeDir = join27(resolvedDir, ".claude");
31413
31824
  const manifestWriter = new ManifestWriter;
31414
31825
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
31415
31826
  const installedFiles = merger.getAllInstalledFiles();
@@ -31418,7 +31829,7 @@ async function newCommand(options) {
31418
31829
  if (!installedPath.startsWith(".claude/"))
31419
31830
  continue;
31420
31831
  const relativePath = installedPath.replace(/^\.claude\//, "");
31421
- const filePath = join25(claudeDir, relativePath);
31832
+ const filePath = join27(claudeDir, relativePath);
31422
31833
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
31423
31834
  const ownership = manifestEntry ? "ck" : "user";
31424
31835
  filesToTrack.push({
@@ -31471,10 +31882,10 @@ async function newCommand(options) {
31471
31882
 
31472
31883
  // src/commands/uninstall.ts
31473
31884
  init_dist2();
31474
- var import_fs_extra18 = __toESM(require_lib(), 1);
31885
+ var import_fs_extra19 = __toESM(require_lib(), 1);
31475
31886
  var import_picocolors10 = __toESM(require_picocolors(), 1);
31476
31887
  import { readdirSync, rmSync } from "node:fs";
31477
- import { dirname as dirname4, join as join26 } from "node:path";
31888
+ import { dirname as dirname4, join as join28 } from "node:path";
31478
31889
  init_types2();
31479
31890
  init_logger();
31480
31891
  async function detectInstallations() {
@@ -31484,14 +31895,14 @@ async function detectInstallations() {
31484
31895
  installations.push({
31485
31896
  type: "local",
31486
31897
  path: setup.project.path,
31487
- exists: await import_fs_extra18.pathExists(setup.project.path)
31898
+ exists: await import_fs_extra19.pathExists(setup.project.path)
31488
31899
  });
31489
31900
  }
31490
31901
  if (setup.global.path && setup.global.metadata) {
31491
31902
  installations.push({
31492
31903
  type: "global",
31493
31904
  path: setup.global.path,
31494
- exists: await import_fs_extra18.pathExists(setup.global.path)
31905
+ exists: await import_fs_extra19.pathExists(setup.global.path)
31495
31906
  });
31496
31907
  }
31497
31908
  return installations.filter((i) => i.exists);
@@ -31565,7 +31976,7 @@ async function analyzeInstallation(installation, forceOverwrite) {
31565
31976
  return result;
31566
31977
  }
31567
31978
  for (const trackedFile of metadata.files) {
31568
- const filePath = join26(installation.path, trackedFile.path);
31979
+ const filePath = join28(installation.path, trackedFile.path);
31569
31980
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
31570
31981
  if (!ownershipResult.exists)
31571
31982
  continue;
@@ -31623,9 +32034,9 @@ async function removeInstallations(installations, options) {
31623
32034
  let removedCount = 0;
31624
32035
  let cleanedDirs = 0;
31625
32036
  for (const item of analysis.toDelete) {
31626
- const filePath = join26(installation.path, item.path);
31627
- if (await import_fs_extra18.pathExists(filePath)) {
31628
- await import_fs_extra18.remove(filePath);
32037
+ const filePath = join28(installation.path, item.path);
32038
+ if (await import_fs_extra19.pathExists(filePath)) {
32039
+ await import_fs_extra19.remove(filePath);
31629
32040
  removedCount++;
31630
32041
  logger.debug(`Removed: ${item.path}`);
31631
32042
  cleanedDirs += await cleanupEmptyDirectories(filePath, installation.path);
@@ -31725,7 +32136,7 @@ import { promisify as promisify6 } from "node:util";
31725
32136
  // package.json
31726
32137
  var package_default2 = {
31727
32138
  name: "claudekit-cli",
31728
- version: "3.1.0",
32139
+ version: "3.3.0",
31729
32140
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
31730
32141
  type: "module",
31731
32142
  repository: {
@@ -32170,14 +32581,14 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
32170
32581
  // src/lib/version-cache.ts
32171
32582
  init_logger();
32172
32583
  import { existsSync as existsSync6 } from "node:fs";
32173
- import { mkdir as mkdir9, readFile as readFile12, writeFile as writeFile10 } from "node:fs/promises";
32174
- import { join as join27 } from "node:path";
32584
+ import { mkdir as mkdir9, readFile as readFile13, writeFile as writeFile11 } from "node:fs/promises";
32585
+ import { join as join29 } from "node:path";
32175
32586
  class VersionCacheManager {
32176
32587
  static CACHE_FILENAME = "version-check.json";
32177
32588
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
32178
32589
  static getCacheFile() {
32179
32590
  const cacheDir = PathResolver.getCacheDir(false);
32180
- return join27(cacheDir, VersionCacheManager.CACHE_FILENAME);
32591
+ return join29(cacheDir, VersionCacheManager.CACHE_FILENAME);
32181
32592
  }
32182
32593
  static async load() {
32183
32594
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -32186,7 +32597,7 @@ class VersionCacheManager {
32186
32597
  logger.debug("Version check cache not found");
32187
32598
  return null;
32188
32599
  }
32189
- const content = await readFile12(cacheFile, "utf-8");
32600
+ const content = await readFile13(cacheFile, "utf-8");
32190
32601
  const cache2 = JSON.parse(content);
32191
32602
  if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
32192
32603
  logger.debug("Invalid cache structure, ignoring");
@@ -32206,7 +32617,7 @@ class VersionCacheManager {
32206
32617
  if (!existsSync6(cacheDir)) {
32207
32618
  await mkdir9(cacheDir, { recursive: true, mode: 448 });
32208
32619
  }
32209
- await writeFile10(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
32620
+ await writeFile11(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
32210
32621
  logger.debug(`Version check cache saved to ${cacheFile}`);
32211
32622
  } catch (error2) {
32212
32623
  logger.debug(`Failed to save version check cache: ${error2}`);
@@ -32417,6 +32828,10 @@ class CliVersionChecker {
32417
32828
  init_zod();
32418
32829
  var KitType2 = exports_external.enum(["engineer", "marketing"]);
32419
32830
  var ExcludePatternSchema2 = exports_external.string().trim().min(1, "Exclude pattern cannot be empty").max(500, "Exclude pattern too long").refine((val) => !val.startsWith("/"), "Absolute paths not allowed in exclude patterns").refine((val) => !val.includes(".."), "Path traversal not allowed in exclude patterns");
32831
+ var FoldersConfigSchema2 = exports_external.object({
32832
+ docs: exports_external.string().optional(),
32833
+ plans: exports_external.string().optional()
32834
+ });
32420
32835
  var NewCommandOptionsSchema2 = exports_external.object({
32421
32836
  dir: exports_external.string().default("."),
32422
32837
  kit: KitType2.optional(),
@@ -32429,7 +32844,9 @@ var NewCommandOptionsSchema2 = exports_external.object({
32429
32844
  prefix: exports_external.boolean().default(false),
32430
32845
  beta: exports_external.boolean().default(false),
32431
32846
  dryRun: exports_external.boolean().default(false),
32432
- refresh: exports_external.boolean().default(false)
32847
+ refresh: exports_external.boolean().default(false),
32848
+ docsDir: exports_external.string().optional(),
32849
+ plansDir: exports_external.string().optional()
32433
32850
  });
32434
32851
  var UpdateCommandOptionsSchema2 = exports_external.object({
32435
32852
  dir: exports_external.string().default("."),
@@ -32445,7 +32862,9 @@ var UpdateCommandOptionsSchema2 = exports_external.object({
32445
32862
  dryRun: exports_external.boolean().default(false),
32446
32863
  forceOverwrite: exports_external.boolean().default(false),
32447
32864
  skipSetup: exports_external.boolean().default(false),
32448
- refresh: exports_external.boolean().default(false)
32865
+ refresh: exports_external.boolean().default(false),
32866
+ docsDir: exports_external.string().optional(),
32867
+ plansDir: exports_external.string().optional()
32449
32868
  });
32450
32869
  var VersionCommandOptionsSchema2 = exports_external.object({
32451
32870
  kit: KitType2.optional(),
@@ -32486,7 +32905,8 @@ var ConfigSchema2 = exports_external.object({
32486
32905
  defaults: exports_external.object({
32487
32906
  kit: KitType2.optional(),
32488
32907
  dir: exports_external.string().optional()
32489
- }).optional()
32908
+ }).optional(),
32909
+ folders: FoldersConfigSchema2.optional()
32490
32910
  });
32491
32911
  var GitHubReleaseAssetSchema2 = exports_external.object({
32492
32912
  id: exports_external.number(),
@@ -32643,7 +33063,7 @@ var logger2 = new Logger2;
32643
33063
 
32644
33064
  // src/utils/path-resolver.ts
32645
33065
  import { homedir as homedir2, platform as platform9 } from "node:os";
32646
- import { join as join28, normalize as normalize4 } from "node:path";
33066
+ import { join as join30, normalize as normalize4 } from "node:path";
32647
33067
 
32648
33068
  class PathResolver2 {
32649
33069
  static getTestHomeDir() {
@@ -32676,50 +33096,50 @@ class PathResolver2 {
32676
33096
  static getConfigDir(global3 = false) {
32677
33097
  const testHome = PathResolver2.getTestHomeDir();
32678
33098
  if (testHome) {
32679
- return global3 ? join28(testHome, ".config", "claude") : join28(testHome, ".claudekit");
33099
+ return global3 ? join30(testHome, ".config", "claude") : join30(testHome, ".claudekit");
32680
33100
  }
32681
33101
  if (!global3) {
32682
- return join28(homedir2(), ".claudekit");
33102
+ return join30(homedir2(), ".claudekit");
32683
33103
  }
32684
33104
  const os2 = platform9();
32685
33105
  if (os2 === "win32") {
32686
- const localAppData = process.env.LOCALAPPDATA || join28(homedir2(), "AppData", "Local");
32687
- return join28(localAppData, "claude");
33106
+ const localAppData = process.env.LOCALAPPDATA || join30(homedir2(), "AppData", "Local");
33107
+ return join30(localAppData, "claude");
32688
33108
  }
32689
33109
  const xdgConfigHome = process.env.XDG_CONFIG_HOME;
32690
33110
  if (xdgConfigHome) {
32691
- return join28(xdgConfigHome, "claude");
33111
+ return join30(xdgConfigHome, "claude");
32692
33112
  }
32693
- return join28(homedir2(), ".config", "claude");
33113
+ return join30(homedir2(), ".config", "claude");
32694
33114
  }
32695
33115
  static getConfigFile(global3 = false) {
32696
- return join28(PathResolver2.getConfigDir(global3), "config.json");
33116
+ return join30(PathResolver2.getConfigDir(global3), "config.json");
32697
33117
  }
32698
33118
  static getCacheDir(global3 = false) {
32699
33119
  const testHome = PathResolver2.getTestHomeDir();
32700
33120
  if (testHome) {
32701
- return global3 ? join28(testHome, ".cache", "claude") : join28(testHome, ".claudekit", "cache");
33121
+ return global3 ? join30(testHome, ".cache", "claude") : join30(testHome, ".claudekit", "cache");
32702
33122
  }
32703
33123
  if (!global3) {
32704
- return join28(homedir2(), ".claudekit", "cache");
33124
+ return join30(homedir2(), ".claudekit", "cache");
32705
33125
  }
32706
33126
  const os2 = platform9();
32707
33127
  if (os2 === "win32") {
32708
- const localAppData = process.env.LOCALAPPDATA || join28(homedir2(), "AppData", "Local");
32709
- return join28(localAppData, "claude", "cache");
33128
+ const localAppData = process.env.LOCALAPPDATA || join30(homedir2(), "AppData", "Local");
33129
+ return join30(localAppData, "claude", "cache");
32710
33130
  }
32711
33131
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
32712
33132
  if (xdgCacheHome) {
32713
- return join28(xdgCacheHome, "claude");
33133
+ return join30(xdgCacheHome, "claude");
32714
33134
  }
32715
- return join28(homedir2(), ".cache", "claude");
33135
+ return join30(homedir2(), ".cache", "claude");
32716
33136
  }
32717
33137
  static getGlobalKitDir() {
32718
33138
  const testHome = PathResolver2.getTestHomeDir();
32719
33139
  if (testHome) {
32720
- return join28(testHome, ".claude");
33140
+ return join30(testHome, ".claude");
32721
33141
  }
32722
- return join28(homedir2(), ".claude");
33142
+ return join30(homedir2(), ".claude");
32723
33143
  }
32724
33144
  static getPathPrefix(global3) {
32725
33145
  return global3 ? "" : ".claude";
@@ -32727,9 +33147,9 @@ class PathResolver2 {
32727
33147
  static buildSkillsPath(baseDir, global3) {
32728
33148
  const prefix = PathResolver2.getPathPrefix(global3);
32729
33149
  if (prefix) {
32730
- return join28(baseDir, prefix, "skills");
33150
+ return join30(baseDir, prefix, "skills");
32731
33151
  }
32732
- return join28(baseDir, "skills");
33152
+ return join30(baseDir, "skills");
32733
33153
  }
32734
33154
  static buildComponentPath(baseDir, component, global3) {
32735
33155
  if (!PathResolver2.isPathSafe(component)) {
@@ -32737,9 +33157,9 @@ class PathResolver2 {
32737
33157
  }
32738
33158
  const prefix = PathResolver2.getPathPrefix(global3);
32739
33159
  if (prefix) {
32740
- return join28(baseDir, prefix, component);
33160
+ return join30(baseDir, prefix, component);
32741
33161
  }
32742
- return join28(baseDir, component);
33162
+ return join30(baseDir, component);
32743
33163
  }
32744
33164
  }
32745
33165
 
@@ -32757,9 +33177,9 @@ async function displayVersion() {
32757
33177
  let localKitVersion = null;
32758
33178
  let isGlobalOnlyKit = false;
32759
33179
  const globalKitDir = PathResolver2.getGlobalKitDir();
32760
- const globalMetadataPath = join29(globalKitDir, "metadata.json");
33180
+ const globalMetadataPath = join31(globalKitDir, "metadata.json");
32761
33181
  const prefix = PathResolver2.getPathPrefix(false);
32762
- const localMetadataPath = prefix ? join29(process.cwd(), prefix, "metadata.json") : join29(process.cwd(), "metadata.json");
33182
+ const localMetadataPath = prefix ? join31(process.cwd(), prefix, "metadata.json") : join31(process.cwd(), "metadata.json");
32763
33183
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
32764
33184
  if (!isLocalSameAsGlobal && existsSync7(localMetadataPath)) {
32765
33185
  try {
@@ -32817,13 +33237,13 @@ async function displayVersion() {
32817
33237
  var cli = cac("ck");
32818
33238
  cli.option("--verbose", "Enable verbose logging for debugging");
32819
33239
  cli.option("--log-file <path>", "Write logs to file");
32820
- cli.command("new", "Bootstrap a new ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer, marketing)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--force", "Overwrite existing files without confirmation").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--opencode", "Install OpenCode CLI package (non-interactive mode)").option("--gemini", "Install Google Gemini CLI package (non-interactive mode)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").action(async (options) => {
33240
+ cli.command("new", "Bootstrap a new ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer, marketing)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--force", "Overwrite existing files without confirmation").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--opencode", "Install OpenCode CLI package (non-interactive mode)").option("--gemini", "Install Google Gemini CLI package (non-interactive mode)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").action(async (options) => {
32821
33241
  if (options.exclude && !Array.isArray(options.exclude)) {
32822
33242
  options.exclude = [options.exclude];
32823
33243
  }
32824
33244
  await newCommand(options);
32825
33245
  });
32826
- cli.command("init", "Initialize or update ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer, marketing)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Completely remove .claude directory before downloading (requires confirmation)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--skip-setup", "Skip interactive configuration wizard").action(async (options) => {
33246
+ cli.command("init", "Initialize or update ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use (engineer, marketing)").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Completely remove .claude directory before downloading (requires confirmation)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").action(async (options) => {
32827
33247
  if (options.exclude && !Array.isArray(options.exclude)) {
32828
33248
  options.exclude = [options.exclude];
32829
33249
  }
@@ -32868,27 +33288,39 @@ cli.command("uninstall", "Remove ClaudeKit installations").option("-y, --yes", "
32868
33288
  cli.option("-V, --version", "Display version number");
32869
33289
  cli.option("-h, --help", "Display help information");
32870
33290
  var parsed = cli.parse(process.argv, { run: false });
32871
- if (parsed.options.version) {
32872
- await displayVersion();
32873
- process.exit(0);
32874
- }
32875
- if (parsed.options.help || !cli.matchedCommand && parsed.args.length === 0) {
32876
- const { handleHelp: handleHelp2 } = await Promise.resolve().then(() => (init_help_interceptor(), exports_help_interceptor));
32877
- await handleHelp2(parsed.args);
32878
- }
32879
- var envVerbose = process.env.CLAUDEKIT_VERBOSE === "1" || process.env.CLAUDEKIT_VERBOSE === "true";
32880
- var isVerbose = parsed.options.verbose || envVerbose;
32881
- if (isVerbose) {
32882
- logger2.setVerbose(true);
32883
- }
32884
- if (parsed.options.logFile) {
32885
- logger2.setLogFile(parsed.options.logFile);
32886
- }
32887
- logger2.verbose("ClaudeKit CLI starting", {
32888
- version: packageVersion,
32889
- command: parsed.args[0] || "none",
32890
- options: parsed.options,
32891
- cwd: process.cwd(),
32892
- node: process.version
33291
+ (async () => {
33292
+ try {
33293
+ if (parsed.options.version) {
33294
+ await displayVersion();
33295
+ process.exitCode = 0;
33296
+ return;
33297
+ }
33298
+ if (parsed.options.help || !cli.matchedCommand && parsed.args.length === 0) {
33299
+ const { handleHelp: handleHelp2 } = await Promise.resolve().then(() => (init_help_interceptor(), exports_help_interceptor));
33300
+ await handleHelp2(parsed.args);
33301
+ return;
33302
+ }
33303
+ const envVerbose = process.env.CLAUDEKIT_VERBOSE === "1" || process.env.CLAUDEKIT_VERBOSE === "true";
33304
+ const isVerbose = parsed.options.verbose || envVerbose;
33305
+ if (isVerbose) {
33306
+ logger2.setVerbose(true);
33307
+ }
33308
+ if (parsed.options.logFile) {
33309
+ logger2.setLogFile(parsed.options.logFile);
33310
+ }
33311
+ logger2.verbose("ClaudeKit CLI starting", {
33312
+ version: packageVersion,
33313
+ command: parsed.args[0] || "none",
33314
+ options: parsed.options,
33315
+ cwd: process.cwd(),
33316
+ node: process.version
33317
+ });
33318
+ cli.parse();
33319
+ } catch (error2) {
33320
+ console.error("CLI error:", error2 instanceof Error ? error2.message : error2);
33321
+ process.exitCode = 1;
33322
+ }
33323
+ })().catch((error2) => {
33324
+ console.error("Unhandled error:", error2 instanceof Error ? error2.message : error2);
33325
+ process.exitCode = 1;
32893
33326
  });
32894
- cli.parse();