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.
- package/dist/index.js +373 -134
- 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,
|
|
@@ -12802,11 +13032,7 @@ async function installSkillsDependencies(skillsDir) {
|
|
|
12802
13032
|
NON_INTERACTIVE: "1"
|
|
12803
13033
|
};
|
|
12804
13034
|
if (platform9 === "win32") {
|
|
12805
|
-
|
|
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 ${
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
13773
|
+
resolve8(code2 === 0);
|
|
13548
13774
|
});
|
|
13549
13775
|
pager.on("error", () => {
|
|
13550
13776
|
clearTimeout(timeout);
|
|
13551
|
-
|
|
13777
|
+
resolve8(false);
|
|
13552
13778
|
});
|
|
13553
13779
|
} catch {
|
|
13554
|
-
|
|
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((
|
|
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
|
-
|
|
13812
|
+
resolve8();
|
|
13587
13813
|
return;
|
|
13588
13814
|
}
|
|
13589
13815
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
13590
|
-
|
|
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
|
|
13849
|
-
import { join as
|
|
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.
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
31637
|
-
const sourceSubDir =
|
|
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 =
|
|
31666
|
-
const resolvedTarget =
|
|
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
|
|
31676
|
-
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";
|
|
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 =
|
|
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 =
|
|
31724
|
-
const tempDir =
|
|
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 =
|
|
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
|
|
31742
|
-
const ckDir =
|
|
31743
|
-
await
|
|
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 =
|
|
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 =
|
|
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 :
|
|
31801
|
-
const commandsDir =
|
|
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 =
|
|
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 =
|
|
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
|
|
32015
|
-
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";
|
|
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 =
|
|
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:
|
|
32291
|
+
to: join29(extractDir, folders.docs)
|
|
32066
32292
|
});
|
|
32067
32293
|
}
|
|
32068
|
-
const claudeDocsPath =
|
|
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:
|
|
32298
|
+
to: join29(extractDir, ".claude", folders.docs)
|
|
32073
32299
|
});
|
|
32074
32300
|
}
|
|
32075
32301
|
}
|
|
32076
32302
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
32077
|
-
const plansPath =
|
|
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:
|
|
32307
|
+
to: join29(extractDir, folders.plans)
|
|
32082
32308
|
});
|
|
32083
32309
|
}
|
|
32084
|
-
const claudePlansPath =
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
32562
|
+
const content = await readFile16(fullPath, "utf-8");
|
|
32337
32563
|
const { transformed, changes } = transformContent(content);
|
|
32338
32564
|
if (changes > 0) {
|
|
32339
|
-
await
|
|
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 =
|
|
32388
|
-
const isInGlobalDir = cwdResolved === globalKitDir || cwdResolved ===
|
|
32389
|
-
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");
|
|
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 =
|
|
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 =
|
|
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:
|
|
32450
|
-
await
|
|
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 ?
|
|
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 ?
|
|
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 =
|
|
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 ?
|
|
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 :
|
|
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 ?
|
|
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 =
|
|
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 =
|
|
32726
|
-
const claudeMdDest =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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.
|
|
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
|
|
33720
|
-
import { mkdir as
|
|
33721
|
-
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";
|
|
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
|
|
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 (!
|
|
33971
|
+
if (!existsSync8(cacheFile)) {
|
|
33733
33972
|
logger.debug("Version check cache not found");
|
|
33734
33973
|
return null;
|
|
33735
33974
|
}
|
|
33736
|
-
const content = await
|
|
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 (!
|
|
33754
|
-
await
|
|
33992
|
+
if (!existsSync8(cacheDir)) {
|
|
33993
|
+
await mkdir11(cacheDir, { recursive: true, mode: 448 });
|
|
33755
33994
|
}
|
|
33756
|
-
await
|
|
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 (
|
|
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
|
|
34239
|
-
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";
|
|
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 ?
|
|
34511
|
+
return global3 ? join35(testHome, ".config", "claude") : join35(testHome, ".claudekit");
|
|
34273
34512
|
}
|
|
34274
34513
|
if (!global3) {
|
|
34275
|
-
return
|
|
34514
|
+
return join35(homedir5(), ".claudekit");
|
|
34276
34515
|
}
|
|
34277
34516
|
const os2 = platform10();
|
|
34278
34517
|
if (os2 === "win32") {
|
|
34279
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
34280
|
-
return
|
|
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
|
|
34523
|
+
return join35(xdgConfigHome, "claude");
|
|
34285
34524
|
}
|
|
34286
|
-
return
|
|
34525
|
+
return join35(homedir5(), ".config", "claude");
|
|
34287
34526
|
}
|
|
34288
34527
|
static getConfigFile(global3 = false) {
|
|
34289
|
-
return
|
|
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 ?
|
|
34533
|
+
return global3 ? join35(testHome, ".cache", "claude") : join35(testHome, ".claudekit", "cache");
|
|
34295
34534
|
}
|
|
34296
34535
|
if (!global3) {
|
|
34297
|
-
return
|
|
34536
|
+
return join35(homedir5(), ".claudekit", "cache");
|
|
34298
34537
|
}
|
|
34299
34538
|
const os2 = platform10();
|
|
34300
34539
|
if (os2 === "win32") {
|
|
34301
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
34302
|
-
return
|
|
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
|
|
34545
|
+
return join35(xdgCacheHome, "claude");
|
|
34307
34546
|
}
|
|
34308
|
-
return
|
|
34547
|
+
return join35(homedir5(), ".cache", "claude");
|
|
34309
34548
|
}
|
|
34310
34549
|
static getGlobalKitDir() {
|
|
34311
34550
|
const testHome = PathResolver2.getTestHomeDir();
|
|
34312
34551
|
if (testHome) {
|
|
34313
|
-
return
|
|
34552
|
+
return join35(testHome, ".claude");
|
|
34314
34553
|
}
|
|
34315
|
-
return
|
|
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
|
|
34562
|
+
return join35(baseDir, prefix, "skills");
|
|
34324
34563
|
}
|
|
34325
|
-
return
|
|
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
|
|
34572
|
+
return join35(baseDir, prefix, component);
|
|
34334
34573
|
}
|
|
34335
|
-
return
|
|
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 =
|
|
34606
|
+
const globalMetadataPath = join36(globalKitDir, "metadata.json");
|
|
34368
34607
|
const prefix = PathResolver2.getPathPrefix(false);
|
|
34369
|
-
const localMetadataPath = prefix ?
|
|
34608
|
+
const localMetadataPath = prefix ? join36(process.cwd(), prefix, "metadata.json") : join36(process.cwd(), "metadata.json");
|
|
34370
34609
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
34371
|
-
if (!isLocalSameAsGlobal &&
|
|
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 (
|
|
34624
|
+
if (existsSync9(globalMetadataPath)) {
|
|
34386
34625
|
try {
|
|
34387
34626
|
const rawMetadata = JSON.parse(readFileSync5(globalMetadataPath, "utf-8"));
|
|
34388
34627
|
const metadata = MetadataSchema.parse(rawMetadata);
|