claudekit-cli 3.9.2 → 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.
- package/dist/index.js +372 -129
- 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
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
12651
|
-
const scriptPathResolved =
|
|
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:
|
|
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 =
|
|
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 (!
|
|
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: ${
|
|
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:
|
|
12724
|
-
const scriptContent = await
|
|
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(` ${
|
|
12980
|
+
logger.info(` ${join26(skillsDir, "INSTALLATION.md")}`);
|
|
12751
12981
|
return {
|
|
12752
12982
|
success: false,
|
|
12753
12983
|
package: displayName,
|
|
@@ -12848,7 +13078,7 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
12848
13078
|
logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
|
|
12849
13079
|
logger.info("");
|
|
12850
13080
|
logger.info("See complete guide:");
|
|
12851
|
-
logger.info(` cat ${
|
|
13081
|
+
logger.info(` cat ${join26(skillsDir, "INSTALLATION.md")}`);
|
|
12852
13082
|
logger.info("");
|
|
12853
13083
|
logger.info("Quick start:");
|
|
12854
13084
|
logger.info(" cd .claude/skills/ai-multimodal/scripts");
|
|
@@ -13524,7 +13754,7 @@ function getPagerArgs(pagerCmd) {
|
|
|
13524
13754
|
return [];
|
|
13525
13755
|
}
|
|
13526
13756
|
async function trySystemPager(content) {
|
|
13527
|
-
return new Promise((
|
|
13757
|
+
return new Promise((resolve8) => {
|
|
13528
13758
|
const pagerCmd = process.env.PAGER || "less";
|
|
13529
13759
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
13530
13760
|
try {
|
|
@@ -13534,20 +13764,20 @@ async function trySystemPager(content) {
|
|
|
13534
13764
|
});
|
|
13535
13765
|
const timeout = setTimeout(() => {
|
|
13536
13766
|
pager.kill();
|
|
13537
|
-
|
|
13767
|
+
resolve8(false);
|
|
13538
13768
|
}, 30000);
|
|
13539
13769
|
pager.stdin.write(content);
|
|
13540
13770
|
pager.stdin.end();
|
|
13541
13771
|
pager.on("close", (code2) => {
|
|
13542
13772
|
clearTimeout(timeout);
|
|
13543
|
-
|
|
13773
|
+
resolve8(code2 === 0);
|
|
13544
13774
|
});
|
|
13545
13775
|
pager.on("error", () => {
|
|
13546
13776
|
clearTimeout(timeout);
|
|
13547
|
-
|
|
13777
|
+
resolve8(false);
|
|
13548
13778
|
});
|
|
13549
13779
|
} catch {
|
|
13550
|
-
|
|
13780
|
+
resolve8(false);
|
|
13551
13781
|
}
|
|
13552
13782
|
});
|
|
13553
13783
|
}
|
|
@@ -13574,16 +13804,16 @@ async function basicPager(content) {
|
|
|
13574
13804
|
break;
|
|
13575
13805
|
}
|
|
13576
13806
|
const remaining = lines.length - currentLine;
|
|
13577
|
-
await new Promise((
|
|
13807
|
+
await new Promise((resolve8) => {
|
|
13578
13808
|
rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
|
|
13579
13809
|
if (answer.toLowerCase() === "q") {
|
|
13580
13810
|
rl.close();
|
|
13581
13811
|
process.exitCode = 0;
|
|
13582
|
-
|
|
13812
|
+
resolve8();
|
|
13583
13813
|
return;
|
|
13584
13814
|
}
|
|
13585
13815
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
13586
|
-
|
|
13816
|
+
resolve8();
|
|
13587
13817
|
});
|
|
13588
13818
|
});
|
|
13589
13819
|
}
|
|
@@ -13841,8 +14071,8 @@ var init_help_interceptor = __esm(() => {
|
|
|
13841
14071
|
});
|
|
13842
14072
|
|
|
13843
14073
|
// src/index.ts
|
|
13844
|
-
import { existsSync as
|
|
13845
|
-
import { join as
|
|
14074
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
14075
|
+
import { join as join36 } from "path";
|
|
13846
14076
|
|
|
13847
14077
|
// node_modules/cac/dist/index.mjs
|
|
13848
14078
|
import { EventEmitter } from "events";
|
|
@@ -14447,7 +14677,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
14447
14677
|
// package.json
|
|
14448
14678
|
var package_default = {
|
|
14449
14679
|
name: "claudekit-cli",
|
|
14450
|
-
version: "3.
|
|
14680
|
+
version: "3.10.0",
|
|
14451
14681
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
14452
14682
|
type: "module",
|
|
14453
14683
|
repository: {
|
|
@@ -18291,7 +18521,7 @@ async function doctorCommand(options = {}) {
|
|
|
18291
18521
|
}
|
|
18292
18522
|
|
|
18293
18523
|
// src/commands/init.ts
|
|
18294
|
-
import { join as
|
|
18524
|
+
import { join as join31, resolve as resolve6 } from "node:path";
|
|
18295
18525
|
|
|
18296
18526
|
// src/domains/config/config-manager.ts
|
|
18297
18527
|
init_logger();
|
|
@@ -31577,7 +31807,7 @@ class PromptsManager {
|
|
|
31577
31807
|
|
|
31578
31808
|
// src/services/file-operations/file-scanner.ts
|
|
31579
31809
|
init_logger();
|
|
31580
|
-
import { join as
|
|
31810
|
+
import { join as join27, relative as relative7, resolve as resolve5 } from "node:path";
|
|
31581
31811
|
var import_fs_extra15 = __toESM(require_lib(), 1);
|
|
31582
31812
|
|
|
31583
31813
|
class FileScanner {
|
|
@@ -31594,7 +31824,7 @@ class FileScanner {
|
|
|
31594
31824
|
logger.debug(`Skipping directory: ${entry}`);
|
|
31595
31825
|
continue;
|
|
31596
31826
|
}
|
|
31597
|
-
const fullPath =
|
|
31827
|
+
const fullPath = join27(dirPath, entry);
|
|
31598
31828
|
if (!FileScanner.isSafePath(basePath, fullPath)) {
|
|
31599
31829
|
logger.warning(`Skipping potentially unsafe path: ${entry}`);
|
|
31600
31830
|
continue;
|
|
@@ -31629,8 +31859,8 @@ class FileScanner {
|
|
|
31629
31859
|
return files;
|
|
31630
31860
|
}
|
|
31631
31861
|
static async findCustomFiles(destDir, sourceDir, subPath) {
|
|
31632
|
-
const destSubDir =
|
|
31633
|
-
const sourceSubDir =
|
|
31862
|
+
const destSubDir = join27(destDir, subPath);
|
|
31863
|
+
const sourceSubDir = join27(sourceDir, subPath);
|
|
31634
31864
|
logger.debug(`findCustomFiles - destDir: ${destDir}`);
|
|
31635
31865
|
logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
|
|
31636
31866
|
logger.debug(`findCustomFiles - subPath: "${subPath}"`);
|
|
@@ -31658,8 +31888,8 @@ class FileScanner {
|
|
|
31658
31888
|
return customFiles;
|
|
31659
31889
|
}
|
|
31660
31890
|
static isSafePath(basePath, targetPath) {
|
|
31661
|
-
const resolvedBase =
|
|
31662
|
-
const resolvedTarget =
|
|
31891
|
+
const resolvedBase = resolve5(basePath);
|
|
31892
|
+
const resolvedTarget = resolve5(targetPath);
|
|
31663
31893
|
return resolvedTarget.startsWith(resolvedBase);
|
|
31664
31894
|
}
|
|
31665
31895
|
static toPosixPath(path9) {
|
|
@@ -31668,8 +31898,8 @@ class FileScanner {
|
|
|
31668
31898
|
}
|
|
31669
31899
|
|
|
31670
31900
|
// src/services/transformers/commands-prefix.ts
|
|
31671
|
-
import { lstat as lstat3, mkdir as
|
|
31672
|
-
import { join as
|
|
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";
|
|
31673
31903
|
init_logger();
|
|
31674
31904
|
var import_fs_extra16 = __toESM(require_lib(), 1);
|
|
31675
31905
|
function stripWindowsDrivePrefix(path9) {
|
|
@@ -31710,14 +31940,14 @@ function validatePath4(path9, paramName) {
|
|
|
31710
31940
|
class CommandsPrefix {
|
|
31711
31941
|
static async applyPrefix(extractDir) {
|
|
31712
31942
|
validatePath4(extractDir, "extractDir");
|
|
31713
|
-
const commandsDir =
|
|
31943
|
+
const commandsDir = join28(extractDir, ".claude", "commands");
|
|
31714
31944
|
if (!await import_fs_extra16.pathExists(commandsDir)) {
|
|
31715
31945
|
logger.verbose("No commands directory found, skipping prefix application");
|
|
31716
31946
|
return;
|
|
31717
31947
|
}
|
|
31718
31948
|
logger.info("Applying /ck: prefix to slash commands...");
|
|
31719
|
-
const backupDir =
|
|
31720
|
-
const tempDir =
|
|
31949
|
+
const backupDir = join28(extractDir, ".commands-backup");
|
|
31950
|
+
const tempDir = join28(extractDir, ".commands-prefix-temp");
|
|
31721
31951
|
try {
|
|
31722
31952
|
const entries = await readdir11(commandsDir);
|
|
31723
31953
|
if (entries.length === 0) {
|
|
@@ -31725,7 +31955,7 @@ class CommandsPrefix {
|
|
|
31725
31955
|
return;
|
|
31726
31956
|
}
|
|
31727
31957
|
if (entries.length === 1 && entries[0] === "ck") {
|
|
31728
|
-
const ckDir2 =
|
|
31958
|
+
const ckDir2 = join28(commandsDir, "ck");
|
|
31729
31959
|
const ckStat = await stat4(ckDir2);
|
|
31730
31960
|
if (ckStat.isDirectory()) {
|
|
31731
31961
|
logger.verbose("Commands already have /ck: prefix, skipping");
|
|
@@ -31734,18 +31964,18 @@ class CommandsPrefix {
|
|
|
31734
31964
|
}
|
|
31735
31965
|
await import_fs_extra16.copy(commandsDir, backupDir);
|
|
31736
31966
|
logger.verbose("Created backup of commands directory");
|
|
31737
|
-
await
|
|
31738
|
-
const ckDir =
|
|
31739
|
-
await
|
|
31967
|
+
await mkdir10(tempDir, { recursive: true });
|
|
31968
|
+
const ckDir = join28(tempDir, "ck");
|
|
31969
|
+
await mkdir10(ckDir, { recursive: true });
|
|
31740
31970
|
let processedCount = 0;
|
|
31741
31971
|
for (const entry of entries) {
|
|
31742
|
-
const sourcePath =
|
|
31972
|
+
const sourcePath = join28(commandsDir, entry);
|
|
31743
31973
|
const stats = await lstat3(sourcePath);
|
|
31744
31974
|
if (stats.isSymbolicLink()) {
|
|
31745
31975
|
logger.warning(`Skipping symlink for security: ${entry}`);
|
|
31746
31976
|
continue;
|
|
31747
31977
|
}
|
|
31748
|
-
const destPath =
|
|
31978
|
+
const destPath = join28(ckDir, entry);
|
|
31749
31979
|
await import_fs_extra16.copy(sourcePath, destPath, {
|
|
31750
31980
|
overwrite: false,
|
|
31751
31981
|
errorOnExist: true
|
|
@@ -31793,8 +32023,8 @@ class CommandsPrefix {
|
|
|
31793
32023
|
static async cleanupCommandsDirectory(targetDir, isGlobal, options = {}) {
|
|
31794
32024
|
const { dryRun = false, forceOverwrite = false } = options;
|
|
31795
32025
|
validatePath4(targetDir, "targetDir");
|
|
31796
|
-
const claudeDir = isGlobal ? targetDir :
|
|
31797
|
-
const commandsDir =
|
|
32026
|
+
const claudeDir = isGlobal ? targetDir : join28(targetDir, ".claude");
|
|
32027
|
+
const commandsDir = join28(claudeDir, "commands");
|
|
31798
32028
|
const result = {
|
|
31799
32029
|
results: [],
|
|
31800
32030
|
deletedCount: 0,
|
|
@@ -31822,7 +32052,7 @@ class CommandsPrefix {
|
|
|
31822
32052
|
return result;
|
|
31823
32053
|
}
|
|
31824
32054
|
for (const entry of entries) {
|
|
31825
|
-
const entryPath =
|
|
32055
|
+
const entryPath = join28(commandsDir, entry);
|
|
31826
32056
|
const stats = await lstat3(entryPath);
|
|
31827
32057
|
if (stats.isSymbolicLink()) {
|
|
31828
32058
|
logger.warning(`Skipping symlink: ${entry}`);
|
|
@@ -31988,7 +32218,7 @@ class CommandsPrefix {
|
|
|
31988
32218
|
const files = [];
|
|
31989
32219
|
const entries = await readdir11(dir);
|
|
31990
32220
|
for (const entry of entries) {
|
|
31991
|
-
const fullPath =
|
|
32221
|
+
const fullPath = join28(dir, entry);
|
|
31992
32222
|
const stats = await lstat3(fullPath);
|
|
31993
32223
|
if (stats.isSymbolicLink()) {
|
|
31994
32224
|
continue;
|
|
@@ -32007,8 +32237,8 @@ class CommandsPrefix {
|
|
|
32007
32237
|
init_logger();
|
|
32008
32238
|
init_types2();
|
|
32009
32239
|
var import_fs_extra17 = __toESM(require_lib(), 1);
|
|
32010
|
-
import { readFile as
|
|
32011
|
-
import { join as
|
|
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";
|
|
32012
32242
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
32013
32243
|
".md",
|
|
32014
32244
|
".txt",
|
|
@@ -32054,34 +32284,34 @@ async function transformFolderPaths(extractDir, folders, options = {}) {
|
|
|
32054
32284
|
}
|
|
32055
32285
|
const dirsToRename = [];
|
|
32056
32286
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
32057
|
-
const docsPath =
|
|
32287
|
+
const docsPath = join29(extractDir, DEFAULT_FOLDERS.docs);
|
|
32058
32288
|
if (await import_fs_extra17.pathExists(docsPath)) {
|
|
32059
32289
|
dirsToRename.push({
|
|
32060
32290
|
from: docsPath,
|
|
32061
|
-
to:
|
|
32291
|
+
to: join29(extractDir, folders.docs)
|
|
32062
32292
|
});
|
|
32063
32293
|
}
|
|
32064
|
-
const claudeDocsPath =
|
|
32294
|
+
const claudeDocsPath = join29(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
32065
32295
|
if (await import_fs_extra17.pathExists(claudeDocsPath)) {
|
|
32066
32296
|
dirsToRename.push({
|
|
32067
32297
|
from: claudeDocsPath,
|
|
32068
|
-
to:
|
|
32298
|
+
to: join29(extractDir, ".claude", folders.docs)
|
|
32069
32299
|
});
|
|
32070
32300
|
}
|
|
32071
32301
|
}
|
|
32072
32302
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
32073
|
-
const plansPath =
|
|
32303
|
+
const plansPath = join29(extractDir, DEFAULT_FOLDERS.plans);
|
|
32074
32304
|
if (await import_fs_extra17.pathExists(plansPath)) {
|
|
32075
32305
|
dirsToRename.push({
|
|
32076
32306
|
from: plansPath,
|
|
32077
|
-
to:
|
|
32307
|
+
to: join29(extractDir, folders.plans)
|
|
32078
32308
|
});
|
|
32079
32309
|
}
|
|
32080
|
-
const claudePlansPath =
|
|
32310
|
+
const claudePlansPath = join29(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
32081
32311
|
if (await import_fs_extra17.pathExists(claudePlansPath)) {
|
|
32082
32312
|
dirsToRename.push({
|
|
32083
32313
|
from: claudePlansPath,
|
|
32084
|
-
to:
|
|
32314
|
+
to: join29(extractDir, ".claude", folders.plans)
|
|
32085
32315
|
});
|
|
32086
32316
|
}
|
|
32087
32317
|
}
|
|
@@ -32118,7 +32348,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
|
|
|
32118
32348
|
let replacementsCount = 0;
|
|
32119
32349
|
const entries = await readdir12(dir, { withFileTypes: true });
|
|
32120
32350
|
for (const entry of entries) {
|
|
32121
|
-
const fullPath =
|
|
32351
|
+
const fullPath = join29(dir, entry.name);
|
|
32122
32352
|
if (entry.isDirectory()) {
|
|
32123
32353
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
32124
32354
|
continue;
|
|
@@ -32131,7 +32361,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
|
|
|
32131
32361
|
if (!shouldTransform)
|
|
32132
32362
|
continue;
|
|
32133
32363
|
try {
|
|
32134
|
-
const content = await
|
|
32364
|
+
const content = await readFile15(fullPath, "utf-8");
|
|
32135
32365
|
let newContent = content;
|
|
32136
32366
|
let changeCount = 0;
|
|
32137
32367
|
for (const { regex: regex2, replacement } of compiledReplacements) {
|
|
@@ -32147,7 +32377,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
|
|
|
32147
32377
|
if (options.dryRun) {
|
|
32148
32378
|
logger.debug(`[dry-run] Would update ${relative8(dir, fullPath)}: ${changeCount} replacement(s)`);
|
|
32149
32379
|
} else {
|
|
32150
|
-
await
|
|
32380
|
+
await writeFile13(fullPath, newContent, "utf-8");
|
|
32151
32381
|
logger.debug(`Updated ${relative8(dir, fullPath)}: ${changeCount} replacement(s)`);
|
|
32152
32382
|
}
|
|
32153
32383
|
filesChanged++;
|
|
@@ -32227,9 +32457,9 @@ function validateFolderName(name2) {
|
|
|
32227
32457
|
|
|
32228
32458
|
// src/services/transformers/global-path-transformer.ts
|
|
32229
32459
|
init_logger();
|
|
32230
|
-
import { readFile as
|
|
32460
|
+
import { readFile as readFile16, readdir as readdir13, writeFile as writeFile14 } from "node:fs/promises";
|
|
32231
32461
|
import { platform as platform9 } from "node:os";
|
|
32232
|
-
import { extname, join as
|
|
32462
|
+
import { extname, join as join30 } from "node:path";
|
|
32233
32463
|
var IS_WINDOWS2 = platform9() === "win32";
|
|
32234
32464
|
var HOME_PREFIX = IS_WINDOWS2 ? "%USERPROFILE%" : "$HOME";
|
|
32235
32465
|
function getHomeDirPrefix() {
|
|
@@ -32321,7 +32551,7 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
|
|
|
32321
32551
|
async function processDirectory(dir) {
|
|
32322
32552
|
const entries = await readdir13(dir, { withFileTypes: true });
|
|
32323
32553
|
for (const entry of entries) {
|
|
32324
|
-
const fullPath =
|
|
32554
|
+
const fullPath = join30(dir, entry.name);
|
|
32325
32555
|
if (entry.isDirectory()) {
|
|
32326
32556
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
32327
32557
|
continue;
|
|
@@ -32329,10 +32559,10 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
|
|
|
32329
32559
|
await processDirectory(fullPath);
|
|
32330
32560
|
} else if (entry.isFile() && shouldTransformFile(entry.name)) {
|
|
32331
32561
|
try {
|
|
32332
|
-
const content = await
|
|
32562
|
+
const content = await readFile16(fullPath, "utf-8");
|
|
32333
32563
|
const { transformed, changes } = transformContent(content);
|
|
32334
32564
|
if (changes > 0) {
|
|
32335
|
-
await
|
|
32565
|
+
await writeFile14(fullPath, transformed, "utf-8");
|
|
32336
32566
|
filesTransformed++;
|
|
32337
32567
|
totalChanges += changes;
|
|
32338
32568
|
if (options.verbose) {
|
|
@@ -32380,9 +32610,9 @@ async function initCommand(options) {
|
|
|
32380
32610
|
}
|
|
32381
32611
|
if (validOptions.global) {
|
|
32382
32612
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
32383
|
-
const cwdResolved =
|
|
32384
|
-
const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved ===
|
|
32385
|
-
const localSettingsPath =
|
|
32613
|
+
const cwdResolved = resolve6(process.cwd());
|
|
32614
|
+
const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved === resolve6(globalKitDir, "..");
|
|
32615
|
+
const localSettingsPath = join31(process.cwd(), ".claude", "settings.json");
|
|
32386
32616
|
if (!isInGlobalDir && await import_fs_extra18.pathExists(localSettingsPath)) {
|
|
32387
32617
|
if (isNonInteractive2) {
|
|
32388
32618
|
logger.warning("Local .claude/settings.json detected. Local settings take precedence over global.");
|
|
@@ -32394,7 +32624,7 @@ async function initCommand(options) {
|
|
|
32394
32624
|
return;
|
|
32395
32625
|
}
|
|
32396
32626
|
if (choice === "remove") {
|
|
32397
|
-
const localClaudeDir =
|
|
32627
|
+
const localClaudeDir = join31(process.cwd(), ".claude");
|
|
32398
32628
|
try {
|
|
32399
32629
|
await import_fs_extra18.remove(localClaudeDir);
|
|
32400
32630
|
logger.success("Removed local .claude/ directory");
|
|
@@ -32438,12 +32668,12 @@ async function initCommand(options) {
|
|
|
32438
32668
|
}
|
|
32439
32669
|
}
|
|
32440
32670
|
}
|
|
32441
|
-
const resolvedDir =
|
|
32671
|
+
const resolvedDir = resolve6(targetDir);
|
|
32442
32672
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
32443
32673
|
if (!await import_fs_extra18.pathExists(resolvedDir)) {
|
|
32444
32674
|
if (validOptions.global) {
|
|
32445
|
-
const { mkdir:
|
|
32446
|
-
await
|
|
32675
|
+
const { mkdir: mkdir11 } = await import("node:fs/promises");
|
|
32676
|
+
await mkdir11(resolvedDir, { recursive: true });
|
|
32447
32677
|
logger.info(`Created global directory: ${resolvedDir}`);
|
|
32448
32678
|
} else {
|
|
32449
32679
|
logger.error(`Directory does not exist: ${resolvedDir}`);
|
|
@@ -32453,7 +32683,7 @@ async function initCommand(options) {
|
|
|
32453
32683
|
}
|
|
32454
32684
|
if (validOptions.fresh) {
|
|
32455
32685
|
const prefix = PathResolver.getPathPrefix(validOptions.global);
|
|
32456
|
-
const claudeDir2 = prefix ?
|
|
32686
|
+
const claudeDir2 = prefix ? join31(resolvedDir, prefix) : resolvedDir;
|
|
32457
32687
|
const canProceed = await handleFreshInstallation(claudeDir2, prompts);
|
|
32458
32688
|
if (!canProceed) {
|
|
32459
32689
|
return;
|
|
@@ -32481,7 +32711,7 @@ async function initCommand(options) {
|
|
|
32481
32711
|
logger.info("Fetching available versions...");
|
|
32482
32712
|
let currentVersion = null;
|
|
32483
32713
|
try {
|
|
32484
|
-
const metadataPath = validOptions.global ?
|
|
32714
|
+
const metadataPath = validOptions.global ? join31(PathResolver.getGlobalKitDir(), "metadata.json") : join31(resolvedDir, ".claude", "metadata.json");
|
|
32485
32715
|
const metadata = await readClaudeKitMetadata(metadataPath);
|
|
32486
32716
|
currentVersion = metadata?.version || null;
|
|
32487
32717
|
if (currentVersion) {
|
|
@@ -32606,7 +32836,7 @@ async function initCommand(options) {
|
|
|
32606
32836
|
}
|
|
32607
32837
|
}
|
|
32608
32838
|
if (!validOptions.fresh) {
|
|
32609
|
-
const newSkillsDir =
|
|
32839
|
+
const newSkillsDir = join31(extractDir, ".claude", "skills");
|
|
32610
32840
|
const currentSkillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
|
|
32611
32841
|
if (await import_fs_extra18.pathExists(newSkillsDir) && await import_fs_extra18.pathExists(currentSkillsDir)) {
|
|
32612
32842
|
logger.info("Checking for skills directory migration...");
|
|
@@ -32631,7 +32861,7 @@ async function initCommand(options) {
|
|
|
32631
32861
|
let customClaudeFiles = [];
|
|
32632
32862
|
if (!validOptions.fresh) {
|
|
32633
32863
|
logger.info("Scanning for custom .claude files...");
|
|
32634
|
-
const scanSourceDir = validOptions.global ?
|
|
32864
|
+
const scanSourceDir = validOptions.global ? join31(extractDir, ".claude") : extractDir;
|
|
32635
32865
|
const scanTargetSubdir = validOptions.global ? "" : ".claude";
|
|
32636
32866
|
customClaudeFiles = await FileScanner.findCustomFiles(resolvedDir, scanSourceDir, scanTargetSubdir);
|
|
32637
32867
|
} else {
|
|
@@ -32666,7 +32896,7 @@ async function initCommand(options) {
|
|
|
32666
32896
|
}
|
|
32667
32897
|
merger.setGlobalFlag(validOptions.global);
|
|
32668
32898
|
merger.setForceOverwriteSettings(validOptions.forceOverwriteSettings);
|
|
32669
|
-
const claudeDir = validOptions.global ? resolvedDir :
|
|
32899
|
+
const claudeDir = validOptions.global ? resolvedDir : join31(resolvedDir, ".claude");
|
|
32670
32900
|
const releaseManifest = await ReleaseManifestLoader.load(extractDir);
|
|
32671
32901
|
if (!validOptions.fresh && await import_fs_extra18.pathExists(claudeDir)) {
|
|
32672
32902
|
const legacyDetection = await LegacyMigration.detectLegacy(claudeDir);
|
|
@@ -32688,7 +32918,7 @@ async function initCommand(options) {
|
|
|
32688
32918
|
return;
|
|
32689
32919
|
}
|
|
32690
32920
|
}
|
|
32691
|
-
const sourceDir = validOptions.global ?
|
|
32921
|
+
const sourceDir = validOptions.global ? join31(extractDir, ".claude") : extractDir;
|
|
32692
32922
|
await merger.merge(sourceDir, resolvedDir, false);
|
|
32693
32923
|
const manifestWriter = new ManifestWriter;
|
|
32694
32924
|
const installedFiles = merger.getAllInstalledFiles();
|
|
@@ -32697,7 +32927,7 @@ async function initCommand(options) {
|
|
|
32697
32927
|
if (!validOptions.global && !installedPath.startsWith(".claude/"))
|
|
32698
32928
|
continue;
|
|
32699
32929
|
const relativePath = validOptions.global ? installedPath : installedPath.replace(/^\.claude\//, "");
|
|
32700
|
-
const filePath =
|
|
32930
|
+
const filePath = join31(claudeDir, relativePath);
|
|
32701
32931
|
const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
|
|
32702
32932
|
const ownership = manifestEntry ? "ck" : "user";
|
|
32703
32933
|
filesToTrack.push({
|
|
@@ -32718,8 +32948,8 @@ async function initCommand(options) {
|
|
|
32718
32948
|
trackingSpinner.succeed(`Tracked ${trackResult.success} files`);
|
|
32719
32949
|
await manifestWriter.writeManifest(claudeDir, kitConfig.name, release.tag_name, validOptions.global ? "global" : "local");
|
|
32720
32950
|
if (validOptions.global) {
|
|
32721
|
-
const claudeMdSource =
|
|
32722
|
-
const claudeMdDest =
|
|
32951
|
+
const claudeMdSource = join31(extractDir, "CLAUDE.md");
|
|
32952
|
+
const claudeMdDest = join31(resolvedDir, "CLAUDE.md");
|
|
32723
32953
|
if (await import_fs_extra18.pathExists(claudeMdSource)) {
|
|
32724
32954
|
if (!await import_fs_extra18.pathExists(claudeMdDest)) {
|
|
32725
32955
|
await import_fs_extra18.copy(claudeMdSource, claudeMdDest);
|
|
@@ -32738,8 +32968,21 @@ async function initCommand(options) {
|
|
|
32738
32968
|
const skillsDir = PathResolver.buildSkillsPath(resolvedDir, validOptions.global);
|
|
32739
32969
|
await handleSkillsInstallation2(skillsDir);
|
|
32740
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
|
+
}
|
|
32741
32984
|
if (!validOptions.skipSetup && !isNonInteractive2) {
|
|
32742
|
-
const envPath =
|
|
32985
|
+
const envPath = join31(claudeDir, ".env");
|
|
32743
32986
|
if (!await import_fs_extra18.pathExists(envPath)) {
|
|
32744
32987
|
const shouldSetup = await prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
|
|
32745
32988
|
if (shouldSetup) {
|
|
@@ -32770,7 +33013,7 @@ Protected files (.env, etc.) were not modified.`;
|
|
|
32770
33013
|
}
|
|
32771
33014
|
|
|
32772
33015
|
// src/commands/new.ts
|
|
32773
|
-
import { join as
|
|
33016
|
+
import { join as join32, resolve as resolve7 } from "node:path";
|
|
32774
33017
|
init_package_installer();
|
|
32775
33018
|
init_environment();
|
|
32776
33019
|
init_logger();
|
|
@@ -32801,7 +33044,7 @@ async function newCommand(options) {
|
|
|
32801
33044
|
targetDir = await prompts.getDirectory(targetDir);
|
|
32802
33045
|
}
|
|
32803
33046
|
}
|
|
32804
|
-
const resolvedDir =
|
|
33047
|
+
const resolvedDir = resolve7(targetDir);
|
|
32805
33048
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
32806
33049
|
if (await import_fs_extra19.pathExists(resolvedDir)) {
|
|
32807
33050
|
const files = await import_fs_extra19.readdir(resolvedDir);
|
|
@@ -32951,7 +33194,7 @@ async function newCommand(options) {
|
|
|
32951
33194
|
await CommandsPrefix.cleanupCommandsDirectory(resolvedDir, false);
|
|
32952
33195
|
}
|
|
32953
33196
|
await merger.merge(extractDir, resolvedDir, true);
|
|
32954
|
-
const claudeDir =
|
|
33197
|
+
const claudeDir = join32(resolvedDir, ".claude");
|
|
32955
33198
|
const manifestWriter = new ManifestWriter;
|
|
32956
33199
|
const releaseManifest = await ReleaseManifestLoader.load(extractDir);
|
|
32957
33200
|
const installedFiles = merger.getAllInstalledFiles();
|
|
@@ -32960,7 +33203,7 @@ async function newCommand(options) {
|
|
|
32960
33203
|
if (!installedPath.startsWith(".claude/"))
|
|
32961
33204
|
continue;
|
|
32962
33205
|
const relativePath = installedPath.replace(/^\.claude\//, "");
|
|
32963
|
-
const filePath =
|
|
33206
|
+
const filePath = join32(claudeDir, relativePath);
|
|
32964
33207
|
const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
|
|
32965
33208
|
const ownership = manifestEntry ? "ck" : "user";
|
|
32966
33209
|
filesToTrack.push({
|
|
@@ -32992,7 +33235,7 @@ async function newCommand(options) {
|
|
|
32992
33235
|
if (installOpenCode2 || installGemini2) {
|
|
32993
33236
|
logger.info("Installing optional packages...");
|
|
32994
33237
|
try {
|
|
32995
|
-
const installationResults = await processPackageInstallations(installOpenCode2, installGemini2);
|
|
33238
|
+
const installationResults = await processPackageInstallations(installOpenCode2, installGemini2, resolvedDir);
|
|
32996
33239
|
prompts.showPackageInstallationResults(installationResults);
|
|
32997
33240
|
} catch (error) {
|
|
32998
33241
|
logger.warning(`Package installation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -33013,7 +33256,7 @@ async function newCommand(options) {
|
|
|
33013
33256
|
|
|
33014
33257
|
// src/commands/uninstall.ts
|
|
33015
33258
|
import { readdirSync, rmSync } from "node:fs";
|
|
33016
|
-
import { dirname as
|
|
33259
|
+
import { dirname as dirname7, join as join33 } from "node:path";
|
|
33017
33260
|
init_logger();
|
|
33018
33261
|
init_types2();
|
|
33019
33262
|
var import_fs_extra20 = __toESM(require_lib(), 1);
|
|
@@ -33075,7 +33318,7 @@ async function confirmUninstall(scope) {
|
|
|
33075
33318
|
}
|
|
33076
33319
|
async function cleanupEmptyDirectories(filePath, installationRoot) {
|
|
33077
33320
|
let cleaned = 0;
|
|
33078
|
-
let currentDir =
|
|
33321
|
+
let currentDir = dirname7(filePath);
|
|
33079
33322
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
33080
33323
|
try {
|
|
33081
33324
|
const entries = readdirSync(currentDir);
|
|
@@ -33083,7 +33326,7 @@ async function cleanupEmptyDirectories(filePath, installationRoot) {
|
|
|
33083
33326
|
rmSync(currentDir, { recursive: true });
|
|
33084
33327
|
cleaned++;
|
|
33085
33328
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
33086
|
-
currentDir =
|
|
33329
|
+
currentDir = dirname7(currentDir);
|
|
33087
33330
|
} else {
|
|
33088
33331
|
break;
|
|
33089
33332
|
}
|
|
@@ -33106,7 +33349,7 @@ async function analyzeInstallation(installation, forceOverwrite) {
|
|
|
33106
33349
|
return result;
|
|
33107
33350
|
}
|
|
33108
33351
|
for (const trackedFile of metadata.files) {
|
|
33109
|
-
const filePath =
|
|
33352
|
+
const filePath = join33(installation.path, trackedFile.path);
|
|
33110
33353
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
33111
33354
|
if (!ownershipResult.exists)
|
|
33112
33355
|
continue;
|
|
@@ -33164,7 +33407,7 @@ async function removeInstallations(installations, options) {
|
|
|
33164
33407
|
let removedCount = 0;
|
|
33165
33408
|
let cleanedDirs = 0;
|
|
33166
33409
|
for (const item of analysis.toDelete) {
|
|
33167
|
-
const filePath =
|
|
33410
|
+
const filePath = join33(installation.path, item.path);
|
|
33168
33411
|
if (await import_fs_extra20.pathExists(filePath)) {
|
|
33169
33412
|
await import_fs_extra20.remove(filePath);
|
|
33170
33413
|
removedCount++;
|
|
@@ -33405,7 +33648,7 @@ var import_compare_versions2 = __toESM(require_umd(), 1);
|
|
|
33405
33648
|
// package.json
|
|
33406
33649
|
var package_default2 = {
|
|
33407
33650
|
name: "claudekit-cli",
|
|
33408
|
-
version: "3.
|
|
33651
|
+
version: "3.10.0",
|
|
33409
33652
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
33410
33653
|
type: "module",
|
|
33411
33654
|
repository: {
|
|
@@ -33712,24 +33955,24 @@ var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
|
33712
33955
|
|
|
33713
33956
|
// src/domains/versioning/version-cache.ts
|
|
33714
33957
|
init_logger();
|
|
33715
|
-
import { existsSync as
|
|
33716
|
-
import { mkdir as
|
|
33717
|
-
import { join as
|
|
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";
|
|
33718
33961
|
class VersionCacheManager {
|
|
33719
33962
|
static CACHE_FILENAME = "version-check.json";
|
|
33720
33963
|
static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
33721
33964
|
static getCacheFile() {
|
|
33722
33965
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
33723
|
-
return
|
|
33966
|
+
return join34(cacheDir, VersionCacheManager.CACHE_FILENAME);
|
|
33724
33967
|
}
|
|
33725
33968
|
static async load() {
|
|
33726
33969
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
33727
33970
|
try {
|
|
33728
|
-
if (!
|
|
33971
|
+
if (!existsSync8(cacheFile)) {
|
|
33729
33972
|
logger.debug("Version check cache not found");
|
|
33730
33973
|
return null;
|
|
33731
33974
|
}
|
|
33732
|
-
const content = await
|
|
33975
|
+
const content = await readFile17(cacheFile, "utf-8");
|
|
33733
33976
|
const cache2 = JSON.parse(content);
|
|
33734
33977
|
if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
|
|
33735
33978
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -33746,10 +33989,10 @@ class VersionCacheManager {
|
|
|
33746
33989
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
33747
33990
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
33748
33991
|
try {
|
|
33749
|
-
if (!
|
|
33750
|
-
await
|
|
33992
|
+
if (!existsSync8(cacheDir)) {
|
|
33993
|
+
await mkdir11(cacheDir, { recursive: true, mode: 448 });
|
|
33751
33994
|
}
|
|
33752
|
-
await
|
|
33995
|
+
await writeFile15(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
|
|
33753
33996
|
logger.debug(`Version check cache saved to ${cacheFile}`);
|
|
33754
33997
|
} catch (error) {
|
|
33755
33998
|
logger.debug(`Failed to save version check cache: ${error}`);
|
|
@@ -33768,7 +34011,7 @@ class VersionCacheManager {
|
|
|
33768
34011
|
static async clear() {
|
|
33769
34012
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
33770
34013
|
try {
|
|
33771
|
-
if (
|
|
34014
|
+
if (existsSync8(cacheFile)) {
|
|
33772
34015
|
const fs12 = await import("node:fs/promises");
|
|
33773
34016
|
await fs12.unlink(cacheFile);
|
|
33774
34017
|
logger.debug("Version check cache cleared");
|
|
@@ -34231,8 +34474,8 @@ class OutputManager2 {
|
|
|
34231
34474
|
var output2 = new OutputManager2;
|
|
34232
34475
|
|
|
34233
34476
|
// src/shared/path-resolver.ts
|
|
34234
|
-
import { homedir as
|
|
34235
|
-
import { join as
|
|
34477
|
+
import { homedir as homedir5, platform as platform10 } from "node:os";
|
|
34478
|
+
import { join as join35, normalize as normalize6 } from "node:path";
|
|
34236
34479
|
|
|
34237
34480
|
class PathResolver2 {
|
|
34238
34481
|
static getTestHomeDir() {
|
|
@@ -34265,50 +34508,50 @@ class PathResolver2 {
|
|
|
34265
34508
|
static getConfigDir(global3 = false) {
|
|
34266
34509
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34267
34510
|
if (testHome) {
|
|
34268
|
-
return global3 ?
|
|
34511
|
+
return global3 ? join35(testHome, ".config", "claude") : join35(testHome, ".claudekit");
|
|
34269
34512
|
}
|
|
34270
34513
|
if (!global3) {
|
|
34271
|
-
return
|
|
34514
|
+
return join35(homedir5(), ".claudekit");
|
|
34272
34515
|
}
|
|
34273
34516
|
const os2 = platform10();
|
|
34274
34517
|
if (os2 === "win32") {
|
|
34275
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
34276
|
-
return
|
|
34518
|
+
const localAppData = process.env.LOCALAPPDATA || join35(homedir5(), "AppData", "Local");
|
|
34519
|
+
return join35(localAppData, "claude");
|
|
34277
34520
|
}
|
|
34278
34521
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
34279
34522
|
if (xdgConfigHome) {
|
|
34280
|
-
return
|
|
34523
|
+
return join35(xdgConfigHome, "claude");
|
|
34281
34524
|
}
|
|
34282
|
-
return
|
|
34525
|
+
return join35(homedir5(), ".config", "claude");
|
|
34283
34526
|
}
|
|
34284
34527
|
static getConfigFile(global3 = false) {
|
|
34285
|
-
return
|
|
34528
|
+
return join35(PathResolver2.getConfigDir(global3), "config.json");
|
|
34286
34529
|
}
|
|
34287
34530
|
static getCacheDir(global3 = false) {
|
|
34288
34531
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34289
34532
|
if (testHome) {
|
|
34290
|
-
return global3 ?
|
|
34533
|
+
return global3 ? join35(testHome, ".cache", "claude") : join35(testHome, ".claudekit", "cache");
|
|
34291
34534
|
}
|
|
34292
34535
|
if (!global3) {
|
|
34293
|
-
return
|
|
34536
|
+
return join35(homedir5(), ".claudekit", "cache");
|
|
34294
34537
|
}
|
|
34295
34538
|
const os2 = platform10();
|
|
34296
34539
|
if (os2 === "win32") {
|
|
34297
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
34298
|
-
return
|
|
34540
|
+
const localAppData = process.env.LOCALAPPDATA || join35(homedir5(), "AppData", "Local");
|
|
34541
|
+
return join35(localAppData, "claude", "cache");
|
|
34299
34542
|
}
|
|
34300
34543
|
const xdgCacheHome = process.env.XDG_CACHE_HOME;
|
|
34301
34544
|
if (xdgCacheHome) {
|
|
34302
|
-
return
|
|
34545
|
+
return join35(xdgCacheHome, "claude");
|
|
34303
34546
|
}
|
|
34304
|
-
return
|
|
34547
|
+
return join35(homedir5(), ".cache", "claude");
|
|
34305
34548
|
}
|
|
34306
34549
|
static getGlobalKitDir() {
|
|
34307
34550
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34308
34551
|
if (testHome) {
|
|
34309
|
-
return
|
|
34552
|
+
return join35(testHome, ".claude");
|
|
34310
34553
|
}
|
|
34311
|
-
return
|
|
34554
|
+
return join35(homedir5(), ".claude");
|
|
34312
34555
|
}
|
|
34313
34556
|
static getPathPrefix(global3) {
|
|
34314
34557
|
return global3 ? "" : ".claude";
|
|
@@ -34316,9 +34559,9 @@ class PathResolver2 {
|
|
|
34316
34559
|
static buildSkillsPath(baseDir, global3) {
|
|
34317
34560
|
const prefix = PathResolver2.getPathPrefix(global3);
|
|
34318
34561
|
if (prefix) {
|
|
34319
|
-
return
|
|
34562
|
+
return join35(baseDir, prefix, "skills");
|
|
34320
34563
|
}
|
|
34321
|
-
return
|
|
34564
|
+
return join35(baseDir, "skills");
|
|
34322
34565
|
}
|
|
34323
34566
|
static buildComponentPath(baseDir, component, global3) {
|
|
34324
34567
|
if (!PathResolver2.isPathSafe(component)) {
|
|
@@ -34326,9 +34569,9 @@ class PathResolver2 {
|
|
|
34326
34569
|
}
|
|
34327
34570
|
const prefix = PathResolver2.getPathPrefix(global3);
|
|
34328
34571
|
if (prefix) {
|
|
34329
|
-
return
|
|
34572
|
+
return join35(baseDir, prefix, component);
|
|
34330
34573
|
}
|
|
34331
|
-
return
|
|
34574
|
+
return join35(baseDir, component);
|
|
34332
34575
|
}
|
|
34333
34576
|
}
|
|
34334
34577
|
|
|
@@ -34360,11 +34603,11 @@ async function displayVersion() {
|
|
|
34360
34603
|
let localKitVersion = null;
|
|
34361
34604
|
let isGlobalOnlyKit = false;
|
|
34362
34605
|
const globalKitDir = PathResolver2.getGlobalKitDir();
|
|
34363
|
-
const globalMetadataPath =
|
|
34606
|
+
const globalMetadataPath = join36(globalKitDir, "metadata.json");
|
|
34364
34607
|
const prefix = PathResolver2.getPathPrefix(false);
|
|
34365
|
-
const localMetadataPath = prefix ?
|
|
34608
|
+
const localMetadataPath = prefix ? join36(process.cwd(), prefix, "metadata.json") : join36(process.cwd(), "metadata.json");
|
|
34366
34609
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
34367
|
-
if (!isLocalSameAsGlobal &&
|
|
34610
|
+
if (!isLocalSameAsGlobal && existsSync9(localMetadataPath)) {
|
|
34368
34611
|
try {
|
|
34369
34612
|
const rawMetadata = JSON.parse(readFileSync5(localMetadataPath, "utf-8"));
|
|
34370
34613
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
@@ -34378,7 +34621,7 @@ async function displayVersion() {
|
|
|
34378
34621
|
logger2.verbose("Failed to parse local metadata.json", { error });
|
|
34379
34622
|
}
|
|
34380
34623
|
}
|
|
34381
|
-
if (
|
|
34624
|
+
if (existsSync9(globalMetadataPath)) {
|
|
34382
34625
|
try {
|
|
34383
34626
|
const rawMetadata = JSON.parse(readFileSync5(globalMetadataPath, "utf-8"));
|
|
34384
34627
|
const metadata = MetadataSchema.parse(rawMetadata);
|