claudekit-cli 3.34.2 → 3.34.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +108 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -33805,14 +33805,11 @@ function normalizeCommand(cmd) {
33805
33805
  if (!cmd)
33806
33806
  return "";
33807
33807
  let normalized = cmd;
33808
- normalized = normalized.replace(/"\$HOME"/g, "$HOME");
33809
- normalized = normalized.replace(/"\$CLAUDE_PROJECT_DIR"/g, "$HOME");
33810
- normalized = normalized.replace(/"\$\{HOME\}"/g, "$HOME");
33808
+ normalized = normalized.replace(/"/g, "");
33809
+ normalized = normalized.replace(/~\//g, "$HOME/");
33811
33810
  normalized = normalized.replace(/\$CLAUDE_PROJECT_DIR/g, "$HOME");
33812
33811
  normalized = normalized.replace(/\$\{HOME\}/g, "$HOME");
33813
- normalized = normalized.replace(/"%USERPROFILE%"/g, "$HOME");
33814
33812
  normalized = normalized.replace(/%USERPROFILE%/g, "$HOME");
33815
- normalized = normalized.replace(/"%CLAUDE_PROJECT_DIR%"/g, "$HOME");
33816
33813
  normalized = normalized.replace(/%CLAUDE_PROJECT_DIR%/g, "$HOME");
33817
33814
  normalized = normalized.replace(/\\/g, "/");
33818
33815
  normalized = normalized.replace(/\s+/g, " ").trim();
@@ -45385,7 +45382,7 @@ var package_default;
45385
45382
  var init_package = __esm(() => {
45386
45383
  package_default = {
45387
45384
  name: "claudekit-cli",
45388
- version: "3.34.2",
45385
+ version: "3.34.4",
45389
45386
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
45390
45387
  type: "module",
45391
45388
  repository: {
@@ -58215,7 +58212,7 @@ var init_init_command_help = __esm(() => {
58215
58212
  },
58216
58213
  {
58217
58214
  flags: "--fresh",
58218
- description: "Remove ClaudeKit directories (commands/, agents/, skills/, rules/, hooks/) and reinstall"
58215
+ description: "Full reset: remove CK files, replace settings.json and CLAUDE.md, reinstall from scratch"
58219
58216
  }
58220
58217
  ]
58221
58218
  },
@@ -76097,7 +76094,6 @@ class InstalledSettingsTracker {
76097
76094
 
76098
76095
  // src/domains/installation/merger/settings-processor.ts
76099
76096
  init_settings_merger();
76100
- init_environment();
76101
76097
  init_logger();
76102
76098
  var import_fs_extra11 = __toESM(require_lib3(), 1);
76103
76099
 
@@ -76135,13 +76131,13 @@ class SettingsProcessor {
76135
76131
  const sourceContent = await import_fs_extra11.readFile(sourceFile, "utf-8");
76136
76132
  let transformedSource = sourceContent;
76137
76133
  if (this.isGlobal) {
76138
- const homeVar = isWindows() ? '"%USERPROFILE%"' : '"$HOME"';
76134
+ const homeVar = '"$HOME"';
76139
76135
  transformedSource = this.transformClaudePaths(sourceContent, homeVar);
76140
76136
  if (transformedSource !== sourceContent) {
76141
76137
  logger.debug(`Transformed .claude/ paths to ${homeVar}/.claude/ in settings.json for global installation`);
76142
76138
  }
76143
76139
  } else {
76144
- const projectDirVar = isWindows() ? '"%CLAUDE_PROJECT_DIR%"' : '"$CLAUDE_PROJECT_DIR"';
76140
+ const projectDirVar = '"$CLAUDE_PROJECT_DIR"';
76145
76141
  transformedSource = this.transformClaudePaths(sourceContent, projectDirVar);
76146
76142
  if (transformedSource !== sourceContent) {
76147
76143
  logger.debug(`Transformed .claude/ paths to ${projectDirVar}/.claude/ in settings.json for local installation`);
@@ -76151,18 +76147,25 @@ class SettingsProcessor {
76151
76147
  if (destExists && !this.forceOverwriteSettings) {
76152
76148
  await this.selectiveMergeSettings(transformedSource, destFile);
76153
76149
  } else {
76154
- const formattedContent = this.formatJsonContent(transformedSource);
76155
- await import_fs_extra11.writeFile(destFile, formattedContent, "utf-8");
76156
76150
  try {
76157
- const parsedSettings = JSON.parse(formattedContent);
76158
- if (this.forceOverwriteSettings && destExists) {
76159
- logger.debug("Force overwrite enabled, replaced settings.json completely");
76160
- if (this.tracker) {
76161
- await this.tracker.clearTracking();
76151
+ const parsedSettings = JSON.parse(transformedSource);
76152
+ this.fixHookCommandPaths(parsedSettings);
76153
+ await SettingsMerger.writeSettingsFile(destFile, parsedSettings);
76154
+ try {
76155
+ if (this.forceOverwriteSettings && destExists) {
76156
+ logger.debug("Force overwrite enabled, replaced settings.json completely");
76157
+ if (this.tracker) {
76158
+ await this.tracker.clearTracking();
76159
+ }
76162
76160
  }
76161
+ await this.trackInstalledSettings(parsedSettings);
76162
+ } catch {
76163
+ logger.debug("Settings tracking failed (non-fatal)");
76163
76164
  }
76164
- await this.trackInstalledSettings(parsedSettings);
76165
- } catch {}
76165
+ } catch {
76166
+ const formattedContent = this.formatJsonContent(transformedSource);
76167
+ await import_fs_extra11.writeFile(destFile, formattedContent, "utf-8");
76168
+ }
76166
76169
  }
76167
76170
  } catch (error) {
76168
76171
  logger.error(`Failed to process settings.json: ${error}`);
@@ -76222,6 +76225,10 @@ class SettingsProcessor {
76222
76225
  }
76223
76226
  await this.tracker.saveInstalledSettings(installedSettings);
76224
76227
  }
76228
+ const pathsFixed = this.fixHookCommandPaths(mergeResult.merged);
76229
+ if (pathsFixed) {
76230
+ logger.info("Fixed hook command paths to canonical quoted format");
76231
+ }
76225
76232
  await SettingsMerger.writeSettingsFile(destFile, mergeResult.merged);
76226
76233
  logger.success("Merged settings.json (user customizations preserved)");
76227
76234
  }
@@ -76306,12 +76313,14 @@ class SettingsProcessor {
76306
76313
  const content = await import_fs_extra11.readFile(destFile, "utf-8");
76307
76314
  if (!content.trim())
76308
76315
  return null;
76309
- const homeVar = isWindows() ? "%USERPROFILE%" : "$HOME";
76316
+ const homeVar = "$HOME";
76310
76317
  let normalized = content;
76311
76318
  normalized = normalized.replace(/"\$CLAUDE_PROJECT_DIR"/g, `"${homeVar}"`);
76312
76319
  normalized = normalized.replace(/\$CLAUDE_PROJECT_DIR/g, homeVar);
76313
76320
  normalized = normalized.replace(/"%CLAUDE_PROJECT_DIR%"/g, `"${homeVar}"`);
76314
76321
  normalized = normalized.replace(/%CLAUDE_PROJECT_DIR%/g, homeVar);
76322
+ normalized = normalized.replace(/"%USERPROFILE%"/g, `"${homeVar}"`);
76323
+ normalized = normalized.replace(/%USERPROFILE%/g, homeVar);
76315
76324
  if (normalized !== content) {
76316
76325
  logger.debug("Normalized $CLAUDE_PROJECT_DIR paths to $HOME in existing global settings");
76317
76326
  }
@@ -76326,15 +76335,85 @@ class SettingsProcessor {
76326
76335
  throw new Error("Settings file contains potentially unsafe path characters");
76327
76336
  }
76328
76337
  let transformed = content;
76329
- const jsonSafePrefix = prefix.includes('"') ? prefix.replace(/"/g, "\\\"") : prefix;
76330
76338
  const rawPrefix = prefix.replace(/"/g, "");
76331
- transformed = transformed.replace(/(node\s+)(?:\.\/)?\.claude\//g, `$1${jsonSafePrefix}/.claude/`);
76339
+ transformed = transformed.replace(/(node\s+)(?:\.\/)?(\.claude\/[^\s"\\]+)/g, `$1\\"${rawPrefix}/$2\\"`);
76332
76340
  if (rawPrefix.includes("HOME") || rawPrefix.includes("USERPROFILE")) {
76333
76341
  transformed = transformed.replace(/\$CLAUDE_PROJECT_DIR/g, rawPrefix);
76334
76342
  transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%/g, rawPrefix);
76335
76343
  }
76336
76344
  return transformed;
76337
76345
  }
76346
+ fixHookCommandPaths(settings) {
76347
+ let fixed = false;
76348
+ if (settings.hooks) {
76349
+ for (const entries of Object.values(settings.hooks)) {
76350
+ for (const entry of entries) {
76351
+ if ("command" in entry && entry.command) {
76352
+ const result = this.fixSingleCommandPath(entry.command);
76353
+ if (result !== entry.command) {
76354
+ entry.command = result;
76355
+ fixed = true;
76356
+ }
76357
+ }
76358
+ if ("hooks" in entry && entry.hooks) {
76359
+ for (const hook of entry.hooks) {
76360
+ if (hook.command) {
76361
+ const result = this.fixSingleCommandPath(hook.command);
76362
+ if (result !== hook.command) {
76363
+ hook.command = result;
76364
+ fixed = true;
76365
+ }
76366
+ }
76367
+ }
76368
+ }
76369
+ }
76370
+ }
76371
+ }
76372
+ const statusLine = settings.statusLine;
76373
+ if (statusLine?.command) {
76374
+ const result = this.fixSingleCommandPath(statusLine.command);
76375
+ if (result !== statusLine.command) {
76376
+ statusLine.command = result;
76377
+ fixed = true;
76378
+ }
76379
+ }
76380
+ return fixed;
76381
+ }
76382
+ fixSingleCommandPath(cmd) {
76383
+ if (!cmd.includes(".claude/") && !cmd.includes(".claude\\"))
76384
+ return cmd;
76385
+ const varOnlyQuotingRe = /^(node\s+)"(\$HOME|\$CLAUDE_PROJECT_DIR|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)"[/\\](.+)$/;
76386
+ const varOnlyMatch = cmd.match(varOnlyQuotingRe);
76387
+ if (varOnlyMatch) {
76388
+ const [, nodePrefix, capturedVar, restPath] = varOnlyMatch;
76389
+ const canonicalVar = this.canonicalizePathVar(capturedVar);
76390
+ return `${nodePrefix}"${canonicalVar}/${restPath.replace(/\\/g, "/")}"`;
76391
+ }
76392
+ const tildeRe = /^(node\s+)~[/\\](.+)$/;
76393
+ const tildeMatch = cmd.match(tildeRe);
76394
+ if (tildeMatch) {
76395
+ const [, nodePrefix, restPath] = tildeMatch;
76396
+ return `${nodePrefix}"$HOME/${restPath.replace(/\\/g, "/")}"`;
76397
+ }
76398
+ const unquotedRe = /^(node\s+)(\$HOME|\$CLAUDE_PROJECT_DIR|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)[/\\](.+)$/;
76399
+ const unquotedMatch = cmd.match(unquotedRe);
76400
+ if (unquotedMatch) {
76401
+ const [, nodePrefix, capturedVar, restPath] = unquotedMatch;
76402
+ const canonicalVar = this.canonicalizePathVar(capturedVar);
76403
+ return `${nodePrefix}"${canonicalVar}/${restPath.replace(/\\/g, "/")}"`;
76404
+ }
76405
+ return cmd;
76406
+ }
76407
+ canonicalizePathVar(capturedVar) {
76408
+ switch (capturedVar) {
76409
+ case "%USERPROFILE%":
76410
+ return "$HOME";
76411
+ case "%CLAUDE_PROJECT_DIR%":
76412
+ return "$CLAUDE_PROJECT_DIR";
76413
+ default:
76414
+ return capturedVar;
76415
+ }
76416
+ }
76338
76417
  }
76339
76418
 
76340
76419
  // src/domains/installation/merger/copy-executor.ts
@@ -79289,6 +79368,10 @@ Please use only one download method.`);
79289
79368
  if (validOptions.useGit && validOptions.beta) {
79290
79369
  logger.warning("--beta flag is ignored when using --use-git (version already specified via --release)");
79291
79370
  }
79371
+ if (validOptions.fresh && !validOptions.forceOverwriteSettings) {
79372
+ validOptions.forceOverwriteSettings = true;
79373
+ logger.debug("--fresh: auto-enabling settings.json full replace");
79374
+ }
79292
79375
  if (validOptions.fresh && validOptions.sync) {
79293
79376
  throw new Error(`--fresh and --sync are mutually exclusive.
79294
79377
 
@@ -79322,9 +79405,9 @@ async function handlePostInstall(ctx) {
79322
79405
  const claudeMdSource = join88(ctx.extractDir, "CLAUDE.md");
79323
79406
  const claudeMdDest = join88(ctx.resolvedDir, "CLAUDE.md");
79324
79407
  if (await import_fs_extra30.pathExists(claudeMdSource)) {
79325
- if (!await import_fs_extra30.pathExists(claudeMdDest)) {
79408
+ if (ctx.options.fresh || !await import_fs_extra30.pathExists(claudeMdDest)) {
79326
79409
  await import_fs_extra30.copy(claudeMdSource, claudeMdDest);
79327
- logger.success("Copied CLAUDE.md to global directory");
79410
+ logger.success(ctx.options.fresh ? "Replaced CLAUDE.md in global directory (fresh install)" : "Copied CLAUDE.md to global directory");
79328
79411
  } else {
79329
79412
  logger.debug("CLAUDE.md already exists in global directory (preserved)");
79330
79413
  }
@@ -82932,7 +83015,7 @@ function registerCommands(cli) {
82932
83015
  }
82933
83016
  await newCommand(options2);
82934
83017
  });
82935
- 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) => {
83018
+ 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) => {
82936
83019
  if (options2.exclude && !Array.isArray(options2.exclude)) {
82937
83020
  options2.exclude = [options2.exclude];
82938
83021
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.34.2",
3
+ "version": "3.34.4",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {