claudekit-cli 3.36.0-dev.1 → 3.36.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +732 -1643
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -38479,10 +38479,7 @@ var init_metadata = __esm(() => {
38479
38479
  files: exports_external.array(TrackedFileSchema).optional(),
38480
38480
  lastUpdateCheck: exports_external.string().optional(),
38481
38481
  dismissedVersion: exports_external.string().optional(),
38482
- installedSettings: InstalledSettingsSchema.optional(),
38483
- pluginInstalled: exports_external.boolean().optional(),
38484
- pluginInstalledAt: exports_external.string().optional(),
38485
- pluginVersion: exports_external.string().optional()
38482
+ installedSettings: InstalledSettingsSchema.optional()
38486
38483
  });
38487
38484
  MultiKitMetadataSchema = exports_external.object({
38488
38485
  kits: exports_external.record(KitType, KitMetadataSchema).optional(),
@@ -53923,17 +53920,6 @@ var init_package_manager_detector = __esm(() => {
53923
53920
  });
53924
53921
 
53925
53922
  // src/domains/migration/metadata-migration.ts
53926
- var exports_metadata_migration = {};
53927
- __export(exports_metadata_migration, {
53928
- updateKitPluginState: () => updateKitPluginState,
53929
- needsMigration: () => needsMigration,
53930
- migrateToMultiKit: () => migrateToMultiKit,
53931
- getTrackedFilesForKit: () => getTrackedFilesForKit,
53932
- getKitMetadata: () => getKitMetadata,
53933
- getInstalledKits: () => getInstalledKits,
53934
- getAllTrackedFiles: () => getAllTrackedFiles,
53935
- detectMetadataFormat: () => detectMetadataFormat
53936
- });
53937
53923
  import { join as join35 } from "node:path";
53938
53924
  async function detectMetadataFormat(claudeDir2) {
53939
53925
  const metadataPath = join35(claudeDir2, "metadata.json");
@@ -53970,9 +53956,6 @@ async function detectMetadataFormat(claudeDir2) {
53970
53956
  return { format: "none", metadata: null, detectedKit: null };
53971
53957
  }
53972
53958
  }
53973
- function needsMigration(detection) {
53974
- return detection.format === "legacy";
53975
- }
53976
53959
  async function migrateToMultiKit(claudeDir2) {
53977
53960
  const detection = await detectMetadataFormat(claudeDir2);
53978
53961
  if (detection.format === "multi-kit") {
@@ -54096,41 +54079,6 @@ function getInstalledKits(metadata) {
54096
54079
  }
54097
54080
  return [];
54098
54081
  }
54099
- async function updateKitPluginState(claudeDir2, kit, state) {
54100
- const metadataPath = join35(claudeDir2, "metadata.json");
54101
- if (!await import_fs_extra3.pathExists(metadataPath)) {
54102
- logger.debug("No metadata.json found — skipping plugin state update");
54103
- return;
54104
- }
54105
- try {
54106
- let metadata = {};
54107
- try {
54108
- const raw = await import_fs_extra3.readFile(metadataPath, "utf-8");
54109
- const parsed = JSON.parse(raw);
54110
- if (parsed && typeof parsed === "object") {
54111
- metadata = parsed;
54112
- } else {
54113
- logger.warning("metadata.json is not an object; rebuilding minimal plugin metadata structure");
54114
- }
54115
- } catch (error) {
54116
- logger.warning(`metadata.json unreadable during plugin state update; rebuilding: ${error}`);
54117
- }
54118
- if (!metadata.kits || typeof metadata.kits !== "object") {
54119
- metadata.kits = {};
54120
- }
54121
- const existingKitState = metadata.kits[kit];
54122
- metadata.kits[kit] = {
54123
- ...existingKitState || {},
54124
- version: existingKitState?.version ?? "",
54125
- installedAt: existingKitState?.installedAt ?? state.pluginInstalledAt,
54126
- ...state
54127
- };
54128
- await import_fs_extra3.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
54129
- logger.debug(`Plugin state saved: ${state.pluginInstalled ? "installed" : "failed"}`);
54130
- } catch (error) {
54131
- logger.debug(`Failed to update plugin state: ${error}`);
54132
- }
54133
- }
54134
54082
  var import_fs_extra3;
54135
54083
  var init_metadata_migration = __esm(() => {
54136
54084
  init_logger();
@@ -54366,7 +54314,7 @@ var package_default;
54366
54314
  var init_package = __esm(() => {
54367
54315
  package_default = {
54368
54316
  name: "claudekit-cli",
54369
- version: "3.36.0-dev.1",
54317
+ version: "3.36.0-dev.3",
54370
54318
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
54371
54319
  type: "module",
54372
54320
  repository: {
@@ -61555,7 +61503,7 @@ var require_picomatch2 = __commonJS((exports, module) => {
61555
61503
  import { exec as exec7, execFile as execFile7, spawn as spawn3 } from "node:child_process";
61556
61504
  import { promisify as promisify13 } from "node:util";
61557
61505
  function executeInteractiveScript(command, args, options2) {
61558
- return new Promise((resolve14, reject) => {
61506
+ return new Promise((resolve13, reject) => {
61559
61507
  const child = spawn3(command, args, {
61560
61508
  stdio: ["ignore", "inherit", "inherit"],
61561
61509
  cwd: options2?.cwd,
@@ -61576,7 +61524,7 @@ function executeInteractiveScript(command, args, options2) {
61576
61524
  } else if (code !== 0) {
61577
61525
  reject(new Error(`Command exited with code ${code}`));
61578
61526
  } else {
61579
- resolve14();
61527
+ resolve13();
61580
61528
  }
61581
61529
  });
61582
61530
  child.on("error", (error) => {
@@ -61597,7 +61545,7 @@ var init_process_executor = __esm(() => {
61597
61545
  });
61598
61546
 
61599
61547
  // src/services/package-installer/validators.ts
61600
- import { resolve as resolve14 } from "node:path";
61548
+ import { resolve as resolve13 } from "node:path";
61601
61549
  function validatePackageName(packageName) {
61602
61550
  if (!packageName || typeof packageName !== "string") {
61603
61551
  throw new Error("Package name must be a non-empty string");
@@ -61610,8 +61558,8 @@ function validatePackageName(packageName) {
61610
61558
  }
61611
61559
  }
61612
61560
  function validateScriptPath(skillsDir2, scriptPath) {
61613
- const skillsDirResolved = resolve14(skillsDir2);
61614
- const scriptPathResolved = resolve14(scriptPath);
61561
+ const skillsDirResolved = resolve13(skillsDir2);
61562
+ const scriptPathResolved = resolve13(scriptPath);
61615
61563
  const skillsDirNormalized = isWindows() ? skillsDirResolved.toLowerCase() : skillsDirResolved;
61616
61564
  const scriptPathNormalized = isWindows() ? scriptPathResolved.toLowerCase() : scriptPathResolved;
61617
61565
  if (!scriptPathNormalized.startsWith(skillsDirNormalized)) {
@@ -61798,7 +61746,7 @@ var init_gemini_installer = __esm(() => {
61798
61746
  });
61799
61747
 
61800
61748
  // src/services/package-installer/opencode-installer.ts
61801
- import { join as join58 } from "node:path";
61749
+ import { join as join59 } from "node:path";
61802
61750
  async function isOpenCodeInstalled() {
61803
61751
  try {
61804
61752
  await execAsync7("opencode --version", { timeout: 5000 });
@@ -61821,7 +61769,7 @@ async function installOpenCode() {
61821
61769
  logger.info(`Installing ${displayName}...`);
61822
61770
  const { unlink: unlink11 } = await import("node:fs/promises");
61823
61771
  const { tmpdir: tmpdir4 } = await import("node:os");
61824
- const tempScriptPath = join58(tmpdir4(), "opencode-install.sh");
61772
+ const tempScriptPath = join59(tmpdir4(), "opencode-install.sh");
61825
61773
  try {
61826
61774
  logger.info("Downloading OpenCode installation script...");
61827
61775
  await execFileAsync5("curl", ["-fsSL", "https://opencode.ai/install", "-o", tempScriptPath], {
@@ -61873,7 +61821,7 @@ var PARTIAL_INSTALL_VERSION = "partial", EXIT_CODE_CRITICAL_FAILURE = 1, EXIT_CO
61873
61821
 
61874
61822
  // src/services/package-installer/install-error-handler.ts
61875
61823
  import { existsSync as existsSync44, readFileSync as readFileSync9, unlinkSync as unlinkSync2 } from "node:fs";
61876
- import { join as join59 } from "node:path";
61824
+ import { join as join60 } from "node:path";
61877
61825
  function parseNameReason(str2) {
61878
61826
  const colonIndex = str2.indexOf(":");
61879
61827
  if (colonIndex === -1) {
@@ -61882,7 +61830,7 @@ function parseNameReason(str2) {
61882
61830
  return [str2.slice(0, colonIndex).trim(), str2.slice(colonIndex + 1).trim()];
61883
61831
  }
61884
61832
  function displayInstallErrors(skillsDir2) {
61885
- const summaryPath = join59(skillsDir2, ".install-error-summary.json");
61833
+ const summaryPath = join60(skillsDir2, ".install-error-summary.json");
61886
61834
  if (!existsSync44(summaryPath)) {
61887
61835
  logger.error("Skills installation failed. Run with --verbose for details.");
61888
61836
  return;
@@ -61973,7 +61921,7 @@ async function checkNeedsSudoPackages() {
61973
61921
  }
61974
61922
  }
61975
61923
  function hasInstallState(skillsDir2) {
61976
- const stateFilePath = join59(skillsDir2, ".install-state.json");
61924
+ const stateFilePath = join60(skillsDir2, ".install-state.json");
61977
61925
  return existsSync44(stateFilePath);
61978
61926
  }
61979
61927
  var WHICH_COMMAND_TIMEOUT_MS = 5000;
@@ -61982,7 +61930,7 @@ var init_install_error_handler = __esm(() => {
61982
61930
  });
61983
61931
 
61984
61932
  // src/services/package-installer/skills-installer.ts
61985
- import { join as join60 } from "node:path";
61933
+ import { join as join61 } from "node:path";
61986
61934
  async function installSkillsDependencies(skillsDir2, options2 = {}) {
61987
61935
  const { skipConfirm = false, withSudo = false } = options2;
61988
61936
  const displayName = "Skills Dependencies";
@@ -62008,7 +61956,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
62008
61956
  const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
62009
61957
  const platform7 = process.platform;
62010
61958
  const scriptName = platform7 === "win32" ? "install.ps1" : "install.sh";
62011
- const scriptPath = join60(skillsDir2, scriptName);
61959
+ const scriptPath = join61(skillsDir2, scriptName);
62012
61960
  try {
62013
61961
  validateScriptPath(skillsDir2, scriptPath);
62014
61962
  } catch (error) {
@@ -62024,7 +61972,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
62024
61972
  logger.warning(`Skills installation script not found: ${scriptPath}`);
62025
61973
  logger.info("");
62026
61974
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
62027
- logger.info(` See: ${join60(skillsDir2, "INSTALLATION.md")}`);
61975
+ logger.info(` See: ${join61(skillsDir2, "INSTALLATION.md")}`);
62028
61976
  logger.info("");
62029
61977
  logger.info("Quick start:");
62030
61978
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -62071,7 +62019,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
62071
62019
  logger.info(` ${platform7 === "win32" ? `powershell -File "${scriptPath}"` : `bash ${scriptPath}`}`);
62072
62020
  logger.info("");
62073
62021
  logger.info("Or see complete guide:");
62074
- logger.info(` ${join60(skillsDir2, "INSTALLATION.md")}`);
62022
+ logger.info(` ${join61(skillsDir2, "INSTALLATION.md")}`);
62075
62023
  return {
62076
62024
  success: false,
62077
62025
  package: displayName,
@@ -62192,7 +62140,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
62192
62140
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
62193
62141
  logger.info("");
62194
62142
  logger.info("See complete guide:");
62195
- logger.info(` cat ${join60(skillsDir2, "INSTALLATION.md")}`);
62143
+ logger.info(` cat ${join61(skillsDir2, "INSTALLATION.md")}`);
62196
62144
  logger.info("");
62197
62145
  logger.info("Quick start:");
62198
62146
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -62238,7 +62186,7 @@ var init_skills_installer2 = __esm(() => {
62238
62186
  // src/services/package-installer/gemini-mcp/config-manager.ts
62239
62187
  import { existsSync as existsSync45 } from "node:fs";
62240
62188
  import { mkdir as mkdir17, readFile as readFile35, writeFile as writeFile20 } from "node:fs/promises";
62241
- import { dirname as dirname16, join as join61 } from "node:path";
62189
+ import { dirname as dirname15, join as join62 } from "node:path";
62242
62190
  async function readJsonFile(filePath) {
62243
62191
  try {
62244
62192
  const content = await readFile35(filePath, "utf-8");
@@ -62250,7 +62198,7 @@ async function readJsonFile(filePath) {
62250
62198
  }
62251
62199
  }
62252
62200
  async function addGeminiToGitignore(projectDir) {
62253
- const gitignorePath = join61(projectDir, ".gitignore");
62201
+ const gitignorePath = join62(projectDir, ".gitignore");
62254
62202
  const geminiPattern = ".gemini/";
62255
62203
  try {
62256
62204
  let content = "";
@@ -62278,7 +62226,7 @@ ${geminiPattern}
62278
62226
  }
62279
62227
  }
62280
62228
  async function createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath) {
62281
- const linkDir = dirname16(geminiSettingsPath);
62229
+ const linkDir = dirname15(geminiSettingsPath);
62282
62230
  if (!existsSync45(linkDir)) {
62283
62231
  await mkdir17(linkDir, { recursive: true });
62284
62232
  logger.debug(`Created directory: ${linkDir}`);
@@ -62342,12 +62290,12 @@ var init_config_manager2 = __esm(() => {
62342
62290
  // src/services/package-installer/gemini-mcp/validation.ts
62343
62291
  import { existsSync as existsSync46, lstatSync, readlinkSync } from "node:fs";
62344
62292
  import { homedir as homedir27 } from "node:os";
62345
- import { join as join62 } from "node:path";
62293
+ import { join as join63 } from "node:path";
62346
62294
  function getGlobalMcpConfigPath() {
62347
- return join62(homedir27(), ".claude", ".mcp.json");
62295
+ return join63(homedir27(), ".claude", ".mcp.json");
62348
62296
  }
62349
62297
  function getLocalMcpConfigPath(projectDir) {
62350
- return join62(projectDir, ".mcp.json");
62298
+ return join63(projectDir, ".mcp.json");
62351
62299
  }
62352
62300
  function findMcpConfigPath(projectDir) {
62353
62301
  const localPath = getLocalMcpConfigPath(projectDir);
@@ -62365,9 +62313,9 @@ function findMcpConfigPath(projectDir) {
62365
62313
  }
62366
62314
  function getGeminiSettingsPath(projectDir, isGlobal) {
62367
62315
  if (isGlobal) {
62368
- return join62(homedir27(), ".gemini", "settings.json");
62316
+ return join63(homedir27(), ".gemini", "settings.json");
62369
62317
  }
62370
- return join62(projectDir, ".gemini", "settings.json");
62318
+ return join63(projectDir, ".gemini", "settings.json");
62371
62319
  }
62372
62320
  function checkExistingGeminiConfig(projectDir, isGlobal = false) {
62373
62321
  const geminiSettingsPath = getGeminiSettingsPath(projectDir, isGlobal);
@@ -62397,9 +62345,9 @@ var init_validation = __esm(() => {
62397
62345
  // src/services/package-installer/gemini-mcp/linker-core.ts
62398
62346
  import { existsSync as existsSync47 } from "node:fs";
62399
62347
  import { mkdir as mkdir18, symlink as symlink2 } from "node:fs/promises";
62400
- import { dirname as dirname17, join as join63 } from "node:path";
62348
+ import { dirname as dirname16, join as join64 } from "node:path";
62401
62349
  async function createSymlink(targetPath, linkPath, projectDir, isGlobal) {
62402
- const linkDir = dirname17(linkPath);
62350
+ const linkDir = dirname16(linkPath);
62403
62351
  if (!existsSync47(linkDir)) {
62404
62352
  await mkdir18(linkDir, { recursive: true });
62405
62353
  logger.debug(`Created directory: ${linkDir}`);
@@ -62408,7 +62356,7 @@ async function createSymlink(targetPath, linkPath, projectDir, isGlobal) {
62408
62356
  if (isGlobal) {
62409
62357
  symlinkTarget = getGlobalMcpConfigPath();
62410
62358
  } else {
62411
- const localMcpPath = join63(projectDir, ".mcp.json");
62359
+ const localMcpPath = join64(projectDir, ".mcp.json");
62412
62360
  const isLocalConfig = targetPath === localMcpPath;
62413
62361
  symlinkTarget = isLocalConfig ? "../.mcp.json" : targetPath;
62414
62362
  }
@@ -62441,10 +62389,10 @@ __export(exports_gemini_mcp_linker, {
62441
62389
  checkExistingGeminiConfig: () => checkExistingGeminiConfig,
62442
62390
  addGeminiToGitignore: () => addGeminiToGitignore
62443
62391
  });
62444
- import { resolve as resolve15 } from "node:path";
62392
+ import { resolve as resolve14 } from "node:path";
62445
62393
  async function linkGeminiMcpConfig(projectDir, options2 = {}) {
62446
62394
  const { skipGitignore = false, isGlobal = false } = options2;
62447
- const resolvedProjectDir = resolve15(projectDir);
62395
+ const resolvedProjectDir = resolve14(projectDir);
62448
62396
  const geminiSettingsPath = getGeminiSettingsPath(resolvedProjectDir, isGlobal);
62449
62397
  const mcpConfigPath = findMcpConfigPath(resolvedProjectDir);
62450
62398
  if (!mcpConfigPath) {
@@ -63092,7 +63040,7 @@ var require_get_stream = __commonJS((exports, module) => {
63092
63040
  };
63093
63041
  const { maxBuffer } = options2;
63094
63042
  let stream;
63095
- await new Promise((resolve17, reject) => {
63043
+ await new Promise((resolve16, reject) => {
63096
63044
  const rejectPromise = (error) => {
63097
63045
  if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
63098
63046
  error.bufferedData = stream.getBufferedValue();
@@ -63104,7 +63052,7 @@ var require_get_stream = __commonJS((exports, module) => {
63104
63052
  rejectPromise(error);
63105
63053
  return;
63106
63054
  }
63107
- resolve17();
63055
+ resolve16();
63108
63056
  });
63109
63057
  stream.on("data", () => {
63110
63058
  if (stream.getBufferedLength() > maxBuffer) {
@@ -64465,7 +64413,7 @@ var require_extract_zip = __commonJS((exports, module) => {
64465
64413
  debug("opening", this.zipPath, "with opts", this.opts);
64466
64414
  this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
64467
64415
  this.canceled = false;
64468
- return new Promise((resolve17, reject) => {
64416
+ return new Promise((resolve16, reject) => {
64469
64417
  this.zipfile.on("error", (err) => {
64470
64418
  this.canceled = true;
64471
64419
  reject(err);
@@ -64474,7 +64422,7 @@ var require_extract_zip = __commonJS((exports, module) => {
64474
64422
  this.zipfile.on("close", () => {
64475
64423
  if (!this.canceled) {
64476
64424
  debug("zip extraction complete");
64477
- resolve17();
64425
+ resolve16();
64478
64426
  }
64479
64427
  });
64480
64428
  this.zipfile.on("entry", async (entry) => {
@@ -64581,412 +64529,6 @@ var require_extract_zip = __commonJS((exports, module) => {
64581
64529
  };
64582
64530
  });
64583
64531
 
64584
- // src/services/file-operations/manifest/manifest-reader.ts
64585
- import { join as join74 } from "node:path";
64586
- async function readManifest(claudeDir2) {
64587
- const metadataPath = join74(claudeDir2, "metadata.json");
64588
- if (!await import_fs_extra8.pathExists(metadataPath)) {
64589
- return null;
64590
- }
64591
- try {
64592
- const content = await import_fs_extra8.readFile(metadataPath, "utf-8");
64593
- const parsed = JSON.parse(content);
64594
- return MetadataSchema.parse(parsed);
64595
- } catch (error) {
64596
- logger.debug(`Failed to read manifest: ${error}`);
64597
- return null;
64598
- }
64599
- }
64600
- async function readKitManifest(claudeDir2, kit) {
64601
- const metadata = await readManifest(claudeDir2);
64602
- if (!metadata)
64603
- return null;
64604
- return getKitMetadata(metadata, kit);
64605
- }
64606
- async function findFileInInstalledKits(claudeDir2, relativePath, excludeKit) {
64607
- const metadata = await readManifest(claudeDir2);
64608
- if (!metadata?.kits) {
64609
- return {
64610
- exists: false,
64611
- ownerKit: null,
64612
- checksum: null,
64613
- version: null,
64614
- sourceTimestamp: null,
64615
- installedAt: null
64616
- };
64617
- }
64618
- for (const [kitName, kitMeta] of Object.entries(metadata.kits)) {
64619
- const kit = kitName;
64620
- if (kit === excludeKit)
64621
- continue;
64622
- if (!kitMeta.files)
64623
- continue;
64624
- const file = kitMeta.files.find((f3) => f3.path === relativePath);
64625
- if (file) {
64626
- return {
64627
- exists: true,
64628
- ownerKit: kit,
64629
- checksum: file.checksum,
64630
- version: kitMeta.version,
64631
- sourceTimestamp: file.sourceTimestamp ?? null,
64632
- installedAt: file.installedAt ?? null
64633
- };
64634
- }
64635
- }
64636
- return {
64637
- exists: false,
64638
- ownerKit: null,
64639
- checksum: null,
64640
- version: null,
64641
- sourceTimestamp: null,
64642
- installedAt: null
64643
- };
64644
- }
64645
- async function getUninstallManifest(claudeDir2, kit) {
64646
- const detection = await detectMetadataFormat(claudeDir2);
64647
- if (detection.format === "multi-kit" && detection.metadata?.kits) {
64648
- const installedKits = Object.keys(detection.metadata.kits);
64649
- if (kit) {
64650
- const kitMeta = detection.metadata.kits[kit];
64651
- if (!kitMeta?.files) {
64652
- return {
64653
- filesToRemove: [],
64654
- filesToPreserve: USER_CONFIG_PATTERNS,
64655
- hasManifest: true,
64656
- isMultiKit: true,
64657
- remainingKits: installedKits.filter((k2) => k2 !== kit)
64658
- };
64659
- }
64660
- const kitFiles = kitMeta.files.map((f3) => f3.path);
64661
- const sharedFiles = new Set;
64662
- for (const otherKit of installedKits) {
64663
- if (otherKit !== kit) {
64664
- const otherMeta = detection.metadata.kits[otherKit];
64665
- if (otherMeta?.files) {
64666
- for (const f3 of otherMeta.files) {
64667
- sharedFiles.add(f3.path);
64668
- }
64669
- }
64670
- }
64671
- }
64672
- const filesToRemove = kitFiles.filter((f3) => !sharedFiles.has(f3));
64673
- const filesToPreserve = [
64674
- ...USER_CONFIG_PATTERNS,
64675
- ...kitFiles.filter((f3) => sharedFiles.has(f3))
64676
- ];
64677
- return {
64678
- filesToRemove,
64679
- filesToPreserve,
64680
- hasManifest: true,
64681
- isMultiKit: true,
64682
- remainingKits: installedKits.filter((k2) => k2 !== kit)
64683
- };
64684
- }
64685
- const allFiles = getAllTrackedFiles(detection.metadata);
64686
- return {
64687
- filesToRemove: allFiles.map((f3) => f3.path),
64688
- filesToPreserve: USER_CONFIG_PATTERNS,
64689
- hasManifest: true,
64690
- isMultiKit: true,
64691
- remainingKits: []
64692
- };
64693
- }
64694
- if (detection.format === "legacy" && detection.metadata) {
64695
- const legacyFiles2 = detection.metadata.files?.map((f3) => f3.path) || [];
64696
- const installedFiles = detection.metadata.installedFiles || [];
64697
- const hasFiles = legacyFiles2.length > 0 || installedFiles.length > 0;
64698
- if (!hasFiles) {
64699
- const legacyDirs2 = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
64700
- const legacyFileList = ["metadata.json"];
64701
- return {
64702
- filesToRemove: [...legacyDirs2, ...legacyFileList],
64703
- filesToPreserve: USER_CONFIG_PATTERNS,
64704
- hasManifest: false,
64705
- isMultiKit: false,
64706
- remainingKits: []
64707
- };
64708
- }
64709
- return {
64710
- filesToRemove: legacyFiles2.length > 0 ? legacyFiles2 : installedFiles,
64711
- filesToPreserve: detection.metadata.userConfigFiles || USER_CONFIG_PATTERNS,
64712
- hasManifest: true,
64713
- isMultiKit: false,
64714
- remainingKits: []
64715
- };
64716
- }
64717
- const legacyDirs = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
64718
- const legacyFiles = ["metadata.json"];
64719
- return {
64720
- filesToRemove: [...legacyDirs, ...legacyFiles],
64721
- filesToPreserve: USER_CONFIG_PATTERNS,
64722
- hasManifest: false,
64723
- isMultiKit: false,
64724
- remainingKits: []
64725
- };
64726
- }
64727
- var import_fs_extra8;
64728
- var init_manifest_reader = __esm(() => {
64729
- init_metadata_migration();
64730
- init_logger();
64731
- init_types3();
64732
- import_fs_extra8 = __toESM(require_lib3(), 1);
64733
- });
64734
-
64735
- // src/domains/installation/deletion-handler.ts
64736
- var exports_deletion_handler = {};
64737
- __export(exports_deletion_handler, {
64738
- handleDeletions: () => handleDeletions,
64739
- categorizeDeletions: () => categorizeDeletions
64740
- });
64741
- import {
64742
- existsSync as existsSync48,
64743
- lstatSync as lstatSync3,
64744
- readdirSync as readdirSync3,
64745
- realpathSync as realpathSync3,
64746
- rmSync as rmSync2,
64747
- rmdirSync,
64748
- unlinkSync as unlinkSync3
64749
- } from "node:fs";
64750
- import { dirname as dirname19, join as join75, relative as relative10, resolve as resolve18, sep as sep3 } from "node:path";
64751
- function findFileInMetadata(metadata, path13) {
64752
- if (!metadata)
64753
- return null;
64754
- const normalizedPath = normalizeRelativePath(path13);
64755
- if (metadata.kits) {
64756
- for (const kitMeta of Object.values(metadata.kits)) {
64757
- if (kitMeta?.files) {
64758
- const found = kitMeta.files.find((f3) => normalizeRelativePath(f3.path) === normalizedPath);
64759
- if (found)
64760
- return found;
64761
- }
64762
- }
64763
- }
64764
- if (metadata.files) {
64765
- const found = metadata.files.find((f3) => normalizeRelativePath(f3.path) === normalizedPath);
64766
- if (found)
64767
- return found;
64768
- }
64769
- return null;
64770
- }
64771
- function shouldDeletePath(path13, metadata) {
64772
- const tracked = findFileInMetadata(metadata, path13);
64773
- if (!tracked)
64774
- return true;
64775
- return tracked.ownership !== "user";
64776
- }
64777
- function collectFilesRecursively(dir, baseDir) {
64778
- const results = [];
64779
- if (!existsSync48(dir))
64780
- return results;
64781
- try {
64782
- const entries = readdirSync3(dir, { withFileTypes: true });
64783
- for (const entry of entries) {
64784
- const fullPath = join75(dir, entry.name);
64785
- const relativePath = relative10(baseDir, fullPath);
64786
- if (entry.isDirectory()) {
64787
- results.push(...collectFilesRecursively(fullPath, baseDir));
64788
- } else {
64789
- results.push(normalizeRelativePath(relativePath));
64790
- }
64791
- }
64792
- } catch {}
64793
- return results;
64794
- }
64795
- function expandGlobPatterns(patterns, claudeDir2) {
64796
- const expanded = [];
64797
- const allFiles = collectFilesRecursively(claudeDir2, claudeDir2);
64798
- for (const pattern of patterns) {
64799
- const normalizedPattern = normalizeRelativePath(pattern);
64800
- if (PathResolver.isGlobPattern(normalizedPattern)) {
64801
- const matcher = import_picomatch2.default(normalizedPattern);
64802
- const matches = allFiles.filter((file) => matcher(file));
64803
- expanded.push(...matches);
64804
- if (matches.length > 0) {
64805
- logger.debug(`Pattern "${normalizedPattern}" matched ${matches.length} files`);
64806
- }
64807
- } else {
64808
- expanded.push(normalizedPattern);
64809
- }
64810
- }
64811
- return [...new Set(expanded)];
64812
- }
64813
- function cleanupEmptyDirectories(filePath, claudeDir2) {
64814
- const normalizedClaudeDir = resolve18(claudeDir2);
64815
- let currentDir = resolve18(dirname19(filePath));
64816
- let iterations = 0;
64817
- while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
64818
- iterations++;
64819
- try {
64820
- const entries = readdirSync3(currentDir);
64821
- if (entries.length === 0) {
64822
- rmdirSync(currentDir);
64823
- logger.debug(`Removed empty directory: ${currentDir}`);
64824
- currentDir = resolve18(dirname19(currentDir));
64825
- } else {
64826
- break;
64827
- }
64828
- } catch {
64829
- break;
64830
- }
64831
- }
64832
- }
64833
- function normalizeRelativePath(path13) {
64834
- return path13.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+/g, "/");
64835
- }
64836
- function isWithinBase(candidatePath, basePath) {
64837
- return candidatePath === basePath || candidatePath.startsWith(`${basePath}${sep3}`);
64838
- }
64839
- function validateExistingDeletionTarget(fullPath, claudeDir2) {
64840
- const normalizedPath = resolve18(fullPath);
64841
- const normalizedClaudeDir = resolve18(claudeDir2);
64842
- if (!isWithinBase(normalizedPath, normalizedClaudeDir)) {
64843
- throw new Error(`Path traversal detected: ${fullPath}`);
64844
- }
64845
- let realBase = normalizedClaudeDir;
64846
- try {
64847
- realBase = realpathSync3(normalizedClaudeDir);
64848
- } catch {}
64849
- try {
64850
- const realParent = realpathSync3(dirname19(fullPath));
64851
- if (!isWithinBase(realParent, realBase)) {
64852
- throw new Error(`Path escapes base via symlink parent: ${fullPath}`);
64853
- }
64854
- } catch (error) {
64855
- throw new Error(`Failed to validate deletion parent for ${fullPath}: ${String(error)}`);
64856
- }
64857
- try {
64858
- const stat13 = lstatSync3(fullPath);
64859
- if (!stat13.isSymbolicLink()) {
64860
- const realTarget = realpathSync3(fullPath);
64861
- if (!isWithinBase(realTarget, realBase)) {
64862
- throw new Error(`Path escapes base via symlink target: ${fullPath}`);
64863
- }
64864
- }
64865
- } catch (error) {
64866
- throw new Error(`Failed to validate deletion target ${fullPath}: ${String(error)}`);
64867
- }
64868
- }
64869
- function deletePath(fullPath, claudeDir2) {
64870
- validateExistingDeletionTarget(fullPath, claudeDir2);
64871
- try {
64872
- const stat13 = lstatSync3(fullPath);
64873
- if (stat13.isDirectory()) {
64874
- rmSync2(fullPath, { recursive: true, force: true });
64875
- } else {
64876
- unlinkSync3(fullPath);
64877
- cleanupEmptyDirectories(fullPath, claudeDir2);
64878
- }
64879
- } catch (error) {
64880
- throw new Error(`Failed to delete ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
64881
- }
64882
- }
64883
- async function updateMetadataAfterDeletion(claudeDir2, deletedPaths) {
64884
- const metadataPath = join75(claudeDir2, "metadata.json");
64885
- if (!await import_fs_extra9.pathExists(metadataPath)) {
64886
- return;
64887
- }
64888
- let content;
64889
- try {
64890
- content = await import_fs_extra9.readFile(metadataPath, "utf-8");
64891
- } catch {
64892
- logger.debug("Failed to read metadata.json for cleanup");
64893
- return;
64894
- }
64895
- let metadata;
64896
- try {
64897
- metadata = JSON.parse(content);
64898
- } catch {
64899
- logger.debug("Failed to parse metadata.json for cleanup");
64900
- return;
64901
- }
64902
- const deletedSet = new Set(deletedPaths);
64903
- const isDeletedOrInDeletedDir = (path13) => {
64904
- if (deletedSet.has(path13))
64905
- return true;
64906
- for (const deleted of deletedPaths) {
64907
- if (path13.startsWith(`${deleted}/`))
64908
- return true;
64909
- }
64910
- return false;
64911
- };
64912
- if (metadata.kits) {
64913
- for (const kitName of Object.keys(metadata.kits)) {
64914
- const kit = metadata.kits[kitName];
64915
- if (kit?.files) {
64916
- kit.files = kit.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
64917
- }
64918
- }
64919
- }
64920
- if (metadata.files) {
64921
- metadata.files = metadata.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
64922
- }
64923
- try {
64924
- await import_fs_extra9.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
64925
- logger.debug(`Updated metadata.json, removed ${deletedPaths.length} entries`);
64926
- } catch {
64927
- logger.debug("Failed to write updated metadata.json");
64928
- }
64929
- }
64930
- function categorizeDeletions(deletions) {
64931
- const immediate = [];
64932
- const deferred = [];
64933
- for (const path13 of deletions) {
64934
- if (path13.startsWith("skills/") || path13.startsWith("skills\\")) {
64935
- deferred.push(path13);
64936
- } else {
64937
- immediate.push(path13);
64938
- }
64939
- }
64940
- return { immediate, deferred };
64941
- }
64942
- async function handleDeletions(sourceMetadata, claudeDir2) {
64943
- const deletionPatterns = sourceMetadata.deletions || [];
64944
- if (deletionPatterns.length === 0) {
64945
- return { deletedPaths: [], preservedPaths: [], errors: [] };
64946
- }
64947
- const deletions = expandGlobPatterns(deletionPatterns, claudeDir2);
64948
- const userMetadata = await readManifest(claudeDir2);
64949
- const result = { deletedPaths: [], preservedPaths: [], errors: [] };
64950
- for (const path13 of deletions) {
64951
- const normalizedRelativePath = normalizeRelativePath(path13);
64952
- const fullPath = join75(claudeDir2, normalizedRelativePath);
64953
- const normalizedResolvedPath = resolve18(fullPath);
64954
- const normalizedClaudeDir = resolve18(claudeDir2);
64955
- if (!isWithinBase(normalizedResolvedPath, normalizedClaudeDir)) {
64956
- logger.warning(`Skipping invalid path: ${normalizedRelativePath}`);
64957
- result.errors.push(normalizedRelativePath);
64958
- continue;
64959
- }
64960
- if (!shouldDeletePath(normalizedRelativePath, userMetadata)) {
64961
- result.preservedPaths.push(normalizedRelativePath);
64962
- logger.verbose(`Preserved user file: ${normalizedRelativePath}`);
64963
- continue;
64964
- }
64965
- if (existsSync48(fullPath)) {
64966
- try {
64967
- deletePath(fullPath, claudeDir2);
64968
- result.deletedPaths.push(normalizedRelativePath);
64969
- logger.verbose(`Deleted: ${normalizedRelativePath}`);
64970
- } catch (error) {
64971
- result.errors.push(normalizedRelativePath);
64972
- logger.debug(`Failed to delete ${normalizedRelativePath}: ${error}`);
64973
- }
64974
- }
64975
- }
64976
- if (result.deletedPaths.length > 0) {
64977
- await updateMetadataAfterDeletion(claudeDir2, result.deletedPaths);
64978
- }
64979
- return result;
64980
- }
64981
- var import_fs_extra9, import_picomatch2, MAX_CLEANUP_ITERATIONS = 50;
64982
- var init_deletion_handler = __esm(() => {
64983
- init_manifest_reader();
64984
- init_logger();
64985
- init_path_resolver();
64986
- import_fs_extra9 = __toESM(require_lib3(), 1);
64987
- import_picomatch2 = __toESM(require_picomatch2(), 1);
64988
- });
64989
-
64990
64532
  // src/domains/ui/ownership-display.ts
64991
64533
  var exports_ownership_display = {};
64992
64534
  __export(exports_ownership_display, {
@@ -65123,481 +64665,6 @@ var init_ownership_display = __esm(() => {
65123
64665
  import_picocolors22 = __toESM(require_picocolors(), 1);
65124
64666
  });
65125
64667
 
65126
- // src/shared/claude-exec-options.ts
65127
- function buildExecOptions(timeout2) {
65128
- const env2 = { ...process.env };
65129
- for (const key of Object.keys(env2)) {
65130
- if (key.startsWith("CLAUDE") && key !== "CLAUDE_CONFIG_DIR") {
65131
- delete env2[key];
65132
- }
65133
- }
65134
- return {
65135
- timeout: timeout2,
65136
- env: env2,
65137
- shell: process.platform === "win32"
65138
- };
65139
- }
65140
-
65141
- // src/services/cc-version-checker.ts
65142
- var exports_cc_version_checker = {};
65143
- __export(exports_cc_version_checker, {
65144
- requireCCPluginSupport: () => requireCCPluginSupport,
65145
- parseVersion: () => parseVersion,
65146
- isCCPluginSupportError: () => isCCPluginSupportError,
65147
- getCCVersion: () => getCCVersion,
65148
- compareVersions: () => compareVersions9,
65149
- MIN_PLUGIN_VERSION: () => MIN_PLUGIN_VERSION,
65150
- CCPluginSupportError: () => CCPluginSupportError
65151
- });
65152
- import { execFile as execFile9 } from "node:child_process";
65153
- import { promisify as promisify14 } from "node:util";
65154
- function parseVersion(version) {
65155
- const match2 = version.match(/^(\d+)\.(\d+)\.(\d+)/);
65156
- if (!match2)
65157
- return null;
65158
- return [Number(match2[1]), Number(match2[2]), Number(match2[3])];
65159
- }
65160
- function compareVersions9(a3, b3) {
65161
- const parsedA = parseVersion(a3);
65162
- const parsedB = parseVersion(b3);
65163
- if (!parsedA || !parsedB)
65164
- return -1;
65165
- for (let i = 0;i < 3; i++) {
65166
- if (parsedA[i] !== parsedB[i])
65167
- return parsedA[i] - parsedB[i];
65168
- }
65169
- return 0;
65170
- }
65171
- async function getCCVersionResult() {
65172
- try {
65173
- const { stdout: stdout2, stderr } = await execFileAsync6("claude", ["--version"], buildExecOptions(5000));
65174
- const output2 = stdout2.trim();
65175
- const match2 = output2.match(/(\d+\.\d+\.\d+)/);
65176
- if (!match2) {
65177
- return {
65178
- version: null,
65179
- error: new CCPluginSupportError("cc_version_unparseable", "Failed to parse Claude Code version output", output2 || stderr?.trim() || "empty output")
65180
- };
65181
- }
65182
- return { version: match2[1] };
65183
- } catch (error) {
65184
- const err = error;
65185
- if (err.code === "ENOENT") {
65186
- return {
65187
- version: null,
65188
- error: new CCPluginSupportError("cc_not_found", "Claude Code CLI not found on PATH")
65189
- };
65190
- }
65191
- return {
65192
- version: null,
65193
- error: new CCPluginSupportError("cc_exec_failed", "Failed to run 'claude --version'", (err.stderr ?? err.message ?? "Unknown error").trim())
65194
- };
65195
- }
65196
- }
65197
- async function getCCVersion() {
65198
- const result = await getCCVersionResult();
65199
- return result.version;
65200
- }
65201
- async function requireCCPluginSupport() {
65202
- const result = await getCCVersionResult();
65203
- const version = result.version;
65204
- if (!version) {
65205
- throw result.error ?? new CCPluginSupportError("cc_exec_failed", "Failed to determine Claude Code version");
65206
- }
65207
- if (compareVersions9(version, MIN_PLUGIN_VERSION) < 0) {
65208
- throw new CCPluginSupportError("cc_version_too_old", `Claude Code ${version} does not support plugins (requires >= ${MIN_PLUGIN_VERSION})`);
65209
- }
65210
- logger.debug(`CC version ${version} supports plugins (>= ${MIN_PLUGIN_VERSION})`);
65211
- }
65212
- function isCCPluginSupportError(error) {
65213
- return error instanceof CCPluginSupportError;
65214
- }
65215
- var execFileAsync6, MIN_PLUGIN_VERSION = "1.0.33", CCPluginSupportError;
65216
- var init_cc_version_checker = __esm(() => {
65217
- init_logger();
65218
- execFileAsync6 = promisify14(execFile9);
65219
- CCPluginSupportError = class CCPluginSupportError extends Error {
65220
- code;
65221
- details;
65222
- constructor(code2, message, details) {
65223
- super(message);
65224
- this.code = code2;
65225
- this.details = details;
65226
- this.name = "CCPluginSupportError";
65227
- }
65228
- };
65229
- });
65230
-
65231
- // src/services/plugin-installer.ts
65232
- var exports_plugin_installer = {};
65233
- __export(exports_plugin_installer, {
65234
- handlePluginUninstall: () => handlePluginUninstall,
65235
- handlePluginInstall: () => handlePluginInstall
65236
- });
65237
- import { execFile as execFile10 } from "node:child_process";
65238
- import { rename as rename6 } from "node:fs/promises";
65239
- import { join as join99 } from "node:path";
65240
- import { promisify as promisify15 } from "node:util";
65241
- function getMarketplacePath() {
65242
- const dataDir = PathResolver.getClaudeKitDir();
65243
- return join99(dataDir, MARKETPLACE_DIR_NAME);
65244
- }
65245
- function escapeRegex2(value) {
65246
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
65247
- }
65248
- function outputContainsToken(output2, token) {
65249
- const tokenPattern = new RegExp(`(^|\\s)${escapeRegex2(token)}(?=\\s|$)`, "i");
65250
- return output2.split(/\r?\n/).map((line) => line.trim()).some((line) => tokenPattern.test(line));
65251
- }
65252
- async function runClaudePlugin(args) {
65253
- try {
65254
- const { stdout: stdout2, stderr } = await execFileAsync7("claude", ["plugin", ...args], buildExecOptions(30000));
65255
- return { success: true, stdout: stdout2.trim(), stderr: stderr.trim() };
65256
- } catch (error) {
65257
- const err = error;
65258
- return {
65259
- success: false,
65260
- stdout: (err.stdout ?? "").trim(),
65261
- stderr: (err.stderr ?? err.message ?? "Unknown error").trim()
65262
- };
65263
- }
65264
- }
65265
- async function isClaudeAvailable() {
65266
- try {
65267
- await execFileAsync7("claude", ["--version"], buildExecOptions(5000));
65268
- return true;
65269
- } catch {
65270
- return false;
65271
- }
65272
- }
65273
- async function copyPluginToMarketplace(extractDir) {
65274
- const marketplacePath = getMarketplacePath();
65275
- const sourceMarketplaceJson = join99(extractDir, ".claude-plugin", "marketplace.json");
65276
- const sourcePluginDir = join99(extractDir, "plugins", PLUGIN_NAME);
65277
- if (!await import_fs_extra30.pathExists(sourceMarketplaceJson) || !await import_fs_extra30.pathExists(sourcePluginDir)) {
65278
- logger.debug("Kit release does not contain plugin structure — skipping plugin install");
65279
- return false;
65280
- }
65281
- await import_fs_extra30.ensureDir(join99(marketplacePath, ".claude-plugin"));
65282
- await import_fs_extra30.ensureDir(join99(marketplacePath, "plugins"));
65283
- const suffix = `${process.pid}-${Date.now()}`;
65284
- const destMarketplaceJson = join99(marketplacePath, ".claude-plugin", "marketplace.json");
65285
- const destPluginDir = join99(marketplacePath, "plugins", PLUGIN_NAME);
65286
- const tempMarketplaceJson = `${destMarketplaceJson}.tmp-${suffix}`;
65287
- const tempPluginDir = `${destPluginDir}.tmp-${suffix}`;
65288
- const backupMarketplaceJson = `${destMarketplaceJson}.bak-${suffix}`;
65289
- const backupPluginDir = `${destPluginDir}.bak-${suffix}`;
65290
- await import_fs_extra30.remove(tempMarketplaceJson).catch(() => {});
65291
- await import_fs_extra30.remove(tempPluginDir).catch(() => {});
65292
- await import_fs_extra30.remove(backupMarketplaceJson).catch(() => {});
65293
- await import_fs_extra30.remove(backupPluginDir).catch(() => {});
65294
- await import_fs_extra30.copy(sourceMarketplaceJson, tempMarketplaceJson, { overwrite: true });
65295
- await import_fs_extra30.copy(sourcePluginDir, tempPluginDir, { overwrite: true });
65296
- let backupMarketplaceCreated = false;
65297
- let backupPluginCreated = false;
65298
- let marketplaceReplaced = false;
65299
- let pluginReplaced = false;
65300
- try {
65301
- if (await import_fs_extra30.pathExists(destMarketplaceJson)) {
65302
- await rename6(destMarketplaceJson, backupMarketplaceJson);
65303
- backupMarketplaceCreated = true;
65304
- }
65305
- await rename6(tempMarketplaceJson, destMarketplaceJson);
65306
- marketplaceReplaced = true;
65307
- if (await import_fs_extra30.pathExists(destPluginDir)) {
65308
- await rename6(destPluginDir, backupPluginDir);
65309
- backupPluginCreated = true;
65310
- }
65311
- await rename6(tempPluginDir, destPluginDir);
65312
- pluginReplaced = true;
65313
- } catch (error) {
65314
- if (marketplaceReplaced) {
65315
- await import_fs_extra30.remove(destMarketplaceJson).catch(() => {});
65316
- }
65317
- if (pluginReplaced) {
65318
- await import_fs_extra30.remove(destPluginDir).catch(() => {});
65319
- }
65320
- if (backupMarketplaceCreated) {
65321
- await rename6(backupMarketplaceJson, destMarketplaceJson).catch(() => {});
65322
- }
65323
- if (backupPluginCreated) {
65324
- await rename6(backupPluginDir, destPluginDir).catch(() => {});
65325
- }
65326
- await import_fs_extra30.remove(tempMarketplaceJson).catch(() => {});
65327
- await import_fs_extra30.remove(tempPluginDir).catch(() => {});
65328
- throw error;
65329
- }
65330
- await import_fs_extra30.remove(backupMarketplaceJson).catch(() => {});
65331
- await import_fs_extra30.remove(backupPluginDir).catch(() => {});
65332
- await import_fs_extra30.remove(tempMarketplaceJson).catch(() => {});
65333
- await import_fs_extra30.remove(tempPluginDir).catch(() => {});
65334
- logger.debug("Plugin copied to marketplace");
65335
- return true;
65336
- }
65337
- async function registerMarketplace() {
65338
- const marketplacePath = getMarketplacePath();
65339
- const listResult = await runClaudePlugin(["marketplace", "list"]);
65340
- const alreadyRegistered = listResult.success && outputContainsToken(listResult.stdout, MARKETPLACE_NAME);
65341
- if (alreadyRegistered) {
65342
- const addResult = await runClaudePlugin(["marketplace", "add", marketplacePath]);
65343
- if (addResult.success) {
65344
- logger.debug("Marketplace re-registered successfully");
65345
- return true;
65346
- }
65347
- logger.debug("Marketplace add failed while registered; removing stale entry and retrying");
65348
- const removeResult = await runClaudePlugin(["marketplace", "remove", MARKETPLACE_NAME]);
65349
- if (!removeResult.success) {
65350
- logger.debug(`Marketplace remove failed: ${removeResult.stderr}`);
65351
- return false;
65352
- }
65353
- const retryResult = await runClaudePlugin(["marketplace", "add", marketplacePath]);
65354
- if (!retryResult.success) {
65355
- logger.warning(`Marketplace remove succeeded but retry-add failed: ${retryResult.stderr}`);
65356
- return false;
65357
- }
65358
- logger.debug("Marketplace re-registered after remove+retry");
65359
- return true;
65360
- }
65361
- const result = await runClaudePlugin(["marketplace", "add", marketplacePath]);
65362
- if (!result.success) {
65363
- logger.debug(`Marketplace registration failed: ${result.stderr}`);
65364
- return false;
65365
- }
65366
- logger.debug("Marketplace registered successfully");
65367
- return true;
65368
- }
65369
- async function installOrUpdatePlugin() {
65370
- const pluginRef = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
65371
- const listResult = await runClaudePlugin(["list"]);
65372
- const isInstalled = listResult.success && outputContainsToken(listResult.stdout, pluginRef);
65373
- if (isInstalled) {
65374
- const result2 = await runClaudePlugin(["update", pluginRef]);
65375
- if (result2.success) {
65376
- logger.debug("Plugin updated successfully");
65377
- return true;
65378
- }
65379
- logger.debug(`Plugin update failed (${result2.stderr}); re-verifying install state`);
65380
- const stillInstalled = await verifyPluginInstalled();
65381
- if (stillInstalled) {
65382
- logger.debug("Plugin update failed but plugin is still installed — treating as success");
65383
- return true;
65384
- }
65385
- logger.debug("Plugin update failed and plugin is no longer listed");
65386
- return false;
65387
- }
65388
- const result = await runClaudePlugin(["install", pluginRef]);
65389
- if (!result.success) {
65390
- logger.debug(`Plugin install failed: ${result.stderr}`);
65391
- return false;
65392
- }
65393
- logger.debug("Plugin installed successfully");
65394
- return true;
65395
- }
65396
- async function verifyPluginInstalled() {
65397
- const pluginRef = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
65398
- const result = await runClaudePlugin(["list"]);
65399
- if (!result.success)
65400
- return false;
65401
- return outputContainsToken(result.stdout, pluginRef);
65402
- }
65403
- async function handlePluginInstall(extractDir) {
65404
- if (!await isClaudeAvailable()) {
65405
- return {
65406
- installed: false,
65407
- marketplaceRegistered: false,
65408
- verified: false,
65409
- error: "Claude Code CLI not found on PATH"
65410
- };
65411
- }
65412
- logger.debug("Registering CK plugin with Claude Code...");
65413
- let copied = false;
65414
- try {
65415
- copied = await copyPluginToMarketplace(extractDir);
65416
- } catch (error) {
65417
- return {
65418
- installed: false,
65419
- marketplaceRegistered: false,
65420
- verified: false,
65421
- error: `Plugin copy failed: ${error instanceof Error ? error.message : "Unknown error"}`
65422
- };
65423
- }
65424
- if (!copied) {
65425
- return {
65426
- installed: false,
65427
- marketplaceRegistered: false,
65428
- verified: false,
65429
- error: "No plugin found in kit release"
65430
- };
65431
- }
65432
- const registered = await registerMarketplace();
65433
- if (!registered) {
65434
- return {
65435
- installed: false,
65436
- marketplaceRegistered: false,
65437
- verified: false,
65438
- error: "Marketplace registration failed"
65439
- };
65440
- }
65441
- const installOk = await installOrUpdatePlugin();
65442
- if (!installOk) {
65443
- return {
65444
- installed: false,
65445
- marketplaceRegistered: true,
65446
- verified: false,
65447
- error: "Plugin install/update failed"
65448
- };
65449
- }
65450
- const verified = await verifyPluginInstalled();
65451
- if (verified) {
65452
- logger.success("CK plugin installed — skills available as /ck:* commands");
65453
- } else {
65454
- logger.warning("Plugin installed but verification failed — skills may not be available");
65455
- }
65456
- return {
65457
- installed: true,
65458
- marketplaceRegistered: true,
65459
- verified,
65460
- error: verified ? undefined : "Post-install verification failed"
65461
- };
65462
- }
65463
- async function handlePluginUninstall() {
65464
- if (!await isClaudeAvailable()) {
65465
- logger.debug("Claude Code CLI not found — skipping plugin cleanup");
65466
- return;
65467
- }
65468
- const isInstalled = await verifyPluginInstalled();
65469
- if (isInstalled) {
65470
- const pluginRef = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
65471
- const uninstallResult = await runClaudePlugin(["uninstall", pluginRef]);
65472
- if (uninstallResult.success) {
65473
- logger.debug("CK plugin uninstalled from Claude Code");
65474
- } else {
65475
- logger.debug(`Plugin uninstall failed: ${uninstallResult.stderr}`);
65476
- }
65477
- }
65478
- const marketplaceRemoveResult = await runClaudePlugin([
65479
- "marketplace",
65480
- "remove",
65481
- MARKETPLACE_NAME
65482
- ]);
65483
- if (!marketplaceRemoveResult.success) {
65484
- logger.debug(`Marketplace remove failed: ${marketplaceRemoveResult.stderr}`);
65485
- }
65486
- const marketplacePath = getMarketplacePath();
65487
- if (await import_fs_extra30.pathExists(marketplacePath)) {
65488
- try {
65489
- await import_fs_extra30.remove(marketplacePath);
65490
- logger.debug("Marketplace directory cleaned up");
65491
- } catch (error) {
65492
- logger.warning(`Failed to clean marketplace directory: ${error instanceof Error ? error.message : String(error)}`);
65493
- }
65494
- }
65495
- }
65496
- var import_fs_extra30, execFileAsync7, MARKETPLACE_DIR_NAME = "marketplace", PLUGIN_NAME = "ck", MARKETPLACE_NAME = "claudekit";
65497
- var init_plugin_installer = __esm(() => {
65498
- init_logger();
65499
- init_path_resolver();
65500
- import_fs_extra30 = __toESM(require_lib3(), 1);
65501
- execFileAsync7 = promisify15(execFile10);
65502
- });
65503
-
65504
- // src/services/skill-migration-merger.ts
65505
- var exports_skill_migration_merger = {};
65506
- __export(exports_skill_migration_merger, {
65507
- migrateUserSkills: () => migrateUserSkills
65508
- });
65509
- import { readFile as readFile47 } from "node:fs/promises";
65510
- import { join as join100 } from "node:path";
65511
- async function migrateUserSkills(claudeDir2, pluginVerified) {
65512
- const result = {
65513
- preserved: [],
65514
- deleted: [],
65515
- userOwned: [],
65516
- canDelete: false
65517
- };
65518
- if (!pluginVerified) {
65519
- return result;
65520
- }
65521
- const metadataPath = join100(claudeDir2, "metadata.json");
65522
- if (!await import_fs_extra31.pathExists(metadataPath)) {
65523
- return result;
65524
- }
65525
- let trackedFiles;
65526
- try {
65527
- const content = await readFile47(metadataPath, "utf-8");
65528
- const metadata = JSON.parse(content);
65529
- trackedFiles = extractTrackedSkillFiles(metadata);
65530
- } catch {
65531
- logger.debug("Could not read metadata for skill migration");
65532
- return result;
65533
- }
65534
- if (trackedFiles.length === 0) {
65535
- return result;
65536
- }
65537
- result.canDelete = true;
65538
- const preservedSet = new Set;
65539
- const deletedSet = new Set;
65540
- const userOwnedSet = new Set;
65541
- for (const file of trackedFiles) {
65542
- const skillDir = extractSkillDir(file.path);
65543
- if (!skillDir)
65544
- continue;
65545
- switch (file.ownership) {
65546
- case "user":
65547
- userOwnedSet.add(skillDir);
65548
- break;
65549
- case "ck-modified":
65550
- preservedSet.add(skillDir);
65551
- break;
65552
- case "ck":
65553
- deletedSet.add(skillDir);
65554
- break;
65555
- }
65556
- }
65557
- for (const dir of preservedSet) {
65558
- deletedSet.delete(dir);
65559
- }
65560
- result.preserved = [...preservedSet];
65561
- result.deleted = [...deletedSet];
65562
- result.userOwned = [...userOwnedSet];
65563
- for (const dir of result.preserved) {
65564
- const skillName = dir.split("/")[1];
65565
- logger.info(`Preserved customizations: /${skillName} (standalone alongside /ck:${skillName})`);
65566
- }
65567
- return result;
65568
- }
65569
- function extractTrackedSkillFiles(metadata) {
65570
- const files = [];
65571
- if (metadata.kits && typeof metadata.kits === "object") {
65572
- for (const kit of Object.values(metadata.kits)) {
65573
- if (kit.files) {
65574
- files.push(...kit.files.filter((f3) => isSkillPath(f3.path)));
65575
- }
65576
- }
65577
- }
65578
- if (Array.isArray(metadata.files)) {
65579
- files.push(...metadata.files.filter((f3) => isSkillPath(f3.path)));
65580
- }
65581
- return files;
65582
- }
65583
- function isSkillPath(path14) {
65584
- const normalized = path14.replace(/\\/g, "/");
65585
- return normalized.startsWith("skills/");
65586
- }
65587
- function extractSkillDir(path14) {
65588
- const normalized = path14.replace(/\\/g, "/");
65589
- const parts = normalized.split("/").filter(Boolean);
65590
- if (parts.length < 2 || parts[0] !== "skills") {
65591
- return null;
65592
- }
65593
- return `skills/${parts[1]}`;
65594
- }
65595
- var import_fs_extra31;
65596
- var init_skill_migration_merger = __esm(() => {
65597
- init_logger();
65598
- import_fs_extra31 = __toESM(require_lib3(), 1);
65599
- });
65600
-
65601
64668
  // src/domains/help/commands/common-options.ts
65602
64669
  var filterOptionsGroup, folderOptionsGroup;
65603
64670
  var init_common_options = __esm(() => {
@@ -66715,7 +65782,7 @@ function getPagerArgs(pagerCmd) {
66715
65782
  return [];
66716
65783
  }
66717
65784
  async function trySystemPager(content) {
66718
- return new Promise((resolve27) => {
65785
+ return new Promise((resolve26) => {
66719
65786
  const pagerCmd = process.env.PAGER || "less";
66720
65787
  const pagerArgs = getPagerArgs(pagerCmd);
66721
65788
  try {
@@ -66725,20 +65792,20 @@ async function trySystemPager(content) {
66725
65792
  });
66726
65793
  const timeout2 = setTimeout(() => {
66727
65794
  pager.kill();
66728
- resolve27(false);
65795
+ resolve26(false);
66729
65796
  }, 30000);
66730
65797
  pager.stdin.write(content);
66731
65798
  pager.stdin.end();
66732
65799
  pager.on("close", (code2) => {
66733
65800
  clearTimeout(timeout2);
66734
- resolve27(code2 === 0);
65801
+ resolve26(code2 === 0);
66735
65802
  });
66736
65803
  pager.on("error", () => {
66737
65804
  clearTimeout(timeout2);
66738
- resolve27(false);
65805
+ resolve26(false);
66739
65806
  });
66740
65807
  } catch {
66741
- resolve27(false);
65808
+ resolve26(false);
66742
65809
  }
66743
65810
  });
66744
65811
  }
@@ -66765,16 +65832,16 @@ async function basicPager(content) {
66765
65832
  break;
66766
65833
  }
66767
65834
  const remaining = lines.length - currentLine;
66768
- await new Promise((resolve27) => {
65835
+ await new Promise((resolve26) => {
66769
65836
  rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
66770
65837
  if (answer.toLowerCase() === "q") {
66771
65838
  rl.close();
66772
65839
  process.exitCode = 0;
66773
- resolve27();
65840
+ resolve26();
66774
65841
  return;
66775
65842
  }
66776
65843
  process.stdout.write("\x1B[1A\x1B[2K");
66777
- resolve27();
65844
+ resolve26();
66778
65845
  });
66779
65846
  });
66780
65847
  }
@@ -73447,7 +72514,7 @@ class ConfigVersionChecker {
73447
72514
  }
73448
72515
  // src/domains/sync/sync-engine.ts
73449
72516
  import { lstat as lstat3, readFile as readFile34, readlink, realpath as realpath3, stat as stat9 } from "node:fs/promises";
73450
- import { dirname as dirname15, isAbsolute as isAbsolute3, normalize as normalize7, relative as relative7, resolve as resolve13 } from "node:path";
72517
+ import { isAbsolute as isAbsolute3, join as join58, normalize as normalize7, relative as relative7 } from "node:path";
73451
72518
 
73452
72519
  // src/services/file-operations/ownership-checker.ts
73453
72520
  init_metadata_migration();
@@ -74808,7 +73875,7 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
74808
73875
  if (!stats.isSymbolicLink())
74809
73876
  break;
74810
73877
  const target = await readlink(current);
74811
- const resolvedTarget = isAbsolute3(target) ? target : resolve13(dirname15(current), target);
73878
+ const resolvedTarget = isAbsolute3(target) ? target : join58(current, "..", target);
74812
73879
  const normalizedTarget = normalize7(resolvedTarget);
74813
73880
  const rel = relative7(basePath, normalizedTarget);
74814
73881
  if (rel.startsWith("..") || isAbsolute3(rel)) {
@@ -74827,10 +73894,6 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
74827
73894
  throw new Error(`Symlink chain too deep (>${maxDepth}): ${path5}`);
74828
73895
  }
74829
73896
  }
74830
- function isOutsideBase(candidatePath, basePath) {
74831
- const rel = relative7(basePath, candidatePath);
74832
- return rel.startsWith("..") || isAbsolute3(rel);
74833
- }
74834
73897
  async function validateSyncPath(basePath, filePath) {
74835
73898
  if (!filePath || filePath.trim() === "") {
74836
73899
  throw new Error("Empty file path not allowed");
@@ -74845,43 +73908,36 @@ async function validateSyncPath(basePath, filePath) {
74845
73908
  if (isAbsolute3(normalized)) {
74846
73909
  throw new Error(`Absolute paths not allowed: ${filePath}`);
74847
73910
  }
74848
- const pathParts = normalized.split(/[\\/]+/).filter(Boolean);
74849
- if (pathParts.includes("..")) {
73911
+ if (normalized.startsWith("..") || normalized.includes("/../")) {
74850
73912
  throw new Error(`Path traversal not allowed: ${filePath}`);
74851
73913
  }
74852
- const lexicalBase = resolve13(basePath);
74853
- const fullPath = resolve13(basePath, normalized);
74854
- const resolvedBase = await realpath3(basePath).catch(() => lexicalBase);
74855
- if (isOutsideBase(fullPath, lexicalBase)) {
73914
+ const fullPath = join58(basePath, normalized);
73915
+ const rel = relative7(basePath, fullPath);
73916
+ if (rel.startsWith("..") || isAbsolute3(rel)) {
74856
73917
  throw new Error(`Path escapes base directory: ${filePath}`);
74857
73918
  }
74858
- await validateSymlinkChain(fullPath, resolvedBase);
73919
+ await validateSymlinkChain(fullPath, basePath);
74859
73920
  try {
73921
+ const resolvedBase = await realpath3(basePath);
74860
73922
  const resolvedFull = await realpath3(fullPath);
74861
- if (isOutsideBase(resolvedFull, resolvedBase)) {
73923
+ const resolvedRel = relative7(resolvedBase, resolvedFull);
73924
+ if (resolvedRel.startsWith("..") || isAbsolute3(resolvedRel)) {
74862
73925
  throw new Error(`Symlink escapes base directory: ${filePath}`);
74863
73926
  }
74864
73927
  } catch (error) {
74865
73928
  if (error.code === "ENOENT") {
74866
- let ancestor = dirname15(fullPath);
74867
- while (ancestor !== lexicalBase) {
74868
- try {
74869
- await lstat3(ancestor);
74870
- break;
74871
- } catch (ancestorError) {
74872
- if (ancestorError.code !== "ENOENT") {
74873
- throw ancestorError;
74874
- }
74875
- const nextAncestor = dirname15(ancestor);
74876
- if (nextAncestor === ancestor) {
74877
- break;
74878
- }
74879
- ancestor = nextAncestor;
73929
+ const parentPath = join58(fullPath, "..");
73930
+ try {
73931
+ const resolvedBase = await realpath3(basePath);
73932
+ const resolvedParent = await realpath3(parentPath);
73933
+ const resolvedRel = relative7(resolvedBase, resolvedParent);
73934
+ if (resolvedRel.startsWith("..") || isAbsolute3(resolvedRel)) {
73935
+ throw new Error(`Parent symlink escapes base directory: ${filePath}`);
73936
+ }
73937
+ } catch (parentError) {
73938
+ if (parentError.code !== "ENOENT") {
73939
+ throw parentError;
74880
73940
  }
74881
- }
74882
- const resolvedAncestor = await realpath3(ancestor).catch(() => null);
74883
- if (!resolvedAncestor || isOutsideBase(resolvedAncestor, resolvedBase)) {
74884
- throw new Error(`Parent symlink escapes base directory: ${filePath}`);
74885
73941
  }
74886
73942
  } else {
74887
73943
  throw error;
@@ -75034,24 +74090,14 @@ class SyncEngine {
75034
74090
  }
75035
74091
  static async loadFileContent(filePath) {
75036
74092
  try {
75037
- const beforeStats = await lstat3(filePath);
75038
- if (beforeStats.isSymbolicLink()) {
74093
+ const lstats = await lstat3(filePath);
74094
+ if (lstats.isSymbolicLink()) {
75039
74095
  throw new Error(`Symlink not allowed for sync: ${filePath}`);
75040
74096
  }
75041
- if (beforeStats.size > MAX_SYNC_FILE_SIZE) {
75042
- throw new Error(`File too large for sync (${Math.round(beforeStats.size / 1024 / 1024)}MB > ${MAX_SYNC_FILE_SIZE / 1024 / 1024}MB limit)`);
74097
+ if (lstats.size > MAX_SYNC_FILE_SIZE) {
74098
+ throw new Error(`File too large for sync (${Math.round(lstats.size / 1024 / 1024)}MB > ${MAX_SYNC_FILE_SIZE / 1024 / 1024}MB limit)`);
75043
74099
  }
75044
74100
  const buffer = await readFile34(filePath);
75045
- const afterStats = await lstat3(filePath);
75046
- if (afterStats.isSymbolicLink()) {
75047
- throw new Error(`File became symlink during read: ${filePath}`);
75048
- }
75049
- if (beforeStats.dev !== afterStats.dev || beforeStats.ino !== afterStats.ino) {
75050
- throw new Error(`File changed identity during read: ${filePath}`);
75051
- }
75052
- if (beforeStats.mtimeMs !== afterStats.mtimeMs || beforeStats.size !== afterStats.size) {
75053
- throw new Error(`File changed during read: ${filePath}`);
75054
- }
75055
74101
  if (buffer.includes(0)) {
75056
74102
  return { content: "", isBinary: true };
75057
74103
  }
@@ -76062,7 +75108,7 @@ init_logger();
76062
75108
  var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
76063
75109
  import { mkdir as mkdir19 } from "node:fs/promises";
76064
75110
  import os5 from "node:os";
76065
- import { join as join64 } from "node:path";
75111
+ import { join as join65 } from "node:path";
76066
75112
  var LOCK_CONFIG = {
76067
75113
  stale: 60000,
76068
75114
  retries: 0
@@ -76070,12 +75116,12 @@ var LOCK_CONFIG = {
76070
75116
  var activeLocks = new Set;
76071
75117
  var cleanupRegistered = false;
76072
75118
  function getLocksDir() {
76073
- return join64(os5.homedir(), ".claudekit", "locks");
75119
+ return join65(os5.homedir(), ".claudekit", "locks");
76074
75120
  }
76075
75121
  function cleanupLocks() {
76076
75122
  for (const name of activeLocks) {
76077
75123
  try {
76078
- const lockPath = join64(getLocksDir(), `${name}.lock`);
75124
+ const lockPath = join65(getLocksDir(), `${name}.lock`);
76079
75125
  import_proper_lockfile4.default.unlockSync(lockPath, { realpath: false });
76080
75126
  } catch {
76081
75127
  try {
@@ -76098,7 +75144,7 @@ async function ensureLocksDir() {
76098
75144
  async function withProcessLock(lockName, fn) {
76099
75145
  registerCleanupHandlers();
76100
75146
  await ensureLocksDir();
76101
- const lockPath = join64(getLocksDir(), `${lockName}.lock`);
75147
+ const lockPath = join65(getLocksDir(), `${lockName}.lock`);
76102
75148
  let release;
76103
75149
  try {
76104
75150
  release = await import_proper_lockfile4.default.lock(lockPath, { ...LOCK_CONFIG, realpath: false });
@@ -76129,7 +75175,7 @@ init_logger();
76129
75175
  init_logger();
76130
75176
  init_path_resolver();
76131
75177
  var import_fs_extra7 = __toESM(require_lib3(), 1);
76132
- import { join as join65 } from "node:path";
75178
+ import { join as join66 } from "node:path";
76133
75179
  async function handleConflicts(ctx) {
76134
75180
  if (ctx.cancelled)
76135
75181
  return ctx;
@@ -76138,7 +75184,7 @@ async function handleConflicts(ctx) {
76138
75184
  if (PathResolver.isLocalSameAsGlobal()) {
76139
75185
  return ctx;
76140
75186
  }
76141
- const localSettingsPath = join65(process.cwd(), ".claude", "settings.json");
75187
+ const localSettingsPath = join66(process.cwd(), ".claude", "settings.json");
76142
75188
  if (!await import_fs_extra7.pathExists(localSettingsPath)) {
76143
75189
  return ctx;
76144
75190
  }
@@ -76153,7 +75199,7 @@ async function handleConflicts(ctx) {
76153
75199
  return { ...ctx, cancelled: true };
76154
75200
  }
76155
75201
  if (choice === "remove") {
76156
- const localClaudeDir = join65(process.cwd(), ".claude");
75202
+ const localClaudeDir = join66(process.cwd(), ".claude");
76157
75203
  try {
76158
75204
  await import_fs_extra7.remove(localClaudeDir);
76159
75205
  logger.success("Removed local .claude/ directory");
@@ -76250,7 +75296,7 @@ init_logger();
76250
75296
  init_safe_spinner();
76251
75297
  import { mkdir as mkdir25, stat as stat12 } from "node:fs/promises";
76252
75298
  import { tmpdir as tmpdir4 } from "node:os";
76253
- import { join as join72 } from "node:path";
75299
+ import { join as join73 } from "node:path";
76254
75300
 
76255
75301
  // src/shared/temp-cleanup.ts
76256
75302
  init_logger();
@@ -76269,7 +75315,7 @@ init_logger();
76269
75315
  init_output_manager();
76270
75316
  import { createWriteStream as createWriteStream2, rmSync } from "node:fs";
76271
75317
  import { mkdir as mkdir20 } from "node:fs/promises";
76272
- import { join as join66 } from "node:path";
75318
+ import { join as join67 } from "node:path";
76273
75319
 
76274
75320
  // src/shared/progress-bar.ts
76275
75321
  init_output_manager();
@@ -76434,10 +75480,10 @@ init_types3();
76434
75480
  // src/domains/installation/utils/path-security.ts
76435
75481
  init_types3();
76436
75482
  import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
76437
- import { relative as relative8, resolve as resolve16 } from "node:path";
75483
+ import { relative as relative8, resolve as resolve15 } from "node:path";
76438
75484
  var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
76439
75485
  function isPathSafe(basePath, targetPath) {
76440
- const resolvedBase = resolve16(basePath);
75486
+ const resolvedBase = resolve15(basePath);
76441
75487
  try {
76442
75488
  const stat10 = lstatSync2(targetPath);
76443
75489
  if (stat10.isSymbolicLink()) {
@@ -76447,7 +75493,7 @@ function isPathSafe(basePath, targetPath) {
76447
75493
  }
76448
75494
  }
76449
75495
  } catch {}
76450
- const resolvedTarget = resolve16(targetPath);
75496
+ const resolvedTarget = resolve15(targetPath);
76451
75497
  const relativePath = relative8(resolvedBase, resolvedTarget);
76452
75498
  return !relativePath.startsWith("..") && !relativePath.startsWith("/") && resolvedTarget.startsWith(resolvedBase);
76453
75499
  }
@@ -76479,7 +75525,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
76479
75525
  class FileDownloader {
76480
75526
  async downloadAsset(asset, destDir) {
76481
75527
  try {
76482
- const destPath = join66(destDir, asset.name);
75528
+ const destPath = join67(destDir, asset.name);
76483
75529
  await mkdir20(destDir, { recursive: true });
76484
75530
  output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
76485
75531
  logger.verbose("Download details", {
@@ -76535,7 +75581,7 @@ class FileDownloader {
76535
75581
  }
76536
75582
  if (downloadedSize !== totalSize) {
76537
75583
  fileStream.end();
76538
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75584
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76539
75585
  try {
76540
75586
  rmSync(destPath, { force: true });
76541
75587
  } catch (cleanupError) {
@@ -76549,7 +75595,7 @@ class FileDownloader {
76549
75595
  return destPath;
76550
75596
  } catch (error) {
76551
75597
  fileStream.end();
76552
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75598
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76553
75599
  try {
76554
75600
  rmSync(destPath, { force: true });
76555
75601
  } catch (cleanupError) {
@@ -76564,7 +75610,7 @@ class FileDownloader {
76564
75610
  }
76565
75611
  async downloadFile(params) {
76566
75612
  const { url, name, size, destDir, token } = params;
76567
- const destPath = join66(destDir, name);
75613
+ const destPath = join67(destDir, name);
76568
75614
  await mkdir20(destDir, { recursive: true });
76569
75615
  output.info(`Downloading ${name}${size ? ` (${formatBytes(size)})` : ""}...`);
76570
75616
  const headers = {};
@@ -76615,7 +75661,7 @@ class FileDownloader {
76615
75661
  const expectedSize = Number(response.headers.get("content-length"));
76616
75662
  if (expectedSize > 0 && downloadedSize !== expectedSize) {
76617
75663
  fileStream.end();
76618
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75664
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76619
75665
  try {
76620
75666
  rmSync(destPath, { force: true });
76621
75667
  } catch (cleanupError) {
@@ -76633,7 +75679,7 @@ class FileDownloader {
76633
75679
  return destPath;
76634
75680
  } catch (error) {
76635
75681
  fileStream.end();
76636
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75682
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76637
75683
  try {
76638
75684
  rmSync(destPath, { force: true });
76639
75685
  } catch (cleanupError) {
@@ -76650,7 +75696,7 @@ init_logger();
76650
75696
  init_types3();
76651
75697
  import { constants as constants4 } from "node:fs";
76652
75698
  import { access as access4, readdir as readdir13 } from "node:fs/promises";
76653
- import { join as join67 } from "node:path";
75699
+ import { join as join68 } from "node:path";
76654
75700
  async function validateExtraction(extractDir) {
76655
75701
  try {
76656
75702
  const entries = await readdir13(extractDir, { encoding: "utf8" });
@@ -76662,7 +75708,7 @@ async function validateExtraction(extractDir) {
76662
75708
  const missingPaths = [];
76663
75709
  for (const path5 of criticalPaths) {
76664
75710
  try {
76665
- await access4(join67(extractDir, path5), constants4.F_OK);
75711
+ await access4(join68(extractDir, path5), constants4.F_OK);
76666
75712
  logger.debug(`Found: ${path5}`);
76667
75713
  } catch {
76668
75714
  logger.warning(`Expected path not found: ${path5}`);
@@ -76684,7 +75730,7 @@ async function validateExtraction(extractDir) {
76684
75730
  // src/domains/installation/extraction/tar-extractor.ts
76685
75731
  init_logger();
76686
75732
  import { copyFile as copyFile4, mkdir as mkdir23, readdir as readdir15, rm as rm8, stat as stat10 } from "node:fs/promises";
76687
- import { join as join70 } from "node:path";
75733
+ import { join as join71 } from "node:path";
76688
75734
 
76689
75735
  // node_modules/@isaacs/fs-minipass/dist/esm/index.js
76690
75736
  import EE from "events";
@@ -77232,10 +76278,10 @@ class Minipass extends EventEmitter3 {
77232
76278
  return this[ENCODING] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
77233
76279
  }
77234
76280
  async promise() {
77235
- return new Promise((resolve17, reject) => {
76281
+ return new Promise((resolve16, reject) => {
77236
76282
  this.on(DESTROYED, () => reject(new Error("stream destroyed")));
77237
76283
  this.on("error", (er) => reject(er));
77238
- this.on("end", () => resolve17());
76284
+ this.on("end", () => resolve16());
77239
76285
  });
77240
76286
  }
77241
76287
  [Symbol.asyncIterator]() {
@@ -77254,7 +76300,7 @@ class Minipass extends EventEmitter3 {
77254
76300
  return Promise.resolve({ done: false, value: res });
77255
76301
  if (this[EOF])
77256
76302
  return stop();
77257
- let resolve17;
76303
+ let resolve16;
77258
76304
  let reject;
77259
76305
  const onerr = (er) => {
77260
76306
  this.off("data", ondata);
@@ -77268,19 +76314,19 @@ class Minipass extends EventEmitter3 {
77268
76314
  this.off("end", onend);
77269
76315
  this.off(DESTROYED, ondestroy);
77270
76316
  this.pause();
77271
- resolve17({ value, done: !!this[EOF] });
76317
+ resolve16({ value, done: !!this[EOF] });
77272
76318
  };
77273
76319
  const onend = () => {
77274
76320
  this.off("error", onerr);
77275
76321
  this.off("data", ondata);
77276
76322
  this.off(DESTROYED, ondestroy);
77277
76323
  stop();
77278
- resolve17({ done: true, value: undefined });
76324
+ resolve16({ done: true, value: undefined });
77279
76325
  };
77280
76326
  const ondestroy = () => onerr(new Error("stream destroyed"));
77281
76327
  return new Promise((res2, rej) => {
77282
76328
  reject = rej;
77283
- resolve17 = res2;
76329
+ resolve16 = res2;
77284
76330
  this.once(DESTROYED, ondestroy);
77285
76331
  this.once("error", onerr);
77286
76332
  this.once("end", onend);
@@ -77737,7 +76783,7 @@ import path7 from "node:path";
77737
76783
 
77738
76784
  // node_modules/tar/dist/esm/list.js
77739
76785
  import fs9 from "node:fs";
77740
- import { dirname as dirname18, parse as parse3 } from "path";
76786
+ import { dirname as dirname17, parse as parse3 } from "path";
77741
76787
 
77742
76788
  // node_modules/tar/dist/esm/options.js
77743
76789
  var argmap = new Map([
@@ -78386,10 +77432,10 @@ class Minipass2 extends EventEmitter4 {
78386
77432
  return this[ENCODING2] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
78387
77433
  }
78388
77434
  async promise() {
78389
- return new Promise((resolve17, reject) => {
77435
+ return new Promise((resolve16, reject) => {
78390
77436
  this.on(DESTROYED2, () => reject(new Error("stream destroyed")));
78391
77437
  this.on("error", (er) => reject(er));
78392
- this.on("end", () => resolve17());
77438
+ this.on("end", () => resolve16());
78393
77439
  });
78394
77440
  }
78395
77441
  [Symbol.asyncIterator]() {
@@ -78408,7 +77454,7 @@ class Minipass2 extends EventEmitter4 {
78408
77454
  return Promise.resolve({ done: false, value: res });
78409
77455
  if (this[EOF2])
78410
77456
  return stop();
78411
- let resolve17;
77457
+ let resolve16;
78412
77458
  let reject;
78413
77459
  const onerr = (er) => {
78414
77460
  this.off("data", ondata);
@@ -78422,19 +77468,19 @@ class Minipass2 extends EventEmitter4 {
78422
77468
  this.off("end", onend);
78423
77469
  this.off(DESTROYED2, ondestroy);
78424
77470
  this.pause();
78425
- resolve17({ value, done: !!this[EOF2] });
77471
+ resolve16({ value, done: !!this[EOF2] });
78426
77472
  };
78427
77473
  const onend = () => {
78428
77474
  this.off("error", onerr);
78429
77475
  this.off("data", ondata);
78430
77476
  this.off(DESTROYED2, ondestroy);
78431
77477
  stop();
78432
- resolve17({ done: true, value: undefined });
77478
+ resolve16({ done: true, value: undefined });
78433
77479
  };
78434
77480
  const ondestroy = () => onerr(new Error("stream destroyed"));
78435
77481
  return new Promise((res2, rej) => {
78436
77482
  reject = rej;
78437
- resolve17 = res2;
77483
+ resolve16 = res2;
78438
77484
  this.once(DESTROYED2, ondestroy);
78439
77485
  this.once("error", onerr);
78440
77486
  this.once("end", onend);
@@ -79862,10 +78908,10 @@ class Minipass3 extends EventEmitter5 {
79862
78908
  return this[ENCODING3] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
79863
78909
  }
79864
78910
  async promise() {
79865
- return new Promise((resolve17, reject) => {
78911
+ return new Promise((resolve16, reject) => {
79866
78912
  this.on(DESTROYED3, () => reject(new Error("stream destroyed")));
79867
78913
  this.on("error", (er) => reject(er));
79868
- this.on("end", () => resolve17());
78914
+ this.on("end", () => resolve16());
79869
78915
  });
79870
78916
  }
79871
78917
  [Symbol.asyncIterator]() {
@@ -79884,7 +78930,7 @@ class Minipass3 extends EventEmitter5 {
79884
78930
  return Promise.resolve({ done: false, value: res });
79885
78931
  if (this[EOF3])
79886
78932
  return stop();
79887
- let resolve17;
78933
+ let resolve16;
79888
78934
  let reject;
79889
78935
  const onerr = (er) => {
79890
78936
  this.off("data", ondata);
@@ -79898,19 +78944,19 @@ class Minipass3 extends EventEmitter5 {
79898
78944
  this.off("end", onend);
79899
78945
  this.off(DESTROYED3, ondestroy);
79900
78946
  this.pause();
79901
- resolve17({ value, done: !!this[EOF3] });
78947
+ resolve16({ value, done: !!this[EOF3] });
79902
78948
  };
79903
78949
  const onend = () => {
79904
78950
  this.off("error", onerr);
79905
78951
  this.off("data", ondata);
79906
78952
  this.off(DESTROYED3, ondestroy);
79907
78953
  stop();
79908
- resolve17({ done: true, value: undefined });
78954
+ resolve16({ done: true, value: undefined });
79909
78955
  };
79910
78956
  const ondestroy = () => onerr(new Error("stream destroyed"));
79911
78957
  return new Promise((res2, rej) => {
79912
78958
  reject = rej;
79913
- resolve17 = res2;
78959
+ resolve16 = res2;
79914
78960
  this.once(DESTROYED3, ondestroy);
79915
78961
  this.once("error", onerr);
79916
78962
  this.once("end", onend);
@@ -80637,7 +79683,7 @@ var filesFilter = (opt, files) => {
80637
79683
  if (m2 !== undefined) {
80638
79684
  ret = m2;
80639
79685
  } else {
80640
- ret = mapHas(dirname18(file), root);
79686
+ ret = mapHas(dirname17(file), root);
80641
79687
  }
80642
79688
  }
80643
79689
  map.set(file, ret);
@@ -80681,9 +79727,9 @@ var listFile = (opt, _files) => {
80681
79727
  const parse4 = new Parser(opt);
80682
79728
  const readSize = opt.maxReadSize || 16 * 1024 * 1024;
80683
79729
  const file = opt.file;
80684
- const p = new Promise((resolve17, reject) => {
79730
+ const p = new Promise((resolve16, reject) => {
80685
79731
  parse4.on("error", reject);
80686
- parse4.on("end", resolve17);
79732
+ parse4.on("end", resolve16);
80687
79733
  fs9.stat(file, (er, stat10) => {
80688
79734
  if (er) {
80689
79735
  reject(er);
@@ -82446,7 +81492,7 @@ var mkdirSync = (dir, opt) => {
82446
81492
  };
82447
81493
 
82448
81494
  // node_modules/tar/dist/esm/path-reservations.js
82449
- import { join as join68 } from "node:path";
81495
+ import { join as join69 } from "node:path";
82450
81496
 
82451
81497
  // node_modules/tar/dist/esm/normalize-unicode.js
82452
81498
  var normalizeCache = Object.create(null);
@@ -82479,7 +81525,7 @@ var getDirs = (path10) => {
82479
81525
  const dirs = path10.split("/").slice(0, -1).reduce((set, path11) => {
82480
81526
  const s = set[set.length - 1];
82481
81527
  if (s !== undefined) {
82482
- path11 = join68(s, path11);
81528
+ path11 = join69(s, path11);
82483
81529
  }
82484
81530
  set.push(path11 || "/");
82485
81531
  return set;
@@ -82493,7 +81539,7 @@ class PathReservations {
82493
81539
  #running = new Set;
82494
81540
  reserve(paths, fn) {
82495
81541
  paths = isWindows4 ? ["win32 parallelization disabled"] : paths.map((p) => {
82496
- return stripTrailingSlashes(join68(normalizeUnicode(p))).toLowerCase();
81542
+ return stripTrailingSlashes(join69(normalizeUnicode(p))).toLowerCase();
82497
81543
  });
82498
81544
  const dirs = new Set(paths.map((path10) => getDirs(path10)).reduce((a3, b3) => a3.concat(b3)));
82499
81545
  this.#reservations.set(fn, { dirs, paths });
@@ -83263,9 +82309,9 @@ var extractFile = (opt, _3) => {
83263
82309
  const u = new Unpack(opt);
83264
82310
  const readSize = opt.maxReadSize || 16 * 1024 * 1024;
83265
82311
  const file = opt.file;
83266
- const p = new Promise((resolve17, reject) => {
82312
+ const p = new Promise((resolve16, reject) => {
83267
82313
  u.on("error", reject);
83268
- u.on("close", resolve17);
82314
+ u.on("close", resolve16);
83269
82315
  fs16.stat(file, (er, stat10) => {
83270
82316
  if (er) {
83271
82317
  reject(er);
@@ -83398,7 +82444,7 @@ var replaceAsync = (opt, files) => {
83398
82444
  };
83399
82445
  fs17.read(fd, headBuf, 0, 512, position, onread);
83400
82446
  };
83401
- const promise = new Promise((resolve17, reject) => {
82447
+ const promise = new Promise((resolve16, reject) => {
83402
82448
  p.on("error", reject);
83403
82449
  let flag = "r+";
83404
82450
  const onopen = (er, fd) => {
@@ -83423,7 +82469,7 @@ var replaceAsync = (opt, files) => {
83423
82469
  });
83424
82470
  p.pipe(stream);
83425
82471
  stream.on("error", reject);
83426
- stream.on("close", resolve17);
82472
+ stream.on("close", resolve16);
83427
82473
  addFilesAsync2(p, files);
83428
82474
  });
83429
82475
  });
@@ -83553,7 +82599,7 @@ function decodeFilePath(path12) {
83553
82599
  init_logger();
83554
82600
  init_types3();
83555
82601
  import { copyFile as copyFile3, lstat as lstat4, mkdir as mkdir22, readdir as readdir14 } from "node:fs/promises";
83556
- import { join as join69, relative as relative9 } from "node:path";
82602
+ import { join as join70, relative as relative9 } from "node:path";
83557
82603
  async function withRetry(fn, retries = 3) {
83558
82604
  for (let i = 0;i < retries; i++) {
83559
82605
  try {
@@ -83575,8 +82621,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
83575
82621
  await mkdir22(destDir, { recursive: true });
83576
82622
  const entries = await readdir14(sourceDir, { encoding: "utf8" });
83577
82623
  for (const entry of entries) {
83578
- const sourcePath = join69(sourceDir, entry);
83579
- const destPath = join69(destDir, entry);
82624
+ const sourcePath = join70(sourceDir, entry);
82625
+ const destPath = join70(destDir, entry);
83580
82626
  const relativePath = relative9(sourceDir, sourcePath);
83581
82627
  if (!isPathSafe(destDir, destPath)) {
83582
82628
  logger.warning(`Skipping unsafe path: ${relativePath}`);
@@ -83603,8 +82649,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
83603
82649
  await mkdir22(destDir, { recursive: true });
83604
82650
  const entries = await readdir14(sourceDir, { encoding: "utf8" });
83605
82651
  for (const entry of entries) {
83606
- const sourcePath = join69(sourceDir, entry);
83607
- const destPath = join69(destDir, entry);
82652
+ const sourcePath = join70(sourceDir, entry);
82653
+ const destPath = join70(destDir, entry);
83608
82654
  const relativePath = relative9(sourceDir, sourcePath);
83609
82655
  if (!isPathSafe(destDir, destPath)) {
83610
82656
  logger.warning(`Skipping unsafe path: ${relativePath}`);
@@ -83652,7 +82698,7 @@ class TarExtractor {
83652
82698
  logger.debug(`Root entries: ${entries.join(", ")}`);
83653
82699
  if (entries.length === 1) {
83654
82700
  const rootEntry = entries[0];
83655
- const rootPath = join70(tempExtractDir, rootEntry);
82701
+ const rootPath = join71(tempExtractDir, rootEntry);
83656
82702
  const rootStat = await stat10(rootPath);
83657
82703
  if (rootStat.isDirectory()) {
83658
82704
  const rootContents = await readdir15(rootPath, { encoding: "utf8" });
@@ -83668,7 +82714,7 @@ class TarExtractor {
83668
82714
  }
83669
82715
  } else {
83670
82716
  await mkdir23(destDir, { recursive: true });
83671
- await copyFile4(rootPath, join70(destDir, rootEntry));
82717
+ await copyFile4(rootPath, join71(destDir, rootEntry));
83672
82718
  }
83673
82719
  } else {
83674
82720
  logger.debug("Multiple root entries - moving all");
@@ -83691,26 +82737,26 @@ init_logger();
83691
82737
  var import_extract_zip = __toESM(require_extract_zip(), 1);
83692
82738
  import { execFile as execFile8 } from "node:child_process";
83693
82739
  import { copyFile as copyFile5, mkdir as mkdir24, readdir as readdir16, rm as rm9, stat as stat11 } from "node:fs/promises";
83694
- import { join as join71 } from "node:path";
82740
+ import { join as join72 } from "node:path";
83695
82741
  class ZipExtractor {
83696
82742
  async tryNativeUnzip(archivePath, destDir) {
83697
82743
  if (!isMacOS()) {
83698
82744
  return false;
83699
82745
  }
83700
- return new Promise((resolve17) => {
82746
+ return new Promise((resolve16) => {
83701
82747
  mkdir24(destDir, { recursive: true }).then(() => {
83702
82748
  execFile8("unzip", ["-o", "-q", archivePath, "-d", destDir], (error, _stdout, stderr) => {
83703
82749
  if (error) {
83704
82750
  logger.debug(`Native unzip failed: ${stderr || error.message}`);
83705
- resolve17(false);
82751
+ resolve16(false);
83706
82752
  return;
83707
82753
  }
83708
82754
  logger.debug("Native unzip succeeded");
83709
- resolve17(true);
82755
+ resolve16(true);
83710
82756
  });
83711
82757
  }).catch((err) => {
83712
82758
  logger.debug(`Failed to create directory for native unzip: ${err.message}`);
83713
- resolve17(false);
82759
+ resolve16(false);
83714
82760
  });
83715
82761
  });
83716
82762
  }
@@ -83739,7 +82785,7 @@ class ZipExtractor {
83739
82785
  logger.debug(`Root entries: ${entries.join(", ")}`);
83740
82786
  if (entries.length === 1) {
83741
82787
  const rootEntry = entries[0];
83742
- const rootPath = join71(tempExtractDir, rootEntry);
82788
+ const rootPath = join72(tempExtractDir, rootEntry);
83743
82789
  const rootStat = await stat11(rootPath);
83744
82790
  if (rootStat.isDirectory()) {
83745
82791
  const rootContents = await readdir16(rootPath, { encoding: "utf8" });
@@ -83755,7 +82801,7 @@ class ZipExtractor {
83755
82801
  }
83756
82802
  } else {
83757
82803
  await mkdir24(destDir, { recursive: true });
83758
- await copyFile5(rootPath, join71(destDir, rootEntry));
82804
+ await copyFile5(rootPath, join72(destDir, rootEntry));
83759
82805
  }
83760
82806
  } else {
83761
82807
  logger.debug("Multiple root entries - moving all");
@@ -83854,7 +82900,7 @@ class DownloadManager {
83854
82900
  async createTempDir() {
83855
82901
  const timestamp = Date.now();
83856
82902
  const counter = DownloadManager.tempDirCounter++;
83857
- const primaryTempDir = join72(tmpdir4(), `claudekit-${timestamp}-${counter}`);
82903
+ const primaryTempDir = join73(tmpdir4(), `claudekit-${timestamp}-${counter}`);
83858
82904
  try {
83859
82905
  await mkdir25(primaryTempDir, { recursive: true });
83860
82906
  logger.debug(`Created temp directory: ${primaryTempDir}`);
@@ -83871,7 +82917,7 @@ Solutions:
83871
82917
  2. Set HOME environment variable
83872
82918
  3. Try running from a different directory`);
83873
82919
  }
83874
- const fallbackTempDir = join72(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
82920
+ const fallbackTempDir = join73(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
83875
82921
  try {
83876
82922
  await mkdir25(fallbackTempDir, { recursive: true });
83877
82923
  logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
@@ -84220,8 +83266,349 @@ async function handleDownload(ctx) {
84220
83266
  };
84221
83267
  }
84222
83268
  // src/commands/init/phases/merge-handler.ts
84223
- init_deletion_handler();
84224
- import { join as join88 } from "node:path";
83269
+ import { join as join89 } from "node:path";
83270
+
83271
+ // src/domains/installation/deletion-handler.ts
83272
+ import { existsSync as existsSync48, lstatSync as lstatSync3, readdirSync as readdirSync3, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
83273
+ import { dirname as dirname18, join as join76, relative as relative10, resolve as resolve17, sep as sep3 } from "node:path";
83274
+
83275
+ // src/services/file-operations/manifest/manifest-reader.ts
83276
+ init_metadata_migration();
83277
+ init_logger();
83278
+ init_types3();
83279
+ var import_fs_extra8 = __toESM(require_lib3(), 1);
83280
+ import { join as join75 } from "node:path";
83281
+ async function readManifest(claudeDir2) {
83282
+ const metadataPath = join75(claudeDir2, "metadata.json");
83283
+ if (!await import_fs_extra8.pathExists(metadataPath)) {
83284
+ return null;
83285
+ }
83286
+ try {
83287
+ const content = await import_fs_extra8.readFile(metadataPath, "utf-8");
83288
+ const parsed = JSON.parse(content);
83289
+ return MetadataSchema.parse(parsed);
83290
+ } catch (error) {
83291
+ logger.debug(`Failed to read manifest: ${error}`);
83292
+ return null;
83293
+ }
83294
+ }
83295
+ async function readKitManifest(claudeDir2, kit) {
83296
+ const metadata = await readManifest(claudeDir2);
83297
+ if (!metadata)
83298
+ return null;
83299
+ return getKitMetadata(metadata, kit);
83300
+ }
83301
+ async function findFileInInstalledKits(claudeDir2, relativePath, excludeKit) {
83302
+ const metadata = await readManifest(claudeDir2);
83303
+ if (!metadata?.kits) {
83304
+ return {
83305
+ exists: false,
83306
+ ownerKit: null,
83307
+ checksum: null,
83308
+ version: null,
83309
+ sourceTimestamp: null,
83310
+ installedAt: null
83311
+ };
83312
+ }
83313
+ for (const [kitName, kitMeta] of Object.entries(metadata.kits)) {
83314
+ const kit = kitName;
83315
+ if (kit === excludeKit)
83316
+ continue;
83317
+ if (!kitMeta.files)
83318
+ continue;
83319
+ const file = kitMeta.files.find((f3) => f3.path === relativePath);
83320
+ if (file) {
83321
+ return {
83322
+ exists: true,
83323
+ ownerKit: kit,
83324
+ checksum: file.checksum,
83325
+ version: kitMeta.version,
83326
+ sourceTimestamp: file.sourceTimestamp ?? null,
83327
+ installedAt: file.installedAt ?? null
83328
+ };
83329
+ }
83330
+ }
83331
+ return {
83332
+ exists: false,
83333
+ ownerKit: null,
83334
+ checksum: null,
83335
+ version: null,
83336
+ sourceTimestamp: null,
83337
+ installedAt: null
83338
+ };
83339
+ }
83340
+ async function getUninstallManifest(claudeDir2, kit) {
83341
+ const detection = await detectMetadataFormat(claudeDir2);
83342
+ if (detection.format === "multi-kit" && detection.metadata?.kits) {
83343
+ const installedKits = Object.keys(detection.metadata.kits);
83344
+ if (kit) {
83345
+ const kitMeta = detection.metadata.kits[kit];
83346
+ if (!kitMeta?.files) {
83347
+ return {
83348
+ filesToRemove: [],
83349
+ filesToPreserve: USER_CONFIG_PATTERNS,
83350
+ hasManifest: true,
83351
+ isMultiKit: true,
83352
+ remainingKits: installedKits.filter((k2) => k2 !== kit)
83353
+ };
83354
+ }
83355
+ const kitFiles = kitMeta.files.map((f3) => f3.path);
83356
+ const sharedFiles = new Set;
83357
+ for (const otherKit of installedKits) {
83358
+ if (otherKit !== kit) {
83359
+ const otherMeta = detection.metadata.kits[otherKit];
83360
+ if (otherMeta?.files) {
83361
+ for (const f3 of otherMeta.files) {
83362
+ sharedFiles.add(f3.path);
83363
+ }
83364
+ }
83365
+ }
83366
+ }
83367
+ const filesToRemove = kitFiles.filter((f3) => !sharedFiles.has(f3));
83368
+ const filesToPreserve = [
83369
+ ...USER_CONFIG_PATTERNS,
83370
+ ...kitFiles.filter((f3) => sharedFiles.has(f3))
83371
+ ];
83372
+ return {
83373
+ filesToRemove,
83374
+ filesToPreserve,
83375
+ hasManifest: true,
83376
+ isMultiKit: true,
83377
+ remainingKits: installedKits.filter((k2) => k2 !== kit)
83378
+ };
83379
+ }
83380
+ const allFiles = getAllTrackedFiles(detection.metadata);
83381
+ return {
83382
+ filesToRemove: allFiles.map((f3) => f3.path),
83383
+ filesToPreserve: USER_CONFIG_PATTERNS,
83384
+ hasManifest: true,
83385
+ isMultiKit: true,
83386
+ remainingKits: []
83387
+ };
83388
+ }
83389
+ if (detection.format === "legacy" && detection.metadata) {
83390
+ const legacyFiles2 = detection.metadata.files?.map((f3) => f3.path) || [];
83391
+ const installedFiles = detection.metadata.installedFiles || [];
83392
+ const hasFiles = legacyFiles2.length > 0 || installedFiles.length > 0;
83393
+ if (!hasFiles) {
83394
+ const legacyDirs2 = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
83395
+ const legacyFileList = ["metadata.json"];
83396
+ return {
83397
+ filesToRemove: [...legacyDirs2, ...legacyFileList],
83398
+ filesToPreserve: USER_CONFIG_PATTERNS,
83399
+ hasManifest: false,
83400
+ isMultiKit: false,
83401
+ remainingKits: []
83402
+ };
83403
+ }
83404
+ return {
83405
+ filesToRemove: legacyFiles2.length > 0 ? legacyFiles2 : installedFiles,
83406
+ filesToPreserve: detection.metadata.userConfigFiles || USER_CONFIG_PATTERNS,
83407
+ hasManifest: true,
83408
+ isMultiKit: false,
83409
+ remainingKits: []
83410
+ };
83411
+ }
83412
+ const legacyDirs = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
83413
+ const legacyFiles = ["metadata.json"];
83414
+ return {
83415
+ filesToRemove: [...legacyDirs, ...legacyFiles],
83416
+ filesToPreserve: USER_CONFIG_PATTERNS,
83417
+ hasManifest: false,
83418
+ isMultiKit: false,
83419
+ remainingKits: []
83420
+ };
83421
+ }
83422
+
83423
+ // src/domains/installation/deletion-handler.ts
83424
+ init_logger();
83425
+ init_path_resolver();
83426
+ var import_fs_extra9 = __toESM(require_lib3(), 1);
83427
+ var import_picomatch2 = __toESM(require_picomatch2(), 1);
83428
+ function findFileInMetadata(metadata, path13) {
83429
+ if (!metadata)
83430
+ return null;
83431
+ if (metadata.kits) {
83432
+ for (const kitMeta of Object.values(metadata.kits)) {
83433
+ if (kitMeta?.files) {
83434
+ const found = kitMeta.files.find((f3) => f3.path === path13);
83435
+ if (found)
83436
+ return found;
83437
+ }
83438
+ }
83439
+ }
83440
+ if (metadata.files) {
83441
+ const found = metadata.files.find((f3) => f3.path === path13);
83442
+ if (found)
83443
+ return found;
83444
+ }
83445
+ return null;
83446
+ }
83447
+ function shouldDeletePath(path13, metadata) {
83448
+ const tracked = findFileInMetadata(metadata, path13);
83449
+ if (!tracked)
83450
+ return true;
83451
+ return tracked.ownership !== "user";
83452
+ }
83453
+ function collectFilesRecursively(dir, baseDir) {
83454
+ const results = [];
83455
+ if (!existsSync48(dir))
83456
+ return results;
83457
+ try {
83458
+ const entries = readdirSync3(dir, { withFileTypes: true });
83459
+ for (const entry of entries) {
83460
+ const fullPath = join76(dir, entry.name);
83461
+ const relativePath = relative10(baseDir, fullPath);
83462
+ if (entry.isDirectory()) {
83463
+ results.push(...collectFilesRecursively(fullPath, baseDir));
83464
+ } else {
83465
+ results.push(relativePath);
83466
+ }
83467
+ }
83468
+ } catch {}
83469
+ return results;
83470
+ }
83471
+ function expandGlobPatterns(patterns, claudeDir2) {
83472
+ const expanded = [];
83473
+ const allFiles = collectFilesRecursively(claudeDir2, claudeDir2);
83474
+ for (const pattern of patterns) {
83475
+ if (PathResolver.isGlobPattern(pattern)) {
83476
+ const matcher = import_picomatch2.default(pattern);
83477
+ const matches = allFiles.filter((file) => matcher(file));
83478
+ expanded.push(...matches);
83479
+ if (matches.length > 0) {
83480
+ logger.debug(`Pattern "${pattern}" matched ${matches.length} files`);
83481
+ }
83482
+ } else {
83483
+ expanded.push(pattern);
83484
+ }
83485
+ }
83486
+ return [...new Set(expanded)];
83487
+ }
83488
+ var MAX_CLEANUP_ITERATIONS = 50;
83489
+ function cleanupEmptyDirectories(filePath, claudeDir2) {
83490
+ const normalizedClaudeDir = resolve17(claudeDir2);
83491
+ let currentDir = resolve17(dirname18(filePath));
83492
+ let iterations = 0;
83493
+ while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
83494
+ iterations++;
83495
+ try {
83496
+ const entries = readdirSync3(currentDir);
83497
+ if (entries.length === 0) {
83498
+ rmdirSync(currentDir);
83499
+ logger.debug(`Removed empty directory: ${currentDir}`);
83500
+ currentDir = resolve17(dirname18(currentDir));
83501
+ } else {
83502
+ break;
83503
+ }
83504
+ } catch {
83505
+ break;
83506
+ }
83507
+ }
83508
+ }
83509
+ function deletePath(fullPath, claudeDir2) {
83510
+ const normalizedPath = resolve17(fullPath);
83511
+ const normalizedClaudeDir = resolve17(claudeDir2);
83512
+ if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep3}`) && normalizedPath !== normalizedClaudeDir) {
83513
+ throw new Error(`Path traversal detected: ${fullPath}`);
83514
+ }
83515
+ try {
83516
+ const stat13 = lstatSync3(fullPath);
83517
+ if (stat13.isDirectory()) {
83518
+ rmSync2(fullPath, { recursive: true, force: true });
83519
+ } else {
83520
+ unlinkSync3(fullPath);
83521
+ cleanupEmptyDirectories(fullPath, claudeDir2);
83522
+ }
83523
+ } catch (error) {
83524
+ throw new Error(`Failed to delete ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
83525
+ }
83526
+ }
83527
+ async function updateMetadataAfterDeletion(claudeDir2, deletedPaths) {
83528
+ const metadataPath = join76(claudeDir2, "metadata.json");
83529
+ if (!await import_fs_extra9.pathExists(metadataPath)) {
83530
+ return;
83531
+ }
83532
+ let content;
83533
+ try {
83534
+ content = await import_fs_extra9.readFile(metadataPath, "utf-8");
83535
+ } catch {
83536
+ logger.debug("Failed to read metadata.json for cleanup");
83537
+ return;
83538
+ }
83539
+ let metadata;
83540
+ try {
83541
+ metadata = JSON.parse(content);
83542
+ } catch {
83543
+ logger.debug("Failed to parse metadata.json for cleanup");
83544
+ return;
83545
+ }
83546
+ const deletedSet = new Set(deletedPaths);
83547
+ const isDeletedOrInDeletedDir = (path13) => {
83548
+ if (deletedSet.has(path13))
83549
+ return true;
83550
+ for (const deleted of deletedPaths) {
83551
+ if (path13.startsWith(`${deleted}/`))
83552
+ return true;
83553
+ }
83554
+ return false;
83555
+ };
83556
+ if (metadata.kits) {
83557
+ for (const kitName of Object.keys(metadata.kits)) {
83558
+ const kit = metadata.kits[kitName];
83559
+ if (kit?.files) {
83560
+ kit.files = kit.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
83561
+ }
83562
+ }
83563
+ }
83564
+ if (metadata.files) {
83565
+ metadata.files = metadata.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
83566
+ }
83567
+ try {
83568
+ await import_fs_extra9.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
83569
+ logger.debug(`Updated metadata.json, removed ${deletedPaths.length} entries`);
83570
+ } catch {
83571
+ logger.debug("Failed to write updated metadata.json");
83572
+ }
83573
+ }
83574
+ async function handleDeletions(sourceMetadata, claudeDir2) {
83575
+ const deletionPatterns = sourceMetadata.deletions || [];
83576
+ if (deletionPatterns.length === 0) {
83577
+ return { deletedPaths: [], preservedPaths: [], errors: [] };
83578
+ }
83579
+ const deletions = expandGlobPatterns(deletionPatterns, claudeDir2);
83580
+ const userMetadata = await readManifest(claudeDir2);
83581
+ const result = { deletedPaths: [], preservedPaths: [], errors: [] };
83582
+ for (const path13 of deletions) {
83583
+ const fullPath = join76(claudeDir2, path13);
83584
+ const normalizedPath = resolve17(fullPath);
83585
+ const normalizedClaudeDir = resolve17(claudeDir2);
83586
+ if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep3}`)) {
83587
+ logger.warning(`Skipping invalid path: ${path13}`);
83588
+ result.errors.push(path13);
83589
+ continue;
83590
+ }
83591
+ if (!shouldDeletePath(path13, userMetadata)) {
83592
+ result.preservedPaths.push(path13);
83593
+ logger.verbose(`Preserved user file: ${path13}`);
83594
+ continue;
83595
+ }
83596
+ if (existsSync48(fullPath)) {
83597
+ try {
83598
+ deletePath(fullPath, claudeDir2);
83599
+ result.deletedPaths.push(path13);
83600
+ logger.verbose(`Deleted: ${path13}`);
83601
+ } catch (error) {
83602
+ result.errors.push(path13);
83603
+ logger.debug(`Failed to delete ${path13}: ${error}`);
83604
+ }
83605
+ }
83606
+ }
83607
+ if (result.deletedPaths.length > 0) {
83608
+ await updateMetadataAfterDeletion(claudeDir2, result.deletedPaths);
83609
+ }
83610
+ return result;
83611
+ }
84225
83612
 
84226
83613
  // src/domains/installation/file-merger.ts
84227
83614
  init_logger();
@@ -84233,10 +83620,9 @@ init_logger();
84233
83620
  init_types3();
84234
83621
  var import_fs_extra12 = __toESM(require_lib3(), 1);
84235
83622
  var import_ignore3 = __toESM(require_ignore(), 1);
84236
- import { dirname as dirname21, join as join78, relative as relative12 } from "node:path";
83623
+ import { dirname as dirname20, join as join79, relative as relative12 } from "node:path";
84237
83624
 
84238
83625
  // src/domains/installation/selective-merger.ts
84239
- init_manifest_reader();
84240
83626
  import { stat as stat13 } from "node:fs/promises";
84241
83627
  init_logger();
84242
83628
  var import_semver2 = __toESM(require_semver2(), 1);
@@ -84413,7 +83799,7 @@ init_logger();
84413
83799
  var import_fs_extra10 = __toESM(require_lib3(), 1);
84414
83800
  var import_ignore2 = __toESM(require_ignore(), 1);
84415
83801
  import { relative as relative11 } from "node:path";
84416
- import { join as join76 } from "node:path";
83802
+ import { join as join77 } from "node:path";
84417
83803
 
84418
83804
  // node_modules/@isaacs/balanced-match/dist/esm/index.js
84419
83805
  var balanced = (a3, b3, str2) => {
@@ -85869,7 +85255,7 @@ class FileScanner {
85869
85255
  const files = [];
85870
85256
  const entries = await import_fs_extra10.readdir(dir, { encoding: "utf8" });
85871
85257
  for (const entry of entries) {
85872
- const fullPath = join76(dir, entry);
85258
+ const fullPath = join77(dir, entry);
85873
85259
  const relativePath = relative11(baseDir, fullPath);
85874
85260
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
85875
85261
  const stats = await import_fs_extra10.lstat(fullPath);
@@ -85909,7 +85295,7 @@ import { execSync as execSync4 } from "node:child_process";
85909
85295
  init_shared();
85910
85296
  import { existsSync as existsSync49 } from "node:fs";
85911
85297
  import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "node:fs/promises";
85912
- import { dirname as dirname20, join as join77 } from "node:path";
85298
+ import { dirname as dirname19, join as join78 } from "node:path";
85913
85299
  var CK_JSON_FILE = ".ck.json";
85914
85300
 
85915
85301
  class InstalledSettingsTracker {
@@ -85923,9 +85309,9 @@ class InstalledSettingsTracker {
85923
85309
  }
85924
85310
  getCkJsonPath() {
85925
85311
  if (this.isGlobal) {
85926
- return join77(this.projectDir, CK_JSON_FILE);
85312
+ return join78(this.projectDir, CK_JSON_FILE);
85927
85313
  }
85928
- return join77(this.projectDir, ".claude", CK_JSON_FILE);
85314
+ return join78(this.projectDir, ".claude", CK_JSON_FILE);
85929
85315
  }
85930
85316
  async loadInstalledSettings() {
85931
85317
  const ckJsonPath = this.getCkJsonPath();
@@ -85960,7 +85346,7 @@ class InstalledSettingsTracker {
85960
85346
  data.kits[this.kitName] = {};
85961
85347
  }
85962
85348
  data.kits[this.kitName].installedSettings = settings;
85963
- await mkdir26(dirname20(ckJsonPath), { recursive: true });
85349
+ await mkdir26(dirname19(ckJsonPath), { recursive: true });
85964
85350
  await writeFile22(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
85965
85351
  logger.debug(`Saved installed settings to ${ckJsonPath}`);
85966
85352
  } catch (error) {
@@ -86478,7 +85864,7 @@ class CopyExecutor {
86478
85864
  for (const file of files) {
86479
85865
  const relativePath = relative12(sourceDir, file);
86480
85866
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
86481
- const destPath = join78(destDir, relativePath);
85867
+ const destPath = join79(destDir, relativePath);
86482
85868
  if (await import_fs_extra12.pathExists(destPath)) {
86483
85869
  if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
86484
85870
  logger.debug(`Security-sensitive file exists but won't be overwritten: ${normalizedRelativePath}`);
@@ -86500,7 +85886,7 @@ class CopyExecutor {
86500
85886
  for (const file of files) {
86501
85887
  const relativePath = relative12(sourceDir, file);
86502
85888
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
86503
- const destPath = join78(destDir, relativePath);
85889
+ const destPath = join79(destDir, relativePath);
86504
85890
  if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
86505
85891
  logger.debug(`Skipping security-sensitive file: ${normalizedRelativePath}`);
86506
85892
  skippedCount++;
@@ -86577,10 +85963,10 @@ class CopyExecutor {
86577
85963
  }
86578
85964
  trackInstalledFile(relativePath) {
86579
85965
  this.installedFiles.add(relativePath);
86580
- let dir = dirname21(relativePath);
85966
+ let dir = dirname20(relativePath);
86581
85967
  while (dir && dir !== "." && dir !== "/") {
86582
85968
  this.installedDirectories.add(`${dir}/`);
86583
- dir = dirname21(dir);
85969
+ dir = dirname20(dir);
86584
85970
  }
86585
85971
  }
86586
85972
  }
@@ -86670,19 +86056,15 @@ class FileMerger {
86670
86056
 
86671
86057
  // src/domains/migration/legacy-migration.ts
86672
86058
  import { readdir as readdir18, stat as stat14 } from "node:fs/promises";
86673
- import { join as join82, relative as relative13 } from "node:path";
86674
-
86675
- // src/services/file-operations/manifest/index.ts
86676
- init_manifest_reader();
86677
-
86059
+ import { join as join83, relative as relative13 } from "node:path";
86678
86060
  // src/services/file-operations/manifest/manifest-tracker.ts
86679
- import { join as join81 } from "node:path";
86061
+ import { join as join82 } from "node:path";
86680
86062
 
86681
86063
  // src/domains/migration/release-manifest.ts
86682
86064
  init_logger();
86683
86065
  init_zod();
86684
86066
  var import_fs_extra13 = __toESM(require_lib3(), 1);
86685
- import { join as join79 } from "node:path";
86067
+ import { join as join80 } from "node:path";
86686
86068
  var ReleaseManifestFileSchema = exports_external.object({
86687
86069
  path: exports_external.string(),
86688
86070
  checksum: exports_external.string().regex(/^[a-f0-9]{64}$/),
@@ -86697,7 +86079,7 @@ var ReleaseManifestSchema = exports_external.object({
86697
86079
 
86698
86080
  class ReleaseManifestLoader {
86699
86081
  static async load(extractDir) {
86700
- const manifestPath = join79(extractDir, "release-manifest.json");
86082
+ const manifestPath = join80(extractDir, "release-manifest.json");
86701
86083
  try {
86702
86084
  const content = await import_fs_extra13.readFile(manifestPath, "utf-8");
86703
86085
  const parsed = JSON.parse(content);
@@ -86721,12 +86103,11 @@ init_safe_spinner();
86721
86103
  init_metadata_migration();
86722
86104
  init_logger();
86723
86105
  init_types3();
86724
- init_manifest_reader();
86725
86106
  var import_fs_extra14 = __toESM(require_lib3(), 1);
86726
86107
  var import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
86727
- import { join as join80 } from "node:path";
86108
+ import { join as join81 } from "node:path";
86728
86109
  async function writeManifest(claudeDir2, kitName, version, scope, kitType, trackedFiles, userConfigFiles) {
86729
- const metadataPath = join80(claudeDir2, "metadata.json");
86110
+ const metadataPath = join81(claudeDir2, "metadata.json");
86730
86111
  const kit = kitType || (/\bmarketing\b/i.test(kitName) ? "marketing" : "engineer");
86731
86112
  await import_fs_extra14.ensureFile(metadataPath);
86732
86113
  let release = null;
@@ -86746,54 +86127,20 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
86746
86127
  const content = await import_fs_extra14.readFile(metadataPath, "utf-8");
86747
86128
  const parsed = JSON.parse(content);
86748
86129
  if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
86749
- const validatedExisting = MetadataSchema.safeParse(parsed);
86750
- if (validatedExisting.success) {
86751
- existingMetadata = validatedExisting.data;
86752
- } else {
86753
- logger.warning("Existing metadata.json is invalid; preserving recoverable fields and rebuilding the rest");
86754
- const raw2 = parsed;
86755
- const recoveredKits = {};
86756
- if (raw2.kits && typeof raw2.kits === "object") {
86757
- for (const [rawKitName, rawKitValue] of Object.entries(raw2.kits)) {
86758
- if ((rawKitName === "engineer" || rawKitName === "marketing") && rawKitValue && typeof rawKitValue === "object") {
86759
- const recoveredKit = rawKitValue;
86760
- if (typeof recoveredKit.version === "string" && typeof recoveredKit.installedAt === "string") {
86761
- recoveredKits[rawKitName] = recoveredKit;
86762
- }
86763
- }
86764
- }
86765
- }
86766
- existingMetadata = {
86767
- kits: recoveredKits,
86768
- scope: raw2.scope === "local" || raw2.scope === "global" ? raw2.scope : undefined,
86769
- name: typeof raw2.name === "string" ? raw2.name : undefined,
86770
- version: typeof raw2.version === "string" ? raw2.version : undefined,
86771
- installedAt: typeof raw2.installedAt === "string" ? raw2.installedAt : undefined,
86772
- userConfigFiles: Array.isArray(raw2.userConfigFiles) ? raw2.userConfigFiles.filter((entry) => typeof entry === "string") : undefined
86773
- };
86774
- }
86130
+ existingMetadata = parsed;
86775
86131
  }
86776
86132
  } catch (error) {
86777
86133
  logger.debug(`Could not read existing metadata: ${error}`);
86778
86134
  }
86779
86135
  }
86780
86136
  const installedAt = new Date().toISOString();
86781
- const existingKits = existingMetadata.kits || {};
86782
- const existingKitMetadata = existingKits[kit];
86783
86137
  const kitMetadata = {
86784
- ...existingKitMetadata,
86785
86138
  version,
86786
86139
  installedAt,
86787
86140
  files: trackedFiles.length > 0 ? trackedFiles : undefined
86788
86141
  };
86142
+ const existingKits = existingMetadata.kits || {};
86789
86143
  const otherKitsExist = Object.keys(existingKits).some((k2) => k2 !== kit);
86790
- const mergedUserConfigFiles = [
86791
- ...new Set([
86792
- ...existingMetadata.userConfigFiles || [],
86793
- ...USER_CONFIG_PATTERNS,
86794
- ...userConfigFiles
86795
- ])
86796
- ];
86797
86144
  const metadata = {
86798
86145
  kits: {
86799
86146
  ...existingKits,
@@ -86803,7 +86150,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
86803
86150
  name: otherKitsExist ? existingMetadata.name ?? kitName : kitName,
86804
86151
  version: otherKitsExist ? existingMetadata.version ?? version : version,
86805
86152
  installedAt: otherKitsExist ? existingMetadata.installedAt ?? installedAt : installedAt,
86806
- userConfigFiles: mergedUserConfigFiles
86153
+ userConfigFiles: [...USER_CONFIG_PATTERNS, ...userConfigFiles]
86807
86154
  };
86808
86155
  const validated = MetadataSchema.parse(metadata);
86809
86156
  await import_fs_extra14.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
@@ -86816,7 +86163,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
86816
86163
  }
86817
86164
  }
86818
86165
  async function removeKitFromManifest(claudeDir2, kit) {
86819
- const metadataPath = join80(claudeDir2, "metadata.json");
86166
+ const metadataPath = join81(claudeDir2, "metadata.json");
86820
86167
  if (!await import_fs_extra14.pathExists(metadataPath))
86821
86168
  return false;
86822
86169
  let release = null;
@@ -86946,7 +86293,7 @@ function buildFileTrackingList(options2) {
86946
86293
  if (!isGlobal && !installedPath.startsWith(".claude/"))
86947
86294
  continue;
86948
86295
  const relativePath = isGlobal ? installedPath : installedPath.replace(/^\.claude\//, "");
86949
- const filePath = join81(claudeDir2, relativePath);
86296
+ const filePath = join82(claudeDir2, relativePath);
86950
86297
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
86951
86298
  const ownership = manifestEntry ? "ck" : "user";
86952
86299
  filesToTrack.push({
@@ -87053,7 +86400,7 @@ class LegacyMigration {
87053
86400
  continue;
87054
86401
  if (SKIP_DIRS_ALL.includes(entry))
87055
86402
  continue;
87056
- const fullPath = join82(dir, entry);
86403
+ const fullPath = join83(dir, entry);
87057
86404
  let stats;
87058
86405
  try {
87059
86406
  stats = await stat14(fullPath);
@@ -87155,7 +86502,7 @@ User-created files (sample):`);
87155
86502
  ];
87156
86503
  if (filesToChecksum.length > 0) {
87157
86504
  const checksumResults = await mapWithLimit(filesToChecksum, async ({ relativePath, ownership }) => {
87158
- const fullPath = join82(claudeDir2, relativePath);
86505
+ const fullPath = join83(claudeDir2, relativePath);
87159
86506
  const checksum = await OwnershipChecker.calculateChecksum(fullPath);
87160
86507
  return { relativePath, checksum, ownership };
87161
86508
  });
@@ -87176,7 +86523,7 @@ User-created files (sample):`);
87176
86523
  installedAt: new Date().toISOString(),
87177
86524
  files: trackedFiles
87178
86525
  };
87179
- const metadataPath = join82(claudeDir2, "metadata.json");
86526
+ const metadataPath = join83(claudeDir2, "metadata.json");
87180
86527
  await import_fs_extra15.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
87181
86528
  logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
87182
86529
  return true;
@@ -87282,7 +86629,7 @@ function buildConflictSummary(fileConflicts, hookConflicts, mcpConflicts) {
87282
86629
  init_logger();
87283
86630
  init_skip_directories();
87284
86631
  var import_fs_extra16 = __toESM(require_lib3(), 1);
87285
- import { join as join83, relative as relative14, resolve as resolve19 } from "node:path";
86632
+ import { join as join84, relative as relative14, resolve as resolve18 } from "node:path";
87286
86633
 
87287
86634
  class FileScanner2 {
87288
86635
  static async getFiles(dirPath, relativeTo) {
@@ -87298,7 +86645,7 @@ class FileScanner2 {
87298
86645
  logger.debug(`Skipping directory: ${entry}`);
87299
86646
  continue;
87300
86647
  }
87301
- const fullPath = join83(dirPath, entry);
86648
+ const fullPath = join84(dirPath, entry);
87302
86649
  if (!FileScanner2.isSafePath(basePath, fullPath)) {
87303
86650
  logger.warning(`Skipping potentially unsafe path: ${entry}`);
87304
86651
  continue;
@@ -87333,8 +86680,8 @@ class FileScanner2 {
87333
86680
  return files;
87334
86681
  }
87335
86682
  static async findCustomFiles(destDir, sourceDir, subPath) {
87336
- const destSubDir = join83(destDir, subPath);
87337
- const sourceSubDir = join83(sourceDir, subPath);
86683
+ const destSubDir = join84(destDir, subPath);
86684
+ const sourceSubDir = join84(sourceDir, subPath);
87338
86685
  logger.debug(`findCustomFiles - destDir: ${destDir}`);
87339
86686
  logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
87340
86687
  logger.debug(`findCustomFiles - subPath: "${subPath}"`);
@@ -87362,8 +86709,8 @@ class FileScanner2 {
87362
86709
  return customFiles;
87363
86710
  }
87364
86711
  static isSafePath(basePath, targetPath) {
87365
- const resolvedBase = resolve19(basePath);
87366
- const resolvedTarget = resolve19(targetPath);
86712
+ const resolvedBase = resolve18(basePath);
86713
+ const resolvedTarget = resolve18(targetPath);
87367
86714
  return resolvedTarget.startsWith(resolvedBase);
87368
86715
  }
87369
86716
  static toPosixPath(path14) {
@@ -87375,12 +86722,12 @@ class FileScanner2 {
87375
86722
  init_logger();
87376
86723
  var import_fs_extra17 = __toESM(require_lib3(), 1);
87377
86724
  import { lstat as lstat7, mkdir as mkdir27, readdir as readdir21, stat as stat15 } from "node:fs/promises";
87378
- import { join as join85 } from "node:path";
86725
+ import { join as join86 } from "node:path";
87379
86726
 
87380
86727
  // src/services/transformers/commands-prefix/content-transformer.ts
87381
86728
  init_logger();
87382
86729
  import { readFile as readFile42, readdir as readdir20, writeFile as writeFile26 } from "node:fs/promises";
87383
- import { join as join84 } from "node:path";
86730
+ import { join as join85 } from "node:path";
87384
86731
  var TRANSFORMABLE_EXTENSIONS = new Set([
87385
86732
  ".md",
87386
86733
  ".txt",
@@ -87441,7 +86788,7 @@ async function transformCommandReferences(directory, options2 = {}) {
87441
86788
  async function processDirectory(dir) {
87442
86789
  const entries = await readdir20(dir, { withFileTypes: true });
87443
86790
  for (const entry of entries) {
87444
- const fullPath = join84(dir, entry.name);
86791
+ const fullPath = join85(dir, entry.name);
87445
86792
  if (entry.isDirectory()) {
87446
86793
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
87447
86794
  continue;
@@ -87516,14 +86863,14 @@ function shouldApplyPrefix(options2) {
87516
86863
  // src/services/transformers/commands-prefix/prefix-applier.ts
87517
86864
  async function applyPrefix(extractDir) {
87518
86865
  validatePath(extractDir, "extractDir");
87519
- const commandsDir = join85(extractDir, ".claude", "commands");
86866
+ const commandsDir = join86(extractDir, ".claude", "commands");
87520
86867
  if (!await import_fs_extra17.pathExists(commandsDir)) {
87521
86868
  logger.verbose("No commands directory found, skipping prefix application");
87522
86869
  return;
87523
86870
  }
87524
86871
  logger.info("Applying /ck: prefix to slash commands...");
87525
- const backupDir = join85(extractDir, ".commands-backup");
87526
- const tempDir = join85(extractDir, ".commands-prefix-temp");
86872
+ const backupDir = join86(extractDir, ".commands-backup");
86873
+ const tempDir = join86(extractDir, ".commands-prefix-temp");
87527
86874
  try {
87528
86875
  const entries = await readdir21(commandsDir);
87529
86876
  if (entries.length === 0) {
@@ -87531,7 +86878,7 @@ async function applyPrefix(extractDir) {
87531
86878
  return;
87532
86879
  }
87533
86880
  if (entries.length === 1 && entries[0] === "ck") {
87534
- const ckDir2 = join85(commandsDir, "ck");
86881
+ const ckDir2 = join86(commandsDir, "ck");
87535
86882
  const ckStat = await stat15(ckDir2);
87536
86883
  if (ckStat.isDirectory()) {
87537
86884
  logger.verbose("Commands already have /ck: prefix, skipping");
@@ -87541,17 +86888,17 @@ async function applyPrefix(extractDir) {
87541
86888
  await import_fs_extra17.copy(commandsDir, backupDir);
87542
86889
  logger.verbose("Created backup of commands directory");
87543
86890
  await mkdir27(tempDir, { recursive: true });
87544
- const ckDir = join85(tempDir, "ck");
86891
+ const ckDir = join86(tempDir, "ck");
87545
86892
  await mkdir27(ckDir, { recursive: true });
87546
86893
  let processedCount = 0;
87547
86894
  for (const entry of entries) {
87548
- const sourcePath = join85(commandsDir, entry);
86895
+ const sourcePath = join86(commandsDir, entry);
87549
86896
  const stats = await lstat7(sourcePath);
87550
86897
  if (stats.isSymbolicLink()) {
87551
86898
  logger.warning(`Skipping symlink for security: ${entry}`);
87552
86899
  continue;
87553
86900
  }
87554
- const destPath = join85(ckDir, entry);
86901
+ const destPath = join86(ckDir, entry);
87555
86902
  await import_fs_extra17.copy(sourcePath, destPath, {
87556
86903
  overwrite: false,
87557
86904
  errorOnExist: true
@@ -87569,7 +86916,7 @@ async function applyPrefix(extractDir) {
87569
86916
  await import_fs_extra17.move(tempDir, commandsDir);
87570
86917
  await import_fs_extra17.remove(backupDir);
87571
86918
  logger.success("Successfully reorganized commands to /ck: prefix");
87572
- const claudeDir2 = join85(extractDir, ".claude");
86919
+ const claudeDir2 = join86(extractDir, ".claude");
87573
86920
  logger.info("Transforming command references in file contents...");
87574
86921
  const transformResult = await transformCommandReferences(claudeDir2, {
87575
86922
  verbose: logger.isVerbose()
@@ -87607,20 +86954,20 @@ async function applyPrefix(extractDir) {
87607
86954
  // src/services/transformers/commands-prefix/prefix-cleaner.ts
87608
86955
  init_metadata_migration();
87609
86956
  import { lstat as lstat9, readdir as readdir23 } from "node:fs/promises";
87610
- import { join as join87 } from "node:path";
86957
+ import { join as join88 } from "node:path";
87611
86958
  init_logger();
87612
86959
  var import_fs_extra19 = __toESM(require_lib3(), 1);
87613
86960
 
87614
86961
  // src/services/transformers/commands-prefix/file-processor.ts
87615
86962
  import { lstat as lstat8, readdir as readdir22 } from "node:fs/promises";
87616
- import { join as join86 } from "node:path";
86963
+ import { join as join87 } from "node:path";
87617
86964
  init_logger();
87618
86965
  var import_fs_extra18 = __toESM(require_lib3(), 1);
87619
86966
  async function scanDirectoryFiles(dir) {
87620
86967
  const files = [];
87621
86968
  const entries = await readdir22(dir);
87622
86969
  for (const entry of entries) {
87623
- const fullPath = join86(dir, entry);
86970
+ const fullPath = join87(dir, entry);
87624
86971
  const stats = await lstat8(fullPath);
87625
86972
  if (stats.isSymbolicLink()) {
87626
86973
  continue;
@@ -87748,8 +87095,8 @@ function isDifferentKitDirectory(dirName, currentKit) {
87748
87095
  async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
87749
87096
  const { dryRun = false } = options2;
87750
87097
  validatePath(targetDir, "targetDir");
87751
- const claudeDir2 = isGlobal ? targetDir : join87(targetDir, ".claude");
87752
- const commandsDir = join87(claudeDir2, "commands");
87098
+ const claudeDir2 = isGlobal ? targetDir : join88(targetDir, ".claude");
87099
+ const commandsDir = join88(claudeDir2, "commands");
87753
87100
  const accumulator = {
87754
87101
  results: [],
87755
87102
  deletedCount: 0,
@@ -87791,7 +87138,7 @@ async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
87791
87138
  }
87792
87139
  const metadataForChecks = options2.kitType ? createKitSpecificMetadata(metadata, options2.kitType) : metadata;
87793
87140
  for (const entry of entries) {
87794
- const entryPath = join87(commandsDir, entry);
87141
+ const entryPath = join88(commandsDir, entry);
87795
87142
  const stats = await lstat9(entryPath);
87796
87143
  if (stats.isSymbolicLink()) {
87797
87144
  addSymlinkSkip(entry, accumulator);
@@ -87848,7 +87195,7 @@ async function handleMerge(ctx) {
87848
87195
  let customClaudeFiles = [];
87849
87196
  if (!ctx.options.fresh) {
87850
87197
  logger.info("Scanning for custom .claude files...");
87851
- const scanSourceDir = ctx.options.global ? join88(ctx.extractDir, ".claude") : ctx.extractDir;
87198
+ const scanSourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
87852
87199
  const scanTargetSubdir = ctx.options.global ? "" : ".claude";
87853
87200
  customClaudeFiles = await FileScanner2.findCustomFiles(ctx.resolvedDir, scanSourceDir, scanTargetSubdir);
87854
87201
  } else {
@@ -87913,38 +87260,28 @@ async function handleMerge(ctx) {
87913
87260
  return { ...ctx, cancelled: true };
87914
87261
  }
87915
87262
  }
87916
- const sourceDir = ctx.options.global ? join88(ctx.extractDir, ".claude") : ctx.extractDir;
87263
+ const sourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
87917
87264
  await merger.merge(sourceDir, ctx.resolvedDir, ctx.isNonInteractive);
87918
87265
  const fileConflicts = merger.getFileConflicts();
87919
87266
  if (fileConflicts.length > 0 && !ctx.isNonInteractive) {
87920
87267
  const summary = buildConflictSummary(fileConflicts, [], []);
87921
87268
  displayConflictSummary(summary);
87922
87269
  }
87923
- let deferredDeletions = [];
87924
87270
  try {
87925
- const sourceMetadataPath = ctx.options.global ? join88(sourceDir, "metadata.json") : join88(sourceDir, ".claude", "metadata.json");
87271
+ const sourceMetadataPath = ctx.options.global ? join89(sourceDir, "metadata.json") : join89(sourceDir, ".claude", "metadata.json");
87926
87272
  if (await import_fs_extra20.pathExists(sourceMetadataPath)) {
87927
87273
  const metadataContent = await import_fs_extra20.readFile(sourceMetadataPath, "utf-8");
87928
87274
  const sourceMetadata = JSON.parse(metadataContent);
87929
87275
  if (sourceMetadata.deletions && sourceMetadata.deletions.length > 0) {
87930
- const { categorizeDeletions: categorizeDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
87931
- const categorized = categorizeDeletions2(sourceMetadata.deletions);
87932
- if (categorized.immediate.length > 0) {
87933
- const immediateMetadata = { ...sourceMetadata, deletions: categorized.immediate };
87934
- const deletionResult = await handleDeletions(immediateMetadata, ctx.claudeDir);
87935
- if (deletionResult.deletedPaths.length > 0) {
87936
- logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
87937
- for (const path14 of deletionResult.deletedPaths) {
87938
- logger.verbose(` - ${path14}`);
87939
- }
87940
- }
87941
- if (deletionResult.preservedPaths.length > 0) {
87942
- logger.verbose(`Preserved ${deletionResult.preservedPaths.length} user-owned file(s)`);
87276
+ const deletionResult = await handleDeletions(sourceMetadata, ctx.claudeDir);
87277
+ if (deletionResult.deletedPaths.length > 0) {
87278
+ logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
87279
+ for (const path14 of deletionResult.deletedPaths) {
87280
+ logger.verbose(` - ${path14}`);
87943
87281
  }
87944
87282
  }
87945
- if (categorized.deferred.length > 0) {
87946
- deferredDeletions = categorized.deferred;
87947
- logger.debug(`Deferred ${categorized.deferred.length} skill deletion(s) to post-install phase`);
87283
+ if (deletionResult.preservedPaths.length > 0) {
87284
+ logger.verbose(`Preserved ${deletionResult.preservedPaths.length} user-owned file(s)`);
87948
87285
  }
87949
87286
  }
87950
87287
  } else {
@@ -87971,12 +87308,11 @@ async function handleMerge(ctx) {
87971
87308
  return {
87972
87309
  ...ctx,
87973
87310
  customClaudeFiles,
87974
- includePatterns,
87975
- deferredDeletions
87311
+ includePatterns
87976
87312
  };
87977
87313
  }
87978
87314
  // src/commands/init/phases/migration-handler.ts
87979
- import { join as join96 } from "node:path";
87315
+ import { join as join97 } from "node:path";
87980
87316
 
87981
87317
  // src/domains/skills/skills-detector.ts
87982
87318
  init_logger();
@@ -87992,7 +87328,7 @@ init_types3();
87992
87328
  var import_fs_extra21 = __toESM(require_lib3(), 1);
87993
87329
  import { createHash as createHash4 } from "node:crypto";
87994
87330
  import { readFile as readFile44, readdir as readdir24, writeFile as writeFile27 } from "node:fs/promises";
87995
- import { join as join89, relative as relative15 } from "node:path";
87331
+ import { join as join90, relative as relative15 } from "node:path";
87996
87332
 
87997
87333
  class SkillsManifestManager {
87998
87334
  static MANIFEST_FILENAME = ".skills-manifest.json";
@@ -88014,12 +87350,12 @@ class SkillsManifestManager {
88014
87350
  return manifest;
88015
87351
  }
88016
87352
  static async writeManifest(skillsDir2, manifest) {
88017
- const manifestPath = join89(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
87353
+ const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
88018
87354
  await writeFile27(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
88019
87355
  logger.debug(`Wrote manifest to: ${manifestPath}`);
88020
87356
  }
88021
87357
  static async readManifest(skillsDir2) {
88022
- const manifestPath = join89(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
87358
+ const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
88023
87359
  if (!await import_fs_extra21.pathExists(manifestPath)) {
88024
87360
  logger.debug(`No manifest found at: ${manifestPath}`);
88025
87361
  return null;
@@ -88042,7 +87378,7 @@ class SkillsManifestManager {
88042
87378
  return "flat";
88043
87379
  }
88044
87380
  for (const dir of dirs.slice(0, 3)) {
88045
- const dirPath = join89(skillsDir2, dir.name);
87381
+ const dirPath = join90(skillsDir2, dir.name);
88046
87382
  const subEntries = await readdir24(dirPath, { withFileTypes: true });
88047
87383
  const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
88048
87384
  if (hasSubdirs) {
@@ -88061,7 +87397,7 @@ class SkillsManifestManager {
88061
87397
  const entries = await readdir24(skillsDir2, { withFileTypes: true });
88062
87398
  for (const entry of entries) {
88063
87399
  if (entry.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
88064
- const skillPath = join89(skillsDir2, entry.name);
87400
+ const skillPath = join90(skillsDir2, entry.name);
88065
87401
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
88066
87402
  skills.push({
88067
87403
  name: entry.name,
@@ -88073,11 +87409,11 @@ class SkillsManifestManager {
88073
87409
  const categories = await readdir24(skillsDir2, { withFileTypes: true });
88074
87410
  for (const category of categories) {
88075
87411
  if (category.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(category.name) && !category.name.startsWith(".")) {
88076
- const categoryPath = join89(skillsDir2, category.name);
87412
+ const categoryPath = join90(skillsDir2, category.name);
88077
87413
  const skillEntries = await readdir24(categoryPath, { withFileTypes: true });
88078
87414
  for (const skillEntry of skillEntries) {
88079
87415
  if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
88080
- const skillPath = join89(categoryPath, skillEntry.name);
87416
+ const skillPath = join90(categoryPath, skillEntry.name);
88081
87417
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
88082
87418
  skills.push({
88083
87419
  name: skillEntry.name,
@@ -88107,7 +87443,7 @@ class SkillsManifestManager {
88107
87443
  const files = [];
88108
87444
  const entries = await readdir24(dirPath, { withFileTypes: true });
88109
87445
  for (const entry of entries) {
88110
- const fullPath = join89(dirPath, entry.name);
87446
+ const fullPath = join90(dirPath, entry.name);
88111
87447
  if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name)) {
88112
87448
  continue;
88113
87449
  }
@@ -88229,7 +87565,7 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
88229
87565
  // src/domains/skills/detection/script-detector.ts
88230
87566
  var import_fs_extra22 = __toESM(require_lib3(), 1);
88231
87567
  import { readdir as readdir25 } from "node:fs/promises";
88232
- import { join as join90 } from "node:path";
87568
+ import { join as join91 } from "node:path";
88233
87569
  async function scanDirectory(skillsDir2) {
88234
87570
  if (!await import_fs_extra22.pathExists(skillsDir2)) {
88235
87571
  return ["flat", []];
@@ -88242,12 +87578,12 @@ async function scanDirectory(skillsDir2) {
88242
87578
  let totalSkillLikeCount = 0;
88243
87579
  const allSkills = [];
88244
87580
  for (const dir of dirs) {
88245
- const dirPath = join90(skillsDir2, dir.name);
87581
+ const dirPath = join91(skillsDir2, dir.name);
88246
87582
  const subEntries = await readdir25(dirPath, { withFileTypes: true });
88247
87583
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
88248
87584
  if (subdirs.length > 0) {
88249
87585
  for (const subdir of subdirs.slice(0, 3)) {
88250
- const subdirPath = join90(dirPath, subdir.name);
87586
+ const subdirPath = join91(dirPath, subdir.name);
88251
87587
  const subdirFiles = await readdir25(subdirPath, { withFileTypes: true });
88252
87588
  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"));
88253
87589
  if (hasSkillMarker) {
@@ -88404,12 +87740,12 @@ class SkillsMigrationDetector {
88404
87740
  // src/domains/skills/skills-migrator.ts
88405
87741
  init_logger();
88406
87742
  init_types3();
88407
- import { join as join95 } from "node:path";
87743
+ import { join as join96 } from "node:path";
88408
87744
 
88409
87745
  // src/domains/skills/migrator/migration-executor.ts
88410
87746
  init_logger();
88411
87747
  import { copyFile as copyFile6, mkdir as mkdir28, readdir as readdir26, rm as rm10 } from "node:fs/promises";
88412
- import { join as join91 } from "node:path";
87748
+ import { join as join92 } from "node:path";
88413
87749
  var import_fs_extra24 = __toESM(require_lib3(), 1);
88414
87750
 
88415
87751
  // src/domains/skills/skills-migration-prompts.ts
@@ -88574,8 +87910,8 @@ async function copySkillDirectory(sourceDir, destDir) {
88574
87910
  await mkdir28(destDir, { recursive: true });
88575
87911
  const entries = await readdir26(sourceDir, { withFileTypes: true });
88576
87912
  for (const entry of entries) {
88577
- const sourcePath = join91(sourceDir, entry.name);
88578
- const destPath = join91(destDir, entry.name);
87913
+ const sourcePath = join92(sourceDir, entry.name);
87914
+ const destPath = join92(destDir, entry.name);
88579
87915
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
88580
87916
  continue;
88581
87917
  }
@@ -88590,7 +87926,7 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
88590
87926
  const migrated = [];
88591
87927
  const preserved = [];
88592
87928
  const errors2 = [];
88593
- const tempDir = join91(currentSkillsDir, "..", ".skills-migration-temp");
87929
+ const tempDir = join92(currentSkillsDir, "..", ".skills-migration-temp");
88594
87930
  await mkdir28(tempDir, { recursive: true });
88595
87931
  try {
88596
87932
  for (const mapping of mappings) {
@@ -88611,9 +87947,9 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
88611
87947
  }
88612
87948
  }
88613
87949
  const category = mapping.category;
88614
- const targetPath = category ? join91(tempDir, category, skillName) : join91(tempDir, skillName);
87950
+ const targetPath = category ? join92(tempDir, category, skillName) : join92(tempDir, skillName);
88615
87951
  if (category) {
88616
- await mkdir28(join91(tempDir, category), { recursive: true });
87952
+ await mkdir28(join92(tempDir, category), { recursive: true });
88617
87953
  }
88618
87954
  await copySkillDirectory(currentSkillPath, targetPath);
88619
87955
  migrated.push(skillName);
@@ -88680,7 +88016,7 @@ init_logger();
88680
88016
  init_types3();
88681
88017
  var import_fs_extra25 = __toESM(require_lib3(), 1);
88682
88018
  import { copyFile as copyFile7, mkdir as mkdir29, readdir as readdir27, rm as rm11, stat as stat16 } from "node:fs/promises";
88683
- import { basename as basename10, join as join92, normalize as normalize8 } from "node:path";
88019
+ import { basename as basename10, join as join93, normalize as normalize8 } from "node:path";
88684
88020
  function validatePath2(path14, paramName) {
88685
88021
  if (!path14 || typeof path14 !== "string") {
88686
88022
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -88706,7 +88042,7 @@ class SkillsBackupManager {
88706
88042
  const timestamp = Date.now();
88707
88043
  const randomSuffix = Math.random().toString(36).substring(2, 8);
88708
88044
  const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
88709
- const backupDir = parentDir ? join92(parentDir, backupDirName) : join92(skillsDir2, "..", backupDirName);
88045
+ const backupDir = parentDir ? join93(parentDir, backupDirName) : join93(skillsDir2, "..", backupDirName);
88710
88046
  logger.info(`Creating backup at: ${backupDir}`);
88711
88047
  try {
88712
88048
  await mkdir29(backupDir, { recursive: true });
@@ -88757,7 +88093,7 @@ class SkillsBackupManager {
88757
88093
  }
88758
88094
  try {
88759
88095
  const entries = await readdir27(parentDir, { withFileTypes: true });
88760
- const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join92(parentDir, entry.name));
88096
+ const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join93(parentDir, entry.name));
88761
88097
  backups.sort().reverse();
88762
88098
  return backups;
88763
88099
  } catch (error) {
@@ -88785,8 +88121,8 @@ class SkillsBackupManager {
88785
88121
  static async copyDirectory(sourceDir, destDir) {
88786
88122
  const entries = await readdir27(sourceDir, { withFileTypes: true });
88787
88123
  for (const entry of entries) {
88788
- const sourcePath = join92(sourceDir, entry.name);
88789
- const destPath = join92(destDir, entry.name);
88124
+ const sourcePath = join93(sourceDir, entry.name);
88125
+ const destPath = join93(destDir, entry.name);
88790
88126
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
88791
88127
  continue;
88792
88128
  }
@@ -88802,7 +88138,7 @@ class SkillsBackupManager {
88802
88138
  let size = 0;
88803
88139
  const entries = await readdir27(dirPath, { withFileTypes: true });
88804
88140
  for (const entry of entries) {
88805
- const fullPath = join92(dirPath, entry.name);
88141
+ const fullPath = join93(dirPath, entry.name);
88806
88142
  if (entry.isSymbolicLink()) {
88807
88143
  continue;
88808
88144
  }
@@ -88838,12 +88174,12 @@ init_skip_directories();
88838
88174
  import { createHash as createHash5 } from "node:crypto";
88839
88175
  import { createReadStream as createReadStream3 } from "node:fs";
88840
88176
  import { readFile as readFile45, readdir as readdir28 } from "node:fs/promises";
88841
- import { join as join93, relative as relative16 } from "node:path";
88177
+ import { join as join94, relative as relative16 } from "node:path";
88842
88178
  async function getAllFiles(dirPath) {
88843
88179
  const files = [];
88844
88180
  const entries = await readdir28(dirPath, { withFileTypes: true });
88845
88181
  for (const entry of entries) {
88846
- const fullPath = join93(dirPath, entry.name);
88182
+ const fullPath = join94(dirPath, entry.name);
88847
88183
  if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name) || entry.isSymbolicLink()) {
88848
88184
  continue;
88849
88185
  }
@@ -88857,12 +88193,12 @@ async function getAllFiles(dirPath) {
88857
88193
  return files;
88858
88194
  }
88859
88195
  async function hashFile(filePath) {
88860
- return new Promise((resolve20, reject) => {
88196
+ return new Promise((resolve19, reject) => {
88861
88197
  const hash = createHash5("sha256");
88862
88198
  const stream = createReadStream3(filePath);
88863
88199
  stream.on("data", (chunk) => hash.update(chunk));
88864
88200
  stream.on("end", () => {
88865
- resolve20(hash.digest("hex"));
88201
+ resolve19(hash.digest("hex"));
88866
88202
  });
88867
88203
  stream.on("error", (error) => {
88868
88204
  stream.destroy();
@@ -88970,7 +88306,7 @@ async function detectFileChanges(currentSkillPath, baselineSkillPath) {
88970
88306
  init_types3();
88971
88307
  var import_fs_extra27 = __toESM(require_lib3(), 1);
88972
88308
  import { readdir as readdir29 } from "node:fs/promises";
88973
- import { join as join94, normalize as normalize9 } from "node:path";
88309
+ import { join as join95, normalize as normalize9 } from "node:path";
88974
88310
  function validatePath3(path14, paramName) {
88975
88311
  if (!path14 || typeof path14 !== "string") {
88976
88312
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -88991,13 +88327,13 @@ async function scanSkillsDirectory(skillsDir2) {
88991
88327
  if (dirs.length === 0) {
88992
88328
  return ["flat", []];
88993
88329
  }
88994
- const firstDirPath = join94(skillsDir2, dirs[0].name);
88330
+ const firstDirPath = join95(skillsDir2, dirs[0].name);
88995
88331
  const subEntries = await readdir29(firstDirPath, { withFileTypes: true });
88996
88332
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
88997
88333
  if (subdirs.length > 0) {
88998
88334
  let skillLikeCount = 0;
88999
88335
  for (const subdir of subdirs.slice(0, 3)) {
89000
- const subdirPath = join94(firstDirPath, subdir.name);
88336
+ const subdirPath = join95(firstDirPath, subdir.name);
89001
88337
  const subdirFiles = await readdir29(subdirPath, { withFileTypes: true });
89002
88338
  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"));
89003
88339
  if (hasSkillMarker) {
@@ -89007,7 +88343,7 @@ async function scanSkillsDirectory(skillsDir2) {
89007
88343
  if (skillLikeCount > 0) {
89008
88344
  const skills = [];
89009
88345
  for (const dir of dirs) {
89010
- const categoryPath = join94(skillsDir2, dir.name);
88346
+ const categoryPath = join95(skillsDir2, dir.name);
89011
88347
  const skillDirs = await readdir29(categoryPath, { withFileTypes: true });
89012
88348
  skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
89013
88349
  }
@@ -89017,7 +88353,7 @@ async function scanSkillsDirectory(skillsDir2) {
89017
88353
  return ["flat", dirs.map((dir) => dir.name)];
89018
88354
  }
89019
88355
  async function findSkillPath(skillsDir2, skillName) {
89020
- const flatPath = join94(skillsDir2, skillName);
88356
+ const flatPath = join95(skillsDir2, skillName);
89021
88357
  if (await import_fs_extra27.pathExists(flatPath)) {
89022
88358
  return { path: flatPath, category: undefined };
89023
88359
  }
@@ -89026,8 +88362,8 @@ async function findSkillPath(skillsDir2, skillName) {
89026
88362
  if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
89027
88363
  continue;
89028
88364
  }
89029
- const categoryPath = join94(skillsDir2, entry.name);
89030
- const skillPath = join94(categoryPath, skillName);
88365
+ const categoryPath = join95(skillsDir2, entry.name);
88366
+ const skillPath = join95(categoryPath, skillName);
89031
88367
  if (await import_fs_extra27.pathExists(skillPath)) {
89032
88368
  return { path: skillPath, category: entry.name };
89033
88369
  }
@@ -89121,7 +88457,7 @@ class SkillsMigrator {
89121
88457
  }
89122
88458
  }
89123
88459
  if (options2.backup && !options2.dryRun) {
89124
- const claudeDir2 = join95(currentSkillsDir, "..");
88460
+ const claudeDir2 = join96(currentSkillsDir, "..");
89125
88461
  result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir2);
89126
88462
  logger.success(`Backup created at: ${result.backupPath}`);
89127
88463
  }
@@ -89182,7 +88518,7 @@ async function handleMigration(ctx) {
89182
88518
  logger.debug("Skipping skills migration (fresh installation)");
89183
88519
  return ctx;
89184
88520
  }
89185
- const newSkillsDir = join96(ctx.extractDir, ".claude", "skills");
88521
+ const newSkillsDir = join97(ctx.extractDir, ".claude", "skills");
89186
88522
  const currentSkillsDir = PathResolver.buildSkillsPath(ctx.resolvedDir, ctx.options.global);
89187
88523
  if (!await import_fs_extra28.pathExists(newSkillsDir) || !await import_fs_extra28.pathExists(currentSkillsDir)) {
89188
88524
  return ctx;
@@ -89206,13 +88542,13 @@ async function handleMigration(ctx) {
89206
88542
  }
89207
88543
  // src/commands/init/phases/opencode-handler.ts
89208
88544
  import { cp as cp3, readdir as readdir31, rm as rm12 } from "node:fs/promises";
89209
- import { join as join98 } from "node:path";
88545
+ import { join as join99 } from "node:path";
89210
88546
 
89211
88547
  // src/services/transformers/opencode-path-transformer.ts
89212
88548
  init_logger();
89213
88549
  import { readFile as readFile46, readdir as readdir30, writeFile as writeFile28 } from "node:fs/promises";
89214
88550
  import { platform as platform12 } from "node:os";
89215
- import { extname as extname5, join as join97 } from "node:path";
88551
+ import { extname as extname5, join as join98 } from "node:path";
89216
88552
  var IS_WINDOWS2 = platform12() === "win32";
89217
88553
  function getOpenCodeGlobalPath() {
89218
88554
  return "$HOME/.config/opencode/";
@@ -89273,7 +88609,7 @@ async function transformPathsForGlobalOpenCode(directory, options2 = {}) {
89273
88609
  async function processDirectory2(dir) {
89274
88610
  const entries = await readdir30(dir, { withFileTypes: true });
89275
88611
  for (const entry of entries) {
89276
- const fullPath = join97(dir, entry.name);
88612
+ const fullPath = join98(dir, entry.name);
89277
88613
  if (entry.isDirectory()) {
89278
88614
  if (entry.name === "node_modules" || entry.name.startsWith(".")) {
89279
88615
  continue;
@@ -89312,7 +88648,7 @@ async function handleOpenCode(ctx) {
89312
88648
  if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir) {
89313
88649
  return ctx;
89314
88650
  }
89315
- const openCodeSource = join98(ctx.extractDir, ".opencode");
88651
+ const openCodeSource = join99(ctx.extractDir, ".opencode");
89316
88652
  if (!await import_fs_extra29.pathExists(openCodeSource)) {
89317
88653
  logger.debug("No .opencode directory in archive, skipping");
89318
88654
  return ctx;
@@ -89330,8 +88666,8 @@ async function handleOpenCode(ctx) {
89330
88666
  await import_fs_extra29.ensureDir(targetDir);
89331
88667
  const entries = await readdir31(openCodeSource, { withFileTypes: true });
89332
88668
  for (const entry of entries) {
89333
- const sourcePath = join98(openCodeSource, entry.name);
89334
- const targetPath = join98(targetDir, entry.name);
88669
+ const sourcePath = join99(openCodeSource, entry.name);
88670
+ const targetPath = join99(targetDir, entry.name);
89335
88671
  if (await import_fs_extra29.pathExists(targetPath)) {
89336
88672
  if (!ctx.options.forceOverwrite) {
89337
88673
  logger.verbose(`Skipping existing: ${entry.name}`);
@@ -89428,21 +88764,20 @@ Please use only one download method.`);
89428
88764
  }
89429
88765
  // src/commands/init/phases/post-install-handler.ts
89430
88766
  init_projects_registry();
89431
- import { join as join101 } from "node:path";
89432
- init_cc_version_checker();
88767
+ import { join as join100 } from "node:path";
89433
88768
  init_logger();
89434
88769
  init_path_resolver();
89435
- var import_fs_extra32 = __toESM(require_lib3(), 1);
88770
+ var import_fs_extra30 = __toESM(require_lib3(), 1);
89436
88771
  async function handlePostInstall(ctx) {
89437
88772
  if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir || !ctx.claudeDir) {
89438
88773
  return ctx;
89439
88774
  }
89440
88775
  if (ctx.options.global) {
89441
- const claudeMdSource = join101(ctx.extractDir, "CLAUDE.md");
89442
- const claudeMdDest = join101(ctx.resolvedDir, "CLAUDE.md");
89443
- if (await import_fs_extra32.pathExists(claudeMdSource)) {
89444
- if (ctx.options.fresh || !await import_fs_extra32.pathExists(claudeMdDest)) {
89445
- await import_fs_extra32.copy(claudeMdSource, claudeMdDest);
88776
+ const claudeMdSource = join100(ctx.extractDir, "CLAUDE.md");
88777
+ const claudeMdDest = join100(ctx.resolvedDir, "CLAUDE.md");
88778
+ if (await import_fs_extra30.pathExists(claudeMdSource)) {
88779
+ if (ctx.options.fresh || !await import_fs_extra30.pathExists(claudeMdDest)) {
88780
+ await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
89446
88781
  logger.success(ctx.options.fresh ? "Replaced CLAUDE.md in global directory (fresh install)" : "Copied CLAUDE.md to global directory");
89447
88782
  } else {
89448
88783
  logger.debug("CLAUDE.md already exists in global directory (preserved)");
@@ -89461,77 +88796,6 @@ async function handlePostInstall(ctx) {
89461
88796
  withSudo: ctx.options.withSudo
89462
88797
  });
89463
88798
  }
89464
- let pluginSupported = false;
89465
- try {
89466
- const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
89467
- await requireCCPluginSupport2();
89468
- pluginSupported = true;
89469
- } catch (error) {
89470
- if (error instanceof CCPluginSupportError) {
89471
- logger.info(`Plugin install skipped: ${error.message}`);
89472
- if (error.code === "cc_version_too_old") {
89473
- logger.info("Upgrade: brew upgrade claude-code (or npm i -g @anthropic-ai/claude-code)");
89474
- }
89475
- if (error.code === "cc_not_found") {
89476
- logger.info("Install Claude Code CLI, then re-run ck init to enable /ck:* plugin skills");
89477
- }
89478
- } else {
89479
- logger.info(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
89480
- }
89481
- }
89482
- let pluginVerified = false;
89483
- if (pluginSupported) {
89484
- try {
89485
- const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
89486
- const pluginResult = await handlePluginInstall2(ctx.extractDir);
89487
- pluginVerified = pluginResult.verified;
89488
- if (pluginResult.error) {
89489
- logger.info(`Plugin install issue: ${pluginResult.error}`);
89490
- }
89491
- } catch (error) {
89492
- logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
89493
- }
89494
- }
89495
- if (ctx.claudeDir && ctx.kitType) {
89496
- try {
89497
- const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
89498
- await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
89499
- pluginInstalled: pluginVerified,
89500
- pluginInstalledAt: new Date().toISOString(),
89501
- pluginVersion: ctx.selectedVersion || "unknown"
89502
- });
89503
- } catch {}
89504
- }
89505
- if (ctx.deferredDeletions?.length && ctx.claudeDir) {
89506
- try {
89507
- const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
89508
- const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
89509
- if (pluginVerified) {
89510
- if (!migration.canDelete) {
89511
- logger.warning("Skill migration metadata unavailable — preserving existing skills (fail-safe)");
89512
- return { ...ctx, installSkills, pluginSupported };
89513
- }
89514
- const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir));
89515
- const safeDeletions = ctx.deferredDeletions.filter((d3) => {
89516
- const dirPath = extractSkillDirFromDeletionPath(d3);
89517
- if (!dirPath)
89518
- return true;
89519
- return !preservedDirs.has(normalizeSkillDir(dirPath));
89520
- });
89521
- if (safeDeletions.length > 0) {
89522
- const { handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
89523
- const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
89524
- if (deferredResult.deletedPaths.length > 0) {
89525
- logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) (replaced by plugin)`);
89526
- }
89527
- }
89528
- } else {
89529
- logger.info("Plugin not verified — keeping existing skills as fallback");
89530
- }
89531
- } catch (error) {
89532
- logger.debug(`Deferred skill deletion failed: ${error}`);
89533
- }
89534
- }
89535
88799
  if (!ctx.isNonInteractive) {
89536
88800
  const { isGeminiInstalled: isGeminiInstalled2 } = await Promise.resolve().then(() => (init_package_installer(), exports_package_installer));
89537
88801
  const { checkExistingGeminiConfig: checkExistingGeminiConfig2, findMcpConfigPath: findMcpConfigPath2, processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
@@ -89558,7 +88822,7 @@ async function handlePostInstall(ctx) {
89558
88822
  }
89559
88823
  if (!ctx.options.skipSetup) {
89560
88824
  await promptSetupWizardIfNeeded({
89561
- envPath: join101(ctx.claudeDir, ".env"),
88825
+ envPath: join100(ctx.claudeDir, ".env"),
89562
88826
  claudeDir: ctx.claudeDir,
89563
88827
  isGlobal: ctx.options.global,
89564
88828
  isNonInteractive: ctx.isNonInteractive,
@@ -89575,26 +88839,14 @@ async function handlePostInstall(ctx) {
89575
88839
  }
89576
88840
  return {
89577
88841
  ...ctx,
89578
- installSkills,
89579
- pluginSupported
88842
+ installSkills
89580
88843
  };
89581
88844
  }
89582
- function normalizeSkillDir(path14) {
89583
- return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
89584
- }
89585
- function extractSkillDirFromDeletionPath(path14) {
89586
- const normalized = normalizeSkillDir(path14);
89587
- const parts = normalized.split("/").filter(Boolean);
89588
- if (parts.length < 2 || parts[0] !== "skills") {
89589
- return null;
89590
- }
89591
- return `skills/${parts[1]}`;
89592
- }
89593
88845
  // src/commands/init/phases/selection-handler.ts
89594
88846
  init_config_manager();
89595
88847
  init_github_client();
89596
88848
  import { mkdir as mkdir30 } from "node:fs/promises";
89597
- import { join as join103, resolve as resolve21 } from "node:path";
88849
+ import { join as join102, resolve as resolve20 } from "node:path";
89598
88850
 
89599
88851
  // src/domains/github/kit-access-checker.ts
89600
88852
  init_logger();
@@ -89626,8 +88878,8 @@ async function detectAccessibleKits() {
89626
88878
  // src/domains/github/preflight-checker.ts
89627
88879
  init_logger();
89628
88880
  import { exec as exec8 } from "node:child_process";
89629
- import { promisify as promisify16 } from "node:util";
89630
- var execAsync8 = promisify16(exec8);
88881
+ import { promisify as promisify14 } from "node:util";
88882
+ var execAsync8 = promisify14(exec8);
89631
88883
  function createSuccessfulPreflightResult() {
89632
88884
  return {
89633
88885
  success: true,
@@ -89724,12 +88976,11 @@ async function runPreflightChecks() {
89724
88976
 
89725
88977
  // src/domains/installation/fresh-installer.ts
89726
88978
  init_metadata_migration();
89727
- init_manifest_reader();
88979
+ import { existsSync as existsSync50, readdirSync as readdirSync4, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4 } from "node:fs";
88980
+ import { dirname as dirname21, join as join101, resolve as resolve19 } from "node:path";
89728
88981
  init_logger();
89729
88982
  init_safe_spinner();
89730
- var import_fs_extra33 = __toESM(require_lib3(), 1);
89731
- import { existsSync as existsSync50, readdirSync as readdirSync4, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4 } from "node:fs";
89732
- import { dirname as dirname22, join as join102, resolve as resolve20 } from "node:path";
88983
+ var import_fs_extra31 = __toESM(require_lib3(), 1);
89733
88984
  var CLAUDEKIT_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
89734
88985
  async function analyzeFreshInstallation(claudeDir2) {
89735
88986
  const metadata = await readManifest(claudeDir2);
@@ -89774,15 +89025,15 @@ async function analyzeFreshInstallation(claudeDir2) {
89774
89025
  };
89775
89026
  }
89776
89027
  function cleanupEmptyDirectories2(filePath, claudeDir2) {
89777
- const normalizedClaudeDir = resolve20(claudeDir2);
89778
- let currentDir = resolve20(dirname22(filePath));
89028
+ const normalizedClaudeDir = resolve19(claudeDir2);
89029
+ let currentDir = resolve19(dirname21(filePath));
89779
89030
  while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
89780
89031
  try {
89781
89032
  const entries = readdirSync4(currentDir);
89782
89033
  if (entries.length === 0) {
89783
89034
  rmdirSync2(currentDir);
89784
89035
  logger.debug(`Removed empty directory: ${currentDir}`);
89785
- currentDir = resolve20(dirname22(currentDir));
89036
+ currentDir = resolve19(dirname21(currentDir));
89786
89037
  } else {
89787
89038
  break;
89788
89039
  }
@@ -89799,7 +89050,7 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
89799
89050
  const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
89800
89051
  const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
89801
89052
  for (const file of filesToRemove) {
89802
- const fullPath = join102(claudeDir2, file.path);
89053
+ const fullPath = join101(claudeDir2, file.path);
89803
89054
  try {
89804
89055
  if (existsSync50(fullPath)) {
89805
89056
  unlinkSync4(fullPath);
@@ -89824,13 +89075,13 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
89824
89075
  };
89825
89076
  }
89826
89077
  async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
89827
- const metadataPath = join102(claudeDir2, "metadata.json");
89828
- if (!await import_fs_extra33.pathExists(metadataPath)) {
89078
+ const metadataPath = join101(claudeDir2, "metadata.json");
89079
+ if (!await import_fs_extra31.pathExists(metadataPath)) {
89829
89080
  return;
89830
89081
  }
89831
89082
  let content;
89832
89083
  try {
89833
- content = await import_fs_extra33.readFile(metadataPath, "utf-8");
89084
+ content = await import_fs_extra31.readFile(metadataPath, "utf-8");
89834
89085
  } catch (readError) {
89835
89086
  logger.warning(`Failed to read metadata.json: ${readError instanceof Error ? readError.message : String(readError)}`);
89836
89087
  return;
@@ -89856,7 +89107,7 @@ async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
89856
89107
  metadata.files = metadata.files.filter((f3) => !removedSet.has(f3.path));
89857
89108
  }
89858
89109
  try {
89859
- await import_fs_extra33.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
89110
+ await import_fs_extra31.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
89860
89111
  logger.debug(`Updated metadata.json, removed ${removedFiles.length} file entries`);
89861
89112
  } catch (writeError) {
89862
89113
  logger.warning(`Failed to write metadata.json: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -89867,16 +89118,16 @@ async function removeSubdirectoriesFallback(claudeDir2) {
89867
89118
  const removedFiles = [];
89868
89119
  let removedDirCount = 0;
89869
89120
  for (const subdir of CLAUDEKIT_SUBDIRECTORIES) {
89870
- const subdirPath = join102(claudeDir2, subdir);
89871
- if (await import_fs_extra33.pathExists(subdirPath)) {
89121
+ const subdirPath = join101(claudeDir2, subdir);
89122
+ if (await import_fs_extra31.pathExists(subdirPath)) {
89872
89123
  rmSync3(subdirPath, { recursive: true, force: true });
89873
89124
  removedDirCount++;
89874
89125
  removedFiles.push(`${subdir}/ (entire directory)`);
89875
89126
  logger.debug(`Removed subdirectory: ${subdir}/`);
89876
89127
  }
89877
89128
  }
89878
- const metadataPath = join102(claudeDir2, "metadata.json");
89879
- if (await import_fs_extra33.pathExists(metadataPath)) {
89129
+ const metadataPath = join101(claudeDir2, "metadata.json");
89130
+ if (await import_fs_extra31.pathExists(metadataPath)) {
89880
89131
  unlinkSync4(metadataPath);
89881
89132
  removedFiles.push("metadata.json");
89882
89133
  }
@@ -89889,7 +89140,7 @@ async function removeSubdirectoriesFallback(claudeDir2) {
89889
89140
  };
89890
89141
  }
89891
89142
  async function handleFreshInstallation(claudeDir2, prompts) {
89892
- if (!await import_fs_extra33.pathExists(claudeDir2)) {
89143
+ if (!await import_fs_extra31.pathExists(claudeDir2)) {
89893
89144
  logger.info(".claude directory does not exist, proceeding with fresh installation");
89894
89145
  return true;
89895
89146
  }
@@ -89921,11 +89172,10 @@ async function handleFreshInstallation(claudeDir2, prompts) {
89921
89172
 
89922
89173
  // src/commands/init/phases/selection-handler.ts
89923
89174
  init_claudekit_scanner();
89924
- init_manifest_reader();
89925
89175
  init_logger();
89926
89176
  init_path_resolver();
89927
89177
  init_types3();
89928
- var import_fs_extra34 = __toESM(require_lib3(), 1);
89178
+ var import_fs_extra32 = __toESM(require_lib3(), 1);
89929
89179
 
89930
89180
  // src/commands/init/types.ts
89931
89181
  function isSyncContext(ctx) {
@@ -90094,7 +89344,7 @@ async function handleSelection(ctx) {
90094
89344
  }
90095
89345
  }
90096
89346
  }
90097
- const resolvedDir = resolve21(targetDir);
89347
+ const resolvedDir = resolve20(targetDir);
90098
89348
  logger.info(`Target directory: ${resolvedDir}`);
90099
89349
  if (!ctx.options.global && PathResolver.isLocalSameAsGlobal(resolvedDir)) {
90100
89350
  logger.warning("You're at HOME directory. Installing here modifies your GLOBAL ClaudeKit.");
@@ -90116,7 +89366,7 @@ async function handleSelection(ctx) {
90116
89366
  return { ...ctx, cancelled: true };
90117
89367
  }
90118
89368
  }
90119
- if (!await import_fs_extra34.pathExists(resolvedDir)) {
89369
+ if (!await import_fs_extra32.pathExists(resolvedDir)) {
90120
89370
  if (ctx.options.global) {
90121
89371
  await mkdir30(resolvedDir, { recursive: true });
90122
89372
  logger.info(`Created global directory: ${resolvedDir}`);
@@ -90128,7 +89378,7 @@ async function handleSelection(ctx) {
90128
89378
  }
90129
89379
  if (!ctx.options.fresh) {
90130
89380
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
90131
- const claudeDir2 = prefix ? join103(resolvedDir, prefix) : resolvedDir;
89381
+ const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
90132
89382
  try {
90133
89383
  const existingMetadata = await readManifest(claudeDir2);
90134
89384
  if (existingMetadata?.kits) {
@@ -90160,7 +89410,7 @@ async function handleSelection(ctx) {
90160
89410
  }
90161
89411
  if (ctx.options.fresh) {
90162
89412
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
90163
- const claudeDir2 = prefix ? join103(resolvedDir, prefix) : resolvedDir;
89413
+ const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
90164
89414
  const canProceed = await handleFreshInstallation(claudeDir2, ctx.prompts);
90165
89415
  if (!canProceed) {
90166
89416
  return { ...ctx, cancelled: true };
@@ -90179,7 +89429,7 @@ async function handleSelection(ctx) {
90179
89429
  logger.info("Fetching available versions...");
90180
89430
  let currentVersion = null;
90181
89431
  try {
90182
- const metadataPath = ctx.options.global ? join103(PathResolver.getGlobalKitDir(), "metadata.json") : join103(resolvedDir, ".claude", "metadata.json");
89432
+ const metadataPath = ctx.options.global ? join102(PathResolver.getGlobalKitDir(), "metadata.json") : join102(resolvedDir, ".claude", "metadata.json");
90183
89433
  const metadata = await readClaudeKitMetadata(metadataPath);
90184
89434
  currentVersion = metadata?.version || null;
90185
89435
  if (currentVersion) {
@@ -90253,27 +89503,25 @@ async function handleSelection(ctx) {
90253
89503
  };
90254
89504
  }
90255
89505
  // src/commands/init/phases/sync-handler.ts
90256
- import { copyFile as copyFile8, mkdir as mkdir31, open as open4, readFile as readFile49, rename as rename7, stat as stat17, unlink as unlink11, writeFile as writeFile30 } from "node:fs/promises";
90257
- import { dirname as dirname23, join as join104, resolve as resolve22 } from "node:path";
90258
- init_cc_version_checker();
90259
- init_manifest_reader();
89506
+ import { copyFile as copyFile8, mkdir as mkdir31, open as open4, readFile as readFile48, rename as rename6, stat as stat17, unlink as unlink11, writeFile as writeFile30 } from "node:fs/promises";
89507
+ import { dirname as dirname22, join as join103, resolve as resolve21 } from "node:path";
90260
89508
  init_logger();
90261
89509
  init_path_resolver();
90262
- var import_fs_extra35 = __toESM(require_lib3(), 1);
89510
+ var import_fs_extra33 = __toESM(require_lib3(), 1);
90263
89511
  var import_picocolors23 = __toESM(require_picocolors(), 1);
90264
89512
  async function handleSync(ctx) {
90265
89513
  if (!ctx.options.sync) {
90266
89514
  return ctx;
90267
89515
  }
90268
- const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() : resolve22(ctx.options.dir || ".");
90269
- const claudeDir2 = ctx.options.global ? resolvedDir : join104(resolvedDir, ".claude");
90270
- if (!await import_fs_extra35.pathExists(claudeDir2)) {
89516
+ const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() : resolve21(ctx.options.dir || ".");
89517
+ const claudeDir2 = ctx.options.global ? resolvedDir : join103(resolvedDir, ".claude");
89518
+ if (!await import_fs_extra33.pathExists(claudeDir2)) {
90271
89519
  logger.error("Cannot sync: no .claude directory found");
90272
89520
  ctx.prompts.note("Run 'ck init' without --sync to install first.", "No Installation Found");
90273
89521
  return { ...ctx, cancelled: true };
90274
89522
  }
90275
- const metadataPath = join104(claudeDir2, "metadata.json");
90276
- if (!await import_fs_extra35.pathExists(metadataPath)) {
89523
+ const metadataPath = join103(claudeDir2, "metadata.json");
89524
+ if (!await import_fs_extra33.pathExists(metadataPath)) {
90277
89525
  logger.error("Cannot sync: no metadata.json found");
90278
89526
  ctx.prompts.note(`Your installation may be from an older version.
90279
89527
  Run 'ck init' to update.`, "Legacy Installation");
@@ -90370,42 +89618,17 @@ function getLockTimeout() {
90370
89618
  return timeoutMs;
90371
89619
  }
90372
89620
  var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
90373
- function isProcessAlive(pid) {
90374
- try {
90375
- process.kill(pid, 0);
90376
- return true;
90377
- } catch (error) {
90378
- const code2 = error.code;
90379
- return code2 === "EPERM";
90380
- }
90381
- }
90382
- async function readLockPayload(lockPath) {
90383
- try {
90384
- const raw2 = await readFile49(lockPath, "utf-8");
90385
- const parsed = JSON.parse(raw2);
90386
- if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0) {
90387
- return {
90388
- pid: parsed.pid,
90389
- startedAt: typeof parsed.startedAt === "string" && parsed.startedAt.length > 0 ? parsed.startedAt : "unknown"
90390
- };
90391
- }
90392
- } catch {}
90393
- return null;
90394
- }
90395
89621
  async function acquireSyncLock(global3) {
90396
89622
  const cacheDir = PathResolver.getCacheDir(global3);
90397
- const lockPath = join104(cacheDir, ".sync-lock");
89623
+ const lockPath = join103(cacheDir, ".sync-lock");
90398
89624
  const startTime = Date.now();
90399
89625
  const lockTimeout = getLockTimeout();
90400
- await mkdir31(dirname23(lockPath), { recursive: true });
89626
+ await mkdir31(dirname22(lockPath), { recursive: true });
90401
89627
  while (Date.now() - startTime < lockTimeout) {
90402
89628
  try {
90403
89629
  const handle = await open4(lockPath, "wx");
90404
- await handle.writeFile(JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }), "utf-8");
90405
89630
  return async () => {
90406
- try {
90407
- await handle.close();
90408
- } catch {}
89631
+ await handle.close();
90409
89632
  await unlink11(lockPath).catch(() => {});
90410
89633
  };
90411
89634
  } catch (err) {
@@ -90413,29 +89636,18 @@ async function acquireSyncLock(global3) {
90413
89636
  try {
90414
89637
  const lockStat = await stat17(lockPath);
90415
89638
  const lockAge = Math.abs(Date.now() - lockStat.mtimeMs);
90416
- const lockOwner = await readLockPayload(lockPath);
90417
- if (lockOwner?.pid === process.pid) {
90418
- throw new Error("Sync lock is already held by current process");
90419
- }
90420
- const ownerAlive = lockOwner?.pid ? isProcessAlive(lockOwner.pid) : null;
90421
- if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive !== true) {
90422
- logger.warning(`Removing stale sync lock (age: ${Math.round(lockAge / 1000)}s${lockOwner?.pid ? `, pid=${lockOwner.pid}` : ""})`);
89639
+ if (lockAge > STALE_LOCK_THRESHOLD_MS) {
89640
+ logger.warning(`Removing stale sync lock (age: ${Math.round(lockAge / 1000)}s)`);
90423
89641
  await unlink11(lockPath).catch(() => {});
90424
89642
  continue;
90425
89643
  }
90426
- if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive === true) {
90427
- logger.debug(`Sync lock older than threshold but owner pid=${lockOwner?.pid} still alive; waiting`);
90428
- }
90429
89644
  } catch (statError) {
90430
- if (statError instanceof Error && statError.message.includes("already held by current process")) {
90431
- throw statError;
90432
- }
90433
89645
  if (statError.code === "ENOENT") {
90434
89646
  continue;
90435
89647
  }
90436
89648
  logger.debug(`Lock stat failed: ${statError}`);
90437
89649
  }
90438
- await new Promise((resolve23) => setTimeout(resolve23, 100));
89650
+ await new Promise((resolve22) => setTimeout(resolve22, 100));
90439
89651
  continue;
90440
89652
  }
90441
89653
  throw err;
@@ -90454,20 +89666,18 @@ async function executeSyncMerge(ctx) {
90454
89666
  const releaseLock = await acquireSyncLock(ctx.options.global);
90455
89667
  try {
90456
89668
  const trackedFiles = ctx.syncTrackedFiles;
90457
- const upstreamDir = ctx.options.global ? join104(ctx.extractDir, ".claude") : ctx.extractDir;
89669
+ const upstreamDir = ctx.options.global ? join103(ctx.extractDir, ".claude") : ctx.extractDir;
90458
89670
  let deletions = [];
90459
89671
  try {
90460
- const sourceMetadataPath = join104(upstreamDir, "metadata.json");
90461
- if (await import_fs_extra35.pathExists(sourceMetadataPath)) {
90462
- const content = await readFile49(sourceMetadataPath, "utf-8");
89672
+ const sourceMetadataPath = join103(upstreamDir, "metadata.json");
89673
+ if (await import_fs_extra33.pathExists(sourceMetadataPath)) {
89674
+ const content = await readFile48(sourceMetadataPath, "utf-8");
90463
89675
  const sourceMetadata = JSON.parse(content);
90464
89676
  deletions = sourceMetadata.deletions || [];
90465
89677
  }
90466
89678
  } catch (error) {
90467
89679
  logger.debug(`Failed to load source metadata for deletion filtering: ${error}`);
90468
89680
  }
90469
- const { categorizeDeletions: categorizeDeletions2, handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
90470
- const categorizedDeletions = categorizeDeletions2(deletions);
90471
89681
  const filteredTrackedFiles = filterDeletionPaths(trackedFiles, deletions);
90472
89682
  if (deletions.length > 0) {
90473
89683
  const filtered = trackedFiles.length - filteredTrackedFiles.length;
@@ -90475,44 +89685,23 @@ async function executeSyncMerge(ctx) {
90475
89685
  }
90476
89686
  logger.info("Analyzing file changes...");
90477
89687
  const plan = await SyncEngine.createSyncPlan(filteredTrackedFiles, ctx.claudeDir, upstreamDir);
90478
- const forceOverwriteNonInteractive = ctx.isNonInteractive && ctx.options.forceOverwrite;
90479
- const autoUpdateQueue = forceOverwriteNonInteractive ? dedupeTrackedFiles([...plan.autoUpdate, ...plan.needsReview]) : plan.autoUpdate;
90480
- const reviewQueue = forceOverwriteNonInteractive ? [] : plan.needsReview;
90481
89688
  displaySyncPlan(plan);
90482
- if (autoUpdateQueue.length === 0 && reviewQueue.length === 0 && categorizedDeletions.immediate.length === 0 && categorizedDeletions.deferred.length === 0) {
89689
+ if (plan.autoUpdate.length === 0 && plan.needsReview.length === 0) {
90483
89690
  ctx.prompts.note("All files are up to date or user-owned.", "No Changes Needed");
90484
- }
90485
- if (reviewQueue.length > 0 && ctx.isNonInteractive) {
90486
- logger.error(`Cannot complete sync: ${reviewQueue.length} file(s) require interactive review`);
90487
- ctx.prompts.note(`The following files have local modifications:
90488
- ${reviewQueue.slice(0, 5).map((f3) => ` • ${f3.path}`).join(`
90489
- `)}${reviewQueue.length > 5 ? `
90490
- ... and ${reviewQueue.length - 5} more` : ""}
90491
-
90492
- Options:
90493
- 1. Run 'ck init --sync' without --yes for interactive merge
90494
- 2. Use --force-overwrite to accept all upstream changes
90495
- 3. Manually resolve conflicts before syncing`, "Sync Blocked");
90496
89691
  return { ...ctx, cancelled: true };
90497
89692
  }
90498
- if (forceOverwriteNonInteractive && plan.needsReview.length > 0) {
90499
- logger.info(`--force-overwrite enabled: auto-updating ${plan.needsReview.length} locally modified file(s)`);
90500
- }
90501
- const willModifyFiles = autoUpdateQueue.length > 0 || reviewQueue.length > 0 || categorizedDeletions.immediate.length > 0 || categorizedDeletions.deferred.length > 0;
90502
- if (willModifyFiles) {
90503
- const backupDir = PathResolver.getBackupDir();
90504
- await createBackup(ctx.claudeDir, trackedFiles, backupDir);
90505
- logger.success(`Backup created at ${import_picocolors23.default.dim(backupDir)}`);
90506
- }
90507
- if (autoUpdateQueue.length > 0) {
90508
- logger.info(`Auto-updating ${autoUpdateQueue.length} file(s)...`);
89693
+ const backupDir = PathResolver.getBackupDir();
89694
+ await createBackup(ctx.claudeDir, trackedFiles, backupDir);
89695
+ logger.success(`Backup created at ${import_picocolors23.default.dim(backupDir)}`);
89696
+ if (plan.autoUpdate.length > 0) {
89697
+ logger.info(`Auto-updating ${plan.autoUpdate.length} file(s)...`);
90509
89698
  let updateSuccess = 0;
90510
89699
  let updateFailed = 0;
90511
- for (const file of autoUpdateQueue) {
89700
+ for (const file of plan.autoUpdate) {
90512
89701
  try {
90513
89702
  const sourcePath = await validateSyncPath(upstreamDir, file.path);
90514
89703
  const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
90515
- const targetDir = dirname23(targetPath);
89704
+ const targetDir = join103(targetPath, "..");
90516
89705
  try {
90517
89706
  await mkdir31(targetDir, { recursive: true });
90518
89707
  } catch (mkdirError) {
@@ -90522,7 +89711,7 @@ Options:
90522
89711
  ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
90523
89712
  return { ...ctx, cancelled: true };
90524
89713
  }
90525
- if (errCode === "EROFS" || errCode === "EACCES" || errCode === "EPERM") {
89714
+ if (errCode === "EROFS" || errCode === "EACCES") {
90526
89715
  logger.warning(`Cannot create directory ${file.path}: ${errCode}`);
90527
89716
  updateFailed++;
90528
89717
  continue;
@@ -90540,7 +89729,7 @@ Options:
90540
89729
  ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
90541
89730
  return { ...ctx, cancelled: true };
90542
89731
  }
90543
- if (errCode === "EACCES" || errCode === "EPERM" || errCode === "EROFS") {
89732
+ if (errCode === "EACCES" || errCode === "EPERM") {
90544
89733
  logger.warning(`Permission denied: ${file.path} - check file permissions`);
90545
89734
  updateFailed++;
90546
89735
  } else if (errMsg.includes("Symlink") || errMsg.includes("Path")) {
@@ -90555,22 +89744,19 @@ Options:
90555
89744
  if (updateSuccess > 0) {
90556
89745
  logger.success(`Auto-updated ${updateSuccess} file(s)${updateFailed > 0 ? ` (${updateFailed} failed)` : ""}`);
90557
89746
  }
90558
- if (updateSuccess === 0 && updateFailed > 0) {
90559
- logger.warning("No files were updated due to write errors");
90560
- }
90561
89747
  }
90562
- if (reviewQueue.length > 0 && !ctx.isNonInteractive) {
90563
- logger.info(`${reviewQueue.length} file(s) need interactive review...`);
89748
+ if (plan.needsReview.length > 0 && !ctx.isNonInteractive) {
89749
+ logger.info(`${plan.needsReview.length} file(s) need interactive review...`);
90564
89750
  let totalApplied = 0;
90565
89751
  let totalRejected = 0;
90566
89752
  let skippedFiles = 0;
90567
- for (const file of reviewQueue) {
89753
+ for (const file of plan.needsReview) {
90568
89754
  let currentPath;
90569
89755
  let upstreamPath;
90570
89756
  try {
90571
89757
  currentPath = await validateSyncPath(ctx.claudeDir, file.path);
90572
89758
  upstreamPath = await validateSyncPath(upstreamDir, file.path);
90573
- } catch {
89759
+ } catch (error) {
90574
89760
  logger.warning(`Skipping invalid path during review: ${file.path}`);
90575
89761
  skippedFiles++;
90576
89762
  continue;
@@ -90597,7 +89783,7 @@ Options:
90597
89783
  const tempPath = `${currentPath}.tmp.${Date.now()}`;
90598
89784
  try {
90599
89785
  await writeFile30(tempPath, result.result, "utf-8");
90600
- await rename7(tempPath, currentPath);
89786
+ await rename6(tempPath, currentPath);
90601
89787
  } catch (atomicError) {
90602
89788
  await unlink11(tempPath).catch(() => {});
90603
89789
  throw atomicError;
@@ -90618,8 +89804,8 @@ Options:
90618
89804
  console.log("");
90619
89805
  console.log(import_picocolors23.default.bold("Sync Summary:"));
90620
89806
  console.log(import_picocolors23.default.dim("─".repeat(40)));
90621
- if (autoUpdateQueue.length > 0) {
90622
- console.log(import_picocolors23.default.green(` ✓ ${autoUpdateQueue.length} file(s) auto-updated`));
89807
+ if (plan.autoUpdate.length > 0) {
89808
+ console.log(import_picocolors23.default.green(` ✓ ${plan.autoUpdate.length} file(s) auto-updated`));
90623
89809
  }
90624
89810
  if (totalApplied > 0) {
90625
89811
  console.log(import_picocolors23.default.green(` ✓ ${totalApplied} hunk(s) applied`));
@@ -90633,96 +89819,23 @@ Options:
90633
89819
  if (plan.skipped.length > 0) {
90634
89820
  console.log(import_picocolors23.default.dim(` ─ ${plan.skipped.length} user-owned file(s) unchanged`));
90635
89821
  }
90636
- }
90637
- if (categorizedDeletions.immediate.length > 0) {
90638
- try {
90639
- const deletionResult = await handleDeletions2({ deletions: categorizedDeletions.immediate }, ctx.claudeDir);
90640
- if (deletionResult.deletedPaths.length > 0) {
90641
- logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
90642
- }
90643
- if (deletionResult.preservedPaths.length > 0) {
90644
- logger.verbose(`Preserved ${deletionResult.preservedPaths.length} user-owned file(s)`);
90645
- }
90646
- } catch (error) {
90647
- logger.debug(`Immediate deletion cleanup failed during sync: ${error}`);
90648
- }
90649
- }
90650
- let pluginSupported = false;
90651
- let pluginVerified = false;
90652
- try {
90653
- const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
90654
- await requireCCPluginSupport2();
90655
- pluginSupported = true;
90656
- } catch (error) {
90657
- if (error instanceof CCPluginSupportError) {
90658
- logger.info(`Plugin install skipped during sync: ${error.message}`);
90659
- if (error.code === "cc_version_too_old") {
90660
- logger.info("Upgrade Claude Code, then re-run: ck init --sync (plugin migration requires >= 1.0.33)");
90661
- }
90662
- if (error.code === "cc_not_found") {
90663
- logger.info("Install Claude Code CLI to enable /ck:* plugin skills");
90664
- }
90665
- } else {
90666
- logger.debug(`Plugin version check failed during sync: ${error instanceof Error ? error.message : "Unknown error"}`);
90667
- }
90668
- }
90669
- if (pluginSupported && ctx.extractDir) {
90670
- try {
90671
- const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
90672
- const pluginResult = await handlePluginInstall2(ctx.extractDir);
90673
- pluginVerified = pluginResult.verified;
90674
- if (pluginResult.error) {
90675
- logger.debug(`Plugin install issue: ${pluginResult.error}`);
90676
- }
90677
- } catch (error) {
90678
- logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
90679
- }
90680
- }
90681
- if (ctx.claudeDir && ctx.kitType) {
90682
- try {
90683
- const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
90684
- await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
90685
- pluginInstalled: pluginVerified,
90686
- pluginInstalledAt: new Date().toISOString(),
90687
- pluginVersion: ctx.selectedVersion || ctx.syncLatestVersion || "unknown"
90688
- });
90689
- } catch {}
90690
- }
90691
- if (categorizedDeletions.deferred.length > 0) {
90692
- if (pluginVerified) {
90693
- try {
90694
- const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
90695
- const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
90696
- if (!migration.canDelete) {
90697
- logger.warning("Skill migration metadata unavailable during sync — preserving existing skills");
90698
- } else {
90699
- const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir2));
90700
- const safeDeletions = categorizedDeletions.deferred.filter((path14) => {
90701
- const skillDir = extractSkillDirFromDeletionPath2(path14);
90702
- return !skillDir || !preservedDirs.has(normalizeSkillDir2(skillDir));
90703
- });
90704
- if (safeDeletions.length > 0) {
90705
- const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
90706
- if (deferredResult.deletedPaths.length > 0) {
90707
- logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) during sync`);
90708
- }
90709
- }
90710
- }
90711
- } catch (error) {
90712
- logger.debug(`Deferred skill cleanup failed during sync: ${error}`);
90713
- }
90714
- } else {
90715
- logger.info("Plugin not verified during sync — keeping existing skills as fallback");
90716
- }
89822
+ } else if (plan.needsReview.length > 0 && ctx.isNonInteractive) {
89823
+ logger.error(`Cannot complete sync: ${plan.needsReview.length} file(s) require interactive review`);
89824
+ ctx.prompts.note(`The following files have local modifications:
89825
+ ${plan.needsReview.slice(0, 5).map((f3) => ` • ${f3.path}`).join(`
89826
+ `)}${plan.needsReview.length > 5 ? `
89827
+ ... and ${plan.needsReview.length - 5} more` : ""}
89828
+
89829
+ Options:
89830
+ 1. Run 'ck init --sync' without --yes for interactive merge
89831
+ 2. Use --force-overwrite to accept all upstream changes
89832
+ 3. Manually resolve conflicts before syncing`, "Sync Blocked");
89833
+ return { ...ctx, cancelled: true };
90717
89834
  }
90718
89835
  ctx.prompts.outro("Config sync completed successfully");
90719
89836
  return { ...ctx, cancelled: true };
90720
89837
  } finally {
90721
- try {
90722
- await releaseLock();
90723
- } catch (error) {
90724
- logger.debug(`Failed to release sync lock: ${error}`);
90725
- }
89838
+ await releaseLock();
90726
89839
  }
90727
89840
  }
90728
89841
  function displaySyncPlan(plan) {
@@ -90757,9 +89870,9 @@ async function createBackup(claudeDir2, files, backupDir) {
90757
89870
  for (const file of files) {
90758
89871
  try {
90759
89872
  const sourcePath = await validateSyncPath(claudeDir2, file.path);
90760
- if (await import_fs_extra35.pathExists(sourcePath)) {
89873
+ if (await import_fs_extra33.pathExists(sourcePath)) {
90761
89874
  const targetPath = await validateSyncPath(backupDir, file.path);
90762
- const targetDir = dirname23(targetPath);
89875
+ const targetDir = join103(targetPath, "..");
90763
89876
  await mkdir31(targetDir, { recursive: true });
90764
89877
  await copyFile8(sourcePath, targetPath);
90765
89878
  }
@@ -90772,27 +89885,9 @@ async function createBackup(claudeDir2, files, backupDir) {
90772
89885
  }
90773
89886
  }
90774
89887
  }
90775
- function dedupeTrackedFiles(files) {
90776
- const deduped = new Map;
90777
- for (const file of files) {
90778
- deduped.set(file.path, file);
90779
- }
90780
- return [...deduped.values()];
90781
- }
90782
- function normalizeSkillDir2(path14) {
90783
- return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
90784
- }
90785
- function extractSkillDirFromDeletionPath2(path14) {
90786
- const normalized = normalizeSkillDir2(path14);
90787
- const parts = normalized.split("/").filter(Boolean);
90788
- if (parts.length < 2 || parts[0] !== "skills") {
90789
- return null;
90790
- }
90791
- return `skills/${parts[1]}`;
90792
- }
90793
89888
  // src/commands/init/phases/transform-handler.ts
90794
89889
  init_config_manager();
90795
- import { join as join108 } from "node:path";
89890
+ import { join as join107 } from "node:path";
90796
89891
 
90797
89892
  // src/services/transformers/folder-path-transformer.ts
90798
89893
  init_logger();
@@ -90801,40 +89896,40 @@ init_types3();
90801
89896
  // src/services/transformers/folder-transform/folder-renamer.ts
90802
89897
  init_logger();
90803
89898
  init_types3();
90804
- var import_fs_extra36 = __toESM(require_lib3(), 1);
90805
- import { rename as rename8, rm as rm13 } from "node:fs/promises";
90806
- import { join as join105, relative as relative18 } from "node:path";
89899
+ var import_fs_extra34 = __toESM(require_lib3(), 1);
89900
+ import { rename as rename7, rm as rm13 } from "node:fs/promises";
89901
+ import { join as join104, relative as relative18 } from "node:path";
90807
89902
  async function collectDirsToRename(extractDir, folders) {
90808
89903
  const dirsToRename = [];
90809
89904
  if (folders.docs !== DEFAULT_FOLDERS.docs) {
90810
- const docsPath = join105(extractDir, DEFAULT_FOLDERS.docs);
90811
- if (await import_fs_extra36.pathExists(docsPath)) {
89905
+ const docsPath = join104(extractDir, DEFAULT_FOLDERS.docs);
89906
+ if (await import_fs_extra34.pathExists(docsPath)) {
90812
89907
  dirsToRename.push({
90813
89908
  from: docsPath,
90814
- to: join105(extractDir, folders.docs)
89909
+ to: join104(extractDir, folders.docs)
90815
89910
  });
90816
89911
  }
90817
- const claudeDocsPath = join105(extractDir, ".claude", DEFAULT_FOLDERS.docs);
90818
- if (await import_fs_extra36.pathExists(claudeDocsPath)) {
89912
+ const claudeDocsPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.docs);
89913
+ if (await import_fs_extra34.pathExists(claudeDocsPath)) {
90819
89914
  dirsToRename.push({
90820
89915
  from: claudeDocsPath,
90821
- to: join105(extractDir, ".claude", folders.docs)
89916
+ to: join104(extractDir, ".claude", folders.docs)
90822
89917
  });
90823
89918
  }
90824
89919
  }
90825
89920
  if (folders.plans !== DEFAULT_FOLDERS.plans) {
90826
- const plansPath = join105(extractDir, DEFAULT_FOLDERS.plans);
90827
- if (await import_fs_extra36.pathExists(plansPath)) {
89921
+ const plansPath = join104(extractDir, DEFAULT_FOLDERS.plans);
89922
+ if (await import_fs_extra34.pathExists(plansPath)) {
90828
89923
  dirsToRename.push({
90829
89924
  from: plansPath,
90830
- to: join105(extractDir, folders.plans)
89925
+ to: join104(extractDir, folders.plans)
90831
89926
  });
90832
89927
  }
90833
- const claudePlansPath = join105(extractDir, ".claude", DEFAULT_FOLDERS.plans);
90834
- if (await import_fs_extra36.pathExists(claudePlansPath)) {
89928
+ const claudePlansPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.plans);
89929
+ if (await import_fs_extra34.pathExists(claudePlansPath)) {
90835
89930
  dirsToRename.push({
90836
89931
  from: claudePlansPath,
90837
- to: join105(extractDir, ".claude", folders.plans)
89932
+ to: join104(extractDir, ".claude", folders.plans)
90838
89933
  });
90839
89934
  }
90840
89935
  }
@@ -90842,11 +89937,11 @@ async function collectDirsToRename(extractDir, folders) {
90842
89937
  }
90843
89938
  async function moveAcrossDevices(src, dest) {
90844
89939
  try {
90845
- await rename8(src, dest);
89940
+ await rename7(src, dest);
90846
89941
  } catch (e2) {
90847
89942
  if (e2.code === "EXDEV") {
90848
89943
  logger.debug(`Cross-device move detected, using copy+delete: ${src} -> ${dest}`);
90849
- await import_fs_extra36.copy(src, dest, { overwrite: true });
89944
+ await import_fs_extra34.copy(src, dest, { overwrite: true });
90850
89945
  await rm13(src, { recursive: true, force: true });
90851
89946
  } else {
90852
89947
  throw e2;
@@ -90874,8 +89969,8 @@ async function renameFolders(dirsToRename, extractDir, options2) {
90874
89969
  // src/services/transformers/folder-transform/path-replacer.ts
90875
89970
  init_logger();
90876
89971
  init_types3();
90877
- import { readFile as readFile50, readdir as readdir32, writeFile as writeFile31 } from "node:fs/promises";
90878
- import { join as join106, relative as relative19 } from "node:path";
89972
+ import { readFile as readFile49, readdir as readdir32, writeFile as writeFile31 } from "node:fs/promises";
89973
+ import { join as join105, relative as relative19 } from "node:path";
90879
89974
  var TRANSFORMABLE_FILE_PATTERNS = [
90880
89975
  ".md",
90881
89976
  ".txt",
@@ -90928,7 +90023,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
90928
90023
  let replacementsCount = 0;
90929
90024
  const entries = await readdir32(dir, { withFileTypes: true });
90930
90025
  for (const entry of entries) {
90931
- const fullPath = join106(dir, entry.name);
90026
+ const fullPath = join105(dir, entry.name);
90932
90027
  if (entry.isDirectory()) {
90933
90028
  if (entry.name === "node_modules" || entry.name === ".git") {
90934
90029
  continue;
@@ -90941,7 +90036,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
90941
90036
  if (!shouldTransform)
90942
90037
  continue;
90943
90038
  try {
90944
- const content = await readFile50(fullPath, "utf-8");
90039
+ const content = await readFile49(fullPath, "utf-8");
90945
90040
  let newContent = content;
90946
90041
  let changeCount = 0;
90947
90042
  for (const { regex: regex2, replacement } of compiledReplacements) {
@@ -91063,9 +90158,9 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
91063
90158
 
91064
90159
  // src/services/transformers/global-path-transformer.ts
91065
90160
  init_logger();
91066
- import { readFile as readFile51, readdir as readdir33, writeFile as writeFile32 } from "node:fs/promises";
90161
+ import { readFile as readFile50, readdir as readdir33, writeFile as writeFile32 } from "node:fs/promises";
91067
90162
  import { platform as platform13 } from "node:os";
91068
- import { extname as extname6, join as join107 } from "node:path";
90163
+ import { extname as extname6, join as join106 } from "node:path";
91069
90164
  var IS_WINDOWS3 = platform13() === "win32";
91070
90165
  var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
91071
90166
  function getHomeDirPrefix() {
@@ -91175,7 +90270,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
91175
90270
  async function processDirectory2(dir) {
91176
90271
  const entries = await readdir33(dir, { withFileTypes: true });
91177
90272
  for (const entry of entries) {
91178
- const fullPath = join107(dir, entry.name);
90273
+ const fullPath = join106(dir, entry.name);
91179
90274
  if (entry.isDirectory()) {
91180
90275
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
91181
90276
  continue;
@@ -91183,7 +90278,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
91183
90278
  await processDirectory2(fullPath);
91184
90279
  } else if (entry.isFile() && shouldTransformFile3(entry.name)) {
91185
90280
  try {
91186
- const content = await readFile51(fullPath, "utf-8");
90281
+ const content = await readFile50(fullPath, "utf-8");
91187
90282
  const { transformed, changes } = transformContent(content);
91188
90283
  if (changes > 0) {
91189
90284
  await writeFile32(fullPath, transformed, "utf-8");
@@ -91251,7 +90346,7 @@ async function handleTransforms(ctx) {
91251
90346
  logger.debug(ctx.options.global ? "Saved folder configuration to ~/.claude/.ck.json" : "Saved folder configuration to .claude/.ck.json");
91252
90347
  }
91253
90348
  }
91254
- const claudeDir2 = ctx.options.global ? ctx.resolvedDir : join108(ctx.resolvedDir, ".claude");
90349
+ const claudeDir2 = ctx.options.global ? ctx.resolvedDir : join107(ctx.resolvedDir, ".claude");
91255
90350
  return {
91256
90351
  ...ctx,
91257
90352
  foldersConfig,
@@ -91445,8 +90540,8 @@ init_checksum_utils();
91445
90540
  init_config_discovery();
91446
90541
  var import_picocolors25 = __toESM(require_picocolors(), 1);
91447
90542
  import { existsSync as existsSync51 } from "node:fs";
91448
- import { readFile as readFile52, rm as rm14, unlink as unlink12 } from "node:fs/promises";
91449
- import { resolve as resolve23 } from "node:path";
90543
+ import { readFile as readFile51, rm as rm14, unlink as unlink12 } from "node:fs/promises";
90544
+ import { resolve as resolve22 } from "node:path";
91450
90545
 
91451
90546
  // src/commands/portable/conflict-resolver.ts
91452
90547
  init_dist2();
@@ -91793,7 +90888,7 @@ function shouldExecuteAction2(action) {
91793
90888
  }
91794
90889
  async function executeDeleteAction(action, options2) {
91795
90890
  const preservePaths = options2?.preservePaths ?? new Set;
91796
- const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(resolve23(action.targetPath));
90891
+ const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(resolve22(action.targetPath));
91797
90892
  try {
91798
90893
  if (!shouldPreserveTarget && action.targetPath && existsSync51(action.targetPath)) {
91799
90894
  await rm14(action.targetPath, { recursive: true, force: true });
@@ -92018,7 +91113,7 @@ async function migrateCommand(options2) {
92018
91113
  for (const action of conflictActions) {
92019
91114
  if (!action.diff && action.targetPath && existsSync51(action.targetPath)) {
92020
91115
  try {
92021
- const targetContent = await readFile52(action.targetPath, "utf-8");
91116
+ const targetContent = await readFile51(action.targetPath, "utf-8");
92022
91117
  const sourceItem = agents2.find((a3) => a3.name === action.item) || commands.find((c2) => c2.name === action.item) || (configItem?.name === action.item ? configItem : null) || ruleItems.find((r2) => r2.name === action.item);
92023
91118
  if (sourceItem) {
92024
91119
  const providerConfig = providers[action.provider];
@@ -92109,7 +91204,7 @@ async function migrateCommand(options2) {
92109
91204
  allResults.push(...await installSkillDirectories(skills, skillProviders, installOpts));
92110
91205
  }
92111
91206
  }
92112
- const writtenPaths = new Set(allResults.filter((result) => result.success && !result.skipped && result.path.length > 0).map((result) => resolve23(result.path)));
91207
+ const writtenPaths = new Set(allResults.filter((result) => result.success && !result.skipped && result.path.length > 0).map((result) => resolve22(result.path)));
92113
91208
  for (const deleteAction of plannedDeleteActions) {
92114
91209
  allResults.push(await executeDeleteAction(deleteAction, {
92115
91210
  preservePaths: writtenPaths
@@ -92225,7 +91320,7 @@ async function computeTargetStates(selectedProviders, global3) {
92225
91320
  exists: true
92226
91321
  };
92227
91322
  try {
92228
- const content = await readFile52(entry.path, "utf-8");
91323
+ const content = await readFile51(entry.path, "utf-8");
92229
91324
  state.currentChecksum = computeContentChecksum(content);
92230
91325
  } catch (error) {
92231
91326
  logger.debug(`[migrate] Failed to read target for checksum: ${entry.path} (${String(error)})`);
@@ -92284,11 +91379,11 @@ var import_picocolors26 = __toESM(require_picocolors(), 1);
92284
91379
 
92285
91380
  // src/commands/new/phases/directory-setup.ts
92286
91381
  init_config_manager();
92287
- import { resolve as resolve24 } from "node:path";
91382
+ import { resolve as resolve23 } from "node:path";
92288
91383
  init_logger();
92289
91384
  init_path_resolver();
92290
91385
  init_types3();
92291
- var import_fs_extra37 = __toESM(require_lib3(), 1);
91386
+ var import_fs_extra35 = __toESM(require_lib3(), 1);
92292
91387
  async function directorySetup(validOptions, prompts) {
92293
91388
  const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
92294
91389
  const config = await ConfigManager.get();
@@ -92369,7 +91464,7 @@ async function directorySetup(validOptions, prompts) {
92369
91464
  targetDir = await prompts.getDirectory(targetDir);
92370
91465
  }
92371
91466
  }
92372
- const resolvedDir = resolve24(targetDir);
91467
+ const resolvedDir = resolve23(targetDir);
92373
91468
  logger.info(`Target directory: ${resolvedDir}`);
92374
91469
  if (PathResolver.isLocalSameAsGlobal(resolvedDir)) {
92375
91470
  logger.warning("You're creating a project at HOME directory.");
@@ -92387,8 +91482,8 @@ async function directorySetup(validOptions, prompts) {
92387
91482
  return null;
92388
91483
  }
92389
91484
  }
92390
- if (await import_fs_extra37.pathExists(resolvedDir)) {
92391
- const files = await import_fs_extra37.readdir(resolvedDir);
91485
+ if (await import_fs_extra35.pathExists(resolvedDir)) {
91486
+ const files = await import_fs_extra35.readdir(resolvedDir);
92392
91487
  const isEmpty = files.length === 0;
92393
91488
  if (!isEmpty) {
92394
91489
  if (isNonInteractive2) {
@@ -92426,7 +91521,7 @@ async function handleDirectorySetup(ctx) {
92426
91521
  // src/commands/new/phases/project-creation.ts
92427
91522
  init_config_manager();
92428
91523
  init_github_client();
92429
- import { join as join109 } from "node:path";
91524
+ import { join as join108 } from "node:path";
92430
91525
  init_logger();
92431
91526
  init_output_manager();
92432
91527
  init_types3();
@@ -92552,7 +91647,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
92552
91647
  output.section("Installing");
92553
91648
  logger.verbose("Installation target", { directory: resolvedDir });
92554
91649
  const merger = new FileMerger;
92555
- const claudeDir2 = join109(resolvedDir, ".claude");
91650
+ const claudeDir2 = join108(resolvedDir, ".claude");
92556
91651
  merger.setMultiKitContext(claudeDir2, kit);
92557
91652
  if (validOptions.exclude && validOptions.exclude.length > 0) {
92558
91653
  merger.addIgnorePatterns(validOptions.exclude);
@@ -92599,7 +91694,7 @@ async function handleProjectCreation(ctx) {
92599
91694
  }
92600
91695
  // src/commands/new/phases/post-setup.ts
92601
91696
  init_projects_registry();
92602
- import { join as join110 } from "node:path";
91697
+ import { join as join109 } from "node:path";
92603
91698
  init_package_installer();
92604
91699
  init_logger();
92605
91700
  init_path_resolver();
@@ -92631,9 +91726,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
92631
91726
  withSudo: validOptions.withSudo
92632
91727
  });
92633
91728
  }
92634
- const claudeDir2 = join110(resolvedDir, ".claude");
91729
+ const claudeDir2 = join109(resolvedDir, ".claude");
92635
91730
  await promptSetupWizardIfNeeded({
92636
- envPath: join110(claudeDir2, ".env"),
91731
+ envPath: join109(claudeDir2, ".env"),
92637
91732
  claudeDir: claudeDir2,
92638
91733
  isGlobal: false,
92639
91734
  isNonInteractive: isNonInteractive2,
@@ -92706,11 +91801,11 @@ init_logger();
92706
91801
  init_safe_prompts();
92707
91802
  var import_picocolors27 = __toESM(require_picocolors(), 1);
92708
91803
  import { existsSync as existsSync52 } from "node:fs";
92709
- import { resolve as resolve25 } from "node:path";
91804
+ import { resolve as resolve24 } from "node:path";
92710
91805
  async function handleAdd(projectPath, options2) {
92711
91806
  logger.debug(`Adding project: ${projectPath}, options: ${JSON.stringify(options2)}`);
92712
91807
  intro("Add Project");
92713
- const absolutePath = resolve25(projectPath);
91808
+ const absolutePath = resolve24(projectPath);
92714
91809
  if (!existsSync52(absolutePath)) {
92715
91810
  log.error(`Path does not exist: ${absolutePath}`);
92716
91811
  process.exitCode = 1;
@@ -93600,7 +92695,7 @@ var import_picocolors32 = __toESM(require_picocolors(), 1);
93600
92695
  // src/commands/uninstall/installation-detector.ts
93601
92696
  init_claudekit_scanner();
93602
92697
  init_path_resolver();
93603
- var import_fs_extra38 = __toESM(require_lib3(), 1);
92698
+ var import_fs_extra36 = __toESM(require_lib3(), 1);
93604
92699
  function hasClaudeKitComponents(components) {
93605
92700
  return components.agents > 0 || components.commands > 0 || components.rules > 0 || components.skills > 0;
93606
92701
  }
@@ -93615,7 +92710,7 @@ async function detectInstallations() {
93615
92710
  installations.push({
93616
92711
  type: "local",
93617
92712
  path: setup.project.path,
93618
- exists: await import_fs_extra38.pathExists(setup.project.path),
92713
+ exists: await import_fs_extra36.pathExists(setup.project.path),
93619
92714
  hasMetadata,
93620
92715
  components: setup.project.components
93621
92716
  });
@@ -93628,7 +92723,7 @@ async function detectInstallations() {
93628
92723
  installations.push({
93629
92724
  type: "global",
93630
92725
  path: setup.global.path,
93631
- exists: await import_fs_extra38.pathExists(setup.global.path),
92726
+ exists: await import_fs_extra36.pathExists(setup.global.path),
93632
92727
  hasMetadata,
93633
92728
  components: setup.global.components
93634
92729
  });
@@ -93639,16 +92734,16 @@ async function detectInstallations() {
93639
92734
 
93640
92735
  // src/commands/uninstall/removal-handler.ts
93641
92736
  import { readdirSync as readdirSync6, rmSync as rmSync5 } from "node:fs";
93642
- import { join as join112, resolve as resolve26, sep as sep5 } from "node:path";
92737
+ import { join as join111, resolve as resolve25, sep as sep5 } from "node:path";
93643
92738
  init_logger();
93644
92739
  init_safe_prompts();
93645
92740
  init_safe_spinner();
93646
- var import_fs_extra39 = __toESM(require_lib3(), 1);
92741
+ var import_fs_extra37 = __toESM(require_lib3(), 1);
93647
92742
 
93648
92743
  // src/commands/uninstall/analysis-handler.ts
93649
92744
  init_metadata_migration();
93650
92745
  import { readdirSync as readdirSync5, rmSync as rmSync4 } from "node:fs";
93651
- import { dirname as dirname24, join as join111 } from "node:path";
92746
+ import { dirname as dirname23, join as join110 } from "node:path";
93652
92747
  init_logger();
93653
92748
  init_safe_prompts();
93654
92749
  var import_picocolors31 = __toESM(require_picocolors(), 1);
@@ -93666,7 +92761,7 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
93666
92761
  }
93667
92762
  async function cleanupEmptyDirectories3(filePath, installationRoot) {
93668
92763
  let cleaned = 0;
93669
- let currentDir = dirname24(filePath);
92764
+ let currentDir = dirname23(filePath);
93670
92765
  while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
93671
92766
  try {
93672
92767
  const entries = readdirSync5(currentDir);
@@ -93674,7 +92769,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
93674
92769
  rmSync4(currentDir, { recursive: true });
93675
92770
  cleaned++;
93676
92771
  logger.debug(`Removed empty directory: ${currentDir}`);
93677
- currentDir = dirname24(currentDir);
92772
+ currentDir = dirname23(currentDir);
93678
92773
  } else {
93679
92774
  break;
93680
92775
  }
@@ -93696,7 +92791,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
93696
92791
  if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
93697
92792
  const kitFiles = metadata.kits[kit].files || [];
93698
92793
  for (const trackedFile of kitFiles) {
93699
- const filePath = join111(installation.path, trackedFile.path);
92794
+ const filePath = join110(installation.path, trackedFile.path);
93700
92795
  if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
93701
92796
  result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
93702
92797
  continue;
@@ -93726,7 +92821,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
93726
92821
  return result;
93727
92822
  }
93728
92823
  for (const trackedFile of allTrackedFiles) {
93729
- const filePath = join111(installation.path, trackedFile.path);
92824
+ const filePath = join110(installation.path, trackedFile.path);
93730
92825
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
93731
92826
  if (!ownershipResult.exists)
93732
92827
  continue;
@@ -93771,7 +92866,7 @@ function displayDryRunPreview(analysis, installationType) {
93771
92866
  // src/commands/uninstall/removal-handler.ts
93772
92867
  async function isDirectory(filePath) {
93773
92868
  try {
93774
- const stats = await import_fs_extra39.lstat(filePath);
92869
+ const stats = await import_fs_extra37.lstat(filePath);
93775
92870
  return stats.isDirectory();
93776
92871
  } catch {
93777
92872
  logger.debug(`Failed to check if path is directory: ${filePath}`);
@@ -93780,16 +92875,16 @@ async function isDirectory(filePath) {
93780
92875
  }
93781
92876
  async function isPathSafeToRemove(filePath, baseDir) {
93782
92877
  try {
93783
- const resolvedPath = resolve26(filePath);
93784
- const resolvedBase = resolve26(baseDir);
92878
+ const resolvedPath = resolve25(filePath);
92879
+ const resolvedBase = resolve25(baseDir);
93785
92880
  if (!resolvedPath.startsWith(resolvedBase + sep5) && resolvedPath !== resolvedBase) {
93786
92881
  logger.debug(`Path outside installation directory: ${filePath}`);
93787
92882
  return false;
93788
92883
  }
93789
- const stats = await import_fs_extra39.lstat(filePath);
92884
+ const stats = await import_fs_extra37.lstat(filePath);
93790
92885
  if (stats.isSymbolicLink()) {
93791
- const realPath = await import_fs_extra39.realpath(filePath);
93792
- const resolvedReal = resolve26(realPath);
92886
+ const realPath = await import_fs_extra37.realpath(filePath);
92887
+ const resolvedReal = resolve25(realPath);
93793
92888
  if (!resolvedReal.startsWith(resolvedBase + sep5) && resolvedReal !== resolvedBase) {
93794
92889
  logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
93795
92890
  return false;
@@ -93823,15 +92918,15 @@ async function removeInstallations(installations, options2) {
93823
92918
  let removedCount = 0;
93824
92919
  let cleanedDirs = 0;
93825
92920
  for (const item of analysis.toDelete) {
93826
- const filePath = join112(installation.path, item.path);
93827
- if (!await import_fs_extra39.pathExists(filePath))
92921
+ const filePath = join111(installation.path, item.path);
92922
+ if (!await import_fs_extra37.pathExists(filePath))
93828
92923
  continue;
93829
92924
  if (!await isPathSafeToRemove(filePath, installation.path)) {
93830
92925
  logger.debug(`Skipping unsafe path: ${item.path}`);
93831
92926
  continue;
93832
92927
  }
93833
92928
  const isDir = await isDirectory(filePath);
93834
- await import_fs_extra39.remove(filePath);
92929
+ await import_fs_extra37.remove(filePath);
93835
92930
  removedCount++;
93836
92931
  logger.debug(`Removed ${isDir ? "directory" : "file"}: ${item.path}`);
93837
92932
  if (!isDir) {
@@ -94015,12 +93110,6 @@ ${import_picocolors32.default.yellow("User modifications will be permanently del
94015
93110
  forceOverwrite: validOptions.forceOverwrite,
94016
93111
  kit: validOptions.kit
94017
93112
  });
94018
- if (!validOptions.kit || validOptions.kit === "engineer") {
94019
- try {
94020
- const { handlePluginUninstall: handlePluginUninstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
94021
- await handlePluginUninstall2();
94022
- } catch {}
94023
- }
94024
93113
  const kitMsg = validOptions.kit ? ` (${validOptions.kit} kit)` : "";
94025
93114
  prompts.outro(`ClaudeKit${kitMsg} uninstalled successfully!`);
94026
93115
  } catch (error) {
@@ -94222,7 +93311,7 @@ init_logger();
94222
93311
  init_path_resolver();
94223
93312
  init_types3();
94224
93313
  import { existsSync as existsSync53, readFileSync as readFileSync10 } from "node:fs";
94225
- import { join as join113 } from "node:path";
93314
+ import { join as join112 } from "node:path";
94226
93315
  var packageVersion = package_default.version;
94227
93316
  function formatInstalledKits(metadata) {
94228
93317
  if (!metadata.kits || Object.keys(metadata.kits).length === 0) {
@@ -94254,9 +93343,9 @@ async function displayVersion() {
94254
93343
  let localKitVersion = null;
94255
93344
  let isGlobalOnlyKit = false;
94256
93345
  const globalKitDir = PathResolver.getGlobalKitDir();
94257
- const globalMetadataPath = join113(globalKitDir, "metadata.json");
93346
+ const globalMetadataPath = join112(globalKitDir, "metadata.json");
94258
93347
  const prefix = PathResolver.getPathPrefix(false);
94259
- const localMetadataPath = prefix ? join113(process.cwd(), prefix, "metadata.json") : join113(process.cwd(), "metadata.json");
93348
+ const localMetadataPath = prefix ? join112(process.cwd(), prefix, "metadata.json") : join112(process.cwd(), "metadata.json");
94260
93349
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
94261
93350
  if (!isLocalSameAsGlobal && existsSync53(localMetadataPath)) {
94262
93351
  try {
@@ -94649,7 +93738,7 @@ var output2 = new OutputManager2;
94649
93738
 
94650
93739
  // src/shared/temp-cleanup.ts
94651
93740
  init_logger();
94652
- var import_fs_extra40 = __toESM(require_lib3(), 1);
93741
+ var import_fs_extra38 = __toESM(require_lib3(), 1);
94653
93742
  import { rmSync as rmSync6 } from "node:fs";
94654
93743
  var tempDirs2 = new Set;
94655
93744
  async function cleanup() {
@@ -94658,7 +93747,7 @@ async function cleanup() {
94658
93747
  logger.debug(`Cleaning up ${tempDirs2.size} temporary director(ies)...`);
94659
93748
  for (const dir of tempDirs2) {
94660
93749
  try {
94661
- await import_fs_extra40.remove(dir);
93750
+ await import_fs_extra38.remove(dir);
94662
93751
  logger.debug(`Cleaned up temp directory: ${dir}`);
94663
93752
  } catch (error) {
94664
93753
  logger.debug(`Failed to clean temp directory ${dir}: ${error}`);