claudekit-cli 4.5.0-dev.4 → 4.5.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "4.5.0-dev.4",
3
- "generatedAt": "2026-06-24T22:46:20.222Z",
2
+ "version": "4.5.0-dev.5",
3
+ "generatedAt": "2026-06-25T20:18:04.882Z",
4
4
  "commands": {
5
5
  "agents": {
6
6
  "name": "agents",
package/dist/index.js CHANGED
@@ -64421,7 +64421,7 @@ var package_default;
64421
64421
  var init_package = __esm(() => {
64422
64422
  package_default = {
64423
64423
  name: "claudekit-cli",
64424
- version: "4.5.0-dev.4",
64424
+ version: "4.5.0-dev.5",
64425
64425
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
64426
64426
  type: "module",
64427
64427
  repository: {
@@ -65083,7 +65083,7 @@ import { spawnSync as spawnSync3 } from "node:child_process";
65083
65083
  import { existsSync as existsSync46, readFileSync as readFileSync14, readdirSync as readdirSync9, statSync as statSync10, writeFileSync as writeFileSync5 } from "node:fs";
65084
65084
  import { readdir as readdir17 } from "node:fs/promises";
65085
65085
  import { homedir as homedir40, tmpdir } from "node:os";
65086
- import { dirname as dirname29, join as join65, resolve as resolve33 } from "node:path";
65086
+ import { dirname as dirname29, join as join65, resolve as resolve33, sep as sep11 } from "node:path";
65087
65087
  function resolveDoctorCkExecutable(platformName = process.platform) {
65088
65088
  return platformName === "win32" ? "ck.cmd" : "ck";
65089
65089
  }
@@ -66085,6 +66085,21 @@ async function countMissingHookFileReferences(projectDir = process.cwd()) {
66085
66085
  }
66086
66086
  return count;
66087
66087
  }
66088
+ async function countMissingHookFileReferencesForClaudeDir(claudeDir3, projectRoot = dirname29(claudeDir3)) {
66089
+ const hooksDirPrefix = `${resolve33(claudeDir3, "hooks")}${sep11}`;
66090
+ let count = 0;
66091
+ for (const fileName of ["settings.json", "settings.local.json"]) {
66092
+ const filePath = resolve33(claudeDir3, fileName);
66093
+ if (!existsSync46(filePath))
66094
+ continue;
66095
+ const settings = await SettingsMerger.readSettingsFile(filePath);
66096
+ if (!settings)
66097
+ continue;
66098
+ const descriptor = { path: filePath, label: fileName, root: "$HOME" };
66099
+ count += collectMissingHookReferences(settings, descriptor, projectRoot).filter((finding) => finding.resolvedPath.startsWith(hooksDirPrefix)).length;
66100
+ }
66101
+ return count;
66102
+ }
66088
66103
  async function repairMissingHookFileReferences(projectDir = process.cwd()) {
66089
66104
  const result = await checkHookFileReferences(projectDir);
66090
66105
  if (result.status !== "fail" || !result.fix) {
@@ -78068,10 +78083,10 @@ __export(exports_worktree_manager, {
78068
78083
  cleanupAllWorktrees: () => cleanupAllWorktrees
78069
78084
  });
78070
78085
  import { existsSync as existsSync77 } from "node:fs";
78071
- import { readFile as readFile69, writeFile as writeFile40 } from "node:fs/promises";
78072
- import { join as join158 } from "node:path";
78086
+ import { readFile as readFile70, writeFile as writeFile41 } from "node:fs/promises";
78087
+ import { join as join159 } from "node:path";
78073
78088
  async function createWorktree(projectDir, issueNumber, baseBranch) {
78074
- const worktreePath = join158(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
78089
+ const worktreePath = join159(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
78075
78090
  const branchName = `ck-watch/issue-${issueNumber}`;
78076
78091
  await spawnAndCollect("git", ["fetch", "origin", baseBranch], projectDir).catch(() => {
78077
78092
  logger.warning(`[worktree] Could not fetch origin/${baseBranch}, using local`);
@@ -78089,7 +78104,7 @@ async function createWorktree(projectDir, issueNumber, baseBranch) {
78089
78104
  return worktreePath;
78090
78105
  }
78091
78106
  async function removeWorktree(projectDir, issueNumber) {
78092
- const worktreePath = join158(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
78107
+ const worktreePath = join159(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
78093
78108
  const branchName = `ck-watch/issue-${issueNumber}`;
78094
78109
  try {
78095
78110
  await spawnAndCollect("git", ["worktree", "remove", worktreePath, "--force"], projectDir);
@@ -78103,7 +78118,7 @@ async function listActiveWorktrees(projectDir) {
78103
78118
  try {
78104
78119
  const output2 = await spawnAndCollect("git", ["worktree", "list", "--porcelain"], projectDir);
78105
78120
  const issueNumbers = [];
78106
- const worktreePrefix = join158(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
78121
+ const worktreePrefix = join159(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
78107
78122
  for (const line of output2.split(`
78108
78123
  `)) {
78109
78124
  if (line.startsWith("worktree ")) {
@@ -78131,16 +78146,16 @@ async function cleanupAllWorktrees(projectDir) {
78131
78146
  await spawnAndCollect("git", ["worktree", "prune"], projectDir).catch(() => {});
78132
78147
  }
78133
78148
  async function ensureGitignore(projectDir) {
78134
- const gitignorePath = join158(projectDir, ".gitignore");
78149
+ const gitignorePath = join159(projectDir, ".gitignore");
78135
78150
  try {
78136
- const content = existsSync77(gitignorePath) ? await readFile69(gitignorePath, "utf-8") : "";
78151
+ const content = existsSync77(gitignorePath) ? await readFile70(gitignorePath, "utf-8") : "";
78137
78152
  if (!content.includes(".worktrees")) {
78138
78153
  const newContent = content.endsWith(`
78139
78154
  `) ? `${content}.worktrees/
78140
78155
  ` : `${content}
78141
78156
  .worktrees/
78142
78157
  `;
78143
- await writeFile40(gitignorePath, newContent, "utf-8");
78158
+ await writeFile41(gitignorePath, newContent, "utf-8");
78144
78159
  logger.info("[worktree] Added .worktrees/ to .gitignore");
78145
78160
  }
78146
78161
  } catch (err) {
@@ -78236,9 +78251,9 @@ var init_content_validator = __esm(() => {
78236
78251
  // src/commands/content/phases/context-cache-manager.ts
78237
78252
  import { createHash as createHash9 } from "node:crypto";
78238
78253
  import { existsSync as existsSync83, mkdirSync as mkdirSync7, readFileSync as readFileSync22, readdirSync as readdirSync14, statSync as statSync15 } from "node:fs";
78239
- import { rename as rename16, writeFile as writeFile42 } from "node:fs/promises";
78254
+ import { rename as rename16, writeFile as writeFile43 } from "node:fs/promises";
78240
78255
  import { homedir as homedir54 } from "node:os";
78241
- import { basename as basename34, join as join165 } from "node:path";
78256
+ import { basename as basename34, join as join166 } from "node:path";
78242
78257
  function getCachedContext(repoPath) {
78243
78258
  const cachePath = getCacheFilePath(repoPath);
78244
78259
  if (!existsSync83(cachePath))
@@ -78263,7 +78278,7 @@ async function saveCachedContext(repoPath, cache5) {
78263
78278
  }
78264
78279
  const cachePath = getCacheFilePath(repoPath);
78265
78280
  const tmpPath = `${cachePath}.tmp`;
78266
- await writeFile42(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
78281
+ await writeFile43(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
78267
78282
  await rename16(tmpPath, cachePath);
78268
78283
  }
78269
78284
  function computeSourceHash(repoPath) {
@@ -78281,25 +78296,25 @@ function computeSourceHash(repoPath) {
78281
78296
  }
78282
78297
  function getDocSourcePaths(repoPath) {
78283
78298
  const paths = [];
78284
- const docsDir = join165(repoPath, "docs");
78299
+ const docsDir = join166(repoPath, "docs");
78285
78300
  if (existsSync83(docsDir)) {
78286
78301
  try {
78287
78302
  const files = readdirSync14(docsDir);
78288
78303
  for (const f3 of files) {
78289
78304
  if (f3.endsWith(".md"))
78290
- paths.push(join165(docsDir, f3));
78305
+ paths.push(join166(docsDir, f3));
78291
78306
  }
78292
78307
  } catch {}
78293
78308
  }
78294
- const readme = join165(repoPath, "README.md");
78309
+ const readme = join166(repoPath, "README.md");
78295
78310
  if (existsSync83(readme))
78296
78311
  paths.push(readme);
78297
- const stylesDir = join165(repoPath, "assets", "writing-styles");
78312
+ const stylesDir = join166(repoPath, "assets", "writing-styles");
78298
78313
  if (existsSync83(stylesDir)) {
78299
78314
  try {
78300
78315
  const files = readdirSync14(stylesDir);
78301
78316
  for (const f3 of files) {
78302
- paths.push(join165(stylesDir, f3));
78317
+ paths.push(join166(stylesDir, f3));
78303
78318
  }
78304
78319
  } catch {}
78305
78320
  }
@@ -78308,11 +78323,11 @@ function getDocSourcePaths(repoPath) {
78308
78323
  function getCacheFilePath(repoPath) {
78309
78324
  const repoName = basename34(repoPath).replace(/[^a-zA-Z0-9_-]/g, "_");
78310
78325
  const pathHash = createHash9("sha256").update(repoPath).digest("hex").slice(0, 8);
78311
- return join165(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
78326
+ return join166(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
78312
78327
  }
78313
78328
  var CACHE_DIR, CACHE_TTL_MS5;
78314
78329
  var init_context_cache_manager = __esm(() => {
78315
- CACHE_DIR = join165(homedir54(), ".claudekit", "cache");
78330
+ CACHE_DIR = join166(homedir54(), ".claudekit", "cache");
78316
78331
  CACHE_TTL_MS5 = 24 * 60 * 60 * 1000;
78317
78332
  });
78318
78333
 
@@ -78493,7 +78508,7 @@ function extractContentFromResponse(response) {
78493
78508
  // src/commands/content/phases/docs-summarizer.ts
78494
78509
  import { execSync as execSync7 } from "node:child_process";
78495
78510
  import { existsSync as existsSync84, readFileSync as readFileSync23, readdirSync as readdirSync15 } from "node:fs";
78496
- import { join as join166 } from "node:path";
78511
+ import { join as join167 } from "node:path";
78497
78512
  async function summarizeProjectDocs(repoPath, contentLogger) {
78498
78513
  const rawContent = collectRawDocs(repoPath);
78499
78514
  if (rawContent.total.length < 200) {
@@ -78547,12 +78562,12 @@ function collectRawDocs(repoPath) {
78547
78562
  return capped;
78548
78563
  };
78549
78564
  const docsContent = [];
78550
- const docsDir = join166(repoPath, "docs");
78565
+ const docsDir = join167(repoPath, "docs");
78551
78566
  if (existsSync84(docsDir)) {
78552
78567
  try {
78553
78568
  const files = readdirSync15(docsDir).filter((f3) => f3.endsWith(".md")).sort();
78554
78569
  for (const f3 of files) {
78555
- const content = readCapped(join166(docsDir, f3), 5000);
78570
+ const content = readCapped(join167(docsDir, f3), 5000);
78556
78571
  if (content) {
78557
78572
  docsContent.push(`### ${f3}
78558
78573
  ${content}`);
@@ -78566,21 +78581,21 @@ ${content}`);
78566
78581
  let brand = "";
78567
78582
  const brandCandidates = ["docs/brand-guidelines.md", "docs/design-guidelines.md"];
78568
78583
  for (const p of brandCandidates) {
78569
- brand = readCapped(join166(repoPath, p), 3000);
78584
+ brand = readCapped(join167(repoPath, p), 3000);
78570
78585
  if (brand)
78571
78586
  break;
78572
78587
  }
78573
78588
  let styles3 = "";
78574
- const stylesDir = join166(repoPath, "assets", "writing-styles");
78589
+ const stylesDir = join167(repoPath, "assets", "writing-styles");
78575
78590
  if (existsSync84(stylesDir)) {
78576
78591
  try {
78577
78592
  const files = readdirSync15(stylesDir).slice(0, 3);
78578
- styles3 = files.map((f3) => readCapped(join166(stylesDir, f3), 1000)).filter(Boolean).join(`
78593
+ styles3 = files.map((f3) => readCapped(join167(stylesDir, f3), 1000)).filter(Boolean).join(`
78579
78594
 
78580
78595
  `);
78581
78596
  } catch {}
78582
78597
  }
78583
- const readme = readCapped(join166(repoPath, "README.md"), 3000);
78598
+ const readme = readCapped(join167(repoPath, "README.md"), 3000);
78584
78599
  const total = [docs, brand, styles3, readme].join(`
78585
78600
  `);
78586
78601
  return { docs, brand, styles: styles3, readme, total };
@@ -78767,9 +78782,9 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
78767
78782
  import { execSync as execSync8 } from "node:child_process";
78768
78783
  import { existsSync as existsSync85, mkdirSync as mkdirSync8, readdirSync as readdirSync16 } from "node:fs";
78769
78784
  import { homedir as homedir55 } from "node:os";
78770
- import { join as join167 } from "node:path";
78785
+ import { join as join168 } from "node:path";
78771
78786
  async function generatePhoto(_content, context, config, platform18, contentId, contentLogger) {
78772
- const mediaDir = join167(config.contentDir.replace(/^~/, homedir55()), "media", String(contentId));
78787
+ const mediaDir = join168(config.contentDir.replace(/^~/, homedir55()), "media", String(contentId));
78773
78788
  if (!existsSync85(mediaDir)) {
78774
78789
  mkdirSync8(mediaDir, { recursive: true });
78775
78790
  }
@@ -78794,7 +78809,7 @@ async function generatePhoto(_content, context, config, platform18, contentId, c
78794
78809
  const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
78795
78810
  if (imageFile) {
78796
78811
  const ext2 = imageFile.split(".").pop() ?? "png";
78797
- return { path: join167(mediaDir, imageFile), ...dimensions, format: ext2 };
78812
+ return { path: join168(mediaDir, imageFile), ...dimensions, format: ext2 };
78798
78813
  }
78799
78814
  contentLogger.warn(`Photo generation produced no image for content ${contentId}`);
78800
78815
  return null;
@@ -78884,7 +78899,7 @@ var init_content_creator = __esm(() => {
78884
78899
  // src/commands/content/phases/content-logger.ts
78885
78900
  import { createWriteStream as createWriteStream4, existsSync as existsSync86, mkdirSync as mkdirSync9, statSync as statSync16 } from "node:fs";
78886
78901
  import { homedir as homedir56 } from "node:os";
78887
- import { join as join168 } from "node:path";
78902
+ import { join as join169 } from "node:path";
78888
78903
 
78889
78904
  class ContentLogger {
78890
78905
  stream = null;
@@ -78892,7 +78907,7 @@ class ContentLogger {
78892
78907
  logDir;
78893
78908
  maxBytes;
78894
78909
  constructor(maxBytes = 0) {
78895
- this.logDir = join168(homedir56(), ".claudekit", "logs");
78910
+ this.logDir = join169(homedir56(), ".claudekit", "logs");
78896
78911
  this.maxBytes = maxBytes;
78897
78912
  }
78898
78913
  init() {
@@ -78924,7 +78939,7 @@ class ContentLogger {
78924
78939
  }
78925
78940
  }
78926
78941
  getLogPath() {
78927
- return join168(this.logDir, `content-${this.getDateStr()}.log`);
78942
+ return join169(this.logDir, `content-${this.getDateStr()}.log`);
78928
78943
  }
78929
78944
  write(level, message) {
78930
78945
  this.rotateIfNeeded();
@@ -78941,18 +78956,18 @@ class ContentLogger {
78941
78956
  if (dateStr !== this.currentDate) {
78942
78957
  this.close();
78943
78958
  this.currentDate = dateStr;
78944
- const logPath = join168(this.logDir, `content-${dateStr}.log`);
78959
+ const logPath = join169(this.logDir, `content-${dateStr}.log`);
78945
78960
  this.stream = createWriteStream4(logPath, { flags: "a", mode: 384 });
78946
78961
  return;
78947
78962
  }
78948
78963
  if (this.maxBytes > 0 && this.stream) {
78949
- const logPath = join168(this.logDir, `content-${this.currentDate}.log`);
78964
+ const logPath = join169(this.logDir, `content-${this.currentDate}.log`);
78950
78965
  try {
78951
78966
  const stat26 = statSync16(logPath);
78952
78967
  if (stat26.size >= this.maxBytes) {
78953
78968
  this.close();
78954
78969
  const suffix = Date.now();
78955
- const rotatedPath = join168(this.logDir, `content-${this.currentDate}-${suffix}.log`);
78970
+ const rotatedPath = join169(this.logDir, `content-${this.currentDate}-${suffix}.log`);
78956
78971
  import("node:fs/promises").then(({ rename: rename17 }) => rename17(logPath, rotatedPath).catch(() => {}));
78957
78972
  this.stream = createWriteStream4(logPath, { flags: "w", mode: 384 });
78958
78973
  }
@@ -79223,7 +79238,7 @@ function isNoiseCommit(title, author) {
79223
79238
  // src/commands/content/phases/change-detector.ts
79224
79239
  import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
79225
79240
  import { existsSync as existsSync88, readFileSync as readFileSync24, readdirSync as readdirSync17, statSync as statSync17 } from "node:fs";
79226
- import { join as join169 } from "node:path";
79241
+ import { join as join170 } from "node:path";
79227
79242
  function detectCommits(repo, since) {
79228
79243
  try {
79229
79244
  const fetchUrl = sshToHttps(repo.remoteUrl);
@@ -79332,7 +79347,7 @@ function detectTags(repo, since) {
79332
79347
  }
79333
79348
  }
79334
79349
  function detectCompletedPlans(repo, since) {
79335
- const plansDir = join169(repo.path, "plans");
79350
+ const plansDir = join170(repo.path, "plans");
79336
79351
  if (!existsSync88(plansDir))
79337
79352
  return [];
79338
79353
  const sinceMs = new Date(since).getTime();
@@ -79342,7 +79357,7 @@ function detectCompletedPlans(repo, since) {
79342
79357
  for (const entry of entries) {
79343
79358
  if (!entry.isDirectory())
79344
79359
  continue;
79345
- const planFile = join169(plansDir, entry.name, "plan.md");
79360
+ const planFile = join170(plansDir, entry.name, "plan.md");
79346
79361
  if (!existsSync88(planFile))
79347
79362
  continue;
79348
79363
  try {
@@ -79420,7 +79435,7 @@ function classifyCommit(event) {
79420
79435
  // src/commands/content/phases/repo-discoverer.ts
79421
79436
  import { execSync as execSync11 } from "node:child_process";
79422
79437
  import { readdirSync as readdirSync18 } from "node:fs";
79423
- import { join as join170 } from "node:path";
79438
+ import { join as join171 } from "node:path";
79424
79439
  function discoverRepos2(cwd2) {
79425
79440
  const repos = [];
79426
79441
  if (isGitRepoRoot(cwd2)) {
@@ -79433,7 +79448,7 @@ function discoverRepos2(cwd2) {
79433
79448
  for (const entry of entries) {
79434
79449
  if (!entry.isDirectory() || entry.name.startsWith("."))
79435
79450
  continue;
79436
- const dirPath = join170(cwd2, entry.name);
79451
+ const dirPath = join171(cwd2, entry.name);
79437
79452
  if (isGitRepoRoot(dirPath)) {
79438
79453
  const info = getRepoInfo(dirPath);
79439
79454
  if (info)
@@ -80100,12 +80115,12 @@ var init_types6 = __esm(() => {
80100
80115
  });
80101
80116
 
80102
80117
  // src/commands/content/phases/state-manager.ts
80103
- import { readFile as readFile71, rename as rename17, writeFile as writeFile43 } from "node:fs/promises";
80104
- import { join as join171 } from "node:path";
80118
+ import { readFile as readFile72, rename as rename17, writeFile as writeFile44 } from "node:fs/promises";
80119
+ import { join as join172 } from "node:path";
80105
80120
  async function loadContentConfig(projectDir) {
80106
- const configPath = join171(projectDir, CK_CONFIG_FILE2);
80121
+ const configPath = join172(projectDir, CK_CONFIG_FILE2);
80107
80122
  try {
80108
- const raw2 = await readFile71(configPath, "utf-8");
80123
+ const raw2 = await readFile72(configPath, "utf-8");
80109
80124
  const json = JSON.parse(raw2);
80110
80125
  return ContentConfigSchema.parse(json.content ?? {});
80111
80126
  } catch {
@@ -80113,15 +80128,15 @@ async function loadContentConfig(projectDir) {
80113
80128
  }
80114
80129
  }
80115
80130
  async function saveContentConfig(projectDir, config) {
80116
- const configPath = join171(projectDir, CK_CONFIG_FILE2);
80131
+ const configPath = join172(projectDir, CK_CONFIG_FILE2);
80117
80132
  const json = await readJsonSafe4(configPath);
80118
80133
  json.content = { ...json.content, ...config };
80119
80134
  await atomicWrite3(configPath, json);
80120
80135
  }
80121
80136
  async function loadContentState(projectDir) {
80122
- const configPath = join171(projectDir, CK_CONFIG_FILE2);
80137
+ const configPath = join172(projectDir, CK_CONFIG_FILE2);
80123
80138
  try {
80124
- const raw2 = await readFile71(configPath, "utf-8");
80139
+ const raw2 = await readFile72(configPath, "utf-8");
80125
80140
  const json = JSON.parse(raw2);
80126
80141
  const contentBlock = json.content ?? {};
80127
80142
  return ContentStateSchema.parse(contentBlock.state ?? {});
@@ -80130,7 +80145,7 @@ async function loadContentState(projectDir) {
80130
80145
  }
80131
80146
  }
80132
80147
  async function saveContentState(projectDir, state) {
80133
- const configPath = join171(projectDir, CK_CONFIG_FILE2);
80148
+ const configPath = join172(projectDir, CK_CONFIG_FILE2);
80134
80149
  const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
80135
80150
  for (const key of Object.keys(state.dailyPostCounts)) {
80136
80151
  const dateStr = key.slice(-10);
@@ -80148,7 +80163,7 @@ async function saveContentState(projectDir, state) {
80148
80163
  }
80149
80164
  async function readJsonSafe4(filePath) {
80150
80165
  try {
80151
- const raw2 = await readFile71(filePath, "utf-8");
80166
+ const raw2 = await readFile72(filePath, "utf-8");
80152
80167
  return JSON.parse(raw2);
80153
80168
  } catch {
80154
80169
  return {};
@@ -80156,7 +80171,7 @@ async function readJsonSafe4(filePath) {
80156
80171
  }
80157
80172
  async function atomicWrite3(filePath, data) {
80158
80173
  const tmpPath = `${filePath}.tmp`;
80159
- await writeFile43(tmpPath, JSON.stringify(data, null, 2), "utf-8");
80174
+ await writeFile44(tmpPath, JSON.stringify(data, null, 2), "utf-8");
80160
80175
  await rename17(tmpPath, filePath);
80161
80176
  }
80162
80177
  var CK_CONFIG_FILE2 = ".ck.json";
@@ -80412,7 +80427,7 @@ var init_platform_setup_x = __esm(() => {
80412
80427
 
80413
80428
  // src/commands/content/phases/setup-wizard.ts
80414
80429
  import { existsSync as existsSync89 } from "node:fs";
80415
- import { join as join172 } from "node:path";
80430
+ import { join as join173 } from "node:path";
80416
80431
  async function runSetupWizard2(cwd2, contentLogger) {
80417
80432
  console.log();
80418
80433
  oe(import_picocolors43.default.bgCyan(import_picocolors43.default.white(" CK Content — Multi-Channel Content Engine ")));
@@ -80480,8 +80495,8 @@ async function showRepoSummary(cwd2) {
80480
80495
  function detectBrandAssets(cwd2, contentLogger) {
80481
80496
  const repos = discoverRepos2(cwd2);
80482
80497
  for (const repo of repos) {
80483
- const hasGuidelines = existsSync89(join172(repo.path, "docs", "brand-guidelines.md"));
80484
- const hasStyles = existsSync89(join172(repo.path, "assets", "writing-styles"));
80498
+ const hasGuidelines = existsSync89(join173(repo.path, "docs", "brand-guidelines.md"));
80499
+ const hasStyles = existsSync89(join173(repo.path, "assets", "writing-styles"));
80485
80500
  if (!hasGuidelines) {
80486
80501
  f2.warning(`${repo.name}: No docs/brand-guidelines.md — content will use generic tone.`);
80487
80502
  contentLogger.warn(`${repo.name}: missing docs/brand-guidelines.md`);
@@ -80623,9 +80638,9 @@ __export(exports_content_subcommands, {
80623
80638
  });
80624
80639
  import { existsSync as existsSync91, readFileSync as readFileSync25, unlinkSync as unlinkSync6 } from "node:fs";
80625
80640
  import { homedir as homedir58 } from "node:os";
80626
- import { join as join173 } from "node:path";
80641
+ import { join as join174 } from "node:path";
80627
80642
  function isDaemonRunning() {
80628
- const lockFile = join173(LOCK_DIR, `${LOCK_NAME2}.lock`);
80643
+ const lockFile = join174(LOCK_DIR, `${LOCK_NAME2}.lock`);
80629
80644
  if (!existsSync91(lockFile))
80630
80645
  return { running: false, pid: null };
80631
80646
  try {
@@ -80657,7 +80672,7 @@ async function startContent(options2) {
80657
80672
  await contentCommand(options2);
80658
80673
  }
80659
80674
  async function stopContent() {
80660
- const lockFile = join173(LOCK_DIR, `${LOCK_NAME2}.lock`);
80675
+ const lockFile = join174(LOCK_DIR, `${LOCK_NAME2}.lock`);
80661
80676
  if (!existsSync91(lockFile)) {
80662
80677
  logger.info("Content daemon is not running.");
80663
80678
  return;
@@ -80696,9 +80711,9 @@ async function statusContent() {
80696
80711
  } catch {}
80697
80712
  }
80698
80713
  async function logsContent(options2) {
80699
- const logDir = join173(homedir58(), ".claudekit", "logs");
80714
+ const logDir = join174(homedir58(), ".claudekit", "logs");
80700
80715
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
80701
- const logPath = join173(logDir, `content-${dateStr}.log`);
80716
+ const logPath = join174(logDir, `content-${dateStr}.log`);
80702
80717
  if (!existsSync91(logPath)) {
80703
80718
  logger.info("No content logs found for today.");
80704
80719
  return;
@@ -80730,13 +80745,13 @@ var init_content_subcommands = __esm(() => {
80730
80745
  init_setup_wizard();
80731
80746
  init_state_manager();
80732
80747
  init_content_review_commands();
80733
- LOCK_DIR = join173(homedir58(), ".claudekit", "locks");
80748
+ LOCK_DIR = join174(homedir58(), ".claudekit", "locks");
80734
80749
  });
80735
80750
 
80736
80751
  // src/commands/content/content-command.ts
80737
80752
  import { existsSync as existsSync92, mkdirSync as mkdirSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync9 } from "node:fs";
80738
80753
  import { homedir as homedir59 } from "node:os";
80739
- import { join as join174 } from "node:path";
80754
+ import { join as join175 } from "node:path";
80740
80755
  async function contentCommand(options2) {
80741
80756
  const cwd2 = process.cwd();
80742
80757
  const contentLogger = new ContentLogger;
@@ -80914,8 +80929,8 @@ var init_content_command = __esm(() => {
80914
80929
  init_publisher();
80915
80930
  init_review_manager();
80916
80931
  init_state_manager();
80917
- LOCK_DIR2 = join174(homedir59(), ".claudekit", "locks");
80918
- LOCK_FILE = join174(LOCK_DIR2, "ck-content.lock");
80932
+ LOCK_DIR2 = join175(homedir59(), ".claudekit", "locks");
80933
+ LOCK_FILE = join175(LOCK_DIR2, "ck-content.lock");
80919
80934
  });
80920
80935
 
80921
80936
  // src/commands/content/index.ts
@@ -102749,7 +102764,7 @@ import { join as join122 } from "node:path";
102749
102764
 
102750
102765
  // src/domains/installation/deletion-handler.ts
102751
102766
  import { existsSync as existsSync66, lstatSync as lstatSync3, readdirSync as readdirSync10, rmSync as rmSync2, rmdirSync, unlinkSync as unlinkSync4 } from "node:fs";
102752
- import { dirname as dirname38, join as join107, relative as relative21, resolve as resolve42, sep as sep11 } from "node:path";
102767
+ import { dirname as dirname38, join as join107, relative as relative21, resolve as resolve42, sep as sep12 } from "node:path";
102753
102768
 
102754
102769
  // src/services/file-operations/manifest/manifest-reader.ts
102755
102770
  init_metadata_migration();
@@ -102996,7 +103011,7 @@ function cleanupEmptyDirectories(filePath, claudeDir3) {
102996
103011
  function deletePath(fullPath, claudeDir3) {
102997
103012
  const normalizedPath = resolve42(fullPath);
102998
103013
  const normalizedClaudeDir = resolve42(claudeDir3);
102999
- if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep11}`) && normalizedPath !== normalizedClaudeDir) {
103014
+ if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep12}`) && normalizedPath !== normalizedClaudeDir) {
103000
103015
  throw new Error(`Path traversal detected: ${fullPath}`);
103001
103016
  }
103002
103017
  try {
@@ -103070,7 +103085,7 @@ async function handleDeletions(sourceMetadata, claudeDir3, kitType) {
103070
103085
  const fullPath = join107(claudeDir3, path16);
103071
103086
  const normalizedPath = resolve42(fullPath);
103072
103087
  const normalizedClaudeDir = resolve42(claudeDir3);
103073
- if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep11}`)) {
103088
+ if (!normalizedPath.startsWith(`${normalizedClaudeDir}${sep12}`)) {
103074
103089
  logger.warning(`Skipping invalid path: ${path16}`);
103075
103090
  result.errors.push(path16);
103076
103091
  continue;
@@ -104168,8 +104183,8 @@ var path16 = {
104168
104183
  win32: { sep: "\\" },
104169
104184
  posix: { sep: "/" }
104170
104185
  };
104171
- var sep12 = defaultPlatform === "win32" ? path16.win32.sep : path16.posix.sep;
104172
- minimatch.sep = sep12;
104186
+ var sep13 = defaultPlatform === "win32" ? path16.win32.sep : path16.posix.sep;
104187
+ minimatch.sep = sep13;
104173
104188
  var GLOBSTAR = Symbol("globstar **");
104174
104189
  minimatch.GLOBSTAR = GLOBSTAR;
104175
104190
  var qmark2 = "[^/]";
@@ -109497,6 +109512,9 @@ async function runPreflightChecks() {
109497
109512
  return result;
109498
109513
  }
109499
109514
 
109515
+ // src/commands/init/phases/selection-handler.ts
109516
+ init_hook_health_checker();
109517
+
109500
109518
  // src/domains/installation/fresh-installer.ts
109501
109519
  init_metadata_migration();
109502
109520
  import { existsSync as existsSync70, readdirSync as readdirSync11, rmSync as rmSync5, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
@@ -110242,8 +110260,13 @@ async function handleSelection(ctx) {
110242
110260
  const existingMetadata = await readManifest(claudeDir3);
110243
110261
  const installedKitVersion = existingMetadata?.kits?.[kitType]?.version;
110244
110262
  if (installedKitVersion && versionsMatch(installedKitVersion, releaseTag)) {
110245
- logger.success(`Already at latest version (${kitType}@${installedKitVersion}), skipping reinstall`);
110246
- return { ...ctx, cancelled: true };
110263
+ const missingHookFiles = await countMissingHookFileReferencesForClaudeDir(claudeDir3);
110264
+ if (missingHookFiles > 0) {
110265
+ logger.warning(`Detected ${missingHookFiles} registered hook(s) whose script is missing on disk; reinstalling to restore them`);
110266
+ } else {
110267
+ logger.success(`Already at latest version (${kitType}@${installedKitVersion}), skipping reinstall`);
110268
+ return { ...ctx, cancelled: true };
110269
+ }
110247
110270
  }
110248
110271
  } catch (error) {
110249
110272
  logger.verbose(`Metadata read failed, proceeding with installation: ${error instanceof Error ? error.message : "unknown"}`);
@@ -115992,11 +116015,11 @@ async function detectInstallations() {
115992
116015
 
115993
116016
  // src/commands/uninstall/removal-handler.ts
115994
116017
  import { readdirSync as readdirSync13, rmSync as rmSync8 } from "node:fs";
115995
- import { basename as basename33, join as join157, resolve as resolve56, sep as sep13 } from "node:path";
116018
+ import { basename as basename33, join as join158, resolve as resolve56, sep as sep14 } from "node:path";
115996
116019
  init_logger();
115997
116020
  init_safe_prompts();
115998
116021
  init_safe_spinner();
115999
- var import_fs_extra43 = __toESM(require_lib(), 1);
116022
+ var import_fs_extra44 = __toESM(require_lib(), 1);
116000
116023
 
116001
116024
  // src/commands/uninstall/analysis-handler.ts
116002
116025
  init_metadata_migration();
@@ -116148,10 +116171,170 @@ function displayDryRunPreview(analysis, installationType) {
116148
116171
  }
116149
116172
  }
116150
116173
 
116174
+ // src/commands/uninstall/settings-cleanup.ts
116175
+ init_settings_merger();
116176
+ init_command_normalizer();
116177
+ init_logger();
116178
+ var import_fs_extra43 = __toESM(require_lib(), 1);
116179
+ import { join as join157 } from "node:path";
116180
+ var CK_JSON_FILE2 = ".ck.json";
116181
+ var SETTINGS_FILE = "settings.json";
116182
+ var EMPTY_RESULT = {
116183
+ hooksRemoved: 0,
116184
+ mcpServersRemoved: 0,
116185
+ settingsFileRemoved: false,
116186
+ ckJsonRemoved: false
116187
+ };
116188
+ function resolveRemovalTargets(kits, removedKitNames, remainingKits) {
116189
+ const retainedHooks = new Set;
116190
+ const retainedServers = new Set;
116191
+ for (const remainingKit of remainingKits) {
116192
+ const installed = kits[remainingKit]?.installedSettings;
116193
+ for (const command of installed?.hooks ?? []) {
116194
+ const normalized = normalizeCommand(command);
116195
+ if (normalized)
116196
+ retainedHooks.add(normalized);
116197
+ }
116198
+ for (const server of installed?.mcpServers ?? []) {
116199
+ retainedServers.add(server);
116200
+ }
116201
+ }
116202
+ const hooks = new Set;
116203
+ const servers = new Set;
116204
+ for (const kitName of removedKitNames) {
116205
+ const installed = kits[kitName]?.installedSettings;
116206
+ for (const command of installed?.hooks ?? []) {
116207
+ const normalized = normalizeCommand(command);
116208
+ if (normalized && !retainedHooks.has(normalized))
116209
+ hooks.add(normalized);
116210
+ }
116211
+ for (const server of installed?.mcpServers ?? []) {
116212
+ if (!retainedServers.has(server))
116213
+ servers.add(server);
116214
+ }
116215
+ }
116216
+ return { hooks, servers };
116217
+ }
116218
+ function removeHooksFromSettings(settings, normalizedToRemove) {
116219
+ if (!settings.hooks || normalizedToRemove.size === 0)
116220
+ return 0;
116221
+ let removed = 0;
116222
+ const eventKeysToDelete = [];
116223
+ for (const [eventName, entries] of Object.entries(settings.hooks)) {
116224
+ const keptEntries = [];
116225
+ for (const entry of entries) {
116226
+ if (Array.isArray(entry.hooks)) {
116227
+ const keptHooks = entry.hooks.filter((hook) => {
116228
+ if (typeof hook.command === "string" && normalizedToRemove.has(normalizeCommand(hook.command))) {
116229
+ removed++;
116230
+ return false;
116231
+ }
116232
+ return true;
116233
+ });
116234
+ if (keptHooks.length > 0) {
116235
+ keptEntries.push({ ...entry, hooks: keptHooks });
116236
+ }
116237
+ continue;
116238
+ }
116239
+ if (typeof entry.command === "string" && normalizedToRemove.has(normalizeCommand(entry.command))) {
116240
+ removed++;
116241
+ continue;
116242
+ }
116243
+ keptEntries.push(entry);
116244
+ }
116245
+ if (keptEntries.length > 0) {
116246
+ settings.hooks[eventName] = keptEntries;
116247
+ } else {
116248
+ eventKeysToDelete.push(eventName);
116249
+ }
116250
+ }
116251
+ for (const eventName of eventKeysToDelete) {
116252
+ delete settings.hooks[eventName];
116253
+ }
116254
+ if (Object.keys(settings.hooks).length === 0) {
116255
+ Reflect.deleteProperty(settings, "hooks");
116256
+ }
116257
+ return removed;
116258
+ }
116259
+ function removeMcpServersFromSettings(settings, serversToRemove) {
116260
+ const servers = settings.mcp?.servers;
116261
+ if (!servers || serversToRemove.size === 0)
116262
+ return 0;
116263
+ let removed = 0;
116264
+ for (const name2 of serversToRemove) {
116265
+ if (Object.hasOwn(servers, name2)) {
116266
+ delete servers[name2];
116267
+ removed++;
116268
+ }
116269
+ }
116270
+ if (removed > 0 && settings.mcp) {
116271
+ if (Object.keys(servers).length === 0) {
116272
+ Reflect.deleteProperty(settings.mcp, "servers");
116273
+ }
116274
+ if (Object.keys(settings.mcp).length === 0) {
116275
+ Reflect.deleteProperty(settings, "mcp");
116276
+ }
116277
+ }
116278
+ return removed;
116279
+ }
116280
+ async function cleanupCkJson(ckJsonPath, data, removedKitNames, dryRun) {
116281
+ if (!data.kits)
116282
+ return false;
116283
+ for (const kitName of removedKitNames) {
116284
+ delete data.kits[kitName];
116285
+ }
116286
+ const noKitsLeft = Object.keys(data.kits).length === 0;
116287
+ const otherTopLevelKeys = Object.keys(data).filter((key) => key !== "kits");
116288
+ if (dryRun)
116289
+ return noKitsLeft && otherTopLevelKeys.length === 0;
116290
+ if (noKitsLeft && otherTopLevelKeys.length === 0) {
116291
+ await import_fs_extra43.remove(ckJsonPath);
116292
+ return true;
116293
+ }
116294
+ if (noKitsLeft) {
116295
+ Reflect.deleteProperty(data, "kits");
116296
+ }
116297
+ await import_fs_extra43.writeFile(ckJsonPath, JSON.stringify(data, null, 2), "utf-8");
116298
+ return false;
116299
+ }
116300
+ async function cleanupUninstalledSettings(installationPath, options2) {
116301
+ const ckJsonPath = join157(installationPath, CK_JSON_FILE2);
116302
+ if (!await import_fs_extra43.pathExists(ckJsonPath)) {
116303
+ return { ...EMPTY_RESULT };
116304
+ }
116305
+ let data;
116306
+ try {
116307
+ data = parseJsonContent(await import_fs_extra43.readFile(ckJsonPath, "utf-8"));
116308
+ } catch (error) {
116309
+ logger.debug(`Settings cleanup: failed to parse ${ckJsonPath}: ${error instanceof Error ? error.message : "unknown error"}`);
116310
+ return { ...EMPTY_RESULT };
116311
+ }
116312
+ const kits = data.kits ?? {};
116313
+ const removedKitNames = options2.kit ? [options2.kit] : Object.keys(kits);
116314
+ const { hooks, servers } = resolveRemovalTargets(kits, removedKitNames, options2.remainingKits);
116315
+ const result = { ...EMPTY_RESULT };
116316
+ const settingsPath = join157(installationPath, SETTINGS_FILE);
116317
+ const settings = await SettingsMerger.readSettingsFile(settingsPath);
116318
+ if (settings) {
116319
+ result.hooksRemoved = removeHooksFromSettings(settings, hooks);
116320
+ result.mcpServersRemoved = removeMcpServersFromSettings(settings, servers);
116321
+ if (!options2.dryRun && (result.hooksRemoved > 0 || result.mcpServersRemoved > 0)) {
116322
+ if (Object.keys(settings).length === 0) {
116323
+ await import_fs_extra43.remove(settingsPath);
116324
+ result.settingsFileRemoved = true;
116325
+ } else {
116326
+ await SettingsMerger.writeSettingsFile(settingsPath, settings);
116327
+ }
116328
+ }
116329
+ }
116330
+ result.ckJsonRemoved = await cleanupCkJson(ckJsonPath, data, removedKitNames, options2.dryRun ?? false);
116331
+ return result;
116332
+ }
116333
+
116151
116334
  // src/commands/uninstall/removal-handler.ts
116152
116335
  async function isDirectory2(filePath) {
116153
116336
  try {
116154
- const stats = await import_fs_extra43.lstat(filePath);
116337
+ const stats = await import_fs_extra44.lstat(filePath);
116155
116338
  return stats.isDirectory();
116156
116339
  } catch {
116157
116340
  logger.debug(`Failed to check if path is directory: ${filePath}`);
@@ -116159,10 +116342,30 @@ async function isDirectory2(filePath) {
116159
116342
  }
116160
116343
  }
116161
116344
  function getUninstallMutatePaths(options2) {
116345
+ const paths = [];
116162
116346
  if (options2.retainedManifestPaths.length > 0) {
116163
- return ["metadata.json"];
116347
+ paths.push("metadata.json");
116164
116348
  }
116165
- return [];
116349
+ if (options2.settingsFileExists) {
116350
+ paths.push("settings.json");
116351
+ }
116352
+ if (options2.ckJsonExists) {
116353
+ paths.push(".ck.json");
116354
+ }
116355
+ return paths;
116356
+ }
116357
+ function logSettingsCleanup(result, dryRun) {
116358
+ if (result.hooksRemoved === 0 && result.mcpServersRemoved === 0)
116359
+ return;
116360
+ const parts = [];
116361
+ if (result.hooksRemoved > 0) {
116362
+ parts.push(`${result.hooksRemoved} hook${result.hooksRemoved === 1 ? "" : "s"}`);
116363
+ }
116364
+ if (result.mcpServersRemoved > 0) {
116365
+ parts.push(`${result.mcpServersRemoved} MCP server${result.mcpServersRemoved === 1 ? "" : "s"}`);
116366
+ }
116367
+ const verb = dryRun ? "Would remove" : "Removed";
116368
+ log.info(`${verb} ${parts.join(" and ")} from settings.json`);
116166
116369
  }
116167
116370
  async function restoreUninstallBackup(backup) {
116168
116371
  const restoreSpinner = createSpinner("Restoring installation from recovery backup...").start();
@@ -116178,15 +116381,15 @@ async function isPathSafeToRemove(filePath, baseDir) {
116178
116381
  try {
116179
116382
  const resolvedPath = resolve56(filePath);
116180
116383
  const resolvedBase = resolve56(baseDir);
116181
- if (!resolvedPath.startsWith(resolvedBase + sep13) && resolvedPath !== resolvedBase) {
116384
+ if (!resolvedPath.startsWith(resolvedBase + sep14) && resolvedPath !== resolvedBase) {
116182
116385
  logger.debug(`Path outside installation directory: ${filePath}`);
116183
116386
  return false;
116184
116387
  }
116185
- const stats = await import_fs_extra43.lstat(filePath);
116388
+ const stats = await import_fs_extra44.lstat(filePath);
116186
116389
  if (stats.isSymbolicLink()) {
116187
- const realPath = await import_fs_extra43.realpath(filePath);
116390
+ const realPath = await import_fs_extra44.realpath(filePath);
116188
116391
  const resolvedReal = resolve56(realPath);
116189
- if (!resolvedReal.startsWith(resolvedBase + sep13) && resolvedReal !== resolvedBase) {
116392
+ if (!resolvedReal.startsWith(resolvedBase + sep14) && resolvedReal !== resolvedBase) {
116190
116393
  logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
116191
116394
  return false;
116192
116395
  }
@@ -116208,6 +116411,12 @@ async function removeInstallations(installations, options2) {
116208
116411
  const label = options2.kit ? `${installation.type} (${options2.kit} kit)` : installation.type;
116209
116412
  const legacyLabel2 = !installation.hasMetadata ? " [legacy]" : "";
116210
116413
  displayDryRunPreview(analysis, `${label}${legacyLabel2}`);
116414
+ const settingsPreview = await cleanupUninstalledSettings(installation.path, {
116415
+ kit: options2.kit,
116416
+ remainingKits: analysis.remainingKits,
116417
+ dryRun: true
116418
+ });
116419
+ logSettingsCleanup(settingsPreview, true);
116211
116420
  if (analysis.remainingKits.length > 0) {
116212
116421
  log.info(`Remaining kits after uninstall: ${analysis.remainingKits.join(", ")}`);
116213
116422
  }
@@ -116217,7 +116426,9 @@ async function removeInstallations(installations, options2) {
116217
116426
  continue;
116218
116427
  }
116219
116428
  const mutatePaths = getUninstallMutatePaths({
116220
- retainedManifestPaths: analysis.retainedManifestPaths
116429
+ retainedManifestPaths: analysis.retainedManifestPaths,
116430
+ settingsFileExists: await import_fs_extra44.pathExists(join158(installation.path, "settings.json")),
116431
+ ckJsonExists: await import_fs_extra44.pathExists(join158(installation.path, ".ck.json"))
116221
116432
  });
116222
116433
  let backup = null;
116223
116434
  if (analysis.toDelete.length > 0 || mutatePaths.length > 0) {
@@ -116245,15 +116456,15 @@ async function removeInstallations(installations, options2) {
116245
116456
  let removedCount = 0;
116246
116457
  let cleanedDirs = 0;
116247
116458
  for (const item of analysis.toDelete) {
116248
- const filePath = join157(installation.path, item.path);
116249
- if (!await import_fs_extra43.pathExists(filePath))
116459
+ const filePath = join158(installation.path, item.path);
116460
+ if (!await import_fs_extra44.pathExists(filePath))
116250
116461
  continue;
116251
116462
  if (!await isPathSafeToRemove(filePath, installation.path)) {
116252
116463
  logger.debug(`Skipping unsafe path: ${item.path}`);
116253
116464
  continue;
116254
116465
  }
116255
116466
  const isDir2 = await isDirectory2(filePath);
116256
- await import_fs_extra43.remove(filePath);
116467
+ await import_fs_extra44.remove(filePath);
116257
116468
  removedCount++;
116258
116469
  logger.debug(`Removed ${isDir2 ? "directory" : "file"}: ${item.path}`);
116259
116470
  if (!isDir2) {
@@ -116269,6 +116480,11 @@ async function removeInstallations(installations, options2) {
116269
116480
  throw new Error("Failed to update metadata.json after partial uninstall");
116270
116481
  }
116271
116482
  }
116483
+ const settingsCleanup = await cleanupUninstalledSettings(installation.path, {
116484
+ kit: options2.kit,
116485
+ remainingKits: analysis.remainingKits
116486
+ });
116487
+ logSettingsCleanup(settingsCleanup, false);
116272
116488
  try {
116273
116489
  const remaining = readdirSync13(installation.path);
116274
116490
  if (remaining.length === 0) {
@@ -116667,7 +116883,7 @@ ${import_picocolors40.default.bold(import_picocolors40.default.cyan(result.kitCo
116667
116883
  init_logger();
116668
116884
  import { existsSync as existsSync82 } from "node:fs";
116669
116885
  import { rm as rm19 } from "node:fs/promises";
116670
- import { join as join164 } from "node:path";
116886
+ import { join as join165 } from "node:path";
116671
116887
  var import_picocolors41 = __toESM(require_picocolors(), 1);
116672
116888
 
116673
116889
  // src/commands/watch/phases/implementation-runner.ts
@@ -117185,8 +117401,8 @@ function spawnAndCollect3(command, args) {
117185
117401
  }
117186
117402
 
117187
117403
  // src/commands/watch/phases/issue-processor.ts
117188
- import { mkdir as mkdir40, writeFile as writeFile41 } from "node:fs/promises";
117189
- import { join as join160 } from "node:path";
117404
+ import { mkdir as mkdir40, writeFile as writeFile42 } from "node:fs/promises";
117405
+ import { join as join161 } from "node:path";
117190
117406
 
117191
117407
  // src/commands/watch/phases/approval-detector.ts
117192
117408
  init_logger();
@@ -117564,9 +117780,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
117564
117780
 
117565
117781
  // src/commands/watch/phases/plan-dir-finder.ts
117566
117782
  import { readdir as readdir46, stat as stat24 } from "node:fs/promises";
117567
- import { join as join159 } from "node:path";
117783
+ import { join as join160 } from "node:path";
117568
117784
  async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
117569
- const plansRoot = join159(cwd2, "plans");
117785
+ const plansRoot = join160(cwd2, "plans");
117570
117786
  try {
117571
117787
  const entries = await readdir46(plansRoot);
117572
117788
  const tenMinAgo = Date.now() - 10 * 60 * 1000;
@@ -117575,14 +117791,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
117575
117791
  for (const entry of entries) {
117576
117792
  if (entry === "watch" || entry === "reports" || entry === "visuals")
117577
117793
  continue;
117578
- const dirPath = join159(plansRoot, entry);
117794
+ const dirPath = join160(plansRoot, entry);
117579
117795
  const dirStat = await stat24(dirPath);
117580
117796
  if (!dirStat.isDirectory())
117581
117797
  continue;
117582
117798
  if (dirStat.mtimeMs < tenMinAgo)
117583
117799
  continue;
117584
117800
  try {
117585
- await stat24(join159(dirPath, "plan.md"));
117801
+ await stat24(join160(dirPath, "plan.md"));
117586
117802
  } catch {
117587
117803
  continue;
117588
117804
  }
@@ -117813,14 +118029,14 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
117813
118029
  stats.plansCreated++;
117814
118030
  const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
117815
118031
  if (detectedPlanDir) {
117816
- state.activeIssues[numStr].planPath = join160(detectedPlanDir, "plan.md");
118032
+ state.activeIssues[numStr].planPath = join161(detectedPlanDir, "plan.md");
117817
118033
  watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
117818
118034
  } else {
117819
118035
  try {
117820
- const planDir = join160(projectDir, "plans", "watch");
118036
+ const planDir = join161(projectDir, "plans", "watch");
117821
118037
  await mkdir40(planDir, { recursive: true });
117822
- const planFilePath = join160(planDir, `issue-${issue.number}-plan.md`);
117823
- await writeFile41(planFilePath, planResult.planText, "utf-8");
118038
+ const planFilePath = join161(planDir, `issue-${issue.number}-plan.md`);
118039
+ await writeFile42(planFilePath, planResult.planText, "utf-8");
117824
118040
  state.activeIssues[numStr].planPath = planFilePath;
117825
118041
  watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
117826
118042
  } catch (err) {
@@ -117965,7 +118181,7 @@ init_ck_config_manager();
117965
118181
  init_file_io();
117966
118182
  init_logger();
117967
118183
  import { existsSync as existsSync78 } from "node:fs";
117968
- import { mkdir as mkdir41, readFile as readFile70 } from "node:fs/promises";
118184
+ import { mkdir as mkdir41, readFile as readFile71 } from "node:fs/promises";
117969
118185
  import { dirname as dirname54 } from "node:path";
117970
118186
  var PROCESSED_ISSUES_CAP = 500;
117971
118187
  async function readCkJson(projectDir) {
@@ -117973,7 +118189,7 @@ async function readCkJson(projectDir) {
117973
118189
  try {
117974
118190
  if (!existsSync78(configPath))
117975
118191
  return {};
117976
- const content = await readFile70(configPath, "utf-8");
118192
+ const content = await readFile71(configPath, "utf-8");
117977
118193
  return JSON.parse(content);
117978
118194
  } catch (error) {
117979
118195
  logger.warning(`Failed to parse .ck.json: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -118126,18 +118342,18 @@ init_logger();
118126
118342
  import { spawnSync as spawnSync7 } from "node:child_process";
118127
118343
  import { existsSync as existsSync79 } from "node:fs";
118128
118344
  import { readdir as readdir47, stat as stat25 } from "node:fs/promises";
118129
- import { join as join161 } from "node:path";
118345
+ import { join as join162 } from "node:path";
118130
118346
  async function scanForRepos(parentDir) {
118131
118347
  const repos = [];
118132
118348
  const entries = await readdir47(parentDir);
118133
118349
  for (const entry of entries) {
118134
118350
  if (entry.startsWith("."))
118135
118351
  continue;
118136
- const fullPath = join161(parentDir, entry);
118352
+ const fullPath = join162(parentDir, entry);
118137
118353
  const entryStat = await stat25(fullPath);
118138
118354
  if (!entryStat.isDirectory())
118139
118355
  continue;
118140
- const gitDir = join161(fullPath, ".git");
118356
+ const gitDir = join162(fullPath, ".git");
118141
118357
  if (!existsSync79(gitDir))
118142
118358
  continue;
118143
118359
  const result = spawnSync7("gh", ["repo", "view", "--json", "owner,name"], {
@@ -118164,7 +118380,7 @@ init_logger();
118164
118380
  import { spawnSync as spawnSync8 } from "node:child_process";
118165
118381
  import { existsSync as existsSync80 } from "node:fs";
118166
118382
  import { homedir as homedir53 } from "node:os";
118167
- import { join as join162 } from "node:path";
118383
+ import { join as join163 } from "node:path";
118168
118384
  async function validateSetup(cwd2) {
118169
118385
  const workDir = cwd2 ?? process.cwd();
118170
118386
  const ghVersion = spawnSync8("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
@@ -118195,7 +118411,7 @@ Run this command from a directory with a GitHub remote.`);
118195
118411
  } catch {
118196
118412
  throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
118197
118413
  }
118198
- const skillsPath = join162(homedir53(), ".claude", "skills");
118414
+ const skillsPath = join163(homedir53(), ".claude", "skills");
118199
118415
  const skillsAvailable = existsSync80(skillsPath);
118200
118416
  if (!skillsAvailable) {
118201
118417
  logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);
@@ -118214,7 +118430,7 @@ init_path_resolver();
118214
118430
  import { createWriteStream as createWriteStream3, statSync as statSync14 } from "node:fs";
118215
118431
  import { existsSync as existsSync81 } from "node:fs";
118216
118432
  import { mkdir as mkdir42, rename as rename15 } from "node:fs/promises";
118217
- import { join as join163 } from "node:path";
118433
+ import { join as join164 } from "node:path";
118218
118434
 
118219
118435
  class WatchLogger {
118220
118436
  logStream = null;
@@ -118222,7 +118438,7 @@ class WatchLogger {
118222
118438
  logPath = null;
118223
118439
  maxBytes;
118224
118440
  constructor(logDir, maxBytes = 0) {
118225
- this.logDir = logDir ?? join163(PathResolver.getClaudeKitDir(), "logs");
118441
+ this.logDir = logDir ?? join164(PathResolver.getClaudeKitDir(), "logs");
118226
118442
  this.maxBytes = maxBytes;
118227
118443
  }
118228
118444
  async init() {
@@ -118231,7 +118447,7 @@ class WatchLogger {
118231
118447
  await mkdir42(this.logDir, { recursive: true });
118232
118448
  }
118233
118449
  const dateStr = formatDate(new Date);
118234
- this.logPath = join163(this.logDir, `watch-${dateStr}.log`);
118450
+ this.logPath = join164(this.logDir, `watch-${dateStr}.log`);
118235
118451
  this.logStream = createWriteStream3(this.logPath, { flags: "a", mode: 384 });
118236
118452
  } catch (error) {
118237
118453
  logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -118413,7 +118629,7 @@ async function watchCommand(options2) {
118413
118629
  }
118414
118630
  async function discoverRepos(options2, watchLog) {
118415
118631
  const cwd2 = process.cwd();
118416
- const isGitRepo = existsSync82(join164(cwd2, ".git"));
118632
+ const isGitRepo = existsSync82(join165(cwd2, ".git"));
118417
118633
  if (options2.force) {
118418
118634
  await forceRemoveLock(watchLog);
118419
118635
  }
@@ -118671,7 +118887,7 @@ function registerCommands(cli) {
118671
118887
  init_package();
118672
118888
  init_config_version_checker();
118673
118889
  import { existsSync as existsSync94, readFileSync as readFileSync26 } from "node:fs";
118674
- import { join as join176 } from "node:path";
118890
+ import { join as join177 } from "node:path";
118675
118891
 
118676
118892
  // src/domains/versioning/version-checker.ts
118677
118893
  init_version_utils();
@@ -118685,15 +118901,15 @@ init_types3();
118685
118901
  init_logger();
118686
118902
  init_path_resolver();
118687
118903
  import { existsSync as existsSync93 } from "node:fs";
118688
- import { mkdir as mkdir43, readFile as readFile72, writeFile as writeFile44 } from "node:fs/promises";
118689
- import { join as join175 } from "node:path";
118904
+ import { mkdir as mkdir43, readFile as readFile73, writeFile as writeFile45 } from "node:fs/promises";
118905
+ import { join as join176 } from "node:path";
118690
118906
 
118691
118907
  class VersionCacheManager {
118692
118908
  static CACHE_FILENAME = "version-check.json";
118693
118909
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
118694
118910
  static getCacheFile() {
118695
118911
  const cacheDir = PathResolver.getCacheDir(false);
118696
- return join175(cacheDir, VersionCacheManager.CACHE_FILENAME);
118912
+ return join176(cacheDir, VersionCacheManager.CACHE_FILENAME);
118697
118913
  }
118698
118914
  static async load() {
118699
118915
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -118702,7 +118918,7 @@ class VersionCacheManager {
118702
118918
  logger.debug("Version check cache not found");
118703
118919
  return null;
118704
118920
  }
118705
- const content = await readFile72(cacheFile, "utf-8");
118921
+ const content = await readFile73(cacheFile, "utf-8");
118706
118922
  const cache5 = JSON.parse(content);
118707
118923
  if (!cache5.lastCheck || !cache5.currentVersion || !cache5.latestVersion) {
118708
118924
  logger.debug("Invalid cache structure, ignoring");
@@ -118722,7 +118938,7 @@ class VersionCacheManager {
118722
118938
  if (!existsSync93(cacheDir)) {
118723
118939
  await mkdir43(cacheDir, { recursive: true, mode: 448 });
118724
118940
  }
118725
- await writeFile44(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
118941
+ await writeFile45(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
118726
118942
  logger.debug(`Version check cache saved to ${cacheFile}`);
118727
118943
  } catch (error) {
118728
118944
  logger.debug(`Failed to save version check cache: ${error}`);
@@ -119004,9 +119220,9 @@ async function displayVersion() {
119004
119220
  let localInstalledKits = [];
119005
119221
  let globalInstalledKits = [];
119006
119222
  const globalKitDir = PathResolver.getGlobalKitDir();
119007
- const globalMetadataPath = join176(globalKitDir, "metadata.json");
119223
+ const globalMetadataPath = join177(globalKitDir, "metadata.json");
119008
119224
  const prefix = PathResolver.getPathPrefix(false);
119009
- const localMetadataPath = prefix ? join176(process.cwd(), prefix, "metadata.json") : join176(process.cwd(), "metadata.json");
119225
+ const localMetadataPath = prefix ? join177(process.cwd(), prefix, "metadata.json") : join177(process.cwd(), "metadata.json");
119010
119226
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
119011
119227
  if (!isLocalSameAsGlobal && existsSync94(localMetadataPath)) {
119012
119228
  try {
@@ -119394,7 +119610,7 @@ var output2 = new OutputManager2;
119394
119610
 
119395
119611
  // src/shared/temp-cleanup.ts
119396
119612
  init_logger();
119397
- var import_fs_extra44 = __toESM(require_lib(), 1);
119613
+ var import_fs_extra45 = __toESM(require_lib(), 1);
119398
119614
  import { rmSync as rmSync9 } from "node:fs";
119399
119615
  var tempDirs2 = new Set;
119400
119616
  async function cleanup() {
@@ -119403,7 +119619,7 @@ async function cleanup() {
119403
119619
  logger.debug(`Cleaning up ${tempDirs2.size} temporary director(ies)...`);
119404
119620
  for (const dir of tempDirs2) {
119405
119621
  try {
119406
- await import_fs_extra44.remove(dir);
119622
+ await import_fs_extra45.remove(dir);
119407
119623
  logger.debug(`Cleaned up temp directory: ${dir}`);
119408
119624
  } catch (error) {
119409
119625
  logger.debug(`Failed to clean temp directory ${dir}: ${error}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "4.5.0-dev.4",
3
+ "version": "4.5.0-dev.5",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {