claudekit-cli 3.32.0-dev.1 → 3.32.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +111 -29
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23196,7 +23196,7 @@ function getPagerArgs(pagerCmd) {
23196
23196
  return [];
23197
23197
  }
23198
23198
  async function trySystemPager(content) {
23199
- return new Promise((resolve12) => {
23199
+ return new Promise((resolve13) => {
23200
23200
  const pagerCmd = process.env.PAGER || "less";
23201
23201
  const pagerArgs = getPagerArgs(pagerCmd);
23202
23202
  try {
@@ -23206,20 +23206,20 @@ async function trySystemPager(content) {
23206
23206
  });
23207
23207
  const timeout = setTimeout(() => {
23208
23208
  pager.kill();
23209
- resolve12(false);
23209
+ resolve13(false);
23210
23210
  }, 30000);
23211
23211
  pager.stdin.write(content);
23212
23212
  pager.stdin.end();
23213
23213
  pager.on("close", (code2) => {
23214
23214
  clearTimeout(timeout);
23215
- resolve12(code2 === 0);
23215
+ resolve13(code2 === 0);
23216
23216
  });
23217
23217
  pager.on("error", () => {
23218
23218
  clearTimeout(timeout);
23219
- resolve12(false);
23219
+ resolve13(false);
23220
23220
  });
23221
23221
  } catch {
23222
- resolve12(false);
23222
+ resolve13(false);
23223
23223
  }
23224
23224
  });
23225
23225
  }
@@ -23246,16 +23246,16 @@ async function basicPager(content) {
23246
23246
  break;
23247
23247
  }
23248
23248
  const remaining = lines.length - currentLine;
23249
- await new Promise((resolve12) => {
23249
+ await new Promise((resolve13) => {
23250
23250
  rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
23251
23251
  if (answer.toLowerCase() === "q") {
23252
23252
  rl.close();
23253
23253
  process.exitCode = 0;
23254
- resolve12();
23254
+ resolve13();
23255
23255
  return;
23256
23256
  }
23257
23257
  process.stdout.write("\x1B[1A\x1B[2K");
23258
- resolve12();
23258
+ resolve13();
23259
23259
  });
23260
23260
  });
23261
23261
  }
@@ -49300,30 +49300,45 @@ var import_picocolors23 = __toESM(require_picocolors(), 1);
49300
49300
  // src/commands/uninstall/installation-detector.ts
49301
49301
  init_path_resolver();
49302
49302
  var import_fs_extra35 = __toESM(require_lib(), 1);
49303
+ function hasClaudeKitComponents(components) {
49304
+ return components.agents > 0 || components.commands > 0 || components.rules > 0 || components.skills > 0;
49305
+ }
49303
49306
  async function detectInstallations() {
49304
49307
  const installations = [];
49305
49308
  const setup = await getClaudeKitSetup(process.cwd());
49306
49309
  const isLocalSameAsGlobal = PathResolver.isLocalSameAsGlobal();
49307
- if (setup.project.path && setup.project.metadata && !isLocalSameAsGlobal) {
49308
- installations.push({
49309
- type: "local",
49310
- path: setup.project.path,
49311
- exists: await import_fs_extra35.pathExists(setup.project.path)
49312
- });
49310
+ if (setup.project.path && !isLocalSameAsGlobal) {
49311
+ const hasMetadata = setup.project.metadata !== null;
49312
+ const hasComponents = hasClaudeKitComponents(setup.project.components);
49313
+ if (hasMetadata || hasComponents) {
49314
+ installations.push({
49315
+ type: "local",
49316
+ path: setup.project.path,
49317
+ exists: await import_fs_extra35.pathExists(setup.project.path),
49318
+ hasMetadata,
49319
+ components: setup.project.components
49320
+ });
49321
+ }
49313
49322
  }
49314
- if (setup.global.path && setup.global.metadata) {
49315
- installations.push({
49316
- type: "global",
49317
- path: setup.global.path,
49318
- exists: await import_fs_extra35.pathExists(setup.global.path)
49319
- });
49323
+ if (setup.global.path) {
49324
+ const hasMetadata = setup.global.metadata !== null;
49325
+ const hasComponents = hasClaudeKitComponents(setup.global.components);
49326
+ if (hasMetadata || hasComponents) {
49327
+ installations.push({
49328
+ type: "global",
49329
+ path: setup.global.path,
49330
+ exists: await import_fs_extra35.pathExists(setup.global.path),
49331
+ hasMetadata,
49332
+ components: setup.global.components
49333
+ });
49334
+ }
49320
49335
  }
49321
49336
  return installations.filter((i) => i.exists);
49322
49337
  }
49323
49338
 
49324
49339
  // src/commands/uninstall/removal-handler.ts
49325
49340
  import { readdirSync as readdirSync4, rmSync as rmSync5 } from "node:fs";
49326
- import { join as join81 } from "node:path";
49341
+ import { join as join81, resolve as resolve12, sep as sep3 } from "node:path";
49327
49342
  init_logger();
49328
49343
  var import_fs_extra36 = __toESM(require_lib(), 1);
49329
49344
 
@@ -49449,28 +49464,72 @@ function displayDryRunPreview(analysis, installationType) {
49449
49464
  }
49450
49465
 
49451
49466
  // src/commands/uninstall/removal-handler.ts
49467
+ async function isDirectory(filePath) {
49468
+ try {
49469
+ const stats = await import_fs_extra36.lstat(filePath);
49470
+ return stats.isDirectory();
49471
+ } catch {
49472
+ logger.debug(`Failed to check if path is directory: ${filePath}`);
49473
+ return false;
49474
+ }
49475
+ }
49476
+ async function isPathSafeToRemove(filePath, baseDir) {
49477
+ try {
49478
+ const resolvedPath = resolve12(filePath);
49479
+ const resolvedBase = resolve12(baseDir);
49480
+ if (!resolvedPath.startsWith(resolvedBase + sep3) && resolvedPath !== resolvedBase) {
49481
+ logger.debug(`Path outside installation directory: ${filePath}`);
49482
+ return false;
49483
+ }
49484
+ const stats = await import_fs_extra36.lstat(filePath);
49485
+ if (stats.isSymbolicLink()) {
49486
+ const realPath = await import_fs_extra36.realpath(filePath);
49487
+ const resolvedReal = resolve12(realPath);
49488
+ if (!resolvedReal.startsWith(resolvedBase + sep3) && resolvedReal !== resolvedBase) {
49489
+ logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
49490
+ return false;
49491
+ }
49492
+ }
49493
+ return true;
49494
+ } catch {
49495
+ logger.debug(`Failed to validate path safety: ${filePath}`);
49496
+ return false;
49497
+ }
49498
+ }
49452
49499
  async function removeInstallations(installations, options2) {
49453
49500
  for (const installation of installations) {
49454
49501
  const analysis = await analyzeInstallation(installation, options2.forceOverwrite, options2.kit);
49455
49502
  if (options2.dryRun) {
49456
49503
  const label = options2.kit ? `${installation.type} (${options2.kit} kit)` : installation.type;
49457
- displayDryRunPreview(analysis, label);
49504
+ const legacyLabel2 = !installation.hasMetadata ? " [legacy]" : "";
49505
+ displayDryRunPreview(analysis, `${label}${legacyLabel2}`);
49458
49506
  if (analysis.remainingKits.length > 0) {
49459
49507
  log.info(`Remaining kits after uninstall: ${analysis.remainingKits.join(", ")}`);
49460
49508
  }
49509
+ if (!installation.hasMetadata) {
49510
+ log.warn("Legacy installation - directories will be removed recursively");
49511
+ }
49461
49512
  continue;
49462
49513
  }
49463
49514
  const kitLabel = options2.kit ? ` ${options2.kit} kit` : "";
49464
- const spinner = createSpinner(`Removing ${installation.type}${kitLabel} ClaudeKit files...`).start();
49515
+ const legacyLabel = !installation.hasMetadata ? " (legacy)" : "";
49516
+ const spinner = createSpinner(`Removing ${installation.type}${kitLabel}${legacyLabel} ClaudeKit files...`).start();
49465
49517
  try {
49466
49518
  let removedCount = 0;
49467
49519
  let cleanedDirs = 0;
49468
49520
  for (const item of analysis.toDelete) {
49469
49521
  const filePath = join81(installation.path, item.path);
49470
- if (await import_fs_extra36.pathExists(filePath)) {
49471
- await import_fs_extra36.remove(filePath);
49472
- removedCount++;
49473
- logger.debug(`Removed: ${item.path}`);
49522
+ if (!await import_fs_extra36.pathExists(filePath))
49523
+ continue;
49524
+ if (!await isPathSafeToRemove(filePath, installation.path)) {
49525
+ logger.debug(`Skipping unsafe path: ${item.path}`);
49526
+ continue;
49527
+ }
49528
+ const isDir = await isDirectory(filePath);
49529
+ await import_fs_extra36.remove(filePath);
49530
+ removedCount++;
49531
+ logger.debug(`Removed ${isDir ? "directory" : "file"}: ${item.path}`);
49532
+ if (!isDir) {
49474
49533
  cleanedDirs += await cleanupEmptyDirectories3(filePath, installation.path);
49475
49534
  }
49476
49535
  }
@@ -49502,11 +49561,34 @@ async function removeInstallations(installations, options2) {
49502
49561
 
49503
49562
  // src/commands/uninstall/uninstall-command.ts
49504
49563
  var prompts = new PromptsManager;
49564
+ function formatComponentSummary(inst) {
49565
+ const parts = [];
49566
+ if (inst.components.skills > 0)
49567
+ parts.push(`${inst.components.skills} skills`);
49568
+ if (inst.components.commands > 0)
49569
+ parts.push(`${inst.components.commands} commands`);
49570
+ if (inst.components.agents > 0)
49571
+ parts.push(`${inst.components.agents} agents`);
49572
+ if (inst.components.rules > 0)
49573
+ parts.push(`${inst.components.rules} rules`);
49574
+ return parts.length > 0 ? ` (${parts.join(", ")})` : "";
49575
+ }
49505
49576
  function displayInstallations(installations, scope) {
49506
49577
  prompts.intro("ClaudeKit Uninstaller");
49507
49578
  const scopeLabel = scope === "all" ? "all" : scope === "local" ? "local only" : "global only";
49508
- prompts.note(installations.map((i) => ` ${i.type === "local" ? "Local " : "Global"}: ${i.path}`).join(`
49579
+ const hasLegacy = installations.some((i) => !i.hasMetadata);
49580
+ const lines = installations.map((i) => {
49581
+ const typeLabel = i.type === "local" ? "Local " : "Global";
49582
+ const legacyTag = !i.hasMetadata ? import_picocolors23.default.yellow(" [legacy]") : "";
49583
+ const components = formatComponentSummary(i);
49584
+ return ` ${typeLabel}: ${i.path}${legacyTag}${components}`;
49585
+ });
49586
+ prompts.note(lines.join(`
49509
49587
  `), `Detected ClaudeKit installations (${scopeLabel})`);
49588
+ if (hasLegacy) {
49589
+ log.warn(import_picocolors23.default.yellow(`[!] Legacy installation(s) detected without metadata.json.
49590
+ `) + import_picocolors23.default.yellow(" These files cannot be selectively removed. Full directory cleanup will be performed."));
49591
+ }
49510
49592
  log.warn("[!] This will permanently delete ClaudeKit files from the above paths.");
49511
49593
  }
49512
49594
  async function promptScope(installations) {
@@ -49787,7 +49869,7 @@ var import_fs_extra37 = __toESM(require_lib(), 1);
49787
49869
  // package.json
49788
49870
  var package_default = {
49789
49871
  name: "claudekit-cli",
49790
- version: "3.32.0-dev.1",
49872
+ version: "3.32.0-dev.2",
49791
49873
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
49792
49874
  type: "module",
49793
49875
  repository: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.32.0-dev.1",
3
+ "version": "3.32.0-dev.2",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {