claudekit-cli 4.3.1-dev.15 → 4.3.1-dev.17

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
@@ -15349,6 +15349,7 @@ var init_commands = __esm(() => {
15349
15349
  dryRun: exports_external.boolean().default(false),
15350
15350
  forceOverwrite: exports_external.boolean().default(false),
15351
15351
  forceOverwriteSettings: exports_external.boolean().default(false),
15352
+ restoreCkHooks: exports_external.boolean().default(false),
15352
15353
  skipSetup: exports_external.boolean().default(false),
15353
15354
  refresh: exports_external.boolean().default(false),
15354
15355
  docsDir: exports_external.string().optional(),
@@ -15891,8 +15892,12 @@ var init_ck_config = __esm(() => {
15891
15892
  CkHooksConfigSchema = exports_external.object({
15892
15893
  "session-init": exports_external.boolean().optional(),
15893
15894
  "subagent-init": exports_external.boolean().optional(),
15895
+ "session-state": exports_external.boolean().optional(),
15896
+ "cook-after-plan-reminder": exports_external.boolean().optional(),
15894
15897
  "descriptive-name": exports_external.boolean().optional(),
15895
15898
  "dev-rules-reminder": exports_external.boolean().optional(),
15899
+ "plan-format-kanban": exports_external.boolean().optional(),
15900
+ "usage-quota-cache-refresh": exports_external.boolean().optional(),
15896
15901
  "usage-context-awareness": exports_external.boolean().optional(),
15897
15902
  "context-tracking": exports_external.boolean().optional(),
15898
15903
  "scout-block": exports_external.boolean().optional(),
@@ -15989,8 +15994,12 @@ var init_ck_config = __esm(() => {
15989
15994
  hooks: {
15990
15995
  "session-init": true,
15991
15996
  "subagent-init": true,
15997
+ "session-state": true,
15998
+ "cook-after-plan-reminder": true,
15992
15999
  "descriptive-name": true,
15993
16000
  "dev-rules-reminder": true,
16001
+ "plan-format-kanban": true,
16002
+ "usage-quota-cache-refresh": true,
15994
16003
  "usage-context-awareness": true,
15995
16004
  "context-tracking": true,
15996
16005
  "scout-block": true,
@@ -16014,8 +16023,12 @@ var init_ck_config = __esm(() => {
16014
16023
  CK_HOOK_NAMES = [
16015
16024
  "session-init",
16016
16025
  "subagent-init",
16026
+ "session-state",
16027
+ "cook-after-plan-reminder",
16017
16028
  "descriptive-name",
16018
16029
  "dev-rules-reminder",
16030
+ "plan-format-kanban",
16031
+ "usage-quota-cache-refresh",
16019
16032
  "usage-context-awareness",
16020
16033
  "context-tracking",
16021
16034
  "scout-block",
@@ -45197,6 +45210,14 @@ var init_open = __esm(() => {
45197
45210
  open_default = open;
45198
45211
  });
45199
45212
 
45213
+ // src/shared/json-content.ts
45214
+ function stripJsonBom(content) {
45215
+ return content.charCodeAt(0) === 65279 ? content.slice(1) : content;
45216
+ }
45217
+ function parseJsonContent(content) {
45218
+ return JSON.parse(stripJsonBom(content));
45219
+ }
45220
+
45200
45221
  // src/domains/config/config-manager.ts
45201
45222
  import { existsSync as existsSync10 } from "node:fs";
45202
45223
  import { mkdir as mkdir6, readFile as readFile7, rename as rename3, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
@@ -45225,7 +45246,7 @@ class ConfigManager {
45225
45246
  try {
45226
45247
  if (existsSync10(configFile)) {
45227
45248
  const content = await readFile7(configFile, "utf-8");
45228
- const data = JSON.parse(content);
45249
+ const data = parseJsonContent(content);
45229
45250
  ConfigManager.config = ConfigSchema.parse(data);
45230
45251
  logger.debug(`Config loaded from ${configFile}`);
45231
45252
  return ConfigManager.config;
@@ -45279,7 +45300,7 @@ class ConfigManager {
45279
45300
  try {
45280
45301
  if (existsSync10(configPath)) {
45281
45302
  const content = await readFile7(configPath, "utf-8");
45282
- const data = JSON.parse(content);
45303
+ const data = parseJsonContent(content);
45283
45304
  const folders = FoldersConfigSchema.parse(data.paths || data);
45284
45305
  logger.debug(`Project config loaded from ${configPath}`);
45285
45306
  return folders;
@@ -45300,7 +45321,7 @@ class ConfigManager {
45300
45321
  if (existsSync10(configPath)) {
45301
45322
  try {
45302
45323
  const content = await readFile7(configPath, "utf-8");
45303
- existingConfig = JSON.parse(content);
45324
+ existingConfig = parseJsonContent(content);
45304
45325
  } catch (error) {
45305
45326
  logger.debug(`Could not parse existing config, starting fresh: ${error instanceof Error ? error.message : "Unknown error"}`);
45306
45327
  }
@@ -45475,7 +45496,7 @@ class CkConfigManager {
45475
45496
  if (!existsSync11(configPath))
45476
45497
  return null;
45477
45498
  const content = await readFile8(configPath, "utf-8");
45478
- const data = normalizeCkConfigInput(JSON.parse(content));
45499
+ const data = normalizeCkConfigInput(parseJsonContent(content));
45479
45500
  return CkConfigSchema.parse(data);
45480
45501
  } catch (error) {
45481
45502
  logger.warning(`Failed to load config from ${configPath}: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -45542,7 +45563,7 @@ class CkConfigManager {
45542
45563
  if (!existingConfig && existsSync11(configPath)) {
45543
45564
  try {
45544
45565
  const content = await readFile8(configPath, "utf-8");
45545
- const parsed = JSON.parse(content);
45566
+ const parsed = parseJsonContent(content);
45546
45567
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
45547
45568
  existingConfig = normalizeCkConfigInput(parsed);
45548
45569
  }
@@ -45794,6 +45815,12 @@ function repairClaudeNodeCommandPath(cmd, root) {
45794
45815
  const command = formatCanonicalClaudeCommand(nodePrefix, root, relativePath, suffix);
45795
45816
  return { command, changed: command !== cmd, issue: "raw-relative" };
45796
45817
  }
45818
+ const quotedRelativeMatch = cmd.match(/^(node\s+)["'](?:\.\/)?(\.claude[/\\][^"']+)["'](.*)$/);
45819
+ if (quotedRelativeMatch) {
45820
+ const [, nodePrefix, relativePath, suffix] = quotedRelativeMatch;
45821
+ const command = formatCanonicalClaudeCommand(nodePrefix, root, relativePath, suffix);
45822
+ return { command, changed: command !== cmd, issue: "raw-relative" };
45823
+ }
45797
45824
  const embeddedQuotedMatch = cmd.match(/^(node\s+)"(?:\$HOME|\$CLAUDE_PROJECT_DIR|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)[/\\](\.claude[/\\][^"]+)"(.*)$/);
45798
45825
  if (embeddedQuotedMatch) {
45799
45826
  const [, nodePrefix, relativePath, suffix] = embeddedQuotedMatch;
@@ -50122,6 +50149,16 @@ var init_ck_config_schema = __esm(() => {
50122
50149
  default: true,
50123
50150
  description: "SubagentStart hook - injects context to subagents"
50124
50151
  },
50152
+ "session-state": {
50153
+ type: "boolean",
50154
+ default: true,
50155
+ description: "Stop/SubagentStop/PostToolUse hook - persists session state for handoff and statusline context"
50156
+ },
50157
+ "cook-after-plan-reminder": {
50158
+ type: "boolean",
50159
+ default: true,
50160
+ description: "SubagentStop hook - reminds agents to continue implementation after planning"
50161
+ },
50125
50162
  "descriptive-name": {
50126
50163
  type: "boolean",
50127
50164
  default: true,
@@ -50132,6 +50169,16 @@ var init_ck_config_schema = __esm(() => {
50132
50169
  default: true,
50133
50170
  description: "UserPromptSubmit hook - injects dev rules context"
50134
50171
  },
50172
+ "plan-format-kanban": {
50173
+ type: "boolean",
50174
+ default: true,
50175
+ description: "PostToolUse hook - keeps plan kanban metadata synchronized after edits"
50176
+ },
50177
+ "usage-quota-cache-refresh": {
50178
+ type: "boolean",
50179
+ default: true,
50180
+ description: "Lifecycle hook - refreshes cached usage quota information"
50181
+ },
50135
50182
  "usage-context-awareness": {
50136
50183
  type: "boolean",
50137
50184
  default: true,
@@ -63806,7 +63853,7 @@ var package_default;
63806
63853
  var init_package = __esm(() => {
63807
63854
  package_default = {
63808
63855
  name: "claudekit-cli",
63809
- version: "4.3.1-dev.15",
63856
+ version: "4.3.1-dev.17",
63810
63857
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
63811
63858
  type: "module",
63812
63859
  repository: {
@@ -64290,8 +64337,9 @@ var init_package_manager_runner = __esm(() => {
64290
64337
  import { existsSync as existsSync44, readdirSync as readdirSync7 } from "node:fs";
64291
64338
  import { homedir as homedir40 } from "node:os";
64292
64339
  import { basename as basename23, dirname as dirname28, isAbsolute as isAbsolute10, resolve as resolve32, sep as sep11 } from "node:path";
64293
- function pruneZombieEngineerWirings(settings, hookDir) {
64340
+ function pruneZombieEngineerWirings(settings, hookDir, preserveCommands = new Set) {
64294
64341
  const pruned = [];
64342
+ const normalizedPreserveCommands = new Set(Array.from(preserveCommands).map((command) => normalizeCommand(command)));
64295
64343
  if (!existsSync44(hookDir)) {
64296
64344
  return { settings, pruned };
64297
64345
  }
@@ -64311,14 +64359,14 @@ function pruneZombieEngineerWirings(settings, hookDir) {
64311
64359
  for (const group of groups) {
64312
64360
  if (!("hooks" in group) || !Array.isArray(group.hooks)) {
64313
64361
  const entry = group;
64314
- if (shouldPruneEntry(entry, hookDir, pruned)) {
64362
+ if (shouldPruneEntry(entry, hookDir, pruned, normalizedPreserveCommands)) {
64315
64363
  continue;
64316
64364
  }
64317
64365
  keptGroups.push(group);
64318
64366
  continue;
64319
64367
  }
64320
64368
  const keptHooks = group.hooks.filter((h2) => {
64321
- return !shouldPruneEntry(h2, hookDir, pruned);
64369
+ return !shouldPruneEntry(h2, hookDir, pruned, normalizedPreserveCommands);
64322
64370
  });
64323
64371
  if (keptHooks.length > 0) {
64324
64372
  keptGroups.push({ ...group, hooks: keptHooks });
@@ -64335,13 +64383,16 @@ function pruneZombieEngineerWirings(settings, hookDir) {
64335
64383
  }
64336
64384
  return { settings, pruned };
64337
64385
  }
64338
- function shouldPruneEntry(entry, hookDir, pruned) {
64386
+ function shouldPruneEntry(entry, hookDir, pruned, preserveCommands) {
64339
64387
  if (isLegacyDescriptiveNamePrompt(entry)) {
64340
64388
  pruned.push("legacy-descriptive-name-prompt");
64341
64389
  return true;
64342
64390
  }
64343
64391
  if (entry._origin !== "engineer")
64344
64392
  return false;
64393
+ if (entry.command && preserveCommands.has(normalizeCommand(entry.command))) {
64394
+ return false;
64395
+ }
64345
64396
  const filePath = extractHookFilePath(entry.command, hookDir);
64346
64397
  if (!filePath)
64347
64398
  return false;
@@ -64426,7 +64477,9 @@ function extractHookFilePath(command, hookDir) {
64426
64477
  }
64427
64478
  return null;
64428
64479
  }
64429
- var init_zombie_wirings_pruner = () => {};
64480
+ var init_zombie_wirings_pruner = __esm(() => {
64481
+ init_command_normalizer();
64482
+ });
64430
64483
 
64431
64484
  // src/domains/health-checks/checkers/shared.ts
64432
64485
  function shouldSkipExpensiveOperations2() {
@@ -65368,6 +65421,17 @@ async function checkHookFileReferences(projectDir) {
65368
65421
  }
65369
65422
  };
65370
65423
  }
65424
+ async function countMissingHookFileReferences(projectDir = process.cwd()) {
65425
+ const settingsFiles = getClaudeSettingsFiles(projectDir);
65426
+ let count = 0;
65427
+ for (const settingsFile of settingsFiles) {
65428
+ const settings = await SettingsMerger.readSettingsFile(settingsFile.path);
65429
+ if (!settings)
65430
+ continue;
65431
+ count += collectMissingHookReferences(settings, settingsFile, projectDir).length;
65432
+ }
65433
+ return count;
65434
+ }
65371
65435
  async function repairMissingHookFileReferences(projectDir = process.cwd()) {
65372
65436
  const result = await checkHookFileReferences(projectDir);
65373
65437
  if (result.status !== "fail" || !result.fix) {
@@ -67331,7 +67395,7 @@ import { exec as exec2, spawn as spawn2 } from "node:child_process";
67331
67395
  import { existsSync as existsSync47 } from "node:fs";
67332
67396
  import { readdir as readdir19 } from "node:fs/promises";
67333
67397
  import { builtinModules } from "node:module";
67334
- import { join as join68 } from "node:path";
67398
+ import { dirname as dirname29, join as join68 } from "node:path";
67335
67399
  import { promisify as promisify9 } from "node:util";
67336
67400
  function selectKitForUpdate(params) {
67337
67401
  const { hasLocal, hasGlobal, localKits, globalKits } = params;
@@ -67380,7 +67444,7 @@ async function readMetadataFile(claudeDir3) {
67380
67444
  return null;
67381
67445
  }
67382
67446
  }
67383
- function buildInitCommand(isGlobal, kit, beta, yes) {
67447
+ function buildInitCommand(isGlobal, kit, beta, yes, restoreCkHooks) {
67384
67448
  const parts = ["ck init"];
67385
67449
  if (isGlobal)
67386
67450
  parts.push("-g");
@@ -67388,6 +67452,8 @@ function buildInitCommand(isGlobal, kit, beta, yes) {
67388
67452
  parts.push(`--kit ${kit}`);
67389
67453
  if (yes)
67390
67454
  parts.push("--yes");
67455
+ if (restoreCkHooks)
67456
+ parts.push("--restore-ck-hooks");
67391
67457
  parts.push("--install-skills");
67392
67458
  if (beta)
67393
67459
  parts.push("--beta");
@@ -67464,19 +67530,49 @@ async function promptKitUpdate(beta, yes, deps) {
67464
67530
  const globalMetadata = hasGlobal ? await readMetadataFile(setup.global.path) : null;
67465
67531
  const localKits = localMetadata ? getInstalledKits(localMetadata) : [];
67466
67532
  const globalKits = globalMetadata ? getInstalledKits(globalMetadata) : [];
67467
- const selection = selectKitForUpdate({ hasLocal, hasGlobal, localKits, globalKits });
67533
+ let selection = selectKitForUpdate({ hasLocal, hasGlobal, localKits, globalKits });
67468
67534
  if (!selection) {
67469
67535
  logger.verbose("No ClaudeKit installations detected, skipping kit update prompt");
67470
67536
  return;
67471
67537
  }
67472
- const kitVersion = selection.kit ? selection.isGlobal ? globalMetadata?.kits?.[selection.kit]?.version : localMetadata?.kits?.[selection.kit]?.version : undefined;
67538
+ let forceKitReinstall = false;
67539
+ if (hasLocal && setup.project.path) {
67540
+ try {
67541
+ const missingHookDeps = await findMissingHookDepsFn(setup.project.path);
67542
+ if (missingHookDeps.length > 0) {
67543
+ logger.warning(`Detected ${missingHookDeps.length} local missing hook dependency(ies); reinstalling local kit content`);
67544
+ forceKitReinstall = true;
67545
+ }
67546
+ } catch (error) {
67547
+ logger.verbose(`Local hook dependency self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67548
+ }
67549
+ try {
67550
+ const countMissingHookRefsFn = deps?.countMissingHookFileReferencesFn ?? countMissingHookFileReferences;
67551
+ const missingHookRefs = await countMissingHookRefsFn(dirname29(setup.project.path));
67552
+ if (missingHookRefs > 0) {
67553
+ logger.warning(`Detected ${missingHookRefs} local broken hook registration(s); reinstalling local kit content`);
67554
+ forceKitReinstall = true;
67555
+ }
67556
+ } catch (error) {
67557
+ logger.verbose(`Local hook registration self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67558
+ }
67559
+ if (forceKitReinstall && selection.isGlobal) {
67560
+ const kit = localKits[0] || selection.kit;
67561
+ selection = {
67562
+ isGlobal: false,
67563
+ kit,
67564
+ promptMessage: `Update local project ClaudeKit content${kit ? ` (${kit})` : ""}?`
67565
+ };
67566
+ }
67567
+ }
67568
+ let kitVersion = selection.kit ? selection.isGlobal ? globalMetadata?.kits?.[selection.kit]?.version : localMetadata?.kits?.[selection.kit]?.version : undefined;
67473
67569
  const isBetaInstalled = isBetaVersion(kitVersion);
67474
67570
  const promptMessage = selection.promptMessage;
67475
67571
  if (selection.kit && kitVersion) {
67476
67572
  logger.info(`Current kit version: ${selection.kit}@${kitVersion}`);
67477
67573
  }
67478
67574
  let alreadyAtLatest = false;
67479
- if (yes && selection.kit && kitVersion) {
67575
+ if (yes && selection.kit && kitVersion && !forceKitReinstall) {
67480
67576
  const getTagFn = deps?.getLatestReleaseTagFn ?? fetchLatestReleaseTag;
67481
67577
  const latestTag = await getTagFn(selection.kit, beta || isBetaInstalled);
67482
67578
  if (latestTag && versionsMatch(kitVersion, latestTag)) {
@@ -67492,11 +67588,34 @@ async function promptKitUpdate(beta, yes, deps) {
67492
67588
  if (missingHookDeps.length > 0) {
67493
67589
  logger.warning(`Detected ${missingHookDeps.length} missing hook dependency(ies); reinstalling kit content`);
67494
67590
  alreadyAtLatest = false;
67591
+ forceKitReinstall = true;
67495
67592
  }
67496
67593
  } catch (error) {
67497
67594
  logger.verbose(`Hook dependency self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67498
67595
  }
67499
67596
  }
67597
+ if (alreadyAtLatest) {
67598
+ try {
67599
+ const countMissingHookRefsFn = deps?.countMissingHookFileReferencesFn ?? countMissingHookFileReferences;
67600
+ const projectDir = setup.project.path ? dirname29(setup.project.path) : process.cwd();
67601
+ const missingHookRefs = await countMissingHookRefsFn(projectDir);
67602
+ if (missingHookRefs > 0) {
67603
+ logger.warning(`Detected ${missingHookRefs} broken hook registration(s); reinstalling kit content`);
67604
+ alreadyAtLatest = false;
67605
+ forceKitReinstall = true;
67606
+ if (setup.project.path && selection.isGlobal) {
67607
+ selection = {
67608
+ isGlobal: false,
67609
+ kit: localKits[0] || selection.kit,
67610
+ promptMessage: `Update local project ClaudeKit content${localKits[0] || selection.kit ? ` (${localKits[0] || selection.kit})` : ""}?`
67611
+ };
67612
+ kitVersion = selection.kit ? localMetadata?.kits?.[selection.kit]?.version : undefined;
67613
+ }
67614
+ }
67615
+ } catch (error) {
67616
+ logger.verbose(`Hook registration self-heal check skipped: ${error instanceof Error ? error.message : "unknown"}`);
67617
+ }
67618
+ }
67500
67619
  let autoInit = false;
67501
67620
  try {
67502
67621
  const ckConfig = await loadFullConfigFn(null);
@@ -67520,7 +67639,7 @@ async function promptKitUpdate(beta, yes, deps) {
67520
67639
  }
67521
67640
  const useBeta = beta || isBetaInstalled;
67522
67641
  if (yes) {
67523
- const initCmd = buildInitCommand(selection.isGlobal, selection.kit, useBeta, true);
67642
+ const initCmd = buildInitCommand(selection.isGlobal, selection.kit, useBeta, true, forceKitReinstall);
67524
67643
  logger.info(`Running: ${initCmd}`);
67525
67644
  const s = (deps?.spinnerFn ?? de)();
67526
67645
  s.start("Updating ClaudeKit content...");
@@ -67553,6 +67672,8 @@ async function promptKitUpdate(beta, yes, deps) {
67553
67672
  const args = ["init"];
67554
67673
  if (selection.isGlobal)
67555
67674
  args.push("-g");
67675
+ if (forceKitReinstall)
67676
+ args.push("--restore-ck-hooks");
67556
67677
  args.push("--install-skills");
67557
67678
  if (useBeta)
67558
67679
  args.push("--beta");
@@ -67622,17 +67743,19 @@ async function promptMigrateUpdate(deps) {
67622
67743
  } catch {}
67623
67744
  try {
67624
67745
  const cleanupFn = deps?.cleanupMigratedHooksFn ?? (await Promise.resolve().then(() => (init_migrated_hooks_cleanup(), exports_migrated_hooks_cleanup))).cleanupMigratedHooksForProviders;
67625
- const cleanupProviders = allProviders.filter((p) => SAFE_PROVIDER_NAME.test(p));
67626
- const cleanupResults = await cleanupFn(cleanupProviders, { global: isGlobal });
67627
- const cleanupCount = cleanupResults.reduce((total, result) => total + result.hooksPruned + result.filesRemoved + result.registryEntriesRemoved, 0);
67628
- if (cleanupCount > 0) {
67629
- logger.info(`Cleaned up ${cleanupCount} generated-context hook artifact(s)`);
67746
+ const cleanupProviders = allProviders.filter((p) => p !== "claude-code" && SAFE_PROVIDER_NAME.test(p));
67747
+ if (cleanupProviders.length > 0) {
67748
+ const cleanupResults = await cleanupFn(cleanupProviders, { global: isGlobal });
67749
+ const cleanupCount = cleanupResults.reduce((total, result) => total + result.hooksPruned + result.filesRemoved + result.registryEntriesRemoved, 0);
67750
+ if (cleanupCount > 0) {
67751
+ logger.info(`Cleaned up ${cleanupCount} generated-context hook artifact(s)`);
67752
+ }
67753
+ await repairLegacyHookPromptsSafely();
67754
+ await repairHookFileReferencesSafely();
67630
67755
  }
67631
67756
  } catch (error) {
67632
67757
  logger.verbose(`Migrated hook cleanup skipped: ${error instanceof Error ? error.message : "unknown"}`);
67633
67758
  }
67634
- await repairLegacyHookPromptsSafely();
67635
- await repairHookFileReferencesSafely();
67636
67759
  const targets = allProviders.filter((p) => p !== "claude-code");
67637
67760
  if (targets.length === 0) {
67638
67761
  logger.verbose("No migration targets detected, skipping migrate step");
@@ -68560,7 +68683,7 @@ var init_routes = __esm(() => {
68560
68683
 
68561
68684
  // src/domains/web-server/static-server.ts
68562
68685
  import { existsSync as existsSync49 } from "node:fs";
68563
- import { basename as basename24, dirname as dirname29, join as join71, resolve as resolve34 } from "node:path";
68686
+ import { basename as basename24, dirname as dirname30, join as join71, resolve as resolve34 } from "node:path";
68564
68687
  import { fileURLToPath as fileURLToPath2 } from "node:url";
68565
68688
  function addRuntimeUiCandidate(candidates, runtimePath) {
68566
68689
  if (!runtimePath) {
@@ -68570,7 +68693,7 @@ function addRuntimeUiCandidate(candidates, runtimePath) {
68570
68693
  if (!looksLikePath) {
68571
68694
  return;
68572
68695
  }
68573
- const entryDir = dirname29(resolve34(runtimePath));
68696
+ const entryDir = dirname30(resolve34(runtimePath));
68574
68697
  if (basename24(entryDir) === "dist") {
68575
68698
  candidates.add(join71(entryDir, "ui"));
68576
68699
  }
@@ -68631,7 +68754,7 @@ var import_express, __dirname3;
68631
68754
  var init_static_server = __esm(() => {
68632
68755
  init_logger();
68633
68756
  import_express = __toESM(require_express2(), 1);
68634
- __dirname3 = dirname29(fileURLToPath2(import.meta.url));
68757
+ __dirname3 = dirname30(fileURLToPath2(import.meta.url));
68635
68758
  });
68636
68759
 
68637
68760
  // node_modules/ws/lib/constants.js
@@ -74141,7 +74264,7 @@ var init_skills_installer2 = __esm(() => {
74141
74264
  // src/services/package-installer/gemini-mcp/config-manager.ts
74142
74265
  import { existsSync as existsSync62 } from "node:fs";
74143
74266
  import { mkdir as mkdir23, readFile as readFile47, writeFile as writeFile23 } from "node:fs/promises";
74144
- import { dirname as dirname32, join as join92 } from "node:path";
74267
+ import { dirname as dirname33, join as join92 } from "node:path";
74145
74268
  async function readJsonFile(filePath) {
74146
74269
  try {
74147
74270
  const content = await readFile47(filePath, "utf-8");
@@ -74181,7 +74304,7 @@ ${geminiPattern}
74181
74304
  }
74182
74305
  }
74183
74306
  async function createNewSettingsWithMerge(geminiSettingsPath, mcpConfigPath) {
74184
- const linkDir = dirname32(geminiSettingsPath);
74307
+ const linkDir = dirname33(geminiSettingsPath);
74185
74308
  if (!existsSync62(linkDir)) {
74186
74309
  await mkdir23(linkDir, { recursive: true });
74187
74310
  logger.debug(`Created directory: ${linkDir}`);
@@ -74300,9 +74423,9 @@ var init_validation = __esm(() => {
74300
74423
  // src/services/package-installer/gemini-mcp/linker-core.ts
74301
74424
  import { existsSync as existsSync64 } from "node:fs";
74302
74425
  import { mkdir as mkdir24, symlink as symlink3 } from "node:fs/promises";
74303
- import { dirname as dirname33, join as join94 } from "node:path";
74426
+ import { dirname as dirname34, join as join94 } from "node:path";
74304
74427
  async function createSymlink(targetPath, linkPath, projectDir, isGlobal) {
74305
- const linkDir = dirname33(linkPath);
74428
+ const linkDir = dirname34(linkPath);
74306
74429
  if (!existsSync64(linkDir)) {
74307
74430
  await mkdir24(linkDir, { recursive: true });
74308
74431
  logger.debug(`Created directory: ${linkDir}`);
@@ -77649,7 +77772,7 @@ var init_sqlite_client = () => {};
77649
77772
 
77650
77773
  // src/commands/content/phases/db-manager.ts
77651
77774
  import { existsSync as existsSync83, mkdirSync as mkdirSync8 } from "node:fs";
77652
- import { dirname as dirname51 } from "node:path";
77775
+ import { dirname as dirname52 } from "node:path";
77653
77776
  function initDatabase(dbPath) {
77654
77777
  ensureParentDir(dbPath);
77655
77778
  const db = openDatabase(dbPath);
@@ -77670,7 +77793,7 @@ function runRetentionCleanup(db, retentionDays = 90) {
77670
77793
  db.prepare("DELETE FROM git_events WHERE processed = 1 AND created_at < ?").run(cutoff);
77671
77794
  }
77672
77795
  function ensureParentDir(dbPath) {
77673
- const dir = dirname51(dbPath);
77796
+ const dir = dirname52(dbPath);
77674
77797
  if (dir && !existsSync83(dir)) {
77675
77798
  mkdirSync8(dir, { recursive: true });
77676
77799
  }
@@ -80691,6 +80814,10 @@ var init_init_command_help = __esm(() => {
80691
80814
  {
80692
80815
  flags: "--force-overwrite-settings",
80693
80816
  description: "Fully replace settings.json instead of selective merge"
80817
+ },
80818
+ {
80819
+ flags: "--restore-ck-hooks",
80820
+ description: "Restore CK-managed hook registrations during update self-heal"
80694
80821
  }
80695
80822
  ]
80696
80823
  },
@@ -88165,7 +88292,7 @@ init_path_resolver();
88165
88292
  import { existsSync as existsSync58 } from "node:fs";
88166
88293
  import { readFile as readFile42 } from "node:fs/promises";
88167
88294
  import { homedir as homedir43 } from "node:os";
88168
- import { dirname as dirname30, join as join80, normalize as normalize6, resolve as resolve36 } from "node:path";
88295
+ import { dirname as dirname31, join as join80, normalize as normalize6, resolve as resolve36 } from "node:path";
88169
88296
  async function checkPathRefsValid(projectDir) {
88170
88297
  const globalClaudeMd = join80(PathResolver.getGlobalKitDir(), "CLAUDE.md");
88171
88298
  const projectClaudeMd = join80(projectDir, ".claude", "CLAUDE.md");
@@ -88196,7 +88323,7 @@ async function checkPathRefsValid(projectDir) {
88196
88323
  autoFixable: false
88197
88324
  };
88198
88325
  }
88199
- const baseDir = dirname30(claudeMdPath);
88326
+ const baseDir = dirname31(claudeMdPath);
88200
88327
  const home5 = homedir43();
88201
88328
  const broken = [];
88202
88329
  for (const ref of refs) {
@@ -90028,14 +90155,14 @@ class AutoHealer {
90028
90155
  import { execSync as execSync4, spawnSync as spawnSync6 } from "node:child_process";
90029
90156
  import { readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
90030
90157
  import { tmpdir as tmpdir3 } from "node:os";
90031
- import { dirname as dirname31, join as join87 } from "node:path";
90158
+ import { dirname as dirname32, join as join87 } from "node:path";
90032
90159
  import { fileURLToPath as fileURLToPath4 } from "node:url";
90033
90160
  init_environment();
90034
90161
  init_logger();
90035
90162
  init_dist2();
90036
90163
  function getCliVersion4() {
90037
90164
  try {
90038
- const __dirname4 = dirname31(fileURLToPath4(import.meta.url));
90165
+ const __dirname4 = dirname32(fileURLToPath4(import.meta.url));
90039
90166
  const pkgPath = join87(__dirname4, "../../../package.json");
90040
90167
  const pkg = JSON.parse(readFileSync17(pkgPath, "utf-8"));
90041
90168
  return pkg.version || "unknown";
@@ -94638,7 +94765,7 @@ import path10 from "node:path";
94638
94765
 
94639
94766
  // node_modules/tar/dist/esm/list.js
94640
94767
  import fs10 from "node:fs";
94641
- import { dirname as dirname34, parse as parse4 } from "path";
94768
+ import { dirname as dirname35, parse as parse4 } from "path";
94642
94769
 
94643
94770
  // node_modules/tar/dist/esm/options.js
94644
94771
  var argmap = new Map([
@@ -97538,7 +97665,7 @@ var filesFilter = (opt, files) => {
97538
97665
  if (m2 !== undefined) {
97539
97666
  ret = m2;
97540
97667
  } else {
97541
- ret = mapHas(dirname34(file), root);
97668
+ ret = mapHas(dirname35(file), root);
97542
97669
  }
97543
97670
  }
97544
97671
  map.set(file, ret);
@@ -100597,7 +100724,7 @@ import { promisify as promisify15 } from "node:util";
100597
100724
  // src/domains/installation/extraction/native-zip-commands.ts
100598
100725
  var NATIVE_EXTRACT_TIMEOUT_MS = 120000;
100599
100726
  function getNativeZipCommands(archivePath, destDir, platformName = process.platform) {
100600
- if (platformName === "darwin") {
100727
+ if (platformName === "darwin" || platformName === "linux") {
100601
100728
  return [
100602
100729
  {
100603
100730
  label: "native unzip",
@@ -101281,7 +101408,7 @@ import { join as join120 } from "node:path";
101281
101408
 
101282
101409
  // src/domains/installation/deletion-handler.ts
101283
101410
  import { existsSync as existsSync65, lstatSync as lstatSync3, readdirSync as readdirSync9, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync4 } from "node:fs";
101284
- import { dirname as dirname36, join as join106, relative as relative21, resolve as resolve41, sep as sep12 } from "node:path";
101411
+ import { dirname as dirname37, join as join106, relative as relative21, resolve as resolve41, sep as sep12 } from "node:path";
101285
101412
 
101286
101413
  // src/services/file-operations/manifest/manifest-reader.ts
101287
101414
  init_metadata_migration();
@@ -101507,7 +101634,7 @@ function expandGlobPatterns(patterns, claudeDir3) {
101507
101634
  var MAX_CLEANUP_ITERATIONS = 50;
101508
101635
  function cleanupEmptyDirectories(filePath, claudeDir3) {
101509
101636
  const normalizedClaudeDir = resolve41(claudeDir3);
101510
- let currentDir = resolve41(dirname36(filePath));
101637
+ let currentDir = resolve41(dirname37(filePath));
101511
101638
  let iterations = 0;
101512
101639
  while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir) && iterations < MAX_CLEANUP_ITERATIONS) {
101513
101640
  iterations++;
@@ -101516,7 +101643,7 @@ function cleanupEmptyDirectories(filePath, claudeDir3) {
101516
101643
  if (entries.length === 0) {
101517
101644
  rmdirSync(currentDir);
101518
101645
  logger.debug(`Removed empty directory: ${currentDir}`);
101519
- currentDir = resolve41(dirname36(currentDir));
101646
+ currentDir = resolve41(dirname37(currentDir));
101520
101647
  } else {
101521
101648
  break;
101522
101649
  }
@@ -101639,7 +101766,7 @@ init_logger();
101639
101766
  init_types3();
101640
101767
  var import_fs_extra15 = __toESM(require_lib(), 1);
101641
101768
  var import_ignore3 = __toESM(require_ignore(), 1);
101642
- import { dirname as dirname39, join as join110, relative as relative23 } from "node:path";
101769
+ import { dirname as dirname40, join as join110, relative as relative23 } from "node:path";
101643
101770
 
101644
101771
  // src/domains/installation/selective-merger.ts
101645
101772
  import { stat as stat18 } from "node:fs/promises";
@@ -103310,13 +103437,13 @@ class FileScanner {
103310
103437
  // src/domains/installation/merger/settings-processor.ts
103311
103438
  import { execSync as execSync5 } from "node:child_process";
103312
103439
  import { homedir as homedir46 } from "node:os";
103313
- import { dirname as dirname38, join as join109 } from "node:path";
103440
+ import { dirname as dirname39, join as join109 } from "node:path";
103314
103441
 
103315
103442
  // src/domains/config/installed-settings-tracker.ts
103316
103443
  init_shared();
103317
103444
  import { existsSync as existsSync66 } from "node:fs";
103318
103445
  import { mkdir as mkdir31, readFile as readFile50, writeFile as writeFile25 } from "node:fs/promises";
103319
- import { dirname as dirname37, join as join108 } from "node:path";
103446
+ import { dirname as dirname38, join as join108 } from "node:path";
103320
103447
  var CK_JSON_FILE = ".ck.json";
103321
103448
 
103322
103449
  class InstalledSettingsTracker {
@@ -103341,7 +103468,7 @@ class InstalledSettingsTracker {
103341
103468
  }
103342
103469
  try {
103343
103470
  const content = await readFile50(ckJsonPath, "utf-8");
103344
- const data = JSON.parse(content);
103471
+ const data = parseJsonContent(content);
103345
103472
  const installed = data.kits?.[this.kitName]?.installedSettings;
103346
103473
  if (installed) {
103347
103474
  return installed;
@@ -103358,7 +103485,7 @@ class InstalledSettingsTracker {
103358
103485
  let data = {};
103359
103486
  if (existsSync66(ckJsonPath)) {
103360
103487
  const content = await readFile50(ckJsonPath, "utf-8");
103361
- data = JSON.parse(content);
103488
+ data = parseJsonContent(content);
103362
103489
  }
103363
103490
  if (!data.kits) {
103364
103491
  data.kits = {};
@@ -103367,7 +103494,7 @@ class InstalledSettingsTracker {
103367
103494
  data.kits[this.kitName] = {};
103368
103495
  }
103369
103496
  data.kits[this.kitName].installedSettings = settings;
103370
- await mkdir31(dirname37(ckJsonPath), { recursive: true });
103497
+ await mkdir31(dirname38(ckJsonPath), { recursive: true });
103371
103498
  await writeFile25(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
103372
103499
  logger.debug(`Saved installed settings to ${ckJsonPath}`);
103373
103500
  } catch (error) {
@@ -103424,6 +103551,7 @@ class SettingsProcessor {
103424
103551
  installingKit;
103425
103552
  cachedVersion = undefined;
103426
103553
  deletionPatterns = [];
103554
+ restoreCkHooks = false;
103427
103555
  zombiePrunerHookDir = null;
103428
103556
  setGlobalFlag(isGlobal) {
103429
103557
  this.isGlobal = isGlobal;
@@ -103431,6 +103559,9 @@ class SettingsProcessor {
103431
103559
  setForceOverwriteSettings(force) {
103432
103560
  this.forceOverwriteSettings = force;
103433
103561
  }
103562
+ setRestoreCkHooks(restore) {
103563
+ this.restoreCkHooks = restore;
103564
+ }
103434
103565
  setProjectDir(dir) {
103435
103566
  this.projectDir = dir;
103436
103567
  this.initTracker();
@@ -103475,6 +103606,7 @@ class SettingsProcessor {
103475
103606
  } else {
103476
103607
  try {
103477
103608
  const parsedSettings = JSON.parse(transformedSource);
103609
+ await this.applyDisabledHookConfig(parsedSettings);
103478
103610
  this.logHookCommandRepair(this.fixHookCommandPaths(parsedSettings), "fresh install");
103479
103611
  await SettingsMerger.writeSettingsFile(destFile, parsedSettings);
103480
103612
  try {
@@ -103504,6 +103636,7 @@ class SettingsProcessor {
103504
103636
  let sourceSettings;
103505
103637
  try {
103506
103638
  sourceSettings = JSON.parse(transformedSourceContent);
103639
+ await this.applyDisabledHookConfig(sourceSettings);
103507
103640
  } catch {
103508
103641
  logger.warning("Failed to parse source settings.json, falling back to overwrite");
103509
103642
  const formattedContent = this.formatJsonContent(transformedSourceContent);
@@ -103526,10 +103659,15 @@ class SettingsProcessor {
103526
103659
  if (this.tracker) {
103527
103660
  installedSettings = await this.tracker.loadInstalledSettings();
103528
103661
  }
103662
+ const mergeInstalledSettings = this.restoreCkHooks ? { ...installedSettings, hooks: [] } : installedSettings;
103529
103663
  const mergeResult = SettingsMerger.merge(sourceSettings, destSettings, {
103530
- installedSettings,
103664
+ installedSettings: mergeInstalledSettings,
103531
103665
  sourceKit: this.installingKit
103532
103666
  });
103667
+ await this.applyDisabledHookConfig(mergeResult.merged);
103668
+ if (this.restoreCkHooks) {
103669
+ logger.info("Restored CK hook registrations while respecting .ck.json hook disables");
103670
+ }
103533
103671
  logger.verbose("Settings merge details", {
103534
103672
  hooksAdded: mergeResult.hooksAdded,
103535
103673
  hooksPreserved: mergeResult.hooksPreserved,
@@ -103559,7 +103697,8 @@ class SettingsProcessor {
103559
103697
  logger.info(`Pruned ${hooksPruned} stale hook(s) referencing deleted files`);
103560
103698
  }
103561
103699
  if (this.zombiePrunerHookDir) {
103562
- const { pruned: zombiePruned } = pruneZombieEngineerWirings(mergeResult.merged, this.zombiePrunerHookDir);
103700
+ const sourceHookCommands = this.collectHookCommands(sourceSettings);
103701
+ const { pruned: zombiePruned } = pruneZombieEngineerWirings(mergeResult.merged, this.zombiePrunerHookDir, sourceHookCommands);
103563
103702
  if (zombiePruned.length > 0) {
103564
103703
  logger.info(`Pruned ${zombiePruned.length} zombie hook entries: ${zombiePruned.join(", ")}`);
103565
103704
  }
@@ -103568,6 +103707,111 @@ class SettingsProcessor {
103568
103707
  logger.success("Merged settings.json (user customizations preserved)");
103569
103708
  await this.injectTeamHooksIfSupported(destFile, mergeResult.merged);
103570
103709
  }
103710
+ async getDisabledHookNames() {
103711
+ if (!this.projectDir) {
103712
+ return new Set;
103713
+ }
103714
+ const disabled = new Set;
103715
+ const addFromConfig = async (configPath) => {
103716
+ const names = await this.readDisabledHookNamesFromConfig(configPath);
103717
+ for (const name2 of names)
103718
+ disabled.add(name2);
103719
+ };
103720
+ try {
103721
+ if (this.isGlobal) {
103722
+ await addFromConfig(join109(this.projectDir, ".ck.json"));
103723
+ } else {
103724
+ await addFromConfig(join109(PathResolver.getGlobalKitDir(), ".ck.json"));
103725
+ await addFromConfig(join109(this.projectDir, ".claude", ".ck.json"));
103726
+ }
103727
+ } catch (error) {
103728
+ logger.debug(`Failed to load .ck.json hook preferences: ${error instanceof Error ? error.message : "unknown"}`);
103729
+ }
103730
+ return disabled;
103731
+ }
103732
+ async readDisabledHookNamesFromConfig(configPath) {
103733
+ if (!await import_fs_extra14.pathExists(configPath))
103734
+ return new Set;
103735
+ const raw2 = parseJsonContent(await import_fs_extra14.readFile(configPath, "utf-8"));
103736
+ const hooks = raw2.hooks;
103737
+ if (!hooks || typeof hooks !== "object")
103738
+ return new Set;
103739
+ return new Set(Object.entries(hooks).filter(([, enabled]) => enabled === false).map(([name2]) => name2));
103740
+ }
103741
+ async applyDisabledHookConfig(settings) {
103742
+ const disabledHooks = await this.getDisabledHookNames();
103743
+ if (disabledHooks.size === 0 || !settings.hooks)
103744
+ return 0;
103745
+ let removed = 0;
103746
+ const hooksRecord = settings.hooks;
103747
+ for (const [eventName, entries] of Object.entries(hooksRecord)) {
103748
+ const filteredEntries = [];
103749
+ for (const entry of entries) {
103750
+ if (Array.isArray(entry.hooks)) {
103751
+ const keptHooks = entry.hooks.filter((hook) => {
103752
+ const command = typeof hook.command === "string" ? hook.command : "";
103753
+ const hookName = this.extractCkHookName(command);
103754
+ if (hookName && disabledHooks.has(hookName)) {
103755
+ removed++;
103756
+ return false;
103757
+ }
103758
+ return true;
103759
+ });
103760
+ if (keptHooks.length > 0) {
103761
+ filteredEntries.push({ ...entry, hooks: keptHooks });
103762
+ }
103763
+ } else {
103764
+ const command = typeof entry.command === "string" ? entry.command : "";
103765
+ const hookName = this.extractCkHookName(command);
103766
+ if (hookName && disabledHooks.has(hookName)) {
103767
+ removed++;
103768
+ continue;
103769
+ }
103770
+ filteredEntries.push(entry);
103771
+ }
103772
+ }
103773
+ if (filteredEntries.length > 0) {
103774
+ hooksRecord[eventName] = filteredEntries;
103775
+ } else {
103776
+ delete hooksRecord[eventName];
103777
+ }
103778
+ }
103779
+ if (Object.keys(hooksRecord).length === 0) {
103780
+ settings.hooks = undefined;
103781
+ }
103782
+ if (removed > 0) {
103783
+ logger.info(`Skipped ${removed} hook registration(s) disabled in .ck.json`);
103784
+ }
103785
+ return removed;
103786
+ }
103787
+ collectHookCommands(settings) {
103788
+ const commands = new Set;
103789
+ if (!settings.hooks)
103790
+ return commands;
103791
+ for (const entries of Object.values(settings.hooks)) {
103792
+ for (const entry of entries) {
103793
+ if ("hooks" in entry && Array.isArray(entry.hooks)) {
103794
+ for (const hook of entry.hooks) {
103795
+ if (typeof hook.command === "string") {
103796
+ commands.add(hook.command);
103797
+ }
103798
+ }
103799
+ continue;
103800
+ }
103801
+ if ("command" in entry && typeof entry.command === "string") {
103802
+ commands.add(entry.command);
103803
+ }
103804
+ }
103805
+ }
103806
+ return commands;
103807
+ }
103808
+ extractCkHookName(command) {
103809
+ if (!command.trim().startsWith("node "))
103810
+ return null;
103811
+ const normalized = command.replace(/\\/g, "/");
103812
+ const match2 = normalized.match(/\/hooks\/([^/"'\s]+)\.(?:cjs|mjs|js)(?:["'\s]|$)/);
103813
+ return match2?.[1] ?? null;
103814
+ }
103571
103815
  migrateDeprecatedMatchers(destSettings, sourceSettings) {
103572
103816
  if (!destSettings.hooks || !sourceSettings.hooks)
103573
103817
  return;
@@ -103829,7 +104073,7 @@ class SettingsProcessor {
103829
104073
  return true;
103830
104074
  }
103831
104075
  async repairSiblingSettingsLocal(destFile) {
103832
- const settingsLocalPath = join109(dirname38(destFile), "settings.local.json");
104076
+ const settingsLocalPath = join109(dirname39(destFile), "settings.local.json");
103833
104077
  if (settingsLocalPath === destFile || !await import_fs_extra14.pathExists(settingsLocalPath)) {
103834
104078
  return;
103835
104079
  }
@@ -103960,6 +104204,9 @@ class CopyExecutor {
103960
104204
  setForceOverwriteSettings(force) {
103961
104205
  this.settingsProcessor.setForceOverwriteSettings(force);
103962
104206
  }
104207
+ setRestoreCkHooks(restore) {
104208
+ this.settingsProcessor.setRestoreCkHooks(restore);
104209
+ }
103963
104210
  setDeletions(deletions) {
103964
104211
  this.settingsProcessor.setDeletions(deletions);
103965
104212
  }
@@ -104092,10 +104339,10 @@ class CopyExecutor {
104092
104339
  }
104093
104340
  trackInstalledFile(relativePath) {
104094
104341
  this.installedFiles.add(relativePath);
104095
- let dir = dirname39(relativePath);
104342
+ let dir = dirname40(relativePath);
104096
104343
  while (dir && dir !== "." && dir !== "/") {
104097
104344
  this.installedDirectories.add(`${dir}/`);
104098
- dir = dirname39(dir);
104345
+ dir = dirname40(dir);
104099
104346
  }
104100
104347
  }
104101
104348
  }
@@ -104132,6 +104379,9 @@ class FileMerger {
104132
104379
  setForceOverwriteSettings(force) {
104133
104380
  this.copyExecutor.setForceOverwriteSettings(force);
104134
104381
  }
104382
+ setRestoreCkHooks(restore) {
104383
+ this.copyExecutor.setRestoreCkHooks(restore);
104384
+ }
104135
104385
  setProjectDir(dir) {
104136
104386
  this.copyExecutor.setProjectDir(dir);
104137
104387
  }
@@ -105455,6 +105705,7 @@ async function handleMerge(ctx) {
105455
105705
  }
105456
105706
  merger.setGlobalFlag(ctx.options.global);
105457
105707
  merger.setForceOverwriteSettings(ctx.options.forceOverwriteSettings);
105708
+ merger.setRestoreCkHooks(ctx.options.restoreCkHooks);
105458
105709
  merger.setProjectDir(ctx.resolvedDir);
105459
105710
  merger.setKitName(ctx.kit.name);
105460
105711
  merger.setZombiePrunerHookDir(join120(ctx.claudeDir, "hooks"));
@@ -106942,6 +107193,7 @@ async function resolveOptions(ctx) {
106942
107193
  skipSetup: parsed.skipSetup ?? false,
106943
107194
  forceOverwrite: parsed.forceOverwrite ?? false,
106944
107195
  forceOverwriteSettings: parsed.forceOverwriteSettings ?? false,
107196
+ restoreCkHooks: parsed.restoreCkHooks ?? false,
106945
107197
  dryRun: parsed.dryRun ?? false,
106946
107198
  prefix: parsed.prefix ?? false,
106947
107199
  sync: parsed.sync ?? false,
@@ -107249,7 +107501,7 @@ async function runPreflightChecks() {
107249
107501
  // src/domains/installation/fresh-installer.ts
107250
107502
  init_metadata_migration();
107251
107503
  import { existsSync as existsSync67, readdirSync as readdirSync10, rmSync as rmSync3, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
107252
- import { basename as basename28, dirname as dirname40, join as join132, resolve as resolve45 } from "node:path";
107504
+ import { basename as basename28, dirname as dirname41, join as join132, resolve as resolve45 } from "node:path";
107253
107505
  init_logger();
107254
107506
  init_safe_spinner();
107255
107507
  var import_fs_extra34 = __toESM(require_lib(), 1);
@@ -107302,14 +107554,14 @@ async function analyzeFreshInstallation(claudeDir3) {
107302
107554
  }
107303
107555
  function cleanupEmptyDirectories2(filePath, claudeDir3) {
107304
107556
  const normalizedClaudeDir = resolve45(claudeDir3);
107305
- let currentDir = resolve45(dirname40(filePath));
107557
+ let currentDir = resolve45(dirname41(filePath));
107306
107558
  while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
107307
107559
  try {
107308
107560
  const entries = readdirSync10(currentDir);
107309
107561
  if (entries.length === 0) {
107310
107562
  rmdirSync2(currentDir);
107311
107563
  logger.debug(`Removed empty directory: ${currentDir}`);
107312
- currentDir = resolve45(dirname40(currentDir));
107564
+ currentDir = resolve45(dirname41(currentDir));
107313
107565
  } else {
107314
107566
  break;
107315
107567
  }
@@ -107499,7 +107751,7 @@ async function handleFreshInstallation(claudeDir3, prompts) {
107499
107751
  var import_fs_extra35 = __toESM(require_lib(), 1);
107500
107752
  import { cp as cp5, mkdir as mkdir35, readdir as readdir42, rename as rename11, rm as rm16, stat as stat22 } from "node:fs/promises";
107501
107753
  import { homedir as homedir47 } from "node:os";
107502
- import { dirname as dirname41, join as join133, normalize as normalize11, resolve as resolve46 } from "node:path";
107754
+ import { dirname as dirname42, join as join133, normalize as normalize11, resolve as resolve46 } from "node:path";
107503
107755
  var LEGACY_KIT_MARKERS = [
107504
107756
  "metadata.json",
107505
107757
  ".ck.json",
@@ -107612,7 +107864,7 @@ async function repairLegacyWindowsGlobalKitDir(options2) {
107612
107864
  if (targetExists) {
107613
107865
  await rm16(targetDir, { recursive: true, force: true });
107614
107866
  }
107615
- await mkdir35(dirname41(targetDir), { recursive: true });
107867
+ await mkdir35(dirname42(targetDir), { recursive: true });
107616
107868
  await moveDirectory(legacyDir, targetDir);
107617
107869
  return { status: "repaired", reason: "repaired", legacyDir, candidateDirs };
107618
107870
  }
@@ -107984,7 +108236,7 @@ async function handleSelection(ctx) {
107984
108236
  logger.info("--force has no effect without --yes (the version-match skip only applies in non-interactive mode)");
107985
108237
  }
107986
108238
  const releaseTag = release?.tag_name;
107987
- if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && releaseTag && !isOfflineMode && !pendingKits?.length) {
108239
+ if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && !ctx.options.restoreCkHooks && releaseTag && !isOfflineMode && !pendingKits?.length) {
107988
108240
  try {
107989
108241
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
107990
108242
  const claudeDir3 = prefix ? join134(resolvedDir, prefix) : resolvedDir;
@@ -108011,7 +108263,7 @@ async function handleSelection(ctx) {
108011
108263
  }
108012
108264
  // src/commands/init/phases/sync-handler.ts
108013
108265
  import { copyFile as copyFile8, mkdir as mkdir37, open as open5, readFile as readFile59, rename as rename12, stat as stat23, unlink as unlink13, writeFile as writeFile33 } from "node:fs/promises";
108014
- import { dirname as dirname42, join as join135, resolve as resolve48 } from "node:path";
108266
+ import { dirname as dirname43, join as join135, resolve as resolve48 } from "node:path";
108015
108267
  init_logger();
108016
108268
  init_path_resolver();
108017
108269
  var import_fs_extra37 = __toESM(require_lib(), 1);
@@ -108130,7 +108382,7 @@ async function acquireSyncLock(global3) {
108130
108382
  const lockPath = join135(cacheDir, ".sync-lock");
108131
108383
  const startTime = Date.now();
108132
108384
  const lockTimeout = getLockTimeout();
108133
- await mkdir37(dirname42(lockPath), { recursive: true });
108385
+ await mkdir37(dirname43(lockPath), { recursive: true });
108134
108386
  while (Date.now() - startTime < lockTimeout) {
108135
108387
  try {
108136
108388
  const handle = await open5(lockPath, "wx");
@@ -108958,6 +109210,7 @@ function createInitContext(rawOptions, prompts) {
108958
109210
  skipSetup: false,
108959
109211
  forceOverwrite: false,
108960
109212
  forceOverwriteSettings: false,
109213
+ restoreCkHooks: false,
108961
109214
  dryRun: false,
108962
109215
  prefix: false,
108963
109216
  sync: false,
@@ -109587,7 +109840,7 @@ init_dist2();
109587
109840
  init_model_taxonomy();
109588
109841
  import { mkdir as mkdir39, readFile as readFile64, writeFile as writeFile37 } from "node:fs/promises";
109589
109842
  import { homedir as homedir52 } from "node:os";
109590
- import { dirname as dirname43, join as join142 } from "node:path";
109843
+ import { dirname as dirname44, join as join142 } from "node:path";
109591
109844
 
109592
109845
  // src/commands/portable/models-dev-cache.ts
109593
109846
  init_logger();
@@ -109940,7 +110193,7 @@ async function ensureOpenCodeModel(options2) {
109940
110193
  }
109941
110194
  const chosenModel2 = response2.action === "custom" ? response2.value : suggestion2.model;
109942
110195
  const next2 = { ...existing, model: chosenModel2 };
109943
- await mkdir39(dirname43(configPath), { recursive: true });
110196
+ await mkdir39(dirname44(configPath), { recursive: true });
109944
110197
  await writeFile37(configPath, `${JSON.stringify(next2, null, 2)}
109945
110198
  `, "utf-8");
109946
110199
  return { path: configPath, action: "added", model: chosenModel2, reason: suggestion2.reason };
@@ -109951,7 +110204,7 @@ async function ensureOpenCodeModel(options2) {
109951
110204
  throw new OpenCodeAuthRequiredError(suggestion.failure);
109952
110205
  }
109953
110206
  const next2 = { ...existing ?? {}, model: suggestion.model };
109954
- await mkdir39(dirname43(configPath), { recursive: true });
110207
+ await mkdir39(dirname44(configPath), { recursive: true });
109955
110208
  await writeFile37(configPath, `${JSON.stringify(next2, null, 2)}
109956
110209
  `, "utf-8");
109957
110210
  return {
@@ -109973,7 +110226,7 @@ async function ensureOpenCodeModel(options2) {
109973
110226
  }
109974
110227
  const chosenModel = response.action === "custom" ? response.value : suggestion.ok ? suggestion.model : "";
109975
110228
  const next = { ...existing ?? {}, model: chosenModel };
109976
- await mkdir39(dirname43(configPath), { recursive: true });
110229
+ await mkdir39(dirname44(configPath), { recursive: true });
109977
110230
  await writeFile37(configPath, `${JSON.stringify(next, null, 2)}
109978
110231
  `, "utf-8");
109979
110232
  return {
@@ -109986,7 +110239,7 @@ async function ensureOpenCodeModel(options2) {
109986
110239
 
109987
110240
  // src/commands/portable/plan-display.ts
109988
110241
  var import_picocolors28 = __toESM(require_picocolors(), 1);
109989
- import { basename as basename29, dirname as dirname44, extname as extname8 } from "node:path";
110242
+ import { basename as basename29, dirname as dirname45, extname as extname8 } from "node:path";
109990
110243
  var DEFAULT_MAX_PLAN_GROUP_ITEMS = 20;
109991
110244
  var TYPE_ORDER = [
109992
110245
  "agent",
@@ -110212,21 +110465,21 @@ function collectPlannedWhereLines(plan) {
110212
110465
  return destinations.map((destination) => `${formatDisplayPath(destination)} -> ${formatCdHint(resolveCdTarget(destination))}`);
110213
110466
  }
110214
110467
  function resolveCdTarget(destination) {
110215
- return extname8(destination).length > 0 ? dirname44(destination) : destination;
110468
+ return extname8(destination).length > 0 ? dirname45(destination) : destination;
110216
110469
  }
110217
110470
  function normalizeWhereDestination(path17, portableType) {
110218
110471
  if (portableType === "agent" || portableType === "command" || portableType === "skill") {
110219
- return dirname44(path17);
110472
+ return dirname45(path17);
110220
110473
  }
110221
110474
  if (portableType === "hooks") {
110222
- return dirname44(path17);
110475
+ return dirname45(path17);
110223
110476
  }
110224
110477
  if (portableType === "rules") {
110225
110478
  const fileName = basename29(path17).toLowerCase();
110226
110479
  if (fileName === "agents.md" || fileName === "gemini.md" || fileName === ".goosehints" || fileName === "custom_modes.yaml" || fileName === "custom_modes.yml") {
110227
110480
  return path17;
110228
110481
  }
110229
- return dirname44(path17);
110482
+ return dirname45(path17);
110230
110483
  }
110231
110484
  return path17;
110232
110485
  }
@@ -111980,7 +112233,7 @@ Please use only one download method.`);
111980
112233
  // src/commands/plan/plan-command.ts
111981
112234
  init_output_manager();
111982
112235
  import { existsSync as existsSync71, statSync as statSync12 } from "node:fs";
111983
- import { dirname as dirname48, isAbsolute as isAbsolute14, join as join148, parse as parse7, resolve as resolve55 } from "node:path";
112236
+ import { dirname as dirname49, isAbsolute as isAbsolute14, join as join148, parse as parse7, resolve as resolve55 } from "node:path";
111984
112237
 
111985
112238
  // src/commands/plan/plan-read-handlers.ts
111986
112239
  init_config();
@@ -111990,18 +112243,18 @@ init_logger();
111990
112243
  init_output_manager();
111991
112244
  var import_picocolors32 = __toESM(require_picocolors(), 1);
111992
112245
  import { existsSync as existsSync70, statSync as statSync11 } from "node:fs";
111993
- import { basename as basename31, dirname as dirname46, join as join147, relative as relative31, resolve as resolve53 } from "node:path";
112246
+ import { basename as basename31, dirname as dirname47, join as join147, relative as relative31, resolve as resolve53 } from "node:path";
111994
112247
 
111995
112248
  // src/commands/plan/plan-dependencies.ts
111996
112249
  init_config();
111997
112250
  init_plan_parser();
111998
112251
  init_plans_registry();
111999
112252
  import { existsSync as existsSync69 } from "node:fs";
112000
- import { dirname as dirname45, join as join146 } from "node:path";
112253
+ import { dirname as dirname46, join as join146 } from "node:path";
112001
112254
  async function resolvePlanDependencies(references, currentPlanFile, options2 = {}) {
112002
112255
  if (references.length === 0)
112003
112256
  return [];
112004
- const currentPlanDir = dirname45(currentPlanFile);
112257
+ const currentPlanDir = dirname46(currentPlanFile);
112005
112258
  const projectRoot = findProjectRoot(currentPlanDir);
112006
112259
  const config = options2.preloadedConfig ?? (await CkConfigManager.loadFull(projectRoot)).config;
112007
112260
  const defaultScope = inferPlanScopeForDir(currentPlanDir, config);
@@ -112088,7 +112341,7 @@ async function handleParse(target, options2) {
112088
112341
  console.log(JSON.stringify({ file: relative31(process.cwd(), planFile), frontmatter, phases }, null, 2));
112089
112342
  return;
112090
112343
  }
112091
- const title = typeof frontmatter.title === "string" ? frontmatter.title : basename31(dirname46(planFile));
112344
+ const title = typeof frontmatter.title === "string" ? frontmatter.title : basename31(dirname47(planFile));
112092
112345
  console.log();
112093
112346
  console.log(import_picocolors32.default.bold(` Plan: ${title}`));
112094
112347
  console.log(` File: ${planFile}`);
@@ -112199,7 +112452,7 @@ async function handleStatus(target, options2) {
112199
112452
  const blockedBy2 = await resolvePlanDependencies(s.blockedBy, pf, { preloadedConfig });
112200
112453
  const blocks2 = await resolvePlanDependencies(s.blocks, pf, { preloadedConfig });
112201
112454
  const bar = progressBar(s.completed, s.totalPhases);
112202
- const title2 = s.title ?? basename31(dirname46(pf));
112455
+ const title2 = s.title ?? basename31(dirname47(pf));
112203
112456
  console.log(` ${import_picocolors32.default.bold(title2)}`);
112204
112457
  console.log(` ${bar}`);
112205
112458
  if (s.inProgress > 0)
@@ -112218,7 +112471,7 @@ async function handleStatus(target, options2) {
112218
112471
  }
112219
112472
  console.log();
112220
112473
  } catch {
112221
- console.log(` [X] Failed to read: ${basename31(dirname46(pf))}`);
112474
+ console.log(` [X] Failed to read: ${basename31(dirname47(pf))}`);
112222
112475
  console.log();
112223
112476
  }
112224
112477
  }
@@ -112245,7 +112498,7 @@ async function handleStatus(target, options2) {
112245
112498
  console.log(JSON.stringify({ ...summary, dependencyStatus: { blockedBy, blocks } }, null, 2));
112246
112499
  return;
112247
112500
  }
112248
- const title = summary.title ?? basename31(dirname46(planFile));
112501
+ const title = summary.title ?? basename31(dirname47(planFile));
112249
112502
  console.log();
112250
112503
  console.log(import_picocolors32.default.bold(` ${title}`));
112251
112504
  if (summary.status)
@@ -112308,7 +112561,7 @@ async function handleKanban(target, options2) {
112308
112561
  process.exitCode = 1;
112309
112562
  return;
112310
112563
  }
112311
- const route = `/plans?dir=${encodeURIComponent(dirname46(dirname46(planFile)))}&view=kanban`;
112564
+ const route = `/plans?dir=${encodeURIComponent(dirname47(dirname47(planFile)))}&view=kanban`;
112312
112565
  const url = `http://localhost:${server.port}${route}`;
112313
112566
  console.log();
112314
112567
  console.log(import_picocolors32.default.bold(" ClaudeKit Dashboard — Plans"));
@@ -112343,7 +112596,7 @@ init_plan_parser();
112343
112596
  init_plans_registry();
112344
112597
  init_output_manager();
112345
112598
  var import_picocolors33 = __toESM(require_picocolors(), 1);
112346
- import { basename as basename32, dirname as dirname47, relative as relative32, resolve as resolve54 } from "node:path";
112599
+ import { basename as basename32, dirname as dirname48, relative as relative32, resolve as resolve54 } from "node:path";
112347
112600
  function quoteReadTarget(filePath) {
112348
112601
  return `"${filePath.replace(/\\/g, "/").replace(/"/g, "\\\"")}"`;
112349
112602
  }
@@ -112457,7 +112710,7 @@ async function handleCheck(target, options2) {
112457
112710
  process.exitCode = 1;
112458
112711
  return;
112459
112712
  }
112460
- const planDir = dirname47(planFile);
112713
+ const planDir = dirname48(planFile);
112461
112714
  let planStatus = "pending";
112462
112715
  try {
112463
112716
  const projectRoot = findProjectRoot(planDir);
@@ -112506,7 +112759,7 @@ async function handleUncheck(target, options2) {
112506
112759
  process.exitCode = 1;
112507
112760
  return;
112508
112761
  }
112509
- const planDir = dirname47(planFile);
112762
+ const planDir = dirname48(planFile);
112510
112763
  try {
112511
112764
  const projectRoot = findProjectRoot(planDir);
112512
112765
  const summary = buildPlanSummary(planFile);
@@ -112545,7 +112798,7 @@ async function handleAddPhase(target, options2) {
112545
112798
  try {
112546
112799
  const result = addPhase(planFile, target, options2.after);
112547
112800
  try {
112548
- const planDir = dirname47(planFile);
112801
+ const planDir = dirname48(planFile);
112549
112802
  const projectRoot = findProjectRoot(planDir);
112550
112803
  updateRegistryAddPhase({
112551
112804
  planDir,
@@ -112599,7 +112852,7 @@ function resolvePlanFile(target, baseDir) {
112599
112852
  const candidate = join148(dir, "plan.md");
112600
112853
  if (existsSync71(candidate))
112601
112854
  return candidate;
112602
- dir = dirname48(dir);
112855
+ dir = dirname49(dir);
112603
112856
  }
112604
112857
  }
112605
112858
  return null;
@@ -113051,6 +113304,7 @@ async function handleKitSelection(ctx) {
113051
113304
  dryRun: false,
113052
113305
  forceOverwrite: false,
113053
113306
  forceOverwriteSettings: false,
113307
+ restoreCkHooks: false,
113054
113308
  skipSetup: true,
113055
113309
  refresh: false,
113056
113310
  sync: false,
@@ -113883,7 +114137,7 @@ var import_fs_extra42 = __toESM(require_lib(), 1);
113883
114137
  // src/commands/uninstall/analysis-handler.ts
113884
114138
  init_metadata_migration();
113885
114139
  import { readdirSync as readdirSync11, rmSync as rmSync4 } from "node:fs";
113886
- import { dirname as dirname49, join as join151 } from "node:path";
114140
+ import { dirname as dirname50, join as join151 } from "node:path";
113887
114141
  init_logger();
113888
114142
  init_safe_prompts();
113889
114143
  var import_fs_extra41 = __toESM(require_lib(), 1);
@@ -113905,7 +114159,7 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
113905
114159
  }
113906
114160
  async function cleanupEmptyDirectories3(filePath, installationRoot) {
113907
114161
  let cleaned = 0;
113908
- let currentDir = dirname49(filePath);
114162
+ let currentDir = dirname50(filePath);
113909
114163
  while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
113910
114164
  try {
113911
114165
  const entries = readdirSync11(currentDir);
@@ -113913,7 +114167,7 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
113913
114167
  rmSync4(currentDir, { recursive: true });
113914
114168
  cleaned++;
113915
114169
  logger.debug(`Removed empty directory: ${currentDir}`);
113916
- currentDir = dirname49(currentDir);
114170
+ currentDir = dirname50(currentDir);
113917
114171
  } else {
113918
114172
  break;
113919
114173
  }
@@ -115835,7 +116089,7 @@ init_file_io();
115835
116089
  init_logger();
115836
116090
  import { existsSync as existsSync74 } from "node:fs";
115837
116091
  import { mkdir as mkdir41, readFile as readFile68 } from "node:fs/promises";
115838
- import { dirname as dirname50 } from "node:path";
116092
+ import { dirname as dirname51 } from "node:path";
115839
116093
  var PROCESSED_ISSUES_CAP = 500;
115840
116094
  async function readCkJson(projectDir) {
115841
116095
  const configPath = CkConfigManager.getProjectConfigPath(projectDir);
@@ -115865,7 +116119,7 @@ async function loadWatchState(projectDir) {
115865
116119
  }
115866
116120
  async function saveWatchState(projectDir, state) {
115867
116121
  const configPath = CkConfigManager.getProjectConfigPath(projectDir);
115868
- const configDir = dirname50(configPath);
116122
+ const configDir = dirname51(configPath);
115869
116123
  if (!existsSync74(configDir)) {
115870
116124
  await mkdir41(configDir, { recursive: true });
115871
116125
  }
@@ -116405,7 +116659,7 @@ function registerCommands(cli) {
116405
116659
  }
116406
116660
  await newCommand(options2);
116407
116661
  });
116408
- 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) => {
116662
+ 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) => {
116409
116663
  if (options2.exclude && !Array.isArray(options2.exclude)) {
116410
116664
  options2.exclude = [options2.exclude];
116411
116665
  }