claudekit-cli 4.3.1-dev.16 → 4.3.1-dev.18

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 CHANGED
@@ -12622,6 +12622,217 @@ var init_converters = __esm(() => {
12622
12622
  init_skill_md();
12623
12623
  });
12624
12624
 
12625
+ // src/shared/path-resolver.ts
12626
+ import { createHash as createHash3 } from "node:crypto";
12627
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
12628
+ import { homedir as homedir3, platform as platform2 } from "node:os";
12629
+ import { join as join2, normalize, resolve } from "node:path";
12630
+ function getEnvVar(name) {
12631
+ const val = process.env[name];
12632
+ if (!val || val.trim() === "")
12633
+ return;
12634
+ if (val.includes("..")) {
12635
+ console.warn(`Environment variable ${name} contains path traversal: ${val}`);
12636
+ return;
12637
+ }
12638
+ return val;
12639
+ }
12640
+ function isWSL() {
12641
+ try {
12642
+ return process.platform === "linux" && existsSync2("/proc/version") && readFileSync2("/proc/version", "utf8").toLowerCase().includes("microsoft");
12643
+ } catch {
12644
+ return false;
12645
+ }
12646
+ }
12647
+ function normalizeWSLPath(p) {
12648
+ if (!isWSL())
12649
+ return p;
12650
+ const windowsMatch = p.match(/^([A-Za-z]):(.*)/);
12651
+ if (windowsMatch) {
12652
+ const drive = windowsMatch[1].toLowerCase();
12653
+ const rest = windowsMatch[2].replace(/\\/g, "/");
12654
+ return `/mnt/${drive}${rest}`;
12655
+ }
12656
+ return p;
12657
+ }
12658
+
12659
+ class PathResolver {
12660
+ static getTestHomeDir() {
12661
+ return process.env.CK_TEST_HOME;
12662
+ }
12663
+ static isValidComponentName(name) {
12664
+ if (!name || typeof name !== "string") {
12665
+ return false;
12666
+ }
12667
+ const dangerousPatterns = [
12668
+ "..",
12669
+ "~"
12670
+ ];
12671
+ for (const pattern of dangerousPatterns) {
12672
+ if (name.includes(pattern)) {
12673
+ return false;
12674
+ }
12675
+ }
12676
+ const normalized = normalize(name);
12677
+ for (const pattern of dangerousPatterns) {
12678
+ if (normalized.includes(pattern)) {
12679
+ return false;
12680
+ }
12681
+ }
12682
+ if (name.startsWith("/") || normalized.startsWith("/") || /^[a-zA-Z]:/.test(name) || name.startsWith("\\\\") || normalized.startsWith("\\\\")) {
12683
+ return false;
12684
+ }
12685
+ return true;
12686
+ }
12687
+ static getConfigDir(global2 = false) {
12688
+ const testHome = PathResolver.getTestHomeDir();
12689
+ if (testHome) {
12690
+ return global2 ? join2(testHome, ".config", "claude") : join2(testHome, ".claudekit");
12691
+ }
12692
+ if (!global2) {
12693
+ return join2(homedir3(), ".claudekit");
12694
+ }
12695
+ const os = platform2();
12696
+ if (os === "win32") {
12697
+ const localAppData = getEnvVar("LOCALAPPDATA") ?? join2(homedir3(), "AppData", "Local");
12698
+ return join2(localAppData, "claude");
12699
+ }
12700
+ const xdgConfigHome = getEnvVar("XDG_CONFIG_HOME");
12701
+ if (xdgConfigHome) {
12702
+ return join2(xdgConfigHome, "claude");
12703
+ }
12704
+ return join2(homedir3(), ".config", "claude");
12705
+ }
12706
+ static getConfigFile(global2 = false) {
12707
+ return join2(PathResolver.getConfigDir(global2), "config.json");
12708
+ }
12709
+ static getCacheDir(global2 = false) {
12710
+ const testHome = PathResolver.getTestHomeDir();
12711
+ if (testHome) {
12712
+ return global2 ? join2(testHome, ".cache", "claude") : join2(testHome, ".claudekit", "cache");
12713
+ }
12714
+ if (!global2) {
12715
+ return join2(homedir3(), ".claudekit", "cache");
12716
+ }
12717
+ const os = platform2();
12718
+ if (os === "win32") {
12719
+ const localAppData = getEnvVar("LOCALAPPDATA") ?? join2(homedir3(), "AppData", "Local");
12720
+ return join2(localAppData, "claude", "cache");
12721
+ }
12722
+ const xdgCacheHome = getEnvVar("XDG_CACHE_HOME");
12723
+ if (xdgCacheHome) {
12724
+ return join2(xdgCacheHome, "claude");
12725
+ }
12726
+ return join2(homedir3(), ".cache", "claude");
12727
+ }
12728
+ static getGlobalKitDir() {
12729
+ const testHome = PathResolver.getTestHomeDir();
12730
+ if (testHome) {
12731
+ return join2(testHome, ".claude");
12732
+ }
12733
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR;
12734
+ if (claudeConfigDir) {
12735
+ return claudeConfigDir;
12736
+ }
12737
+ return join2(homedir3(), ".claude");
12738
+ }
12739
+ static getClaudeKitDir() {
12740
+ const testHome = PathResolver.getTestHomeDir();
12741
+ if (testHome) {
12742
+ return join2(testHome, ".claudekit");
12743
+ }
12744
+ return join2(homedir3(), ".claudekit");
12745
+ }
12746
+ static getProjectsRegistryPath() {
12747
+ return join2(PathResolver.getClaudeKitDir(), "projects.json");
12748
+ }
12749
+ static getOpenCodeDir(global2, baseDir) {
12750
+ const testHome = PathResolver.getTestHomeDir();
12751
+ if (testHome) {
12752
+ return global2 ? join2(testHome, ".config", "opencode") : join2(baseDir || testHome, ".opencode");
12753
+ }
12754
+ if (!global2) {
12755
+ return join2(baseDir || process.cwd(), ".opencode");
12756
+ }
12757
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME;
12758
+ if (xdgConfigHome) {
12759
+ return join2(xdgConfigHome, "opencode");
12760
+ }
12761
+ return join2(homedir3(), ".config", "opencode");
12762
+ }
12763
+ static getPathPrefix(global2) {
12764
+ return global2 ? "" : ".claude";
12765
+ }
12766
+ static buildSkillsPath(baseDir, global2) {
12767
+ const prefix = PathResolver.getPathPrefix(global2);
12768
+ if (prefix) {
12769
+ return join2(baseDir, prefix, "skills");
12770
+ }
12771
+ return join2(baseDir, "skills");
12772
+ }
12773
+ static buildComponentPath(baseDir, component, global2) {
12774
+ if (!PathResolver.isValidComponentName(component)) {
12775
+ throw new Error(`Invalid component name: "${component}" contains path traversal patterns. Valid names are simple directory names like "agents", "commands", "rules", "skills", or "hooks".`);
12776
+ }
12777
+ const prefix = PathResolver.getPathPrefix(global2);
12778
+ if (prefix) {
12779
+ return join2(baseDir, prefix, component);
12780
+ }
12781
+ return join2(baseDir, component);
12782
+ }
12783
+ static getBackupDir(timestamp) {
12784
+ const testHome = PathResolver.getTestHomeDir();
12785
+ const baseDir = testHome ? join2(testHome, ".claudekit") : join2(homedir3(), ".claudekit");
12786
+ if (timestamp) {
12787
+ return join2(baseDir, "backups", timestamp);
12788
+ }
12789
+ const now = new Date;
12790
+ const dateStr = now.toISOString().replace(/[:.]/g, "-").slice(0, 19);
12791
+ const ms = now.getMilliseconds().toString().padStart(3, "0");
12792
+ const random = Math.random().toString(36).slice(2, 6);
12793
+ const ts = `${dateStr}-${ms}-${random}`;
12794
+ return join2(baseDir, "backups", ts);
12795
+ }
12796
+ static normalizeWSLPath(p) {
12797
+ return normalizeWSLPath(p);
12798
+ }
12799
+ static isWSL() {
12800
+ return isWSL();
12801
+ }
12802
+ static isAtHomeDirectory(cwd2) {
12803
+ const currentDir = normalize(cwd2 || process.cwd());
12804
+ const homeDir = normalize(homedir3());
12805
+ return currentDir === homeDir;
12806
+ }
12807
+ static getLocalClaudeDir(baseDir) {
12808
+ const dir = baseDir || process.cwd();
12809
+ return join2(dir, ".claude");
12810
+ }
12811
+ static isLocalSameAsGlobal(cwd2) {
12812
+ const localPath = normalize(PathResolver.getLocalClaudeDir(cwd2));
12813
+ const globalPath = normalize(PathResolver.getGlobalKitDir());
12814
+ return localPath === globalPath;
12815
+ }
12816
+ static isGlobPattern(pattern) {
12817
+ return pattern.includes("*") || pattern.includes("?") || pattern.includes("{");
12818
+ }
12819
+ static computeProjectHash(projectRoot) {
12820
+ let normalized = resolve(projectRoot).replace(/[/\\]+$/, "");
12821
+ if (process.platform === "darwin" || process.platform === "win32") {
12822
+ normalized = normalized.toLowerCase();
12823
+ }
12824
+ return createHash3("sha256").update(normalized).digest("hex").slice(0, 12);
12825
+ }
12826
+ static getPlansRegistriesDir() {
12827
+ return join2(PathResolver.getGlobalKitDir(), "plans-registries");
12828
+ }
12829
+ static getPlansRegistryPath(projectRoot) {
12830
+ const hash = PathResolver.computeProjectHash(projectRoot);
12831
+ return join2(PathResolver.getPlansRegistriesDir(), `${hash}.json`);
12832
+ }
12833
+ }
12834
+ var init_path_resolver = () => {};
12835
+
12625
12836
  // src/commands/portable/reconcile-types.ts
12626
12837
  function normalizeChecksum(checksum) {
12627
12838
  if (!checksum)
@@ -12686,18 +12897,16 @@ function providerConfigAppliesToType(config, type) {
12686
12897
  var UNKNOWN_CHECKSUM = "unknown";
12687
12898
 
12688
12899
  // src/commands/portable/portable-registry.ts
12689
- import { existsSync as existsSync2 } from "node:fs";
12900
+ import { existsSync as existsSync3 } from "node:fs";
12690
12901
  import { mkdir, readFile as readFile2, rename, unlink, writeFile } from "node:fs/promises";
12691
- import { homedir as homedir3 } from "node:os";
12692
- import { dirname, join as join2, resolve } from "node:path";
12902
+ import { dirname, join as join3, resolve as resolve2 } from "node:path";
12693
12903
  function getPortableRegistryPaths() {
12694
- const home2 = homedir3();
12695
- const claudekitDir = join2(home2, ".claudekit");
12904
+ const claudekitDir = PathResolver.getConfigDir(false);
12696
12905
  return {
12697
- registryPath: join2(claudekitDir, "portable-registry.json"),
12698
- registryLockPath: join2(claudekitDir, "portable-registry.lock"),
12699
- legacyRegistryPath: join2(claudekitDir, "skill-registry.json"),
12700
- migrationLockPath: join2(claudekitDir, ".migration.lock")
12906
+ registryPath: join3(claudekitDir, "portable-registry.json"),
12907
+ registryLockPath: join3(claudekitDir, "portable-registry.lock"),
12908
+ legacyRegistryPath: join3(claudekitDir, "skill-registry.json"),
12909
+ migrationLockPath: join3(claudekitDir, ".migration.lock")
12701
12910
  };
12702
12911
  }
12703
12912
  function isErrnoCode(error, code) {
@@ -12721,12 +12930,12 @@ function getCliVersion() {
12721
12930
  if (process.env.npm_package_version) {
12722
12931
  return process.env.npm_package_version;
12723
12932
  }
12724
- const { readFileSync: readFileSync2 } = __require("node:fs");
12933
+ const { readFileSync: readFileSync3 } = __require("node:fs");
12725
12934
  const { dirname: dn, join: jp } = __require("node:path");
12726
12935
  const { fileURLToPath } = __require("node:url");
12727
12936
  const __dirname2 = dn(fileURLToPath(import.meta.url));
12728
12937
  const pkgPath = jp(__dirname2, "../../../package.json");
12729
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
12938
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
12730
12939
  return pkg.version || "unknown";
12731
12940
  } catch {
12732
12941
  return "unknown";
@@ -12762,7 +12971,7 @@ async function migrateRegistryV2ToV3(v2Registry) {
12762
12971
  for (const item of v2Registry.installations) {
12763
12972
  let targetChecksum = UNKNOWN_CHECKSUM;
12764
12973
  try {
12765
- if (existsSync2(item.path)) {
12974
+ if (existsSync3(item.path)) {
12766
12975
  targetChecksum = await computeFileChecksum(item.path);
12767
12976
  }
12768
12977
  } catch (error) {
@@ -12819,7 +13028,7 @@ async function repairStaleRegistryV3(registry) {
12819
13028
  const installations = [];
12820
13029
  for (const item of registry.installations) {
12821
13030
  let targetChecksum = normalizeChecksum(getStringField(item, "targetChecksum")) || UNKNOWN_CHECKSUM;
12822
- if (targetChecksum === UNKNOWN_CHECKSUM && existsSync2(item.path)) {
13031
+ if (targetChecksum === UNKNOWN_CHECKSUM && existsSync3(item.path)) {
12823
13032
  try {
12824
13033
  targetChecksum = await computeFileChecksum(item.path);
12825
13034
  } catch {
@@ -12906,7 +13115,7 @@ async function isMigrationLocked() {
12906
13115
  async function createMigrationLock() {
12907
13116
  const { migrationLockPath } = getPortableRegistryPaths();
12908
13117
  const lockDir = dirname(migrationLockPath);
12909
- if (!existsSync2(lockDir)) {
13118
+ if (!existsSync3(lockDir)) {
12910
13119
  await mkdir(lockDir, { recursive: true });
12911
13120
  }
12912
13121
  await writeFile(migrationLockPath, Date.now().toString(), "utf-8");
@@ -12994,7 +13203,7 @@ async function readPortableRegistryWithinRegistryLock() {
12994
13203
  async function writePortableRegistry(registry) {
12995
13204
  const { registryPath } = getPortableRegistryPaths();
12996
13205
  const dir = dirname(registryPath);
12997
- if (!existsSync2(dir)) {
13206
+ if (!existsSync3(dir)) {
12998
13207
  await mkdir(dir, { recursive: true });
12999
13208
  }
13000
13209
  const normalizedRegistry = normalizePortableRegistryChecksums(registry);
@@ -13012,10 +13221,10 @@ async function writePortableRegistry(registry) {
13012
13221
  async function withRegistryLock(operation) {
13013
13222
  const { registryLockPath } = getPortableRegistryPaths();
13014
13223
  const lockDir = dirname(registryLockPath);
13015
- if (!existsSync2(lockDir)) {
13224
+ if (!existsSync3(lockDir)) {
13016
13225
  await mkdir(lockDir, { recursive: true });
13017
13226
  }
13018
- if (!existsSync2(registryLockPath)) {
13227
+ if (!existsSync3(registryLockPath)) {
13019
13228
  await writeFile(registryLockPath, "", "utf-8");
13020
13229
  }
13021
13230
  const release = await import_proper_lockfile.default.lock(registryLockPath, {
@@ -13057,7 +13266,7 @@ async function addPortableInstallation(item, type, provider, global2, path2, sou
13057
13266
  async function removePortableInstallation(item, type, provider, global2, options2) {
13058
13267
  return withRegistryLock(async () => {
13059
13268
  const registry = await readPortableRegistryWithinRegistryLock();
13060
- const index = registry.installations.findIndex((i) => i.item === item && i.type === type && i.provider === provider && i.global === global2 && (!options2?.path || resolve(i.path) === resolve(options2.path)));
13269
+ const index = registry.installations.findIndex((i) => i.item === item && i.type === type && i.provider === provider && i.global === global2 && (!options2?.path || resolve2(i.path) === resolve2(options2.path)));
13061
13270
  if (index === -1)
13062
13271
  return null;
13063
13272
  const [removed] = registry.installations.splice(index, 1);
@@ -13107,7 +13316,7 @@ async function syncPortableRegistry() {
13107
13316
  const registry = await readPortableRegistryWithinRegistryLock();
13108
13317
  const removed = [];
13109
13318
  registry.installations = registry.installations.filter((i) => {
13110
- if (!existsSync2(i.path)) {
13319
+ if (!existsSync3(i.path)) {
13111
13320
  removed.push(i);
13112
13321
  return false;
13113
13322
  }
@@ -13123,6 +13332,7 @@ var import_proper_lockfile, PortableInstallationSchema, PortableRegistrySchema,
13123
13332
  var init_portable_registry = __esm(() => {
13124
13333
  init_zod();
13125
13334
  init_logger();
13335
+ init_path_resolver();
13126
13336
  init_checksum_utils();
13127
13337
  import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
13128
13338
  PortableInstallationSchema = exports_external.object({
@@ -13181,10 +13391,10 @@ var init_portable_registry = __esm(() => {
13181
13391
  });
13182
13392
 
13183
13393
  // src/commands/portable/codex-toml-installer.ts
13184
- import { existsSync as existsSync3 } from "node:fs";
13394
+ import { existsSync as existsSync4 } from "node:fs";
13185
13395
  import { mkdir as mkdir2, readFile as readFile3, realpath, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
13186
13396
  import { homedir as homedir4 } from "node:os";
13187
- import { basename, dirname as dirname2, isAbsolute, join as join3, relative, resolve as resolve2 } from "node:path";
13397
+ import { basename, dirname as dirname2, isAbsolute, join as join4, relative, resolve as resolve3 } from "node:path";
13188
13398
  function resolveCodexTomlRegistryDeps(deps) {
13189
13399
  return {
13190
13400
  ...defaultCodexTomlRegistryDeps,
@@ -13193,7 +13403,7 @@ function resolveCodexTomlRegistryDeps(deps) {
13193
13403
  }
13194
13404
  async function ensureDir(filePath) {
13195
13405
  const dir = dirname2(filePath);
13196
- if (!existsSync3(dir)) {
13406
+ if (!existsSync4(dir)) {
13197
13407
  await mkdir2(dir, { recursive: true });
13198
13408
  }
13199
13409
  }
@@ -13201,7 +13411,7 @@ function isErrnoCode2(error, code) {
13201
13411
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
13202
13412
  }
13203
13413
  function normalizePathForComparison(path2) {
13204
- const normalized = resolve2(path2);
13414
+ const normalized = resolve3(path2);
13205
13415
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
13206
13416
  }
13207
13417
  function isPathWithinBoundary(targetPath, boundaryPath) {
@@ -13217,7 +13427,7 @@ async function resolveRealPathSafe(path2) {
13217
13427
  try {
13218
13428
  return await realpath(path2);
13219
13429
  } catch {
13220
- return resolve2(path2);
13430
+ return resolve3(path2);
13221
13431
  }
13222
13432
  }
13223
13433
  async function isCanonicalPathWithinBoundary(targetPath, boundaryPath) {
@@ -13391,10 +13601,10 @@ function mergeConfigTomlWithDiagnostics(existing, managedBlock) {
13391
13601
  };
13392
13602
  }
13393
13603
  function getCodexLockPath(configTomlPath) {
13394
- return join3(dirname2(configTomlPath), `.${basename(configTomlPath)}.ck-codex.lock`);
13604
+ return join4(dirname2(configTomlPath), `.${basename(configTomlPath)}.ck-codex.lock`);
13395
13605
  }
13396
13606
  async function withCodexTargetLock(configTomlPath, operation) {
13397
- const resolvedTargetPath = resolve2(configTomlPath);
13607
+ const resolvedTargetPath = resolve3(configTomlPath);
13398
13608
  await ensureDir(resolvedTargetPath);
13399
13609
  const release = await import_proper_lockfile2.default.lock(dirname2(resolvedTargetPath), {
13400
13610
  realpath: false,
@@ -13473,8 +13683,8 @@ async function installCodexToml(items, provider, portableType, options2, deps) {
13473
13683
  };
13474
13684
  }
13475
13685
  const boundary = options2.global ? homedir4() : process.cwd();
13476
- const agentsDir = resolve2(basePath);
13477
- const configTomlPath = join3(dirname2(agentsDir), "config.toml");
13686
+ const agentsDir = resolve3(basePath);
13687
+ const configTomlPath = join4(dirname2(agentsDir), "config.toml");
13478
13688
  if (!isPathWithinBoundary(agentsDir, boundary)) {
13479
13689
  return {
13480
13690
  provider,
@@ -13568,7 +13778,7 @@ async function installCodexToml(items, provider, portableType, options2, deps) {
13568
13778
  continue;
13569
13779
  }
13570
13780
  seenSlugOwners.set(slug, item.name);
13571
- const agentTomlPath = join3(agentsDir, `${slug}.toml`);
13781
+ const agentTomlPath = join4(agentsDir, `${slug}.toml`);
13572
13782
  if (process.platform === "win32" && agentTomlPath.length > MAX_WINDOWS_PATH_LENGTH) {
13573
13783
  allWarnings.push(`Skipped ${item.name}: target path exceeds ${MAX_WINDOWS_PATH_LENGTH} characters on Windows`);
13574
13784
  continue;
@@ -13695,9 +13905,9 @@ async function cleanupStaleCodexConfigEntries(options2) {
13695
13905
  const basePath = options2.global ? pathConfig.globalPath : pathConfig.projectPath;
13696
13906
  if (!basePath)
13697
13907
  return [];
13698
- const agentsDir = resolve2(basePath);
13699
- const configTomlPath = join3(dirname2(agentsDir), "config.toml");
13700
- if (!existsSync3(configTomlPath))
13908
+ const agentsDir = resolve3(basePath);
13909
+ const configTomlPath = join4(dirname2(agentsDir), "config.toml");
13910
+ if (!existsSync4(configTomlPath))
13701
13911
  return [];
13702
13912
  try {
13703
13913
  return await withCodexTargetLock(configTomlPath, async () => {
@@ -13713,8 +13923,8 @@ async function cleanupStaleCodexConfigEntries(options2) {
13713
13923
  if (managedEntries.size > 0) {
13714
13924
  const validEntries = new Map;
13715
13925
  for (const [slug, entry] of managedEntries) {
13716
- const tomlPath = join3(agentsDir, `${slug}.toml`);
13717
- if (existsSync3(tomlPath)) {
13926
+ const tomlPath = join4(agentsDir, `${slug}.toml`);
13927
+ if (existsSync4(tomlPath)) {
13718
13928
  validEntries.set(slug, entry);
13719
13929
  } else {
13720
13930
  allStaleSlugs.push(slug);
@@ -13744,10 +13954,10 @@ async function cleanupStaleCodexConfigEntries(options2) {
13744
13954
  const unmanagedSlugs = extractUnmanagedAgentSlugs(analysis.unmanagedContent);
13745
13955
  const legacyStaleSlugs = [];
13746
13956
  for (const slug of unmanagedSlugs) {
13747
- const tomlPath = join3(agentsDir, `${slug}.toml`);
13957
+ const tomlPath = join4(agentsDir, `${slug}.toml`);
13748
13958
  if (!isPathWithinBoundary(tomlPath, agentsDir))
13749
13959
  continue;
13750
- if (!existsSync3(tomlPath)) {
13960
+ if (!existsSync4(tomlPath)) {
13751
13961
  legacyStaleSlugs.push(slug);
13752
13962
  }
13753
13963
  }
@@ -13992,13 +14202,13 @@ var init_merge_single_sections = __esm(() => {
13992
14202
  });
13993
14203
 
13994
14204
  // src/commands/portable/portable-installer.ts
13995
- import { existsSync as existsSync4 } from "node:fs";
14205
+ import { existsSync as existsSync5 } from "node:fs";
13996
14206
  import { lstat, mkdir as mkdir3, readFile as readFile4, realpath as realpath2, unlink as unlink3, writeFile as writeFile3 } from "node:fs/promises";
13997
14207
  import { homedir as homedir5 } from "node:os";
13998
- import { basename as basename2, dirname as dirname3, join as join4, relative as relative2, resolve as resolve3, sep } from "node:path";
14208
+ import { basename as basename2, dirname as dirname3, join as join5, relative as relative2, resolve as resolve4, sep } from "node:path";
13999
14209
  function isSamePath(path1, path2) {
14000
14210
  try {
14001
- return resolve3(path1) === resolve3(path2);
14211
+ return resolve4(path1) === resolve4(path2);
14002
14212
  } catch {
14003
14213
  return false;
14004
14214
  }
@@ -14027,8 +14237,8 @@ function isWindowsAbsolutePath(path2) {
14027
14237
  return /^[a-zA-Z]:[\\/]/.test(path2) || /^\\\\/.test(path2);
14028
14238
  }
14029
14239
  function isPathWithinBoundary2(targetPath, boundaryPath) {
14030
- const resolvedTarget = resolve3(targetPath);
14031
- const resolvedBoundary = resolve3(boundaryPath);
14240
+ const resolvedTarget = resolve4(targetPath);
14241
+ const resolvedBoundary = resolve4(boundaryPath);
14032
14242
  return resolvedTarget === resolvedBoundary || resolvedTarget.startsWith(`${resolvedBoundary}${sep}`);
14033
14243
  }
14034
14244
  function validateStrategyTargetPath(targetPath, options2) {
@@ -14054,16 +14264,16 @@ function resolvePerFileOutputFilename(filename, pathConfig) {
14054
14264
  return `${nameWithoutExt.replace(/\//g, "-")}${ext}`;
14055
14265
  }
14056
14266
  function validateResolvedTargetWithinBase(targetPath, basePath, pathConfig) {
14057
- const resolvedTarget = resolve3(targetPath);
14058
- const resolvedBase = pathConfig.writeStrategy === "single-file" ? resolve3(dirname3(basePath)) : resolve3(basePath);
14267
+ const resolvedTarget = resolve4(targetPath);
14268
+ const resolvedBase = pathConfig.writeStrategy === "single-file" ? resolve4(dirname3(basePath)) : resolve4(basePath);
14059
14269
  if (!resolvedTarget.startsWith(`${resolvedBase}${sep}`) && resolvedTarget !== resolvedBase) {
14060
14270
  return "Unsafe path: target escapes base directory";
14061
14271
  }
14062
14272
  return null;
14063
14273
  }
14064
14274
  async function validateNoSymlinkComponents(targetPath, boundaryPath) {
14065
- const resolvedTarget = resolve3(targetPath);
14066
- const resolvedBoundary = resolve3(boundaryPath);
14275
+ const resolvedTarget = resolve4(targetPath);
14276
+ const resolvedBoundary = resolve4(boundaryPath);
14067
14277
  if (!isPathWithinBoundary2(resolvedTarget, resolvedBoundary)) {
14068
14278
  return `Unsafe path: target escapes ${resolvedBoundary}`;
14069
14279
  }
@@ -14071,7 +14281,7 @@ async function validateNoSymlinkComponents(targetPath, boundaryPath) {
14071
14281
  let cursor = resolvedBoundary;
14072
14282
  let deepestExisting = resolvedBoundary;
14073
14283
  for (const segment of segments) {
14074
- cursor = join4(cursor, segment);
14284
+ cursor = join5(cursor, segment);
14075
14285
  try {
14076
14286
  await lstat(cursor);
14077
14287
  deepestExisting = cursor;
@@ -14181,13 +14391,13 @@ function buildPerFileCollisionSkips(items, provider, configDisplayName, basePath
14181
14391
  continue;
14182
14392
  }
14183
14393
  const resolvedFilename = resolvePerFileOutputFilename(result.filename, pathConfig);
14184
- const targetPath = pathConfig.writeStrategy === "single-file" ? basePath : join4(basePath, resolvedFilename);
14394
+ const targetPath = pathConfig.writeStrategy === "single-file" ? basePath : join5(basePath, resolvedFilename);
14185
14395
  if (validateResolvedTargetWithinBase(targetPath, basePath, pathConfig)) {
14186
14396
  continue;
14187
14397
  }
14188
- const first = seenTargets.get(resolve3(targetPath));
14398
+ const first = seenTargets.get(resolve4(targetPath));
14189
14399
  if (!first) {
14190
- seenTargets.set(resolve3(targetPath), { itemName: item.name, targetPath });
14400
+ seenTargets.set(resolve4(targetPath), { itemName: item.name, targetPath });
14191
14401
  continue;
14192
14402
  }
14193
14403
  skipped.set(index, {
@@ -14267,16 +14477,16 @@ async function installPerFileItems(items, provider, portableType, pathConfig, op
14267
14477
  }
14268
14478
  async function ensureDir2(filePath) {
14269
14479
  const dir = dirname3(filePath);
14270
- if (!existsSync4(dir)) {
14480
+ if (!existsSync5(dir)) {
14271
14481
  await mkdir3(dir, { recursive: true });
14272
14482
  }
14273
14483
  }
14274
14484
  function getMergeTargetLockPath(targetPath) {
14275
14485
  const lockName = `.${basename2(targetPath)}.ck-merge.lock`;
14276
- return join4(dirname3(targetPath), lockName);
14486
+ return join5(dirname3(targetPath), lockName);
14277
14487
  }
14278
14488
  async function withMergeTargetLock(targetPath, operation) {
14279
- const resolvedTargetPath = resolve3(targetPath);
14489
+ const resolvedTargetPath = resolve4(targetPath);
14280
14490
  await ensureDir2(resolvedTargetPath);
14281
14491
  const release = await import_proper_lockfile3.default.lock(dirname3(resolvedTargetPath), {
14282
14492
  realpath: false,
@@ -14393,7 +14603,7 @@ async function installPerFile(item, provider, portableType, options2, registryDe
14393
14603
  };
14394
14604
  }
14395
14605
  const resolvedFilename = resolvePerFileOutputFilename(result.filename, pathConfig);
14396
- targetPath = pathConfig.writeStrategy === "single-file" ? basePath : join4(basePath, resolvedFilename);
14606
+ targetPath = pathConfig.writeStrategy === "single-file" ? basePath : join5(basePath, resolvedFilename);
14397
14607
  const targetPathError = validateResolvedTargetWithinBase(targetPath, basePath, pathConfig);
14398
14608
  if (targetPathError) {
14399
14609
  return {
@@ -14520,7 +14730,7 @@ async function installMergeSingle(items, provider, portableType, options2, regis
14520
14730
  error: "Config merge target accepts only one item per install"
14521
14731
  };
14522
14732
  }
14523
- const alreadyExists = existsSync4(targetPath);
14733
+ const alreadyExists = existsSync5(targetPath);
14524
14734
  let existingSections = [];
14525
14735
  let existingPreamble = "";
14526
14736
  const allWarnings = [];
@@ -14723,7 +14933,7 @@ async function installYamlMerge(items, provider, portableType, options2, registr
14723
14933
  }
14724
14934
  let targetSnapshot = null;
14725
14935
  try {
14726
- const alreadyExists = existsSync4(targetPath);
14936
+ const alreadyExists = existsSync5(targetPath);
14727
14937
  let existingModes = new Map;
14728
14938
  if (alreadyExists) {
14729
14939
  try {
@@ -14899,7 +15109,7 @@ async function installJsonMerge(items, provider, portableType, options2, registr
14899
15109
  }
14900
15110
  modes.push(parsedMode.data);
14901
15111
  }
14902
- const modesPath = join4(basePath, "cline_custom_modes.json");
15112
+ const modesPath = join5(basePath, "cline_custom_modes.json");
14903
15113
  failurePath = modesPath;
14904
15114
  const modesSymlinkError = await validateWritableTargetPath(modesPath, options2);
14905
15115
  if (modesSymlinkError) {
@@ -14912,7 +15122,7 @@ async function installJsonMerge(items, provider, portableType, options2, registr
14912
15122
  };
14913
15123
  }
14914
15124
  await ensureDir2(modesPath);
14915
- const alreadyExists = existsSync4(modesPath);
15125
+ const alreadyExists = existsSync5(modesPath);
14916
15126
  if (alreadyExists) {
14917
15127
  try {
14918
15128
  const existingRaw = JSON.parse(await readFile4(modesPath, "utf-8"));
@@ -14948,7 +15158,7 @@ async function installJsonMerge(items, provider, portableType, options2, registr
14948
15158
  await writeFile3(modesPath, modesJson, "utf-8");
14949
15159
  const targetChecksum = computeContentChecksum(modesJson);
14950
15160
  const ownedSections = modes.map((m2) => m2.slug);
14951
- const rulesDir = join4(dirname3(basePath), ".clinerules");
15161
+ const rulesDir = join5(dirname3(basePath), ".clinerules");
14952
15162
  await mkdir3(rulesDir, { recursive: true });
14953
15163
  const capturedRuleSnapshots = new Set;
14954
15164
  for (const item of items) {
@@ -14970,10 +15180,10 @@ async function installJsonMerge(items, provider, portableType, options2, registr
14970
15180
  }
14971
15181
  }
14972
15182
  const filename = `${namespacedName}.md`;
14973
- const rulePath = join4(rulesDir, filename);
15183
+ const rulePath = join5(rulesDir, filename);
14974
15184
  failurePath = rulePath;
14975
- const resolvedRulePath = resolve3(rulePath);
14976
- const resolvedRulesDir = resolve3(rulesDir);
15185
+ const resolvedRulePath = resolve4(rulePath);
15186
+ const resolvedRulesDir = resolve4(rulesDir);
14977
15187
  if (!resolvedRulePath.startsWith(resolvedRulesDir + sep) && resolvedRulePath !== resolvedRulesDir) {
14978
15188
  throw new Error(`Unsafe path: rule target escapes rules directory (${rulePath})`);
14979
15189
  }
@@ -15349,6 +15559,7 @@ var init_commands = __esm(() => {
15349
15559
  dryRun: exports_external.boolean().default(false),
15350
15560
  forceOverwrite: exports_external.boolean().default(false),
15351
15561
  forceOverwriteSettings: exports_external.boolean().default(false),
15562
+ restoreCkHooks: exports_external.boolean().default(false),
15352
15563
  skipSetup: exports_external.boolean().default(false),
15353
15564
  refresh: exports_external.boolean().default(false),
15354
15565
  docsDir: exports_external.string().optional(),
@@ -15891,8 +16102,12 @@ var init_ck_config = __esm(() => {
15891
16102
  CkHooksConfigSchema = exports_external.object({
15892
16103
  "session-init": exports_external.boolean().optional(),
15893
16104
  "subagent-init": exports_external.boolean().optional(),
16105
+ "session-state": exports_external.boolean().optional(),
16106
+ "cook-after-plan-reminder": exports_external.boolean().optional(),
15894
16107
  "descriptive-name": exports_external.boolean().optional(),
15895
16108
  "dev-rules-reminder": exports_external.boolean().optional(),
16109
+ "plan-format-kanban": exports_external.boolean().optional(),
16110
+ "usage-quota-cache-refresh": exports_external.boolean().optional(),
15896
16111
  "usage-context-awareness": exports_external.boolean().optional(),
15897
16112
  "context-tracking": exports_external.boolean().optional(),
15898
16113
  "scout-block": exports_external.boolean().optional(),
@@ -15989,8 +16204,12 @@ var init_ck_config = __esm(() => {
15989
16204
  hooks: {
15990
16205
  "session-init": true,
15991
16206
  "subagent-init": true,
16207
+ "session-state": true,
16208
+ "cook-after-plan-reminder": true,
15992
16209
  "descriptive-name": true,
15993
16210
  "dev-rules-reminder": true,
16211
+ "plan-format-kanban": true,
16212
+ "usage-quota-cache-refresh": true,
15994
16213
  "usage-context-awareness": true,
15995
16214
  "context-tracking": true,
15996
16215
  "scout-block": true,
@@ -16014,8 +16233,12 @@ var init_ck_config = __esm(() => {
16014
16233
  CK_HOOK_NAMES = [
16015
16234
  "session-init",
16016
16235
  "subagent-init",
16236
+ "session-state",
16237
+ "cook-after-plan-reminder",
16017
16238
  "descriptive-name",
16018
16239
  "dev-rules-reminder",
16240
+ "plan-format-kanban",
16241
+ "usage-quota-cache-refresh",
16019
16242
  "usage-context-awareness",
16020
16243
  "context-tracking",
16021
16244
  "scout-block",
@@ -16169,26 +16392,26 @@ var init_types3 = __esm(() => {
16169
16392
  });
16170
16393
 
16171
16394
  // src/shared/kit-layout.ts
16172
- import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
16173
- import { join as join5 } from "node:path";
16395
+ import { existsSync as existsSync6, readFileSync as readFileSync3 } from "node:fs";
16396
+ import { join as join6 } from "node:path";
16174
16397
  function uniquePaths(paths) {
16175
16398
  return [...new Set(paths)];
16176
16399
  }
16177
16400
  function findFirstExistingPath(paths) {
16178
16401
  for (const candidate of paths) {
16179
- if (existsSync5(candidate)) {
16402
+ if (existsSync6(candidate)) {
16180
16403
  return candidate;
16181
16404
  }
16182
16405
  }
16183
16406
  return null;
16184
16407
  }
16185
16408
  function resolveKitLayout(projectRoot) {
16186
- const packageJsonPath = join5(projectRoot, "package.json");
16187
- if (!existsSync5(packageJsonPath)) {
16409
+ const packageJsonPath = join6(projectRoot, "package.json");
16410
+ if (!existsSync6(packageJsonPath)) {
16188
16411
  return DEFAULT_KIT_LAYOUT;
16189
16412
  }
16190
16413
  try {
16191
- const parsed = ClaudeKitPackageMetadataSchema.parse(JSON.parse(readFileSync2(packageJsonPath, "utf8")));
16414
+ const parsed = ClaudeKitPackageMetadataSchema.parse(JSON.parse(readFileSync3(packageJsonPath, "utf8")));
16192
16415
  return KitLayoutSchema.parse({
16193
16416
  ...DEFAULT_KIT_LAYOUT,
16194
16417
  ...parsed.claudekit ?? {}
@@ -16200,8 +16423,8 @@ function resolveKitLayout(projectRoot) {
16200
16423
  function getProjectLayoutCandidates(projectRoot, subPath) {
16201
16424
  const layout = resolveKitLayout(projectRoot);
16202
16425
  return uniquePaths([
16203
- join5(projectRoot, layout.sourceDir, subPath),
16204
- join5(projectRoot, DEFAULT_KIT_LAYOUT.sourceDir, subPath)
16426
+ join6(projectRoot, layout.sourceDir, subPath),
16427
+ join6(projectRoot, DEFAULT_KIT_LAYOUT.sourceDir, subPath)
16205
16428
  ]);
16206
16429
  }
16207
16430
  function findExistingProjectLayoutPath(projectRoot, subPath) {
@@ -16210,9 +16433,9 @@ function findExistingProjectLayoutPath(projectRoot, subPath) {
16210
16433
  function getProjectConfigCandidates(projectRoot) {
16211
16434
  const layout = resolveKitLayout(projectRoot);
16212
16435
  return uniquePaths([
16213
- join5(projectRoot, "CLAUDE.md"),
16214
- join5(projectRoot, layout.sourceDir, "CLAUDE.md"),
16215
- join5(projectRoot, DEFAULT_KIT_LAYOUT.sourceDir, "CLAUDE.md")
16436
+ join6(projectRoot, "CLAUDE.md"),
16437
+ join6(projectRoot, layout.sourceDir, "CLAUDE.md"),
16438
+ join6(projectRoot, DEFAULT_KIT_LAYOUT.sourceDir, "CLAUDE.md")
16216
16439
  ]);
16217
16440
  }
16218
16441
  function findExistingProjectConfigPath(projectRoot) {
@@ -16326,9 +16549,9 @@ var init_frontmatter_parser = __esm(() => {
16326
16549
  // src/commands/agents/agents-discovery.ts
16327
16550
  import { readdir } from "node:fs/promises";
16328
16551
  import { homedir as homedir6 } from "node:os";
16329
- import { join as join6 } from "node:path";
16552
+ import { join as join7 } from "node:path";
16330
16553
  function getAgentSourcePath(globalOnly = false) {
16331
- const globalPath = join6(homedir6(), ".claude/agents");
16554
+ const globalPath = join7(homedir6(), ".claude/agents");
16332
16555
  if (globalOnly) {
16333
16556
  return findFirstExistingPath([globalPath]);
16334
16557
  }
@@ -16347,7 +16570,7 @@ async function discoverAgents(sourcePath) {
16347
16570
  for (const entry of entries) {
16348
16571
  if (!entry.isFile() || !entry.name.endsWith(".md"))
16349
16572
  continue;
16350
- const filePath = join6(searchPath, entry.name);
16573
+ const filePath = join7(searchPath, entry.name);
16351
16574
  try {
16352
16575
  const { frontmatter, body } = await parseFrontmatterFile(filePath);
16353
16576
  const name = entry.name.replace(/\.md$/, "");
@@ -19410,217 +19633,6 @@ var init_safe_spinner = __esm(() => {
19410
19633
  };
19411
19634
  });
19412
19635
 
19413
- // src/shared/path-resolver.ts
19414
- import { createHash as createHash3 } from "node:crypto";
19415
- import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
19416
- import { homedir as homedir9, platform as platform2 } from "node:os";
19417
- import { join as join11, normalize, resolve as resolve4 } from "node:path";
19418
- function getEnvVar(name) {
19419
- const val = process.env[name];
19420
- if (!val || val.trim() === "")
19421
- return;
19422
- if (val.includes("..")) {
19423
- console.warn(`Environment variable ${name} contains path traversal: ${val}`);
19424
- return;
19425
- }
19426
- return val;
19427
- }
19428
- function isWSL() {
19429
- try {
19430
- return process.platform === "linux" && existsSync8("/proc/version") && readFileSync4("/proc/version", "utf8").toLowerCase().includes("microsoft");
19431
- } catch {
19432
- return false;
19433
- }
19434
- }
19435
- function normalizeWSLPath(p) {
19436
- if (!isWSL())
19437
- return p;
19438
- const windowsMatch = p.match(/^([A-Za-z]):(.*)/);
19439
- if (windowsMatch) {
19440
- const drive = windowsMatch[1].toLowerCase();
19441
- const rest = windowsMatch[2].replace(/\\/g, "/");
19442
- return `/mnt/${drive}${rest}`;
19443
- }
19444
- return p;
19445
- }
19446
-
19447
- class PathResolver {
19448
- static getTestHomeDir() {
19449
- return process.env.CK_TEST_HOME;
19450
- }
19451
- static isValidComponentName(name) {
19452
- if (!name || typeof name !== "string") {
19453
- return false;
19454
- }
19455
- const dangerousPatterns = [
19456
- "..",
19457
- "~"
19458
- ];
19459
- for (const pattern of dangerousPatterns) {
19460
- if (name.includes(pattern)) {
19461
- return false;
19462
- }
19463
- }
19464
- const normalized = normalize(name);
19465
- for (const pattern of dangerousPatterns) {
19466
- if (normalized.includes(pattern)) {
19467
- return false;
19468
- }
19469
- }
19470
- if (name.startsWith("/") || normalized.startsWith("/") || /^[a-zA-Z]:/.test(name) || name.startsWith("\\\\") || normalized.startsWith("\\\\")) {
19471
- return false;
19472
- }
19473
- return true;
19474
- }
19475
- static getConfigDir(global3 = false) {
19476
- const testHome = PathResolver.getTestHomeDir();
19477
- if (testHome) {
19478
- return global3 ? join11(testHome, ".config", "claude") : join11(testHome, ".claudekit");
19479
- }
19480
- if (!global3) {
19481
- return join11(homedir9(), ".claudekit");
19482
- }
19483
- const os2 = platform2();
19484
- if (os2 === "win32") {
19485
- const localAppData = getEnvVar("LOCALAPPDATA") ?? join11(homedir9(), "AppData", "Local");
19486
- return join11(localAppData, "claude");
19487
- }
19488
- const xdgConfigHome = getEnvVar("XDG_CONFIG_HOME");
19489
- if (xdgConfigHome) {
19490
- return join11(xdgConfigHome, "claude");
19491
- }
19492
- return join11(homedir9(), ".config", "claude");
19493
- }
19494
- static getConfigFile(global3 = false) {
19495
- return join11(PathResolver.getConfigDir(global3), "config.json");
19496
- }
19497
- static getCacheDir(global3 = false) {
19498
- const testHome = PathResolver.getTestHomeDir();
19499
- if (testHome) {
19500
- return global3 ? join11(testHome, ".cache", "claude") : join11(testHome, ".claudekit", "cache");
19501
- }
19502
- if (!global3) {
19503
- return join11(homedir9(), ".claudekit", "cache");
19504
- }
19505
- const os2 = platform2();
19506
- if (os2 === "win32") {
19507
- const localAppData = getEnvVar("LOCALAPPDATA") ?? join11(homedir9(), "AppData", "Local");
19508
- return join11(localAppData, "claude", "cache");
19509
- }
19510
- const xdgCacheHome = getEnvVar("XDG_CACHE_HOME");
19511
- if (xdgCacheHome) {
19512
- return join11(xdgCacheHome, "claude");
19513
- }
19514
- return join11(homedir9(), ".cache", "claude");
19515
- }
19516
- static getGlobalKitDir() {
19517
- const testHome = PathResolver.getTestHomeDir();
19518
- if (testHome) {
19519
- return join11(testHome, ".claude");
19520
- }
19521
- const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR;
19522
- if (claudeConfigDir) {
19523
- return claudeConfigDir;
19524
- }
19525
- return join11(homedir9(), ".claude");
19526
- }
19527
- static getClaudeKitDir() {
19528
- const testHome = PathResolver.getTestHomeDir();
19529
- if (testHome) {
19530
- return join11(testHome, ".claudekit");
19531
- }
19532
- return join11(homedir9(), ".claudekit");
19533
- }
19534
- static getProjectsRegistryPath() {
19535
- return join11(PathResolver.getClaudeKitDir(), "projects.json");
19536
- }
19537
- static getOpenCodeDir(global3, baseDir) {
19538
- const testHome = PathResolver.getTestHomeDir();
19539
- if (testHome) {
19540
- return global3 ? join11(testHome, ".config", "opencode") : join11(baseDir || testHome, ".opencode");
19541
- }
19542
- if (!global3) {
19543
- return join11(baseDir || process.cwd(), ".opencode");
19544
- }
19545
- const xdgConfigHome = process.env.XDG_CONFIG_HOME;
19546
- if (xdgConfigHome) {
19547
- return join11(xdgConfigHome, "opencode");
19548
- }
19549
- return join11(homedir9(), ".config", "opencode");
19550
- }
19551
- static getPathPrefix(global3) {
19552
- return global3 ? "" : ".claude";
19553
- }
19554
- static buildSkillsPath(baseDir, global3) {
19555
- const prefix = PathResolver.getPathPrefix(global3);
19556
- if (prefix) {
19557
- return join11(baseDir, prefix, "skills");
19558
- }
19559
- return join11(baseDir, "skills");
19560
- }
19561
- static buildComponentPath(baseDir, component, global3) {
19562
- if (!PathResolver.isValidComponentName(component)) {
19563
- throw new Error(`Invalid component name: "${component}" contains path traversal patterns. Valid names are simple directory names like "agents", "commands", "rules", "skills", or "hooks".`);
19564
- }
19565
- const prefix = PathResolver.getPathPrefix(global3);
19566
- if (prefix) {
19567
- return join11(baseDir, prefix, component);
19568
- }
19569
- return join11(baseDir, component);
19570
- }
19571
- static getBackupDir(timestamp) {
19572
- const testHome = PathResolver.getTestHomeDir();
19573
- const baseDir = testHome ? join11(testHome, ".claudekit") : join11(homedir9(), ".claudekit");
19574
- if (timestamp) {
19575
- return join11(baseDir, "backups", timestamp);
19576
- }
19577
- const now = new Date;
19578
- const dateStr = now.toISOString().replace(/[:.]/g, "-").slice(0, 19);
19579
- const ms = now.getMilliseconds().toString().padStart(3, "0");
19580
- const random = Math.random().toString(36).slice(2, 6);
19581
- const ts = `${dateStr}-${ms}-${random}`;
19582
- return join11(baseDir, "backups", ts);
19583
- }
19584
- static normalizeWSLPath(p) {
19585
- return normalizeWSLPath(p);
19586
- }
19587
- static isWSL() {
19588
- return isWSL();
19589
- }
19590
- static isAtHomeDirectory(cwd2) {
19591
- const currentDir = normalize(cwd2 || process.cwd());
19592
- const homeDir = normalize(homedir9());
19593
- return currentDir === homeDir;
19594
- }
19595
- static getLocalClaudeDir(baseDir) {
19596
- const dir = baseDir || process.cwd();
19597
- return join11(dir, ".claude");
19598
- }
19599
- static isLocalSameAsGlobal(cwd2) {
19600
- const localPath = normalize(PathResolver.getLocalClaudeDir(cwd2));
19601
- const globalPath = normalize(PathResolver.getGlobalKitDir());
19602
- return localPath === globalPath;
19603
- }
19604
- static isGlobPattern(pattern) {
19605
- return pattern.includes("*") || pattern.includes("?") || pattern.includes("{");
19606
- }
19607
- static computeProjectHash(projectRoot) {
19608
- let normalized = resolve4(projectRoot).replace(/[/\\]+$/, "");
19609
- if (process.platform === "darwin" || process.platform === "win32") {
19610
- normalized = normalized.toLowerCase();
19611
- }
19612
- return createHash3("sha256").update(normalized).digest("hex").slice(0, 12);
19613
- }
19614
- static getPlansRegistriesDir() {
19615
- return join11(PathResolver.getGlobalKitDir(), "plans-registries");
19616
- }
19617
- static getPlansRegistryPath(projectRoot) {
19618
- const hash = PathResolver.computeProjectHash(projectRoot);
19619
- return join11(PathResolver.getPlansRegistriesDir(), `${hash}.json`);
19620
- }
19621
- }
19622
- var init_path_resolver = () => {};
19623
-
19624
19636
  // node_modules/universalify/index.js
19625
19637
  var require_universalify = __commonJS((exports) => {
19626
19638
  exports.fromCallback = function(fn) {
@@ -21009,10 +21021,10 @@ var init_safe_prompts = __esm(() => {
21009
21021
 
21010
21022
  // src/commands/commands/commands-discovery.ts
21011
21023
  import { readdir as readdir4 } from "node:fs/promises";
21012
- import { homedir as homedir10 } from "node:os";
21024
+ import { homedir as homedir9 } from "node:os";
21013
21025
  import { join as join16, relative as relative3 } from "node:path";
21014
21026
  function getCommandSourcePath(globalOnly = false) {
21015
- const globalPath = join16(homedir10(), ".claude/commands");
21027
+ const globalPath = join16(homedir9(), ".claude/commands");
21016
21028
  if (globalOnly) {
21017
21029
  return findFirstExistingPath([globalPath]);
21018
21030
  }
@@ -45197,6 +45209,14 @@ var init_open = __esm(() => {
45197
45209
  open_default = open;
45198
45210
  });
45199
45211
 
45212
+ // src/shared/json-content.ts
45213
+ function stripJsonBom(content) {
45214
+ return content.charCodeAt(0) === 65279 ? content.slice(1) : content;
45215
+ }
45216
+ function parseJsonContent(content) {
45217
+ return JSON.parse(stripJsonBom(content));
45218
+ }
45219
+
45200
45220
  // src/domains/config/config-manager.ts
45201
45221
  import { existsSync as existsSync10 } from "node:fs";
45202
45222
  import { mkdir as mkdir6, readFile as readFile7, rename as rename3, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
@@ -45225,7 +45245,7 @@ class ConfigManager {
45225
45245
  try {
45226
45246
  if (existsSync10(configFile)) {
45227
45247
  const content = await readFile7(configFile, "utf-8");
45228
- const data = JSON.parse(content);
45248
+ const data = parseJsonContent(content);
45229
45249
  ConfigManager.config = ConfigSchema.parse(data);
45230
45250
  logger.debug(`Config loaded from ${configFile}`);
45231
45251
  return ConfigManager.config;
@@ -45279,7 +45299,7 @@ class ConfigManager {
45279
45299
  try {
45280
45300
  if (existsSync10(configPath)) {
45281
45301
  const content = await readFile7(configPath, "utf-8");
45282
- const data = JSON.parse(content);
45302
+ const data = parseJsonContent(content);
45283
45303
  const folders = FoldersConfigSchema.parse(data.paths || data);
45284
45304
  logger.debug(`Project config loaded from ${configPath}`);
45285
45305
  return folders;
@@ -45300,7 +45320,7 @@ class ConfigManager {
45300
45320
  if (existsSync10(configPath)) {
45301
45321
  try {
45302
45322
  const content = await readFile7(configPath, "utf-8");
45303
- existingConfig = JSON.parse(content);
45323
+ existingConfig = parseJsonContent(content);
45304
45324
  } catch (error) {
45305
45325
  logger.debug(`Could not parse existing config, starting fresh: ${error instanceof Error ? error.message : "Unknown error"}`);
45306
45326
  }
@@ -45384,7 +45404,7 @@ __export(exports_ck_config_manager, {
45384
45404
  });
45385
45405
  import { existsSync as existsSync11 } from "node:fs";
45386
45406
  import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile6 } from "node:fs/promises";
45387
- import { homedir as homedir11 } from "node:os";
45407
+ import { homedir as homedir10 } from "node:os";
45388
45408
  import { join as join19 } from "node:path";
45389
45409
  function getNestedValue(obj, path4) {
45390
45410
  if (!obj || typeof obj !== "object")
@@ -45459,7 +45479,7 @@ function valuesEqual(a3, b3) {
45459
45479
 
45460
45480
  class CkConfigManager {
45461
45481
  static getGlobalConfigDir() {
45462
- return join19(homedir11(), ".claude");
45482
+ return join19(homedir10(), ".claude");
45463
45483
  }
45464
45484
  static getGlobalConfigPath() {
45465
45485
  return join19(CkConfigManager.getGlobalConfigDir(), CK_CONFIG_FILE);
@@ -45475,7 +45495,7 @@ class CkConfigManager {
45475
45495
  if (!existsSync11(configPath))
45476
45496
  return null;
45477
45497
  const content = await readFile8(configPath, "utf-8");
45478
- const data = normalizeCkConfigInput(JSON.parse(content));
45498
+ const data = normalizeCkConfigInput(parseJsonContent(content));
45479
45499
  return CkConfigSchema.parse(data);
45480
45500
  } catch (error) {
45481
45501
  logger.warning(`Failed to load config from ${configPath}: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -45542,7 +45562,7 @@ class CkConfigManager {
45542
45562
  if (!existingConfig && existsSync11(configPath)) {
45543
45563
  try {
45544
45564
  const content = await readFile8(configPath, "utf-8");
45545
- const parsed = JSON.parse(content);
45565
+ const parsed = parseJsonContent(content);
45546
45566
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
45547
45567
  existingConfig = normalizeCkConfigInput(parsed);
45548
45568
  }
@@ -45718,7 +45738,7 @@ function notFoundError(type, name, hint) {
45718
45738
  }
45719
45739
 
45720
45740
  // src/shared/command-normalizer.ts
45721
- import { homedir as homedir12 } from "node:os";
45741
+ import { homedir as homedir11 } from "node:os";
45722
45742
  import { join as join20 } from "node:path";
45723
45743
  function escapeRegex(value) {
45724
45744
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -45758,7 +45778,7 @@ function resolveClaudePathArg(arg, root) {
45758
45778
  const isWin2 = process.platform === "win32";
45759
45779
  const cmp = (s) => isWin2 ? s.toLowerCase() : s;
45760
45780
  const globalRoots = [
45761
- `${homedir12().replace(/\\/g, "/").replace(/\/+$/, "")}/.claude/`,
45781
+ `${homedir11().replace(/\\/g, "/").replace(/\/+$/, "")}/.claude/`,
45762
45782
  `${PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "")}/`
45763
45783
  ];
45764
45784
  const isUnderGlobal = globalRoots.some((g2) => cmp(absolutePath).startsWith(cmp(g2)));
@@ -45794,6 +45814,12 @@ function repairClaudeNodeCommandPath(cmd, root) {
45794
45814
  const command = formatCanonicalClaudeCommand(nodePrefix, root, relativePath, suffix);
45795
45815
  return { command, changed: command !== cmd, issue: "raw-relative" };
45796
45816
  }
45817
+ const quotedRelativeMatch = cmd.match(/^(node\s+)["'](?:\.\/)?(\.claude[/\\][^"']+)["'](.*)$/);
45818
+ if (quotedRelativeMatch) {
45819
+ const [, nodePrefix, relativePath, suffix] = quotedRelativeMatch;
45820
+ const command = formatCanonicalClaudeCommand(nodePrefix, root, relativePath, suffix);
45821
+ return { command, changed: command !== cmd, issue: "raw-relative" };
45822
+ }
45797
45823
  const embeddedQuotedMatch = cmd.match(/^(node\s+)"(?:\$HOME|\$CLAUDE_PROJECT_DIR|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)[/\\](\.claude[/\\][^"]+)"(.*)$/);
45798
45824
  if (embeddedQuotedMatch) {
45799
45825
  const [, nodePrefix, relativePath, suffix] = embeddedQuotedMatch;
@@ -45829,7 +45855,7 @@ function repairClaudeNodeCommandPath(cmd, root) {
45829
45855
  const isWin2 = process.platform === "win32";
45830
45856
  const cmp = (s) => isWin2 ? s.toLowerCase() : s;
45831
45857
  const globalRoots = [
45832
- `${homedir12().replace(/\\/g, "/").replace(/\/+$/, "")}/.claude/`,
45858
+ `${homedir11().replace(/\\/g, "/").replace(/\/+$/, "")}/.claude/`,
45833
45859
  `${PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "")}/`
45834
45860
  ];
45835
45861
  const isUnderGlobal = globalRoots.some((g2) => cmp(normalizedAbsPath).startsWith(cmp(g2)));
@@ -45878,7 +45904,7 @@ function normalizeCommand(cmd) {
45878
45904
  return "";
45879
45905
  let normalized = cmd;
45880
45906
  const globalKitDir = PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "");
45881
- const defaultGlobalKitDir = join20(homedir12(), ".claude").replace(/\\/g, "/");
45907
+ const defaultGlobalKitDir = join20(homedir11(), ".claude").replace(/\\/g, "/");
45882
45908
  normalized = normalized.replace(/"/g, "");
45883
45909
  normalized = normalized.replace(/~\//g, "$HOME/");
45884
45910
  normalized = normalized.replace(/\$CLAUDE_PROJECT_DIR/g, "$HOME");
@@ -46076,11 +46102,15 @@ function mergeHookEntries(sourceEntries, destEntries, eventName, result, install
46076
46102
  const isFullyDuplicated = commands.length > 0 && commands.every((cmd) => existingCommands.has(normalizeCommand(cmd)));
46077
46103
  const duplicateCommands = commands.filter((cmd) => existingCommands.has(normalizeCommand(cmd)));
46078
46104
  logDuplicates(duplicateCommands, eventName, result);
46079
- const hasNonRemovedCommands = commands.length === 0 || commands.some((cmd) => !existingCommands.has(normalizeCommand(cmd)) && !wasCommandInstalled(cmd, installedHooks));
46105
+ const newCommands = commands.filter((cmd) => !existingCommands.has(normalizeCommand(cmd)) && !wasCommandInstalled(cmd, installedHooks));
46106
+ const hasNonRemovedCommands = commands.length === 0 || newCommands.length > 0;
46080
46107
  if (!isFullyDuplicated && hasNonRemovedCommands) {
46081
46108
  let filteredEntry = entry;
46082
- if ("hooks" in entry && entry.hooks && userRemovedCommands.length > 0) {
46083
- const filteredHooks = entry.hooks.filter((h2) => !h2.command || !wasCommandInstalled(h2.command, installedHooks));
46109
+ if ("hooks" in entry && entry.hooks && commands.length > 0) {
46110
+ const filteredHooks = entry.hooks.filter((h2) => !h2.command || !existingCommands.has(normalizeCommand(h2.command)) && !wasCommandInstalled(h2.command, installedHooks));
46111
+ if (filteredHooks.length === 0) {
46112
+ continue;
46113
+ }
46084
46114
  filteredEntry = { ...entry, hooks: filteredHooks };
46085
46115
  } else if ("command" in entry && wasCommandInstalled(entry.command, installedHooks)) {
46086
46116
  continue;
@@ -46091,16 +46121,12 @@ function mergeHookEntries(sourceEntries, destEntries, eventName, result, install
46091
46121
  if (sourceMatcher) {
46092
46122
  matcherIndex.set(sourceMatcher, merged.length - 1);
46093
46123
  }
46094
- for (const cmd of commands) {
46124
+ for (const cmd of newCommands) {
46095
46125
  const normalizedCmd = normalizeCommand(cmd);
46096
- if (!existingCommands.has(normalizedCmd) && !wasCommandInstalled(cmd, installedHooks)) {
46097
- existingCommands.add(normalizedCmd);
46098
- result.newlyInstalledHooks.push(cmd);
46099
- if (sourceKit) {
46100
- trackHookOrigin(result, sourceKit, cmd);
46101
- }
46102
- } else if (!existingCommands.has(normalizedCmd)) {
46103
- existingCommands.add(normalizedCmd);
46126
+ existingCommands.add(normalizedCmd);
46127
+ result.newlyInstalledHooks.push(cmd);
46128
+ if (sourceKit) {
46129
+ trackHookOrigin(result, sourceKit, cmd);
46104
46130
  }
46105
46131
  }
46106
46132
  }
@@ -48071,7 +48097,7 @@ var init_chokidar = __esm(() => {
48071
48097
  });
48072
48098
 
48073
48099
  // src/domains/web-server/file-watcher.ts
48074
- import { homedir as homedir13 } from "node:os";
48100
+ import { homedir as homedir12 } from "node:os";
48075
48101
  import { join as join25 } from "node:path";
48076
48102
 
48077
48103
  class FileWatcher {
@@ -48094,9 +48120,9 @@ class FileWatcher {
48094
48120
  }
48095
48121
  getWatchPaths() {
48096
48122
  const paths = [];
48097
- const globalDir = join25(homedir13(), ".claudekit");
48123
+ const globalDir = join25(homedir12(), ".claudekit");
48098
48124
  paths.push(join25(globalDir, "config.json"));
48099
- const globalKitDir = join25(homedir13(), ".claude");
48125
+ const globalKitDir = join25(homedir12(), ".claude");
48100
48126
  paths.push(join25(globalKitDir, ".ck.json"));
48101
48127
  paths.push(join25(globalKitDir, "settings.json"));
48102
48128
  paths.push(join25(globalKitDir, "settings.local.json"));
@@ -48146,8 +48172,8 @@ class FileWatcher {
48146
48172
  return path4.endsWith("config.json") || path4.endsWith(".ck.json") || path4.endsWith("settings.json") || path4.endsWith("settings.local.json");
48147
48173
  }
48148
48174
  getConfigScope(path4) {
48149
- const globalDir = join25(homedir13(), ".claudekit");
48150
- const globalKitDir = join25(homedir13(), ".claude");
48175
+ const globalDir = join25(homedir12(), ".claudekit");
48176
+ const globalKitDir = join25(homedir12(), ".claude");
48151
48177
  return path4.startsWith(globalDir) || path4.startsWith(globalKitDir) ? "global" : "local";
48152
48178
  }
48153
48179
  stop() {
@@ -48638,7 +48664,7 @@ var init_claudekit_data2 = __esm(() => {
48638
48664
  // src/domains/web-server/routes/action-routes.ts
48639
48665
  import { spawn, spawnSync } from "node:child_process";
48640
48666
  import { existsSync as existsSync14 } from "node:fs";
48641
- import { homedir as homedir14 } from "node:os";
48667
+ import { homedir as homedir13 } from "node:os";
48642
48668
  import { join as join27, resolve as resolve12, sep as sep5 } from "node:path";
48643
48669
  function getWindowsPaths(...relativePaths) {
48644
48670
  const roots = [
@@ -48915,7 +48941,7 @@ async function isActionPathAllowed(dirPath, projectId) {
48915
48941
  try {
48916
48942
  const encodedPath = projectId.slice("discovered-".length);
48917
48943
  const discoveredPath = resolve12(Buffer.from(encodedPath, "base64url").toString("utf-8"));
48918
- if (discoveredPath === dirPath && (isPathInsideBase(discoveredPath, process.cwd()) || isPathInsideBase(discoveredPath, homedir14()))) {
48944
+ if (discoveredPath === dirPath && (isPathInsideBase(discoveredPath, process.cwd()) || isPathInsideBase(discoveredPath, homedir13()))) {
48919
48945
  return true;
48920
48946
  }
48921
48947
  } catch {}
@@ -48927,7 +48953,7 @@ async function isActionPathAllowed(dirPath, projectId) {
48927
48953
  if (isPathInsideBase(dirPath, process.cwd())) {
48928
48954
  return true;
48929
48955
  }
48930
- return isPathInsideBase(dirPath, homedir14());
48956
+ return isPathInsideBase(dirPath, homedir13());
48931
48957
  }
48932
48958
  function buildSystemTerminalCommand(dirPath) {
48933
48959
  if (isMacOS()) {
@@ -49266,7 +49292,7 @@ var init_action_routes = __esm(() => {
49266
49292
  projectId: exports_external.string().min(1).max(256).optional()
49267
49293
  }).strict();
49268
49294
  WINDOWS_PATHS = {
49269
- localAppData: process.env.LOCALAPPDATA || join27(homedir14(), "AppData", "Local"),
49295
+ localAppData: process.env.LOCALAPPDATA || join27(homedir13(), "AppData", "Local"),
49270
49296
  programFiles: process.env.ProgramFiles || "C:\\Program Files",
49271
49297
  programFilesX86: process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)"
49272
49298
  };
@@ -49287,7 +49313,7 @@ var init_action_routes = __esm(() => {
49287
49313
  openMode: "open-directory",
49288
49314
  capabilities: ["open-directory", "run-command"],
49289
49315
  macAppName: "iTerm",
49290
- macAppPaths: ["/Applications/iTerm.app", join27(homedir14(), "Applications", "iTerm.app")]
49316
+ macAppPaths: ["/Applications/iTerm.app", join27(homedir13(), "Applications", "iTerm.app")]
49291
49317
  },
49292
49318
  {
49293
49319
  id: "warp",
@@ -49298,7 +49324,7 @@ var init_action_routes = __esm(() => {
49298
49324
  capabilities: ["open-directory", "uri-scheme"],
49299
49325
  commands: ["warp"],
49300
49326
  macAppName: "Warp",
49301
- macAppPaths: ["/Applications/Warp.app", join27(homedir14(), "Applications", "Warp.app")],
49327
+ macAppPaths: ["/Applications/Warp.app", join27(homedir13(), "Applications", "Warp.app")],
49302
49328
  windowsAppPaths: getWindowsPaths("Warp\\Warp.exe"),
49303
49329
  linuxAppPaths: ["/usr/bin/warp", "/usr/local/bin/warp"]
49304
49330
  },
@@ -49321,7 +49347,7 @@ var init_action_routes = __esm(() => {
49321
49347
  capabilities: ["open-directory"],
49322
49348
  commands: ["wezterm"],
49323
49349
  macAppName: "WezTerm",
49324
- macAppPaths: ["/Applications/WezTerm.app", join27(homedir14(), "Applications", "WezTerm.app")],
49350
+ macAppPaths: ["/Applications/WezTerm.app", join27(homedir13(), "Applications", "WezTerm.app")],
49325
49351
  windowsAppPaths: getWindowsPaths("WezTerm\\wezterm-gui.exe", "WezTerm\\wezterm.exe"),
49326
49352
  linuxAppPaths: ["/usr/bin/wezterm", "/usr/local/bin/wezterm"]
49327
49353
  },
@@ -49334,7 +49360,7 @@ var init_action_routes = __esm(() => {
49334
49360
  capabilities: ["open-directory"],
49335
49361
  commands: ["kitty"],
49336
49362
  macAppName: "kitty",
49337
- macAppPaths: ["/Applications/kitty.app", join27(homedir14(), "Applications", "kitty.app")],
49363
+ macAppPaths: ["/Applications/kitty.app", join27(homedir13(), "Applications", "kitty.app")],
49338
49364
  windowsAppPaths: getWindowsPaths("kitty\\kitty.exe"),
49339
49365
  linuxAppPaths: ["/usr/bin/kitty", "/usr/local/bin/kitty"]
49340
49366
  },
@@ -49347,7 +49373,7 @@ var init_action_routes = __esm(() => {
49347
49373
  capabilities: ["open-directory"],
49348
49374
  commands: ["alacritty"],
49349
49375
  macAppName: "Alacritty",
49350
- macAppPaths: ["/Applications/Alacritty.app", join27(homedir14(), "Applications", "Alacritty.app")],
49376
+ macAppPaths: ["/Applications/Alacritty.app", join27(homedir13(), "Applications", "Alacritty.app")],
49351
49377
  windowsAppPaths: getWindowsPaths("Alacritty\\alacritty.exe"),
49352
49378
  linuxAppPaths: ["/usr/bin/alacritty", "/usr/local/bin/alacritty"]
49353
49379
  },
@@ -49420,7 +49446,7 @@ var init_action_routes = __esm(() => {
49420
49446
  capabilities: ["open-app"],
49421
49447
  commands: ["termius"],
49422
49448
  macAppName: "Termius",
49423
- macAppPaths: ["/Applications/Termius.app", join27(homedir14(), "Applications", "Termius.app")],
49449
+ macAppPaths: ["/Applications/Termius.app", join27(homedir13(), "Applications", "Termius.app")],
49424
49450
  windowsAppPaths: getWindowsPaths("Termius\\Termius.exe"),
49425
49451
  linuxAppPaths: ["/usr/bin/termius"]
49426
49452
  },
@@ -49443,7 +49469,7 @@ var init_action_routes = __esm(() => {
49443
49469
  macAppName: "Visual Studio Code",
49444
49470
  macAppPaths: [
49445
49471
  "/Applications/Visual Studio Code.app",
49446
- join27(homedir14(), "Applications", "Visual Studio Code.app")
49472
+ join27(homedir13(), "Applications", "Visual Studio Code.app")
49447
49473
  ],
49448
49474
  windowsAppPaths: getWindowsPaths("Programs\\Microsoft VS Code\\Code.exe", "Microsoft VS Code\\Code.exe"),
49449
49475
  linuxAppPaths: ["/usr/bin/code", "/snap/bin/code"]
@@ -49457,7 +49483,7 @@ var init_action_routes = __esm(() => {
49457
49483
  capabilities: ["open-directory"],
49458
49484
  commands: ["cursor"],
49459
49485
  macAppName: "Cursor",
49460
- macAppPaths: ["/Applications/Cursor.app", join27(homedir14(), "Applications", "Cursor.app")],
49486
+ macAppPaths: ["/Applications/Cursor.app", join27(homedir13(), "Applications", "Cursor.app")],
49461
49487
  windowsAppPaths: getWindowsPaths("Programs\\Cursor\\Cursor.exe", "Cursor\\Cursor.exe"),
49462
49488
  linuxAppPaths: ["/usr/bin/cursor"]
49463
49489
  },
@@ -49470,7 +49496,7 @@ var init_action_routes = __esm(() => {
49470
49496
  capabilities: ["open-directory"],
49471
49497
  commands: ["windsurf"],
49472
49498
  macAppName: "Windsurf",
49473
- macAppPaths: ["/Applications/Windsurf.app", join27(homedir14(), "Applications", "Windsurf.app")],
49499
+ macAppPaths: ["/Applications/Windsurf.app", join27(homedir13(), "Applications", "Windsurf.app")],
49474
49500
  windowsAppPaths: getWindowsPaths("Programs\\Windsurf\\Windsurf.exe", "Windsurf\\Windsurf.exe"),
49475
49501
  linuxAppPaths: ["/usr/bin/windsurf"]
49476
49502
  },
@@ -49485,11 +49511,11 @@ var init_action_routes = __esm(() => {
49485
49511
  macAppName: "Antigravity",
49486
49512
  macAppPaths: [
49487
49513
  "/Applications/Antigravity.app",
49488
- join27(homedir14(), "Applications", "Antigravity.app")
49514
+ join27(homedir13(), "Applications", "Antigravity.app")
49489
49515
  ],
49490
49516
  windowsAppPaths: getWindowsPaths("Programs\\Antigravity\\Antigravity.exe"),
49491
49517
  linuxAppPaths: ["/usr/bin/antigravity"],
49492
- fallbackDetectionPaths: [join27(homedir14(), ".gemini", "antigravity")]
49518
+ fallbackDetectionPaths: [join27(homedir13(), ".gemini", "antigravity")]
49493
49519
  },
49494
49520
  {
49495
49521
  id: "zed",
@@ -49500,7 +49526,7 @@ var init_action_routes = __esm(() => {
49500
49526
  capabilities: ["open-directory"],
49501
49527
  commands: ["zed"],
49502
49528
  macAppName: "Zed",
49503
- macAppPaths: ["/Applications/Zed.app", join27(homedir14(), "Applications", "Zed.app")],
49529
+ macAppPaths: ["/Applications/Zed.app", join27(homedir13(), "Applications", "Zed.app")],
49504
49530
  windowsAppPaths: getWindowsPaths("Zed\\Zed.exe"),
49505
49531
  linuxAppPaths: ["/usr/bin/zed", "/usr/local/bin/zed"]
49506
49532
  },
@@ -49515,7 +49541,7 @@ var init_action_routes = __esm(() => {
49515
49541
  macAppName: "Sublime Text",
49516
49542
  macAppPaths: [
49517
49543
  "/Applications/Sublime Text.app",
49518
- join27(homedir14(), "Applications", "Sublime Text.app")
49544
+ join27(homedir13(), "Applications", "Sublime Text.app")
49519
49545
  ],
49520
49546
  windowsAppPaths: getWindowsPaths("Sublime Text\\sublime_text.exe"),
49521
49547
  linuxAppPaths: ["/usr/bin/subl", "/snap/bin/subl"]
@@ -49556,7 +49582,7 @@ var init_action_routes = __esm(() => {
49556
49582
 
49557
49583
  // src/domains/web-server/routes/agents-routes.ts
49558
49584
  import { readdir as readdir7 } from "node:fs/promises";
49559
- import { homedir as homedir15 } from "node:os";
49585
+ import { homedir as homedir14 } from "node:os";
49560
49586
  import { isAbsolute as isAbsolute4, join as join28, relative as relative7 } from "node:path";
49561
49587
  function resolveAgentDirs() {
49562
49588
  const dirs = [];
@@ -49601,7 +49627,7 @@ async function scanAgentDir(dirPath, dirLabel) {
49601
49627
  color: frontmatter.color || null,
49602
49628
  skillCount: countSkills(frontmatter.tools),
49603
49629
  dirLabel,
49604
- relativePath: relative7(homedir15(), filePath)
49630
+ relativePath: relative7(homedir14(), filePath)
49605
49631
  });
49606
49632
  } catch {}
49607
49633
  }
@@ -49645,7 +49671,7 @@ function registerAgentsBrowserRoutes(app) {
49645
49671
  color: frontmatter.color || null,
49646
49672
  skillCount: countSkills(frontmatter.tools),
49647
49673
  dirLabel: dir.label,
49648
- relativePath: relative7(homedir15(), filePath),
49674
+ relativePath: relative7(homedir14(), filePath),
49649
49675
  frontmatter,
49650
49676
  body
49651
49677
  };
@@ -49660,7 +49686,7 @@ var home2;
49660
49686
  var init_agents_routes = __esm(() => {
49661
49687
  init_frontmatter_parser();
49662
49688
  init_kit_layout();
49663
- home2 = homedir15();
49689
+ home2 = homedir14();
49664
49690
  });
49665
49691
 
49666
49692
  // src/schemas/ck-config.schema.json
@@ -50122,6 +50148,16 @@ var init_ck_config_schema = __esm(() => {
50122
50148
  default: true,
50123
50149
  description: "SubagentStart hook - injects context to subagents"
50124
50150
  },
50151
+ "session-state": {
50152
+ type: "boolean",
50153
+ default: true,
50154
+ description: "Stop/SubagentStop/PostToolUse hook - persists session state for handoff and statusline context"
50155
+ },
50156
+ "cook-after-plan-reminder": {
50157
+ type: "boolean",
50158
+ default: true,
50159
+ description: "SubagentStop hook - reminds agents to continue implementation after planning"
50160
+ },
50125
50161
  "descriptive-name": {
50126
50162
  type: "boolean",
50127
50163
  default: true,
@@ -50132,6 +50168,16 @@ var init_ck_config_schema = __esm(() => {
50132
50168
  default: true,
50133
50169
  description: "UserPromptSubmit hook - injects dev rules context"
50134
50170
  },
50171
+ "plan-format-kanban": {
50172
+ type: "boolean",
50173
+ default: true,
50174
+ description: "PostToolUse hook - keeps plan kanban metadata synchronized after edits"
50175
+ },
50176
+ "usage-quota-cache-refresh": {
50177
+ type: "boolean",
50178
+ default: true,
50179
+ description: "Lifecycle hook - refreshes cached usage quota information"
50180
+ },
50135
50181
  "usage-context-awareness": {
50136
50182
  type: "boolean",
50137
50183
  default: true,
@@ -50477,7 +50523,7 @@ var init_ck_config_routes = __esm(() => {
50477
50523
  // src/domains/web-server/routes/command-routes.ts
50478
50524
  import { existsSync as existsSync16 } from "node:fs";
50479
50525
  import { readFile as readFile12, readdir as readdir8 } from "node:fs/promises";
50480
- import { homedir as homedir16 } from "node:os";
50526
+ import { homedir as homedir15 } from "node:os";
50481
50527
  import { basename as basename9, isAbsolute as isAbsolute5, join as join30, relative as relative8, resolve as resolve13 } from "node:path";
50482
50528
  async function buildCommandTree(dir, baseDir) {
50483
50529
  let dirents;
@@ -50519,7 +50565,7 @@ async function buildCommandTree(dir, baseDir) {
50519
50565
  }
50520
50566
  function registerCommandRoutes(app) {
50521
50567
  app.get("/api/commands", async (_req, res) => {
50522
- const commandsDir = join30(homedir16(), ".claude", "commands");
50568
+ const commandsDir = join30(homedir15(), ".claude", "commands");
50523
50569
  if (!existsSync16(commandsDir)) {
50524
50570
  res.json({ tree: [] });
50525
50571
  return;
@@ -50542,7 +50588,7 @@ function registerCommandRoutes(app) {
50542
50588
  res.status(400).json({ error: "Invalid path" });
50543
50589
  return;
50544
50590
  }
50545
- const commandsDir = join30(homedir16(), ".claude", "commands");
50591
+ const commandsDir = join30(homedir15(), ".claude", "commands");
50546
50592
  const safePath = resolve13(commandsDir, rawPath);
50547
50593
  const rel = relative8(commandsDir, safePath);
50548
50594
  if (rel.startsWith("..") || isAbsolute5(rel)) {
@@ -50616,11 +50662,11 @@ var init_types5 = __esm(() => {
50616
50662
 
50617
50663
  // src/services/claude-data/history-parser.ts
50618
50664
  import { createReadStream, statSync as statSync4 } from "node:fs";
50619
- import { homedir as homedir17 } from "node:os";
50665
+ import { homedir as homedir16 } from "node:os";
50620
50666
  import { join as join31 } from "node:path";
50621
50667
  import { createInterface as createInterface2 } from "node:readline";
50622
50668
  function getHistoryPath() {
50623
- return process.env.CLAUDE_HISTORY_PATH ?? join31(homedir17(), ".claude", "history.jsonl");
50669
+ return process.env.CLAUDE_HISTORY_PATH ?? join31(homedir16(), ".claude", "history.jsonl");
50624
50670
  }
50625
50671
  function emptyResult(parseTimeMs, error) {
50626
50672
  return { projects: [], totalEntries: 0, errorCount: 0, parseTimeMs, error };
@@ -50818,10 +50864,10 @@ var init_session_parser = () => {};
50818
50864
  // src/services/claude-data/skill-scanner.ts
50819
50865
  import { existsSync as existsSync18 } from "node:fs";
50820
50866
  import { readFile as readFile14, readdir as readdir10, stat as stat6 } from "node:fs/promises";
50821
- import { homedir as homedir18 } from "node:os";
50867
+ import { homedir as homedir17 } from "node:os";
50822
50868
  import { join as join33 } from "node:path";
50823
50869
  async function getCkSkillMetadata(scope) {
50824
- const metaPath = scope === "global" ? join33(homedir18(), ".claude", "metadata.json") : join33(process.cwd(), ".claude", "metadata.json");
50870
+ const metaPath = scope === "global" ? join33(homedir17(), ".claude", "metadata.json") : join33(process.cwd(), ".claude", "metadata.json");
50825
50871
  if (!existsSync18(metaPath))
50826
50872
  return null;
50827
50873
  const result = new Map;
@@ -50951,14 +50997,14 @@ async function scanSkills() {
50951
50997
  var import_gray_matter4, skillsDir, SKIP_DIRS2;
50952
50998
  var init_skill_scanner = __esm(() => {
50953
50999
  import_gray_matter4 = __toESM(require_gray_matter(), 1);
50954
- skillsDir = join33(homedir18(), ".claude", "skills");
51000
+ skillsDir = join33(homedir17(), ".claude", "skills");
50955
51001
  SKIP_DIRS2 = [".venv", "scripts", "__pycache__", "node_modules", ".git", "common"];
50956
51002
  });
50957
51003
 
50958
51004
  // src/services/claude-data/settings-reader.ts
50959
51005
  import { existsSync as existsSync19 } from "node:fs";
50960
51006
  import { copyFile as copyFile2, mkdir as mkdir9, readFile as readFile15, rename as rename5, rm as rm4, writeFile as writeFile10 } from "node:fs/promises";
50961
- import { homedir as homedir19 } from "node:os";
51007
+ import { homedir as homedir18 } from "node:os";
50962
51008
  import { join as join34 } from "node:path";
50963
51009
  function getSettingsPath() {
50964
51010
  return join34(claudeDir, settingsFilename);
@@ -51020,7 +51066,7 @@ function countMcpServers(settings) {
51020
51066
  }
51021
51067
  var claudeDir, settingsFilename = "settings.json", settingsBackupDir;
51022
51068
  var init_settings_reader = __esm(() => {
51023
- claudeDir = join34(homedir19(), ".claude");
51069
+ claudeDir = join34(homedir18(), ".claude");
51024
51070
  settingsBackupDir = join34(claudeDir, ".ck-backups", "settings");
51025
51071
  });
51026
51072
 
@@ -51188,7 +51234,7 @@ var init_hook_log_reader = __esm(() => {
51188
51234
  });
51189
51235
 
51190
51236
  // src/services/claude-data/project-scanner.ts
51191
- import { homedir as homedir20 } from "node:os";
51237
+ import { homedir as homedir19 } from "node:os";
51192
51238
  import { basename as basename10, join as join36, normalize as normalize4 } from "node:path";
51193
51239
  function decodePath(encoded) {
51194
51240
  const decoded = encoded.replace(/^-/, "/").replace(/-/g, "/");
@@ -51203,7 +51249,7 @@ function encodePath(path4) {
51203
51249
  }
51204
51250
  var projectsDir;
51205
51251
  var init_project_scanner = __esm(() => {
51206
- projectsDir = join36(homedir20(), ".claude", "projects");
51252
+ projectsDir = join36(homedir19(), ".claude", "projects");
51207
51253
  });
51208
51254
 
51209
51255
  // src/services/claude-data/project-discovery.ts
@@ -51298,10 +51344,10 @@ var init_project_discovery = __esm(() => {
51298
51344
 
51299
51345
  // src/services/claude-data/user-preferences.ts
51300
51346
  import { readFile as readFile16, stat as stat7 } from "node:fs/promises";
51301
- import { homedir as homedir21 } from "node:os";
51347
+ import { homedir as homedir20 } from "node:os";
51302
51348
  import { join as join37 } from "node:path";
51303
51349
  function getPreferencesPath() {
51304
- return join37(homedir21(), ".claude.json");
51350
+ return join37(homedir20(), ".claude.json");
51305
51351
  }
51306
51352
  async function readUserPreferences(filePath) {
51307
51353
  const path4 = filePath ?? getPreferencesPath();
@@ -51392,7 +51438,7 @@ var init_claude_data = __esm(() => {
51392
51438
  // src/domains/web-server/routes/dashboard-routes.ts
51393
51439
  import { existsSync as existsSync20 } from "node:fs";
51394
51440
  import { readFile as readFile17, readdir as readdir11 } from "node:fs/promises";
51395
- import { homedir as homedir22 } from "node:os";
51441
+ import { homedir as homedir21 } from "node:os";
51396
51442
  import { join as join38 } from "node:path";
51397
51443
  async function readAgents() {
51398
51444
  const agentsDir = join38(claudeDir2, "agents");
@@ -51462,7 +51508,7 @@ async function countAllMcpServers() {
51462
51508
  }
51463
51509
  let claudeJsonCount = 0;
51464
51510
  try {
51465
- const claudeJsonPath = join38(homedir22(), ".claude.json");
51511
+ const claudeJsonPath = join38(homedir21(), ".claude.json");
51466
51512
  if (existsSync20(claudeJsonPath)) {
51467
51513
  const content = await readFile17(claudeJsonPath, "utf-8");
51468
51514
  const data = JSON.parse(content);
@@ -51589,7 +51635,7 @@ var claudeDir2;
51589
51635
  var init_dashboard_routes = __esm(() => {
51590
51636
  init_frontmatter_parser();
51591
51637
  init_claude_data();
51592
- claudeDir2 = join38(homedir22(), ".claude");
51638
+ claudeDir2 = join38(homedir21(), ".claude");
51593
51639
  });
51594
51640
 
51595
51641
  // src/domains/web-server/routes/health-routes.ts
@@ -51663,7 +51709,7 @@ var init_hook_log_routes = __esm(() => {
51663
51709
  // src/domains/web-server/routes/mcp-routes.ts
51664
51710
  import { existsSync as existsSync21 } from "node:fs";
51665
51711
  import { readFile as readFile18 } from "node:fs/promises";
51666
- import { homedir as homedir23 } from "node:os";
51712
+ import { homedir as homedir22 } from "node:os";
51667
51713
  import { basename as basename12, join as join39, resolve as resolve14 } from "node:path";
51668
51714
  function parseMcpServers(raw, source, sourceLabel) {
51669
51715
  const entries = [];
@@ -51712,7 +51758,7 @@ function mergeServers(lists) {
51712
51758
  function isSafeProjectPath(projectPath) {
51713
51759
  if (projectPath.includes(".."))
51714
51760
  return false;
51715
- const home3 = homedir23();
51761
+ const home3 = homedir22();
51716
51762
  try {
51717
51763
  const resolved = resolve14(projectPath);
51718
51764
  if (!resolved.startsWith(home3))
@@ -51725,7 +51771,7 @@ function isSafeProjectPath(projectPath) {
51725
51771
  function registerMcpRoutes(app) {
51726
51772
  app.get("/api/mcp-servers", async (_req, res) => {
51727
51773
  try {
51728
- const claudeDir3 = join39(homedir23(), ".claude");
51774
+ const claudeDir3 = join39(homedir22(), ".claude");
51729
51775
  const allLists = [];
51730
51776
  try {
51731
51777
  const settings = await readSettings();
@@ -51735,7 +51781,7 @@ function registerMcpRoutes(app) {
51735
51781
  }
51736
51782
  } catch {}
51737
51783
  try {
51738
- const claudeJsonPath = join39(homedir23(), ".claude.json");
51784
+ const claudeJsonPath = join39(homedir22(), ".claude.json");
51739
51785
  if (existsSync21(claudeJsonPath)) {
51740
51786
  const content = await readFile18(claudeJsonPath, "utf-8");
51741
51787
  const parsed = JSON.parse(content);
@@ -51996,7 +52042,7 @@ var init_skill_directory_installer = __esm(() => {
51996
52042
  // src/commands/portable/config-discovery.ts
51997
52043
  import { existsSync as existsSync23, readFileSync as readFileSync6 } from "node:fs";
51998
52044
  import { cp as cp2, mkdir as mkdir11, readFile as readFile19, readdir as readdir12, stat as stat8 } from "node:fs/promises";
51999
- import { homedir as homedir24 } from "node:os";
52045
+ import { homedir as homedir23 } from "node:os";
52000
52046
  import { basename as basename13, dirname as dirname12, extname as extname3, join as join41, relative as relative9, resolve as resolve16, sep as sep6 } from "node:path";
52001
52047
  async function copyHooksCompanionDirs(sourceDir, targetDir) {
52002
52048
  const result = {
@@ -52079,7 +52125,7 @@ async function copyHooksCompanionDirs(sourceDir, targetDir) {
52079
52125
  function resolveSourceOrigin(sourcePath) {
52080
52126
  if (!sourcePath)
52081
52127
  return "global";
52082
- const home3 = homedir24();
52128
+ const home3 = homedir23();
52083
52129
  const cwd2 = process.cwd();
52084
52130
  if (cwd2 === home3)
52085
52131
  return "global";
@@ -52094,16 +52140,16 @@ function getConfigSourcePath(globalOnly = false) {
52094
52140
  return findExistingProjectConfigPath(process.cwd()) ?? getGlobalConfigSourcePath();
52095
52141
  }
52096
52142
  function getGlobalConfigSourcePath() {
52097
- return join41(homedir24(), ".claude", "CLAUDE.md");
52143
+ return join41(homedir23(), ".claude", "CLAUDE.md");
52098
52144
  }
52099
52145
  function getRulesSourcePath(globalOnly = false) {
52100
- const globalPath = join41(homedir24(), ".claude", "rules");
52146
+ const globalPath = join41(homedir23(), ".claude", "rules");
52101
52147
  if (globalOnly)
52102
52148
  return globalPath;
52103
52149
  return findExistingProjectLayoutPath(process.cwd(), "rules") ?? globalPath;
52104
52150
  }
52105
52151
  function getHooksSourcePath(globalOnly = false) {
52106
- const globalPath = join41(homedir24(), ".claude", "hooks");
52152
+ const globalPath = join41(homedir23(), ".claude", "hooks");
52107
52153
  if (globalOnly)
52108
52154
  return globalPath;
52109
52155
  return findExistingProjectLayoutPath(process.cwd(), "hooks") ?? globalPath;
@@ -54292,7 +54338,7 @@ var init_codex_capabilities = __esm(() => {
54292
54338
  // src/commands/portable/codex-path-safety.ts
54293
54339
  import { existsSync as existsSync24 } from "node:fs";
54294
54340
  import { mkdir as mkdir12, realpath as realpath7 } from "node:fs/promises";
54295
- import { homedir as homedir25 } from "node:os";
54341
+ import { homedir as homedir24 } from "node:os";
54296
54342
  import { dirname as dirname13, join as join42, resolve as resolve17, sep as sep7 } from "node:path";
54297
54343
  function isPathWithinBoundary3(targetPath, boundaryPath) {
54298
54344
  const resolvedTarget = resolve17(targetPath);
@@ -54339,7 +54385,7 @@ async function withCodexTargetLock2(targetFilePath, operation) {
54339
54385
  }
54340
54386
  }
54341
54387
  function getCodexGlobalBoundary() {
54342
- return join42(homedir25(), ".codex");
54388
+ return join42(homedir24(), ".codex");
54343
54389
  }
54344
54390
  var import_proper_lockfile6;
54345
54391
  var init_codex_path_safety = __esm(() => {
@@ -54734,7 +54780,7 @@ var init_codex_hook_wrapper = __esm(() => {
54734
54780
  });
54735
54781
 
54736
54782
  // src/commands/portable/converters/claude-to-codex-hooks.ts
54737
- import { homedir as homedir26 } from "node:os";
54783
+ import { homedir as homedir25 } from "node:os";
54738
54784
  function convertClaudeHooksToCodex(sourceHooks, capabilities, pathRewrite) {
54739
54785
  const result = {};
54740
54786
  for (const [event, groups] of Object.entries(sourceHooks)) {
@@ -54792,7 +54838,7 @@ function rewriteCommandPath(command, pathRewrite) {
54792
54838
  const normalizeSlashes = (s) => s.replace(/\\/g, "/");
54793
54839
  let rewritten = command;
54794
54840
  if (pathRewrite.commandSubstitutions && pathRewrite.commandSubstitutions.size > 0) {
54795
- const home3 = homedir26();
54841
+ const home3 = homedir25();
54796
54842
  const homeForward = normalizeSlashes(home3);
54797
54843
  for (const [originalAbsPath, wrapperAbsPath] of pathRewrite.commandSubstitutions) {
54798
54844
  const originalAbsForward = normalizeSlashes(originalAbsPath);
@@ -54895,7 +54941,7 @@ var init_gemini_hook_event_map = __esm(() => {
54895
54941
  // src/commands/portable/hooks-settings-merger.ts
54896
54942
  import { existsSync as existsSync26 } from "node:fs";
54897
54943
  import { mkdir as mkdir13, readFile as readFile21, rename as rename8, rm as rm6, writeFile as writeFile12 } from "node:fs/promises";
54898
- import { homedir as homedir27 } from "node:os";
54944
+ import { homedir as homedir26 } from "node:os";
54899
54945
  import { basename as basename14, dirname as dirname16, extname as extname4, join as join44, resolve as resolve20 } from "node:path";
54900
54946
  function isCodexWrappableHookPath(filePath) {
54901
54947
  return hookAssetBasename(filePath) !== "node-hook-runner.sh" && CODEX_WRAPPABLE_HOOK_EXTENSIONS.has(extname4(filePath).toLowerCase());
@@ -54978,7 +55024,7 @@ function normalizeDirPattern(value) {
54978
55024
  }
54979
55025
  function homeRelativeDir(value) {
54980
55026
  const normalized = normalizeDirPattern(value);
54981
- const home3 = normalizeDirPattern(homedir27());
55027
+ const home3 = normalizeDirPattern(homedir26());
54982
55028
  return normalized.startsWith(`${home3}/`) ? normalized.slice(home3.length + 1) : normalized;
54983
55029
  }
54984
55030
  function buildHookDirRewritePairs(sourceHooksDir, targetHooksDir) {
@@ -55535,7 +55581,7 @@ async function migrateHooksSettingsForCodex(options2) {
55535
55581
  }
55536
55582
  let featureFlagWritten = false;
55537
55583
  if (capabilities.requiresFeatureFlag) {
55538
- const configTomlPath = isGlobal ? join44(homedir27(), ".codex", "config.toml") : join44(process.cwd(), ".codex", "config.toml");
55584
+ const configTomlPath = isGlobal ? join44(homedir26(), ".codex", "config.toml") : join44(process.cwd(), ".codex", "config.toml");
55539
55585
  const flagResult = await ensureCodexHooksFeatureFlag(configTomlPath, isGlobal);
55540
55586
  featureFlagWritten = flagResult.status === "written" || flagResult.status === "updated";
55541
55587
  }
@@ -56940,10 +56986,10 @@ __export(exports_skills_discovery, {
56940
56986
  discoverSkills: () => discoverSkills
56941
56987
  });
56942
56988
  import { readFile as readFile25, readdir as readdir13, stat as stat9 } from "node:fs/promises";
56943
- import { homedir as homedir28 } from "node:os";
56989
+ import { homedir as homedir27 } from "node:os";
56944
56990
  import { dirname as dirname17, join as join45 } from "node:path";
56945
56991
  function getSkillSourcePath(globalOnly = false) {
56946
- const globalPath = join45(homedir28(), ".claude/skills");
56992
+ const globalPath = join45(homedir27(), ".claude/skills");
56947
56993
  if (globalOnly) {
56948
56994
  return findFirstExistingPath([globalPath]);
56949
56995
  }
@@ -57184,7 +57230,7 @@ var init_migration_result_utils = __esm(() => {
57184
57230
  // src/domains/web-server/routes/migration-routes.ts
57185
57231
  import { existsSync as existsSync30 } from "node:fs";
57186
57232
  import { readFile as readFile26, rm as rm8 } from "node:fs/promises";
57187
- import { homedir as homedir29 } from "node:os";
57233
+ import { homedir as homedir28 } from "node:os";
57188
57234
  import { basename as basename17, join as join46, resolve as resolve23 } from "node:path";
57189
57235
  function resolveRegistryDeps(deps) {
57190
57236
  return {
@@ -57863,7 +57909,7 @@ function registerMigrationRoutes(app, deps) {
57863
57909
  };
57864
57910
  const discovered = await discoverMigrationItems(includeAll);
57865
57911
  const cwd2 = process.cwd();
57866
- const home3 = homedir29();
57912
+ const home3 = homedir28();
57867
57913
  res.status(200).json({
57868
57914
  cwd: cwd2,
57869
57915
  targetPaths: {
@@ -59379,7 +59425,7 @@ function scanPlanDir(dir) {
59379
59425
  var init_plan_scanner = () => {};
59380
59426
 
59381
59427
  // src/domains/plan-parser/plan-scope.ts
59382
- import { homedir as homedir30 } from "node:os";
59428
+ import { homedir as homedir29 } from "node:os";
59383
59429
  import { isAbsolute as isAbsolute8, join as join49, relative as relative12, resolve as resolve25 } from "node:path";
59384
59430
  function resolveConfiguredDir(configuredPath, baseDir) {
59385
59431
  const trimmed = configuredPath?.trim();
@@ -59392,7 +59438,7 @@ function resolveProjectPlansDir(projectRoot, config) {
59392
59438
  return resolveConfiguredDir(config?.paths?.plans, projectRoot);
59393
59439
  }
59394
59440
  function resolveGlobalPlansDir(config) {
59395
- return resolveConfiguredDir(config?.paths?.globalPlans, join49(homedir30(), ".claude"));
59441
+ return resolveConfiguredDir(config?.paths?.globalPlans, join49(homedir29(), ".claude"));
59396
59442
  }
59397
59443
  function resolvePlanDirForScope(scope, projectRoot, config) {
59398
59444
  return scope === "global" ? resolveGlobalPlansDir(config) : resolveProjectPlansDir(projectRoot, config);
@@ -60664,7 +60710,7 @@ var init_p_limit = __esm(() => {
60664
60710
 
60665
60711
  // src/domains/web-server/routes/plan-routes.ts
60666
60712
  import { existsSync as existsSync36, readFileSync as readFileSync12, realpathSync as realpathSync2 } from "node:fs";
60667
- import { homedir as homedir31 } from "node:os";
60713
+ import { homedir as homedir30 } from "node:os";
60668
60714
  import { basename as basename20, dirname as dirname24, join as join54, relative as relative14, resolve as resolve27, sep as sep8 } from "node:path";
60669
60715
  function sanitizeError(err) {
60670
60716
  if (err instanceof Error) {
@@ -60855,7 +60901,7 @@ function withTimeout(promiseFactory, timeoutMs, label) {
60855
60901
  function isCurrentProjectFallbackCandidate(currentPath, globalProjectKey) {
60856
60902
  if (toProjectPathKey(currentPath) === globalProjectKey)
60857
60903
  return false;
60858
- if (toProjectPathKey(currentPath) === toProjectPathKey(homedir31()))
60904
+ if (toProjectPathKey(currentPath) === toProjectPathKey(homedir30()))
60859
60905
  return false;
60860
60906
  return existsSync36(join54(currentPath, ".git")) || existsSync36(CkConfigManager.getProjectConfigPath(currentPath)) || existsSync36(join54(currentPath, "plans"));
60861
60907
  }
@@ -60920,7 +60966,7 @@ function registerPlanRoutes(app) {
60920
60966
  });
60921
60967
  app.get("/api/plan/list-all", async (_req, res) => {
60922
60968
  try {
60923
- const globalProjectKey = toProjectPathKey(join54(homedir31(), ".claude"));
60969
+ const globalProjectKey = toProjectPathKey(join54(homedir30(), ".claude"));
60924
60970
  const seenProjectKeys = new Set;
60925
60971
  const scanTargets = [];
60926
60972
  for (const project of await ProjectsRegistryManager.listProjects()) {
@@ -61167,7 +61213,7 @@ var init_project_plan_data = __esm(() => {
61167
61213
  // src/domains/web-server/routes/project-routes.ts
61168
61214
  import { existsSync as existsSync37 } from "node:fs";
61169
61215
  import { readFile as readFile27 } from "node:fs/promises";
61170
- import { homedir as homedir32 } from "node:os";
61216
+ import { homedir as homedir31 } from "node:os";
61171
61217
  import { basename as basename21, join as join55, resolve as resolve28 } from "node:path";
61172
61218
  function registerProjectRoutes(app) {
61173
61219
  app.get("/api/projects", async (req, res) => {
@@ -61188,7 +61234,7 @@ function registerProjectRoutes(app) {
61188
61234
  for (const discovered of discoveredProjects) {
61189
61235
  if (registeredPaths.has(discovered.path))
61190
61236
  continue;
61191
- if (discovered.path === join55(homedir32(), ".claude"))
61237
+ if (discovered.path === join55(homedir31(), ".claude"))
61192
61238
  continue;
61193
61239
  const projectInfo = await detectAndBuildProjectInfo(discovered.path, `discovered-${discovered.path}`, cachedSettings, cachedSkills, false);
61194
61240
  if (projectInfo) {
@@ -61204,7 +61250,7 @@ function registerProjectRoutes(app) {
61204
61250
  if (cwdProject) {
61205
61251
  projects.push(cwdProject);
61206
61252
  }
61207
- const globalDir = join55(homedir32(), ".claude");
61253
+ const globalDir = join55(homedir31(), ".claude");
61208
61254
  const globalProject = await detectAndBuildProjectInfo(globalDir, "global", undefined, undefined, false);
61209
61255
  if (globalProject) {
61210
61256
  projects.push(globalProject);
@@ -61276,12 +61322,12 @@ function registerProjectRoutes(app) {
61276
61322
  const body = validation.data;
61277
61323
  let projectPath = body.path;
61278
61324
  if (projectPath.startsWith("~/") || projectPath === "~") {
61279
- projectPath = join55(homedir32(), projectPath.slice(1));
61325
+ projectPath = join55(homedir31(), projectPath.slice(1));
61280
61326
  } else if (projectPath.startsWith("~\\")) {
61281
- projectPath = join55(homedir32(), projectPath.slice(1));
61327
+ projectPath = join55(homedir31(), projectPath.slice(1));
61282
61328
  }
61283
61329
  projectPath = resolve28(projectPath);
61284
- const homeDir = homedir32();
61330
+ const homeDir = homedir31();
61285
61331
  if (projectPath.includes("..") || !projectPath.startsWith(homeDir)) {
61286
61332
  res.status(400).json({ error: "Invalid path after expansion" });
61287
61333
  return;
@@ -61338,7 +61384,7 @@ function registerProjectRoutes(app) {
61338
61384
  if (id === "current") {
61339
61385
  projectPath = process.cwd();
61340
61386
  } else if (id === "global") {
61341
- projectPath = join55(homedir32(), ".claude");
61387
+ projectPath = join55(homedir31(), ".claude");
61342
61388
  } else {
61343
61389
  res.status(404).json({ error: "Project not found" });
61344
61390
  return;
@@ -61418,7 +61464,7 @@ async function buildProjectInfoFromRegistry(registered, cachedSettings, cachedSk
61418
61464
  const hasLocalConfig = hasClaudeDir && CkConfigManager.projectConfigExists(registered.path, false);
61419
61465
  const settings = cachedSettings !== undefined ? cachedSettings : await readSettings();
61420
61466
  const skills = cachedSkills !== undefined ? cachedSkills : await scanSkills();
61421
- const settingsPath = join55(homedir32(), ".claude", "settings.json");
61467
+ const settingsPath = join55(homedir31(), ".claude", "settings.json");
61422
61468
  const health = existsSync37(settingsPath) ? "healthy" : "warning";
61423
61469
  const model = getCurrentModel() || settings?.model || "claude-sonnet-4";
61424
61470
  const planData = includePlanData ? await buildProjectPlanData(registered.path, "project") : null;
@@ -61460,7 +61506,7 @@ async function detectAndBuildProjectInfo(path6, id, cachedSettings, cachedSkills
61460
61506
  const hasLocalConfig = CkConfigManager.projectConfigExists(path6, id === "global");
61461
61507
  const settings = cachedSettings !== undefined ? cachedSettings : await readSettings();
61462
61508
  const skills = cachedSkills !== undefined ? cachedSkills : await scanSkills();
61463
- const settingsPath = join55(homedir32(), ".claude", "settings.json");
61509
+ const settingsPath = join55(homedir31(), ".claude", "settings.json");
61464
61510
  const health = existsSync37(settingsPath) ? "healthy" : "warning";
61465
61511
  const model = getCurrentModel() || settings?.model || "claude-sonnet-4";
61466
61512
  const scope = id === "global" ? "global" : "project";
@@ -61508,7 +61554,7 @@ var init_project_routes = __esm(() => {
61508
61554
  // src/domains/web-server/routes/session-routes.ts
61509
61555
  import { existsSync as existsSync38 } from "node:fs";
61510
61556
  import { readFile as readFile28, readdir as readdir14, stat as stat10 } from "node:fs/promises";
61511
- import { homedir as homedir33 } from "node:os";
61557
+ import { homedir as homedir32 } from "node:os";
61512
61558
  import { basename as basename22, join as join56 } from "node:path";
61513
61559
  function toDateStr(d3) {
61514
61560
  const y3 = d3.getFullYear();
@@ -61517,7 +61563,7 @@ function toDateStr(d3) {
61517
61563
  return `${y3}-${m2}-${day}`;
61518
61564
  }
61519
61565
  async function scanActivityMetrics(periodDays) {
61520
- const home3 = homedir33();
61566
+ const home3 = homedir32();
61521
61567
  const projectsDir2 = join56(home3, ".claude", "projects");
61522
61568
  const cutoff = new Date;
61523
61569
  cutoff.setDate(cutoff.getDate() - periodDays);
@@ -61588,7 +61634,7 @@ async function scanActivityMetrics(periodDays) {
61588
61634
  return { totalSessions, projects: projectActivities, dailyCounts };
61589
61635
  }
61590
61636
  async function resolveSessionDir(projectId) {
61591
- const home3 = homedir33();
61637
+ const home3 = homedir32();
61592
61638
  if (projectId.startsWith("discovered-")) {
61593
61639
  try {
61594
61640
  const encodedPathB64 = projectId.slice("discovered-".length);
@@ -61762,7 +61808,7 @@ async function parseSessionDetail(filePath, limit, offset) {
61762
61808
  }
61763
61809
  function registerSessionRoutes(app) {
61764
61810
  app.get("/api/sessions", async (_req, res) => {
61765
- const home3 = homedir33();
61811
+ const home3 = homedir32();
61766
61812
  const projectsDir2 = join56(home3, ".claude", "projects");
61767
61813
  if (!existsSync38(projectsDir2)) {
61768
61814
  res.json({ projects: [] });
@@ -61831,7 +61877,7 @@ function registerSessionRoutes(app) {
61831
61877
  res.status(404).json({ error: "Project not found" });
61832
61878
  return;
61833
61879
  }
61834
- const allowedBase = join56(homedir33(), ".claude", "projects");
61880
+ const allowedBase = join56(homedir32(), ".claude", "projects");
61835
61881
  if (!projectDir.startsWith(allowedBase)) {
61836
61882
  res.status(403).json({ error: "Access denied" });
61837
61883
  return;
@@ -61861,7 +61907,7 @@ function registerSessionRoutes(app) {
61861
61907
  res.status(404).json({ error: "Project not found" });
61862
61908
  return;
61863
61909
  }
61864
- const allowedBase = join56(homedir33(), ".claude", "projects");
61910
+ const allowedBase = join56(homedir32(), ".claude", "projects");
61865
61911
  if (!projectDir.startsWith(allowedBase)) {
61866
61912
  res.status(403).json({ error: "Access denied" });
61867
61913
  return;
@@ -61895,7 +61941,7 @@ var init_session_routes = __esm(() => {
61895
61941
  });
61896
61942
 
61897
61943
  // src/domains/web-server/routes/settings-routes.ts
61898
- import { homedir as homedir34 } from "node:os";
61944
+ import { homedir as homedir33 } from "node:os";
61899
61945
  function registerSettingsRoutes(app) {
61900
61946
  app.get("/api/settings", async (_req, res) => {
61901
61947
  try {
@@ -61951,7 +61997,7 @@ function registerSettingsRoutes(app) {
61951
61997
  res.json({
61952
61998
  success: true,
61953
61999
  path: "~/.claude/settings.json",
61954
- backupPath: saveResult.backupPath ? saveResult.backupPath.replace(homedir34(), "~") : null,
62000
+ backupPath: saveResult.backupPath ? saveResult.backupPath.replace(homedir33(), "~") : null,
61955
62001
  absolutePath: getSettingsPath()
61956
62002
  });
61957
62003
  } catch (error) {
@@ -61985,7 +62031,7 @@ var init_settings_routes = __esm(() => {
61985
62031
 
61986
62032
  // src/domains/skills/skill-catalog-generator.ts
61987
62033
  import { mkdir as mkdir14, readFile as readFile29, readdir as readdir15, rename as rename10, stat as stat11, writeFile as writeFile14 } from "node:fs/promises";
61988
- import { homedir as homedir35 } from "node:os";
62034
+ import { homedir as homedir34 } from "node:os";
61989
62035
  import { dirname as dirname25, join as join57, relative as relative15 } from "node:path";
61990
62036
  async function hasScripts(skillPath) {
61991
62037
  try {
@@ -62128,7 +62174,7 @@ var CATALOG_PATH, CATALOG_VERSION = "1.0.0", SKIP_DIRS4, skillCatalogGenerator;
62128
62174
  var init_skill_catalog_generator = __esm(() => {
62129
62175
  init_skills_discovery();
62130
62176
  init_logger();
62131
- CATALOG_PATH = join57(homedir35(), ".claude", ".skills-catalog.json");
62177
+ CATALOG_PATH = join57(homedir34(), ".claude", ".skills-catalog.json");
62132
62178
  SKIP_DIRS4 = [".venv", "__pycache__", "node_modules", ".git"];
62133
62179
  skillCatalogGenerator = new SkillCatalogGenerator;
62134
62180
  });
@@ -62418,7 +62464,7 @@ var init_skill_browser_routes = __esm(() => {
62418
62464
 
62419
62465
  // src/commands/skills/agents.ts
62420
62466
  import { existsSync as existsSync39, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
62421
- import { homedir as homedir37, platform as platform5 } from "node:os";
62467
+ import { homedir as homedir36, platform as platform5 } from "node:os";
62422
62468
  import { join as join59 } from "node:path";
62423
62469
  function hasInstallSignal2(path7) {
62424
62470
  if (!path7 || !existsSync39(path7)) {
@@ -62475,7 +62521,7 @@ function isSkillInstalled(skillName, agent, options2) {
62475
62521
  }
62476
62522
  var home3, OPENCODE_BINARY_NAME2, agents;
62477
62523
  var init_agents = __esm(() => {
62478
- home3 = homedir37();
62524
+ home3 = homedir36();
62479
62525
  OPENCODE_BINARY_NAME2 = platform5() === "win32" ? "opencode.exe" : "opencode";
62480
62526
  agents = {
62481
62527
  "claude-code": {
@@ -62582,7 +62628,7 @@ var init_agents = __esm(() => {
62582
62628
  // src/commands/skills/skills-registry.ts
62583
62629
  import { existsSync as existsSync40 } from "node:fs";
62584
62630
  import { mkdir as mkdir15, readFile as readFile31, writeFile as writeFile15 } from "node:fs/promises";
62585
- import { homedir as homedir38 } from "node:os";
62631
+ import { homedir as homedir37 } from "node:os";
62586
62632
  import { dirname as dirname26, join as join60, sep as sep10 } from "node:path";
62587
62633
  function getCliVersion3() {
62588
62634
  try {
@@ -62694,7 +62740,7 @@ async function syncRegistry() {
62694
62740
  var home4, REGISTRY_PATH, SkillInstallationSchema, SkillRegistrySchema, REGISTRY_PATH_MIGRATIONS;
62695
62741
  var init_skills_registry = __esm(() => {
62696
62742
  init_zod();
62697
- home4 = homedir38();
62743
+ home4 = homedir37();
62698
62744
  REGISTRY_PATH = join60(home4, ".claudekit", "skill-registry.json");
62699
62745
  SkillInstallationSchema = exports_external.object({
62700
62746
  skill: exports_external.string(),
@@ -62726,7 +62772,7 @@ var init_skills_registry = __esm(() => {
62726
62772
  // src/commands/skills/skills-installer.ts
62727
62773
  import { existsSync as existsSync41 } from "node:fs";
62728
62774
  import { cp as cp3, mkdir as mkdir16, rm as rm9, stat as stat12 } from "node:fs/promises";
62729
- import { homedir as homedir39 } from "node:os";
62775
+ import { homedir as homedir38 } from "node:os";
62730
62776
  import { dirname as dirname27, join as join61, resolve as resolve30 } from "node:path";
62731
62777
  function isSamePath2(path1, path22) {
62732
62778
  try {
@@ -62857,7 +62903,7 @@ var init_skills_installer = __esm(() => {
62857
62903
  LEGACY_SKILL_PATHS = {
62858
62904
  "gemini-cli": {
62859
62905
  project: ".gemini/skills",
62860
- global: join61(homedir39(), ".gemini/skills")
62906
+ global: join61(homedir38(), ".gemini/skills")
62861
62907
  }
62862
62908
  };
62863
62909
  });
@@ -63806,7 +63852,7 @@ var package_default;
63806
63852
  var init_package = __esm(() => {
63807
63853
  package_default = {
63808
63854
  name: "claudekit-cli",
63809
- version: "4.3.1-dev.16",
63855
+ version: "4.3.1-dev.18",
63810
63856
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
63811
63857
  type: "module",
63812
63858
  repository: {
@@ -64288,10 +64334,11 @@ var init_package_manager_runner = __esm(() => {
64288
64334
 
64289
64335
  // src/domains/installation/merger/zombie-wirings-pruner.ts
64290
64336
  import { existsSync as existsSync44, readdirSync as readdirSync7 } from "node:fs";
64291
- import { homedir as homedir40 } from "node:os";
64337
+ import { homedir as homedir39 } from "node:os";
64292
64338
  import { basename as basename23, dirname as dirname28, isAbsolute as isAbsolute10, resolve as resolve32, sep as sep11 } from "node:path";
64293
- function pruneZombieEngineerWirings(settings, hookDir) {
64339
+ function pruneZombieEngineerWirings(settings, hookDir, preserveCommands = new Set) {
64294
64340
  const pruned = [];
64341
+ const normalizedPreserveCommands = new Set(Array.from(preserveCommands).map((command) => normalizeCommand(command)));
64295
64342
  if (!existsSync44(hookDir)) {
64296
64343
  return { settings, pruned };
64297
64344
  }
@@ -64311,14 +64358,14 @@ function pruneZombieEngineerWirings(settings, hookDir) {
64311
64358
  for (const group of groups) {
64312
64359
  if (!("hooks" in group) || !Array.isArray(group.hooks)) {
64313
64360
  const entry = group;
64314
- if (shouldPruneEntry(entry, hookDir, pruned)) {
64361
+ if (shouldPruneEntry(entry, hookDir, pruned, normalizedPreserveCommands)) {
64315
64362
  continue;
64316
64363
  }
64317
64364
  keptGroups.push(group);
64318
64365
  continue;
64319
64366
  }
64320
64367
  const keptHooks = group.hooks.filter((h2) => {
64321
- return !shouldPruneEntry(h2, hookDir, pruned);
64368
+ return !shouldPruneEntry(h2, hookDir, pruned, normalizedPreserveCommands);
64322
64369
  });
64323
64370
  if (keptHooks.length > 0) {
64324
64371
  keptGroups.push({ ...group, hooks: keptHooks });
@@ -64335,13 +64382,16 @@ function pruneZombieEngineerWirings(settings, hookDir) {
64335
64382
  }
64336
64383
  return { settings, pruned };
64337
64384
  }
64338
- function shouldPruneEntry(entry, hookDir, pruned) {
64385
+ function shouldPruneEntry(entry, hookDir, pruned, preserveCommands) {
64339
64386
  if (isLegacyDescriptiveNamePrompt(entry)) {
64340
64387
  pruned.push("legacy-descriptive-name-prompt");
64341
64388
  return true;
64342
64389
  }
64343
64390
  if (entry._origin !== "engineer")
64344
64391
  return false;
64392
+ if (entry.command && preserveCommands.has(normalizeCommand(entry.command))) {
64393
+ return false;
64394
+ }
64345
64395
  const filePath = extractHookFilePath(entry.command, hookDir);
64346
64396
  if (!filePath)
64347
64397
  return false;
@@ -64364,7 +64414,7 @@ function extractHookFilePath(command, hookDir) {
64364
64414
  return null;
64365
64415
  if (/&&|\|\||;|(?<!["|'])\|(?!["|'])/.test(command))
64366
64416
  return null;
64367
- const home5 = homedir40().replace(/\\/g, "/");
64417
+ const home5 = homedir39().replace(/\\/g, "/");
64368
64418
  const hookDirNorm = hookDir.replace(/\\/g, "/");
64369
64419
  function resolveEnvPath(prefix, rest) {
64370
64420
  const normRest = rest.replace(/\\/g, "/");
@@ -64426,7 +64476,9 @@ function extractHookFilePath(command, hookDir) {
64426
64476
  }
64427
64477
  return null;
64428
64478
  }
64429
- var init_zombie_wirings_pruner = () => {};
64479
+ var init_zombie_wirings_pruner = __esm(() => {
64480
+ init_command_normalizer();
64481
+ });
64430
64482
 
64431
64483
  // src/domains/health-checks/checkers/shared.ts
64432
64484
  function shouldSkipExpensiveOperations2() {
@@ -64442,7 +64494,7 @@ var init_shared2 = __esm(() => {
64442
64494
  import { spawnSync as spawnSync3 } from "node:child_process";
64443
64495
  import { existsSync as existsSync45, readFileSync as readFileSync13, readdirSync as readdirSync8, statSync as statSync9, writeFileSync as writeFileSync5 } from "node:fs";
64444
64496
  import { readdir as readdir17 } from "node:fs/promises";
64445
- import { homedir as homedir41, tmpdir } from "node:os";
64497
+ import { homedir as homedir40, tmpdir } from "node:os";
64446
64498
  import { join as join64, resolve as resolve33 } from "node:path";
64447
64499
  function resolveDoctorCkExecutable(platformName = process.platform) {
64448
64500
  return platformName === "win32" ? "ck.cmd" : "ck";
@@ -64472,12 +64524,12 @@ function isPathWithin2(filePath, parentDir) {
64472
64524
  }
64473
64525
  function getCanonicalGlobalCommandRoot() {
64474
64526
  const configuredGlobalDir = PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "");
64475
- const defaultGlobalDir = join64(homedir41(), ".claude").replace(/\\/g, "/");
64527
+ const defaultGlobalDir = join64(homedir40(), ".claude").replace(/\\/g, "/");
64476
64528
  return configuredGlobalDir === defaultGlobalDir ? "$HOME" : configuredGlobalDir;
64477
64529
  }
64478
64530
  function getClaudeSettingsFiles(projectDir) {
64479
64531
  const globalClaudeDir = PathResolver.getGlobalKitDir();
64480
- const ccsSettingsDir = join64(process.env.CK_TEST_HOME ?? homedir41(), ".ccs");
64532
+ const ccsSettingsDir = join64(process.env.CK_TEST_HOME ?? homedir40(), ".ccs");
64481
64533
  const candidates = [
64482
64534
  {
64483
64535
  path: resolve33(projectDir, ".claude", "settings.json"),
@@ -65176,7 +65228,7 @@ function extractHookReferencePaths(cmd) {
65176
65228
  }
65177
65229
  function resolveHookScriptPath(scriptPath, projectDir) {
65178
65230
  let resolved = scriptPath.replace(/\\/g, "/");
65179
- const home5 = homedir41();
65231
+ const home5 = homedir40();
65180
65232
  resolved = resolved.replace(/^\$\{?HOME\}?/, home5);
65181
65233
  resolved = resolved.replace(/^\$\{?CLAUDE_PROJECT_DIR\}?/, projectDir);
65182
65234
  resolved = resolved.replace(/^%USERPROFILE%/, home5);
@@ -67391,7 +67443,62 @@ async function readMetadataFile(claudeDir3) {
67391
67443
  return null;
67392
67444
  }
67393
67445
  }
67394
- function buildInitCommand(isGlobal, kit, beta, yes) {
67446
+ function extractCkHookName(command) {
67447
+ if (!command.trim().startsWith("node "))
67448
+ return null;
67449
+ const normalized = command.replace(/\\/g, "/");
67450
+ const match = normalized.match(/\/hooks\/([^/"'\s]+)\.(?:cjs|mjs|js)(?:["'\s]|$)/);
67451
+ return match?.[1] ?? null;
67452
+ }
67453
+ function collectSettingsHookCommands(settings) {
67454
+ const commands = new Set;
67455
+ for (const entries of Object.values(settings.hooks ?? {})) {
67456
+ for (const entry of entries) {
67457
+ if (typeof entry.command === "string") {
67458
+ commands.add(normalizeCommand(entry.command));
67459
+ }
67460
+ for (const hook of entry.hooks ?? []) {
67461
+ if (typeof hook.command === "string") {
67462
+ commands.add(normalizeCommand(hook.command));
67463
+ }
67464
+ }
67465
+ }
67466
+ }
67467
+ return commands;
67468
+ }
67469
+ function getInstalledHookCommands(config, kit) {
67470
+ const kits = Object.entries(config.kits ?? {});
67471
+ if (kits.length === 0)
67472
+ return [];
67473
+ const kitKey = kit?.toLowerCase();
67474
+ const preferred = kitKey ? kits.filter(([name]) => {
67475
+ const normalizedName = name.toLowerCase();
67476
+ return normalizedName === kitKey || normalizedName.includes(kitKey);
67477
+ }) : [];
67478
+ const candidates = preferred.length > 0 ? preferred : kits;
67479
+ return candidates.flatMap(([, entry]) => entry.installedSettings?.hooks ?? []);
67480
+ }
67481
+ async function countMissingCkHookRegistrations(claudeDir3, kit) {
67482
+ const settingsPath = join68(claudeDir3, "settings.json");
67483
+ const configPath = join68(claudeDir3, ".ck.json");
67484
+ if (!existsSync47(settingsPath) || !existsSync47(configPath))
67485
+ return 0;
67486
+ const settings = parseJsonContent(await import_fs_extra8.readFile(settingsPath, "utf-8"));
67487
+ const config = parseJsonContent(await import_fs_extra8.readFile(configPath, "utf-8"));
67488
+ const existingCommands = collectSettingsHookCommands(settings);
67489
+ const disabledHooks = new Set(Object.entries(config.hooks ?? {}).filter(([, enabled]) => enabled === false).map(([name]) => name));
67490
+ let missing = 0;
67491
+ for (const command of getInstalledHookCommands(config, kit)) {
67492
+ const hookName = extractCkHookName(command);
67493
+ if (hookName && disabledHooks.has(hookName))
67494
+ continue;
67495
+ if (!existingCommands.has(normalizeCommand(command))) {
67496
+ missing++;
67497
+ }
67498
+ }
67499
+ return missing;
67500
+ }
67501
+ function buildInitCommand(isGlobal, kit, beta, yes, restoreCkHooks) {
67395
67502
  const parts = ["ck init"];
67396
67503
  if (isGlobal)
67397
67504
  parts.push("-g");
@@ -67399,6 +67506,8 @@ function buildInitCommand(isGlobal, kit, beta, yes) {
67399
67506
  parts.push(`--kit ${kit}`);
67400
67507
  if (yes)
67401
67508
  parts.push("--yes");
67509
+ if (restoreCkHooks)
67510
+ parts.push("--restore-ck-hooks");
67402
67511
  parts.push("--install-skills");
67403
67512
  if (beta)
67404
67513
  parts.push("--beta");
@@ -67480,6 +67589,57 @@ async function promptKitUpdate(beta, yes, deps) {
67480
67589
  logger.verbose("No ClaudeKit installations detected, skipping kit update prompt");
67481
67590
  return;
67482
67591
  }
67592
+ let forceKitReinstall = false;
67593
+ if (hasLocal && setup.project.path) {
67594
+ try {
67595
+ const missingHookDeps = await findMissingHookDepsFn(setup.project.path);
67596
+ if (missingHookDeps.length > 0) {
67597
+ logger.warning(`Detected ${missingHookDeps.length} local missing hook dependency(ies); reinstalling local kit content`);
67598
+ forceKitReinstall = true;
67599
+ }
67600
+ } catch (error) {
67601
+ logger.verbose(`Local hook dependency self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67602
+ }
67603
+ try {
67604
+ const countMissingHookRefsFn = deps?.countMissingHookFileReferencesFn ?? countMissingHookFileReferences;
67605
+ const missingHookRefs = await countMissingHookRefsFn(dirname29(setup.project.path));
67606
+ if (missingHookRefs > 0) {
67607
+ logger.warning(`Detected ${missingHookRefs} local broken hook registration(s); reinstalling local kit content`);
67608
+ forceKitReinstall = true;
67609
+ }
67610
+ } catch (error) {
67611
+ logger.verbose(`Local hook registration self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67612
+ }
67613
+ if (forceKitReinstall && selection.isGlobal) {
67614
+ const kit = localKits[0] || selection.kit;
67615
+ selection = {
67616
+ isGlobal: false,
67617
+ kit,
67618
+ promptMessage: `Update local project ClaudeKit content${kit ? ` (${kit})` : ""}?`
67619
+ };
67620
+ }
67621
+ }
67622
+ const selectedClaudeDir = selection.isGlobal ? setup.global.path : setup.project.path;
67623
+ if (selectedClaudeDir) {
67624
+ try {
67625
+ const missingHookDeps = await findMissingHookDepsFn(selectedClaudeDir);
67626
+ if (missingHookDeps.length > 0) {
67627
+ logger.warning(`Detected ${missingHookDeps.length} ${selection.isGlobal ? "global" : "local"} missing hook dependency(ies); reinstalling kit content`);
67628
+ forceKitReinstall = true;
67629
+ }
67630
+ } catch (error) {
67631
+ logger.verbose(`Selected hook dependency self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67632
+ }
67633
+ try {
67634
+ const missingHookRegistrations = await countMissingCkHookRegistrations(selectedClaudeDir, selection.kit);
67635
+ if (missingHookRegistrations > 0) {
67636
+ logger.warning(`Detected ${missingHookRegistrations} ${selection.isGlobal ? "global" : "local"} missing hook registration(s); reinstalling kit content`);
67637
+ forceKitReinstall = true;
67638
+ }
67639
+ } catch (error) {
67640
+ logger.verbose(`Selected hook registration self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67641
+ }
67642
+ }
67483
67643
  let kitVersion = selection.kit ? selection.isGlobal ? globalMetadata?.kits?.[selection.kit]?.version : localMetadata?.kits?.[selection.kit]?.version : undefined;
67484
67644
  const isBetaInstalled = isBetaVersion(kitVersion);
67485
67645
  const promptMessage = selection.promptMessage;
@@ -67487,7 +67647,7 @@ async function promptKitUpdate(beta, yes, deps) {
67487
67647
  logger.info(`Current kit version: ${selection.kit}@${kitVersion}`);
67488
67648
  }
67489
67649
  let alreadyAtLatest = false;
67490
- if (yes && selection.kit && kitVersion) {
67650
+ if (yes && selection.kit && kitVersion && !forceKitReinstall) {
67491
67651
  const getTagFn = deps?.getLatestReleaseTagFn ?? fetchLatestReleaseTag;
67492
67652
  const latestTag = await getTagFn(selection.kit, beta || isBetaInstalled);
67493
67653
  if (latestTag && versionsMatch(kitVersion, latestTag)) {
@@ -67503,6 +67663,7 @@ async function promptKitUpdate(beta, yes, deps) {
67503
67663
  if (missingHookDeps.length > 0) {
67504
67664
  logger.warning(`Detected ${missingHookDeps.length} missing hook dependency(ies); reinstalling kit content`);
67505
67665
  alreadyAtLatest = false;
67666
+ forceKitReinstall = true;
67506
67667
  }
67507
67668
  } catch (error) {
67508
67669
  logger.verbose(`Hook dependency self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
@@ -67516,6 +67677,7 @@ async function promptKitUpdate(beta, yes, deps) {
67516
67677
  if (missingHookRefs > 0) {
67517
67678
  logger.warning(`Detected ${missingHookRefs} broken hook registration(s); reinstalling kit content`);
67518
67679
  alreadyAtLatest = false;
67680
+ forceKitReinstall = true;
67519
67681
  if (setup.project.path && selection.isGlobal) {
67520
67682
  selection = {
67521
67683
  isGlobal: false,
@@ -67552,7 +67714,7 @@ async function promptKitUpdate(beta, yes, deps) {
67552
67714
  }
67553
67715
  const useBeta = beta || isBetaInstalled;
67554
67716
  if (yes) {
67555
- const initCmd = buildInitCommand(selection.isGlobal, selection.kit, useBeta, true);
67717
+ const initCmd = buildInitCommand(selection.isGlobal, selection.kit, useBeta, true, forceKitReinstall);
67556
67718
  logger.info(`Running: ${initCmd}`);
67557
67719
  const s = (deps?.spinnerFn ?? de)();
67558
67720
  s.start("Updating ClaudeKit content...");
@@ -67585,6 +67747,8 @@ async function promptKitUpdate(beta, yes, deps) {
67585
67747
  const args = ["init"];
67586
67748
  if (selection.isGlobal)
67587
67749
  args.push("-g");
67750
+ if (forceKitReinstall)
67751
+ args.push("--restore-ck-hooks");
67588
67752
  args.push("--install-skills");
67589
67753
  if (useBeta)
67590
67754
  args.push("--beta");
@@ -67654,17 +67818,19 @@ async function promptMigrateUpdate(deps) {
67654
67818
  } catch {}
67655
67819
  try {
67656
67820
  const cleanupFn = deps?.cleanupMigratedHooksFn ?? (await Promise.resolve().then(() => (init_migrated_hooks_cleanup(), exports_migrated_hooks_cleanup))).cleanupMigratedHooksForProviders;
67657
- const cleanupProviders = allProviders.filter((p) => SAFE_PROVIDER_NAME.test(p));
67658
- const cleanupResults = await cleanupFn(cleanupProviders, { global: isGlobal });
67659
- const cleanupCount = cleanupResults.reduce((total, result) => total + result.hooksPruned + result.filesRemoved + result.registryEntriesRemoved, 0);
67660
- if (cleanupCount > 0) {
67661
- logger.info(`Cleaned up ${cleanupCount} generated-context hook artifact(s)`);
67821
+ const cleanupProviders = allProviders.filter((p) => p !== "claude-code" && SAFE_PROVIDER_NAME.test(p));
67822
+ if (cleanupProviders.length > 0) {
67823
+ const cleanupResults = await cleanupFn(cleanupProviders, { global: isGlobal });
67824
+ const cleanupCount = cleanupResults.reduce((total, result) => total + result.hooksPruned + result.filesRemoved + result.registryEntriesRemoved, 0);
67825
+ if (cleanupCount > 0) {
67826
+ logger.info(`Cleaned up ${cleanupCount} generated-context hook artifact(s)`);
67827
+ }
67828
+ await repairLegacyHookPromptsSafely();
67829
+ await repairHookFileReferencesSafely();
67662
67830
  }
67663
67831
  } catch (error) {
67664
67832
  logger.verbose(`Migrated hook cleanup skipped: ${error instanceof Error ? error.message : "unknown"}`);
67665
67833
  }
67666
- await repairLegacyHookPromptsSafely();
67667
- await repairHookFileReferencesSafely();
67668
67834
  const targets = allProviders.filter((p) => p !== "claude-code");
67669
67835
  if (targets.length === 0) {
67670
67836
  logger.verbose("No migration targets detected, skipping migrate step");
@@ -67743,6 +67909,7 @@ var init_post_update_handler = __esm(() => {
67743
67909
  init_metadata_migration();
67744
67910
  init_version_utils();
67745
67911
  init_claudekit_scanner();
67912
+ init_command_normalizer();
67746
67913
  init_logger();
67747
67914
  init_safe_prompts();
67748
67915
  init_types3();
@@ -68148,7 +68315,7 @@ import { spawn as spawn3 } from "node:child_process";
68148
68315
  import { execFile as execFile8 } from "node:child_process";
68149
68316
  import { existsSync as existsSync48 } from "node:fs";
68150
68317
  import { readFile as readFile38 } from "node:fs/promises";
68151
- import { cpus, homedir as homedir42, totalmem } from "node:os";
68318
+ import { cpus, homedir as homedir41, totalmem } from "node:os";
68152
68319
  import { join as join70 } from "node:path";
68153
68320
  function runCommand(cmd, args, fallback2) {
68154
68321
  return new Promise((resolve34) => {
@@ -68314,7 +68481,7 @@ function registerSystemRoutes(app) {
68314
68481
  gitVersion,
68315
68482
  ghVersion,
68316
68483
  shell: process.env.SHELL ?? process.env.ComSpec ?? "unknown",
68317
- homeDir: homedir42(),
68484
+ homeDir: homedir41(),
68318
68485
  cpuCores: cpus().length,
68319
68486
  totalMemoryGb: (totalmem() / 1024 ** 3).toFixed(1)
68320
68487
  };
@@ -74276,10 +74443,10 @@ var init_config_manager2 = __esm(() => {
74276
74443
 
74277
74444
  // src/services/package-installer/gemini-mcp/validation.ts
74278
74445
  import { existsSync as existsSync63, lstatSync, readlinkSync } from "node:fs";
74279
- import { homedir as homedir45 } from "node:os";
74446
+ import { homedir as homedir44 } from "node:os";
74280
74447
  import { join as join93 } from "node:path";
74281
74448
  function getGlobalMcpConfigPath() {
74282
- return join93(homedir45(), ".claude", ".mcp.json");
74449
+ return join93(homedir44(), ".claude", ".mcp.json");
74283
74450
  }
74284
74451
  function getLocalMcpConfigPath(projectDir) {
74285
74452
  return join93(projectDir, ".mcp.json");
@@ -74300,7 +74467,7 @@ function findMcpConfigPath(projectDir) {
74300
74467
  }
74301
74468
  function getGeminiSettingsPath(projectDir, isGlobal) {
74302
74469
  if (isGlobal) {
74303
- return join93(homedir45(), ".gemini", "settings.json");
74470
+ return join93(homedir44(), ".gemini", "settings.json");
74304
74471
  }
74305
74472
  return join93(projectDir, ".gemini", "settings.json");
74306
74473
  }
@@ -76928,7 +77095,7 @@ var init_content_validator = __esm(() => {
76928
77095
  import { createHash as createHash9 } from "node:crypto";
76929
77096
  import { existsSync as existsSync79, mkdirSync as mkdirSync5, readFileSync as readFileSync19, readdirSync as readdirSync13, statSync as statSync14 } from "node:fs";
76930
77097
  import { rename as rename16, writeFile as writeFile40 } from "node:fs/promises";
76931
- import { homedir as homedir55 } from "node:os";
77098
+ import { homedir as homedir54 } from "node:os";
76932
77099
  import { basename as basename34, join as join160 } from "node:path";
76933
77100
  function getCachedContext(repoPath) {
76934
77101
  const cachePath = getCacheFilePath(repoPath);
@@ -77003,7 +77170,7 @@ function getCacheFilePath(repoPath) {
77003
77170
  }
77004
77171
  var CACHE_DIR, CACHE_TTL_MS5;
77005
77172
  var init_context_cache_manager = __esm(() => {
77006
- CACHE_DIR = join160(homedir55(), ".claudekit", "cache");
77173
+ CACHE_DIR = join160(homedir54(), ".claudekit", "cache");
77007
77174
  CACHE_TTL_MS5 = 24 * 60 * 60 * 1000;
77008
77175
  });
77009
77176
 
@@ -77457,10 +77624,10 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
77457
77624
  // src/commands/content/phases/photo-generator.ts
77458
77625
  import { execSync as execSync8 } from "node:child_process";
77459
77626
  import { existsSync as existsSync81, mkdirSync as mkdirSync6, readdirSync as readdirSync15 } from "node:fs";
77460
- import { homedir as homedir56 } from "node:os";
77627
+ import { homedir as homedir55 } from "node:os";
77461
77628
  import { join as join162 } from "node:path";
77462
77629
  async function generatePhoto(_content, context, config, platform18, contentId, contentLogger) {
77463
- const mediaDir = join162(config.contentDir.replace(/^~/, homedir56()), "media", String(contentId));
77630
+ const mediaDir = join162(config.contentDir.replace(/^~/, homedir55()), "media", String(contentId));
77464
77631
  if (!existsSync81(mediaDir)) {
77465
77632
  mkdirSync6(mediaDir, { recursive: true });
77466
77633
  }
@@ -77574,7 +77741,7 @@ var init_content_creator = __esm(() => {
77574
77741
 
77575
77742
  // src/commands/content/phases/content-logger.ts
77576
77743
  import { createWriteStream as createWriteStream4, existsSync as existsSync82, mkdirSync as mkdirSync7, statSync as statSync15 } from "node:fs";
77577
- import { homedir as homedir57 } from "node:os";
77744
+ import { homedir as homedir56 } from "node:os";
77578
77745
  import { join as join163 } from "node:path";
77579
77746
 
77580
77747
  class ContentLogger {
@@ -77583,7 +77750,7 @@ class ContentLogger {
77583
77750
  logDir;
77584
77751
  maxBytes;
77585
77752
  constructor(maxBytes = 0) {
77586
- this.logDir = join163(homedir57(), ".claudekit", "logs");
77753
+ this.logDir = join163(homedir56(), ".claudekit", "logs");
77587
77754
  this.maxBytes = maxBytes;
77588
77755
  }
77589
77756
  init() {
@@ -79194,11 +79361,11 @@ var init_setup_wizard = __esm(() => {
79194
79361
 
79195
79362
  // src/commands/content/content-review-commands.ts
79196
79363
  import { existsSync as existsSync86 } from "node:fs";
79197
- import { homedir as homedir58 } from "node:os";
79364
+ import { homedir as homedir57 } from "node:os";
79198
79365
  async function queueContent() {
79199
79366
  const cwd2 = process.cwd();
79200
79367
  const config = await loadContentConfig(cwd2);
79201
- const dbPath = config.dbPath.replace(/^~/, homedir58());
79368
+ const dbPath = config.dbPath.replace(/^~/, homedir57());
79202
79369
  if (!existsSync86(dbPath)) {
79203
79370
  logger.info("No content database found. Run 'ck content setup' first.");
79204
79371
  return;
@@ -79225,7 +79392,7 @@ async function queueContent() {
79225
79392
  async function approveContentCmd(id) {
79226
79393
  const cwd2 = process.cwd();
79227
79394
  const config = await loadContentConfig(cwd2);
79228
- const dbPath = config.dbPath.replace(/^~/, homedir58());
79395
+ const dbPath = config.dbPath.replace(/^~/, homedir57());
79229
79396
  const db = initDatabase(dbPath);
79230
79397
  try {
79231
79398
  approveContent(db, Number.parseInt(id, 10));
@@ -79237,7 +79404,7 @@ async function approveContentCmd(id) {
79237
79404
  async function rejectContentCmd(id, reason) {
79238
79405
  const cwd2 = process.cwd();
79239
79406
  const config = await loadContentConfig(cwd2);
79240
- const dbPath = config.dbPath.replace(/^~/, homedir58());
79407
+ const dbPath = config.dbPath.replace(/^~/, homedir57());
79241
79408
  const db = initDatabase(dbPath);
79242
79409
  try {
79243
79410
  rejectContent(db, Number.parseInt(id, 10), reason);
@@ -79268,7 +79435,7 @@ __export(exports_content_subcommands, {
79268
79435
  approveContentCmd: () => approveContentCmd
79269
79436
  });
79270
79437
  import { existsSync as existsSync87, readFileSync as readFileSync22, unlinkSync as unlinkSync6 } from "node:fs";
79271
- import { homedir as homedir59 } from "node:os";
79438
+ import { homedir as homedir58 } from "node:os";
79272
79439
  import { join as join168 } from "node:path";
79273
79440
  function isDaemonRunning() {
79274
79441
  const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
@@ -79342,7 +79509,7 @@ async function statusContent() {
79342
79509
  } catch {}
79343
79510
  }
79344
79511
  async function logsContent(options2) {
79345
- const logDir = join168(homedir59(), ".claudekit", "logs");
79512
+ const logDir = join168(homedir58(), ".claudekit", "logs");
79346
79513
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
79347
79514
  const logPath = join168(logDir, `content-${dateStr}.log`);
79348
79515
  if (!existsSync87(logPath)) {
@@ -79376,12 +79543,12 @@ var init_content_subcommands = __esm(() => {
79376
79543
  init_setup_wizard();
79377
79544
  init_state_manager();
79378
79545
  init_content_review_commands();
79379
- LOCK_DIR = join168(homedir59(), ".claudekit", "locks");
79546
+ LOCK_DIR = join168(homedir58(), ".claudekit", "locks");
79380
79547
  });
79381
79548
 
79382
79549
  // src/commands/content/content-command.ts
79383
79550
  import { existsSync as existsSync88, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync7 } from "node:fs";
79384
- import { homedir as homedir60 } from "node:os";
79551
+ import { homedir as homedir59 } from "node:os";
79385
79552
  import { join as join169 } from "node:path";
79386
79553
  async function contentCommand(options2) {
79387
79554
  const cwd2 = process.cwd();
@@ -79414,7 +79581,7 @@ async function contentCommand(options2) {
79414
79581
  if (!existsSync88(LOCK_DIR2))
79415
79582
  mkdirSync9(LOCK_DIR2, { recursive: true });
79416
79583
  writeFileSync7(LOCK_FILE, String(process.pid), "utf-8");
79417
- const dbPath = config.dbPath.replace(/^~/, homedir60());
79584
+ const dbPath = config.dbPath.replace(/^~/, homedir59());
79418
79585
  const db = initDatabase(dbPath);
79419
79586
  contentLogger.info(`Database initialised at ${dbPath}`);
79420
79587
  const adapters = initializeAdapters(config);
@@ -79560,7 +79727,7 @@ var init_content_command = __esm(() => {
79560
79727
  init_publisher();
79561
79728
  init_review_manager();
79562
79729
  init_state_manager();
79563
- LOCK_DIR2 = join169(homedir60(), ".claudekit", "locks");
79730
+ LOCK_DIR2 = join169(homedir59(), ".claudekit", "locks");
79564
79731
  LOCK_FILE = join169(LOCK_DIR2, "ck-content.lock");
79565
79732
  });
79566
79733
 
@@ -80723,6 +80890,10 @@ var init_init_command_help = __esm(() => {
80723
80890
  {
80724
80891
  flags: "--force-overwrite-settings",
80725
80892
  description: "Fully replace settings.json instead of selective merge"
80893
+ },
80894
+ {
80895
+ flags: "--restore-ck-hooks",
80896
+ description: "Restore CK-managed hook registrations during update self-heal"
80726
80897
  }
80727
80898
  ]
80728
80899
  },
@@ -82777,9 +82948,9 @@ var import_picocolors6 = __toESM(require_picocolors(), 1);
82777
82948
  init_fm_to_json();
82778
82949
  init_portable_registry();
82779
82950
  init_provider_registry();
82780
- import { existsSync as existsSync6 } from "node:fs";
82951
+ import { existsSync as existsSync7 } from "node:fs";
82781
82952
  import { readFile as readFile6, rm, writeFile as writeFile4 } from "node:fs/promises";
82782
- import { dirname as dirname4, join as join7 } from "node:path";
82953
+ import { dirname as dirname4, join as join8 } from "node:path";
82783
82954
  function toSlug3(name) {
82784
82955
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
82785
82956
  }
@@ -82899,7 +83070,7 @@ async function removeFromJsonMerge(agentName, filePath) {
82899
83070
  const rulesDir = dirname4(filePath);
82900
83071
  const ruleNames = new Set([`${agentName}.md`, `${slug}.md`]);
82901
83072
  for (const ruleName of ruleNames) {
82902
- await rm(join7(rulesDir, ruleName), { force: true });
83073
+ await rm(join8(rulesDir, ruleName), { force: true });
82903
83074
  }
82904
83075
  if (filtered.length === 0) {
82905
83076
  await rm(filePath, { force: true });
@@ -82929,7 +83100,7 @@ async function uninstallAgentFromProvider(agentName, provider, global2) {
82929
83100
  };
82930
83101
  }
82931
83102
  const installation = installations[0];
82932
- const fileExists = existsSync6(installation.path);
83103
+ const fileExists = existsSync7(installation.path);
82933
83104
  try {
82934
83105
  const config = providers[provider];
82935
83106
  const pathConfig = config.agents;
@@ -83018,8 +83189,8 @@ async function forceUninstallAgentFromProvider(agentName, provider, global2) {
83018
83189
  };
83019
83190
  }
83020
83191
  const writeStrategy = pathConfig.writeStrategy;
83021
- const targetPath = writeStrategy === "json-merge" ? join7(basePath, "cline_custom_modes.json") : writeStrategy === "merge-single" || writeStrategy === "yaml-merge" || writeStrategy === "single-file" ? basePath : join7(basePath, `${agentName}${pathConfig.fileExtension}`);
83022
- const fileExists = existsSync6(targetPath);
83192
+ const targetPath = writeStrategy === "json-merge" ? join8(basePath, "cline_custom_modes.json") : writeStrategy === "merge-single" || writeStrategy === "yaml-merge" || writeStrategy === "single-file" ? basePath : join8(basePath, `${agentName}${pathConfig.fileExtension}`);
83193
+ const fileExists = existsSync7(targetPath);
83023
83194
  try {
83024
83195
  if (!fileExists) {
83025
83196
  return {
@@ -83538,7 +83709,7 @@ var import_picocolors8 = __toESM(require_picocolors(), 1);
83538
83709
 
83539
83710
  // src/domains/claudekit-api/index.ts
83540
83711
  import { homedir as homedir7 } from "node:os";
83541
- import { join as join9 } from "node:path";
83712
+ import { join as join10 } from "node:path";
83542
83713
 
83543
83714
  // src/domains/api-key/validator.ts
83544
83715
  var API_BASE_URL = "https://claudekit.cc/api";
@@ -83585,20 +83756,20 @@ function isValidKeyFormat(key) {
83585
83756
  return /^ck_live_[A-Za-z0-9_-]{32}$/.test(key);
83586
83757
  }
83587
83758
  // src/domains/api-key/storage.ts
83588
- import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync } from "node:fs";
83589
- import { join as join8 } from "node:path";
83759
+ import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync } from "node:fs";
83760
+ import { join as join9 } from "node:path";
83590
83761
  var ENV_FILE = ".env";
83591
83762
  var API_KEY_VAR = "CLAUDEKIT_API_KEY";
83592
83763
  function getEnvFilePath(claudeDir) {
83593
- return join8(claudeDir, ENV_FILE);
83764
+ return join9(claudeDir, ENV_FILE);
83594
83765
  }
83595
83766
  function readExistingApiKey(claudeDir) {
83596
83767
  const envPath = getEnvFilePath(claudeDir);
83597
- if (!existsSync7(envPath)) {
83768
+ if (!existsSync8(envPath)) {
83598
83769
  return null;
83599
83770
  }
83600
83771
  try {
83601
- const content = readFileSync3(envPath, "utf-8");
83772
+ const content = readFileSync4(envPath, "utf-8");
83602
83773
  const match = content.match(new RegExp(`^${API_KEY_VAR}=(.+)$`, "m"));
83603
83774
  return match?.[1]?.trim() ?? null;
83604
83775
  } catch {
@@ -83608,8 +83779,8 @@ function readExistingApiKey(claudeDir) {
83608
83779
  function saveApiKey(claudeDir, apiKey) {
83609
83780
  const envPath = getEnvFilePath(claudeDir);
83610
83781
  let content = "";
83611
- if (existsSync7(envPath)) {
83612
- content = readFileSync3(envPath, "utf-8");
83782
+ if (existsSync8(envPath)) {
83783
+ content = readFileSync4(envPath, "utf-8");
83613
83784
  if (content.includes(`${API_KEY_VAR}=`)) {
83614
83785
  content = content.replace(new RegExp(`^${API_KEY_VAR}=.*$`, "m"), `${API_KEY_VAR}=${apiKey}`);
83615
83786
  } else {
@@ -83765,7 +83936,7 @@ class ClaudekitHttpClient {
83765
83936
  } catch (error) {
83766
83937
  if (error instanceof CkApiError && error.code === "RATE_LIMIT_EXCEEDED" && error.retryAfter) {
83767
83938
  const delayMs = error.retryAfter * 1000;
83768
- await new Promise((resolve4) => setTimeout(resolve4, delayMs));
83939
+ await new Promise((resolve5) => setTimeout(resolve5, delayMs));
83769
83940
  return fn();
83770
83941
  }
83771
83942
  throw error;
@@ -83775,7 +83946,7 @@ class ClaudekitHttpClient {
83775
83946
 
83776
83947
  // src/domains/claudekit-api/index.ts
83777
83948
  function createApiClient(claudeDir) {
83778
- const dir = claudeDir ?? join9(homedir7(), ".claude");
83949
+ const dir = claudeDir ?? join10(homedir7(), ".claude");
83779
83950
  const apiKey = readExistingApiKey(dir);
83780
83951
  if (!apiKey) {
83781
83952
  throw new CkApiError("MISSING_API_KEY", "No API key found. Run `ck api setup` to configure your ClaudeKit API key.", 401);
@@ -84206,13 +84377,13 @@ async function handleApiServices(options2) {
84206
84377
 
84207
84378
  // src/commands/api/subcommands/api-setup-handler.ts
84208
84379
  import { homedir as homedir8 } from "node:os";
84209
- import { join as join10 } from "node:path";
84380
+ import { join as join11 } from "node:path";
84210
84381
  init_logger();
84211
84382
  init_dist2();
84212
84383
  var DASHBOARD_URL = "https://claudekit.cc/api-keys";
84213
84384
  var MAX_ATTEMPTS = 3;
84214
84385
  async function handleApiSetup(options2) {
84215
- const claudeDir = join10(homedir8(), ".claude");
84386
+ const claudeDir = join11(homedir8(), ".claude");
84216
84387
  const existing = readExistingApiKey(claudeDir);
84217
84388
  if (existing && !options2.force) {
84218
84389
  const masked = `${existing.slice(0, 15)}...`;
@@ -88196,7 +88367,7 @@ init_logger();
88196
88367
  init_path_resolver();
88197
88368
  import { existsSync as existsSync58 } from "node:fs";
88198
88369
  import { readFile as readFile42 } from "node:fs/promises";
88199
- import { homedir as homedir43 } from "node:os";
88370
+ import { homedir as homedir42 } from "node:os";
88200
88371
  import { dirname as dirname31, join as join80, normalize as normalize6, resolve as resolve36 } from "node:path";
88201
88372
  async function checkPathRefsValid(projectDir) {
88202
88373
  const globalClaudeMd = join80(PathResolver.getGlobalKitDir(), "CLAUDE.md");
@@ -88229,7 +88400,7 @@ async function checkPathRefsValid(projectDir) {
88229
88400
  };
88230
88401
  }
88231
88402
  const baseDir = dirname31(claudeMdPath);
88232
- const home5 = homedir43();
88403
+ const home5 = homedir42();
88233
88404
  const broken = [];
88234
88405
  for (const ref of refs) {
88235
88406
  let refPath;
@@ -89233,7 +89404,7 @@ import { platform as platform8 } from "node:os";
89233
89404
  init_environment();
89234
89405
  init_path_resolver();
89235
89406
  import { constants as constants3, access as access4, mkdir as mkdir21, readFile as readFile44, unlink as unlink11, writeFile as writeFile21 } from "node:fs/promises";
89236
- import { arch as arch2, homedir as homedir44, platform as platform7 } from "node:os";
89407
+ import { arch as arch2, homedir as homedir43, platform as platform7 } from "node:os";
89237
89408
  import { join as join85, normalize as normalize7 } from "node:path";
89238
89409
  function shouldSkipExpensiveOperations4() {
89239
89410
  return shouldSkipExpensiveOperations();
@@ -89256,7 +89427,7 @@ async function checkPlatformDetect() {
89256
89427
  };
89257
89428
  }
89258
89429
  async function checkHomeDirResolution() {
89259
- const nodeHome = normalize7(homedir44());
89430
+ const nodeHome = normalize7(homedir43());
89260
89431
  const rawEnvHome = getHomeDirectoryFromEnv(platform7());
89261
89432
  const envHome = rawEnvHome ? normalize7(rawEnvHome) : "";
89262
89433
  const match = nodeHome === envHome && envHome !== "";
@@ -103341,7 +103512,7 @@ class FileScanner {
103341
103512
 
103342
103513
  // src/domains/installation/merger/settings-processor.ts
103343
103514
  import { execSync as execSync5 } from "node:child_process";
103344
- import { homedir as homedir46 } from "node:os";
103515
+ import { homedir as homedir45 } from "node:os";
103345
103516
  import { dirname as dirname39, join as join109 } from "node:path";
103346
103517
 
103347
103518
  // src/domains/config/installed-settings-tracker.ts
@@ -103373,7 +103544,7 @@ class InstalledSettingsTracker {
103373
103544
  }
103374
103545
  try {
103375
103546
  const content = await readFile50(ckJsonPath, "utf-8");
103376
- const data = JSON.parse(content);
103547
+ const data = parseJsonContent(content);
103377
103548
  const installed = data.kits?.[this.kitName]?.installedSettings;
103378
103549
  if (installed) {
103379
103550
  return installed;
@@ -103390,7 +103561,7 @@ class InstalledSettingsTracker {
103390
103561
  let data = {};
103391
103562
  if (existsSync66(ckJsonPath)) {
103392
103563
  const content = await readFile50(ckJsonPath, "utf-8");
103393
- data = JSON.parse(content);
103564
+ data = parseJsonContent(content);
103394
103565
  }
103395
103566
  if (!data.kits) {
103396
103567
  data.kits = {};
@@ -103456,6 +103627,7 @@ class SettingsProcessor {
103456
103627
  installingKit;
103457
103628
  cachedVersion = undefined;
103458
103629
  deletionPatterns = [];
103630
+ restoreCkHooks = false;
103459
103631
  zombiePrunerHookDir = null;
103460
103632
  setGlobalFlag(isGlobal) {
103461
103633
  this.isGlobal = isGlobal;
@@ -103463,6 +103635,9 @@ class SettingsProcessor {
103463
103635
  setForceOverwriteSettings(force) {
103464
103636
  this.forceOverwriteSettings = force;
103465
103637
  }
103638
+ setRestoreCkHooks(restore) {
103639
+ this.restoreCkHooks = restore;
103640
+ }
103466
103641
  setProjectDir(dir) {
103467
103642
  this.projectDir = dir;
103468
103643
  this.initTracker();
@@ -103507,6 +103682,7 @@ class SettingsProcessor {
103507
103682
  } else {
103508
103683
  try {
103509
103684
  const parsedSettings = JSON.parse(transformedSource);
103685
+ await this.applyDisabledHookConfig(parsedSettings);
103510
103686
  this.logHookCommandRepair(this.fixHookCommandPaths(parsedSettings), "fresh install");
103511
103687
  await SettingsMerger.writeSettingsFile(destFile, parsedSettings);
103512
103688
  try {
@@ -103536,6 +103712,7 @@ class SettingsProcessor {
103536
103712
  let sourceSettings;
103537
103713
  try {
103538
103714
  sourceSettings = JSON.parse(transformedSourceContent);
103715
+ await this.applyDisabledHookConfig(sourceSettings);
103539
103716
  } catch {
103540
103717
  logger.warning("Failed to parse source settings.json, falling back to overwrite");
103541
103718
  const formattedContent = this.formatJsonContent(transformedSourceContent);
@@ -103558,10 +103735,15 @@ class SettingsProcessor {
103558
103735
  if (this.tracker) {
103559
103736
  installedSettings = await this.tracker.loadInstalledSettings();
103560
103737
  }
103738
+ const mergeInstalledSettings = this.restoreCkHooks ? { ...installedSettings, hooks: [] } : installedSettings;
103561
103739
  const mergeResult = SettingsMerger.merge(sourceSettings, destSettings, {
103562
- installedSettings,
103740
+ installedSettings: mergeInstalledSettings,
103563
103741
  sourceKit: this.installingKit
103564
103742
  });
103743
+ await this.applyDisabledHookConfig(mergeResult.merged);
103744
+ if (this.restoreCkHooks) {
103745
+ logger.info("Restored CK hook registrations while respecting .ck.json hook disables");
103746
+ }
103565
103747
  logger.verbose("Settings merge details", {
103566
103748
  hooksAdded: mergeResult.hooksAdded,
103567
103749
  hooksPreserved: mergeResult.hooksPreserved,
@@ -103591,7 +103773,8 @@ class SettingsProcessor {
103591
103773
  logger.info(`Pruned ${hooksPruned} stale hook(s) referencing deleted files`);
103592
103774
  }
103593
103775
  if (this.zombiePrunerHookDir) {
103594
- const { pruned: zombiePruned } = pruneZombieEngineerWirings(mergeResult.merged, this.zombiePrunerHookDir);
103776
+ const sourceHookCommands = this.collectHookCommands(sourceSettings);
103777
+ const { pruned: zombiePruned } = pruneZombieEngineerWirings(mergeResult.merged, this.zombiePrunerHookDir, sourceHookCommands);
103595
103778
  if (zombiePruned.length > 0) {
103596
103779
  logger.info(`Pruned ${zombiePruned.length} zombie hook entries: ${zombiePruned.join(", ")}`);
103597
103780
  }
@@ -103600,6 +103783,111 @@ class SettingsProcessor {
103600
103783
  logger.success("Merged settings.json (user customizations preserved)");
103601
103784
  await this.injectTeamHooksIfSupported(destFile, mergeResult.merged);
103602
103785
  }
103786
+ async getDisabledHookNames() {
103787
+ if (!this.projectDir) {
103788
+ return new Set;
103789
+ }
103790
+ const disabled = new Set;
103791
+ const addFromConfig = async (configPath) => {
103792
+ const names = await this.readDisabledHookNamesFromConfig(configPath);
103793
+ for (const name2 of names)
103794
+ disabled.add(name2);
103795
+ };
103796
+ try {
103797
+ if (this.isGlobal) {
103798
+ await addFromConfig(join109(this.projectDir, ".ck.json"));
103799
+ } else {
103800
+ await addFromConfig(join109(PathResolver.getGlobalKitDir(), ".ck.json"));
103801
+ await addFromConfig(join109(this.projectDir, ".claude", ".ck.json"));
103802
+ }
103803
+ } catch (error) {
103804
+ logger.debug(`Failed to load .ck.json hook preferences: ${error instanceof Error ? error.message : "unknown"}`);
103805
+ }
103806
+ return disabled;
103807
+ }
103808
+ async readDisabledHookNamesFromConfig(configPath) {
103809
+ if (!await import_fs_extra14.pathExists(configPath))
103810
+ return new Set;
103811
+ const raw2 = parseJsonContent(await import_fs_extra14.readFile(configPath, "utf-8"));
103812
+ const hooks = raw2.hooks;
103813
+ if (!hooks || typeof hooks !== "object")
103814
+ return new Set;
103815
+ return new Set(Object.entries(hooks).filter(([, enabled]) => enabled === false).map(([name2]) => name2));
103816
+ }
103817
+ async applyDisabledHookConfig(settings) {
103818
+ const disabledHooks = await this.getDisabledHookNames();
103819
+ if (disabledHooks.size === 0 || !settings.hooks)
103820
+ return 0;
103821
+ let removed = 0;
103822
+ const hooksRecord = settings.hooks;
103823
+ for (const [eventName, entries] of Object.entries(hooksRecord)) {
103824
+ const filteredEntries = [];
103825
+ for (const entry of entries) {
103826
+ if (Array.isArray(entry.hooks)) {
103827
+ const keptHooks = entry.hooks.filter((hook) => {
103828
+ const command = typeof hook.command === "string" ? hook.command : "";
103829
+ const hookName = this.extractCkHookName(command);
103830
+ if (hookName && disabledHooks.has(hookName)) {
103831
+ removed++;
103832
+ return false;
103833
+ }
103834
+ return true;
103835
+ });
103836
+ if (keptHooks.length > 0) {
103837
+ filteredEntries.push({ ...entry, hooks: keptHooks });
103838
+ }
103839
+ } else {
103840
+ const command = typeof entry.command === "string" ? entry.command : "";
103841
+ const hookName = this.extractCkHookName(command);
103842
+ if (hookName && disabledHooks.has(hookName)) {
103843
+ removed++;
103844
+ continue;
103845
+ }
103846
+ filteredEntries.push(entry);
103847
+ }
103848
+ }
103849
+ if (filteredEntries.length > 0) {
103850
+ hooksRecord[eventName] = filteredEntries;
103851
+ } else {
103852
+ delete hooksRecord[eventName];
103853
+ }
103854
+ }
103855
+ if (Object.keys(hooksRecord).length === 0) {
103856
+ settings.hooks = undefined;
103857
+ }
103858
+ if (removed > 0) {
103859
+ logger.info(`Skipped ${removed} hook registration(s) disabled in .ck.json`);
103860
+ }
103861
+ return removed;
103862
+ }
103863
+ collectHookCommands(settings) {
103864
+ const commands = new Set;
103865
+ if (!settings.hooks)
103866
+ return commands;
103867
+ for (const entries of Object.values(settings.hooks)) {
103868
+ for (const entry of entries) {
103869
+ if ("hooks" in entry && Array.isArray(entry.hooks)) {
103870
+ for (const hook of entry.hooks) {
103871
+ if (typeof hook.command === "string") {
103872
+ commands.add(hook.command);
103873
+ }
103874
+ }
103875
+ continue;
103876
+ }
103877
+ if ("command" in entry && typeof entry.command === "string") {
103878
+ commands.add(entry.command);
103879
+ }
103880
+ }
103881
+ }
103882
+ return commands;
103883
+ }
103884
+ extractCkHookName(command) {
103885
+ if (!command.trim().startsWith("node "))
103886
+ return null;
103887
+ const normalized = command.replace(/\\/g, "/");
103888
+ const match2 = normalized.match(/\/hooks\/([^/"'\s]+)\.(?:cjs|mjs|js)(?:["'\s]|$)/);
103889
+ return match2?.[1] ?? null;
103890
+ }
103603
103891
  migrateDeprecatedMatchers(destSettings, sourceSettings) {
103604
103892
  if (!destSettings.hooks || !sourceSettings.hooks)
103605
103893
  return;
@@ -103841,7 +104129,7 @@ class SettingsProcessor {
103841
104129
  return false;
103842
104130
  }
103843
104131
  const configuredGlobalDir = PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "");
103844
- const defaultGlobalDir = join109(homedir46(), ".claude").replace(/\\/g, "/");
104132
+ const defaultGlobalDir = join109(homedir45(), ".claude").replace(/\\/g, "/");
103845
104133
  return configuredGlobalDir !== defaultGlobalDir;
103846
104134
  }
103847
104135
  getClaudeCommandRoot() {
@@ -103992,6 +104280,9 @@ class CopyExecutor {
103992
104280
  setForceOverwriteSettings(force) {
103993
104281
  this.settingsProcessor.setForceOverwriteSettings(force);
103994
104282
  }
104283
+ setRestoreCkHooks(restore) {
104284
+ this.settingsProcessor.setRestoreCkHooks(restore);
104285
+ }
103995
104286
  setDeletions(deletions) {
103996
104287
  this.settingsProcessor.setDeletions(deletions);
103997
104288
  }
@@ -104164,6 +104455,9 @@ class FileMerger {
104164
104455
  setForceOverwriteSettings(force) {
104165
104456
  this.copyExecutor.setForceOverwriteSettings(force);
104166
104457
  }
104458
+ setRestoreCkHooks(restore) {
104459
+ this.copyExecutor.setRestoreCkHooks(restore);
104460
+ }
104167
104461
  setProjectDir(dir) {
104168
104462
  this.copyExecutor.setProjectDir(dir);
104169
104463
  }
@@ -105487,6 +105781,7 @@ async function handleMerge(ctx) {
105487
105781
  }
105488
105782
  merger.setGlobalFlag(ctx.options.global);
105489
105783
  merger.setForceOverwriteSettings(ctx.options.forceOverwriteSettings);
105784
+ merger.setRestoreCkHooks(ctx.options.restoreCkHooks);
105490
105785
  merger.setProjectDir(ctx.resolvedDir);
105491
105786
  merger.setKitName(ctx.kit.name);
105492
105787
  merger.setZombiePrunerHookDir(join120(ctx.claudeDir, "hooks"));
@@ -106974,6 +107269,7 @@ async function resolveOptions(ctx) {
106974
107269
  skipSetup: parsed.skipSetup ?? false,
106975
107270
  forceOverwrite: parsed.forceOverwrite ?? false,
106976
107271
  forceOverwriteSettings: parsed.forceOverwriteSettings ?? false,
107272
+ restoreCkHooks: parsed.restoreCkHooks ?? false,
106977
107273
  dryRun: parsed.dryRun ?? false,
106978
107274
  prefix: parsed.prefix ?? false,
106979
107275
  sync: parsed.sync ?? false,
@@ -107530,7 +107826,7 @@ async function handleFreshInstallation(claudeDir3, prompts) {
107530
107826
  // src/domains/installation/global-kit-legacy-repair.ts
107531
107827
  var import_fs_extra35 = __toESM(require_lib(), 1);
107532
107828
  import { cp as cp5, mkdir as mkdir35, readdir as readdir42, rename as rename11, rm as rm16, stat as stat22 } from "node:fs/promises";
107533
- import { homedir as homedir47 } from "node:os";
107829
+ import { homedir as homedir46 } from "node:os";
107534
107830
  import { dirname as dirname42, join as join133, normalize as normalize11, resolve as resolve46 } from "node:path";
107535
107831
  var LEGACY_KIT_MARKERS = [
107536
107832
  "metadata.json",
@@ -107565,7 +107861,7 @@ function uniqueNormalizedPaths(paths) {
107565
107861
  }
107566
107862
  return result;
107567
107863
  }
107568
- function getLegacyWindowsGlobalKitDirCandidates(env2 = process.env, homeDir = homedir47()) {
107864
+ function getLegacyWindowsGlobalKitDirCandidates(env2 = process.env, homeDir = homedir46()) {
107569
107865
  const candidates = [];
107570
107866
  const localAppData = safeEnvPath(env2.LOCALAPPDATA);
107571
107867
  const appData = safeEnvPath(env2.APPDATA);
@@ -108016,7 +108312,7 @@ async function handleSelection(ctx) {
108016
108312
  logger.info("--force has no effect without --yes (the version-match skip only applies in non-interactive mode)");
108017
108313
  }
108018
108314
  const releaseTag = release?.tag_name;
108019
- if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && releaseTag && !isOfflineMode && !pendingKits?.length) {
108315
+ if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && !ctx.options.restoreCkHooks && releaseTag && !isOfflineMode && !pendingKits?.length) {
108020
108316
  try {
108021
108317
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
108022
108318
  const claudeDir3 = prefix ? join134(resolvedDir, prefix) : resolvedDir;
@@ -108698,7 +108994,7 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
108698
108994
  // src/services/transformers/global-path-transformer.ts
108699
108995
  init_logger();
108700
108996
  import { readFile as readFile61, readdir as readdir44, writeFile as writeFile35 } from "node:fs/promises";
108701
- import { homedir as homedir48, platform as platform15 } from "node:os";
108997
+ import { homedir as homedir47, platform as platform15 } from "node:os";
108702
108998
  import { extname as extname7, join as join138 } from "node:path";
108703
108999
  var IS_WINDOWS3 = platform15() === "win32";
108704
109000
  var HOME_PREFIX = "$HOME";
@@ -108709,7 +109005,7 @@ function normalizeInstallPath(path17) {
108709
109005
  return path17.replace(/\\/g, "/").replace(/\/+$/, "");
108710
109006
  }
108711
109007
  function getDefaultGlobalClaudeDir() {
108712
- return normalizeInstallPath(join138(homedir48(), ".claude"));
109008
+ return normalizeInstallPath(join138(homedir47(), ".claude"));
108713
109009
  }
108714
109010
  function getCustomGlobalClaudeDir(targetClaudeDir) {
108715
109011
  if (!targetClaudeDir)
@@ -108990,6 +109286,7 @@ function createInitContext(rawOptions, prompts) {
108990
109286
  skipSetup: false,
108991
109287
  forceOverwrite: false,
108992
109288
  forceOverwriteSettings: false,
109289
+ restoreCkHooks: false,
108993
109290
  dryRun: false,
108994
109291
  prefix: false,
108995
109292
  sync: false,
@@ -109140,13 +109437,13 @@ init_dist2();
109140
109437
  var import_picocolors30 = __toESM(require_picocolors(), 1);
109141
109438
  import { existsSync as existsSync68 } from "node:fs";
109142
109439
  import { readFile as readFile65, rm as rm18, unlink as unlink14 } from "node:fs/promises";
109143
- import { homedir as homedir53 } from "node:os";
109440
+ import { homedir as homedir52 } from "node:os";
109144
109441
  import { basename as basename30, join as join143, resolve as resolve50 } from "node:path";
109145
109442
  init_logger();
109146
109443
 
109147
109444
  // src/ui/ck-cli-design/tokens.ts
109148
109445
  var import_picocolors27 = __toESM(require_picocolors(), 1);
109149
- import { homedir as homedir49, platform as platform16 } from "node:os";
109446
+ import { homedir as homedir48, platform as platform16 } from "node:os";
109150
109447
  import { resolve as resolve49, win32 as win322 } from "node:path";
109151
109448
  var PANEL_MIN_WIDTH = 60;
109152
109449
  var PANEL_MAX_WIDTH = 72;
@@ -109304,7 +109601,7 @@ function wrapText(value, width) {
109304
109601
  }
109305
109602
  function formatDisplayPath(value) {
109306
109603
  const normalized = value.replace(/\\/g, "/");
109307
- const home5 = homedir49().replace(/\\/g, "/");
109604
+ const home5 = homedir48().replace(/\\/g, "/");
109308
109605
  if (normalized === home5)
109309
109606
  return "~";
109310
109607
  if (normalized.startsWith(`${home5}/`)) {
@@ -109618,13 +109915,13 @@ init_logger();
109618
109915
  init_dist2();
109619
109916
  init_model_taxonomy();
109620
109917
  import { mkdir as mkdir39, readFile as readFile64, writeFile as writeFile37 } from "node:fs/promises";
109621
- import { homedir as homedir52 } from "node:os";
109918
+ import { homedir as homedir51 } from "node:os";
109622
109919
  import { dirname as dirname44, join as join142 } from "node:path";
109623
109920
 
109624
109921
  // src/commands/portable/models-dev-cache.ts
109625
109922
  init_logger();
109626
109923
  import { mkdir as mkdir38, readFile as readFile62, rename as rename14, writeFile as writeFile36 } from "node:fs/promises";
109627
- import { homedir as homedir50 } from "node:os";
109924
+ import { homedir as homedir49 } from "node:os";
109628
109925
  import { join as join140 } from "node:path";
109629
109926
 
109630
109927
  class ModelsDevUnavailableError extends Error {
@@ -109637,7 +109934,7 @@ var MODELS_DEV_URL = "https://models.dev/api.json";
109637
109934
  var CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
109638
109935
  var FETCH_TIMEOUT_MS = 1e4;
109639
109936
  function defaultCacheDir() {
109640
- return join140(homedir50(), ".config", "claudekit", "cache");
109937
+ return join140(homedir49(), ".config", "claudekit", "cache");
109641
109938
  }
109642
109939
  function cacheFilePath(cacheDir) {
109643
109940
  return join140(cacheDir, "models-dev.json");
@@ -109717,7 +110014,7 @@ async function getModelsDevCatalog(opts = {}) {
109717
110014
  // src/commands/portable/opencode-model-discovery.ts
109718
110015
  init_logger();
109719
110016
  import { readFile as readFile63 } from "node:fs/promises";
109720
- import { homedir as homedir51, platform as platform17 } from "node:os";
110017
+ import { homedir as homedir50, platform as platform17 } from "node:os";
109721
110018
  import { join as join141 } from "node:path";
109722
110019
  function resolveOpenCodeAuthPath(homeDir) {
109723
110020
  if (platform17() === "win32") {
@@ -109763,7 +110060,7 @@ function pickGenericModel(models) {
109763
110060
  return sorted[0] ?? null;
109764
110061
  }
109765
110062
  async function resolveOpenCodeDefaultModel(opts = {}) {
109766
- const home5 = opts.homeDir ?? homedir51();
110063
+ const home5 = opts.homeDir ?? homedir50();
109767
110064
  const authedProviders = await readAuthedProviders(home5);
109768
110065
  if (authedProviders.length === 0) {
109769
110066
  return { ok: false, reason: "no-auth", authedProviders: [] };
@@ -109827,7 +110124,7 @@ function messageForReason(reason) {
109827
110124
  }
109828
110125
  function getOpenCodeConfigPath(options2) {
109829
110126
  if (options2.global) {
109830
- return join142(options2.homeDir ?? homedir52(), ".config", "opencode", "opencode.json");
110127
+ return join142(options2.homeDir ?? homedir51(), ".config", "opencode", "opencode.json");
109831
110128
  }
109832
110129
  return join142(options2.cwd ?? process.cwd(), "opencode.json");
109833
110130
  }
@@ -110834,7 +111131,7 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
110834
111131
  }
110835
111132
  if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
110836
111133
  return;
110837
- const claudeDir3 = installGlobally ? join143(homedir53(), ".claude") : join143(process.cwd(), ".claude");
111134
+ const claudeDir3 = installGlobally ? join143(homedir52(), ".claude") : join143(process.cwd(), ".claude");
110838
111135
  if (!existsSync68(claudeDir3))
110839
111136
  return;
110840
111137
  try {
@@ -110963,7 +111260,7 @@ async function migrateCommand(options2) {
110963
111260
  let installGlobally = requestedGlobal;
110964
111261
  if (options2.global === undefined && !options2.yes) {
110965
111262
  const projectTarget = join143(process.cwd(), ".claude");
110966
- const globalTarget = join143(homedir53(), ".claude");
111263
+ const globalTarget = join143(homedir52(), ".claude");
110967
111264
  const scopeChoice = await ie({
110968
111265
  message: "Installation scope",
110969
111266
  options: [
@@ -111036,7 +111333,7 @@ async function migrateCommand(options2) {
111036
111333
  }).join(`
111037
111334
  `));
111038
111335
  if (sourceGlobalOnly) {
111039
- f2.info(import_picocolors30.default.dim(` Scope: global (--global / -g) - reading from ${formatDisplayPath(join143(homedir53(), ".claude"))}`));
111336
+ f2.info(import_picocolors30.default.dim(` Scope: global (--global / -g) - reading from ${formatDisplayPath(join143(homedir52(), ".claude"))}`));
111040
111337
  } else {
111041
111338
  f2.info(import_picocolors30.default.dim(` CWD: ${process.cwd()}`));
111042
111339
  }
@@ -113083,6 +113380,7 @@ async function handleKitSelection(ctx) {
113083
113380
  dryRun: false,
113084
113381
  forceOverwrite: false,
113085
113382
  forceOverwriteSettings: false,
113383
+ restoreCkHooks: false,
113086
113384
  skipSetup: true,
113087
113385
  refresh: false,
113088
113386
  sync: false,
@@ -116064,7 +116362,7 @@ async function scanForRepos(parentDir) {
116064
116362
  init_logger();
116065
116363
  import { spawnSync as spawnSync8 } from "node:child_process";
116066
116364
  import { existsSync as existsSync76 } from "node:fs";
116067
- import { homedir as homedir54 } from "node:os";
116365
+ import { homedir as homedir53 } from "node:os";
116068
116366
  import { join as join157 } from "node:path";
116069
116367
  async function validateSetup(cwd2) {
116070
116368
  const workDir = cwd2 ?? process.cwd();
@@ -116096,7 +116394,7 @@ Run this command from a directory with a GitHub remote.`);
116096
116394
  } catch {
116097
116395
  throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
116098
116396
  }
116099
- const skillsPath = join157(homedir54(), ".claude", "skills");
116397
+ const skillsPath = join157(homedir53(), ".claude", "skills");
116100
116398
  const skillsAvailable = existsSync76(skillsPath);
116101
116399
  if (!skillsAvailable) {
116102
116400
  logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);
@@ -116437,7 +116735,7 @@ function registerCommands(cli) {
116437
116735
  }
116438
116736
  await newCommand(options2);
116439
116737
  });
116440
- 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("--force", "Force reinstall even if already at latest version (use with --yes; re-onboards missing files without full reset)").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) => {
116738
+ 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("--force", "Force reinstall even if already at latest version (use with --yes; re-onboards missing files without full reset)").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("--restore-ck-hooks", "Restore CK-managed hook registrations during update self-heal").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) => {
116441
116739
  if (options2.exclude && !Array.isArray(options2.exclude)) {
116442
116740
  options2.exclude = [options2.exclude];
116443
116741
  }