claudekit-cli 3.35.0-dev.23 → 3.35.0-dev.25

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 +271 -146
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -42500,14 +42500,11 @@ function normalizeCommand(cmd) {
42500
42500
  if (!cmd)
42501
42501
  return "";
42502
42502
  let normalized = cmd;
42503
- normalized = normalized.replace(/"\$HOME"/g, "$HOME");
42504
- normalized = normalized.replace(/"\$CLAUDE_PROJECT_DIR"/g, "$HOME");
42505
- normalized = normalized.replace(/"\$\{HOME\}"/g, "$HOME");
42503
+ normalized = normalized.replace(/"/g, "");
42504
+ normalized = normalized.replace(/~\//g, "$HOME/");
42506
42505
  normalized = normalized.replace(/\$CLAUDE_PROJECT_DIR/g, "$HOME");
42507
42506
  normalized = normalized.replace(/\$\{HOME\}/g, "$HOME");
42508
- normalized = normalized.replace(/"%USERPROFILE%"/g, "$HOME");
42509
42507
  normalized = normalized.replace(/%USERPROFILE%/g, "$HOME");
42510
- normalized = normalized.replace(/"%CLAUDE_PROJECT_DIR%"/g, "$HOME");
42511
42508
  normalized = normalized.replace(/%CLAUDE_PROJECT_DIR%/g, "$HOME");
42512
42509
  normalized = normalized.replace(/\\/g, "/");
42513
42510
  normalized = normalized.replace(/\s+/g, " ").trim();
@@ -50915,11 +50912,17 @@ function registerMigrationRoutes(app) {
50915
50912
  const registry = await readPortableRegistry();
50916
50913
  const targetStates = new Map;
50917
50914
  for (const entry of registry.installations) {
50915
+ if (entry.type === "skill")
50916
+ continue;
50918
50917
  const exists = existsSync20(entry.path);
50919
50918
  const state = { path: entry.path, exists };
50920
50919
  if (exists) {
50921
- const content = await readFile15(entry.path, "utf-8");
50922
- state.currentChecksum = computeContentChecksum(content);
50920
+ try {
50921
+ const content = await readFile15(entry.path, "utf-8");
50922
+ state.currentChecksum = computeContentChecksum(content);
50923
+ } catch (error) {
50924
+ warnReadFailure("registry-target", entry.path, error);
50925
+ }
50923
50926
  }
50924
50927
  targetStates.set(entry.path, state);
50925
50928
  }
@@ -52836,6 +52839,27 @@ var init_skill_routes = __esm(() => {
52836
52839
  });
52837
52840
 
52838
52841
  // src/domains/github/npm-registry.ts
52842
+ function redactRegistryUrlForLog(url) {
52843
+ if (!url)
52844
+ return url;
52845
+ try {
52846
+ const parsed = new URL(url);
52847
+ if (parsed.username) {
52848
+ parsed.username = REDACTED_VALUE;
52849
+ }
52850
+ if (parsed.password) {
52851
+ parsed.password = REDACTED_VALUE;
52852
+ }
52853
+ for (const key of parsed.searchParams.keys()) {
52854
+ if (/(token|auth|password|secret|key)/i.test(key)) {
52855
+ parsed.searchParams.set(key, REDACTED_VALUE);
52856
+ }
52857
+ }
52858
+ return parsed.toString();
52859
+ } catch {
52860
+ return url.replace(/\/\/([^/@\s]+)@/, `//${REDACTED_VALUE}@`);
52861
+ }
52862
+ }
52839
52863
  async function fetchWithTimeout(url, options2 = {}, timeout2 = REQUEST_TIMEOUT) {
52840
52864
  const controller = new AbortController;
52841
52865
  const timeoutId = setTimeout(() => controller.abort(), timeout2);
@@ -52857,7 +52881,7 @@ class NpmRegistryClient {
52857
52881
  }
52858
52882
  const registry = registryUrl || DEFAULT_REGISTRY_URL;
52859
52883
  const url = `${registry}/${encodeURIComponent(packageName)}`;
52860
- logger.debug(`Fetching package info from: ${url}`);
52884
+ logger.debug(`Fetching package info from: ${redactRegistryUrlForLog(url)}`);
52861
52885
  try {
52862
52886
  const response = await fetchWithTimeout(url, {
52863
52887
  headers: {
@@ -52920,18 +52944,12 @@ class NpmRegistryClient {
52920
52944
  }
52921
52945
  }
52922
52946
  static async versionExists(packageName, version, registryUrl) {
52923
- try {
52924
- const info = await NpmRegistryClient.getPackageInfo(packageName, registryUrl);
52925
- if (!info)
52926
- return false;
52927
- const exists = version in (info.versions || {});
52928
- logger.debug(`Version ${version} exists for ${packageName}: ${exists}`);
52929
- return exists;
52930
- } catch (error) {
52931
- const message = error instanceof Error ? error.message : "Unknown error";
52932
- logger.debug(`Failed to check version ${version} for ${packageName}: ${message}`);
52947
+ const info = await NpmRegistryClient.getPackageInfo(packageName, registryUrl);
52948
+ if (!info)
52933
52949
  return false;
52934
- }
52950
+ const exists = version in (info.versions || {});
52951
+ logger.debug(`Version ${version} exists for ${packageName}: ${exists}`);
52952
+ return exists;
52935
52953
  }
52936
52954
  static async getVersionInfo(packageName, version, registryUrl) {
52937
52955
  try {
@@ -52969,7 +52987,7 @@ class NpmRegistryClient {
52969
52987
  }
52970
52988
  }
52971
52989
  }
52972
- var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org", REQUEST_TIMEOUT = 5000;
52990
+ var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org", REQUEST_TIMEOUT = 5000, REDACTED_VALUE = "***";
52973
52991
  var init_npm_registry = __esm(() => {
52974
52992
  init_logger();
52975
52993
  });
@@ -53006,9 +53024,9 @@ function getNpmQuery() {
53006
53024
  checkFn: (stdout) => {
53007
53025
  try {
53008
53026
  const data = JSON.parse(stdout);
53009
- return !!(data.dependencies?.[CLAUDEKIT_CLI_NPM_PACKAGE_NAME] || stdout.includes(CLAUDEKIT_CLI_NPM_PACKAGE_NAME));
53027
+ return !!data.dependencies?.["claudekit-cli"];
53010
53028
  } catch {
53011
- return stdout.includes(CLAUDEKIT_CLI_NPM_PACKAGE_NAME);
53029
+ return /"claudekit-cli"\s*:/.test(stdout) || /(?:^|[^a-z0-9-])claudekit-cli@/m.test(stdout);
53012
53030
  }
53013
53031
  }
53014
53032
  };
@@ -53026,7 +53044,36 @@ async function getNpmVersion() {
53026
53044
  return null;
53027
53045
  }
53028
53046
  }
53029
- function getNpmUpdateCommand(packageName, version) {
53047
+ function normalizeNpmRegistryUrl(rawValue) {
53048
+ const value = rawValue.trim();
53049
+ if (!value) {
53050
+ return null;
53051
+ }
53052
+ if (!/^https?:\/\//i.test(value)) {
53053
+ return null;
53054
+ }
53055
+ try {
53056
+ const parsed = new URL(value);
53057
+ const protocol = parsed.protocol.toLowerCase();
53058
+ if (protocol !== "http:" && protocol !== "https:") {
53059
+ return null;
53060
+ }
53061
+ const normalizedPath = parsed.pathname.replace(/\/+$/, "");
53062
+ return `${parsed.protocol}//${parsed.host}${normalizedPath}${parsed.search}${parsed.hash}`;
53063
+ } catch {
53064
+ return null;
53065
+ }
53066
+ }
53067
+ async function getNpmRegistryUrl() {
53068
+ try {
53069
+ const cmd = isWindows() ? "npm.cmd config get registry" : "npm config get registry";
53070
+ const { stdout } = await execAsync(cmd, { timeout: 3000 });
53071
+ return normalizeNpmRegistryUrl(stdout);
53072
+ } catch {
53073
+ return null;
53074
+ }
53075
+ }
53076
+ function getNpmUpdateCommand(packageName, version, registryUrl) {
53030
53077
  if (!isValidPackageName(packageName)) {
53031
53078
  throw new Error(`Invalid package name: ${packageName}`);
53032
53079
  }
@@ -53034,7 +53081,8 @@ function getNpmUpdateCommand(packageName, version) {
53034
53081
  throw new Error(`Invalid version: ${version}`);
53035
53082
  }
53036
53083
  const versionSuffix = version ? `@${version}` : "@latest";
53037
- return isWindows() ? `npm.cmd install -g ${packageName}${versionSuffix}` : `npm install -g ${packageName}${versionSuffix}`;
53084
+ const registryFlag = registryUrl ? ` --registry ${registryUrl}` : "";
53085
+ return isWindows() ? `npm.cmd install -g ${packageName}${versionSuffix}${registryFlag}` : `npm install -g ${packageName}${versionSuffix}${registryFlag}`;
53038
53086
  }
53039
53087
  var init_npm_detector = __esm(() => {
53040
53088
  init_claudekit_constants();
@@ -53048,7 +53096,7 @@ function getBunQuery() {
53048
53096
  return {
53049
53097
  pm: "bun",
53050
53098
  cmd: "bun pm ls -g",
53051
- checkFn: (stdout) => stdout.includes(CLAUDEKIT_CLI_NPM_PACKAGE_NAME)
53099
+ checkFn: (stdout) => /(?:^|[^a-z0-9-])claudekit-cli@/m.test(stdout)
53052
53100
  };
53053
53101
  }
53054
53102
  function getBunVersionCommand() {
@@ -53064,7 +53112,7 @@ async function getBunVersion() {
53064
53112
  return null;
53065
53113
  }
53066
53114
  }
53067
- function getBunUpdateCommand(packageName, version) {
53115
+ function getBunUpdateCommand(packageName, version, registryUrl) {
53068
53116
  if (!isValidPackageName(packageName)) {
53069
53117
  throw new Error(`Invalid package name: ${packageName}`);
53070
53118
  }
@@ -53072,10 +53120,10 @@ function getBunUpdateCommand(packageName, version) {
53072
53120
  throw new Error(`Invalid version: ${version}`);
53073
53121
  }
53074
53122
  const versionSuffix = version ? `@${version}` : "@latest";
53075
- return `bun add -g ${packageName}${versionSuffix}`;
53123
+ const registryFlag = registryUrl ? ` --registry ${registryUrl}` : "";
53124
+ return `bun add -g ${packageName}${versionSuffix}${registryFlag}`;
53076
53125
  }
53077
53126
  var init_bun_detector = __esm(() => {
53078
- init_claudekit_constants();
53079
53127
  init_constants();
53080
53128
  init_detector_base();
53081
53129
  });
@@ -53084,8 +53132,8 @@ var init_bun_detector = __esm(() => {
53084
53132
  function getYarnQuery() {
53085
53133
  return {
53086
53134
  pm: "yarn",
53087
- cmd: isWindows() ? `yarn.cmd global list --pattern ${CLAUDEKIT_CLI_NPM_PACKAGE_NAME}` : `yarn global list --pattern ${CLAUDEKIT_CLI_NPM_PACKAGE_NAME}`,
53088
- checkFn: (stdout) => stdout.includes(CLAUDEKIT_CLI_NPM_PACKAGE_NAME)
53135
+ cmd: isWindows() ? "yarn.cmd global list --pattern claudekit-cli" : "yarn global list --pattern claudekit-cli",
53136
+ checkFn: (stdout) => /(?:^|[^a-z0-9-])claudekit-cli@/m.test(stdout)
53089
53137
  };
53090
53138
  }
53091
53139
  function getYarnVersionCommand() {
@@ -53101,7 +53149,7 @@ async function getYarnVersion() {
53101
53149
  return null;
53102
53150
  }
53103
53151
  }
53104
- function getYarnUpdateCommand(packageName, version) {
53152
+ function getYarnUpdateCommand(packageName, version, registryUrl) {
53105
53153
  if (!isValidPackageName(packageName)) {
53106
53154
  throw new Error(`Invalid package name: ${packageName}`);
53107
53155
  }
@@ -53109,10 +53157,10 @@ function getYarnUpdateCommand(packageName, version) {
53109
53157
  throw new Error(`Invalid version: ${version}`);
53110
53158
  }
53111
53159
  const versionSuffix = version ? `@${version}` : "@latest";
53112
- return isWindows() ? `yarn.cmd global add ${packageName}${versionSuffix}` : `yarn global add ${packageName}${versionSuffix}`;
53160
+ const registryFlag = registryUrl ? ` --registry ${registryUrl}` : "";
53161
+ return isWindows() ? `yarn.cmd global add ${packageName}${versionSuffix}${registryFlag}` : `yarn global add ${packageName}${versionSuffix}${registryFlag}`;
53113
53162
  }
53114
53163
  var init_yarn_detector = __esm(() => {
53115
- init_claudekit_constants();
53116
53164
  init_environment();
53117
53165
  init_constants();
53118
53166
  init_detector_base();
@@ -53122,8 +53170,8 @@ var init_yarn_detector = __esm(() => {
53122
53170
  function getPnpmQuery() {
53123
53171
  return {
53124
53172
  pm: "pnpm",
53125
- cmd: isWindows() ? `pnpm.cmd ls -g ${CLAUDEKIT_CLI_NPM_PACKAGE_NAME}` : `pnpm ls -g ${CLAUDEKIT_CLI_NPM_PACKAGE_NAME}`,
53126
- checkFn: (stdout) => stdout.includes(CLAUDEKIT_CLI_NPM_PACKAGE_NAME)
53173
+ cmd: isWindows() ? "pnpm.cmd ls -g claudekit-cli" : "pnpm ls -g claudekit-cli",
53174
+ checkFn: (stdout) => /(?:^|[^a-z0-9-])claudekit-cli(?:@|\s+\d)/m.test(stdout)
53127
53175
  };
53128
53176
  }
53129
53177
  function getPnpmVersionCommand() {
@@ -53139,7 +53187,7 @@ async function getPnpmVersion() {
53139
53187
  return null;
53140
53188
  }
53141
53189
  }
53142
- function getPnpmUpdateCommand(packageName, version) {
53190
+ function getPnpmUpdateCommand(packageName, version, registryUrl) {
53143
53191
  if (!isValidPackageName(packageName)) {
53144
53192
  throw new Error(`Invalid package name: ${packageName}`);
53145
53193
  }
@@ -53147,10 +53195,10 @@ function getPnpmUpdateCommand(packageName, version) {
53147
53195
  throw new Error(`Invalid version: ${version}`);
53148
53196
  }
53149
53197
  const versionSuffix = version ? `@${version}` : "@latest";
53150
- return isWindows() ? `pnpm.cmd add -g ${packageName}${versionSuffix}` : `pnpm add -g ${packageName}${versionSuffix}`;
53198
+ const registryFlag = registryUrl ? ` --registry ${registryUrl}` : "";
53199
+ return isWindows() ? `pnpm.cmd add -g ${packageName}${versionSuffix}${registryFlag}` : `pnpm add -g ${packageName}${versionSuffix}${registryFlag}`;
53151
53200
  }
53152
53201
  var init_pnpm_detector = __esm(() => {
53153
- init_claudekit_constants();
53154
53202
  init_environment();
53155
53203
  init_constants();
53156
53204
  init_detector_base();
@@ -53423,24 +53471,25 @@ var init_package_manager_detector = __esm(() => {
53423
53471
  return "echo unknown";
53424
53472
  }
53425
53473
  }
53426
- static getUpdateCommand(pm, packageName, version) {
53474
+ static getNpmRegistryUrl = getNpmRegistryUrl;
53475
+ static getUpdateCommand(pm, packageName, version, registryUrl) {
53427
53476
  if (!isValidPackageName(packageName))
53428
53477
  throw new Error(`Invalid package name: ${packageName}`);
53429
53478
  if (version && !isValidVersion(version))
53430
53479
  throw new Error(`Invalid version: ${version}`);
53431
53480
  switch (pm) {
53432
53481
  case "bun":
53433
- return getBunUpdateCommand(packageName, version);
53482
+ return getBunUpdateCommand(packageName, version, registryUrl);
53434
53483
  case "yarn":
53435
- return getYarnUpdateCommand(packageName, version);
53484
+ return getYarnUpdateCommand(packageName, version, registryUrl);
53436
53485
  case "pnpm":
53437
- return getPnpmUpdateCommand(packageName, version);
53486
+ return getPnpmUpdateCommand(packageName, version, registryUrl);
53438
53487
  default:
53439
- return getNpmUpdateCommand(packageName, version);
53488
+ return getNpmUpdateCommand(packageName, version, registryUrl);
53440
53489
  }
53441
53490
  }
53442
- static getInstallCommand(pm, packageName, version) {
53443
- return PackageManagerDetector.getUpdateCommand(pm, packageName, version);
53491
+ static getInstallCommand(pm, packageName, version, registryUrl) {
53492
+ return PackageManagerDetector.getUpdateCommand(pm, packageName, version, registryUrl);
53444
53493
  }
53445
53494
  static getDisplayName(pm) {
53446
53495
  switch (pm) {
@@ -53869,7 +53918,7 @@ var package_default;
53869
53918
  var init_package = __esm(() => {
53870
53919
  package_default = {
53871
53920
  name: "claudekit-cli",
53872
- version: "3.35.0-dev.23",
53921
+ version: "3.35.0-dev.25",
53873
53922
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
53874
53923
  type: "module",
53875
53924
  repository: {
@@ -53980,6 +54029,12 @@ var init_package = __esm(() => {
53980
54029
  import { exec as exec2 } from "node:child_process";
53981
54030
  import { join as join37 } from "node:path";
53982
54031
  import { promisify as promisify8 } from "node:util";
54032
+ function redactCommandForLog(command) {
54033
+ if (!command)
54034
+ return command;
54035
+ const redactedRegistryFlags = command.replace(/(--registry(?:=|\s+))(['"]?)(\S+?)(\2)(?=\s|$)/g, (_match, prefix, quote, url) => `${prefix}${quote}${redactRegistryUrlForLog(url)}${quote}`);
54036
+ return redactedRegistryFlags.replace(/https?:\/\/[^\s"']+/g, (url) => redactRegistryUrlForLog(url));
54037
+ }
53983
54038
  function buildInitCommand(isGlobal, kit, beta) {
53984
54039
  const parts = ["ck init"];
53985
54040
  if (isGlobal)
@@ -54109,31 +54164,50 @@ async function updateCliCommand(options2) {
54109
54164
  const pmVersion = await PackageManagerDetector.getVersion(pm);
54110
54165
  s.stop(`Using ${PackageManagerDetector.getDisplayName(pm)}${pmVersion ? ` v${pmVersion}` : ""}`);
54111
54166
  logger.verbose(`Detected package manager: ${pm}`);
54167
+ let registryUrl = opts.registry;
54168
+ if (!registryUrl && pm === "npm") {
54169
+ const userRegistry = await PackageManagerDetector.getNpmRegistryUrl();
54170
+ if (userRegistry) {
54171
+ registryUrl = userRegistry;
54172
+ logger.verbose(`Using npm configured registry: ${redactRegistryUrlForLog(registryUrl)}`);
54173
+ }
54174
+ }
54112
54175
  s.start("Checking for updates...");
54113
54176
  let targetVersion = null;
54114
54177
  if (opts.release && opts.release !== "latest") {
54115
- const exists = await NpmRegistryClient.versionExists(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.release, opts.registry);
54116
- if (!exists) {
54117
- s.stop("Version not found");
54118
- throw new CliUpdateError(`Version ${opts.release} does not exist on npm registry. Run 'ck versions' to see available versions.`);
54178
+ try {
54179
+ const exists = await NpmRegistryClient.versionExists(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.release, registryUrl);
54180
+ if (!exists) {
54181
+ s.stop("Version not found");
54182
+ throw new CliUpdateError(`Version ${opts.release} does not exist on npm registry. Run 'ck versions' to see available versions.`);
54183
+ }
54184
+ } catch (error) {
54185
+ if (error instanceof CliUpdateError) {
54186
+ throw error;
54187
+ }
54188
+ s.stop("Version check failed");
54189
+ const message = error instanceof Error ? error.message : "Unknown error";
54190
+ logger.verbose(`Release check failed for ${opts.release}: ${message}`);
54191
+ const registryHint = registryUrl ? ` (${redactRegistryUrlForLog(registryUrl)})` : " (default registry)";
54192
+ throw new CliUpdateError(`Failed to verify version ${opts.release} on npm registry${registryHint}. Check registry settings/network connectivity and try again.`);
54119
54193
  }
54120
54194
  targetVersion = opts.release;
54121
54195
  s.stop(`Target version: ${targetVersion}`);
54122
54196
  } else if (opts.dev || opts.beta) {
54123
- targetVersion = await NpmRegistryClient.getDevVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.registry);
54197
+ targetVersion = await NpmRegistryClient.getDevVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
54124
54198
  if (!targetVersion) {
54125
54199
  s.stop("No dev version available");
54126
54200
  logger.warning("No dev version found. Using latest stable version instead.");
54127
- targetVersion = await NpmRegistryClient.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.registry);
54201
+ targetVersion = await NpmRegistryClient.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
54128
54202
  } else {
54129
54203
  s.stop(`Latest dev version: ${targetVersion}`);
54130
54204
  }
54131
54205
  } else {
54132
- targetVersion = await NpmRegistryClient.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.registry);
54206
+ targetVersion = await NpmRegistryClient.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
54133
54207
  s.stop(`Latest version: ${targetVersion || "unknown"}`);
54134
54208
  }
54135
54209
  if (!targetVersion) {
54136
- throw new CliUpdateError(`Failed to fetch version information from npm registry. Check your internet connection and try again. Manual update: ${PackageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME)}`);
54210
+ throw new CliUpdateError(`Failed to fetch version information from npm registry. Check your internet connection and try again. Manual update: ${PackageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME, undefined, registryUrl)}`);
54137
54211
  }
54138
54212
  const comparison = import_compare_versions.compareVersions(currentVersion, targetVersion);
54139
54213
  if (comparison === 0) {
@@ -54166,8 +54240,8 @@ Run 'ck update' to install`, "Update Check");
54166
54240
  return;
54167
54241
  }
54168
54242
  }
54169
- const updateCmd = PackageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME, targetVersion);
54170
- logger.info(`Running: ${updateCmd}`);
54243
+ const updateCmd = PackageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME, targetVersion, registryUrl);
54244
+ logger.info(`Running: ${redactCommandForLog(updateCmd)}`);
54171
54245
  s.start("Updating CLI...");
54172
54246
  try {
54173
54247
  await execAsync2(updateCmd, {
@@ -54194,7 +54268,7 @@ Or fix npm permissions: https://docs.npmjs.com/resolving-eacces-permissions-erro
54194
54268
  throw new CliUpdateError(`Permission denied. Try: ${elevationHint}${permHint}`);
54195
54269
  }
54196
54270
  logger.error(`Update failed: ${errorMessage}`);
54197
- logger.info(`Try running: ${updateCmd}`);
54271
+ logger.info(`Try running: ${redactCommandForLog(updateCmd)}`);
54198
54272
  throw new CliUpdateError(`Update failed: ${errorMessage}
54199
54273
 
54200
54274
  Manual update: ${updateCmd}`);
@@ -54214,7 +54288,6 @@ Manual update: ${updateCmd}`);
54214
54288
  }
54215
54289
  } catch (error) {
54216
54290
  if (error instanceof CliUpdateError) {
54217
- logger.error(error.message);
54218
54291
  throw error;
54219
54292
  }
54220
54293
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
@@ -64243,7 +64316,7 @@ var init_init_command_help = __esm(() => {
64243
64316
  },
64244
64317
  {
64245
64318
  flags: "--fresh",
64246
- description: "Remove ClaudeKit directories (commands/, agents/, skills/, rules/, hooks/) and reinstall"
64319
+ description: "Full reset: remove CK files, replace settings.json and CLAUDE.md, reinstall from scratch"
64247
64320
  }
64248
64321
  ]
64249
64322
  },
@@ -84784,7 +84857,6 @@ class InstalledSettingsTracker {
84784
84857
 
84785
84858
  // src/domains/installation/merger/settings-processor.ts
84786
84859
  init_settings_merger();
84787
- init_environment();
84788
84860
  init_logger();
84789
84861
  var import_fs_extra11 = __toESM(require_lib3(), 1);
84790
84862
  var import_semver3 = __toESM(require_semver2(), 1);
@@ -84825,13 +84897,13 @@ class SettingsProcessor {
84825
84897
  const sourceContent = await import_fs_extra11.readFile(sourceFile, "utf-8");
84826
84898
  let transformedSource = sourceContent;
84827
84899
  if (this.isGlobal) {
84828
- const homeVar = isWindows() ? '"%USERPROFILE%"' : '"$HOME"';
84900
+ const homeVar = '"$HOME"';
84829
84901
  transformedSource = this.transformClaudePaths(sourceContent, homeVar);
84830
84902
  if (transformedSource !== sourceContent) {
84831
84903
  logger.debug(`Transformed .claude/ paths to ${homeVar}/.claude/ in settings.json for global installation`);
84832
84904
  }
84833
84905
  } else {
84834
- const projectDirVar = isWindows() ? '"%CLAUDE_PROJECT_DIR%"' : '"$CLAUDE_PROJECT_DIR"';
84906
+ const projectDirVar = '"$CLAUDE_PROJECT_DIR"';
84835
84907
  transformedSource = this.transformClaudePaths(sourceContent, projectDirVar);
84836
84908
  if (transformedSource !== sourceContent) {
84837
84909
  logger.debug(`Transformed .claude/ paths to ${projectDirVar}/.claude/ in settings.json for local installation`);
@@ -84841,20 +84913,26 @@ class SettingsProcessor {
84841
84913
  if (destExists && !this.forceOverwriteSettings) {
84842
84914
  await this.selectiveMergeSettings(transformedSource, destFile);
84843
84915
  } else {
84844
- const formattedContent = this.formatJsonContent(transformedSource);
84845
- await import_fs_extra11.writeFile(destFile, formattedContent, "utf-8");
84846
- let parsedSettings;
84847
84916
  try {
84848
- parsedSettings = JSON.parse(formattedContent);
84849
- if (this.forceOverwriteSettings && destExists) {
84850
- logger.debug("Force overwrite enabled, replaced settings.json completely");
84851
- if (this.tracker) {
84852
- await this.tracker.clearTracking();
84917
+ const parsedSettings = JSON.parse(transformedSource);
84918
+ this.fixHookCommandPaths(parsedSettings);
84919
+ await SettingsMerger.writeSettingsFile(destFile, parsedSettings);
84920
+ try {
84921
+ if (this.forceOverwriteSettings && destExists) {
84922
+ logger.debug("Force overwrite enabled, replaced settings.json completely");
84923
+ if (this.tracker) {
84924
+ await this.tracker.clearTracking();
84925
+ }
84853
84926
  }
84927
+ await this.trackInstalledSettings(parsedSettings);
84928
+ } catch {
84929
+ logger.debug("Settings tracking failed (non-fatal)");
84854
84930
  }
84855
- await this.trackInstalledSettings(parsedSettings);
84856
- } catch {}
84857
- await this.injectTeamHooksIfSupported(destFile, parsedSettings);
84931
+ } catch {
84932
+ const formattedContent = this.formatJsonContent(transformedSource);
84933
+ await import_fs_extra11.writeFile(destFile, formattedContent, "utf-8");
84934
+ }
84935
+ await this.injectTeamHooksIfSupported(destFile);
84858
84936
  }
84859
84937
  } catch (error) {
84860
84938
  logger.error(`Failed to process settings.json: ${error}`);
@@ -84914,6 +84992,10 @@ class SettingsProcessor {
84914
84992
  }
84915
84993
  await this.tracker.saveInstalledSettings(installedSettings);
84916
84994
  }
84995
+ const pathsFixed = this.fixHookCommandPaths(mergeResult.merged);
84996
+ if (pathsFixed) {
84997
+ logger.info("Fixed hook command paths to canonical quoted format");
84998
+ }
84917
84999
  await SettingsMerger.writeSettingsFile(destFile, mergeResult.merged);
84918
85000
  logger.success("Merged settings.json (user customizations preserved)");
84919
85001
  await this.injectTeamHooksIfSupported(destFile, mergeResult.merged);
@@ -84999,12 +85081,14 @@ class SettingsProcessor {
84999
85081
  const content = await import_fs_extra11.readFile(destFile, "utf-8");
85000
85082
  if (!content.trim())
85001
85083
  return null;
85002
- const homeVar = isWindows() ? "%USERPROFILE%" : "$HOME";
85084
+ const homeVar = "$HOME";
85003
85085
  let normalized = content;
85004
85086
  normalized = normalized.replace(/"\$CLAUDE_PROJECT_DIR"/g, `"${homeVar}"`);
85005
85087
  normalized = normalized.replace(/\$CLAUDE_PROJECT_DIR/g, homeVar);
85006
85088
  normalized = normalized.replace(/"%CLAUDE_PROJECT_DIR%"/g, `"${homeVar}"`);
85007
85089
  normalized = normalized.replace(/%CLAUDE_PROJECT_DIR%/g, homeVar);
85090
+ normalized = normalized.replace(/"%USERPROFILE%"/g, `"${homeVar}"`);
85091
+ normalized = normalized.replace(/%USERPROFILE%/g, homeVar);
85008
85092
  if (normalized !== content) {
85009
85093
  logger.debug("Normalized $CLAUDE_PROJECT_DIR paths to $HOME in existing global settings");
85010
85094
  }
@@ -85019,15 +85103,85 @@ class SettingsProcessor {
85019
85103
  throw new Error("Settings file contains potentially unsafe path characters");
85020
85104
  }
85021
85105
  let transformed = content;
85022
- const jsonSafePrefix = prefix.includes('"') ? prefix.replace(/"/g, "\\\"") : prefix;
85023
85106
  const rawPrefix = prefix.replace(/"/g, "");
85024
- transformed = transformed.replace(/(node\s+)(?:\.\/)?\.claude\//g, `$1${jsonSafePrefix}/.claude/`);
85107
+ transformed = transformed.replace(/(node\s+)(?:\.\/)?(\.claude\/[^\s"\\]+)/g, `$1\\"${rawPrefix}/$2\\"`);
85025
85108
  if (rawPrefix.includes("HOME") || rawPrefix.includes("USERPROFILE")) {
85026
85109
  transformed = transformed.replace(/\$CLAUDE_PROJECT_DIR/g, rawPrefix);
85027
85110
  transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%/g, rawPrefix);
85028
85111
  }
85029
85112
  return transformed;
85030
85113
  }
85114
+ fixHookCommandPaths(settings) {
85115
+ let fixed = false;
85116
+ if (settings.hooks) {
85117
+ for (const entries of Object.values(settings.hooks)) {
85118
+ for (const entry of entries) {
85119
+ if ("command" in entry && entry.command) {
85120
+ const result = this.fixSingleCommandPath(entry.command);
85121
+ if (result !== entry.command) {
85122
+ entry.command = result;
85123
+ fixed = true;
85124
+ }
85125
+ }
85126
+ if ("hooks" in entry && entry.hooks) {
85127
+ for (const hook of entry.hooks) {
85128
+ if (hook.command) {
85129
+ const result = this.fixSingleCommandPath(hook.command);
85130
+ if (result !== hook.command) {
85131
+ hook.command = result;
85132
+ fixed = true;
85133
+ }
85134
+ }
85135
+ }
85136
+ }
85137
+ }
85138
+ }
85139
+ }
85140
+ const statusLine = settings.statusLine;
85141
+ if (statusLine?.command) {
85142
+ const result = this.fixSingleCommandPath(statusLine.command);
85143
+ if (result !== statusLine.command) {
85144
+ statusLine.command = result;
85145
+ fixed = true;
85146
+ }
85147
+ }
85148
+ return fixed;
85149
+ }
85150
+ fixSingleCommandPath(cmd) {
85151
+ if (!cmd.includes(".claude/") && !cmd.includes(".claude\\"))
85152
+ return cmd;
85153
+ const varOnlyQuotingRe = /^(node\s+)"(\$HOME|\$CLAUDE_PROJECT_DIR|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)"[/\\](.+)$/;
85154
+ const varOnlyMatch = cmd.match(varOnlyQuotingRe);
85155
+ if (varOnlyMatch) {
85156
+ const [, nodePrefix, capturedVar, restPath] = varOnlyMatch;
85157
+ const canonicalVar = this.canonicalizePathVar(capturedVar);
85158
+ return `${nodePrefix}"${canonicalVar}/${restPath.replace(/\\/g, "/")}"`;
85159
+ }
85160
+ const tildeRe = /^(node\s+)~[/\\](.+)$/;
85161
+ const tildeMatch = cmd.match(tildeRe);
85162
+ if (tildeMatch) {
85163
+ const [, nodePrefix, restPath] = tildeMatch;
85164
+ return `${nodePrefix}"$HOME/${restPath.replace(/\\/g, "/")}"`;
85165
+ }
85166
+ const unquotedRe = /^(node\s+)(\$HOME|\$CLAUDE_PROJECT_DIR|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)[/\\](.+)$/;
85167
+ const unquotedMatch = cmd.match(unquotedRe);
85168
+ if (unquotedMatch) {
85169
+ const [, nodePrefix, capturedVar, restPath] = unquotedMatch;
85170
+ const canonicalVar = this.canonicalizePathVar(capturedVar);
85171
+ return `${nodePrefix}"${canonicalVar}/${restPath.replace(/\\/g, "/")}"`;
85172
+ }
85173
+ return cmd;
85174
+ }
85175
+ canonicalizePathVar(capturedVar) {
85176
+ switch (capturedVar) {
85177
+ case "%USERPROFILE%":
85178
+ return "$HOME";
85179
+ case "%CLAUDE_PROJECT_DIR%":
85180
+ return "$CLAUDE_PROJECT_DIR";
85181
+ default:
85182
+ return capturedVar;
85183
+ }
85184
+ }
85031
85185
  detectClaudeCodeVersion() {
85032
85186
  if (this.cachedVersion !== undefined)
85033
85187
  return this.cachedVersion;
@@ -85066,7 +85220,7 @@ class SettingsProcessor {
85066
85220
  logger.warning("Failed to read settings file for team hooks injection");
85067
85221
  return;
85068
85222
  }
85069
- const prefix = this.isGlobal ? isWindows() ? "%USERPROFILE%" : "$HOME" : isWindows() ? "%CLAUDE_PROJECT_DIR%" : "$CLAUDE_PROJECT_DIR";
85223
+ const prefix = this.isGlobal ? "$HOME" : "$CLAUDE_PROJECT_DIR";
85070
85224
  if (!settings.hooks) {
85071
85225
  settings.hooks = {};
85072
85226
  }
@@ -85077,7 +85231,7 @@ class SettingsProcessor {
85077
85231
  { event: "TeammateIdle", handler: "teammate-idle-handler.cjs" }
85078
85232
  ];
85079
85233
  for (const { event, handler } of teamHooks) {
85080
- const hookCommand = `node ${prefix}/.claude/hooks/${handler}`;
85234
+ const hookCommand = `node "${prefix}/.claude/hooks/${handler}"`;
85081
85235
  const eventHooks = settings.hooks[event];
85082
85236
  if (eventHooks && eventHooks.length > 0)
85083
85237
  continue;
@@ -88056,6 +88210,10 @@ Please use only one download method.`);
88056
88210
  if (validOptions.useGit && validOptions.beta) {
88057
88211
  logger.warning("--beta flag is ignored when using --use-git (version already specified via --release)");
88058
88212
  }
88213
+ if (validOptions.fresh && !validOptions.forceOverwriteSettings) {
88214
+ validOptions.forceOverwriteSettings = true;
88215
+ logger.debug("--fresh: auto-enabling settings.json full replace");
88216
+ }
88059
88217
  if (validOptions.fresh && validOptions.sync) {
88060
88218
  throw new Error(`--fresh and --sync are mutually exclusive.
88061
88219
 
@@ -88086,7 +88244,16 @@ async function handlePostInstall(ctx) {
88086
88244
  return ctx;
88087
88245
  }
88088
88246
  if (ctx.options.global) {
88089
- await handleGlobalClaudeMd(ctx);
88247
+ const claudeMdSource = join100(ctx.extractDir, "CLAUDE.md");
88248
+ const claudeMdDest = join100(ctx.resolvedDir, "CLAUDE.md");
88249
+ if (await import_fs_extra30.pathExists(claudeMdSource)) {
88250
+ if (ctx.options.fresh || !await import_fs_extra30.pathExists(claudeMdDest)) {
88251
+ await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
88252
+ logger.success(ctx.options.fresh ? "Replaced CLAUDE.md in global directory (fresh install)" : "Copied CLAUDE.md to global directory");
88253
+ } else {
88254
+ logger.debug("CLAUDE.md already exists in global directory (preserved)");
88255
+ }
88256
+ }
88090
88257
  }
88091
88258
  let installSkills = ctx.options.installSkills;
88092
88259
  if (!ctx.isNonInteractive && !installSkills) {
@@ -88146,49 +88313,6 @@ async function handlePostInstall(ctx) {
88146
88313
  installSkills
88147
88314
  };
88148
88315
  }
88149
- function normalizeLineEndings(content) {
88150
- return content.replace(/\r\n/g, `
88151
- `);
88152
- }
88153
- async function handleGlobalClaudeMd(ctx) {
88154
- if (!ctx.extractDir || !ctx.resolvedDir)
88155
- return;
88156
- const claudeMdSource = join100(ctx.extractDir, "CLAUDE.md");
88157
- const claudeMdDest = join100(ctx.resolvedDir, "CLAUDE.md");
88158
- if (!await import_fs_extra30.pathExists(claudeMdSource))
88159
- return;
88160
- const destExists = await import_fs_extra30.pathExists(claudeMdDest);
88161
- if (!destExists) {
88162
- await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
88163
- logger.success("Copied CLAUDE.md to global directory");
88164
- return;
88165
- }
88166
- if (ctx.options.fresh || ctx.options.forceOverwrite) {
88167
- await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
88168
- logger.success("Updated CLAUDE.md in global directory");
88169
- return;
88170
- }
88171
- const [srcContent, destContent] = await Promise.all([
88172
- import_fs_extra30.readFile(claudeMdSource, "utf-8"),
88173
- import_fs_extra30.readFile(claudeMdDest, "utf-8")
88174
- ]);
88175
- if (normalizeLineEndings(srcContent) === normalizeLineEndings(destContent)) {
88176
- logger.debug("CLAUDE.md already up to date");
88177
- return;
88178
- }
88179
- if (!ctx.isNonInteractive) {
88180
- const shouldOverwrite = await ctx.prompts.confirm(`CLAUDE.md has changed in the new version. Update it?
88181
- (Your customizations will be replaced)`);
88182
- if (!shouldOverwrite) {
88183
- logger.info("CLAUDE.md preserved (user chose to keep existing)");
88184
- return;
88185
- }
88186
- } else {
88187
- logger.warning("Updating CLAUDE.md (content differs from new version)");
88188
- }
88189
- await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
88190
- logger.success("Updated CLAUDE.md (new version detected)");
88191
- }
88192
88316
  // src/commands/init/phases/selection-handler.ts
88193
88317
  init_config_manager();
88194
88318
  init_github_client();
@@ -88850,7 +88974,7 @@ async function handleSelection(ctx) {
88850
88974
  };
88851
88975
  }
88852
88976
  // src/commands/init/phases/sync-handler.ts
88853
- import { copyFile as copyFile7, mkdir as mkdir30, open as open4, readFile as readFile49, rename as rename5, stat as stat17, unlink as unlink11, writeFile as writeFile29 } from "node:fs/promises";
88977
+ import { copyFile as copyFile7, mkdir as mkdir30, open as open4, readFile as readFile48, rename as rename5, stat as stat17, unlink as unlink11, writeFile as writeFile29 } from "node:fs/promises";
88854
88978
  import { dirname as dirname22, join as join103, resolve as resolve21 } from "node:path";
88855
88979
  init_logger();
88856
88980
  init_path_resolver();
@@ -89018,7 +89142,7 @@ async function executeSyncMerge(ctx) {
89018
89142
  try {
89019
89143
  const sourceMetadataPath = join103(upstreamDir, "metadata.json");
89020
89144
  if (await import_fs_extra33.pathExists(sourceMetadataPath)) {
89021
- const content = await readFile49(sourceMetadataPath, "utf-8");
89145
+ const content = await readFile48(sourceMetadataPath, "utf-8");
89022
89146
  const sourceMetadata = JSON.parse(content);
89023
89147
  deletions = sourceMetadata.deletions || [];
89024
89148
  }
@@ -89316,7 +89440,7 @@ async function renameFolders(dirsToRename, extractDir, options2) {
89316
89440
  // src/services/transformers/folder-transform/path-replacer.ts
89317
89441
  init_logger();
89318
89442
  init_types3();
89319
- import { readFile as readFile50, readdir as readdir32, writeFile as writeFile30 } from "node:fs/promises";
89443
+ import { readFile as readFile49, readdir as readdir32, writeFile as writeFile30 } from "node:fs/promises";
89320
89444
  import { join as join105, relative as relative19 } from "node:path";
89321
89445
  var TRANSFORMABLE_FILE_PATTERNS = [
89322
89446
  ".md",
@@ -89383,7 +89507,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
89383
89507
  if (!shouldTransform)
89384
89508
  continue;
89385
89509
  try {
89386
- const content = await readFile50(fullPath, "utf-8");
89510
+ const content = await readFile49(fullPath, "utf-8");
89387
89511
  let newContent = content;
89388
89512
  let changeCount = 0;
89389
89513
  for (const { regex: regex2, replacement } of compiledReplacements) {
@@ -89505,7 +89629,7 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
89505
89629
 
89506
89630
  // src/services/transformers/global-path-transformer.ts
89507
89631
  init_logger();
89508
- import { readFile as readFile51, readdir as readdir33, writeFile as writeFile31 } from "node:fs/promises";
89632
+ import { readFile as readFile50, readdir as readdir33, writeFile as writeFile31 } from "node:fs/promises";
89509
89633
  import { platform as platform13 } from "node:os";
89510
89634
  import { extname as extname5, join as join106 } from "node:path";
89511
89635
  var IS_WINDOWS3 = platform13() === "win32";
@@ -89625,7 +89749,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
89625
89749
  await processDirectory2(fullPath);
89626
89750
  } else if (entry.isFile() && shouldTransformFile3(entry.name)) {
89627
89751
  try {
89628
- const content = await readFile51(fullPath, "utf-8");
89752
+ const content = await readFile50(fullPath, "utf-8");
89629
89753
  const { transformed, changes } = transformContent(content);
89630
89754
  if (changes > 0) {
89631
89755
  await writeFile31(fullPath, transformed, "utf-8");
@@ -89887,7 +90011,7 @@ init_checksum_utils();
89887
90011
  init_config_discovery();
89888
90012
  var import_picocolors25 = __toESM(require_picocolors(), 1);
89889
90013
  import { existsSync as existsSync51 } from "node:fs";
89890
- import { readFile as readFile52, rm as rm13, unlink as unlink12 } from "node:fs/promises";
90014
+ import { readFile as readFile51, rm as rm13, unlink as unlink12 } from "node:fs/promises";
89891
90015
  import { resolve as resolve22 } from "node:path";
89892
90016
 
89893
90017
  // src/commands/portable/conflict-resolver.ts
@@ -90461,7 +90585,7 @@ async function migrateCommand(options2) {
90461
90585
  for (const action of conflictActions) {
90462
90586
  if (!action.diff && action.targetPath && existsSync51(action.targetPath)) {
90463
90587
  try {
90464
- const targetContent = await readFile52(action.targetPath, "utf-8");
90588
+ const targetContent = await readFile51(action.targetPath, "utf-8");
90465
90589
  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);
90466
90590
  if (sourceItem) {
90467
90591
  const providerConfig = providers[action.provider];
@@ -90653,26 +90777,27 @@ async function computeTargetStates(selectedProviders, global3) {
90653
90777
  continue;
90654
90778
  if (entry.global !== global3)
90655
90779
  continue;
90656
- try {
90657
- if (existsSync51(entry.path)) {
90658
- const content = await readFile52(entry.path, "utf-8");
90659
- states.set(entry.path, {
90660
- path: entry.path,
90661
- exists: true,
90662
- currentChecksum: computeContentChecksum(content)
90663
- });
90664
- } else {
90665
- states.set(entry.path, {
90666
- path: entry.path,
90667
- exists: false
90668
- });
90669
- }
90670
- } catch {
90780
+ if (entry.type === "skill")
90781
+ continue;
90782
+ const exists = existsSync51(entry.path);
90783
+ if (!exists) {
90671
90784
  states.set(entry.path, {
90672
90785
  path: entry.path,
90673
90786
  exists: false
90674
90787
  });
90788
+ continue;
90789
+ }
90790
+ const state = {
90791
+ path: entry.path,
90792
+ exists: true
90793
+ };
90794
+ try {
90795
+ const content = await readFile51(entry.path, "utf-8");
90796
+ state.currentChecksum = computeContentChecksum(content);
90797
+ } catch (error) {
90798
+ logger.debug(`[migrate] Failed to read target for checksum: ${entry.path} (${String(error)})`);
90675
90799
  }
90800
+ states.set(entry.path, state);
90676
90801
  }
90677
90802
  return states;
90678
90803
  }
@@ -92573,7 +92698,7 @@ function registerCommands(cli) {
92573
92698
  }
92574
92699
  await newCommand(options2);
92575
92700
  });
92576
- cli.command("init", "Initialize or update ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use: engineer, marketing, all, or comma-separated").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Completely remove .claude directory before downloading (requires confirmation)").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--sync", "Sync config files from upstream with interactive hunk-by-hunk merge").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").action(async (options2) => {
92701
+ cli.command("init", "Initialize or update ClaudeKit project (with interactive version selection)").option("--dir <dir>", "Target directory (default: .)").option("--kit <kit>", "Kit to use: engineer, marketing, all, or comma-separated").option("-r, --release <version>", "Skip version selection, use specific version (e.g., latest, v1.0.0)").option("--exclude <pattern>", "Exclude files matching glob pattern (can be used multiple times)").option("--only <pattern>", "Include only files matching glob pattern (can be used multiple times)").option("-g, --global", "Use platform-specific user configuration directory").option("--fresh", "Full reset: remove CK files, replace settings.json and CLAUDE.md, reinstall from scratch").option("--install-skills", "Install skills dependencies (non-interactive mode)").option("--with-sudo", "Include system packages requiring sudo (Linux: ffmpeg, imagemagick)").option("--prefix", "Add /ck: prefix to all slash commands by moving them to commands/ck/ subdirectory").option("--beta", "Show beta versions in selection prompt").option("--refresh", "Bypass release cache to fetch latest versions from GitHub").option("--dry-run", "Preview changes without applying them (requires --prefix)").option("--force-overwrite", "Override ownership protections and delete user-modified files (requires --prefix)").option("--force-overwrite-settings", "Fully replace settings.json instead of selective merge (destroys user customizations)").option("--skip-setup", "Skip interactive configuration wizard").option("--docs-dir <name>", "Custom docs folder name (default: docs)").option("--plans-dir <name>", "Custom plans folder name (default: plans)").option("-y, --yes", "Non-interactive mode with sensible defaults (skip all prompts)").option("--sync", "Sync config files from upstream with interactive hunk-by-hunk merge").option("--use-git", "Use git clone instead of GitHub API (uses SSH/HTTPS credentials)").option("--archive <path>", "Use local archive file instead of downloading (zip/tar.gz)").option("--kit-path <path>", "Use local kit directory instead of downloading").action(async (options2) => {
92577
92702
  if (options2.exclude && !Array.isArray(options2.exclude)) {
92578
92703
  options2.exclude = [options2.exclude];
92579
92704
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.35.0-dev.23",
3
+ "version": "3.35.0-dev.25",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {