claudekit-cli 3.36.0-dev.2 → 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 +734 -1773
  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.2",
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,596 +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
- // src/services/standalone-skill-cleanup.ts
65602
- var exports_standalone_skill_cleanup = {};
65603
- __export(exports_standalone_skill_cleanup, {
65604
- cleanupOverlappingStandaloneSkills: () => cleanupOverlappingStandaloneSkills
65605
- });
65606
- import { readFile as readFile48, readdir as readdir32 } from "node:fs/promises";
65607
- import { join as join101 } from "node:path";
65608
- async function listSkillDirs(dir) {
65609
- if (!await import_fs_extra32.pathExists(dir))
65610
- return new Set;
65611
- try {
65612
- const entries = await readdir32(dir, { withFileTypes: true });
65613
- const dirs = entries.filter((e2) => e2.isDirectory());
65614
- const results = await Promise.all(dirs.map(async (e2) => {
65615
- const exists = await import_fs_extra32.pathExists(join101(dir, e2.name, "SKILL.md"));
65616
- return exists ? e2.name : null;
65617
- }));
65618
- return new Set(results.filter(Boolean));
65619
- } catch {
65620
- return new Set;
65621
- }
65622
- }
65623
- async function getSkillOwnershipMap(claudeDir2) {
65624
- const ownershipMap = new Map;
65625
- const metadataPath = join101(claudeDir2, "metadata.json");
65626
- if (!await import_fs_extra32.pathExists(metadataPath))
65627
- return ownershipMap;
65628
- let trackedFiles;
65629
- try {
65630
- const content = await readFile48(metadataPath, "utf-8");
65631
- const metadata = JSON.parse(content);
65632
- trackedFiles = extractTrackedSkillFiles2(metadata);
65633
- } catch {
65634
- logger.debug("standalone-skill-cleanup: could not read metadata");
65635
- return ownershipMap;
65636
- }
65637
- for (const file of trackedFiles) {
65638
- const skillDirName = extractSkillDirName(file.path);
65639
- if (!skillDirName)
65640
- continue;
65641
- const existing = ownershipMap.get(skillDirName);
65642
- if (file.ownership === "user" || file.ownership === "ck-modified") {
65643
- ownershipMap.set(skillDirName, "user");
65644
- } else if (!existing) {
65645
- ownershipMap.set(skillDirName, "ck");
65646
- }
65647
- }
65648
- return ownershipMap;
65649
- }
65650
- function extractTrackedSkillFiles2(metadata) {
65651
- const files = [];
65652
- if (metadata.kits && typeof metadata.kits === "object") {
65653
- for (const kit of Object.values(metadata.kits)) {
65654
- if (kit.files) {
65655
- files.push(...kit.files.filter((f3) => f3.path?.startsWith("skills/")));
65656
- }
65657
- }
65658
- }
65659
- if (Array.isArray(metadata.files)) {
65660
- files.push(...metadata.files.filter((f3) => f3.path?.startsWith("skills/")));
65661
- }
65662
- return files;
65663
- }
65664
- function extractSkillDirName(filePath) {
65665
- const normalized = filePath.replace(/\\/g, "/");
65666
- const parts = normalized.split("/").filter(Boolean);
65667
- if (parts.length < 2 || parts[0] !== "skills")
65668
- return null;
65669
- return parts[1];
65670
- }
65671
- async function cleanupOverlappingStandaloneSkills(claudeDir2, pluginSkillsDir) {
65672
- const standaloneSkillsDir = join101(claudeDir2, "skills");
65673
- const result = {
65674
- removed: [],
65675
- preserved: [],
65676
- pluginSkillsDir
65677
- };
65678
- const [pluginSkills, standaloneSkills] = await Promise.all([
65679
- listSkillDirs(pluginSkillsDir),
65680
- listSkillDirs(standaloneSkillsDir)
65681
- ]);
65682
- if (pluginSkills.size === 0 || standaloneSkills.size === 0) {
65683
- logger.debug(`standalone-skill-cleanup: nothing to clean (plugin=${pluginSkills.size}, standalone=${standaloneSkills.size})`);
65684
- return result;
65685
- }
65686
- const overlaps = [...standaloneSkills].filter((name2) => pluginSkills.has(name2));
65687
- if (overlaps.length === 0)
65688
- return result;
65689
- const ownershipMap = await getSkillOwnershipMap(claudeDir2);
65690
- for (const skillName of overlaps) {
65691
- const ownership = ownershipMap.get(skillName);
65692
- const skillPath = join101(standaloneSkillsDir, skillName);
65693
- if (ownership === "user" || ownership === undefined) {
65694
- result.preserved.push(skillName);
65695
- const reason = ownership === "user" ? "user-owned/modified" : "untracked";
65696
- logger.debug(`standalone-skill-cleanup: preserved ${skillName} (${reason})`);
65697
- continue;
65698
- }
65699
- try {
65700
- await import_fs_extra32.remove(skillPath);
65701
- result.removed.push(skillName);
65702
- logger.debug(`standalone-skill-cleanup: removed standalone ${skillName} (plugin has it)`);
65703
- } catch (error) {
65704
- result.preserved.push(skillName);
65705
- logger.debug(`standalone-skill-cleanup: could not remove ${skillName}: ${error}`);
65706
- }
65707
- }
65708
- return result;
65709
- }
65710
- var import_fs_extra32;
65711
- var init_standalone_skill_cleanup = __esm(() => {
65712
- init_logger();
65713
- import_fs_extra32 = __toESM(require_lib3(), 1);
65714
- });
65715
-
65716
64668
  // src/domains/help/commands/common-options.ts
65717
64669
  var filterOptionsGroup, folderOptionsGroup;
65718
64670
  var init_common_options = __esm(() => {
@@ -66830,7 +65782,7 @@ function getPagerArgs(pagerCmd) {
66830
65782
  return [];
66831
65783
  }
66832
65784
  async function trySystemPager(content) {
66833
- return new Promise((resolve27) => {
65785
+ return new Promise((resolve26) => {
66834
65786
  const pagerCmd = process.env.PAGER || "less";
66835
65787
  const pagerArgs = getPagerArgs(pagerCmd);
66836
65788
  try {
@@ -66840,20 +65792,20 @@ async function trySystemPager(content) {
66840
65792
  });
66841
65793
  const timeout2 = setTimeout(() => {
66842
65794
  pager.kill();
66843
- resolve27(false);
65795
+ resolve26(false);
66844
65796
  }, 30000);
66845
65797
  pager.stdin.write(content);
66846
65798
  pager.stdin.end();
66847
65799
  pager.on("close", (code2) => {
66848
65800
  clearTimeout(timeout2);
66849
- resolve27(code2 === 0);
65801
+ resolve26(code2 === 0);
66850
65802
  });
66851
65803
  pager.on("error", () => {
66852
65804
  clearTimeout(timeout2);
66853
- resolve27(false);
65805
+ resolve26(false);
66854
65806
  });
66855
65807
  } catch {
66856
- resolve27(false);
65808
+ resolve26(false);
66857
65809
  }
66858
65810
  });
66859
65811
  }
@@ -66880,16 +65832,16 @@ async function basicPager(content) {
66880
65832
  break;
66881
65833
  }
66882
65834
  const remaining = lines.length - currentLine;
66883
- await new Promise((resolve27) => {
65835
+ await new Promise((resolve26) => {
66884
65836
  rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
66885
65837
  if (answer.toLowerCase() === "q") {
66886
65838
  rl.close();
66887
65839
  process.exitCode = 0;
66888
- resolve27();
65840
+ resolve26();
66889
65841
  return;
66890
65842
  }
66891
65843
  process.stdout.write("\x1B[1A\x1B[2K");
66892
- resolve27();
65844
+ resolve26();
66893
65845
  });
66894
65846
  });
66895
65847
  }
@@ -73562,7 +72514,7 @@ class ConfigVersionChecker {
73562
72514
  }
73563
72515
  // src/domains/sync/sync-engine.ts
73564
72516
  import { lstat as lstat3, readFile as readFile34, readlink, realpath as realpath3, stat as stat9 } from "node:fs/promises";
73565
- 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";
73566
72518
 
73567
72519
  // src/services/file-operations/ownership-checker.ts
73568
72520
  init_metadata_migration();
@@ -74923,7 +73875,7 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
74923
73875
  if (!stats.isSymbolicLink())
74924
73876
  break;
74925
73877
  const target = await readlink(current);
74926
- const resolvedTarget = isAbsolute3(target) ? target : resolve13(dirname15(current), target);
73878
+ const resolvedTarget = isAbsolute3(target) ? target : join58(current, "..", target);
74927
73879
  const normalizedTarget = normalize7(resolvedTarget);
74928
73880
  const rel = relative7(basePath, normalizedTarget);
74929
73881
  if (rel.startsWith("..") || isAbsolute3(rel)) {
@@ -74942,10 +73894,6 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
74942
73894
  throw new Error(`Symlink chain too deep (>${maxDepth}): ${path5}`);
74943
73895
  }
74944
73896
  }
74945
- function isOutsideBase(candidatePath, basePath) {
74946
- const rel = relative7(basePath, candidatePath);
74947
- return rel.startsWith("..") || isAbsolute3(rel);
74948
- }
74949
73897
  async function validateSyncPath(basePath, filePath) {
74950
73898
  if (!filePath || filePath.trim() === "") {
74951
73899
  throw new Error("Empty file path not allowed");
@@ -74960,43 +73908,36 @@ async function validateSyncPath(basePath, filePath) {
74960
73908
  if (isAbsolute3(normalized)) {
74961
73909
  throw new Error(`Absolute paths not allowed: ${filePath}`);
74962
73910
  }
74963
- const pathParts = normalized.split(/[\\/]+/).filter(Boolean);
74964
- if (pathParts.includes("..")) {
73911
+ if (normalized.startsWith("..") || normalized.includes("/../")) {
74965
73912
  throw new Error(`Path traversal not allowed: ${filePath}`);
74966
73913
  }
74967
- const lexicalBase = resolve13(basePath);
74968
- const fullPath = resolve13(basePath, normalized);
74969
- const resolvedBase = await realpath3(basePath).catch(() => lexicalBase);
74970
- if (isOutsideBase(fullPath, lexicalBase)) {
73914
+ const fullPath = join58(basePath, normalized);
73915
+ const rel = relative7(basePath, fullPath);
73916
+ if (rel.startsWith("..") || isAbsolute3(rel)) {
74971
73917
  throw new Error(`Path escapes base directory: ${filePath}`);
74972
73918
  }
74973
- await validateSymlinkChain(fullPath, resolvedBase);
73919
+ await validateSymlinkChain(fullPath, basePath);
74974
73920
  try {
73921
+ const resolvedBase = await realpath3(basePath);
74975
73922
  const resolvedFull = await realpath3(fullPath);
74976
- if (isOutsideBase(resolvedFull, resolvedBase)) {
73923
+ const resolvedRel = relative7(resolvedBase, resolvedFull);
73924
+ if (resolvedRel.startsWith("..") || isAbsolute3(resolvedRel)) {
74977
73925
  throw new Error(`Symlink escapes base directory: ${filePath}`);
74978
73926
  }
74979
73927
  } catch (error) {
74980
73928
  if (error.code === "ENOENT") {
74981
- let ancestor = dirname15(fullPath);
74982
- while (ancestor !== lexicalBase) {
74983
- try {
74984
- await lstat3(ancestor);
74985
- break;
74986
- } catch (ancestorError) {
74987
- if (ancestorError.code !== "ENOENT") {
74988
- throw ancestorError;
74989
- }
74990
- const nextAncestor = dirname15(ancestor);
74991
- if (nextAncestor === ancestor) {
74992
- break;
74993
- }
74994
- 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;
74995
73940
  }
74996
- }
74997
- const resolvedAncestor = await realpath3(ancestor).catch(() => null);
74998
- if (!resolvedAncestor || isOutsideBase(resolvedAncestor, resolvedBase)) {
74999
- throw new Error(`Parent symlink escapes base directory: ${filePath}`);
75000
73941
  }
75001
73942
  } else {
75002
73943
  throw error;
@@ -75149,24 +74090,14 @@ class SyncEngine {
75149
74090
  }
75150
74091
  static async loadFileContent(filePath) {
75151
74092
  try {
75152
- const beforeStats = await lstat3(filePath);
75153
- if (beforeStats.isSymbolicLink()) {
74093
+ const lstats = await lstat3(filePath);
74094
+ if (lstats.isSymbolicLink()) {
75154
74095
  throw new Error(`Symlink not allowed for sync: ${filePath}`);
75155
74096
  }
75156
- if (beforeStats.size > MAX_SYNC_FILE_SIZE) {
75157
- 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)`);
75158
74099
  }
75159
74100
  const buffer = await readFile34(filePath);
75160
- const afterStats = await lstat3(filePath);
75161
- if (afterStats.isSymbolicLink()) {
75162
- throw new Error(`File became symlink during read: ${filePath}`);
75163
- }
75164
- if (beforeStats.dev !== afterStats.dev || beforeStats.ino !== afterStats.ino) {
75165
- throw new Error(`File changed identity during read: ${filePath}`);
75166
- }
75167
- if (beforeStats.mtimeMs !== afterStats.mtimeMs || beforeStats.size !== afterStats.size) {
75168
- throw new Error(`File changed during read: ${filePath}`);
75169
- }
75170
74101
  if (buffer.includes(0)) {
75171
74102
  return { content: "", isBinary: true };
75172
74103
  }
@@ -76177,7 +75108,7 @@ init_logger();
76177
75108
  var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
76178
75109
  import { mkdir as mkdir19 } from "node:fs/promises";
76179
75110
  import os5 from "node:os";
76180
- import { join as join64 } from "node:path";
75111
+ import { join as join65 } from "node:path";
76181
75112
  var LOCK_CONFIG = {
76182
75113
  stale: 60000,
76183
75114
  retries: 0
@@ -76185,12 +75116,12 @@ var LOCK_CONFIG = {
76185
75116
  var activeLocks = new Set;
76186
75117
  var cleanupRegistered = false;
76187
75118
  function getLocksDir() {
76188
- return join64(os5.homedir(), ".claudekit", "locks");
75119
+ return join65(os5.homedir(), ".claudekit", "locks");
76189
75120
  }
76190
75121
  function cleanupLocks() {
76191
75122
  for (const name of activeLocks) {
76192
75123
  try {
76193
- const lockPath = join64(getLocksDir(), `${name}.lock`);
75124
+ const lockPath = join65(getLocksDir(), `${name}.lock`);
76194
75125
  import_proper_lockfile4.default.unlockSync(lockPath, { realpath: false });
76195
75126
  } catch {
76196
75127
  try {
@@ -76213,7 +75144,7 @@ async function ensureLocksDir() {
76213
75144
  async function withProcessLock(lockName, fn) {
76214
75145
  registerCleanupHandlers();
76215
75146
  await ensureLocksDir();
76216
- const lockPath = join64(getLocksDir(), `${lockName}.lock`);
75147
+ const lockPath = join65(getLocksDir(), `${lockName}.lock`);
76217
75148
  let release;
76218
75149
  try {
76219
75150
  release = await import_proper_lockfile4.default.lock(lockPath, { ...LOCK_CONFIG, realpath: false });
@@ -76244,7 +75175,7 @@ init_logger();
76244
75175
  init_logger();
76245
75176
  init_path_resolver();
76246
75177
  var import_fs_extra7 = __toESM(require_lib3(), 1);
76247
- import { join as join65 } from "node:path";
75178
+ import { join as join66 } from "node:path";
76248
75179
  async function handleConflicts(ctx) {
76249
75180
  if (ctx.cancelled)
76250
75181
  return ctx;
@@ -76253,7 +75184,7 @@ async function handleConflicts(ctx) {
76253
75184
  if (PathResolver.isLocalSameAsGlobal()) {
76254
75185
  return ctx;
76255
75186
  }
76256
- const localSettingsPath = join65(process.cwd(), ".claude", "settings.json");
75187
+ const localSettingsPath = join66(process.cwd(), ".claude", "settings.json");
76257
75188
  if (!await import_fs_extra7.pathExists(localSettingsPath)) {
76258
75189
  return ctx;
76259
75190
  }
@@ -76268,7 +75199,7 @@ async function handleConflicts(ctx) {
76268
75199
  return { ...ctx, cancelled: true };
76269
75200
  }
76270
75201
  if (choice === "remove") {
76271
- const localClaudeDir = join65(process.cwd(), ".claude");
75202
+ const localClaudeDir = join66(process.cwd(), ".claude");
76272
75203
  try {
76273
75204
  await import_fs_extra7.remove(localClaudeDir);
76274
75205
  logger.success("Removed local .claude/ directory");
@@ -76365,7 +75296,7 @@ init_logger();
76365
75296
  init_safe_spinner();
76366
75297
  import { mkdir as mkdir25, stat as stat12 } from "node:fs/promises";
76367
75298
  import { tmpdir as tmpdir4 } from "node:os";
76368
- import { join as join72 } from "node:path";
75299
+ import { join as join73 } from "node:path";
76369
75300
 
76370
75301
  // src/shared/temp-cleanup.ts
76371
75302
  init_logger();
@@ -76384,7 +75315,7 @@ init_logger();
76384
75315
  init_output_manager();
76385
75316
  import { createWriteStream as createWriteStream2, rmSync } from "node:fs";
76386
75317
  import { mkdir as mkdir20 } from "node:fs/promises";
76387
- import { join as join66 } from "node:path";
75318
+ import { join as join67 } from "node:path";
76388
75319
 
76389
75320
  // src/shared/progress-bar.ts
76390
75321
  init_output_manager();
@@ -76549,10 +75480,10 @@ init_types3();
76549
75480
  // src/domains/installation/utils/path-security.ts
76550
75481
  init_types3();
76551
75482
  import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
76552
- import { relative as relative8, resolve as resolve16 } from "node:path";
75483
+ import { relative as relative8, resolve as resolve15 } from "node:path";
76553
75484
  var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
76554
75485
  function isPathSafe(basePath, targetPath) {
76555
- const resolvedBase = resolve16(basePath);
75486
+ const resolvedBase = resolve15(basePath);
76556
75487
  try {
76557
75488
  const stat10 = lstatSync2(targetPath);
76558
75489
  if (stat10.isSymbolicLink()) {
@@ -76562,7 +75493,7 @@ function isPathSafe(basePath, targetPath) {
76562
75493
  }
76563
75494
  }
76564
75495
  } catch {}
76565
- const resolvedTarget = resolve16(targetPath);
75496
+ const resolvedTarget = resolve15(targetPath);
76566
75497
  const relativePath = relative8(resolvedBase, resolvedTarget);
76567
75498
  return !relativePath.startsWith("..") && !relativePath.startsWith("/") && resolvedTarget.startsWith(resolvedBase);
76568
75499
  }
@@ -76594,7 +75525,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
76594
75525
  class FileDownloader {
76595
75526
  async downloadAsset(asset, destDir) {
76596
75527
  try {
76597
- const destPath = join66(destDir, asset.name);
75528
+ const destPath = join67(destDir, asset.name);
76598
75529
  await mkdir20(destDir, { recursive: true });
76599
75530
  output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
76600
75531
  logger.verbose("Download details", {
@@ -76650,7 +75581,7 @@ class FileDownloader {
76650
75581
  }
76651
75582
  if (downloadedSize !== totalSize) {
76652
75583
  fileStream.end();
76653
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75584
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76654
75585
  try {
76655
75586
  rmSync(destPath, { force: true });
76656
75587
  } catch (cleanupError) {
@@ -76664,7 +75595,7 @@ class FileDownloader {
76664
75595
  return destPath;
76665
75596
  } catch (error) {
76666
75597
  fileStream.end();
76667
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75598
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76668
75599
  try {
76669
75600
  rmSync(destPath, { force: true });
76670
75601
  } catch (cleanupError) {
@@ -76679,7 +75610,7 @@ class FileDownloader {
76679
75610
  }
76680
75611
  async downloadFile(params) {
76681
75612
  const { url, name, size, destDir, token } = params;
76682
- const destPath = join66(destDir, name);
75613
+ const destPath = join67(destDir, name);
76683
75614
  await mkdir20(destDir, { recursive: true });
76684
75615
  output.info(`Downloading ${name}${size ? ` (${formatBytes(size)})` : ""}...`);
76685
75616
  const headers = {};
@@ -76730,7 +75661,7 @@ class FileDownloader {
76730
75661
  const expectedSize = Number(response.headers.get("content-length"));
76731
75662
  if (expectedSize > 0 && downloadedSize !== expectedSize) {
76732
75663
  fileStream.end();
76733
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75664
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76734
75665
  try {
76735
75666
  rmSync(destPath, { force: true });
76736
75667
  } catch (cleanupError) {
@@ -76748,7 +75679,7 @@ class FileDownloader {
76748
75679
  return destPath;
76749
75680
  } catch (error) {
76750
75681
  fileStream.end();
76751
- await new Promise((resolve17) => fileStream.once("close", resolve17));
75682
+ await new Promise((resolve16) => fileStream.once("close", resolve16));
76752
75683
  try {
76753
75684
  rmSync(destPath, { force: true });
76754
75685
  } catch (cleanupError) {
@@ -76765,7 +75696,7 @@ init_logger();
76765
75696
  init_types3();
76766
75697
  import { constants as constants4 } from "node:fs";
76767
75698
  import { access as access4, readdir as readdir13 } from "node:fs/promises";
76768
- import { join as join67 } from "node:path";
75699
+ import { join as join68 } from "node:path";
76769
75700
  async function validateExtraction(extractDir) {
76770
75701
  try {
76771
75702
  const entries = await readdir13(extractDir, { encoding: "utf8" });
@@ -76777,7 +75708,7 @@ async function validateExtraction(extractDir) {
76777
75708
  const missingPaths = [];
76778
75709
  for (const path5 of criticalPaths) {
76779
75710
  try {
76780
- await access4(join67(extractDir, path5), constants4.F_OK);
75711
+ await access4(join68(extractDir, path5), constants4.F_OK);
76781
75712
  logger.debug(`Found: ${path5}`);
76782
75713
  } catch {
76783
75714
  logger.warning(`Expected path not found: ${path5}`);
@@ -76799,7 +75730,7 @@ async function validateExtraction(extractDir) {
76799
75730
  // src/domains/installation/extraction/tar-extractor.ts
76800
75731
  init_logger();
76801
75732
  import { copyFile as copyFile4, mkdir as mkdir23, readdir as readdir15, rm as rm8, stat as stat10 } from "node:fs/promises";
76802
- import { join as join70 } from "node:path";
75733
+ import { join as join71 } from "node:path";
76803
75734
 
76804
75735
  // node_modules/@isaacs/fs-minipass/dist/esm/index.js
76805
75736
  import EE from "events";
@@ -77347,10 +76278,10 @@ class Minipass extends EventEmitter3 {
77347
76278
  return this[ENCODING] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
77348
76279
  }
77349
76280
  async promise() {
77350
- return new Promise((resolve17, reject) => {
76281
+ return new Promise((resolve16, reject) => {
77351
76282
  this.on(DESTROYED, () => reject(new Error("stream destroyed")));
77352
76283
  this.on("error", (er) => reject(er));
77353
- this.on("end", () => resolve17());
76284
+ this.on("end", () => resolve16());
77354
76285
  });
77355
76286
  }
77356
76287
  [Symbol.asyncIterator]() {
@@ -77369,7 +76300,7 @@ class Minipass extends EventEmitter3 {
77369
76300
  return Promise.resolve({ done: false, value: res });
77370
76301
  if (this[EOF])
77371
76302
  return stop();
77372
- let resolve17;
76303
+ let resolve16;
77373
76304
  let reject;
77374
76305
  const onerr = (er) => {
77375
76306
  this.off("data", ondata);
@@ -77383,19 +76314,19 @@ class Minipass extends EventEmitter3 {
77383
76314
  this.off("end", onend);
77384
76315
  this.off(DESTROYED, ondestroy);
77385
76316
  this.pause();
77386
- resolve17({ value, done: !!this[EOF] });
76317
+ resolve16({ value, done: !!this[EOF] });
77387
76318
  };
77388
76319
  const onend = () => {
77389
76320
  this.off("error", onerr);
77390
76321
  this.off("data", ondata);
77391
76322
  this.off(DESTROYED, ondestroy);
77392
76323
  stop();
77393
- resolve17({ done: true, value: undefined });
76324
+ resolve16({ done: true, value: undefined });
77394
76325
  };
77395
76326
  const ondestroy = () => onerr(new Error("stream destroyed"));
77396
76327
  return new Promise((res2, rej) => {
77397
76328
  reject = rej;
77398
- resolve17 = res2;
76329
+ resolve16 = res2;
77399
76330
  this.once(DESTROYED, ondestroy);
77400
76331
  this.once("error", onerr);
77401
76332
  this.once("end", onend);
@@ -77852,7 +76783,7 @@ import path7 from "node:path";
77852
76783
 
77853
76784
  // node_modules/tar/dist/esm/list.js
77854
76785
  import fs9 from "node:fs";
77855
- import { dirname as dirname18, parse as parse3 } from "path";
76786
+ import { dirname as dirname17, parse as parse3 } from "path";
77856
76787
 
77857
76788
  // node_modules/tar/dist/esm/options.js
77858
76789
  var argmap = new Map([
@@ -78501,10 +77432,10 @@ class Minipass2 extends EventEmitter4 {
78501
77432
  return this[ENCODING2] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
78502
77433
  }
78503
77434
  async promise() {
78504
- return new Promise((resolve17, reject) => {
77435
+ return new Promise((resolve16, reject) => {
78505
77436
  this.on(DESTROYED2, () => reject(new Error("stream destroyed")));
78506
77437
  this.on("error", (er) => reject(er));
78507
- this.on("end", () => resolve17());
77438
+ this.on("end", () => resolve16());
78508
77439
  });
78509
77440
  }
78510
77441
  [Symbol.asyncIterator]() {
@@ -78523,7 +77454,7 @@ class Minipass2 extends EventEmitter4 {
78523
77454
  return Promise.resolve({ done: false, value: res });
78524
77455
  if (this[EOF2])
78525
77456
  return stop();
78526
- let resolve17;
77457
+ let resolve16;
78527
77458
  let reject;
78528
77459
  const onerr = (er) => {
78529
77460
  this.off("data", ondata);
@@ -78537,19 +77468,19 @@ class Minipass2 extends EventEmitter4 {
78537
77468
  this.off("end", onend);
78538
77469
  this.off(DESTROYED2, ondestroy);
78539
77470
  this.pause();
78540
- resolve17({ value, done: !!this[EOF2] });
77471
+ resolve16({ value, done: !!this[EOF2] });
78541
77472
  };
78542
77473
  const onend = () => {
78543
77474
  this.off("error", onerr);
78544
77475
  this.off("data", ondata);
78545
77476
  this.off(DESTROYED2, ondestroy);
78546
77477
  stop();
78547
- resolve17({ done: true, value: undefined });
77478
+ resolve16({ done: true, value: undefined });
78548
77479
  };
78549
77480
  const ondestroy = () => onerr(new Error("stream destroyed"));
78550
77481
  return new Promise((res2, rej) => {
78551
77482
  reject = rej;
78552
- resolve17 = res2;
77483
+ resolve16 = res2;
78553
77484
  this.once(DESTROYED2, ondestroy);
78554
77485
  this.once("error", onerr);
78555
77486
  this.once("end", onend);
@@ -79977,10 +78908,10 @@ class Minipass3 extends EventEmitter5 {
79977
78908
  return this[ENCODING3] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
79978
78909
  }
79979
78910
  async promise() {
79980
- return new Promise((resolve17, reject) => {
78911
+ return new Promise((resolve16, reject) => {
79981
78912
  this.on(DESTROYED3, () => reject(new Error("stream destroyed")));
79982
78913
  this.on("error", (er) => reject(er));
79983
- this.on("end", () => resolve17());
78914
+ this.on("end", () => resolve16());
79984
78915
  });
79985
78916
  }
79986
78917
  [Symbol.asyncIterator]() {
@@ -79999,7 +78930,7 @@ class Minipass3 extends EventEmitter5 {
79999
78930
  return Promise.resolve({ done: false, value: res });
80000
78931
  if (this[EOF3])
80001
78932
  return stop();
80002
- let resolve17;
78933
+ let resolve16;
80003
78934
  let reject;
80004
78935
  const onerr = (er) => {
80005
78936
  this.off("data", ondata);
@@ -80013,19 +78944,19 @@ class Minipass3 extends EventEmitter5 {
80013
78944
  this.off("end", onend);
80014
78945
  this.off(DESTROYED3, ondestroy);
80015
78946
  this.pause();
80016
- resolve17({ value, done: !!this[EOF3] });
78947
+ resolve16({ value, done: !!this[EOF3] });
80017
78948
  };
80018
78949
  const onend = () => {
80019
78950
  this.off("error", onerr);
80020
78951
  this.off("data", ondata);
80021
78952
  this.off(DESTROYED3, ondestroy);
80022
78953
  stop();
80023
- resolve17({ done: true, value: undefined });
78954
+ resolve16({ done: true, value: undefined });
80024
78955
  };
80025
78956
  const ondestroy = () => onerr(new Error("stream destroyed"));
80026
78957
  return new Promise((res2, rej) => {
80027
78958
  reject = rej;
80028
- resolve17 = res2;
78959
+ resolve16 = res2;
80029
78960
  this.once(DESTROYED3, ondestroy);
80030
78961
  this.once("error", onerr);
80031
78962
  this.once("end", onend);
@@ -80752,7 +79683,7 @@ var filesFilter = (opt, files) => {
80752
79683
  if (m2 !== undefined) {
80753
79684
  ret = m2;
80754
79685
  } else {
80755
- ret = mapHas(dirname18(file), root);
79686
+ ret = mapHas(dirname17(file), root);
80756
79687
  }
80757
79688
  }
80758
79689
  map.set(file, ret);
@@ -80796,9 +79727,9 @@ var listFile = (opt, _files) => {
80796
79727
  const parse4 = new Parser(opt);
80797
79728
  const readSize = opt.maxReadSize || 16 * 1024 * 1024;
80798
79729
  const file = opt.file;
80799
- const p = new Promise((resolve17, reject) => {
79730
+ const p = new Promise((resolve16, reject) => {
80800
79731
  parse4.on("error", reject);
80801
- parse4.on("end", resolve17);
79732
+ parse4.on("end", resolve16);
80802
79733
  fs9.stat(file, (er, stat10) => {
80803
79734
  if (er) {
80804
79735
  reject(er);
@@ -82561,7 +81492,7 @@ var mkdirSync = (dir, opt) => {
82561
81492
  };
82562
81493
 
82563
81494
  // node_modules/tar/dist/esm/path-reservations.js
82564
- import { join as join68 } from "node:path";
81495
+ import { join as join69 } from "node:path";
82565
81496
 
82566
81497
  // node_modules/tar/dist/esm/normalize-unicode.js
82567
81498
  var normalizeCache = Object.create(null);
@@ -82594,7 +81525,7 @@ var getDirs = (path10) => {
82594
81525
  const dirs = path10.split("/").slice(0, -1).reduce((set, path11) => {
82595
81526
  const s = set[set.length - 1];
82596
81527
  if (s !== undefined) {
82597
- path11 = join68(s, path11);
81528
+ path11 = join69(s, path11);
82598
81529
  }
82599
81530
  set.push(path11 || "/");
82600
81531
  return set;
@@ -82608,7 +81539,7 @@ class PathReservations {
82608
81539
  #running = new Set;
82609
81540
  reserve(paths, fn) {
82610
81541
  paths = isWindows4 ? ["win32 parallelization disabled"] : paths.map((p) => {
82611
- return stripTrailingSlashes(join68(normalizeUnicode(p))).toLowerCase();
81542
+ return stripTrailingSlashes(join69(normalizeUnicode(p))).toLowerCase();
82612
81543
  });
82613
81544
  const dirs = new Set(paths.map((path10) => getDirs(path10)).reduce((a3, b3) => a3.concat(b3)));
82614
81545
  this.#reservations.set(fn, { dirs, paths });
@@ -83378,9 +82309,9 @@ var extractFile = (opt, _3) => {
83378
82309
  const u = new Unpack(opt);
83379
82310
  const readSize = opt.maxReadSize || 16 * 1024 * 1024;
83380
82311
  const file = opt.file;
83381
- const p = new Promise((resolve17, reject) => {
82312
+ const p = new Promise((resolve16, reject) => {
83382
82313
  u.on("error", reject);
83383
- u.on("close", resolve17);
82314
+ u.on("close", resolve16);
83384
82315
  fs16.stat(file, (er, stat10) => {
83385
82316
  if (er) {
83386
82317
  reject(er);
@@ -83513,7 +82444,7 @@ var replaceAsync = (opt, files) => {
83513
82444
  };
83514
82445
  fs17.read(fd, headBuf, 0, 512, position, onread);
83515
82446
  };
83516
- const promise = new Promise((resolve17, reject) => {
82447
+ const promise = new Promise((resolve16, reject) => {
83517
82448
  p.on("error", reject);
83518
82449
  let flag = "r+";
83519
82450
  const onopen = (er, fd) => {
@@ -83538,7 +82469,7 @@ var replaceAsync = (opt, files) => {
83538
82469
  });
83539
82470
  p.pipe(stream);
83540
82471
  stream.on("error", reject);
83541
- stream.on("close", resolve17);
82472
+ stream.on("close", resolve16);
83542
82473
  addFilesAsync2(p, files);
83543
82474
  });
83544
82475
  });
@@ -83668,7 +82599,7 @@ function decodeFilePath(path12) {
83668
82599
  init_logger();
83669
82600
  init_types3();
83670
82601
  import { copyFile as copyFile3, lstat as lstat4, mkdir as mkdir22, readdir as readdir14 } from "node:fs/promises";
83671
- import { join as join69, relative as relative9 } from "node:path";
82602
+ import { join as join70, relative as relative9 } from "node:path";
83672
82603
  async function withRetry(fn, retries = 3) {
83673
82604
  for (let i = 0;i < retries; i++) {
83674
82605
  try {
@@ -83690,8 +82621,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
83690
82621
  await mkdir22(destDir, { recursive: true });
83691
82622
  const entries = await readdir14(sourceDir, { encoding: "utf8" });
83692
82623
  for (const entry of entries) {
83693
- const sourcePath = join69(sourceDir, entry);
83694
- const destPath = join69(destDir, entry);
82624
+ const sourcePath = join70(sourceDir, entry);
82625
+ const destPath = join70(destDir, entry);
83695
82626
  const relativePath = relative9(sourceDir, sourcePath);
83696
82627
  if (!isPathSafe(destDir, destPath)) {
83697
82628
  logger.warning(`Skipping unsafe path: ${relativePath}`);
@@ -83718,8 +82649,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
83718
82649
  await mkdir22(destDir, { recursive: true });
83719
82650
  const entries = await readdir14(sourceDir, { encoding: "utf8" });
83720
82651
  for (const entry of entries) {
83721
- const sourcePath = join69(sourceDir, entry);
83722
- const destPath = join69(destDir, entry);
82652
+ const sourcePath = join70(sourceDir, entry);
82653
+ const destPath = join70(destDir, entry);
83723
82654
  const relativePath = relative9(sourceDir, sourcePath);
83724
82655
  if (!isPathSafe(destDir, destPath)) {
83725
82656
  logger.warning(`Skipping unsafe path: ${relativePath}`);
@@ -83767,7 +82698,7 @@ class TarExtractor {
83767
82698
  logger.debug(`Root entries: ${entries.join(", ")}`);
83768
82699
  if (entries.length === 1) {
83769
82700
  const rootEntry = entries[0];
83770
- const rootPath = join70(tempExtractDir, rootEntry);
82701
+ const rootPath = join71(tempExtractDir, rootEntry);
83771
82702
  const rootStat = await stat10(rootPath);
83772
82703
  if (rootStat.isDirectory()) {
83773
82704
  const rootContents = await readdir15(rootPath, { encoding: "utf8" });
@@ -83783,7 +82714,7 @@ class TarExtractor {
83783
82714
  }
83784
82715
  } else {
83785
82716
  await mkdir23(destDir, { recursive: true });
83786
- await copyFile4(rootPath, join70(destDir, rootEntry));
82717
+ await copyFile4(rootPath, join71(destDir, rootEntry));
83787
82718
  }
83788
82719
  } else {
83789
82720
  logger.debug("Multiple root entries - moving all");
@@ -83806,26 +82737,26 @@ init_logger();
83806
82737
  var import_extract_zip = __toESM(require_extract_zip(), 1);
83807
82738
  import { execFile as execFile8 } from "node:child_process";
83808
82739
  import { copyFile as copyFile5, mkdir as mkdir24, readdir as readdir16, rm as rm9, stat as stat11 } from "node:fs/promises";
83809
- import { join as join71 } from "node:path";
82740
+ import { join as join72 } from "node:path";
83810
82741
  class ZipExtractor {
83811
82742
  async tryNativeUnzip(archivePath, destDir) {
83812
82743
  if (!isMacOS()) {
83813
82744
  return false;
83814
82745
  }
83815
- return new Promise((resolve17) => {
82746
+ return new Promise((resolve16) => {
83816
82747
  mkdir24(destDir, { recursive: true }).then(() => {
83817
82748
  execFile8("unzip", ["-o", "-q", archivePath, "-d", destDir], (error, _stdout, stderr) => {
83818
82749
  if (error) {
83819
82750
  logger.debug(`Native unzip failed: ${stderr || error.message}`);
83820
- resolve17(false);
82751
+ resolve16(false);
83821
82752
  return;
83822
82753
  }
83823
82754
  logger.debug("Native unzip succeeded");
83824
- resolve17(true);
82755
+ resolve16(true);
83825
82756
  });
83826
82757
  }).catch((err) => {
83827
82758
  logger.debug(`Failed to create directory for native unzip: ${err.message}`);
83828
- resolve17(false);
82759
+ resolve16(false);
83829
82760
  });
83830
82761
  });
83831
82762
  }
@@ -83854,7 +82785,7 @@ class ZipExtractor {
83854
82785
  logger.debug(`Root entries: ${entries.join(", ")}`);
83855
82786
  if (entries.length === 1) {
83856
82787
  const rootEntry = entries[0];
83857
- const rootPath = join71(tempExtractDir, rootEntry);
82788
+ const rootPath = join72(tempExtractDir, rootEntry);
83858
82789
  const rootStat = await stat11(rootPath);
83859
82790
  if (rootStat.isDirectory()) {
83860
82791
  const rootContents = await readdir16(rootPath, { encoding: "utf8" });
@@ -83870,7 +82801,7 @@ class ZipExtractor {
83870
82801
  }
83871
82802
  } else {
83872
82803
  await mkdir24(destDir, { recursive: true });
83873
- await copyFile5(rootPath, join71(destDir, rootEntry));
82804
+ await copyFile5(rootPath, join72(destDir, rootEntry));
83874
82805
  }
83875
82806
  } else {
83876
82807
  logger.debug("Multiple root entries - moving all");
@@ -83969,7 +82900,7 @@ class DownloadManager {
83969
82900
  async createTempDir() {
83970
82901
  const timestamp = Date.now();
83971
82902
  const counter = DownloadManager.tempDirCounter++;
83972
- const primaryTempDir = join72(tmpdir4(), `claudekit-${timestamp}-${counter}`);
82903
+ const primaryTempDir = join73(tmpdir4(), `claudekit-${timestamp}-${counter}`);
83973
82904
  try {
83974
82905
  await mkdir25(primaryTempDir, { recursive: true });
83975
82906
  logger.debug(`Created temp directory: ${primaryTempDir}`);
@@ -83986,7 +82917,7 @@ Solutions:
83986
82917
  2. Set HOME environment variable
83987
82918
  3. Try running from a different directory`);
83988
82919
  }
83989
- const fallbackTempDir = join72(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
82920
+ const fallbackTempDir = join73(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
83990
82921
  try {
83991
82922
  await mkdir25(fallbackTempDir, { recursive: true });
83992
82923
  logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
@@ -84335,8 +83266,349 @@ async function handleDownload(ctx) {
84335
83266
  };
84336
83267
  }
84337
83268
  // src/commands/init/phases/merge-handler.ts
84338
- init_deletion_handler();
84339
- 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
+ }
84340
83612
 
84341
83613
  // src/domains/installation/file-merger.ts
84342
83614
  init_logger();
@@ -84348,10 +83620,9 @@ init_logger();
84348
83620
  init_types3();
84349
83621
  var import_fs_extra12 = __toESM(require_lib3(), 1);
84350
83622
  var import_ignore3 = __toESM(require_ignore(), 1);
84351
- 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";
84352
83624
 
84353
83625
  // src/domains/installation/selective-merger.ts
84354
- init_manifest_reader();
84355
83626
  import { stat as stat13 } from "node:fs/promises";
84356
83627
  init_logger();
84357
83628
  var import_semver2 = __toESM(require_semver2(), 1);
@@ -84528,7 +83799,7 @@ init_logger();
84528
83799
  var import_fs_extra10 = __toESM(require_lib3(), 1);
84529
83800
  var import_ignore2 = __toESM(require_ignore(), 1);
84530
83801
  import { relative as relative11 } from "node:path";
84531
- import { join as join76 } from "node:path";
83802
+ import { join as join77 } from "node:path";
84532
83803
 
84533
83804
  // node_modules/@isaacs/balanced-match/dist/esm/index.js
84534
83805
  var balanced = (a3, b3, str2) => {
@@ -85984,7 +85255,7 @@ class FileScanner {
85984
85255
  const files = [];
85985
85256
  const entries = await import_fs_extra10.readdir(dir, { encoding: "utf8" });
85986
85257
  for (const entry of entries) {
85987
- const fullPath = join76(dir, entry);
85258
+ const fullPath = join77(dir, entry);
85988
85259
  const relativePath = relative11(baseDir, fullPath);
85989
85260
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
85990
85261
  const stats = await import_fs_extra10.lstat(fullPath);
@@ -86024,7 +85295,7 @@ import { execSync as execSync4 } from "node:child_process";
86024
85295
  init_shared();
86025
85296
  import { existsSync as existsSync49 } from "node:fs";
86026
85297
  import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "node:fs/promises";
86027
- import { dirname as dirname20, join as join77 } from "node:path";
85298
+ import { dirname as dirname19, join as join78 } from "node:path";
86028
85299
  var CK_JSON_FILE = ".ck.json";
86029
85300
 
86030
85301
  class InstalledSettingsTracker {
@@ -86038,9 +85309,9 @@ class InstalledSettingsTracker {
86038
85309
  }
86039
85310
  getCkJsonPath() {
86040
85311
  if (this.isGlobal) {
86041
- return join77(this.projectDir, CK_JSON_FILE);
85312
+ return join78(this.projectDir, CK_JSON_FILE);
86042
85313
  }
86043
- return join77(this.projectDir, ".claude", CK_JSON_FILE);
85314
+ return join78(this.projectDir, ".claude", CK_JSON_FILE);
86044
85315
  }
86045
85316
  async loadInstalledSettings() {
86046
85317
  const ckJsonPath = this.getCkJsonPath();
@@ -86075,7 +85346,7 @@ class InstalledSettingsTracker {
86075
85346
  data.kits[this.kitName] = {};
86076
85347
  }
86077
85348
  data.kits[this.kitName].installedSettings = settings;
86078
- await mkdir26(dirname20(ckJsonPath), { recursive: true });
85349
+ await mkdir26(dirname19(ckJsonPath), { recursive: true });
86079
85350
  await writeFile22(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
86080
85351
  logger.debug(`Saved installed settings to ${ckJsonPath}`);
86081
85352
  } catch (error) {
@@ -86593,7 +85864,7 @@ class CopyExecutor {
86593
85864
  for (const file of files) {
86594
85865
  const relativePath = relative12(sourceDir, file);
86595
85866
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
86596
- const destPath = join78(destDir, relativePath);
85867
+ const destPath = join79(destDir, relativePath);
86597
85868
  if (await import_fs_extra12.pathExists(destPath)) {
86598
85869
  if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
86599
85870
  logger.debug(`Security-sensitive file exists but won't be overwritten: ${normalizedRelativePath}`);
@@ -86615,7 +85886,7 @@ class CopyExecutor {
86615
85886
  for (const file of files) {
86616
85887
  const relativePath = relative12(sourceDir, file);
86617
85888
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
86618
- const destPath = join78(destDir, relativePath);
85889
+ const destPath = join79(destDir, relativePath);
86619
85890
  if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
86620
85891
  logger.debug(`Skipping security-sensitive file: ${normalizedRelativePath}`);
86621
85892
  skippedCount++;
@@ -86692,10 +85963,10 @@ class CopyExecutor {
86692
85963
  }
86693
85964
  trackInstalledFile(relativePath) {
86694
85965
  this.installedFiles.add(relativePath);
86695
- let dir = dirname21(relativePath);
85966
+ let dir = dirname20(relativePath);
86696
85967
  while (dir && dir !== "." && dir !== "/") {
86697
85968
  this.installedDirectories.add(`${dir}/`);
86698
- dir = dirname21(dir);
85969
+ dir = dirname20(dir);
86699
85970
  }
86700
85971
  }
86701
85972
  }
@@ -86785,19 +86056,15 @@ class FileMerger {
86785
86056
 
86786
86057
  // src/domains/migration/legacy-migration.ts
86787
86058
  import { readdir as readdir18, stat as stat14 } from "node:fs/promises";
86788
- import { join as join82, relative as relative13 } from "node:path";
86789
-
86790
- // src/services/file-operations/manifest/index.ts
86791
- init_manifest_reader();
86792
-
86059
+ import { join as join83, relative as relative13 } from "node:path";
86793
86060
  // src/services/file-operations/manifest/manifest-tracker.ts
86794
- import { join as join81 } from "node:path";
86061
+ import { join as join82 } from "node:path";
86795
86062
 
86796
86063
  // src/domains/migration/release-manifest.ts
86797
86064
  init_logger();
86798
86065
  init_zod();
86799
86066
  var import_fs_extra13 = __toESM(require_lib3(), 1);
86800
- import { join as join79 } from "node:path";
86067
+ import { join as join80 } from "node:path";
86801
86068
  var ReleaseManifestFileSchema = exports_external.object({
86802
86069
  path: exports_external.string(),
86803
86070
  checksum: exports_external.string().regex(/^[a-f0-9]{64}$/),
@@ -86812,7 +86079,7 @@ var ReleaseManifestSchema = exports_external.object({
86812
86079
 
86813
86080
  class ReleaseManifestLoader {
86814
86081
  static async load(extractDir) {
86815
- const manifestPath = join79(extractDir, "release-manifest.json");
86082
+ const manifestPath = join80(extractDir, "release-manifest.json");
86816
86083
  try {
86817
86084
  const content = await import_fs_extra13.readFile(manifestPath, "utf-8");
86818
86085
  const parsed = JSON.parse(content);
@@ -86836,12 +86103,11 @@ init_safe_spinner();
86836
86103
  init_metadata_migration();
86837
86104
  init_logger();
86838
86105
  init_types3();
86839
- init_manifest_reader();
86840
86106
  var import_fs_extra14 = __toESM(require_lib3(), 1);
86841
86107
  var import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
86842
- import { join as join80 } from "node:path";
86108
+ import { join as join81 } from "node:path";
86843
86109
  async function writeManifest(claudeDir2, kitName, version, scope, kitType, trackedFiles, userConfigFiles) {
86844
- const metadataPath = join80(claudeDir2, "metadata.json");
86110
+ const metadataPath = join81(claudeDir2, "metadata.json");
86845
86111
  const kit = kitType || (/\bmarketing\b/i.test(kitName) ? "marketing" : "engineer");
86846
86112
  await import_fs_extra14.ensureFile(metadataPath);
86847
86113
  let release = null;
@@ -86861,54 +86127,20 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
86861
86127
  const content = await import_fs_extra14.readFile(metadataPath, "utf-8");
86862
86128
  const parsed = JSON.parse(content);
86863
86129
  if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
86864
- const validatedExisting = MetadataSchema.safeParse(parsed);
86865
- if (validatedExisting.success) {
86866
- existingMetadata = validatedExisting.data;
86867
- } else {
86868
- logger.warning("Existing metadata.json is invalid; preserving recoverable fields and rebuilding the rest");
86869
- const raw2 = parsed;
86870
- const recoveredKits = {};
86871
- if (raw2.kits && typeof raw2.kits === "object") {
86872
- for (const [rawKitName, rawKitValue] of Object.entries(raw2.kits)) {
86873
- if ((rawKitName === "engineer" || rawKitName === "marketing") && rawKitValue && typeof rawKitValue === "object") {
86874
- const recoveredKit = rawKitValue;
86875
- if (typeof recoveredKit.version === "string" && typeof recoveredKit.installedAt === "string") {
86876
- recoveredKits[rawKitName] = recoveredKit;
86877
- }
86878
- }
86879
- }
86880
- }
86881
- existingMetadata = {
86882
- kits: recoveredKits,
86883
- scope: raw2.scope === "local" || raw2.scope === "global" ? raw2.scope : undefined,
86884
- name: typeof raw2.name === "string" ? raw2.name : undefined,
86885
- version: typeof raw2.version === "string" ? raw2.version : undefined,
86886
- installedAt: typeof raw2.installedAt === "string" ? raw2.installedAt : undefined,
86887
- userConfigFiles: Array.isArray(raw2.userConfigFiles) ? raw2.userConfigFiles.filter((entry) => typeof entry === "string") : undefined
86888
- };
86889
- }
86130
+ existingMetadata = parsed;
86890
86131
  }
86891
86132
  } catch (error) {
86892
86133
  logger.debug(`Could not read existing metadata: ${error}`);
86893
86134
  }
86894
86135
  }
86895
86136
  const installedAt = new Date().toISOString();
86896
- const existingKits = existingMetadata.kits || {};
86897
- const existingKitMetadata = existingKits[kit];
86898
86137
  const kitMetadata = {
86899
- ...existingKitMetadata,
86900
86138
  version,
86901
86139
  installedAt,
86902
86140
  files: trackedFiles.length > 0 ? trackedFiles : undefined
86903
86141
  };
86142
+ const existingKits = existingMetadata.kits || {};
86904
86143
  const otherKitsExist = Object.keys(existingKits).some((k2) => k2 !== kit);
86905
- const mergedUserConfigFiles = [
86906
- ...new Set([
86907
- ...existingMetadata.userConfigFiles || [],
86908
- ...USER_CONFIG_PATTERNS,
86909
- ...userConfigFiles
86910
- ])
86911
- ];
86912
86144
  const metadata = {
86913
86145
  kits: {
86914
86146
  ...existingKits,
@@ -86918,7 +86150,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
86918
86150
  name: otherKitsExist ? existingMetadata.name ?? kitName : kitName,
86919
86151
  version: otherKitsExist ? existingMetadata.version ?? version : version,
86920
86152
  installedAt: otherKitsExist ? existingMetadata.installedAt ?? installedAt : installedAt,
86921
- userConfigFiles: mergedUserConfigFiles
86153
+ userConfigFiles: [...USER_CONFIG_PATTERNS, ...userConfigFiles]
86922
86154
  };
86923
86155
  const validated = MetadataSchema.parse(metadata);
86924
86156
  await import_fs_extra14.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
@@ -86931,7 +86163,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
86931
86163
  }
86932
86164
  }
86933
86165
  async function removeKitFromManifest(claudeDir2, kit) {
86934
- const metadataPath = join80(claudeDir2, "metadata.json");
86166
+ const metadataPath = join81(claudeDir2, "metadata.json");
86935
86167
  if (!await import_fs_extra14.pathExists(metadataPath))
86936
86168
  return false;
86937
86169
  let release = null;
@@ -87061,7 +86293,7 @@ function buildFileTrackingList(options2) {
87061
86293
  if (!isGlobal && !installedPath.startsWith(".claude/"))
87062
86294
  continue;
87063
86295
  const relativePath = isGlobal ? installedPath : installedPath.replace(/^\.claude\//, "");
87064
- const filePath = join81(claudeDir2, relativePath);
86296
+ const filePath = join82(claudeDir2, relativePath);
87065
86297
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
87066
86298
  const ownership = manifestEntry ? "ck" : "user";
87067
86299
  filesToTrack.push({
@@ -87168,7 +86400,7 @@ class LegacyMigration {
87168
86400
  continue;
87169
86401
  if (SKIP_DIRS_ALL.includes(entry))
87170
86402
  continue;
87171
- const fullPath = join82(dir, entry);
86403
+ const fullPath = join83(dir, entry);
87172
86404
  let stats;
87173
86405
  try {
87174
86406
  stats = await stat14(fullPath);
@@ -87270,7 +86502,7 @@ User-created files (sample):`);
87270
86502
  ];
87271
86503
  if (filesToChecksum.length > 0) {
87272
86504
  const checksumResults = await mapWithLimit(filesToChecksum, async ({ relativePath, ownership }) => {
87273
- const fullPath = join82(claudeDir2, relativePath);
86505
+ const fullPath = join83(claudeDir2, relativePath);
87274
86506
  const checksum = await OwnershipChecker.calculateChecksum(fullPath);
87275
86507
  return { relativePath, checksum, ownership };
87276
86508
  });
@@ -87291,7 +86523,7 @@ User-created files (sample):`);
87291
86523
  installedAt: new Date().toISOString(),
87292
86524
  files: trackedFiles
87293
86525
  };
87294
- const metadataPath = join82(claudeDir2, "metadata.json");
86526
+ const metadataPath = join83(claudeDir2, "metadata.json");
87295
86527
  await import_fs_extra15.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
87296
86528
  logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
87297
86529
  return true;
@@ -87397,7 +86629,7 @@ function buildConflictSummary(fileConflicts, hookConflicts, mcpConflicts) {
87397
86629
  init_logger();
87398
86630
  init_skip_directories();
87399
86631
  var import_fs_extra16 = __toESM(require_lib3(), 1);
87400
- 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";
87401
86633
 
87402
86634
  class FileScanner2 {
87403
86635
  static async getFiles(dirPath, relativeTo) {
@@ -87413,7 +86645,7 @@ class FileScanner2 {
87413
86645
  logger.debug(`Skipping directory: ${entry}`);
87414
86646
  continue;
87415
86647
  }
87416
- const fullPath = join83(dirPath, entry);
86648
+ const fullPath = join84(dirPath, entry);
87417
86649
  if (!FileScanner2.isSafePath(basePath, fullPath)) {
87418
86650
  logger.warning(`Skipping potentially unsafe path: ${entry}`);
87419
86651
  continue;
@@ -87448,8 +86680,8 @@ class FileScanner2 {
87448
86680
  return files;
87449
86681
  }
87450
86682
  static async findCustomFiles(destDir, sourceDir, subPath) {
87451
- const destSubDir = join83(destDir, subPath);
87452
- const sourceSubDir = join83(sourceDir, subPath);
86683
+ const destSubDir = join84(destDir, subPath);
86684
+ const sourceSubDir = join84(sourceDir, subPath);
87453
86685
  logger.debug(`findCustomFiles - destDir: ${destDir}`);
87454
86686
  logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
87455
86687
  logger.debug(`findCustomFiles - subPath: "${subPath}"`);
@@ -87477,8 +86709,8 @@ class FileScanner2 {
87477
86709
  return customFiles;
87478
86710
  }
87479
86711
  static isSafePath(basePath, targetPath) {
87480
- const resolvedBase = resolve19(basePath);
87481
- const resolvedTarget = resolve19(targetPath);
86712
+ const resolvedBase = resolve18(basePath);
86713
+ const resolvedTarget = resolve18(targetPath);
87482
86714
  return resolvedTarget.startsWith(resolvedBase);
87483
86715
  }
87484
86716
  static toPosixPath(path14) {
@@ -87490,12 +86722,12 @@ class FileScanner2 {
87490
86722
  init_logger();
87491
86723
  var import_fs_extra17 = __toESM(require_lib3(), 1);
87492
86724
  import { lstat as lstat7, mkdir as mkdir27, readdir as readdir21, stat as stat15 } from "node:fs/promises";
87493
- import { join as join85 } from "node:path";
86725
+ import { join as join86 } from "node:path";
87494
86726
 
87495
86727
  // src/services/transformers/commands-prefix/content-transformer.ts
87496
86728
  init_logger();
87497
86729
  import { readFile as readFile42, readdir as readdir20, writeFile as writeFile26 } from "node:fs/promises";
87498
- import { join as join84 } from "node:path";
86730
+ import { join as join85 } from "node:path";
87499
86731
  var TRANSFORMABLE_EXTENSIONS = new Set([
87500
86732
  ".md",
87501
86733
  ".txt",
@@ -87556,7 +86788,7 @@ async function transformCommandReferences(directory, options2 = {}) {
87556
86788
  async function processDirectory(dir) {
87557
86789
  const entries = await readdir20(dir, { withFileTypes: true });
87558
86790
  for (const entry of entries) {
87559
- const fullPath = join84(dir, entry.name);
86791
+ const fullPath = join85(dir, entry.name);
87560
86792
  if (entry.isDirectory()) {
87561
86793
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
87562
86794
  continue;
@@ -87631,14 +86863,14 @@ function shouldApplyPrefix(options2) {
87631
86863
  // src/services/transformers/commands-prefix/prefix-applier.ts
87632
86864
  async function applyPrefix(extractDir) {
87633
86865
  validatePath(extractDir, "extractDir");
87634
- const commandsDir = join85(extractDir, ".claude", "commands");
86866
+ const commandsDir = join86(extractDir, ".claude", "commands");
87635
86867
  if (!await import_fs_extra17.pathExists(commandsDir)) {
87636
86868
  logger.verbose("No commands directory found, skipping prefix application");
87637
86869
  return;
87638
86870
  }
87639
86871
  logger.info("Applying /ck: prefix to slash commands...");
87640
- const backupDir = join85(extractDir, ".commands-backup");
87641
- const tempDir = join85(extractDir, ".commands-prefix-temp");
86872
+ const backupDir = join86(extractDir, ".commands-backup");
86873
+ const tempDir = join86(extractDir, ".commands-prefix-temp");
87642
86874
  try {
87643
86875
  const entries = await readdir21(commandsDir);
87644
86876
  if (entries.length === 0) {
@@ -87646,7 +86878,7 @@ async function applyPrefix(extractDir) {
87646
86878
  return;
87647
86879
  }
87648
86880
  if (entries.length === 1 && entries[0] === "ck") {
87649
- const ckDir2 = join85(commandsDir, "ck");
86881
+ const ckDir2 = join86(commandsDir, "ck");
87650
86882
  const ckStat = await stat15(ckDir2);
87651
86883
  if (ckStat.isDirectory()) {
87652
86884
  logger.verbose("Commands already have /ck: prefix, skipping");
@@ -87656,17 +86888,17 @@ async function applyPrefix(extractDir) {
87656
86888
  await import_fs_extra17.copy(commandsDir, backupDir);
87657
86889
  logger.verbose("Created backup of commands directory");
87658
86890
  await mkdir27(tempDir, { recursive: true });
87659
- const ckDir = join85(tempDir, "ck");
86891
+ const ckDir = join86(tempDir, "ck");
87660
86892
  await mkdir27(ckDir, { recursive: true });
87661
86893
  let processedCount = 0;
87662
86894
  for (const entry of entries) {
87663
- const sourcePath = join85(commandsDir, entry);
86895
+ const sourcePath = join86(commandsDir, entry);
87664
86896
  const stats = await lstat7(sourcePath);
87665
86897
  if (stats.isSymbolicLink()) {
87666
86898
  logger.warning(`Skipping symlink for security: ${entry}`);
87667
86899
  continue;
87668
86900
  }
87669
- const destPath = join85(ckDir, entry);
86901
+ const destPath = join86(ckDir, entry);
87670
86902
  await import_fs_extra17.copy(sourcePath, destPath, {
87671
86903
  overwrite: false,
87672
86904
  errorOnExist: true
@@ -87684,7 +86916,7 @@ async function applyPrefix(extractDir) {
87684
86916
  await import_fs_extra17.move(tempDir, commandsDir);
87685
86917
  await import_fs_extra17.remove(backupDir);
87686
86918
  logger.success("Successfully reorganized commands to /ck: prefix");
87687
- const claudeDir2 = join85(extractDir, ".claude");
86919
+ const claudeDir2 = join86(extractDir, ".claude");
87688
86920
  logger.info("Transforming command references in file contents...");
87689
86921
  const transformResult = await transformCommandReferences(claudeDir2, {
87690
86922
  verbose: logger.isVerbose()
@@ -87722,20 +86954,20 @@ async function applyPrefix(extractDir) {
87722
86954
  // src/services/transformers/commands-prefix/prefix-cleaner.ts
87723
86955
  init_metadata_migration();
87724
86956
  import { lstat as lstat9, readdir as readdir23 } from "node:fs/promises";
87725
- import { join as join87 } from "node:path";
86957
+ import { join as join88 } from "node:path";
87726
86958
  init_logger();
87727
86959
  var import_fs_extra19 = __toESM(require_lib3(), 1);
87728
86960
 
87729
86961
  // src/services/transformers/commands-prefix/file-processor.ts
87730
86962
  import { lstat as lstat8, readdir as readdir22 } from "node:fs/promises";
87731
- import { join as join86 } from "node:path";
86963
+ import { join as join87 } from "node:path";
87732
86964
  init_logger();
87733
86965
  var import_fs_extra18 = __toESM(require_lib3(), 1);
87734
86966
  async function scanDirectoryFiles(dir) {
87735
86967
  const files = [];
87736
86968
  const entries = await readdir22(dir);
87737
86969
  for (const entry of entries) {
87738
- const fullPath = join86(dir, entry);
86970
+ const fullPath = join87(dir, entry);
87739
86971
  const stats = await lstat8(fullPath);
87740
86972
  if (stats.isSymbolicLink()) {
87741
86973
  continue;
@@ -87863,8 +87095,8 @@ function isDifferentKitDirectory(dirName, currentKit) {
87863
87095
  async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
87864
87096
  const { dryRun = false } = options2;
87865
87097
  validatePath(targetDir, "targetDir");
87866
- const claudeDir2 = isGlobal ? targetDir : join87(targetDir, ".claude");
87867
- const commandsDir = join87(claudeDir2, "commands");
87098
+ const claudeDir2 = isGlobal ? targetDir : join88(targetDir, ".claude");
87099
+ const commandsDir = join88(claudeDir2, "commands");
87868
87100
  const accumulator = {
87869
87101
  results: [],
87870
87102
  deletedCount: 0,
@@ -87906,7 +87138,7 @@ async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
87906
87138
  }
87907
87139
  const metadataForChecks = options2.kitType ? createKitSpecificMetadata(metadata, options2.kitType) : metadata;
87908
87140
  for (const entry of entries) {
87909
- const entryPath = join87(commandsDir, entry);
87141
+ const entryPath = join88(commandsDir, entry);
87910
87142
  const stats = await lstat9(entryPath);
87911
87143
  if (stats.isSymbolicLink()) {
87912
87144
  addSymlinkSkip(entry, accumulator);
@@ -87963,7 +87195,7 @@ async function handleMerge(ctx) {
87963
87195
  let customClaudeFiles = [];
87964
87196
  if (!ctx.options.fresh) {
87965
87197
  logger.info("Scanning for custom .claude files...");
87966
- const scanSourceDir = ctx.options.global ? join88(ctx.extractDir, ".claude") : ctx.extractDir;
87198
+ const scanSourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
87967
87199
  const scanTargetSubdir = ctx.options.global ? "" : ".claude";
87968
87200
  customClaudeFiles = await FileScanner2.findCustomFiles(ctx.resolvedDir, scanSourceDir, scanTargetSubdir);
87969
87201
  } else {
@@ -88028,38 +87260,28 @@ async function handleMerge(ctx) {
88028
87260
  return { ...ctx, cancelled: true };
88029
87261
  }
88030
87262
  }
88031
- const sourceDir = ctx.options.global ? join88(ctx.extractDir, ".claude") : ctx.extractDir;
87263
+ const sourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
88032
87264
  await merger.merge(sourceDir, ctx.resolvedDir, ctx.isNonInteractive);
88033
87265
  const fileConflicts = merger.getFileConflicts();
88034
87266
  if (fileConflicts.length > 0 && !ctx.isNonInteractive) {
88035
87267
  const summary = buildConflictSummary(fileConflicts, [], []);
88036
87268
  displayConflictSummary(summary);
88037
87269
  }
88038
- let deferredDeletions = [];
88039
87270
  try {
88040
- 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");
88041
87272
  if (await import_fs_extra20.pathExists(sourceMetadataPath)) {
88042
87273
  const metadataContent = await import_fs_extra20.readFile(sourceMetadataPath, "utf-8");
88043
87274
  const sourceMetadata = JSON.parse(metadataContent);
88044
87275
  if (sourceMetadata.deletions && sourceMetadata.deletions.length > 0) {
88045
- const { categorizeDeletions: categorizeDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
88046
- const categorized = categorizeDeletions2(sourceMetadata.deletions);
88047
- if (categorized.immediate.length > 0) {
88048
- const immediateMetadata = { ...sourceMetadata, deletions: categorized.immediate };
88049
- const deletionResult = await handleDeletions(immediateMetadata, ctx.claudeDir);
88050
- if (deletionResult.deletedPaths.length > 0) {
88051
- logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
88052
- for (const path14 of deletionResult.deletedPaths) {
88053
- logger.verbose(` - ${path14}`);
88054
- }
88055
- }
88056
- if (deletionResult.preservedPaths.length > 0) {
88057
- 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}`);
88058
87281
  }
88059
87282
  }
88060
- if (categorized.deferred.length > 0) {
88061
- deferredDeletions = categorized.deferred;
88062
- 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)`);
88063
87285
  }
88064
87286
  }
88065
87287
  } else {
@@ -88086,12 +87308,11 @@ async function handleMerge(ctx) {
88086
87308
  return {
88087
87309
  ...ctx,
88088
87310
  customClaudeFiles,
88089
- includePatterns,
88090
- deferredDeletions
87311
+ includePatterns
88091
87312
  };
88092
87313
  }
88093
87314
  // src/commands/init/phases/migration-handler.ts
88094
- import { join as join96 } from "node:path";
87315
+ import { join as join97 } from "node:path";
88095
87316
 
88096
87317
  // src/domains/skills/skills-detector.ts
88097
87318
  init_logger();
@@ -88107,7 +87328,7 @@ init_types3();
88107
87328
  var import_fs_extra21 = __toESM(require_lib3(), 1);
88108
87329
  import { createHash as createHash4 } from "node:crypto";
88109
87330
  import { readFile as readFile44, readdir as readdir24, writeFile as writeFile27 } from "node:fs/promises";
88110
- import { join as join89, relative as relative15 } from "node:path";
87331
+ import { join as join90, relative as relative15 } from "node:path";
88111
87332
 
88112
87333
  class SkillsManifestManager {
88113
87334
  static MANIFEST_FILENAME = ".skills-manifest.json";
@@ -88129,12 +87350,12 @@ class SkillsManifestManager {
88129
87350
  return manifest;
88130
87351
  }
88131
87352
  static async writeManifest(skillsDir2, manifest) {
88132
- const manifestPath = join89(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
87353
+ const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
88133
87354
  await writeFile27(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
88134
87355
  logger.debug(`Wrote manifest to: ${manifestPath}`);
88135
87356
  }
88136
87357
  static async readManifest(skillsDir2) {
88137
- const manifestPath = join89(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
87358
+ const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
88138
87359
  if (!await import_fs_extra21.pathExists(manifestPath)) {
88139
87360
  logger.debug(`No manifest found at: ${manifestPath}`);
88140
87361
  return null;
@@ -88157,7 +87378,7 @@ class SkillsManifestManager {
88157
87378
  return "flat";
88158
87379
  }
88159
87380
  for (const dir of dirs.slice(0, 3)) {
88160
- const dirPath = join89(skillsDir2, dir.name);
87381
+ const dirPath = join90(skillsDir2, dir.name);
88161
87382
  const subEntries = await readdir24(dirPath, { withFileTypes: true });
88162
87383
  const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
88163
87384
  if (hasSubdirs) {
@@ -88176,7 +87397,7 @@ class SkillsManifestManager {
88176
87397
  const entries = await readdir24(skillsDir2, { withFileTypes: true });
88177
87398
  for (const entry of entries) {
88178
87399
  if (entry.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
88179
- const skillPath = join89(skillsDir2, entry.name);
87400
+ const skillPath = join90(skillsDir2, entry.name);
88180
87401
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
88181
87402
  skills.push({
88182
87403
  name: entry.name,
@@ -88188,11 +87409,11 @@ class SkillsManifestManager {
88188
87409
  const categories = await readdir24(skillsDir2, { withFileTypes: true });
88189
87410
  for (const category of categories) {
88190
87411
  if (category.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(category.name) && !category.name.startsWith(".")) {
88191
- const categoryPath = join89(skillsDir2, category.name);
87412
+ const categoryPath = join90(skillsDir2, category.name);
88192
87413
  const skillEntries = await readdir24(categoryPath, { withFileTypes: true });
88193
87414
  for (const skillEntry of skillEntries) {
88194
87415
  if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
88195
- const skillPath = join89(categoryPath, skillEntry.name);
87416
+ const skillPath = join90(categoryPath, skillEntry.name);
88196
87417
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
88197
87418
  skills.push({
88198
87419
  name: skillEntry.name,
@@ -88222,7 +87443,7 @@ class SkillsManifestManager {
88222
87443
  const files = [];
88223
87444
  const entries = await readdir24(dirPath, { withFileTypes: true });
88224
87445
  for (const entry of entries) {
88225
- const fullPath = join89(dirPath, entry.name);
87446
+ const fullPath = join90(dirPath, entry.name);
88226
87447
  if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name)) {
88227
87448
  continue;
88228
87449
  }
@@ -88344,7 +87565,7 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
88344
87565
  // src/domains/skills/detection/script-detector.ts
88345
87566
  var import_fs_extra22 = __toESM(require_lib3(), 1);
88346
87567
  import { readdir as readdir25 } from "node:fs/promises";
88347
- import { join as join90 } from "node:path";
87568
+ import { join as join91 } from "node:path";
88348
87569
  async function scanDirectory(skillsDir2) {
88349
87570
  if (!await import_fs_extra22.pathExists(skillsDir2)) {
88350
87571
  return ["flat", []];
@@ -88357,12 +87578,12 @@ async function scanDirectory(skillsDir2) {
88357
87578
  let totalSkillLikeCount = 0;
88358
87579
  const allSkills = [];
88359
87580
  for (const dir of dirs) {
88360
- const dirPath = join90(skillsDir2, dir.name);
87581
+ const dirPath = join91(skillsDir2, dir.name);
88361
87582
  const subEntries = await readdir25(dirPath, { withFileTypes: true });
88362
87583
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
88363
87584
  if (subdirs.length > 0) {
88364
87585
  for (const subdir of subdirs.slice(0, 3)) {
88365
- const subdirPath = join90(dirPath, subdir.name);
87586
+ const subdirPath = join91(dirPath, subdir.name);
88366
87587
  const subdirFiles = await readdir25(subdirPath, { withFileTypes: true });
88367
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"));
88368
87589
  if (hasSkillMarker) {
@@ -88519,12 +87740,12 @@ class SkillsMigrationDetector {
88519
87740
  // src/domains/skills/skills-migrator.ts
88520
87741
  init_logger();
88521
87742
  init_types3();
88522
- import { join as join95 } from "node:path";
87743
+ import { join as join96 } from "node:path";
88523
87744
 
88524
87745
  // src/domains/skills/migrator/migration-executor.ts
88525
87746
  init_logger();
88526
87747
  import { copyFile as copyFile6, mkdir as mkdir28, readdir as readdir26, rm as rm10 } from "node:fs/promises";
88527
- import { join as join91 } from "node:path";
87748
+ import { join as join92 } from "node:path";
88528
87749
  var import_fs_extra24 = __toESM(require_lib3(), 1);
88529
87750
 
88530
87751
  // src/domains/skills/skills-migration-prompts.ts
@@ -88689,8 +87910,8 @@ async function copySkillDirectory(sourceDir, destDir) {
88689
87910
  await mkdir28(destDir, { recursive: true });
88690
87911
  const entries = await readdir26(sourceDir, { withFileTypes: true });
88691
87912
  for (const entry of entries) {
88692
- const sourcePath = join91(sourceDir, entry.name);
88693
- const destPath = join91(destDir, entry.name);
87913
+ const sourcePath = join92(sourceDir, entry.name);
87914
+ const destPath = join92(destDir, entry.name);
88694
87915
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
88695
87916
  continue;
88696
87917
  }
@@ -88705,7 +87926,7 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
88705
87926
  const migrated = [];
88706
87927
  const preserved = [];
88707
87928
  const errors2 = [];
88708
- const tempDir = join91(currentSkillsDir, "..", ".skills-migration-temp");
87929
+ const tempDir = join92(currentSkillsDir, "..", ".skills-migration-temp");
88709
87930
  await mkdir28(tempDir, { recursive: true });
88710
87931
  try {
88711
87932
  for (const mapping of mappings) {
@@ -88726,9 +87947,9 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
88726
87947
  }
88727
87948
  }
88728
87949
  const category = mapping.category;
88729
- const targetPath = category ? join91(tempDir, category, skillName) : join91(tempDir, skillName);
87950
+ const targetPath = category ? join92(tempDir, category, skillName) : join92(tempDir, skillName);
88730
87951
  if (category) {
88731
- await mkdir28(join91(tempDir, category), { recursive: true });
87952
+ await mkdir28(join92(tempDir, category), { recursive: true });
88732
87953
  }
88733
87954
  await copySkillDirectory(currentSkillPath, targetPath);
88734
87955
  migrated.push(skillName);
@@ -88795,7 +88016,7 @@ init_logger();
88795
88016
  init_types3();
88796
88017
  var import_fs_extra25 = __toESM(require_lib3(), 1);
88797
88018
  import { copyFile as copyFile7, mkdir as mkdir29, readdir as readdir27, rm as rm11, stat as stat16 } from "node:fs/promises";
88798
- 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";
88799
88020
  function validatePath2(path14, paramName) {
88800
88021
  if (!path14 || typeof path14 !== "string") {
88801
88022
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -88821,7 +88042,7 @@ class SkillsBackupManager {
88821
88042
  const timestamp = Date.now();
88822
88043
  const randomSuffix = Math.random().toString(36).substring(2, 8);
88823
88044
  const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
88824
- const backupDir = parentDir ? join92(parentDir, backupDirName) : join92(skillsDir2, "..", backupDirName);
88045
+ const backupDir = parentDir ? join93(parentDir, backupDirName) : join93(skillsDir2, "..", backupDirName);
88825
88046
  logger.info(`Creating backup at: ${backupDir}`);
88826
88047
  try {
88827
88048
  await mkdir29(backupDir, { recursive: true });
@@ -88872,7 +88093,7 @@ class SkillsBackupManager {
88872
88093
  }
88873
88094
  try {
88874
88095
  const entries = await readdir27(parentDir, { withFileTypes: true });
88875
- 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));
88876
88097
  backups.sort().reverse();
88877
88098
  return backups;
88878
88099
  } catch (error) {
@@ -88900,8 +88121,8 @@ class SkillsBackupManager {
88900
88121
  static async copyDirectory(sourceDir, destDir) {
88901
88122
  const entries = await readdir27(sourceDir, { withFileTypes: true });
88902
88123
  for (const entry of entries) {
88903
- const sourcePath = join92(sourceDir, entry.name);
88904
- const destPath = join92(destDir, entry.name);
88124
+ const sourcePath = join93(sourceDir, entry.name);
88125
+ const destPath = join93(destDir, entry.name);
88905
88126
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
88906
88127
  continue;
88907
88128
  }
@@ -88917,7 +88138,7 @@ class SkillsBackupManager {
88917
88138
  let size = 0;
88918
88139
  const entries = await readdir27(dirPath, { withFileTypes: true });
88919
88140
  for (const entry of entries) {
88920
- const fullPath = join92(dirPath, entry.name);
88141
+ const fullPath = join93(dirPath, entry.name);
88921
88142
  if (entry.isSymbolicLink()) {
88922
88143
  continue;
88923
88144
  }
@@ -88953,12 +88174,12 @@ init_skip_directories();
88953
88174
  import { createHash as createHash5 } from "node:crypto";
88954
88175
  import { createReadStream as createReadStream3 } from "node:fs";
88955
88176
  import { readFile as readFile45, readdir as readdir28 } from "node:fs/promises";
88956
- import { join as join93, relative as relative16 } from "node:path";
88177
+ import { join as join94, relative as relative16 } from "node:path";
88957
88178
  async function getAllFiles(dirPath) {
88958
88179
  const files = [];
88959
88180
  const entries = await readdir28(dirPath, { withFileTypes: true });
88960
88181
  for (const entry of entries) {
88961
- const fullPath = join93(dirPath, entry.name);
88182
+ const fullPath = join94(dirPath, entry.name);
88962
88183
  if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name) || entry.isSymbolicLink()) {
88963
88184
  continue;
88964
88185
  }
@@ -88972,12 +88193,12 @@ async function getAllFiles(dirPath) {
88972
88193
  return files;
88973
88194
  }
88974
88195
  async function hashFile(filePath) {
88975
- return new Promise((resolve20, reject) => {
88196
+ return new Promise((resolve19, reject) => {
88976
88197
  const hash = createHash5("sha256");
88977
88198
  const stream = createReadStream3(filePath);
88978
88199
  stream.on("data", (chunk) => hash.update(chunk));
88979
88200
  stream.on("end", () => {
88980
- resolve20(hash.digest("hex"));
88201
+ resolve19(hash.digest("hex"));
88981
88202
  });
88982
88203
  stream.on("error", (error) => {
88983
88204
  stream.destroy();
@@ -89085,7 +88306,7 @@ async function detectFileChanges(currentSkillPath, baselineSkillPath) {
89085
88306
  init_types3();
89086
88307
  var import_fs_extra27 = __toESM(require_lib3(), 1);
89087
88308
  import { readdir as readdir29 } from "node:fs/promises";
89088
- import { join as join94, normalize as normalize9 } from "node:path";
88309
+ import { join as join95, normalize as normalize9 } from "node:path";
89089
88310
  function validatePath3(path14, paramName) {
89090
88311
  if (!path14 || typeof path14 !== "string") {
89091
88312
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -89106,13 +88327,13 @@ async function scanSkillsDirectory(skillsDir2) {
89106
88327
  if (dirs.length === 0) {
89107
88328
  return ["flat", []];
89108
88329
  }
89109
- const firstDirPath = join94(skillsDir2, dirs[0].name);
88330
+ const firstDirPath = join95(skillsDir2, dirs[0].name);
89110
88331
  const subEntries = await readdir29(firstDirPath, { withFileTypes: true });
89111
88332
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
89112
88333
  if (subdirs.length > 0) {
89113
88334
  let skillLikeCount = 0;
89114
88335
  for (const subdir of subdirs.slice(0, 3)) {
89115
- const subdirPath = join94(firstDirPath, subdir.name);
88336
+ const subdirPath = join95(firstDirPath, subdir.name);
89116
88337
  const subdirFiles = await readdir29(subdirPath, { withFileTypes: true });
89117
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"));
89118
88339
  if (hasSkillMarker) {
@@ -89122,7 +88343,7 @@ async function scanSkillsDirectory(skillsDir2) {
89122
88343
  if (skillLikeCount > 0) {
89123
88344
  const skills = [];
89124
88345
  for (const dir of dirs) {
89125
- const categoryPath = join94(skillsDir2, dir.name);
88346
+ const categoryPath = join95(skillsDir2, dir.name);
89126
88347
  const skillDirs = await readdir29(categoryPath, { withFileTypes: true });
89127
88348
  skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
89128
88349
  }
@@ -89132,7 +88353,7 @@ async function scanSkillsDirectory(skillsDir2) {
89132
88353
  return ["flat", dirs.map((dir) => dir.name)];
89133
88354
  }
89134
88355
  async function findSkillPath(skillsDir2, skillName) {
89135
- const flatPath = join94(skillsDir2, skillName);
88356
+ const flatPath = join95(skillsDir2, skillName);
89136
88357
  if (await import_fs_extra27.pathExists(flatPath)) {
89137
88358
  return { path: flatPath, category: undefined };
89138
88359
  }
@@ -89141,8 +88362,8 @@ async function findSkillPath(skillsDir2, skillName) {
89141
88362
  if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
89142
88363
  continue;
89143
88364
  }
89144
- const categoryPath = join94(skillsDir2, entry.name);
89145
- const skillPath = join94(categoryPath, skillName);
88365
+ const categoryPath = join95(skillsDir2, entry.name);
88366
+ const skillPath = join95(categoryPath, skillName);
89146
88367
  if (await import_fs_extra27.pathExists(skillPath)) {
89147
88368
  return { path: skillPath, category: entry.name };
89148
88369
  }
@@ -89236,7 +88457,7 @@ class SkillsMigrator {
89236
88457
  }
89237
88458
  }
89238
88459
  if (options2.backup && !options2.dryRun) {
89239
- const claudeDir2 = join95(currentSkillsDir, "..");
88460
+ const claudeDir2 = join96(currentSkillsDir, "..");
89240
88461
  result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir2);
89241
88462
  logger.success(`Backup created at: ${result.backupPath}`);
89242
88463
  }
@@ -89297,7 +88518,7 @@ async function handleMigration(ctx) {
89297
88518
  logger.debug("Skipping skills migration (fresh installation)");
89298
88519
  return ctx;
89299
88520
  }
89300
- const newSkillsDir = join96(ctx.extractDir, ".claude", "skills");
88521
+ const newSkillsDir = join97(ctx.extractDir, ".claude", "skills");
89301
88522
  const currentSkillsDir = PathResolver.buildSkillsPath(ctx.resolvedDir, ctx.options.global);
89302
88523
  if (!await import_fs_extra28.pathExists(newSkillsDir) || !await import_fs_extra28.pathExists(currentSkillsDir)) {
89303
88524
  return ctx;
@@ -89321,13 +88542,13 @@ async function handleMigration(ctx) {
89321
88542
  }
89322
88543
  // src/commands/init/phases/opencode-handler.ts
89323
88544
  import { cp as cp3, readdir as readdir31, rm as rm12 } from "node:fs/promises";
89324
- import { join as join98 } from "node:path";
88545
+ import { join as join99 } from "node:path";
89325
88546
 
89326
88547
  // src/services/transformers/opencode-path-transformer.ts
89327
88548
  init_logger();
89328
88549
  import { readFile as readFile46, readdir as readdir30, writeFile as writeFile28 } from "node:fs/promises";
89329
88550
  import { platform as platform12 } from "node:os";
89330
- import { extname as extname5, join as join97 } from "node:path";
88551
+ import { extname as extname5, join as join98 } from "node:path";
89331
88552
  var IS_WINDOWS2 = platform12() === "win32";
89332
88553
  function getOpenCodeGlobalPath() {
89333
88554
  return "$HOME/.config/opencode/";
@@ -89388,7 +88609,7 @@ async function transformPathsForGlobalOpenCode(directory, options2 = {}) {
89388
88609
  async function processDirectory2(dir) {
89389
88610
  const entries = await readdir30(dir, { withFileTypes: true });
89390
88611
  for (const entry of entries) {
89391
- const fullPath = join97(dir, entry.name);
88612
+ const fullPath = join98(dir, entry.name);
89392
88613
  if (entry.isDirectory()) {
89393
88614
  if (entry.name === "node_modules" || entry.name.startsWith(".")) {
89394
88615
  continue;
@@ -89427,7 +88648,7 @@ async function handleOpenCode(ctx) {
89427
88648
  if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir) {
89428
88649
  return ctx;
89429
88650
  }
89430
- const openCodeSource = join98(ctx.extractDir, ".opencode");
88651
+ const openCodeSource = join99(ctx.extractDir, ".opencode");
89431
88652
  if (!await import_fs_extra29.pathExists(openCodeSource)) {
89432
88653
  logger.debug("No .opencode directory in archive, skipping");
89433
88654
  return ctx;
@@ -89445,8 +88666,8 @@ async function handleOpenCode(ctx) {
89445
88666
  await import_fs_extra29.ensureDir(targetDir);
89446
88667
  const entries = await readdir31(openCodeSource, { withFileTypes: true });
89447
88668
  for (const entry of entries) {
89448
- const sourcePath = join98(openCodeSource, entry.name);
89449
- const targetPath = join98(targetDir, entry.name);
88669
+ const sourcePath = join99(openCodeSource, entry.name);
88670
+ const targetPath = join99(targetDir, entry.name);
89450
88671
  if (await import_fs_extra29.pathExists(targetPath)) {
89451
88672
  if (!ctx.options.forceOverwrite) {
89452
88673
  logger.verbose(`Skipping existing: ${entry.name}`);
@@ -89543,21 +88764,20 @@ Please use only one download method.`);
89543
88764
  }
89544
88765
  // src/commands/init/phases/post-install-handler.ts
89545
88766
  init_projects_registry();
89546
- import { join as join102 } from "node:path";
89547
- init_cc_version_checker();
88767
+ import { join as join100 } from "node:path";
89548
88768
  init_logger();
89549
88769
  init_path_resolver();
89550
- var import_fs_extra33 = __toESM(require_lib3(), 1);
88770
+ var import_fs_extra30 = __toESM(require_lib3(), 1);
89551
88771
  async function handlePostInstall(ctx) {
89552
88772
  if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir || !ctx.claudeDir) {
89553
88773
  return ctx;
89554
88774
  }
89555
88775
  if (ctx.options.global) {
89556
- const claudeMdSource = join102(ctx.extractDir, "CLAUDE.md");
89557
- const claudeMdDest = join102(ctx.resolvedDir, "CLAUDE.md");
89558
- if (await import_fs_extra33.pathExists(claudeMdSource)) {
89559
- if (ctx.options.fresh || !await import_fs_extra33.pathExists(claudeMdDest)) {
89560
- await import_fs_extra33.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);
89561
88781
  logger.success(ctx.options.fresh ? "Replaced CLAUDE.md in global directory (fresh install)" : "Copied CLAUDE.md to global directory");
89562
88782
  } else {
89563
88783
  logger.debug("CLAUDE.md already exists in global directory (preserved)");
@@ -89576,90 +88796,6 @@ async function handlePostInstall(ctx) {
89576
88796
  withSudo: ctx.options.withSudo
89577
88797
  });
89578
88798
  }
89579
- let pluginSupported = false;
89580
- try {
89581
- const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
89582
- await requireCCPluginSupport2();
89583
- pluginSupported = true;
89584
- } catch (error) {
89585
- if (error instanceof CCPluginSupportError) {
89586
- logger.info(`Plugin install skipped: ${error.message}`);
89587
- if (error.code === "cc_version_too_old") {
89588
- logger.info("Upgrade: brew upgrade claude-code (or npm i -g @anthropic-ai/claude-code)");
89589
- }
89590
- if (error.code === "cc_not_found") {
89591
- logger.info("Install Claude Code CLI, then re-run ck init to enable /ck:* plugin skills");
89592
- }
89593
- } else {
89594
- logger.info(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
89595
- }
89596
- }
89597
- let pluginVerified = false;
89598
- if (pluginSupported) {
89599
- try {
89600
- const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
89601
- const pluginResult = await handlePluginInstall2(ctx.extractDir);
89602
- pluginVerified = pluginResult.verified;
89603
- if (pluginResult.error) {
89604
- logger.info(`Plugin install issue: ${pluginResult.error}`);
89605
- }
89606
- } catch (error) {
89607
- logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
89608
- }
89609
- }
89610
- if (ctx.claudeDir && ctx.kitType) {
89611
- try {
89612
- const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
89613
- await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
89614
- pluginInstalled: pluginVerified,
89615
- pluginInstalledAt: new Date().toISOString(),
89616
- pluginVersion: ctx.selectedVersion || "unknown"
89617
- });
89618
- } catch {}
89619
- }
89620
- if (ctx.deferredDeletions?.length && ctx.claudeDir) {
89621
- try {
89622
- const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
89623
- const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
89624
- if (pluginVerified) {
89625
- if (!migration.canDelete) {
89626
- logger.warning("Skill migration metadata unavailable — preserving existing skills (fail-safe)");
89627
- return { ...ctx, installSkills, pluginSupported };
89628
- }
89629
- const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir));
89630
- const safeDeletions = ctx.deferredDeletions.filter((d3) => {
89631
- const dirPath = extractSkillDirFromDeletionPath(d3);
89632
- if (!dirPath)
89633
- return true;
89634
- return !preservedDirs.has(normalizeSkillDir(dirPath));
89635
- });
89636
- if (safeDeletions.length > 0) {
89637
- const { handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
89638
- const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
89639
- if (deferredResult.deletedPaths.length > 0) {
89640
- logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) (replaced by plugin)`);
89641
- }
89642
- }
89643
- } else {
89644
- logger.info("Plugin not verified — keeping existing skills as fallback");
89645
- }
89646
- } catch (error) {
89647
- logger.debug(`Deferred skill deletion failed: ${error}`);
89648
- }
89649
- }
89650
- if (pluginVerified) {
89651
- try {
89652
- const { cleanupOverlappingStandaloneSkills: cleanupOverlappingStandaloneSkills2 } = await Promise.resolve().then(() => (init_standalone_skill_cleanup(), exports_standalone_skill_cleanup));
89653
- const globalClaudeDir = PathResolver.getGlobalKitDir();
89654
- const pluginSkillsDir = join102(PathResolver.getClaudeKitDir(), "marketplace", "plugins", "ck", "skills");
89655
- const overlap = await cleanupOverlappingStandaloneSkills2(globalClaudeDir, pluginSkillsDir);
89656
- if (overlap.removed.length > 0) {
89657
- logger.info(`Cleaned up ${overlap.removed.length} standalone skill(s) now provided by /ck:* plugin`);
89658
- }
89659
- } catch (error) {
89660
- logger.info(`Standalone skill cleanup failed: ${error}`);
89661
- }
89662
- }
89663
88799
  if (!ctx.isNonInteractive) {
89664
88800
  const { isGeminiInstalled: isGeminiInstalled2 } = await Promise.resolve().then(() => (init_package_installer(), exports_package_installer));
89665
88801
  const { checkExistingGeminiConfig: checkExistingGeminiConfig2, findMcpConfigPath: findMcpConfigPath2, processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
@@ -89686,7 +88822,7 @@ async function handlePostInstall(ctx) {
89686
88822
  }
89687
88823
  if (!ctx.options.skipSetup) {
89688
88824
  await promptSetupWizardIfNeeded({
89689
- envPath: join102(ctx.claudeDir, ".env"),
88825
+ envPath: join100(ctx.claudeDir, ".env"),
89690
88826
  claudeDir: ctx.claudeDir,
89691
88827
  isGlobal: ctx.options.global,
89692
88828
  isNonInteractive: ctx.isNonInteractive,
@@ -89703,26 +88839,14 @@ async function handlePostInstall(ctx) {
89703
88839
  }
89704
88840
  return {
89705
88841
  ...ctx,
89706
- installSkills,
89707
- pluginSupported
88842
+ installSkills
89708
88843
  };
89709
88844
  }
89710
- function normalizeSkillDir(path14) {
89711
- return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
89712
- }
89713
- function extractSkillDirFromDeletionPath(path14) {
89714
- const normalized = normalizeSkillDir(path14);
89715
- const parts = normalized.split("/").filter(Boolean);
89716
- if (parts.length < 2 || parts[0] !== "skills") {
89717
- return null;
89718
- }
89719
- return `skills/${parts[1]}`;
89720
- }
89721
88845
  // src/commands/init/phases/selection-handler.ts
89722
88846
  init_config_manager();
89723
88847
  init_github_client();
89724
88848
  import { mkdir as mkdir30 } from "node:fs/promises";
89725
- import { join as join104, resolve as resolve21 } from "node:path";
88849
+ import { join as join102, resolve as resolve20 } from "node:path";
89726
88850
 
89727
88851
  // src/domains/github/kit-access-checker.ts
89728
88852
  init_logger();
@@ -89754,8 +88878,8 @@ async function detectAccessibleKits() {
89754
88878
  // src/domains/github/preflight-checker.ts
89755
88879
  init_logger();
89756
88880
  import { exec as exec8 } from "node:child_process";
89757
- import { promisify as promisify16 } from "node:util";
89758
- var execAsync8 = promisify16(exec8);
88881
+ import { promisify as promisify14 } from "node:util";
88882
+ var execAsync8 = promisify14(exec8);
89759
88883
  function createSuccessfulPreflightResult() {
89760
88884
  return {
89761
88885
  success: true,
@@ -89852,12 +88976,11 @@ async function runPreflightChecks() {
89852
88976
 
89853
88977
  // src/domains/installation/fresh-installer.ts
89854
88978
  init_metadata_migration();
89855
- 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";
89856
88981
  init_logger();
89857
88982
  init_safe_spinner();
89858
- var import_fs_extra34 = __toESM(require_lib3(), 1);
89859
- import { existsSync as existsSync50, readdirSync as readdirSync4, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4 } from "node:fs";
89860
- import { dirname as dirname22, join as join103, resolve as resolve20 } from "node:path";
88983
+ var import_fs_extra31 = __toESM(require_lib3(), 1);
89861
88984
  var CLAUDEKIT_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
89862
88985
  async function analyzeFreshInstallation(claudeDir2) {
89863
88986
  const metadata = await readManifest(claudeDir2);
@@ -89902,15 +89025,15 @@ async function analyzeFreshInstallation(claudeDir2) {
89902
89025
  };
89903
89026
  }
89904
89027
  function cleanupEmptyDirectories2(filePath, claudeDir2) {
89905
- const normalizedClaudeDir = resolve20(claudeDir2);
89906
- let currentDir = resolve20(dirname22(filePath));
89028
+ const normalizedClaudeDir = resolve19(claudeDir2);
89029
+ let currentDir = resolve19(dirname21(filePath));
89907
89030
  while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
89908
89031
  try {
89909
89032
  const entries = readdirSync4(currentDir);
89910
89033
  if (entries.length === 0) {
89911
89034
  rmdirSync2(currentDir);
89912
89035
  logger.debug(`Removed empty directory: ${currentDir}`);
89913
- currentDir = resolve20(dirname22(currentDir));
89036
+ currentDir = resolve19(dirname21(currentDir));
89914
89037
  } else {
89915
89038
  break;
89916
89039
  }
@@ -89927,7 +89050,7 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
89927
89050
  const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
89928
89051
  const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
89929
89052
  for (const file of filesToRemove) {
89930
- const fullPath = join103(claudeDir2, file.path);
89053
+ const fullPath = join101(claudeDir2, file.path);
89931
89054
  try {
89932
89055
  if (existsSync50(fullPath)) {
89933
89056
  unlinkSync4(fullPath);
@@ -89952,13 +89075,13 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
89952
89075
  };
89953
89076
  }
89954
89077
  async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
89955
- const metadataPath = join103(claudeDir2, "metadata.json");
89956
- if (!await import_fs_extra34.pathExists(metadataPath)) {
89078
+ const metadataPath = join101(claudeDir2, "metadata.json");
89079
+ if (!await import_fs_extra31.pathExists(metadataPath)) {
89957
89080
  return;
89958
89081
  }
89959
89082
  let content;
89960
89083
  try {
89961
- content = await import_fs_extra34.readFile(metadataPath, "utf-8");
89084
+ content = await import_fs_extra31.readFile(metadataPath, "utf-8");
89962
89085
  } catch (readError) {
89963
89086
  logger.warning(`Failed to read metadata.json: ${readError instanceof Error ? readError.message : String(readError)}`);
89964
89087
  return;
@@ -89984,7 +89107,7 @@ async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
89984
89107
  metadata.files = metadata.files.filter((f3) => !removedSet.has(f3.path));
89985
89108
  }
89986
89109
  try {
89987
- await import_fs_extra34.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
89110
+ await import_fs_extra31.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
89988
89111
  logger.debug(`Updated metadata.json, removed ${removedFiles.length} file entries`);
89989
89112
  } catch (writeError) {
89990
89113
  logger.warning(`Failed to write metadata.json: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -89995,16 +89118,16 @@ async function removeSubdirectoriesFallback(claudeDir2) {
89995
89118
  const removedFiles = [];
89996
89119
  let removedDirCount = 0;
89997
89120
  for (const subdir of CLAUDEKIT_SUBDIRECTORIES) {
89998
- const subdirPath = join103(claudeDir2, subdir);
89999
- if (await import_fs_extra34.pathExists(subdirPath)) {
89121
+ const subdirPath = join101(claudeDir2, subdir);
89122
+ if (await import_fs_extra31.pathExists(subdirPath)) {
90000
89123
  rmSync3(subdirPath, { recursive: true, force: true });
90001
89124
  removedDirCount++;
90002
89125
  removedFiles.push(`${subdir}/ (entire directory)`);
90003
89126
  logger.debug(`Removed subdirectory: ${subdir}/`);
90004
89127
  }
90005
89128
  }
90006
- const metadataPath = join103(claudeDir2, "metadata.json");
90007
- if (await import_fs_extra34.pathExists(metadataPath)) {
89129
+ const metadataPath = join101(claudeDir2, "metadata.json");
89130
+ if (await import_fs_extra31.pathExists(metadataPath)) {
90008
89131
  unlinkSync4(metadataPath);
90009
89132
  removedFiles.push("metadata.json");
90010
89133
  }
@@ -90017,7 +89140,7 @@ async function removeSubdirectoriesFallback(claudeDir2) {
90017
89140
  };
90018
89141
  }
90019
89142
  async function handleFreshInstallation(claudeDir2, prompts) {
90020
- if (!await import_fs_extra34.pathExists(claudeDir2)) {
89143
+ if (!await import_fs_extra31.pathExists(claudeDir2)) {
90021
89144
  logger.info(".claude directory does not exist, proceeding with fresh installation");
90022
89145
  return true;
90023
89146
  }
@@ -90049,11 +89172,10 @@ async function handleFreshInstallation(claudeDir2, prompts) {
90049
89172
 
90050
89173
  // src/commands/init/phases/selection-handler.ts
90051
89174
  init_claudekit_scanner();
90052
- init_manifest_reader();
90053
89175
  init_logger();
90054
89176
  init_path_resolver();
90055
89177
  init_types3();
90056
- var import_fs_extra35 = __toESM(require_lib3(), 1);
89178
+ var import_fs_extra32 = __toESM(require_lib3(), 1);
90057
89179
 
90058
89180
  // src/commands/init/types.ts
90059
89181
  function isSyncContext(ctx) {
@@ -90222,7 +89344,7 @@ async function handleSelection(ctx) {
90222
89344
  }
90223
89345
  }
90224
89346
  }
90225
- const resolvedDir = resolve21(targetDir);
89347
+ const resolvedDir = resolve20(targetDir);
90226
89348
  logger.info(`Target directory: ${resolvedDir}`);
90227
89349
  if (!ctx.options.global && PathResolver.isLocalSameAsGlobal(resolvedDir)) {
90228
89350
  logger.warning("You're at HOME directory. Installing here modifies your GLOBAL ClaudeKit.");
@@ -90244,7 +89366,7 @@ async function handleSelection(ctx) {
90244
89366
  return { ...ctx, cancelled: true };
90245
89367
  }
90246
89368
  }
90247
- if (!await import_fs_extra35.pathExists(resolvedDir)) {
89369
+ if (!await import_fs_extra32.pathExists(resolvedDir)) {
90248
89370
  if (ctx.options.global) {
90249
89371
  await mkdir30(resolvedDir, { recursive: true });
90250
89372
  logger.info(`Created global directory: ${resolvedDir}`);
@@ -90256,7 +89378,7 @@ async function handleSelection(ctx) {
90256
89378
  }
90257
89379
  if (!ctx.options.fresh) {
90258
89380
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
90259
- const claudeDir2 = prefix ? join104(resolvedDir, prefix) : resolvedDir;
89381
+ const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
90260
89382
  try {
90261
89383
  const existingMetadata = await readManifest(claudeDir2);
90262
89384
  if (existingMetadata?.kits) {
@@ -90288,7 +89410,7 @@ async function handleSelection(ctx) {
90288
89410
  }
90289
89411
  if (ctx.options.fresh) {
90290
89412
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
90291
- const claudeDir2 = prefix ? join104(resolvedDir, prefix) : resolvedDir;
89413
+ const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
90292
89414
  const canProceed = await handleFreshInstallation(claudeDir2, ctx.prompts);
90293
89415
  if (!canProceed) {
90294
89416
  return { ...ctx, cancelled: true };
@@ -90307,7 +89429,7 @@ async function handleSelection(ctx) {
90307
89429
  logger.info("Fetching available versions...");
90308
89430
  let currentVersion = null;
90309
89431
  try {
90310
- const metadataPath = ctx.options.global ? join104(PathResolver.getGlobalKitDir(), "metadata.json") : join104(resolvedDir, ".claude", "metadata.json");
89432
+ const metadataPath = ctx.options.global ? join102(PathResolver.getGlobalKitDir(), "metadata.json") : join102(resolvedDir, ".claude", "metadata.json");
90311
89433
  const metadata = await readClaudeKitMetadata(metadataPath);
90312
89434
  currentVersion = metadata?.version || null;
90313
89435
  if (currentVersion) {
@@ -90381,27 +89503,25 @@ async function handleSelection(ctx) {
90381
89503
  };
90382
89504
  }
90383
89505
  // src/commands/init/phases/sync-handler.ts
90384
- import { copyFile as copyFile8, mkdir as mkdir31, open as open4, readFile as readFile50, rename as rename7, stat as stat17, unlink as unlink11, writeFile as writeFile30 } from "node:fs/promises";
90385
- import { dirname as dirname23, join as join105, resolve as resolve22 } from "node:path";
90386
- init_cc_version_checker();
90387
- 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";
90388
89508
  init_logger();
90389
89509
  init_path_resolver();
90390
- var import_fs_extra36 = __toESM(require_lib3(), 1);
89510
+ var import_fs_extra33 = __toESM(require_lib3(), 1);
90391
89511
  var import_picocolors23 = __toESM(require_picocolors(), 1);
90392
89512
  async function handleSync(ctx) {
90393
89513
  if (!ctx.options.sync) {
90394
89514
  return ctx;
90395
89515
  }
90396
- const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() : resolve22(ctx.options.dir || ".");
90397
- const claudeDir2 = ctx.options.global ? resolvedDir : join105(resolvedDir, ".claude");
90398
- if (!await import_fs_extra36.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)) {
90399
89519
  logger.error("Cannot sync: no .claude directory found");
90400
89520
  ctx.prompts.note("Run 'ck init' without --sync to install first.", "No Installation Found");
90401
89521
  return { ...ctx, cancelled: true };
90402
89522
  }
90403
- const metadataPath = join105(claudeDir2, "metadata.json");
90404
- if (!await import_fs_extra36.pathExists(metadataPath)) {
89523
+ const metadataPath = join103(claudeDir2, "metadata.json");
89524
+ if (!await import_fs_extra33.pathExists(metadataPath)) {
90405
89525
  logger.error("Cannot sync: no metadata.json found");
90406
89526
  ctx.prompts.note(`Your installation may be from an older version.
90407
89527
  Run 'ck init' to update.`, "Legacy Installation");
@@ -90498,42 +89618,17 @@ function getLockTimeout() {
90498
89618
  return timeoutMs;
90499
89619
  }
90500
89620
  var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
90501
- function isProcessAlive(pid) {
90502
- try {
90503
- process.kill(pid, 0);
90504
- return true;
90505
- } catch (error) {
90506
- const code2 = error.code;
90507
- return code2 === "EPERM";
90508
- }
90509
- }
90510
- async function readLockPayload(lockPath) {
90511
- try {
90512
- const raw2 = await readFile50(lockPath, "utf-8");
90513
- const parsed = JSON.parse(raw2);
90514
- if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0) {
90515
- return {
90516
- pid: parsed.pid,
90517
- startedAt: typeof parsed.startedAt === "string" && parsed.startedAt.length > 0 ? parsed.startedAt : "unknown"
90518
- };
90519
- }
90520
- } catch {}
90521
- return null;
90522
- }
90523
89621
  async function acquireSyncLock(global3) {
90524
89622
  const cacheDir = PathResolver.getCacheDir(global3);
90525
- const lockPath = join105(cacheDir, ".sync-lock");
89623
+ const lockPath = join103(cacheDir, ".sync-lock");
90526
89624
  const startTime = Date.now();
90527
89625
  const lockTimeout = getLockTimeout();
90528
- await mkdir31(dirname23(lockPath), { recursive: true });
89626
+ await mkdir31(dirname22(lockPath), { recursive: true });
90529
89627
  while (Date.now() - startTime < lockTimeout) {
90530
89628
  try {
90531
89629
  const handle = await open4(lockPath, "wx");
90532
- await handle.writeFile(JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }), "utf-8");
90533
89630
  return async () => {
90534
- try {
90535
- await handle.close();
90536
- } catch {}
89631
+ await handle.close();
90537
89632
  await unlink11(lockPath).catch(() => {});
90538
89633
  };
90539
89634
  } catch (err) {
@@ -90541,29 +89636,18 @@ async function acquireSyncLock(global3) {
90541
89636
  try {
90542
89637
  const lockStat = await stat17(lockPath);
90543
89638
  const lockAge = Math.abs(Date.now() - lockStat.mtimeMs);
90544
- const lockOwner = await readLockPayload(lockPath);
90545
- if (lockOwner?.pid === process.pid) {
90546
- throw new Error("Sync lock is already held by current process");
90547
- }
90548
- const ownerAlive = lockOwner?.pid ? isProcessAlive(lockOwner.pid) : null;
90549
- if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive !== true) {
90550
- 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)`);
90551
89641
  await unlink11(lockPath).catch(() => {});
90552
89642
  continue;
90553
89643
  }
90554
- if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive === true) {
90555
- logger.debug(`Sync lock older than threshold but owner pid=${lockOwner?.pid} still alive; waiting`);
90556
- }
90557
89644
  } catch (statError) {
90558
- if (statError instanceof Error && statError.message.includes("already held by current process")) {
90559
- throw statError;
90560
- }
90561
89645
  if (statError.code === "ENOENT") {
90562
89646
  continue;
90563
89647
  }
90564
89648
  logger.debug(`Lock stat failed: ${statError}`);
90565
89649
  }
90566
- await new Promise((resolve23) => setTimeout(resolve23, 100));
89650
+ await new Promise((resolve22) => setTimeout(resolve22, 100));
90567
89651
  continue;
90568
89652
  }
90569
89653
  throw err;
@@ -90582,20 +89666,18 @@ async function executeSyncMerge(ctx) {
90582
89666
  const releaseLock = await acquireSyncLock(ctx.options.global);
90583
89667
  try {
90584
89668
  const trackedFiles = ctx.syncTrackedFiles;
90585
- const upstreamDir = ctx.options.global ? join105(ctx.extractDir, ".claude") : ctx.extractDir;
89669
+ const upstreamDir = ctx.options.global ? join103(ctx.extractDir, ".claude") : ctx.extractDir;
90586
89670
  let deletions = [];
90587
89671
  try {
90588
- const sourceMetadataPath = join105(upstreamDir, "metadata.json");
90589
- if (await import_fs_extra36.pathExists(sourceMetadataPath)) {
90590
- const content = await readFile50(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");
90591
89675
  const sourceMetadata = JSON.parse(content);
90592
89676
  deletions = sourceMetadata.deletions || [];
90593
89677
  }
90594
89678
  } catch (error) {
90595
89679
  logger.debug(`Failed to load source metadata for deletion filtering: ${error}`);
90596
89680
  }
90597
- const { categorizeDeletions: categorizeDeletions2, handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
90598
- const categorizedDeletions = categorizeDeletions2(deletions);
90599
89681
  const filteredTrackedFiles = filterDeletionPaths(trackedFiles, deletions);
90600
89682
  if (deletions.length > 0) {
90601
89683
  const filtered = trackedFiles.length - filteredTrackedFiles.length;
@@ -90603,44 +89685,23 @@ async function executeSyncMerge(ctx) {
90603
89685
  }
90604
89686
  logger.info("Analyzing file changes...");
90605
89687
  const plan = await SyncEngine.createSyncPlan(filteredTrackedFiles, ctx.claudeDir, upstreamDir);
90606
- const forceOverwriteNonInteractive = ctx.isNonInteractive && ctx.options.forceOverwrite;
90607
- const autoUpdateQueue = forceOverwriteNonInteractive ? dedupeTrackedFiles([...plan.autoUpdate, ...plan.needsReview]) : plan.autoUpdate;
90608
- const reviewQueue = forceOverwriteNonInteractive ? [] : plan.needsReview;
90609
89688
  displaySyncPlan(plan);
90610
- 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) {
90611
89690
  ctx.prompts.note("All files are up to date or user-owned.", "No Changes Needed");
90612
- }
90613
- if (reviewQueue.length > 0 && ctx.isNonInteractive) {
90614
- logger.error(`Cannot complete sync: ${reviewQueue.length} file(s) require interactive review`);
90615
- ctx.prompts.note(`The following files have local modifications:
90616
- ${reviewQueue.slice(0, 5).map((f3) => ` • ${f3.path}`).join(`
90617
- `)}${reviewQueue.length > 5 ? `
90618
- ... and ${reviewQueue.length - 5} more` : ""}
90619
-
90620
- Options:
90621
- 1. Run 'ck init --sync' without --yes for interactive merge
90622
- 2. Use --force-overwrite to accept all upstream changes
90623
- 3. Manually resolve conflicts before syncing`, "Sync Blocked");
90624
89691
  return { ...ctx, cancelled: true };
90625
89692
  }
90626
- if (forceOverwriteNonInteractive && plan.needsReview.length > 0) {
90627
- logger.info(`--force-overwrite enabled: auto-updating ${plan.needsReview.length} locally modified file(s)`);
90628
- }
90629
- const willModifyFiles = autoUpdateQueue.length > 0 || reviewQueue.length > 0 || categorizedDeletions.immediate.length > 0 || categorizedDeletions.deferred.length > 0;
90630
- if (willModifyFiles) {
90631
- const backupDir = PathResolver.getBackupDir();
90632
- await createBackup(ctx.claudeDir, trackedFiles, backupDir);
90633
- logger.success(`Backup created at ${import_picocolors23.default.dim(backupDir)}`);
90634
- }
90635
- if (autoUpdateQueue.length > 0) {
90636
- 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)...`);
90637
89698
  let updateSuccess = 0;
90638
89699
  let updateFailed = 0;
90639
- for (const file of autoUpdateQueue) {
89700
+ for (const file of plan.autoUpdate) {
90640
89701
  try {
90641
89702
  const sourcePath = await validateSyncPath(upstreamDir, file.path);
90642
89703
  const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
90643
- const targetDir = dirname23(targetPath);
89704
+ const targetDir = join103(targetPath, "..");
90644
89705
  try {
90645
89706
  await mkdir31(targetDir, { recursive: true });
90646
89707
  } catch (mkdirError) {
@@ -90650,7 +89711,7 @@ Options:
90650
89711
  ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
90651
89712
  return { ...ctx, cancelled: true };
90652
89713
  }
90653
- if (errCode === "EROFS" || errCode === "EACCES" || errCode === "EPERM") {
89714
+ if (errCode === "EROFS" || errCode === "EACCES") {
90654
89715
  logger.warning(`Cannot create directory ${file.path}: ${errCode}`);
90655
89716
  updateFailed++;
90656
89717
  continue;
@@ -90668,7 +89729,7 @@ Options:
90668
89729
  ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
90669
89730
  return { ...ctx, cancelled: true };
90670
89731
  }
90671
- if (errCode === "EACCES" || errCode === "EPERM" || errCode === "EROFS") {
89732
+ if (errCode === "EACCES" || errCode === "EPERM") {
90672
89733
  logger.warning(`Permission denied: ${file.path} - check file permissions`);
90673
89734
  updateFailed++;
90674
89735
  } else if (errMsg.includes("Symlink") || errMsg.includes("Path")) {
@@ -90683,22 +89744,19 @@ Options:
90683
89744
  if (updateSuccess > 0) {
90684
89745
  logger.success(`Auto-updated ${updateSuccess} file(s)${updateFailed > 0 ? ` (${updateFailed} failed)` : ""}`);
90685
89746
  }
90686
- if (updateSuccess === 0 && updateFailed > 0) {
90687
- logger.warning("No files were updated due to write errors");
90688
- }
90689
89747
  }
90690
- if (reviewQueue.length > 0 && !ctx.isNonInteractive) {
90691
- 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...`);
90692
89750
  let totalApplied = 0;
90693
89751
  let totalRejected = 0;
90694
89752
  let skippedFiles = 0;
90695
- for (const file of reviewQueue) {
89753
+ for (const file of plan.needsReview) {
90696
89754
  let currentPath;
90697
89755
  let upstreamPath;
90698
89756
  try {
90699
89757
  currentPath = await validateSyncPath(ctx.claudeDir, file.path);
90700
89758
  upstreamPath = await validateSyncPath(upstreamDir, file.path);
90701
- } catch {
89759
+ } catch (error) {
90702
89760
  logger.warning(`Skipping invalid path during review: ${file.path}`);
90703
89761
  skippedFiles++;
90704
89762
  continue;
@@ -90725,7 +89783,7 @@ Options:
90725
89783
  const tempPath = `${currentPath}.tmp.${Date.now()}`;
90726
89784
  try {
90727
89785
  await writeFile30(tempPath, result.result, "utf-8");
90728
- await rename7(tempPath, currentPath);
89786
+ await rename6(tempPath, currentPath);
90729
89787
  } catch (atomicError) {
90730
89788
  await unlink11(tempPath).catch(() => {});
90731
89789
  throw atomicError;
@@ -90746,8 +89804,8 @@ Options:
90746
89804
  console.log("");
90747
89805
  console.log(import_picocolors23.default.bold("Sync Summary:"));
90748
89806
  console.log(import_picocolors23.default.dim("─".repeat(40)));
90749
- if (autoUpdateQueue.length > 0) {
90750
- 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`));
90751
89809
  }
90752
89810
  if (totalApplied > 0) {
90753
89811
  console.log(import_picocolors23.default.green(` ✓ ${totalApplied} hunk(s) applied`));
@@ -90761,96 +89819,23 @@ Options:
90761
89819
  if (plan.skipped.length > 0) {
90762
89820
  console.log(import_picocolors23.default.dim(` ─ ${plan.skipped.length} user-owned file(s) unchanged`));
90763
89821
  }
90764
- }
90765
- if (categorizedDeletions.immediate.length > 0) {
90766
- try {
90767
- const deletionResult = await handleDeletions2({ deletions: categorizedDeletions.immediate }, ctx.claudeDir);
90768
- if (deletionResult.deletedPaths.length > 0) {
90769
- logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
90770
- }
90771
- if (deletionResult.preservedPaths.length > 0) {
90772
- logger.verbose(`Preserved ${deletionResult.preservedPaths.length} user-owned file(s)`);
90773
- }
90774
- } catch (error) {
90775
- logger.debug(`Immediate deletion cleanup failed during sync: ${error}`);
90776
- }
90777
- }
90778
- let pluginSupported = false;
90779
- let pluginVerified = false;
90780
- try {
90781
- const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
90782
- await requireCCPluginSupport2();
90783
- pluginSupported = true;
90784
- } catch (error) {
90785
- if (error instanceof CCPluginSupportError) {
90786
- logger.info(`Plugin install skipped during sync: ${error.message}`);
90787
- if (error.code === "cc_version_too_old") {
90788
- logger.info("Upgrade Claude Code, then re-run: ck init --sync (plugin migration requires >= 1.0.33)");
90789
- }
90790
- if (error.code === "cc_not_found") {
90791
- logger.info("Install Claude Code CLI to enable /ck:* plugin skills");
90792
- }
90793
- } else {
90794
- logger.debug(`Plugin version check failed during sync: ${error instanceof Error ? error.message : "Unknown error"}`);
90795
- }
90796
- }
90797
- if (pluginSupported && ctx.extractDir) {
90798
- try {
90799
- const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
90800
- const pluginResult = await handlePluginInstall2(ctx.extractDir);
90801
- pluginVerified = pluginResult.verified;
90802
- if (pluginResult.error) {
90803
- logger.debug(`Plugin install issue: ${pluginResult.error}`);
90804
- }
90805
- } catch (error) {
90806
- logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
90807
- }
90808
- }
90809
- if (ctx.claudeDir && ctx.kitType) {
90810
- try {
90811
- const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
90812
- await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
90813
- pluginInstalled: pluginVerified,
90814
- pluginInstalledAt: new Date().toISOString(),
90815
- pluginVersion: ctx.selectedVersion || ctx.syncLatestVersion || "unknown"
90816
- });
90817
- } catch {}
90818
- }
90819
- if (categorizedDeletions.deferred.length > 0) {
90820
- if (pluginVerified) {
90821
- try {
90822
- const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
90823
- const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
90824
- if (!migration.canDelete) {
90825
- logger.warning("Skill migration metadata unavailable during sync — preserving existing skills");
90826
- } else {
90827
- const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir2));
90828
- const safeDeletions = categorizedDeletions.deferred.filter((path14) => {
90829
- const skillDir = extractSkillDirFromDeletionPath2(path14);
90830
- return !skillDir || !preservedDirs.has(normalizeSkillDir2(skillDir));
90831
- });
90832
- if (safeDeletions.length > 0) {
90833
- const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
90834
- if (deferredResult.deletedPaths.length > 0) {
90835
- logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) during sync`);
90836
- }
90837
- }
90838
- }
90839
- } catch (error) {
90840
- logger.debug(`Deferred skill cleanup failed during sync: ${error}`);
90841
- }
90842
- } else {
90843
- logger.info("Plugin not verified during sync — keeping existing skills as fallback");
90844
- }
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 };
90845
89834
  }
90846
89835
  ctx.prompts.outro("Config sync completed successfully");
90847
89836
  return { ...ctx, cancelled: true };
90848
89837
  } finally {
90849
- try {
90850
- await releaseLock();
90851
- } catch (error) {
90852
- logger.debug(`Failed to release sync lock: ${error}`);
90853
- }
89838
+ await releaseLock();
90854
89839
  }
90855
89840
  }
90856
89841
  function displaySyncPlan(plan) {
@@ -90885,9 +89870,9 @@ async function createBackup(claudeDir2, files, backupDir) {
90885
89870
  for (const file of files) {
90886
89871
  try {
90887
89872
  const sourcePath = await validateSyncPath(claudeDir2, file.path);
90888
- if (await import_fs_extra36.pathExists(sourcePath)) {
89873
+ if (await import_fs_extra33.pathExists(sourcePath)) {
90889
89874
  const targetPath = await validateSyncPath(backupDir, file.path);
90890
- const targetDir = dirname23(targetPath);
89875
+ const targetDir = join103(targetPath, "..");
90891
89876
  await mkdir31(targetDir, { recursive: true });
90892
89877
  await copyFile8(sourcePath, targetPath);
90893
89878
  }
@@ -90900,27 +89885,9 @@ async function createBackup(claudeDir2, files, backupDir) {
90900
89885
  }
90901
89886
  }
90902
89887
  }
90903
- function dedupeTrackedFiles(files) {
90904
- const deduped = new Map;
90905
- for (const file of files) {
90906
- deduped.set(file.path, file);
90907
- }
90908
- return [...deduped.values()];
90909
- }
90910
- function normalizeSkillDir2(path14) {
90911
- return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
90912
- }
90913
- function extractSkillDirFromDeletionPath2(path14) {
90914
- const normalized = normalizeSkillDir2(path14);
90915
- const parts = normalized.split("/").filter(Boolean);
90916
- if (parts.length < 2 || parts[0] !== "skills") {
90917
- return null;
90918
- }
90919
- return `skills/${parts[1]}`;
90920
- }
90921
89888
  // src/commands/init/phases/transform-handler.ts
90922
89889
  init_config_manager();
90923
- import { join as join109 } from "node:path";
89890
+ import { join as join107 } from "node:path";
90924
89891
 
90925
89892
  // src/services/transformers/folder-path-transformer.ts
90926
89893
  init_logger();
@@ -90929,40 +89896,40 @@ init_types3();
90929
89896
  // src/services/transformers/folder-transform/folder-renamer.ts
90930
89897
  init_logger();
90931
89898
  init_types3();
90932
- var import_fs_extra37 = __toESM(require_lib3(), 1);
90933
- import { rename as rename8, rm as rm13 } from "node:fs/promises";
90934
- import { join as join106, 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";
90935
89902
  async function collectDirsToRename(extractDir, folders) {
90936
89903
  const dirsToRename = [];
90937
89904
  if (folders.docs !== DEFAULT_FOLDERS.docs) {
90938
- const docsPath = join106(extractDir, DEFAULT_FOLDERS.docs);
90939
- if (await import_fs_extra37.pathExists(docsPath)) {
89905
+ const docsPath = join104(extractDir, DEFAULT_FOLDERS.docs);
89906
+ if (await import_fs_extra34.pathExists(docsPath)) {
90940
89907
  dirsToRename.push({
90941
89908
  from: docsPath,
90942
- to: join106(extractDir, folders.docs)
89909
+ to: join104(extractDir, folders.docs)
90943
89910
  });
90944
89911
  }
90945
- const claudeDocsPath = join106(extractDir, ".claude", DEFAULT_FOLDERS.docs);
90946
- if (await import_fs_extra37.pathExists(claudeDocsPath)) {
89912
+ const claudeDocsPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.docs);
89913
+ if (await import_fs_extra34.pathExists(claudeDocsPath)) {
90947
89914
  dirsToRename.push({
90948
89915
  from: claudeDocsPath,
90949
- to: join106(extractDir, ".claude", folders.docs)
89916
+ to: join104(extractDir, ".claude", folders.docs)
90950
89917
  });
90951
89918
  }
90952
89919
  }
90953
89920
  if (folders.plans !== DEFAULT_FOLDERS.plans) {
90954
- const plansPath = join106(extractDir, DEFAULT_FOLDERS.plans);
90955
- if (await import_fs_extra37.pathExists(plansPath)) {
89921
+ const plansPath = join104(extractDir, DEFAULT_FOLDERS.plans);
89922
+ if (await import_fs_extra34.pathExists(plansPath)) {
90956
89923
  dirsToRename.push({
90957
89924
  from: plansPath,
90958
- to: join106(extractDir, folders.plans)
89925
+ to: join104(extractDir, folders.plans)
90959
89926
  });
90960
89927
  }
90961
- const claudePlansPath = join106(extractDir, ".claude", DEFAULT_FOLDERS.plans);
90962
- if (await import_fs_extra37.pathExists(claudePlansPath)) {
89928
+ const claudePlansPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.plans);
89929
+ if (await import_fs_extra34.pathExists(claudePlansPath)) {
90963
89930
  dirsToRename.push({
90964
89931
  from: claudePlansPath,
90965
- to: join106(extractDir, ".claude", folders.plans)
89932
+ to: join104(extractDir, ".claude", folders.plans)
90966
89933
  });
90967
89934
  }
90968
89935
  }
@@ -90970,11 +89937,11 @@ async function collectDirsToRename(extractDir, folders) {
90970
89937
  }
90971
89938
  async function moveAcrossDevices(src, dest) {
90972
89939
  try {
90973
- await rename8(src, dest);
89940
+ await rename7(src, dest);
90974
89941
  } catch (e2) {
90975
89942
  if (e2.code === "EXDEV") {
90976
89943
  logger.debug(`Cross-device move detected, using copy+delete: ${src} -> ${dest}`);
90977
- await import_fs_extra37.copy(src, dest, { overwrite: true });
89944
+ await import_fs_extra34.copy(src, dest, { overwrite: true });
90978
89945
  await rm13(src, { recursive: true, force: true });
90979
89946
  } else {
90980
89947
  throw e2;
@@ -91002,8 +89969,8 @@ async function renameFolders(dirsToRename, extractDir, options2) {
91002
89969
  // src/services/transformers/folder-transform/path-replacer.ts
91003
89970
  init_logger();
91004
89971
  init_types3();
91005
- import { readFile as readFile51, readdir as readdir33, writeFile as writeFile31 } from "node:fs/promises";
91006
- import { join as join107, 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";
91007
89974
  var TRANSFORMABLE_FILE_PATTERNS = [
91008
89975
  ".md",
91009
89976
  ".txt",
@@ -91054,9 +90021,9 @@ function compileReplacements(replacements) {
91054
90021
  async function transformFileContents(dir, compiledReplacements, options2) {
91055
90022
  let filesChanged = 0;
91056
90023
  let replacementsCount = 0;
91057
- const entries = await readdir33(dir, { withFileTypes: true });
90024
+ const entries = await readdir32(dir, { withFileTypes: true });
91058
90025
  for (const entry of entries) {
91059
- const fullPath = join107(dir, entry.name);
90026
+ const fullPath = join105(dir, entry.name);
91060
90027
  if (entry.isDirectory()) {
91061
90028
  if (entry.name === "node_modules" || entry.name === ".git") {
91062
90029
  continue;
@@ -91069,7 +90036,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
91069
90036
  if (!shouldTransform)
91070
90037
  continue;
91071
90038
  try {
91072
- const content = await readFile51(fullPath, "utf-8");
90039
+ const content = await readFile49(fullPath, "utf-8");
91073
90040
  let newContent = content;
91074
90041
  let changeCount = 0;
91075
90042
  for (const { regex: regex2, replacement } of compiledReplacements) {
@@ -91191,9 +90158,9 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
91191
90158
 
91192
90159
  // src/services/transformers/global-path-transformer.ts
91193
90160
  init_logger();
91194
- import { readFile as readFile52, readdir as readdir34, writeFile as writeFile32 } from "node:fs/promises";
90161
+ import { readFile as readFile50, readdir as readdir33, writeFile as writeFile32 } from "node:fs/promises";
91195
90162
  import { platform as platform13 } from "node:os";
91196
- import { extname as extname6, join as join108 } from "node:path";
90163
+ import { extname as extname6, join as join106 } from "node:path";
91197
90164
  var IS_WINDOWS3 = platform13() === "win32";
91198
90165
  var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
91199
90166
  function getHomeDirPrefix() {
@@ -91301,9 +90268,9 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
91301
90268
  let filesSkipped = 0;
91302
90269
  const skippedFiles = [];
91303
90270
  async function processDirectory2(dir) {
91304
- const entries = await readdir34(dir, { withFileTypes: true });
90271
+ const entries = await readdir33(dir, { withFileTypes: true });
91305
90272
  for (const entry of entries) {
91306
- const fullPath = join108(dir, entry.name);
90273
+ const fullPath = join106(dir, entry.name);
91307
90274
  if (entry.isDirectory()) {
91308
90275
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
91309
90276
  continue;
@@ -91311,7 +90278,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
91311
90278
  await processDirectory2(fullPath);
91312
90279
  } else if (entry.isFile() && shouldTransformFile3(entry.name)) {
91313
90280
  try {
91314
- const content = await readFile52(fullPath, "utf-8");
90281
+ const content = await readFile50(fullPath, "utf-8");
91315
90282
  const { transformed, changes } = transformContent(content);
91316
90283
  if (changes > 0) {
91317
90284
  await writeFile32(fullPath, transformed, "utf-8");
@@ -91379,7 +90346,7 @@ async function handleTransforms(ctx) {
91379
90346
  logger.debug(ctx.options.global ? "Saved folder configuration to ~/.claude/.ck.json" : "Saved folder configuration to .claude/.ck.json");
91380
90347
  }
91381
90348
  }
91382
- const claudeDir2 = ctx.options.global ? ctx.resolvedDir : join109(ctx.resolvedDir, ".claude");
90349
+ const claudeDir2 = ctx.options.global ? ctx.resolvedDir : join107(ctx.resolvedDir, ".claude");
91383
90350
  return {
91384
90351
  ...ctx,
91385
90352
  foldersConfig,
@@ -91573,8 +90540,8 @@ init_checksum_utils();
91573
90540
  init_config_discovery();
91574
90541
  var import_picocolors25 = __toESM(require_picocolors(), 1);
91575
90542
  import { existsSync as existsSync51 } from "node:fs";
91576
- import { readFile as readFile53, rm as rm14, unlink as unlink12 } from "node:fs/promises";
91577
- 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";
91578
90545
 
91579
90546
  // src/commands/portable/conflict-resolver.ts
91580
90547
  init_dist2();
@@ -91921,7 +90888,7 @@ function shouldExecuteAction2(action) {
91921
90888
  }
91922
90889
  async function executeDeleteAction(action, options2) {
91923
90890
  const preservePaths = options2?.preservePaths ?? new Set;
91924
- const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(resolve23(action.targetPath));
90891
+ const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(resolve22(action.targetPath));
91925
90892
  try {
91926
90893
  if (!shouldPreserveTarget && action.targetPath && existsSync51(action.targetPath)) {
91927
90894
  await rm14(action.targetPath, { recursive: true, force: true });
@@ -92146,7 +91113,7 @@ async function migrateCommand(options2) {
92146
91113
  for (const action of conflictActions) {
92147
91114
  if (!action.diff && action.targetPath && existsSync51(action.targetPath)) {
92148
91115
  try {
92149
- const targetContent = await readFile53(action.targetPath, "utf-8");
91116
+ const targetContent = await readFile51(action.targetPath, "utf-8");
92150
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);
92151
91118
  if (sourceItem) {
92152
91119
  const providerConfig = providers[action.provider];
@@ -92237,7 +91204,7 @@ async function migrateCommand(options2) {
92237
91204
  allResults.push(...await installSkillDirectories(skills, skillProviders, installOpts));
92238
91205
  }
92239
91206
  }
92240
- 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)));
92241
91208
  for (const deleteAction of plannedDeleteActions) {
92242
91209
  allResults.push(await executeDeleteAction(deleteAction, {
92243
91210
  preservePaths: writtenPaths
@@ -92353,7 +91320,7 @@ async function computeTargetStates(selectedProviders, global3) {
92353
91320
  exists: true
92354
91321
  };
92355
91322
  try {
92356
- const content = await readFile53(entry.path, "utf-8");
91323
+ const content = await readFile51(entry.path, "utf-8");
92357
91324
  state.currentChecksum = computeContentChecksum(content);
92358
91325
  } catch (error) {
92359
91326
  logger.debug(`[migrate] Failed to read target for checksum: ${entry.path} (${String(error)})`);
@@ -92412,11 +91379,11 @@ var import_picocolors26 = __toESM(require_picocolors(), 1);
92412
91379
 
92413
91380
  // src/commands/new/phases/directory-setup.ts
92414
91381
  init_config_manager();
92415
- import { resolve as resolve24 } from "node:path";
91382
+ import { resolve as resolve23 } from "node:path";
92416
91383
  init_logger();
92417
91384
  init_path_resolver();
92418
91385
  init_types3();
92419
- var import_fs_extra38 = __toESM(require_lib3(), 1);
91386
+ var import_fs_extra35 = __toESM(require_lib3(), 1);
92420
91387
  async function directorySetup(validOptions, prompts) {
92421
91388
  const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
92422
91389
  const config = await ConfigManager.get();
@@ -92497,7 +91464,7 @@ async function directorySetup(validOptions, prompts) {
92497
91464
  targetDir = await prompts.getDirectory(targetDir);
92498
91465
  }
92499
91466
  }
92500
- const resolvedDir = resolve24(targetDir);
91467
+ const resolvedDir = resolve23(targetDir);
92501
91468
  logger.info(`Target directory: ${resolvedDir}`);
92502
91469
  if (PathResolver.isLocalSameAsGlobal(resolvedDir)) {
92503
91470
  logger.warning("You're creating a project at HOME directory.");
@@ -92515,8 +91482,8 @@ async function directorySetup(validOptions, prompts) {
92515
91482
  return null;
92516
91483
  }
92517
91484
  }
92518
- if (await import_fs_extra38.pathExists(resolvedDir)) {
92519
- const files = await import_fs_extra38.readdir(resolvedDir);
91485
+ if (await import_fs_extra35.pathExists(resolvedDir)) {
91486
+ const files = await import_fs_extra35.readdir(resolvedDir);
92520
91487
  const isEmpty = files.length === 0;
92521
91488
  if (!isEmpty) {
92522
91489
  if (isNonInteractive2) {
@@ -92554,7 +91521,7 @@ async function handleDirectorySetup(ctx) {
92554
91521
  // src/commands/new/phases/project-creation.ts
92555
91522
  init_config_manager();
92556
91523
  init_github_client();
92557
- import { join as join110 } from "node:path";
91524
+ import { join as join108 } from "node:path";
92558
91525
  init_logger();
92559
91526
  init_output_manager();
92560
91527
  init_types3();
@@ -92680,7 +91647,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
92680
91647
  output.section("Installing");
92681
91648
  logger.verbose("Installation target", { directory: resolvedDir });
92682
91649
  const merger = new FileMerger;
92683
- const claudeDir2 = join110(resolvedDir, ".claude");
91650
+ const claudeDir2 = join108(resolvedDir, ".claude");
92684
91651
  merger.setMultiKitContext(claudeDir2, kit);
92685
91652
  if (validOptions.exclude && validOptions.exclude.length > 0) {
92686
91653
  merger.addIgnorePatterns(validOptions.exclude);
@@ -92727,7 +91694,7 @@ async function handleProjectCreation(ctx) {
92727
91694
  }
92728
91695
  // src/commands/new/phases/post-setup.ts
92729
91696
  init_projects_registry();
92730
- import { join as join111 } from "node:path";
91697
+ import { join as join109 } from "node:path";
92731
91698
  init_package_installer();
92732
91699
  init_logger();
92733
91700
  init_path_resolver();
@@ -92759,9 +91726,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
92759
91726
  withSudo: validOptions.withSudo
92760
91727
  });
92761
91728
  }
92762
- const claudeDir2 = join111(resolvedDir, ".claude");
91729
+ const claudeDir2 = join109(resolvedDir, ".claude");
92763
91730
  await promptSetupWizardIfNeeded({
92764
- envPath: join111(claudeDir2, ".env"),
91731
+ envPath: join109(claudeDir2, ".env"),
92765
91732
  claudeDir: claudeDir2,
92766
91733
  isGlobal: false,
92767
91734
  isNonInteractive: isNonInteractive2,
@@ -92834,11 +91801,11 @@ init_logger();
92834
91801
  init_safe_prompts();
92835
91802
  var import_picocolors27 = __toESM(require_picocolors(), 1);
92836
91803
  import { existsSync as existsSync52 } from "node:fs";
92837
- import { resolve as resolve25 } from "node:path";
91804
+ import { resolve as resolve24 } from "node:path";
92838
91805
  async function handleAdd(projectPath, options2) {
92839
91806
  logger.debug(`Adding project: ${projectPath}, options: ${JSON.stringify(options2)}`);
92840
91807
  intro("Add Project");
92841
- const absolutePath = resolve25(projectPath);
91808
+ const absolutePath = resolve24(projectPath);
92842
91809
  if (!existsSync52(absolutePath)) {
92843
91810
  log.error(`Path does not exist: ${absolutePath}`);
92844
91811
  process.exitCode = 1;
@@ -93728,7 +92695,7 @@ var import_picocolors32 = __toESM(require_picocolors(), 1);
93728
92695
  // src/commands/uninstall/installation-detector.ts
93729
92696
  init_claudekit_scanner();
93730
92697
  init_path_resolver();
93731
- var import_fs_extra39 = __toESM(require_lib3(), 1);
92698
+ var import_fs_extra36 = __toESM(require_lib3(), 1);
93732
92699
  function hasClaudeKitComponents(components) {
93733
92700
  return components.agents > 0 || components.commands > 0 || components.rules > 0 || components.skills > 0;
93734
92701
  }
@@ -93743,7 +92710,7 @@ async function detectInstallations() {
93743
92710
  installations.push({
93744
92711
  type: "local",
93745
92712
  path: setup.project.path,
93746
- exists: await import_fs_extra39.pathExists(setup.project.path),
92713
+ exists: await import_fs_extra36.pathExists(setup.project.path),
93747
92714
  hasMetadata,
93748
92715
  components: setup.project.components
93749
92716
  });
@@ -93756,7 +92723,7 @@ async function detectInstallations() {
93756
92723
  installations.push({
93757
92724
  type: "global",
93758
92725
  path: setup.global.path,
93759
- exists: await import_fs_extra39.pathExists(setup.global.path),
92726
+ exists: await import_fs_extra36.pathExists(setup.global.path),
93760
92727
  hasMetadata,
93761
92728
  components: setup.global.components
93762
92729
  });
@@ -93767,16 +92734,16 @@ async function detectInstallations() {
93767
92734
 
93768
92735
  // src/commands/uninstall/removal-handler.ts
93769
92736
  import { readdirSync as readdirSync6, rmSync as rmSync5 } from "node:fs";
93770
- import { join as join113, resolve as resolve26, sep as sep5 } from "node:path";
92737
+ import { join as join111, resolve as resolve25, sep as sep5 } from "node:path";
93771
92738
  init_logger();
93772
92739
  init_safe_prompts();
93773
92740
  init_safe_spinner();
93774
- var import_fs_extra40 = __toESM(require_lib3(), 1);
92741
+ var import_fs_extra37 = __toESM(require_lib3(), 1);
93775
92742
 
93776
92743
  // src/commands/uninstall/analysis-handler.ts
93777
92744
  init_metadata_migration();
93778
92745
  import { readdirSync as readdirSync5, rmSync as rmSync4 } from "node:fs";
93779
- import { dirname as dirname24, join as join112 } from "node:path";
92746
+ import { dirname as dirname23, join as join110 } from "node:path";
93780
92747
  init_logger();
93781
92748
  init_safe_prompts();
93782
92749
  var import_picocolors31 = __toESM(require_picocolors(), 1);
@@ -93794,7 +92761,7 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
93794
92761
  }
93795
92762
  async function cleanupEmptyDirectories3(filePath, installationRoot) {
93796
92763
  let cleaned = 0;
93797
- let currentDir = dirname24(filePath);
92764
+ let currentDir = dirname23(filePath);
93798
92765
  while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
93799
92766
  try {
93800
92767
  const entries = readdirSync5(currentDir);
@@ -93802,7 +92769,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
93802
92769
  rmSync4(currentDir, { recursive: true });
93803
92770
  cleaned++;
93804
92771
  logger.debug(`Removed empty directory: ${currentDir}`);
93805
- currentDir = dirname24(currentDir);
92772
+ currentDir = dirname23(currentDir);
93806
92773
  } else {
93807
92774
  break;
93808
92775
  }
@@ -93824,7 +92791,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
93824
92791
  if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
93825
92792
  const kitFiles = metadata.kits[kit].files || [];
93826
92793
  for (const trackedFile of kitFiles) {
93827
- const filePath = join112(installation.path, trackedFile.path);
92794
+ const filePath = join110(installation.path, trackedFile.path);
93828
92795
  if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
93829
92796
  result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
93830
92797
  continue;
@@ -93854,7 +92821,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
93854
92821
  return result;
93855
92822
  }
93856
92823
  for (const trackedFile of allTrackedFiles) {
93857
- const filePath = join112(installation.path, trackedFile.path);
92824
+ const filePath = join110(installation.path, trackedFile.path);
93858
92825
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
93859
92826
  if (!ownershipResult.exists)
93860
92827
  continue;
@@ -93899,7 +92866,7 @@ function displayDryRunPreview(analysis, installationType) {
93899
92866
  // src/commands/uninstall/removal-handler.ts
93900
92867
  async function isDirectory(filePath) {
93901
92868
  try {
93902
- const stats = await import_fs_extra40.lstat(filePath);
92869
+ const stats = await import_fs_extra37.lstat(filePath);
93903
92870
  return stats.isDirectory();
93904
92871
  } catch {
93905
92872
  logger.debug(`Failed to check if path is directory: ${filePath}`);
@@ -93908,16 +92875,16 @@ async function isDirectory(filePath) {
93908
92875
  }
93909
92876
  async function isPathSafeToRemove(filePath, baseDir) {
93910
92877
  try {
93911
- const resolvedPath = resolve26(filePath);
93912
- const resolvedBase = resolve26(baseDir);
92878
+ const resolvedPath = resolve25(filePath);
92879
+ const resolvedBase = resolve25(baseDir);
93913
92880
  if (!resolvedPath.startsWith(resolvedBase + sep5) && resolvedPath !== resolvedBase) {
93914
92881
  logger.debug(`Path outside installation directory: ${filePath}`);
93915
92882
  return false;
93916
92883
  }
93917
- const stats = await import_fs_extra40.lstat(filePath);
92884
+ const stats = await import_fs_extra37.lstat(filePath);
93918
92885
  if (stats.isSymbolicLink()) {
93919
- const realPath = await import_fs_extra40.realpath(filePath);
93920
- const resolvedReal = resolve26(realPath);
92886
+ const realPath = await import_fs_extra37.realpath(filePath);
92887
+ const resolvedReal = resolve25(realPath);
93921
92888
  if (!resolvedReal.startsWith(resolvedBase + sep5) && resolvedReal !== resolvedBase) {
93922
92889
  logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
93923
92890
  return false;
@@ -93951,15 +92918,15 @@ async function removeInstallations(installations, options2) {
93951
92918
  let removedCount = 0;
93952
92919
  let cleanedDirs = 0;
93953
92920
  for (const item of analysis.toDelete) {
93954
- const filePath = join113(installation.path, item.path);
93955
- if (!await import_fs_extra40.pathExists(filePath))
92921
+ const filePath = join111(installation.path, item.path);
92922
+ if (!await import_fs_extra37.pathExists(filePath))
93956
92923
  continue;
93957
92924
  if (!await isPathSafeToRemove(filePath, installation.path)) {
93958
92925
  logger.debug(`Skipping unsafe path: ${item.path}`);
93959
92926
  continue;
93960
92927
  }
93961
92928
  const isDir = await isDirectory(filePath);
93962
- await import_fs_extra40.remove(filePath);
92929
+ await import_fs_extra37.remove(filePath);
93963
92930
  removedCount++;
93964
92931
  logger.debug(`Removed ${isDir ? "directory" : "file"}: ${item.path}`);
93965
92932
  if (!isDir) {
@@ -94143,12 +93110,6 @@ ${import_picocolors32.default.yellow("User modifications will be permanently del
94143
93110
  forceOverwrite: validOptions.forceOverwrite,
94144
93111
  kit: validOptions.kit
94145
93112
  });
94146
- if (!validOptions.kit || validOptions.kit === "engineer") {
94147
- try {
94148
- const { handlePluginUninstall: handlePluginUninstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
94149
- await handlePluginUninstall2();
94150
- } catch {}
94151
- }
94152
93113
  const kitMsg = validOptions.kit ? ` (${validOptions.kit} kit)` : "";
94153
93114
  prompts.outro(`ClaudeKit${kitMsg} uninstalled successfully!`);
94154
93115
  } catch (error) {
@@ -94350,7 +93311,7 @@ init_logger();
94350
93311
  init_path_resolver();
94351
93312
  init_types3();
94352
93313
  import { existsSync as existsSync53, readFileSync as readFileSync10 } from "node:fs";
94353
- import { join as join114 } from "node:path";
93314
+ import { join as join112 } from "node:path";
94354
93315
  var packageVersion = package_default.version;
94355
93316
  function formatInstalledKits(metadata) {
94356
93317
  if (!metadata.kits || Object.keys(metadata.kits).length === 0) {
@@ -94382,9 +93343,9 @@ async function displayVersion() {
94382
93343
  let localKitVersion = null;
94383
93344
  let isGlobalOnlyKit = false;
94384
93345
  const globalKitDir = PathResolver.getGlobalKitDir();
94385
- const globalMetadataPath = join114(globalKitDir, "metadata.json");
93346
+ const globalMetadataPath = join112(globalKitDir, "metadata.json");
94386
93347
  const prefix = PathResolver.getPathPrefix(false);
94387
- const localMetadataPath = prefix ? join114(process.cwd(), prefix, "metadata.json") : join114(process.cwd(), "metadata.json");
93348
+ const localMetadataPath = prefix ? join112(process.cwd(), prefix, "metadata.json") : join112(process.cwd(), "metadata.json");
94388
93349
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
94389
93350
  if (!isLocalSameAsGlobal && existsSync53(localMetadataPath)) {
94390
93351
  try {
@@ -94777,7 +93738,7 @@ var output2 = new OutputManager2;
94777
93738
 
94778
93739
  // src/shared/temp-cleanup.ts
94779
93740
  init_logger();
94780
- var import_fs_extra41 = __toESM(require_lib3(), 1);
93741
+ var import_fs_extra38 = __toESM(require_lib3(), 1);
94781
93742
  import { rmSync as rmSync6 } from "node:fs";
94782
93743
  var tempDirs2 = new Set;
94783
93744
  async function cleanup() {
@@ -94786,7 +93747,7 @@ async function cleanup() {
94786
93747
  logger.debug(`Cleaning up ${tempDirs2.size} temporary director(ies)...`);
94787
93748
  for (const dir of tempDirs2) {
94788
93749
  try {
94789
- await import_fs_extra41.remove(dir);
93750
+ await import_fs_extra38.remove(dir);
94790
93751
  logger.debug(`Cleaned up temp directory: ${dir}`);
94791
93752
  } catch (error) {
94792
93753
  logger.debug(`Failed to clean temp directory ${dir}: ${error}`);