claudekit-cli 3.42.2-dev.7 → 3.42.2-dev.9

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
@@ -6944,7 +6944,7 @@ function resolveModel(sourceModel, targetProvider) {
6944
6944
  }
6945
6945
  return { resolved: providerMap[tier] };
6946
6946
  }
6947
- var OPENCODE_DEFAULT_MODEL = "anthropic/claude-sonnet-4-6", SOURCE_TIER_MAP, DEFAULT_PROVIDER_MODEL_MAP, userOverrides;
6947
+ var SOURCE_TIER_MAP, DEFAULT_PROVIDER_MODEL_MAP, userOverrides;
6948
6948
  var init_model_taxonomy = __esm(() => {
6949
6949
  SOURCE_TIER_MAP = {
6950
6950
  opus: "heavy",
@@ -62389,7 +62389,7 @@ var package_default;
62389
62389
  var init_package = __esm(() => {
62390
62390
  package_default = {
62391
62391
  name: "claudekit-cli",
62392
- version: "3.42.2-dev.7",
62392
+ version: "3.42.2-dev.9",
62393
62393
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
62394
62394
  type: "module",
62395
62395
  repository: {
@@ -63356,6 +63356,9 @@ async function invalidateAuth() {
63356
63356
  cachedOctokit = null;
63357
63357
  logger.debug("Invalidated cached authentication due to 401 error");
63358
63358
  }
63359
+ function resetClient() {
63360
+ cachedOctokit = null;
63361
+ }
63359
63362
  var cachedOctokit = null;
63360
63363
  var init_auth_api = __esm(() => {
63361
63364
  init_claudekit_constants();
@@ -64268,6 +64271,16 @@ var init_asset_utils = __esm(() => {
64268
64271
  });
64269
64272
 
64270
64273
  // src/domains/github/client/index.ts
64274
+ var exports_client = {};
64275
+ __export(exports_client, {
64276
+ resetClient: () => resetClient,
64277
+ invalidateAuth: () => invalidateAuth,
64278
+ handleHttpError: () => handleHttpError,
64279
+ getDownloadableAsset: () => getDownloadableAsset,
64280
+ getAuthenticatedClient: () => getAuthenticatedClient,
64281
+ RepoApi: () => RepoApi,
64282
+ ReleasesApi: () => ReleasesApi
64283
+ });
64271
64284
  var init_client = __esm(() => {
64272
64285
  init_auth_api();
64273
64286
  init_error_handler2();
@@ -73512,7 +73525,7 @@ async function restoreOriginalBranch(branchName, cwd2, issueNumber) {
73512
73525
  }
73513
73526
  }
73514
73527
  function spawnAndCollect(command, args, cwd2) {
73515
- return new Promise((resolve49, reject) => {
73528
+ return new Promise((resolve44, reject) => {
73516
73529
  const child = spawn6(command, args, { ...cwd2 && { cwd: cwd2 }, stdio: ["ignore", "pipe", "pipe"] });
73517
73530
  const chunks = [];
73518
73531
  const stderrChunks = [];
@@ -73525,7 +73538,7 @@ function spawnAndCollect(command, args, cwd2) {
73525
73538
  reject(new Error(`${command} ${args[0] ?? ""} exited with code ${code2}: ${stderr}`));
73526
73539
  return;
73527
73540
  }
73528
- resolve49(Buffer.concat(chunks).toString("utf-8"));
73541
+ resolve44(Buffer.concat(chunks).toString("utf-8"));
73529
73542
  });
73530
73543
  });
73531
73544
  }
@@ -73543,10 +73556,10 @@ __export(exports_worktree_manager, {
73543
73556
  cleanupAllWorktrees: () => cleanupAllWorktrees
73544
73557
  });
73545
73558
  import { existsSync as existsSync69 } from "node:fs";
73546
- import { readFile as readFile63, writeFile as writeFile36 } from "node:fs/promises";
73547
- import { join as join151 } from "node:path";
73559
+ import { readFile as readFile65, writeFile as writeFile37 } from "node:fs/promises";
73560
+ import { join as join153 } from "node:path";
73548
73561
  async function createWorktree(projectDir, issueNumber, baseBranch) {
73549
- const worktreePath = join151(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
73562
+ const worktreePath = join153(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
73550
73563
  const branchName = `ck-watch/issue-${issueNumber}`;
73551
73564
  await spawnAndCollect("git", ["fetch", "origin", baseBranch], projectDir).catch(() => {
73552
73565
  logger.warning(`[worktree] Could not fetch origin/${baseBranch}, using local`);
@@ -73564,7 +73577,7 @@ async function createWorktree(projectDir, issueNumber, baseBranch) {
73564
73577
  return worktreePath;
73565
73578
  }
73566
73579
  async function removeWorktree(projectDir, issueNumber) {
73567
- const worktreePath = join151(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
73580
+ const worktreePath = join153(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
73568
73581
  const branchName = `ck-watch/issue-${issueNumber}`;
73569
73582
  try {
73570
73583
  await spawnAndCollect("git", ["worktree", "remove", worktreePath, "--force"], projectDir);
@@ -73578,7 +73591,7 @@ async function listActiveWorktrees(projectDir) {
73578
73591
  try {
73579
73592
  const output2 = await spawnAndCollect("git", ["worktree", "list", "--porcelain"], projectDir);
73580
73593
  const issueNumbers = [];
73581
- const worktreePrefix = join151(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
73594
+ const worktreePrefix = join153(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
73582
73595
  for (const line of output2.split(`
73583
73596
  `)) {
73584
73597
  if (line.startsWith("worktree ")) {
@@ -73606,16 +73619,16 @@ async function cleanupAllWorktrees(projectDir) {
73606
73619
  await spawnAndCollect("git", ["worktree", "prune"], projectDir).catch(() => {});
73607
73620
  }
73608
73621
  async function ensureGitignore(projectDir) {
73609
- const gitignorePath = join151(projectDir, ".gitignore");
73622
+ const gitignorePath = join153(projectDir, ".gitignore");
73610
73623
  try {
73611
- const content = existsSync69(gitignorePath) ? await readFile63(gitignorePath, "utf-8") : "";
73624
+ const content = existsSync69(gitignorePath) ? await readFile65(gitignorePath, "utf-8") : "";
73612
73625
  if (!content.includes(".worktrees")) {
73613
73626
  const newContent = content.endsWith(`
73614
73627
  `) ? `${content}.worktrees/
73615
73628
  ` : `${content}
73616
73629
  .worktrees/
73617
73630
  `;
73618
- await writeFile36(gitignorePath, newContent, "utf-8");
73631
+ await writeFile37(gitignorePath, newContent, "utf-8");
73619
73632
  logger.info("[worktree] Added .worktrees/ to .gitignore");
73620
73633
  }
73621
73634
  } catch (err) {
@@ -73644,15 +73657,15 @@ function countTwitterChars(text) {
73644
73657
  }
73645
73658
  return count;
73646
73659
  }
73647
- function validateContent(content, platform17) {
73660
+ function validateContent(content, platform18) {
73648
73661
  const issues = [];
73649
73662
  if (!content.text || content.text.trim().length === 0) {
73650
73663
  issues.push("Content text is empty");
73651
73664
  return { valid: false, issues };
73652
73665
  }
73653
- if (platform17 !== "x_thread") {
73654
- const limit = platform17 === "facebook" ? 500 : 280;
73655
- const charCount = platform17 === "x" ? countTwitterChars(content.text) : content.text.length;
73666
+ if (platform18 !== "x_thread") {
73667
+ const limit = platform18 === "facebook" ? 500 : 280;
73668
+ const charCount = platform18 === "x" ? countTwitterChars(content.text) : content.text.length;
73656
73669
  if (charCount > limit) {
73657
73670
  issues.push(`Text exceeds ${limit} char limit (${charCount} weighted chars)`);
73658
73671
  }
@@ -73675,7 +73688,7 @@ function validateContent(content, platform17) {
73675
73688
  issues.push("Hook (first sentence) is too long (>25 words)");
73676
73689
  }
73677
73690
  const hashtagCount = content.hashtags?.length ?? 0;
73678
- if (platform17 === "x" && hashtagCount > 5) {
73691
+ if (platform18 === "x" && hashtagCount > 5) {
73679
73692
  issues.push("Too many hashtags for X (max 5)");
73680
73693
  }
73681
73694
  return { valid: issues.length === 0, issues };
@@ -73711,9 +73724,9 @@ var init_content_validator = __esm(() => {
73711
73724
  // src/commands/content/phases/context-cache-manager.ts
73712
73725
  import { createHash as createHash9 } from "node:crypto";
73713
73726
  import { existsSync as existsSync75, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync14 } from "node:fs";
73714
- import { rename as rename14, writeFile as writeFile38 } from "node:fs/promises";
73715
- import { homedir as homedir52 } from "node:os";
73716
- import { basename as basename31, join as join158 } from "node:path";
73727
+ import { rename as rename15, writeFile as writeFile39 } from "node:fs/promises";
73728
+ import { homedir as homedir54 } from "node:os";
73729
+ import { basename as basename31, join as join160 } from "node:path";
73717
73730
  function getCachedContext(repoPath) {
73718
73731
  const cachePath = getCacheFilePath(repoPath);
73719
73732
  if (!existsSync75(cachePath))
@@ -73722,7 +73735,7 @@ function getCachedContext(repoPath) {
73722
73735
  const raw2 = readFileSync18(cachePath, "utf-8");
73723
73736
  const cache5 = JSON.parse(raw2);
73724
73737
  const age = Date.now() - new Date(cache5.createdAt).getTime();
73725
- if (age >= CACHE_TTL_MS4)
73738
+ if (age >= CACHE_TTL_MS5)
73726
73739
  return null;
73727
73740
  const currentHash = computeSourceHash(repoPath);
73728
73741
  if (currentHash !== cache5.sourceHash)
@@ -73738,8 +73751,8 @@ async function saveCachedContext(repoPath, cache5) {
73738
73751
  }
73739
73752
  const cachePath = getCacheFilePath(repoPath);
73740
73753
  const tmpPath = `${cachePath}.tmp`;
73741
- await writeFile38(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
73742
- await rename14(tmpPath, cachePath);
73754
+ await writeFile39(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
73755
+ await rename15(tmpPath, cachePath);
73743
73756
  }
73744
73757
  function computeSourceHash(repoPath) {
73745
73758
  const hash = createHash9("sha256");
@@ -73756,25 +73769,25 @@ function computeSourceHash(repoPath) {
73756
73769
  }
73757
73770
  function getDocSourcePaths(repoPath) {
73758
73771
  const paths = [];
73759
- const docsDir = join158(repoPath, "docs");
73772
+ const docsDir = join160(repoPath, "docs");
73760
73773
  if (existsSync75(docsDir)) {
73761
73774
  try {
73762
73775
  const files = readdirSync11(docsDir);
73763
73776
  for (const f3 of files) {
73764
73777
  if (f3.endsWith(".md"))
73765
- paths.push(join158(docsDir, f3));
73778
+ paths.push(join160(docsDir, f3));
73766
73779
  }
73767
73780
  } catch {}
73768
73781
  }
73769
- const readme = join158(repoPath, "README.md");
73782
+ const readme = join160(repoPath, "README.md");
73770
73783
  if (existsSync75(readme))
73771
73784
  paths.push(readme);
73772
- const stylesDir = join158(repoPath, "assets", "writing-styles");
73785
+ const stylesDir = join160(repoPath, "assets", "writing-styles");
73773
73786
  if (existsSync75(stylesDir)) {
73774
73787
  try {
73775
73788
  const files = readdirSync11(stylesDir);
73776
73789
  for (const f3 of files) {
73777
- paths.push(join158(stylesDir, f3));
73790
+ paths.push(join160(stylesDir, f3));
73778
73791
  }
73779
73792
  } catch {}
73780
73793
  }
@@ -73783,12 +73796,12 @@ function getDocSourcePaths(repoPath) {
73783
73796
  function getCacheFilePath(repoPath) {
73784
73797
  const repoName = basename31(repoPath).replace(/[^a-zA-Z0-9_-]/g, "_");
73785
73798
  const pathHash = createHash9("sha256").update(repoPath).digest("hex").slice(0, 8);
73786
- return join158(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
73799
+ return join160(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
73787
73800
  }
73788
- var CACHE_DIR, CACHE_TTL_MS4;
73801
+ var CACHE_DIR, CACHE_TTL_MS5;
73789
73802
  var init_context_cache_manager = __esm(() => {
73790
- CACHE_DIR = join158(homedir52(), ".claudekit", "cache");
73791
- CACHE_TTL_MS4 = 24 * 60 * 60 * 1000;
73803
+ CACHE_DIR = join160(homedir54(), ".claudekit", "cache");
73804
+ CACHE_TTL_MS5 = 24 * 60 * 60 * 1000;
73792
73805
  });
73793
73806
 
73794
73807
  // src/commands/content/phases/db-queries-git-events.ts
@@ -73968,7 +73981,7 @@ function extractContentFromResponse(response) {
73968
73981
  // src/commands/content/phases/docs-summarizer.ts
73969
73982
  import { execSync as execSync7 } from "node:child_process";
73970
73983
  import { existsSync as existsSync76, readFileSync as readFileSync19, readdirSync as readdirSync12 } from "node:fs";
73971
- import { join as join159 } from "node:path";
73984
+ import { join as join161 } from "node:path";
73972
73985
  async function summarizeProjectDocs(repoPath, contentLogger) {
73973
73986
  const rawContent = collectRawDocs(repoPath);
73974
73987
  if (rawContent.total.length < 200) {
@@ -74022,12 +74035,12 @@ function collectRawDocs(repoPath) {
74022
74035
  return capped;
74023
74036
  };
74024
74037
  const docsContent = [];
74025
- const docsDir = join159(repoPath, "docs");
74038
+ const docsDir = join161(repoPath, "docs");
74026
74039
  if (existsSync76(docsDir)) {
74027
74040
  try {
74028
74041
  const files = readdirSync12(docsDir).filter((f3) => f3.endsWith(".md")).sort();
74029
74042
  for (const f3 of files) {
74030
- const content = readCapped(join159(docsDir, f3), 5000);
74043
+ const content = readCapped(join161(docsDir, f3), 5000);
74031
74044
  if (content) {
74032
74045
  docsContent.push(`### ${f3}
74033
74046
  ${content}`);
@@ -74041,21 +74054,21 @@ ${content}`);
74041
74054
  let brand = "";
74042
74055
  const brandCandidates = ["docs/brand-guidelines.md", "docs/design-guidelines.md"];
74043
74056
  for (const p of brandCandidates) {
74044
- brand = readCapped(join159(repoPath, p), 3000);
74057
+ brand = readCapped(join161(repoPath, p), 3000);
74045
74058
  if (brand)
74046
74059
  break;
74047
74060
  }
74048
74061
  let styles3 = "";
74049
- const stylesDir = join159(repoPath, "assets", "writing-styles");
74062
+ const stylesDir = join161(repoPath, "assets", "writing-styles");
74050
74063
  if (existsSync76(stylesDir)) {
74051
74064
  try {
74052
74065
  const files = readdirSync12(stylesDir).slice(0, 3);
74053
- styles3 = files.map((f3) => readCapped(join159(stylesDir, f3), 1000)).filter(Boolean).join(`
74066
+ styles3 = files.map((f3) => readCapped(join161(stylesDir, f3), 1000)).filter(Boolean).join(`
74054
74067
 
74055
74068
  `);
74056
74069
  } catch {}
74057
74070
  }
74058
- const readme = readCapped(join159(repoPath, "README.md"), 3000);
74071
+ const readme = readCapped(join161(repoPath, "README.md"), 3000);
74059
74072
  const total = [docs, brand, styles3, readme].join(`
74060
74073
  `);
74061
74074
  return { docs, brand, styles: styles3, readme, total };
@@ -74089,10 +74102,10 @@ var MAX_RAW_CONTENT_CHARS = 50000;
74089
74102
  var init_docs_summarizer = () => {};
74090
74103
 
74091
74104
  // src/commands/content/phases/context-builder.ts
74092
- async function buildContentContext(event, repoPath, config, db, platform17, contentLogger) {
74105
+ async function buildContentContext(event, repoPath, config, db, platform18, contentLogger) {
74093
74106
  const cached = getCachedContext(repoPath);
74094
74107
  if (cached) {
74095
- return buildFromCache(cached, event, db, platform17, config);
74108
+ return buildFromCache(cached, event, db, platform18, config);
74096
74109
  }
74097
74110
  const noopLogger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} };
74098
74111
  const log2 = contentLogger ?? noopLogger;
@@ -74107,16 +74120,16 @@ async function buildContentContext(event, repoPath, config, db, platform17, cont
74107
74120
  sourceHash: hash
74108
74121
  };
74109
74122
  await saveCachedContext(repoPath, newCache);
74110
- return buildFromCache(newCache, event, db, platform17, config);
74123
+ return buildFromCache(newCache, event, db, platform18, config);
74111
74124
  }
74112
- function buildFromCache(cache5, event, db, platform17, config) {
74125
+ function buildFromCache(cache5, event, db, platform18, config) {
74113
74126
  return {
74114
74127
  brandGuidelines: cache5.brandSummary,
74115
74128
  writingStyles: cache5.stylesSummary,
74116
74129
  gitEventDetails: formatGitEvent(event),
74117
74130
  recentContent: formatRecentContent(db),
74118
74131
  topPerformingContent: "",
74119
- platformRules: getPlatformRules(platform17, config),
74132
+ platformRules: getPlatformRules(platform18, config),
74120
74133
  projectReadme: cache5.readmeSummary,
74121
74134
  projectDocsSummary: cache5.docsSummary,
74122
74135
  currentDateTime: new Date().toISOString()
@@ -74145,8 +74158,8 @@ function formatRecentContent(db) {
74145
74158
  return recent.map((c2) => `[${c2.platform}] ${c2.textContent.slice(0, 100)}`).join(`
74146
74159
  `);
74147
74160
  }
74148
- function getPlatformRules(platform17, config) {
74149
- switch (platform17) {
74161
+ function getPlatformRules(platform18, config) {
74162
+ switch (platform18) {
74150
74163
  case "x":
74151
74164
  return [
74152
74165
  "Platform: X (Twitter)",
@@ -74185,8 +74198,8 @@ var init_context_builder = __esm(() => {
74185
74198
  });
74186
74199
 
74187
74200
  // src/commands/content/phases/prompt-templates.ts
74188
- function buildTextPrompt(context, platform17) {
74189
- const charLimit = platform17 === "x" || platform17 === "x_thread" ? 280 : 500;
74201
+ function buildTextPrompt(context, platform18) {
74202
+ const charLimit = platform18 === "x" || platform18 === "x_thread" ? 280 : 500;
74190
74203
  return `You are a social media content creator.
74191
74204
 
74192
74205
  ## Project Context
@@ -74201,14 +74214,14 @@ ${context.writingStyles}
74201
74214
  ## Content Source
74202
74215
  ${context.gitEventDetails}
74203
74216
 
74204
- ## Platform: ${platform17}
74217
+ ## Platform: ${platform18}
74205
74218
  ${context.platformRules}
74206
74219
 
74207
74220
  ## Past Content (avoid repetition)
74208
74221
  ${context.recentContent}
74209
74222
 
74210
74223
  ## Instructions
74211
- 1. Create a ${platform17} post about this development update
74224
+ 1. Create a ${platform18} post about this development update
74212
74225
  2. Start with a compelling hook that creates curiosity
74213
74226
  3. Keep it conversational and authentic (avoid AI-sounding language)
74214
74227
  4. No generic statements — be specific about what changed and why it matters
@@ -74218,8 +74231,8 @@ ${context.recentContent}
74218
74231
 
74219
74232
  IMPORTANT: Output ONLY the JSON object, nothing else.`;
74220
74233
  }
74221
- function buildPhotoPrompt(context, platform17) {
74222
- const dimensions = platform17 === "facebook" ? "1200x630" : "1200x675";
74234
+ function buildPhotoPrompt(context, platform18) {
74235
+ const dimensions = platform18 === "facebook" ? "1200x630" : "1200x675";
74223
74236
  return `Generate an image for this social media post.
74224
74237
 
74225
74238
  ## Brand Guidelines
@@ -74241,15 +74254,15 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
74241
74254
  // src/commands/content/phases/photo-generator.ts
74242
74255
  import { execSync as execSync8 } from "node:child_process";
74243
74256
  import { existsSync as existsSync77, mkdirSync as mkdirSync6, readdirSync as readdirSync13 } from "node:fs";
74244
- import { homedir as homedir53 } from "node:os";
74245
- import { join as join160 } from "node:path";
74246
- async function generatePhoto(_content, context, config, platform17, contentId, contentLogger) {
74247
- const mediaDir = join160(config.contentDir.replace(/^~/, homedir53()), "media", String(contentId));
74257
+ import { homedir as homedir55 } from "node:os";
74258
+ import { join as join162 } from "node:path";
74259
+ async function generatePhoto(_content, context, config, platform18, contentId, contentLogger) {
74260
+ const mediaDir = join162(config.contentDir.replace(/^~/, homedir55()), "media", String(contentId));
74248
74261
  if (!existsSync77(mediaDir)) {
74249
74262
  mkdirSync6(mediaDir, { recursive: true });
74250
74263
  }
74251
- const prompt = buildPhotoPrompt(context, platform17);
74252
- const dimensions = platform17 === "facebook" ? { width: 1200, height: 630 } : { width: 1200, height: 675 };
74264
+ const prompt = buildPhotoPrompt(context, platform18);
74265
+ const dimensions = platform18 === "facebook" ? { width: 1200, height: 630 } : { width: 1200, height: 675 };
74253
74266
  try {
74254
74267
  contentLogger.debug(`Generating photo for content ${contentId}...`);
74255
74268
  const result = execSync8("claude -p --output-format text --max-turns 40", {
@@ -74269,7 +74282,7 @@ async function generatePhoto(_content, context, config, platform17, contentId, c
74269
74282
  const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
74270
74283
  if (imageFile) {
74271
74284
  const ext2 = imageFile.split(".").pop() ?? "png";
74272
- return { path: join160(mediaDir, imageFile), ...dimensions, format: ext2 };
74285
+ return { path: join162(mediaDir, imageFile), ...dimensions, format: ext2 };
74273
74286
  }
74274
74287
  contentLogger.warn(`Photo generation produced no image for content ${contentId}`);
74275
74288
  return null;
@@ -74287,14 +74300,14 @@ async function createContent(event, config, db, contentLogger, options2) {
74287
74300
  const startTime = Date.now();
74288
74301
  const items = [];
74289
74302
  const platforms = resolveEnabledPlatforms(config);
74290
- for (const platform17 of platforms) {
74303
+ for (const platform18 of platforms) {
74291
74304
  try {
74292
- const item = await createContentForPlatform(event, platform17, config, db, contentLogger, options2);
74305
+ const item = await createContentForPlatform(event, platform18, config, db, contentLogger, options2);
74293
74306
  if (item)
74294
74307
  items.push(item);
74295
74308
  } catch (err) {
74296
74309
  const msg = err instanceof Error ? err.message : String(err);
74297
- contentLogger.error(`Failed to create ${platform17} content: ${msg}`);
74310
+ contentLogger.error(`Failed to create ${platform18} content: ${msg}`);
74298
74311
  }
74299
74312
  }
74300
74313
  insertTaskLog(db, {
@@ -74313,10 +74326,10 @@ function resolveEnabledPlatforms(config) {
74313
74326
  platforms.push("facebook");
74314
74327
  return platforms;
74315
74328
  }
74316
- async function createContentForPlatform(event, platform17, config, db, contentLogger, options2) {
74317
- const context = await buildContentContext(event, event.repoPath, config, db, platform17, contentLogger);
74318
- const prompt = buildTextPrompt(context, platform17);
74319
- contentLogger.debug(`Generating ${platform17} content for event ${event.id}...`);
74329
+ async function createContentForPlatform(event, platform18, config, db, contentLogger, options2) {
74330
+ const context = await buildContentContext(event, event.repoPath, config, db, platform18, contentLogger);
74331
+ const prompt = buildTextPrompt(context, platform18);
74332
+ contentLogger.debug(`Generating ${platform18} content for event ${event.id}...`);
74320
74333
  const stdout2 = execSync9("claude -p --output-format text --max-turns 5", {
74321
74334
  input: prompt,
74322
74335
  stdio: ["pipe", "pipe", "pipe"],
@@ -74324,14 +74337,14 @@ async function createContentForPlatform(event, platform17, config, db, contentLo
74324
74337
  }).toString();
74325
74338
  const parsed = parseClaudeJsonOutput(stdout2);
74326
74339
  const generated = extractContentFromResponse(parsed);
74327
- const validation = validateContent(generated, platform17);
74340
+ const validation = validateContent(generated, platform18);
74328
74341
  if (!validation.valid) {
74329
- contentLogger.warn(`Content validation failed for ${platform17}: ${validation.issues.join(", ")}`);
74342
+ contentLogger.warn(`Content validation failed for ${platform18}: ${validation.issues.join(", ")}`);
74330
74343
  }
74331
74344
  const status = validation.valid ? config.reviewMode === "auto" ? "scheduled" : "reviewing" : "draft";
74332
74345
  const itemId = insertContentItem(db, {
74333
74346
  gitEventId: event.id,
74334
- platform: platform17,
74347
+ platform: platform18,
74335
74348
  textContent: generated.text,
74336
74349
  hashtags: JSON.stringify(generated.hashtags),
74337
74350
  hookLine: generated.hook,
@@ -74341,12 +74354,12 @@ async function createContentForPlatform(event, platform17, config, db, contentLo
74341
74354
  scheduledAt: null
74342
74355
  });
74343
74356
  if (!options2.dryRun && generated.mediaPrompt) {
74344
- const photo = await generatePhoto(generated, context, config, platform17, itemId, contentLogger);
74357
+ const photo = await generatePhoto(generated, context, config, platform18, itemId, contentLogger);
74345
74358
  if (photo) {
74346
74359
  db.prepare("UPDATE content_items SET media_path = ? WHERE id = ?").run(photo.path, itemId);
74347
74360
  }
74348
74361
  }
74349
- contentLogger.info(`Created ${platform17} content (id: ${itemId}, status: ${status})`);
74362
+ contentLogger.info(`Created ${platform18} content (id: ${itemId}, status: ${status})`);
74350
74363
  return getContentById(db, itemId);
74351
74364
  }
74352
74365
  var init_content_creator = __esm(() => {
@@ -74358,8 +74371,8 @@ var init_content_creator = __esm(() => {
74358
74371
 
74359
74372
  // src/commands/content/phases/content-logger.ts
74360
74373
  import { createWriteStream as createWriteStream4, existsSync as existsSync78, mkdirSync as mkdirSync7, statSync as statSync15 } from "node:fs";
74361
- import { homedir as homedir54 } from "node:os";
74362
- import { join as join161 } from "node:path";
74374
+ import { homedir as homedir56 } from "node:os";
74375
+ import { join as join163 } from "node:path";
74363
74376
 
74364
74377
  class ContentLogger {
74365
74378
  stream = null;
@@ -74367,7 +74380,7 @@ class ContentLogger {
74367
74380
  logDir;
74368
74381
  maxBytes;
74369
74382
  constructor(maxBytes = 0) {
74370
- this.logDir = join161(homedir54(), ".claudekit", "logs");
74383
+ this.logDir = join163(homedir56(), ".claudekit", "logs");
74371
74384
  this.maxBytes = maxBytes;
74372
74385
  }
74373
74386
  init() {
@@ -74399,7 +74412,7 @@ class ContentLogger {
74399
74412
  }
74400
74413
  }
74401
74414
  getLogPath() {
74402
- return join161(this.logDir, `content-${this.getDateStr()}.log`);
74415
+ return join163(this.logDir, `content-${this.getDateStr()}.log`);
74403
74416
  }
74404
74417
  write(level, message) {
74405
74418
  this.rotateIfNeeded();
@@ -74416,19 +74429,19 @@ class ContentLogger {
74416
74429
  if (dateStr !== this.currentDate) {
74417
74430
  this.close();
74418
74431
  this.currentDate = dateStr;
74419
- const logPath = join161(this.logDir, `content-${dateStr}.log`);
74432
+ const logPath = join163(this.logDir, `content-${dateStr}.log`);
74420
74433
  this.stream = createWriteStream4(logPath, { flags: "a", mode: 384 });
74421
74434
  return;
74422
74435
  }
74423
74436
  if (this.maxBytes > 0 && this.stream) {
74424
- const logPath = join161(this.logDir, `content-${this.currentDate}.log`);
74437
+ const logPath = join163(this.logDir, `content-${this.currentDate}.log`);
74425
74438
  try {
74426
74439
  const stat26 = statSync15(logPath);
74427
74440
  if (stat26.size >= this.maxBytes) {
74428
74441
  this.close();
74429
74442
  const suffix = Date.now();
74430
- const rotatedPath = join161(this.logDir, `content-${this.currentDate}-${suffix}.log`);
74431
- import("node:fs/promises").then(({ rename: rename15 }) => rename15(logPath, rotatedPath).catch(() => {}));
74443
+ const rotatedPath = join163(this.logDir, `content-${this.currentDate}-${suffix}.log`);
74444
+ import("node:fs/promises").then(({ rename: rename16 }) => rename16(logPath, rotatedPath).catch(() => {}));
74432
74445
  this.stream = createWriteStream4(logPath, { flags: "w", mode: 384 });
74433
74446
  }
74434
74447
  } catch {}
@@ -74653,7 +74666,7 @@ function isNoiseCommit(title, author) {
74653
74666
  // src/commands/content/phases/change-detector.ts
74654
74667
  import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
74655
74668
  import { existsSync as existsSync80, readFileSync as readFileSync20, readdirSync as readdirSync14, statSync as statSync16 } from "node:fs";
74656
- import { join as join162 } from "node:path";
74669
+ import { join as join164 } from "node:path";
74657
74670
  function detectCommits(repo, since) {
74658
74671
  try {
74659
74672
  const fetchUrl = sshToHttps(repo.remoteUrl);
@@ -74762,7 +74775,7 @@ function detectTags(repo, since) {
74762
74775
  }
74763
74776
  }
74764
74777
  function detectCompletedPlans(repo, since) {
74765
- const plansDir = join162(repo.path, "plans");
74778
+ const plansDir = join164(repo.path, "plans");
74766
74779
  if (!existsSync80(plansDir))
74767
74780
  return [];
74768
74781
  const sinceMs = new Date(since).getTime();
@@ -74772,7 +74785,7 @@ function detectCompletedPlans(repo, since) {
74772
74785
  for (const entry of entries) {
74773
74786
  if (!entry.isDirectory())
74774
74787
  continue;
74775
- const planFile = join162(plansDir, entry.name, "plan.md");
74788
+ const planFile = join164(plansDir, entry.name, "plan.md");
74776
74789
  if (!existsSync80(planFile))
74777
74790
  continue;
74778
74791
  try {
@@ -74850,7 +74863,7 @@ function classifyCommit(event) {
74850
74863
  // src/commands/content/phases/repo-discoverer.ts
74851
74864
  import { execSync as execSync11 } from "node:child_process";
74852
74865
  import { readdirSync as readdirSync15 } from "node:fs";
74853
- import { join as join163 } from "node:path";
74866
+ import { join as join165 } from "node:path";
74854
74867
  function discoverRepos2(cwd2) {
74855
74868
  const repos = [];
74856
74869
  if (isGitRepoRoot(cwd2)) {
@@ -74863,7 +74876,7 @@ function discoverRepos2(cwd2) {
74863
74876
  for (const entry of entries) {
74864
74877
  if (!entry.isDirectory() || entry.name.startsWith("."))
74865
74878
  continue;
74866
- const dirPath = join163(cwd2, entry.name);
74879
+ const dirPath = join165(cwd2, entry.name);
74867
74880
  if (isGitRepoRoot(dirPath)) {
74868
74881
  const info = getRepoInfo(dirPath);
74869
74882
  if (info)
@@ -75233,15 +75246,15 @@ class RateLimiter {
75233
75246
  this.state = state;
75234
75247
  this.config = config;
75235
75248
  }
75236
- canPost(platform17) {
75237
- return this.getTodayCount(platform17) < this.getMaxPerDay(platform17);
75249
+ canPost(platform18) {
75250
+ return this.getTodayCount(platform18) < this.getMaxPerDay(platform18);
75238
75251
  }
75239
- recordPost(platform17) {
75240
- const key = this.dailyKey(platform17);
75252
+ recordPost(platform18) {
75253
+ const key = this.dailyKey(platform18);
75241
75254
  this.state.dailyPostCounts[key] = (this.state.dailyPostCounts[key] ?? 0) + 1;
75242
75255
  }
75243
- getRemainingToday(platform17) {
75244
- return Math.max(0, this.getMaxPerDay(platform17) - this.getTodayCount(platform17));
75256
+ getRemainingToday(platform18) {
75257
+ return Math.max(0, this.getMaxPerDay(platform18) - this.getTodayCount(platform18));
75245
75258
  }
75246
75259
  isInQuietHours() {
75247
75260
  const { timezone, quietHoursStart, quietHoursEnd } = this.config.schedule;
@@ -75261,19 +75274,19 @@ class RateLimiter {
75261
75274
  return false;
75262
75275
  }
75263
75276
  }
75264
- getMaxPerDay(platform17) {
75265
- if (platform17 === "x" || platform17 === "x_thread") {
75277
+ getMaxPerDay(platform18) {
75278
+ if (platform18 === "x" || platform18 === "x_thread") {
75266
75279
  return this.config.platforms.x.maxPostsPerDay;
75267
75280
  }
75268
- if (platform17 === "facebook") {
75281
+ if (platform18 === "facebook") {
75269
75282
  return this.config.platforms.facebook.maxPostsPerDay;
75270
75283
  }
75271
75284
  return this.config.maxContentPerDay;
75272
75285
  }
75273
- getTodayCount(platform17) {
75274
- return this.state.dailyPostCounts[this.dailyKey(platform17)] ?? 0;
75286
+ getTodayCount(platform18) {
75287
+ return this.state.dailyPostCounts[this.dailyKey(platform18)] ?? 0;
75275
75288
  }
75276
- dailyKey(platform17) {
75289
+ dailyKey(platform18) {
75277
75290
  const { timezone } = this.config.schedule;
75278
75291
  let dateStr;
75279
75292
  try {
@@ -75287,7 +75300,7 @@ class RateLimiter {
75287
75300
  } catch {
75288
75301
  dateStr = new Date().toISOString().slice(0, 10);
75289
75302
  }
75290
- return `${platform17}-${dateStr}`;
75303
+ return `${platform18}-${dateStr}`;
75291
75304
  }
75292
75305
  }
75293
75306
 
@@ -75404,8 +75417,8 @@ function previewContent(content) {
75404
75417
  console.log(import_picocolors42.default.dim("─".repeat(60)));
75405
75418
  console.log();
75406
75419
  }
75407
- function getPlatformBadge(platform17) {
75408
- switch (platform17) {
75420
+ function getPlatformBadge(platform18) {
75421
+ switch (platform18) {
75409
75422
  case "x":
75410
75423
  return import_picocolors42.default.bgBlue(import_picocolors42.default.white(" X "));
75411
75424
  case "x_thread":
@@ -75413,7 +75426,7 @@ function getPlatformBadge(platform17) {
75413
75426
  case "facebook":
75414
75427
  return import_picocolors42.default.bgCyan(import_picocolors42.default.white(" Facebook "));
75415
75428
  default:
75416
- return import_picocolors42.default.bgBlack(import_picocolors42.default.white(` ${platform17} `));
75429
+ return import_picocolors42.default.bgBlack(import_picocolors42.default.white(` ${platform18} `));
75417
75430
  }
75418
75431
  }
75419
75432
  function getStatusColor(status) {
@@ -75530,12 +75543,12 @@ var init_types6 = __esm(() => {
75530
75543
  });
75531
75544
 
75532
75545
  // src/commands/content/phases/state-manager.ts
75533
- import { readFile as readFile65, rename as rename15, writeFile as writeFile39 } from "node:fs/promises";
75534
- import { join as join164 } from "node:path";
75546
+ import { readFile as readFile67, rename as rename16, writeFile as writeFile40 } from "node:fs/promises";
75547
+ import { join as join166 } from "node:path";
75535
75548
  async function loadContentConfig(projectDir) {
75536
- const configPath = join164(projectDir, CK_CONFIG_FILE2);
75549
+ const configPath = join166(projectDir, CK_CONFIG_FILE2);
75537
75550
  try {
75538
- const raw2 = await readFile65(configPath, "utf-8");
75551
+ const raw2 = await readFile67(configPath, "utf-8");
75539
75552
  const json = JSON.parse(raw2);
75540
75553
  return ContentConfigSchema.parse(json.content ?? {});
75541
75554
  } catch {
@@ -75543,15 +75556,15 @@ async function loadContentConfig(projectDir) {
75543
75556
  }
75544
75557
  }
75545
75558
  async function saveContentConfig(projectDir, config) {
75546
- const configPath = join164(projectDir, CK_CONFIG_FILE2);
75559
+ const configPath = join166(projectDir, CK_CONFIG_FILE2);
75547
75560
  const json = await readJsonSafe(configPath);
75548
75561
  json.content = { ...json.content, ...config };
75549
75562
  await atomicWrite2(configPath, json);
75550
75563
  }
75551
75564
  async function loadContentState(projectDir) {
75552
- const configPath = join164(projectDir, CK_CONFIG_FILE2);
75565
+ const configPath = join166(projectDir, CK_CONFIG_FILE2);
75553
75566
  try {
75554
- const raw2 = await readFile65(configPath, "utf-8");
75567
+ const raw2 = await readFile67(configPath, "utf-8");
75555
75568
  const json = JSON.parse(raw2);
75556
75569
  const contentBlock = json.content ?? {};
75557
75570
  return ContentStateSchema.parse(contentBlock.state ?? {});
@@ -75560,7 +75573,7 @@ async function loadContentState(projectDir) {
75560
75573
  }
75561
75574
  }
75562
75575
  async function saveContentState(projectDir, state) {
75563
- const configPath = join164(projectDir, CK_CONFIG_FILE2);
75576
+ const configPath = join166(projectDir, CK_CONFIG_FILE2);
75564
75577
  const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
75565
75578
  for (const key of Object.keys(state.dailyPostCounts)) {
75566
75579
  const dateStr = key.slice(-10);
@@ -75578,7 +75591,7 @@ async function saveContentState(projectDir, state) {
75578
75591
  }
75579
75592
  async function readJsonSafe(filePath) {
75580
75593
  try {
75581
- const raw2 = await readFile65(filePath, "utf-8");
75594
+ const raw2 = await readFile67(filePath, "utf-8");
75582
75595
  return JSON.parse(raw2);
75583
75596
  } catch {
75584
75597
  return {};
@@ -75586,8 +75599,8 @@ async function readJsonSafe(filePath) {
75586
75599
  }
75587
75600
  async function atomicWrite2(filePath, data) {
75588
75601
  const tmpPath = `${filePath}.tmp`;
75589
- await writeFile39(tmpPath, JSON.stringify(data, null, 2), "utf-8");
75590
- await rename15(tmpPath, filePath);
75602
+ await writeFile40(tmpPath, JSON.stringify(data, null, 2), "utf-8");
75603
+ await rename16(tmpPath, filePath);
75591
75604
  }
75592
75605
  var CK_CONFIG_FILE2 = ".ck.json";
75593
75606
  var init_state_manager = __esm(() => {
@@ -75693,15 +75706,15 @@ async function autoInstallFbcli(contentLogger) {
75693
75706
  contentLogger.warn("go install failed or Go not available");
75694
75707
  }
75695
75708
  try {
75696
- const { platform: platform17, arch: arch3 } = process;
75709
+ const { platform: platform18, arch: arch3 } = process;
75697
75710
  const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
75698
75711
  const archMap = { arm64: "arm64", x64: "amd64" };
75699
- const os7 = osMap[platform17];
75712
+ const os7 = osMap[platform18];
75700
75713
  const cpu = archMap[arch3];
75701
75714
  if (os7 && cpu) {
75702
- const ext2 = platform17 === "win32" ? ".exe" : "";
75715
+ const ext2 = platform18 === "win32" ? ".exe" : "";
75703
75716
  const url = `https://github.com/mrgoonie/fbcli/releases/latest/download/fbcli_${os7}_${cpu}${ext2}`;
75704
- const dest = platform17 === "win32" ? "fbcli.exe" : "/usr/local/bin/fbcli";
75717
+ const dest = platform18 === "win32" ? "fbcli.exe" : "/usr/local/bin/fbcli";
75705
75718
  f2.warning(`Will download fbcli binary from: ${url}`);
75706
75719
  f2.warning("Note: Binary integrity is not verified. Review the source at https://github.com/mrgoonie/fbcli");
75707
75720
  const consent = await se({ message: `Download and install fbcli to ${dest}?` });
@@ -75785,15 +75798,15 @@ async function autoInstallXurl(contentLogger) {
75785
75798
  contentLogger.warn("go install failed or Go not available");
75786
75799
  }
75787
75800
  try {
75788
- const { platform: platform17, arch: arch3 } = process;
75801
+ const { platform: platform18, arch: arch3 } = process;
75789
75802
  const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
75790
75803
  const archMap = { arm64: "arm64", x64: "amd64" };
75791
- const os7 = osMap[platform17];
75804
+ const os7 = osMap[platform18];
75792
75805
  const cpu = archMap[arch3];
75793
75806
  if (os7 && cpu) {
75794
- const ext2 = platform17 === "win32" ? ".exe" : "";
75807
+ const ext2 = platform18 === "win32" ? ".exe" : "";
75795
75808
  const url = `https://github.com/xdevplatform/xurl/releases/latest/download/xurl_${os7}_${cpu}${ext2}`;
75796
- const dest = platform17 === "win32" ? "xurl.exe" : "/usr/local/bin/xurl";
75809
+ const dest = platform18 === "win32" ? "xurl.exe" : "/usr/local/bin/xurl";
75797
75810
  f2.info(`Downloading xurl binary for ${os7}/${cpu}...`);
75798
75811
  execSync14(`curl -fsSL "${url}" -o "${dest}" && chmod +x "${dest}"`, {
75799
75812
  stdio: "inherit",
@@ -75842,7 +75855,7 @@ var init_platform_setup_x = __esm(() => {
75842
75855
 
75843
75856
  // src/commands/content/phases/setup-wizard.ts
75844
75857
  import { existsSync as existsSync81 } from "node:fs";
75845
- import { join as join165 } from "node:path";
75858
+ import { join as join167 } from "node:path";
75846
75859
  async function runSetupWizard2(cwd2, contentLogger) {
75847
75860
  console.log();
75848
75861
  oe(import_picocolors43.default.bgCyan(import_picocolors43.default.white(" CK Content — Multi-Channel Content Engine ")));
@@ -75910,8 +75923,8 @@ async function showRepoSummary(cwd2) {
75910
75923
  function detectBrandAssets(cwd2, contentLogger) {
75911
75924
  const repos = discoverRepos2(cwd2);
75912
75925
  for (const repo of repos) {
75913
- const hasGuidelines = existsSync81(join165(repo.path, "docs", "brand-guidelines.md"));
75914
- const hasStyles = existsSync81(join165(repo.path, "assets", "writing-styles"));
75926
+ const hasGuidelines = existsSync81(join167(repo.path, "docs", "brand-guidelines.md"));
75927
+ const hasStyles = existsSync81(join167(repo.path, "assets", "writing-styles"));
75915
75928
  if (!hasGuidelines) {
75916
75929
  f2.warning(`${repo.name}: No docs/brand-guidelines.md — content will use generic tone.`);
75917
75930
  contentLogger.warn(`${repo.name}: missing docs/brand-guidelines.md`);
@@ -75978,11 +75991,11 @@ var init_setup_wizard = __esm(() => {
75978
75991
 
75979
75992
  // src/commands/content/content-review-commands.ts
75980
75993
  import { existsSync as existsSync82 } from "node:fs";
75981
- import { homedir as homedir55 } from "node:os";
75994
+ import { homedir as homedir57 } from "node:os";
75982
75995
  async function queueContent() {
75983
75996
  const cwd2 = process.cwd();
75984
75997
  const config = await loadContentConfig(cwd2);
75985
- const dbPath = config.dbPath.replace(/^~/, homedir55());
75998
+ const dbPath = config.dbPath.replace(/^~/, homedir57());
75986
75999
  if (!existsSync82(dbPath)) {
75987
76000
  logger.info("No content database found. Run 'ck content setup' first.");
75988
76001
  return;
@@ -76009,7 +76022,7 @@ async function queueContent() {
76009
76022
  async function approveContentCmd(id) {
76010
76023
  const cwd2 = process.cwd();
76011
76024
  const config = await loadContentConfig(cwd2);
76012
- const dbPath = config.dbPath.replace(/^~/, homedir55());
76025
+ const dbPath = config.dbPath.replace(/^~/, homedir57());
76013
76026
  const db = initDatabase(dbPath);
76014
76027
  try {
76015
76028
  approveContent(db, Number.parseInt(id, 10));
@@ -76021,7 +76034,7 @@ async function approveContentCmd(id) {
76021
76034
  async function rejectContentCmd(id, reason) {
76022
76035
  const cwd2 = process.cwd();
76023
76036
  const config = await loadContentConfig(cwd2);
76024
- const dbPath = config.dbPath.replace(/^~/, homedir55());
76037
+ const dbPath = config.dbPath.replace(/^~/, homedir57());
76025
76038
  const db = initDatabase(dbPath);
76026
76039
  try {
76027
76040
  rejectContent(db, Number.parseInt(id, 10), reason);
@@ -76052,10 +76065,10 @@ __export(exports_content_subcommands, {
76052
76065
  approveContentCmd: () => approveContentCmd
76053
76066
  });
76054
76067
  import { existsSync as existsSync83, readFileSync as readFileSync21, unlinkSync as unlinkSync6 } from "node:fs";
76055
- import { homedir as homedir56 } from "node:os";
76056
- import { join as join166 } from "node:path";
76068
+ import { homedir as homedir58 } from "node:os";
76069
+ import { join as join168 } from "node:path";
76057
76070
  function isDaemonRunning() {
76058
- const lockFile = join166(LOCK_DIR, `${LOCK_NAME2}.lock`);
76071
+ const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
76059
76072
  if (!existsSync83(lockFile))
76060
76073
  return { running: false, pid: null };
76061
76074
  try {
@@ -76087,7 +76100,7 @@ async function startContent(options2) {
76087
76100
  await contentCommand(options2);
76088
76101
  }
76089
76102
  async function stopContent() {
76090
- const lockFile = join166(LOCK_DIR, `${LOCK_NAME2}.lock`);
76103
+ const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
76091
76104
  if (!existsSync83(lockFile)) {
76092
76105
  logger.info("Content daemon is not running.");
76093
76106
  return;
@@ -76126,9 +76139,9 @@ async function statusContent() {
76126
76139
  } catch {}
76127
76140
  }
76128
76141
  async function logsContent(options2) {
76129
- const logDir = join166(homedir56(), ".claudekit", "logs");
76142
+ const logDir = join168(homedir58(), ".claudekit", "logs");
76130
76143
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
76131
- const logPath = join166(logDir, `content-${dateStr}.log`);
76144
+ const logPath = join168(logDir, `content-${dateStr}.log`);
76132
76145
  if (!existsSync83(logPath)) {
76133
76146
  logger.info("No content logs found for today.");
76134
76147
  return;
@@ -76160,13 +76173,13 @@ var init_content_subcommands = __esm(() => {
76160
76173
  init_setup_wizard();
76161
76174
  init_state_manager();
76162
76175
  init_content_review_commands();
76163
- LOCK_DIR = join166(homedir56(), ".claudekit", "locks");
76176
+ LOCK_DIR = join168(homedir58(), ".claudekit", "locks");
76164
76177
  });
76165
76178
 
76166
76179
  // src/commands/content/content-command.ts
76167
76180
  import { existsSync as existsSync84, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync7 } from "node:fs";
76168
- import { homedir as homedir57 } from "node:os";
76169
- import { join as join167 } from "node:path";
76181
+ import { homedir as homedir59 } from "node:os";
76182
+ import { join as join169 } from "node:path";
76170
76183
  async function contentCommand(options2) {
76171
76184
  const cwd2 = process.cwd();
76172
76185
  const contentLogger = new ContentLogger;
@@ -76198,7 +76211,7 @@ async function contentCommand(options2) {
76198
76211
  if (!existsSync84(LOCK_DIR2))
76199
76212
  mkdirSync9(LOCK_DIR2, { recursive: true });
76200
76213
  writeFileSync7(LOCK_FILE, String(process.pid), "utf-8");
76201
- const dbPath = config.dbPath.replace(/^~/, homedir57());
76214
+ const dbPath = config.dbPath.replace(/^~/, homedir59());
76202
76215
  const db = initDatabase(dbPath);
76203
76216
  contentLogger.info(`Database initialised at ${dbPath}`);
76204
76217
  const adapters = initializeAdapters(config);
@@ -76327,8 +76340,8 @@ function shouldRunCleanup(lastAt) {
76327
76340
  return Date.now() - new Date(lastAt).getTime() >= 86400000;
76328
76341
  }
76329
76342
  function sleep2(ms) {
76330
- return new Promise((resolve49) => {
76331
- setTimeout(resolve49, ms);
76343
+ return new Promise((resolve44) => {
76344
+ setTimeout(resolve44, ms);
76332
76345
  });
76333
76346
  }
76334
76347
  var LOCK_DIR2, LOCK_FILE, MAX_CREATION_RETRIES = 3, MAX_PUBLISH_RETRIES_PER_CYCLE = 3, PUBLISH_RETRY_WINDOW_HOURS = 24;
@@ -76344,8 +76357,8 @@ var init_content_command = __esm(() => {
76344
76357
  init_publisher();
76345
76358
  init_review_manager();
76346
76359
  init_state_manager();
76347
- LOCK_DIR2 = join167(homedir57(), ".claudekit", "locks");
76348
- LOCK_FILE = join167(LOCK_DIR2, "ck-content.lock");
76360
+ LOCK_DIR2 = join169(homedir59(), ".claudekit", "locks");
76361
+ LOCK_FILE = join169(LOCK_DIR2, "ck-content.lock");
76349
76362
  });
76350
76363
 
76351
76364
  // src/commands/content/index.ts
@@ -78611,7 +78624,7 @@ function getPagerArgs(pagerCmd) {
78611
78624
  return [];
78612
78625
  }
78613
78626
  async function trySystemPager(content) {
78614
- return new Promise((resolve49) => {
78627
+ return new Promise((resolve44) => {
78615
78628
  const pagerCmd = process.env.PAGER || "less";
78616
78629
  const pagerArgs = getPagerArgs(pagerCmd);
78617
78630
  try {
@@ -78621,20 +78634,20 @@ async function trySystemPager(content) {
78621
78634
  });
78622
78635
  const timeout2 = setTimeout(() => {
78623
78636
  pager.kill();
78624
- resolve49(false);
78637
+ resolve44(false);
78625
78638
  }, 30000);
78626
78639
  pager.stdin.write(content);
78627
78640
  pager.stdin.end();
78628
78641
  pager.on("close", (code2) => {
78629
78642
  clearTimeout(timeout2);
78630
- resolve49(code2 === 0);
78643
+ resolve44(code2 === 0);
78631
78644
  });
78632
78645
  pager.on("error", () => {
78633
78646
  clearTimeout(timeout2);
78634
- resolve49(false);
78647
+ resolve44(false);
78635
78648
  });
78636
78649
  } catch {
78637
- resolve49(false);
78650
+ resolve44(false);
78638
78651
  }
78639
78652
  });
78640
78653
  }
@@ -78661,16 +78674,16 @@ async function basicPager(content) {
78661
78674
  break;
78662
78675
  }
78663
78676
  const remaining = lines.length - currentLine;
78664
- await new Promise((resolve49) => {
78677
+ await new Promise((resolve44) => {
78665
78678
  rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
78666
78679
  if (answer.toLowerCase() === "q") {
78667
78680
  rl.close();
78668
78681
  process.exitCode = 0;
78669
- resolve49();
78682
+ resolve44();
78670
78683
  return;
78671
78684
  }
78672
78685
  process.stdout.write("\x1B[1A\x1B[2K");
78673
- resolve49();
78686
+ resolve44();
78674
78687
  });
78675
78688
  });
78676
78689
  }
@@ -88254,6 +88267,313 @@ class NetworkChecker {
88254
88267
  }
88255
88268
  }
88256
88269
  }
88270
+ // src/domains/health-checks/checkers/github-reachability-checker.ts
88271
+ init_environment();
88272
+ init_logger();
88273
+ init_types3();
88274
+ import * as dnsPromises from "node:dns/promises";
88275
+ import * as https from "node:https";
88276
+ import * as net2 from "node:net";
88277
+ var DNS_TIMEOUT_MS = (() => {
88278
+ const envVal = Number.parseInt(process.env.CLAUDEKIT_DNS_TIMEOUT ?? "", 10);
88279
+ return Number.isFinite(envVal) && envVal > 0 ? envVal : 500;
88280
+ })();
88281
+ var TCP_TIMEOUT_MS = 1000;
88282
+ var TLS_TIMEOUT_MS = 3000;
88283
+ var AUTH_TIMEOUT_MS = 5000;
88284
+ var API_HOST = "api.github.com";
88285
+ var ZEN_URL = `https://${API_HOST}/zen`;
88286
+ var PROBE_KIT = "engineer";
88287
+ function createDefaultDeps() {
88288
+ return {
88289
+ dns: createDefaultDns(),
88290
+ tcp: createDefaultTcp(),
88291
+ tls: createDefaultTls(),
88292
+ auth: createDefaultAuth()
88293
+ };
88294
+ }
88295
+ function createDefaultDns() {
88296
+ return {
88297
+ resolve4: (host) => dnsPromises.resolve4(host),
88298
+ resolve6: (host) => dnsPromises.resolve6(host)
88299
+ };
88300
+ }
88301
+ function createDefaultTcp() {
88302
+ return {
88303
+ connect: ({ host, port, timeoutMs }) => new Promise((resolve32) => {
88304
+ const start = Date.now();
88305
+ const socket = net2.createConnection({ host, port });
88306
+ const timer = setTimeout(() => {
88307
+ socket.destroy();
88308
+ resolve32({ ok: false, layer: "tcp", detail: "timeout", latencyMs: Date.now() - start });
88309
+ }, timeoutMs);
88310
+ socket.on("connect", () => {
88311
+ clearTimeout(timer);
88312
+ socket.destroy();
88313
+ resolve32({
88314
+ ok: true,
88315
+ layer: "tcp",
88316
+ detail: "connected",
88317
+ latencyMs: Date.now() - start
88318
+ });
88319
+ });
88320
+ socket.on("error", (err) => {
88321
+ clearTimeout(timer);
88322
+ resolve32({
88323
+ ok: false,
88324
+ layer: "tcp",
88325
+ detail: err.message,
88326
+ latencyMs: Date.now() - start
88327
+ });
88328
+ });
88329
+ })
88330
+ };
88331
+ }
88332
+ function createDefaultTls() {
88333
+ return {
88334
+ get: (url, timeoutMs) => new Promise((resolve32) => {
88335
+ const start = Date.now();
88336
+ const timer = setTimeout(() => {
88337
+ req.destroy();
88338
+ resolve32({ ok: false, layer: "tls", detail: "timeout", latencyMs: Date.now() - start });
88339
+ }, timeoutMs);
88340
+ const req = https.get(url, {
88341
+ headers: {
88342
+ "User-Agent": "claudekit-cli-doctor/1.0"
88343
+ }
88344
+ }, (res) => {
88345
+ res.resume();
88346
+ clearTimeout(timer);
88347
+ const status = res.statusCode ?? 0;
88348
+ const latencyMs = Date.now() - start;
88349
+ if (status === 200) {
88350
+ resolve32({ ok: true, layer: "tls", detail: `HTTP ${status}`, latencyMs });
88351
+ } else {
88352
+ resolve32({ ok: false, layer: "tls", detail: `HTTP ${status}`, latencyMs });
88353
+ }
88354
+ });
88355
+ req.on("error", (err) => {
88356
+ clearTimeout(timer);
88357
+ resolve32({
88358
+ ok: false,
88359
+ layer: "tls",
88360
+ detail: err.message,
88361
+ latencyMs: Date.now() - start
88362
+ });
88363
+ });
88364
+ })
88365
+ };
88366
+ }
88367
+ function createDefaultAuth() {
88368
+ return {
88369
+ checkKitAccess: async () => {
88370
+ const start = Date.now();
88371
+ const { getAuthenticatedClient: getAuthenticatedClient2 } = await Promise.resolve().then(() => (init_client(), exports_client));
88372
+ const kit = AVAILABLE_KITS[PROBE_KIT];
88373
+ try {
88374
+ const client = await getAuthenticatedClient2();
88375
+ await client.repos.get({ owner: kit.owner, repo: kit.repo });
88376
+ return {
88377
+ ok: true,
88378
+ layer: "auth",
88379
+ detail: "200 OK",
88380
+ latencyMs: Date.now() - start,
88381
+ statusCode: 200
88382
+ };
88383
+ } catch (err) {
88384
+ const latencyMs = Date.now() - start;
88385
+ const status = err?.status ?? err?.statusCode;
88386
+ const message = err instanceof Error ? err.message : String(err);
88387
+ if (status === 401) {
88388
+ return {
88389
+ ok: false,
88390
+ layer: "auth",
88391
+ detail: `401 Unauthorized — token invalid or missing. ${message}`,
88392
+ latencyMs,
88393
+ statusCode: 401
88394
+ };
88395
+ }
88396
+ if (status === 404) {
88397
+ return {
88398
+ ok: false,
88399
+ layer: "auth",
88400
+ detail: `404 — no repository access (invitation pending). ${message}`,
88401
+ latencyMs,
88402
+ statusCode: 404
88403
+ };
88404
+ }
88405
+ return {
88406
+ ok: false,
88407
+ layer: "auth",
88408
+ detail: `${status ?? "?"} — ${message}`,
88409
+ latencyMs,
88410
+ statusCode: status
88411
+ };
88412
+ }
88413
+ }
88414
+ };
88415
+ }
88416
+ async function checkGitHubReachability(deps) {
88417
+ const dnsStart = Date.now();
88418
+ let dnsResult;
88419
+ try {
88420
+ const [r4, r6] = await Promise.allSettled([
88421
+ raceTimeout(deps.dns.resolve4(API_HOST), DNS_TIMEOUT_MS),
88422
+ raceTimeout(deps.dns.resolve6(API_HOST), DNS_TIMEOUT_MS)
88423
+ ]);
88424
+ const ok = r4.status === "fulfilled" || r6.status === "fulfilled";
88425
+ let detail;
88426
+ if (ok) {
88427
+ if (r4.status === "fulfilled") {
88428
+ detail = `resolved: ${r4.value[0]}`;
88429
+ } else {
88430
+ const r6Value = r6.value;
88431
+ detail = `resolved (IPv6): ${r6Value[0]}`;
88432
+ }
88433
+ } else {
88434
+ detail = "NXDOMAIN / timeout";
88435
+ }
88436
+ dnsResult = { ok, layer: "dns", detail, latencyMs: Date.now() - dnsStart };
88437
+ } catch {
88438
+ dnsResult = {
88439
+ ok: false,
88440
+ layer: "dns",
88441
+ detail: "DNS resolution failed",
88442
+ latencyMs: Date.now() - dnsStart
88443
+ };
88444
+ }
88445
+ if (!dnsResult.ok) {
88446
+ return { ok: false, failedLayer: "dns", layers: { dns: dnsResult } };
88447
+ }
88448
+ const tcpResult = await deps.tcp.connect({
88449
+ host: API_HOST,
88450
+ port: 443,
88451
+ timeoutMs: TCP_TIMEOUT_MS
88452
+ });
88453
+ if (!tcpResult.ok) {
88454
+ return { ok: false, failedLayer: "tcp", layers: { dns: dnsResult, tcp: tcpResult } };
88455
+ }
88456
+ const tlsResult = await deps.tls.get(ZEN_URL, TLS_TIMEOUT_MS);
88457
+ if (!tlsResult.ok) {
88458
+ return {
88459
+ ok: false,
88460
+ failedLayer: "tls",
88461
+ layers: { dns: dnsResult, tcp: tcpResult, tls: tlsResult }
88462
+ };
88463
+ }
88464
+ const authResult = await deps.auth.checkKitAccess();
88465
+ if (!authResult.ok) {
88466
+ return {
88467
+ ok: false,
88468
+ failedLayer: "auth",
88469
+ layers: { dns: dnsResult, tcp: tcpResult, tls: tlsResult, auth: authResult }
88470
+ };
88471
+ }
88472
+ return {
88473
+ ok: true,
88474
+ layers: { dns: dnsResult, tcp: tcpResult, tls: tlsResult, auth: authResult }
88475
+ };
88476
+ }
88477
+ function raceTimeout(promise, ms) {
88478
+ return new Promise((resolve32, reject) => {
88479
+ const timer = setTimeout(() => reject(new Error(`timeout after ${ms}ms`)), ms);
88480
+ promise.then((v2) => {
88481
+ clearTimeout(timer);
88482
+ resolve32(v2);
88483
+ }, (e2) => {
88484
+ clearTimeout(timer);
88485
+ reject(e2);
88486
+ });
88487
+ });
88488
+ }
88489
+
88490
+ class GitHubReachabilityChecker {
88491
+ group = "network";
88492
+ deps;
88493
+ usingRealDeps;
88494
+ constructor(options2 = {}) {
88495
+ this.usingRealDeps = options2.deps === undefined;
88496
+ this.deps = options2.deps ?? createDefaultDeps();
88497
+ }
88498
+ async run() {
88499
+ if (this.usingRealDeps && (isCIEnvironment() || isTestEnvironment())) {
88500
+ return [
88501
+ {
88502
+ id: "github-reachability",
88503
+ name: "GitHub Reachability",
88504
+ group: "network",
88505
+ priority: "standard",
88506
+ status: "info",
88507
+ message: "Skipped in CI/test environment",
88508
+ autoFixable: false
88509
+ }
88510
+ ];
88511
+ }
88512
+ logger.verbose("GitHubReachabilityChecker: running layered probe");
88513
+ let result;
88514
+ try {
88515
+ result = await raceTimeout(checkGitHubReachability(this.deps), AUTH_TIMEOUT_MS + TLS_TIMEOUT_MS + TCP_TIMEOUT_MS + DNS_TIMEOUT_MS + 500);
88516
+ } catch (err) {
88517
+ return [
88518
+ {
88519
+ id: "github-reachability",
88520
+ name: "GitHub Reachability",
88521
+ group: "network",
88522
+ priority: "standard",
88523
+ status: "fail",
88524
+ message: "Probe timed out",
88525
+ details: err instanceof Error ? err.message : String(err),
88526
+ suggestion: "Check internet connection and proxy settings",
88527
+ autoFixable: false
88528
+ }
88529
+ ];
88530
+ }
88531
+ logger.verbose("GitHubReachabilityChecker: probe complete", { result });
88532
+ return [buildCheckResult(result)];
88533
+ }
88534
+ }
88535
+ function buildCheckResult(result) {
88536
+ if (result.ok) {
88537
+ const { dns, tcp, tls, auth } = result.layers;
88538
+ const details = [
88539
+ `DNS: ${dns.latencyMs}ms`,
88540
+ tcp ? `TCP: ${tcp.latencyMs}ms` : null,
88541
+ tls ? `TLS/GET: ${tls.latencyMs}ms` : null,
88542
+ auth ? `Auth: ${auth.latencyMs}ms` : null
88543
+ ].filter(Boolean).join(", ");
88544
+ return {
88545
+ id: "github-reachability",
88546
+ name: "GitHub Reachability",
88547
+ group: "network",
88548
+ priority: "standard",
88549
+ status: "pass",
88550
+ message: "All layers reachable",
88551
+ details,
88552
+ autoFixable: false
88553
+ };
88554
+ }
88555
+ const { failedLayer, layers } = result;
88556
+ const failedProbe = layers[failedLayer];
88557
+ const detail = failedProbe?.detail ?? "unknown";
88558
+ const authSuggestion = failedProbe?.statusCode === 401 ? "GitHub token invalid or missing — run: gh auth login" : "No repository access — check GitHub invitation email or purchase at https://claudekit.cc";
88559
+ const suggestions = {
88560
+ dns: "DNS resolution failed — check /etc/resolv.conf or system DNS settings",
88561
+ tcp: "TCP connect to api.github.com:443 failed — check firewall or proxy blocking port 443",
88562
+ tls: "HTTPS GET /zen returned unexpected status — possible TLS interception or GitHub outage. Check https://githubstatus.com",
88563
+ auth: authSuggestion
88564
+ };
88565
+ return {
88566
+ id: "github-reachability",
88567
+ name: "GitHub Reachability",
88568
+ group: "network",
88569
+ priority: "standard",
88570
+ status: "fail",
88571
+ message: `GitHub unreachable at ${failedLayer?.toUpperCase()} layer`,
88572
+ details: detail,
88573
+ suggestion: suggestions[failedLayer ?? ""] ?? "Run: ck doctor for full diagnostics",
88574
+ autoFixable: false
88575
+ };
88576
+ }
88257
88577
  // src/domains/health-checks/auto-healer.ts
88258
88578
  class AutoHealer {
88259
88579
  timeout;
@@ -88680,6 +89000,7 @@ async function doctorCommand(options2 = {}) {
88680
89000
  runner.registerChecker(new AuthChecker);
88681
89001
  runner.registerChecker(new PlatformChecker);
88682
89002
  runner.registerChecker(new NetworkChecker);
89003
+ runner.registerChecker(new GitHubReachabilityChecker);
88683
89004
  const summary = await runner.run();
88684
89005
  if (json) {
88685
89006
  const generator = new ReportGenerator;
@@ -105382,7 +105703,15 @@ async function handleSelection(ctx) {
105382
105703
  logger.info("Full diagnostics: ck doctor");
105383
105704
  return { ...ctx, cancelled: true };
105384
105705
  }
105385
- accessibleKits = await detectAccessibleKits();
105706
+ try {
105707
+ accessibleKits = await detectAccessibleKits();
105708
+ } catch (err) {
105709
+ const message = err instanceof Error ? err.message : String(err);
105710
+ logger.error(`Failed to check repository access: ${message}`);
105711
+ logger.info("");
105712
+ logger.info("Run: ck doctor");
105713
+ return { ...ctx, cancelled: true };
105714
+ }
105386
105715
  if (accessibleKits.length === 0) {
105387
105716
  logger.error("No ClaudeKit repository access found.");
105388
105717
  logger.info("Check email for GitHub invitation, or purchase at https://claudekit.cc");
@@ -106746,9 +107075,9 @@ async function initCommand(options2) {
106746
107075
  init_dist2();
106747
107076
  var import_picocolors30 = __toESM(require_picocolors(), 1);
106748
107077
  import { existsSync as existsSync64 } from "node:fs";
106749
- import { readFile as readFile61, rm as rm16, unlink as unlink13 } from "node:fs/promises";
106750
- import { homedir as homedir50 } from "node:os";
106751
- import { basename as basename27, join as join142, resolve as resolve41 } from "node:path";
107078
+ import { readFile as readFile63, rm as rm16, unlink as unlink13 } from "node:fs/promises";
107079
+ import { homedir as homedir52 } from "node:os";
107080
+ import { basename as basename27, join as join144, resolve as resolve41 } from "node:path";
106752
107081
  init_logger();
106753
107082
 
106754
107083
  // src/ui/ck-cli-design/tokens.ts
@@ -107220,32 +107549,262 @@ init_model_taxonomy();
107220
107549
  init_logger();
107221
107550
  init_dist2();
107222
107551
  init_model_taxonomy();
107223
- import { mkdir as mkdir36, readFile as readFile60, writeFile as writeFile35 } from "node:fs/promises";
107552
+ import { mkdir as mkdir37, readFile as readFile62, writeFile as writeFile36 } from "node:fs/promises";
107553
+ import { homedir as homedir51 } from "node:os";
107554
+ import { dirname as dirname41, join as join143 } from "node:path";
107555
+
107556
+ // src/commands/portable/models-dev-cache.ts
107557
+ init_logger();
107558
+ import { mkdir as mkdir36, readFile as readFile60, rename as rename13, writeFile as writeFile35 } from "node:fs/promises";
107224
107559
  import { homedir as homedir49 } from "node:os";
107225
- import { dirname as dirname41, join as join141 } from "node:path";
107226
- function getOpenCodeConfigPath(options2) {
107227
- if (options2.global) {
107228
- return join141(options2.homeDir ?? homedir49(), ".config", "opencode", "opencode.json");
107560
+ import { join as join141 } from "node:path";
107561
+
107562
+ class ModelsDevUnavailableError extends Error {
107563
+ constructor(message, cause) {
107564
+ super(message, { cause });
107565
+ this.name = "ModelsDevUnavailableError";
107566
+ }
107567
+ }
107568
+ var MODELS_DEV_URL = "https://models.dev/api.json";
107569
+ var CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
107570
+ var FETCH_TIMEOUT_MS = 1e4;
107571
+ function defaultCacheDir() {
107572
+ return join141(homedir49(), ".config", "claudekit", "cache");
107573
+ }
107574
+ function cacheFilePath(cacheDir) {
107575
+ return join141(cacheDir, "models-dev.json");
107576
+ }
107577
+ function tmpFilePath(cacheDir) {
107578
+ return join141(cacheDir, "models-dev.json.tmp");
107579
+ }
107580
+ async function readCacheEntry(cacheDir) {
107581
+ const filePath = cacheFilePath(cacheDir);
107582
+ try {
107583
+ const raw2 = await readFile60(filePath, "utf-8");
107584
+ const parsed = JSON.parse(raw2);
107585
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && "fetchedAt" in parsed && typeof parsed.fetchedAt === "string" && "payload" in parsed && typeof parsed.payload === "object" && parsed.payload !== null) {
107586
+ return parsed;
107587
+ }
107588
+ return null;
107589
+ } catch {
107590
+ return null;
107591
+ }
107592
+ }
107593
+ function isCacheFresh(entry) {
107594
+ const fetchedAt = new Date(entry.fetchedAt).getTime();
107595
+ return Date.now() - fetchedAt < CACHE_TTL_MS3;
107596
+ }
107597
+ async function writeCacheEntry(cacheDir, entry) {
107598
+ await mkdir36(cacheDir, { recursive: true });
107599
+ const tmp = tmpFilePath(cacheDir);
107600
+ const dest = cacheFilePath(cacheDir);
107601
+ await writeFile35(tmp, JSON.stringify(entry), "utf-8");
107602
+ await rename13(tmp, dest);
107603
+ }
107604
+ async function fetchCatalog(fetcher) {
107605
+ const controller = new AbortController;
107606
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
107607
+ try {
107608
+ const response = await fetcher(MODELS_DEV_URL, { signal: controller.signal });
107609
+ if (!response.ok) {
107610
+ throw new Error(`models.dev returned HTTP ${response.status}`);
107611
+ }
107612
+ const json = await response.json();
107613
+ if (json === null || typeof json !== "object" || Array.isArray(json)) {
107614
+ throw new Error("models.dev response is not an object");
107615
+ }
107616
+ return json;
107617
+ } finally {
107618
+ clearTimeout(timer);
107619
+ }
107620
+ }
107621
+ async function getModelsDevCatalog(opts = {}) {
107622
+ const cacheDir = opts.cacheDir ?? defaultCacheDir();
107623
+ const fetcher = opts.fetcher ?? globalThis.fetch;
107624
+ const cached = await readCacheEntry(cacheDir);
107625
+ if (cached !== null && isCacheFresh(cached)) {
107626
+ return cached.payload;
107627
+ }
107628
+ try {
107629
+ const payload = await fetchCatalog(fetcher);
107630
+ const entry = {
107631
+ fetchedAt: new Date().toISOString(),
107632
+ payload
107633
+ };
107634
+ try {
107635
+ await writeCacheEntry(cacheDir, entry);
107636
+ } catch (writeErr) {
107637
+ logger.verbose(`models-dev-cache: failed to write cache to ${cacheDir}: ${String(writeErr)}`);
107638
+ }
107639
+ return payload;
107640
+ } catch (fetchErr) {
107641
+ if (cached !== null) {
107642
+ logger.warning(`models-dev-cache: fetch failed (${String(fetchErr)}), using stale cache from ${cached.fetchedAt}`);
107643
+ return cached.payload;
107644
+ }
107645
+ throw new ModelsDevUnavailableError(`models.dev catalog unavailable: ${String(fetchErr)}`, fetchErr);
107229
107646
  }
107230
- return join141(options2.cwd ?? process.cwd(), "opencode.json");
107231
107647
  }
107232
- async function detectAuthenticatedProviders(homeDir) {
107233
- const authPath = join141(homeDir ?? homedir49(), ".local", "share", "opencode", "auth.json");
107648
+
107649
+ // src/commands/portable/opencode-model-discovery.ts
107650
+ init_logger();
107651
+ import { readFile as readFile61 } from "node:fs/promises";
107652
+ import { homedir as homedir50, platform as platform17 } from "node:os";
107653
+ import { join as join142 } from "node:path";
107654
+ function resolveOpenCodeAuthPath(homeDir) {
107655
+ if (platform17() === "win32") {
107656
+ const dataRoot2 = process.env.LOCALAPPDATA ?? join142(homeDir, "AppData", "Local");
107657
+ return join142(dataRoot2, "opencode", "auth.json");
107658
+ }
107659
+ const dataRoot = process.env.XDG_DATA_HOME ?? join142(homeDir, ".local", "share");
107660
+ return join142(dataRoot, "opencode", "auth.json");
107661
+ }
107662
+ async function readAuthedProviders(homeDir) {
107663
+ const authPath = resolveOpenCodeAuthPath(homeDir);
107234
107664
  try {
107235
- const raw2 = await readFile60(authPath, "utf-8");
107665
+ const raw2 = await readFile61(authPath, "utf-8");
107236
107666
  const parsed = JSON.parse(raw2);
107237
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
107667
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
107238
107668
  return Object.keys(parsed);
107239
107669
  }
107240
107670
  } catch {}
107241
107671
  return [];
107242
107672
  }
107243
- async function suggestOpenCodeDefaultModel(homeDir) {
107673
+ function releaseDateMs(model) {
107674
+ const d3 = new Date(model.release_date);
107675
+ return Number.isNaN(d3.getTime()) ? 0 : d3.getTime();
107676
+ }
107677
+ function sortByDateDesc(models) {
107678
+ return [...models].sort((a3, b3) => releaseDateMs(b3) - releaseDateMs(a3));
107679
+ }
107680
+ function pickOpenCodeModel(models) {
107681
+ const all = Object.values(models);
107682
+ const freeCallable = all.filter((m2) => m2.tool_call && m2.id.endsWith("-free"));
107683
+ const sortedFree = sortByDateDesc(freeCallable);
107684
+ const topFree = sortedFree[0];
107685
+ if (topFree !== undefined) {
107686
+ return topFree;
107687
+ }
107688
+ const callable = all.filter((m2) => m2.tool_call);
107689
+ const sortedCallable = sortByDateDesc(callable);
107690
+ return sortedCallable[0] ?? null;
107691
+ }
107692
+ function pickGenericModel(models) {
107693
+ const callable = Object.values(models).filter((m2) => m2.tool_call);
107694
+ const sorted = sortByDateDesc(callable);
107695
+ return sorted[0] ?? null;
107696
+ }
107697
+ async function resolveOpenCodeDefaultModel(opts = {}) {
107698
+ const home9 = opts.homeDir ?? homedir50();
107699
+ const authedProviders = await readAuthedProviders(home9);
107700
+ if (authedProviders.length === 0) {
107701
+ return { ok: false, reason: "no-auth", authedProviders: [] };
107702
+ }
107703
+ let catalog;
107704
+ try {
107705
+ catalog = await getModelsDevCatalog({ fetcher: opts.fetcher, cacheDir: opts.cacheDir });
107706
+ } catch (err) {
107707
+ if (err instanceof ModelsDevUnavailableError) {
107708
+ logger.verbose(`opencode-model-discovery: models.dev unavailable, cannot auto-resolve model: ${err.message}`);
107709
+ return { ok: false, reason: "catalog-unavailable", authedProviders };
107710
+ }
107711
+ throw err;
107712
+ }
107713
+ const orderedProviders = [
107714
+ ...authedProviders.filter((id) => id === "opencode"),
107715
+ ...authedProviders.filter((id) => id !== "opencode")
107716
+ ];
107717
+ for (const providerId of orderedProviders) {
107718
+ const providerEntry = catalog[providerId];
107719
+ if (!providerEntry) {
107720
+ continue;
107721
+ }
107722
+ const picked = providerId === "opencode" ? pickOpenCodeModel(providerEntry.models) : pickGenericModel(providerEntry.models);
107723
+ if (!picked) {
107724
+ continue;
107725
+ }
107726
+ const isFree = picked.id.endsWith("-free");
107727
+ const tierLabel = isFree ? "free tier" : "paid";
107728
+ const reason = `auth-detected: ${providerId} (${tierLabel}, released ${picked.release_date})`;
107729
+ return {
107730
+ ok: true,
107731
+ value: {
107732
+ model: `${providerId}/${picked.id}`,
107733
+ reason,
107734
+ authedProviders
107735
+ }
107736
+ };
107737
+ }
107738
+ return { ok: false, reason: "no-usable-model", authedProviders };
107739
+ }
107740
+
107741
+ // src/commands/portable/opencode-config-installer.ts
107742
+ class OpenCodeAuthRequiredError extends Error {
107743
+ reason;
107744
+ constructor(reason = "no-auth") {
107745
+ super(messageForReason(reason));
107746
+ this.name = "OpenCodeAuthRequiredError";
107747
+ this.reason = reason;
107748
+ }
107749
+ }
107750
+ function messageForReason(reason) {
107751
+ switch (reason) {
107752
+ case "no-auth":
107753
+ return "opencode has no authenticated providers. Run `opencode auth login` first, then re-run `ck migrate`.";
107754
+ case "catalog-unavailable":
107755
+ return "Cannot reach models.dev to pick a default model. Check your network, then re-run `ck migrate` — or set `model` in opencode.json manually.";
107756
+ case "no-usable-model":
107757
+ return "None of your authenticated opencode providers have a tool-capable model in the models.dev catalog. Set `model` in opencode.json manually.";
107758
+ }
107759
+ }
107760
+ function getOpenCodeConfigPath(options2) {
107761
+ if (options2.global) {
107762
+ return join143(options2.homeDir ?? homedir51(), ".config", "opencode", "opencode.json");
107763
+ }
107764
+ return join143(options2.cwd ?? process.cwd(), "opencode.json");
107765
+ }
107766
+ function makeCatalogOpts(options2) {
107767
+ return {
107768
+ fetcher: options2.fetcher,
107769
+ cacheDir: options2.cacheDir
107770
+ };
107771
+ }
107772
+ async function validateModelAgainstCatalog(model, options2) {
107773
+ const slashIdx = model.indexOf("/");
107774
+ if (slashIdx <= 0 || slashIdx === model.length - 1) {
107775
+ return false;
107776
+ }
107777
+ const providerId = model.slice(0, slashIdx);
107778
+ const modelId = model.slice(slashIdx + 1);
107779
+ try {
107780
+ const catalog = await getModelsDevCatalog(makeCatalogOpts(options2));
107781
+ const provider = catalog[providerId];
107782
+ if (!provider)
107783
+ return false;
107784
+ return modelId in provider.models;
107785
+ } catch {
107786
+ return true;
107787
+ }
107788
+ }
107789
+ async function suggestModel(options2) {
107244
107790
  const override = getOpenCodeDefaultModelOverride();
107245
107791
  if (override) {
107246
- return { model: override, reason: ".ck.json override" };
107792
+ return { ok: true, model: override, reason: ".ck.json override", authedProviders: [] };
107247
107793
  }
107248
- return { model: OPENCODE_DEFAULT_MODEL, reason: "fallback default" };
107794
+ const result = await resolveOpenCodeDefaultModel({
107795
+ homeDir: options2.homeDir,
107796
+ fetcher: options2.fetcher,
107797
+ cacheDir: options2.cacheDir
107798
+ });
107799
+ if (result.ok) {
107800
+ return {
107801
+ ok: true,
107802
+ model: result.value.model,
107803
+ reason: result.value.reason,
107804
+ authedProviders: result.value.authedProviders
107805
+ };
107806
+ }
107807
+ return { ok: false, failure: result.reason, authedProviders: result.authedProviders };
107249
107808
  }
107250
107809
  var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
107251
107810
  const providersHint = detectedProviders.length > 0 ? `Authenticated providers in opencode: ${detectedProviders.join(", ")}` : "No authenticated providers detected in opencode.";
@@ -107267,7 +107826,7 @@ var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
107267
107826
  if (response === "accept")
107268
107827
  return { action: "accept" };
107269
107828
  const custom2 = await te({
107270
- message: "Model (format: provider/model-id, e.g. openai/gpt-5)",
107829
+ message: "Model (format: provider/model-id, e.g. opencode/qwen3.5-plus-free)",
107271
107830
  placeholder: suggestion,
107272
107831
  validate: (value) => {
107273
107832
  if (!value || !value.includes("/"))
@@ -107279,13 +107838,35 @@ var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
107279
107838
  return { action: "skip" };
107280
107839
  return { action: "custom", value: custom2 };
107281
107840
  };
107841
+ var makeInvalidModelPrompter = (existingModel, suggestion, reason) => async ({ detectedProviders }) => {
107842
+ const providersHint = detectedProviders.length > 0 ? `Authenticated providers: ${detectedProviders.join(", ")}` : "No authenticated providers detected.";
107843
+ const response = await ie({
107844
+ message: `Existing model "${existingModel}" is not in the models.dev catalog. ${providersHint}`,
107845
+ options: [
107846
+ {
107847
+ value: "rewrite",
107848
+ label: `Replace with "${suggestion}"`,
107849
+ hint: reason
107850
+ },
107851
+ {
107852
+ value: "keep",
107853
+ label: `Keep "${existingModel}" as-is`,
107854
+ hint: "May cause ProviderModelNotFoundError at runtime"
107855
+ }
107856
+ ],
107857
+ initialValue: "rewrite"
107858
+ });
107859
+ if (lD(response) || response === "keep")
107860
+ return { action: "skip" };
107861
+ return { action: "accept" };
107862
+ };
107282
107863
  async function ensureOpenCodeModel(options2) {
107283
107864
  const configPath = getOpenCodeConfigPath(options2);
107284
107865
  let existing = null;
107285
107866
  try {
107286
- const raw2 = await readFile60(configPath, "utf-8");
107867
+ const raw2 = await readFile62(configPath, "utf-8");
107287
107868
  const parsed = JSON.parse(raw2);
107288
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
107869
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
107289
107870
  existing = parsed;
107290
107871
  } else {
107291
107872
  logger.warning(`ensureOpenCodeModel: ${configPath} is valid JSON but not an object; overwriting with default model`);
@@ -107298,40 +107879,72 @@ async function ensureOpenCodeModel(options2) {
107298
107879
  logger.verbose(`ensureOpenCodeModel: failed to read ${configPath} (${errno ?? String(err)}); recreating`);
107299
107880
  }
107300
107881
  }
107301
- if (existing && typeof existing.model === "string" && existing.model.trim().length > 0) {
107302
- return { path: configPath, action: "existing", model: existing.model };
107303
- }
107304
- const suggestion = await suggestOpenCodeDefaultModel(options2.homeDir);
107305
- let chosenModel = suggestion.model;
107306
- if (options2.interactive) {
107307
- const detectedProviders = await detectAuthenticatedProviders(options2.homeDir);
107308
- const prompter = options2.prompter ?? clackPrompter;
107309
- const response = await prompter({
107310
- suggestion: suggestion.model,
107311
- reason: suggestion.reason,
107312
- detectedProviders
107882
+ if (existing !== null && typeof existing.model === "string" && existing.model.trim().length > 0) {
107883
+ const existingModel = existing.model.trim();
107884
+ const isValid2 = await validateModelAgainstCatalog(existingModel, options2);
107885
+ if (isValid2) {
107886
+ return { path: configPath, action: "existing", model: existingModel };
107887
+ }
107888
+ if (!options2.interactive) {
107889
+ logger.warning(`ensureOpenCodeModel: existing model "${existingModel}" is not found in the models.dev catalog. ` + `Run \`ck migrate --agent opencode\` interactively to update it, or edit ${configPath} manually.`);
107890
+ return { path: configPath, action: "existing", model: existingModel };
107891
+ }
107892
+ const suggestion2 = await suggestModel(options2);
107893
+ if (!suggestion2.ok) {
107894
+ return { path: configPath, action: "existing", model: existingModel };
107895
+ }
107896
+ const invalidPrompter = options2.prompter ?? makeInvalidModelPrompter(existingModel, suggestion2.model, suggestion2.reason);
107897
+ const response2 = await invalidPrompter({
107898
+ suggestion: suggestion2.model,
107899
+ reason: suggestion2.reason,
107900
+ detectedProviders: suggestion2.authedProviders
107313
107901
  });
107314
- if (response.action === "skip") {
107315
- return {
107316
- path: configPath,
107317
- action: "skipped",
107318
- model: "",
107319
- reason: "user declined"
107320
- };
107902
+ if (response2.action === "skip") {
107903
+ return { path: configPath, action: "existing", model: existingModel };
107321
107904
  }
107322
- if (response.action === "custom") {
107323
- chosenModel = response.value;
107905
+ const chosenModel2 = response2.action === "custom" ? response2.value : suggestion2.model;
107906
+ const next2 = { ...existing, model: chosenModel2 };
107907
+ await mkdir37(dirname41(configPath), { recursive: true });
107908
+ await writeFile36(configPath, `${JSON.stringify(next2, null, 2)}
107909
+ `, "utf-8");
107910
+ return { path: configPath, action: "added", model: chosenModel2, reason: suggestion2.reason };
107911
+ }
107912
+ const suggestion = await suggestModel(options2);
107913
+ if (!options2.interactive) {
107914
+ if (!suggestion.ok) {
107915
+ throw new OpenCodeAuthRequiredError(suggestion.failure);
107324
107916
  }
107917
+ const next2 = { ...existing ?? {}, model: suggestion.model };
107918
+ await mkdir37(dirname41(configPath), { recursive: true });
107919
+ await writeFile36(configPath, `${JSON.stringify(next2, null, 2)}
107920
+ `, "utf-8");
107921
+ return {
107922
+ path: configPath,
107923
+ action: existing ? "added" : "created",
107924
+ model: suggestion.model,
107925
+ reason: suggestion.reason
107926
+ };
107927
+ }
107928
+ const prompter = options2.prompter ?? clackPrompter;
107929
+ const detectedProviders = suggestion.ok ? suggestion.authedProviders : suggestion.authedProviders;
107930
+ const response = await prompter({
107931
+ suggestion: suggestion.ok ? suggestion.model : "",
107932
+ reason: suggestion.ok ? suggestion.reason : messageForReason(suggestion.failure),
107933
+ detectedProviders
107934
+ });
107935
+ if (response.action === "skip") {
107936
+ return { path: configPath, action: "skipped", model: "", reason: "user declined" };
107325
107937
  }
107938
+ const chosenModel = response.action === "custom" ? response.value : suggestion.ok ? suggestion.model : "";
107326
107939
  const next = { ...existing ?? {}, model: chosenModel };
107327
- await mkdir36(dirname41(configPath), { recursive: true });
107328
- await writeFile35(configPath, `${JSON.stringify(next, null, 2)}
107940
+ await mkdir37(dirname41(configPath), { recursive: true });
107941
+ await writeFile36(configPath, `${JSON.stringify(next, null, 2)}
107329
107942
  `, "utf-8");
107330
107943
  return {
107331
107944
  path: configPath,
107332
107945
  action: existing ? "added" : "created",
107333
107946
  model: chosenModel,
107334
- reason: suggestion.reason
107947
+ reason: suggestion.ok ? suggestion.reason : undefined
107335
107948
  };
107336
107949
  }
107337
107950
 
@@ -108106,12 +108719,12 @@ async function executeDeleteAction(action, options2) {
108106
108719
  async function processMetadataDeletions(skillSourcePath, installGlobally) {
108107
108720
  if (!skillSourcePath)
108108
108721
  return;
108109
- const sourceMetadataPath = join142(resolve41(skillSourcePath, ".."), "metadata.json");
108722
+ const sourceMetadataPath = join144(resolve41(skillSourcePath, ".."), "metadata.json");
108110
108723
  if (!existsSync64(sourceMetadataPath))
108111
108724
  return;
108112
108725
  let sourceMetadata;
108113
108726
  try {
108114
- const content = await readFile61(sourceMetadataPath, "utf-8");
108727
+ const content = await readFile63(sourceMetadataPath, "utf-8");
108115
108728
  sourceMetadata = JSON.parse(content);
108116
108729
  } catch (error) {
108117
108730
  logger.debug(`[migrate] Failed to parse source metadata.json: ${error}`);
@@ -108119,7 +108732,7 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
108119
108732
  }
108120
108733
  if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
108121
108734
  return;
108122
- const claudeDir3 = installGlobally ? join142(homedir50(), ".claude") : join142(process.cwd(), ".claude");
108735
+ const claudeDir3 = installGlobally ? join144(homedir52(), ".claude") : join144(process.cwd(), ".claude");
108123
108736
  if (!existsSync64(claudeDir3))
108124
108737
  return;
108125
108738
  try {
@@ -108241,8 +108854,8 @@ async function migrateCommand(options2) {
108241
108854
  let requestedGlobal = options2.global ?? false;
108242
108855
  let installGlobally = requestedGlobal;
108243
108856
  if (options2.global === undefined && !options2.yes) {
108244
- const projectTarget = join142(process.cwd(), ".claude");
108245
- const globalTarget = join142(homedir50(), ".claude");
108857
+ const projectTarget = join144(process.cwd(), ".claude");
108858
+ const globalTarget = join144(homedir52(), ".claude");
108246
108859
  const scopeChoice = await ie({
108247
108860
  message: "Installation scope",
108248
108861
  options: [
@@ -108405,7 +109018,7 @@ async function migrateCommand(options2) {
108405
109018
  for (const action of conflictActions) {
108406
109019
  if (!action.diff && action.targetPath && existsSync64(action.targetPath)) {
108407
109020
  try {
108408
- const targetContent = await readFile61(action.targetPath, "utf-8");
109021
+ const targetContent = await readFile63(action.targetPath, "utf-8");
108409
109022
  const sourceItem = effectiveAgents.find((a3) => a3.name === action.item) || effectiveCommands.find((c2) => c2.name === action.item) || (effectiveConfigItem?.name === action.item ? effectiveConfigItem : null) || effectiveRuleItems.find((r2) => r2.name === action.item) || effectiveHookItems.find((h2) => h2.name === action.item);
108410
109023
  if (sourceItem) {
108411
109024
  const providerConfig = providers[action.provider];
@@ -108552,7 +109165,12 @@ async function migrateCommand(options2) {
108552
109165
  f2.warn("Skipped writing default model to opencode.json. Migrated agents may fail with ProviderModelNotFoundError until you set one.");
108553
109166
  }
108554
109167
  } catch (err) {
108555
- postProgressWarnings.push(`Could not update opencode.json model (${err instanceof Error ? err.message : String(err)}). Agents may fail with ProviderModelNotFoundError until a model is set.`);
109168
+ if (err instanceof OpenCodeAuthRequiredError) {
109169
+ f2.warn(err.message);
109170
+ postProgressWarnings.push(`opencode setup is incomplete: ${err.message}`);
109171
+ } else {
109172
+ postProgressWarnings.push(`Could not update opencode.json model (${err instanceof Error ? err.message : String(err)}). Agents may fail with ProviderModelNotFoundError until a model is set.`);
109173
+ }
108556
109174
  }
108557
109175
  }
108558
109176
  if (hooksSource && successfulHookFiles.size > 0) {
@@ -108817,7 +109435,7 @@ function buildDryRunFallbackResults(skills, selectedProviders, installGlobally,
108817
109435
  results.push({
108818
109436
  itemName: skill.name,
108819
109437
  operation: "apply",
108820
- path: join142(basePath, skill.name),
109438
+ path: join144(basePath, skill.name),
108821
109439
  portableType: "skill",
108822
109440
  provider,
108823
109441
  providerDisplayName: providers[provider].displayName,
@@ -108835,7 +109453,7 @@ var import_picocolors31 = __toESM(require_picocolors(), 1);
108835
109453
 
108836
109454
  // src/commands/new/phases/directory-setup.ts
108837
109455
  init_config_manager();
108838
- import { resolve as resolve42 } from "node:path";
109456
+ import { resolve as resolve43 } from "node:path";
108839
109457
  init_logger();
108840
109458
  init_path_resolver();
108841
109459
  init_types3();
@@ -108920,7 +109538,7 @@ async function directorySetup(validOptions, prompts) {
108920
109538
  targetDir = await prompts.getDirectory(targetDir);
108921
109539
  }
108922
109540
  }
108923
- const resolvedDir = resolve42(targetDir);
109541
+ const resolvedDir = resolve43(targetDir);
108924
109542
  logger.info(`Target directory: ${resolvedDir}`);
108925
109543
  if (PathResolver.isLocalSameAsGlobal(resolvedDir)) {
108926
109544
  logger.warning("You're creating a project at HOME directory.");
@@ -108977,7 +109595,7 @@ async function handleDirectorySetup(ctx) {
108977
109595
  // src/commands/new/phases/project-creation.ts
108978
109596
  init_config_manager();
108979
109597
  init_github_client();
108980
- import { join as join143 } from "node:path";
109598
+ import { join as join145 } from "node:path";
108981
109599
  init_logger();
108982
109600
  init_output_manager();
108983
109601
  init_types3();
@@ -109103,7 +109721,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
109103
109721
  output.section("Installing");
109104
109722
  logger.verbose("Installation target", { directory: resolvedDir });
109105
109723
  const merger = new FileMerger;
109106
- const claudeDir3 = join143(resolvedDir, ".claude");
109724
+ const claudeDir3 = join145(resolvedDir, ".claude");
109107
109725
  merger.setMultiKitContext(claudeDir3, kit);
109108
109726
  if (validOptions.exclude && validOptions.exclude.length > 0) {
109109
109727
  merger.addIgnorePatterns(validOptions.exclude);
@@ -109150,7 +109768,7 @@ async function handleProjectCreation(ctx) {
109150
109768
  }
109151
109769
  // src/commands/new/phases/post-setup.ts
109152
109770
  init_projects_registry();
109153
- import { join as join144 } from "node:path";
109771
+ import { join as join146 } from "node:path";
109154
109772
  init_package_installer();
109155
109773
  init_logger();
109156
109774
  init_path_resolver();
@@ -109182,9 +109800,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
109182
109800
  withSudo: validOptions.withSudo
109183
109801
  });
109184
109802
  }
109185
- const claudeDir3 = join144(resolvedDir, ".claude");
109803
+ const claudeDir3 = join146(resolvedDir, ".claude");
109186
109804
  await promptSetupWizardIfNeeded({
109187
- envPath: join144(claudeDir3, ".env"),
109805
+ envPath: join146(claudeDir3, ".env"),
109188
109806
  claudeDir: claudeDir3,
109189
109807
  isGlobal: false,
109190
109808
  isNonInteractive: isNonInteractive2,
@@ -109254,7 +109872,7 @@ Please use only one download method.`);
109254
109872
  // src/commands/plan/plan-command.ts
109255
109873
  init_output_manager();
109256
109874
  import { existsSync as existsSync67, statSync as statSync12 } from "node:fs";
109257
- import { dirname as dirname46, isAbsolute as isAbsolute11, join as join147, parse as parse7, resolve as resolve46 } from "node:path";
109875
+ import { dirname as dirname46, isAbsolute as isAbsolute11, join as join149, parse as parse7, resolve as resolve48 } from "node:path";
109258
109876
 
109259
109877
  // src/commands/plan/plan-read-handlers.ts
109260
109878
  init_config();
@@ -109264,14 +109882,14 @@ init_logger();
109264
109882
  init_output_manager();
109265
109883
  var import_picocolors32 = __toESM(require_picocolors(), 1);
109266
109884
  import { existsSync as existsSync66, statSync as statSync11 } from "node:fs";
109267
- import { basename as basename28, dirname as dirname44, join as join146, relative as relative27, resolve as resolve44 } from "node:path";
109885
+ import { basename as basename28, dirname as dirname44, join as join148, relative as relative27, resolve as resolve46 } from "node:path";
109268
109886
 
109269
109887
  // src/commands/plan/plan-dependencies.ts
109270
109888
  init_config();
109271
109889
  init_plan_parser();
109272
109890
  init_plans_registry();
109273
109891
  import { existsSync as existsSync65 } from "node:fs";
109274
- import { dirname as dirname43, join as join145 } from "node:path";
109892
+ import { dirname as dirname43, join as join147 } from "node:path";
109275
109893
  async function resolvePlanDependencies(references, currentPlanFile, options2 = {}) {
109276
109894
  if (references.length === 0)
109277
109895
  return [];
@@ -109291,7 +109909,7 @@ async function resolvePlanDependencies(references, currentPlanFile, options2 = {
109291
109909
  };
109292
109910
  }
109293
109911
  const scopeRoot = resolvePlanDirForScope(scope, projectRoot, config);
109294
- const planFile = join145(scopeRoot, planId, "plan.md");
109912
+ const planFile = join147(scopeRoot, planId, "plan.md");
109295
109913
  const isSelfReference = planFile === currentPlanFile;
109296
109914
  if (!existsSync65(planFile)) {
109297
109915
  return {
@@ -109322,14 +109940,14 @@ init_config();
109322
109940
  init_plan_parser();
109323
109941
  init_plan_scope();
109324
109942
  init_plans_registry();
109325
- import { isAbsolute as isAbsolute10, resolve as resolve43 } from "node:path";
109943
+ import { isAbsolute as isAbsolute10, resolve as resolve45 } from "node:path";
109326
109944
  async function getGlobalPlansDirFromCwd() {
109327
109945
  const projectRoot = findProjectRoot(process.cwd());
109328
109946
  const { config } = await CkConfigManager.loadFull(projectRoot);
109329
109947
  return resolveGlobalPlansDir(config);
109330
109948
  }
109331
109949
  function resolveTargetFromBase(target, baseDir) {
109332
- const resolvedTarget = isAbsolute10(target) ? resolve43(target) : resolve43(baseDir, target);
109950
+ const resolvedTarget = isAbsolute10(target) ? resolve45(target) : resolve45(baseDir, target);
109333
109951
  return isWithinDir(resolvedTarget, baseDir) ? resolvedTarget : null;
109334
109952
  }
109335
109953
 
@@ -109432,8 +110050,8 @@ async function handleStatus(target, options2) {
109432
110050
  return;
109433
110051
  }
109434
110052
  const effectiveTarget = !resolvedTarget && globalBaseDir ? globalBaseDir : resolvedTarget;
109435
- const t = effectiveTarget ? resolve44(effectiveTarget) : null;
109436
- const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(join146(t, "plan.md")) ? t : null;
110053
+ const t = effectiveTarget ? resolve46(effectiveTarget) : null;
110054
+ const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(join148(t, "plan.md")) ? t : null;
109437
110055
  if (plansDir) {
109438
110056
  const planFiles = scanPlanDir(plansDir);
109439
110057
  if (planFiles.length === 0) {
@@ -109617,7 +110235,7 @@ init_plan_parser();
109617
110235
  init_plans_registry();
109618
110236
  init_output_manager();
109619
110237
  var import_picocolors33 = __toESM(require_picocolors(), 1);
109620
- import { basename as basename29, dirname as dirname45, relative as relative28, resolve as resolve45 } from "node:path";
110238
+ import { basename as basename29, dirname as dirname45, relative as relative28, resolve as resolve47 } from "node:path";
109621
110239
  async function handleCreate(target, options2) {
109622
110240
  if (!options2.title) {
109623
110241
  output.error("[X] --title is required for create");
@@ -109649,13 +110267,13 @@ async function handleCreate(target, options2) {
109649
110267
  return;
109650
110268
  }
109651
110269
  const globalBaseDir = options2.global ? await getGlobalPlansDirFromCwd() : undefined;
109652
- const resolvedDir = globalBaseDir ? resolveTargetFromBase(dir, globalBaseDir) : resolve45(dir);
110270
+ const resolvedDir = globalBaseDir ? resolveTargetFromBase(dir, globalBaseDir) : resolve47(dir);
109653
110271
  if (globalBaseDir && !resolvedDir) {
109654
110272
  output.error("[X] Target directory must stay within the configured global plans root");
109655
110273
  process.exitCode = 1;
109656
110274
  return;
109657
110275
  }
109658
- const safeResolvedDir = resolvedDir ?? resolve45(dir);
110276
+ const safeResolvedDir = resolvedDir ?? resolve47(dir);
109659
110277
  const result = scaffoldPlan({
109660
110278
  title: options2.title,
109661
110279
  phases: phaseNames.map((name2) => ({ name: name2 })),
@@ -109831,24 +110449,24 @@ async function handleAddPhase(target, options2) {
109831
110449
  // src/commands/plan/plan-command.ts
109832
110450
  function resolveTargetPath(target, baseDir) {
109833
110451
  if (!baseDir) {
109834
- return resolve46(target);
110452
+ return resolve48(target);
109835
110453
  }
109836
110454
  if (isAbsolute11(target)) {
109837
- return resolve46(target);
110455
+ return resolve48(target);
109838
110456
  }
109839
- const cwdCandidate = resolve46(target);
110457
+ const cwdCandidate = resolve48(target);
109840
110458
  if (existsSync67(cwdCandidate)) {
109841
110459
  return cwdCandidate;
109842
110460
  }
109843
- return resolve46(baseDir, target);
110461
+ return resolve48(baseDir, target);
109844
110462
  }
109845
110463
  function resolvePlanFile(target, baseDir) {
109846
- const t = target ? resolveTargetPath(target, baseDir) : baseDir ? resolve46(baseDir) : process.cwd();
110464
+ const t = target ? resolveTargetPath(target, baseDir) : baseDir ? resolve48(baseDir) : process.cwd();
109847
110465
  if (existsSync67(t)) {
109848
110466
  const stat24 = statSync12(t);
109849
110467
  if (stat24.isFile())
109850
110468
  return t;
109851
- const candidate = join147(t, "plan.md");
110469
+ const candidate = join149(t, "plan.md");
109852
110470
  if (existsSync67(candidate))
109853
110471
  return candidate;
109854
110472
  }
@@ -109856,7 +110474,7 @@ function resolvePlanFile(target, baseDir) {
109856
110474
  let dir = process.cwd();
109857
110475
  const root = parse7(dir).root;
109858
110476
  while (dir !== root) {
109859
- const candidate = join147(dir, "plan.md");
110477
+ const candidate = join149(dir, "plan.md");
109860
110478
  if (existsSync67(candidate))
109861
110479
  return candidate;
109862
110480
  dir = dirname46(dir);
@@ -109907,7 +110525,7 @@ async function planCommand(action, target, options2) {
109907
110525
  let resolvedTarget = target;
109908
110526
  if (resolvedAction && !knownActions.has(resolvedAction)) {
109909
110527
  const looksLikePath = resolvedAction.includes("/") || resolvedAction.includes("\\") || resolvedAction.endsWith(".md") || resolvedAction === "." || resolvedAction === "..";
109910
- const existsOnDisk = !looksLikePath && existsSync67(resolve46(resolvedAction));
110528
+ const existsOnDisk = !looksLikePath && existsSync67(resolve48(resolvedAction));
109911
110529
  if (looksLikePath || existsOnDisk) {
109912
110530
  resolvedTarget = resolvedAction;
109913
110531
  resolvedAction = undefined;
@@ -109950,11 +110568,11 @@ init_logger();
109950
110568
  init_safe_prompts();
109951
110569
  var import_picocolors34 = __toESM(require_picocolors(), 1);
109952
110570
  import { existsSync as existsSync68 } from "node:fs";
109953
- import { resolve as resolve47 } from "node:path";
110571
+ import { resolve as resolve49 } from "node:path";
109954
110572
  async function handleAdd(projectPath, options2) {
109955
110573
  logger.debug(`Adding project: ${projectPath}, options: ${JSON.stringify(options2)}`);
109956
110574
  intro("Add Project");
109957
- const absolutePath = resolve47(projectPath);
110575
+ const absolutePath = resolve49(projectPath);
109958
110576
  if (!existsSync68(absolutePath)) {
109959
110577
  log.error(`Path does not exist: ${absolutePath}`);
109960
110578
  process.exitCode = 1;
@@ -110378,8 +110996,8 @@ init_skills_registry();
110378
110996
  init_skills_uninstaller();
110379
110997
  var import_gray_matter11 = __toESM(require_gray_matter(), 1);
110380
110998
  var import_picocolors37 = __toESM(require_picocolors(), 1);
110381
- import { readFile as readFile62 } from "node:fs/promises";
110382
- import { join as join148 } from "node:path";
110999
+ import { readFile as readFile64 } from "node:fs/promises";
111000
+ import { join as join150 } from "node:path";
110383
111001
 
110384
111002
  // src/commands/skills/types.ts
110385
111003
  init_zod();
@@ -110501,9 +111119,9 @@ async function handleValidate2(sourcePath) {
110501
111119
  spinner.stop(`Checked ${skills.length} skill(s)`);
110502
111120
  let hasIssues = false;
110503
111121
  for (const skill of skills) {
110504
- const skillMdPath = join148(skill.path, "SKILL.md");
111122
+ const skillMdPath = join150(skill.path, "SKILL.md");
110505
111123
  try {
110506
- const content = await readFile62(skillMdPath, "utf-8");
111124
+ const content = await readFile64(skillMdPath, "utf-8");
110507
111125
  const { data } = import_gray_matter11.default(content, {
110508
111126
  engines: { javascript: { parse: () => ({}) } }
110509
111127
  });
@@ -111059,7 +111677,7 @@ async function detectInstallations() {
111059
111677
 
111060
111678
  // src/commands/uninstall/removal-handler.ts
111061
111679
  import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
111062
- import { basename as basename30, join as join150, resolve as resolve48, sep as sep12 } from "node:path";
111680
+ import { basename as basename30, join as join152, resolve as resolve50, sep as sep12 } from "node:path";
111063
111681
  init_logger();
111064
111682
  init_safe_prompts();
111065
111683
  init_safe_spinner();
@@ -111068,7 +111686,7 @@ var import_fs_extra44 = __toESM(require_lib3(), 1);
111068
111686
  // src/commands/uninstall/analysis-handler.ts
111069
111687
  init_metadata_migration();
111070
111688
  import { readdirSync as readdirSync9, rmSync as rmSync4 } from "node:fs";
111071
- import { dirname as dirname47, join as join149 } from "node:path";
111689
+ import { dirname as dirname47, join as join151 } from "node:path";
111072
111690
  init_logger();
111073
111691
  init_safe_prompts();
111074
111692
  var import_fs_extra43 = __toESM(require_lib3(), 1);
@@ -111125,7 +111743,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
111125
111743
  const remainingFiles = metadata.kits?.[remainingKit]?.files || [];
111126
111744
  for (const file of remainingFiles) {
111127
111745
  const relativePath = normalizeTrackedPath(file.path);
111128
- if (await import_fs_extra43.pathExists(join149(installation.path, relativePath))) {
111746
+ if (await import_fs_extra43.pathExists(join151(installation.path, relativePath))) {
111129
111747
  result.retainedManifestPaths.push(relativePath);
111130
111748
  }
111131
111749
  }
@@ -111133,7 +111751,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
111133
111751
  const kitFiles = metadata.kits[kit].files || [];
111134
111752
  for (const trackedFile of kitFiles) {
111135
111753
  const relativePath = normalizeTrackedPath(trackedFile.path);
111136
- const filePath = join149(installation.path, relativePath);
111754
+ const filePath = join151(installation.path, relativePath);
111137
111755
  if (preservedPaths.has(relativePath)) {
111138
111756
  result.toPreserve.push({ path: relativePath, reason: "shared with other kit" });
111139
111757
  continue;
@@ -111166,7 +111784,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
111166
111784
  }
111167
111785
  for (const trackedFile of allTrackedFiles) {
111168
111786
  const relativePath = normalizeTrackedPath(trackedFile.path);
111169
- const filePath = join149(installation.path, relativePath);
111787
+ const filePath = join151(installation.path, relativePath);
111170
111788
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
111171
111789
  if (!ownershipResult.exists)
111172
111790
  continue;
@@ -111240,8 +111858,8 @@ async function restoreUninstallBackup(backup) {
111240
111858
  }
111241
111859
  async function isPathSafeToRemove(filePath, baseDir) {
111242
111860
  try {
111243
- const resolvedPath = resolve48(filePath);
111244
- const resolvedBase = resolve48(baseDir);
111861
+ const resolvedPath = resolve50(filePath);
111862
+ const resolvedBase = resolve50(baseDir);
111245
111863
  if (!resolvedPath.startsWith(resolvedBase + sep12) && resolvedPath !== resolvedBase) {
111246
111864
  logger.debug(`Path outside installation directory: ${filePath}`);
111247
111865
  return false;
@@ -111249,7 +111867,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
111249
111867
  const stats = await import_fs_extra44.lstat(filePath);
111250
111868
  if (stats.isSymbolicLink()) {
111251
111869
  const realPath = await import_fs_extra44.realpath(filePath);
111252
- const resolvedReal = resolve48(realPath);
111870
+ const resolvedReal = resolve50(realPath);
111253
111871
  if (!resolvedReal.startsWith(resolvedBase + sep12) && resolvedReal !== resolvedBase) {
111254
111872
  logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
111255
111873
  return false;
@@ -111309,7 +111927,7 @@ async function removeInstallations(installations, options2) {
111309
111927
  let removedCount = 0;
111310
111928
  let cleanedDirs = 0;
111311
111929
  for (const item of analysis.toDelete) {
111312
- const filePath = join150(installation.path, item.path);
111930
+ const filePath = join152(installation.path, item.path);
111313
111931
  if (!await import_fs_extra44.pathExists(filePath))
111314
111932
  continue;
111315
111933
  if (!await isPathSafeToRemove(filePath, installation.path)) {
@@ -111643,7 +112261,7 @@ ${import_picocolors40.default.bold(import_picocolors40.default.cyan(result.kitCo
111643
112261
  init_logger();
111644
112262
  import { existsSync as existsSync74 } from "node:fs";
111645
112263
  import { rm as rm17 } from "node:fs/promises";
111646
- import { join as join157 } from "node:path";
112264
+ import { join as join159 } from "node:path";
111647
112265
  var import_picocolors41 = __toESM(require_picocolors(), 1);
111648
112266
 
111649
112267
  // src/commands/watch/phases/implementation-runner.ts
@@ -111712,7 +112330,7 @@ function getDisclaimerMarker() {
111712
112330
  return AI_DISCLAIMER;
111713
112331
  }
111714
112332
  function spawnAndCollect2(command, args) {
111715
- return new Promise((resolve49, reject) => {
112333
+ return new Promise((resolve44, reject) => {
111716
112334
  const child = spawn7(command, args, { stdio: ["ignore", "pipe", "pipe"] });
111717
112335
  const chunks = [];
111718
112336
  const stderrChunks = [];
@@ -111725,7 +112343,7 @@ function spawnAndCollect2(command, args) {
111725
112343
  reject(new Error(`${command} exited with code ${code2}: ${stderr}`));
111726
112344
  return;
111727
112345
  }
111728
- resolve49(Buffer.concat(chunks).toString("utf-8"));
112346
+ resolve44(Buffer.concat(chunks).toString("utf-8"));
111729
112347
  });
111730
112348
  });
111731
112349
  }
@@ -111833,7 +112451,7 @@ function formatResponse(content, showBranding) {
111833
112451
  return disclaimer + formatted + branding;
111834
112452
  }
111835
112453
  async function postViaGh(owner, repo, issueNumber, body) {
111836
- return new Promise((resolve49, reject) => {
112454
+ return new Promise((resolve44, reject) => {
111837
112455
  const args = [
111838
112456
  "issue",
111839
112457
  "comment",
@@ -111855,7 +112473,7 @@ async function postViaGh(owner, repo, issueNumber, body) {
111855
112473
  reject(new Error(`gh exited with code ${code2}: ${stderr}`));
111856
112474
  return;
111857
112475
  }
111858
- resolve49();
112476
+ resolve44();
111859
112477
  });
111860
112478
  });
111861
112479
  }
@@ -111973,7 +112591,7 @@ After completing the implementation:
111973
112591
  "--allowedTools",
111974
112592
  tools
111975
112593
  ];
111976
- await new Promise((resolve49, reject) => {
112594
+ await new Promise((resolve44, reject) => {
111977
112595
  const child = spawn9("claude", args, { cwd: cwd2, stdio: ["pipe", "pipe", "pipe"], detached: false });
111978
112596
  child.stdin.write(prompt);
111979
112597
  child.stdin.end();
@@ -111998,7 +112616,7 @@ After completing the implementation:
111998
112616
  reject(new Error(`Claude exited ${code2}: ${stderr.slice(0, 500)}`));
111999
112617
  return;
112000
112618
  }
112001
- resolve49();
112619
+ resolve44();
112002
112620
  });
112003
112621
  });
112004
112622
  }
@@ -112142,7 +112760,7 @@ function checkRateLimit2(processedThisHour, maxPerHour) {
112142
112760
  return processedThisHour < maxPerHour;
112143
112761
  }
112144
112762
  function spawnAndCollect3(command, args) {
112145
- return new Promise((resolve49, reject) => {
112763
+ return new Promise((resolve44, reject) => {
112146
112764
  const child = spawn10(command, args, { stdio: ["ignore", "pipe", "pipe"] });
112147
112765
  const chunks = [];
112148
112766
  const stderrChunks = [];
@@ -112155,14 +112773,14 @@ function spawnAndCollect3(command, args) {
112155
112773
  reject(new Error(`${command} exited with code ${code2}: ${stderr}`));
112156
112774
  return;
112157
112775
  }
112158
- resolve49(Buffer.concat(chunks).toString("utf-8"));
112776
+ resolve44(Buffer.concat(chunks).toString("utf-8"));
112159
112777
  });
112160
112778
  });
112161
112779
  }
112162
112780
 
112163
112781
  // src/commands/watch/phases/issue-processor.ts
112164
- import { mkdir as mkdir37, writeFile as writeFile37 } from "node:fs/promises";
112165
- import { join as join153 } from "node:path";
112782
+ import { mkdir as mkdir38, writeFile as writeFile38 } from "node:fs/promises";
112783
+ import { join as join155 } from "node:path";
112166
112784
 
112167
112785
  // src/commands/watch/phases/approval-detector.ts
112168
112786
  init_logger();
@@ -112207,7 +112825,7 @@ async function invokeClaude(options2) {
112207
112825
  return collectClaudeOutput(child, options2.timeoutSec, verbose);
112208
112826
  }
112209
112827
  function collectClaudeOutput(child, timeoutSec, verbose = false) {
112210
- return new Promise((resolve49, reject) => {
112828
+ return new Promise((resolve44, reject) => {
112211
112829
  const chunks = [];
112212
112830
  const stderrChunks = [];
112213
112831
  child.stdout?.on("data", (chunk) => {
@@ -112237,7 +112855,7 @@ function collectClaudeOutput(child, timeoutSec, verbose = false) {
112237
112855
  reject(new Error(`Claude exited with code ${code2}: ${stderr}`));
112238
112856
  return;
112239
112857
  }
112240
- resolve49(verbose ? parseStreamJsonOutput(stdout2) : parseClaudeOutput(stdout2));
112858
+ resolve44(verbose ? parseStreamJsonOutput(stdout2) : parseClaudeOutput(stdout2));
112241
112859
  });
112242
112860
  });
112243
112861
  }
@@ -112540,9 +113158,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
112540
113158
 
112541
113159
  // src/commands/watch/phases/plan-dir-finder.ts
112542
113160
  import { readdir as readdir44, stat as stat24 } from "node:fs/promises";
112543
- import { join as join152 } from "node:path";
113161
+ import { join as join154 } from "node:path";
112544
113162
  async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
112545
- const plansRoot = join152(cwd2, "plans");
113163
+ const plansRoot = join154(cwd2, "plans");
112546
113164
  try {
112547
113165
  const entries = await readdir44(plansRoot);
112548
113166
  const tenMinAgo = Date.now() - 10 * 60 * 1000;
@@ -112551,14 +113169,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
112551
113169
  for (const entry of entries) {
112552
113170
  if (entry === "watch" || entry === "reports" || entry === "visuals")
112553
113171
  continue;
112554
- const dirPath = join152(plansRoot, entry);
113172
+ const dirPath = join154(plansRoot, entry);
112555
113173
  const dirStat = await stat24(dirPath);
112556
113174
  if (!dirStat.isDirectory())
112557
113175
  continue;
112558
113176
  if (dirStat.mtimeMs < tenMinAgo)
112559
113177
  continue;
112560
113178
  try {
112561
- await stat24(join152(dirPath, "plan.md"));
113179
+ await stat24(join154(dirPath, "plan.md"));
112562
113180
  } catch {
112563
113181
  continue;
112564
113182
  }
@@ -112789,14 +113407,14 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
112789
113407
  stats.plansCreated++;
112790
113408
  const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
112791
113409
  if (detectedPlanDir) {
112792
- state.activeIssues[numStr].planPath = join153(detectedPlanDir, "plan.md");
113410
+ state.activeIssues[numStr].planPath = join155(detectedPlanDir, "plan.md");
112793
113411
  watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
112794
113412
  } else {
112795
113413
  try {
112796
- const planDir = join153(projectDir, "plans", "watch");
112797
- await mkdir37(planDir, { recursive: true });
112798
- const planFilePath = join153(planDir, `issue-${issue.number}-plan.md`);
112799
- await writeFile37(planFilePath, planResult.planText, "utf-8");
113414
+ const planDir = join155(projectDir, "plans", "watch");
113415
+ await mkdir38(planDir, { recursive: true });
113416
+ const planFilePath = join155(planDir, `issue-${issue.number}-plan.md`);
113417
+ await writeFile38(planFilePath, planResult.planText, "utf-8");
112800
113418
  state.activeIssues[numStr].planPath = planFilePath;
112801
113419
  watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
112802
113420
  } catch (err) {
@@ -112873,7 +113491,7 @@ async function checkActiveIssues(state, config, setup, options2, watchLog, stats
112873
113491
  // src/commands/watch/phases/maintainer-resolver.ts
112874
113492
  init_logger();
112875
113493
  init_implementation_git_helpers();
112876
- var CACHE_TTL_MS3 = 3600000;
113494
+ var CACHE_TTL_MS4 = 3600000;
112877
113495
  var cache4 = new Map;
112878
113496
  async function resolveMaintainers(owner, repo, excludeAuthors, autoDetect) {
112879
113497
  const normalizedExclude = excludeAuthors.map((s) => s.toLowerCase());
@@ -112882,7 +113500,7 @@ async function resolveMaintainers(owner, repo, excludeAuthors, autoDetect) {
112882
113500
  }
112883
113501
  const cacheKey = `${owner}/${repo}`;
112884
113502
  const cached = cache4.get(cacheKey);
112885
- if (cached && Date.now() - cached.fetchedAt >= CACHE_TTL_MS3) {
113503
+ if (cached && Date.now() - cached.fetchedAt >= CACHE_TTL_MS4) {
112886
113504
  cache4.delete(cacheKey);
112887
113505
  } else if (cached) {
112888
113506
  const merged = Array.from(new Set([...cached.users, ...normalizedExclude]));
@@ -112941,7 +113559,7 @@ init_ck_config_manager();
112941
113559
  init_file_io();
112942
113560
  init_logger();
112943
113561
  import { existsSync as existsSync70 } from "node:fs";
112944
- import { mkdir as mkdir38, readFile as readFile64 } from "node:fs/promises";
113562
+ import { mkdir as mkdir39, readFile as readFile66 } from "node:fs/promises";
112945
113563
  import { dirname as dirname48 } from "node:path";
112946
113564
  var PROCESSED_ISSUES_CAP = 500;
112947
113565
  async function readCkJson(projectDir) {
@@ -112949,7 +113567,7 @@ async function readCkJson(projectDir) {
112949
113567
  try {
112950
113568
  if (!existsSync70(configPath))
112951
113569
  return {};
112952
- const content = await readFile64(configPath, "utf-8");
113570
+ const content = await readFile66(configPath, "utf-8");
112953
113571
  return JSON.parse(content);
112954
113572
  } catch (error) {
112955
113573
  logger.warning(`Failed to parse .ck.json: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -112974,7 +113592,7 @@ async function saveWatchState(projectDir, state) {
112974
113592
  const configPath = CkConfigManager.getProjectConfigPath(projectDir);
112975
113593
  const configDir = dirname48(configPath);
112976
113594
  if (!existsSync70(configDir)) {
112977
- await mkdir38(configDir, { recursive: true });
113595
+ await mkdir39(configDir, { recursive: true });
112978
113596
  }
112979
113597
  const raw2 = await readCkJson(projectDir);
112980
113598
  const watchRaw = raw2.watch ?? {};
@@ -113102,18 +113720,18 @@ init_logger();
113102
113720
  import { spawnSync as spawnSync7 } from "node:child_process";
113103
113721
  import { existsSync as existsSync71 } from "node:fs";
113104
113722
  import { readdir as readdir45, stat as stat25 } from "node:fs/promises";
113105
- import { join as join154 } from "node:path";
113723
+ import { join as join156 } from "node:path";
113106
113724
  async function scanForRepos(parentDir) {
113107
113725
  const repos = [];
113108
113726
  const entries = await readdir45(parentDir);
113109
113727
  for (const entry of entries) {
113110
113728
  if (entry.startsWith("."))
113111
113729
  continue;
113112
- const fullPath = join154(parentDir, entry);
113730
+ const fullPath = join156(parentDir, entry);
113113
113731
  const entryStat = await stat25(fullPath);
113114
113732
  if (!entryStat.isDirectory())
113115
113733
  continue;
113116
- const gitDir = join154(fullPath, ".git");
113734
+ const gitDir = join156(fullPath, ".git");
113117
113735
  if (!existsSync71(gitDir))
113118
113736
  continue;
113119
113737
  const result = spawnSync7("gh", ["repo", "view", "--json", "owner,name"], {
@@ -113139,8 +113757,8 @@ async function scanForRepos(parentDir) {
113139
113757
  init_logger();
113140
113758
  import { spawnSync as spawnSync8 } from "node:child_process";
113141
113759
  import { existsSync as existsSync72 } from "node:fs";
113142
- import { homedir as homedir51 } from "node:os";
113143
- import { join as join155 } from "node:path";
113760
+ import { homedir as homedir53 } from "node:os";
113761
+ import { join as join157 } from "node:path";
113144
113762
  async function validateSetup(cwd2) {
113145
113763
  const workDir = cwd2 ?? process.cwd();
113146
113764
  const ghVersion = spawnSync8("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
@@ -113171,7 +113789,7 @@ Run this command from a directory with a GitHub remote.`);
113171
113789
  } catch {
113172
113790
  throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
113173
113791
  }
113174
- const skillsPath = join155(homedir51(), ".claude", "skills");
113792
+ const skillsPath = join157(homedir53(), ".claude", "skills");
113175
113793
  const skillsAvailable = existsSync72(skillsPath);
113176
113794
  if (!skillsAvailable) {
113177
113795
  logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);
@@ -113189,8 +113807,8 @@ init_logger();
113189
113807
  init_path_resolver();
113190
113808
  import { createWriteStream as createWriteStream3, statSync as statSync13 } from "node:fs";
113191
113809
  import { existsSync as existsSync73 } from "node:fs";
113192
- import { mkdir as mkdir39, rename as rename13 } from "node:fs/promises";
113193
- import { join as join156 } from "node:path";
113810
+ import { mkdir as mkdir40, rename as rename14 } from "node:fs/promises";
113811
+ import { join as join158 } from "node:path";
113194
113812
 
113195
113813
  class WatchLogger {
113196
113814
  logStream = null;
@@ -113198,16 +113816,16 @@ class WatchLogger {
113198
113816
  logPath = null;
113199
113817
  maxBytes;
113200
113818
  constructor(logDir, maxBytes = 0) {
113201
- this.logDir = logDir ?? join156(PathResolver.getClaudeKitDir(), "logs");
113819
+ this.logDir = logDir ?? join158(PathResolver.getClaudeKitDir(), "logs");
113202
113820
  this.maxBytes = maxBytes;
113203
113821
  }
113204
113822
  async init() {
113205
113823
  try {
113206
113824
  if (!existsSync73(this.logDir)) {
113207
- await mkdir39(this.logDir, { recursive: true });
113825
+ await mkdir40(this.logDir, { recursive: true });
113208
113826
  }
113209
113827
  const dateStr = formatDate(new Date);
113210
- this.logPath = join156(this.logDir, `watch-${dateStr}.log`);
113828
+ this.logPath = join158(this.logDir, `watch-${dateStr}.log`);
113211
113829
  this.logStream = createWriteStream3(this.logPath, { flags: "a", mode: 384 });
113212
113830
  } catch (error) {
113213
113831
  logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
@@ -113272,7 +113890,7 @@ class WatchLogger {
113272
113890
  try {
113273
113891
  this.logStream.end();
113274
113892
  const rotatedPath = `${this.logPath}.1`;
113275
- rename13(this.logPath, rotatedPath).catch(() => {});
113893
+ rename14(this.logPath, rotatedPath).catch(() => {});
113276
113894
  this.logStream = createWriteStream3(this.logPath, { flags: "w", mode: 384 });
113277
113895
  } catch {}
113278
113896
  }
@@ -113389,7 +114007,7 @@ async function watchCommand(options2) {
113389
114007
  }
113390
114008
  async function discoverRepos(options2, watchLog) {
113391
114009
  const cwd2 = process.cwd();
113392
- const isGitRepo = existsSync74(join157(cwd2, ".git"));
114010
+ const isGitRepo = existsSync74(join159(cwd2, ".git"));
113393
114011
  if (options2.force) {
113394
114012
  await forceRemoveLock(watchLog);
113395
114013
  }
@@ -113501,7 +114119,7 @@ function formatQueueInfo(state) {
113501
114119
  return "idle";
113502
114120
  }
113503
114121
  function sleep(ms) {
113504
- return new Promise((resolve49) => setTimeout(resolve49, ms));
114122
+ return new Promise((resolve44) => setTimeout(resolve44, ms));
113505
114123
  }
113506
114124
  // src/cli/command-registry.ts
113507
114125
  init_logger();
@@ -113648,7 +114266,7 @@ function registerCommands(cli) {
113648
114266
  init_package();
113649
114267
  init_config_version_checker();
113650
114268
  import { existsSync as existsSync86, readFileSync as readFileSync22 } from "node:fs";
113651
- import { join as join169 } from "node:path";
114269
+ import { join as join171 } from "node:path";
113652
114270
 
113653
114271
  // src/domains/versioning/version-checker.ts
113654
114272
  init_version_utils();
@@ -113662,15 +114280,15 @@ init_types3();
113662
114280
  init_logger();
113663
114281
  init_path_resolver();
113664
114282
  import { existsSync as existsSync85 } from "node:fs";
113665
- import { mkdir as mkdir40, readFile as readFile66, writeFile as writeFile40 } from "node:fs/promises";
113666
- import { join as join168 } from "node:path";
114283
+ import { mkdir as mkdir41, readFile as readFile68, writeFile as writeFile41 } from "node:fs/promises";
114284
+ import { join as join170 } from "node:path";
113667
114285
 
113668
114286
  class VersionCacheManager {
113669
114287
  static CACHE_FILENAME = "version-check.json";
113670
114288
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
113671
114289
  static getCacheFile() {
113672
114290
  const cacheDir = PathResolver.getCacheDir(false);
113673
- return join168(cacheDir, VersionCacheManager.CACHE_FILENAME);
114291
+ return join170(cacheDir, VersionCacheManager.CACHE_FILENAME);
113674
114292
  }
113675
114293
  static async load() {
113676
114294
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -113679,7 +114297,7 @@ class VersionCacheManager {
113679
114297
  logger.debug("Version check cache not found");
113680
114298
  return null;
113681
114299
  }
113682
- const content = await readFile66(cacheFile, "utf-8");
114300
+ const content = await readFile68(cacheFile, "utf-8");
113683
114301
  const cache5 = JSON.parse(content);
113684
114302
  if (!cache5.lastCheck || !cache5.currentVersion || !cache5.latestVersion) {
113685
114303
  logger.debug("Invalid cache structure, ignoring");
@@ -113697,9 +114315,9 @@ class VersionCacheManager {
113697
114315
  const cacheDir = PathResolver.getCacheDir(false);
113698
114316
  try {
113699
114317
  if (!existsSync85(cacheDir)) {
113700
- await mkdir40(cacheDir, { recursive: true, mode: 448 });
114318
+ await mkdir41(cacheDir, { recursive: true, mode: 448 });
113701
114319
  }
113702
- await writeFile40(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
114320
+ await writeFile41(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
113703
114321
  logger.debug(`Version check cache saved to ${cacheFile}`);
113704
114322
  } catch (error) {
113705
114323
  logger.debug(`Failed to save version check cache: ${error}`);
@@ -113981,9 +114599,9 @@ async function displayVersion() {
113981
114599
  let localInstalledKits = [];
113982
114600
  let globalInstalledKits = [];
113983
114601
  const globalKitDir = PathResolver.getGlobalKitDir();
113984
- const globalMetadataPath = join169(globalKitDir, "metadata.json");
114602
+ const globalMetadataPath = join171(globalKitDir, "metadata.json");
113985
114603
  const prefix = PathResolver.getPathPrefix(false);
113986
- const localMetadataPath = prefix ? join169(process.cwd(), prefix, "metadata.json") : join169(process.cwd(), "metadata.json");
114604
+ const localMetadataPath = prefix ? join171(process.cwd(), prefix, "metadata.json") : join171(process.cwd(), "metadata.json");
113987
114605
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
113988
114606
  if (!isLocalSameAsGlobal && existsSync86(localMetadataPath)) {
113989
114607
  try {