claudekit-cli 3.9.1 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +373 -134
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12363,6 +12363,231 @@ var init_install_error_handler = __esm(() => {
12363
12363
  init_logger();
12364
12364
  });
12365
12365
 
12366
+ // src/services/package-installer/gemini-mcp-linker.ts
12367
+ var exports_gemini_mcp_linker = {};
12368
+ __export(exports_gemini_mcp_linker, {
12369
+ processGeminiMcpLinking: () => processGeminiMcpLinking,
12370
+ linkGeminiMcpConfig: () => linkGeminiMcpConfig,
12371
+ findMcpConfigPath: () => findMcpConfigPath,
12372
+ checkExistingGeminiConfig: () => checkExistingGeminiConfig,
12373
+ addGeminiToGitignore: () => addGeminiToGitignore
12374
+ });
12375
+ import { existsSync as existsSync7, lstatSync, readlinkSync } from "node:fs";
12376
+ import { mkdir as mkdir9, readFile as readFile14, symlink as symlink2, writeFile as writeFile12 } from "node:fs/promises";
12377
+ import { homedir as homedir4 } from "node:os";
12378
+ import { dirname as dirname6, join as join25, resolve as resolve3 } from "node:path";
12379
+ function getGlobalMcpConfigPath() {
12380
+ return join25(homedir4(), ".claude", ".mcp.json");
12381
+ }
12382
+ function getLocalMcpConfigPath(projectDir) {
12383
+ return join25(projectDir, ".mcp.json");
12384
+ }
12385
+ function findMcpConfigPath(projectDir) {
12386
+ const localPath = getLocalMcpConfigPath(projectDir);
12387
+ if (existsSync7(localPath)) {
12388
+ logger.debug(`Found local MCP config: ${localPath}`);
12389
+ return localPath;
12390
+ }
12391
+ const globalPath = getGlobalMcpConfigPath();
12392
+ if (existsSync7(globalPath)) {
12393
+ logger.debug(`Found global MCP config: ${globalPath}`);
12394
+ return globalPath;
12395
+ }
12396
+ logger.debug("No MCP config found (local or global)");
12397
+ return null;
12398
+ }
12399
+ function checkExistingGeminiConfig(projectDir) {
12400
+ const geminiSettingsPath = join25(projectDir, ".gemini", "settings.json");
12401
+ if (!existsSync7(geminiSettingsPath)) {
12402
+ return { exists: false, isSymlink: false };
12403
+ }
12404
+ try {
12405
+ const stats = lstatSync(geminiSettingsPath);
12406
+ if (stats.isSymbolicLink()) {
12407
+ const target = readlinkSync(geminiSettingsPath);
12408
+ return { exists: true, isSymlink: true, currentTarget: target };
12409
+ }
12410
+ return { exists: true, isSymlink: false };
12411
+ } catch {
12412
+ return { exists: true, isSymlink: false };
12413
+ }
12414
+ }
12415
+ async function readJsonFile(filePath) {
12416
+ try {
12417
+ const content = await readFile14(filePath, "utf-8");
12418
+ return JSON.parse(content);
12419
+ } catch (error) {
12420
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
12421
+ logger.debug(`Failed to read/parse JSON file ${filePath}: ${errorMessage}`);
12422
+ return null;
12423
+ }
12424
+ }
12425
+ async function createSymlink(targetPath, linkPath, projectDir) {
12426
+ const isWindows5 = process.platform === "win32";
12427
+ const linkDir = dirname6(linkPath);
12428
+ if (!existsSync7(linkDir)) {
12429
+ await mkdir9(linkDir, { recursive: true });
12430
+ logger.debug(`Created directory: ${linkDir}`);
12431
+ }
12432
+ const localMcpPath = join25(projectDir, ".mcp.json");
12433
+ const isLocalConfig = targetPath === localMcpPath;
12434
+ const symlinkTarget = isLocalConfig ? "../.mcp.json" : targetPath;
12435
+ try {
12436
+ await symlink2(symlinkTarget, linkPath, isWindows5 ? "file" : undefined);
12437
+ logger.debug(`Created symlink: ${linkPath} → ${symlinkTarget}`);
12438
+ return { success: true, method: "symlink", targetPath };
12439
+ } catch (error) {
12440
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
12441
+ return {
12442
+ success: false,
12443
+ method: "symlink",
12444
+ error: `Failed to create symlink: ${errorMessage}`
12445
+ };
12446
+ }
12447
+ }
12448
+ async function createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath) {
12449
+ const linkDir = dirname6(geminiSettingsPath);
12450
+ if (!existsSync7(linkDir)) {
12451
+ await mkdir9(linkDir, { recursive: true });
12452
+ logger.debug(`Created directory: ${linkDir}`);
12453
+ }
12454
+ const mcpConfig = await readJsonFile(mcpConfigPath);
12455
+ if (!mcpConfig) {
12456
+ return { success: false, method: "merge", error: "Failed to read MCP config" };
12457
+ }
12458
+ const mcpServers = mcpConfig.mcpServers;
12459
+ if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
12460
+ return { success: false, method: "merge", error: "MCP config has no valid mcpServers object" };
12461
+ }
12462
+ const newSettings = { mcpServers };
12463
+ try {
12464
+ await writeFile12(geminiSettingsPath, JSON.stringify(newSettings, null, 2), "utf-8");
12465
+ logger.debug(`Created new Gemini settings with mcpServers: ${geminiSettingsPath}`);
12466
+ return { success: true, method: "merge", targetPath: mcpConfigPath };
12467
+ } catch (error) {
12468
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
12469
+ return {
12470
+ success: false,
12471
+ method: "merge",
12472
+ error: `Failed to write settings: ${errorMessage}`
12473
+ };
12474
+ }
12475
+ }
12476
+ async function mergeGeminiSettings(geminiSettingsPath, mcpConfigPath) {
12477
+ const geminiSettings = await readJsonFile(geminiSettingsPath);
12478
+ if (!geminiSettings) {
12479
+ return { success: false, method: "merge", error: "Failed to read existing Gemini settings" };
12480
+ }
12481
+ const mcpConfig = await readJsonFile(mcpConfigPath);
12482
+ if (!mcpConfig) {
12483
+ return { success: false, method: "merge", error: "Failed to read MCP config" };
12484
+ }
12485
+ const mcpServers = mcpConfig.mcpServers;
12486
+ if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
12487
+ return { success: false, method: "merge", error: "MCP config has no valid mcpServers object" };
12488
+ }
12489
+ const mergedSettings = {
12490
+ ...geminiSettings,
12491
+ mcpServers
12492
+ };
12493
+ try {
12494
+ await writeFile12(geminiSettingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
12495
+ logger.debug(`Merged mcpServers into: ${geminiSettingsPath}`);
12496
+ return { success: true, method: "merge", targetPath: mcpConfigPath };
12497
+ } catch (error) {
12498
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
12499
+ return {
12500
+ success: false,
12501
+ method: "merge",
12502
+ error: `Failed to write merged settings: ${errorMessage}`
12503
+ };
12504
+ }
12505
+ }
12506
+ async function addGeminiToGitignore(projectDir) {
12507
+ const gitignorePath = join25(projectDir, ".gitignore");
12508
+ const geminiPattern = ".gemini/";
12509
+ try {
12510
+ let content = "";
12511
+ if (existsSync7(gitignorePath)) {
12512
+ content = await readFile14(gitignorePath, "utf-8");
12513
+ const lines = content.split(`
12514
+ `).map((line) => line.trim()).filter((line) => !line.startsWith("#"));
12515
+ const geminiPatterns = [".gemini/", ".gemini", "/.gemini/", "/.gemini"];
12516
+ if (lines.some((line) => geminiPatterns.includes(line))) {
12517
+ logger.debug(".gemini/ already in .gitignore");
12518
+ return;
12519
+ }
12520
+ }
12521
+ const newLine = content.endsWith(`
12522
+ `) || content === "" ? "" : `
12523
+ `;
12524
+ const comment = "# Gemini CLI settings (contains user-specific config)";
12525
+ await writeFile12(gitignorePath, `${content}${newLine}${comment}
12526
+ ${geminiPattern}
12527
+ `, "utf-8");
12528
+ logger.debug(`Added ${geminiPattern} to .gitignore`);
12529
+ } catch (error) {
12530
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
12531
+ logger.warning(`Failed to update .gitignore: ${errorMessage}`);
12532
+ }
12533
+ }
12534
+ async function linkGeminiMcpConfig(projectDir, options = {}) {
12535
+ const { skipGitignore = false } = options;
12536
+ const resolvedProjectDir = resolve3(projectDir);
12537
+ const geminiSettingsPath = join25(resolvedProjectDir, ".gemini", "settings.json");
12538
+ const mcpConfigPath = findMcpConfigPath(resolvedProjectDir);
12539
+ if (!mcpConfigPath) {
12540
+ return {
12541
+ success: false,
12542
+ method: "symlink",
12543
+ error: "No MCP config found. Create .mcp.json or ~/.claude/.mcp.json first."
12544
+ };
12545
+ }
12546
+ const existing = checkExistingGeminiConfig(resolvedProjectDir);
12547
+ let result;
12548
+ if (!existing.exists) {
12549
+ result = await createSymlink(mcpConfigPath, geminiSettingsPath, resolvedProjectDir);
12550
+ if (!result.success && process.platform === "win32") {
12551
+ logger.debug("Symlink failed on Windows, falling back to creating new settings with mcpServers");
12552
+ result = await createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath);
12553
+ }
12554
+ } else if (existing.isSymlink) {
12555
+ logger.debug(`Gemini config already symlinked: ${existing.currentTarget}`);
12556
+ result = { success: true, method: "skipped", targetPath: existing.currentTarget };
12557
+ } else {
12558
+ result = await mergeGeminiSettings(geminiSettingsPath, mcpConfigPath);
12559
+ }
12560
+ if (result.success && !skipGitignore) {
12561
+ await addGeminiToGitignore(resolvedProjectDir);
12562
+ }
12563
+ return result;
12564
+ }
12565
+ async function processGeminiMcpLinking(projectDir) {
12566
+ logger.info("Setting up Gemini CLI MCP integration...");
12567
+ const result = await linkGeminiMcpConfig(projectDir);
12568
+ if (result.success) {
12569
+ switch (result.method) {
12570
+ case "symlink":
12571
+ logger.success(`Gemini MCP linked: .gemini/settings.json → ${result.targetPath}`);
12572
+ logger.info("MCP servers will auto-sync with your Claude config.");
12573
+ break;
12574
+ case "merge":
12575
+ logger.success("Gemini MCP config updated (merged mcpServers, preserved your settings)");
12576
+ logger.info("Note: Run 'ck init' again to sync MCP config changes.");
12577
+ break;
12578
+ case "skipped":
12579
+ logger.info("Gemini MCP config already configured.");
12580
+ break;
12581
+ }
12582
+ } else {
12583
+ logger.warning(`Gemini MCP setup incomplete: ${result.error}`);
12584
+ logger.info("Manual setup: mkdir -p .gemini && ln -sf .claude/.mcp.json .gemini/settings.json");
12585
+ }
12586
+ }
12587
+ var init_gemini_mcp_linker = __esm(() => {
12588
+ init_logger();
12589
+ });
12590
+
12366
12591
  // src/services/package-installer/package-installer.ts
12367
12592
  var exports_package_installer = {};
12368
12593
  __export(exports_package_installer, {
@@ -12379,10 +12604,10 @@ __export(exports_package_installer, {
12379
12604
  getPackageVersion: () => getPackageVersion
12380
12605
  });
12381
12606
  import { exec as exec5, execFile as execFile2, spawn } from "node:child_process";
12382
- import { join as join25, resolve as resolve3 } from "node:path";
12607
+ import { join as join26, resolve as resolve4 } from "node:path";
12383
12608
  import { promisify as promisify5 } from "node:util";
12384
12609
  function executeInteractiveScript(command, args, options) {
12385
- return new Promise((resolve4, reject) => {
12610
+ return new Promise((resolve5, reject) => {
12386
12611
  const child = spawn(command, args, {
12387
12612
  stdio: ["ignore", "inherit", "inherit"],
12388
12613
  cwd: options?.cwd,
@@ -12403,7 +12628,7 @@ function executeInteractiveScript(command, args, options) {
12403
12628
  } else if (code2 !== 0) {
12404
12629
  reject(new Error(`Command exited with code ${code2}`));
12405
12630
  } else {
12406
- resolve4();
12631
+ resolve5();
12407
12632
  }
12408
12633
  });
12409
12634
  child.on("error", (error) => {
@@ -12574,7 +12799,7 @@ async function installOpenCode() {
12574
12799
  logger.info(`Installing ${displayName}...`);
12575
12800
  const { unlink: unlink5 } = await import("node:fs/promises");
12576
12801
  const { tmpdir: tmpdir3 } = await import("node:os");
12577
- const tempScriptPath = join25(tmpdir3(), "opencode-install.sh");
12802
+ const tempScriptPath = join26(tmpdir3(), "opencode-install.sh");
12578
12803
  try {
12579
12804
  logger.info("Downloading OpenCode installation script...");
12580
12805
  await execFileAsync("curl", ["-fsSL", "https://opencode.ai/install", "-o", tempScriptPath], {
@@ -12618,7 +12843,7 @@ async function installOpenCode() {
12618
12843
  async function installGemini() {
12619
12844
  return installPackageGlobally("@google/gemini-cli", "Google Gemini CLI");
12620
12845
  }
12621
- async function processPackageInstallations(shouldInstallOpenCode, shouldInstallGemini) {
12846
+ async function processPackageInstallations(shouldInstallOpenCode, shouldInstallGemini, projectDir) {
12622
12847
  const results = {};
12623
12848
  if (shouldInstallOpenCode) {
12624
12849
  const alreadyInstalled = await isOpenCodeInstalled();
@@ -12643,12 +12868,17 @@ async function processPackageInstallations(shouldInstallOpenCode, shouldInstallG
12643
12868
  } else {
12644
12869
  results.gemini = await installGemini();
12645
12870
  }
12871
+ const geminiAvailable = alreadyInstalled || results.gemini?.success;
12872
+ if (projectDir && geminiAvailable) {
12873
+ const { processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
12874
+ await processGeminiMcpLinking2(projectDir);
12875
+ }
12646
12876
  }
12647
12877
  return results;
12648
12878
  }
12649
12879
  function validateScriptPath(skillsDir, scriptPath) {
12650
- const skillsDirResolved = resolve3(skillsDir);
12651
- const scriptPathResolved = resolve3(scriptPath);
12880
+ const skillsDirResolved = resolve4(skillsDir);
12881
+ const scriptPathResolved = resolve4(scriptPath);
12652
12882
  const isWindows5 = process.platform === "win32";
12653
12883
  const skillsDirNormalized = isWindows5 ? skillsDirResolved.toLowerCase() : skillsDirResolved;
12654
12884
  const scriptPathNormalized = isWindows5 ? scriptPathResolved.toLowerCase() : scriptPathResolved;
@@ -12684,11 +12914,11 @@ async function installSkillsDependencies(skillsDir) {
12684
12914
  };
12685
12915
  }
12686
12916
  try {
12687
- const { existsSync: existsSync7 } = await import("node:fs");
12917
+ const { existsSync: existsSync8 } = await import("node:fs");
12688
12918
  const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
12689
12919
  const platform9 = process.platform;
12690
12920
  const scriptName = platform9 === "win32" ? "install.ps1" : "install.sh";
12691
- const scriptPath = join25(skillsDir, scriptName);
12921
+ const scriptPath = join26(skillsDir, scriptName);
12692
12922
  try {
12693
12923
  validateScriptPath(skillsDir, scriptPath);
12694
12924
  } catch (error) {
@@ -12700,11 +12930,11 @@ async function installSkillsDependencies(skillsDir) {
12700
12930
  error: `Path validation failed: ${errorMessage}`
12701
12931
  };
12702
12932
  }
12703
- if (!existsSync7(scriptPath)) {
12933
+ if (!existsSync8(scriptPath)) {
12704
12934
  logger.warning(`Skills installation script not found: ${scriptPath}`);
12705
12935
  logger.info("");
12706
12936
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
12707
- logger.info(` See: ${join25(skillsDir, "INSTALLATION.md")}`);
12937
+ logger.info(` See: ${join26(skillsDir, "INSTALLATION.md")}`);
12708
12938
  logger.info("");
12709
12939
  logger.info("Quick start:");
12710
12940
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -12720,8 +12950,8 @@ async function installSkillsDependencies(skillsDir) {
12720
12950
  logger.info(` Platform: ${platform9 === "win32" ? "Windows (PowerShell)" : "Unix (bash)"}`);
12721
12951
  if (logger.isVerbose()) {
12722
12952
  try {
12723
- const { readFile: readFile14 } = await import("node:fs/promises");
12724
- const scriptContent = await readFile14(scriptPath, "utf-8");
12953
+ const { readFile: readFile15 } = await import("node:fs/promises");
12954
+ const scriptContent = await readFile15(scriptPath, "utf-8");
12725
12955
  const previewLines = scriptContent.split(`
12726
12956
  `).slice(0, 20);
12727
12957
  logger.verbose("Script preview (first 20 lines):");
@@ -12747,7 +12977,7 @@ async function installSkillsDependencies(skillsDir) {
12747
12977
  logger.info(` ${platform9 === "win32" ? `powershell -File "${scriptPath}"` : `bash ${scriptPath}`}`);
12748
12978
  logger.info("");
12749
12979
  logger.info("Or see complete guide:");
12750
- logger.info(` ${join25(skillsDir, "INSTALLATION.md")}`);
12980
+ logger.info(` ${join26(skillsDir, "INSTALLATION.md")}`);
12751
12981
  return {
12752
12982
  success: false,
12753
12983
  package: displayName,
@@ -12802,11 +13032,7 @@ async function installSkillsDependencies(skillsDir) {
12802
13032
  NON_INTERACTIVE: "1"
12803
13033
  };
12804
13034
  if (platform9 === "win32") {
12805
- logger.warning("⚠️ Windows: Respecting system PowerShell execution policy");
12806
- logger.info(" If the script fails, you may need to set execution policy:");
12807
- logger.info(" Set-ExecutionPolicy RemoteSigned -Scope CurrentUser");
12808
- logger.info("");
12809
- await executeInteractiveScript("powershell", ["-File", scriptPath, "-Y"], {
13035
+ await executeInteractiveScript("powershell.exe", ["-NoLogo", "-ExecutionPolicy", "Bypass", "-File", scriptPath, "-Y"], {
12810
13036
  timeout: 600000,
12811
13037
  cwd: skillsDir,
12812
13038
  env: scriptEnv
@@ -12852,7 +13078,7 @@ async function installSkillsDependencies(skillsDir) {
12852
13078
  logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
12853
13079
  logger.info("");
12854
13080
  logger.info("See complete guide:");
12855
- logger.info(` cat ${join25(skillsDir, "INSTALLATION.md")}`);
13081
+ logger.info(` cat ${join26(skillsDir, "INSTALLATION.md")}`);
12856
13082
  logger.info("");
12857
13083
  logger.info("Quick start:");
12858
13084
  logger.info(" cd .claude/skills/ai-multimodal/scripts");
@@ -13528,7 +13754,7 @@ function getPagerArgs(pagerCmd) {
13528
13754
  return [];
13529
13755
  }
13530
13756
  async function trySystemPager(content) {
13531
- return new Promise((resolve7) => {
13757
+ return new Promise((resolve8) => {
13532
13758
  const pagerCmd = process.env.PAGER || "less";
13533
13759
  const pagerArgs = getPagerArgs(pagerCmd);
13534
13760
  try {
@@ -13538,20 +13764,20 @@ async function trySystemPager(content) {
13538
13764
  });
13539
13765
  const timeout = setTimeout(() => {
13540
13766
  pager.kill();
13541
- resolve7(false);
13767
+ resolve8(false);
13542
13768
  }, 30000);
13543
13769
  pager.stdin.write(content);
13544
13770
  pager.stdin.end();
13545
13771
  pager.on("close", (code2) => {
13546
13772
  clearTimeout(timeout);
13547
- resolve7(code2 === 0);
13773
+ resolve8(code2 === 0);
13548
13774
  });
13549
13775
  pager.on("error", () => {
13550
13776
  clearTimeout(timeout);
13551
- resolve7(false);
13777
+ resolve8(false);
13552
13778
  });
13553
13779
  } catch {
13554
- resolve7(false);
13780
+ resolve8(false);
13555
13781
  }
13556
13782
  });
13557
13783
  }
@@ -13578,16 +13804,16 @@ async function basicPager(content) {
13578
13804
  break;
13579
13805
  }
13580
13806
  const remaining = lines.length - currentLine;
13581
- await new Promise((resolve7) => {
13807
+ await new Promise((resolve8) => {
13582
13808
  rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
13583
13809
  if (answer.toLowerCase() === "q") {
13584
13810
  rl.close();
13585
13811
  process.exitCode = 0;
13586
- resolve7();
13812
+ resolve8();
13587
13813
  return;
13588
13814
  }
13589
13815
  process.stdout.write("\x1B[1A\x1B[2K");
13590
- resolve7();
13816
+ resolve8();
13591
13817
  });
13592
13818
  });
13593
13819
  }
@@ -13845,8 +14071,8 @@ var init_help_interceptor = __esm(() => {
13845
14071
  });
13846
14072
 
13847
14073
  // src/index.ts
13848
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
13849
- import { join as join35 } from "path";
14074
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
14075
+ import { join as join36 } from "path";
13850
14076
 
13851
14077
  // node_modules/cac/dist/index.mjs
13852
14078
  import { EventEmitter } from "events";
@@ -14451,7 +14677,7 @@ var cac = (name = "") => new CAC(name);
14451
14677
  // package.json
14452
14678
  var package_default = {
14453
14679
  name: "claudekit-cli",
14454
- version: "3.9.1",
14680
+ version: "3.10.0",
14455
14681
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
14456
14682
  type: "module",
14457
14683
  repository: {
@@ -18295,7 +18521,7 @@ async function doctorCommand(options = {}) {
18295
18521
  }
18296
18522
 
18297
18523
  // src/commands/init.ts
18298
- import { join as join30, resolve as resolve5 } from "node:path";
18524
+ import { join as join31, resolve as resolve6 } from "node:path";
18299
18525
 
18300
18526
  // src/domains/config/config-manager.ts
18301
18527
  init_logger();
@@ -31581,7 +31807,7 @@ class PromptsManager {
31581
31807
 
31582
31808
  // src/services/file-operations/file-scanner.ts
31583
31809
  init_logger();
31584
- import { join as join26, relative as relative7, resolve as resolve4 } from "node:path";
31810
+ import { join as join27, relative as relative7, resolve as resolve5 } from "node:path";
31585
31811
  var import_fs_extra15 = __toESM(require_lib(), 1);
31586
31812
 
31587
31813
  class FileScanner {
@@ -31598,7 +31824,7 @@ class FileScanner {
31598
31824
  logger.debug(`Skipping directory: ${entry}`);
31599
31825
  continue;
31600
31826
  }
31601
- const fullPath = join26(dirPath, entry);
31827
+ const fullPath = join27(dirPath, entry);
31602
31828
  if (!FileScanner.isSafePath(basePath, fullPath)) {
31603
31829
  logger.warning(`Skipping potentially unsafe path: ${entry}`);
31604
31830
  continue;
@@ -31633,8 +31859,8 @@ class FileScanner {
31633
31859
  return files;
31634
31860
  }
31635
31861
  static async findCustomFiles(destDir, sourceDir, subPath) {
31636
- const destSubDir = join26(destDir, subPath);
31637
- const sourceSubDir = join26(sourceDir, subPath);
31862
+ const destSubDir = join27(destDir, subPath);
31863
+ const sourceSubDir = join27(sourceDir, subPath);
31638
31864
  logger.debug(`findCustomFiles - destDir: ${destDir}`);
31639
31865
  logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
31640
31866
  logger.debug(`findCustomFiles - subPath: "${subPath}"`);
@@ -31662,8 +31888,8 @@ class FileScanner {
31662
31888
  return customFiles;
31663
31889
  }
31664
31890
  static isSafePath(basePath, targetPath) {
31665
- const resolvedBase = resolve4(basePath);
31666
- const resolvedTarget = resolve4(targetPath);
31891
+ const resolvedBase = resolve5(basePath);
31892
+ const resolvedTarget = resolve5(targetPath);
31667
31893
  return resolvedTarget.startsWith(resolvedBase);
31668
31894
  }
31669
31895
  static toPosixPath(path9) {
@@ -31672,8 +31898,8 @@ class FileScanner {
31672
31898
  }
31673
31899
 
31674
31900
  // src/services/transformers/commands-prefix.ts
31675
- import { lstat as lstat3, mkdir as mkdir9, readdir as readdir11, stat as stat4 } from "node:fs/promises";
31676
- import { join as join27 } from "node:path";
31901
+ import { lstat as lstat3, mkdir as mkdir10, readdir as readdir11, stat as stat4 } from "node:fs/promises";
31902
+ import { join as join28 } from "node:path";
31677
31903
  init_logger();
31678
31904
  var import_fs_extra16 = __toESM(require_lib(), 1);
31679
31905
  function stripWindowsDrivePrefix(path9) {
@@ -31714,14 +31940,14 @@ function validatePath4(path9, paramName) {
31714
31940
  class CommandsPrefix {
31715
31941
  static async applyPrefix(extractDir) {
31716
31942
  validatePath4(extractDir, "extractDir");
31717
- const commandsDir = join27(extractDir, ".claude", "commands");
31943
+ const commandsDir = join28(extractDir, ".claude", "commands");
31718
31944
  if (!await import_fs_extra16.pathExists(commandsDir)) {
31719
31945
  logger.verbose("No commands directory found, skipping prefix application");
31720
31946
  return;
31721
31947
  }
31722
31948
  logger.info("Applying /ck: prefix to slash commands...");
31723
- const backupDir = join27(extractDir, ".commands-backup");
31724
- const tempDir = join27(extractDir, ".commands-prefix-temp");
31949
+ const backupDir = join28(extractDir, ".commands-backup");
31950
+ const tempDir = join28(extractDir, ".commands-prefix-temp");
31725
31951
  try {
31726
31952
  const entries = await readdir11(commandsDir);
31727
31953
  if (entries.length === 0) {
@@ -31729,7 +31955,7 @@ class CommandsPrefix {
31729
31955
  return;
31730
31956
  }
31731
31957
  if (entries.length === 1 && entries[0] === "ck") {
31732
- const ckDir2 = join27(commandsDir, "ck");
31958
+ const ckDir2 = join28(commandsDir, "ck");
31733
31959
  const ckStat = await stat4(ckDir2);
31734
31960
  if (ckStat.isDirectory()) {
31735
31961
  logger.verbose("Commands already have /ck: prefix, skipping");
@@ -31738,18 +31964,18 @@ class CommandsPrefix {
31738
31964
  }
31739
31965
  await import_fs_extra16.copy(commandsDir, backupDir);
31740
31966
  logger.verbose("Created backup of commands directory");
31741
- await mkdir9(tempDir, { recursive: true });
31742
- const ckDir = join27(tempDir, "ck");
31743
- await mkdir9(ckDir, { recursive: true });
31967
+ await mkdir10(tempDir, { recursive: true });
31968
+ const ckDir = join28(tempDir, "ck");
31969
+ await mkdir10(ckDir, { recursive: true });
31744
31970
  let processedCount = 0;
31745
31971
  for (const entry of entries) {
31746
- const sourcePath = join27(commandsDir, entry);
31972
+ const sourcePath = join28(commandsDir, entry);
31747
31973
  const stats = await lstat3(sourcePath);
31748
31974
  if (stats.isSymbolicLink()) {
31749
31975
  logger.warning(`Skipping symlink for security: ${entry}`);
31750
31976
  continue;
31751
31977
  }
31752
- const destPath = join27(ckDir, entry);
31978
+ const destPath = join28(ckDir, entry);
31753
31979
  await import_fs_extra16.copy(sourcePath, destPath, {
31754
31980
  overwrite: false,
31755
31981
  errorOnExist: true
@@ -31797,8 +32023,8 @@ class CommandsPrefix {
31797
32023
  static async cleanupCommandsDirectory(targetDir, isGlobal, options = {}) {
31798
32024
  const { dryRun = false, forceOverwrite = false } = options;
31799
32025
  validatePath4(targetDir, "targetDir");
31800
- const claudeDir = isGlobal ? targetDir : join27(targetDir, ".claude");
31801
- const commandsDir = join27(claudeDir, "commands");
32026
+ const claudeDir = isGlobal ? targetDir : join28(targetDir, ".claude");
32027
+ const commandsDir = join28(claudeDir, "commands");
31802
32028
  const result = {
31803
32029
  results: [],
31804
32030
  deletedCount: 0,
@@ -31826,7 +32052,7 @@ class CommandsPrefix {
31826
32052
  return result;
31827
32053
  }
31828
32054
  for (const entry of entries) {
31829
- const entryPath = join27(commandsDir, entry);
32055
+ const entryPath = join28(commandsDir, entry);
31830
32056
  const stats = await lstat3(entryPath);
31831
32057
  if (stats.isSymbolicLink()) {
31832
32058
  logger.warning(`Skipping symlink: ${entry}`);
@@ -31992,7 +32218,7 @@ class CommandsPrefix {
31992
32218
  const files = [];
31993
32219
  const entries = await readdir11(dir);
31994
32220
  for (const entry of entries) {
31995
- const fullPath = join27(dir, entry);
32221
+ const fullPath = join28(dir, entry);
31996
32222
  const stats = await lstat3(fullPath);
31997
32223
  if (stats.isSymbolicLink()) {
31998
32224
  continue;
@@ -32011,8 +32237,8 @@ class CommandsPrefix {
32011
32237
  init_logger();
32012
32238
  init_types2();
32013
32239
  var import_fs_extra17 = __toESM(require_lib(), 1);
32014
- import { readFile as readFile14, readdir as readdir12, rename as rename3, writeFile as writeFile12 } from "node:fs/promises";
32015
- import { join as join28, relative as relative8 } from "node:path";
32240
+ import { readFile as readFile15, readdir as readdir12, rename as rename3, writeFile as writeFile13 } from "node:fs/promises";
32241
+ import { join as join29, relative as relative8 } from "node:path";
32016
32242
  var TRANSFORMABLE_FILE_PATTERNS = [
32017
32243
  ".md",
32018
32244
  ".txt",
@@ -32058,34 +32284,34 @@ async function transformFolderPaths(extractDir, folders, options = {}) {
32058
32284
  }
32059
32285
  const dirsToRename = [];
32060
32286
  if (folders.docs !== DEFAULT_FOLDERS.docs) {
32061
- const docsPath = join28(extractDir, DEFAULT_FOLDERS.docs);
32287
+ const docsPath = join29(extractDir, DEFAULT_FOLDERS.docs);
32062
32288
  if (await import_fs_extra17.pathExists(docsPath)) {
32063
32289
  dirsToRename.push({
32064
32290
  from: docsPath,
32065
- to: join28(extractDir, folders.docs)
32291
+ to: join29(extractDir, folders.docs)
32066
32292
  });
32067
32293
  }
32068
- const claudeDocsPath = join28(extractDir, ".claude", DEFAULT_FOLDERS.docs);
32294
+ const claudeDocsPath = join29(extractDir, ".claude", DEFAULT_FOLDERS.docs);
32069
32295
  if (await import_fs_extra17.pathExists(claudeDocsPath)) {
32070
32296
  dirsToRename.push({
32071
32297
  from: claudeDocsPath,
32072
- to: join28(extractDir, ".claude", folders.docs)
32298
+ to: join29(extractDir, ".claude", folders.docs)
32073
32299
  });
32074
32300
  }
32075
32301
  }
32076
32302
  if (folders.plans !== DEFAULT_FOLDERS.plans) {
32077
- const plansPath = join28(extractDir, DEFAULT_FOLDERS.plans);
32303
+ const plansPath = join29(extractDir, DEFAULT_FOLDERS.plans);
32078
32304
  if (await import_fs_extra17.pathExists(plansPath)) {
32079
32305
  dirsToRename.push({
32080
32306
  from: plansPath,
32081
- to: join28(extractDir, folders.plans)
32307
+ to: join29(extractDir, folders.plans)
32082
32308
  });
32083
32309
  }
32084
- const claudePlansPath = join28(extractDir, ".claude", DEFAULT_FOLDERS.plans);
32310
+ const claudePlansPath = join29(extractDir, ".claude", DEFAULT_FOLDERS.plans);
32085
32311
  if (await import_fs_extra17.pathExists(claudePlansPath)) {
32086
32312
  dirsToRename.push({
32087
32313
  from: claudePlansPath,
32088
- to: join28(extractDir, ".claude", folders.plans)
32314
+ to: join29(extractDir, ".claude", folders.plans)
32089
32315
  });
32090
32316
  }
32091
32317
  }
@@ -32122,7 +32348,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
32122
32348
  let replacementsCount = 0;
32123
32349
  const entries = await readdir12(dir, { withFileTypes: true });
32124
32350
  for (const entry of entries) {
32125
- const fullPath = join28(dir, entry.name);
32351
+ const fullPath = join29(dir, entry.name);
32126
32352
  if (entry.isDirectory()) {
32127
32353
  if (entry.name === "node_modules" || entry.name === ".git") {
32128
32354
  continue;
@@ -32135,7 +32361,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
32135
32361
  if (!shouldTransform)
32136
32362
  continue;
32137
32363
  try {
32138
- const content = await readFile14(fullPath, "utf-8");
32364
+ const content = await readFile15(fullPath, "utf-8");
32139
32365
  let newContent = content;
32140
32366
  let changeCount = 0;
32141
32367
  for (const { regex: regex2, replacement } of compiledReplacements) {
@@ -32151,7 +32377,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
32151
32377
  if (options.dryRun) {
32152
32378
  logger.debug(`[dry-run] Would update ${relative8(dir, fullPath)}: ${changeCount} replacement(s)`);
32153
32379
  } else {
32154
- await writeFile12(fullPath, newContent, "utf-8");
32380
+ await writeFile13(fullPath, newContent, "utf-8");
32155
32381
  logger.debug(`Updated ${relative8(dir, fullPath)}: ${changeCount} replacement(s)`);
32156
32382
  }
32157
32383
  filesChanged++;
@@ -32231,9 +32457,9 @@ function validateFolderName(name2) {
32231
32457
 
32232
32458
  // src/services/transformers/global-path-transformer.ts
32233
32459
  init_logger();
32234
- import { readFile as readFile15, readdir as readdir13, writeFile as writeFile13 } from "node:fs/promises";
32460
+ import { readFile as readFile16, readdir as readdir13, writeFile as writeFile14 } from "node:fs/promises";
32235
32461
  import { platform as platform9 } from "node:os";
32236
- import { extname, join as join29 } from "node:path";
32462
+ import { extname, join as join30 } from "node:path";
32237
32463
  var IS_WINDOWS2 = platform9() === "win32";
32238
32464
  var HOME_PREFIX = IS_WINDOWS2 ? "%USERPROFILE%" : "$HOME";
32239
32465
  function getHomeDirPrefix() {
@@ -32325,7 +32551,7 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
32325
32551
  async function processDirectory(dir) {
32326
32552
  const entries = await readdir13(dir, { withFileTypes: true });
32327
32553
  for (const entry of entries) {
32328
- const fullPath = join29(dir, entry.name);
32554
+ const fullPath = join30(dir, entry.name);
32329
32555
  if (entry.isDirectory()) {
32330
32556
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
32331
32557
  continue;
@@ -32333,10 +32559,10 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
32333
32559
  await processDirectory(fullPath);
32334
32560
  } else if (entry.isFile() && shouldTransformFile(entry.name)) {
32335
32561
  try {
32336
- const content = await readFile15(fullPath, "utf-8");
32562
+ const content = await readFile16(fullPath, "utf-8");
32337
32563
  const { transformed, changes } = transformContent(content);
32338
32564
  if (changes > 0) {
32339
- await writeFile13(fullPath, transformed, "utf-8");
32565
+ await writeFile14(fullPath, transformed, "utf-8");
32340
32566
  filesTransformed++;
32341
32567
  totalChanges += changes;
32342
32568
  if (options.verbose) {
@@ -32384,9 +32610,9 @@ async function initCommand(options) {
32384
32610
  }
32385
32611
  if (validOptions.global) {
32386
32612
  const globalKitDir = PathResolver.getGlobalKitDir();
32387
- const cwdResolved = resolve5(process.cwd());
32388
- const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved === resolve5(globalKitDir, "..");
32389
- const localSettingsPath = join30(process.cwd(), ".claude", "settings.json");
32613
+ const cwdResolved = resolve6(process.cwd());
32614
+ const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved === resolve6(globalKitDir, "..");
32615
+ const localSettingsPath = join31(process.cwd(), ".claude", "settings.json");
32390
32616
  if (!isInGlobalDir && await import_fs_extra18.pathExists(localSettingsPath)) {
32391
32617
  if (isNonInteractive2) {
32392
32618
  logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
@@ -32398,7 +32624,7 @@ async function initCommand(options) {
32398
32624
  return;
32399
32625
  }
32400
32626
  if (choice === "remove") {
32401
- const localClaudeDir = join30(process.cwd(), ".claude");
32627
+ const localClaudeDir = join31(process.cwd(), ".claude");
32402
32628
  try {
32403
32629
  await import_fs_extra18.remove(localClaudeDir);
32404
32630
  logger.success("Removed local .claude/ directory");
@@ -32442,12 +32668,12 @@ async function initCommand(options) {
32442
32668
  }
32443
32669
  }
32444
32670
  }
32445
- const resolvedDir = resolve5(targetDir);
32671
+ const resolvedDir = resolve6(targetDir);
32446
32672
  logger.info(`Target directory: ${resolvedDir}`);
32447
32673
  if (!await import_fs_extra18.pathExists(resolvedDir)) {
32448
32674
  if (validOptions.global) {
32449
- const { mkdir: mkdir10 } = await import("node:fs/promises");
32450
- await mkdir10(resolvedDir, { recursive: true });
32675
+ const { mkdir: mkdir11 } = await import("node:fs/promises");
32676
+ await mkdir11(resolvedDir, { recursive: true });
32451
32677
  logger.info(`Created global directory: ${resolvedDir}`);
32452
32678
  } else {
32453
32679
  logger.error(`Directory does not exist: ${resolvedDir}`);
@@ -32457,7 +32683,7 @@ async function initCommand(options) {
32457
32683
  }
32458
32684
  if (validOptions.fresh) {
32459
32685
  const prefix = PathResolver.getPathPrefix(validOptions.global);
32460
- const claudeDir2 = prefix ? join30(resolvedDir, prefix) : resolvedDir;
32686
+ const claudeDir2 = prefix ? join31(resolvedDir, prefix) : resolvedDir;
32461
32687
  const canProceed = await handleFreshInstallation(claudeDir2, prompts);
32462
32688
  if (!canProceed) {
32463
32689
  return;
@@ -32485,7 +32711,7 @@ async function initCommand(options) {
32485
32711
  logger.info("Fetching available versions...");
32486
32712
  let currentVersion = null;
32487
32713
  try {
32488
- const metadataPath = validOptions.global ? join30(PathResolver.getGlobalKitDir(), "metadata.json") : join30(resolvedDir, ".claude", "metadata.json");
32714
+ const metadataPath = validOptions.global ? join31(PathResolver.getGlobalKitDir(), "metadata.json") : join31(resolvedDir, ".claude", "metadata.json");
32489
32715
  const metadata = await readClaudeKitMetadata(metadataPath);
32490
32716
  currentVersion = metadata?.version || null;
32491
32717
  if (currentVersion) {
@@ -32610,7 +32836,7 @@ async function initCommand(options) {
32610
32836
  }
32611
32837
  }
32612
32838
  if (!validOptions.fresh) {
32613
- const newSkillsDir = join30(extractDir, ".claude", "skills");
32839
+ const newSkillsDir = join31(extractDir, ".claude", "skills");
32614
32840
  const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
32615
32841
  if (await import_fs_extra18.pathExists(newSkillsDir) && await import_fs_extra18.pathExists(currentSkillsDir)) {
32616
32842
  logger.info("Checking for skills directory migration...");
@@ -32635,7 +32861,7 @@ async function initCommand(options) {
32635
32861
  let customClaudeFiles = [];
32636
32862
  if (!validOptions.fresh) {
32637
32863
  logger.info("Scanning for custom .claude files...");
32638
- const scanSourceDir = validOptions.global ? join30(extractDir, ".claude") : extractDir;
32864
+ const scanSourceDir = validOptions.global ? join31(extractDir, ".claude") : extractDir;
32639
32865
  const scanTargetSubdir = validOptions.global ? "" : ".claude";
32640
32866
  customClaudeFiles = await FileScanner.findCustomFiles(resolvedDir, scanSourceDir, scanTargetSubdir);
32641
32867
  } else {
@@ -32670,7 +32896,7 @@ async function initCommand(options) {
32670
32896
  }
32671
32897
  merger.setGlobalFlag(validOptions.global);
32672
32898
  merger.setForceOverwriteSettings(validOptions.forceOverwriteSettings);
32673
- const claudeDir = validOptions.global ? resolvedDir : join30(resolvedDir, ".claude");
32899
+ const claudeDir = validOptions.global ? resolvedDir : join31(resolvedDir, ".claude");
32674
32900
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
32675
32901
  if (!validOptions.fresh && await import_fs_extra18.pathExists(claudeDir)) {
32676
32902
  const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
@@ -32692,7 +32918,7 @@ async function initCommand(options) {
32692
32918
  return;
32693
32919
  }
32694
32920
  }
32695
- const sourceDir = validOptions.global ? join30(extractDir, ".claude") : extractDir;
32921
+ const sourceDir = validOptions.global ? join31(extractDir, ".claude") : extractDir;
32696
32922
  await merger.merge(sourceDir, resolvedDir, false);
32697
32923
  const manifestWriter = new ManifestWriter;
32698
32924
  const installedFiles = merger.getAllInstalledFiles();
@@ -32701,7 +32927,7 @@ async function initCommand(options) {
32701
32927
  if (!validOptions.global && !installedPath.startsWith(".claude/"))
32702
32928
  continue;
32703
32929
  const relativePath = validOptions.global ? installedPath : installedPath.replace(/^\.claude\//, "");
32704
- const filePath = join30(claudeDir, relativePath);
32930
+ const filePath = join31(claudeDir, relativePath);
32705
32931
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
32706
32932
  const ownership = manifestEntry ? "ck" : "user";
32707
32933
  filesToTrack.push({
@@ -32722,8 +32948,8 @@ async function initCommand(options) {
32722
32948
  trackingSpinner.succeed(`Tracked ${trackResult.success} files`);
32723
32949
  await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local");
32724
32950
  if (validOptions.global) {
32725
- const claudeMdSource = join30(extractDir, "CLAUDE.md");
32726
- const claudeMdDest = join30(resolvedDir, "CLAUDE.md");
32951
+ const claudeMdSource = join31(extractDir, "CLAUDE.md");
32952
+ const claudeMdDest = join31(resolvedDir, "CLAUDE.md");
32727
32953
  if (await import_fs_extra18.pathExists(claudeMdSource)) {
32728
32954
  if (!await import_fs_extra18.pathExists(claudeMdDest)) {
32729
32955
  await import_fs_extra18.copy(claudeMdSource, claudeMdDest);
@@ -32742,8 +32968,21 @@ async function initCommand(options) {
32742
32968
  const skillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
32743
32969
  await handleSkillsInstallation2(skillsDir);
32744
32970
  }
32971
+ if (!isNonInteractive2) {
32972
+ const { isGeminiInstalled: isGeminiInstalled2 } = await Promise.resolve().then(() => (init_package_installer(), exports_package_installer));
32973
+ const { checkExistingGeminiConfig: checkExistingGeminiConfig2, findMcpConfigPath: findMcpConfigPath2, processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
32974
+ const geminiInstalled = await isGeminiInstalled2();
32975
+ const existingConfig = checkExistingGeminiConfig2(resolvedDir);
32976
+ const mcpConfigExists = findMcpConfigPath2(resolvedDir) !== null;
32977
+ if (geminiInstalled && !existingConfig.exists && mcpConfigExists) {
32978
+ const shouldSetupGemini = await prompts.confirm("Gemini CLI detected. Set up MCP integration? (creates .gemini/settings.json symlink)");
32979
+ if (shouldSetupGemini) {
32980
+ await processGeminiMcpLinking2(resolvedDir);
32981
+ }
32982
+ }
32983
+ }
32745
32984
  if (!validOptions.skipSetup && !isNonInteractive2) {
32746
- const envPath = join30(claudeDir, ".env");
32985
+ const envPath = join31(claudeDir, ".env");
32747
32986
  if (!await import_fs_extra18.pathExists(envPath)) {
32748
32987
  const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
32749
32988
  if (shouldSetup) {
@@ -32774,7 +33013,7 @@ Protected files (.env, etc.) were not modified.`;
32774
33013
  }
32775
33014
 
32776
33015
  // src/commands/new.ts
32777
- import { join as join31, resolve as resolve6 } from "node:path";
33016
+ import { join as join32, resolve as resolve7 } from "node:path";
32778
33017
  init_package_installer();
32779
33018
  init_environment();
32780
33019
  init_logger();
@@ -32805,7 +33044,7 @@ async function newCommand(options) {
32805
33044
  targetDir = await prompts.getDirectory(targetDir);
32806
33045
  }
32807
33046
  }
32808
- const resolvedDir = resolve6(targetDir);
33047
+ const resolvedDir = resolve7(targetDir);
32809
33048
  logger.info(`Target directory: ${resolvedDir}`);
32810
33049
  if (await import_fs_extra19.pathExists(resolvedDir)) {
32811
33050
  const files = await import_fs_extra19.readdir(resolvedDir);
@@ -32955,7 +33194,7 @@ async function newCommand(options) {
32955
33194
  await CommandsPrefix.cleanupCommandsDirectory(resolvedDir, false);
32956
33195
  }
32957
33196
  await merger.merge(extractDir, resolvedDir, true);
32958
- const claudeDir = join31(resolvedDir, ".claude");
33197
+ const claudeDir = join32(resolvedDir, ".claude");
32959
33198
  const manifestWriter = new ManifestWriter;
32960
33199
  const releaseManifest = await ReleaseManifestLoader.load(extractDir);
32961
33200
  const installedFiles = merger.getAllInstalledFiles();
@@ -32964,7 +33203,7 @@ async function newCommand(options) {
32964
33203
  if (!installedPath.startsWith(".claude/"))
32965
33204
  continue;
32966
33205
  const relativePath = installedPath.replace(/^\.claude\//, "");
32967
- const filePath = join31(claudeDir, relativePath);
33206
+ const filePath = join32(claudeDir, relativePath);
32968
33207
  const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
32969
33208
  const ownership = manifestEntry ? "ck" : "user";
32970
33209
  filesToTrack.push({
@@ -32996,7 +33235,7 @@ async function newCommand(options) {
32996
33235
  if (installOpenCode2 || installGemini2) {
32997
33236
  logger.info("Installing optional packages...");
32998
33237
  try {
32999
- const installationResults = await processPackageInstallations(installOpenCode2, installGemini2);
33238
+ const installationResults = await processPackageInstallations(installOpenCode2, installGemini2, resolvedDir);
33000
33239
  prompts.showPackageInstallationResults(installationResults);
33001
33240
  } catch (error) {
33002
33241
  logger.warning(`Package installation failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -33017,7 +33256,7 @@ async function newCommand(options) {
33017
33256
 
33018
33257
  // src/commands/uninstall.ts
33019
33258
  import { readdirSync, rmSync } from "node:fs";
33020
- import { dirname as dirname6, join as join32 } from "node:path";
33259
+ import { dirname as dirname7, join as join33 } from "node:path";
33021
33260
  init_logger();
33022
33261
  init_types2();
33023
33262
  var import_fs_extra20 = __toESM(require_lib(), 1);
@@ -33079,7 +33318,7 @@ async function confirmUninstall(scope) {
33079
33318
  }
33080
33319
  async function cleanupEmptyDirectories(filePath, installationRoot) {
33081
33320
  let cleaned = 0;
33082
- let currentDir = dirname6(filePath);
33321
+ let currentDir = dirname7(filePath);
33083
33322
  while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
33084
33323
  try {
33085
33324
  const entries = readdirSync(currentDir);
@@ -33087,7 +33326,7 @@ async function cleanupEmptyDirectories(filePath, installationRoot) {
33087
33326
  rmSync(currentDir, { recursive: true });
33088
33327
  cleaned++;
33089
33328
  logger.debug(`Removed empty directory: ${currentDir}`);
33090
- currentDir = dirname6(currentDir);
33329
+ currentDir = dirname7(currentDir);
33091
33330
  } else {
33092
33331
  break;
33093
33332
  }
@@ -33110,7 +33349,7 @@ async function analyzeInstallation(installation, forceOverwrite) {
33110
33349
  return result;
33111
33350
  }
33112
33351
  for (const trackedFile of metadata.files) {
33113
- const filePath = join32(installation.path, trackedFile.path);
33352
+ const filePath = join33(installation.path, trackedFile.path);
33114
33353
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
33115
33354
  if (!ownershipResult.exists)
33116
33355
  continue;
@@ -33168,7 +33407,7 @@ async function removeInstallations(installations, options) {
33168
33407
  let removedCount = 0;
33169
33408
  let cleanedDirs = 0;
33170
33409
  for (const item of analysis.toDelete) {
33171
- const filePath = join32(installation.path, item.path);
33410
+ const filePath = join33(installation.path, item.path);
33172
33411
  if (await import_fs_extra20.pathExists(filePath)) {
33173
33412
  await import_fs_extra20.remove(filePath);
33174
33413
  removedCount++;
@@ -33409,7 +33648,7 @@ var import_compare_versions2 = __toESM(require_umd(), 1);
33409
33648
  // package.json
33410
33649
  var package_default2 = {
33411
33650
  name: "claudekit-cli",
33412
- version: "3.9.1",
33651
+ version: "3.10.0",
33413
33652
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
33414
33653
  type: "module",
33415
33654
  repository: {
@@ -33716,24 +33955,24 @@ var import_picocolors15 = __toESM(require_picocolors(), 1);
33716
33955
 
33717
33956
  // src/domains/versioning/version-cache.ts
33718
33957
  init_logger();
33719
- import { existsSync as existsSync7 } from "node:fs";
33720
- import { mkdir as mkdir10, readFile as readFile16, writeFile as writeFile14 } from "node:fs/promises";
33721
- import { join as join33 } from "node:path";
33958
+ import { existsSync as existsSync8 } from "node:fs";
33959
+ import { mkdir as mkdir11, readFile as readFile17, writeFile as writeFile15 } from "node:fs/promises";
33960
+ import { join as join34 } from "node:path";
33722
33961
  class VersionCacheManager {
33723
33962
  static CACHE_FILENAME = "version-check.json";
33724
33963
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
33725
33964
  static getCacheFile() {
33726
33965
  const cacheDir = PathResolver.getCacheDir(false);
33727
- return join33(cacheDir, VersionCacheManager.CACHE_FILENAME);
33966
+ return join34(cacheDir, VersionCacheManager.CACHE_FILENAME);
33728
33967
  }
33729
33968
  static async load() {
33730
33969
  const cacheFile = VersionCacheManager.getCacheFile();
33731
33970
  try {
33732
- if (!existsSync7(cacheFile)) {
33971
+ if (!existsSync8(cacheFile)) {
33733
33972
  logger.debug("Version check cache not found");
33734
33973
  return null;
33735
33974
  }
33736
- const content = await readFile16(cacheFile, "utf-8");
33975
+ const content = await readFile17(cacheFile, "utf-8");
33737
33976
  const cache2 = JSON.parse(content);
33738
33977
  if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
33739
33978
  logger.debug("Invalid cache structure, ignoring");
@@ -33750,10 +33989,10 @@ class VersionCacheManager {
33750
33989
  const cacheFile = VersionCacheManager.getCacheFile();
33751
33990
  const cacheDir = PathResolver.getCacheDir(false);
33752
33991
  try {
33753
- if (!existsSync7(cacheDir)) {
33754
- await mkdir10(cacheDir, { recursive: true, mode: 448 });
33992
+ if (!existsSync8(cacheDir)) {
33993
+ await mkdir11(cacheDir, { recursive: true, mode: 448 });
33755
33994
  }
33756
- await writeFile14(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
33995
+ await writeFile15(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
33757
33996
  logger.debug(`Version check cache saved to ${cacheFile}`);
33758
33997
  } catch (error) {
33759
33998
  logger.debug(`Failed to save version check cache: ${error}`);
@@ -33772,7 +34011,7 @@ class VersionCacheManager {
33772
34011
  static async clear() {
33773
34012
  const cacheFile = VersionCacheManager.getCacheFile();
33774
34013
  try {
33775
- if (existsSync7(cacheFile)) {
34014
+ if (existsSync8(cacheFile)) {
33776
34015
  const fs12 = await import("node:fs/promises");
33777
34016
  await fs12.unlink(cacheFile);
33778
34017
  logger.debug("Version check cache cleared");
@@ -34235,8 +34474,8 @@ class OutputManager2 {
34235
34474
  var output2 = new OutputManager2;
34236
34475
 
34237
34476
  // src/shared/path-resolver.ts
34238
- import { homedir as homedir4, platform as platform10 } from "node:os";
34239
- import { join as join34, normalize as normalize6 } from "node:path";
34477
+ import { homedir as homedir5, platform as platform10 } from "node:os";
34478
+ import { join as join35, normalize as normalize6 } from "node:path";
34240
34479
 
34241
34480
  class PathResolver2 {
34242
34481
  static getTestHomeDir() {
@@ -34269,50 +34508,50 @@ class PathResolver2 {
34269
34508
  static getConfigDir(global3 = false) {
34270
34509
  const testHome = PathResolver2.getTestHomeDir();
34271
34510
  if (testHome) {
34272
- return global3 ? join34(testHome, ".config", "claude") : join34(testHome, ".claudekit");
34511
+ return global3 ? join35(testHome, ".config", "claude") : join35(testHome, ".claudekit");
34273
34512
  }
34274
34513
  if (!global3) {
34275
- return join34(homedir4(), ".claudekit");
34514
+ return join35(homedir5(), ".claudekit");
34276
34515
  }
34277
34516
  const os2 = platform10();
34278
34517
  if (os2 === "win32") {
34279
- const localAppData = process.env.LOCALAPPDATA || join34(homedir4(), "AppData", "Local");
34280
- return join34(localAppData, "claude");
34518
+ const localAppData = process.env.LOCALAPPDATA || join35(homedir5(), "AppData", "Local");
34519
+ return join35(localAppData, "claude");
34281
34520
  }
34282
34521
  const xdgConfigHome = process.env.XDG_CONFIG_HOME;
34283
34522
  if (xdgConfigHome) {
34284
- return join34(xdgConfigHome, "claude");
34523
+ return join35(xdgConfigHome, "claude");
34285
34524
  }
34286
- return join34(homedir4(), ".config", "claude");
34525
+ return join35(homedir5(), ".config", "claude");
34287
34526
  }
34288
34527
  static getConfigFile(global3 = false) {
34289
- return join34(PathResolver2.getConfigDir(global3), "config.json");
34528
+ return join35(PathResolver2.getConfigDir(global3), "config.json");
34290
34529
  }
34291
34530
  static getCacheDir(global3 = false) {
34292
34531
  const testHome = PathResolver2.getTestHomeDir();
34293
34532
  if (testHome) {
34294
- return global3 ? join34(testHome, ".cache", "claude") : join34(testHome, ".claudekit", "cache");
34533
+ return global3 ? join35(testHome, ".cache", "claude") : join35(testHome, ".claudekit", "cache");
34295
34534
  }
34296
34535
  if (!global3) {
34297
- return join34(homedir4(), ".claudekit", "cache");
34536
+ return join35(homedir5(), ".claudekit", "cache");
34298
34537
  }
34299
34538
  const os2 = platform10();
34300
34539
  if (os2 === "win32") {
34301
- const localAppData = process.env.LOCALAPPDATA || join34(homedir4(), "AppData", "Local");
34302
- return join34(localAppData, "claude", "cache");
34540
+ const localAppData = process.env.LOCALAPPDATA || join35(homedir5(), "AppData", "Local");
34541
+ return join35(localAppData, "claude", "cache");
34303
34542
  }
34304
34543
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
34305
34544
  if (xdgCacheHome) {
34306
- return join34(xdgCacheHome, "claude");
34545
+ return join35(xdgCacheHome, "claude");
34307
34546
  }
34308
- return join34(homedir4(), ".cache", "claude");
34547
+ return join35(homedir5(), ".cache", "claude");
34309
34548
  }
34310
34549
  static getGlobalKitDir() {
34311
34550
  const testHome = PathResolver2.getTestHomeDir();
34312
34551
  if (testHome) {
34313
- return join34(testHome, ".claude");
34552
+ return join35(testHome, ".claude");
34314
34553
  }
34315
- return join34(homedir4(), ".claude");
34554
+ return join35(homedir5(), ".claude");
34316
34555
  }
34317
34556
  static getPathPrefix(global3) {
34318
34557
  return global3 ? "" : ".claude";
@@ -34320,9 +34559,9 @@ class PathResolver2 {
34320
34559
  static buildSkillsPath(baseDir, global3) {
34321
34560
  const prefix = PathResolver2.getPathPrefix(global3);
34322
34561
  if (prefix) {
34323
- return join34(baseDir, prefix, "skills");
34562
+ return join35(baseDir, prefix, "skills");
34324
34563
  }
34325
- return join34(baseDir, "skills");
34564
+ return join35(baseDir, "skills");
34326
34565
  }
34327
34566
  static buildComponentPath(baseDir, component, global3) {
34328
34567
  if (!PathResolver2.isPathSafe(component)) {
@@ -34330,9 +34569,9 @@ class PathResolver2 {
34330
34569
  }
34331
34570
  const prefix = PathResolver2.getPathPrefix(global3);
34332
34571
  if (prefix) {
34333
- return join34(baseDir, prefix, component);
34572
+ return join35(baseDir, prefix, component);
34334
34573
  }
34335
- return join34(baseDir, component);
34574
+ return join35(baseDir, component);
34336
34575
  }
34337
34576
  }
34338
34577
 
@@ -34364,11 +34603,11 @@ async function displayVersion() {
34364
34603
  let localKitVersion = null;
34365
34604
  let isGlobalOnlyKit = false;
34366
34605
  const globalKitDir = PathResolver2.getGlobalKitDir();
34367
- const globalMetadataPath = join35(globalKitDir, "metadata.json");
34606
+ const globalMetadataPath = join36(globalKitDir, "metadata.json");
34368
34607
  const prefix = PathResolver2.getPathPrefix(false);
34369
- const localMetadataPath = prefix ? join35(process.cwd(), prefix, "metadata.json") : join35(process.cwd(), "metadata.json");
34608
+ const localMetadataPath = prefix ? join36(process.cwd(), prefix, "metadata.json") : join36(process.cwd(), "metadata.json");
34370
34609
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
34371
- if (!isLocalSameAsGlobal && existsSync8(localMetadataPath)) {
34610
+ if (!isLocalSameAsGlobal && existsSync9(localMetadataPath)) {
34372
34611
  try {
34373
34612
  const rawMetadata = JSON.parse(readFileSync5(localMetadataPath, "utf-8"));
34374
34613
  const metadata = MetadataSchema.parse(rawMetadata);
@@ -34382,7 +34621,7 @@ async function displayVersion() {
34382
34621
  logger2.verbose("Failed to parse local metadata.json", { error });
34383
34622
  }
34384
34623
  }
34385
- if (existsSync8(globalMetadataPath)) {
34624
+ if (existsSync9(globalMetadataPath)) {
34386
34625
  try {
34387
34626
  const rawMetadata = JSON.parse(readFileSync5(globalMetadataPath, "utf-8"));
34388
34627
  const metadata = MetadataSchema.parse(rawMetadata);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.9.1",
3
+ "version": "3.10.0",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {