claudekit-cli 3.24.1 → 3.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +537 -538
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -16529,22 +16529,22 @@ function padEnd(text, width) {
16529
16529
  const padding = Math.max(0, width - visibleLength);
16530
16530
  return text + " ".repeat(padding);
16531
16531
  }
16532
- var import_picocolors28, NO_COLOR, isColorSupported, identity = (text) => text, colors, defaultTheme;
16532
+ var import_picocolors27, NO_COLOR, isColorSupported, identity = (text) => text, colors, defaultTheme;
16533
16533
  var init_help_colors = __esm(() => {
16534
- import_picocolors28 = __toESM(require_picocolors(), 1);
16534
+ import_picocolors27 = __toESM(require_picocolors(), 1);
16535
16535
  NO_COLOR = process.env.NO_COLOR !== undefined;
16536
16536
  isColorSupported = !NO_COLOR && Boolean(process.stdout.isTTY);
16537
16537
  colors = {
16538
- banner: isColorSupported ? import_picocolors28.default.cyan : identity,
16539
- command: isColorSupported ? import_picocolors28.default.bold : identity,
16540
- heading: isColorSupported ? import_picocolors28.default.yellow : identity,
16541
- flag: isColorSupported ? import_picocolors28.default.green : identity,
16542
- description: isColorSupported ? import_picocolors28.default.gray : identity,
16543
- example: isColorSupported ? import_picocolors28.default.blue : identity,
16544
- warning: isColorSupported ? import_picocolors28.default.yellow : identity,
16545
- error: isColorSupported ? import_picocolors28.default.red : identity,
16546
- muted: isColorSupported ? import_picocolors28.default.dim : identity,
16547
- success: isColorSupported ? import_picocolors28.default.green : identity
16538
+ banner: isColorSupported ? import_picocolors27.default.cyan : identity,
16539
+ command: isColorSupported ? import_picocolors27.default.bold : identity,
16540
+ heading: isColorSupported ? import_picocolors27.default.yellow : identity,
16541
+ flag: isColorSupported ? import_picocolors27.default.green : identity,
16542
+ description: isColorSupported ? import_picocolors27.default.gray : identity,
16543
+ example: isColorSupported ? import_picocolors27.default.blue : identity,
16544
+ warning: isColorSupported ? import_picocolors27.default.yellow : identity,
16545
+ error: isColorSupported ? import_picocolors27.default.red : identity,
16546
+ muted: isColorSupported ? import_picocolors27.default.dim : identity,
16547
+ success: isColorSupported ? import_picocolors27.default.green : identity
16548
16548
  };
16549
16549
  defaultTheme = {
16550
16550
  banner: colors.banner,
@@ -37841,12 +37841,12 @@ function buildCommandPatterns() {
37841
37841
  const patterns = [];
37842
37842
  for (const cmd of COMMAND_ROOTS) {
37843
37843
  patterns.push({
37844
- regex: new RegExp(`(?<![\\w:])(\\/)${cmd}(:)`, "g"),
37845
- replacement: "$1ck:$2".replace("$2", `${cmd}:`)
37844
+ regex: new RegExp(`(?:^|(?<=[\\s\`]))(/)(${cmd})(:)(?!/)`, "gm"),
37845
+ replacement: "$1ck:$2$3"
37846
37846
  });
37847
37847
  patterns.push({
37848
- regex: new RegExp(`(?<![\\w:])(\\/)${cmd}(?=[\\s\`"'\\)\\]}>.,;:!?]|$)`, "g"),
37849
- replacement: `$1ck:${cmd}`
37848
+ regex: new RegExp(`(?:^|(?<=[\\s\`]))(/)(${cmd})(?![?/=&:\\w])(?=[\\s\`\\]\\)]|$)`, "gm"),
37849
+ replacement: "$1ck:$2"
37850
37850
  });
37851
37851
  }
37852
37852
  return patterns;
@@ -37856,11 +37856,9 @@ function transformCommandContent(content) {
37856
37856
  let transformed = content;
37857
37857
  const patterns = buildCommandPatterns();
37858
37858
  for (const { regex: regex2, replacement } of patterns) {
37859
- regex2.lastIndex = 0;
37860
37859
  const matches = transformed.match(regex2);
37861
37860
  if (matches) {
37862
37861
  changes += matches.length;
37863
- regex2.lastIndex = 0;
37864
37862
  transformed = transformed.replace(regex2, replacement);
37865
37863
  }
37866
37864
  }
@@ -40379,7 +40377,7 @@ async function handleSelection(ctx) {
40379
40377
  }
40380
40378
  const config = await ConfigManager.get();
40381
40379
  let accessibleKits;
40382
- if (!ctx.options.useGit) {
40380
+ if (!ctx.options.useGit && !ctx.options.kitPath && !ctx.options.archive) {
40383
40381
  accessibleKits = await detectAccessibleKits();
40384
40382
  if (accessibleKits.length === 0) {
40385
40383
  logger.error("No ClaudeKit access found.");
@@ -41672,7 +41670,7 @@ async function directorySetup(validOptions, prompts) {
41672
41670
  const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
41673
41671
  const config = await ConfigManager.get();
41674
41672
  let accessibleKits;
41675
- if (!validOptions.useGit) {
41673
+ if (!validOptions.useGit && !validOptions.kitPath && !validOptions.archive) {
41676
41674
  accessibleKits = await detectAccessibleKits();
41677
41675
  if (accessibleKits.length === 0) {
41678
41676
  logger.error("No ClaudeKit access found.");
@@ -41811,6 +41809,22 @@ init_types2();
41811
41809
  // src/commands/new/phases/version-selection.ts
41812
41810
  init_logger();
41813
41811
  async function selectVersion2(kit, options, isNonInteractive2, prompts, github) {
41812
+ if (options.kitPath || options.archive) {
41813
+ const localVersion = options.release || "local";
41814
+ return {
41815
+ release: {
41816
+ id: 0,
41817
+ tag_name: localVersion,
41818
+ name: localVersion,
41819
+ draft: false,
41820
+ prerelease: false,
41821
+ tarball_url: "",
41822
+ zipball_url: "",
41823
+ assets: []
41824
+ },
41825
+ selectedVersion: localVersion
41826
+ };
41827
+ }
41814
41828
  let selectedVersion = options.release;
41815
41829
  if (!selectedVersion && isNonInteractive2) {
41816
41830
  throw new Error("Interactive version selection unavailable in non-interactive mode. " + "Either: (1) use --release <tag> flag, or (2) set CI=false to enable interactive mode");
@@ -42388,7 +42402,7 @@ ${import_picocolors22.default.yellow("User modifications will be permanently del
42388
42402
  }
42389
42403
  // src/commands/update-cli.ts
42390
42404
  import { exec as exec7 } from "node:child_process";
42391
- import { join as join76 } from "node:path";
42405
+ import { join as join75 } from "node:path";
42392
42406
  import { promisify as promisify7 } from "node:util";
42393
42407
 
42394
42408
  // src/domains/github/npm-registry.ts
@@ -42526,500 +42540,219 @@ class NpmRegistryClient {
42526
42540
  }
42527
42541
  }
42528
42542
 
42529
- // src/domains/versioning/checking/version-utils.ts
42543
+ // src/commands/update-cli.ts
42544
+ init_logger();
42545
+ init_types2();
42546
+ init_types2();
42530
42547
  var import_compare_versions3 = __toESM(require_umd(), 1);
42531
- function isUpdateCheckDisabled() {
42532
- return process.env.NO_UPDATE_NOTIFIER === "1" || process.env.NO_UPDATE_NOTIFIER === "true" || !process.stdout.isTTY;
42548
+ var import_fs_extra36 = __toESM(require_lib(), 1);
42549
+ // package.json
42550
+ var package_default = {
42551
+ name: "claudekit-cli",
42552
+ version: "3.25.0",
42553
+ description: "CLI tool for bootstrapping and updating ClaudeKit projects",
42554
+ type: "module",
42555
+ repository: {
42556
+ type: "git",
42557
+ url: "git+https://github.com/mrgoonie/claudekit-cli.git"
42558
+ },
42559
+ publishConfig: {
42560
+ access: "public",
42561
+ registry: "https://registry.npmjs.org"
42562
+ },
42563
+ bin: {
42564
+ ck: "bin/ck.js"
42565
+ },
42566
+ files: [
42567
+ "bin/ck.js",
42568
+ "dist/index.js"
42569
+ ],
42570
+ scripts: {
42571
+ dev: "bun run src/index.ts",
42572
+ build: "bun build src/index.ts --outdir dist --target node --external @octokit/rest",
42573
+ compile: "bun build src/index.ts --compile --outfile ck",
42574
+ "compile:binary": "bun build src/index.ts --compile --outfile bin/ck",
42575
+ "compile:binaries": "node scripts/build-all-binaries.js",
42576
+ "check-version-sync": "node scripts/check-binary-version-sync.js",
42577
+ "build:platform-binaries": "bun run scripts/build-platform-binaries.js",
42578
+ test: "bun test",
42579
+ "test:watch": "bun test --watch",
42580
+ "test:quick": "./scripts/dev-quick-start.sh test",
42581
+ lint: "biome check .",
42582
+ "lint:fix": "biome check --fix .",
42583
+ "lint:fix-unsafe": "biome check --fix --unsafe .",
42584
+ format: "biome format --write .",
42585
+ typecheck: "tsc --noEmit",
42586
+ "dev:quick": "./scripts/dev-quick-start.sh",
42587
+ "dev:all": "./scripts/dev-quick-start.sh all",
42588
+ metrics: "bun run scripts/workflow-metrics.ts",
42589
+ "install:hooks": "./.githooks/install.sh"
42590
+ },
42591
+ keywords: [
42592
+ "cli",
42593
+ "claudekit",
42594
+ "boilerplate",
42595
+ "bootstrap",
42596
+ "template"
42597
+ ],
42598
+ author: "ClaudeKit",
42599
+ license: "MIT",
42600
+ engines: {
42601
+ bun: ">=1.3.2",
42602
+ node: ">=18.0.0"
42603
+ },
42604
+ dependencies: {
42605
+ "@clack/prompts": "^0.7.0",
42606
+ "@octokit/rest": "^22.0.0",
42607
+ cac: "^6.7.14",
42608
+ "cli-progress": "^3.12.0",
42609
+ "compare-versions": "^6.1.1",
42610
+ diff: "^8.0.2",
42611
+ "extract-zip": "^2.0.1",
42612
+ "fs-extra": "^11.2.0",
42613
+ ignore: "^5.3.2",
42614
+ minimatch: "^10.1.1",
42615
+ ora: "^8.0.0",
42616
+ "p-limit": "^7.2.0",
42617
+ picocolors: "^1.1.1",
42618
+ "proper-lockfile": "^4.1.2",
42619
+ semver: "^7.7.3",
42620
+ tar: "^7.4.3",
42621
+ tmp: "^0.2.3",
42622
+ zod: "^3.23.8"
42623
+ },
42624
+ devDependencies: {
42625
+ "@biomejs/biome": "^1.9.4",
42626
+ "@semantic-release/changelog": "^6.0.3",
42627
+ "@semantic-release/git": "^10.0.1",
42628
+ "@types/bun": "latest",
42629
+ "@types/cli-progress": "^3.11.6",
42630
+ "@types/diff": "^8.0.0",
42631
+ "@types/fs-extra": "^11.0.4",
42632
+ "@types/node": "^22.10.1",
42633
+ "@types/proper-lockfile": "^4.1.4",
42634
+ "@types/semver": "^7.7.1",
42635
+ "@types/tar": "^6.1.13",
42636
+ "@types/tmp": "^0.2.6",
42637
+ "semantic-release": "^24.2.0",
42638
+ typescript: "^5.7.2"
42639
+ }
42640
+ };
42641
+
42642
+ // src/commands/update-cli.ts
42643
+ var execAsync7 = promisify7(exec7);
42644
+
42645
+ class CliUpdateError extends ClaudeKitError {
42646
+ constructor(message) {
42647
+ super(message, "CLI_UPDATE_ERROR");
42648
+ this.name = "CliUpdateError";
42649
+ }
42533
42650
  }
42534
- function normalizeVersion(version) {
42535
- return version.replace(/^v/, "");
42651
+ var PACKAGE_NAME = "claudekit-cli";
42652
+ function buildInitCommand(isGlobal, kit, beta) {
42653
+ const parts = ["ck init"];
42654
+ if (isGlobal)
42655
+ parts.push("-g");
42656
+ if (kit)
42657
+ parts.push(`--kit ${kit}`);
42658
+ parts.push("--yes --install-skills");
42659
+ if (beta)
42660
+ parts.push("--beta");
42661
+ return parts.join(" ");
42536
42662
  }
42537
- function isNewerVersion(currentVersion, latestVersion) {
42538
- try {
42539
- const current = normalizeVersion(currentVersion);
42540
- const latest = normalizeVersion(latestVersion);
42541
- return import_compare_versions3.compareVersions(latest, current) > 0;
42542
- } catch {
42543
- return false;
42663
+ function selectKitForUpdate(params) {
42664
+ const { hasLocal, hasGlobal, localKits, globalKits } = params;
42665
+ const hasLocalKit = localKits.length > 0 || hasLocal;
42666
+ const hasGlobalKit = globalKits.length > 0 || hasGlobal;
42667
+ if (!hasLocalKit && !hasGlobalKit) {
42668
+ return null;
42544
42669
  }
42545
- }
42546
- // src/domains/versioning/checking/kit-version-checker.ts
42547
- init_logger();
42548
- init_types2();
42549
-
42550
- // src/domains/versioning/version-cache.ts
42551
- init_logger();
42552
- import { existsSync as existsSync19 } from "node:fs";
42553
- import { mkdir as mkdir22, readFile as readFile25, writeFile as writeFile22 } from "node:fs/promises";
42554
- import { join as join75 } from "node:path";
42555
- class VersionCacheManager {
42556
- static CACHE_FILENAME = "version-check.json";
42557
- static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
42558
- static getCacheFile() {
42559
- const cacheDir = PathResolver.getCacheDir(false);
42560
- return join75(cacheDir, VersionCacheManager.CACHE_FILENAME);
42670
+ if (hasGlobalKit && !hasLocalKit) {
42671
+ const kit2 = globalKits[0] || localKits[0];
42672
+ return {
42673
+ isGlobal: true,
42674
+ kit: kit2,
42675
+ promptMessage: `Update global ClaudeKit content${kit2 ? ` (${kit2})` : ""}?`
42676
+ };
42561
42677
  }
42562
- static async load() {
42563
- const cacheFile = VersionCacheManager.getCacheFile();
42564
- try {
42565
- if (!existsSync19(cacheFile)) {
42566
- logger.debug("Version check cache not found");
42567
- return null;
42568
- }
42569
- const content = await readFile25(cacheFile, "utf-8");
42570
- const cache2 = JSON.parse(content);
42571
- if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
42572
- logger.debug("Invalid cache structure, ignoring");
42573
- return null;
42574
- }
42575
- logger.debug(`Version check cache loaded: ${JSON.stringify(cache2)}`);
42576
- return cache2;
42577
- } catch (error) {
42578
- logger.debug(`Failed to load version check cache: ${error}`);
42678
+ if (hasLocalKit && !hasGlobalKit) {
42679
+ const kit2 = localKits[0] || globalKits[0];
42680
+ return {
42681
+ isGlobal: false,
42682
+ kit: kit2,
42683
+ promptMessage: `Update local project ClaudeKit content${kit2 ? ` (${kit2})` : ""}?`
42684
+ };
42685
+ }
42686
+ const kit = globalKits[0] || localKits[0];
42687
+ return {
42688
+ isGlobal: true,
42689
+ kit,
42690
+ promptMessage: `Update global ClaudeKit content${kit ? ` (${kit})` : ""}?`
42691
+ };
42692
+ }
42693
+ async function readMetadataFile(claudeDir) {
42694
+ const metadataPath = join75(claudeDir, "metadata.json");
42695
+ try {
42696
+ if (!await import_fs_extra36.pathExists(metadataPath)) {
42579
42697
  return null;
42580
42698
  }
42581
- }
42582
- static async save(cache2) {
42583
- const cacheFile = VersionCacheManager.getCacheFile();
42584
- const cacheDir = PathResolver.getCacheDir(false);
42585
- try {
42586
- if (!existsSync19(cacheDir)) {
42587
- await mkdir22(cacheDir, { recursive: true, mode: 448 });
42588
- }
42589
- await writeFile22(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
42590
- logger.debug(`Version check cache saved to ${cacheFile}`);
42591
- } catch (error) {
42592
- logger.debug(`Failed to save version check cache: ${error}`);
42699
+ const content = await import_fs_extra36.readFile(metadataPath, "utf-8");
42700
+ const parsed = JSON.parse(content);
42701
+ const validated = MetadataSchema.safeParse(parsed);
42702
+ if (!validated.success) {
42703
+ logger.verbose(`Invalid metadata format: ${validated.error.message}`);
42704
+ return null;
42593
42705
  }
42706
+ return validated.data;
42707
+ } catch (error) {
42708
+ logger.verbose(`Failed to read metadata: ${error instanceof Error ? error.message : "unknown"}`);
42709
+ return null;
42594
42710
  }
42595
- static isCacheValid(cache2) {
42596
- if (!cache2)
42597
- return false;
42598
- const now = Date.now();
42599
- const age = now - cache2.lastCheck;
42600
- const isValid2 = age < VersionCacheManager.CACHE_TTL_MS;
42601
- const ageDays = (age / 1000 / 60 / 60 / 24).toFixed(1);
42602
- logger.debug(`Cache validity check: age=${ageDays} days, valid=${isValid2}`);
42603
- return isValid2;
42604
- }
42605
- static async clear() {
42606
- const cacheFile = VersionCacheManager.getCacheFile();
42711
+ }
42712
+ async function promptKitUpdate(beta) {
42713
+ try {
42714
+ const setup = await getClaudeKitSetup();
42715
+ const hasLocal = !!setup.project.metadata;
42716
+ const hasGlobal = !!setup.global.metadata;
42717
+ const localMetadata = hasLocal ? await readMetadataFile(setup.project.path) : null;
42718
+ const globalMetadata = hasGlobal ? await readMetadataFile(setup.global.path) : null;
42719
+ const localKits = localMetadata ? getInstalledKits(localMetadata) : [];
42720
+ const globalKits = globalMetadata ? getInstalledKits(globalMetadata) : [];
42721
+ const selection = selectKitForUpdate({ hasLocal, hasGlobal, localKits, globalKits });
42722
+ if (!selection) {
42723
+ logger.verbose("No ClaudeKit installations detected, skipping kit update prompt");
42724
+ return;
42725
+ }
42726
+ const initCmd = buildInitCommand(selection.isGlobal, selection.kit, beta);
42727
+ const promptMessage = selection.promptMessage;
42728
+ logger.info("");
42729
+ const shouldUpdate = await se({
42730
+ message: promptMessage
42731
+ });
42732
+ if (lD(shouldUpdate) || !shouldUpdate) {
42733
+ log.info("Skipped kit content update");
42734
+ return;
42735
+ }
42736
+ logger.info(`Running: ${initCmd}`);
42737
+ const s = de();
42738
+ s.start("Updating ClaudeKit content...");
42607
42739
  try {
42608
- if (existsSync19(cacheFile)) {
42609
- const fs14 = await import("node:fs/promises");
42610
- await fs14.unlink(cacheFile);
42611
- logger.debug("Version check cache cleared");
42612
- }
42740
+ await execAsync7(initCmd, {
42741
+ timeout: 300000
42742
+ });
42743
+ s.stop("Kit content updated");
42613
42744
  } catch (error) {
42614
- logger.debug(`Failed to clear version check cache: ${error}`);
42745
+ s.stop("Kit update finished");
42746
+ const errorMsg = error instanceof Error ? error.message : "unknown";
42747
+ if (errorMsg.includes("exit code") && !errorMsg.includes("exit code 0")) {
42748
+ logger.warning("Kit content update may have encountered issues");
42749
+ logger.verbose(`Error: ${errorMsg}`);
42750
+ } else {
42751
+ logger.verbose(`Init command completed: ${errorMsg}`);
42752
+ }
42615
42753
  }
42616
- }
42617
- }
42618
-
42619
- // src/domains/versioning/checking/kit-version-checker.ts
42620
- async function fetchLatestRelease(currentVersion) {
42621
- try {
42622
- const githubClient = new GitHubClient;
42623
- const kit = AVAILABLE_KITS.engineer;
42624
- const timeoutPromise = new Promise((_3, reject) => setTimeout(() => reject(new Error("Timeout")), 5000));
42625
- const releasePromise = githubClient.getLatestRelease(kit);
42626
- const release = await Promise.race([releasePromise, timeoutPromise]);
42627
- const latestVersion = release.tag_name;
42628
- const updateAvailable = isNewerVersion(currentVersion, latestVersion);
42629
- const releaseUrl = `https://github.com/${kit.owner}/${kit.repo}/releases/tag/${latestVersion}`;
42630
- logger.debug(`Fetched latest release: current=${currentVersion}, latest=${latestVersion}, updateAvailable=${updateAvailable}`);
42631
- return {
42632
- currentVersion,
42633
- latestVersion,
42634
- updateAvailable,
42635
- releaseUrl
42636
- };
42637
42754
  } catch (error) {
42638
- logger.debug(`Failed to fetch latest release: ${error}`);
42639
- return null;
42640
- }
42641
- }
42642
-
42643
- class VersionChecker {
42644
- static async check(currentVersion) {
42645
- if (isUpdateCheckDisabled()) {
42646
- logger.debug("Update check disabled by environment");
42647
- return null;
42648
- }
42649
- const cache2 = await VersionCacheManager.load();
42650
- if (cache2 && VersionCacheManager.isCacheValid(cache2) && cache2.currentVersion === currentVersion) {
42651
- logger.debug("Using cached version check result");
42652
- return {
42653
- currentVersion: cache2.currentVersion,
42654
- latestVersion: cache2.latestVersion,
42655
- updateAvailable: cache2.updateAvailable,
42656
- releaseUrl: cache2.latestUrl
42657
- };
42658
- }
42659
- logger.debug("Cache expired or invalid, fetching latest release");
42660
- const result = await fetchLatestRelease(currentVersion);
42661
- if (result) {
42662
- await VersionCacheManager.save({
42663
- lastCheck: Date.now(),
42664
- currentVersion: result.currentVersion,
42665
- latestVersion: result.latestVersion,
42666
- latestUrl: result.releaseUrl,
42667
- updateAvailable: result.updateAvailable
42668
- });
42669
- }
42670
- return result;
42671
- }
42672
- }
42673
- // src/domains/versioning/checking/cli-version-checker.ts
42674
- init_logger();
42675
- var import_compare_versions4 = __toESM(require_umd(), 1);
42676
- var PACKAGE_NAME = "claudekit-cli";
42677
-
42678
- class CliVersionChecker {
42679
- static async check(currentVersion) {
42680
- if (isUpdateCheckDisabled()) {
42681
- logger.debug("CLI update check disabled by environment");
42682
- return null;
42683
- }
42684
- try {
42685
- const latestVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME);
42686
- if (!latestVersion) {
42687
- logger.debug("Failed to fetch latest CLI version from npm");
42688
- return null;
42689
- }
42690
- const current = normalizeVersion(currentVersion);
42691
- const latest = normalizeVersion(latestVersion);
42692
- const updateAvailable = import_compare_versions4.compareVersions(latest, current) > 0;
42693
- logger.debug(`CLI version check: current=${current}, latest=${latest}, updateAvailable=${updateAvailable}`);
42694
- return {
42695
- currentVersion: current,
42696
- latestVersion: latest,
42697
- updateAvailable,
42698
- releaseUrl: `https://www.npmjs.com/package/${PACKAGE_NAME}`
42699
- };
42700
- } catch (error) {
42701
- logger.debug(`CLI version check failed: ${error}`);
42702
- return null;
42703
- }
42704
- }
42705
- }
42706
- // src/domains/versioning/checking/notification-display.ts
42707
- var import_picocolors23 = __toESM(require_picocolors(), 1);
42708
- function createNotificationBox2(borderColor, boxWidth) {
42709
- const contentWidth = boxWidth - 2;
42710
- const topBorder = borderColor(`╭${"─".repeat(contentWidth)}╮`);
42711
- const bottomBorder = borderColor(`╰${"─".repeat(contentWidth)}╯`);
42712
- const emptyLine = borderColor("│") + " ".repeat(contentWidth) + borderColor("│");
42713
- const padLine = (text, visibleLen) => {
42714
- const len = visibleLen ?? text.length;
42715
- const displayText = len > contentWidth ? `${text.slice(0, contentWidth - 3)}...` : text;
42716
- const actualLen = visibleLen ?? displayText.length;
42717
- const totalPadding = contentWidth - actualLen;
42718
- const leftPadding = Math.max(0, Math.floor(totalPadding / 2));
42719
- const rightPadding = Math.max(0, totalPadding - leftPadding);
42720
- return borderColor("│") + " ".repeat(leftPadding) + displayText + " ".repeat(rightPadding) + borderColor("│");
42721
- };
42722
- return { topBorder, bottomBorder, emptyLine, padLine };
42723
- }
42724
- function displayKitNotification(result, options = {}) {
42725
- if (!result.updateAvailable)
42726
- return;
42727
- const { currentVersion, latestVersion } = result;
42728
- const { isGlobal = false } = options;
42729
- const displayCurrent = normalizeVersion(currentVersion);
42730
- const displayLatest = normalizeVersion(latestVersion);
42731
- const boxWidth = 52;
42732
- const { topBorder, bottomBorder, emptyLine, padLine } = createNotificationBox2(import_picocolors23.default.cyan, boxWidth);
42733
- const headerText = import_picocolors23.default.bold(import_picocolors23.default.yellow("⬆ Kit Update Available"));
42734
- const headerLen = "⬆ Kit Update Available".length;
42735
- const versionText = `${import_picocolors23.default.dim(displayCurrent)} ${import_picocolors23.default.white("→")} ${import_picocolors23.default.green(import_picocolors23.default.bold(displayLatest))}`;
42736
- const versionLen = displayCurrent.length + 3 + displayLatest.length;
42737
- const updateCmd = isGlobal ? "ck init -g" : "ck init";
42738
- const commandText = `Run: ${import_picocolors23.default.cyan(import_picocolors23.default.bold(updateCmd))}`;
42739
- const commandLen = `Run: ${updateCmd}`.length;
42740
- console.log("");
42741
- console.log(topBorder);
42742
- console.log(emptyLine);
42743
- console.log(padLine(headerText, headerLen));
42744
- console.log(padLine(versionText, versionLen));
42745
- console.log(emptyLine);
42746
- console.log(padLine(commandText, commandLen));
42747
- console.log(emptyLine);
42748
- console.log(bottomBorder);
42749
- console.log("");
42750
- }
42751
- function displayCliNotification(result) {
42752
- if (!result.updateAvailable)
42753
- return;
42754
- const { currentVersion, latestVersion } = result;
42755
- const boxWidth = 52;
42756
- const { topBorder, bottomBorder, emptyLine, padLine } = createNotificationBox2(import_picocolors23.default.magenta, boxWidth);
42757
- const headerText = import_picocolors23.default.bold(import_picocolors23.default.yellow("⬆ CLI Update Available"));
42758
- const headerLen = "⬆ CLI Update Available".length;
42759
- const versionText = `${import_picocolors23.default.dim(currentVersion)} ${import_picocolors23.default.white("→")} ${import_picocolors23.default.green(import_picocolors23.default.bold(latestVersion))}`;
42760
- const versionLen = currentVersion.length + 3 + latestVersion.length;
42761
- const commandText = `Run: ${import_picocolors23.default.magenta(import_picocolors23.default.bold("ck update"))}`;
42762
- const commandLen = "Run: ck update".length;
42763
- console.log("");
42764
- console.log(topBorder);
42765
- console.log(emptyLine);
42766
- console.log(padLine(headerText, headerLen));
42767
- console.log(padLine(versionText, versionLen));
42768
- console.log(emptyLine);
42769
- console.log(padLine(commandText, commandLen));
42770
- console.log(emptyLine);
42771
- console.log(bottomBorder);
42772
- console.log("");
42773
- }
42774
- // src/domains/versioning/version-checker.ts
42775
- class VersionChecker2 {
42776
- static async check(currentVersion) {
42777
- return VersionChecker.check(currentVersion);
42778
- }
42779
- static displayNotification(result, options = {}) {
42780
- displayKitNotification(result, options);
42781
- }
42782
- }
42783
-
42784
- class CliVersionChecker2 {
42785
- static async check(currentVersion) {
42786
- return CliVersionChecker.check(currentVersion);
42787
- }
42788
- static displayNotification(result) {
42789
- displayCliNotification(result);
42790
- }
42791
- }
42792
-
42793
- // src/commands/update-cli.ts
42794
- init_logger();
42795
- init_types2();
42796
- init_types2();
42797
- var import_compare_versions5 = __toESM(require_umd(), 1);
42798
- var import_fs_extra36 = __toESM(require_lib(), 1);
42799
- var import_picocolors24 = __toESM(require_picocolors(), 1);
42800
- // package.json
42801
- var package_default = {
42802
- name: "claudekit-cli",
42803
- version: "3.24.1",
42804
- description: "CLI tool for bootstrapping and updating ClaudeKit projects",
42805
- type: "module",
42806
- repository: {
42807
- type: "git",
42808
- url: "git+https://github.com/mrgoonie/claudekit-cli.git"
42809
- },
42810
- publishConfig: {
42811
- access: "public",
42812
- registry: "https://registry.npmjs.org"
42813
- },
42814
- bin: {
42815
- ck: "bin/ck.js"
42816
- },
42817
- files: [
42818
- "bin/ck.js",
42819
- "dist/index.js"
42820
- ],
42821
- scripts: {
42822
- dev: "bun run src/index.ts",
42823
- build: "bun build src/index.ts --outdir dist --target node --external @octokit/rest",
42824
- compile: "bun build src/index.ts --compile --outfile ck",
42825
- "compile:binary": "bun build src/index.ts --compile --outfile bin/ck",
42826
- "compile:binaries": "node scripts/build-all-binaries.js",
42827
- "check-version-sync": "node scripts/check-binary-version-sync.js",
42828
- "build:platform-binaries": "bun run scripts/build-platform-binaries.js",
42829
- test: "bun test",
42830
- "test:watch": "bun test --watch",
42831
- "test:quick": "./scripts/dev-quick-start.sh test",
42832
- lint: "biome check .",
42833
- "lint:fix": "biome check --fix .",
42834
- "lint:fix-unsafe": "biome check --fix --unsafe .",
42835
- format: "biome format --write .",
42836
- typecheck: "tsc --noEmit",
42837
- "dev:quick": "./scripts/dev-quick-start.sh",
42838
- "dev:all": "./scripts/dev-quick-start.sh all",
42839
- metrics: "bun run scripts/workflow-metrics.ts",
42840
- "install:hooks": "./.githooks/install.sh"
42841
- },
42842
- keywords: [
42843
- "cli",
42844
- "claudekit",
42845
- "boilerplate",
42846
- "bootstrap",
42847
- "template"
42848
- ],
42849
- author: "ClaudeKit",
42850
- license: "MIT",
42851
- engines: {
42852
- bun: ">=1.3.2",
42853
- node: ">=18.0.0"
42854
- },
42855
- dependencies: {
42856
- "@clack/prompts": "^0.7.0",
42857
- "@octokit/rest": "^22.0.0",
42858
- cac: "^6.7.14",
42859
- "cli-progress": "^3.12.0",
42860
- "compare-versions": "^6.1.1",
42861
- diff: "^8.0.2",
42862
- "extract-zip": "^2.0.1",
42863
- "fs-extra": "^11.2.0",
42864
- ignore: "^5.3.2",
42865
- minimatch: "^10.1.1",
42866
- ora: "^8.0.0",
42867
- "p-limit": "^7.2.0",
42868
- picocolors: "^1.1.1",
42869
- "proper-lockfile": "^4.1.2",
42870
- semver: "^7.7.3",
42871
- tar: "^7.4.3",
42872
- tmp: "^0.2.3",
42873
- zod: "^3.23.8"
42874
- },
42875
- devDependencies: {
42876
- "@biomejs/biome": "^1.9.4",
42877
- "@semantic-release/changelog": "^6.0.3",
42878
- "@semantic-release/git": "^10.0.1",
42879
- "@types/bun": "latest",
42880
- "@types/cli-progress": "^3.11.6",
42881
- "@types/diff": "^8.0.0",
42882
- "@types/fs-extra": "^11.0.4",
42883
- "@types/node": "^22.10.1",
42884
- "@types/proper-lockfile": "^4.1.4",
42885
- "@types/semver": "^7.7.1",
42886
- "@types/tar": "^6.1.13",
42887
- "@types/tmp": "^0.2.6",
42888
- "semantic-release": "^24.2.0",
42889
- typescript: "^5.7.2"
42890
- }
42891
- };
42892
-
42893
- // src/commands/update-cli.ts
42894
- var execAsync7 = promisify7(exec7);
42895
-
42896
- class CliUpdateError extends ClaudeKitError {
42897
- constructor(message) {
42898
- super(message, "CLI_UPDATE_ERROR");
42899
- this.name = "CliUpdateError";
42900
- }
42901
- }
42902
- var PACKAGE_NAME2 = "claudekit-cli";
42903
- var KIT_UPDATE_REMINDER_HEADER = "Note: 'ck update' only updates the CLI tool itself.";
42904
- function buildInitCommand(isGlobal, kit, beta) {
42905
- const parts = ["ck init"];
42906
- if (isGlobal)
42907
- parts.push("-g");
42908
- if (kit)
42909
- parts.push(`--kit ${kit}`);
42910
- parts.push("--yes --install-skills");
42911
- if (beta)
42912
- parts.push("--beta");
42913
- return parts.join(" ");
42914
- }
42915
- async function readMetadataFile(claudeDir) {
42916
- const metadataPath = join76(claudeDir, "metadata.json");
42917
- try {
42918
- if (!await import_fs_extra36.pathExists(metadataPath)) {
42919
- return null;
42920
- }
42921
- const content = await import_fs_extra36.readFile(metadataPath, "utf-8");
42922
- return JSON.parse(content);
42923
- } catch {
42924
- return null;
42925
- }
42926
- }
42927
- async function displayKitUpdateReminder(beta) {
42928
- try {
42929
- const setup = await getClaudeKitSetup();
42930
- const hasLocal = !!setup.project.metadata;
42931
- const hasGlobal = !!setup.global.metadata;
42932
- const localMetadata = hasLocal ? await readMetadataFile(setup.project.path) : null;
42933
- const globalMetadata = hasGlobal ? await readMetadataFile(setup.global.path) : null;
42934
- const localKits = localMetadata ? getInstalledKits(localMetadata) : [];
42935
- const globalKits = globalMetadata ? getInstalledKits(globalMetadata) : [];
42936
- const versionsToCheck = new Set;
42937
- if (localMetadata) {
42938
- for (const kit of localKits) {
42939
- const version = localMetadata.kits?.[kit]?.version || localMetadata.version;
42940
- if (version)
42941
- versionsToCheck.add(version);
42942
- }
42943
- }
42944
- if (globalMetadata) {
42945
- for (const kit of globalKits) {
42946
- const version = globalMetadata.kits?.[kit]?.version || globalMetadata.version;
42947
- if (version)
42948
- versionsToCheck.add(version);
42949
- }
42950
- }
42951
- const versionCheckResults = new Map;
42952
- if (versionsToCheck.size > 0) {
42953
- const checkPromises = [...versionsToCheck].map(async (version) => {
42954
- const result = await VersionChecker2.check(version).catch(() => null);
42955
- return { version, result };
42956
- });
42957
- const results = await Promise.all(checkPromises);
42958
- for (const { version, result } of results) {
42959
- versionCheckResults.set(version, result);
42960
- }
42961
- }
42962
- const commands = [];
42963
- if (localKits.length > 0) {
42964
- for (const kit of localKits) {
42965
- const cmd = buildInitCommand(false, kit, beta);
42966
- const version = localMetadata?.kits?.[kit]?.version || localMetadata?.version;
42967
- commands.push({
42968
- cmd,
42969
- desc: `Update local project (${kit}${version ? `@${version}` : ""})`,
42970
- version
42971
- });
42972
- }
42973
- } else if (hasLocal) {
42974
- commands.push({ cmd: beta ? "ck init --beta" : "ck init", desc: "Update local project" });
42975
- } else {
42976
- commands.push({
42977
- cmd: beta ? "ck init --beta" : "ck init",
42978
- desc: "Initialize in current project"
42979
- });
42980
- }
42981
- if (globalKits.length > 0) {
42982
- for (const kit of globalKits) {
42983
- const cmd = buildInitCommand(true, kit, beta);
42984
- const version = globalMetadata?.kits?.[kit]?.version || globalMetadata?.version;
42985
- commands.push({
42986
- cmd,
42987
- desc: `Update global ~/.claude (${kit}${version ? `@${version}` : ""})`,
42988
- version
42989
- });
42990
- }
42991
- } else if (hasGlobal) {
42992
- commands.push({
42993
- cmd: beta ? "ck init -g --beta" : "ck init -g",
42994
- desc: "Update global ~/.claude"
42995
- });
42996
- } else {
42997
- commands.push({
42998
- cmd: beta ? "ck init -g --beta" : "ck init -g",
42999
- desc: "Initialize global ~/.claude"
43000
- });
43001
- }
43002
- const maxCmdLen = Math.max(...commands.map((c2) => c2.cmd.length));
43003
- const pad = (cmd) => cmd.padEnd(maxCmdLen);
43004
- const lines = [];
43005
- lines.push(import_picocolors24.default.yellow(KIT_UPDATE_REMINDER_HEADER));
43006
- lines.push("");
43007
- lines.push("To update your ClaudeKit content (skills, commands, workflows):");
43008
- for (const { cmd, desc: desc2, version } of commands) {
43009
- lines.push(` ${import_picocolors24.default.cyan(pad(cmd))} ${desc2}`);
43010
- if (version) {
43011
- const versionCheck = versionCheckResults.get(version);
43012
- if (versionCheck?.updateAvailable) {
43013
- const indent = " ".repeat(maxCmdLen + 4);
43014
- lines.push(`${indent}${import_picocolors24.default.green(`→ ${versionCheck.latestVersion} available!`)}`);
43015
- }
43016
- }
43017
- }
43018
- logger.info("");
43019
- log.info(lines.join(`
43020
- `));
43021
- } catch (error) {
43022
- logger.verbose(`Failed to display kit update reminder: ${error instanceof Error ? error.message : "unknown error"}`);
42755
+ logger.verbose(`Failed to prompt for kit update: ${error instanceof Error ? error.message : "unknown error"}`);
43023
42756
  }
43024
42757
  }
43025
42758
  async function updateCliCommand(options) {
@@ -43037,7 +42770,7 @@ async function updateCliCommand(options) {
43037
42770
  s.start("Checking for updates...");
43038
42771
  let targetVersion = null;
43039
42772
  if (opts.release && opts.release !== "latest") {
43040
- const exists = await NpmRegistryClient.versionExists(PACKAGE_NAME2, opts.release, opts.registry);
42773
+ const exists = await NpmRegistryClient.versionExists(PACKAGE_NAME, opts.release, opts.registry);
43041
42774
  if (!exists) {
43042
42775
  s.stop("Version not found");
43043
42776
  throw new CliUpdateError(`Version ${opts.release} does not exist on npm registry. Run 'ck versions' to see available versions.`);
@@ -43045,25 +42778,25 @@ async function updateCliCommand(options) {
43045
42778
  targetVersion = opts.release;
43046
42779
  s.stop(`Target version: ${targetVersion}`);
43047
42780
  } else if (opts.beta) {
43048
- targetVersion = await NpmRegistryClient.getBetaVersion(PACKAGE_NAME2, opts.registry);
42781
+ targetVersion = await NpmRegistryClient.getBetaVersion(PACKAGE_NAME, opts.registry);
43049
42782
  if (!targetVersion) {
43050
42783
  s.stop("No beta version available");
43051
42784
  logger.warning("No beta version found. Using latest stable version instead.");
43052
- targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME2, opts.registry);
42785
+ targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME, opts.registry);
43053
42786
  } else {
43054
42787
  s.stop(`Latest beta version: ${targetVersion}`);
43055
42788
  }
43056
42789
  } else {
43057
- targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME2, opts.registry);
42790
+ targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME, opts.registry);
43058
42791
  s.stop(`Latest version: ${targetVersion || "unknown"}`);
43059
42792
  }
43060
42793
  if (!targetVersion) {
43061
- throw new CliUpdateError(`Failed to fetch version information from npm registry. Check your internet connection and try again. Manual update: ${PackageManagerDetector.getUpdateCommand(pm, PACKAGE_NAME2)}`);
42794
+ throw new CliUpdateError(`Failed to fetch version information from npm registry. Check your internet connection and try again. Manual update: ${PackageManagerDetector.getUpdateCommand(pm, PACKAGE_NAME)}`);
43062
42795
  }
43063
- const comparison = import_compare_versions5.compareVersions(currentVersion, targetVersion);
42796
+ const comparison = import_compare_versions3.compareVersions(currentVersion, targetVersion);
43064
42797
  if (comparison === 0) {
43065
42798
  outro(`[+] Already on the latest CLI version (${currentVersion})`);
43066
- await displayKitUpdateReminder(opts.beta);
42799
+ await promptKitUpdate(opts.beta);
43067
42800
  return;
43068
42801
  }
43069
42802
  if (comparison > 0 && !opts.release) {
@@ -43077,7 +42810,7 @@ async function updateCliCommand(options) {
43077
42810
  note(`CLI update available: ${currentVersion} -> ${targetVersion}
43078
42811
 
43079
42812
  Run 'ck update' to install`, "Update Check");
43080
- await displayKitUpdateReminder(opts.beta);
42813
+ await promptKitUpdate(opts.beta);
43081
42814
  outro("Check complete");
43082
42815
  return;
43083
42816
  }
@@ -43090,7 +42823,7 @@ Run 'ck update' to install`, "Update Check");
43090
42823
  return;
43091
42824
  }
43092
42825
  }
43093
- const updateCmd = PackageManagerDetector.getUpdateCommand(pm, PACKAGE_NAME2, targetVersion);
42826
+ const updateCmd = PackageManagerDetector.getUpdateCommand(pm, PACKAGE_NAME, targetVersion);
43094
42827
  logger.info(`Running: ${updateCmd}`);
43095
42828
  s.start("Updating CLI...");
43096
42829
  try {
@@ -43117,11 +42850,11 @@ Manual update: ${updateCmd}`);
43117
42850
  const newVersion = newVersionMatch ? newVersionMatch[1] : targetVersion;
43118
42851
  s.stop(`Installed version: ${newVersion}`);
43119
42852
  outro(`[+] Successfully updated ClaudeKit CLI to ${newVersion}`);
43120
- await displayKitUpdateReminder(opts.beta);
42853
+ await promptKitUpdate(opts.beta);
43121
42854
  } catch {
43122
42855
  s.stop("Verification completed");
43123
42856
  outro(`[+] Update completed. Please restart your terminal to use CLI ${targetVersion}`);
43124
- await displayKitUpdateReminder(opts.beta);
42857
+ await promptKitUpdate(opts.beta);
43125
42858
  }
43126
42859
  } catch (error) {
43127
42860
  if (error instanceof CliUpdateError) {
@@ -43137,7 +42870,7 @@ Manual update: ${updateCmd}`);
43137
42870
  // src/commands/version.ts
43138
42871
  init_logger();
43139
42872
  init_types2();
43140
- var import_picocolors25 = __toESM(require_picocolors(), 1);
42873
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
43141
42874
  function formatRelativeTime(dateString) {
43142
42875
  if (!dateString)
43143
42876
  return "Unknown";
@@ -43159,30 +42892,30 @@ function formatRelativeTime(dateString) {
43159
42892
  }
43160
42893
  function displayKitReleases(kitName, releases) {
43161
42894
  console.log(`
43162
- ${import_picocolors25.default.bold(import_picocolors25.default.cyan(kitName))} - Available Versions:
42895
+ ${import_picocolors23.default.bold(import_picocolors23.default.cyan(kitName))} - Available Versions:
43163
42896
  `);
43164
42897
  if (releases.length === 0) {
43165
- console.log(import_picocolors25.default.dim(" No releases found"));
42898
+ console.log(import_picocolors23.default.dim(" No releases found"));
43166
42899
  return;
43167
42900
  }
43168
42901
  for (const release of releases) {
43169
- const version = import_picocolors25.default.green(release.tag_name);
42902
+ const version = import_picocolors23.default.green(release.tag_name);
43170
42903
  const name2 = release.name || "No title";
43171
42904
  const publishedAt = formatRelativeTime(release.published_at);
43172
42905
  const assetCount = release.assets.length;
43173
42906
  const badges = [];
43174
42907
  if (release.prerelease)
43175
- badges.push(import_picocolors25.default.yellow("[prerelease]"));
42908
+ badges.push(import_picocolors23.default.yellow("[prerelease]"));
43176
42909
  if (release.draft)
43177
- badges.push(import_picocolors25.default.gray("[draft]"));
42910
+ badges.push(import_picocolors23.default.gray("[draft]"));
43178
42911
  const badgeStr = badges.length > 0 ? ` ${badges.join(" ")}` : "";
43179
42912
  const versionPart = version.padEnd(20);
43180
42913
  const namePart = name2.length > 40 ? `${name2.slice(0, 37)}...` : name2.padEnd(40);
43181
- const timePart = import_picocolors25.default.dim(publishedAt.padEnd(20));
43182
- const assetPart = import_picocolors25.default.dim(`(${assetCount} ${assetCount === 1 ? "asset" : "assets"})`);
42914
+ const timePart = import_picocolors23.default.dim(publishedAt.padEnd(20));
42915
+ const assetPart = import_picocolors23.default.dim(`(${assetCount} ${assetCount === 1 ? "asset" : "assets"})`);
43183
42916
  console.log(` ${versionPart} ${namePart} ${timePart} ${assetPart}${badgeStr}`);
43184
42917
  }
43185
- console.log(import_picocolors25.default.dim(`
42918
+ console.log(import_picocolors23.default.dim(`
43186
42919
  Showing ${releases.length} ${releases.length === 1 ? "release" : "releases"}`));
43187
42920
  }
43188
42921
  async function versionCommand(options) {
@@ -43217,8 +42950,8 @@ async function versionCommand(options) {
43217
42950
  for (const result of results) {
43218
42951
  if (result.error) {
43219
42952
  console.log(`
43220
- ${import_picocolors25.default.bold(import_picocolors25.default.cyan(result.kitConfig.name))} - ${import_picocolors25.default.red("Error")}`);
43221
- console.log(import_picocolors25.default.dim(` ${result.error}`));
42953
+ ${import_picocolors23.default.bold(import_picocolors23.default.cyan(result.kitConfig.name))} - ${import_picocolors23.default.red("Error")}`);
42954
+ console.log(import_picocolors23.default.dim(` ${result.error}`));
43222
42955
  } else {
43223
42956
  displayKitReleases(result.kitConfig.name, result.releases);
43224
42957
  }
@@ -43289,6 +43022,272 @@ function registerCommands(cli) {
43289
43022
  // src/cli/version-display.ts
43290
43023
  import { existsSync as existsSync20, readFileSync as readFileSync6 } from "node:fs";
43291
43024
  import { join as join77 } from "node:path";
43025
+
43026
+ // src/domains/versioning/checking/version-utils.ts
43027
+ var import_compare_versions4 = __toESM(require_umd(), 1);
43028
+ function isUpdateCheckDisabled() {
43029
+ return process.env.NO_UPDATE_NOTIFIER === "1" || process.env.NO_UPDATE_NOTIFIER === "true" || !process.stdout.isTTY;
43030
+ }
43031
+ function normalizeVersion(version) {
43032
+ return version.replace(/^v/, "");
43033
+ }
43034
+ function isNewerVersion(currentVersion, latestVersion) {
43035
+ try {
43036
+ const current = normalizeVersion(currentVersion);
43037
+ const latest = normalizeVersion(latestVersion);
43038
+ return import_compare_versions4.compareVersions(latest, current) > 0;
43039
+ } catch {
43040
+ return false;
43041
+ }
43042
+ }
43043
+ // src/domains/versioning/checking/kit-version-checker.ts
43044
+ init_logger();
43045
+ init_types2();
43046
+
43047
+ // src/domains/versioning/version-cache.ts
43048
+ init_logger();
43049
+ import { existsSync as existsSync19 } from "node:fs";
43050
+ import { mkdir as mkdir22, readFile as readFile26, writeFile as writeFile22 } from "node:fs/promises";
43051
+ import { join as join76 } from "node:path";
43052
+ class VersionCacheManager {
43053
+ static CACHE_FILENAME = "version-check.json";
43054
+ static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
43055
+ static getCacheFile() {
43056
+ const cacheDir = PathResolver.getCacheDir(false);
43057
+ return join76(cacheDir, VersionCacheManager.CACHE_FILENAME);
43058
+ }
43059
+ static async load() {
43060
+ const cacheFile = VersionCacheManager.getCacheFile();
43061
+ try {
43062
+ if (!existsSync19(cacheFile)) {
43063
+ logger.debug("Version check cache not found");
43064
+ return null;
43065
+ }
43066
+ const content = await readFile26(cacheFile, "utf-8");
43067
+ const cache2 = JSON.parse(content);
43068
+ if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
43069
+ logger.debug("Invalid cache structure, ignoring");
43070
+ return null;
43071
+ }
43072
+ logger.debug(`Version check cache loaded: ${JSON.stringify(cache2)}`);
43073
+ return cache2;
43074
+ } catch (error) {
43075
+ logger.debug(`Failed to load version check cache: ${error}`);
43076
+ return null;
43077
+ }
43078
+ }
43079
+ static async save(cache2) {
43080
+ const cacheFile = VersionCacheManager.getCacheFile();
43081
+ const cacheDir = PathResolver.getCacheDir(false);
43082
+ try {
43083
+ if (!existsSync19(cacheDir)) {
43084
+ await mkdir22(cacheDir, { recursive: true, mode: 448 });
43085
+ }
43086
+ await writeFile22(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
43087
+ logger.debug(`Version check cache saved to ${cacheFile}`);
43088
+ } catch (error) {
43089
+ logger.debug(`Failed to save version check cache: ${error}`);
43090
+ }
43091
+ }
43092
+ static isCacheValid(cache2) {
43093
+ if (!cache2)
43094
+ return false;
43095
+ const now = Date.now();
43096
+ const age = now - cache2.lastCheck;
43097
+ const isValid2 = age < VersionCacheManager.CACHE_TTL_MS;
43098
+ const ageDays = (age / 1000 / 60 / 60 / 24).toFixed(1);
43099
+ logger.debug(`Cache validity check: age=${ageDays} days, valid=${isValid2}`);
43100
+ return isValid2;
43101
+ }
43102
+ static async clear() {
43103
+ const cacheFile = VersionCacheManager.getCacheFile();
43104
+ try {
43105
+ if (existsSync19(cacheFile)) {
43106
+ const fs14 = await import("node:fs/promises");
43107
+ await fs14.unlink(cacheFile);
43108
+ logger.debug("Version check cache cleared");
43109
+ }
43110
+ } catch (error) {
43111
+ logger.debug(`Failed to clear version check cache: ${error}`);
43112
+ }
43113
+ }
43114
+ }
43115
+
43116
+ // src/domains/versioning/checking/kit-version-checker.ts
43117
+ async function fetchLatestRelease(currentVersion) {
43118
+ try {
43119
+ const githubClient = new GitHubClient;
43120
+ const kit = AVAILABLE_KITS.engineer;
43121
+ const timeoutPromise = new Promise((_3, reject) => setTimeout(() => reject(new Error("Timeout")), 5000));
43122
+ const releasePromise = githubClient.getLatestRelease(kit);
43123
+ const release = await Promise.race([releasePromise, timeoutPromise]);
43124
+ const latestVersion = release.tag_name;
43125
+ const updateAvailable = isNewerVersion(currentVersion, latestVersion);
43126
+ const releaseUrl = `https://github.com/${kit.owner}/${kit.repo}/releases/tag/${latestVersion}`;
43127
+ logger.debug(`Fetched latest release: current=${currentVersion}, latest=${latestVersion}, updateAvailable=${updateAvailable}`);
43128
+ return {
43129
+ currentVersion,
43130
+ latestVersion,
43131
+ updateAvailable,
43132
+ releaseUrl
43133
+ };
43134
+ } catch (error) {
43135
+ logger.debug(`Failed to fetch latest release: ${error}`);
43136
+ return null;
43137
+ }
43138
+ }
43139
+
43140
+ class VersionChecker {
43141
+ static async check(currentVersion) {
43142
+ if (isUpdateCheckDisabled()) {
43143
+ logger.debug("Update check disabled by environment");
43144
+ return null;
43145
+ }
43146
+ const cache2 = await VersionCacheManager.load();
43147
+ if (cache2 && VersionCacheManager.isCacheValid(cache2) && cache2.currentVersion === currentVersion) {
43148
+ logger.debug("Using cached version check result");
43149
+ return {
43150
+ currentVersion: cache2.currentVersion,
43151
+ latestVersion: cache2.latestVersion,
43152
+ updateAvailable: cache2.updateAvailable,
43153
+ releaseUrl: cache2.latestUrl
43154
+ };
43155
+ }
43156
+ logger.debug("Cache expired or invalid, fetching latest release");
43157
+ const result = await fetchLatestRelease(currentVersion);
43158
+ if (result) {
43159
+ await VersionCacheManager.save({
43160
+ lastCheck: Date.now(),
43161
+ currentVersion: result.currentVersion,
43162
+ latestVersion: result.latestVersion,
43163
+ latestUrl: result.releaseUrl,
43164
+ updateAvailable: result.updateAvailable
43165
+ });
43166
+ }
43167
+ return result;
43168
+ }
43169
+ }
43170
+ // src/domains/versioning/checking/cli-version-checker.ts
43171
+ init_logger();
43172
+ var import_compare_versions5 = __toESM(require_umd(), 1);
43173
+ var PACKAGE_NAME2 = "claudekit-cli";
43174
+
43175
+ class CliVersionChecker {
43176
+ static async check(currentVersion) {
43177
+ if (isUpdateCheckDisabled()) {
43178
+ logger.debug("CLI update check disabled by environment");
43179
+ return null;
43180
+ }
43181
+ try {
43182
+ const latestVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME2);
43183
+ if (!latestVersion) {
43184
+ logger.debug("Failed to fetch latest CLI version from npm");
43185
+ return null;
43186
+ }
43187
+ const current = normalizeVersion(currentVersion);
43188
+ const latest = normalizeVersion(latestVersion);
43189
+ const updateAvailable = import_compare_versions5.compareVersions(latest, current) > 0;
43190
+ logger.debug(`CLI version check: current=${current}, latest=${latest}, updateAvailable=${updateAvailable}`);
43191
+ return {
43192
+ currentVersion: current,
43193
+ latestVersion: latest,
43194
+ updateAvailable,
43195
+ releaseUrl: `https://www.npmjs.com/package/${PACKAGE_NAME2}`
43196
+ };
43197
+ } catch (error) {
43198
+ logger.debug(`CLI version check failed: ${error}`);
43199
+ return null;
43200
+ }
43201
+ }
43202
+ }
43203
+ // src/domains/versioning/checking/notification-display.ts
43204
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
43205
+ function createNotificationBox2(borderColor, boxWidth) {
43206
+ const contentWidth = boxWidth - 2;
43207
+ const topBorder = borderColor(`╭${"─".repeat(contentWidth)}╮`);
43208
+ const bottomBorder = borderColor(`╰${"─".repeat(contentWidth)}╯`);
43209
+ const emptyLine = borderColor("│") + " ".repeat(contentWidth) + borderColor("│");
43210
+ const padLine = (text, visibleLen) => {
43211
+ const len = visibleLen ?? text.length;
43212
+ const displayText = len > contentWidth ? `${text.slice(0, contentWidth - 3)}...` : text;
43213
+ const actualLen = visibleLen ?? displayText.length;
43214
+ const totalPadding = contentWidth - actualLen;
43215
+ const leftPadding = Math.max(0, Math.floor(totalPadding / 2));
43216
+ const rightPadding = Math.max(0, totalPadding - leftPadding);
43217
+ return borderColor("│") + " ".repeat(leftPadding) + displayText + " ".repeat(rightPadding) + borderColor("│");
43218
+ };
43219
+ return { topBorder, bottomBorder, emptyLine, padLine };
43220
+ }
43221
+ function displayKitNotification(result, options = {}) {
43222
+ if (!result.updateAvailable)
43223
+ return;
43224
+ const { currentVersion, latestVersion } = result;
43225
+ const { isGlobal = false } = options;
43226
+ const displayCurrent = normalizeVersion(currentVersion);
43227
+ const displayLatest = normalizeVersion(latestVersion);
43228
+ const boxWidth = 52;
43229
+ const { topBorder, bottomBorder, emptyLine, padLine } = createNotificationBox2(import_picocolors24.default.cyan, boxWidth);
43230
+ const headerText = import_picocolors24.default.bold(import_picocolors24.default.yellow("⬆ Kit Update Available"));
43231
+ const headerLen = "⬆ Kit Update Available".length;
43232
+ const versionText = `${import_picocolors24.default.dim(displayCurrent)} ${import_picocolors24.default.white("→")} ${import_picocolors24.default.green(import_picocolors24.default.bold(displayLatest))}`;
43233
+ const versionLen = displayCurrent.length + 3 + displayLatest.length;
43234
+ const updateCmd = isGlobal ? "ck init -g" : "ck init";
43235
+ const commandText = `Run: ${import_picocolors24.default.cyan(import_picocolors24.default.bold(updateCmd))}`;
43236
+ const commandLen = `Run: ${updateCmd}`.length;
43237
+ console.log("");
43238
+ console.log(topBorder);
43239
+ console.log(emptyLine);
43240
+ console.log(padLine(headerText, headerLen));
43241
+ console.log(padLine(versionText, versionLen));
43242
+ console.log(emptyLine);
43243
+ console.log(padLine(commandText, commandLen));
43244
+ console.log(emptyLine);
43245
+ console.log(bottomBorder);
43246
+ console.log("");
43247
+ }
43248
+ function displayCliNotification(result) {
43249
+ if (!result.updateAvailable)
43250
+ return;
43251
+ const { currentVersion, latestVersion } = result;
43252
+ const boxWidth = 52;
43253
+ const { topBorder, bottomBorder, emptyLine, padLine } = createNotificationBox2(import_picocolors24.default.magenta, boxWidth);
43254
+ const headerText = import_picocolors24.default.bold(import_picocolors24.default.yellow("⬆ CLI Update Available"));
43255
+ const headerLen = "⬆ CLI Update Available".length;
43256
+ const versionText = `${import_picocolors24.default.dim(currentVersion)} ${import_picocolors24.default.white("→")} ${import_picocolors24.default.green(import_picocolors24.default.bold(latestVersion))}`;
43257
+ const versionLen = currentVersion.length + 3 + latestVersion.length;
43258
+ const commandText = `Run: ${import_picocolors24.default.magenta(import_picocolors24.default.bold("ck update"))}`;
43259
+ const commandLen = "Run: ck update".length;
43260
+ console.log("");
43261
+ console.log(topBorder);
43262
+ console.log(emptyLine);
43263
+ console.log(padLine(headerText, headerLen));
43264
+ console.log(padLine(versionText, versionLen));
43265
+ console.log(emptyLine);
43266
+ console.log(padLine(commandText, commandLen));
43267
+ console.log(emptyLine);
43268
+ console.log(bottomBorder);
43269
+ console.log("");
43270
+ }
43271
+ // src/domains/versioning/version-checker.ts
43272
+ class VersionChecker2 {
43273
+ static async check(currentVersion) {
43274
+ return VersionChecker.check(currentVersion);
43275
+ }
43276
+ static displayNotification(result, options = {}) {
43277
+ displayKitNotification(result, options);
43278
+ }
43279
+ }
43280
+
43281
+ class CliVersionChecker2 {
43282
+ static async check(currentVersion) {
43283
+ return CliVersionChecker.check(currentVersion);
43284
+ }
43285
+ static displayNotification(result) {
43286
+ displayCliNotification(result);
43287
+ }
43288
+ }
43289
+
43290
+ // src/cli/version-display.ts
43292
43291
  init_logger();
43293
43292
  init_types2();
43294
43293
  var packageVersion = package_default.version;
@@ -43387,7 +43386,7 @@ function getPackageVersion2() {
43387
43386
 
43388
43387
  // src/shared/logger.ts
43389
43388
  init_output_manager();
43390
- var import_picocolors26 = __toESM(require_picocolors(), 1);
43389
+ var import_picocolors25 = __toESM(require_picocolors(), 1);
43391
43390
  import { createWriteStream as createWriteStream3 } from "node:fs";
43392
43391
 
43393
43392
  class Logger2 {
@@ -43396,23 +43395,23 @@ class Logger2 {
43396
43395
  exitHandlerRegistered = false;
43397
43396
  info(message) {
43398
43397
  const symbols = output.getSymbols();
43399
- console.log(import_picocolors26.default.blue(symbols.info), message);
43398
+ console.log(import_picocolors25.default.blue(symbols.info), message);
43400
43399
  }
43401
43400
  success(message) {
43402
43401
  const symbols = output.getSymbols();
43403
- console.log(import_picocolors26.default.green(symbols.success), message);
43402
+ console.log(import_picocolors25.default.green(symbols.success), message);
43404
43403
  }
43405
43404
  warning(message) {
43406
43405
  const symbols = output.getSymbols();
43407
- console.log(import_picocolors26.default.yellow(symbols.warning), message);
43406
+ console.log(import_picocolors25.default.yellow(symbols.warning), message);
43408
43407
  }
43409
43408
  error(message) {
43410
43409
  const symbols = output.getSymbols();
43411
- console.error(import_picocolors26.default.red(symbols.error), message);
43410
+ console.error(import_picocolors25.default.red(symbols.error), message);
43412
43411
  }
43413
43412
  debug(message) {
43414
43413
  if (process.env.DEBUG) {
43415
- console.log(import_picocolors26.default.gray("[DEBUG]"), message);
43414
+ console.log(import_picocolors25.default.gray("[DEBUG]"), message);
43416
43415
  }
43417
43416
  }
43418
43417
  verbose(message, context) {
@@ -43421,7 +43420,7 @@ class Logger2 {
43421
43420
  const timestamp = this.getTimestamp();
43422
43421
  const sanitizedMessage = this.sanitize(message);
43423
43422
  const formattedContext = context ? this.formatContext(context) : "";
43424
- const logLine = `${timestamp} ${import_picocolors26.default.gray("[VERBOSE]")} ${sanitizedMessage}${formattedContext}`;
43423
+ const logLine = `${timestamp} ${import_picocolors25.default.gray("[VERBOSE]")} ${sanitizedMessage}${formattedContext}`;
43425
43424
  console.error(logLine);
43426
43425
  if (this.logFileStream) {
43427
43426
  const plainLogLine = `${timestamp} [VERBOSE] ${sanitizedMessage}${formattedContext}`;
@@ -43524,7 +43523,7 @@ var logger3 = new Logger2;
43524
43523
 
43525
43524
  // src/shared/output-manager.ts
43526
43525
  init_terminal_utils();
43527
- var import_picocolors27 = __toESM(require_picocolors(), 1);
43526
+ var import_picocolors26 = __toESM(require_picocolors(), 1);
43528
43527
  var SYMBOLS2 = {
43529
43528
  unicode: {
43530
43529
  prompt: "◇",
@@ -43603,7 +43602,7 @@ class OutputManager2 {
43603
43602
  if (this.config.quiet)
43604
43603
  return;
43605
43604
  const symbol = this.getSymbols().success;
43606
- console.log(import_picocolors27.default.green(`${symbol} ${message}`));
43605
+ console.log(import_picocolors26.default.green(`${symbol} ${message}`));
43607
43606
  }
43608
43607
  error(message, data) {
43609
43608
  if (this.config.json) {
@@ -43611,7 +43610,7 @@ class OutputManager2 {
43611
43610
  return;
43612
43611
  }
43613
43612
  const symbol = this.getSymbols().error;
43614
- console.error(import_picocolors27.default.red(`${symbol} ${message}`));
43613
+ console.error(import_picocolors26.default.red(`${symbol} ${message}`));
43615
43614
  }
43616
43615
  warning(message, data) {
43617
43616
  if (this.config.json) {
@@ -43621,7 +43620,7 @@ class OutputManager2 {
43621
43620
  if (this.config.quiet)
43622
43621
  return;
43623
43622
  const symbol = this.getSymbols().warning;
43624
- console.log(import_picocolors27.default.yellow(`${symbol} ${message}`));
43623
+ console.log(import_picocolors26.default.yellow(`${symbol} ${message}`));
43625
43624
  }
43626
43625
  info(message, data) {
43627
43626
  if (this.config.json) {
@@ -43631,7 +43630,7 @@ class OutputManager2 {
43631
43630
  if (this.config.quiet)
43632
43631
  return;
43633
43632
  const symbol = this.getSymbols().info;
43634
- console.log(import_picocolors27.default.blue(`${symbol} ${message}`));
43633
+ console.log(import_picocolors26.default.blue(`${symbol} ${message}`));
43635
43634
  }
43636
43635
  verbose(message, data) {
43637
43636
  if (!this.config.verbose)
@@ -43640,7 +43639,7 @@ class OutputManager2 {
43640
43639
  this.addJsonEntry({ type: "info", message, data });
43641
43640
  return;
43642
43641
  }
43643
- console.log(import_picocolors27.default.dim(` ${message}`));
43642
+ console.log(import_picocolors26.default.dim(` ${message}`));
43644
43643
  }
43645
43644
  indent(message) {
43646
43645
  if (this.config.json)
@@ -43665,7 +43664,7 @@ class OutputManager2 {
43665
43664
  return;
43666
43665
  const symbols = this.getSymbols();
43667
43666
  console.log();
43668
- console.log(import_picocolors27.default.bold(import_picocolors27.default.cyan(`${symbols.line} ${title}`)));
43667
+ console.log(import_picocolors26.default.bold(import_picocolors26.default.cyan(`${symbols.line} ${title}`)));
43669
43668
  }
43670
43669
  addJsonEntry(entry) {
43671
43670
  this.jsonBuffer.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.24.1",
3
+ "version": "3.25.0",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {