claudekit-cli 3.24.0 → 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 -527
  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,489 +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.0",
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) {
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
- return parts.join(" ");
42912
- }
42913
- async function readMetadataFile(claudeDir) {
42914
- const metadataPath = join76(claudeDir, "metadata.json");
42915
- try {
42916
- if (!await import_fs_extra36.pathExists(metadataPath)) {
42917
- return null;
42918
- }
42919
- const content = await import_fs_extra36.readFile(metadataPath, "utf-8");
42920
- return JSON.parse(content);
42921
- } catch {
42922
- return null;
42923
- }
42924
- }
42925
- async function displayKitUpdateReminder() {
42926
- try {
42927
- const setup = await getClaudeKitSetup();
42928
- const hasLocal = !!setup.project.metadata;
42929
- const hasGlobal = !!setup.global.metadata;
42930
- const localMetadata = hasLocal ? await readMetadataFile(setup.project.path) : null;
42931
- const globalMetadata = hasGlobal ? await readMetadataFile(setup.global.path) : null;
42932
- const localKits = localMetadata ? getInstalledKits(localMetadata) : [];
42933
- const globalKits = globalMetadata ? getInstalledKits(globalMetadata) : [];
42934
- const versionsToCheck = new Set;
42935
- if (localMetadata) {
42936
- for (const kit of localKits) {
42937
- const version = localMetadata.kits?.[kit]?.version || localMetadata.version;
42938
- if (version)
42939
- versionsToCheck.add(version);
42940
- }
42941
- }
42942
- if (globalMetadata) {
42943
- for (const kit of globalKits) {
42944
- const version = globalMetadata.kits?.[kit]?.version || globalMetadata.version;
42945
- if (version)
42946
- versionsToCheck.add(version);
42947
- }
42948
- }
42949
- const versionCheckResults = new Map;
42950
- if (versionsToCheck.size > 0) {
42951
- const checkPromises = [...versionsToCheck].map(async (version) => {
42952
- const result = await VersionChecker2.check(version).catch(() => null);
42953
- return { version, result };
42954
- });
42955
- const results = await Promise.all(checkPromises);
42956
- for (const { version, result } of results) {
42957
- versionCheckResults.set(version, result);
42958
- }
42959
- }
42960
- const commands = [];
42961
- if (localKits.length > 0) {
42962
- for (const kit of localKits) {
42963
- const cmd = buildInitCommand(false, kit);
42964
- const version = localMetadata?.kits?.[kit]?.version || localMetadata?.version;
42965
- commands.push({
42966
- cmd,
42967
- desc: `Update local project (${kit}${version ? `@${version}` : ""})`,
42968
- version
42969
- });
42970
- }
42971
- } else if (hasLocal) {
42972
- commands.push({ cmd: "ck init", desc: "Update local project" });
42973
- } else {
42974
- commands.push({ cmd: "ck init", desc: "Initialize in current project" });
42975
- }
42976
- if (globalKits.length > 0) {
42977
- for (const kit of globalKits) {
42978
- const cmd = buildInitCommand(true, kit);
42979
- const version = globalMetadata?.kits?.[kit]?.version || globalMetadata?.version;
42980
- commands.push({
42981
- cmd,
42982
- desc: `Update global ~/.claude (${kit}${version ? `@${version}` : ""})`,
42983
- version
42984
- });
42985
- }
42986
- } else if (hasGlobal) {
42987
- commands.push({ cmd: "ck init -g", desc: "Update global ~/.claude" });
42988
- } else {
42989
- commands.push({ cmd: "ck init -g", desc: "Initialize global ~/.claude" });
42990
- }
42991
- const maxCmdLen = Math.max(...commands.map((c2) => c2.cmd.length));
42992
- const pad = (cmd) => cmd.padEnd(maxCmdLen);
42993
- const lines = [];
42994
- lines.push(import_picocolors24.default.yellow(KIT_UPDATE_REMINDER_HEADER));
42995
- lines.push("");
42996
- lines.push("To update your ClaudeKit content (skills, commands, workflows):");
42997
- for (const { cmd, desc: desc2, version } of commands) {
42998
- lines.push(` ${import_picocolors24.default.cyan(pad(cmd))} ${desc2}`);
42999
- if (version) {
43000
- const versionCheck = versionCheckResults.get(version);
43001
- if (versionCheck?.updateAvailable) {
43002
- const indent = " ".repeat(maxCmdLen + 4);
43003
- lines.push(`${indent}${import_picocolors24.default.green(`→ ${versionCheck.latestVersion} available!`)}`);
43004
- }
43005
- }
43006
- }
43007
- logger.info("");
43008
- log.info(lines.join(`
43009
- `));
43010
- } catch (error) {
43011
- 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"}`);
43012
42756
  }
43013
42757
  }
43014
42758
  async function updateCliCommand(options) {
@@ -43026,7 +42770,7 @@ async function updateCliCommand(options) {
43026
42770
  s.start("Checking for updates...");
43027
42771
  let targetVersion = null;
43028
42772
  if (opts.release && opts.release !== "latest") {
43029
- const exists = await NpmRegistryClient.versionExists(PACKAGE_NAME2, opts.release, opts.registry);
42773
+ const exists = await NpmRegistryClient.versionExists(PACKAGE_NAME, opts.release, opts.registry);
43030
42774
  if (!exists) {
43031
42775
  s.stop("Version not found");
43032
42776
  throw new CliUpdateError(`Version ${opts.release} does not exist on npm registry. Run 'ck versions' to see available versions.`);
@@ -43034,25 +42778,25 @@ async function updateCliCommand(options) {
43034
42778
  targetVersion = opts.release;
43035
42779
  s.stop(`Target version: ${targetVersion}`);
43036
42780
  } else if (opts.beta) {
43037
- targetVersion = await NpmRegistryClient.getBetaVersion(PACKAGE_NAME2, opts.registry);
42781
+ targetVersion = await NpmRegistryClient.getBetaVersion(PACKAGE_NAME, opts.registry);
43038
42782
  if (!targetVersion) {
43039
42783
  s.stop("No beta version available");
43040
42784
  logger.warning("No beta version found. Using latest stable version instead.");
43041
- targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME2, opts.registry);
42785
+ targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME, opts.registry);
43042
42786
  } else {
43043
42787
  s.stop(`Latest beta version: ${targetVersion}`);
43044
42788
  }
43045
42789
  } else {
43046
- targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME2, opts.registry);
42790
+ targetVersion = await NpmRegistryClient.getLatestVersion(PACKAGE_NAME, opts.registry);
43047
42791
  s.stop(`Latest version: ${targetVersion || "unknown"}`);
43048
42792
  }
43049
42793
  if (!targetVersion) {
43050
- 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)}`);
43051
42795
  }
43052
- const comparison = import_compare_versions5.compareVersions(currentVersion, targetVersion);
42796
+ const comparison = import_compare_versions3.compareVersions(currentVersion, targetVersion);
43053
42797
  if (comparison === 0) {
43054
42798
  outro(`[+] Already on the latest CLI version (${currentVersion})`);
43055
- await displayKitUpdateReminder();
42799
+ await promptKitUpdate(opts.beta);
43056
42800
  return;
43057
42801
  }
43058
42802
  if (comparison > 0 && !opts.release) {
@@ -43066,7 +42810,7 @@ async function updateCliCommand(options) {
43066
42810
  note(`CLI update available: ${currentVersion} -> ${targetVersion}
43067
42811
 
43068
42812
  Run 'ck update' to install`, "Update Check");
43069
- await displayKitUpdateReminder();
42813
+ await promptKitUpdate(opts.beta);
43070
42814
  outro("Check complete");
43071
42815
  return;
43072
42816
  }
@@ -43079,7 +42823,7 @@ Run 'ck update' to install`, "Update Check");
43079
42823
  return;
43080
42824
  }
43081
42825
  }
43082
- const updateCmd = PackageManagerDetector.getUpdateCommand(pm, PACKAGE_NAME2, targetVersion);
42826
+ const updateCmd = PackageManagerDetector.getUpdateCommand(pm, PACKAGE_NAME, targetVersion);
43083
42827
  logger.info(`Running: ${updateCmd}`);
43084
42828
  s.start("Updating CLI...");
43085
42829
  try {
@@ -43106,11 +42850,11 @@ Manual update: ${updateCmd}`);
43106
42850
  const newVersion = newVersionMatch ? newVersionMatch[1] : targetVersion;
43107
42851
  s.stop(`Installed version: ${newVersion}`);
43108
42852
  outro(`[+] Successfully updated ClaudeKit CLI to ${newVersion}`);
43109
- await displayKitUpdateReminder();
42853
+ await promptKitUpdate(opts.beta);
43110
42854
  } catch {
43111
42855
  s.stop("Verification completed");
43112
42856
  outro(`[+] Update completed. Please restart your terminal to use CLI ${targetVersion}`);
43113
- await displayKitUpdateReminder();
42857
+ await promptKitUpdate(opts.beta);
43114
42858
  }
43115
42859
  } catch (error) {
43116
42860
  if (error instanceof CliUpdateError) {
@@ -43126,7 +42870,7 @@ Manual update: ${updateCmd}`);
43126
42870
  // src/commands/version.ts
43127
42871
  init_logger();
43128
42872
  init_types2();
43129
- var import_picocolors25 = __toESM(require_picocolors(), 1);
42873
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
43130
42874
  function formatRelativeTime(dateString) {
43131
42875
  if (!dateString)
43132
42876
  return "Unknown";
@@ -43148,30 +42892,30 @@ function formatRelativeTime(dateString) {
43148
42892
  }
43149
42893
  function displayKitReleases(kitName, releases) {
43150
42894
  console.log(`
43151
- ${import_picocolors25.default.bold(import_picocolors25.default.cyan(kitName))} - Available Versions:
42895
+ ${import_picocolors23.default.bold(import_picocolors23.default.cyan(kitName))} - Available Versions:
43152
42896
  `);
43153
42897
  if (releases.length === 0) {
43154
- console.log(import_picocolors25.default.dim(" No releases found"));
42898
+ console.log(import_picocolors23.default.dim(" No releases found"));
43155
42899
  return;
43156
42900
  }
43157
42901
  for (const release of releases) {
43158
- const version = import_picocolors25.default.green(release.tag_name);
42902
+ const version = import_picocolors23.default.green(release.tag_name);
43159
42903
  const name2 = release.name || "No title";
43160
42904
  const publishedAt = formatRelativeTime(release.published_at);
43161
42905
  const assetCount = release.assets.length;
43162
42906
  const badges = [];
43163
42907
  if (release.prerelease)
43164
- badges.push(import_picocolors25.default.yellow("[prerelease]"));
42908
+ badges.push(import_picocolors23.default.yellow("[prerelease]"));
43165
42909
  if (release.draft)
43166
- badges.push(import_picocolors25.default.gray("[draft]"));
42910
+ badges.push(import_picocolors23.default.gray("[draft]"));
43167
42911
  const badgeStr = badges.length > 0 ? ` ${badges.join(" ")}` : "";
43168
42912
  const versionPart = version.padEnd(20);
43169
42913
  const namePart = name2.length > 40 ? `${name2.slice(0, 37)}...` : name2.padEnd(40);
43170
- const timePart = import_picocolors25.default.dim(publishedAt.padEnd(20));
43171
- 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"})`);
43172
42916
  console.log(` ${versionPart} ${namePart} ${timePart} ${assetPart}${badgeStr}`);
43173
42917
  }
43174
- console.log(import_picocolors25.default.dim(`
42918
+ console.log(import_picocolors23.default.dim(`
43175
42919
  Showing ${releases.length} ${releases.length === 1 ? "release" : "releases"}`));
43176
42920
  }
43177
42921
  async function versionCommand(options) {
@@ -43206,8 +42950,8 @@ async function versionCommand(options) {
43206
42950
  for (const result of results) {
43207
42951
  if (result.error) {
43208
42952
  console.log(`
43209
- ${import_picocolors25.default.bold(import_picocolors25.default.cyan(result.kitConfig.name))} - ${import_picocolors25.default.red("Error")}`);
43210
- 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}`));
43211
42955
  } else {
43212
42956
  displayKitReleases(result.kitConfig.name, result.releases);
43213
42957
  }
@@ -43278,6 +43022,272 @@ function registerCommands(cli) {
43278
43022
  // src/cli/version-display.ts
43279
43023
  import { existsSync as existsSync20, readFileSync as readFileSync6 } from "node:fs";
43280
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
43281
43291
  init_logger();
43282
43292
  init_types2();
43283
43293
  var packageVersion = package_default.version;
@@ -43376,7 +43386,7 @@ function getPackageVersion2() {
43376
43386
 
43377
43387
  // src/shared/logger.ts
43378
43388
  init_output_manager();
43379
- var import_picocolors26 = __toESM(require_picocolors(), 1);
43389
+ var import_picocolors25 = __toESM(require_picocolors(), 1);
43380
43390
  import { createWriteStream as createWriteStream3 } from "node:fs";
43381
43391
 
43382
43392
  class Logger2 {
@@ -43385,23 +43395,23 @@ class Logger2 {
43385
43395
  exitHandlerRegistered = false;
43386
43396
  info(message) {
43387
43397
  const symbols = output.getSymbols();
43388
- console.log(import_picocolors26.default.blue(symbols.info), message);
43398
+ console.log(import_picocolors25.default.blue(symbols.info), message);
43389
43399
  }
43390
43400
  success(message) {
43391
43401
  const symbols = output.getSymbols();
43392
- console.log(import_picocolors26.default.green(symbols.success), message);
43402
+ console.log(import_picocolors25.default.green(symbols.success), message);
43393
43403
  }
43394
43404
  warning(message) {
43395
43405
  const symbols = output.getSymbols();
43396
- console.log(import_picocolors26.default.yellow(symbols.warning), message);
43406
+ console.log(import_picocolors25.default.yellow(symbols.warning), message);
43397
43407
  }
43398
43408
  error(message) {
43399
43409
  const symbols = output.getSymbols();
43400
- console.error(import_picocolors26.default.red(symbols.error), message);
43410
+ console.error(import_picocolors25.default.red(symbols.error), message);
43401
43411
  }
43402
43412
  debug(message) {
43403
43413
  if (process.env.DEBUG) {
43404
- console.log(import_picocolors26.default.gray("[DEBUG]"), message);
43414
+ console.log(import_picocolors25.default.gray("[DEBUG]"), message);
43405
43415
  }
43406
43416
  }
43407
43417
  verbose(message, context) {
@@ -43410,7 +43420,7 @@ class Logger2 {
43410
43420
  const timestamp = this.getTimestamp();
43411
43421
  const sanitizedMessage = this.sanitize(message);
43412
43422
  const formattedContext = context ? this.formatContext(context) : "";
43413
- const logLine = `${timestamp} ${import_picocolors26.default.gray("[VERBOSE]")} ${sanitizedMessage}${formattedContext}`;
43423
+ const logLine = `${timestamp} ${import_picocolors25.default.gray("[VERBOSE]")} ${sanitizedMessage}${formattedContext}`;
43414
43424
  console.error(logLine);
43415
43425
  if (this.logFileStream) {
43416
43426
  const plainLogLine = `${timestamp} [VERBOSE] ${sanitizedMessage}${formattedContext}`;
@@ -43513,7 +43523,7 @@ var logger3 = new Logger2;
43513
43523
 
43514
43524
  // src/shared/output-manager.ts
43515
43525
  init_terminal_utils();
43516
- var import_picocolors27 = __toESM(require_picocolors(), 1);
43526
+ var import_picocolors26 = __toESM(require_picocolors(), 1);
43517
43527
  var SYMBOLS2 = {
43518
43528
  unicode: {
43519
43529
  prompt: "◇",
@@ -43592,7 +43602,7 @@ class OutputManager2 {
43592
43602
  if (this.config.quiet)
43593
43603
  return;
43594
43604
  const symbol = this.getSymbols().success;
43595
- console.log(import_picocolors27.default.green(`${symbol} ${message}`));
43605
+ console.log(import_picocolors26.default.green(`${symbol} ${message}`));
43596
43606
  }
43597
43607
  error(message, data) {
43598
43608
  if (this.config.json) {
@@ -43600,7 +43610,7 @@ class OutputManager2 {
43600
43610
  return;
43601
43611
  }
43602
43612
  const symbol = this.getSymbols().error;
43603
- console.error(import_picocolors27.default.red(`${symbol} ${message}`));
43613
+ console.error(import_picocolors26.default.red(`${symbol} ${message}`));
43604
43614
  }
43605
43615
  warning(message, data) {
43606
43616
  if (this.config.json) {
@@ -43610,7 +43620,7 @@ class OutputManager2 {
43610
43620
  if (this.config.quiet)
43611
43621
  return;
43612
43622
  const symbol = this.getSymbols().warning;
43613
- console.log(import_picocolors27.default.yellow(`${symbol} ${message}`));
43623
+ console.log(import_picocolors26.default.yellow(`${symbol} ${message}`));
43614
43624
  }
43615
43625
  info(message, data) {
43616
43626
  if (this.config.json) {
@@ -43620,7 +43630,7 @@ class OutputManager2 {
43620
43630
  if (this.config.quiet)
43621
43631
  return;
43622
43632
  const symbol = this.getSymbols().info;
43623
- console.log(import_picocolors27.default.blue(`${symbol} ${message}`));
43633
+ console.log(import_picocolors26.default.blue(`${symbol} ${message}`));
43624
43634
  }
43625
43635
  verbose(message, data) {
43626
43636
  if (!this.config.verbose)
@@ -43629,7 +43639,7 @@ class OutputManager2 {
43629
43639
  this.addJsonEntry({ type: "info", message, data });
43630
43640
  return;
43631
43641
  }
43632
- console.log(import_picocolors27.default.dim(` ${message}`));
43642
+ console.log(import_picocolors26.default.dim(` ${message}`));
43633
43643
  }
43634
43644
  indent(message) {
43635
43645
  if (this.config.json)
@@ -43654,7 +43664,7 @@ class OutputManager2 {
43654
43664
  return;
43655
43665
  const symbols = this.getSymbols();
43656
43666
  console.log();
43657
- 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}`)));
43658
43668
  }
43659
43669
  addJsonEntry(entry) {
43660
43670
  this.jsonBuffer.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.24.0",
3
+ "version": "3.25.0",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {