claudekit-cli 4.2.1 → 4.2.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/cli-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "4.2.1",
3
- "generatedAt": "2026-05-12T16:32:49.942Z",
2
+ "version": "4.2.3",
3
+ "generatedAt": "2026-05-12T19:34:12.422Z",
4
4
  "commands": {
5
5
  "agents": {
6
6
  "name": "agents",
package/dist/index.js CHANGED
@@ -45544,6 +45544,45 @@ function formatCanonicalClaudeCommand(nodePrefix, root, relativePath, suffix = "
45544
45544
  }
45545
45545
  return normalizedRoot === "$CLAUDE_PROJECT_DIR" ? `${nodePrefix}"${normalizedRoot}"/${normalizedRelativePath}${suffix}` : `${nodePrefix}"${normalizedRoot}/${normalizedRelativePath}"${suffix}`;
45546
45546
  }
45547
+ function resolveClaudePathArg(arg, root) {
45548
+ const normalizedArg = arg.replace(/\\/g, "/");
45549
+ const bareRelativeMatch = normalizedArg.match(/^(?:\.\/)?(\.claude\/.+)$/);
45550
+ if (bareRelativeMatch) {
45551
+ return { root, relativePath: bareRelativeMatch[1] };
45552
+ }
45553
+ const variableMatch = normalizedArg.match(/^(?:\$HOME|\$\{HOME\}|\$CLAUDE_PROJECT_DIR|\$\{CLAUDE_PROJECT_DIR\}|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)\/(\.claude\/.+)$/);
45554
+ if (variableMatch) {
45555
+ return { root, relativePath: variableMatch[1] };
45556
+ }
45557
+ const tildeMatch = normalizedArg.match(/^~\/(\.claude\/.+)$/);
45558
+ if (tildeMatch) {
45559
+ return { root, relativePath: tildeMatch[1] };
45560
+ }
45561
+ const absoluteMatch = normalizedArg.match(/^((?:[A-Za-z]:\/|\/).*?\/\.claude\/.+)$/);
45562
+ if (absoluteMatch) {
45563
+ const absolutePath = absoluteMatch[1];
45564
+ const dotClaudeIdx = absolutePath.indexOf("/.claude/");
45565
+ if (dotClaudeIdx === -1) {
45566
+ return null;
45567
+ }
45568
+ const isWin2 = process.platform === "win32";
45569
+ const cmp = (s) => isWin2 ? s.toLowerCase() : s;
45570
+ const globalRoots = [
45571
+ `${homedir12().replace(/\\/g, "/").replace(/\/+$/, "")}/.claude/`,
45572
+ `${PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "")}/`
45573
+ ];
45574
+ const isUnderGlobal = globalRoots.some((g2) => cmp(absolutePath).startsWith(cmp(g2)));
45575
+ const resolvedRoot = isUnderGlobal ? "$HOME" : root;
45576
+ return {
45577
+ root: resolvedRoot,
45578
+ relativePath: absolutePath.slice(dotClaudeIdx + 1)
45579
+ };
45580
+ }
45581
+ return null;
45582
+ }
45583
+ function formatCanonicalClaudeArg(pathArg) {
45584
+ return formatCanonicalClaudeCommand("", pathArg.root, pathArg.relativePath);
45585
+ }
45547
45586
  function isNodeClaudeCommand(cmd) {
45548
45587
  if (!cmd)
45549
45588
  return false;
@@ -45611,6 +45650,39 @@ function repairClaudeNodeCommandPath(cmd, root) {
45611
45650
  }
45612
45651
  return { command: cmd, changed: false, issue: null };
45613
45652
  }
45653
+ function repairClaudeHookRunnerCommandPath(cmd, root) {
45654
+ if (!cmd) {
45655
+ return { command: cmd ?? "", changed: false, issue: null };
45656
+ }
45657
+ const runnerMatch = cmd.match(/^(\s*bash\s+)(?:"([^"]+)"|([^\s"]+))\s+(?:"([^"]+)"|([^\s"]+))(.*)$/);
45658
+ if (!runnerMatch) {
45659
+ return { command: cmd, changed: false, issue: null };
45660
+ }
45661
+ const [, bashPrefix, quotedRunner, unquotedRunner, quotedTarget, unquotedTarget, suffix] = runnerMatch;
45662
+ const runnerArg = quotedRunner ?? unquotedRunner;
45663
+ const targetArg = quotedTarget ?? unquotedTarget;
45664
+ const runnerPath = resolveClaudePathArg(runnerArg, root);
45665
+ if (!runnerPath || runnerPath.relativePath.replace(/\\/g, "/") !== ".claude/hooks/node-hook-runner.sh") {
45666
+ return { command: cmd, changed: false, issue: null };
45667
+ }
45668
+ const targetPath = resolveClaudePathArg(targetArg, root);
45669
+ if (!targetPath) {
45670
+ return { command: cmd, changed: false, issue: null };
45671
+ }
45672
+ const command = `${bashPrefix}${formatCanonicalClaudeArg(runnerPath)} ${formatCanonicalClaudeArg(targetPath)}${suffix}`;
45673
+ return {
45674
+ command,
45675
+ changed: command !== cmd,
45676
+ issue: command !== cmd ? "invalid-format" : null
45677
+ };
45678
+ }
45679
+ function repairClaudeHookCommandPath(cmd, root) {
45680
+ const nodeRepair = repairClaudeNodeCommandPath(cmd, root);
45681
+ if (nodeRepair.changed || nodeRepair.issue || isNodeClaudeCommand(cmd)) {
45682
+ return nodeRepair;
45683
+ }
45684
+ return repairClaudeHookRunnerCommandPath(cmd, root);
45685
+ }
45614
45686
  function normalizeCommand(cmd) {
45615
45687
  if (!cmd)
45616
45688
  return "";
@@ -62890,7 +62962,7 @@ var package_default;
62890
62962
  var init_package = __esm(() => {
62891
62963
  package_default = {
62892
62964
  name: "claudekit-cli",
62893
- version: "4.2.1",
62965
+ version: "4.2.3",
62894
62966
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
62895
62967
  type: "module",
62896
62968
  repository: {
@@ -85190,12 +85262,13 @@ async function applyBudgetDefaults(settingsPath, projectClaudeDir, requiredFract
85190
85262
  var ENGINEER_SKILL_COUNT_THRESHOLD = 20;
85191
85263
  async function checkSkillBudget(setup, projectDir) {
85192
85264
  const projectClaudeDir = resolve31(projectDir, ".claude");
85193
- const globalClaudeDir = PathResolver.getGlobalKitDir();
85265
+ const globalClaudeDir = resolve31(PathResolver.getGlobalKitDir());
85266
+ const projectScopeAliasesGlobal = projectClaudeDir === globalClaudeDir;
85194
85267
  const [projectSkills, globalSkills] = await Promise.all([
85195
- scanSkills2(join75(projectClaudeDir, "skills")),
85268
+ projectScopeAliasesGlobal ? Promise.resolve([]) : scanSkills2(join75(projectClaudeDir, "skills")),
85196
85269
  scanSkills2(join75(globalClaudeDir, "skills"))
85197
85270
  ]);
85198
- if (!isEngineerLikeProject(setup, projectSkills))
85271
+ if (!isEngineerLikeProject(setup, [...projectSkills, ...globalSkills]))
85199
85272
  return [];
85200
85273
  const settingsPath = join75(projectClaudeDir, "settings.json");
85201
85274
  const settings = await readProjectSettings(settingsPath);
@@ -85216,7 +85289,10 @@ function isEngineerLikeProject(setup, projectSkills) {
85216
85289
  const metadataText = [
85217
85290
  setup.project.metadata?.name,
85218
85291
  setup.project.metadata?.description,
85219
- setup.project.metadata?.repository?.url
85292
+ setup.project.metadata?.repository?.url,
85293
+ setup.global.metadata?.name,
85294
+ setup.global.metadata?.description,
85295
+ setup.global.metadata?.repository?.url
85220
85296
  ].filter(Boolean).join(" ").toLowerCase();
85221
85297
  return metadataText.includes("engineer") || projectSkills.length >= ENGINEER_SKILL_COUNT_THRESHOLD;
85222
85298
  }
@@ -86280,7 +86356,7 @@ function getClaudeSettingsFiles(projectDir) {
86280
86356
  return candidates.filter((candidate) => existsSync56(candidate.path));
86281
86357
  }
86282
86358
  function isAlreadyCanonical(cmd) {
86283
- return /^node\s+"\$HOME\/\.claude\/[^"]+"/.test(cmd) || /^node\s+"\$CLAUDE_PROJECT_DIR"\/\.claude\/\S+/.test(cmd);
86359
+ return /^node\s+"\$HOME\/\.claude\/[^"]+"/.test(cmd) || /^node\s+"\$CLAUDE_PROJECT_DIR"\/\.claude\/\S+/.test(cmd) || /^bash\s+"\$HOME\/\.claude\/hooks\/node-hook-runner\.sh"\s+"\$HOME\/\.claude\/[^"]+"/.test(cmd) || /^bash\s+"\$CLAUDE_PROJECT_DIR"\/\.claude\/hooks\/node-hook-runner\.sh\s+"\$CLAUDE_PROJECT_DIR"\/\.claude\/\S+/.test(cmd);
86284
86360
  }
86285
86361
  function collectHookCommandFindings(settings, settingsFile) {
86286
86362
  if (!settings.hooks) {
@@ -86292,7 +86368,7 @@ function collectHookCommandFindings(settings, settingsFile) {
86292
86368
  if ("command" in entry && typeof entry.command === "string") {
86293
86369
  if (isAlreadyCanonical(entry.command))
86294
86370
  continue;
86295
- const repair = repairClaudeNodeCommandPath(entry.command, settingsFile.root);
86371
+ const repair = repairClaudeHookCommandPath(entry.command, settingsFile.root);
86296
86372
  if (repair.changed && repair.issue) {
86297
86373
  findings.push({
86298
86374
  path: settingsFile.path,
@@ -86313,7 +86389,7 @@ function collectHookCommandFindings(settings, settingsFile) {
86313
86389
  }
86314
86390
  if (isAlreadyCanonical(hook.command))
86315
86391
  continue;
86316
- const repair = repairClaudeNodeCommandPath(hook.command, settingsFile.root);
86392
+ const repair = repairClaudeHookCommandPath(hook.command, settingsFile.root);
86317
86393
  if (!repair.changed || !repair.issue) {
86318
86394
  continue;
86319
86395
  }
@@ -102339,7 +102415,7 @@ class SettingsProcessor {
102339
102415
  return fixed;
102340
102416
  }
102341
102417
  fixSingleCommandPath(cmd) {
102342
- return repairClaudeNodeCommandPath(cmd, this.getClaudeCommandRoot()).command;
102418
+ return repairClaudeHookCommandPath(cmd, this.getClaudeCommandRoot()).command;
102343
102419
  }
102344
102420
  formatCommandPath(nodePrefix, capturedVar, relativePath, suffix = "") {
102345
102421
  const canonicalRoot = this.canonicalizePathRoot(capturedVar);
@@ -111466,7 +111542,7 @@ import { readFile as readFile65 } from "node:fs/promises";
111466
111542
  import { join as join149 } from "node:path";
111467
111543
 
111468
111544
  // src/commands/skills/installed-skills-inventory.ts
111469
- import { join as join148 } from "node:path";
111545
+ import { join as join148, resolve as resolve53 } from "node:path";
111470
111546
  init_path_resolver();
111471
111547
  var SCOPE_SORT_ORDER = {
111472
111548
  project: 0,
@@ -111474,9 +111550,11 @@ var SCOPE_SORT_ORDER = {
111474
111550
  };
111475
111551
  async function getActiveClaudeSkillInstallations(options2 = {}) {
111476
111552
  const projectDir = options2.projectDir ?? process.cwd();
111477
- const globalDir = options2.globalDir ?? PathResolver.getGlobalKitDir();
111553
+ const globalDir = resolve53(options2.globalDir ?? PathResolver.getGlobalKitDir());
111554
+ const projectClaudeDir = resolve53(projectDir, ".claude");
111555
+ const projectScopeAliasesGlobal = projectClaudeDir === globalDir;
111478
111556
  const [projectSkills, globalSkills] = await Promise.all([
111479
- scanSkills2(join148(projectDir, ".claude", "skills")),
111557
+ projectScopeAliasesGlobal ? Promise.resolve([]) : scanSkills2(join148(projectClaudeDir, "skills")),
111480
111558
  scanSkills2(join148(globalDir, "skills"))
111481
111559
  ]);
111482
111560
  const projectIds = new Set(projectSkills.map((skill) => skill.id));
@@ -112220,7 +112298,7 @@ async function detectInstallations() {
112220
112298
 
112221
112299
  // src/commands/uninstall/removal-handler.ts
112222
112300
  import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
112223
- import { basename as basename30, join as join151, resolve as resolve53, sep as sep13 } from "node:path";
112301
+ import { basename as basename30, join as join151, resolve as resolve54, sep as sep13 } from "node:path";
112224
112302
  init_logger();
112225
112303
  init_safe_prompts();
112226
112304
  init_safe_spinner();
@@ -112404,8 +112482,8 @@ async function restoreUninstallBackup(backup) {
112404
112482
  }
112405
112483
  async function isPathSafeToRemove(filePath, baseDir) {
112406
112484
  try {
112407
- const resolvedPath = resolve53(filePath);
112408
- const resolvedBase = resolve53(baseDir);
112485
+ const resolvedPath = resolve54(filePath);
112486
+ const resolvedBase = resolve54(baseDir);
112409
112487
  if (!resolvedPath.startsWith(resolvedBase + sep13) && resolvedPath !== resolvedBase) {
112410
112488
  logger.debug(`Path outside installation directory: ${filePath}`);
112411
112489
  return false;
@@ -112413,7 +112491,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
112413
112491
  const stats = await import_fs_extra41.lstat(filePath);
112414
112492
  if (stats.isSymbolicLink()) {
112415
112493
  const realPath = await import_fs_extra41.realpath(filePath);
112416
- const resolvedReal = resolve53(realPath);
112494
+ const resolvedReal = resolve54(realPath);
112417
112495
  if (!resolvedReal.startsWith(resolvedBase + sep13) && resolvedReal !== resolvedBase) {
112418
112496
  logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
112419
112497
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "4.2.1",
3
+ "version": "4.2.3",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {