claudekit-cli 3.36.0-dev.1 → 3.36.0-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +732 -1643
- 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.3",
|
|
54370
54318
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
54371
54319
|
type: "module",
|
|
54372
54320
|
repository: {
|
|
@@ -61555,7 +61503,7 @@ var require_picomatch2 = __commonJS((exports, module) => {
|
|
|
61555
61503
|
import { exec as exec7, execFile as execFile7, spawn as spawn3 } from "node:child_process";
|
|
61556
61504
|
import { promisify as promisify13 } from "node:util";
|
|
61557
61505
|
function executeInteractiveScript(command, args, options2) {
|
|
61558
|
-
return new Promise((
|
|
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,481 +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
64668
|
// src/domains/help/commands/common-options.ts
|
|
65602
64669
|
var filterOptionsGroup, folderOptionsGroup;
|
|
65603
64670
|
var init_common_options = __esm(() => {
|
|
@@ -66715,7 +65782,7 @@ function getPagerArgs(pagerCmd) {
|
|
|
66715
65782
|
return [];
|
|
66716
65783
|
}
|
|
66717
65784
|
async function trySystemPager(content) {
|
|
66718
|
-
return new Promise((
|
|
65785
|
+
return new Promise((resolve26) => {
|
|
66719
65786
|
const pagerCmd = process.env.PAGER || "less";
|
|
66720
65787
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
66721
65788
|
try {
|
|
@@ -66725,20 +65792,20 @@ async function trySystemPager(content) {
|
|
|
66725
65792
|
});
|
|
66726
65793
|
const timeout2 = setTimeout(() => {
|
|
66727
65794
|
pager.kill();
|
|
66728
|
-
|
|
65795
|
+
resolve26(false);
|
|
66729
65796
|
}, 30000);
|
|
66730
65797
|
pager.stdin.write(content);
|
|
66731
65798
|
pager.stdin.end();
|
|
66732
65799
|
pager.on("close", (code2) => {
|
|
66733
65800
|
clearTimeout(timeout2);
|
|
66734
|
-
|
|
65801
|
+
resolve26(code2 === 0);
|
|
66735
65802
|
});
|
|
66736
65803
|
pager.on("error", () => {
|
|
66737
65804
|
clearTimeout(timeout2);
|
|
66738
|
-
|
|
65805
|
+
resolve26(false);
|
|
66739
65806
|
});
|
|
66740
65807
|
} catch {
|
|
66741
|
-
|
|
65808
|
+
resolve26(false);
|
|
66742
65809
|
}
|
|
66743
65810
|
});
|
|
66744
65811
|
}
|
|
@@ -66765,16 +65832,16 @@ async function basicPager(content) {
|
|
|
66765
65832
|
break;
|
|
66766
65833
|
}
|
|
66767
65834
|
const remaining = lines.length - currentLine;
|
|
66768
|
-
await new Promise((
|
|
65835
|
+
await new Promise((resolve26) => {
|
|
66769
65836
|
rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
|
|
66770
65837
|
if (answer.toLowerCase() === "q") {
|
|
66771
65838
|
rl.close();
|
|
66772
65839
|
process.exitCode = 0;
|
|
66773
|
-
|
|
65840
|
+
resolve26();
|
|
66774
65841
|
return;
|
|
66775
65842
|
}
|
|
66776
65843
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
66777
|
-
|
|
65844
|
+
resolve26();
|
|
66778
65845
|
});
|
|
66779
65846
|
});
|
|
66780
65847
|
}
|
|
@@ -73447,7 +72514,7 @@ class ConfigVersionChecker {
|
|
|
73447
72514
|
}
|
|
73448
72515
|
// src/domains/sync/sync-engine.ts
|
|
73449
72516
|
import { lstat as lstat3, readFile as readFile34, readlink, realpath as realpath3, stat as stat9 } from "node:fs/promises";
|
|
73450
|
-
import {
|
|
72517
|
+
import { isAbsolute as isAbsolute3, join as join58, normalize as normalize7, relative as relative7 } from "node:path";
|
|
73451
72518
|
|
|
73452
72519
|
// src/services/file-operations/ownership-checker.ts
|
|
73453
72520
|
init_metadata_migration();
|
|
@@ -74808,7 +73875,7 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
74808
73875
|
if (!stats.isSymbolicLink())
|
|
74809
73876
|
break;
|
|
74810
73877
|
const target = await readlink(current);
|
|
74811
|
-
const resolvedTarget = isAbsolute3(target) ? target :
|
|
73878
|
+
const resolvedTarget = isAbsolute3(target) ? target : join58(current, "..", target);
|
|
74812
73879
|
const normalizedTarget = normalize7(resolvedTarget);
|
|
74813
73880
|
const rel = relative7(basePath, normalizedTarget);
|
|
74814
73881
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
@@ -74827,10 +73894,6 @@ async function validateSymlinkChain(path5, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
74827
73894
|
throw new Error(`Symlink chain too deep (>${maxDepth}): ${path5}`);
|
|
74828
73895
|
}
|
|
74829
73896
|
}
|
|
74830
|
-
function isOutsideBase(candidatePath, basePath) {
|
|
74831
|
-
const rel = relative7(basePath, candidatePath);
|
|
74832
|
-
return rel.startsWith("..") || isAbsolute3(rel);
|
|
74833
|
-
}
|
|
74834
73897
|
async function validateSyncPath(basePath, filePath) {
|
|
74835
73898
|
if (!filePath || filePath.trim() === "") {
|
|
74836
73899
|
throw new Error("Empty file path not allowed");
|
|
@@ -74845,43 +73908,36 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
74845
73908
|
if (isAbsolute3(normalized)) {
|
|
74846
73909
|
throw new Error(`Absolute paths not allowed: ${filePath}`);
|
|
74847
73910
|
}
|
|
74848
|
-
|
|
74849
|
-
if (pathParts.includes("..")) {
|
|
73911
|
+
if (normalized.startsWith("..") || normalized.includes("/../")) {
|
|
74850
73912
|
throw new Error(`Path traversal not allowed: ${filePath}`);
|
|
74851
73913
|
}
|
|
74852
|
-
const
|
|
74853
|
-
const
|
|
74854
|
-
|
|
74855
|
-
if (isOutsideBase(fullPath, lexicalBase)) {
|
|
73914
|
+
const fullPath = join58(basePath, normalized);
|
|
73915
|
+
const rel = relative7(basePath, fullPath);
|
|
73916
|
+
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
74856
73917
|
throw new Error(`Path escapes base directory: ${filePath}`);
|
|
74857
73918
|
}
|
|
74858
|
-
await validateSymlinkChain(fullPath,
|
|
73919
|
+
await validateSymlinkChain(fullPath, basePath);
|
|
74859
73920
|
try {
|
|
73921
|
+
const resolvedBase = await realpath3(basePath);
|
|
74860
73922
|
const resolvedFull = await realpath3(fullPath);
|
|
74861
|
-
|
|
73923
|
+
const resolvedRel = relative7(resolvedBase, resolvedFull);
|
|
73924
|
+
if (resolvedRel.startsWith("..") || isAbsolute3(resolvedRel)) {
|
|
74862
73925
|
throw new Error(`Symlink escapes base directory: ${filePath}`);
|
|
74863
73926
|
}
|
|
74864
73927
|
} catch (error) {
|
|
74865
73928
|
if (error.code === "ENOENT") {
|
|
74866
|
-
|
|
74867
|
-
|
|
74868
|
-
|
|
74869
|
-
|
|
74870
|
-
|
|
74871
|
-
|
|
74872
|
-
|
|
74873
|
-
|
|
74874
|
-
|
|
74875
|
-
|
|
74876
|
-
|
|
74877
|
-
break;
|
|
74878
|
-
}
|
|
74879
|
-
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;
|
|
74880
73940
|
}
|
|
74881
|
-
}
|
|
74882
|
-
const resolvedAncestor = await realpath3(ancestor).catch(() => null);
|
|
74883
|
-
if (!resolvedAncestor || isOutsideBase(resolvedAncestor, resolvedBase)) {
|
|
74884
|
-
throw new Error(`Parent symlink escapes base directory: ${filePath}`);
|
|
74885
73941
|
}
|
|
74886
73942
|
} else {
|
|
74887
73943
|
throw error;
|
|
@@ -75034,24 +74090,14 @@ class SyncEngine {
|
|
|
75034
74090
|
}
|
|
75035
74091
|
static async loadFileContent(filePath) {
|
|
75036
74092
|
try {
|
|
75037
|
-
const
|
|
75038
|
-
if (
|
|
74093
|
+
const lstats = await lstat3(filePath);
|
|
74094
|
+
if (lstats.isSymbolicLink()) {
|
|
75039
74095
|
throw new Error(`Symlink not allowed for sync: ${filePath}`);
|
|
75040
74096
|
}
|
|
75041
|
-
if (
|
|
75042
|
-
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)`);
|
|
75043
74099
|
}
|
|
75044
74100
|
const buffer = await readFile34(filePath);
|
|
75045
|
-
const afterStats = await lstat3(filePath);
|
|
75046
|
-
if (afterStats.isSymbolicLink()) {
|
|
75047
|
-
throw new Error(`File became symlink during read: ${filePath}`);
|
|
75048
|
-
}
|
|
75049
|
-
if (beforeStats.dev !== afterStats.dev || beforeStats.ino !== afterStats.ino) {
|
|
75050
|
-
throw new Error(`File changed identity during read: ${filePath}`);
|
|
75051
|
-
}
|
|
75052
|
-
if (beforeStats.mtimeMs !== afterStats.mtimeMs || beforeStats.size !== afterStats.size) {
|
|
75053
|
-
throw new Error(`File changed during read: ${filePath}`);
|
|
75054
|
-
}
|
|
75055
74101
|
if (buffer.includes(0)) {
|
|
75056
74102
|
return { content: "", isBinary: true };
|
|
75057
74103
|
}
|
|
@@ -76062,7 +75108,7 @@ init_logger();
|
|
|
76062
75108
|
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
76063
75109
|
import { mkdir as mkdir19 } from "node:fs/promises";
|
|
76064
75110
|
import os5 from "node:os";
|
|
76065
|
-
import { join as
|
|
75111
|
+
import { join as join65 } from "node:path";
|
|
76066
75112
|
var LOCK_CONFIG = {
|
|
76067
75113
|
stale: 60000,
|
|
76068
75114
|
retries: 0
|
|
@@ -76070,12 +75116,12 @@ var LOCK_CONFIG = {
|
|
|
76070
75116
|
var activeLocks = new Set;
|
|
76071
75117
|
var cleanupRegistered = false;
|
|
76072
75118
|
function getLocksDir() {
|
|
76073
|
-
return
|
|
75119
|
+
return join65(os5.homedir(), ".claudekit", "locks");
|
|
76074
75120
|
}
|
|
76075
75121
|
function cleanupLocks() {
|
|
76076
75122
|
for (const name of activeLocks) {
|
|
76077
75123
|
try {
|
|
76078
|
-
const lockPath =
|
|
75124
|
+
const lockPath = join65(getLocksDir(), `${name}.lock`);
|
|
76079
75125
|
import_proper_lockfile4.default.unlockSync(lockPath, { realpath: false });
|
|
76080
75126
|
} catch {
|
|
76081
75127
|
try {
|
|
@@ -76098,7 +75144,7 @@ async function ensureLocksDir() {
|
|
|
76098
75144
|
async function withProcessLock(lockName, fn) {
|
|
76099
75145
|
registerCleanupHandlers();
|
|
76100
75146
|
await ensureLocksDir();
|
|
76101
|
-
const lockPath =
|
|
75147
|
+
const lockPath = join65(getLocksDir(), `${lockName}.lock`);
|
|
76102
75148
|
let release;
|
|
76103
75149
|
try {
|
|
76104
75150
|
release = await import_proper_lockfile4.default.lock(lockPath, { ...LOCK_CONFIG, realpath: false });
|
|
@@ -76129,7 +75175,7 @@ init_logger();
|
|
|
76129
75175
|
init_logger();
|
|
76130
75176
|
init_path_resolver();
|
|
76131
75177
|
var import_fs_extra7 = __toESM(require_lib3(), 1);
|
|
76132
|
-
import { join as
|
|
75178
|
+
import { join as join66 } from "node:path";
|
|
76133
75179
|
async function handleConflicts(ctx) {
|
|
76134
75180
|
if (ctx.cancelled)
|
|
76135
75181
|
return ctx;
|
|
@@ -76138,7 +75184,7 @@ async function handleConflicts(ctx) {
|
|
|
76138
75184
|
if (PathResolver.isLocalSameAsGlobal()) {
|
|
76139
75185
|
return ctx;
|
|
76140
75186
|
}
|
|
76141
|
-
const localSettingsPath =
|
|
75187
|
+
const localSettingsPath = join66(process.cwd(), ".claude", "settings.json");
|
|
76142
75188
|
if (!await import_fs_extra7.pathExists(localSettingsPath)) {
|
|
76143
75189
|
return ctx;
|
|
76144
75190
|
}
|
|
@@ -76153,7 +75199,7 @@ async function handleConflicts(ctx) {
|
|
|
76153
75199
|
return { ...ctx, cancelled: true };
|
|
76154
75200
|
}
|
|
76155
75201
|
if (choice === "remove") {
|
|
76156
|
-
const localClaudeDir =
|
|
75202
|
+
const localClaudeDir = join66(process.cwd(), ".claude");
|
|
76157
75203
|
try {
|
|
76158
75204
|
await import_fs_extra7.remove(localClaudeDir);
|
|
76159
75205
|
logger.success("Removed local .claude/ directory");
|
|
@@ -76250,7 +75296,7 @@ init_logger();
|
|
|
76250
75296
|
init_safe_spinner();
|
|
76251
75297
|
import { mkdir as mkdir25, stat as stat12 } from "node:fs/promises";
|
|
76252
75298
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
76253
|
-
import { join as
|
|
75299
|
+
import { join as join73 } from "node:path";
|
|
76254
75300
|
|
|
76255
75301
|
// src/shared/temp-cleanup.ts
|
|
76256
75302
|
init_logger();
|
|
@@ -76269,7 +75315,7 @@ init_logger();
|
|
|
76269
75315
|
init_output_manager();
|
|
76270
75316
|
import { createWriteStream as createWriteStream2, rmSync } from "node:fs";
|
|
76271
75317
|
import { mkdir as mkdir20 } from "node:fs/promises";
|
|
76272
|
-
import { join as
|
|
75318
|
+
import { join as join67 } from "node:path";
|
|
76273
75319
|
|
|
76274
75320
|
// src/shared/progress-bar.ts
|
|
76275
75321
|
init_output_manager();
|
|
@@ -76434,10 +75480,10 @@ init_types3();
|
|
|
76434
75480
|
// src/domains/installation/utils/path-security.ts
|
|
76435
75481
|
init_types3();
|
|
76436
75482
|
import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
76437
|
-
import { relative as relative8, resolve as
|
|
75483
|
+
import { relative as relative8, resolve as resolve15 } from "node:path";
|
|
76438
75484
|
var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
|
|
76439
75485
|
function isPathSafe(basePath, targetPath) {
|
|
76440
|
-
const resolvedBase =
|
|
75486
|
+
const resolvedBase = resolve15(basePath);
|
|
76441
75487
|
try {
|
|
76442
75488
|
const stat10 = lstatSync2(targetPath);
|
|
76443
75489
|
if (stat10.isSymbolicLink()) {
|
|
@@ -76447,7 +75493,7 @@ function isPathSafe(basePath, targetPath) {
|
|
|
76447
75493
|
}
|
|
76448
75494
|
}
|
|
76449
75495
|
} catch {}
|
|
76450
|
-
const resolvedTarget =
|
|
75496
|
+
const resolvedTarget = resolve15(targetPath);
|
|
76451
75497
|
const relativePath = relative8(resolvedBase, resolvedTarget);
|
|
76452
75498
|
return !relativePath.startsWith("..") && !relativePath.startsWith("/") && resolvedTarget.startsWith(resolvedBase);
|
|
76453
75499
|
}
|
|
@@ -76479,7 +75525,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
|
|
|
76479
75525
|
class FileDownloader {
|
|
76480
75526
|
async downloadAsset(asset, destDir) {
|
|
76481
75527
|
try {
|
|
76482
|
-
const destPath =
|
|
75528
|
+
const destPath = join67(destDir, asset.name);
|
|
76483
75529
|
await mkdir20(destDir, { recursive: true });
|
|
76484
75530
|
output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
|
|
76485
75531
|
logger.verbose("Download details", {
|
|
@@ -76535,7 +75581,7 @@ class FileDownloader {
|
|
|
76535
75581
|
}
|
|
76536
75582
|
if (downloadedSize !== totalSize) {
|
|
76537
75583
|
fileStream.end();
|
|
76538
|
-
await new Promise((
|
|
75584
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76539
75585
|
try {
|
|
76540
75586
|
rmSync(destPath, { force: true });
|
|
76541
75587
|
} catch (cleanupError) {
|
|
@@ -76549,7 +75595,7 @@ class FileDownloader {
|
|
|
76549
75595
|
return destPath;
|
|
76550
75596
|
} catch (error) {
|
|
76551
75597
|
fileStream.end();
|
|
76552
|
-
await new Promise((
|
|
75598
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76553
75599
|
try {
|
|
76554
75600
|
rmSync(destPath, { force: true });
|
|
76555
75601
|
} catch (cleanupError) {
|
|
@@ -76564,7 +75610,7 @@ class FileDownloader {
|
|
|
76564
75610
|
}
|
|
76565
75611
|
async downloadFile(params) {
|
|
76566
75612
|
const { url, name, size, destDir, token } = params;
|
|
76567
|
-
const destPath =
|
|
75613
|
+
const destPath = join67(destDir, name);
|
|
76568
75614
|
await mkdir20(destDir, { recursive: true });
|
|
76569
75615
|
output.info(`Downloading ${name}${size ? ` (${formatBytes(size)})` : ""}...`);
|
|
76570
75616
|
const headers = {};
|
|
@@ -76615,7 +75661,7 @@ class FileDownloader {
|
|
|
76615
75661
|
const expectedSize = Number(response.headers.get("content-length"));
|
|
76616
75662
|
if (expectedSize > 0 && downloadedSize !== expectedSize) {
|
|
76617
75663
|
fileStream.end();
|
|
76618
|
-
await new Promise((
|
|
75664
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76619
75665
|
try {
|
|
76620
75666
|
rmSync(destPath, { force: true });
|
|
76621
75667
|
} catch (cleanupError) {
|
|
@@ -76633,7 +75679,7 @@ class FileDownloader {
|
|
|
76633
75679
|
return destPath;
|
|
76634
75680
|
} catch (error) {
|
|
76635
75681
|
fileStream.end();
|
|
76636
|
-
await new Promise((
|
|
75682
|
+
await new Promise((resolve16) => fileStream.once("close", resolve16));
|
|
76637
75683
|
try {
|
|
76638
75684
|
rmSync(destPath, { force: true });
|
|
76639
75685
|
} catch (cleanupError) {
|
|
@@ -76650,7 +75696,7 @@ init_logger();
|
|
|
76650
75696
|
init_types3();
|
|
76651
75697
|
import { constants as constants4 } from "node:fs";
|
|
76652
75698
|
import { access as access4, readdir as readdir13 } from "node:fs/promises";
|
|
76653
|
-
import { join as
|
|
75699
|
+
import { join as join68 } from "node:path";
|
|
76654
75700
|
async function validateExtraction(extractDir) {
|
|
76655
75701
|
try {
|
|
76656
75702
|
const entries = await readdir13(extractDir, { encoding: "utf8" });
|
|
@@ -76662,7 +75708,7 @@ async function validateExtraction(extractDir) {
|
|
|
76662
75708
|
const missingPaths = [];
|
|
76663
75709
|
for (const path5 of criticalPaths) {
|
|
76664
75710
|
try {
|
|
76665
|
-
await access4(
|
|
75711
|
+
await access4(join68(extractDir, path5), constants4.F_OK);
|
|
76666
75712
|
logger.debug(`Found: ${path5}`);
|
|
76667
75713
|
} catch {
|
|
76668
75714
|
logger.warning(`Expected path not found: ${path5}`);
|
|
@@ -76684,7 +75730,7 @@ async function validateExtraction(extractDir) {
|
|
|
76684
75730
|
// src/domains/installation/extraction/tar-extractor.ts
|
|
76685
75731
|
init_logger();
|
|
76686
75732
|
import { copyFile as copyFile4, mkdir as mkdir23, readdir as readdir15, rm as rm8, stat as stat10 } from "node:fs/promises";
|
|
76687
|
-
import { join as
|
|
75733
|
+
import { join as join71 } from "node:path";
|
|
76688
75734
|
|
|
76689
75735
|
// node_modules/@isaacs/fs-minipass/dist/esm/index.js
|
|
76690
75736
|
import EE from "events";
|
|
@@ -77232,10 +76278,10 @@ class Minipass extends EventEmitter3 {
|
|
|
77232
76278
|
return this[ENCODING] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
|
|
77233
76279
|
}
|
|
77234
76280
|
async promise() {
|
|
77235
|
-
return new Promise((
|
|
76281
|
+
return new Promise((resolve16, reject) => {
|
|
77236
76282
|
this.on(DESTROYED, () => reject(new Error("stream destroyed")));
|
|
77237
76283
|
this.on("error", (er) => reject(er));
|
|
77238
|
-
this.on("end", () =>
|
|
76284
|
+
this.on("end", () => resolve16());
|
|
77239
76285
|
});
|
|
77240
76286
|
}
|
|
77241
76287
|
[Symbol.asyncIterator]() {
|
|
@@ -77254,7 +76300,7 @@ class Minipass extends EventEmitter3 {
|
|
|
77254
76300
|
return Promise.resolve({ done: false, value: res });
|
|
77255
76301
|
if (this[EOF])
|
|
77256
76302
|
return stop();
|
|
77257
|
-
let
|
|
76303
|
+
let resolve16;
|
|
77258
76304
|
let reject;
|
|
77259
76305
|
const onerr = (er) => {
|
|
77260
76306
|
this.off("data", ondata);
|
|
@@ -77268,19 +76314,19 @@ class Minipass extends EventEmitter3 {
|
|
|
77268
76314
|
this.off("end", onend);
|
|
77269
76315
|
this.off(DESTROYED, ondestroy);
|
|
77270
76316
|
this.pause();
|
|
77271
|
-
|
|
76317
|
+
resolve16({ value, done: !!this[EOF] });
|
|
77272
76318
|
};
|
|
77273
76319
|
const onend = () => {
|
|
77274
76320
|
this.off("error", onerr);
|
|
77275
76321
|
this.off("data", ondata);
|
|
77276
76322
|
this.off(DESTROYED, ondestroy);
|
|
77277
76323
|
stop();
|
|
77278
|
-
|
|
76324
|
+
resolve16({ done: true, value: undefined });
|
|
77279
76325
|
};
|
|
77280
76326
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
77281
76327
|
return new Promise((res2, rej) => {
|
|
77282
76328
|
reject = rej;
|
|
77283
|
-
|
|
76329
|
+
resolve16 = res2;
|
|
77284
76330
|
this.once(DESTROYED, ondestroy);
|
|
77285
76331
|
this.once("error", onerr);
|
|
77286
76332
|
this.once("end", onend);
|
|
@@ -77737,7 +76783,7 @@ import path7 from "node:path";
|
|
|
77737
76783
|
|
|
77738
76784
|
// node_modules/tar/dist/esm/list.js
|
|
77739
76785
|
import fs9 from "node:fs";
|
|
77740
|
-
import { dirname as
|
|
76786
|
+
import { dirname as dirname17, parse as parse3 } from "path";
|
|
77741
76787
|
|
|
77742
76788
|
// node_modules/tar/dist/esm/options.js
|
|
77743
76789
|
var argmap = new Map([
|
|
@@ -78386,10 +77432,10 @@ class Minipass2 extends EventEmitter4 {
|
|
|
78386
77432
|
return this[ENCODING2] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
|
|
78387
77433
|
}
|
|
78388
77434
|
async promise() {
|
|
78389
|
-
return new Promise((
|
|
77435
|
+
return new Promise((resolve16, reject) => {
|
|
78390
77436
|
this.on(DESTROYED2, () => reject(new Error("stream destroyed")));
|
|
78391
77437
|
this.on("error", (er) => reject(er));
|
|
78392
|
-
this.on("end", () =>
|
|
77438
|
+
this.on("end", () => resolve16());
|
|
78393
77439
|
});
|
|
78394
77440
|
}
|
|
78395
77441
|
[Symbol.asyncIterator]() {
|
|
@@ -78408,7 +77454,7 @@ class Minipass2 extends EventEmitter4 {
|
|
|
78408
77454
|
return Promise.resolve({ done: false, value: res });
|
|
78409
77455
|
if (this[EOF2])
|
|
78410
77456
|
return stop();
|
|
78411
|
-
let
|
|
77457
|
+
let resolve16;
|
|
78412
77458
|
let reject;
|
|
78413
77459
|
const onerr = (er) => {
|
|
78414
77460
|
this.off("data", ondata);
|
|
@@ -78422,19 +77468,19 @@ class Minipass2 extends EventEmitter4 {
|
|
|
78422
77468
|
this.off("end", onend);
|
|
78423
77469
|
this.off(DESTROYED2, ondestroy);
|
|
78424
77470
|
this.pause();
|
|
78425
|
-
|
|
77471
|
+
resolve16({ value, done: !!this[EOF2] });
|
|
78426
77472
|
};
|
|
78427
77473
|
const onend = () => {
|
|
78428
77474
|
this.off("error", onerr);
|
|
78429
77475
|
this.off("data", ondata);
|
|
78430
77476
|
this.off(DESTROYED2, ondestroy);
|
|
78431
77477
|
stop();
|
|
78432
|
-
|
|
77478
|
+
resolve16({ done: true, value: undefined });
|
|
78433
77479
|
};
|
|
78434
77480
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
78435
77481
|
return new Promise((res2, rej) => {
|
|
78436
77482
|
reject = rej;
|
|
78437
|
-
|
|
77483
|
+
resolve16 = res2;
|
|
78438
77484
|
this.once(DESTROYED2, ondestroy);
|
|
78439
77485
|
this.once("error", onerr);
|
|
78440
77486
|
this.once("end", onend);
|
|
@@ -79862,10 +78908,10 @@ class Minipass3 extends EventEmitter5 {
|
|
|
79862
78908
|
return this[ENCODING3] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
|
|
79863
78909
|
}
|
|
79864
78910
|
async promise() {
|
|
79865
|
-
return new Promise((
|
|
78911
|
+
return new Promise((resolve16, reject) => {
|
|
79866
78912
|
this.on(DESTROYED3, () => reject(new Error("stream destroyed")));
|
|
79867
78913
|
this.on("error", (er) => reject(er));
|
|
79868
|
-
this.on("end", () =>
|
|
78914
|
+
this.on("end", () => resolve16());
|
|
79869
78915
|
});
|
|
79870
78916
|
}
|
|
79871
78917
|
[Symbol.asyncIterator]() {
|
|
@@ -79884,7 +78930,7 @@ class Minipass3 extends EventEmitter5 {
|
|
|
79884
78930
|
return Promise.resolve({ done: false, value: res });
|
|
79885
78931
|
if (this[EOF3])
|
|
79886
78932
|
return stop();
|
|
79887
|
-
let
|
|
78933
|
+
let resolve16;
|
|
79888
78934
|
let reject;
|
|
79889
78935
|
const onerr = (er) => {
|
|
79890
78936
|
this.off("data", ondata);
|
|
@@ -79898,19 +78944,19 @@ class Minipass3 extends EventEmitter5 {
|
|
|
79898
78944
|
this.off("end", onend);
|
|
79899
78945
|
this.off(DESTROYED3, ondestroy);
|
|
79900
78946
|
this.pause();
|
|
79901
|
-
|
|
78947
|
+
resolve16({ value, done: !!this[EOF3] });
|
|
79902
78948
|
};
|
|
79903
78949
|
const onend = () => {
|
|
79904
78950
|
this.off("error", onerr);
|
|
79905
78951
|
this.off("data", ondata);
|
|
79906
78952
|
this.off(DESTROYED3, ondestroy);
|
|
79907
78953
|
stop();
|
|
79908
|
-
|
|
78954
|
+
resolve16({ done: true, value: undefined });
|
|
79909
78955
|
};
|
|
79910
78956
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
79911
78957
|
return new Promise((res2, rej) => {
|
|
79912
78958
|
reject = rej;
|
|
79913
|
-
|
|
78959
|
+
resolve16 = res2;
|
|
79914
78960
|
this.once(DESTROYED3, ondestroy);
|
|
79915
78961
|
this.once("error", onerr);
|
|
79916
78962
|
this.once("end", onend);
|
|
@@ -80637,7 +79683,7 @@ var filesFilter = (opt, files) => {
|
|
|
80637
79683
|
if (m2 !== undefined) {
|
|
80638
79684
|
ret = m2;
|
|
80639
79685
|
} else {
|
|
80640
|
-
ret = mapHas(
|
|
79686
|
+
ret = mapHas(dirname17(file), root);
|
|
80641
79687
|
}
|
|
80642
79688
|
}
|
|
80643
79689
|
map.set(file, ret);
|
|
@@ -80681,9 +79727,9 @@ var listFile = (opt, _files) => {
|
|
|
80681
79727
|
const parse4 = new Parser(opt);
|
|
80682
79728
|
const readSize = opt.maxReadSize || 16 * 1024 * 1024;
|
|
80683
79729
|
const file = opt.file;
|
|
80684
|
-
const p = new Promise((
|
|
79730
|
+
const p = new Promise((resolve16, reject) => {
|
|
80685
79731
|
parse4.on("error", reject);
|
|
80686
|
-
parse4.on("end",
|
|
79732
|
+
parse4.on("end", resolve16);
|
|
80687
79733
|
fs9.stat(file, (er, stat10) => {
|
|
80688
79734
|
if (er) {
|
|
80689
79735
|
reject(er);
|
|
@@ -82446,7 +81492,7 @@ var mkdirSync = (dir, opt) => {
|
|
|
82446
81492
|
};
|
|
82447
81493
|
|
|
82448
81494
|
// node_modules/tar/dist/esm/path-reservations.js
|
|
82449
|
-
import { join as
|
|
81495
|
+
import { join as join69 } from "node:path";
|
|
82450
81496
|
|
|
82451
81497
|
// node_modules/tar/dist/esm/normalize-unicode.js
|
|
82452
81498
|
var normalizeCache = Object.create(null);
|
|
@@ -82479,7 +81525,7 @@ var getDirs = (path10) => {
|
|
|
82479
81525
|
const dirs = path10.split("/").slice(0, -1).reduce((set, path11) => {
|
|
82480
81526
|
const s = set[set.length - 1];
|
|
82481
81527
|
if (s !== undefined) {
|
|
82482
|
-
path11 =
|
|
81528
|
+
path11 = join69(s, path11);
|
|
82483
81529
|
}
|
|
82484
81530
|
set.push(path11 || "/");
|
|
82485
81531
|
return set;
|
|
@@ -82493,7 +81539,7 @@ class PathReservations {
|
|
|
82493
81539
|
#running = new Set;
|
|
82494
81540
|
reserve(paths, fn) {
|
|
82495
81541
|
paths = isWindows4 ? ["win32 parallelization disabled"] : paths.map((p) => {
|
|
82496
|
-
return stripTrailingSlashes(
|
|
81542
|
+
return stripTrailingSlashes(join69(normalizeUnicode(p))).toLowerCase();
|
|
82497
81543
|
});
|
|
82498
81544
|
const dirs = new Set(paths.map((path10) => getDirs(path10)).reduce((a3, b3) => a3.concat(b3)));
|
|
82499
81545
|
this.#reservations.set(fn, { dirs, paths });
|
|
@@ -83263,9 +82309,9 @@ var extractFile = (opt, _3) => {
|
|
|
83263
82309
|
const u = new Unpack(opt);
|
|
83264
82310
|
const readSize = opt.maxReadSize || 16 * 1024 * 1024;
|
|
83265
82311
|
const file = opt.file;
|
|
83266
|
-
const p = new Promise((
|
|
82312
|
+
const p = new Promise((resolve16, reject) => {
|
|
83267
82313
|
u.on("error", reject);
|
|
83268
|
-
u.on("close",
|
|
82314
|
+
u.on("close", resolve16);
|
|
83269
82315
|
fs16.stat(file, (er, stat10) => {
|
|
83270
82316
|
if (er) {
|
|
83271
82317
|
reject(er);
|
|
@@ -83398,7 +82444,7 @@ var replaceAsync = (opt, files) => {
|
|
|
83398
82444
|
};
|
|
83399
82445
|
fs17.read(fd, headBuf, 0, 512, position, onread);
|
|
83400
82446
|
};
|
|
83401
|
-
const promise = new Promise((
|
|
82447
|
+
const promise = new Promise((resolve16, reject) => {
|
|
83402
82448
|
p.on("error", reject);
|
|
83403
82449
|
let flag = "r+";
|
|
83404
82450
|
const onopen = (er, fd) => {
|
|
@@ -83423,7 +82469,7 @@ var replaceAsync = (opt, files) => {
|
|
|
83423
82469
|
});
|
|
83424
82470
|
p.pipe(stream);
|
|
83425
82471
|
stream.on("error", reject);
|
|
83426
|
-
stream.on("close",
|
|
82472
|
+
stream.on("close", resolve16);
|
|
83427
82473
|
addFilesAsync2(p, files);
|
|
83428
82474
|
});
|
|
83429
82475
|
});
|
|
@@ -83553,7 +82599,7 @@ function decodeFilePath(path12) {
|
|
|
83553
82599
|
init_logger();
|
|
83554
82600
|
init_types3();
|
|
83555
82601
|
import { copyFile as copyFile3, lstat as lstat4, mkdir as mkdir22, readdir as readdir14 } from "node:fs/promises";
|
|
83556
|
-
import { join as
|
|
82602
|
+
import { join as join70, relative as relative9 } from "node:path";
|
|
83557
82603
|
async function withRetry(fn, retries = 3) {
|
|
83558
82604
|
for (let i = 0;i < retries; i++) {
|
|
83559
82605
|
try {
|
|
@@ -83575,8 +82621,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
|
|
|
83575
82621
|
await mkdir22(destDir, { recursive: true });
|
|
83576
82622
|
const entries = await readdir14(sourceDir, { encoding: "utf8" });
|
|
83577
82623
|
for (const entry of entries) {
|
|
83578
|
-
const sourcePath =
|
|
83579
|
-
const destPath =
|
|
82624
|
+
const sourcePath = join70(sourceDir, entry);
|
|
82625
|
+
const destPath = join70(destDir, entry);
|
|
83580
82626
|
const relativePath = relative9(sourceDir, sourcePath);
|
|
83581
82627
|
if (!isPathSafe(destDir, destPath)) {
|
|
83582
82628
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -83603,8 +82649,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
|
|
|
83603
82649
|
await mkdir22(destDir, { recursive: true });
|
|
83604
82650
|
const entries = await readdir14(sourceDir, { encoding: "utf8" });
|
|
83605
82651
|
for (const entry of entries) {
|
|
83606
|
-
const sourcePath =
|
|
83607
|
-
const destPath =
|
|
82652
|
+
const sourcePath = join70(sourceDir, entry);
|
|
82653
|
+
const destPath = join70(destDir, entry);
|
|
83608
82654
|
const relativePath = relative9(sourceDir, sourcePath);
|
|
83609
82655
|
if (!isPathSafe(destDir, destPath)) {
|
|
83610
82656
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -83652,7 +82698,7 @@ class TarExtractor {
|
|
|
83652
82698
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
83653
82699
|
if (entries.length === 1) {
|
|
83654
82700
|
const rootEntry = entries[0];
|
|
83655
|
-
const rootPath =
|
|
82701
|
+
const rootPath = join71(tempExtractDir, rootEntry);
|
|
83656
82702
|
const rootStat = await stat10(rootPath);
|
|
83657
82703
|
if (rootStat.isDirectory()) {
|
|
83658
82704
|
const rootContents = await readdir15(rootPath, { encoding: "utf8" });
|
|
@@ -83668,7 +82714,7 @@ class TarExtractor {
|
|
|
83668
82714
|
}
|
|
83669
82715
|
} else {
|
|
83670
82716
|
await mkdir23(destDir, { recursive: true });
|
|
83671
|
-
await copyFile4(rootPath,
|
|
82717
|
+
await copyFile4(rootPath, join71(destDir, rootEntry));
|
|
83672
82718
|
}
|
|
83673
82719
|
} else {
|
|
83674
82720
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -83691,26 +82737,26 @@ init_logger();
|
|
|
83691
82737
|
var import_extract_zip = __toESM(require_extract_zip(), 1);
|
|
83692
82738
|
import { execFile as execFile8 } from "node:child_process";
|
|
83693
82739
|
import { copyFile as copyFile5, mkdir as mkdir24, readdir as readdir16, rm as rm9, stat as stat11 } from "node:fs/promises";
|
|
83694
|
-
import { join as
|
|
82740
|
+
import { join as join72 } from "node:path";
|
|
83695
82741
|
class ZipExtractor {
|
|
83696
82742
|
async tryNativeUnzip(archivePath, destDir) {
|
|
83697
82743
|
if (!isMacOS()) {
|
|
83698
82744
|
return false;
|
|
83699
82745
|
}
|
|
83700
|
-
return new Promise((
|
|
82746
|
+
return new Promise((resolve16) => {
|
|
83701
82747
|
mkdir24(destDir, { recursive: true }).then(() => {
|
|
83702
82748
|
execFile8("unzip", ["-o", "-q", archivePath, "-d", destDir], (error, _stdout, stderr) => {
|
|
83703
82749
|
if (error) {
|
|
83704
82750
|
logger.debug(`Native unzip failed: ${stderr || error.message}`);
|
|
83705
|
-
|
|
82751
|
+
resolve16(false);
|
|
83706
82752
|
return;
|
|
83707
82753
|
}
|
|
83708
82754
|
logger.debug("Native unzip succeeded");
|
|
83709
|
-
|
|
82755
|
+
resolve16(true);
|
|
83710
82756
|
});
|
|
83711
82757
|
}).catch((err) => {
|
|
83712
82758
|
logger.debug(`Failed to create directory for native unzip: ${err.message}`);
|
|
83713
|
-
|
|
82759
|
+
resolve16(false);
|
|
83714
82760
|
});
|
|
83715
82761
|
});
|
|
83716
82762
|
}
|
|
@@ -83739,7 +82785,7 @@ class ZipExtractor {
|
|
|
83739
82785
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
83740
82786
|
if (entries.length === 1) {
|
|
83741
82787
|
const rootEntry = entries[0];
|
|
83742
|
-
const rootPath =
|
|
82788
|
+
const rootPath = join72(tempExtractDir, rootEntry);
|
|
83743
82789
|
const rootStat = await stat11(rootPath);
|
|
83744
82790
|
if (rootStat.isDirectory()) {
|
|
83745
82791
|
const rootContents = await readdir16(rootPath, { encoding: "utf8" });
|
|
@@ -83755,7 +82801,7 @@ class ZipExtractor {
|
|
|
83755
82801
|
}
|
|
83756
82802
|
} else {
|
|
83757
82803
|
await mkdir24(destDir, { recursive: true });
|
|
83758
|
-
await copyFile5(rootPath,
|
|
82804
|
+
await copyFile5(rootPath, join72(destDir, rootEntry));
|
|
83759
82805
|
}
|
|
83760
82806
|
} else {
|
|
83761
82807
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -83854,7 +82900,7 @@ class DownloadManager {
|
|
|
83854
82900
|
async createTempDir() {
|
|
83855
82901
|
const timestamp = Date.now();
|
|
83856
82902
|
const counter = DownloadManager.tempDirCounter++;
|
|
83857
|
-
const primaryTempDir =
|
|
82903
|
+
const primaryTempDir = join73(tmpdir4(), `claudekit-${timestamp}-${counter}`);
|
|
83858
82904
|
try {
|
|
83859
82905
|
await mkdir25(primaryTempDir, { recursive: true });
|
|
83860
82906
|
logger.debug(`Created temp directory: ${primaryTempDir}`);
|
|
@@ -83871,7 +82917,7 @@ Solutions:
|
|
|
83871
82917
|
2. Set HOME environment variable
|
|
83872
82918
|
3. Try running from a different directory`);
|
|
83873
82919
|
}
|
|
83874
|
-
const fallbackTempDir =
|
|
82920
|
+
const fallbackTempDir = join73(homeDir, ".claudekit", "tmp", `claudekit-${timestamp}-${counter}`);
|
|
83875
82921
|
try {
|
|
83876
82922
|
await mkdir25(fallbackTempDir, { recursive: true });
|
|
83877
82923
|
logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
|
|
@@ -84220,8 +83266,349 @@ async function handleDownload(ctx) {
|
|
|
84220
83266
|
};
|
|
84221
83267
|
}
|
|
84222
83268
|
// src/commands/init/phases/merge-handler.ts
|
|
84223
|
-
|
|
84224
|
-
|
|
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
|
+
}
|
|
84225
83612
|
|
|
84226
83613
|
// src/domains/installation/file-merger.ts
|
|
84227
83614
|
init_logger();
|
|
@@ -84233,10 +83620,9 @@ init_logger();
|
|
|
84233
83620
|
init_types3();
|
|
84234
83621
|
var import_fs_extra12 = __toESM(require_lib3(), 1);
|
|
84235
83622
|
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
84236
|
-
import { dirname as
|
|
83623
|
+
import { dirname as dirname20, join as join79, relative as relative12 } from "node:path";
|
|
84237
83624
|
|
|
84238
83625
|
// src/domains/installation/selective-merger.ts
|
|
84239
|
-
init_manifest_reader();
|
|
84240
83626
|
import { stat as stat13 } from "node:fs/promises";
|
|
84241
83627
|
init_logger();
|
|
84242
83628
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
@@ -84413,7 +83799,7 @@ init_logger();
|
|
|
84413
83799
|
var import_fs_extra10 = __toESM(require_lib3(), 1);
|
|
84414
83800
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
84415
83801
|
import { relative as relative11 } from "node:path";
|
|
84416
|
-
import { join as
|
|
83802
|
+
import { join as join77 } from "node:path";
|
|
84417
83803
|
|
|
84418
83804
|
// node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
84419
83805
|
var balanced = (a3, b3, str2) => {
|
|
@@ -85869,7 +85255,7 @@ class FileScanner {
|
|
|
85869
85255
|
const files = [];
|
|
85870
85256
|
const entries = await import_fs_extra10.readdir(dir, { encoding: "utf8" });
|
|
85871
85257
|
for (const entry of entries) {
|
|
85872
|
-
const fullPath =
|
|
85258
|
+
const fullPath = join77(dir, entry);
|
|
85873
85259
|
const relativePath = relative11(baseDir, fullPath);
|
|
85874
85260
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
85875
85261
|
const stats = await import_fs_extra10.lstat(fullPath);
|
|
@@ -85909,7 +85295,7 @@ import { execSync as execSync4 } from "node:child_process";
|
|
|
85909
85295
|
init_shared();
|
|
85910
85296
|
import { existsSync as existsSync49 } from "node:fs";
|
|
85911
85297
|
import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "node:fs/promises";
|
|
85912
|
-
import { dirname as
|
|
85298
|
+
import { dirname as dirname19, join as join78 } from "node:path";
|
|
85913
85299
|
var CK_JSON_FILE = ".ck.json";
|
|
85914
85300
|
|
|
85915
85301
|
class InstalledSettingsTracker {
|
|
@@ -85923,9 +85309,9 @@ class InstalledSettingsTracker {
|
|
|
85923
85309
|
}
|
|
85924
85310
|
getCkJsonPath() {
|
|
85925
85311
|
if (this.isGlobal) {
|
|
85926
|
-
return
|
|
85312
|
+
return join78(this.projectDir, CK_JSON_FILE);
|
|
85927
85313
|
}
|
|
85928
|
-
return
|
|
85314
|
+
return join78(this.projectDir, ".claude", CK_JSON_FILE);
|
|
85929
85315
|
}
|
|
85930
85316
|
async loadInstalledSettings() {
|
|
85931
85317
|
const ckJsonPath = this.getCkJsonPath();
|
|
@@ -85960,7 +85346,7 @@ class InstalledSettingsTracker {
|
|
|
85960
85346
|
data.kits[this.kitName] = {};
|
|
85961
85347
|
}
|
|
85962
85348
|
data.kits[this.kitName].installedSettings = settings;
|
|
85963
|
-
await mkdir26(
|
|
85349
|
+
await mkdir26(dirname19(ckJsonPath), { recursive: true });
|
|
85964
85350
|
await writeFile22(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
|
|
85965
85351
|
logger.debug(`Saved installed settings to ${ckJsonPath}`);
|
|
85966
85352
|
} catch (error) {
|
|
@@ -86478,7 +85864,7 @@ class CopyExecutor {
|
|
|
86478
85864
|
for (const file of files) {
|
|
86479
85865
|
const relativePath = relative12(sourceDir, file);
|
|
86480
85866
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
86481
|
-
const destPath =
|
|
85867
|
+
const destPath = join79(destDir, relativePath);
|
|
86482
85868
|
if (await import_fs_extra12.pathExists(destPath)) {
|
|
86483
85869
|
if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
|
|
86484
85870
|
logger.debug(`Security-sensitive file exists but won't be overwritten: ${normalizedRelativePath}`);
|
|
@@ -86500,7 +85886,7 @@ class CopyExecutor {
|
|
|
86500
85886
|
for (const file of files) {
|
|
86501
85887
|
const relativePath = relative12(sourceDir, file);
|
|
86502
85888
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
86503
|
-
const destPath =
|
|
85889
|
+
const destPath = join79(destDir, relativePath);
|
|
86504
85890
|
if (this.fileScanner.shouldNeverCopy(normalizedRelativePath)) {
|
|
86505
85891
|
logger.debug(`Skipping security-sensitive file: ${normalizedRelativePath}`);
|
|
86506
85892
|
skippedCount++;
|
|
@@ -86577,10 +85963,10 @@ class CopyExecutor {
|
|
|
86577
85963
|
}
|
|
86578
85964
|
trackInstalledFile(relativePath) {
|
|
86579
85965
|
this.installedFiles.add(relativePath);
|
|
86580
|
-
let dir =
|
|
85966
|
+
let dir = dirname20(relativePath);
|
|
86581
85967
|
while (dir && dir !== "." && dir !== "/") {
|
|
86582
85968
|
this.installedDirectories.add(`${dir}/`);
|
|
86583
|
-
dir =
|
|
85969
|
+
dir = dirname20(dir);
|
|
86584
85970
|
}
|
|
86585
85971
|
}
|
|
86586
85972
|
}
|
|
@@ -86670,19 +86056,15 @@ class FileMerger {
|
|
|
86670
86056
|
|
|
86671
86057
|
// src/domains/migration/legacy-migration.ts
|
|
86672
86058
|
import { readdir as readdir18, stat as stat14 } from "node:fs/promises";
|
|
86673
|
-
import { join as
|
|
86674
|
-
|
|
86675
|
-
// src/services/file-operations/manifest/index.ts
|
|
86676
|
-
init_manifest_reader();
|
|
86677
|
-
|
|
86059
|
+
import { join as join83, relative as relative13 } from "node:path";
|
|
86678
86060
|
// src/services/file-operations/manifest/manifest-tracker.ts
|
|
86679
|
-
import { join as
|
|
86061
|
+
import { join as join82 } from "node:path";
|
|
86680
86062
|
|
|
86681
86063
|
// src/domains/migration/release-manifest.ts
|
|
86682
86064
|
init_logger();
|
|
86683
86065
|
init_zod();
|
|
86684
86066
|
var import_fs_extra13 = __toESM(require_lib3(), 1);
|
|
86685
|
-
import { join as
|
|
86067
|
+
import { join as join80 } from "node:path";
|
|
86686
86068
|
var ReleaseManifestFileSchema = exports_external.object({
|
|
86687
86069
|
path: exports_external.string(),
|
|
86688
86070
|
checksum: exports_external.string().regex(/^[a-f0-9]{64}$/),
|
|
@@ -86697,7 +86079,7 @@ var ReleaseManifestSchema = exports_external.object({
|
|
|
86697
86079
|
|
|
86698
86080
|
class ReleaseManifestLoader {
|
|
86699
86081
|
static async load(extractDir) {
|
|
86700
|
-
const manifestPath =
|
|
86082
|
+
const manifestPath = join80(extractDir, "release-manifest.json");
|
|
86701
86083
|
try {
|
|
86702
86084
|
const content = await import_fs_extra13.readFile(manifestPath, "utf-8");
|
|
86703
86085
|
const parsed = JSON.parse(content);
|
|
@@ -86721,12 +86103,11 @@ init_safe_spinner();
|
|
|
86721
86103
|
init_metadata_migration();
|
|
86722
86104
|
init_logger();
|
|
86723
86105
|
init_types3();
|
|
86724
|
-
init_manifest_reader();
|
|
86725
86106
|
var import_fs_extra14 = __toESM(require_lib3(), 1);
|
|
86726
86107
|
var import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
|
|
86727
|
-
import { join as
|
|
86108
|
+
import { join as join81 } from "node:path";
|
|
86728
86109
|
async function writeManifest(claudeDir2, kitName, version, scope, kitType, trackedFiles, userConfigFiles) {
|
|
86729
|
-
const metadataPath =
|
|
86110
|
+
const metadataPath = join81(claudeDir2, "metadata.json");
|
|
86730
86111
|
const kit = kitType || (/\bmarketing\b/i.test(kitName) ? "marketing" : "engineer");
|
|
86731
86112
|
await import_fs_extra14.ensureFile(metadataPath);
|
|
86732
86113
|
let release = null;
|
|
@@ -86746,54 +86127,20 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
|
|
|
86746
86127
|
const content = await import_fs_extra14.readFile(metadataPath, "utf-8");
|
|
86747
86128
|
const parsed = JSON.parse(content);
|
|
86748
86129
|
if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
|
|
86749
|
-
|
|
86750
|
-
if (validatedExisting.success) {
|
|
86751
|
-
existingMetadata = validatedExisting.data;
|
|
86752
|
-
} else {
|
|
86753
|
-
logger.warning("Existing metadata.json is invalid; preserving recoverable fields and rebuilding the rest");
|
|
86754
|
-
const raw2 = parsed;
|
|
86755
|
-
const recoveredKits = {};
|
|
86756
|
-
if (raw2.kits && typeof raw2.kits === "object") {
|
|
86757
|
-
for (const [rawKitName, rawKitValue] of Object.entries(raw2.kits)) {
|
|
86758
|
-
if ((rawKitName === "engineer" || rawKitName === "marketing") && rawKitValue && typeof rawKitValue === "object") {
|
|
86759
|
-
const recoveredKit = rawKitValue;
|
|
86760
|
-
if (typeof recoveredKit.version === "string" && typeof recoveredKit.installedAt === "string") {
|
|
86761
|
-
recoveredKits[rawKitName] = recoveredKit;
|
|
86762
|
-
}
|
|
86763
|
-
}
|
|
86764
|
-
}
|
|
86765
|
-
}
|
|
86766
|
-
existingMetadata = {
|
|
86767
|
-
kits: recoveredKits,
|
|
86768
|
-
scope: raw2.scope === "local" || raw2.scope === "global" ? raw2.scope : undefined,
|
|
86769
|
-
name: typeof raw2.name === "string" ? raw2.name : undefined,
|
|
86770
|
-
version: typeof raw2.version === "string" ? raw2.version : undefined,
|
|
86771
|
-
installedAt: typeof raw2.installedAt === "string" ? raw2.installedAt : undefined,
|
|
86772
|
-
userConfigFiles: Array.isArray(raw2.userConfigFiles) ? raw2.userConfigFiles.filter((entry) => typeof entry === "string") : undefined
|
|
86773
|
-
};
|
|
86774
|
-
}
|
|
86130
|
+
existingMetadata = parsed;
|
|
86775
86131
|
}
|
|
86776
86132
|
} catch (error) {
|
|
86777
86133
|
logger.debug(`Could not read existing metadata: ${error}`);
|
|
86778
86134
|
}
|
|
86779
86135
|
}
|
|
86780
86136
|
const installedAt = new Date().toISOString();
|
|
86781
|
-
const existingKits = existingMetadata.kits || {};
|
|
86782
|
-
const existingKitMetadata = existingKits[kit];
|
|
86783
86137
|
const kitMetadata = {
|
|
86784
|
-
...existingKitMetadata,
|
|
86785
86138
|
version,
|
|
86786
86139
|
installedAt,
|
|
86787
86140
|
files: trackedFiles.length > 0 ? trackedFiles : undefined
|
|
86788
86141
|
};
|
|
86142
|
+
const existingKits = existingMetadata.kits || {};
|
|
86789
86143
|
const otherKitsExist = Object.keys(existingKits).some((k2) => k2 !== kit);
|
|
86790
|
-
const mergedUserConfigFiles = [
|
|
86791
|
-
...new Set([
|
|
86792
|
-
...existingMetadata.userConfigFiles || [],
|
|
86793
|
-
...USER_CONFIG_PATTERNS,
|
|
86794
|
-
...userConfigFiles
|
|
86795
|
-
])
|
|
86796
|
-
];
|
|
86797
86144
|
const metadata = {
|
|
86798
86145
|
kits: {
|
|
86799
86146
|
...existingKits,
|
|
@@ -86803,7 +86150,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
|
|
|
86803
86150
|
name: otherKitsExist ? existingMetadata.name ?? kitName : kitName,
|
|
86804
86151
|
version: otherKitsExist ? existingMetadata.version ?? version : version,
|
|
86805
86152
|
installedAt: otherKitsExist ? existingMetadata.installedAt ?? installedAt : installedAt,
|
|
86806
|
-
userConfigFiles:
|
|
86153
|
+
userConfigFiles: [...USER_CONFIG_PATTERNS, ...userConfigFiles]
|
|
86807
86154
|
};
|
|
86808
86155
|
const validated = MetadataSchema.parse(metadata);
|
|
86809
86156
|
await import_fs_extra14.writeFile(metadataPath, JSON.stringify(validated, null, 2), "utf-8");
|
|
@@ -86816,7 +86163,7 @@ async function writeManifest(claudeDir2, kitName, version, scope, kitType, track
|
|
|
86816
86163
|
}
|
|
86817
86164
|
}
|
|
86818
86165
|
async function removeKitFromManifest(claudeDir2, kit) {
|
|
86819
|
-
const metadataPath =
|
|
86166
|
+
const metadataPath = join81(claudeDir2, "metadata.json");
|
|
86820
86167
|
if (!await import_fs_extra14.pathExists(metadataPath))
|
|
86821
86168
|
return false;
|
|
86822
86169
|
let release = null;
|
|
@@ -86946,7 +86293,7 @@ function buildFileTrackingList(options2) {
|
|
|
86946
86293
|
if (!isGlobal && !installedPath.startsWith(".claude/"))
|
|
86947
86294
|
continue;
|
|
86948
86295
|
const relativePath = isGlobal ? installedPath : installedPath.replace(/^\.claude\//, "");
|
|
86949
|
-
const filePath =
|
|
86296
|
+
const filePath = join82(claudeDir2, relativePath);
|
|
86950
86297
|
const manifestEntry = releaseManifest ? ReleaseManifestLoader.findFile(releaseManifest, installedPath) : null;
|
|
86951
86298
|
const ownership = manifestEntry ? "ck" : "user";
|
|
86952
86299
|
filesToTrack.push({
|
|
@@ -87053,7 +86400,7 @@ class LegacyMigration {
|
|
|
87053
86400
|
continue;
|
|
87054
86401
|
if (SKIP_DIRS_ALL.includes(entry))
|
|
87055
86402
|
continue;
|
|
87056
|
-
const fullPath =
|
|
86403
|
+
const fullPath = join83(dir, entry);
|
|
87057
86404
|
let stats;
|
|
87058
86405
|
try {
|
|
87059
86406
|
stats = await stat14(fullPath);
|
|
@@ -87155,7 +86502,7 @@ User-created files (sample):`);
|
|
|
87155
86502
|
];
|
|
87156
86503
|
if (filesToChecksum.length > 0) {
|
|
87157
86504
|
const checksumResults = await mapWithLimit(filesToChecksum, async ({ relativePath, ownership }) => {
|
|
87158
|
-
const fullPath =
|
|
86505
|
+
const fullPath = join83(claudeDir2, relativePath);
|
|
87159
86506
|
const checksum = await OwnershipChecker.calculateChecksum(fullPath);
|
|
87160
86507
|
return { relativePath, checksum, ownership };
|
|
87161
86508
|
});
|
|
@@ -87176,7 +86523,7 @@ User-created files (sample):`);
|
|
|
87176
86523
|
installedAt: new Date().toISOString(),
|
|
87177
86524
|
files: trackedFiles
|
|
87178
86525
|
};
|
|
87179
|
-
const metadataPath =
|
|
86526
|
+
const metadataPath = join83(claudeDir2, "metadata.json");
|
|
87180
86527
|
await import_fs_extra15.writeFile(metadataPath, JSON.stringify(updatedMetadata, null, 2));
|
|
87181
86528
|
logger.success(`Migration complete: tracked ${trackedFiles.length} files`);
|
|
87182
86529
|
return true;
|
|
@@ -87282,7 +86629,7 @@ function buildConflictSummary(fileConflicts, hookConflicts, mcpConflicts) {
|
|
|
87282
86629
|
init_logger();
|
|
87283
86630
|
init_skip_directories();
|
|
87284
86631
|
var import_fs_extra16 = __toESM(require_lib3(), 1);
|
|
87285
|
-
import { join as
|
|
86632
|
+
import { join as join84, relative as relative14, resolve as resolve18 } from "node:path";
|
|
87286
86633
|
|
|
87287
86634
|
class FileScanner2 {
|
|
87288
86635
|
static async getFiles(dirPath, relativeTo) {
|
|
@@ -87298,7 +86645,7 @@ class FileScanner2 {
|
|
|
87298
86645
|
logger.debug(`Skipping directory: ${entry}`);
|
|
87299
86646
|
continue;
|
|
87300
86647
|
}
|
|
87301
|
-
const fullPath =
|
|
86648
|
+
const fullPath = join84(dirPath, entry);
|
|
87302
86649
|
if (!FileScanner2.isSafePath(basePath, fullPath)) {
|
|
87303
86650
|
logger.warning(`Skipping potentially unsafe path: ${entry}`);
|
|
87304
86651
|
continue;
|
|
@@ -87333,8 +86680,8 @@ class FileScanner2 {
|
|
|
87333
86680
|
return files;
|
|
87334
86681
|
}
|
|
87335
86682
|
static async findCustomFiles(destDir, sourceDir, subPath) {
|
|
87336
|
-
const destSubDir =
|
|
87337
|
-
const sourceSubDir =
|
|
86683
|
+
const destSubDir = join84(destDir, subPath);
|
|
86684
|
+
const sourceSubDir = join84(sourceDir, subPath);
|
|
87338
86685
|
logger.debug(`findCustomFiles - destDir: ${destDir}`);
|
|
87339
86686
|
logger.debug(`findCustomFiles - sourceDir: ${sourceDir}`);
|
|
87340
86687
|
logger.debug(`findCustomFiles - subPath: "${subPath}"`);
|
|
@@ -87362,8 +86709,8 @@ class FileScanner2 {
|
|
|
87362
86709
|
return customFiles;
|
|
87363
86710
|
}
|
|
87364
86711
|
static isSafePath(basePath, targetPath) {
|
|
87365
|
-
const resolvedBase =
|
|
87366
|
-
const resolvedTarget =
|
|
86712
|
+
const resolvedBase = resolve18(basePath);
|
|
86713
|
+
const resolvedTarget = resolve18(targetPath);
|
|
87367
86714
|
return resolvedTarget.startsWith(resolvedBase);
|
|
87368
86715
|
}
|
|
87369
86716
|
static toPosixPath(path14) {
|
|
@@ -87375,12 +86722,12 @@ class FileScanner2 {
|
|
|
87375
86722
|
init_logger();
|
|
87376
86723
|
var import_fs_extra17 = __toESM(require_lib3(), 1);
|
|
87377
86724
|
import { lstat as lstat7, mkdir as mkdir27, readdir as readdir21, stat as stat15 } from "node:fs/promises";
|
|
87378
|
-
import { join as
|
|
86725
|
+
import { join as join86 } from "node:path";
|
|
87379
86726
|
|
|
87380
86727
|
// src/services/transformers/commands-prefix/content-transformer.ts
|
|
87381
86728
|
init_logger();
|
|
87382
86729
|
import { readFile as readFile42, readdir as readdir20, writeFile as writeFile26 } from "node:fs/promises";
|
|
87383
|
-
import { join as
|
|
86730
|
+
import { join as join85 } from "node:path";
|
|
87384
86731
|
var TRANSFORMABLE_EXTENSIONS = new Set([
|
|
87385
86732
|
".md",
|
|
87386
86733
|
".txt",
|
|
@@ -87441,7 +86788,7 @@ async function transformCommandReferences(directory, options2 = {}) {
|
|
|
87441
86788
|
async function processDirectory(dir) {
|
|
87442
86789
|
const entries = await readdir20(dir, { withFileTypes: true });
|
|
87443
86790
|
for (const entry of entries) {
|
|
87444
|
-
const fullPath =
|
|
86791
|
+
const fullPath = join85(dir, entry.name);
|
|
87445
86792
|
if (entry.isDirectory()) {
|
|
87446
86793
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
87447
86794
|
continue;
|
|
@@ -87516,14 +86863,14 @@ function shouldApplyPrefix(options2) {
|
|
|
87516
86863
|
// src/services/transformers/commands-prefix/prefix-applier.ts
|
|
87517
86864
|
async function applyPrefix(extractDir) {
|
|
87518
86865
|
validatePath(extractDir, "extractDir");
|
|
87519
|
-
const commandsDir =
|
|
86866
|
+
const commandsDir = join86(extractDir, ".claude", "commands");
|
|
87520
86867
|
if (!await import_fs_extra17.pathExists(commandsDir)) {
|
|
87521
86868
|
logger.verbose("No commands directory found, skipping prefix application");
|
|
87522
86869
|
return;
|
|
87523
86870
|
}
|
|
87524
86871
|
logger.info("Applying /ck: prefix to slash commands...");
|
|
87525
|
-
const backupDir =
|
|
87526
|
-
const tempDir =
|
|
86872
|
+
const backupDir = join86(extractDir, ".commands-backup");
|
|
86873
|
+
const tempDir = join86(extractDir, ".commands-prefix-temp");
|
|
87527
86874
|
try {
|
|
87528
86875
|
const entries = await readdir21(commandsDir);
|
|
87529
86876
|
if (entries.length === 0) {
|
|
@@ -87531,7 +86878,7 @@ async function applyPrefix(extractDir) {
|
|
|
87531
86878
|
return;
|
|
87532
86879
|
}
|
|
87533
86880
|
if (entries.length === 1 && entries[0] === "ck") {
|
|
87534
|
-
const ckDir2 =
|
|
86881
|
+
const ckDir2 = join86(commandsDir, "ck");
|
|
87535
86882
|
const ckStat = await stat15(ckDir2);
|
|
87536
86883
|
if (ckStat.isDirectory()) {
|
|
87537
86884
|
logger.verbose("Commands already have /ck: prefix, skipping");
|
|
@@ -87541,17 +86888,17 @@ async function applyPrefix(extractDir) {
|
|
|
87541
86888
|
await import_fs_extra17.copy(commandsDir, backupDir);
|
|
87542
86889
|
logger.verbose("Created backup of commands directory");
|
|
87543
86890
|
await mkdir27(tempDir, { recursive: true });
|
|
87544
|
-
const ckDir =
|
|
86891
|
+
const ckDir = join86(tempDir, "ck");
|
|
87545
86892
|
await mkdir27(ckDir, { recursive: true });
|
|
87546
86893
|
let processedCount = 0;
|
|
87547
86894
|
for (const entry of entries) {
|
|
87548
|
-
const sourcePath =
|
|
86895
|
+
const sourcePath = join86(commandsDir, entry);
|
|
87549
86896
|
const stats = await lstat7(sourcePath);
|
|
87550
86897
|
if (stats.isSymbolicLink()) {
|
|
87551
86898
|
logger.warning(`Skipping symlink for security: ${entry}`);
|
|
87552
86899
|
continue;
|
|
87553
86900
|
}
|
|
87554
|
-
const destPath =
|
|
86901
|
+
const destPath = join86(ckDir, entry);
|
|
87555
86902
|
await import_fs_extra17.copy(sourcePath, destPath, {
|
|
87556
86903
|
overwrite: false,
|
|
87557
86904
|
errorOnExist: true
|
|
@@ -87569,7 +86916,7 @@ async function applyPrefix(extractDir) {
|
|
|
87569
86916
|
await import_fs_extra17.move(tempDir, commandsDir);
|
|
87570
86917
|
await import_fs_extra17.remove(backupDir);
|
|
87571
86918
|
logger.success("Successfully reorganized commands to /ck: prefix");
|
|
87572
|
-
const claudeDir2 =
|
|
86919
|
+
const claudeDir2 = join86(extractDir, ".claude");
|
|
87573
86920
|
logger.info("Transforming command references in file contents...");
|
|
87574
86921
|
const transformResult = await transformCommandReferences(claudeDir2, {
|
|
87575
86922
|
verbose: logger.isVerbose()
|
|
@@ -87607,20 +86954,20 @@ async function applyPrefix(extractDir) {
|
|
|
87607
86954
|
// src/services/transformers/commands-prefix/prefix-cleaner.ts
|
|
87608
86955
|
init_metadata_migration();
|
|
87609
86956
|
import { lstat as lstat9, readdir as readdir23 } from "node:fs/promises";
|
|
87610
|
-
import { join as
|
|
86957
|
+
import { join as join88 } from "node:path";
|
|
87611
86958
|
init_logger();
|
|
87612
86959
|
var import_fs_extra19 = __toESM(require_lib3(), 1);
|
|
87613
86960
|
|
|
87614
86961
|
// src/services/transformers/commands-prefix/file-processor.ts
|
|
87615
86962
|
import { lstat as lstat8, readdir as readdir22 } from "node:fs/promises";
|
|
87616
|
-
import { join as
|
|
86963
|
+
import { join as join87 } from "node:path";
|
|
87617
86964
|
init_logger();
|
|
87618
86965
|
var import_fs_extra18 = __toESM(require_lib3(), 1);
|
|
87619
86966
|
async function scanDirectoryFiles(dir) {
|
|
87620
86967
|
const files = [];
|
|
87621
86968
|
const entries = await readdir22(dir);
|
|
87622
86969
|
for (const entry of entries) {
|
|
87623
|
-
const fullPath =
|
|
86970
|
+
const fullPath = join87(dir, entry);
|
|
87624
86971
|
const stats = await lstat8(fullPath);
|
|
87625
86972
|
if (stats.isSymbolicLink()) {
|
|
87626
86973
|
continue;
|
|
@@ -87748,8 +87095,8 @@ function isDifferentKitDirectory(dirName, currentKit) {
|
|
|
87748
87095
|
async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
|
|
87749
87096
|
const { dryRun = false } = options2;
|
|
87750
87097
|
validatePath(targetDir, "targetDir");
|
|
87751
|
-
const claudeDir2 = isGlobal ? targetDir :
|
|
87752
|
-
const commandsDir =
|
|
87098
|
+
const claudeDir2 = isGlobal ? targetDir : join88(targetDir, ".claude");
|
|
87099
|
+
const commandsDir = join88(claudeDir2, "commands");
|
|
87753
87100
|
const accumulator = {
|
|
87754
87101
|
results: [],
|
|
87755
87102
|
deletedCount: 0,
|
|
@@ -87791,7 +87138,7 @@ async function cleanupCommandsDirectory(targetDir, isGlobal, options2 = {}) {
|
|
|
87791
87138
|
}
|
|
87792
87139
|
const metadataForChecks = options2.kitType ? createKitSpecificMetadata(metadata, options2.kitType) : metadata;
|
|
87793
87140
|
for (const entry of entries) {
|
|
87794
|
-
const entryPath =
|
|
87141
|
+
const entryPath = join88(commandsDir, entry);
|
|
87795
87142
|
const stats = await lstat9(entryPath);
|
|
87796
87143
|
if (stats.isSymbolicLink()) {
|
|
87797
87144
|
addSymlinkSkip(entry, accumulator);
|
|
@@ -87848,7 +87195,7 @@ async function handleMerge(ctx) {
|
|
|
87848
87195
|
let customClaudeFiles = [];
|
|
87849
87196
|
if (!ctx.options.fresh) {
|
|
87850
87197
|
logger.info("Scanning for custom .claude files...");
|
|
87851
|
-
const scanSourceDir = ctx.options.global ?
|
|
87198
|
+
const scanSourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
|
|
87852
87199
|
const scanTargetSubdir = ctx.options.global ? "" : ".claude";
|
|
87853
87200
|
customClaudeFiles = await FileScanner2.findCustomFiles(ctx.resolvedDir, scanSourceDir, scanTargetSubdir);
|
|
87854
87201
|
} else {
|
|
@@ -87913,38 +87260,28 @@ async function handleMerge(ctx) {
|
|
|
87913
87260
|
return { ...ctx, cancelled: true };
|
|
87914
87261
|
}
|
|
87915
87262
|
}
|
|
87916
|
-
const sourceDir = ctx.options.global ?
|
|
87263
|
+
const sourceDir = ctx.options.global ? join89(ctx.extractDir, ".claude") : ctx.extractDir;
|
|
87917
87264
|
await merger.merge(sourceDir, ctx.resolvedDir, ctx.isNonInteractive);
|
|
87918
87265
|
const fileConflicts = merger.getFileConflicts();
|
|
87919
87266
|
if (fileConflicts.length > 0 && !ctx.isNonInteractive) {
|
|
87920
87267
|
const summary = buildConflictSummary(fileConflicts, [], []);
|
|
87921
87268
|
displayConflictSummary(summary);
|
|
87922
87269
|
}
|
|
87923
|
-
let deferredDeletions = [];
|
|
87924
87270
|
try {
|
|
87925
|
-
const sourceMetadataPath = ctx.options.global ?
|
|
87271
|
+
const sourceMetadataPath = ctx.options.global ? join89(sourceDir, "metadata.json") : join89(sourceDir, ".claude", "metadata.json");
|
|
87926
87272
|
if (await import_fs_extra20.pathExists(sourceMetadataPath)) {
|
|
87927
87273
|
const metadataContent = await import_fs_extra20.readFile(sourceMetadataPath, "utf-8");
|
|
87928
87274
|
const sourceMetadata = JSON.parse(metadataContent);
|
|
87929
87275
|
if (sourceMetadata.deletions && sourceMetadata.deletions.length > 0) {
|
|
87930
|
-
const
|
|
87931
|
-
|
|
87932
|
-
|
|
87933
|
-
const
|
|
87934
|
-
|
|
87935
|
-
if (deletionResult.deletedPaths.length > 0) {
|
|
87936
|
-
logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
|
|
87937
|
-
for (const path14 of deletionResult.deletedPaths) {
|
|
87938
|
-
logger.verbose(` - ${path14}`);
|
|
87939
|
-
}
|
|
87940
|
-
}
|
|
87941
|
-
if (deletionResult.preservedPaths.length > 0) {
|
|
87942
|
-
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}`);
|
|
87943
87281
|
}
|
|
87944
87282
|
}
|
|
87945
|
-
if (
|
|
87946
|
-
|
|
87947
|
-
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)`);
|
|
87948
87285
|
}
|
|
87949
87286
|
}
|
|
87950
87287
|
} else {
|
|
@@ -87971,12 +87308,11 @@ async function handleMerge(ctx) {
|
|
|
87971
87308
|
return {
|
|
87972
87309
|
...ctx,
|
|
87973
87310
|
customClaudeFiles,
|
|
87974
|
-
includePatterns
|
|
87975
|
-
deferredDeletions
|
|
87311
|
+
includePatterns
|
|
87976
87312
|
};
|
|
87977
87313
|
}
|
|
87978
87314
|
// src/commands/init/phases/migration-handler.ts
|
|
87979
|
-
import { join as
|
|
87315
|
+
import { join as join97 } from "node:path";
|
|
87980
87316
|
|
|
87981
87317
|
// src/domains/skills/skills-detector.ts
|
|
87982
87318
|
init_logger();
|
|
@@ -87992,7 +87328,7 @@ init_types3();
|
|
|
87992
87328
|
var import_fs_extra21 = __toESM(require_lib3(), 1);
|
|
87993
87329
|
import { createHash as createHash4 } from "node:crypto";
|
|
87994
87330
|
import { readFile as readFile44, readdir as readdir24, writeFile as writeFile27 } from "node:fs/promises";
|
|
87995
|
-
import { join as
|
|
87331
|
+
import { join as join90, relative as relative15 } from "node:path";
|
|
87996
87332
|
|
|
87997
87333
|
class SkillsManifestManager {
|
|
87998
87334
|
static MANIFEST_FILENAME = ".skills-manifest.json";
|
|
@@ -88014,12 +87350,12 @@ class SkillsManifestManager {
|
|
|
88014
87350
|
return manifest;
|
|
88015
87351
|
}
|
|
88016
87352
|
static async writeManifest(skillsDir2, manifest) {
|
|
88017
|
-
const manifestPath =
|
|
87353
|
+
const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
|
|
88018
87354
|
await writeFile27(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
88019
87355
|
logger.debug(`Wrote manifest to: ${manifestPath}`);
|
|
88020
87356
|
}
|
|
88021
87357
|
static async readManifest(skillsDir2) {
|
|
88022
|
-
const manifestPath =
|
|
87358
|
+
const manifestPath = join90(skillsDir2, SkillsManifestManager.MANIFEST_FILENAME);
|
|
88023
87359
|
if (!await import_fs_extra21.pathExists(manifestPath)) {
|
|
88024
87360
|
logger.debug(`No manifest found at: ${manifestPath}`);
|
|
88025
87361
|
return null;
|
|
@@ -88042,7 +87378,7 @@ class SkillsManifestManager {
|
|
|
88042
87378
|
return "flat";
|
|
88043
87379
|
}
|
|
88044
87380
|
for (const dir of dirs.slice(0, 3)) {
|
|
88045
|
-
const dirPath =
|
|
87381
|
+
const dirPath = join90(skillsDir2, dir.name);
|
|
88046
87382
|
const subEntries = await readdir24(dirPath, { withFileTypes: true });
|
|
88047
87383
|
const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
|
|
88048
87384
|
if (hasSubdirs) {
|
|
@@ -88061,7 +87397,7 @@ class SkillsManifestManager {
|
|
|
88061
87397
|
const entries = await readdir24(skillsDir2, { withFileTypes: true });
|
|
88062
87398
|
for (const entry of entries) {
|
|
88063
87399
|
if (entry.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
|
|
88064
|
-
const skillPath =
|
|
87400
|
+
const skillPath = join90(skillsDir2, entry.name);
|
|
88065
87401
|
const hash = await SkillsManifestManager.hashDirectory(skillPath);
|
|
88066
87402
|
skills.push({
|
|
88067
87403
|
name: entry.name,
|
|
@@ -88073,11 +87409,11 @@ class SkillsManifestManager {
|
|
|
88073
87409
|
const categories = await readdir24(skillsDir2, { withFileTypes: true });
|
|
88074
87410
|
for (const category of categories) {
|
|
88075
87411
|
if (category.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(category.name) && !category.name.startsWith(".")) {
|
|
88076
|
-
const categoryPath =
|
|
87412
|
+
const categoryPath = join90(skillsDir2, category.name);
|
|
88077
87413
|
const skillEntries = await readdir24(categoryPath, { withFileTypes: true });
|
|
88078
87414
|
for (const skillEntry of skillEntries) {
|
|
88079
87415
|
if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
|
|
88080
|
-
const skillPath =
|
|
87416
|
+
const skillPath = join90(categoryPath, skillEntry.name);
|
|
88081
87417
|
const hash = await SkillsManifestManager.hashDirectory(skillPath);
|
|
88082
87418
|
skills.push({
|
|
88083
87419
|
name: skillEntry.name,
|
|
@@ -88107,7 +87443,7 @@ class SkillsManifestManager {
|
|
|
88107
87443
|
const files = [];
|
|
88108
87444
|
const entries = await readdir24(dirPath, { withFileTypes: true });
|
|
88109
87445
|
for (const entry of entries) {
|
|
88110
|
-
const fullPath =
|
|
87446
|
+
const fullPath = join90(dirPath, entry.name);
|
|
88111
87447
|
if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name)) {
|
|
88112
87448
|
continue;
|
|
88113
87449
|
}
|
|
@@ -88229,7 +87565,7 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
|
|
|
88229
87565
|
// src/domains/skills/detection/script-detector.ts
|
|
88230
87566
|
var import_fs_extra22 = __toESM(require_lib3(), 1);
|
|
88231
87567
|
import { readdir as readdir25 } from "node:fs/promises";
|
|
88232
|
-
import { join as
|
|
87568
|
+
import { join as join91 } from "node:path";
|
|
88233
87569
|
async function scanDirectory(skillsDir2) {
|
|
88234
87570
|
if (!await import_fs_extra22.pathExists(skillsDir2)) {
|
|
88235
87571
|
return ["flat", []];
|
|
@@ -88242,12 +87578,12 @@ async function scanDirectory(skillsDir2) {
|
|
|
88242
87578
|
let totalSkillLikeCount = 0;
|
|
88243
87579
|
const allSkills = [];
|
|
88244
87580
|
for (const dir of dirs) {
|
|
88245
|
-
const dirPath =
|
|
87581
|
+
const dirPath = join91(skillsDir2, dir.name);
|
|
88246
87582
|
const subEntries = await readdir25(dirPath, { withFileTypes: true });
|
|
88247
87583
|
const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
|
|
88248
87584
|
if (subdirs.length > 0) {
|
|
88249
87585
|
for (const subdir of subdirs.slice(0, 3)) {
|
|
88250
|
-
const subdirPath =
|
|
87586
|
+
const subdirPath = join91(dirPath, subdir.name);
|
|
88251
87587
|
const subdirFiles = await readdir25(subdirPath, { withFileTypes: true });
|
|
88252
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"));
|
|
88253
87589
|
if (hasSkillMarker) {
|
|
@@ -88404,12 +87740,12 @@ class SkillsMigrationDetector {
|
|
|
88404
87740
|
// src/domains/skills/skills-migrator.ts
|
|
88405
87741
|
init_logger();
|
|
88406
87742
|
init_types3();
|
|
88407
|
-
import { join as
|
|
87743
|
+
import { join as join96 } from "node:path";
|
|
88408
87744
|
|
|
88409
87745
|
// src/domains/skills/migrator/migration-executor.ts
|
|
88410
87746
|
init_logger();
|
|
88411
87747
|
import { copyFile as copyFile6, mkdir as mkdir28, readdir as readdir26, rm as rm10 } from "node:fs/promises";
|
|
88412
|
-
import { join as
|
|
87748
|
+
import { join as join92 } from "node:path";
|
|
88413
87749
|
var import_fs_extra24 = __toESM(require_lib3(), 1);
|
|
88414
87750
|
|
|
88415
87751
|
// src/domains/skills/skills-migration-prompts.ts
|
|
@@ -88574,8 +87910,8 @@ async function copySkillDirectory(sourceDir, destDir) {
|
|
|
88574
87910
|
await mkdir28(destDir, { recursive: true });
|
|
88575
87911
|
const entries = await readdir26(sourceDir, { withFileTypes: true });
|
|
88576
87912
|
for (const entry of entries) {
|
|
88577
|
-
const sourcePath =
|
|
88578
|
-
const destPath =
|
|
87913
|
+
const sourcePath = join92(sourceDir, entry.name);
|
|
87914
|
+
const destPath = join92(destDir, entry.name);
|
|
88579
87915
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
88580
87916
|
continue;
|
|
88581
87917
|
}
|
|
@@ -88590,7 +87926,7 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
|
|
|
88590
87926
|
const migrated = [];
|
|
88591
87927
|
const preserved = [];
|
|
88592
87928
|
const errors2 = [];
|
|
88593
|
-
const tempDir =
|
|
87929
|
+
const tempDir = join92(currentSkillsDir, "..", ".skills-migration-temp");
|
|
88594
87930
|
await mkdir28(tempDir, { recursive: true });
|
|
88595
87931
|
try {
|
|
88596
87932
|
for (const mapping of mappings) {
|
|
@@ -88611,9 +87947,9 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
|
|
|
88611
87947
|
}
|
|
88612
87948
|
}
|
|
88613
87949
|
const category = mapping.category;
|
|
88614
|
-
const targetPath = category ?
|
|
87950
|
+
const targetPath = category ? join92(tempDir, category, skillName) : join92(tempDir, skillName);
|
|
88615
87951
|
if (category) {
|
|
88616
|
-
await mkdir28(
|
|
87952
|
+
await mkdir28(join92(tempDir, category), { recursive: true });
|
|
88617
87953
|
}
|
|
88618
87954
|
await copySkillDirectory(currentSkillPath, targetPath);
|
|
88619
87955
|
migrated.push(skillName);
|
|
@@ -88680,7 +88016,7 @@ init_logger();
|
|
|
88680
88016
|
init_types3();
|
|
88681
88017
|
var import_fs_extra25 = __toESM(require_lib3(), 1);
|
|
88682
88018
|
import { copyFile as copyFile7, mkdir as mkdir29, readdir as readdir27, rm as rm11, stat as stat16 } from "node:fs/promises";
|
|
88683
|
-
import { basename as basename10, join as
|
|
88019
|
+
import { basename as basename10, join as join93, normalize as normalize8 } from "node:path";
|
|
88684
88020
|
function validatePath2(path14, paramName) {
|
|
88685
88021
|
if (!path14 || typeof path14 !== "string") {
|
|
88686
88022
|
throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
|
|
@@ -88706,7 +88042,7 @@ class SkillsBackupManager {
|
|
|
88706
88042
|
const timestamp = Date.now();
|
|
88707
88043
|
const randomSuffix = Math.random().toString(36).substring(2, 8);
|
|
88708
88044
|
const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
|
|
88709
|
-
const backupDir = parentDir ?
|
|
88045
|
+
const backupDir = parentDir ? join93(parentDir, backupDirName) : join93(skillsDir2, "..", backupDirName);
|
|
88710
88046
|
logger.info(`Creating backup at: ${backupDir}`);
|
|
88711
88047
|
try {
|
|
88712
88048
|
await mkdir29(backupDir, { recursive: true });
|
|
@@ -88757,7 +88093,7 @@ class SkillsBackupManager {
|
|
|
88757
88093
|
}
|
|
88758
88094
|
try {
|
|
88759
88095
|
const entries = await readdir27(parentDir, { withFileTypes: true });
|
|
88760
|
-
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));
|
|
88761
88097
|
backups.sort().reverse();
|
|
88762
88098
|
return backups;
|
|
88763
88099
|
} catch (error) {
|
|
@@ -88785,8 +88121,8 @@ class SkillsBackupManager {
|
|
|
88785
88121
|
static async copyDirectory(sourceDir, destDir) {
|
|
88786
88122
|
const entries = await readdir27(sourceDir, { withFileTypes: true });
|
|
88787
88123
|
for (const entry of entries) {
|
|
88788
|
-
const sourcePath =
|
|
88789
|
-
const destPath =
|
|
88124
|
+
const sourcePath = join93(sourceDir, entry.name);
|
|
88125
|
+
const destPath = join93(destDir, entry.name);
|
|
88790
88126
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
|
|
88791
88127
|
continue;
|
|
88792
88128
|
}
|
|
@@ -88802,7 +88138,7 @@ class SkillsBackupManager {
|
|
|
88802
88138
|
let size = 0;
|
|
88803
88139
|
const entries = await readdir27(dirPath, { withFileTypes: true });
|
|
88804
88140
|
for (const entry of entries) {
|
|
88805
|
-
const fullPath =
|
|
88141
|
+
const fullPath = join93(dirPath, entry.name);
|
|
88806
88142
|
if (entry.isSymbolicLink()) {
|
|
88807
88143
|
continue;
|
|
88808
88144
|
}
|
|
@@ -88838,12 +88174,12 @@ init_skip_directories();
|
|
|
88838
88174
|
import { createHash as createHash5 } from "node:crypto";
|
|
88839
88175
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
88840
88176
|
import { readFile as readFile45, readdir as readdir28 } from "node:fs/promises";
|
|
88841
|
-
import { join as
|
|
88177
|
+
import { join as join94, relative as relative16 } from "node:path";
|
|
88842
88178
|
async function getAllFiles(dirPath) {
|
|
88843
88179
|
const files = [];
|
|
88844
88180
|
const entries = await readdir28(dirPath, { withFileTypes: true });
|
|
88845
88181
|
for (const entry of entries) {
|
|
88846
|
-
const fullPath =
|
|
88182
|
+
const fullPath = join94(dirPath, entry.name);
|
|
88847
88183
|
if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name) || entry.isSymbolicLink()) {
|
|
88848
88184
|
continue;
|
|
88849
88185
|
}
|
|
@@ -88857,12 +88193,12 @@ async function getAllFiles(dirPath) {
|
|
|
88857
88193
|
return files;
|
|
88858
88194
|
}
|
|
88859
88195
|
async function hashFile(filePath) {
|
|
88860
|
-
return new Promise((
|
|
88196
|
+
return new Promise((resolve19, reject) => {
|
|
88861
88197
|
const hash = createHash5("sha256");
|
|
88862
88198
|
const stream = createReadStream3(filePath);
|
|
88863
88199
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
88864
88200
|
stream.on("end", () => {
|
|
88865
|
-
|
|
88201
|
+
resolve19(hash.digest("hex"));
|
|
88866
88202
|
});
|
|
88867
88203
|
stream.on("error", (error) => {
|
|
88868
88204
|
stream.destroy();
|
|
@@ -88970,7 +88306,7 @@ async function detectFileChanges(currentSkillPath, baselineSkillPath) {
|
|
|
88970
88306
|
init_types3();
|
|
88971
88307
|
var import_fs_extra27 = __toESM(require_lib3(), 1);
|
|
88972
88308
|
import { readdir as readdir29 } from "node:fs/promises";
|
|
88973
|
-
import { join as
|
|
88309
|
+
import { join as join95, normalize as normalize9 } from "node:path";
|
|
88974
88310
|
function validatePath3(path14, paramName) {
|
|
88975
88311
|
if (!path14 || typeof path14 !== "string") {
|
|
88976
88312
|
throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
|
|
@@ -88991,13 +88327,13 @@ async function scanSkillsDirectory(skillsDir2) {
|
|
|
88991
88327
|
if (dirs.length === 0) {
|
|
88992
88328
|
return ["flat", []];
|
|
88993
88329
|
}
|
|
88994
|
-
const firstDirPath =
|
|
88330
|
+
const firstDirPath = join95(skillsDir2, dirs[0].name);
|
|
88995
88331
|
const subEntries = await readdir29(firstDirPath, { withFileTypes: true });
|
|
88996
88332
|
const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
|
|
88997
88333
|
if (subdirs.length > 0) {
|
|
88998
88334
|
let skillLikeCount = 0;
|
|
88999
88335
|
for (const subdir of subdirs.slice(0, 3)) {
|
|
89000
|
-
const subdirPath =
|
|
88336
|
+
const subdirPath = join95(firstDirPath, subdir.name);
|
|
89001
88337
|
const subdirFiles = await readdir29(subdirPath, { withFileTypes: true });
|
|
89002
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"));
|
|
89003
88339
|
if (hasSkillMarker) {
|
|
@@ -89007,7 +88343,7 @@ async function scanSkillsDirectory(skillsDir2) {
|
|
|
89007
88343
|
if (skillLikeCount > 0) {
|
|
89008
88344
|
const skills = [];
|
|
89009
88345
|
for (const dir of dirs) {
|
|
89010
|
-
const categoryPath =
|
|
88346
|
+
const categoryPath = join95(skillsDir2, dir.name);
|
|
89011
88347
|
const skillDirs = await readdir29(categoryPath, { withFileTypes: true });
|
|
89012
88348
|
skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
|
|
89013
88349
|
}
|
|
@@ -89017,7 +88353,7 @@ async function scanSkillsDirectory(skillsDir2) {
|
|
|
89017
88353
|
return ["flat", dirs.map((dir) => dir.name)];
|
|
89018
88354
|
}
|
|
89019
88355
|
async function findSkillPath(skillsDir2, skillName) {
|
|
89020
|
-
const flatPath =
|
|
88356
|
+
const flatPath = join95(skillsDir2, skillName);
|
|
89021
88357
|
if (await import_fs_extra27.pathExists(flatPath)) {
|
|
89022
88358
|
return { path: flatPath, category: undefined };
|
|
89023
88359
|
}
|
|
@@ -89026,8 +88362,8 @@ async function findSkillPath(skillsDir2, skillName) {
|
|
|
89026
88362
|
if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
89027
88363
|
continue;
|
|
89028
88364
|
}
|
|
89029
|
-
const categoryPath =
|
|
89030
|
-
const skillPath =
|
|
88365
|
+
const categoryPath = join95(skillsDir2, entry.name);
|
|
88366
|
+
const skillPath = join95(categoryPath, skillName);
|
|
89031
88367
|
if (await import_fs_extra27.pathExists(skillPath)) {
|
|
89032
88368
|
return { path: skillPath, category: entry.name };
|
|
89033
88369
|
}
|
|
@@ -89121,7 +88457,7 @@ class SkillsMigrator {
|
|
|
89121
88457
|
}
|
|
89122
88458
|
}
|
|
89123
88459
|
if (options2.backup && !options2.dryRun) {
|
|
89124
|
-
const claudeDir2 =
|
|
88460
|
+
const claudeDir2 = join96(currentSkillsDir, "..");
|
|
89125
88461
|
result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir2);
|
|
89126
88462
|
logger.success(`Backup created at: ${result.backupPath}`);
|
|
89127
88463
|
}
|
|
@@ -89182,7 +88518,7 @@ async function handleMigration(ctx) {
|
|
|
89182
88518
|
logger.debug("Skipping skills migration (fresh installation)");
|
|
89183
88519
|
return ctx;
|
|
89184
88520
|
}
|
|
89185
|
-
const newSkillsDir =
|
|
88521
|
+
const newSkillsDir = join97(ctx.extractDir, ".claude", "skills");
|
|
89186
88522
|
const currentSkillsDir = PathResolver.buildSkillsPath(ctx.resolvedDir, ctx.options.global);
|
|
89187
88523
|
if (!await import_fs_extra28.pathExists(newSkillsDir) || !await import_fs_extra28.pathExists(currentSkillsDir)) {
|
|
89188
88524
|
return ctx;
|
|
@@ -89206,13 +88542,13 @@ async function handleMigration(ctx) {
|
|
|
89206
88542
|
}
|
|
89207
88543
|
// src/commands/init/phases/opencode-handler.ts
|
|
89208
88544
|
import { cp as cp3, readdir as readdir31, rm as rm12 } from "node:fs/promises";
|
|
89209
|
-
import { join as
|
|
88545
|
+
import { join as join99 } from "node:path";
|
|
89210
88546
|
|
|
89211
88547
|
// src/services/transformers/opencode-path-transformer.ts
|
|
89212
88548
|
init_logger();
|
|
89213
88549
|
import { readFile as readFile46, readdir as readdir30, writeFile as writeFile28 } from "node:fs/promises";
|
|
89214
88550
|
import { platform as platform12 } from "node:os";
|
|
89215
|
-
import { extname as extname5, join as
|
|
88551
|
+
import { extname as extname5, join as join98 } from "node:path";
|
|
89216
88552
|
var IS_WINDOWS2 = platform12() === "win32";
|
|
89217
88553
|
function getOpenCodeGlobalPath() {
|
|
89218
88554
|
return "$HOME/.config/opencode/";
|
|
@@ -89273,7 +88609,7 @@ async function transformPathsForGlobalOpenCode(directory, options2 = {}) {
|
|
|
89273
88609
|
async function processDirectory2(dir) {
|
|
89274
88610
|
const entries = await readdir30(dir, { withFileTypes: true });
|
|
89275
88611
|
for (const entry of entries) {
|
|
89276
|
-
const fullPath =
|
|
88612
|
+
const fullPath = join98(dir, entry.name);
|
|
89277
88613
|
if (entry.isDirectory()) {
|
|
89278
88614
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
89279
88615
|
continue;
|
|
@@ -89312,7 +88648,7 @@ async function handleOpenCode(ctx) {
|
|
|
89312
88648
|
if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir) {
|
|
89313
88649
|
return ctx;
|
|
89314
88650
|
}
|
|
89315
|
-
const openCodeSource =
|
|
88651
|
+
const openCodeSource = join99(ctx.extractDir, ".opencode");
|
|
89316
88652
|
if (!await import_fs_extra29.pathExists(openCodeSource)) {
|
|
89317
88653
|
logger.debug("No .opencode directory in archive, skipping");
|
|
89318
88654
|
return ctx;
|
|
@@ -89330,8 +88666,8 @@ async function handleOpenCode(ctx) {
|
|
|
89330
88666
|
await import_fs_extra29.ensureDir(targetDir);
|
|
89331
88667
|
const entries = await readdir31(openCodeSource, { withFileTypes: true });
|
|
89332
88668
|
for (const entry of entries) {
|
|
89333
|
-
const sourcePath =
|
|
89334
|
-
const targetPath =
|
|
88669
|
+
const sourcePath = join99(openCodeSource, entry.name);
|
|
88670
|
+
const targetPath = join99(targetDir, entry.name);
|
|
89335
88671
|
if (await import_fs_extra29.pathExists(targetPath)) {
|
|
89336
88672
|
if (!ctx.options.forceOverwrite) {
|
|
89337
88673
|
logger.verbose(`Skipping existing: ${entry.name}`);
|
|
@@ -89428,21 +88764,20 @@ Please use only one download method.`);
|
|
|
89428
88764
|
}
|
|
89429
88765
|
// src/commands/init/phases/post-install-handler.ts
|
|
89430
88766
|
init_projects_registry();
|
|
89431
|
-
import { join as
|
|
89432
|
-
init_cc_version_checker();
|
|
88767
|
+
import { join as join100 } from "node:path";
|
|
89433
88768
|
init_logger();
|
|
89434
88769
|
init_path_resolver();
|
|
89435
|
-
var
|
|
88770
|
+
var import_fs_extra30 = __toESM(require_lib3(), 1);
|
|
89436
88771
|
async function handlePostInstall(ctx) {
|
|
89437
88772
|
if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir || !ctx.claudeDir) {
|
|
89438
88773
|
return ctx;
|
|
89439
88774
|
}
|
|
89440
88775
|
if (ctx.options.global) {
|
|
89441
|
-
const claudeMdSource =
|
|
89442
|
-
const claudeMdDest =
|
|
89443
|
-
if (await
|
|
89444
|
-
if (ctx.options.fresh || !await
|
|
89445
|
-
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);
|
|
89446
88781
|
logger.success(ctx.options.fresh ? "Replaced CLAUDE.md in global directory (fresh install)" : "Copied CLAUDE.md to global directory");
|
|
89447
88782
|
} else {
|
|
89448
88783
|
logger.debug("CLAUDE.md already exists in global directory (preserved)");
|
|
@@ -89461,77 +88796,6 @@ async function handlePostInstall(ctx) {
|
|
|
89461
88796
|
withSudo: ctx.options.withSudo
|
|
89462
88797
|
});
|
|
89463
88798
|
}
|
|
89464
|
-
let pluginSupported = false;
|
|
89465
|
-
try {
|
|
89466
|
-
const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
|
|
89467
|
-
await requireCCPluginSupport2();
|
|
89468
|
-
pluginSupported = true;
|
|
89469
|
-
} catch (error) {
|
|
89470
|
-
if (error instanceof CCPluginSupportError) {
|
|
89471
|
-
logger.info(`Plugin install skipped: ${error.message}`);
|
|
89472
|
-
if (error.code === "cc_version_too_old") {
|
|
89473
|
-
logger.info("Upgrade: brew upgrade claude-code (or npm i -g @anthropic-ai/claude-code)");
|
|
89474
|
-
}
|
|
89475
|
-
if (error.code === "cc_not_found") {
|
|
89476
|
-
logger.info("Install Claude Code CLI, then re-run ck init to enable /ck:* plugin skills");
|
|
89477
|
-
}
|
|
89478
|
-
} else {
|
|
89479
|
-
logger.info(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
89480
|
-
}
|
|
89481
|
-
}
|
|
89482
|
-
let pluginVerified = false;
|
|
89483
|
-
if (pluginSupported) {
|
|
89484
|
-
try {
|
|
89485
|
-
const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
|
|
89486
|
-
const pluginResult = await handlePluginInstall2(ctx.extractDir);
|
|
89487
|
-
pluginVerified = pluginResult.verified;
|
|
89488
|
-
if (pluginResult.error) {
|
|
89489
|
-
logger.info(`Plugin install issue: ${pluginResult.error}`);
|
|
89490
|
-
}
|
|
89491
|
-
} catch (error) {
|
|
89492
|
-
logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
89493
|
-
}
|
|
89494
|
-
}
|
|
89495
|
-
if (ctx.claudeDir && ctx.kitType) {
|
|
89496
|
-
try {
|
|
89497
|
-
const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
|
|
89498
|
-
await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
|
|
89499
|
-
pluginInstalled: pluginVerified,
|
|
89500
|
-
pluginInstalledAt: new Date().toISOString(),
|
|
89501
|
-
pluginVersion: ctx.selectedVersion || "unknown"
|
|
89502
|
-
});
|
|
89503
|
-
} catch {}
|
|
89504
|
-
}
|
|
89505
|
-
if (ctx.deferredDeletions?.length && ctx.claudeDir) {
|
|
89506
|
-
try {
|
|
89507
|
-
const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
|
|
89508
|
-
const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
|
|
89509
|
-
if (pluginVerified) {
|
|
89510
|
-
if (!migration.canDelete) {
|
|
89511
|
-
logger.warning("Skill migration metadata unavailable — preserving existing skills (fail-safe)");
|
|
89512
|
-
return { ...ctx, installSkills, pluginSupported };
|
|
89513
|
-
}
|
|
89514
|
-
const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir));
|
|
89515
|
-
const safeDeletions = ctx.deferredDeletions.filter((d3) => {
|
|
89516
|
-
const dirPath = extractSkillDirFromDeletionPath(d3);
|
|
89517
|
-
if (!dirPath)
|
|
89518
|
-
return true;
|
|
89519
|
-
return !preservedDirs.has(normalizeSkillDir(dirPath));
|
|
89520
|
-
});
|
|
89521
|
-
if (safeDeletions.length > 0) {
|
|
89522
|
-
const { handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
|
|
89523
|
-
const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
|
|
89524
|
-
if (deferredResult.deletedPaths.length > 0) {
|
|
89525
|
-
logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) (replaced by plugin)`);
|
|
89526
|
-
}
|
|
89527
|
-
}
|
|
89528
|
-
} else {
|
|
89529
|
-
logger.info("Plugin not verified — keeping existing skills as fallback");
|
|
89530
|
-
}
|
|
89531
|
-
} catch (error) {
|
|
89532
|
-
logger.debug(`Deferred skill deletion failed: ${error}`);
|
|
89533
|
-
}
|
|
89534
|
-
}
|
|
89535
88799
|
if (!ctx.isNonInteractive) {
|
|
89536
88800
|
const { isGeminiInstalled: isGeminiInstalled2 } = await Promise.resolve().then(() => (init_package_installer(), exports_package_installer));
|
|
89537
88801
|
const { checkExistingGeminiConfig: checkExistingGeminiConfig2, findMcpConfigPath: findMcpConfigPath2, processGeminiMcpLinking: processGeminiMcpLinking2 } = await Promise.resolve().then(() => (init_gemini_mcp_linker(), exports_gemini_mcp_linker));
|
|
@@ -89558,7 +88822,7 @@ async function handlePostInstall(ctx) {
|
|
|
89558
88822
|
}
|
|
89559
88823
|
if (!ctx.options.skipSetup) {
|
|
89560
88824
|
await promptSetupWizardIfNeeded({
|
|
89561
|
-
envPath:
|
|
88825
|
+
envPath: join100(ctx.claudeDir, ".env"),
|
|
89562
88826
|
claudeDir: ctx.claudeDir,
|
|
89563
88827
|
isGlobal: ctx.options.global,
|
|
89564
88828
|
isNonInteractive: ctx.isNonInteractive,
|
|
@@ -89575,26 +88839,14 @@ async function handlePostInstall(ctx) {
|
|
|
89575
88839
|
}
|
|
89576
88840
|
return {
|
|
89577
88841
|
...ctx,
|
|
89578
|
-
installSkills
|
|
89579
|
-
pluginSupported
|
|
88842
|
+
installSkills
|
|
89580
88843
|
};
|
|
89581
88844
|
}
|
|
89582
|
-
function normalizeSkillDir(path14) {
|
|
89583
|
-
return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
89584
|
-
}
|
|
89585
|
-
function extractSkillDirFromDeletionPath(path14) {
|
|
89586
|
-
const normalized = normalizeSkillDir(path14);
|
|
89587
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
89588
|
-
if (parts.length < 2 || parts[0] !== "skills") {
|
|
89589
|
-
return null;
|
|
89590
|
-
}
|
|
89591
|
-
return `skills/${parts[1]}`;
|
|
89592
|
-
}
|
|
89593
88845
|
// src/commands/init/phases/selection-handler.ts
|
|
89594
88846
|
init_config_manager();
|
|
89595
88847
|
init_github_client();
|
|
89596
88848
|
import { mkdir as mkdir30 } from "node:fs/promises";
|
|
89597
|
-
import { join as
|
|
88849
|
+
import { join as join102, resolve as resolve20 } from "node:path";
|
|
89598
88850
|
|
|
89599
88851
|
// src/domains/github/kit-access-checker.ts
|
|
89600
88852
|
init_logger();
|
|
@@ -89626,8 +88878,8 @@ async function detectAccessibleKits() {
|
|
|
89626
88878
|
// src/domains/github/preflight-checker.ts
|
|
89627
88879
|
init_logger();
|
|
89628
88880
|
import { exec as exec8 } from "node:child_process";
|
|
89629
|
-
import { promisify as
|
|
89630
|
-
var execAsync8 =
|
|
88881
|
+
import { promisify as promisify14 } from "node:util";
|
|
88882
|
+
var execAsync8 = promisify14(exec8);
|
|
89631
88883
|
function createSuccessfulPreflightResult() {
|
|
89632
88884
|
return {
|
|
89633
88885
|
success: true,
|
|
@@ -89724,12 +88976,11 @@ async function runPreflightChecks() {
|
|
|
89724
88976
|
|
|
89725
88977
|
// src/domains/installation/fresh-installer.ts
|
|
89726
88978
|
init_metadata_migration();
|
|
89727
|
-
|
|
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";
|
|
89728
88981
|
init_logger();
|
|
89729
88982
|
init_safe_spinner();
|
|
89730
|
-
var
|
|
89731
|
-
import { existsSync as existsSync50, readdirSync as readdirSync4, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4 } from "node:fs";
|
|
89732
|
-
import { dirname as dirname22, join as join102, resolve as resolve20 } from "node:path";
|
|
88983
|
+
var import_fs_extra31 = __toESM(require_lib3(), 1);
|
|
89733
88984
|
var CLAUDEKIT_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
|
|
89734
88985
|
async function analyzeFreshInstallation(claudeDir2) {
|
|
89735
88986
|
const metadata = await readManifest(claudeDir2);
|
|
@@ -89774,15 +89025,15 @@ async function analyzeFreshInstallation(claudeDir2) {
|
|
|
89774
89025
|
};
|
|
89775
89026
|
}
|
|
89776
89027
|
function cleanupEmptyDirectories2(filePath, claudeDir2) {
|
|
89777
|
-
const normalizedClaudeDir =
|
|
89778
|
-
let currentDir =
|
|
89028
|
+
const normalizedClaudeDir = resolve19(claudeDir2);
|
|
89029
|
+
let currentDir = resolve19(dirname21(filePath));
|
|
89779
89030
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
89780
89031
|
try {
|
|
89781
89032
|
const entries = readdirSync4(currentDir);
|
|
89782
89033
|
if (entries.length === 0) {
|
|
89783
89034
|
rmdirSync2(currentDir);
|
|
89784
89035
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
89785
|
-
currentDir =
|
|
89036
|
+
currentDir = resolve19(dirname21(currentDir));
|
|
89786
89037
|
} else {
|
|
89787
89038
|
break;
|
|
89788
89039
|
}
|
|
@@ -89799,7 +89050,7 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
|
|
|
89799
89050
|
const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
|
|
89800
89051
|
const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
|
|
89801
89052
|
for (const file of filesToRemove) {
|
|
89802
|
-
const fullPath =
|
|
89053
|
+
const fullPath = join101(claudeDir2, file.path);
|
|
89803
89054
|
try {
|
|
89804
89055
|
if (existsSync50(fullPath)) {
|
|
89805
89056
|
unlinkSync4(fullPath);
|
|
@@ -89824,13 +89075,13 @@ async function removeFilesByOwnership(claudeDir2, analysis, includeModified) {
|
|
|
89824
89075
|
};
|
|
89825
89076
|
}
|
|
89826
89077
|
async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
|
|
89827
|
-
const metadataPath =
|
|
89828
|
-
if (!await
|
|
89078
|
+
const metadataPath = join101(claudeDir2, "metadata.json");
|
|
89079
|
+
if (!await import_fs_extra31.pathExists(metadataPath)) {
|
|
89829
89080
|
return;
|
|
89830
89081
|
}
|
|
89831
89082
|
let content;
|
|
89832
89083
|
try {
|
|
89833
|
-
content = await
|
|
89084
|
+
content = await import_fs_extra31.readFile(metadataPath, "utf-8");
|
|
89834
89085
|
} catch (readError) {
|
|
89835
89086
|
logger.warning(`Failed to read metadata.json: ${readError instanceof Error ? readError.message : String(readError)}`);
|
|
89836
89087
|
return;
|
|
@@ -89856,7 +89107,7 @@ async function updateMetadataAfterFresh(claudeDir2, removedFiles) {
|
|
|
89856
89107
|
metadata.files = metadata.files.filter((f3) => !removedSet.has(f3.path));
|
|
89857
89108
|
}
|
|
89858
89109
|
try {
|
|
89859
|
-
await
|
|
89110
|
+
await import_fs_extra31.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
89860
89111
|
logger.debug(`Updated metadata.json, removed ${removedFiles.length} file entries`);
|
|
89861
89112
|
} catch (writeError) {
|
|
89862
89113
|
logger.warning(`Failed to write metadata.json: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -89867,16 +89118,16 @@ async function removeSubdirectoriesFallback(claudeDir2) {
|
|
|
89867
89118
|
const removedFiles = [];
|
|
89868
89119
|
let removedDirCount = 0;
|
|
89869
89120
|
for (const subdir of CLAUDEKIT_SUBDIRECTORIES) {
|
|
89870
|
-
const subdirPath =
|
|
89871
|
-
if (await
|
|
89121
|
+
const subdirPath = join101(claudeDir2, subdir);
|
|
89122
|
+
if (await import_fs_extra31.pathExists(subdirPath)) {
|
|
89872
89123
|
rmSync3(subdirPath, { recursive: true, force: true });
|
|
89873
89124
|
removedDirCount++;
|
|
89874
89125
|
removedFiles.push(`${subdir}/ (entire directory)`);
|
|
89875
89126
|
logger.debug(`Removed subdirectory: ${subdir}/`);
|
|
89876
89127
|
}
|
|
89877
89128
|
}
|
|
89878
|
-
const metadataPath =
|
|
89879
|
-
if (await
|
|
89129
|
+
const metadataPath = join101(claudeDir2, "metadata.json");
|
|
89130
|
+
if (await import_fs_extra31.pathExists(metadataPath)) {
|
|
89880
89131
|
unlinkSync4(metadataPath);
|
|
89881
89132
|
removedFiles.push("metadata.json");
|
|
89882
89133
|
}
|
|
@@ -89889,7 +89140,7 @@ async function removeSubdirectoriesFallback(claudeDir2) {
|
|
|
89889
89140
|
};
|
|
89890
89141
|
}
|
|
89891
89142
|
async function handleFreshInstallation(claudeDir2, prompts) {
|
|
89892
|
-
if (!await
|
|
89143
|
+
if (!await import_fs_extra31.pathExists(claudeDir2)) {
|
|
89893
89144
|
logger.info(".claude directory does not exist, proceeding with fresh installation");
|
|
89894
89145
|
return true;
|
|
89895
89146
|
}
|
|
@@ -89921,11 +89172,10 @@ async function handleFreshInstallation(claudeDir2, prompts) {
|
|
|
89921
89172
|
|
|
89922
89173
|
// src/commands/init/phases/selection-handler.ts
|
|
89923
89174
|
init_claudekit_scanner();
|
|
89924
|
-
init_manifest_reader();
|
|
89925
89175
|
init_logger();
|
|
89926
89176
|
init_path_resolver();
|
|
89927
89177
|
init_types3();
|
|
89928
|
-
var
|
|
89178
|
+
var import_fs_extra32 = __toESM(require_lib3(), 1);
|
|
89929
89179
|
|
|
89930
89180
|
// src/commands/init/types.ts
|
|
89931
89181
|
function isSyncContext(ctx) {
|
|
@@ -90094,7 +89344,7 @@ async function handleSelection(ctx) {
|
|
|
90094
89344
|
}
|
|
90095
89345
|
}
|
|
90096
89346
|
}
|
|
90097
|
-
const resolvedDir =
|
|
89347
|
+
const resolvedDir = resolve20(targetDir);
|
|
90098
89348
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
90099
89349
|
if (!ctx.options.global && PathResolver.isLocalSameAsGlobal(resolvedDir)) {
|
|
90100
89350
|
logger.warning("You're at HOME directory. Installing here modifies your GLOBAL ClaudeKit.");
|
|
@@ -90116,7 +89366,7 @@ async function handleSelection(ctx) {
|
|
|
90116
89366
|
return { ...ctx, cancelled: true };
|
|
90117
89367
|
}
|
|
90118
89368
|
}
|
|
90119
|
-
if (!await
|
|
89369
|
+
if (!await import_fs_extra32.pathExists(resolvedDir)) {
|
|
90120
89370
|
if (ctx.options.global) {
|
|
90121
89371
|
await mkdir30(resolvedDir, { recursive: true });
|
|
90122
89372
|
logger.info(`Created global directory: ${resolvedDir}`);
|
|
@@ -90128,7 +89378,7 @@ async function handleSelection(ctx) {
|
|
|
90128
89378
|
}
|
|
90129
89379
|
if (!ctx.options.fresh) {
|
|
90130
89380
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
90131
|
-
const claudeDir2 = prefix ?
|
|
89381
|
+
const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
|
|
90132
89382
|
try {
|
|
90133
89383
|
const existingMetadata = await readManifest(claudeDir2);
|
|
90134
89384
|
if (existingMetadata?.kits) {
|
|
@@ -90160,7 +89410,7 @@ async function handleSelection(ctx) {
|
|
|
90160
89410
|
}
|
|
90161
89411
|
if (ctx.options.fresh) {
|
|
90162
89412
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
90163
|
-
const claudeDir2 = prefix ?
|
|
89413
|
+
const claudeDir2 = prefix ? join102(resolvedDir, prefix) : resolvedDir;
|
|
90164
89414
|
const canProceed = await handleFreshInstallation(claudeDir2, ctx.prompts);
|
|
90165
89415
|
if (!canProceed) {
|
|
90166
89416
|
return { ...ctx, cancelled: true };
|
|
@@ -90179,7 +89429,7 @@ async function handleSelection(ctx) {
|
|
|
90179
89429
|
logger.info("Fetching available versions...");
|
|
90180
89430
|
let currentVersion = null;
|
|
90181
89431
|
try {
|
|
90182
|
-
const metadataPath = ctx.options.global ?
|
|
89432
|
+
const metadataPath = ctx.options.global ? join102(PathResolver.getGlobalKitDir(), "metadata.json") : join102(resolvedDir, ".claude", "metadata.json");
|
|
90183
89433
|
const metadata = await readClaudeKitMetadata(metadataPath);
|
|
90184
89434
|
currentVersion = metadata?.version || null;
|
|
90185
89435
|
if (currentVersion) {
|
|
@@ -90253,27 +89503,25 @@ async function handleSelection(ctx) {
|
|
|
90253
89503
|
};
|
|
90254
89504
|
}
|
|
90255
89505
|
// src/commands/init/phases/sync-handler.ts
|
|
90256
|
-
import { copyFile as copyFile8, mkdir as mkdir31, open as open4, readFile as
|
|
90257
|
-
import { dirname as
|
|
90258
|
-
init_cc_version_checker();
|
|
90259
|
-
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";
|
|
90260
89508
|
init_logger();
|
|
90261
89509
|
init_path_resolver();
|
|
90262
|
-
var
|
|
89510
|
+
var import_fs_extra33 = __toESM(require_lib3(), 1);
|
|
90263
89511
|
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
90264
89512
|
async function handleSync(ctx) {
|
|
90265
89513
|
if (!ctx.options.sync) {
|
|
90266
89514
|
return ctx;
|
|
90267
89515
|
}
|
|
90268
|
-
const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() :
|
|
90269
|
-
const claudeDir2 = ctx.options.global ? resolvedDir :
|
|
90270
|
-
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)) {
|
|
90271
89519
|
logger.error("Cannot sync: no .claude directory found");
|
|
90272
89520
|
ctx.prompts.note("Run 'ck init' without --sync to install first.", "No Installation Found");
|
|
90273
89521
|
return { ...ctx, cancelled: true };
|
|
90274
89522
|
}
|
|
90275
|
-
const metadataPath =
|
|
90276
|
-
if (!await
|
|
89523
|
+
const metadataPath = join103(claudeDir2, "metadata.json");
|
|
89524
|
+
if (!await import_fs_extra33.pathExists(metadataPath)) {
|
|
90277
89525
|
logger.error("Cannot sync: no metadata.json found");
|
|
90278
89526
|
ctx.prompts.note(`Your installation may be from an older version.
|
|
90279
89527
|
Run 'ck init' to update.`, "Legacy Installation");
|
|
@@ -90370,42 +89618,17 @@ function getLockTimeout() {
|
|
|
90370
89618
|
return timeoutMs;
|
|
90371
89619
|
}
|
|
90372
89620
|
var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
|
|
90373
|
-
function isProcessAlive(pid) {
|
|
90374
|
-
try {
|
|
90375
|
-
process.kill(pid, 0);
|
|
90376
|
-
return true;
|
|
90377
|
-
} catch (error) {
|
|
90378
|
-
const code2 = error.code;
|
|
90379
|
-
return code2 === "EPERM";
|
|
90380
|
-
}
|
|
90381
|
-
}
|
|
90382
|
-
async function readLockPayload(lockPath) {
|
|
90383
|
-
try {
|
|
90384
|
-
const raw2 = await readFile49(lockPath, "utf-8");
|
|
90385
|
-
const parsed = JSON.parse(raw2);
|
|
90386
|
-
if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0) {
|
|
90387
|
-
return {
|
|
90388
|
-
pid: parsed.pid,
|
|
90389
|
-
startedAt: typeof parsed.startedAt === "string" && parsed.startedAt.length > 0 ? parsed.startedAt : "unknown"
|
|
90390
|
-
};
|
|
90391
|
-
}
|
|
90392
|
-
} catch {}
|
|
90393
|
-
return null;
|
|
90394
|
-
}
|
|
90395
89621
|
async function acquireSyncLock(global3) {
|
|
90396
89622
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
90397
|
-
const lockPath =
|
|
89623
|
+
const lockPath = join103(cacheDir, ".sync-lock");
|
|
90398
89624
|
const startTime = Date.now();
|
|
90399
89625
|
const lockTimeout = getLockTimeout();
|
|
90400
|
-
await mkdir31(
|
|
89626
|
+
await mkdir31(dirname22(lockPath), { recursive: true });
|
|
90401
89627
|
while (Date.now() - startTime < lockTimeout) {
|
|
90402
89628
|
try {
|
|
90403
89629
|
const handle = await open4(lockPath, "wx");
|
|
90404
|
-
await handle.writeFile(JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }), "utf-8");
|
|
90405
89630
|
return async () => {
|
|
90406
|
-
|
|
90407
|
-
await handle.close();
|
|
90408
|
-
} catch {}
|
|
89631
|
+
await handle.close();
|
|
90409
89632
|
await unlink11(lockPath).catch(() => {});
|
|
90410
89633
|
};
|
|
90411
89634
|
} catch (err) {
|
|
@@ -90413,29 +89636,18 @@ async function acquireSyncLock(global3) {
|
|
|
90413
89636
|
try {
|
|
90414
89637
|
const lockStat = await stat17(lockPath);
|
|
90415
89638
|
const lockAge = Math.abs(Date.now() - lockStat.mtimeMs);
|
|
90416
|
-
|
|
90417
|
-
|
|
90418
|
-
throw new Error("Sync lock is already held by current process");
|
|
90419
|
-
}
|
|
90420
|
-
const ownerAlive = lockOwner?.pid ? isProcessAlive(lockOwner.pid) : null;
|
|
90421
|
-
if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive !== true) {
|
|
90422
|
-
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)`);
|
|
90423
89641
|
await unlink11(lockPath).catch(() => {});
|
|
90424
89642
|
continue;
|
|
90425
89643
|
}
|
|
90426
|
-
if (lockAge > STALE_LOCK_THRESHOLD_MS && ownerAlive === true) {
|
|
90427
|
-
logger.debug(`Sync lock older than threshold but owner pid=${lockOwner?.pid} still alive; waiting`);
|
|
90428
|
-
}
|
|
90429
89644
|
} catch (statError) {
|
|
90430
|
-
if (statError instanceof Error && statError.message.includes("already held by current process")) {
|
|
90431
|
-
throw statError;
|
|
90432
|
-
}
|
|
90433
89645
|
if (statError.code === "ENOENT") {
|
|
90434
89646
|
continue;
|
|
90435
89647
|
}
|
|
90436
89648
|
logger.debug(`Lock stat failed: ${statError}`);
|
|
90437
89649
|
}
|
|
90438
|
-
await new Promise((
|
|
89650
|
+
await new Promise((resolve22) => setTimeout(resolve22, 100));
|
|
90439
89651
|
continue;
|
|
90440
89652
|
}
|
|
90441
89653
|
throw err;
|
|
@@ -90454,20 +89666,18 @@ async function executeSyncMerge(ctx) {
|
|
|
90454
89666
|
const releaseLock = await acquireSyncLock(ctx.options.global);
|
|
90455
89667
|
try {
|
|
90456
89668
|
const trackedFiles = ctx.syncTrackedFiles;
|
|
90457
|
-
const upstreamDir = ctx.options.global ?
|
|
89669
|
+
const upstreamDir = ctx.options.global ? join103(ctx.extractDir, ".claude") : ctx.extractDir;
|
|
90458
89670
|
let deletions = [];
|
|
90459
89671
|
try {
|
|
90460
|
-
const sourceMetadataPath =
|
|
90461
|
-
if (await
|
|
90462
|
-
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");
|
|
90463
89675
|
const sourceMetadata = JSON.parse(content);
|
|
90464
89676
|
deletions = sourceMetadata.deletions || [];
|
|
90465
89677
|
}
|
|
90466
89678
|
} catch (error) {
|
|
90467
89679
|
logger.debug(`Failed to load source metadata for deletion filtering: ${error}`);
|
|
90468
89680
|
}
|
|
90469
|
-
const { categorizeDeletions: categorizeDeletions2, handleDeletions: handleDeletions2 } = await Promise.resolve().then(() => (init_deletion_handler(), exports_deletion_handler));
|
|
90470
|
-
const categorizedDeletions = categorizeDeletions2(deletions);
|
|
90471
89681
|
const filteredTrackedFiles = filterDeletionPaths(trackedFiles, deletions);
|
|
90472
89682
|
if (deletions.length > 0) {
|
|
90473
89683
|
const filtered = trackedFiles.length - filteredTrackedFiles.length;
|
|
@@ -90475,44 +89685,23 @@ async function executeSyncMerge(ctx) {
|
|
|
90475
89685
|
}
|
|
90476
89686
|
logger.info("Analyzing file changes...");
|
|
90477
89687
|
const plan = await SyncEngine.createSyncPlan(filteredTrackedFiles, ctx.claudeDir, upstreamDir);
|
|
90478
|
-
const forceOverwriteNonInteractive = ctx.isNonInteractive && ctx.options.forceOverwrite;
|
|
90479
|
-
const autoUpdateQueue = forceOverwriteNonInteractive ? dedupeTrackedFiles([...plan.autoUpdate, ...plan.needsReview]) : plan.autoUpdate;
|
|
90480
|
-
const reviewQueue = forceOverwriteNonInteractive ? [] : plan.needsReview;
|
|
90481
89688
|
displaySyncPlan(plan);
|
|
90482
|
-
if (
|
|
89689
|
+
if (plan.autoUpdate.length === 0 && plan.needsReview.length === 0) {
|
|
90483
89690
|
ctx.prompts.note("All files are up to date or user-owned.", "No Changes Needed");
|
|
90484
|
-
}
|
|
90485
|
-
if (reviewQueue.length > 0 && ctx.isNonInteractive) {
|
|
90486
|
-
logger.error(`Cannot complete sync: ${reviewQueue.length} file(s) require interactive review`);
|
|
90487
|
-
ctx.prompts.note(`The following files have local modifications:
|
|
90488
|
-
${reviewQueue.slice(0, 5).map((f3) => ` • ${f3.path}`).join(`
|
|
90489
|
-
`)}${reviewQueue.length > 5 ? `
|
|
90490
|
-
... and ${reviewQueue.length - 5} more` : ""}
|
|
90491
|
-
|
|
90492
|
-
Options:
|
|
90493
|
-
1. Run 'ck init --sync' without --yes for interactive merge
|
|
90494
|
-
2. Use --force-overwrite to accept all upstream changes
|
|
90495
|
-
3. Manually resolve conflicts before syncing`, "Sync Blocked");
|
|
90496
89691
|
return { ...ctx, cancelled: true };
|
|
90497
89692
|
}
|
|
90498
|
-
|
|
90499
|
-
|
|
90500
|
-
}
|
|
90501
|
-
|
|
90502
|
-
|
|
90503
|
-
const backupDir = PathResolver.getBackupDir();
|
|
90504
|
-
await createBackup(ctx.claudeDir, trackedFiles, backupDir);
|
|
90505
|
-
logger.success(`Backup created at ${import_picocolors23.default.dim(backupDir)}`);
|
|
90506
|
-
}
|
|
90507
|
-
if (autoUpdateQueue.length > 0) {
|
|
90508
|
-
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)...`);
|
|
90509
89698
|
let updateSuccess = 0;
|
|
90510
89699
|
let updateFailed = 0;
|
|
90511
|
-
for (const file of
|
|
89700
|
+
for (const file of plan.autoUpdate) {
|
|
90512
89701
|
try {
|
|
90513
89702
|
const sourcePath = await validateSyncPath(upstreamDir, file.path);
|
|
90514
89703
|
const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
90515
|
-
const targetDir =
|
|
89704
|
+
const targetDir = join103(targetPath, "..");
|
|
90516
89705
|
try {
|
|
90517
89706
|
await mkdir31(targetDir, { recursive: true });
|
|
90518
89707
|
} catch (mkdirError) {
|
|
@@ -90522,7 +89711,7 @@ Options:
|
|
|
90522
89711
|
ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
|
|
90523
89712
|
return { ...ctx, cancelled: true };
|
|
90524
89713
|
}
|
|
90525
|
-
if (errCode === "EROFS" || errCode === "EACCES"
|
|
89714
|
+
if (errCode === "EROFS" || errCode === "EACCES") {
|
|
90526
89715
|
logger.warning(`Cannot create directory ${file.path}: ${errCode}`);
|
|
90527
89716
|
updateFailed++;
|
|
90528
89717
|
continue;
|
|
@@ -90540,7 +89729,7 @@ Options:
|
|
|
90540
89729
|
ctx.prompts.note("Your disk is full. Free up space and try again.", "Sync Failed");
|
|
90541
89730
|
return { ...ctx, cancelled: true };
|
|
90542
89731
|
}
|
|
90543
|
-
if (errCode === "EACCES" || errCode === "EPERM"
|
|
89732
|
+
if (errCode === "EACCES" || errCode === "EPERM") {
|
|
90544
89733
|
logger.warning(`Permission denied: ${file.path} - check file permissions`);
|
|
90545
89734
|
updateFailed++;
|
|
90546
89735
|
} else if (errMsg.includes("Symlink") || errMsg.includes("Path")) {
|
|
@@ -90555,22 +89744,19 @@ Options:
|
|
|
90555
89744
|
if (updateSuccess > 0) {
|
|
90556
89745
|
logger.success(`Auto-updated ${updateSuccess} file(s)${updateFailed > 0 ? ` (${updateFailed} failed)` : ""}`);
|
|
90557
89746
|
}
|
|
90558
|
-
if (updateSuccess === 0 && updateFailed > 0) {
|
|
90559
|
-
logger.warning("No files were updated due to write errors");
|
|
90560
|
-
}
|
|
90561
89747
|
}
|
|
90562
|
-
if (
|
|
90563
|
-
logger.info(`${
|
|
89748
|
+
if (plan.needsReview.length > 0 && !ctx.isNonInteractive) {
|
|
89749
|
+
logger.info(`${plan.needsReview.length} file(s) need interactive review...`);
|
|
90564
89750
|
let totalApplied = 0;
|
|
90565
89751
|
let totalRejected = 0;
|
|
90566
89752
|
let skippedFiles = 0;
|
|
90567
|
-
for (const file of
|
|
89753
|
+
for (const file of plan.needsReview) {
|
|
90568
89754
|
let currentPath;
|
|
90569
89755
|
let upstreamPath;
|
|
90570
89756
|
try {
|
|
90571
89757
|
currentPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
90572
89758
|
upstreamPath = await validateSyncPath(upstreamDir, file.path);
|
|
90573
|
-
} catch {
|
|
89759
|
+
} catch (error) {
|
|
90574
89760
|
logger.warning(`Skipping invalid path during review: ${file.path}`);
|
|
90575
89761
|
skippedFiles++;
|
|
90576
89762
|
continue;
|
|
@@ -90597,7 +89783,7 @@ Options:
|
|
|
90597
89783
|
const tempPath = `${currentPath}.tmp.${Date.now()}`;
|
|
90598
89784
|
try {
|
|
90599
89785
|
await writeFile30(tempPath, result.result, "utf-8");
|
|
90600
|
-
await
|
|
89786
|
+
await rename6(tempPath, currentPath);
|
|
90601
89787
|
} catch (atomicError) {
|
|
90602
89788
|
await unlink11(tempPath).catch(() => {});
|
|
90603
89789
|
throw atomicError;
|
|
@@ -90618,8 +89804,8 @@ Options:
|
|
|
90618
89804
|
console.log("");
|
|
90619
89805
|
console.log(import_picocolors23.default.bold("Sync Summary:"));
|
|
90620
89806
|
console.log(import_picocolors23.default.dim("─".repeat(40)));
|
|
90621
|
-
if (
|
|
90622
|
-
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`));
|
|
90623
89809
|
}
|
|
90624
89810
|
if (totalApplied > 0) {
|
|
90625
89811
|
console.log(import_picocolors23.default.green(` ✓ ${totalApplied} hunk(s) applied`));
|
|
@@ -90633,96 +89819,23 @@ Options:
|
|
|
90633
89819
|
if (plan.skipped.length > 0) {
|
|
90634
89820
|
console.log(import_picocolors23.default.dim(` ─ ${plan.skipped.length} user-owned file(s) unchanged`));
|
|
90635
89821
|
}
|
|
90636
|
-
}
|
|
90637
|
-
|
|
90638
|
-
|
|
90639
|
-
|
|
90640
|
-
|
|
90641
|
-
|
|
90642
|
-
|
|
90643
|
-
|
|
90644
|
-
|
|
90645
|
-
|
|
90646
|
-
|
|
90647
|
-
|
|
90648
|
-
}
|
|
90649
|
-
}
|
|
90650
|
-
let pluginSupported = false;
|
|
90651
|
-
let pluginVerified = false;
|
|
90652
|
-
try {
|
|
90653
|
-
const { requireCCPluginSupport: requireCCPluginSupport2 } = await Promise.resolve().then(() => (init_cc_version_checker(), exports_cc_version_checker));
|
|
90654
|
-
await requireCCPluginSupport2();
|
|
90655
|
-
pluginSupported = true;
|
|
90656
|
-
} catch (error) {
|
|
90657
|
-
if (error instanceof CCPluginSupportError) {
|
|
90658
|
-
logger.info(`Plugin install skipped during sync: ${error.message}`);
|
|
90659
|
-
if (error.code === "cc_version_too_old") {
|
|
90660
|
-
logger.info("Upgrade Claude Code, then re-run: ck init --sync (plugin migration requires >= 1.0.33)");
|
|
90661
|
-
}
|
|
90662
|
-
if (error.code === "cc_not_found") {
|
|
90663
|
-
logger.info("Install Claude Code CLI to enable /ck:* plugin skills");
|
|
90664
|
-
}
|
|
90665
|
-
} else {
|
|
90666
|
-
logger.debug(`Plugin version check failed during sync: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
90667
|
-
}
|
|
90668
|
-
}
|
|
90669
|
-
if (pluginSupported && ctx.extractDir) {
|
|
90670
|
-
try {
|
|
90671
|
-
const { handlePluginInstall: handlePluginInstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
|
|
90672
|
-
const pluginResult = await handlePluginInstall2(ctx.extractDir);
|
|
90673
|
-
pluginVerified = pluginResult.verified;
|
|
90674
|
-
if (pluginResult.error) {
|
|
90675
|
-
logger.debug(`Plugin install issue: ${pluginResult.error}`);
|
|
90676
|
-
}
|
|
90677
|
-
} catch (error) {
|
|
90678
|
-
logger.debug(`Plugin install skipped: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
90679
|
-
}
|
|
90680
|
-
}
|
|
90681
|
-
if (ctx.claudeDir && ctx.kitType) {
|
|
90682
|
-
try {
|
|
90683
|
-
const { updateKitPluginState: updateKitPluginState2 } = await Promise.resolve().then(() => (init_metadata_migration(), exports_metadata_migration));
|
|
90684
|
-
await updateKitPluginState2(ctx.claudeDir, ctx.kitType, {
|
|
90685
|
-
pluginInstalled: pluginVerified,
|
|
90686
|
-
pluginInstalledAt: new Date().toISOString(),
|
|
90687
|
-
pluginVersion: ctx.selectedVersion || ctx.syncLatestVersion || "unknown"
|
|
90688
|
-
});
|
|
90689
|
-
} catch {}
|
|
90690
|
-
}
|
|
90691
|
-
if (categorizedDeletions.deferred.length > 0) {
|
|
90692
|
-
if (pluginVerified) {
|
|
90693
|
-
try {
|
|
90694
|
-
const { migrateUserSkills: migrateUserSkills2 } = await Promise.resolve().then(() => (init_skill_migration_merger(), exports_skill_migration_merger));
|
|
90695
|
-
const migration = await migrateUserSkills2(ctx.claudeDir, pluginVerified);
|
|
90696
|
-
if (!migration.canDelete) {
|
|
90697
|
-
logger.warning("Skill migration metadata unavailable during sync — preserving existing skills");
|
|
90698
|
-
} else {
|
|
90699
|
-
const preservedDirs = new Set(migration.preserved.map(normalizeSkillDir2));
|
|
90700
|
-
const safeDeletions = categorizedDeletions.deferred.filter((path14) => {
|
|
90701
|
-
const skillDir = extractSkillDirFromDeletionPath2(path14);
|
|
90702
|
-
return !skillDir || !preservedDirs.has(normalizeSkillDir2(skillDir));
|
|
90703
|
-
});
|
|
90704
|
-
if (safeDeletions.length > 0) {
|
|
90705
|
-
const deferredResult = await handleDeletions2({ deletions: safeDeletions }, ctx.claudeDir);
|
|
90706
|
-
if (deferredResult.deletedPaths.length > 0) {
|
|
90707
|
-
logger.info(`Removed ${deferredResult.deletedPaths.length} old skill file(s) during sync`);
|
|
90708
|
-
}
|
|
90709
|
-
}
|
|
90710
|
-
}
|
|
90711
|
-
} catch (error) {
|
|
90712
|
-
logger.debug(`Deferred skill cleanup failed during sync: ${error}`);
|
|
90713
|
-
}
|
|
90714
|
-
} else {
|
|
90715
|
-
logger.info("Plugin not verified during sync — keeping existing skills as fallback");
|
|
90716
|
-
}
|
|
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 };
|
|
90717
89834
|
}
|
|
90718
89835
|
ctx.prompts.outro("Config sync completed successfully");
|
|
90719
89836
|
return { ...ctx, cancelled: true };
|
|
90720
89837
|
} finally {
|
|
90721
|
-
|
|
90722
|
-
await releaseLock();
|
|
90723
|
-
} catch (error) {
|
|
90724
|
-
logger.debug(`Failed to release sync lock: ${error}`);
|
|
90725
|
-
}
|
|
89838
|
+
await releaseLock();
|
|
90726
89839
|
}
|
|
90727
89840
|
}
|
|
90728
89841
|
function displaySyncPlan(plan) {
|
|
@@ -90757,9 +89870,9 @@ async function createBackup(claudeDir2, files, backupDir) {
|
|
|
90757
89870
|
for (const file of files) {
|
|
90758
89871
|
try {
|
|
90759
89872
|
const sourcePath = await validateSyncPath(claudeDir2, file.path);
|
|
90760
|
-
if (await
|
|
89873
|
+
if (await import_fs_extra33.pathExists(sourcePath)) {
|
|
90761
89874
|
const targetPath = await validateSyncPath(backupDir, file.path);
|
|
90762
|
-
const targetDir =
|
|
89875
|
+
const targetDir = join103(targetPath, "..");
|
|
90763
89876
|
await mkdir31(targetDir, { recursive: true });
|
|
90764
89877
|
await copyFile8(sourcePath, targetPath);
|
|
90765
89878
|
}
|
|
@@ -90772,27 +89885,9 @@ async function createBackup(claudeDir2, files, backupDir) {
|
|
|
90772
89885
|
}
|
|
90773
89886
|
}
|
|
90774
89887
|
}
|
|
90775
|
-
function dedupeTrackedFiles(files) {
|
|
90776
|
-
const deduped = new Map;
|
|
90777
|
-
for (const file of files) {
|
|
90778
|
-
deduped.set(file.path, file);
|
|
90779
|
-
}
|
|
90780
|
-
return [...deduped.values()];
|
|
90781
|
-
}
|
|
90782
|
-
function normalizeSkillDir2(path14) {
|
|
90783
|
-
return path14.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
90784
|
-
}
|
|
90785
|
-
function extractSkillDirFromDeletionPath2(path14) {
|
|
90786
|
-
const normalized = normalizeSkillDir2(path14);
|
|
90787
|
-
const parts = normalized.split("/").filter(Boolean);
|
|
90788
|
-
if (parts.length < 2 || parts[0] !== "skills") {
|
|
90789
|
-
return null;
|
|
90790
|
-
}
|
|
90791
|
-
return `skills/${parts[1]}`;
|
|
90792
|
-
}
|
|
90793
89888
|
// src/commands/init/phases/transform-handler.ts
|
|
90794
89889
|
init_config_manager();
|
|
90795
|
-
import { join as
|
|
89890
|
+
import { join as join107 } from "node:path";
|
|
90796
89891
|
|
|
90797
89892
|
// src/services/transformers/folder-path-transformer.ts
|
|
90798
89893
|
init_logger();
|
|
@@ -90801,40 +89896,40 @@ init_types3();
|
|
|
90801
89896
|
// src/services/transformers/folder-transform/folder-renamer.ts
|
|
90802
89897
|
init_logger();
|
|
90803
89898
|
init_types3();
|
|
90804
|
-
var
|
|
90805
|
-
import { rename as
|
|
90806
|
-
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";
|
|
90807
89902
|
async function collectDirsToRename(extractDir, folders) {
|
|
90808
89903
|
const dirsToRename = [];
|
|
90809
89904
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
90810
|
-
const docsPath =
|
|
90811
|
-
if (await
|
|
89905
|
+
const docsPath = join104(extractDir, DEFAULT_FOLDERS.docs);
|
|
89906
|
+
if (await import_fs_extra34.pathExists(docsPath)) {
|
|
90812
89907
|
dirsToRename.push({
|
|
90813
89908
|
from: docsPath,
|
|
90814
|
-
to:
|
|
89909
|
+
to: join104(extractDir, folders.docs)
|
|
90815
89910
|
});
|
|
90816
89911
|
}
|
|
90817
|
-
const claudeDocsPath =
|
|
90818
|
-
if (await
|
|
89912
|
+
const claudeDocsPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
89913
|
+
if (await import_fs_extra34.pathExists(claudeDocsPath)) {
|
|
90819
89914
|
dirsToRename.push({
|
|
90820
89915
|
from: claudeDocsPath,
|
|
90821
|
-
to:
|
|
89916
|
+
to: join104(extractDir, ".claude", folders.docs)
|
|
90822
89917
|
});
|
|
90823
89918
|
}
|
|
90824
89919
|
}
|
|
90825
89920
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
90826
|
-
const plansPath =
|
|
90827
|
-
if (await
|
|
89921
|
+
const plansPath = join104(extractDir, DEFAULT_FOLDERS.plans);
|
|
89922
|
+
if (await import_fs_extra34.pathExists(plansPath)) {
|
|
90828
89923
|
dirsToRename.push({
|
|
90829
89924
|
from: plansPath,
|
|
90830
|
-
to:
|
|
89925
|
+
to: join104(extractDir, folders.plans)
|
|
90831
89926
|
});
|
|
90832
89927
|
}
|
|
90833
|
-
const claudePlansPath =
|
|
90834
|
-
if (await
|
|
89928
|
+
const claudePlansPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
89929
|
+
if (await import_fs_extra34.pathExists(claudePlansPath)) {
|
|
90835
89930
|
dirsToRename.push({
|
|
90836
89931
|
from: claudePlansPath,
|
|
90837
|
-
to:
|
|
89932
|
+
to: join104(extractDir, ".claude", folders.plans)
|
|
90838
89933
|
});
|
|
90839
89934
|
}
|
|
90840
89935
|
}
|
|
@@ -90842,11 +89937,11 @@ async function collectDirsToRename(extractDir, folders) {
|
|
|
90842
89937
|
}
|
|
90843
89938
|
async function moveAcrossDevices(src, dest) {
|
|
90844
89939
|
try {
|
|
90845
|
-
await
|
|
89940
|
+
await rename7(src, dest);
|
|
90846
89941
|
} catch (e2) {
|
|
90847
89942
|
if (e2.code === "EXDEV") {
|
|
90848
89943
|
logger.debug(`Cross-device move detected, using copy+delete: ${src} -> ${dest}`);
|
|
90849
|
-
await
|
|
89944
|
+
await import_fs_extra34.copy(src, dest, { overwrite: true });
|
|
90850
89945
|
await rm13(src, { recursive: true, force: true });
|
|
90851
89946
|
} else {
|
|
90852
89947
|
throw e2;
|
|
@@ -90874,8 +89969,8 @@ async function renameFolders(dirsToRename, extractDir, options2) {
|
|
|
90874
89969
|
// src/services/transformers/folder-transform/path-replacer.ts
|
|
90875
89970
|
init_logger();
|
|
90876
89971
|
init_types3();
|
|
90877
|
-
import { readFile as
|
|
90878
|
-
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";
|
|
90879
89974
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
90880
89975
|
".md",
|
|
90881
89976
|
".txt",
|
|
@@ -90928,7 +90023,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
90928
90023
|
let replacementsCount = 0;
|
|
90929
90024
|
const entries = await readdir32(dir, { withFileTypes: true });
|
|
90930
90025
|
for (const entry of entries) {
|
|
90931
|
-
const fullPath =
|
|
90026
|
+
const fullPath = join105(dir, entry.name);
|
|
90932
90027
|
if (entry.isDirectory()) {
|
|
90933
90028
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
90934
90029
|
continue;
|
|
@@ -90941,7 +90036,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
90941
90036
|
if (!shouldTransform)
|
|
90942
90037
|
continue;
|
|
90943
90038
|
try {
|
|
90944
|
-
const content = await
|
|
90039
|
+
const content = await readFile49(fullPath, "utf-8");
|
|
90945
90040
|
let newContent = content;
|
|
90946
90041
|
let changeCount = 0;
|
|
90947
90042
|
for (const { regex: regex2, replacement } of compiledReplacements) {
|
|
@@ -91063,9 +90158,9 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
|
|
|
91063
90158
|
|
|
91064
90159
|
// src/services/transformers/global-path-transformer.ts
|
|
91065
90160
|
init_logger();
|
|
91066
|
-
import { readFile as
|
|
90161
|
+
import { readFile as readFile50, readdir as readdir33, writeFile as writeFile32 } from "node:fs/promises";
|
|
91067
90162
|
import { platform as platform13 } from "node:os";
|
|
91068
|
-
import { extname as extname6, join as
|
|
90163
|
+
import { extname as extname6, join as join106 } from "node:path";
|
|
91069
90164
|
var IS_WINDOWS3 = platform13() === "win32";
|
|
91070
90165
|
var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
|
|
91071
90166
|
function getHomeDirPrefix() {
|
|
@@ -91175,7 +90270,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
91175
90270
|
async function processDirectory2(dir) {
|
|
91176
90271
|
const entries = await readdir33(dir, { withFileTypes: true });
|
|
91177
90272
|
for (const entry of entries) {
|
|
91178
|
-
const fullPath =
|
|
90273
|
+
const fullPath = join106(dir, entry.name);
|
|
91179
90274
|
if (entry.isDirectory()) {
|
|
91180
90275
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
91181
90276
|
continue;
|
|
@@ -91183,7 +90278,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
91183
90278
|
await processDirectory2(fullPath);
|
|
91184
90279
|
} else if (entry.isFile() && shouldTransformFile3(entry.name)) {
|
|
91185
90280
|
try {
|
|
91186
|
-
const content = await
|
|
90281
|
+
const content = await readFile50(fullPath, "utf-8");
|
|
91187
90282
|
const { transformed, changes } = transformContent(content);
|
|
91188
90283
|
if (changes > 0) {
|
|
91189
90284
|
await writeFile32(fullPath, transformed, "utf-8");
|
|
@@ -91251,7 +90346,7 @@ async function handleTransforms(ctx) {
|
|
|
91251
90346
|
logger.debug(ctx.options.global ? "Saved folder configuration to ~/.claude/.ck.json" : "Saved folder configuration to .claude/.ck.json");
|
|
91252
90347
|
}
|
|
91253
90348
|
}
|
|
91254
|
-
const claudeDir2 = ctx.options.global ? ctx.resolvedDir :
|
|
90349
|
+
const claudeDir2 = ctx.options.global ? ctx.resolvedDir : join107(ctx.resolvedDir, ".claude");
|
|
91255
90350
|
return {
|
|
91256
90351
|
...ctx,
|
|
91257
90352
|
foldersConfig,
|
|
@@ -91445,8 +90540,8 @@ init_checksum_utils();
|
|
|
91445
90540
|
init_config_discovery();
|
|
91446
90541
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
91447
90542
|
import { existsSync as existsSync51 } from "node:fs";
|
|
91448
|
-
import { readFile as
|
|
91449
|
-
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";
|
|
91450
90545
|
|
|
91451
90546
|
// src/commands/portable/conflict-resolver.ts
|
|
91452
90547
|
init_dist2();
|
|
@@ -91793,7 +90888,7 @@ function shouldExecuteAction2(action) {
|
|
|
91793
90888
|
}
|
|
91794
90889
|
async function executeDeleteAction(action, options2) {
|
|
91795
90890
|
const preservePaths = options2?.preservePaths ?? new Set;
|
|
91796
|
-
const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(
|
|
90891
|
+
const shouldPreserveTarget = action.targetPath.length > 0 && preservePaths.has(resolve22(action.targetPath));
|
|
91797
90892
|
try {
|
|
91798
90893
|
if (!shouldPreserveTarget && action.targetPath && existsSync51(action.targetPath)) {
|
|
91799
90894
|
await rm14(action.targetPath, { recursive: true, force: true });
|
|
@@ -92018,7 +91113,7 @@ async function migrateCommand(options2) {
|
|
|
92018
91113
|
for (const action of conflictActions) {
|
|
92019
91114
|
if (!action.diff && action.targetPath && existsSync51(action.targetPath)) {
|
|
92020
91115
|
try {
|
|
92021
|
-
const targetContent = await
|
|
91116
|
+
const targetContent = await readFile51(action.targetPath, "utf-8");
|
|
92022
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);
|
|
92023
91118
|
if (sourceItem) {
|
|
92024
91119
|
const providerConfig = providers[action.provider];
|
|
@@ -92109,7 +91204,7 @@ async function migrateCommand(options2) {
|
|
|
92109
91204
|
allResults.push(...await installSkillDirectories(skills, skillProviders, installOpts));
|
|
92110
91205
|
}
|
|
92111
91206
|
}
|
|
92112
|
-
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)));
|
|
92113
91208
|
for (const deleteAction of plannedDeleteActions) {
|
|
92114
91209
|
allResults.push(await executeDeleteAction(deleteAction, {
|
|
92115
91210
|
preservePaths: writtenPaths
|
|
@@ -92225,7 +91320,7 @@ async function computeTargetStates(selectedProviders, global3) {
|
|
|
92225
91320
|
exists: true
|
|
92226
91321
|
};
|
|
92227
91322
|
try {
|
|
92228
|
-
const content = await
|
|
91323
|
+
const content = await readFile51(entry.path, "utf-8");
|
|
92229
91324
|
state.currentChecksum = computeContentChecksum(content);
|
|
92230
91325
|
} catch (error) {
|
|
92231
91326
|
logger.debug(`[migrate] Failed to read target for checksum: ${entry.path} (${String(error)})`);
|
|
@@ -92284,11 +91379,11 @@ var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
|
92284
91379
|
|
|
92285
91380
|
// src/commands/new/phases/directory-setup.ts
|
|
92286
91381
|
init_config_manager();
|
|
92287
|
-
import { resolve as
|
|
91382
|
+
import { resolve as resolve23 } from "node:path";
|
|
92288
91383
|
init_logger();
|
|
92289
91384
|
init_path_resolver();
|
|
92290
91385
|
init_types3();
|
|
92291
|
-
var
|
|
91386
|
+
var import_fs_extra35 = __toESM(require_lib3(), 1);
|
|
92292
91387
|
async function directorySetup(validOptions, prompts) {
|
|
92293
91388
|
const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
|
|
92294
91389
|
const config = await ConfigManager.get();
|
|
@@ -92369,7 +91464,7 @@ async function directorySetup(validOptions, prompts) {
|
|
|
92369
91464
|
targetDir = await prompts.getDirectory(targetDir);
|
|
92370
91465
|
}
|
|
92371
91466
|
}
|
|
92372
|
-
const resolvedDir =
|
|
91467
|
+
const resolvedDir = resolve23(targetDir);
|
|
92373
91468
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
92374
91469
|
if (PathResolver.isLocalSameAsGlobal(resolvedDir)) {
|
|
92375
91470
|
logger.warning("You're creating a project at HOME directory.");
|
|
@@ -92387,8 +91482,8 @@ async function directorySetup(validOptions, prompts) {
|
|
|
92387
91482
|
return null;
|
|
92388
91483
|
}
|
|
92389
91484
|
}
|
|
92390
|
-
if (await
|
|
92391
|
-
const files = await
|
|
91485
|
+
if (await import_fs_extra35.pathExists(resolvedDir)) {
|
|
91486
|
+
const files = await import_fs_extra35.readdir(resolvedDir);
|
|
92392
91487
|
const isEmpty = files.length === 0;
|
|
92393
91488
|
if (!isEmpty) {
|
|
92394
91489
|
if (isNonInteractive2) {
|
|
@@ -92426,7 +91521,7 @@ async function handleDirectorySetup(ctx) {
|
|
|
92426
91521
|
// src/commands/new/phases/project-creation.ts
|
|
92427
91522
|
init_config_manager();
|
|
92428
91523
|
init_github_client();
|
|
92429
|
-
import { join as
|
|
91524
|
+
import { join as join108 } from "node:path";
|
|
92430
91525
|
init_logger();
|
|
92431
91526
|
init_output_manager();
|
|
92432
91527
|
init_types3();
|
|
@@ -92552,7 +91647,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
|
|
|
92552
91647
|
output.section("Installing");
|
|
92553
91648
|
logger.verbose("Installation target", { directory: resolvedDir });
|
|
92554
91649
|
const merger = new FileMerger;
|
|
92555
|
-
const claudeDir2 =
|
|
91650
|
+
const claudeDir2 = join108(resolvedDir, ".claude");
|
|
92556
91651
|
merger.setMultiKitContext(claudeDir2, kit);
|
|
92557
91652
|
if (validOptions.exclude && validOptions.exclude.length > 0) {
|
|
92558
91653
|
merger.addIgnorePatterns(validOptions.exclude);
|
|
@@ -92599,7 +91694,7 @@ async function handleProjectCreation(ctx) {
|
|
|
92599
91694
|
}
|
|
92600
91695
|
// src/commands/new/phases/post-setup.ts
|
|
92601
91696
|
init_projects_registry();
|
|
92602
|
-
import { join as
|
|
91697
|
+
import { join as join109 } from "node:path";
|
|
92603
91698
|
init_package_installer();
|
|
92604
91699
|
init_logger();
|
|
92605
91700
|
init_path_resolver();
|
|
@@ -92631,9 +91726,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
|
|
|
92631
91726
|
withSudo: validOptions.withSudo
|
|
92632
91727
|
});
|
|
92633
91728
|
}
|
|
92634
|
-
const claudeDir2 =
|
|
91729
|
+
const claudeDir2 = join109(resolvedDir, ".claude");
|
|
92635
91730
|
await promptSetupWizardIfNeeded({
|
|
92636
|
-
envPath:
|
|
91731
|
+
envPath: join109(claudeDir2, ".env"),
|
|
92637
91732
|
claudeDir: claudeDir2,
|
|
92638
91733
|
isGlobal: false,
|
|
92639
91734
|
isNonInteractive: isNonInteractive2,
|
|
@@ -92706,11 +91801,11 @@ init_logger();
|
|
|
92706
91801
|
init_safe_prompts();
|
|
92707
91802
|
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
92708
91803
|
import { existsSync as existsSync52 } from "node:fs";
|
|
92709
|
-
import { resolve as
|
|
91804
|
+
import { resolve as resolve24 } from "node:path";
|
|
92710
91805
|
async function handleAdd(projectPath, options2) {
|
|
92711
91806
|
logger.debug(`Adding project: ${projectPath}, options: ${JSON.stringify(options2)}`);
|
|
92712
91807
|
intro("Add Project");
|
|
92713
|
-
const absolutePath =
|
|
91808
|
+
const absolutePath = resolve24(projectPath);
|
|
92714
91809
|
if (!existsSync52(absolutePath)) {
|
|
92715
91810
|
log.error(`Path does not exist: ${absolutePath}`);
|
|
92716
91811
|
process.exitCode = 1;
|
|
@@ -93600,7 +92695,7 @@ var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
|
93600
92695
|
// src/commands/uninstall/installation-detector.ts
|
|
93601
92696
|
init_claudekit_scanner();
|
|
93602
92697
|
init_path_resolver();
|
|
93603
|
-
var
|
|
92698
|
+
var import_fs_extra36 = __toESM(require_lib3(), 1);
|
|
93604
92699
|
function hasClaudeKitComponents(components) {
|
|
93605
92700
|
return components.agents > 0 || components.commands > 0 || components.rules > 0 || components.skills > 0;
|
|
93606
92701
|
}
|
|
@@ -93615,7 +92710,7 @@ async function detectInstallations() {
|
|
|
93615
92710
|
installations.push({
|
|
93616
92711
|
type: "local",
|
|
93617
92712
|
path: setup.project.path,
|
|
93618
|
-
exists: await
|
|
92713
|
+
exists: await import_fs_extra36.pathExists(setup.project.path),
|
|
93619
92714
|
hasMetadata,
|
|
93620
92715
|
components: setup.project.components
|
|
93621
92716
|
});
|
|
@@ -93628,7 +92723,7 @@ async function detectInstallations() {
|
|
|
93628
92723
|
installations.push({
|
|
93629
92724
|
type: "global",
|
|
93630
92725
|
path: setup.global.path,
|
|
93631
|
-
exists: await
|
|
92726
|
+
exists: await import_fs_extra36.pathExists(setup.global.path),
|
|
93632
92727
|
hasMetadata,
|
|
93633
92728
|
components: setup.global.components
|
|
93634
92729
|
});
|
|
@@ -93639,16 +92734,16 @@ async function detectInstallations() {
|
|
|
93639
92734
|
|
|
93640
92735
|
// src/commands/uninstall/removal-handler.ts
|
|
93641
92736
|
import { readdirSync as readdirSync6, rmSync as rmSync5 } from "node:fs";
|
|
93642
|
-
import { join as
|
|
92737
|
+
import { join as join111, resolve as resolve25, sep as sep5 } from "node:path";
|
|
93643
92738
|
init_logger();
|
|
93644
92739
|
init_safe_prompts();
|
|
93645
92740
|
init_safe_spinner();
|
|
93646
|
-
var
|
|
92741
|
+
var import_fs_extra37 = __toESM(require_lib3(), 1);
|
|
93647
92742
|
|
|
93648
92743
|
// src/commands/uninstall/analysis-handler.ts
|
|
93649
92744
|
init_metadata_migration();
|
|
93650
92745
|
import { readdirSync as readdirSync5, rmSync as rmSync4 } from "node:fs";
|
|
93651
|
-
import { dirname as
|
|
92746
|
+
import { dirname as dirname23, join as join110 } from "node:path";
|
|
93652
92747
|
init_logger();
|
|
93653
92748
|
init_safe_prompts();
|
|
93654
92749
|
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
@@ -93666,7 +92761,7 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
|
|
|
93666
92761
|
}
|
|
93667
92762
|
async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
93668
92763
|
let cleaned = 0;
|
|
93669
|
-
let currentDir =
|
|
92764
|
+
let currentDir = dirname23(filePath);
|
|
93670
92765
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
93671
92766
|
try {
|
|
93672
92767
|
const entries = readdirSync5(currentDir);
|
|
@@ -93674,7 +92769,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
|
93674
92769
|
rmSync4(currentDir, { recursive: true });
|
|
93675
92770
|
cleaned++;
|
|
93676
92771
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
93677
|
-
currentDir =
|
|
92772
|
+
currentDir = dirname23(currentDir);
|
|
93678
92773
|
} else {
|
|
93679
92774
|
break;
|
|
93680
92775
|
}
|
|
@@ -93696,7 +92791,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
93696
92791
|
if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
|
|
93697
92792
|
const kitFiles = metadata.kits[kit].files || [];
|
|
93698
92793
|
for (const trackedFile of kitFiles) {
|
|
93699
|
-
const filePath =
|
|
92794
|
+
const filePath = join110(installation.path, trackedFile.path);
|
|
93700
92795
|
if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
|
|
93701
92796
|
result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
|
|
93702
92797
|
continue;
|
|
@@ -93726,7 +92821,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
93726
92821
|
return result;
|
|
93727
92822
|
}
|
|
93728
92823
|
for (const trackedFile of allTrackedFiles) {
|
|
93729
|
-
const filePath =
|
|
92824
|
+
const filePath = join110(installation.path, trackedFile.path);
|
|
93730
92825
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
93731
92826
|
if (!ownershipResult.exists)
|
|
93732
92827
|
continue;
|
|
@@ -93771,7 +92866,7 @@ function displayDryRunPreview(analysis, installationType) {
|
|
|
93771
92866
|
// src/commands/uninstall/removal-handler.ts
|
|
93772
92867
|
async function isDirectory(filePath) {
|
|
93773
92868
|
try {
|
|
93774
|
-
const stats = await
|
|
92869
|
+
const stats = await import_fs_extra37.lstat(filePath);
|
|
93775
92870
|
return stats.isDirectory();
|
|
93776
92871
|
} catch {
|
|
93777
92872
|
logger.debug(`Failed to check if path is directory: ${filePath}`);
|
|
@@ -93780,16 +92875,16 @@ async function isDirectory(filePath) {
|
|
|
93780
92875
|
}
|
|
93781
92876
|
async function isPathSafeToRemove(filePath, baseDir) {
|
|
93782
92877
|
try {
|
|
93783
|
-
const resolvedPath =
|
|
93784
|
-
const resolvedBase =
|
|
92878
|
+
const resolvedPath = resolve25(filePath);
|
|
92879
|
+
const resolvedBase = resolve25(baseDir);
|
|
93785
92880
|
if (!resolvedPath.startsWith(resolvedBase + sep5) && resolvedPath !== resolvedBase) {
|
|
93786
92881
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
93787
92882
|
return false;
|
|
93788
92883
|
}
|
|
93789
|
-
const stats = await
|
|
92884
|
+
const stats = await import_fs_extra37.lstat(filePath);
|
|
93790
92885
|
if (stats.isSymbolicLink()) {
|
|
93791
|
-
const realPath = await
|
|
93792
|
-
const resolvedReal =
|
|
92886
|
+
const realPath = await import_fs_extra37.realpath(filePath);
|
|
92887
|
+
const resolvedReal = resolve25(realPath);
|
|
93793
92888
|
if (!resolvedReal.startsWith(resolvedBase + sep5) && resolvedReal !== resolvedBase) {
|
|
93794
92889
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
93795
92890
|
return false;
|
|
@@ -93823,15 +92918,15 @@ async function removeInstallations(installations, options2) {
|
|
|
93823
92918
|
let removedCount = 0;
|
|
93824
92919
|
let cleanedDirs = 0;
|
|
93825
92920
|
for (const item of analysis.toDelete) {
|
|
93826
|
-
const filePath =
|
|
93827
|
-
if (!await
|
|
92921
|
+
const filePath = join111(installation.path, item.path);
|
|
92922
|
+
if (!await import_fs_extra37.pathExists(filePath))
|
|
93828
92923
|
continue;
|
|
93829
92924
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
93830
92925
|
logger.debug(`Skipping unsafe path: ${item.path}`);
|
|
93831
92926
|
continue;
|
|
93832
92927
|
}
|
|
93833
92928
|
const isDir = await isDirectory(filePath);
|
|
93834
|
-
await
|
|
92929
|
+
await import_fs_extra37.remove(filePath);
|
|
93835
92930
|
removedCount++;
|
|
93836
92931
|
logger.debug(`Removed ${isDir ? "directory" : "file"}: ${item.path}`);
|
|
93837
92932
|
if (!isDir) {
|
|
@@ -94015,12 +93110,6 @@ ${import_picocolors32.default.yellow("User modifications will be permanently del
|
|
|
94015
93110
|
forceOverwrite: validOptions.forceOverwrite,
|
|
94016
93111
|
kit: validOptions.kit
|
|
94017
93112
|
});
|
|
94018
|
-
if (!validOptions.kit || validOptions.kit === "engineer") {
|
|
94019
|
-
try {
|
|
94020
|
-
const { handlePluginUninstall: handlePluginUninstall2 } = await Promise.resolve().then(() => (init_plugin_installer(), exports_plugin_installer));
|
|
94021
|
-
await handlePluginUninstall2();
|
|
94022
|
-
} catch {}
|
|
94023
|
-
}
|
|
94024
93113
|
const kitMsg = validOptions.kit ? ` (${validOptions.kit} kit)` : "";
|
|
94025
93114
|
prompts.outro(`ClaudeKit${kitMsg} uninstalled successfully!`);
|
|
94026
93115
|
} catch (error) {
|
|
@@ -94222,7 +93311,7 @@ init_logger();
|
|
|
94222
93311
|
init_path_resolver();
|
|
94223
93312
|
init_types3();
|
|
94224
93313
|
import { existsSync as existsSync53, readFileSync as readFileSync10 } from "node:fs";
|
|
94225
|
-
import { join as
|
|
93314
|
+
import { join as join112 } from "node:path";
|
|
94226
93315
|
var packageVersion = package_default.version;
|
|
94227
93316
|
function formatInstalledKits(metadata) {
|
|
94228
93317
|
if (!metadata.kits || Object.keys(metadata.kits).length === 0) {
|
|
@@ -94254,9 +93343,9 @@ async function displayVersion() {
|
|
|
94254
93343
|
let localKitVersion = null;
|
|
94255
93344
|
let isGlobalOnlyKit = false;
|
|
94256
93345
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
94257
|
-
const globalMetadataPath =
|
|
93346
|
+
const globalMetadataPath = join112(globalKitDir, "metadata.json");
|
|
94258
93347
|
const prefix = PathResolver.getPathPrefix(false);
|
|
94259
|
-
const localMetadataPath = prefix ?
|
|
93348
|
+
const localMetadataPath = prefix ? join112(process.cwd(), prefix, "metadata.json") : join112(process.cwd(), "metadata.json");
|
|
94260
93349
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
94261
93350
|
if (!isLocalSameAsGlobal && existsSync53(localMetadataPath)) {
|
|
94262
93351
|
try {
|
|
@@ -94649,7 +93738,7 @@ var output2 = new OutputManager2;
|
|
|
94649
93738
|
|
|
94650
93739
|
// src/shared/temp-cleanup.ts
|
|
94651
93740
|
init_logger();
|
|
94652
|
-
var
|
|
93741
|
+
var import_fs_extra38 = __toESM(require_lib3(), 1);
|
|
94653
93742
|
import { rmSync as rmSync6 } from "node:fs";
|
|
94654
93743
|
var tempDirs2 = new Set;
|
|
94655
93744
|
async function cleanup() {
|
|
@@ -94658,7 +93747,7 @@ async function cleanup() {
|
|
|
94658
93747
|
logger.debug(`Cleaning up ${tempDirs2.size} temporary director(ies)...`);
|
|
94659
93748
|
for (const dir of tempDirs2) {
|
|
94660
93749
|
try {
|
|
94661
|
-
await
|
|
93750
|
+
await import_fs_extra38.remove(dir);
|
|
94662
93751
|
logger.debug(`Cleaned up temp directory: ${dir}`);
|
|
94663
93752
|
} catch (error) {
|
|
94664
93753
|
logger.debug(`Failed to clean temp directory ${dir}: ${error}`);
|