claudekit-cli 3.36.0-dev.2 → 3.36.0-dev.4
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 +734 -1773
- package/dist/ui/assets/{index-Dpm-K_Vt.js → index-CP1z4SKN.js} +21 -21
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38479,10 +38479,7 @@ var init_metadata = __esm(() => {
|
|
|
38479
38479
|
files: exports_external.array(TrackedFileSchema).optional(),
|
|
38480
38480
|
lastUpdateCheck: exports_external.string().optional(),
|
|
38481
38481
|
dismissedVersion: exports_external.string().optional(),
|
|
38482
|
-
installedSettings: InstalledSettingsSchema.optional()
|
|
38483
|
-
pluginInstalled: exports_external.boolean().optional(),
|
|
38484
|
-
pluginInstalledAt: exports_external.string().optional(),
|
|
38485
|
-
pluginVersion: exports_external.string().optional()
|
|
38482
|
+
installedSettings: InstalledSettingsSchema.optional()
|
|
38486
38483
|
});
|
|
38487
38484
|
MultiKitMetadataSchema = exports_external.object({
|
|
38488
38485
|
kits: exports_external.record(KitType, KitMetadataSchema).optional(),
|
|
@@ -53923,17 +53920,6 @@ var init_package_manager_detector = __esm(() => {
|
|
|
53923
53920
|
});
|
|
53924
53921
|
|
|
53925
53922
|
// src/domains/migration/metadata-migration.ts
|
|
53926
|
-
var exports_metadata_migration = {};
|
|
53927
|
-
__export(exports_metadata_migration, {
|
|
53928
|
-
updateKitPluginState: () => updateKitPluginState,
|
|
53929
|
-
needsMigration: () => needsMigration,
|
|
53930
|
-
migrateToMultiKit: () => migrateToMultiKit,
|
|
53931
|
-
getTrackedFilesForKit: () => getTrackedFilesForKit,
|
|
53932
|
-
getKitMetadata: () => getKitMetadata,
|
|
53933
|
-
getInstalledKits: () => getInstalledKits,
|
|
53934
|
-
getAllTrackedFiles: () => getAllTrackedFiles,
|
|
53935
|
-
detectMetadataFormat: () => detectMetadataFormat
|
|
53936
|
-
});
|
|
53937
53923
|
import { join as join35 } from "node:path";
|
|
53938
53924
|
async function detectMetadataFormat(claudeDir2) {
|
|
53939
53925
|
const metadataPath = join35(claudeDir2, "metadata.json");
|
|
@@ -53970,9 +53956,6 @@ async function detectMetadataFormat(claudeDir2) {
|
|
|
53970
53956
|
return { format: "none", metadata: null, detectedKit: null };
|
|
53971
53957
|
}
|
|
53972
53958
|
}
|
|
53973
|
-
function needsMigration(detection) {
|
|
53974
|
-
return detection.format === "legacy";
|
|
53975
|
-
}
|
|
53976
53959
|
async function migrateToMultiKit(claudeDir2) {
|
|
53977
53960
|
const detection = await detectMetadataFormat(claudeDir2);
|
|
53978
53961
|
if (detection.format === "multi-kit") {
|
|
@@ -54096,41 +54079,6 @@ function getInstalledKits(metadata) {
|
|
|
54096
54079
|
}
|
|
54097
54080
|
return [];
|
|
54098
54081
|
}
|
|
54099
|
-
async function updateKitPluginState(claudeDir2, kit, state) {
|
|
54100
|
-
const metadataPath = join35(claudeDir2, "metadata.json");
|
|
54101
|
-
if (!await import_fs_extra3.pathExists(metadataPath)) {
|
|
54102
|
-
logger.debug("No metadata.json found — skipping plugin state update");
|
|
54103
|
-
return;
|
|
54104
|
-
}
|
|
54105
|
-
try {
|
|
54106
|
-
let metadata = {};
|
|
54107
|
-
try {
|
|
54108
|
-
const raw = await import_fs_extra3.readFile(metadataPath, "utf-8");
|
|
54109
|
-
const parsed = JSON.parse(raw);
|
|
54110
|
-
if (parsed && typeof parsed === "object") {
|
|
54111
|
-
metadata = parsed;
|
|
54112
|
-
} else {
|
|
54113
|
-
logger.warning("metadata.json is not an object; rebuilding minimal plugin metadata structure");
|
|
54114
|
-
}
|
|
54115
|
-
} catch (error) {
|
|
54116
|
-
logger.warning(`metadata.json unreadable during plugin state update; rebuilding: ${error}`);
|
|
54117
|
-
}
|
|
54118
|
-
if (!metadata.kits || typeof metadata.kits !== "object") {
|
|
54119
|
-
metadata.kits = {};
|
|
54120
|
-
}
|
|
54121
|
-
const existingKitState = metadata.kits[kit];
|
|
54122
|
-
metadata.kits[kit] = {
|
|
54123
|
-
...existingKitState || {},
|
|
54124
|
-
version: existingKitState?.version ?? "",
|
|
54125
|
-
installedAt: existingKitState?.installedAt ?? state.pluginInstalledAt,
|
|
54126
|
-
...state
|
|
54127
|
-
};
|
|
54128
|
-
await import_fs_extra3.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
54129
|
-
logger.debug(`Plugin state saved: ${state.pluginInstalled ? "installed" : "failed"}`);
|
|
54130
|
-
} catch (error) {
|
|
54131
|
-
logger.debug(`Failed to update plugin state: ${error}`);
|
|
54132
|
-
}
|
|
54133
|
-
}
|
|
54134
54082
|
var import_fs_extra3;
|
|
54135
54083
|
var init_metadata_migration = __esm(() => {
|
|
54136
54084
|
init_logger();
|
|
@@ -54366,7 +54314,7 @@ var package_default;
|
|
|
54366
54314
|
var init_package = __esm(() => {
|
|
54367
54315
|
package_default = {
|
|
54368
54316
|
name: "claudekit-cli",
|
|
54369
|
-
version: "3.36.0-dev.
|
|
54317
|
+
version: "3.36.0-dev.4",
|
|
54370
54318
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
54371
54319
|
type: "module",
|
|
54372
54320
|
repository: {
|
|
@@ -61555,7 +61503,7 @@ var require_picomatch2 = __commonJS((exports, module) => {
|
|
|
61555
61503
|
import { exec as exec7, execFile as execFile7, spawn as spawn3 } from "node:child_process";
|
|
61556
61504
|
import { promisify as promisify13 } from "node:util";
|
|
61557
61505
|
function executeInteractiveScript(command, args, options2) {
|
|
61558
|
-
return new Promise((
|
|
61506
|
+
return new Promise((resolve13, reject) => {
|
|
61559
61507
|
const child = spawn3(command, args, {
|
|
61560
61508
|
stdio: ["ignore", "inherit", "inherit"],
|
|
61561
61509
|
cwd: options2?.cwd,
|
|
@@ -61576,7 +61524,7 @@ function executeInteractiveScript(command, args, options2) {
|
|
|
61576
61524
|
} else if (code !== 0) {
|
|
61577
61525
|
reject(new Error(`Command exited with code ${code}`));
|
|
61578
61526
|
} else {
|
|
61579
|
-
|
|
61527
|
+
resolve13();
|
|
61580
61528
|
}
|
|
61581
61529
|
});
|
|
61582
61530
|
child.on("error", (error) => {
|
|
@@ -61597,7 +61545,7 @@ var init_process_executor = __esm(() => {
|
|
|
61597
61545
|
});
|
|
61598
61546
|
|
|
61599
61547
|
// src/services/package-installer/validators.ts
|
|
61600
|
-
import { resolve as
|
|
61548
|
+
import { resolve as resolve13 } from "node:path";
|
|
61601
61549
|
function validatePackageName(packageName) {
|
|
61602
61550
|
if (!packageName || typeof packageName !== "string") {
|
|
61603
61551
|
throw new Error("Package name must be a non-empty string");
|
|
@@ -61610,8 +61558,8 @@ function validatePackageName(packageName) {
|
|
|
61610
61558
|
}
|
|
61611
61559
|
}
|
|
61612
61560
|
function validateScriptPath(skillsDir2, scriptPath) {
|
|
61613
|
-
const skillsDirResolved =
|
|
61614
|
-
const scriptPathResolved =
|
|
61561
|
+
const skillsDirResolved = resolve13(skillsDir2);
|
|
61562
|
+
const scriptPathResolved = resolve13(scriptPath);
|
|
61615
61563
|
const skillsDirNormalized = isWindows() ? skillsDirResolved.toLowerCase() : skillsDirResolved;
|
|
61616
61564
|
const scriptPathNormalized = isWindows() ? scriptPathResolved.toLowerCase() : scriptPathResolved;
|
|
61617
61565
|
if (!scriptPathNormalized.startsWith(skillsDirNormalized)) {
|
|
@@ -61798,7 +61746,7 @@ var init_gemini_installer = __esm(() => {
|
|
|
61798
61746
|
});
|
|
61799
61747
|
|
|
61800
61748
|
// src/services/package-installer/opencode-installer.ts
|
|
61801
|
-
import { join as
|
|
61749
|
+
import { join as join59 } from "node:path";
|
|
61802
61750
|
async function isOpenCodeInstalled() {
|
|
61803
61751
|
try {
|
|
61804
61752
|
await execAsync7("opencode --version", { timeout: 5000 });
|
|
@@ -61821,7 +61769,7 @@ async function installOpenCode() {
|
|
|
61821
61769
|
logger.info(`Installing ${displayName}...`);
|
|
61822
61770
|
const { unlink: unlink11 } = await import("node:fs/promises");
|
|
61823
61771
|
const { tmpdir: tmpdir4 } = await import("node:os");
|
|
61824
|
-
const tempScriptPath =
|
|
61772
|
+
const tempScriptPath = join59(tmpdir4(), "opencode-install.sh");
|
|
61825
61773
|
try {
|
|
61826
61774
|
logger.info("Downloading OpenCode installation script...");
|
|
61827
61775
|
await execFileAsync5("curl", ["-fsSL", "https://opencode.ai/install", "-o", tempScriptPath], {
|
|
@@ -61873,7 +61821,7 @@ var PARTIAL_INSTALL_VERSION = "partial", EXIT_CODE_CRITICAL_FAILURE = 1, EXIT_CO
|
|
|
61873
61821
|
|
|
61874
61822
|
// src/services/package-installer/install-error-handler.ts
|
|
61875
61823
|
import { existsSync as existsSync44, readFileSync as readFileSync9, unlinkSync as unlinkSync2 } from "node:fs";
|
|
61876
|
-
import { join as
|
|
61824
|
+
import { join as join60 } from "node:path";
|
|
61877
61825
|
function parseNameReason(str2) {
|
|
61878
61826
|
const colonIndex = str2.indexOf(":");
|
|
61879
61827
|
if (colonIndex === -1) {
|
|
@@ -61882,7 +61830,7 @@ function parseNameReason(str2) {
|
|
|
61882
61830
|
return [str2.slice(0, colonIndex).trim(), str2.slice(colonIndex + 1).trim()];
|
|
61883
61831
|
}
|
|
61884
61832
|
function displayInstallErrors(skillsDir2) {
|
|
61885
|
-
const summaryPath =
|
|
61833
|
+
const summaryPath = join60(skillsDir2, ".install-error-summary.json");
|
|
61886
61834
|
if (!existsSync44(summaryPath)) {
|
|
61887
61835
|
logger.error("Skills installation failed. Run with --verbose for details.");
|
|
61888
61836
|
return;
|
|
@@ -61973,7 +61921,7 @@ async function checkNeedsSudoPackages() {
|
|
|
61973
61921
|
}
|
|
61974
61922
|
}
|
|
61975
61923
|
function hasInstallState(skillsDir2) {
|
|
61976
|
-
const stateFilePath =
|
|
61924
|
+
const stateFilePath = join60(skillsDir2, ".install-state.json");
|
|
61977
61925
|
return existsSync44(stateFilePath);
|
|
61978
61926
|
}
|
|
61979
61927
|
var WHICH_COMMAND_TIMEOUT_MS = 5000;
|
|
@@ -61982,7 +61930,7 @@ var init_install_error_handler = __esm(() => {
|
|
|
61982
61930
|
});
|
|
61983
61931
|
|
|
61984
61932
|
// src/services/package-installer/skills-installer.ts
|
|
61985
|
-
import { join as
|
|
61933
|
+
import { join as join61 } from "node:path";
|
|
61986
61934
|
async function installSkillsDependencies(skillsDir2, options2 = {}) {
|
|
61987
61935
|
const { skipConfirm = false, withSudo = false } = options2;
|
|
61988
61936
|
const displayName = "Skills Dependencies";
|
|
@@ -62008,7 +61956,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
|
|
|
62008
61956
|
const clack = await Promise.resolve().then(() => (init_dist2(), exports_dist));
|
|
62009
61957
|
const platform7 = process.platform;
|
|
62010
61958
|
const scriptName = platform7 === "win32" ? "install.ps1" : "install.sh";
|
|
62011
|
-
const scriptPath =
|
|
61959
|
+
const scriptPath = join61(skillsDir2, scriptName);
|
|
62012
61960
|
try {
|
|
62013
61961
|
validateScriptPath(skillsDir2, scriptPath);
|
|
62014
61962
|
} catch (error) {
|
|
@@ -62024,7 +61972,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
|
|
|
62024
61972
|
logger.warning(`Skills installation script not found: ${scriptPath}`);
|
|
62025
61973
|
logger.info("");
|
|
62026
61974
|
logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
|
|
62027
|
-
logger.info(` See: ${
|
|
61975
|
+
logger.info(` See: ${join61(skillsDir2, "INSTALLATION.md")}`);
|
|
62028
61976
|
logger.info("");
|
|
62029
61977
|
logger.info("Quick start:");
|
|
62030
61978
|
logger.info(" cd .claude/skills/ai-multimodal/scripts");
|
|
@@ -62071,7 +62019,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
|
|
|
62071
62019
|
logger.info(` ${platform7 === "win32" ? `powershell -File "${scriptPath}"` : `bash ${scriptPath}`}`);
|
|
62072
62020
|
logger.info("");
|
|
62073
62021
|
logger.info("Or see complete guide:");
|
|
62074
|
-
logger.info(` ${
|
|
62022
|
+
logger.info(` ${join61(skillsDir2, "INSTALLATION.md")}`);
|
|
62075
62023
|
return {
|
|
62076
62024
|
success: false,
|
|
62077
62025
|
package: displayName,
|
|
@@ -62192,7 +62140,7 @@ async function installSkillsDependencies(skillsDir2, options2 = {}) {
|
|
|
62192
62140
|
logger.info("\uD83D\uDCD6 Manual Installation Instructions:");
|
|
62193
62141
|
logger.info("");
|
|
62194
62142
|
logger.info("See complete guide:");
|
|
62195
|
-
logger.info(` cat ${
|
|
62143
|
+
logger.info(` cat ${join61(skillsDir2, "INSTALLATION.md")}`);
|
|
62196
62144
|
logger.info("");
|
|
62197
62145
|
logger.info("Quick start:");
|
|
62198
62146
|
logger.info(" cd .claude/skills/ai-multimodal/scripts");
|
|
@@ -62238,7 +62186,7 @@ var init_skills_installer2 = __esm(() => {
|
|
|
62238
62186
|
// src/services/package-installer/gemini-mcp/config-manager.ts
|
|
62239
62187
|
import { existsSync as existsSync45 } from "node:fs";
|
|
62240
62188
|
import { mkdir as mkdir17, readFile as readFile35, writeFile as writeFile20 } from "node:fs/promises";
|
|
62241
|
-
import { dirname as
|
|
62189
|
+
import { dirname as dirname15, join as join62 } from "node:path";
|
|
62242
62190
|
async function readJsonFile(filePath) {
|
|
62243
62191
|
try {
|
|
62244
62192
|
const content = await readFile35(filePath, "utf-8");
|
|
@@ -62250,7 +62198,7 @@ async function readJsonFile(filePath) {
|
|
|
62250
62198
|
}
|
|
62251
62199
|
}
|
|
62252
62200
|
async function addGeminiToGitignore(projectDir) {
|
|
62253
|
-
const gitignorePath =
|
|
62201
|
+
const gitignorePath = join62(projectDir, ".gitignore");
|
|
62254
62202
|
const geminiPattern = ".gemini/";
|
|
62255
62203
|
try {
|
|
62256
62204
|
let content = "";
|
|
@@ -62278,7 +62226,7 @@ ${geminiPattern}
|
|
|
62278
62226
|
}
|
|
62279
62227
|
}
|
|
62280
62228
|
async function createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath) {
|
|
62281
|
-
const linkDir =
|
|
62229
|
+
const linkDir = dirname15(geminiSettingsPath);
|
|
62282
62230
|
if (!existsSync45(linkDir)) {
|
|
62283
62231
|
await mkdir17(linkDir, { recursive: true });
|
|
62284
62232
|
logger.debug(`Created directory: ${linkDir}`);
|
|
@@ -62342,12 +62290,12 @@ var init_config_manager2 = __esm(() => {
|
|
|
62342
62290
|
// src/services/package-installer/gemini-mcp/validation.ts
|
|
62343
62291
|
import { existsSync as existsSync46, lstatSync, readlinkSync } from "node:fs";
|
|
62344
62292
|
import { homedir as homedir27 } from "node:os";
|
|
62345
|
-
import { join as
|
|
62293
|
+
import { join as join63 } from "node:path";
|
|
62346
62294
|
function getGlobalMcpConfigPath() {
|
|
62347
|
-
return
|
|
62295
|
+
return join63(homedir27(), ".claude", ".mcp.json");
|
|
62348
62296
|
}
|
|
62349
62297
|
function getLocalMcpConfigPath(projectDir) {
|
|
62350
|
-
return
|
|
62298
|
+
return join63(projectDir, ".mcp.json");
|
|
62351
62299
|
}
|
|
62352
62300
|
function findMcpConfigPath(projectDir) {
|
|
62353
62301
|
const localPath = getLocalMcpConfigPath(projectDir);
|
|
@@ -62365,9 +62313,9 @@ function findMcpConfigPath(projectDir) {
|
|
|
62365
62313
|
}
|
|
62366
62314
|
function getGeminiSettingsPath(projectDir, isGlobal) {
|
|
62367
62315
|
if (isGlobal) {
|
|
62368
|
-
return
|
|
62316
|
+
return join63(homedir27(), ".gemini", "settings.json");
|
|
62369
62317
|
}
|
|
62370
|
-
return
|
|
62318
|
+
return join63(projectDir, ".gemini", "settings.json");
|
|
62371
62319
|
}
|
|
62372
62320
|
function checkExistingGeminiConfig(projectDir, isGlobal = false) {
|
|
62373
62321
|
const geminiSettingsPath = getGeminiSettingsPath(projectDir, isGlobal);
|
|
@@ -62397,9 +62345,9 @@ var init_validation = __esm(() => {
|
|
|
62397
62345
|
// src/services/package-installer/gemini-mcp/linker-core.ts
|
|
62398
62346
|
import { existsSync as existsSync47 } from "node:fs";
|
|
62399
62347
|
import { mkdir as mkdir18, symlink as symlink2 } from "node:fs/promises";
|
|
62400
|
-
import { dirname as
|
|
62348
|
+
import { dirname as dirname16, join as join64 } from "node:path";
|
|
62401
62349
|
async function createSymlink(targetPath, linkPath, projectDir, isGlobal) {
|
|
62402
|
-
const linkDir =
|
|
62350
|
+
const linkDir = dirname16(linkPath);
|
|
62403
62351
|
if (!existsSync47(linkDir)) {
|
|
62404
62352
|
await mkdir18(linkDir, { recursive: true });
|
|
62405
62353
|
logger.debug(`Created directory: ${linkDir}`);
|
|
@@ -62408,7 +62356,7 @@ async function createSymlink(targetPath, linkPath, projectDir, isGlobal) {
|
|
|
62408
62356
|
if (isGlobal) {
|
|
62409
62357
|
symlinkTarget = getGlobalMcpConfigPath();
|
|
62410
62358
|
} else {
|
|
62411
|
-
const localMcpPath =
|
|
62359
|
+
const localMcpPath = join64(projectDir, ".mcp.json");
|
|
62412
62360
|
const isLocalConfig = targetPath === localMcpPath;
|
|
62413
62361
|
symlinkTarget = isLocalConfig ? "../.mcp.json" : targetPath;
|
|
62414
62362
|
}
|
|
@@ -62441,10 +62389,10 @@ __export(exports_gemini_mcp_linker, {
|
|
|
62441
62389
|
checkExistingGeminiConfig: () => checkExistingGeminiConfig,
|
|
62442
62390
|
addGeminiToGitignore: () => addGeminiToGitignore
|
|
62443
62391
|
});
|
|
62444
|
-
import { resolve as
|
|
62392
|
+
import { resolve as resolve14 } from "node:path";
|
|
62445
62393
|
async function linkGeminiMcpConfig(projectDir, options2 = {}) {
|
|
62446
62394
|
const { skipGitignore = false, isGlobal = false } = options2;
|
|
62447
|
-
const resolvedProjectDir =
|
|
62395
|
+
const resolvedProjectDir = resolve14(projectDir);
|
|
62448
62396
|
const geminiSettingsPath = getGeminiSettingsPath(resolvedProjectDir, isGlobal);
|
|
62449
62397
|
const mcpConfigPath = findMcpConfigPath(resolvedProjectDir);
|
|
62450
62398
|
if (!mcpConfigPath) {
|
|
@@ -63092,7 +63040,7 @@ var require_get_stream = __commonJS((exports, module) => {
|
|
|
63092
63040
|
};
|
|
63093
63041
|
const { maxBuffer } = options2;
|
|
63094
63042
|
let stream;
|
|
63095
|
-
await new Promise((
|
|
63043
|
+
await new Promise((resolve16, reject) => {
|
|
63096
63044
|
const rejectPromise = (error) => {
|
|
63097
63045
|
if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
|
|
63098
63046
|
error.bufferedData = stream.getBufferedValue();
|
|
@@ -63104,7 +63052,7 @@ var require_get_stream = __commonJS((exports, module) => {
|
|
|
63104
63052
|
rejectPromise(error);
|
|
63105
63053
|
return;
|
|
63106
63054
|
}
|
|
63107
|
-
|
|
63055
|
+
resolve16();
|
|
63108
63056
|
});
|
|
63109
63057
|
stream.on("data", () => {
|
|
63110
63058
|
if (stream.getBufferedLength() > maxBuffer) {
|
|
@@ -64465,7 +64413,7 @@ var require_extract_zip = __commonJS((exports, module) => {
|
|
|
64465
64413
|
debug("opening", this.zipPath, "with opts", this.opts);
|
|
64466
64414
|
this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
|
|
64467
64415
|
this.canceled = false;
|
|
64468
|
-
return new Promise((
|
|
64416
|
+
return new Promise((resolve16, reject) => {
|
|
64469
64417
|
this.zipfile.on("error", (err) => {
|
|
64470
64418
|
this.canceled = true;
|
|
64471
64419
|
reject(err);
|
|
@@ -64474,7 +64422,7 @@ var require_extract_zip = __commonJS((exports, module) => {
|
|
|
64474
64422
|
this.zipfile.on("close", () => {
|
|
64475
64423
|
if (!this.canceled) {
|
|
64476
64424
|
debug("zip extraction complete");
|
|
64477
|
-
|
|
64425
|
+
resolve16();
|
|
64478
64426
|
}
|
|
64479
64427
|
});
|
|
64480
64428
|
this.zipfile.on("entry", async (entry) => {
|
|
@@ -64581,412 +64529,6 @@ var require_extract_zip = __commonJS((exports, module) => {
|
|
|
64581
64529
|
};
|
|
64582
64530
|
});
|
|
64583
64531
|
|
|
64584
|
-
// src/services/file-operations/manifest/manifest-reader.ts
|
|
64585
|
-
import { join as join74 } from "node:path";
|
|
64586
|
-
async function readManifest(claudeDir2) {
|
|
64587
|
-
const metadataPath = join74(claudeDir2, "metadata.json");
|
|
64588
|
-
if (!await import_fs_extra8.pathExists(metadataPath)) {
|
|
64589
|
-
return null;
|
|
64590
|
-
}
|
|
64591
|
-
try {
|
|
64592
|
-
const content = await import_fs_extra8.readFile(metadataPath, "utf-8");
|
|
64593
|
-
const parsed = JSON.parse(content);
|
|
64594
|
-
return MetadataSchema.parse(parsed);
|
|
64595
|
-
} catch (error) {
|
|
64596
|
-
logger.debug(`Failed to read manifest: ${error}`);
|
|
64597
|
-
return null;
|
|
64598
|
-
}
|
|
64599
|
-
}
|
|
64600
|
-
async function readKitManifest(claudeDir2, kit) {
|
|
64601
|
-
const metadata = await readManifest(claudeDir2);
|
|
64602
|
-
if (!metadata)
|
|
64603
|
-
return null;
|
|
64604
|
-
return getKitMetadata(metadata, kit);
|
|
64605
|
-
}
|
|
64606
|
-
async function findFileInInstalledKits(claudeDir2, relativePath, excludeKit) {
|
|
64607
|
-
const metadata = await readManifest(claudeDir2);
|
|
64608
|
-
if (!metadata?.kits) {
|
|
64609
|
-
return {
|
|
64610
|
-
exists: false,
|
|
64611
|
-
ownerKit: null,
|
|
64612
|
-
checksum: null,
|
|
64613
|
-
version: null,
|
|
64614
|
-
sourceTimestamp: null,
|
|
64615
|
-
installedAt: null
|
|
64616
|
-
};
|
|
64617
|
-
}
|
|
64618
|
-
for (const [kitName, kitMeta] of Object.entries(metadata.kits)) {
|
|
64619
|
-
const kit = kitName;
|
|
64620
|
-
if (kit === excludeKit)
|
|
64621
|
-
continue;
|
|
64622
|
-
if (!kitMeta.files)
|
|
64623
|
-
continue;
|
|
64624
|
-
const file = kitMeta.files.find((f3) => f3.path === relativePath);
|
|
64625
|
-
if (file) {
|
|
64626
|
-
return {
|
|
64627
|
-
exists: true,
|
|
64628
|
-
ownerKit: kit,
|
|
64629
|
-
checksum: file.checksum,
|
|
64630
|
-
version: kitMeta.version,
|
|
64631
|
-
sourceTimestamp: file.sourceTimestamp ?? null,
|
|
64632
|
-
installedAt: file.installedAt ?? null
|
|
64633
|
-
};
|
|
64634
|
-
}
|
|
64635
|
-
}
|
|
64636
|
-
return {
|
|
64637
|
-
exists: false,
|
|
64638
|
-
ownerKit: null,
|
|
64639
|
-
checksum: null,
|
|
64640
|
-
version: null,
|
|
64641
|
-
sourceTimestamp: null,
|
|
64642
|
-
installedAt: null
|
|
64643
|
-
};
|
|
64644
|
-
}
|
|
64645
|
-
async function getUninstallManifest(claudeDir2, kit) {
|
|
64646
|
-
const detection = await detectMetadataFormat(claudeDir2);
|
|
64647
|
-
if (detection.format === "multi-kit" && detection.metadata?.kits) {
|
|
64648
|
-
const installedKits = Object.keys(detection.metadata.kits);
|
|
64649
|
-
if (kit) {
|
|
64650
|
-
const kitMeta = detection.metadata.kits[kit];
|
|
64651
|
-
if (!kitMeta?.files) {
|
|
64652
|
-
return {
|
|
64653
|
-
filesToRemove: [],
|
|
64654
|
-
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
64655
|
-
hasManifest: true,
|
|
64656
|
-
isMultiKit: true,
|
|
64657
|
-
remainingKits: installedKits.filter((k2) => k2 !== kit)
|
|
64658
|
-
};
|
|
64659
|
-
}
|
|
64660
|
-
const kitFiles = kitMeta.files.map((f3) => f3.path);
|
|
64661
|
-
const sharedFiles = new Set;
|
|
64662
|
-
for (const otherKit of installedKits) {
|
|
64663
|
-
if (otherKit !== kit) {
|
|
64664
|
-
const otherMeta = detection.metadata.kits[otherKit];
|
|
64665
|
-
if (otherMeta?.files) {
|
|
64666
|
-
for (const f3 of otherMeta.files) {
|
|
64667
|
-
sharedFiles.add(f3.path);
|
|
64668
|
-
}
|
|
64669
|
-
}
|
|
64670
|
-
}
|
|
64671
|
-
}
|
|
64672
|
-
const filesToRemove = kitFiles.filter((f3) => !sharedFiles.has(f3));
|
|
64673
|
-
const filesToPreserve = [
|
|
64674
|
-
...USER_CONFIG_PATTERNS,
|
|
64675
|
-
...kitFiles.filter((f3) => sharedFiles.has(f3))
|
|
64676
|
-
];
|
|
64677
|
-
return {
|
|
64678
|
-
filesToRemove,
|
|
64679
|
-
filesToPreserve,
|
|
64680
|
-
hasManifest: true,
|
|
64681
|
-
isMultiKit: true,
|
|
64682
|
-
remainingKits: installedKits.filter((k2) => k2 !== kit)
|
|
64683
|
-
};
|
|
64684
|
-
}
|
|
64685
|
-
const allFiles = getAllTrackedFiles(detection.metadata);
|
|
64686
|
-
return {
|
|
64687
|
-
filesToRemove: allFiles.map((f3) => f3.path),
|
|
64688
|
-
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
64689
|
-
hasManifest: true,
|
|
64690
|
-
isMultiKit: true,
|
|
64691
|
-
remainingKits: []
|
|
64692
|
-
};
|
|
64693
|
-
}
|
|
64694
|
-
if (detection.format === "legacy" && detection.metadata) {
|
|
64695
|
-
const legacyFiles2 = detection.metadata.files?.map((f3) => f3.path) || [];
|
|
64696
|
-
const installedFiles = detection.metadata.installedFiles || [];
|
|
64697
|
-
const hasFiles = legacyFiles2.length > 0 || installedFiles.length > 0;
|
|
64698
|
-
if (!hasFiles) {
|
|
64699
|
-
const legacyDirs2 = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
|
|
64700
|
-
const legacyFileList = ["metadata.json"];
|
|
64701
|
-
return {
|
|
64702
|
-
filesToRemove: [...legacyDirs2, ...legacyFileList],
|
|
64703
|
-
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
64704
|
-
hasManifest: false,
|
|
64705
|
-
isMultiKit: false,
|
|
64706
|
-
remainingKits: []
|
|
64707
|
-
};
|
|
64708
|
-
}
|
|
64709
|
-
return {
|
|
64710
|
-
filesToRemove: legacyFiles2.length > 0 ? legacyFiles2 : installedFiles,
|
|
64711
|
-
filesToPreserve: detection.metadata.userConfigFiles || USER_CONFIG_PATTERNS,
|
|
64712
|
-
hasManifest: true,
|
|
64713
|
-
isMultiKit: false,
|
|
64714
|
-
remainingKits: []
|
|
64715
|
-
};
|
|
64716
|
-
}
|
|
64717
|
-
const legacyDirs = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
|
|
64718
|
-
const legacyFiles = ["metadata.json"];
|
|
64719
|
-
return {
|
|
64720
|
-
filesToRemove: [...legacyDirs, ...legacyFiles],
|
|
64721
|
-
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
64722
|
-
hasManifest: false,
|
|
64723
|
-
isMultiKit: false,
|
|
64724
|
-
remainingKits: []
|
|
64725
|
-
};
|
|
64726
|
-
}
|
|
64727
|
-
var import_fs_extra8;
|
|
64728
|
-
var init_manifest_reader = __esm(() => {
|
|
64729
|
-
init_metadata_migration();
|
|
64730
|
-
init_logger();
|
|
64731
|
-
init_types3();
|
|
64732
|
-
import_fs_extra8 = __toESM(require_lib3(), 1);
|
|
64733
|
-
});
|
|
64734
|
-
|
|
64735
|
-
// src/domains/installation/deletion-handler.ts
|
|
64736
|
-
var exports_deletion_handler = {};
|
|
64737
|
-
__export(exports_deletion_handler, {
|
|
64738
|
-
handleDeletions: () => handleDeletions,
|
|
64739
|
-
categorizeDeletions: () => categorizeDeletions
|
|
64740
|
-
});
|
|
64741
|
-
import {
|
|
64742
|
-
existsSync as existsSync48,
|
|
64743
|
-
lstatSync as lstatSync3,
|
|
64744
|
-
readdirSync as readdirSync3,
|
|
64745
|
-
realpathSync as realpathSync3,
|
|
64746
|
-
rmSync as rmSync2,
|
|
64747
|
-
rmdirSync,
|
|
64748
|
-
unlinkSync as unlinkSync3
|
|
64749
|
-
} from "node:fs";
|
|
64750
|
-
import { dirname as dirname19, join as join75, relative as relative10, resolve as resolve18, sep as sep3 } from "node:path";
|
|
64751
|
-
function findFileInMetadata(metadata, path13) {
|
|
64752
|
-
if (!metadata)
|
|
64753
|
-
return null;
|
|
64754
|
-
const normalizedPath = normalizeRelativePath(path13);
|
|
64755
|
-
if (metadata.kits) {
|
|
64756
|
-
for (const kitMeta of Object.values(metadata.kits)) {
|
|
64757
|
-
if (kitMeta?.files) {
|
|
64758
|
-
const found = kitMeta.files.find((f3) => normalizeRelativePath(f3.path) === normalizedPath);
|
|
64759
|
-
if (found)
|
|
64760
|
-
return found;
|
|
64761
|
-
}
|
|
64762
|
-
}
|
|
64763
|
-
}
|
|
64764
|
-
if (metadata.files) {
|
|
64765
|
-
const found = metadata.files.find((f3) => normalizeRelativePath(f3.path) === normalizedPath);
|
|
64766
|
-
if (found)
|
|
64767
|
-
return found;
|
|
64768
|
-
}
|
|
64769
|
-
return null;
|
|
64770
|
-
}
|
|
64771
|
-
function shouldDeletePath(path13, metadata) {
|
|
64772
|
-
const tracked = findFileInMetadata(metadata, path13);
|
|
64773
|
-
if (!tracked)
|
|
64774
|
-
return true;
|
|
64775
|
-
return tracked.ownership !== "user";
|
|
64776
|
-
}
|
|
64777
|
-
function collectFilesRecursively(dir, baseDir) {
|
|
64778
|
-
const results = [];
|
|
64779
|
-
if (!existsSync48(dir))
|
|
64780
|
-
return results;
|
|
64781
|
-
try {
|
|
64782
|
-
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
64783
|
-
for (const entry of entries) {
|
|
64784
|
-
const fullPath = join75(dir, entry.name);
|
|
64785
|
-
const relativePath = relative10(baseDir, fullPath);
|
|
64786
|
-
if (entry.isDirectory()) {
|
|
64787
|
-
results.push(...collectFilesRecursively(fullPath, baseDir));
|
|
64788
|
-
} else {
|
|
64789
|
-
results.push(normalizeRelativePath(relativePath));
|
|
64790
|
-
}
|
|
64791
|
-
}
|
|
64792
|
-
} catch {}
|
|
64793
|
-
return results;
|
|
64794
|
-
}
|
|
64795
|
-
function expandGlobPatterns(patterns, claudeDir2) {
|
|
64796
|
-
const expanded = [];
|
|
64797
|
-
const allFiles = collectFilesRecursively(claudeDir2, claudeDir2);
|
|
64798
|
-
for (const pattern of patterns) {
|
|
64799
|
-
const normalizedPattern = normalizeRelativePath(pattern);
|
|
64800
|
-
if (PathResolver.isGlobPattern(normalizedPattern)) {
|
|
64801
|
-
const matcher = import_picomatch2.default(normalizedPattern);
|
|
64802
|
-
const matches = allFiles.filter((file) => matcher(file));
|
|
64803
|
-
expanded.push(...matches);
|
|
64804
|
-
if (matches.length > 0) {
|
|
64805
|
-
logger.debug(`Pattern "${normalizedPattern}" matched ${matches.length} files`);
|
|
64806
|
-
}
|
|
64807
|
-
} else {
|
|
64808
|
-
expanded.push(normalizedPattern);
|
|
64809
|
-
}
|
|
64810
|
-
}
|
|
64811
|
-
return [...new Set(expanded)];
|
|
64812
|
-
}
|
|
64813
|
-
function cleanupEmptyDirectories(filePath, claudeDir2) {
|
|
64814
|
-
const normalizedClaudeDir = resolve18(claudeDir2);
|
|
64815
|
-
let currentDir = resolve18(dirname19(filePath));
|
|
64816
|
-
let iterations = 0;
|
|
64817
|
-
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
|
|
64818
|
-
iterations++;
|
|
64819
|
-
try {
|
|
64820
|
-
const entries = readdirSync3(currentDir);
|
|
64821
|
-
if (entries.length === 0) {
|
|
64822
|
-
rmdirSync(currentDir);
|
|
64823
|
-
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
64824
|
-
currentDir = resolve18(dirname19(currentDir));
|
|
64825
|
-
} else {
|
|
64826
|
-
break;
|
|
64827
|
-
}
|
|
64828
|
-
} catch {
|
|
64829
|
-
break;
|
|
64830
|
-
}
|
|
64831
|
-
}
|
|
64832
|
-
}
|
|
64833
|
-
function normalizeRelativePath(path13) {
|
|
64834
|
-
return path13.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+/g, "/");
|
|
64835
|
-
}
|
|
64836
|
-
function isWithinBase(candidatePath, basePath) {
|
|
64837
|
-
return candidatePath === basePath || candidatePath.startsWith(`${basePath}${sep3}`);
|
|
64838
|
-
}
|
|
64839
|
-
function validateExistingDeletionTarget(fullPath, claudeDir2) {
|
|
64840
|
-
const normalizedPath = resolve18(fullPath);
|
|
64841
|
-
const normalizedClaudeDir = resolve18(claudeDir2);
|
|
64842
|
-
if (!isWithinBase(normalizedPath, normalizedClaudeDir)) {
|
|
64843
|
-
throw new Error(`Path traversal detected: ${fullPath}`);
|
|
64844
|
-
}
|
|
64845
|
-
let realBase = normalizedClaudeDir;
|
|
64846
|
-
try {
|
|
64847
|
-
realBase = realpathSync3(normalizedClaudeDir);
|
|
64848
|
-
} catch {}
|
|
64849
|
-
try {
|
|
64850
|
-
const realParent = realpathSync3(dirname19(fullPath));
|
|
64851
|
-
if (!isWithinBase(realParent, realBase)) {
|
|
64852
|
-
throw new Error(`Path escapes base via symlink parent: ${fullPath}`);
|
|
64853
|
-
}
|
|
64854
|
-
} catch (error) {
|
|
64855
|
-
throw new Error(`Failed to validate deletion parent for ${fullPath}: ${String(error)}`);
|
|
64856
|
-
}
|
|
64857
|
-
try {
|
|
64858
|
-
const stat13 = lstatSync3(fullPath);
|
|
64859
|
-
if (!stat13.isSymbolicLink()) {
|
|
64860
|
-
const realTarget = realpathSync3(fullPath);
|
|
64861
|
-
if (!isWithinBase(realTarget, realBase)) {
|
|
64862
|
-
throw new Error(`Path escapes base via symlink target: ${fullPath}`);
|
|
64863
|
-
}
|
|
64864
|
-
}
|
|
64865
|
-
} catch (error) {
|
|
64866
|
-
throw new Error(`Failed to validate deletion target ${fullPath}: ${String(error)}`);
|
|
64867
|
-
}
|
|
64868
|
-
}
|
|
64869
|
-
function deletePath(fullPath, claudeDir2) {
|
|
64870
|
-
validateExistingDeletionTarget(fullPath, claudeDir2);
|
|
64871
|
-
try {
|
|
64872
|
-
const stat13 = lstatSync3(fullPath);
|
|
64873
|
-
if (stat13.isDirectory()) {
|
|
64874
|
-
rmSync2(fullPath, { recursive: true, force: true });
|
|
64875
|
-
} else {
|
|
64876
|
-
unlinkSync3(fullPath);
|
|
64877
|
-
cleanupEmptyDirectories(fullPath, claudeDir2);
|
|
64878
|
-
}
|
|
64879
|
-
} catch (error) {
|
|
64880
|
-
throw new Error(`Failed to delete ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
64881
|
-
}
|
|
64882
|
-
}
|
|
64883
|
-
async function updateMetadataAfterDeletion(claudeDir2, deletedPaths) {
|
|
64884
|
-
const metadataPath = join75(claudeDir2, "metadata.json");
|
|
64885
|
-
if (!await import_fs_extra9.pathExists(metadataPath)) {
|
|
64886
|
-
return;
|
|
64887
|
-
}
|
|
64888
|
-
let content;
|
|
64889
|
-
try {
|
|
64890
|
-
content = await import_fs_extra9.readFile(metadataPath, "utf-8");
|
|
64891
|
-
} catch {
|
|
64892
|
-
logger.debug("Failed to read metadata.json for cleanup");
|
|
64893
|
-
return;
|
|
64894
|
-
}
|
|
64895
|
-
let metadata;
|
|
64896
|
-
try {
|
|
64897
|
-
metadata = JSON.parse(content);
|
|
64898
|
-
} catch {
|
|
64899
|
-
logger.debug("Failed to parse metadata.json for cleanup");
|
|
64900
|
-
return;
|
|
64901
|
-
}
|
|
64902
|
-
const deletedSet = new Set(deletedPaths);
|
|
64903
|
-
const isDeletedOrInDeletedDir = (path13) => {
|
|
64904
|
-
if (deletedSet.has(path13))
|
|
64905
|
-
return true;
|
|
64906
|
-
for (const deleted of deletedPaths) {
|
|
64907
|
-
if (path13.startsWith(`${deleted}/`))
|
|
64908
|
-
return true;
|
|
64909
|
-
}
|
|
64910
|
-
return false;
|
|
64911
|
-
};
|
|
64912
|
-
if (metadata.kits) {
|
|
64913
|
-
for (const kitName of Object.keys(metadata.kits)) {
|
|
64914
|
-
const kit = metadata.kits[kitName];
|
|
64915
|
-
if (kit?.files) {
|
|
64916
|
-
kit.files = kit.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
|
|
64917
|
-
}
|
|
64918
|
-
}
|
|
64919
|
-
}
|
|
64920
|
-
if (metadata.files) {
|
|
64921
|
-
metadata.files = metadata.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
|
|
64922
|
-
}
|
|
64923
|
-
try {
|
|
64924
|
-
await import_fs_extra9.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
64925
|
-
logger.debug(`Updated metadata.json, removed ${deletedPaths.length} entries`);
|
|
64926
|
-
} catch {
|
|
64927
|
-
logger.debug("Failed to write updated metadata.json");
|
|
64928
|
-
}
|
|
64929
|
-
}
|
|
64930
|
-
function categorizeDeletions(deletions) {
|
|
64931
|
-
const immediate = [];
|
|
64932
|
-
const deferred = [];
|
|
64933
|
-
for (const path13 of deletions) {
|
|
64934
|
-
if (path13.startsWith("skills/") || path13.startsWith("skills\\")) {
|
|
64935
|
-
deferred.push(path13);
|
|
64936
|
-
} else {
|
|
64937
|
-
immediate.push(path13);
|
|
64938
|
-
}
|
|
64939
|
-
}
|
|
64940
|
-
return { immediate, deferred };
|
|
64941
|
-
}
|
|
64942
|
-
async function handleDeletions(sourceMetadata, claudeDir2) {
|
|
64943
|
-
const deletionPatterns = sourceMetadata.deletions || [];
|
|
64944
|
-
if (deletionPatterns.length === 0) {
|
|
64945
|
-
return { deletedPaths: [], preservedPaths: [], errors: [] };
|
|
64946
|
-
}
|
|
64947
|
-
const deletions = expandGlobPatterns(deletionPatterns, claudeDir2);
|
|
64948
|
-
const userMetadata = await readManifest(claudeDir2);
|
|
64949
|
-
const result = { deletedPaths: [], preservedPaths: [], errors: [] };
|
|
64950
|
-
for (const path13 of deletions) {
|
|
64951
|
-
const normalizedRelativePath = normalizeRelativePath(path13);
|
|
64952
|
-
const fullPath = join75(claudeDir2, normalizedRelativePath);
|
|
64953
|
-
const normalizedResolvedPath = resolve18(fullPath);
|
|
64954
|
-
const normalizedClaudeDir = resolve18(claudeDir2);
|
|
64955
|
-
if (!isWithinBase(normalizedResolvedPath, normalizedClaudeDir)) {
|
|
64956
|
-
logger.warning(`Skipping invalid path: ${normalizedRelativePath}`);
|
|
64957
|
-
result.errors.push(normalizedRelativePath);
|
|
64958
|
-
continue;
|
|
64959
|
-
}
|
|
64960
|
-
if (!shouldDeletePath(normalizedRelativePath, userMetadata)) {
|
|
64961
|
-
result.preservedPaths.push(normalizedRelativePath);
|
|
64962
|
-
logger.verbose(`Preserved user file: ${normalizedRelativePath}`);
|
|
64963
|
-
continue;
|
|
64964
|
-
}
|
|
64965
|
-
if (existsSync48(fullPath)) {
|
|
64966
|
-
try {
|
|
64967
|
-
deletePath(fullPath, claudeDir2);
|
|
64968
|
-
result.deletedPaths.push(normalizedRelativePath);
|
|
64969
|
-
logger.verbose(`Deleted: ${normalizedRelativePath}`);
|
|
64970
|
-
} catch (error) {
|
|
64971
|
-
result.errors.push(normalizedRelativePath);
|
|
64972
|
-
logger.debug(`Failed to delete ${normalizedRelativePath}: ${error}`);
|
|
64973
|
-
}
|
|
64974
|
-
}
|
|
64975
|
-
}
|
|
64976
|
-
if (result.deletedPaths.length > 0) {
|
|
64977
|
-
await updateMetadataAfterDeletion(claudeDir2, result.deletedPaths);
|
|
64978
|
-
}
|
|
64979
|
-
return result;
|
|
64980
|
-
}
|
|
64981
|
-
var import_fs_extra9, import_picomatch2, MAX_CLEANUP_ITERATIONS = 50;
|
|
64982
|
-
var init_deletion_handler = __esm(() => {
|
|
64983
|
-
init_manifest_reader();
|
|
64984
|
-
init_logger();
|
|
64985
|
-
init_path_resolver();
|
|
64986
|
-
import_fs_extra9 = __toESM(require_lib3(), 1);
|
|
64987
|
-
import_picomatch2 = __toESM(require_picomatch2(), 1);
|
|
64988
|
-
});
|
|
64989
|
-
|
|
64990
64532
|
// src/domains/ui/ownership-display.ts
|
|
64991
64533
|
var exports_ownership_display = {};
|
|
64992
64534
|
__export(exports_ownership_display, {
|
|
@@ -65123,596 +64665,6 @@ var init_ownership_display = __esm(() => {
|
|
|
65123
64665
|
import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
65124
64666
|
});
|
|
65125
64667
|
|
|
65126
|
-
// src/shared/claude-exec-options.ts
|
|
65127
|
-
function buildExecOptions(timeout2) {
|
|
65128
|
-
const env2 = { ...process.env };
|
|
65129
|
-
for (const key of Object.keys(env2)) {
|
|
65130
|
-
if (key.startsWith("CLAUDE") && key !== "CLAUDE_CONFIG_DIR") {
|
|
65131
|
-
delete env2[key];
|
|
65132
|
-
}
|
|
65133
|
-
}
|
|
65134
|
-
return {
|
|
65135
|
-
timeout: timeout2,
|
|
65136
|
-
env: env2,
|
|
65137
|
-
shell: process.platform === "win32"
|
|
65138
|
-
};
|
|
65139
|
-
}
|
|
65140
|
-
|
|
65141
|
-
// src/services/cc-version-checker.ts
|
|
65142
|
-
var exports_cc_version_checker = {};
|
|
65143
|
-
__export(exports_cc_version_checker, {
|
|
65144
|
-
requireCCPluginSupport: () => requireCCPluginSupport,
|
|
65145
|
-
parseVersion: () => parseVersion,
|
|
65146
|
-
isCCPluginSupportError: () => isCCPluginSupportError,
|
|
65147
|
-
getCCVersion: () => getCCVersion,
|
|
65148
|
-
compareVersions: () => compareVersions9,
|
|
65149
|
-
MIN_PLUGIN_VERSION: () => MIN_PLUGIN_VERSION,
|
|
65150
|
-
CCPluginSupportError: () => CCPluginSupportError
|
|
65151
|
-
});
|
|
65152
|
-
import { execFile as execFile9 } from "node:child_process";
|
|
65153
|
-
import { promisify as promisify14 } from "node:util";
|
|
65154
|
-
function parseVersion(version) {
|
|
65155
|
-
const match2 = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
65156
|
-
if (!match2)
|
|
65157
|
-
return null;
|
|
65158
|
-
return [Number(match2[1]), Number(match2[2]), Number(match2[3])];
|
|
65159
|
-
}
|
|
65160
|
-
function compareVersions9(a3, b3) {
|
|
65161
|
-
const parsedA = parseVersion(a3);
|
|
65162
|
-
const parsedB = parseVersion(b3);
|
|
65163
|
-
if (!parsedA || !parsedB)
|
|
65164
|
-
return -1;
|
|
65165
|
-
for (let i = 0;i < 3; i++) {
|
|
65166
|
-
if (parsedA[i] !== parsedB[i])
|
|
65167
|
-
return parsedA[i] - parsedB[i];
|
|
65168
|
-
}
|
|
65169
|
-
return 0;
|
|
65170
|
-
}
|
|
65171
|
-
async function getCCVersionResult() {
|
|
65172
|
-
try {
|
|
65173
|
-
const { stdout: stdout2, stderr } = await execFileAsync6("claude", ["--version"], buildExecOptions(5000));
|
|
65174
|
-
const output2 = stdout2.trim();
|
|
65175
|
-
const match2 = output2.match(/(\d+\.\d+\.\d+)/);
|
|
65176
|
-
if (!match2) {
|
|
65177
|
-
return {
|
|
65178
|
-
version: null,
|
|
65179
|
-
error: new CCPluginSupportError("cc_version_unparseable", "Failed to parse Claude Code version output", output2 || stderr?.trim() || "empty output")
|
|
65180
|
-
};
|
|
65181
|
-
}
|
|
65182
|
-
return { version: match2[1] };
|
|
65183
|
-
} catch (error) {
|
|
65184
|
-
const err = error;
|
|
65185
|
-
if (err.code === "ENOENT") {
|
|
65186
|
-
return {
|
|
65187
|
-
version: null,
|
|
65188
|
-
error: new CCPluginSupportError("cc_not_found", "Claude Code CLI not found on PATH")
|
|
65189
|
-
};
|
|
65190
|
-
}
|
|
65191
|
-
return {
|
|
65192
|
-
version: null,
|
|
65193
|
-
error: new CCPluginSupportError("cc_exec_failed", "Failed to run 'claude --version'", (err.stderr ?? err.message ?? "Unknown error").trim())
|
|
65194
|
-
};
|
|
65195
|
-
}
|
|
65196
|
-
}
|
|
65197
|
-
async function getCCVersion() {
|
|
65198
|
-
const result = await getCCVersionResult();
|
|
65199
|
-
return result.version;
|
|
65200
|
-
}
|
|
65201
|
-
async function requireCCPluginSupport() {
|
|
65202
|
-
const result = await getCCVersionResult();
|
|
65203
|
-
const version = result.version;
|
|
65204
|
-
if (!version) {
|
|
65205
|
-
throw result.error ?? new CCPluginSupportError("cc_exec_failed", "Failed to determine Claude Code version");
|
|
65206
|
-
}
|
|
65207
|
-
if (compareVersions9(version, MIN_PLUGIN_VERSION) < 0) {
|
|
65208
|
-
throw new CCPluginSupportError("cc_version_too_old", `Claude Code ${version} does not support plugins (requires >= ${MIN_PLUGIN_VERSION})`);
|
|
65209
|
-
}
|
|
65210
|
-
logger.debug(`CC version ${version} supports plugins (>= ${MIN_PLUGIN_VERSION})`);
|
|
65211
|
-
}
|
|
65212
|
-
function isCCPluginSupportError(error) {
|
|
65213
|
-
return error instanceof CCPluginSupportError;
|
|
65214
|
-
}
|
|
65215
|
-
var execFileAsync6, MIN_PLUGIN_VERSION = "1.0.33", CCPluginSupportError;
|
|
65216
|
-
var init_cc_version_checker = __esm(() => {
|
|
65217
|
-
init_logger();
|
|
65218
|
-
execFileAsync6 = promisify14(execFile9);
|
|
65219
|
-
CCPluginSupportError = class CCPluginSupportError extends Error {
|
|
65220
|
-
code;
|
|
65221
|
-
details;
|
|
65222
|
-
constructor(code2, message, details) {
|
|
65223
|
-
super(message);
|
|
65224
|
-
this.code = code2;
|
|
65225
|
-
this.details = details;
|
|
65226
|
-
this.name = "CCPluginSupportError";
|
|
65227
|
-
}
|
|
65228
|
-
};
|
|
65229
|
-
});
|
|
65230
|
-
|
|
65231
|
-
// src/services/plugin-installer.ts
|
|
65232
|
-
var exports_plugin_installer = {};
|
|
65233
|
-
__export(exports_plugin_installer, {
|
|
65234
|
-
handlePluginUninstall: () => handlePluginUninstall,
|
|
65235
|
-
handlePluginInstall: () => handlePluginInstall
|
|
65236
|
-
});
|
|
65237
|
-
import { execFile as execFile10 } from "node:child_process";
|
|
65238
|
-
import { rename as rename6 } from "node:fs/promises";
|
|
65239
|
-
import { join as join99 } from "node:path";
|
|
65240
|
-
import { promisify as promisify15 } from "node:util";
|
|
65241
|
-
function getMarketplacePath() {
|
|
65242
|
-
const dataDir = PathResolver.getClaudeKitDir();
|
|
65243
|
-
return join99(dataDir, MARKETPLACE_DIR_NAME);
|
|
65244
|
-
}
|
|
65245
|
-
function escapeRegex2(value) {
|
|
65246
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
65247
|
-
}
|
|
65248
|
-
function outputContainsToken(output2, token) {
|
|
65249
|
-
const tokenPattern = new RegExp(`(^|\\s)${escapeRegex2(token)}(?=\\s|$)`, "i");
|
|
65250
|
-
return output2.split(/\r?\n/).map((line) => line.trim()).some((line) => tokenPattern.test(line));
|
|
65251
|
-
}
|
|
65252
|
-
async function runClaudePlugin(args) {
|
|
65253
|
-
try {
|
|
65254
|
-
const { stdout: stdout2, stderr } = await execFileAsync7("claude", ["plugin", ...args], buildExecOptions(30000));
|
|
65255
|
-
return { success: true, stdout: stdout2.trim(), stderr: stderr.trim() };
|
|
65256
|
-
} catch (error) {
|
|
65257
|
-
const err = error;
|
|
65258
|
-
return {
|
|
65259
|
-
success: false,
|
|
65260
|
-
stdout: (err.stdout ?? "").trim(),
|
|
65261
|
-
stderr: (err.stderr ?? err.message ?? "Unknown error").trim()
|
|
65262
|
-
};
|
|
65263
|
-
}
|
|
65264
|
-
}
|
|
65265
|
-
async function isClaudeAvailable() {
|
|
65266
|
-
try {
|
|
65267
|
-
await execFileAsync7("claude", ["--version"], buildExecOptions(5000));
|
|
65268
|
-
return true;
|
|
65269
|
-
} catch {
|
|
65270
|
-
return false;
|
|
65271
|
-
}
|
|
65272
|
-
}
|
|
65273
|
-
async function copyPluginToMarketplace(extractDir) {
|
|
65274
|
-
const marketplacePath = getMarketplacePath();
|
|
65275
|
-
const sourceMarketplaceJson = join99(extractDir, ".claude-plugin", "marketplace.json");
|
|
65276
|
-
const sourcePluginDir = join99(extractDir, "plugins", PLUGIN_NAME);
|
|
65277
|
-
if (!await import_fs_extra30.pathExists(sourceMarketplaceJson) || !await import_fs_extra30.pathExists(sourcePluginDir)) {
|
|
65278
|
-
logger.debug("Kit release does not contain plugin structure — skipping plugin install");
|
|
65279
|
-
return false;
|
|
65280
|
-
}
|
|
65281
|
-
await import_fs_extra30.ensureDir(join99(marketplacePath, ".claude-plugin"));
|
|
65282
|
-
await import_fs_extra30.ensureDir(join99(marketplacePath, "plugins"));
|
|
65283
|
-
const suffix = `${process.pid}-${Date.now()}`;
|
|
65284
|
-
const destMarketplaceJson = join99(marketplacePath, ".claude-plugin", "marketplace.json");
|
|
65285
|
-
const destPluginDir = join99(marketplacePath, "plugins", PLUGIN_NAME);
|
|
65286
|
-
const tempMarketplaceJson = `${destMarketplaceJson}.tmp-${suffix}`;
|
|
65287
|
-
const tempPluginDir = `${destPluginDir}.tmp-${suffix}`;
|
|
65288
|
-
const backupMarketplaceJson = `${destMarketplaceJson}.bak-${suffix}`;
|
|
65289
|
-
const backupPluginDir = `${destPluginDir}.bak-${suffix}`;
|
|
65290
|
-
await import_fs_extra30.remove(tempMarketplaceJson).catch(() => {});
|
|
65291
|
-
await import_fs_extra30.remove(tempPluginDir).catch(() => {});
|
|
65292
|
-
await import_fs_extra30.remove(backupMarketplaceJson).catch(() => {});
|
|
65293
|
-
await import_fs_extra30.remove(backupPluginDir).catch(() => {});
|
|
65294
|
-
await import_fs_extra30.copy(sourceMarketplaceJson, tempMarketplaceJson, { overwrite: true });
|
|
65295
|
-
await import_fs_extra30.copy(sourcePluginDir, tempPluginDir, { overwrite: true });
|
|
65296
|
-
let backupMarketplaceCreated = false;
|
|
65297
|
-
let backupPluginCreated = false;
|
|
65298
|
-
let marketplaceReplaced = false;
|
|
65299
|
-
let pluginReplaced = false;
|
|
65300
|
-
try {
|
|
65301
|
-
if (await import_fs_extra30.pathExists(destMarketplaceJson)) {
|
|
65302
|
-
await rename6(destMarketplaceJson, backupMarketplaceJson);
|
|
65303
|
-
backupMarketplaceCreated = true;
|
|
65304
|
-
}
|
|
65305
|
-
await rename6(tempMarketplaceJson, destMarketplaceJson);
|
|
65306
|
-
marketplaceReplaced = true;
|
|
65307
|
-
if (await import_fs_extra30.pathExists(destPluginDir)) {
|
|
65308
|
-
await rename6(destPluginDir, backupPluginDir);
|
|
65309
|
-
backupPluginCreated = true;
|
|
65310
|
-
}
|
|
65311
|
-
await rename6(tempPluginDir, destPluginDir);
|
|
65312
|
-
pluginReplaced = true;
|
|
65313
|
-
} catch (error) {
|
|
65314
|
-
if (marketplaceReplaced) {
|
|
65315
|
-
await import_fs_extra30.remove(destMarketplaceJson).catch(() => {});
|
|
65316
|
-
}
|
|
65317
|
-
if (pluginReplaced) {
|
|
65318
|
-
await import_fs_extra30.remove(destPluginDir).catch(() => {});
|
|
65319
|
-
}
|
|
65320
|
-
if (backupMarketplaceCreated) {
|
|
65321
|
-
await rename6(backupMarketplaceJson, destMarketplaceJson).catch(() => {});
|
|
65322
|
-
}
|
|
65323
|
-
if (backupPluginCreated) {
|
|
65324
|
-
await rename6(backupPluginDir, destPluginDir).catch(() => {});
|
|
65325
|
-
}
|
|
65326
|
-
await import_fs_extra30.remove(tempMarketplaceJson).catch(() => {});
|
|
65327
|
-
await import_fs_extra30.remove(tempPluginDir).catch(() => {});
|
|
65328
|
-
throw error;
|
|
65329
|
-
}
|
|
65330
|
-
await import_fs_extra30.remove(backupMarketplaceJson).catch(() => {});
|
|
65331
|
-
await import_fs_extra30.remove(backupPluginDir).catch(() => {});
|
|
65332
|
-
await import_fs_extra30.remove(tempMarketplaceJson).catch(() => {});
|
|
65333
|
-
await import_fs_extra30.remove(tempPluginDir).catch(() => {});
|
|
65334
|
-
logger.debug("Plugin copied to marketplace");
|
|
65335
|
-
return true;
|
|
65336
|
-
}
|
|
65337
|
-
async function registerMarketplace() {
|
|
65338
|
-
const marketplacePath = getMarketplacePath();
|
|
65339
|
-
const listResult = await runClaudePlugin(["marketplace", "list"]);
|
|
65340
|
-
const alreadyRegistered = listResult.success && outputContainsToken(listResult.stdout, MARKETPLACE_NAME);
|
|
65341
|
-
if (alreadyRegistered) {
|
|
65342
|
-
const addResult = await runClaudePlugin(["marketplace", "add", marketplacePath]);
|
|
65343
|
-
if (addResult.success) {
|
|
65344
|
-
logger.debug("Marketplace re-registered successfully");
|
|
65345
|
-
return true;
|
|
65346
|
-
}
|
|
65347
|
-
logger.debug("Marketplace add failed while registered; removing stale entry and retrying");
|
|
65348
|
-
const removeResult = await runClaudePlugin(["marketplace", "remove", MARKETPLACE_NAME]);
|
|
65349
|
-
if (!removeResult.success) {
|
|
65350
|
-
logger.debug(`Marketplace remove failed: ${removeResult.stderr}`);
|
|
65351
|
-
return false;
|
|
65352
|
-
}
|
|
65353
|
-
const retryResult = await runClaudePlugin(["marketplace", "add", marketplacePath]);
|
|
65354
|
-
if (!retryResult.success) {
|
|
65355
|
-
logger.warning(`Marketplace remove succeeded but retry-add failed: ${retryResult.stderr}`);
|
|
65356
|
-
return false;
|
|
65357
|
-
}
|
|
65358
|
-
logger.debug("Marketplace re-registered after remove+retry");
|
|
65359
|
-
return true;
|
|
65360
|
-
}
|
|
65361
|
-
const result = await runClaudePlugin(["marketplace", "add", marketplacePath]);
|
|
65362
|
-
if (!result.success) {
|
|
65363
|
-
logger.debug(`Marketplace registration failed: ${result.stderr}`);
|
|
65364
|
-
return false;
|
|
65365
|
-
}
|
|
65366
|
-
logger.debug("Marketplace registered successfully");
|
|
65367
|
-
return true;
|
|
65368
|
-
}
|
|
65369
|
-
async function installOrUpdatePlugin() {
|
|
65370
|
-
const pluginRef = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
65371
|
-
const listResult = await runClaudePlugin(["list"]);
|
|
65372
|
-
const isInstalled = listResult.success && outputContainsToken(listResult.stdout, pluginRef);
|
|
65373
|
-
if (isInstalled) {
|
|
65374
|
-
const result2 = await runClaudePlugin(["update", pluginRef]);
|
|
65375
|
-
if (result2.success) {
|
|
65376
|
-
logger.debug("Plugin updated successfully");
|
|
65377
|
-
return true;
|
|
65378
|
-
}
|
|
65379
|
-
logger.debug(`Plugin update failed (${result2.stderr}); re-verifying install state`);
|
|
65380
|
-
const stillInstalled = await verifyPluginInstalled();
|
|
65381
|
-
if (stillInstalled) {
|
|
65382
|
-
logger.debug("Plugin update failed but plugin is still installed — treating as success");
|
|
65383
|
-
return true;
|
|
65384
|
-
}
|
|
65385
|
-
logger.debug("Plugin update failed and plugin is no longer listed");
|
|
65386
|
-
return false;
|
|
65387
|
-
}
|
|
65388
|
-
const result = await runClaudePlugin(["install", pluginRef]);
|
|
65389
|
-
if (!result.success) {
|
|
65390
|
-
logger.debug(`Plugin install failed: ${result.stderr}`);
|
|
65391
|
-
return false;
|
|
65392
|
-
}
|
|
65393
|
-
logger.debug("Plugin installed successfully");
|
|
65394
|
-
return true;
|
|
65395
|
-
}
|
|
65396
|
-
async function verifyPluginInstalled() {
|
|
65397
|
-
const pluginRef = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
65398
|
-
const result = await runClaudePlugin(["list"]);
|
|
65399
|
-
if (!result.success)
|
|
65400
|
-
return false;
|
|
65401
|
-
return outputContainsToken(result.stdout, pluginRef);
|
|
65402
|
-
}
|
|
65403
|
-
async function handlePluginInstall(extractDir) {
|
|
65404
|
-
if (!await isClaudeAvailable()) {
|
|
65405
|
-
return {
|
|
65406
|
-
installed: false,
|
|
65407
|
-
marketplaceRegistered: false,
|
|
65408
|
-
verified: false,
|
|
65409
|
-
error: "Claude Code CLI not found on PATH"
|
|
65410
|
-
};
|
|
65411
|
-
}
|
|
65412
|
-
logger.debug("Registering CK plugin with Claude Code...");
|
|
65413
|
-
let copied = false;
|
|
65414
|
-
try {
|
|
65415
|
-
copied = await copyPluginToMarketplace(extractDir);
|
|
65416
|
-
} catch (error) {
|
|
65417
|
-
return {
|
|
65418
|
-
installed: false,
|
|
65419
|
-
marketplaceRegistered: false,
|
|
65420
|
-
verified: false,
|
|
65421
|
-
error: `Plugin copy failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
65422
|
-
};
|
|
65423
|
-
}
|
|
65424
|
-
if (!copied) {
|
|
65425
|
-
return {
|
|
65426
|
-
installed: false,
|
|
65427
|
-
marketplaceRegistered: false,
|
|
65428
|
-
verified: false,
|
|
65429
|
-
error: "No plugin found in kit release"
|
|
65430
|
-
};
|
|
65431
|
-
}
|
|
65432
|
-
const registered = await registerMarketplace();
|
|
65433
|
-
if (!registered) {
|
|
65434
|
-
return {
|
|
65435
|
-
installed: false,
|
|
65436
|
-
marketplaceRegistered: false,
|
|
65437
|
-
verified: false,
|
|
65438
|
-
error: "Marketplace registration failed"
|
|
65439
|
-
};
|
|
65440
|
-
}
|
|
65441
|
-
const installOk = await installOrUpdatePlugin();
|
|
65442
|
-
if (!installOk) {
|
|
65443
|
-
return {
|
|
65444
|
-
installed: false,
|
|
65445
|
-
marketplaceRegistered: true,
|
|
65446
|
-
verified: false,
|
|
65447
|
-
error: "Plugin install/update failed"
|
|
65448
|
-
};
|
|
65449
|
-
}
|
|
65450
|
-
const verified = await verifyPluginInstalled();
|
|
65451
|
-
if (verified) {
|
|
65452
|
-
logger.success("CK plugin installed — skills available as /ck:* commands");
|
|
65453
|
-
} else {
|
|
65454
|
-
logger.warning("Plugin installed but verification failed — skills may not be available");
|
|
65455
|
-
}
|
|
65456
|
-
return {
|
|
65457
|
-
installed: true,
|
|
65458
|
-
marketplaceRegistered: true,
|
|
65459
|
-
verified,
|
|
65460
|
-
error: verified ? undefined : "Post-install verification failed"
|
|
65461
|
-
};
|
|
65462
|
-
}
|
|
65463
|
-
async function handlePluginUninstall() {
|
|
65464
|
-
if (!await isClaudeAvailable()) {
|
|
65465
|
-
logger.debug("Claude Code CLI not found — skipping plugin cleanup");
|
|
65466
|
-
return;
|
|
65467
|
-
}
|
|
65468
|
-
const isInstalled = await verifyPluginInstalled();
|
|
65469
|
-
if (isInstalled) {
|
|
65470
|
-
const pluginRef = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
65471
|
-
const uninstallResult = await runClaudePlugin(["uninstall", pluginRef]);
|
|
65472
|
-
if (uninstallResult.success) {
|
|
65473
|
-
logger.debug("CK plugin uninstalled from Claude Code");
|
|
65474
|
-
} else {
|
|
65475
|
-
logger.debug(`Plugin uninstall failed: ${uninstallResult.stderr}`);
|
|
65476
|
-
}
|
|
65477
|
-
}
|
|
65478
|
-
const marketplaceRemoveResult = await runClaudePlugin([
|
|
65479
|
-
"marketplace",
|
|
65480
|
-
"remove",
|
|
65481
|
-
MARKETPLACE_NAME
|
|
65482
|
-
]);
|
|
65483
|
-
if (!marketplaceRemoveResult.success) {
|
|
65484
|
-
logger.debug(`Marketplace remove failed: ${marketplaceRemoveResult.stderr}`);
|
|
65485
|
-
}
|
|
65486
|
-
const marketplacePath = getMarketplacePath();
|
|
65487
|
-
if (await import_fs_extra30.pathExists(marketplacePath)) {
|
|
65488
|
-
try {
|
|
65489
|
-
await import_fs_extra30.remove(marketplacePath);
|
|
65490
|
-
logger.debug("Marketplace directory cleaned up");
|
|
65491
|
-
} catch (error) {
|
|
65492
|
-
logger.warning(`Failed to clean marketplace directory: ${error instanceof Error ? error.message : String(error)}`);
|
|
65493
|
-
}
|
|
65494
|
-
}
|
|
65495
|
-
}
|
|
65496
|
-
var import_fs_extra30, execFileAsync7, MARKETPLACE_DIR_NAME = "marketplace", PLUGIN_NAME = "ck", MARKETPLACE_NAME = "claudekit";
|
|
65497
|
-
var init_plugin_installer = __esm(() => {
|
|
65498
|
-
init_logger();
|
|
65499
|
-
init_path_resolver();
|
|
65500
|
-
import_fs_extra30 = __toESM(require_lib3(), 1);
|
|
65501
|
-
execFileAsync7 = promisify15(execFile10);
|
|
65502
|
-
});
|
|
65503
|
-
|
|
65504
|
-
// src/services/skill-migration-merger.ts
|
|
65505
|
-
var exports_skill_migration_merger = {};
|
|
65506
|
-
__export(exports_skill_migration_merger, {
|
|
65507
|
-
migrateUserSkills: () => migrateUserSkills
|
|
65508
|
-
});
|
|
65509
|
-
import { readFile as readFile47 } from "node:fs/promises";
|
|
65510
|
-
import { join as join100 } from "node:path";
|
|
65511
|
-
async function migrateUserSkills(claudeDir2, pluginVerified) {
|
|
65512
|
-
const result = {
|
|
65513
|
-
preserved: [],
|
|
65514
|
-
deleted: [],
|
|
65515
|
-
userOwned: [],
|
|
65516
|
-
canDelete: false
|
|
65517
|
-
};
|
|
65518
|
-
if (!pluginVerified) {
|
|
65519
|
-
return result;
|
|
65520
|
-
}
|
|
65521
|
-
const metadataPath = join100(claudeDir2, "metadata.json");
|
|
65522
|
-
if (!await import_fs_extra31.pathExists(metadataPath)) {
|
|
65523
|
-
return result;
|
|
65524
|
-
}
|
|
65525
|
-
let trackedFiles;
|
|
65526
|
-
try {
|
|
65527
|
-
const content = await readFile47(metadataPath, "utf-8");
|
|
65528
|
-
const metadata = JSON.parse(content);
|
|
65529
|
-
trackedFiles = extractTrackedSkillFiles(metadata);
|
|
65530
|
-
} catch {
|
|
65531
|
-
logger.debug("Could not read metadata for skill migration");
|
|
65532
|
-
return result;
|
|
65533
|
-
}
|
|
65534
|
-
if (trackedFiles.length === 0) {
|
|
65535
|
-
return result;
|
|
65536
|
-
}
|
|
65537
|
-
result.canDelete = true;
|
|
65538
|
-
const preservedSet = new Set;
|
|
65539
|
-
const deletedSet = new Set;
|
|
65540
|
-
const userOwnedSet = new Set;
|
|
65541
|
-
for (const file of trackedFiles) {
|
|
65542
|
-
const skillDir = extractSkillDir(file.path);
|
|
65543
|
-
if (!skillDir)
|
|
65544
|
-
continue;
|
|
65545
|
-
switch (file.ownership) {
|
|
65546
|
-
case "user":
|
|
65547
|
-
userOwnedSet.add(skillDir);
|
|
65548
|
-
break;
|
|
65549
|
-
case "ck-modified":
|
|
65550
|
-
preservedSet.add(skillDir);
|
|
65551
|
-
break;
|
|
65552
|
-
case "ck":
|
|
65553
|
-
deletedSet.add(skillDir);
|
|
65554
|
-
break;
|
|
65555
|
-
}
|
|
65556
|
-
}
|
|
65557
|
-
for (const dir of preservedSet) {
|
|
65558
|
-
deletedSet.delete(dir);
|
|
65559
|
-
}
|
|
65560
|
-
result.preserved = [...preservedSet];
|
|
65561
|
-
result.deleted = [...deletedSet];
|
|
65562
|
-
result.userOwned = [...userOwnedSet];
|
|
65563
|
-
for (const dir of result.preserved) {
|
|
65564
|
-
const skillName = dir.split("/")[1];
|
|
65565
|
-
logger.info(`Preserved customizations: /${skillName} (standalone alongside /ck:${skillName})`);
|
|
65566
|
-
}
|
|
65567
|
-
return result;
|
|
65568
|
-
}
|
|
65569
|
-
function extractTrackedSkillFiles(metadata) {
|
|
65570
|
-
const files = [];
|
|
65571
|
-
if (metadata.kits && typeof metadata.kits === "object") {
|
|
65572
|
-
for (const kit of Object.values(metadata.kits)) {
|
|
65573
|
-
if (kit.files) {
|
|
65574
|
-
files.push(...kit.files.filter((f3) => isSkillPath(f3.path)));
|
|
65575
|
-
}
|
|
65576
|
-
}
|
|
65577
|
-
}
|
|
65578
|
-
if (Array.isArray(metadata.files)) {
|
|
65579
|
-
files.push(...metadata.files.filter((f3) => isSkillPath(f3.path)));
|
|
65580
|
-
}
|
|
65581
|
-
return files;
|
|
65582
|
-
}
|
|
65583
|
-
function isSkillPath(path14) {
|
|
65584
|
-
const normalized = path14.replace(/\\/g, "/");
|
|
65585
|
-
return normalized.startsWith("skills/");
|
|
65586
|
-
}
|
|
65587
|
-
function extractSkillDir(path14) {
|
|
65588
|
-
const normalized = path14.replace(/\\/g, "/");
|
|
65589
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
65590
|
-
if (parts.length < 2 || parts[0] !== "skills") {
|
|
65591
|
-
return null;
|
|
65592
|
-
}
|
|
65593
|
-
return `skills/${parts[1]}`;
|
|
65594
|
-
}
|
|
65595
|
-
var import_fs_extra31;
|
|
65596
|
-
var init_skill_migration_merger = __esm(() => {
|
|
65597
|
-
init_logger();
|
|
65598
|
-
import_fs_extra31 = __toESM(require_lib3(), 1);
|
|
65599
|
-
});
|
|
65600
|
-
|
|
65601
|
-
// src/services/standalone-skill-cleanup.ts
|
|
65602
|
-
var exports_standalone_skill_cleanup = {};
|
|
65603
|
-
__export(exports_standalone_skill_cleanup, {
|
|
65604
|
-
cleanupOverlappingStandaloneSkills: () => cleanupOverlappingStandaloneSkills
|
|
65605
|
-
});
|
|
65606
|
-
import { readFile as readFile48, readdir as readdir32 } from "node:fs/promises";
|
|
65607
|
-
import { join as join101 } from "node:path";
|
|
65608
|
-
async function listSkillDirs(dir) {
|
|
65609
|
-
if (!await import_fs_extra32.pathExists(dir))
|
|
65610
|
-
return new Set;
|
|
65611
|
-
try {
|
|
65612
|
-
const entries = await readdir32(dir, { withFileTypes: true });
|
|
65613
|
-
const dirs = entries.filter((e2) => e2.isDirectory());
|
|
65614
|
-
const results = await Promise.all(dirs.map(async (e2) => {
|
|
65615
|
-
const exists = await import_fs_extra32.pathExists(join101(dir, e2.name, "SKILL.md"));
|
|
65616
|
-
return exists ? e2.name : null;
|
|
65617
|
-
}));
|
|
65618
|
-
return new Set(results.filter(Boolean));
|
|
65619
|
-
} catch {
|
|
65620
|
-
return new Set;
|
|
65621
|
-
}
|
|
65622
|
-
}
|
|
65623
|
-
async function getSkillOwnershipMap(claudeDir2) {
|
|
65624
|
-
const ownershipMap = new Map;
|
|
65625
|
-
const metadataPath = join101(claudeDir2, "metadata.json");
|
|
65626
|
-
if (!await import_fs_extra32.pathExists(metadataPath))
|
|
65627
|
-
return ownershipMap;
|
|
65628
|
-
let trackedFiles;
|
|
65629
|
-
try {
|
|
65630
|
-
const content = await readFile48(metadataPath, "utf-8");
|
|
65631
|
-
const metadata = JSON.parse(content);
|
|
65632
|
-
trackedFiles = extractTrackedSkillFiles2(metadata);
|
|
65633
|
-
} catch {
|
|
65634
|
-
logger.debug("standalone-skill-cleanup: could not read metadata");
|
|
65635
|
-
return ownershipMap;
|
|
65636
|
-
}
|
|
65637
|
-
for (const file of trackedFiles) {
|
|
65638
|
-
const skillDirName = extractSkillDirName(file.path);
|
|
65639
|
-
if (!skillDirName)
|
|
65640
|
-
continue;
|
|
65641
|
-
const existing = ownershipMap.get(skillDirName);
|
|
65642
|
-
if (file.ownership === "user" || file.ownership === "ck-modified") {
|
|
65643
|
-
ownershipMap.set(skillDirName, "user");
|
|
65644
|
-
} else if (!existing) {
|
|
65645
|
-
ownershipMap.set(skillDirName, "ck");
|
|
65646
|
-
}
|
|
65647
|
-
}
|
|
65648
|
-
return ownershipMap;
|
|
65649
|
-
}
|
|
65650
|
-
function extractTrackedSkillFiles2(metadata) {
|
|
65651
|
-
const files = [];
|
|
65652
|
-
if (metadata.kits && typeof metadata.kits === "object") {
|
|
65653
|
-
for (const kit of Object.values(metadata.kits)) {
|
|
65654
|
-
if (kit.files) {
|
|
65655
|
-
files.push(...kit.files.filter((f3) => f3.path?.startsWith("skills/")));
|
|
65656
|
-
}
|
|
65657
|
-
}
|
|
65658
|
-
}
|
|
65659
|
-
if (Array.isArray(metadata.files)) {
|
|
65660
|
-
files.push(...metadata.files.filter((f3) => f3.path?.startsWith("skills/")));
|
|
65661
|
-
}
|
|
65662
|
-
return files;
|
|
65663
|
-
}
|
|
65664
|
-
function extractSkillDirName(filePath) {
|
|
65665
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
65666
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
65667
|
-
if (parts.length < 2 || parts[0] !== "skills")
|
|
65668
|
-
return null;
|
|
65669
|
-
return parts[1];
|
|
65670
|
-
}
|
|
65671
|
-
async function cleanupOverlappingStandaloneSkills(claudeDir2, pluginSkillsDir) {
|
|
65672
|
-
const standaloneSkillsDir = join101(claudeDir2, "skills");
|
|
65673
|
-
const result = {
|
|
65674
|
-
removed: [],
|
|
65675
|
-
preserved: [],
|
|
65676
|
-
pluginSkillsDir
|
|
65677
|
-
};
|
|
65678
|
-
const [pluginSkills, standaloneSkills] = await Promise.all([
|
|
65679
|
-
listSkillDirs(pluginSkillsDir),
|
|
65680
|
-
listSkillDirs(standaloneSkillsDir)
|
|
65681
|
-
]);
|
|
65682
|
-
if (pluginSkills.size === 0 || standaloneSkills.size === 0) {
|
|
65683
|
-
logger.debug(`standalone-skill-cleanup: nothing to clean (plugin=${pluginSkills.size}, standalone=${standaloneSkills.size})`);
|
|
65684
|
-
return result;
|
|
65685
|
-
}
|
|
65686
|
-
const overlaps = [...standaloneSkills].filter((name2) => pluginSkills.has(name2));
|
|
65687
|
-
if (overlaps.length === 0)
|
|
65688
|
-
return result;
|
|
65689
|
-
const ownershipMap = await getSkillOwnershipMap(claudeDir2);
|
|
65690
|
-
for (const skillName of overlaps) {
|
|
65691
|
-
const ownership = ownershipMap.get(skillName);
|
|
65692
|
-
const skillPath = join101(standaloneSkillsDir, skillName);
|
|
65693
|
-
if (ownership === "user" || ownership === undefined) {
|
|
65694
|
-
result.preserved.push(skillName);
|
|
65695
|
-
const reason = ownership === "user" ? "user-owned/modified" : "untracked";
|
|
65696
|
-
logger.debug(`standalone-skill-cleanup: preserved ${skillName} (${reason})`);
|
|
65697
|
-
continue;
|
|
65698
|
-
}
|
|
65699
|
-
try {
|
|
65700
|
-
await import_fs_extra32.remove(skillPath);
|
|
65701
|
-
result.removed.push(skillName);
|
|
65702
|
-
logger.debug(`standalone-skill-cleanup: removed standalone ${skillName} (plugin has it)`);
|
|
65703
|
-
} catch (error) {
|
|
65704
|
-
result.preserved.push(skillName);
|
|
65705
|
-
logger.debug(`standalone-skill-cleanup: could not remove ${skillName}: ${error}`);
|
|
65706
|
-
}
|
|
65707
|
-
}
|
|
65708
|
-
return result;
|
|
65709
|
-
}
|
|
65710
|
-
var import_fs_extra32;
|
|
65711
|
-
var init_standalone_skill_cleanup = __esm(() => {
|
|
65712
|
-
init_logger();
|
|
65713
|
-
import_fs_extra32 = __toESM(require_lib3(), 1);
|
|
65714
|
-
});
|
|
65715
|
-
|
|
65716
64668
|
// src/domains/help/commands/common-options.ts
|
|
65717
64669
|
var filterOptionsGroup, folderOptionsGroup;
|
|
65718
64670
|
var init_common_options = __esm(() => {
|
|
@@ -66830,7 +65782,7 @@ function getPagerArgs(pagerCmd) {
|
|
|
66830
65782
|
return [];
|
|
66831
65783
|
}
|
|
66832
65784
|
async function trySystemPager(content) {
|
|
66833
|
-
return new Promise((
|
|
65785
|
+
return new Promise((resolve26) => {
|
|
66834
65786
|
const pagerCmd = process.env.PAGER || "less";
|
|
66835
65787
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
66836
65788
|
try {
|
|
@@ -66840,20 +65792,20 @@ async function trySystemPager(content) {
|
|
|
66840
65792
|
});
|
|
66841
65793
|
const timeout2 = setTimeout(() => {
|
|
66842
65794
|
pager.kill();
|
|
66843
|
-
|
|
65795
|
+
resolve26(false);
|
|
66844
65796
|
}, 30000);
|
|
66845
65797
|
pager.stdin.write(content);
|
|
66846
65798
|
pager.stdin.end();
|
|
66847
65799
|
pager.on("close", (code2) => {
|
|
66848
65800
|
clearTimeout(timeout2);
|
|
66849
|
-
|
|
65801
|
+
resolve26(code2 === 0);
|
|
66850
65802
|
});
|
|
66851
65803
|
pager.on("error", () => {
|
|
66852
65804
|
clearTimeout(timeout2);
|
|
66853
|
-
|
|
65805
|
+
resolve26(false);
|
|
66854
65806
|
});
|
|
66855
65807
|
} catch {
|
|
66856
|
-
|
|
65808
|
+
resolve26(false);
|
|
66857
65809
|
}
|
|
66858
65810
|
});
|
|
66859
65811
|
}
|
|
@@ -66880,16 +65832,16 @@ async function basicPager(content) {
|
|
|
66880
65832
|
break;
|
|
66881
65833
|
}
|
|
66882
65834
|
const remaining = lines.length - currentLine;
|
|
66883
|
-
await new Promise((
|
|
65835
|
+
await new Promise((resolve26) => {
|
|
66884
65836
|
rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
|
|
66885
65837
|
if (answer.toLowerCase() === "q") {
|
|
66886
65838
|
rl.close();
|
|
66887
65839
|
process.exitCode = 0;
|
|
66888
|
-
|
|
65840
|
+
resolve26();
|
|
66889
65841
|
return;
|
|
66890
65842
|
}
|
|
66891
65843
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
66892
|
-
|
|
65844
|
+
resolve26();
|
|
66893
65845
|
});
|
|
66894
65846
|
});
|
|
66895
65847
|
}
|
|
@@ -73562,7 +72514,7 @@ class ConfigVersionChecker {
|
|
|
73562
72514
|
}
|
|
73563
72515
|
// src/domains/sync/sync-engine.ts
|
|
73564
72516
|
import { lstat as lstat3, readFile as readFile34, readlink, realpath as realpath3, stat as stat9 } from "node:fs/promises";
|
|
73565
|
-
import {
|
|
72517
|
+
import { isAbsolute as isAbsolute3, join as join58, normalize as normalize7, relative as relative7 } from "node:path";
|
|
73566
72518
|
|
|
73567
72519
|
// src/services/file-operations/ownership-checker.ts
|
|
73568
72520
|
init_metadata_migration();
|
|
@@ -74923,7 +73875,7 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
74923
73875
|
if (!stats.isSymbolicLink())
|
|
74924
73876
|
break;
|
|
74925
73877
|
const target = await readlink(current);
|
|
74926
|
-
const resolvedTarget = isAbsolute3(target) ? target :
|
|
73878
|
+
const resolvedTarget = isAbsolute3(target) ? target : join58(current, "..", target);
|
|
74927
73879
|
const normalizedTarget = normalize7(resolvedTarget);
|
|
74928
73880
|
const rel = relative7(basePath, normalizedTarget);
|
|
74929
73881
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
@@ -74942,10 +73894,6 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
74942
73894
|
throw new Error(`Symlink chain too deep (>${maxDepth}): ${path5}`);
|
|
74943
73895
|
}
|
|
74944
73896
|
}
|
|
74945
|
-
function isOutsideBase(candidatePath, basePath) {
|
|
74946
|
-
const rel = relative7(basePath, candidatePath);
|
|
74947
|
-
return rel.startsWith("..") || isAbsolute3(rel);
|
|
74948
|
-
}
|
|
74949
73897
|
async function validateSyncPath(basePath, filePath) {
|
|
74950
73898
|
if (!filePath || filePath.trim() === "") {
|
|
74951
73899
|
throw new Error("Empty file path not allowed");
|
|
@@ -74960,43 +73908,36 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
74960
73908
|
if (isAbsolute3(normalized)) {
|
|
74961
73909
|
throw new Error(`Absolute paths not allowed: ${filePath}`);
|
|
74962
73910
|
}
|
|
74963
|
-
|
|
74964
|
-
if (pathParts.includes("..")) {
|
|
73911
|
+
if (normalized.startsWith("..") || normalized.includes("/../")) {
|
|
74965
73912
|
throw new Error(`Path traversal not allowed: ${filePath}`);
|
|
74966
73913
|
}
|
|
74967
|
-
const
|
|
74968
|
-
const
|
|
74969
|
-
|
|
74970
|
-
if (isOutsideBase(fullPath, lexicalBase)) {
|
|
73914
|
+
const fullPath = join58(basePath, normalized);
|
|
73915
|
+
const rel = relative7(basePath, fullPath);
|
|
73916
|
+
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
74971
73917
|
throw new Error(`Path escapes base directory: ${filePath}`);
|
|
74972
73918
|
}
|
|
74973
|
-
await validateSymlinkChain(fullPath,
|
|
73919
|
+
await validateSymlinkChain(fullPath, basePath);
|
|
74974
73920
|
try {
|
|
73921
|
+
const resolvedBase = await realpath3(basePath);
|
|
74975
73922
|
const resolvedFull = await realpath3(fullPath);
|
|
74976
|
-
|
|
73923
|
+
const resolvedRel = relative7(resolvedBase, resolvedFull);
|
|
73924
|
+
if (resolvedRel.startsWith("..") || isAbsolute3(resolvedRel)) {
|
|
74977
73925
|
throw new Error(`Symlink escapes base directory: ${filePath}`);
|
|
74978
73926
|
}
|
|
74979
73927
|
} catch (error) {
|
|
74980
73928
|
if (error.code === "ENOENT") {
|
|
74981
|
-
|
|
74982
|
-
|
|
74983
|
-
|
|
74984
|
-
|
|
74985
|
-
|
|
74986
|
-
|
|
74987
|
-
|
|
74988
|
-
|
|
74989
|
-
|
|
74990
|
-
|
|
74991
|
-
|
|
74992
|
-
break;
|
|
74993
|
-
}
|
|
74994
|
-
ancestor = nextAncestor;
|
|
73929
|
+
const parentPath = join58(fullPath, "..");
|
|
73930
|
+
try {
|
|
73931
|
+
const resolvedBase = await realpath3(basePath);
|
|
73932
|
+
const resolvedParent = await realpath3(parentPath);
|
|
73933
|
+
const resolvedRel = relative7(resolvedBase, resolvedParent);
|
|
73934
|
+
if (resolvedRel.startsWith("..") || isAbsolute3(resolvedRel)) {
|
|
73935
|
+
throw new Error(`Parent symlink escapes base directory: ${filePath}`);
|
|
73936
|
+
}
|
|
73937
|
+
} catch (parentError) {
|
|
73938
|
+
if (parentError.code !== "ENOENT") {
|
|
73939
|
+
throw parentError;
|
|
74995
73940
|
}
|
|
74996
|
-
}
|
|
74997
|
-
const resolvedAncestor = await realpath3(ancestor).catch(() => null);
|
|
74998
|
-
if (!resolvedAncestor || isOutsideBase(resolvedAncestor, resolvedBase)) {
|
|
74999
|
-
throw new Error(`Parent symlink escapes base directory: ${filePath}`);
|
|
75000
73941
|
}
|
|
75001
73942
|
} else {
|
|
75002
73943
|
throw error;
|
|
@@ -75149,24 +74090,14 @@ class SyncEngine {
|
|
|
75149
74090
|
}
|
|
75150
74091
|
static async loadFileContent(filePath) {
|
|
75151
74092
|
try {
|
|
75152
|
-
const
|
|
75153
|
-
if (
|
|
74093
|
+
const lstats = await lstat3(filePath);
|
|
74094
|
+
if (lstats.isSymbolicLink()) {
|
|
75154
74095
|
throw new Error(`Symlink not allowed for sync: ${filePath}`);
|
|
75155
74096
|
}
|
|
75156
|
-
if (
|
|
75157
|
-
throw new Error(`File too large for sync (${Math.round(
|
|
74097
|
+
if (lstats.size > MAX_SYNC_FILE_SIZE) {
|
|
74098
|
+
throw new Error(`File too large for sync (${Math.round(lstats.size / 1024 / 1024)}MB > ${MAX_SYNC_FILE_SIZE / 1024 / 1024}MB limit)`);
|
|
75158
74099
|
}
|
|
75159
74100
|
const buffer = await readFile34(filePath);
|
|
75160
|
-
const afterStats = await lstat3(filePath);
|
|
75161
|
-
if (afterStats.isSymbolicLink()) {
|
|
75162
|
-
throw new Error(`File became symlink during read: ${filePath}`);
|
|
75163
|
-
}
|
|
75164
|
-
if (beforeStats.dev !== afterStats.dev || beforeStats.ino !== afterStats.ino) {
|
|
75165
|
-
throw new Error(`File changed identity during read: ${filePath}`);
|
|
75166
|
-
}
|
|
75167
|
-
if (beforeStats.mtimeMs !== afterStats.mtimeMs || beforeStats.size !== afterStats.size) {
|
|
75168
|
-
throw new Error(`File changed during read: ${filePath}`);
|
|
75169
|
-
}
|
|
75170
74101
|
if (buffer.includes(0)) {
|
|
75171
74102
|
return { content: "", isBinary: true };
|
|
75172
74103
|
}
|
|
@@ -76177,7 +75108,7 @@ init_logger();
|
|
|
76177
75108
|
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
76178
75109
|
import { mkdir as mkdir19 } from "node:fs/promises";
|
|
76179
75110
|
import os5 from "node:os";
|
|
76180
|
-
import { join as
|
|
75111
|
+
import { join as join65 } from "node:path";
|
|
76181
75112
|
var LOCK_CONFIG = {
|
|
76182
75113
|
stale: 60000,
|
|
76183
75114
|
retries: 0
|
|
@@ -76185,12 +75116,12 @@ var LOCK_CONFIG = {
|
|
|
76185
75116
|
var activeLocks = new Set;
|
|
76186
75117
|
var cleanupRegistered = false;
|
|
76187
75118
|
function getLocksDir() {
|
|
76188
|
-
return
|
|
75119
|
+
return join65(os5.homedir(), ".claudekit", "locks");
|
|
76189
75120
|
}
|
|
76190
75121
|
function cleanupLocks() {
|
|
76191
75122
|
for (const name of activeLocks) {
|
|
76192
75123
|
try {
|
|
76193
|
-
const lockPath =
|
|
75124
|
+
const lockPath = join65(getLocksDir(), `${name}.lock`);
|
|
76194
75125
|
import_proper_lockfile4.default.unlockSync(lockPath, { realpath: false });
|
|
76195
75126
|
} catch {
|
|
76196
75127
|
try {
|
|
@@ -76213,7 +75144,7 @@ async function ensureLocksDir() {
|
|
|
76213
75144
|
async function withProcessLock(lockName, fn) {
|
|
76214
75145
|
registerCleanupHandlers();
|
|
76215
75146
|
await ensureLocksDir();
|
|
76216
|
-
const lockPath =
|
|
75147
|
+
const lockPath = join65(getLocksDir(), `${lockName}.lock`);
|
|
76217
75148
|
let release;
|
|
76218
75149
|
try {
|
|
76219
75150
|
release = await import_proper_lockfile4.default.lock(lockPath, { ...LOCK_CONFIG, realpath: false });
|
|
@@ -76244,7 +75175,7 @@ init_logger();
|
|
|
76244
75175
|
init_logger();
|
|
76245
75176
|
init_path_resolver();
|
|
76246
75177
|
var import_fs_extra7 = __toESM(require_lib3(), 1);
|
|
76247
|
-
import { join as
|
|
75178
|
+
import { join as join66 } from "node:path";
|
|
76248
75179
|
async function handleConflicts(ctx) {
|
|
76249
75180
|
if (ctx.cancelled)
|
|
76250
75181
|
return ctx;
|
|
@@ -76253,7 +75184,7 @@ async function handleConflicts(ctx) {
|
|
|
76253
75184
|
if (PathResolver.isLocalSameAsGlobal()) {
|
|
76254
75185
|
return ctx;
|
|
76255
75186
|
}
|
|
76256
|
-
const localSettingsPath =
|
|
75187
|
+
const localSettingsPath = join66(process.cwd(), ".claude", "settings.json");
|
|
76257
75188
|
if (!await import_fs_extra7.pathExists(localSettingsPath)) {
|
|
76258
75189
|
return ctx;
|
|
76259
75190
|
}
|
|
@@ -76268,7 +75199,7 @@ async function handleConflicts(ctx) {
|
|
|
76268
75199
|
return { ...ctx, cancelled: true };
|
|
76269
75200
|
}
|
|
76270
75201
|
if (choice === "remove") {
|
|
76271
|
-
const localClaudeDir =
|
|
75202
|
+
const localClaudeDir = join66(process.cwd(), ".claude");
|
|
76272
75203
|
try {
|
|
76273
75204
|
await import_fs_extra7.remove(localClaudeDir);
|
|
76274
75205
|
logger.success("Removed local .claude/ directory");
|
|
@@ -76365,7 +75296,7 @@ init_logger();
|
|
|
76365
75296
|
init_safe_spinner();
|
|
76366
75297
|
import { mkdir as mkdir25, stat as stat12 } from "node:fs/promises";
|
|
76367
75298
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
76368
|
-
import { join as
|
|
75299
|
+
import { join as join73 } from "node:path";
|
|
76369
75300
|
|
|
76370
75301
|
// src/shared/temp-cleanup.ts
|
|
76371
75302
|
init_logger();
|
|
@@ -76384,7 +75315,7 @@ init_logger();
|
|
|
76384
75315
|
init_output_manager();
|
|
76385
75316
|
import { createWriteStream as createWriteStream2, rmSync } from "node:fs";
|
|
76386
75317
|
import { mkdir as mkdir20 } from "node:fs/promises";
|
|
76387
|
-
import { join as
|
|
75318
|
+
import { join as join67 } from "node:path";
|
|
76388
75319
|
|
|
76389
75320
|
// src/shared/progress-bar.ts
|
|
76390
75321
|
init_output_manager();
|
|
@@ -76549,10 +75480,10 @@ init_types3();
|
|
|
76549
75480
|
// src/domains/installation/utils/path-security.ts
|
|
76550
75481
|
init_types3();
|
|
76551
75482
|
import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
76552
|
-
import { relative as relative8, resolve as
|
|
75483
|
+
import { relative as relative8, resolve as resolve15 } from "node:path";
|
|
76553
75484
|
var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
|
|
76554
75485
|
function isPathSafe(basePath, targetPath) {
|
|
76555
|
-
const resolvedBase =
|
|
75486
|
+
const resolvedBase = resolve15(basePath);
|
|
76556
75487
|
try {
|
|
76557
75488
|
const stat10 = lstatSync2(targetPath);
|
|
76558
75489
|
if (stat10.isSymbolicLink()) {
|
|
@@ -76562,7 +75493,7 @@ function isPathSafe(basePath, targetPath) {
|
|
|
76562
75493
|
}
|
|
76563
75494
|
}
|
|
76564
75495
|
} catch {}
|
|
76565
|
-
const resolvedTarget =
|
|
75496
|
+
const resolvedTarget = resolve15(targetPath);
|
|
76566
75497
|
const relativePath = relative8(resolvedBase, resolvedTarget);
|
|
76567
75498
|
return !relativePath.startsWith("..") && !relativePath.startsWith("/") && resolvedTarget.startsWith(resolvedBase);
|
|
76568
75499
|
}
|
|
@@ -76594,7 +75525,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
|
|
|
76594
75525
|
class FileDownloader {
|
|
76595
75526
|
async downloadAsset(asset, destDir) {
|
|
76596
75527
|
try {
|
|
76597
|
-
const destPath =
|
|
75528
|
+
const destPath = join67(destDir, asset.name);
|
|
76598
75529
|
await mkdir20(destDir, { recursive: true });
|
|
76599
75530
|
output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
|
|
76600
75531
|
logger.verbose("Download details", {
|
|
@@ -76650,7 +75581,7 @@ class FileDownloader {
|
|
|
76650
75581
|
}
|
|
76651
75582
|
if (downloadedSize !== totalSize) {
|
|
76652
75583
|
fileStream.end();
|
|
76653
|
-
await new Promise((
|
|
75584
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76654
75585
|
try {
|
|
76655
75586
|
rmSync(destPath, { force: true });
|
|
76656
75587
|
} catch (cleanupError) {
|
|
@@ -76664,7 +75595,7 @@ class FileDownloader {
|
|
|
76664
75595
|
return destPath;
|
|
76665
75596
|
} catch (error) {
|
|
76666
75597
|
fileStream.end();
|
|
76667
|
-
await new Promise((
|
|
75598
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76668
75599
|
try {
|
|
76669
75600
|
rmSync(destPath, { force: true });
|
|
76670
75601
|
} catch (cleanupError) {
|
|
@@ -76679,7 +75610,7 @@ class FileDownloader {
|
|
|
76679
75610
|
}
|
|
76680
75611
|
async downloadFile(params) {
|
|
76681
75612
|
const { url, name, size, destDir, token } = params;
|
|
76682
|
-
const destPath =
|
|
75613
|
+
const destPath = join67(destDir, name);
|
|
76683
75614
|
await mkdir20(destDir, { recursive: true });
|
|
76684
75615
|
output.info(`Downloading ${name}${size ? ` (${formatBytes(size)})` : ""}...`);
|
|
76685
75616
|
const headers = {};
|
|
@@ -76730,7 +75661,7 @@ class FileDownloader {
|
|
|
76730
75661
|
const expectedSize = Number(response.headers.get("content-length"));
|
|
76731
75662
|
if (expectedSize > 0 && downloadedSize !== expectedSize) {
|
|
76732
75663
|
fileStream.end();
|
|
76733
|
-
await new Promise((
|
|
75664
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76734
75665
|
try {
|
|
76735
75666
|
rmSync(destPath, { force: true });
|
|
76736
75667
|
} catch (cleanupError) {
|
|
@@ -76748,7 +75679,7 @@ class FileDownloader {
|
|
|
76748
75679
|
return destPath;
|
|
76749
75680
|
} catch (error) {
|
|
76750
75681
|
fileStream.end();
|
|
76751
|
-
await new Promise((
|
|
75682
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76752
75683
|
try {
|
|
76753
75684
|
rmSync(destPath, { force: true });
|
|
76754
75685
|
} catch (cleanupError) {
|
|
@@ -76765,7 +75696,7 @@ init_logger();
|
|
|
76765
75696
|
init_types3();
|
|
76766
75697
|
import { constants as constants4 } from "node:fs";
|
|
76767
75698
|
import { access as access4, readdir as readdir13 } from "node:fs/promises";
|
|
76768
|
-
import { join as
|
|
75699
|
+
import { join as join68 } from "node:path";
|
|
76769
75700
|
async function validateExtraction(extractDir) {
|
|
76770
75701
|
try {
|
|
76771
75702
|
const entries = await readdir13(extractDir, { encoding: "utf8" });
|
|
@@ -76777,7 +75708,7 @@ async function validateExtraction(extractDir) {
|
|
|
76777
75708
|
const missingPaths = [];
|
|
76778
75709
|
for (const path5 of criticalPaths) {
|
|
76779
75710
|
try {
|
|
76780
|
-
await access4(
|
|
75711
|
+
await access4(join68(extractDir, path5), constants4.F_OK);
|
|
76781
75712
|
logger.debug(`Found: ${path5}`);
|
|
76782
75713
|
} catch {
|
|
76783
75714
|
logger.warning(`Expected path not found: ${path5}`);
|
|
@@ -76799,7 +75730,7 @@ async function validateExtraction(extractDir) {
|
|
|
76799
75730
|
// src/domains/installation/extraction/tar-extractor.ts
|
|
76800
75731
|
init_logger();
|
|
76801
75732
|
import { copyFile as copyFile4, mkdir as mkdir23, readdir as readdir15, rm as rm8, stat as stat10 } from "node:fs/promises";
|
|
76802
|
-
import { join as
|
|
75733
|
+
import { join as join71 } from "node:path";
|
|
76803
75734
|
|
|
76804
75735
|
// node_modules/@isaacs/fs-minipass/dist/esm/index.js
|
|
76805
75736
|
import EE from "events";
|
|
@@ -77347,10 +76278,10 @@ class Minipass extends EventEmitter3 {
|
|
|
77347
76278
|
return this[ENCODING] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
|
|
77348
76279
|
}
|
|
77349
76280
|
async promise() {
|
|
77350
|
-
return new Promise((
|
|
76281
|
+
return new Promise((resolve16, reject) => {
|
|
77351
76282
|
this.on(DESTROYED, () => reject(new Error("stream destroyed")));
|
|
77352
76283
|
this.on("error", (er) => reject(er));
|
|
77353
|
-
this.on("end", () =>
|
|
76284
|
+
this.on("end", () => resolve16());
|
|
77354
76285
|
});
|
|
77355
76286
|
}
|
|
77356
76287
|
[Symbol.asyncIterator]() {
|
|
@@ -77369,7 +76300,7 @@ class Minipass extends EventEmitter3 {
|
|
|
77369
76300
|
return Promise.resolve({ done: false, value: res });
|
|
77370
76301
|
if (this[EOF])
|
|
77371
76302
|
return stop();
|
|
77372
|
-
let
|
|
76303
|
+
let resolve16;
|
|
77373
76304
|
let reject;
|
|
77374
76305
|
const onerr = (er) => {
|
|
77375
76306
|
this.off("data", ondata);
|
|
@@ -77383,19 +76314,19 @@ class Minipass extends EventEmitter3 {
|
|
|
77383
76314
|
this.off("end", onend);
|
|
77384
76315
|
this.off(DESTROYED, ondestroy);
|
|
77385
76316
|
this.pause();
|
|
77386
|
-
|
|
76317
|
+
resolve16({ value, done: !!this[EOF] });
|
|
77387
76318
|
};
|
|
77388
76319
|
const onend = () => {
|
|
77389
76320
|
this.off("error", onerr);
|
|
77390
76321
|
this.off("data", ondata);
|
|
77391
76322
|
this.off(DESTROYED, ondestroy);
|
|
77392
76323
|
stop();
|
|
77393
|
-
|
|
76324
|
+
resolve16({ done: true, value: undefined });
|
|
77394
76325
|
};
|
|
77395
76326
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
77396
76327
|
return new Promise((res2, rej) => {
|
|
77397
76328
|
reject = rej;
|
|
77398
|
-
|
|
76329
|
+
resolve16 = res2;
|
|
77399
76330
|
this.once(DESTROYED, ondestroy);
|
|
77400
76331
|
this.once("error", onerr);
|
|
77401
76332
|
this.once("end", onend);
|
|
@@ -77852,7 +76783,7 @@ import path7 from "node:path";
|
|
|
77852
76783
|
|
|
77853
76784
|
// node_modules/tar/dist/esm/list.js
|
|
77854
76785
|
import fs9 from "node:fs";
|
|
77855
|
-
import { dirname as
|
|
76786
|
+
import { dirname as dirname17, parse as parse3 } from "path";
|
|
77856
76787
|
|
|
77857
76788
|
// node_modules/tar/dist/esm/options.js
|
|
77858
76789
|
var argmap = new Map([
|
|
@@ -78501,10 +77432,10 @@ class Minipass2 extends EventEmitter4 {
|
|
|
78501
77432
|
return this[ENCODING2] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
|
|
78502
77433
|
}
|
|
78503
77434
|
async promise() {
|
|
78504
|
-
return new Promise((
|
|
77435
|
+
return new Promise((resolve16, reject) => {
|
|
78505
77436
|
this.on(DESTROYED2, () => reject(new Error("stream destroyed")));
|
|
78506
77437
|
this.on("error", (er) => reject(er));
|
|
78507
|
-
this.on("end", () =>
|
|
77438
|
+
this.on("end", () => resolve16());
|
|
78508
77439
|
});
|
|
78509
77440
|
}
|
|
78510
77441
|
[Symbol.asyncIterator]() {
|
|
@@ -78523,7 +77454,7 @@ class Minipass2 extends EventEmitter4 {
|
|
|
78523
77454
|
return Promise.resolve({ done: false, value: res });
|
|
78524
77455
|
if (this[EOF2])
|
|
78525
77456
|
return stop();
|
|
78526
|
-
let
|
|
77457
|
+
let resolve16;
|
|
78527
77458
|
let reject;
|
|
78528
77459
|
const onerr = (er) => {
|
|
78529
77460
|
this.off("data", ondata);
|
|
@@ -78537,19 +77468,19 @@ class Minipass2 extends EventEmitter4 {
|
|
|
78537
77468
|
this.off("end", onend);
|
|
78538
77469
|
this.off(DESTROYED2, ondestroy);
|
|
78539
77470
|
this.pause();
|
|
78540
|
-
|
|
77471
|
+
resolve16({ value, done: !!this[EOF2] });
|
|
78541
77472
|
};
|
|
78542
77473
|
const onend = () => {
|
|
78543
77474
|
this.off("error", onerr);
|
|
78544
77475
|
this.off("data", ondata);
|
|
78545
77476
|
this.off(DESTROYED2, ondestroy);
|
|
78546
77477
|
stop();
|
|
78547
|
-
|
|
77478
|
+
resolve16({ done: true, value: undefined });
|
|
78548
77479
|
};
|
|
78549
77480
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
78550
77481
|
return new Promise((res2, rej) => {
|
|
78551
77482
|
reject = rej;
|
|
78552
|
-
|
|
77483
|
+
resolve16 = res2;
|
|
78553
77484
|
this.once(DESTROYED2, ondestroy);
|
|
78554
77485
|
this.once("error", onerr);
|
|
78555
77486
|
this.once("end", onend);
|
|
@@ -79977,10 +78908,10 @@ class Minipass3 extends EventEmitter5 {
|
|
|
79977
78908
|
return this[ENCODING3] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
|
|
79978
78909
|
}
|
|
79979
78910
|
async promise() {
|
|
79980
|
-
return new Promise((
|
|
78911
|
+
return new Promise((resolve16, reject) => {
|
|
79981
78912
|
this.on(DESTROYED3, () => reject(new Error("stream destroyed")));
|
|
79982
78913
|
this.on("error", (er) => reject(er));
|
|
79983
|
-
this.on("end", () =>
|
|
78914
|
+
this.on("end", () => resolve16());
|
|
79984
78915
|
});
|
|
79985
78916
|
}
|
|
79986
78917
|
[Symbol.asyncIterator]() {
|
|
@@ -79999,7 +78930,7 @@ class Minipass3 extends EventEmitter5 {
|
|
|
79999
78930
|
return Promise.resolve({ done: false, value: res });
|
|
80000
78931
|
if (this[EOF3])
|
|
80001
78932
|
return stop();
|
|
80002
|
-
let
|
|
78933
|
+
let resolve16;
|
|
80003
78934
|
let reject;
|
|
80004
78935
|
const onerr = (er) => {
|
|
80005
78936
|
this.off("data", ondata);
|
|
@@ -80013,19 +78944,19 @@ class Minipass3 extends EventEmitter5 {
|
|
|
80013
78944
|
this.off("end", onend);
|
|
80014
78945
|
this.off(DESTROYED3, ondestroy);
|
|
80015
78946
|
this.pause();
|
|
80016
|
-
|
|
78947
|
+
resolve16({ value, done: !!this[EOF3] });
|
|
80017
78948
|
};
|
|
80018
78949
|
const onend = () => {
|
|
80019
78950
|
this.off("error", onerr);
|
|
80020
78951
|
this.off("data", ondata);
|
|
80021
78952
|
this.off(DESTROYED3, ondestroy);
|
|
80022
78953
|
stop();
|
|
80023
|
-
|
|
78954
|
+
resolve16({ done: true, value: undefined });
|
|
80024
78955
|
};
|
|
80025
78956
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
80026
78957
|
return new Promise((res2, rej) => {
|
|
80027
78958
|
reject = rej;
|
|
80028
|
-
|
|
78959
|
+
resolve16 = res2;
|
|
80029
78960
|
this.once(DESTROYED3, ondestroy);
|
|
80030
78961
|
this.once("error", onerr);
|
|
80031
78962
|
this.once("end", onend);
|
|
@@ -80752,7 +79683,7 @@ var filesFilter = (opt, files) => {
|
|
|
80752
79683
|
if (m2 !== undefined) {
|
|
80753
79684
|
ret = m2;
|
|
80754
79685
|
} else {
|
|
80755
|
-
ret = mapHas(
|
|
79686
|
+
ret = mapHas(dirname17(file), root);
|
|
80756
79687
|
}
|
|
80757
79688
|
}
|
|
80758
79689
|
map.set(file, ret);
|
|
@@ -80796,9 +79727,9 @@ var listFile = (opt, _files) => {
|
|
|
80796
79727
|
const parse4 = new Parser(opt);
|
|
80797
79728
|
const readSize = opt.maxReadSize || 16 * 1024 * 1024;
|
|
80798
79729
|
const file = opt.file;
|
|
80799
|
-
const p = new Promise((
|
|
79730
|
+
const p = new Promise((resolve16, reject) => {
|
|
80800
79731
|
parse4.on("error", reject);
|
|
80801
|
-
parse4.on("end",
|
|
79732
|
+
parse4.on("end", resolve16);
|
|
80802
79733
|
fs9.stat(file, (er, stat10) => {
|
|
80803
79734
|
if (er) {
|
|
80804
79735
|
reject(er);
|
|
@@ -82561,7 +81492,7 @@ var mkdirSync = (dir, opt) => {
|
|
|
82561
81492
|
};
|
|
82562
81493
|
|
|
82563
81494
|
// node_modules/tar/dist/esm/path-reservations.js
|
|
82564
|
-
import { join as
|
|
81495
|
+
import { join as join69 } from "node:path";
|
|
82565
81496
|
|
|
82566
81497
|
// node_modules/tar/dist/esm/normalize-unicode.js
|
|
82567
81498
|
var normalizeCache = Object.create(null);
|
|
@@ -82594,7 +81525,7 @@ var getDirs = (path10) => {
|
|
|
82594
81525
|
const dirs = path10.split("/").slice(0, -1).reduce((set, path11) => {
|
|
82595
81526
|
const s = set[set.length - 1];
|
|
82596
81527
|
if (s !== undefined) {
|
|
82597
|
-
path11 =
|
|
81528
|
+
path11 = join69(s, path11);
|
|
82598
81529
|
}
|
|
82599
81530
|
set.push(path11 || "/");
|
|
82600
81531
|
return set;
|
|
@@ -82608,7 +81539,7 @@ class PathReservations {
|
|
|
82608
81539
|
#running = new Set;
|
|
82609
81540
|
reserve(paths, fn) {
|
|
82610
81541
|
paths = isWindows4 ? ["win32 parallelization disabled"] : paths.map((p) => {
|
|
82611
|
-
return stripTrailingSlashes(
|
|
81542
|
+
return stripTrailingSlashes(join69(normalizeUnicode(p))).toLowerCase();
|
|
82612
81543
|
});
|
|
82613
81544
|
const dirs = new Set(paths.map((path10) => getDirs(path10)).reduce((a3, b3) => a3.concat(b3)));
|
|
82614
81545
|
this.#reservations.set(fn, { dirs, paths });
|
|
@@ -83378,9 +82309,9 @@ var extractFile = (opt, _3) => {
|
|
|
83378
82309
|
const u = new Unpack(opt);
|
|
83379
82310
|
const readSize = opt.maxReadSize || 16 * 1024 * 1024;
|
|
83380
82311
|
const file = opt.file;
|
|
83381
|
-
const p = new Promise((
|
|
82312
|
+
const p = new Promise((resolve16, reject) => {
|
|
83382
82313
|
u.on("error", reject);
|
|
83383
|
-
u.on("close",
|
|
82314
|
+
u.on("close", resolve16);
|
|
83384
82315
|
fs16.stat(file, (er, stat10) => {
|
|
83385
82316
|
if (er) {
|
|
83386
82317
|
reject(er);
|
|
@@ -83513,7 +82444,7 @@ var replaceAsync = (opt, files) => {
|
|
|
83513
82444
|
};
|
|
83514
82445
|
fs17.read(fd, headBuf, 0, 512, position, onread);
|
|
83515
82446
|
};
|
|
83516
|
-
const promise = new Promise((
|
|
82447
|
+
const promise = new Promise((resolve16, reject) => {
|
|
83517
82448
|
p.on("error", reject);
|
|
83518
82449
|
let flag = "r+";
|
|
83519
82450
|
const onopen = (er, fd) => {
|
|
@@ -83538,7 +82469,7 @@ var replaceAsync = (opt, files) => {
|
|
|
83538
82469
|
});
|
|
83539
82470
|
p.pipe(stream);
|
|
83540
82471
|
stream.on("error", reject);
|
|
83541
|
-
stream.on("close",
|
|
82472
|
+
stream.on("close", resolve16);
|
|
83542
82473
|
addFilesAsync2(p, files);
|
|
83543
82474
|
});
|
|
83544
82475
|
});
|
|
@@ -83668,7 +82599,7 @@ function decodeFilePath(path12) {
|
|
|
83668
82599
|
init_logger();
|
|
83669
82600
|
init_types3();
|
|
83670
82601
|
import { copyFile as copyFile3, lstat as lstat4, mkdir as mkdir22, readdir as readdir14 } from "node:fs/promises";
|
|
83671
|
-
import { join as
|
|
82602
|
+
import { join as join70, relative as relative9 } from "node:path";
|
|
83672
82603
|
async function withRetry(fn, retries = 3) {
|
|
83673
82604
|
for (let i = 0;i < retries; i++) {
|
|
83674
82605
|
try {
|
|
@@ -83690,8 +82621,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
|
|
|
83690
82621
|
await mkdir22(destDir, { recursive: true });
|
|
83691
82622
|
const entries = await readdir14(sourceDir, { encoding: "utf8" });
|
|
83692
82623
|
for (const entry of entries) {
|
|
83693
|
-
const sourcePath =
|
|
83694
|
-
const destPath =
|
|
82624
|
+
const sourcePath = join70(sourceDir, entry);
|
|
82625
|
+
const destPath = join70(destDir, entry);
|
|
83695
82626
|
const relativePath = relative9(sourceDir, sourcePath);
|
|
83696
82627
|
if (!isPathSafe(destDir, destPath)) {
|
|
83697
82628
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -83718,8 +82649,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
|
|
|
83718
82649
|
await mkdir22(destDir, { recursive: true });
|
|
83719
82650
|
const entries = await readdir14(sourceDir, { encoding: "utf8" });
|
|
83720
82651
|
for (const entry of entries) {
|
|
83721
|
-
const sourcePath =
|
|
83722
|
-
const destPath =
|
|
82652
|
+
const sourcePath = join70(sourceDir, entry);
|
|
82653
|
+
const destPath = join70(destDir, entry);
|
|
83723
82654
|
const relativePath = relative9(sourceDir, sourcePath);
|
|
83724
82655
|
if (!isPathSafe(destDir, destPath)) {
|
|
83725
82656
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -83767,7 +82698,7 @@ class TarExtractor {
|
|
|
83767
82698
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
83768
82699
|
if (entries.length === 1) {
|
|
83769
82700
|
const rootEntry = entries[0];
|
|
83770
|
-
const rootPath =
|
|
82701
|
+
const rootPath = join71(tempExtractDir, rootEntry);
|
|
83771
82702
|
const rootStat = await stat10(rootPath);
|
|
83772
82703
|
if (rootStat.isDirectory()) {
|
|
83773
82704
|
const rootContents = await readdir15(rootPath, { encoding: "utf8" });
|
|
@@ -83783,7 +82714,7 @@ class TarExtractor {
|
|
|
83783
82714
|
}
|
|
83784
82715
|
} else {
|
|
83785
82716
|
await mkdir23(destDir, { recursive: true });
|
|
83786
|
-
await copyFile4(rootPath,
|
|
82717
|
+
await copyFile4(rootPath, join71(destDir, rootEntry));
|
|
83787
82718
|
}
|
|
83788
82719
|
} else {
|
|
83789
82720
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -83806,26 +82737,26 @@ init_logger();
|
|
|
83806
82737
|
var import_extract_zip = __toESM(require_extract_zip(), 1);
|
|
83807
82738
|
import { execFile as execFile8 } from "node:child_process";
|
|
83808
82739
|
import { copyFile as copyFile5, mkdir as mkdir24, readdir as readdir16, rm as rm9, stat as stat11 } from "node:fs/promises";
|
|
83809
|
-
import { join as
|
|
82740
|
+
import { join as join72 } from "node:path";
|
|
83810
82741
|
class ZipExtractor {
|
|
83811
82742
|
async tryNativeUnzip(archivePath, destDir) {
|
|
83812
82743
|
if (!isMacOS()) {
|
|
83813
82744
|
return false;
|
|
83814
82745
|
}
|
|
83815
|
-
return new Promise((
|
|
82746
|
+
return new Promise((resolve16) => {
|
|
83816
82747
|
mkdir24(destDir, { recursive: true }).then(() => {
|
|
83817
82748
|
execFile8("unzip", ["-o", "-q", archivePath, "-d", destDir], (error, _stdout, stderr) => {
|
|
83818
82749
|
if (error) {
|
|
83819
82750
|
logger.debug(`Native unzip failed: ${stderr || error.message}`);
|
|
83820
|
-
|
|
82751
|
+
resolve16(false);
|
|
83821
82752
|
return;
|
|
83822
82753
|
}
|
|
83823
82754
|
logger.debug("Native unzip succeeded");
|
|
83824
|
-
|
|
82755
|
+
resolve16(true);
|
|
83825
82756
|
});
|
|
83826
82757
|
}).catch((err) => {
|
|
83827
82758
|
logger.debug(`Failed to create directory for native unzip: ${err.message}`);
|
|
83828
|
-
|
|
82759
|
+
resolve16(false);
|
|
83829
82760
|
});
|
|
83830
82761
|
});
|
|
83831
82762
|
}
|
|
@@ -83854,7 +82785,7 @@ class ZipExtractor {
|
|
|
83854
82785
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
83855
82786
|
if (entries.length === 1) {
|
|
83856
82787
|
const rootEntry = entries[0];
|
|
83857
|
-
const rootPath =
|
|
82788
|
+
const rootPath = join72(tempExtractDir, rootEntry);
|
|
83858
82789
|
const rootStat = await stat11(rootPath);
|
|
83859
82790
|
if (rootStat.isDirectory()) {
|
|
83860
82791
|
const rootContents = await readdir16(rootPath, { encoding: "utf8" });
|
|
@@ -83870,7 +82801,7 @@ class ZipExtractor {
|
|
|
83870
82801
|
}
|
|
83871
82802
|
} else {
|
|
83872
82803
|
await mkdir24(destDir, { recursive: true });
|
|
83873
|
-
await copyFile5(rootPath,
|
|
82804
|
+
await copyFile5(rootPath, join72(destDir, rootEntry));
|
|
83874
82805
|
}
|
|
83875
82806
|
} else {
|
|
83876
82807
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -83969,7 +82900,7 @@ class DownloadManager {
|
|
|
83969
82900
|
async createTempDir() {
|
|
83970
82901
|
const timestamp = Date.now();
|
|
83971
82902
|
const counter = DownloadManager.tempDirCounter++;
|
|
83972
|
-
const primaryTempDir =
|
|
82903
|
+
const primaryTempDir = join73(tmpdir4(), `claudekit-${timestamp}-${counter}`);
|
|
83973
82904
|
try {
|
|
83974
82905
|
await mkdir25(primaryTempDir, { recursive: true });
|
|
83975
82906
|
logger.debug(`Created temp directory: ${primaryTempDir}`);
|
|
@@ -83986,7 +82917,7 @@ Solutions:
|
|
|
83986
82917
|
2. Set HOME environment variable
|
|
83987
82918
|
3. Try running from a different directory`);
|
|
83988
82919
|
}
|
|
83989
|
-
const fallbackTempDir =
|
|
82920
|
+
const fallbackTempDir = join73(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
|
|
83990
82921
|
try {
|
|
83991
82922
|
await mkdir25(fallbackTempDir, { recursive: true });
|
|
83992
82923
|
logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
|
|
@@ -84335,8 +83266,349 @@ async function handleDownload(ctx) {
|
|
|
84335
83266
|
};
|
|
84336
83267
|
}
|
|
84337
83268
|
// src/commands/init/phases/merge-handler.ts
|
|
84338
|
-
|
|
84339
|
-
|
|
83269
|
+
import { join as join89 } from "node:path";
|
|
83270
|
+
|
|
83271
|
+
// src/domains/installation/deletion-handler.ts
|
|
83272
|
+
import { existsSync as existsSync48, lstatSync as lstatSync3, readdirSync as readdirSync3, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
|
|
83273
|
+
import { dirname as dirname18, join as join76, relative as relative10, resolve as resolve17, sep as sep3 } from "node:path";
|
|
83274
|
+
|
|
83275
|
+
// src/services/file-operations/manifest/manifest-reader.ts
|
|
83276
|
+
init_metadata_migration();
|
|
83277
|
+
init_logger();
|
|
83278
|
+
init_types3();
|
|
83279
|
+
var import_fs_extra8 = __toESM(require_lib3(), 1);
|
|
83280
|
+
import { join as join75 } from "node:path";
|
|
83281
|
+
async function readManifest(claudeDir2) {
|
|
83282
|
+
const metadataPath = join75(claudeDir2, "metadata.json");
|
|
83283
|
+
if (!await import_fs_extra8.pathExists(metadataPath)) {
|
|
83284
|
+
return null;
|
|
83285
|
+
}
|
|
83286
|
+
try {
|
|
83287
|
+
const content = await import_fs_extra8.readFile(metadataPath, "utf-8");
|
|
83288
|
+
const parsed = JSON.parse(content);
|
|
83289
|
+
return MetadataSchema.parse(parsed);
|
|
83290
|
+
} catch (error) {
|
|
83291
|
+
logger.debug(`Failed to read manifest: ${error}`);
|
|
83292
|
+
return null;
|
|
83293
|
+
}
|
|
83294
|
+
}
|
|
83295
|
+
async function readKitManifest(claudeDir2, kit) {
|
|
83296
|
+
const metadata = await readManifest(claudeDir2);
|
|
83297
|
+
if (!metadata)
|
|
83298
|
+
return null;
|
|
83299
|
+
return getKitMetadata(metadata, kit);
|
|
83300
|
+
}
|
|
83301
|
+
async function findFileInInstalledKits(claudeDir2, relativePath, excludeKit) {
|
|
83302
|
+
const metadata = await readManifest(claudeDir2);
|
|
83303
|
+
if (!metadata?.kits) {
|
|
83304
|
+
return {
|
|
83305
|
+
exists: false,
|
|
83306
|
+
ownerKit: null,
|
|
83307
|
+
checksum: null,
|
|
83308
|
+
version: null,
|
|
83309
|
+
sourceTimestamp: null,
|
|
83310
|
+
installedAt: null
|
|
83311
|
+
};
|
|
83312
|
+
}
|
|
83313
|
+
for (const [kitName, kitMeta] of Object.entries(metadata.kits)) {
|
|
83314
|
+
const kit = kitName;
|
|
83315
|
+
if (kit === excludeKit)
|
|
83316
|
+
continue;
|
|
83317
|
+
if (!kitMeta.files)
|
|
83318
|
+
continue;
|
|
83319
|
+
const file = kitMeta.files.find((f3) => f3.path === relativePath);
|
|
83320
|
+
if (file) {
|
|
83321
|
+
return {
|
|
83322
|
+
exists: true,
|
|
83323
|
+
ownerKit: kit,
|
|
83324
|
+
checksum: file.checksum,
|
|
83325
|
+
version: kitMeta.version,
|
|
83326
|
+
sourceTimestamp: file.sourceTimestamp ?? null,
|
|
83327
|
+
installedAt: file.installedAt ?? null
|
|
83328
|
+
};
|
|
83329
|
+
}
|
|
83330
|
+
}
|
|
83331
|
+
return {
|
|
83332
|
+
exists: false,
|
|
83333
|
+
ownerKit: null,
|
|
83334
|
+
checksum: null,
|
|
83335
|
+
version: null,
|
|
83336
|
+
sourceTimestamp: null,
|
|
83337
|
+
installedAt: null
|
|
83338
|
+
};
|
|
83339
|
+
}
|
|
83340
|
+
async function getUninstallManifest(claudeDir2, kit) {
|
|
83341
|
+
const detection = await detectMetadataFormat(claudeDir2);
|
|
83342
|
+
if (detection.format === "multi-kit" && detection.metadata?.kits) {
|
|
83343
|
+
const installedKits = Object.keys(detection.metadata.kits);
|
|
83344
|
+
if (kit) {
|
|
83345
|
+
const kitMeta = detection.metadata.kits[kit];
|
|
83346
|
+
if (!kitMeta?.files) {
|
|
83347
|
+
return {
|
|
83348
|
+
filesToRemove: [],
|
|
83349
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
83350
|
+
hasManifest: true,
|
|
83351
|
+
isMultiKit: true,
|
|
83352
|
+
remainingKits: installedKits.filter((k2) => k2 !== kit)
|
|
83353
|
+
};
|
|
83354
|
+
}
|
|
83355
|
+
const kitFiles = kitMeta.files.map((f3) => f3.path);
|
|
83356
|
+
const sharedFiles = new Set;
|
|
83357
|
+
for (const otherKit of installedKits) {
|
|
83358
|
+
if (otherKit !== kit) {
|
|
83359
|
+
const otherMeta = detection.metadata.kits[otherKit];
|
|
83360
|
+
if (otherMeta?.files) {
|
|
83361
|
+
for (const f3 of otherMeta.files) {
|
|
83362
|
+
sharedFiles.add(f3.path);
|
|
83363
|
+
}
|
|
83364
|
+
}
|
|
83365
|
+
}
|
|
83366
|
+
}
|
|
83367
|
+
const filesToRemove = kitFiles.filter((f3) => !sharedFiles.has(f3));
|
|
83368
|
+
const filesToPreserve = [
|
|
83369
|
+
...USER_CONFIG_PATTERNS,
|
|
83370
|
+
...kitFiles.filter((f3) => sharedFiles.has(f3))
|
|
83371
|
+
];
|
|
83372
|
+
return {
|
|
83373
|
+
filesToRemove,
|
|
83374
|
+
filesToPreserve,
|
|
83375
|
+
hasManifest: true,
|
|
83376
|
+
isMultiKit: true,
|
|
83377
|
+
remainingKits: installedKits.filter((k2) => k2 !== kit)
|
|
83378
|
+
};
|
|
83379
|
+
}
|
|
83380
|
+
const allFiles = getAllTrackedFiles(detection.metadata);
|
|
83381
|
+
return {
|
|
83382
|
+
filesToRemove: allFiles.map((f3) => f3.path),
|
|
83383
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
83384
|
+
hasManifest: true,
|
|
83385
|
+
isMultiKit: true,
|
|
83386
|
+
remainingKits: []
|
|
83387
|
+
};
|
|
83388
|
+
}
|
|
83389
|
+
if (detection.format === "legacy" && detection.metadata) {
|
|
83390
|
+
const legacyFiles2 = detection.metadata.files?.map((f3) => f3.path) || [];
|
|
83391
|
+
const installedFiles = detection.metadata.installedFiles || [];
|
|
83392
|
+
const hasFiles = legacyFiles2.length > 0 || installedFiles.length > 0;
|
|
83393
|
+
if (!hasFiles) {
|
|
83394
|
+
const legacyDirs2 = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
|
|
83395
|
+
const legacyFileList = ["metadata.json"];
|
|
83396
|
+
return {
|
|
83397
|
+
filesToRemove: [...legacyDirs2, ...legacyFileList],
|
|
83398
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
83399
|
+
hasManifest: false,
|
|
83400
|
+
isMultiKit: false,
|
|
83401
|
+
remainingKits: []
|
|
83402
|
+
};
|
|
83403
|
+
}
|
|
83404
|
+
return {
|
|
83405
|
+
filesToRemove: legacyFiles2.length > 0 ? legacyFiles2 : installedFiles,
|
|
83406
|
+
filesToPreserve: detection.metadata.userConfigFiles || USER_CONFIG_PATTERNS,
|
|
83407
|
+
hasManifest: true,
|
|
83408
|
+
isMultiKit: false,
|
|
83409
|
+
remainingKits: []
|
|
83410
|
+
};
|
|
83411
|
+
}
|
|
83412
|
+
const legacyDirs = ["commands", "agents", "skills", "rules", "workflows", "hooks", "scripts"];
|
|
83413
|
+
const legacyFiles = ["metadata.json"];
|
|
83414
|
+
return {
|
|
83415
|
+
filesToRemove: [...legacyDirs, ...legacyFiles],
|
|
83416
|
+
filesToPreserve: USER_CONFIG_PATTERNS,
|
|
83417
|
+
hasManifest: false,
|
|
83418
|
+
isMultiKit: false,
|
|
83419
|
+
remainingKits: []
|
|
83420
|
+
};
|
|
83421
|
+
}
|
|
83422
|
+
|
|
83423
|
+
// src/domains/installation/deletion-handler.ts
|
|
83424
|
+
init_logger();
|
|
83425
|
+
init_path_resolver();
|
|
83426
|
+
var import_fs_extra9 = __toESM(require_lib3(), 1);
|
|
83427
|
+
var import_picomatch2 = __toESM(require_picomatch2(), 1);
|
|
83428
|
+
function findFileInMetadata(metadata, path13) {
|
|
83429
|
+
if (!metadata)
|
|
83430
|
+
return null;
|
|
83431
|
+
if (metadata.kits) {
|
|
83432
|
+
for (const kitMeta of Object.values(metadata.kits)) {
|
|
83433
|
+
if (kitMeta?.files) {
|
|
83434
|
+
const found = kitMeta.files.find((f3) => f3.path === path13);
|
|
83435
|
+
if (found)
|
|
83436
|
+
return found;
|
|
83437
|
+
}
|
|
83438
|
+
}
|
|
83439
|
+
}
|
|
83440
|
+
if (metadata.files) {
|
|
83441
|
+
const found = metadata.files.find((f3) => f3.path === path13);
|
|
83442
|
+
if (found)
|
|
83443
|
+
return found;
|
|
83444
|
+
}
|
|
83445
|
+
return null;
|
|
83446
|
+
}
|
|
83447
|
+
function shouldDeletePath(path13, metadata) {
|
|
83448
|
+
const tracked = findFileInMetadata(metadata, path13);
|
|
83449
|
+
if (!tracked)
|
|
83450
|
+
return true;
|
|
83451
|
+
return tracked.ownership !== "user";
|
|
83452
|
+
}
|
|
83453
|
+
function collectFilesRecursively(dir, baseDir) {
|
|
83454
|
+
const results = [];
|
|
83455
|
+
if (!existsSync48(dir))
|
|
83456
|
+
return results;
|
|
83457
|
+
try {
|
|
83458
|
+
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
83459
|
+
for (const entry of entries) {
|
|
83460
|
+
const fullPath = join76(dir, entry.name);
|
|
83461
|
+
const relativePath = relative10(baseDir, fullPath);
|
|
83462
|
+
if (entry.isDirectory()) {
|
|
83463
|
+
results.push(...collectFilesRecursively(fullPath, baseDir));
|
|
83464
|
+
} else {
|
|
83465
|
+
results.push(relativePath);
|
|
83466
|
+
}
|
|
83467
|
+
}
|
|
83468
|
+
} catch {}
|
|
83469
|
+
return results;
|
|
83470
|
+
}
|
|
83471
|
+
function expandGlobPatterns(patterns, claudeDir2) {
|
|
83472
|
+
const expanded = [];
|
|
83473
|
+
const allFiles = collectFilesRecursively(claudeDir2, claudeDir2);
|
|
83474
|
+
for (const pattern of patterns) {
|
|
83475
|
+
if (PathResolver.isGlobPattern(pattern)) {
|
|
83476
|
+
const matcher = import_picomatch2.default(pattern);
|
|
83477
|
+
const matches = allFiles.filter((file) => matcher(file));
|
|
83478
|
+
expanded.push(...matches);
|
|
83479
|
+
if (matches.length > 0) {
|
|
83480
|
+
logger.debug(`Pattern "${pattern}" matched ${matches.length} files`);
|
|
83481
|
+
}
|
|
83482
|
+
} else {
|
|
83483
|
+
expanded.push(pattern);
|
|
83484
|
+
}
|
|
83485
|
+
}
|
|
83486
|
+
return [...new Set(expanded)];
|
|
83487
|
+
}
|
|
83488
|
+
var MAX_CLEANUP_ITERATIONS = 50;
|
|
83489
|
+
function cleanupEmptyDirectories(filePath, claudeDir2) {
|
|
83490
|
+
const normalizedClaudeDir = resolve17(claudeDir2);
|
|
83491
|
+
let currentDir = resolve17(dirname18(filePath));
|
|
83492
|
+
let iterations = 0;
|
|
83493
|
+
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
|
|
83494
|
+
iterations++;
|
|
83495
|
+
try {
|
|
83496
|
+
const entries = readdirSync3(currentDir);
|
|
83497
|
+
if (entries.length === 0) {
|
|
83498
|
+
rmdirSync(currentDir);
|
|
83499
|
+
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
83500
|
+
currentDir = resolve17(dirname18(currentDir));
|
|
83501
|
+
} else {
|
|
83502
|
+
break;
|
|
83503
|
+
}
|
|
83504
|
+
} catch {
|
|
83505
|
+
break;
|
|
83506
|
+
}
|
|
83507
|
+
}
|
|
83508
|
+
}
|
|
83509
|
+
function deletePath(fullPath, claudeDir2) {
|
|
83510
|
+
const normalizedPath = resolve17(fullPath);
|
|
83511
|
+
const normalizedClaudeDir = resolve17(claudeDir2);
|
|
83512
|
+
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep3}`) && normalizedPath !== normalizedClaudeDir) {
|
|
83513
|
+
throw new Error(`Path traversal detected: ${fullPath}`);
|
|
83514
|
+
}
|
|
83515
|
+
try {
|
|
83516
|
+
const stat13 = lstatSync3(fullPath);
|
|
83517
|
+
if (stat13.isDirectory()) {
|
|
83518
|
+
rmSync2(fullPath, { recursive: true, force: true });
|
|
83519
|
+
} else {
|
|
83520
|
+
unlinkSync3(fullPath);
|
|
83521
|
+
cleanupEmptyDirectories(fullPath, claudeDir2);
|
|
83522
|
+
}
|
|
83523
|
+
} catch (error) {
|
|
83524
|
+
throw new Error(`Failed to delete ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
83525
|
+
}
|
|
83526
|
+
}
|
|
83527
|
+
async function updateMetadataAfterDeletion(claudeDir2, deletedPaths) {
|
|
83528
|
+
const metadataPath = join76(claudeDir2, "metadata.json");
|
|
83529
|
+
if (!await import_fs_extra9.pathExists(metadataPath)) {
|
|
83530
|
+
return;
|
|
83531
|
+
}
|
|
83532
|
+
let content;
|
|
83533
|
+
try {
|
|
83534
|
+
content = await import_fs_extra9.readFile(metadataPath, "utf-8");
|
|
83535
|
+
} catch {
|
|
83536
|
+
logger.debug("Failed to read metadata.json for cleanup");
|
|
83537
|
+
return;
|
|
83538
|
+
}
|
|
83539
|
+
let metadata;
|
|
83540
|
+
try {
|
|
83541
|
+
metadata = JSON.parse(content);
|
|
83542
|
+
} catch {
|
|
83543
|
+
logger.debug("Failed to parse metadata.json for cleanup");
|
|
83544
|
+
return;
|
|
83545
|
+
}
|
|
83546
|
+
const deletedSet = new Set(deletedPaths);
|
|
83547
|
+
const isDeletedOrInDeletedDir = (path13) => {
|
|
83548
|
+
if (deletedSet.has(path13))
|
|
83549
|
+
return true;
|
|
83550
|
+
for (const deleted of deletedPaths) {
|
|
83551
|
+
if (path13.startsWith(`${deleted}/`))
|
|
83552
|
+
return true;
|
|
83553
|
+
}
|
|
83554
|
+
return false;
|
|
83555
|
+
};
|
|
83556
|
+
if (metadata.kits) {
|
|
83557
|
+
for (const kitName of Object.keys(metadata.kits)) {
|
|
83558
|
+
const kit = metadata.kits[kitName];
|
|
83559
|
+
if (kit?.files) {
|
|
83560
|
+
kit.files = kit.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
|
|
83561
|
+
}
|
|
83562
|
+
}
|
|
83563
|
+
}
|
|
83564
|
+
if (metadata.files) {
|
|
83565
|
+
metadata.files = metadata.files.filter((f3) => !isDeletedOrInDeletedDir(f3.path));
|
|
83566
|
+
}
|
|
83567
|
+
try {
|
|
83568
|
+
await import_fs_extra9.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
83569
|
+
logger.debug(`Updated metadata.json, removed ${deletedPaths.length} entries`);
|
|
83570
|
+
} catch {
|
|
83571
|
+
logger.debug("Failed to write updated metadata.json");
|
|
83572
|
+
}
|
|
83573
|
+
}
|
|
83574
|
+
async function handleDeletions(sourceMetadata, claudeDir2) {
|
|
83575
|
+
const deletionPatterns = sourceMetadata.deletions || [];
|
|
83576
|
+
if (deletionPatterns.length === 0) {
|
|
83577
|
+
return { deletedPaths: [], preservedPaths: [], errors: [] };
|
|
83578
|
+
}
|
|
83579
|
+
const deletions = expandGlobPatterns(deletionPatterns, claudeDir2);
|
|
83580
|
+
const userMetadata = await readManifest(claudeDir2);
|
|
83581
|
+
const result = { deletedPaths: [], preservedPaths: [], errors: [] };
|
|
83582
|
+
for (const path13 of deletions) {
|
|
83583
|
+
const fullPath = join76(claudeDir2, path13);
|
|
83584
|
+
const normalizedPath = resolve17(fullPath);
|
|
83585
|
+
const normalizedClaudeDir = resolve17(claudeDir2);
|
|
83586
|
+
if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep3}`)) {
|
|
83587
|
+
logger.warning(`Skipping invalid path: ${path13}`);
|
|
83588
|
+
result.errors.push(path13);
|
|
83589
|
+
continue;
|
|
83590
|
+
}
|
|
83591
|
+
if (!shouldDeletePath(path13, userMetadata)) {
|
|
83592
|
+
result.preservedPaths.push(path13);
|
|
83593
|
+
logger.verbose(`Preserved user file: ${path13}`);
|
|
83594
|
+
continue;
|
|
83595
|
+
}
|
|
83596
|
+
if (existsSync48(fullPath)) {
|
|
83597
|
+
try {
|
|
83598
|
+
deletePath(fullPath, claudeDir2);
|
|
83599
|
+
result.deletedPaths.push(path13);
|
|
83600
|
+
logger.verbose(`Deleted: ${path13}`);
|
|
83601
|
+
} catch (error) {
|
|
83602
|
+
result.errors.push(path13);
|
|
83603
|
+
logger.debug(`Failed to delete ${path13}: ${error}`);
|
|
83604
|
+
}
|
|
83605
|
+
}
|
|
83606
|
+
}
|
|
83607
|
+
if (result.deletedPaths.length > 0) {
|
|
83608
|
+
await updateMetadataAfterDeletion(claudeDir2, result.deletedPaths);
|
|
83609
|
+
}
|
|
83610
|
+
return result;
|
|
83611
|
+
}
|
|
84340
83612
|
|
|
84341
83613
|
// src/domains/installation/file-merger.ts
|
|
84342
83614
|
init_logger();
|
|
@@ -84348,10 +83620,9 @@ init_logger();
|
|
|
84348
83620
|
init_types3();
|
|
84349
83621
|
var import_fs_extra12 = __toESM(require_lib3(), 1);
|
|
84350
83622
|
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
84351
|
-
import { dirname as
|
|
83623
|
+
import { dirname as dirname20, join as join79, relative as relative12 } from "node:path";
|
|
84352
83624
|
|
|
84353
83625
|
// src/domains/installation/selective-merger.ts
|
|
84354
|
-
init_manifest_reader();
|
|
84355
83626
|
import { stat as stat13 } from "node:fs/promises";
|
|
84356
83627
|
init_logger();
|
|
84357
83628
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
@@ -84528,7 +83799,7 @@ init_logger();
|
|
|
84528
83799
|
var import_fs_extra10 = __toESM(require_lib3(), 1);
|
|
84529
83800
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
84530
83801
|
import { relative as relative11 } from "node:path";
|
|
84531
|
-
import { join as
|
|
83802
|
+
import { join as join77 } from "node:path";
|
|
84532
83803
|
|
|
84533
83804
|
// node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
84534
83805
|
var balanced = (a3, b3, str2) => {
|
|
@@ -85984,7 +85255,7 @@ class FileScanner {
|
|
|
85984
85255
|
const files = [];
|
|
85985
85256
|
const entries = await import_fs_extra10.readdir(dir, { encoding: "utf8" });
|
|
85986
85257
|
for (const entry of entries) {
|
|
85987
|
-
const fullPath =
|
|
85258
|
+
const fullPath = join77(dir, entry);
|
|
85988
85259
|
const relativePath = relative11(baseDir, fullPath);
|
|
85989
85260
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
85990
85261
|
const stats = await import_fs_extra10.lstat(fullPath);
|
|
@@ -86024,7 +85295,7 @@ import { execSync as execSync4 } from "node:child_process";
|
|
|
86024
85295
|
init_shared();
|
|
86025
85296
|
import { existsSync as existsSync49 } from "node:fs";
|
|
86026
85297
|
import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "node:fs/promises";
|
|
86027
|
-
import { dirname as
|
|
85298
|
+
import { dirname as dirname19, join as join78 } from "node:path";
|
|
86028
85299
|
var CK_JSON_FILE = ".ck.json";
|
|
86029
85300
|
|
|
86030
85301
|
class InstalledSettingsTracker {
|
|
@@ -86038,9 +85309,9 @@ class InstalledSettingsTracker {
|
|
|
86038
85309
|
}
|
|
86039
85310
|
getCkJsonPath() {
|
|
86040
85311
|
if (this.isGlobal) {
|
|
86041
|
-
return
|
|
85312
|
+
return join78(this.projectDir, CK_JSON_FILE);
|
|
86042
85313
|
}
|
|
86043
|
-
return
|
|
85314
|
+
return join78(this.projectDir, ".claude", CK_JSON_FILE);
|
|
86044
85315
|
}
|
|
86045
85316
|
async loadInstalledSettings() {
|
|
86046
85317
|
const ckJsonPath = this.getCkJsonPath();
|
|
@@ -86075,7 +85346,7 @@ class InstalledSettingsTracker {
|
|
|
86075
85346
|
data.kits[this.kitName] = {};
|
|
86076
85347
|
}
|
|
86077
85348
|
data.kits[this.kitName].installedSettings = settings;
|
|
86078
|
-
await mkdir26(
|
|
85349
|
+
await mkdir26(dirname19(ckJsonPath), { recursive: true });
|
|
86079
85350
|
await writeFile22(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
|
|
86080
85351
|
logger.debug(`Saved installed settings to ${ckJsonPath}`);
|
|
86081
85352
|
} catch (error) {
|
|
@@ -86593,7 +85864,7 @@ class CopyExecutor {
|
|
|
86593
85864
|
for (const file of files) {
|
|
86594
85865
|
const relativePath = relative12(sourceDir, file);
|
|
86595
85866
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
86596
|
-
const destPath =
|
|
85867
|
+
const destPath = join79(destDir, relativePath);
|
|
86597
85868
|
if (await import_fs_extra12.pathExists(destPath)) {
|
|
86598
85869
|
if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
|
|
86599
85870
|
logger.debug(`Security-sensitive file exists but won't be overwritten: ${normalizedRelativePath}`);
|
|
@@ -86615,7 +85886,7 @@ class CopyExecutor {
|
|
|
86615
85886
|
for (const file of files) {
|
|
86616
85887
|
const relativePath = relative12(sourceDir, file);
|
|
86617
85888
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
86618
|
-
const destPath =
|
|
85889
|
+
const destPath = join79(destDir, relativePath);
|
|
86619
85890
|
if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
|
|
86620
85891
|
logger.debug(`Skipping security-sensitive file: ${normalizedRelativePath}`);
|
|
86621
85892
|
skippedCount++;
|
|
@@ -86692,10 +85963,10 @@ class CopyExecutor {
|
|
|
86692
85963
|
}
|
|
86693
85964
|
trackInstalledFile(relativePath) {
|
|
86694
85965
|
this.installedFiles.add(relativePath);
|
|
86695
|
-
let dir =
|
|
85966
|
+
let dir = dirname20(relativePath);
|
|
86696
85967
|
while (dir && dir !== "." && dir !== "/") {
|
|
86697
85968
|
this.installedDirectories.add(`${dir}/`);
|
|
86698
|
-
dir =
|
|
85969
|
+
dir = dirname20(dir);
|
|
86699
85970
|
}
|
|
86700
85971
|
}
|
|
86701
85972
|
}
|
|
@@ -86785,19 +86056,15 @@ class FileMerger {
|
|
|
86785
86056
|
|
|
86786
86057
|
// src/domains/migration/legacy-migration.ts
|
|
86787
86058
|
import { readdir as readdir18, stat as stat14 } from "node:fs/promises";
|
|
86788
|
-
import { join as
|
|
86789
|
-
|
|
86790
|
-
// src/services/file-operations/manifest/index.ts
|
|
86791
|
-
init_manifest_reader();
|
|
86792
|
-
|
|
86059
|
+
import { join as join83, relative as relative13 } from "node:path";
|
|
86793
86060
|
// src/services/file-operations/manifest/manifest-tracker.ts
|
|
86794
|
-
import { join as
|
|
86061
|
+
import { join as join82 } from "node:path";
|
|
86795
86062
|
|
|
86796
86063
|
// src/domains/migration/release-manifest.ts
|
|
86797
86064
|
init_logger();
|
|
86798
86065
|
init_zod();
|
|
86799
86066
|
var import_fs_extra13 = __toESM(require_lib3(), 1);
|
|
86800
|
-
import { join as
|
|
86067
|
+
import { join as join80 } from "node:path";
|
|
86801
86068
|
var ReleaseManifestFileSchema = exports_external.object({
|
|
86802
86069
|
path: exports_external.string(),
|
|
86803
86070
|
checksum: exports_external.string().regex(/^[a-f0-9]{64}$/),
|
|
@@ -86812,7 +86079,7 @@ var ReleaseManifestSchema = exports_external.object({
|
|
|
86812
86079
|
|
|
86813
86080
|
class ReleaseManifestLoader {
|
|
86814
86081
|
static async load(extractDir) {
|
|
86815
|
-
const manifestPath =
|
|
86082
|
+
const manifestPath = join80(extractDir, "release-manifest.json");
|
|
86816
86083
|
try {
|
|
86817
86084
|
const content = await import_fs_extra13.readFile(manifestPath, "utf-8");
|
|
86818
86085
|
const parsed = JSON.parse(content);
|
|
@@ -86836,12 +86103,11 @@ init_safe_spinner();
|
|
|
86836
86103
|
init_metadata_migration();
|
|
86837
86104
|
init_logger();
|
|
86838
86105
|
init_types3();
|
|
86839
|
-
init_manifest_reader();
|
|
86840
86106
|
var import_fs_extra14 = __toESM(require_lib3(), 1);
|
|
86841
86107
|
var import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
|
|
86842
|
-
import { join as
|
|
86108
|
+
import { join as join81 } from "node:path";
|
|
86843
86109
|
async function writeManifest(claudeDir2, kitName, version, scope, kitType, trackedFiles, userConfigFiles) {
|
|
86844
|
-
const metadataPath =
|
|
86110
|
+
const metadataPath = join81(claudeDir2, "metadata.json");
|
|
86845
86111
|
const kit = kitType || (/\bmarketing\b/i.test(kitName) ? "marketing" : "engineer");
|
|
86846
86112
|
await import_fs_extra14.ensureFile(metadataPath);
|
|
86847
86113
|
let release = null;
|
|
@@ -86861,54 +86127,20 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
|
|
|
86861
86127
|
const content = await import_fs_extra14.readFile(metadataPath, "utf-8");
|
|
86862
86128
|
const parsed = JSON.parse(content);
|
|
86863
86129
|
if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
|
|
86864
|
-
|
|
86865
|
-
if (validatedExisting.success) {
|
|
86866
|
-
existingMetadata = validatedExisting.data;
|
|
86867
|
-
} else {
|
|
86868
|
-
logger.warning("Existing metadata.json is invalid; preserving recoverable fields and rebuilding the rest");
|
|
86869
|
-
const raw2 = parsed;
|
|
86870
|
-
const recoveredKits = {};
|
|
86871
|
-
if (raw2.kits && typeof raw2.kits === "object") {
|
|
86872
|
-
for (const [rawKitName, rawKitValue] of Object.entries(raw2.kits)) {
|
|
86873
|
-
if ((rawKitName === "engineer" || rawKitName === "marketing") && rawKitValue && typeof rawKitValue === "object") {
|
|
86874
|
-
const recoveredKit = rawKitValue;
|
|
86875
|
-
if (typeof recoveredKit.version === "string" && typeof recoveredKit.installedAt === "string") {
|
|
86876
|
-
recoveredKits[rawKitName] = recoveredKit;
|
|
86877
|
-
}
|
|
86878
|
-
}
|
|
86879
|
-
}
|
|
86880
|
-
}
|
|
86881
|
-
existingMetadata = {
|
|
86882
|
-
kits: recoveredKits,
|
|
86883
|
-
scope: raw2.scope === "local" || raw2.scope === "global" ? raw2.scope : undefined,
|
|
86884
|
-
name: typeof raw2.name === "string" ? raw2.name : undefined,
|
|
86885
|
-
version: typeof raw2.version === "string" ? raw2.version : undefined,
|
|
86886
|
-
installedAt: typeof raw2.installedAt === "string" ? raw2.installedAt : undefined,
|
|
86887
|
-
userConfigFiles: Array.isArray(raw2.userConfigFiles) ? raw2.userConfigFiles.filter((entry) => typeof entry === "string") : undefined
|
|
86888
|
-
};
|
|
86889
|
-
}
|
|
86130
|
+
existingMetadata = parsed;
|
|
86890
86131
|
}
|
|
86891
86132
|
} catch (error) {
|
|
86892
86133
|
logger.debug(`Could not read existing metadata: ${error}`);
|
|
86893
86134
|
}
|
|
86894
86135
|
}
|
|
86895
86136
|
const installedAt = new Date().toISOString();
|
|
86896
|
-
const existingKits = existingMetadata.kits || {};
|
|
86897
|
-
const existingKitMetadata = existingKits[kit];
|
|
86898
86137
|
const kitMetadata = {
|
|
86899
|
-
...existingKitMetadata,
|
|
86900
86138
|
version,
|
|
86901
86139
|
installedAt,
|
|
86902
86140
|
files: trackedFiles.length > 0 ? trackedFiles : undefined
|
|
86903
86141
|
};
|
|
86142
|
+
const existingKits = existingMetadata.kits || {};
|
|
86904
86143
|
const otherKitsExist = Object.keys(existingKits).some((k2) => k2 !== kit);
|
|
86905
|
-
const mergedUserConfigFiles = [
|
|
86906
|
-
...new Set([
|
|
86907
|
-
...existingMetadata.userConfigFiles || [],
|
|
86908
|
-
...USER_CONFIG_PATTERNS,
|
|
86909
|
-
...userConfigFiles
|
|
86910
|
-
])
|
|
86911
|
-
];
|
|
86912
86144
|
const metadata = {
|
|
86913
86145
|
kits: {
|
|
86914
86146
|
...existingKits,
|
|
@@ -86918,7 +86150,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
|
|
|
86918
86150
|
name: otherKitsExist ? existingMetadata.name ?? kitName : kitName,
|
|
86919
86151
|
version: otherKitsExist ? existingMetadata.version ?? version : version,
|
|
86920
86152
|
installedAt: otherKitsExist ? existingMetadata.installedAt ?? installedAt : installedAt,
|
|
86921
|
-
userConfigFiles:
|
|
86153
|
+
userConfigFiles: [...USER_CONFIG_PATTERNS, ...userConfigFiles]
|
|
86922
86154
|
};
|
|
86923
86155
|
const validated = MetadataSchema.parse(metadata);
|
|
86924
86156
|
await import_fs_extra14.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
|
|
@@ -86931,7 +86163,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
|
|
|
86931
86163
|
}
|
|
86932
86164
|
}
|
|
86933
86165
|
async function removeKitFromManifest(claudeDir2, kit) {
|
|
86934
|
-
const metadataPath =
|
|
86166
|
+
const metadataPath = join81(claudeDir2, "metadata.json");
|
|
86935
86167
|
if (!await import_fs_extra14.pathExists(metadataPath))
|
|
86936
86168
|
return false;
|
|
86937
86169
|
let release = null;
|
|
@@ -87061,7 +86293,7 @@ function buildFileTrackingList(options2) {
|
|
|
87061
86293
|
if (!isGlobal && !installedPath.startsWith(".claude/"))
|
|
87062
86294
|
continue;
|
|
87063
86295
|
const relativePath = isGlobal ? installedPath : installedPath.replace(/^\.claude\//, "");
|
|
87064
|
-
const filePath =
|
|
86296
|
+
const filePath = join82(claudeDir2, relativePath);
|
|
87065
86297
|
const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
|
|
87066
86298
|
const ownership = manifestEntry ? "ck" : "user";
|
|
87067
86299
|
filesToTrack.push({
|
|
@@ -87168,7 +86400,7 @@ class LegacyMigration {
|
|
|
87168
86400
|
continue;
|
|
87169
86401
|
if (SKIP_DIRS_ALL.includes(entry))
|
|
87170
86402
|
continue;
|
|
87171
|
-
const fullPath =
|
|
86403
|
+
const fullPath = join83(dir, entry);
|
|
87172
86404
|
let stats;
|
|
87173
86405
|
try {
|
|
87174
86406
|
stats = await stat14(fullPath);
|
|
@@ -87270,7 +86502,7 @@ User-created files (sample):`);
|
|
|
87270
86502
|
];
|
|
87271
86503
|
if (filesToChecksum.length > 0) {
|
|
87272
86504
|
const checksumResults = await mapWithLimit(filesToChecksum, async ({ relativePath, ownership }) => {
|
|
87273
|
-
const fullPath =
|
|
86505
|
+
const fullPath = join83(claudeDir2, relativePath);
|
|
87274
86506
|
const checksum = await OwnershipChecker.calculateChecksum(fullPath);
|
|
87275
86507
|
return { relativePath, checksum, ownership };
|
|
87276
86508
|
});
|
|
@@ -87291,7 +86523,7 @@ User-created files (sample):`);
|
|
|
87291
86523
|
installedAt: new Date().toISOString(),
|
|
87292
86524
|
files: trackedFiles
|
|
87293
86525
|
};
|
|
87294
|
-
const metadataPath =
|
|
86526
|
+
const metadataPath = join83(claudeDir2, "metadata.json");
|
|
87295
86527
|
await import_fs_extra15.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
|
|
87296
86528
|
logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
|
|
87297
86529
|
return true;
|
|
@@ -87397,7 +86629,7 @@ function buildConflictSummary(fileConflicts, hookConflicts, mcpConflicts) {
|
|
|
87397
86629
|
init_logger();
|
|
87398
86630
|
init_skip_directories();
|
|
87399
86631
|
var import_fs_extra16 = __toESM(require_lib3(), 1);
|
|
87400
|
-
import { join as
|
|
86632
|
+
import { join as join84, relative as relative14, resolve as resolve18 } from "node:path";
|
|
87401
86633
|
|
|
87402
86634
|
class FileScanner2 {
|
|
87403
86635
|
static async getFiles(dirPath, relativeTo) {
|
|
@@ -87413,7 +86645,7 @@ class FileScanner2 {
|
|
|
87413
86645
|
logger.debug(`Skipping directory: ${entry}`);
|
|
87414
86646
|
continue;
|
|
87415
86647
|
}
|
|
87416
|
-
const fullPath =
|
|
86648
|
+
const fullPath = join84(dirPath, entry);
|
|
87417
86649
|
if (!FileScanner2.isSafePath(basePath, fullPath)) {
|
|
87418
86650
|
logger.warning(`Skipping potentially unsafe path: ${entry}`);
|
|
87419
86651
|
continue;
|
|
@@ -87448,8 +86680,8 @@ class FileScanner2 {
|
|
|
87448
86680
|
return files;
|
|
87449
86681
|
}
|
|
87450
86682
|
static async findCustomFiles(destDir, sourceDir, subPath) {
|
|
87451
|
-
const destSubDir =
|
|
87452
|
-
const sourceSubDir =
|
|
86683
|
+
const destSubDir = join84(destDir, subPath);
|
|
86684
|
+
const sourceSubDir = join84(sourceDir, subPath);
|
|
87453
86685
|
logger.debug(`findCustomFiles - destDir: ${destDir}`);
|
|
87454
86686
|
logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
|
|
87455
86687
|
logger.debug(`findCustomFiles - subPath: "${subPath}"`);
|
|
@@ -87477,8 +86709,8 @@ class FileScanner2 {
|
|
|
87477
86709
|
return customFiles;
|
|
87478
86710
|
}
|
|
87479
86711
|
static isSafePath(basePath, targetPath) {
|
|
87480
|
-
const resolvedBase =
|
|
87481
|
-
const resolvedTarget =
|
|
86712
|
+
const resolvedBase = resolve18(basePath);
|
|
86713
|
+
const resolvedTarget = resolve18(targetPath);
|
|
87482
86714
|
return resolvedTarget.startsWith(resolvedBase);
|
|
87483
86715
|
}
|
|
87484
86716
|
static toPosixPath(path14) {
|
|
@@ -87490,12 +86722,12 @@ class FileScanner2 {
|
|
|
87490
86722
|
init_logger();
|
|
87491
86723
|
var import_fs_extra17 = __toESM(require_lib3(), 1);
|
|
87492
86724
|
import { lstat as lstat7, mkdir as mkdir27, readdir as readdir21, stat as stat15 } from "node:fs/promises";
|
|
87493
|
-
import { join as
|
|
86725
|
+
import { join as join86 } from "node:path";
|
|
87494
86726
|
|
|
87495
86727
|
// src/services/transformers/commands-prefix/content-transformer.ts
|
|
87496
86728
|
init_logger();
|
|
87497
86729
|
import { readFile as readFile42, readdir as readdir20, writeFile as writeFile26 } from "node:fs/promises";
|
|
87498
|
-
import { join as
|
|
86730
|
+
import { join as join85 } from "node:path";
|
|
87499
86731
|
var TRANSFORMABLE_EXTENSIONS = new Set([
|
|
87500
86732
|
".md",
|
|
87501
86733
|
".txt",
|
|
@@ -87556,7 +86788,7 @@ async function transformCommandReferences(directory, options2 = {}) {
|
|
|
87556
86788
|
async function processDirectory(dir) {
|
|
87557
86789
|
const entries = await readdir20(dir, { withFileTypes: true });
|
|
87558
86790
|
for (const entry of entries) {
|
|
87559
|
-
const fullPath =
|
|
86791
|
+
const fullPath = join85(dir, entry.name);
|
|
87560
86792
|
if (entry.isDirectory()) {
|
|
87561
86793
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
87562
86794
|
continue;
|
|
@@ -87631,14 +86863,14 @@ function shouldApplyPrefix(options2) {
|
|
|
87631
86863
|
// src/services/transformers/commands-prefix/prefix-applier.ts
|
|
87632
86864
|
async function applyPrefix(extractDir) {
|
|
87633
86865
|
validatePath(extractDir, "extractDir");
|
|
87634
|
-
const commandsDir =
|
|
86866
|
+
const commandsDir = join86(extractDir, ".claude", "commands");
|
|
87635
86867
|
if (!await import_fs_extra17.pathExists(commandsDir)) {
|
|
87636
86868
|
logger.verbose("No commands directory found, skipping prefix application");
|
|
87637
86869
|
return;
|
|
87638
86870
|
}
|
|
87639
86871
|
logger.info("Applying /ck: prefix to slash commands...");
|
|
87640
|
-
const backupDir =
|
|
87641
|
-
const tempDir =
|
|
86872
|
+
const backupDir = join86(extractDir, ".commands-backup");
|
|
86873
|
+
const tempDir = join86(extractDir, ".commands-prefix-temp");
|
|
87642
86874
|
try {
|
|
87643
86875
|
const entries = await readdir21(commandsDir);
|
|
87644
86876
|
if (entries.length === 0) {
|
|
@@ -87646,7 +86878,7 @@ async function applyPrefix(extractDir) {
|
|
|
87646
86878
|
return;
|
|
87647
86879
|
}
|
|
87648
86880
|
if (entries.length === 1 && entries[0] === "ck") {
|
|
87649
|
-
const ckDir2 =
|
|
86881
|
+
const ckDir2 = join86(commandsDir, "ck");
|
|
87650
86882
|
const ckStat = await stat15(ckDir2);
|
|
87651
86883
|
if (ckStat.isDirectory()) {
|
|
87652
86884
|
logger.verbose("Commands already have /ck: prefix, skipping");
|
|
@@ -87656,17 +86888,17 @@ async function applyPrefix(extractDir) {
|
|
|
87656
86888
|
await import_fs_extra17.copy(commandsDir, backupDir);
|
|
87657
86889
|
logger.verbose("Created backup of commands directory");
|
|
87658
86890
|
await mkdir27(tempDir, { recursive: true });
|
|
87659
|
-
const ckDir =
|
|
86891
|
+
const ckDir = join86(tempDir, "ck");
|
|
87660
86892
|
await mkdir27(ckDir, { recursive: true });
|
|
87661
86893
|
let processedCount = 0;
|
|
87662
86894
|
for (const entry of entries) {
|
|
87663
|
-
const sourcePath =
|
|
86895
|
+
const sourcePath = join86(commandsDir, entry);
|
|
87664
86896
|
const stats = await lstat7(sourcePath);
|
|
87665
86897
|
if (stats.isSymbolicLink()) {
|
|
87666
86898
|
logger.warning(`Skipping symlink for security: ${entry}`);
|
|
87667
86899
|
continue;
|
|
87668
86900
|
}
|
|
87669
|
-
const destPath =
|
|
86901
|
+
const destPath = join86(ckDir, entry);
|
|
87670
86902
|
await import_fs_extra17.copy(sourcePath, destPath, {
|
|
87671
86903
|
overwrite: false,
|
|
87672
86904
|
errorOnExist: true
|
|
@@ -87684,7 +86916,7 @@ async function applyPrefix(extractDir) {
|
|
|
87684
86916
|
await import_fs_extra17.move(tempDir, commandsDir);
|
|
87685
86917
|
await import_fs_extra17.remove(backupDir);
|
|
87686
86918
|
logger.success("Successfully reorganized commands to /ck: prefix");
|
|
87687
|
-
const claudeDir2 =
|
|
86919
|
+
const claudeDir2 = join86(extractDir, ".claude");
|
|
87688
86920
|
logger.info("Transforming command references in file contents...");
|
|
87689
86921
|
const transformResult = await transformCommandReferences(claudeDir2, {
|
|
87690
86922
|
verbose: logger.isVerbose()
|
|
@@ -87722,20 +86954,20 @@ async function applyPrefix(extractDir) {
|
|
|
87722
86954
|
// src/services/transformers/commands-prefix/prefix-cleaner.ts
|
|
87723
86955
|
init_metadata_migration();
|
|
87724
86956
|
import { lstat as lstat9, readdir as readdir23 } from "node:fs/promises";
|
|
87725
|
-
import { join as
|
|
86957
|
+
import { join as join88 } from "node:path";
|
|
87726
86958
|
init_logger();
|
|
87727
86959
|
var import_fs_extra19 = __toESM(require_lib3(), 1);
|
|
87728
86960
|
|
|
87729
86961
|
// src/services/transformers/commands-prefix/file-processor.ts
|
|
87730
86962
|
import { lstat as lstat8, readdir as readdir22 } from "node:fs/promises";
|
|
87731
|
-
import { join as
|
|
86963
|
+
import { join as join87 } from "node:path";
|
|
87732
86964
|
init_logger();
|
|
87733
86965
|
var import_fs_extra18 = __toESM(require_lib3(), 1);
|
|
87734
86966
|
async function scanDirectoryFiles(dir) {
|
|
87735
86967
|
const files = [];
|
|
87736
86968
|
const entries = await readdir22(dir);
|
|
87737
86969
|
for (const entry of entries) {
|
|
87738
|
-
const fullPath =
|
|
86970
|
+
const fullPath = join87(dir, entry);
|
|
87739
86971
|
const stats = await lstat8(fullPath);
|
|
87740
86972
|
if (stats.isSymbolicLink()) {
|
|
87741
86973
|
continue;
|
|
@@ -87863,8 +87095,8 @@ function isDifferentKitDirectory(dirName, currentKit) {
|
|
|
87863
87095
|
async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
|
|
87864
87096
|
const { dryRun = false } = options2;
|
|
87865
87097
|
validatePath(targetDir, "targetDir");
|
|
87866
|
-
const claudeDir2 = isGlobal ? targetDir :
|
|
87867
|
-
const commandsDir =
|
|
87098
|
+
const claudeDir2 = isGlobal ? targetDir : join88(targetDir, ".claude");
|
|
87099
|
+
const commandsDir = join88(claudeDir2, "commands");
|
|
87868
87100
|
const accumulator = {
|
|
87869
87101
|
results: [],
|
|
87870
87102
|
deletedCount: 0,
|
|
@@ -87906,7 +87138,7 @@ async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
|
|
|
87906
87138
|
}
|
|
87907
87139
|
const metadataForChecks = options2.kitType ? createKitSpecificMetadata(metadata, options2.kitType) : metadata;
|
|
87908
87140
|
for (const entry of entries) {
|
|
87909
|
-
const entryPath =
|
|
87141
|
+
const entryPath = join88(commandsDir, entry);
|
|
87910
87142
|
const stats = await lstat9(entryPath);
|
|
87911
87143
|
if (stats.isSymbolicLink()) {
|
|
87912
87144
|
addSymlinkSkip(entry, accumulator);
|
|
@@ -87963,7 +87195,7 @@ async function handleMerge(ctx) {
|
|
|
87963
87195
|
let customClaudeFiles = [];
|
|
87964
87196
|
if (!ctx.options.fresh) {
|
|
87965
87197
|
logger.info("Scanning for custom .claude files...");
|
|
87966
|
-
const scanSourceDir = ctx.options.global ?
|
|
87198
|
+
const scanSourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
|
|
87967
87199
|
const scanTargetSubdir = ctx.options.global ? "" : ".claude";
|
|
87968
87200
|
customClaudeFiles = await FileScanner2.findCustomFiles(ctx.resolvedDir, scanSourceDir, scanTargetSubdir);
|
|
87969
87201
|
} else {
|
|
@@ -88028,38 +87260,28 @@ async function handleMerge(ctx) {
|
|
|
88028
87260
|
return { ...ctx, cancelled: true };
|
|
88029
87261
|
}
|
|
88030
87262
|
}
|
|
88031
|
-
const sourceDir = ctx.options.global ?
|
|
87263
|
+
const sourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
|
|
88032
87264
|
await merger.merge(sourceDir, ctx.resolvedDir, ctx.isNonInteractive);
|
|
88033
87265
|
const fileConflicts = merger.getFileConflicts();
|
|
88034
87266
|
if (fileConflicts.length > 0 && !ctx.isNonInteractive) {
|
|
88035
87267
|
const summary = buildConflictSummary(fileConflicts, [], []);
|
|
88036
87268
|
displayConflictSummary(summary);
|
|
88037
87269
|
}
|
|
88038
|
-
let deferredDeletions = [];
|
|
88039
87270
|
try {
|
|
88040
|
-
const sourceMetadataPath = ctx.options.global ?
|
|
87271
|
+
const sourceMetadataPath = ctx.options.global ? join89(sourceDir, "metadata.json") : join89(sourceDir, ".claude", "metadata.json");
|
|
88041
87272
|
if (await import_fs_extra20.pathExists(sourceMetadataPath)) {
|
|
88042
87273
|
const metadataContent = await import_fs_extra20.readFile(sourceMetadataPath, "utf-8");
|
|
88043
87274
|
const sourceMetadata = JSON.parse(metadataContent);
|
|
88044
87275
|
if (sourceMetadata.deletions && sourceMetadata.deletions.length > 0) {
|
|
88045
|
-
const
|
|
88046
|
-
|
|
88047
|
-
|
|
88048
|
-
const
|
|
88049
|
-
|
|
88050
|
-
if (deletionResult.deletedPaths.length > 0) {
|
|
88051
|
-
logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
|
|
88052
|
-
for (const path14 of deletionResult.deletedPaths) {
|
|
88053
|
-
logger.verbose(` - ${path14}`);
|
|
88054
|
-
}
|
|
88055
|
-
}
|
|
88056
|
-
if (deletionResult.preservedPaths.length > 0) {
|
|
88057
|
-
logger.verbose(`Preserved ${deletionResult.preservedPaths.length} user-owned file(s)`);
|
|
87276
|
+
const deletionResult = await handleDeletions(sourceMetadata, ctx.claudeDir);
|
|
87277
|
+
if (deletionResult.deletedPaths.length > 0) {
|
|
87278
|
+
logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
|
|
87279
|
+
for (const path14 of deletionResult.deletedPaths) {
|
|
87280
|
+
logger.verbose(` - ${path14}`);
|
|
88058
87281
|
}
|
|
88059
87282
|
}
|
|
88060
|
-
if (
|
|
88061
|
-
|
|
88062
|
-
logger.debug(`Deferred ${categorized.deferred.length} skill deletion(s) to post-install phase`);
|
|
87283
|
+
if (deletionResult.preservedPaths.length > 0) {
|
|
87284
|
+
logger.verbose(`Preserved ${deletionResult.preservedPaths.length} user-owned file(s)`);
|
|
88063
87285
|
}
|
|
88064
87286
|
}
|
|
88065
87287
|
} else {
|
|
@@ -88086,12 +87308,11 @@ async function handleMerge(ctx) {
|
|
|
88086
87308
|
return {
|
|
88087
87309
|
...ctx,
|
|
88088
87310
|
customClaudeFiles,
|
|
88089
|
-
includePatterns
|
|
88090
|
-
deferredDeletions
|
|
87311
|
+
includePatterns
|
|
88091
87312
|
};
|
|
88092
87313
|
}
|
|
88093
87314
|
// src/commands/init/phases/migration-handler.ts
|
|
88094
|
-
import { join as
|
|
87315
|
+
import { join as join97 } from "node:path";
|
|
88095
87316
|
|
|
88096
87317
|
// src/domains/skills/skills-detector.ts
|
|
88097
87318
|
init_logger();
|
|
@@ -88107,7 +87328,7 @@ init_types3();
|
|
|
88107
87328
|
var import_fs_extra21 = __toESM(require_lib3(), 1);
|
|
88108
87329
|
import { createHash as createHash4 } from "node:crypto";
|
|
88109
87330
|
import { readFile as readFile44, readdir as readdir24, writeFile as writeFile27 } from "node:fs/promises";
|
|
88110
|
-
import { join as
|
|
87331
|
+
import { join as join90, relative as relative15 } from "node:path";
|
|
88111
87332
|
|
|
88112
87333
|
class SkillsManifestManager {
|
|
88113
87334
|
static MANIFEST_FILENAME = ".skills-manifest.json";
|
|
@@ -88129,12 +87350,12 @@ class SkillsManifestManager {
|
|
|
88129
87350
|
return manifest;
|
|
88130
87351
|
}
|
|
88131
87352
|
static async writeManifest(skillsDir2, manifest) {
|
|
88132
|
-
const manifestPath =
|
|
87353
|
+
const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
|
|
88133
87354
|
await writeFile27(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
88134
87355
|
logger.debug(`Wrote manifest to: ${manifestPath}`);
|
|
88135
87356
|
}
|
|
88136
87357
|
static async readManifest(skillsDir2) {
|
|
88137
|
-
const manifestPath =
|
|
87358
|
+
const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
|
|
88138
87359
|
if (!await import_fs_extra21.pathExists(manifestPath)) {
|
|
88139
87360
|
logger.debug(`No manifest found at: ${manifestPath}`);
|
|
88140
87361
|
return null;
|
|
@@ -88157,7 +87378,7 @@ class SkillsManifestManager {
|
|
|
88157
87378
|
return "flat";
|
|
88158
87379
|
}
|
|
88159
87380
|
for (const dir of dirs.slice(0, 3)) {
|
|
88160
|
-
const dirPath =
|
|
87381
|
+
const dirPath = join90(skillsDir2, dir.name);
|
|
88161
87382
|
const subEntries = await readdir24(dirPath, { withFileTypes: true });
|
|
88162
87383
|
const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
|
|
88163
87384
|
if (hasSubdirs) {
|
|
@@ -88176,7 +87397,7 @@ class SkillsManifestManager {
|
|
|
88176
87397
|
const entries = await readdir24(skillsDir2, { withFileTypes: true });
|
|
88177
87398
|
for (const entry of entries) {
|
|
88178
87399
|
if (entry.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
|
|
88179
|
-
const skillPath =
|
|
87400
|
+
const skillPath = join90(skillsDir2, entry.name);
|
|
88180
87401
|
const hash = await SkillsManifestManager.hashDirectory(skillPath);
|
|
88181
87402
|
skills.push({
|
|
88182
87403
|
name: entry.name,
|
|
@@ -88188,11 +87409,11 @@ class SkillsManifestManager {
|
|
|
88188
87409
|
const categories = await readdir24(skillsDir2, { withFileTypes: true });
|
|
88189
87410
|
for (const category of categories) {
|
|
88190
87411
|
if (category.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(category.name) && !category.name.startsWith(".")) {
|
|
88191
|
-
const categoryPath =
|
|
87412
|
+
const categoryPath = join90(skillsDir2, category.name);
|
|
88192
87413
|
const skillEntries = await readdir24(categoryPath, { withFileTypes: true });
|
|
88193
87414
|
for (const skillEntry of skillEntries) {
|
|
88194
87415
|
if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
|
|
88195
|
-
const skillPath =
|
|
87416
|
+
const skillPath = join90(categoryPath, skillEntry.name);
|
|
88196
87417
|
const hash = await SkillsManifestManager.hashDirectory(skillPath);
|
|
88197
87418
|
skills.push({
|
|
88198
87419
|
name: skillEntry.name,
|
|
@@ -88222,7 +87443,7 @@ class SkillsManifestManager {
|
|
|
88222
87443
|
const files = [];
|
|
88223
87444
|
const entries = await readdir24(dirPath, { withFileTypes: true });
|
|
88224
87445
|
for (const entry of entries) {
|
|
88225
|
-
const fullPath =
|
|
87446
|
+
const fullPath = join90(dirPath, entry.name);
|
|
88226
87447
|
if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name)) {
|
|
88227
87448
|
continue;
|
|
88228
87449
|
}
|
|
@@ -88344,7 +87565,7 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
|
|
|
88344
87565
|
// src/domains/skills/detection/script-detector.ts
|
|
88345
87566
|
var import_fs_extra22 = __toESM(require_lib3(), 1);
|
|
88346
87567
|
import { readdir as readdir25 } from "node:fs/promises";
|
|
88347
|
-
import { join as
|
|
87568
|
+
import { join as join91 } from "node:path";
|
|
88348
87569
|
async function scanDirectory(skillsDir2) {
|
|
88349
87570
|
if (!await import_fs_extra22.pathExists(skillsDir2)) {
|
|
88350
87571
|
return ["flat", []];
|
|
@@ -88357,12 +87578,12 @@ async function scanDirectory(skillsDir2) {
|
|
|
88357
87578
|
let totalSkillLikeCount = 0;
|
|
88358
87579
|
const allSkills = [];
|
|
88359
87580
|
for (const dir of dirs) {
|
|
88360
|
-
const dirPath =
|
|
87581
|
+
const dirPath = join91(skillsDir2, dir.name);
|
|
88361
87582
|
const subEntries = await readdir25(dirPath, { withFileTypes: true });
|
|
88362
87583
|
const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
|
|
88363
87584
|
if (subdirs.length > 0) {
|
|
88364
87585
|
for (const subdir of subdirs.slice(0, 3)) {
|
|
88365
|
-
const subdirPath =
|
|
87586
|
+
const subdirPath = join91(dirPath, subdir.name);
|
|
88366
87587
|
const subdirFiles = await readdir25(subdirPath, { withFileTypes: true });
|
|
88367
87588
|
const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
|
|
88368
87589
|
if (hasSkillMarker) {
|
|
@@ -88519,12 +87740,12 @@ class SkillsMigrationDetector {
|
|
|
88519
87740
|
// src/domains/skills/skills-migrator.ts
|
|
88520
87741
|
init_logger();
|
|
88521
87742
|
init_types3();
|
|
88522
|
-
import { join as
|
|
87743
|
+
import { join as join96 } from "node:path";
|
|
88523
87744
|
|
|
88524
87745
|
// src/domains/skills/migrator/migration-executor.ts
|
|
88525
87746
|
init_logger();
|
|
88526
87747
|
import { copyFile as copyFile6, mkdir as mkdir28, readdir as readdir26, rm as rm10 } from "node:fs/promises";
|
|
88527
|
-
import { join as
|
|
87748
|
+
import { join as join92 } from "node:path";
|
|
88528
87749
|
var import_fs_extra24 = __toESM(require_lib3(), 1);
|
|
88529
87750
|
|
|
88530
87751
|
// src/domains/skills/skills-migration-prompts.ts
|
|
@@ -88689,8 +87910,8 @@ async function copySkillDirectory(sourceDir, destDir) {
|
|
|
88689
87910
|
await mkdir28(destDir, { recursive: true });
|
|
88690
87911
|
const entries = await readdir26(sourceDir, { withFileTypes: true });
|
|
88691
87912
|
for (const entry of entries) {
|
|
88692
|
-
const sourcePath =
|
|
88693
|
-
const destPath =
|
|
87913
|
+
const sourcePath = join92(sourceDir, entry.name);
|
|
87914
|
+
const destPath = join92(destDir, entry.name);
|
|
88694
87915
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
88695
87916
|
continue;
|
|
88696
87917
|
}
|
|
@@ -88705,7 +87926,7 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
|
|
|
88705
87926
|
const migrated = [];
|
|
88706
87927
|
const preserved = [];
|
|
88707
87928
|
const errors2 = [];
|
|
88708
|
-
const tempDir =
|
|
87929
|
+
const tempDir = join92(currentSkillsDir, "..", ".skills-migration-temp");
|
|
88709
87930
|
await mkdir28(tempDir, { recursive: true });
|
|
88710
87931
|
try {
|
|
88711
87932
|
for (const mapping of mappings) {
|
|
@@ -88726,9 +87947,9 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
|
|
|
88726
87947
|
}
|
|
88727
87948
|
}
|
|
88728
87949
|
const category = mapping.category;
|
|
88729
|
-
const targetPath = category ?
|
|
87950
|
+
const targetPath = category ? join92(tempDir, category, skillName) : join92(tempDir, skillName);
|
|
88730
87951
|
if (category) {
|
|
88731
|
-
await mkdir28(
|
|
87952
|
+
await mkdir28(join92(tempDir, category), { recursive: true });
|
|
88732
87953
|
}
|
|
88733
87954
|
await copySkillDirectory(currentSkillPath, targetPath);
|
|
88734
87955
|
migrated.push(skillName);
|
|
@@ -88795,7 +88016,7 @@ init_logger();
|
|
|
88795
88016
|
init_types3();
|
|
88796
88017
|
var import_fs_extra25 = __toESM(require_lib3(), 1);
|
|
88797
88018
|
import { copyFile as copyFile7, mkdir as mkdir29, readdir as readdir27, rm as rm11, stat as stat16 } from "node:fs/promises";
|
|
88798
|
-
import { basename as basename10, join as
|
|
88019
|
+
import { basename as basename10, join as join93, normalize as normalize8 } from "node:path";
|
|
88799
88020
|
function validatePath2(path14, paramName) {
|
|
88800
88021
|
if (!path14 || typeof path14 !== "string") {
|
|
88801
88022
|
throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
|
|
@@ -88821,7 +88042,7 @@ class SkillsBackupManager {
|
|
|
88821
88042
|
const timestamp = Date.now();
|
|
88822
88043
|
const randomSuffix = Math.random().toString(36).substring(2, 8);
|
|
88823
88044
|
const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
|
|
88824
|
-
const backupDir = parentDir ?
|
|
88045
|
+
const backupDir = parentDir ? join93(parentDir, backupDirName) : join93(skillsDir2, "..", backupDirName);
|
|
88825
88046
|
logger.info(`Creating backup at: ${backupDir}`);
|
|
88826
88047
|
try {
|
|
88827
88048
|
await mkdir29(backupDir, { recursive: true });
|
|
@@ -88872,7 +88093,7 @@ class SkillsBackupManager {
|
|
|
88872
88093
|
}
|
|
88873
88094
|
try {
|
|
88874
88095
|
const entries = await readdir27(parentDir, { withFileTypes: true });
|
|
88875
|
-
const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) =>
|
|
88096
|
+
const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join93(parentDir, entry.name));
|
|
88876
88097
|
backups.sort().reverse();
|
|
88877
88098
|
return backups;
|
|
88878
88099
|
} catch (error) {
|
|
@@ -88900,8 +88121,8 @@ class SkillsBackupManager {
|
|
|
88900
88121
|
static async copyDirectory(sourceDir, destDir) {
|
|
88901
88122
|
const entries = await readdir27(sourceDir, { withFileTypes: true });
|
|
88902
88123
|
for (const entry of entries) {
|
|
88903
|
-
const sourcePath =
|
|
88904
|
-
const destPath =
|
|
88124
|
+
const sourcePath = join93(sourceDir, entry.name);
|
|
88125
|
+
const destPath = join93(destDir, entry.name);
|
|
88905
88126
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
88906
88127
|
continue;
|
|
88907
88128
|
}
|
|
@@ -88917,7 +88138,7 @@ class SkillsBackupManager {
|
|
|
88917
88138
|
let size = 0;
|
|
88918
88139
|
const entries = await readdir27(dirPath, { withFileTypes: true });
|
|
88919
88140
|
for (const entry of entries) {
|
|
88920
|
-
const fullPath =
|
|
88141
|
+
const fullPath = join93(dirPath, entry.name);
|
|
88921
88142
|
if (entry.isSymbolicLink()) {
|
|
88922
88143
|
continue;
|
|
88923
88144
|
}
|
|
@@ -88953,12 +88174,12 @@ init_skip_directories();
|
|
|
88953
88174
|
import { createHash as createHash5 } from "node:crypto";
|
|
88954
88175
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
88955
88176
|
import { readFile as readFile45, readdir as readdir28 } from "node:fs/promises";
|
|
88956
|
-
import { join as
|
|
88177
|
+
import { join as join94, relative as relative16 } from "node:path";
|
|
88957
88178
|
async function getAllFiles(dirPath) {
|
|
88958
88179
|
const files = [];
|
|
88959
88180
|
const entries = await readdir28(dirPath, { withFileTypes: true });
|
|
88960
88181
|
for (const entry of entries) {
|
|
88961
|
-
const fullPath =
|
|
88182
|
+
const fullPath = join94(dirPath, entry.name);
|
|
88962
88183
|
if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name) || entry.isSymbolicLink()) {
|
|
88963
88184
|
continue;
|
|
88964
88185
|
}
|
|
@@ -88972,12 +88193,12 @@ async function getAllFiles(dirPath) {
|
|
|
88972
88193
|
return files;
|
|
88973
88194
|
}
|
|
88974
88195
|
async function hashFile(filePath) {
|
|
88975
|
-
return new Promise((
|
|
88196
|
+
return new Promise((resolve19, reject) => {
|
|
88976
88197
|
const hash = createHash5("sha256");
|
|
88977
88198
|
const stream = createReadStream3(filePath);
|
|
88978
88199
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
88979
88200
|
stream.on("end", () => {
|
|
88980
|
-
|
|
88201
|
+
resolve19(hash.digest("hex"));
|
|
88981
88202
|
});
|
|
88982
88203
|
stream.on("error", (error) => {
|
|
88983
88204
|
stream.destroy();
|
|
@@ -89085,7 +88306,7 @@ async function detectFileChanges(currentSkillPath, baselineSkillPath) {
|
|
|
89085
88306
|
init_types3();
|
|
89086
88307
|
var import_fs_extra27 = __toESM(require_lib3(), 1);
|
|
89087
88308
|
import { readdir as readdir29 } from "node:fs/promises";
|
|
89088
|
-
import { join as
|
|
88309
|
+
import { join as join95, normalize as normalize9 } from "node:path";
|
|
89089
88310
|
function validatePath3(path14, paramName) {
|
|
89090
88311
|
if (!path14 || typeof path14 !== "string") {
|
|
89091
88312
|
throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
|
|
@@ -89106,13 +88327,13 @@ async function scanSkillsDirectory(skillsDir2) {
|
|
|
89106
88327
|
if (dirs.length === 0) {
|
|
89107
88328
|
return ["flat", []];
|
|
89108
88329
|
}
|
|
89109
|
-
const firstDirPath =
|
|
88330
|
+
const firstDirPath = join95(skillsDir2, dirs[0].name);
|
|
89110
88331
|
const subEntries = await readdir29(firstDirPath, { withFileTypes: true });
|
|
89111
88332
|
const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
|
|
89112
88333
|
if (subdirs.length > 0) {
|
|
89113
88334
|
let skillLikeCount = 0;
|
|
89114
88335
|
for (const subdir of subdirs.slice(0, 3)) {
|
|
89115
|
-
const subdirPath =
|
|
88336
|
+
const subdirPath = join95(firstDirPath, subdir.name);
|
|
89116
88337
|
const subdirFiles = await readdir29(subdirPath, { withFileTypes: true });
|
|
89117
88338
|
const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
|
|
89118
88339
|
if (hasSkillMarker) {
|
|
@@ -89122,7 +88343,7 @@ async function scanSkillsDirectory(skillsDir2) {
|
|
|
89122
88343
|
if (skillLikeCount > 0) {
|
|
89123
88344
|
const skills = [];
|
|
89124
88345
|
for (const dir of dirs) {
|
|
89125
|
-
const categoryPath =
|
|
88346
|
+
const categoryPath = join95(skillsDir2, dir.name);
|
|
89126
88347
|
const skillDirs = await readdir29(categoryPath, { withFileTypes: true });
|
|
89127
88348
|
skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
|
|
89128
88349
|
}
|
|
@@ -89132,7 +88353,7 @@ async function scanSkillsDirectory(skillsDir2) {
|
|
|
89132
88353
|
return ["flat", dirs.map((dir) => dir.name)];
|
|
89133
88354
|
}
|
|
89134
88355
|
async function findSkillPath(skillsDir2, skillName) {
|
|
89135
|
-
const flatPath =
|
|
88356
|
+
const flatPath = join95(skillsDir2, skillName);
|
|
89136
88357
|
if (await import_fs_extra27.pathExists(flatPath)) {
|
|
89137
88358
|
return { path: flatPath, category: undefined };
|
|
89138
88359
|
}
|
|
@@ -89141,8 +88362,8 @@ async function findSkillPath(skillsDir2, skillName) {
|
|
|
89141
88362
|
if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
89142
88363
|
continue;
|
|
89143
88364
|
}
|
|
89144
|
-
const categoryPath =
|
|
89145
|
-
const skillPath =
|
|
88365
|
+
const categoryPath = join95(skillsDir2, entry.name);
|
|
88366
|
+
const skillPath = join95(categoryPath, skillName);
|
|
89146
88367
|
if (await import_fs_extra27.pathExists(skillPath)) {
|
|
89147
88368
|
return { path: skillPath, category: entry.name };
|
|
89148
88369
|
}
|
|
@@ -89236,7 +88457,7 @@ class SkillsMigrator {
|
|
|
89236
88457
|
}
|
|
89237
88458
|
}
|
|
89238
88459
|
if (options2.backup && !options2.dryRun) {
|
|
89239
|
-
const claudeDir2 =
|
|
88460
|
+
const claudeDir2 = join96(currentSkillsDir, "..");
|
|
89240
88461
|
result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir2);
|
|
89241
88462
|
logger.success(`Backup created at: ${result.backupPath}`);
|
|
89242
88463
|
}
|
|
@@ -89297,7 +88518,7 @@ async function handleMigration(ctx) {
|
|
|
89297
88518
|
logger.debug("Skipping skills migration (fresh installation)");
|
|
89298
88519
|
return ctx;
|
|
89299
88520
|
}
|
|
89300
|
-
const newSkillsDir =
|
|
88521
|
+
const newSkillsDir = join97(ctx.extractDir, ".claude", "skills");
|
|
89301
88522
|
const currentSkillsDir = PathResolver.buildSkillsPath(ctx.resolvedDir, ctx.options.global);
|
|
89302
88523
|
if (!await import_fs_extra28.pathExists(newSkillsDir) || !await import_fs_extra28.pathExists(currentSkillsDir)) {
|
|
89303
88524
|
return ctx;
|
|
@@ -89321,13 +88542,13 @@ async function handleMigration(ctx) {
|
|
|
89321
88542
|
}
|
|
89322
88543
|
// src/commands/init/phases/opencode-handler.ts
|
|
89323
88544
|
import { cp as cp3, readdir as readdir31, rm as rm12 } from "node:fs/promises";
|
|
89324
|
-
import { join as
|
|
88545
|
+
import { join as join99 } from "node:path";
|
|
89325
88546
|
|
|
89326
88547
|
// src/services/transformers/opencode-path-transformer.ts
|
|
89327
88548
|
init_logger();
|
|
89328
88549
|
import { readFile as readFile46, readdir as readdir30, writeFile as writeFile28 } from "node:fs/promises";
|
|
89329
88550
|
import { platform as platform12 } from "node:os";
|
|
89330
|
-
import { extname as extname5, join as
|
|
88551
|
+
import { extname as extname5, join as join98 } from "node:path";
|
|
89331
88552
|
var IS_WINDOWS2 = platform12() === "win32";
|
|
89332
88553
|
function getOpenCodeGlobalPath() {
|
|
89333
88554
|
return "$HOME/.config/opencode/";
|
|
@@ -89388,7 +88609,7 @@ async function transformPathsForGlobalOpenCode(directory, options2 = {}) {
|
|
|
89388
88609
|
async function processDirectory2(dir) {
|
|
89389
88610
|
const entries = await readdir30(dir, { withFileTypes: true });
|
|
89390
88611
|
for (const entry of entries) {
|
|
89391
|
-
const fullPath =
|
|
88612
|
+
const fullPath = join98(dir, entry.name);
|
|
89392
88613
|
if (entry.isDirectory()) {
|
|
89393
88614
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
89394
88615
|
continue;
|
|
@@ -89427,7 +88648,7 @@ async function handleOpenCode(ctx) {
|
|
|
89427
88648
|
if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir) {
|
|
89428
88649
|
return ctx;
|
|
89429
88650
|
}
|
|
89430
|
-
const openCodeSource =
|
|
88651
|
+
const openCodeSource = join99(ctx.extractDir, ".opencode");
|
|
89431
88652
|
if (!await import_fs_extra29.pathExists(openCodeSource)) {
|
|
89432
88653
|
logger.debug("No .opencode directory in archive, skipping");
|
|
89433
88654
|
return ctx;
|
|
@@ -89445,8 +88666,8 @@ async function handleOpenCode(ctx) {
|
|
|
89445
88666
|
await import_fs_extra29.ensureDir(targetDir);
|
|
89446
88667
|
const entries = await readdir31(openCodeSource, { withFileTypes: true });
|
|
89447
88668
|
for (const entry of entries) {
|
|
89448
|
-
const sourcePath =
|
|
89449
|
-
const targetPath =
|
|
88669
|
+
const sourcePath = join99(openCodeSource, entry.name);
|
|
88670
|
+
const targetPath = join99(targetDir, entry.name);
|
|
89450
88671
|
if (await import_fs_extra29.pathExists(targetPath)) {
|
|
89451
88672
|
if (!ctx.options.forceOverwrite) {
|
|
89452
88673
|
logger.verbose(`Skipping existing: ${entry.name}`);
|
|
@@ -89543,21 +88764,20 @@ Please use only one download method.`);
|
|
|
89543
88764
|
}
|
|
89544
88765
|
// src/commands/init/phases/post-install-handler.ts
|
|
89545
88766
|
init_projects_registry();
|
|
89546
|
-
import { join as
|
|
89547
|
-
init_cc_version_checker();
|
|
88767
|
+
import { join as join100 } from "node:path";
|
|
89548
88768
|
init_logger();
|
|
89549
88769
|
init_path_resolver();
|
|
89550
|
-
var
|
|
88770
|
+
var import_fs_extra30 = __toESM(require_lib3(), 1);
|
|
89551
88771
|
async function handlePostInstall(ctx) {
|
|
89552
88772
|
if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir || !ctx.claudeDir) {
|
|
89553
88773
|
return ctx;
|
|
89554
88774
|
}
|
|
89555
88775
|
if (ctx.options.global) {
|
|
89556
|
-
const claudeMdSource =
|
|
89557
|
-
const claudeMdDest =
|
|
89558
|
-
if (await
|
|
89559
|
-
if (ctx.options.fresh || !await
|
|
89560
|
-
await
|
|
88776
|
+
const claudeMdSource = join100(ctx.extractDir, "CLAUDE.md");
|
|
88777
|
+
const claudeMdDest = join100(ctx.resolvedDir, "CLAUDE.md");
|
|
88778
|
+
if (await import_fs_extra30.pathExists(claudeMdSource)) {
|
|
88779
|
+
if (ctx.options.fresh || !await import_fs_extra30.pathExists(claudeMdDest)) {
|
|
88780
|
+
await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
|
|
89561
88781
|
logger.success(ctx.options.fresh ? "Replaced CLAUDE.md in global directory (fresh install)" : "Copied CLAUDE.md to global directory");
|
|
89562
88782
|
} else {
|
|
89563
88783
|
logger.debug("CLAUDE.md already exists in global directory (preserved)");
|
|
@@ -89576,90 +88796,6 @@ async function handlePostInstall(ctx) {
|
|
|
89576
88796
|
withSudo: ctx.options.withSudo
|
|
89577
88797
|
});
|
|
89578
88798
|
}
|
|
89579
|
-
let pluginSupported = false;
|
|
89580
|
-
try {
|
|
89581
|
-
const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
|
|
89582
|
-
await requireCCPluginSupport2();
|
|
89583
|
-
pluginSupported = true;
|
|
89584
|
-
} catch (error) {
|
|
89585
|
-
if (error instanceof CCPluginSupportError) {
|
|
89586
|
-
logger.info(`Plugin install skipped: ${error.message}`);
|
|
89587
|
-
if (error.code === "cc_version_too_old") {
|
|
89588
|
-
logger.info("Upgrade: brew upgrade claude-code (or npm i -g @anthropic-ai/claude-code)");
|
|
89589
|
-
}
|
|
89590
|
-
if (error.code === "cc_not_found") {
|
|
89591
|
-
logger.info("Install Claude Code CLI, then re-run ck init to enable /ck:* plugin skills");
|
|
89592
|
-
}
|
|
89593
|
-
} else {
|
|
89594
|
-
logger.info(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
89595
|
-
}
|
|
89596
|
-
}
|
|
89597
|
-
let pluginVerified = false;
|
|
89598
|
-
if (pluginSupported) {
|
|
89599
|
-
try {
|
|
89600
|
-
const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
|
|
89601
|
-
const pluginResult = await handlePluginInstall2(ctx.extractDir);
|
|
89602
|
-
pluginVerified = pluginResult.verified;
|
|
89603
|
-
if (pluginResult.error) {
|
|
89604
|
-
logger.info(`Plugin install issue: ${pluginResult.error}`);
|
|
89605
|
-
}
|
|
89606
|
-
} catch (error) {
|
|
89607
|
-
logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
89608
|
-
}
|
|
89609
|
-
}
|
|
89610
|
-
if (ctx.claudeDir && ctx.kitType) {
|
|
89611
|
-
try {
|
|
89612
|
-
const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
|
|
89613
|
-
await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
|
|
89614
|
-
pluginInstalled: pluginVerified,
|
|
89615
|
-
pluginInstalledAt: new Date().toISOString(),
|
|
89616
|
-
pluginVersion: ctx.selectedVersion || "unknown"
|
|
89617
|
-
});
|
|
89618
|
-
} catch {}
|
|
89619
|
-
}
|
|
89620
|
-
if (ctx.deferredDeletions?.length && ctx.claudeDir) {
|
|
89621
|
-
try {
|
|
89622
|
-
const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
|
|
89623
|
-
const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
|
|
89624
|
-
if (pluginVerified) {
|
|
89625
|
-
if (!migration.canDelete) {
|
|
89626
|
-
logger.warning("Skill migration metadata unavailable — preserving existing skills (fail-safe)");
|
|
89627
|
-
return { ...ctx, installSkills, pluginSupported };
|
|
89628
|
-
}
|
|
89629
|
-
const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir));
|
|
89630
|
-
const safeDeletions = ctx.deferredDeletions.filter((d3) => {
|
|
89631
|
-
const dirPath = extractSkillDirFromDeletionPath(d3);
|
|
89632
|
-
if (!dirPath)
|
|
89633
|
-
return true;
|
|
89634
|
-
return !preservedDirs.has(normalizeSkillDir(dirPath));
|
|
89635
|
-
});
|
|
89636
|
-
if (safeDeletions.length > 0) {
|
|
89637
|
-
const { handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
|
|
89638
|
-
const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
|
|
89639
|
-
if (deferredResult.deletedPaths.length > 0) {
|
|
89640
|
-
logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) (replaced by plugin)`);
|
|
89641
|
-
}
|
|
89642
|
-
}
|
|
89643
|
-
} else {
|
|
89644
|
-
logger.info("Plugin not verified — keeping existing skills as fallback");
|
|
89645
|
-
}
|
|
89646
|
-
} catch (error) {
|
|
89647
|
-
logger.debug(`Deferred skill deletion failed: ${error}`);
|
|
89648
|
-
}
|
|
89649
|
-
}
|
|
89650
|
-
if (pluginVerified) {
|
|
89651
|
-
try {
|
|
89652
|
-
const { cleanupOverlappingStandaloneSkills: cleanupOverlappingStandaloneSkills2 } = await Promise.resolve().then(() => (init_standalone_skill_cleanup(), exports_standalone_skill_cleanup));
|
|
89653
|
-
const globalClaudeDir = PathResolver.getGlobalKitDir();
|
|
89654
|
-
const pluginSkillsDir = join102(PathResolver.getClaudeKitDir(), "marketplace", "plugins", "ck", "skills");
|
|
89655
|
-
const overlap = await cleanupOverlappingStandaloneSkills2(globalClaudeDir, pluginSkillsDir);
|
|
89656
|
-
if (overlap.removed.length > 0) {
|
|
89657
|
-
logger.info(`Cleaned up ${overlap.removed.length} standalone skill(s) now provided by /ck:* plugin`);
|
|
89658
|
-
}
|
|
89659
|
-
} catch (error) {
|
|
89660
|
-
logger.info(`Standalone skill cleanup failed: ${error}`);
|
|
89661
|
-
}
|
|
89662
|
-
}
|
|
89663
88799
|
if (!ctx.isNonInteractive) {
|
|
89664
88800
|
const { isGeminiInstalled: isGeminiInstalled2 } = await Promise.resolve().then(() => (init_package_installer(), exports_package_installer));
|
|
89665
88801
|
const { checkExistingGeminiConfig: checkExistingGeminiConfig2, findMcpConfigPath: findMcpConfigPath2, processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
|
|
@@ -89686,7 +88822,7 @@ async function handlePostInstall(ctx) {
|
|
|
89686
88822
|
}
|
|
89687
88823
|
if (!ctx.options.skipSetup) {
|
|
89688
88824
|
await promptSetupWizardIfNeeded({
|
|
89689
|
-
envPath:
|
|
88825
|
+
envPath: join100(ctx.claudeDir, ".env"),
|
|
89690
88826
|
claudeDir: ctx.claudeDir,
|
|
89691
88827
|
isGlobal: ctx.options.global,
|
|
89692
88828
|
isNonInteractive: ctx.isNonInteractive,
|
|
@@ -89703,26 +88839,14 @@ async function handlePostInstall(ctx) {
|
|
|
89703
88839
|
}
|
|
89704
88840
|
return {
|
|
89705
88841
|
...ctx,
|
|
89706
|
-
installSkills
|
|
89707
|
-
pluginSupported
|
|
88842
|
+
installSkills
|
|
89708
88843
|
};
|
|
89709
88844
|
}
|
|
89710
|
-
function normalizeSkillDir(path14) {
|
|
89711
|
-
return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
89712
|
-
}
|
|
89713
|
-
function extractSkillDirFromDeletionPath(path14) {
|
|
89714
|
-
const normalized = normalizeSkillDir(path14);
|
|
89715
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
89716
|
-
if (parts.length < 2 || parts[0] !== "skills") {
|
|
89717
|
-
return null;
|
|
89718
|
-
}
|
|
89719
|
-
return `skills/${parts[1]}`;
|
|
89720
|
-
}
|
|
89721
88845
|
// src/commands/init/phases/selection-handler.ts
|
|
89722
88846
|
init_config_manager();
|
|
89723
88847
|
init_github_client();
|
|
89724
88848
|
import { mkdir as mkdir30 } from "node:fs/promises";
|
|
89725
|
-
import { join as
|
|
88849
|
+
import { join as join102, resolve as resolve20 } from "node:path";
|
|
89726
88850
|
|
|
89727
88851
|
// src/domains/github/kit-access-checker.ts
|
|
89728
88852
|
init_logger();
|
|
@@ -89754,8 +88878,8 @@ async function detectAccessibleKits() {
|
|
|
89754
88878
|
// src/domains/github/preflight-checker.ts
|
|
89755
88879
|
init_logger();
|
|
89756
88880
|
import { exec as exec8 } from "node:child_process";
|
|
89757
|
-
import { promisify as
|
|
89758
|
-
var execAsync8 =
|
|
88881
|
+
import { promisify as promisify14 } from "node:util";
|
|
88882
|
+
var execAsync8 = promisify14(exec8);
|
|
89759
88883
|
function createSuccessfulPreflightResult() {
|
|
89760
88884
|
return {
|
|
89761
88885
|
success: true,
|
|
@@ -89852,12 +88976,11 @@ async function runPreflightChecks() {
|
|
|
89852
88976
|
|
|
89853
88977
|
// src/domains/installation/fresh-installer.ts
|
|
89854
88978
|
init_metadata_migration();
|
|
89855
|
-
|
|
88979
|
+
import { existsSync as existsSync50, readdirSync as readdirSync4, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4 } from "node:fs";
|
|
88980
|
+
import { dirname as dirname21, join as join101, resolve as resolve19 } from "node:path";
|
|
89856
88981
|
init_logger();
|
|
89857
88982
|
init_safe_spinner();
|
|
89858
|
-
var
|
|
89859
|
-
import { existsSync as existsSync50, readdirSync as readdirSync4, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4 } from "node:fs";
|
|
89860
|
-
import { dirname as dirname22, join as join103, resolve as resolve20 } from "node:path";
|
|
88983
|
+
var import_fs_extra31 = __toESM(require_lib3(), 1);
|
|
89861
88984
|
var CLAUDEKIT_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
|
|
89862
88985
|
async function analyzeFreshInstallation(claudeDir2) {
|
|
89863
88986
|
const metadata = await readManifest(claudeDir2);
|
|
@@ -89902,15 +89025,15 @@ async function analyzeFreshInstallation(claudeDir2) {
|
|
|
89902
89025
|
};
|
|
89903
89026
|
}
|
|
89904
89027
|
function cleanupEmptyDirectories2(filePath, claudeDir2) {
|
|
89905
|
-
const normalizedClaudeDir =
|
|
89906
|
-
let currentDir =
|
|
89028
|
+
const normalizedClaudeDir = resolve19(claudeDir2);
|
|
89029
|
+
let currentDir = resolve19(dirname21(filePath));
|
|
89907
89030
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
89908
89031
|
try {
|
|
89909
89032
|
const entries = readdirSync4(currentDir);
|
|
89910
89033
|
if (entries.length === 0) {
|
|
89911
89034
|
rmdirSync2(currentDir);
|
|
89912
89035
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
89913
|
-
currentDir =
|
|
89036
|
+
currentDir = resolve19(dirname21(currentDir));
|
|
89914
89037
|
} else {
|
|
89915
89038
|
break;
|
|
89916
89039
|
}
|
|
@@ -89927,7 +89050,7 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
|
|
|
89927
89050
|
const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
|
|
89928
89051
|
const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
|
|
89929
89052
|
for (const file of filesToRemove) {
|
|
89930
|
-
const fullPath =
|
|
89053
|
+
const fullPath = join101(claudeDir2, file.path);
|
|
89931
89054
|
try {
|
|
89932
89055
|
if (existsSync50(fullPath)) {
|
|
89933
89056
|
unlinkSync4(fullPath);
|
|
@@ -89952,13 +89075,13 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
|
|
|
89952
89075
|
};
|
|
89953
89076
|
}
|
|
89954
89077
|
async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
|
|
89955
|
-
const metadataPath =
|
|
89956
|
-
if (!await
|
|
89078
|
+
const metadataPath = join101(claudeDir2, "metadata.json");
|
|
89079
|
+
if (!await import_fs_extra31.pathExists(metadataPath)) {
|
|
89957
89080
|
return;
|
|
89958
89081
|
}
|
|
89959
89082
|
let content;
|
|
89960
89083
|
try {
|
|
89961
|
-
content = await
|
|
89084
|
+
content = await import_fs_extra31.readFile(metadataPath, "utf-8");
|
|
89962
89085
|
} catch (readError) {
|
|
89963
89086
|
logger.warning(`Failed to read metadata.json: ${readError instanceof Error ? readError.message : String(readError)}`);
|
|
89964
89087
|
return;
|
|
@@ -89984,7 +89107,7 @@ async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
|
|
|
89984
89107
|
metadata.files = metadata.files.filter((f3) => !removedSet.has(f3.path));
|
|
89985
89108
|
}
|
|
89986
89109
|
try {
|
|
89987
|
-
await
|
|
89110
|
+
await import_fs_extra31.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
89988
89111
|
logger.debug(`Updated metadata.json, removed ${removedFiles.length} file entries`);
|
|
89989
89112
|
} catch (writeError) {
|
|
89990
89113
|
logger.warning(`Failed to write metadata.json: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -89995,16 +89118,16 @@ async function removeSubdirectoriesFallback(claudeDir2) {
|
|
|
89995
89118
|
const removedFiles = [];
|
|
89996
89119
|
let removedDirCount = 0;
|
|
89997
89120
|
for (const subdir of CLAUDEKIT_SUBDIRECTORIES) {
|
|
89998
|
-
const subdirPath =
|
|
89999
|
-
if (await
|
|
89121
|
+
const subdirPath = join101(claudeDir2, subdir);
|
|
89122
|
+
if (await import_fs_extra31.pathExists(subdirPath)) {
|
|
90000
89123
|
rmSync3(subdirPath, { recursive: true, force: true });
|
|
90001
89124
|
removedDirCount++;
|
|
90002
89125
|
removedFiles.push(`${subdir}/ (entire directory)`);
|
|
90003
89126
|
logger.debug(`Removed subdirectory: ${subdir}/`);
|
|
90004
89127
|
}
|
|
90005
89128
|
}
|
|
90006
|
-
const metadataPath =
|
|
90007
|
-
if (await
|
|
89129
|
+
const metadataPath = join101(claudeDir2, "metadata.json");
|
|
89130
|
+
if (await import_fs_extra31.pathExists(metadataPath)) {
|
|
90008
89131
|
unlinkSync4(metadataPath);
|
|
90009
89132
|
removedFiles.push("metadata.json");
|
|
90010
89133
|
}
|
|
@@ -90017,7 +89140,7 @@ async function removeSubdirectoriesFallback(claudeDir2) {
|
|
|
90017
89140
|
};
|
|
90018
89141
|
}
|
|
90019
89142
|
async function handleFreshInstallation(claudeDir2, prompts) {
|
|
90020
|
-
if (!await
|
|
89143
|
+
if (!await import_fs_extra31.pathExists(claudeDir2)) {
|
|
90021
89144
|
logger.info(".claude directory does not exist, proceeding with fresh installation");
|
|
90022
89145
|
return true;
|
|
90023
89146
|
}
|
|
@@ -90049,11 +89172,10 @@ async function handleFreshInstallation(claudeDir2, prompts) {
|
|
|
90049
89172
|
|
|
90050
89173
|
// src/commands/init/phases/selection-handler.ts
|
|
90051
89174
|
init_claudekit_scanner();
|
|
90052
|
-
init_manifest_reader();
|
|
90053
89175
|
init_logger();
|
|
90054
89176
|
init_path_resolver();
|
|
90055
89177
|
init_types3();
|
|
90056
|
-
var
|
|
89178
|
+
var import_fs_extra32 = __toESM(require_lib3(), 1);
|
|
90057
89179
|
|
|
90058
89180
|
// src/commands/init/types.ts
|
|
90059
89181
|
function isSyncContext(ctx) {
|
|
@@ -90222,7 +89344,7 @@ async function handleSelection(ctx) {
|
|
|
90222
89344
|
}
|
|
90223
89345
|
}
|
|
90224
89346
|
}
|
|
90225
|
-
const resolvedDir =
|
|
89347
|
+
const resolvedDir = resolve20(targetDir);
|
|
90226
89348
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
90227
89349
|
if (!ctx.options.global && PathResolver.isLocalSameAsGlobal(resolvedDir)) {
|
|
90228
89350
|
logger.warning("You're at HOME directory. Installing here modifies your GLOBAL ClaudeKit.");
|
|
@@ -90244,7 +89366,7 @@ async function handleSelection(ctx) {
|
|
|
90244
89366
|
return { ...ctx, cancelled: true };
|
|
90245
89367
|
}
|
|
90246
89368
|
}
|
|
90247
|
-
if (!await
|
|
89369
|
+
if (!await import_fs_extra32.pathExists(resolvedDir)) {
|
|
90248
89370
|
if (ctx.options.global) {
|
|
90249
89371
|
await mkdir30(resolvedDir, { recursive: true });
|
|
90250
89372
|
logger.info(`Created global directory: ${resolvedDir}`);
|
|
@@ -90256,7 +89378,7 @@ async function handleSelection(ctx) {
|
|
|
90256
89378
|
}
|
|
90257
89379
|
if (!ctx.options.fresh) {
|
|
90258
89380
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
90259
|
-
const claudeDir2 = prefix ?
|
|
89381
|
+
const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
|
|
90260
89382
|
try {
|
|
90261
89383
|
const existingMetadata = await readManifest(claudeDir2);
|
|
90262
89384
|
if (existingMetadata?.kits) {
|
|
@@ -90288,7 +89410,7 @@ async function handleSelection(ctx) {
|
|
|
90288
89410
|
}
|
|
90289
89411
|
if (ctx.options.fresh) {
|
|
90290
89412
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
90291
|
-
const claudeDir2 = prefix ?
|
|
89413
|
+
const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
|
|
90292
89414
|
const canProceed = await handleFreshInstallation(claudeDir2, ctx.prompts);
|
|
90293
89415
|
if (!canProceed) {
|
|
90294
89416
|
return { ...ctx, cancelled: true };
|
|
@@ -90307,7 +89429,7 @@ async function handleSelection(ctx) {
|
|
|
90307
89429
|
logger.info("Fetching available versions...");
|
|
90308
89430
|
let currentVersion = null;
|
|
90309
89431
|
try {
|
|
90310
|
-
const metadataPath = ctx.options.global ?
|
|
89432
|
+
const metadataPath = ctx.options.global ? join102(PathResolver.getGlobalKitDir(), "metadata.json") : join102(resolvedDir, ".claude", "metadata.json");
|
|
90311
89433
|
const metadata = await readClaudeKitMetadata(metadataPath);
|
|
90312
89434
|
currentVersion = metadata?.version || null;
|
|
90313
89435
|
if (currentVersion) {
|
|
@@ -90381,27 +89503,25 @@ async function handleSelection(ctx) {
|
|
|
90381
89503
|
};
|
|
90382
89504
|
}
|
|
90383
89505
|
// src/commands/init/phases/sync-handler.ts
|
|
90384
|
-
import { copyFile as copyFile8, mkdir as mkdir31, open as open4, readFile as
|
|
90385
|
-
import { dirname as
|
|
90386
|
-
init_cc_version_checker();
|
|
90387
|
-
init_manifest_reader();
|
|
89506
|
+
import { copyFile as copyFile8, mkdir as mkdir31, open as open4, readFile as readFile48, rename as rename6, stat as stat17, unlink as unlink11, writeFile as writeFile30 } from "node:fs/promises";
|
|
89507
|
+
import { dirname as dirname22, join as join103, resolve as resolve21 } from "node:path";
|
|
90388
89508
|
init_logger();
|
|
90389
89509
|
init_path_resolver();
|
|
90390
|
-
var
|
|
89510
|
+
var import_fs_extra33 = __toESM(require_lib3(), 1);
|
|
90391
89511
|
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
90392
89512
|
async function handleSync(ctx) {
|
|
90393
89513
|
if (!ctx.options.sync) {
|
|
90394
89514
|
return ctx;
|
|
90395
89515
|
}
|
|
90396
|
-
const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() :
|
|
90397
|
-
const claudeDir2 = ctx.options.global ? resolvedDir :
|
|
90398
|
-
if (!await
|
|
89516
|
+
const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() : resolve21(ctx.options.dir || ".");
|
|
89517
|
+
const claudeDir2 = ctx.options.global ? resolvedDir : join103(resolvedDir, ".claude");
|
|
89518
|
+
if (!await import_fs_extra33.pathExists(claudeDir2)) {
|
|
90399
89519
|
logger.error("Cannot sync: no .claude directory found");
|
|
90400
89520
|
ctx.prompts.note("Run 'ck init' without --sync to install first.", "No Installation Found");
|
|
90401
89521
|
return { ...ctx, cancelled: true };
|
|
90402
89522
|
}
|
|
90403
|
-
const metadataPath =
|
|
90404
|
-
if (!await
|
|
89523
|
+
const metadataPath = join103(claudeDir2, "metadata.json");
|
|
89524
|
+
if (!await import_fs_extra33.pathExists(metadataPath)) {
|
|
90405
89525
|
logger.error("Cannot sync: no metadata.json found");
|
|
90406
89526
|
ctx.prompts.note(`Your installation may be from an older version.
|
|
90407
89527
|
Run 'ck init' to update.`, "Legacy Installation");
|
|
@@ -90498,42 +89618,17 @@ function getLockTimeout() {
|
|
|
90498
89618
|
return timeoutMs;
|
|
90499
89619
|
}
|
|
90500
89620
|
var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
|
|
90501
|
-
function isProcessAlive(pid) {
|
|
90502
|
-
try {
|
|
90503
|
-
process.kill(pid, 0);
|
|
90504
|
-
return true;
|
|
90505
|
-
} catch (error) {
|
|
90506
|
-
const code2 = error.code;
|
|
90507
|
-
return code2 === "EPERM";
|
|
90508
|
-
}
|
|
90509
|
-
}
|
|
90510
|
-
async function readLockPayload(lockPath) {
|
|
90511
|
-
try {
|
|
90512
|
-
const raw2 = await readFile50(lockPath, "utf-8");
|
|
90513
|
-
const parsed = JSON.parse(raw2);
|
|
90514
|
-
if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0) {
|
|
90515
|
-
return {
|
|
90516
|
-
pid: parsed.pid,
|
|
90517
|
-
startedAt: typeof parsed.startedAt === "string" && parsed.startedAt.length > 0 ? parsed.startedAt : "unknown"
|
|
90518
|
-
};
|
|
90519
|
-
}
|
|
90520
|
-
} catch {}
|
|
90521
|
-
return null;
|
|
90522
|
-
}
|
|
90523
89621
|
async function acquireSyncLock(global3) {
|
|
90524
89622
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
90525
|
-
const lockPath =
|
|
89623
|
+
const lockPath = join103(cacheDir, ".sync-lock");
|
|
90526
89624
|
const startTime = Date.now();
|
|
90527
89625
|
const lockTimeout = getLockTimeout();
|
|
90528
|
-
await mkdir31(
|
|
89626
|
+
await mkdir31(dirname22(lockPath), { recursive: true });
|
|
90529
89627
|
while (Date.now() - startTime < lockTimeout) {
|
|
90530
89628
|
try {
|
|
90531
89629
|
const handle = await open4(lockPath, "wx");
|
|
90532
|
-
await handle.writeFile(JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }), "utf-8");
|
|
90533
89630
|
return async () => {
|
|
90534
|
-
|
|
90535
|
-
await handle.close();
|
|
90536
|
-
} catch {}
|
|
89631
|
+
await handle.close();
|
|
90537
89632
|
await unlink11(lockPath).catch(() => {});
|
|
90538
89633
|
};
|
|
90539
89634
|
} catch (err) {
|
|
@@ -90541,29 +89636,18 @@ async function acquireSyncLock(global3) {
|
|
|
90541
89636
|
try {
|
|
90542
89637
|
const lockStat = await stat17(lockPath);
|
|
90543
89638
|
const lockAge = Math.abs(Date.now() - lockStat.mtimeMs);
|
|
90544
|
-
|
|
90545
|
-
|
|
90546
|
-
throw new Error("Sync lock is already held by current process");
|
|
90547
|
-
}
|
|
90548
|
-
const ownerAlive = lockOwner?.pid ? isProcessAlive(lockOwner.pid) : null;
|
|
90549
|
-
if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive !== true) {
|
|
90550
|
-
logger.warning(`Removing stale sync lock (age: ${Math.round(lockAge / 1000)}s${lockOwner?.pid ? `, pid=${lockOwner.pid}` : ""})`);
|
|
89639
|
+
if (lockAge > STALE_LOCK_THRESHOLD_MS) {
|
|
89640
|
+
logger.warning(`Removing stale sync lock (age: ${Math.round(lockAge / 1000)}s)`);
|
|
90551
89641
|
await unlink11(lockPath).catch(() => {});
|
|
90552
89642
|
continue;
|
|
90553
89643
|
}
|
|
90554
|
-
if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive === true) {
|
|
90555
|
-
logger.debug(`Sync lock older than threshold but owner pid=${lockOwner?.pid} still alive; waiting`);
|
|
90556
|
-
}
|
|
90557
89644
|
} catch (statError) {
|
|
90558
|
-
if (statError instanceof Error && statError.message.includes("already held by current process")) {
|
|
90559
|
-
throw statError;
|
|
90560
|
-
}
|
|
90561
89645
|
if (statError.code === "ENOENT") {
|
|
90562
89646
|
continue;
|
|
90563
89647
|
}
|
|
90564
89648
|
logger.debug(`Lock stat failed: ${statError}`);
|
|
90565
89649
|
}
|
|
90566
|
-
await new Promise((
|
|
89650
|
+
await new Promise((resolve22) => setTimeout(resolve22, 100));
|
|
90567
89651
|
continue;
|
|
90568
89652
|
}
|
|
90569
89653
|
throw err;
|
|
@@ -90582,20 +89666,18 @@ async function executeSyncMerge(ctx) {
|
|
|
90582
89666
|
const releaseLock = await acquireSyncLock(ctx.options.global);
|
|
90583
89667
|
try {
|
|
90584
89668
|
const trackedFiles = ctx.syncTrackedFiles;
|
|
90585
|
-
const upstreamDir = ctx.options.global ?
|
|
89669
|
+
const upstreamDir = ctx.options.global ? join103(ctx.extractDir, ".claude") : ctx.extractDir;
|
|
90586
89670
|
let deletions = [];
|
|
90587
89671
|
try {
|
|
90588
|
-
const sourceMetadataPath =
|
|
90589
|
-
if (await
|
|
90590
|
-
const content = await
|
|
89672
|
+
const sourceMetadataPath = join103(upstreamDir, "metadata.json");
|
|
89673
|
+
if (await import_fs_extra33.pathExists(sourceMetadataPath)) {
|
|
89674
|
+
const content = await readFile48(sourceMetadataPath, "utf-8");
|
|
90591
89675
|
const sourceMetadata = JSON.parse(content);
|
|
90592
89676
|
deletions = sourceMetadata.deletions || [];
|
|
90593
89677
|
}
|
|
90594
89678
|
} catch (error) {
|
|
90595
89679
|
logger.debug(`Failed to load source metadata for deletion filtering: ${error}`);
|
|
90596
89680
|
}
|
|
90597
|
-
const { categorizeDeletions: categorizeDeletions2, handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
|
|
90598
|
-
const categorizedDeletions = categorizeDeletions2(deletions);
|
|
90599
89681
|
const filteredTrackedFiles = filterDeletionPaths(trackedFiles, deletions);
|
|
90600
89682
|
if (deletions.length > 0) {
|
|
90601
89683
|
const filtered = trackedFiles.length - filteredTrackedFiles.length;
|
|
@@ -90603,44 +89685,23 @@ async function executeSyncMerge(ctx) {
|
|
|
90603
89685
|
}
|
|
90604
89686
|
logger.info("Analyzing file changes...");
|
|
90605
89687
|
const plan = await SyncEngine.createSyncPlan(filteredTrackedFiles, ctx.claudeDir, upstreamDir);
|
|
90606
|
-
const forceOverwriteNonInteractive = ctx.isNonInteractive && ctx.options.forceOverwrite;
|
|
90607
|
-
const autoUpdateQueue = forceOverwriteNonInteractive ? dedupeTrackedFiles([...plan.autoUpdate, ...plan.needsReview]) : plan.autoUpdate;
|
|
90608
|
-
const reviewQueue = forceOverwriteNonInteractive ? [] : plan.needsReview;
|
|
90609
89688
|
displaySyncPlan(plan);
|
|
90610
|
-
if (
|
|
89689
|
+
if (plan.autoUpdate.length === 0 && plan.needsReview.length === 0) {
|
|
90611
89690
|
ctx.prompts.note("All files are up to date or user-owned.", "No Changes Needed");
|
|
90612
|
-
}
|
|
90613
|
-
if (reviewQueue.length > 0 && ctx.isNonInteractive) {
|
|
90614
|
-
logger.error(`Cannot complete sync: ${reviewQueue.length} file(s) require interactive review`);
|
|
90615
|
-
ctx.prompts.note(`The following files have local modifications:
|
|
90616
|
-
${reviewQueue.slice(0, 5).map((f3) => ` • ${f3.path}`).join(`
|
|
90617
|
-
`)}${reviewQueue.length > 5 ? `
|
|
90618
|
-
... and ${reviewQueue.length - 5} more` : ""}
|
|
90619
|
-
|
|
90620
|
-
Options:
|
|
90621
|
-
1. Run 'ck init --sync' without --yes for interactive merge
|
|
90622
|
-
2. Use --force-overwrite to accept all upstream changes
|
|
90623
|
-
3. Manually resolve conflicts before syncing`, "Sync Blocked");
|
|
90624
89691
|
return { ...ctx, cancelled: true };
|
|
90625
89692
|
}
|
|
90626
|
-
|
|
90627
|
-
|
|
90628
|
-
}
|
|
90629
|
-
|
|
90630
|
-
|
|
90631
|
-
const backupDir = PathResolver.getBackupDir();
|
|
90632
|
-
await createBackup(ctx.claudeDir, trackedFiles, backupDir);
|
|
90633
|
-
logger.success(`Backup created at ${import_picocolors23.default.dim(backupDir)}`);
|
|
90634
|
-
}
|
|
90635
|
-
if (autoUpdateQueue.length > 0) {
|
|
90636
|
-
logger.info(`Auto-updating ${autoUpdateQueue.length} file(s)...`);
|
|
89693
|
+
const backupDir = PathResolver.getBackupDir();
|
|
89694
|
+
await createBackup(ctx.claudeDir, trackedFiles, backupDir);
|
|
89695
|
+
logger.success(`Backup created at ${import_picocolors23.default.dim(backupDir)}`);
|
|
89696
|
+
if (plan.autoUpdate.length > 0) {
|
|
89697
|
+
logger.info(`Auto-updating ${plan.autoUpdate.length} file(s)...`);
|
|
90637
89698
|
let updateSuccess = 0;
|
|
90638
89699
|
let updateFailed = 0;
|
|
90639
|
-
for (const file of
|
|
89700
|
+
for (const file of plan.autoUpdate) {
|
|
90640
89701
|
try {
|
|
90641
89702
|
const sourcePath = await validateSyncPath(upstreamDir, file.path);
|
|
90642
89703
|
const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
90643
|
-
const targetDir =
|
|
89704
|
+
const targetDir = join103(targetPath, "..");
|
|
90644
89705
|
try {
|
|
90645
89706
|
await mkdir31(targetDir, { recursive: true });
|
|
90646
89707
|
} catch (mkdirError) {
|
|
@@ -90650,7 +89711,7 @@ Options:
|
|
|
90650
89711
|
ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
|
|
90651
89712
|
return { ...ctx, cancelled: true };
|
|
90652
89713
|
}
|
|
90653
|
-
if (errCode === "EROFS" || errCode === "EACCES"
|
|
89714
|
+
if (errCode === "EROFS" || errCode === "EACCES") {
|
|
90654
89715
|
logger.warning(`Cannot create directory ${file.path}: ${errCode}`);
|
|
90655
89716
|
updateFailed++;
|
|
90656
89717
|
continue;
|
|
@@ -90668,7 +89729,7 @@ Options:
|
|
|
90668
89729
|
ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
|
|
90669
89730
|
return { ...ctx, cancelled: true };
|
|
90670
89731
|
}
|
|
90671
|
-
if (errCode === "EACCES" || errCode === "EPERM"
|
|
89732
|
+
if (errCode === "EACCES" || errCode === "EPERM") {
|
|
90672
89733
|
logger.warning(`Permission denied: ${file.path} - check file permissions`);
|
|
90673
89734
|
updateFailed++;
|
|
90674
89735
|
} else if (errMsg.includes("Symlink") || errMsg.includes("Path")) {
|
|
@@ -90683,22 +89744,19 @@ Options:
|
|
|
90683
89744
|
if (updateSuccess > 0) {
|
|
90684
89745
|
logger.success(`Auto-updated ${updateSuccess} file(s)${updateFailed > 0 ? ` (${updateFailed} failed)` : ""}`);
|
|
90685
89746
|
}
|
|
90686
|
-
if (updateSuccess === 0 && updateFailed > 0) {
|
|
90687
|
-
logger.warning("No files were updated due to write errors");
|
|
90688
|
-
}
|
|
90689
89747
|
}
|
|
90690
|
-
if (
|
|
90691
|
-
logger.info(`${
|
|
89748
|
+
if (plan.needsReview.length > 0 && !ctx.isNonInteractive) {
|
|
89749
|
+
logger.info(`${plan.needsReview.length} file(s) need interactive review...`);
|
|
90692
89750
|
let totalApplied = 0;
|
|
90693
89751
|
let totalRejected = 0;
|
|
90694
89752
|
let skippedFiles = 0;
|
|
90695
|
-
for (const file of
|
|
89753
|
+
for (const file of plan.needsReview) {
|
|
90696
89754
|
let currentPath;
|
|
90697
89755
|
let upstreamPath;
|
|
90698
89756
|
try {
|
|
90699
89757
|
currentPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
90700
89758
|
upstreamPath = await validateSyncPath(upstreamDir, file.path);
|
|
90701
|
-
} catch {
|
|
89759
|
+
} catch (error) {
|
|
90702
89760
|
logger.warning(`Skipping invalid path during review: ${file.path}`);
|
|
90703
89761
|
skippedFiles++;
|
|
90704
89762
|
continue;
|
|
@@ -90725,7 +89783,7 @@ Options:
|
|
|
90725
89783
|
const tempPath = `${currentPath}.tmp.${Date.now()}`;
|
|
90726
89784
|
try {
|
|
90727
89785
|
await writeFile30(tempPath, result.result, "utf-8");
|
|
90728
|
-
await
|
|
89786
|
+
await rename6(tempPath, currentPath);
|
|
90729
89787
|
} catch (atomicError) {
|
|
90730
89788
|
await unlink11(tempPath).catch(() => {});
|
|
90731
89789
|
throw atomicError;
|
|
@@ -90746,8 +89804,8 @@ Options:
|
|
|
90746
89804
|
console.log("");
|
|
90747
89805
|
console.log(import_picocolors23.default.bold("Sync Summary:"));
|
|
90748
89806
|
console.log(import_picocolors23.default.dim("─".repeat(40)));
|
|
90749
|
-
if (
|
|
90750
|
-
console.log(import_picocolors23.default.green(` ✓ ${
|
|
89807
|
+
if (plan.autoUpdate.length > 0) {
|
|
89808
|
+
console.log(import_picocolors23.default.green(` ✓ ${plan.autoUpdate.length} file(s) auto-updated`));
|
|
90751
89809
|
}
|
|
90752
89810
|
if (totalApplied > 0) {
|
|
90753
89811
|
console.log(import_picocolors23.default.green(` ✓ ${totalApplied} hunk(s) applied`));
|
|
@@ -90761,96 +89819,23 @@ Options:
|
|
|
90761
89819
|
if (plan.skipped.length > 0) {
|
|
90762
89820
|
console.log(import_picocolors23.default.dim(` ─ ${plan.skipped.length} user-owned file(s) unchanged`));
|
|
90763
89821
|
}
|
|
90764
|
-
}
|
|
90765
|
-
|
|
90766
|
-
|
|
90767
|
-
|
|
90768
|
-
|
|
90769
|
-
|
|
90770
|
-
|
|
90771
|
-
|
|
90772
|
-
|
|
90773
|
-
|
|
90774
|
-
|
|
90775
|
-
|
|
90776
|
-
}
|
|
90777
|
-
}
|
|
90778
|
-
let pluginSupported = false;
|
|
90779
|
-
let pluginVerified = false;
|
|
90780
|
-
try {
|
|
90781
|
-
const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
|
|
90782
|
-
await requireCCPluginSupport2();
|
|
90783
|
-
pluginSupported = true;
|
|
90784
|
-
} catch (error) {
|
|
90785
|
-
if (error instanceof CCPluginSupportError) {
|
|
90786
|
-
logger.info(`Plugin install skipped during sync: ${error.message}`);
|
|
90787
|
-
if (error.code === "cc_version_too_old") {
|
|
90788
|
-
logger.info("Upgrade Claude Code, then re-run: ck init --sync (plugin migration requires >= 1.0.33)");
|
|
90789
|
-
}
|
|
90790
|
-
if (error.code === "cc_not_found") {
|
|
90791
|
-
logger.info("Install Claude Code CLI to enable /ck:* plugin skills");
|
|
90792
|
-
}
|
|
90793
|
-
} else {
|
|
90794
|
-
logger.debug(`Plugin version check failed during sync: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
90795
|
-
}
|
|
90796
|
-
}
|
|
90797
|
-
if (pluginSupported && ctx.extractDir) {
|
|
90798
|
-
try {
|
|
90799
|
-
const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
|
|
90800
|
-
const pluginResult = await handlePluginInstall2(ctx.extractDir);
|
|
90801
|
-
pluginVerified = pluginResult.verified;
|
|
90802
|
-
if (pluginResult.error) {
|
|
90803
|
-
logger.debug(`Plugin install issue: ${pluginResult.error}`);
|
|
90804
|
-
}
|
|
90805
|
-
} catch (error) {
|
|
90806
|
-
logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
90807
|
-
}
|
|
90808
|
-
}
|
|
90809
|
-
if (ctx.claudeDir && ctx.kitType) {
|
|
90810
|
-
try {
|
|
90811
|
-
const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
|
|
90812
|
-
await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
|
|
90813
|
-
pluginInstalled: pluginVerified,
|
|
90814
|
-
pluginInstalledAt: new Date().toISOString(),
|
|
90815
|
-
pluginVersion: ctx.selectedVersion || ctx.syncLatestVersion || "unknown"
|
|
90816
|
-
});
|
|
90817
|
-
} catch {}
|
|
90818
|
-
}
|
|
90819
|
-
if (categorizedDeletions.deferred.length > 0) {
|
|
90820
|
-
if (pluginVerified) {
|
|
90821
|
-
try {
|
|
90822
|
-
const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
|
|
90823
|
-
const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
|
|
90824
|
-
if (!migration.canDelete) {
|
|
90825
|
-
logger.warning("Skill migration metadata unavailable during sync — preserving existing skills");
|
|
90826
|
-
} else {
|
|
90827
|
-
const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir2));
|
|
90828
|
-
const safeDeletions = categorizedDeletions.deferred.filter((path14) => {
|
|
90829
|
-
const skillDir = extractSkillDirFromDeletionPath2(path14);
|
|
90830
|
-
return !skillDir || !preservedDirs.has(normalizeSkillDir2(skillDir));
|
|
90831
|
-
});
|
|
90832
|
-
if (safeDeletions.length > 0) {
|
|
90833
|
-
const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
|
|
90834
|
-
if (deferredResult.deletedPaths.length > 0) {
|
|
90835
|
-
logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) during sync`);
|
|
90836
|
-
}
|
|
90837
|
-
}
|
|
90838
|
-
}
|
|
90839
|
-
} catch (error) {
|
|
90840
|
-
logger.debug(`Deferred skill cleanup failed during sync: ${error}`);
|
|
90841
|
-
}
|
|
90842
|
-
} else {
|
|
90843
|
-
logger.info("Plugin not verified during sync — keeping existing skills as fallback");
|
|
90844
|
-
}
|
|
89822
|
+
} else if (plan.needsReview.length > 0 && ctx.isNonInteractive) {
|
|
89823
|
+
logger.error(`Cannot complete sync: ${plan.needsReview.length} file(s) require interactive review`);
|
|
89824
|
+
ctx.prompts.note(`The following files have local modifications:
|
|
89825
|
+
${plan.needsReview.slice(0, 5).map((f3) => ` • ${f3.path}`).join(`
|
|
89826
|
+
`)}${plan.needsReview.length > 5 ? `
|
|
89827
|
+
... and ${plan.needsReview.length - 5} more` : ""}
|
|
89828
|
+
|
|
89829
|
+
Options:
|
|
89830
|
+
1. Run 'ck init --sync' without --yes for interactive merge
|
|
89831
|
+
2. Use --force-overwrite to accept all upstream changes
|
|
89832
|
+
3. Manually resolve conflicts before syncing`, "Sync Blocked");
|
|
89833
|
+
return { ...ctx, cancelled: true };
|
|
90845
89834
|
}
|
|
90846
89835
|
ctx.prompts.outro("Config sync completed successfully");
|
|
90847
89836
|
return { ...ctx, cancelled: true };
|
|
90848
89837
|
} finally {
|
|
90849
|
-
|
|
90850
|
-
await releaseLock();
|
|
90851
|
-
} catch (error) {
|
|
90852
|
-
logger.debug(`Failed to release sync lock: ${error}`);
|
|
90853
|
-
}
|
|
89838
|
+
await releaseLock();
|
|
90854
89839
|
}
|
|
90855
89840
|
}
|
|
90856
89841
|
function displaySyncPlan(plan) {
|
|
@@ -90885,9 +89870,9 @@ async function createBackup(claudeDir2, files, backupDir) {
|
|
|
90885
89870
|
for (const file of files) {
|
|
90886
89871
|
try {
|
|
90887
89872
|
const sourcePath = await validateSyncPath(claudeDir2, file.path);
|
|
90888
|
-
if (await
|
|
89873
|
+
if (await import_fs_extra33.pathExists(sourcePath)) {
|
|
90889
89874
|
const targetPath = await validateSyncPath(backupDir, file.path);
|
|
90890
|
-
const targetDir =
|
|
89875
|
+
const targetDir = join103(targetPath, "..");
|
|
90891
89876
|
await mkdir31(targetDir, { recursive: true });
|
|
90892
89877
|
await copyFile8(sourcePath, targetPath);
|
|
90893
89878
|
}
|
|
@@ -90900,27 +89885,9 @@ async function createBackup(claudeDir2, files, backupDir) {
|
|
|
90900
89885
|
}
|
|
90901
89886
|
}
|
|
90902
89887
|
}
|
|
90903
|
-
function dedupeTrackedFiles(files) {
|
|
90904
|
-
const deduped = new Map;
|
|
90905
|
-
for (const file of files) {
|
|
90906
|
-
deduped.set(file.path, file);
|
|
90907
|
-
}
|
|
90908
|
-
return [...deduped.values()];
|
|
90909
|
-
}
|
|
90910
|
-
function normalizeSkillDir2(path14) {
|
|
90911
|
-
return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
90912
|
-
}
|
|
90913
|
-
function extractSkillDirFromDeletionPath2(path14) {
|
|
90914
|
-
const normalized = normalizeSkillDir2(path14);
|
|
90915
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
90916
|
-
if (parts.length < 2 || parts[0] !== "skills") {
|
|
90917
|
-
return null;
|
|
90918
|
-
}
|
|
90919
|
-
return `skills/${parts[1]}`;
|
|
90920
|
-
}
|
|
90921
89888
|
// src/commands/init/phases/transform-handler.ts
|
|
90922
89889
|
init_config_manager();
|
|
90923
|
-
import { join as
|
|
89890
|
+
import { join as join107 } from "node:path";
|
|
90924
89891
|
|
|
90925
89892
|
// src/services/transformers/folder-path-transformer.ts
|
|
90926
89893
|
init_logger();
|
|
@@ -90929,40 +89896,40 @@ init_types3();
|
|
|
90929
89896
|
// src/services/transformers/folder-transform/folder-renamer.ts
|
|
90930
89897
|
init_logger();
|
|
90931
89898
|
init_types3();
|
|
90932
|
-
var
|
|
90933
|
-
import { rename as
|
|
90934
|
-
import { join as
|
|
89899
|
+
var import_fs_extra34 = __toESM(require_lib3(), 1);
|
|
89900
|
+
import { rename as rename7, rm as rm13 } from "node:fs/promises";
|
|
89901
|
+
import { join as join104, relative as relative18 } from "node:path";
|
|
90935
89902
|
async function collectDirsToRename(extractDir, folders) {
|
|
90936
89903
|
const dirsToRename = [];
|
|
90937
89904
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
90938
|
-
const docsPath =
|
|
90939
|
-
if (await
|
|
89905
|
+
const docsPath = join104(extractDir, DEFAULT_FOLDERS.docs);
|
|
89906
|
+
if (await import_fs_extra34.pathExists(docsPath)) {
|
|
90940
89907
|
dirsToRename.push({
|
|
90941
89908
|
from: docsPath,
|
|
90942
|
-
to:
|
|
89909
|
+
to: join104(extractDir, folders.docs)
|
|
90943
89910
|
});
|
|
90944
89911
|
}
|
|
90945
|
-
const claudeDocsPath =
|
|
90946
|
-
if (await
|
|
89912
|
+
const claudeDocsPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
89913
|
+
if (await import_fs_extra34.pathExists(claudeDocsPath)) {
|
|
90947
89914
|
dirsToRename.push({
|
|
90948
89915
|
from: claudeDocsPath,
|
|
90949
|
-
to:
|
|
89916
|
+
to: join104(extractDir, ".claude", folders.docs)
|
|
90950
89917
|
});
|
|
90951
89918
|
}
|
|
90952
89919
|
}
|
|
90953
89920
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
90954
|
-
const plansPath =
|
|
90955
|
-
if (await
|
|
89921
|
+
const plansPath = join104(extractDir, DEFAULT_FOLDERS.plans);
|
|
89922
|
+
if (await import_fs_extra34.pathExists(plansPath)) {
|
|
90956
89923
|
dirsToRename.push({
|
|
90957
89924
|
from: plansPath,
|
|
90958
|
-
to:
|
|
89925
|
+
to: join104(extractDir, folders.plans)
|
|
90959
89926
|
});
|
|
90960
89927
|
}
|
|
90961
|
-
const claudePlansPath =
|
|
90962
|
-
if (await
|
|
89928
|
+
const claudePlansPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
89929
|
+
if (await import_fs_extra34.pathExists(claudePlansPath)) {
|
|
90963
89930
|
dirsToRename.push({
|
|
90964
89931
|
from: claudePlansPath,
|
|
90965
|
-
to:
|
|
89932
|
+
to: join104(extractDir, ".claude", folders.plans)
|
|
90966
89933
|
});
|
|
90967
89934
|
}
|
|
90968
89935
|
}
|
|
@@ -90970,11 +89937,11 @@ async function collectDirsToRename(extractDir, folders) {
|
|
|
90970
89937
|
}
|
|
90971
89938
|
async function moveAcrossDevices(src, dest) {
|
|
90972
89939
|
try {
|
|
90973
|
-
await
|
|
89940
|
+
await rename7(src, dest);
|
|
90974
89941
|
} catch (e2) {
|
|
90975
89942
|
if (e2.code === "EXDEV") {
|
|
90976
89943
|
logger.debug(`Cross-device move detected, using copy+delete: ${src} -> ${dest}`);
|
|
90977
|
-
await
|
|
89944
|
+
await import_fs_extra34.copy(src, dest, { overwrite: true });
|
|
90978
89945
|
await rm13(src, { recursive: true, force: true });
|
|
90979
89946
|
} else {
|
|
90980
89947
|
throw e2;
|
|
@@ -91002,8 +89969,8 @@ async function renameFolders(dirsToRename, extractDir, options2) {
|
|
|
91002
89969
|
// src/services/transformers/folder-transform/path-replacer.ts
|
|
91003
89970
|
init_logger();
|
|
91004
89971
|
init_types3();
|
|
91005
|
-
import { readFile as
|
|
91006
|
-
import { join as
|
|
89972
|
+
import { readFile as readFile49, readdir as readdir32, writeFile as writeFile31 } from "node:fs/promises";
|
|
89973
|
+
import { join as join105, relative as relative19 } from "node:path";
|
|
91007
89974
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
91008
89975
|
".md",
|
|
91009
89976
|
".txt",
|
|
@@ -91054,9 +90021,9 @@ function compileReplacements(replacements) {
|
|
|
91054
90021
|
async function transformFileContents(dir, compiledReplacements, options2) {
|
|
91055
90022
|
let filesChanged = 0;
|
|
91056
90023
|
let replacementsCount = 0;
|
|
91057
|
-
const entries = await
|
|
90024
|
+
const entries = await readdir32(dir, { withFileTypes: true });
|
|
91058
90025
|
for (const entry of entries) {
|
|
91059
|
-
const fullPath =
|
|
90026
|
+
const fullPath = join105(dir, entry.name);
|
|
91060
90027
|
if (entry.isDirectory()) {
|
|
91061
90028
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
91062
90029
|
continue;
|
|
@@ -91069,7 +90036,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
91069
90036
|
if (!shouldTransform)
|
|
91070
90037
|
continue;
|
|
91071
90038
|
try {
|
|
91072
|
-
const content = await
|
|
90039
|
+
const content = await readFile49(fullPath, "utf-8");
|
|
91073
90040
|
let newContent = content;
|
|
91074
90041
|
let changeCount = 0;
|
|
91075
90042
|
for (const { regex: regex2, replacement } of compiledReplacements) {
|
|
@@ -91191,9 +90158,9 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
|
|
|
91191
90158
|
|
|
91192
90159
|
// src/services/transformers/global-path-transformer.ts
|
|
91193
90160
|
init_logger();
|
|
91194
|
-
import { readFile as
|
|
90161
|
+
import { readFile as readFile50, readdir as readdir33, writeFile as writeFile32 } from "node:fs/promises";
|
|
91195
90162
|
import { platform as platform13 } from "node:os";
|
|
91196
|
-
import { extname as extname6, join as
|
|
90163
|
+
import { extname as extname6, join as join106 } from "node:path";
|
|
91197
90164
|
var IS_WINDOWS3 = platform13() === "win32";
|
|
91198
90165
|
var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
|
|
91199
90166
|
function getHomeDirPrefix() {
|
|
@@ -91301,9 +90268,9 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
91301
90268
|
let filesSkipped = 0;
|
|
91302
90269
|
const skippedFiles = [];
|
|
91303
90270
|
async function processDirectory2(dir) {
|
|
91304
|
-
const entries = await
|
|
90271
|
+
const entries = await readdir33(dir, { withFileTypes: true });
|
|
91305
90272
|
for (const entry of entries) {
|
|
91306
|
-
const fullPath =
|
|
90273
|
+
const fullPath = join106(dir, entry.name);
|
|
91307
90274
|
if (entry.isDirectory()) {
|
|
91308
90275
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
91309
90276
|
continue;
|
|
@@ -91311,7 +90278,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
91311
90278
|
await processDirectory2(fullPath);
|
|
91312
90279
|
} else if (entry.isFile() && shouldTransformFile3(entry.name)) {
|
|
91313
90280
|
try {
|
|
91314
|
-
const content = await
|
|
90281
|
+
const content = await readFile50(fullPath, "utf-8");
|
|
91315
90282
|
const { transformed, changes } = transformContent(content);
|
|
91316
90283
|
if (changes > 0) {
|
|
91317
90284
|
await writeFile32(fullPath, transformed, "utf-8");
|
|
@@ -91379,7 +90346,7 @@ async function handleTransforms(ctx) {
|
|
|
91379
90346
|
logger.debug(ctx.options.global ? "Saved folder configuration to ~/.claude/.ck.json" : "Saved folder configuration to .claude/.ck.json");
|
|
91380
90347
|
}
|
|
91381
90348
|
}
|
|
91382
|
-
const claudeDir2 = ctx.options.global ? ctx.resolvedDir :
|
|
90349
|
+
const claudeDir2 = ctx.options.global ? ctx.resolvedDir : join107(ctx.resolvedDir, ".claude");
|
|
91383
90350
|
return {
|
|
91384
90351
|
...ctx,
|
|
91385
90352
|
foldersConfig,
|
|
@@ -91573,8 +90540,8 @@ init_checksum_utils();
|
|
|
91573
90540
|
init_config_discovery();
|
|
91574
90541
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
91575
90542
|
import { existsSync as existsSync51 } from "node:fs";
|
|
91576
|
-
import { readFile as
|
|
91577
|
-
import { resolve as
|
|
90543
|
+
import { readFile as readFile51, rm as rm14, unlink as unlink12 } from "node:fs/promises";
|
|
90544
|
+
import { resolve as resolve22 } from "node:path";
|
|
91578
90545
|
|
|
91579
90546
|
// src/commands/portable/conflict-resolver.ts
|
|
91580
90547
|
init_dist2();
|
|
@@ -91921,7 +90888,7 @@ function shouldExecuteAction2(action) {
|
|
|
91921
90888
|
}
|
|
91922
90889
|
async function executeDeleteAction(action, options2) {
|
|
91923
90890
|
const preservePaths = options2?.preservePaths ?? new Set;
|
|
91924
|
-
const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(
|
|
90891
|
+
const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(resolve22(action.targetPath));
|
|
91925
90892
|
try {
|
|
91926
90893
|
if (!shouldPreserveTarget && action.targetPath && existsSync51(action.targetPath)) {
|
|
91927
90894
|
await rm14(action.targetPath, { recursive: true, force: true });
|
|
@@ -92146,7 +91113,7 @@ async function migrateCommand(options2) {
|
|
|
92146
91113
|
for (const action of conflictActions) {
|
|
92147
91114
|
if (!action.diff && action.targetPath && existsSync51(action.targetPath)) {
|
|
92148
91115
|
try {
|
|
92149
|
-
const targetContent = await
|
|
91116
|
+
const targetContent = await readFile51(action.targetPath, "utf-8");
|
|
92150
91117
|
const sourceItem = agents2.find((a3) => a3.name === action.item) || commands.find((c2) => c2.name === action.item) || (configItem?.name === action.item ? configItem : null) || ruleItems.find((r2) => r2.name === action.item);
|
|
92151
91118
|
if (sourceItem) {
|
|
92152
91119
|
const providerConfig = providers[action.provider];
|
|
@@ -92237,7 +91204,7 @@ async function migrateCommand(options2) {
|
|
|
92237
91204
|
allResults.push(...await installSkillDirectories(skills, skillProviders, installOpts));
|
|
92238
91205
|
}
|
|
92239
91206
|
}
|
|
92240
|
-
const writtenPaths = new Set(allResults.filter((result) => result.success && !result.skipped && result.path.length > 0).map((result) =>
|
|
91207
|
+
const writtenPaths = new Set(allResults.filter((result) => result.success && !result.skipped && result.path.length > 0).map((result) => resolve22(result.path)));
|
|
92241
91208
|
for (const deleteAction of plannedDeleteActions) {
|
|
92242
91209
|
allResults.push(await executeDeleteAction(deleteAction, {
|
|
92243
91210
|
preservePaths: writtenPaths
|
|
@@ -92353,7 +91320,7 @@ async function computeTargetStates(selectedProviders, global3) {
|
|
|
92353
91320
|
exists: true
|
|
92354
91321
|
};
|
|
92355
91322
|
try {
|
|
92356
|
-
const content = await
|
|
91323
|
+
const content = await readFile51(entry.path, "utf-8");
|
|
92357
91324
|
state.currentChecksum = computeContentChecksum(content);
|
|
92358
91325
|
} catch (error) {
|
|
92359
91326
|
logger.debug(`[migrate] Failed to read target for checksum: ${entry.path} (${String(error)})`);
|
|
@@ -92412,11 +91379,11 @@ var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
|
92412
91379
|
|
|
92413
91380
|
// src/commands/new/phases/directory-setup.ts
|
|
92414
91381
|
init_config_manager();
|
|
92415
|
-
import { resolve as
|
|
91382
|
+
import { resolve as resolve23 } from "node:path";
|
|
92416
91383
|
init_logger();
|
|
92417
91384
|
init_path_resolver();
|
|
92418
91385
|
init_types3();
|
|
92419
|
-
var
|
|
91386
|
+
var import_fs_extra35 = __toESM(require_lib3(), 1);
|
|
92420
91387
|
async function directorySetup(validOptions, prompts) {
|
|
92421
91388
|
const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
|
|
92422
91389
|
const config = await ConfigManager.get();
|
|
@@ -92497,7 +91464,7 @@ async function directorySetup(validOptions, prompts) {
|
|
|
92497
91464
|
targetDir = await prompts.getDirectory(targetDir);
|
|
92498
91465
|
}
|
|
92499
91466
|
}
|
|
92500
|
-
const resolvedDir =
|
|
91467
|
+
const resolvedDir = resolve23(targetDir);
|
|
92501
91468
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
92502
91469
|
if (PathResolver.isLocalSameAsGlobal(resolvedDir)) {
|
|
92503
91470
|
logger.warning("You're creating a project at HOME directory.");
|
|
@@ -92515,8 +91482,8 @@ async function directorySetup(validOptions, prompts) {
|
|
|
92515
91482
|
return null;
|
|
92516
91483
|
}
|
|
92517
91484
|
}
|
|
92518
|
-
if (await
|
|
92519
|
-
const files = await
|
|
91485
|
+
if (await import_fs_extra35.pathExists(resolvedDir)) {
|
|
91486
|
+
const files = await import_fs_extra35.readdir(resolvedDir);
|
|
92520
91487
|
const isEmpty = files.length === 0;
|
|
92521
91488
|
if (!isEmpty) {
|
|
92522
91489
|
if (isNonInteractive2) {
|
|
@@ -92554,7 +91521,7 @@ async function handleDirectorySetup(ctx) {
|
|
|
92554
91521
|
// src/commands/new/phases/project-creation.ts
|
|
92555
91522
|
init_config_manager();
|
|
92556
91523
|
init_github_client();
|
|
92557
|
-
import { join as
|
|
91524
|
+
import { join as join108 } from "node:path";
|
|
92558
91525
|
init_logger();
|
|
92559
91526
|
init_output_manager();
|
|
92560
91527
|
init_types3();
|
|
@@ -92680,7 +91647,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
|
|
|
92680
91647
|
output.section("Installing");
|
|
92681
91648
|
logger.verbose("Installation target", { directory: resolvedDir });
|
|
92682
91649
|
const merger = new FileMerger;
|
|
92683
|
-
const claudeDir2 =
|
|
91650
|
+
const claudeDir2 = join108(resolvedDir, ".claude");
|
|
92684
91651
|
merger.setMultiKitContext(claudeDir2, kit);
|
|
92685
91652
|
if (validOptions.exclude && validOptions.exclude.length > 0) {
|
|
92686
91653
|
merger.addIgnorePatterns(validOptions.exclude);
|
|
@@ -92727,7 +91694,7 @@ async function handleProjectCreation(ctx) {
|
|
|
92727
91694
|
}
|
|
92728
91695
|
// src/commands/new/phases/post-setup.ts
|
|
92729
91696
|
init_projects_registry();
|
|
92730
|
-
import { join as
|
|
91697
|
+
import { join as join109 } from "node:path";
|
|
92731
91698
|
init_package_installer();
|
|
92732
91699
|
init_logger();
|
|
92733
91700
|
init_path_resolver();
|
|
@@ -92759,9 +91726,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
|
|
|
92759
91726
|
withSudo: validOptions.withSudo
|
|
92760
91727
|
});
|
|
92761
91728
|
}
|
|
92762
|
-
const claudeDir2 =
|
|
91729
|
+
const claudeDir2 = join109(resolvedDir, ".claude");
|
|
92763
91730
|
await promptSetupWizardIfNeeded({
|
|
92764
|
-
envPath:
|
|
91731
|
+
envPath: join109(claudeDir2, ".env"),
|
|
92765
91732
|
claudeDir: claudeDir2,
|
|
92766
91733
|
isGlobal: false,
|
|
92767
91734
|
isNonInteractive: isNonInteractive2,
|
|
@@ -92834,11 +91801,11 @@ init_logger();
|
|
|
92834
91801
|
init_safe_prompts();
|
|
92835
91802
|
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
92836
91803
|
import { existsSync as existsSync52 } from "node:fs";
|
|
92837
|
-
import { resolve as
|
|
91804
|
+
import { resolve as resolve24 } from "node:path";
|
|
92838
91805
|
async function handleAdd(projectPath, options2) {
|
|
92839
91806
|
logger.debug(`Adding project: ${projectPath}, options: ${JSON.stringify(options2)}`);
|
|
92840
91807
|
intro("Add Project");
|
|
92841
|
-
const absolutePath =
|
|
91808
|
+
const absolutePath = resolve24(projectPath);
|
|
92842
91809
|
if (!existsSync52(absolutePath)) {
|
|
92843
91810
|
log.error(`Path does not exist: ${absolutePath}`);
|
|
92844
91811
|
process.exitCode = 1;
|
|
@@ -93728,7 +92695,7 @@ var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
|
93728
92695
|
// src/commands/uninstall/installation-detector.ts
|
|
93729
92696
|
init_claudekit_scanner();
|
|
93730
92697
|
init_path_resolver();
|
|
93731
|
-
var
|
|
92698
|
+
var import_fs_extra36 = __toESM(require_lib3(), 1);
|
|
93732
92699
|
function hasClaudeKitComponents(components) {
|
|
93733
92700
|
return components.agents > 0 || components.commands > 0 || components.rules > 0 || components.skills > 0;
|
|
93734
92701
|
}
|
|
@@ -93743,7 +92710,7 @@ async function detectInstallations() {
|
|
|
93743
92710
|
installations.push({
|
|
93744
92711
|
type: "local",
|
|
93745
92712
|
path: setup.project.path,
|
|
93746
|
-
exists: await
|
|
92713
|
+
exists: await import_fs_extra36.pathExists(setup.project.path),
|
|
93747
92714
|
hasMetadata,
|
|
93748
92715
|
components: setup.project.components
|
|
93749
92716
|
});
|
|
@@ -93756,7 +92723,7 @@ async function detectInstallations() {
|
|
|
93756
92723
|
installations.push({
|
|
93757
92724
|
type: "global",
|
|
93758
92725
|
path: setup.global.path,
|
|
93759
|
-
exists: await
|
|
92726
|
+
exists: await import_fs_extra36.pathExists(setup.global.path),
|
|
93760
92727
|
hasMetadata,
|
|
93761
92728
|
components: setup.global.components
|
|
93762
92729
|
});
|
|
@@ -93767,16 +92734,16 @@ async function detectInstallations() {
|
|
|
93767
92734
|
|
|
93768
92735
|
// src/commands/uninstall/removal-handler.ts
|
|
93769
92736
|
import { readdirSync as readdirSync6, rmSync as rmSync5 } from "node:fs";
|
|
93770
|
-
import { join as
|
|
92737
|
+
import { join as join111, resolve as resolve25, sep as sep5 } from "node:path";
|
|
93771
92738
|
init_logger();
|
|
93772
92739
|
init_safe_prompts();
|
|
93773
92740
|
init_safe_spinner();
|
|
93774
|
-
var
|
|
92741
|
+
var import_fs_extra37 = __toESM(require_lib3(), 1);
|
|
93775
92742
|
|
|
93776
92743
|
// src/commands/uninstall/analysis-handler.ts
|
|
93777
92744
|
init_metadata_migration();
|
|
93778
92745
|
import { readdirSync as readdirSync5, rmSync as rmSync4 } from "node:fs";
|
|
93779
|
-
import { dirname as
|
|
92746
|
+
import { dirname as dirname23, join as join110 } from "node:path";
|
|
93780
92747
|
init_logger();
|
|
93781
92748
|
init_safe_prompts();
|
|
93782
92749
|
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
@@ -93794,7 +92761,7 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
|
|
|
93794
92761
|
}
|
|
93795
92762
|
async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
93796
92763
|
let cleaned = 0;
|
|
93797
|
-
let currentDir =
|
|
92764
|
+
let currentDir = dirname23(filePath);
|
|
93798
92765
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
93799
92766
|
try {
|
|
93800
92767
|
const entries = readdirSync5(currentDir);
|
|
@@ -93802,7 +92769,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
|
93802
92769
|
rmSync4(currentDir, { recursive: true });
|
|
93803
92770
|
cleaned++;
|
|
93804
92771
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
93805
|
-
currentDir =
|
|
92772
|
+
currentDir = dirname23(currentDir);
|
|
93806
92773
|
} else {
|
|
93807
92774
|
break;
|
|
93808
92775
|
}
|
|
@@ -93824,7 +92791,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
93824
92791
|
if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
|
|
93825
92792
|
const kitFiles = metadata.kits[kit].files || [];
|
|
93826
92793
|
for (const trackedFile of kitFiles) {
|
|
93827
|
-
const filePath =
|
|
92794
|
+
const filePath = join110(installation.path, trackedFile.path);
|
|
93828
92795
|
if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
|
|
93829
92796
|
result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
|
|
93830
92797
|
continue;
|
|
@@ -93854,7 +92821,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
93854
92821
|
return result;
|
|
93855
92822
|
}
|
|
93856
92823
|
for (const trackedFile of allTrackedFiles) {
|
|
93857
|
-
const filePath =
|
|
92824
|
+
const filePath = join110(installation.path, trackedFile.path);
|
|
93858
92825
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
93859
92826
|
if (!ownershipResult.exists)
|
|
93860
92827
|
continue;
|
|
@@ -93899,7 +92866,7 @@ function displayDryRunPreview(analysis, installationType) {
|
|
|
93899
92866
|
// src/commands/uninstall/removal-handler.ts
|
|
93900
92867
|
async function isDirectory(filePath) {
|
|
93901
92868
|
try {
|
|
93902
|
-
const stats = await
|
|
92869
|
+
const stats = await import_fs_extra37.lstat(filePath);
|
|
93903
92870
|
return stats.isDirectory();
|
|
93904
92871
|
} catch {
|
|
93905
92872
|
logger.debug(`Failed to check if path is directory: ${filePath}`);
|
|
@@ -93908,16 +92875,16 @@ async function isDirectory(filePath) {
|
|
|
93908
92875
|
}
|
|
93909
92876
|
async function isPathSafeToRemove(filePath, baseDir) {
|
|
93910
92877
|
try {
|
|
93911
|
-
const resolvedPath =
|
|
93912
|
-
const resolvedBase =
|
|
92878
|
+
const resolvedPath = resolve25(filePath);
|
|
92879
|
+
const resolvedBase = resolve25(baseDir);
|
|
93913
92880
|
if (!resolvedPath.startsWith(resolvedBase + sep5) && resolvedPath !== resolvedBase) {
|
|
93914
92881
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
93915
92882
|
return false;
|
|
93916
92883
|
}
|
|
93917
|
-
const stats = await
|
|
92884
|
+
const stats = await import_fs_extra37.lstat(filePath);
|
|
93918
92885
|
if (stats.isSymbolicLink()) {
|
|
93919
|
-
const realPath = await
|
|
93920
|
-
const resolvedReal =
|
|
92886
|
+
const realPath = await import_fs_extra37.realpath(filePath);
|
|
92887
|
+
const resolvedReal = resolve25(realPath);
|
|
93921
92888
|
if (!resolvedReal.startsWith(resolvedBase + sep5) && resolvedReal !== resolvedBase) {
|
|
93922
92889
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
93923
92890
|
return false;
|
|
@@ -93951,15 +92918,15 @@ async function removeInstallations(installations, options2) {
|
|
|
93951
92918
|
let removedCount = 0;
|
|
93952
92919
|
let cleanedDirs = 0;
|
|
93953
92920
|
for (const item of analysis.toDelete) {
|
|
93954
|
-
const filePath =
|
|
93955
|
-
if (!await
|
|
92921
|
+
const filePath = join111(installation.path, item.path);
|
|
92922
|
+
if (!await import_fs_extra37.pathExists(filePath))
|
|
93956
92923
|
continue;
|
|
93957
92924
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
93958
92925
|
logger.debug(`Skipping unsafe path: ${item.path}`);
|
|
93959
92926
|
continue;
|
|
93960
92927
|
}
|
|
93961
92928
|
const isDir = await isDirectory(filePath);
|
|
93962
|
-
await
|
|
92929
|
+
await import_fs_extra37.remove(filePath);
|
|
93963
92930
|
removedCount++;
|
|
93964
92931
|
logger.debug(`Removed ${isDir ? "directory" : "file"}: ${item.path}`);
|
|
93965
92932
|
if (!isDir) {
|
|
@@ -94143,12 +93110,6 @@ ${import_picocolors32.default.yellow("User modifications will be permanently del
|
|
|
94143
93110
|
forceOverwrite: validOptions.forceOverwrite,
|
|
94144
93111
|
kit: validOptions.kit
|
|
94145
93112
|
});
|
|
94146
|
-
if (!validOptions.kit || validOptions.kit === "engineer") {
|
|
94147
|
-
try {
|
|
94148
|
-
const { handlePluginUninstall: handlePluginUninstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
|
|
94149
|
-
await handlePluginUninstall2();
|
|
94150
|
-
} catch {}
|
|
94151
|
-
}
|
|
94152
93113
|
const kitMsg = validOptions.kit ? ` (${validOptions.kit} kit)` : "";
|
|
94153
93114
|
prompts.outro(`ClaudeKit${kitMsg} uninstalled successfully!`);
|
|
94154
93115
|
} catch (error) {
|
|
@@ -94350,7 +93311,7 @@ init_logger();
|
|
|
94350
93311
|
init_path_resolver();
|
|
94351
93312
|
init_types3();
|
|
94352
93313
|
import { existsSync as existsSync53, readFileSync as readFileSync10 } from "node:fs";
|
|
94353
|
-
import { join as
|
|
93314
|
+
import { join as join112 } from "node:path";
|
|
94354
93315
|
var packageVersion = package_default.version;
|
|
94355
93316
|
function formatInstalledKits(metadata) {
|
|
94356
93317
|
if (!metadata.kits || Object.keys(metadata.kits).length === 0) {
|
|
@@ -94382,9 +93343,9 @@ async function displayVersion() {
|
|
|
94382
93343
|
let localKitVersion = null;
|
|
94383
93344
|
let isGlobalOnlyKit = false;
|
|
94384
93345
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
94385
|
-
const globalMetadataPath =
|
|
93346
|
+
const globalMetadataPath = join112(globalKitDir, "metadata.json");
|
|
94386
93347
|
const prefix = PathResolver.getPathPrefix(false);
|
|
94387
|
-
const localMetadataPath = prefix ?
|
|
93348
|
+
const localMetadataPath = prefix ? join112(process.cwd(), prefix, "metadata.json") : join112(process.cwd(), "metadata.json");
|
|
94388
93349
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
94389
93350
|
if (!isLocalSameAsGlobal && existsSync53(localMetadataPath)) {
|
|
94390
93351
|
try {
|
|
@@ -94777,7 +93738,7 @@ var output2 = new OutputManager2;
|
|
|
94777
93738
|
|
|
94778
93739
|
// src/shared/temp-cleanup.ts
|
|
94779
93740
|
init_logger();
|
|
94780
|
-
var
|
|
93741
|
+
var import_fs_extra38 = __toESM(require_lib3(), 1);
|
|
94781
93742
|
import { rmSync as rmSync6 } from "node:fs";
|
|
94782
93743
|
var tempDirs2 = new Set;
|
|
94783
93744
|
async function cleanup() {
|
|
@@ -94786,7 +93747,7 @@ async function cleanup() {
|
|
|
94786
93747
|
logger.debug(`Cleaning up ${tempDirs2.size} temporary director(ies)...`);
|
|
94787
93748
|
for (const dir of tempDirs2) {
|
|
94788
93749
|
try {
|
|
94789
|
-
await
|
|
93750
|
+
await import_fs_extra38.remove(dir);
|
|
94790
93751
|
logger.debug(`Cleaned up temp directory: ${dir}`);
|
|
94791
93752
|
} catch (error) {
|
|
94792
93753
|
logger.debug(`Failed to clean temp directory ${dir}: ${error}`);
|