claudekit-cli 3.41.2-dev.1 → 3.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14880,7 +14880,7 @@ var init_ck_config = __esm(() => {
14880
14880
  "gemini-3-flash": "gemini-3-flash-preview",
14881
14881
  "gemini-3-pro": "gemini-3-pro-preview"
14882
14882
  };
14883
- GeminiModelSchema = exports_external.string().default("gemini-3-flash-preview");
14883
+ GeminiModelSchema = exports_external.enum(GEMINI_MODEL_VALUES);
14884
14884
  StatuslineModeSchema = exports_external.enum(["full", "compact", "minimal", "none"]);
14885
14885
  StatuslineSectionIdSchema = exports_external.enum([
14886
14886
  "model",
@@ -15193,7 +15193,6 @@ __export(exports_types, {
15193
15193
  GitHubReleaseAssetSchema: () => GitHubReleaseAssetSchema,
15194
15194
  GitHubError: () => GitHubError,
15195
15195
  GeminiModelSchema: () => GeminiModelSchema,
15196
- GEMINI_MODEL_VALUES: () => GEMINI_MODEL_VALUES,
15197
15196
  FrameworkSchema: () => FrameworkSchema,
15198
15197
  FoldersConfigSchema: () => FoldersConfigSchema,
15199
15198
  ExtractionError: () => ExtractionError,
@@ -47784,14 +47783,6 @@ async function isActionPathAllowed(dirPath, projectId) {
47784
47783
  return false;
47785
47784
  return resolve6(project.path) === dirPath;
47786
47785
  }
47787
- if (projectId?.startsWith("discovered-")) {
47788
- try {
47789
- const encodedPath = projectId.slice("discovered-".length);
47790
- const discoveredPath = Buffer.from(encodedPath, "base64url").toString("utf-8");
47791
- if (resolve6(discoveredPath) === dirPath)
47792
- return true;
47793
- } catch {}
47794
- }
47795
47786
  const registeredProjects = await ProjectsRegistryManager.listProjects();
47796
47787
  if (registeredProjects.some((project) => resolve6(project.path) === dirPath)) {
47797
47788
  return true;
@@ -56501,11 +56492,6 @@ var init_skill_routes = __esm(() => {
56501
56492
  });
56502
56493
 
56503
56494
  // src/domains/github/npm-registry.ts
56504
- var exports_npm_registry = {};
56505
- __export(exports_npm_registry, {
56506
- redactRegistryUrlForLog: () => redactRegistryUrlForLog,
56507
- NpmRegistryClient: () => NpmRegistryClient
56508
- });
56509
56495
  function redactRegistryUrlForLog(url) {
56510
56496
  if (!url)
56511
56497
  return url;
@@ -57202,120 +57188,170 @@ var init_package_manager_detector = __esm(() => {
57202
57188
  };
57203
57189
  });
57204
57190
 
57205
- // package.json
57206
- var package_default;
57207
- var init_package = __esm(() => {
57208
- package_default = {
57209
- name: "claudekit-cli",
57210
- version: "3.41.2-dev.1",
57211
- description: "CLI tool for bootstrapping and updating ClaudeKit projects",
57212
- type: "module",
57213
- repository: {
57214
- type: "git",
57215
- url: "git+https://github.com/mrgoonie/claudekit-cli.git"
57216
- },
57217
- publishConfig: {
57218
- access: "public",
57219
- registry: "https://registry.npmjs.org"
57220
- },
57221
- bin: {
57222
- ck: "bin/ck.js"
57223
- },
57224
- files: [
57225
- "bin/ck.js",
57226
- "dist/index.js",
57227
- "dist/ui/"
57228
- ],
57229
- scripts: {
57230
- tauri: "tauri",
57231
- "tauri:dev": "tauri dev",
57232
- "tauri:build": "tauri build",
57233
- dev: "bun run src/index.ts",
57234
- "dashboard:dev": "cd src/ui && bun install --silent && cd ../.. && bun run src/index.ts config ui --dev",
57235
- "dashboard:tauri": "cd src/ui && bun install --silent && cd ../.. && bun run src/index.ts config ui --dev --no-open --port 3456",
57236
- "ui:build": "cd src/ui && bun install --silent && bun run build",
57237
- "ui:dev": "cd src/ui && bun run dev",
57238
- build: `bun build src/index.ts --outdir dist --target node --external @octokit/rest --external better-sqlite3 && node -e "const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf-8');fs.writeFileSync(f,c.replace(/^#!.*\\n\\/\\/ @bun\\n/,''))"`,
57239
- "verify:package": "node scripts/prepublish-check.js",
57240
- test: "bun test",
57241
- "test:integration": "CK_RUN_CLI_INTEGRATION=1 bun test tests/integration/cli.test.ts",
57242
- "test:watch": "bun test --watch",
57243
- "test:quick": "./scripts/dev-quick-start.sh test",
57244
- lint: "biome check .",
57245
- "lint:fix": "biome check --fix .",
57246
- "lint:fix-unsafe": "biome check --fix --unsafe .",
57247
- format: "biome format --write .",
57248
- typecheck: "tsc --noEmit",
57249
- "dev:quick": "./scripts/dev-quick-start.sh",
57250
- "dev:all": "./scripts/dev-quick-start.sh all",
57251
- metrics: "bun run scripts/workflow-metrics.ts",
57252
- validate: "bun run typecheck && bun run lint && bun test && bun run build",
57253
- "install:hooks": "./.githooks/install.sh",
57254
- prepare: `node -e "try{require('child_process').execSync('git rev-parse --git-dir',{stdio:'ignore'});require('child_process').execSync('bash .githooks/install.sh',{stdio:'inherit'})}catch(e){console.warn('[i] Hook install skipped:',e.message)}"`
57255
- },
57256
- keywords: [
57257
- "cli",
57258
- "claudekit",
57259
- "boilerplate",
57260
- "bootstrap",
57261
- "template"
57262
- ],
57263
- author: "ClaudeKit",
57264
- license: "MIT",
57265
- engines: {
57266
- node: ">=18.0.0"
57267
- },
57268
- dependencies: {
57269
- "@clack/prompts": "^0.7.0",
57270
- "@octokit/rest": "^22.0.0",
57271
- "better-sqlite3": "^12.6.2",
57272
- cac: "^6.7.14",
57273
- chokidar: "^5.0.0",
57274
- "cli-progress": "^3.12.0",
57275
- "compare-versions": "^6.1.1",
57276
- diff: "^8.0.3",
57277
- express: "^5.2.1",
57278
- "extract-zip": "^2.0.1",
57279
- "fs-extra": "^11.2.0",
57280
- "get-port": "^7.1.0",
57281
- "gray-matter": "^4.0.3",
57282
- ignore: "^5.3.2",
57283
- minimatch: "^10.1.1",
57284
- open: "^11.0.0",
57285
- ora: "^8.0.0",
57286
- "p-limit": "^7.2.0",
57287
- picocolors: "^1.1.1",
57288
- picomatch: "^4.0.3",
57289
- "proper-lockfile": "^4.1.2",
57290
- semver: "^7.7.3",
57291
- tar: "^7.4.3",
57292
- tmp: "^0.2.3",
57293
- ws: "^8.19.0",
57294
- zod: "^3.23.8"
57295
- },
57296
- devDependencies: {
57297
- "@biomejs/biome": "^1.9.4",
57298
- "@semantic-release/changelog": "^6.0.3",
57299
- "@semantic-release/git": "^10.0.1",
57300
- "@tauri-apps/cli": "^2",
57301
- "@types/better-sqlite3": "^7.6.13",
57302
- "@types/bun": "latest",
57303
- "@types/cli-progress": "^3.11.6",
57304
- "@types/diff": "^8.0.0",
57305
- "@types/express": "^5.0.6",
57306
- "@types/fs-extra": "^11.0.4",
57307
- "@types/node": "^22.19.7",
57308
- "@types/picomatch": "^4.0.2",
57309
- "@types/proper-lockfile": "^4.1.4",
57310
- "@types/semver": "^7.7.1",
57311
- "@types/tar": "^6.1.13",
57312
- "@types/tmp": "^0.2.6",
57313
- "@types/ws": "^8.18.1",
57314
- "conventional-changelog-conventionalcommits": "^9.1.0",
57315
- "semantic-release": "^24.2.0",
57316
- typescript: "^5.7.2"
57191
+ // src/domains/migration/metadata-migration.ts
57192
+ import { join as join45 } from "node:path";
57193
+ async function detectMetadataFormat(claudeDir2) {
57194
+ const metadataPath = join45(claudeDir2, "metadata.json");
57195
+ if (!await import_fs_extra3.pathExists(metadataPath)) {
57196
+ return { format: "none", metadata: null, detectedKit: null };
57197
+ }
57198
+ try {
57199
+ const content = await import_fs_extra3.readFile(metadataPath, "utf-8");
57200
+ const parsed = JSON.parse(content);
57201
+ if (parsed.kits && Object.keys(parsed.kits).length > 0) {
57202
+ const installedKits = Object.keys(parsed.kits);
57203
+ return {
57204
+ format: "multi-kit",
57205
+ metadata: parsed,
57206
+ detectedKit: installedKits[0] || null
57207
+ };
57317
57208
  }
57318
- };
57209
+ if (parsed.name || parsed.version || parsed.files) {
57210
+ let detectedKit = null;
57211
+ const nameToCheck = parsed.name || "";
57212
+ if (/\bengineer\b/i.test(nameToCheck)) {
57213
+ detectedKit = "engineer";
57214
+ } else if (/\bmarketing\b/i.test(nameToCheck)) {
57215
+ detectedKit = "marketing";
57216
+ } else {
57217
+ detectedKit = "engineer";
57218
+ }
57219
+ return { format: "legacy", metadata: parsed, detectedKit };
57220
+ }
57221
+ logger.warning("Metadata file exists but has unrecognized format (missing kits, name, version, or files)");
57222
+ return { format: "none", metadata: null, detectedKit: null };
57223
+ } catch (error) {
57224
+ logger.warning(`Failed to read metadata file (may be corrupted): ${error}`);
57225
+ return { format: "none", metadata: null, detectedKit: null };
57226
+ }
57227
+ }
57228
+ async function migrateToMultiKit(claudeDir2) {
57229
+ const detection = await detectMetadataFormat(claudeDir2);
57230
+ if (detection.format === "multi-kit") {
57231
+ return {
57232
+ success: true,
57233
+ migrated: false,
57234
+ fromFormat: "multi-kit",
57235
+ toFormat: "multi-kit"
57236
+ };
57237
+ }
57238
+ if (detection.format === "none") {
57239
+ return {
57240
+ success: true,
57241
+ migrated: false,
57242
+ fromFormat: "none",
57243
+ toFormat: "multi-kit"
57244
+ };
57245
+ }
57246
+ const metadataPath = join45(claudeDir2, "metadata.json");
57247
+ const legacy = detection.metadata;
57248
+ if (!legacy) {
57249
+ return {
57250
+ success: false,
57251
+ migrated: false,
57252
+ fromFormat: "legacy",
57253
+ toFormat: "multi-kit",
57254
+ error: "Metadata exists but could not be read"
57255
+ };
57256
+ }
57257
+ const legacyKit = detection.detectedKit || "engineer";
57258
+ try {
57259
+ const kitMetadata = {
57260
+ version: legacy.version || "unknown",
57261
+ installedAt: legacy.installedAt || new Date().toISOString(),
57262
+ files: legacy.files || []
57263
+ };
57264
+ const multiKit = {
57265
+ kits: {
57266
+ [legacyKit]: kitMetadata
57267
+ },
57268
+ scope: legacy.scope,
57269
+ name: legacy.name,
57270
+ version: legacy.version,
57271
+ installedAt: legacy.installedAt,
57272
+ installedFiles: legacy.installedFiles,
57273
+ userConfigFiles: legacy.userConfigFiles,
57274
+ files: legacy.files
57275
+ };
57276
+ await import_fs_extra3.writeFile(metadataPath, JSON.stringify(multiKit, null, 2), "utf-8");
57277
+ logger.info(`Migrated metadata from legacy format to multi-kit (detected: ${legacyKit})`);
57278
+ return {
57279
+ success: true,
57280
+ migrated: true,
57281
+ fromFormat: "legacy",
57282
+ toFormat: "multi-kit"
57283
+ };
57284
+ } catch (error) {
57285
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
57286
+ logger.error(`Metadata migration failed: ${errorMsg}`);
57287
+ return {
57288
+ success: false,
57289
+ migrated: false,
57290
+ fromFormat: "legacy",
57291
+ toFormat: "multi-kit",
57292
+ error: errorMsg
57293
+ };
57294
+ }
57295
+ }
57296
+ function getKitMetadata(metadata, kit) {
57297
+ if (metadata.kits?.[kit]) {
57298
+ return metadata.kits[kit];
57299
+ }
57300
+ if (!metadata.kits && metadata.version) {
57301
+ return {
57302
+ version: metadata.version,
57303
+ installedAt: metadata.installedAt || "",
57304
+ files: metadata.files
57305
+ };
57306
+ }
57307
+ return null;
57308
+ }
57309
+ function getAllTrackedFiles(metadata) {
57310
+ if (metadata.kits) {
57311
+ const allFiles = [];
57312
+ for (const kit of Object.values(metadata.kits)) {
57313
+ if (kit.files) {
57314
+ allFiles.push(...kit.files);
57315
+ }
57316
+ }
57317
+ return allFiles;
57318
+ }
57319
+ return metadata.files || [];
57320
+ }
57321
+ function getTrackedFilesForKit(metadata, kitType) {
57322
+ if (metadata.kits?.[kitType]) {
57323
+ return metadata.kits[kitType].files || [];
57324
+ }
57325
+ const detectedKits = getInstalledKits(metadata);
57326
+ if (detectedKits.includes(kitType)) {
57327
+ return metadata.files || [];
57328
+ }
57329
+ return [];
57330
+ }
57331
+ function getInstalledKits(metadata) {
57332
+ if (metadata.kits) {
57333
+ return Object.keys(metadata.kits);
57334
+ }
57335
+ const nameToCheck = metadata.name || "";
57336
+ const kits = [];
57337
+ if (/\bengineer\b/i.test(nameToCheck)) {
57338
+ kits.push("engineer");
57339
+ }
57340
+ if (/\bmarketing\b/i.test(nameToCheck)) {
57341
+ kits.push("marketing");
57342
+ }
57343
+ if (kits.length > 0) {
57344
+ return kits;
57345
+ }
57346
+ if (metadata.version) {
57347
+ return ["engineer"];
57348
+ }
57349
+ return [];
57350
+ }
57351
+ var import_fs_extra3;
57352
+ var init_metadata_migration = __esm(() => {
57353
+ init_logger();
57354
+ import_fs_extra3 = __toESM(require_lib3(), 1);
57319
57355
  });
57320
57356
 
57321
57357
  // node_modules/compare-versions/lib/umd/index.js
@@ -57489,362 +57525,6 @@ var init_version_utils = __esm(() => {
57489
57525
  import_compare_versions = __toESM(require_umd(), 1);
57490
57526
  });
57491
57527
 
57492
- // src/commands/update/error.ts
57493
- var CliUpdateError;
57494
- var init_error = __esm(() => {
57495
- init_types3();
57496
- CliUpdateError = class CliUpdateError extends ClaudeKitError {
57497
- constructor(message) {
57498
- super(message, "CLI_UPDATE_ERROR");
57499
- this.name = "CliUpdateError";
57500
- }
57501
- };
57502
- });
57503
-
57504
- // src/commands/update/channel-resolver.ts
57505
- async function resolveTargetVersion(opts, deps) {
57506
- const client = deps.npmRegistryClient ?? NpmRegistryClient;
57507
- const registryUrl = deps.registryUrl ?? undefined;
57508
- const { spinnerStop } = deps;
57509
- if (opts.release && opts.release !== "latest") {
57510
- let exists;
57511
- try {
57512
- exists = await client.versionExists(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.release, registryUrl);
57513
- } catch (error) {
57514
- spinnerStop("Version check failed");
57515
- const message = error instanceof Error ? error.message : "Unknown error";
57516
- logger.verbose(`Release check failed for ${opts.release}: ${message}`);
57517
- const registryHint = registryUrl ? ` (${redactRegistryUrlForLog(registryUrl)})` : " (default registry)";
57518
- throw new CliUpdateError(`Failed to verify version ${opts.release} on npm registry${registryHint}. Check registry settings/network connectivity and try again.`);
57519
- }
57520
- if (!exists) {
57521
- spinnerStop("Version not found");
57522
- throw new CliUpdateError(`Version ${opts.release} does not exist on npm registry. Run 'ck versions' to see available versions.`);
57523
- }
57524
- const targetVersion2 = opts.release;
57525
- spinnerStop(`Target version: ${targetVersion2}`);
57526
- return { targetVersion: targetVersion2, targetIsPrerelease: isPrereleaseVersion(targetVersion2) };
57527
- }
57528
- const usePrereleaseChannel = opts.dev || opts.beta;
57529
- if (usePrereleaseChannel) {
57530
- let targetVersion2 = await client.getDevVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
57531
- if (!targetVersion2) {
57532
- spinnerStop("No dev version available");
57533
- logger.warning("No dev version found. Using latest stable version instead.");
57534
- targetVersion2 = await client.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
57535
- } else {
57536
- spinnerStop(`Latest dev version: ${targetVersion2}`);
57537
- return { targetVersion: targetVersion2, targetIsPrerelease: isPrereleaseVersion(targetVersion2) };
57538
- }
57539
- if (!targetVersion2) {
57540
- throw new CliUpdateError("Failed to fetch version information from npm registry. Check your internet connection and try again.");
57541
- }
57542
- spinnerStop(`Latest version: ${targetVersion2}`);
57543
- return { targetVersion: targetVersion2, targetIsPrerelease: isPrereleaseVersion(targetVersion2) };
57544
- }
57545
- const targetVersion = await client.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
57546
- spinnerStop(`Latest version: ${targetVersion || "unknown"}`);
57547
- if (!targetVersion) {
57548
- throw new CliUpdateError("Failed to fetch version information from npm registry. Check your internet connection and try again.");
57549
- }
57550
- return { targetVersion, targetIsPrerelease: isPrereleaseVersion(targetVersion) };
57551
- }
57552
- var init_channel_resolver = __esm(() => {
57553
- init_npm_registry();
57554
- init_version_utils();
57555
- init_claudekit_constants();
57556
- init_logger();
57557
- init_error();
57558
- });
57559
-
57560
- // src/commands/update/registry-client.ts
57561
- function redactCommandForLog(command) {
57562
- if (!command)
57563
- return command;
57564
- const redactedRegistryFlags = command.replace(/(--registry(?:=|\s+))(['"]?)(\S+?)(\2)(?=\s|$)/g, (_match, prefix, quote, url) => `${prefix}${quote}${redactRegistryUrlForLog(url)}${quote}`);
57565
- return redactedRegistryFlags.replace(/https?:\/\/[^\s"']+/g, (url) => redactRegistryUrlForLog(url));
57566
- }
57567
- var init_registry_client = __esm(() => {
57568
- init_npm_registry();
57569
- });
57570
-
57571
- // src/commands/update/version-comparator.ts
57572
- function compareCliVersions(currentVersion, targetVersion, opts) {
57573
- const comparison = import_compare_versions2.compareVersions(currentVersion, targetVersion);
57574
- if (comparison === 0) {
57575
- return { status: "up-to-date" };
57576
- }
57577
- const isDevChannelSwitch = (opts.dev || opts.beta) && isPrereleaseVersion(targetVersion) && !isPrereleaseVersion(currentVersion);
57578
- if (isDevChannelSwitch) {
57579
- return { status: "dev-channel-switch", changeType: "upgrade" };
57580
- }
57581
- if (comparison > 0 && !opts.release) {
57582
- return { status: "newer", changeType: "downgrade" };
57583
- }
57584
- return { status: "older", changeType: comparison < 0 ? "upgrade" : "downgrade" };
57585
- }
57586
- function isBetaVersion(version) {
57587
- return isPrereleaseVersion(version);
57588
- }
57589
- function parseCliVersionFromOutput(output2) {
57590
- if (!output2)
57591
- return null;
57592
- const match = output2.match(/CLI Version:\s*(\S+)/);
57593
- return match ? match[1] : null;
57594
- }
57595
- var import_compare_versions2;
57596
- var init_version_comparator = __esm(() => {
57597
- init_version_utils();
57598
- import_compare_versions2 = __toESM(require_umd(), 1);
57599
- });
57600
-
57601
- // src/commands/update/package-manager-runner.ts
57602
- function extractCommandStdout(result) {
57603
- if (typeof result === "string")
57604
- return result;
57605
- if (result && typeof result.stdout === "string")
57606
- return result.stdout;
57607
- return "";
57608
- }
57609
- async function runPackageManagerUpdate(updateCmd, pm, deps) {
57610
- const { execAsyncFn, spinnerStart, spinnerStop } = deps;
57611
- spinnerStart("Updating CLI...");
57612
- try {
57613
- await execAsyncFn(updateCmd, { timeout: 120000 });
57614
- spinnerStop("Update completed");
57615
- } catch (error) {
57616
- spinnerStop("Update failed");
57617
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
57618
- if (errorMessage.includes("EACCES") || errorMessage.includes("EPERM") || errorMessage.includes("permission") || errorMessage.includes("Access is denied")) {
57619
- const permHint = pm === "npm" ? `
57620
-
57621
- Or fix npm permissions: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally` : "";
57622
- const isWindows3 = process.platform === "win32";
57623
- const elevationHint = isWindows3 ? `Run your terminal as Administrator and retry: ${updateCmd}` : `sudo ${updateCmd}`;
57624
- throw new CliUpdateError(`Permission denied. Try: ${elevationHint}${permHint}`);
57625
- }
57626
- logger.error(`Update failed: ${errorMessage}`);
57627
- logger.info(`Try running: ${updateCmd}`);
57628
- throw new CliUpdateError(`Update failed: ${errorMessage}
57629
-
57630
- Manual update: ${updateCmd}`);
57631
- }
57632
- }
57633
- async function verifyInstalledVersion(targetVersion, updateCmd, deps) {
57634
- const { execAsyncFn, spinnerStart, spinnerStop } = deps;
57635
- spinnerStart("Verifying installation...");
57636
- try {
57637
- const versionResult = await execAsyncFn("ck --version", { timeout: 5000 });
57638
- const stdout = extractCommandStdout(versionResult);
57639
- const activeVersion = parseCliVersionFromOutput(stdout);
57640
- if (!activeVersion) {
57641
- spinnerStop("Verification failed");
57642
- const message = `Update completed but could not parse 'ck --version' output.
57643
- Please restart your terminal and run 'ck --version'. Expected: ${targetVersion}
57644
-
57645
- Manual update: ${redactCommandForLog(updateCmd)}`;
57646
- logger.error(message);
57647
- throw new CliUpdateError(message);
57648
- }
57649
- spinnerStop(`Installed version: ${activeVersion}`);
57650
- if (activeVersion !== targetVersion) {
57651
- const mismatchMessage = `Update did not activate the requested version.
57652
- Expected: ${targetVersion}
57653
- Active ck: ${activeVersion}
57654
-
57655
- Likely causes: multiple global installations (npm/bun/pnpm/yarn) or stale shell shim/cache (common on Windows).
57656
- Run '${redactCommandForLog(updateCmd)}' manually, restart terminal, then check command resolution:
57657
- - Windows: where ck
57658
- - macOS/Linux: which -a ck`;
57659
- logger.error(mismatchMessage);
57660
- throw new CliUpdateError(mismatchMessage);
57661
- }
57662
- return activeVersion;
57663
- } catch (error) {
57664
- if (error instanceof CliUpdateError)
57665
- throw error;
57666
- spinnerStop("Verification failed");
57667
- const message = `Update completed but automatic verification failed.
57668
- Please restart your terminal and run 'ck --version'. Expected: ${targetVersion}
57669
-
57670
- Manual update: ${redactCommandForLog(updateCmd)}`;
57671
- logger.error(message);
57672
- throw new CliUpdateError(message);
57673
- }
57674
- }
57675
- var init_package_manager_runner = __esm(() => {
57676
- init_logger();
57677
- init_error();
57678
- init_registry_client();
57679
- init_version_comparator();
57680
- });
57681
-
57682
- // src/domains/migration/metadata-migration.ts
57683
- import { join as join45 } from "node:path";
57684
- async function detectMetadataFormat(claudeDir2) {
57685
- const metadataPath = join45(claudeDir2, "metadata.json");
57686
- if (!await import_fs_extra3.pathExists(metadataPath)) {
57687
- return { format: "none", metadata: null, detectedKit: null };
57688
- }
57689
- try {
57690
- const content = await import_fs_extra3.readFile(metadataPath, "utf-8");
57691
- const parsed = JSON.parse(content);
57692
- if (parsed.kits && Object.keys(parsed.kits).length > 0) {
57693
- const installedKits = Object.keys(parsed.kits);
57694
- return {
57695
- format: "multi-kit",
57696
- metadata: parsed,
57697
- detectedKit: installedKits[0] || null
57698
- };
57699
- }
57700
- if (parsed.name || parsed.version || parsed.files) {
57701
- let detectedKit = null;
57702
- const nameToCheck = parsed.name || "";
57703
- if (/\bengineer\b/i.test(nameToCheck)) {
57704
- detectedKit = "engineer";
57705
- } else if (/\bmarketing\b/i.test(nameToCheck)) {
57706
- detectedKit = "marketing";
57707
- } else {
57708
- detectedKit = "engineer";
57709
- }
57710
- return { format: "legacy", metadata: parsed, detectedKit };
57711
- }
57712
- logger.warning("Metadata file exists but has unrecognized format (missing kits, name, version, or files)");
57713
- return { format: "none", metadata: null, detectedKit: null };
57714
- } catch (error) {
57715
- logger.warning(`Failed to read metadata file (may be corrupted): ${error}`);
57716
- return { format: "none", metadata: null, detectedKit: null };
57717
- }
57718
- }
57719
- async function migrateToMultiKit(claudeDir2) {
57720
- const detection = await detectMetadataFormat(claudeDir2);
57721
- if (detection.format === "multi-kit") {
57722
- return {
57723
- success: true,
57724
- migrated: false,
57725
- fromFormat: "multi-kit",
57726
- toFormat: "multi-kit"
57727
- };
57728
- }
57729
- if (detection.format === "none") {
57730
- return {
57731
- success: true,
57732
- migrated: false,
57733
- fromFormat: "none",
57734
- toFormat: "multi-kit"
57735
- };
57736
- }
57737
- const metadataPath = join45(claudeDir2, "metadata.json");
57738
- const legacy = detection.metadata;
57739
- if (!legacy) {
57740
- return {
57741
- success: false,
57742
- migrated: false,
57743
- fromFormat: "legacy",
57744
- toFormat: "multi-kit",
57745
- error: "Metadata exists but could not be read"
57746
- };
57747
- }
57748
- const legacyKit = detection.detectedKit || "engineer";
57749
- try {
57750
- const kitMetadata = {
57751
- version: legacy.version || "unknown",
57752
- installedAt: legacy.installedAt || new Date().toISOString(),
57753
- files: legacy.files || []
57754
- };
57755
- const multiKit = {
57756
- kits: {
57757
- [legacyKit]: kitMetadata
57758
- },
57759
- scope: legacy.scope,
57760
- name: legacy.name,
57761
- version: legacy.version,
57762
- installedAt: legacy.installedAt,
57763
- installedFiles: legacy.installedFiles,
57764
- userConfigFiles: legacy.userConfigFiles,
57765
- files: legacy.files
57766
- };
57767
- await import_fs_extra3.writeFile(metadataPath, JSON.stringify(multiKit, null, 2), "utf-8");
57768
- logger.info(`Migrated metadata from legacy format to multi-kit (detected: ${legacyKit})`);
57769
- return {
57770
- success: true,
57771
- migrated: true,
57772
- fromFormat: "legacy",
57773
- toFormat: "multi-kit"
57774
- };
57775
- } catch (error) {
57776
- const errorMsg = error instanceof Error ? error.message : "Unknown error";
57777
- logger.error(`Metadata migration failed: ${errorMsg}`);
57778
- return {
57779
- success: false,
57780
- migrated: false,
57781
- fromFormat: "legacy",
57782
- toFormat: "multi-kit",
57783
- error: errorMsg
57784
- };
57785
- }
57786
- }
57787
- function getKitMetadata(metadata, kit) {
57788
- if (metadata.kits?.[kit]) {
57789
- return metadata.kits[kit];
57790
- }
57791
- if (!metadata.kits && metadata.version) {
57792
- return {
57793
- version: metadata.version,
57794
- installedAt: metadata.installedAt || "",
57795
- files: metadata.files
57796
- };
57797
- }
57798
- return null;
57799
- }
57800
- function getAllTrackedFiles(metadata) {
57801
- if (metadata.kits) {
57802
- const allFiles = [];
57803
- for (const kit of Object.values(metadata.kits)) {
57804
- if (kit.files) {
57805
- allFiles.push(...kit.files);
57806
- }
57807
- }
57808
- return allFiles;
57809
- }
57810
- return metadata.files || [];
57811
- }
57812
- function getTrackedFilesForKit(metadata, kitType) {
57813
- if (metadata.kits?.[kitType]) {
57814
- return metadata.kits[kitType].files || [];
57815
- }
57816
- const detectedKits = getInstalledKits(metadata);
57817
- if (detectedKits.includes(kitType)) {
57818
- return metadata.files || [];
57819
- }
57820
- return [];
57821
- }
57822
- function getInstalledKits(metadata) {
57823
- if (metadata.kits) {
57824
- return Object.keys(metadata.kits);
57825
- }
57826
- const nameToCheck = metadata.name || "";
57827
- const kits = [];
57828
- if (/\bengineer\b/i.test(nameToCheck)) {
57829
- kits.push("engineer");
57830
- }
57831
- if (/\bmarketing\b/i.test(nameToCheck)) {
57832
- kits.push("marketing");
57833
- }
57834
- if (kits.length > 0) {
57835
- return kits;
57836
- }
57837
- if (metadata.version) {
57838
- return ["engineer"];
57839
- }
57840
- return [];
57841
- }
57842
- var import_fs_extra3;
57843
- var init_metadata_migration = __esm(() => {
57844
- init_logger();
57845
- import_fs_extra3 = __toESM(require_lib3(), 1);
57846
- });
57847
-
57848
57528
  // src/services/file-operations/claudekit-scanner.ts
57849
57529
  import { join as join46 } from "node:path";
57850
57530
  async function scanClaudeKitDirectory(directoryPath) {
@@ -57947,6 +57627,117 @@ var init_claudekit_scanner = __esm(() => {
57947
57627
  import_fs_extra4 = __toESM(require_lib3(), 1);
57948
57628
  });
57949
57629
 
57630
+ // package.json
57631
+ var package_default;
57632
+ var init_package = __esm(() => {
57633
+ package_default = {
57634
+ name: "claudekit-cli",
57635
+ version: "3.41.2",
57636
+ description: "CLI tool for bootstrapping and updating ClaudeKit projects",
57637
+ type: "module",
57638
+ repository: {
57639
+ type: "git",
57640
+ url: "git+https://github.com/mrgoonie/claudekit-cli.git"
57641
+ },
57642
+ publishConfig: {
57643
+ access: "public",
57644
+ registry: "https://registry.npmjs.org"
57645
+ },
57646
+ bin: {
57647
+ ck: "bin/ck.js"
57648
+ },
57649
+ files: [
57650
+ "bin/ck.js",
57651
+ "dist/index.js",
57652
+ "dist/ui/"
57653
+ ],
57654
+ scripts: {
57655
+ dev: "bun run src/index.ts",
57656
+ "dashboard:dev": "cd src/ui && bun install --silent && cd ../.. && bun run src/index.ts config ui --dev",
57657
+ "ui:build": "cd src/ui && bun install --silent && bun run build",
57658
+ "ui:dev": "cd src/ui && bun run dev",
57659
+ build: `bun build src/index.ts --outdir dist --target node --external @octokit/rest --external better-sqlite3 && node -e "const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf-8');fs.writeFileSync(f,c.replace(/^#!.*\\n\\/\\/ @bun\\n/,''))"`,
57660
+ "verify:package": "node scripts/prepublish-check.js",
57661
+ test: "bun test",
57662
+ "test:integration": "CK_RUN_CLI_INTEGRATION=1 bun test tests/integration/cli.test.ts",
57663
+ "test:watch": "bun test --watch",
57664
+ "test:quick": "./scripts/dev-quick-start.sh test",
57665
+ lint: "biome check .",
57666
+ "lint:fix": "biome check --fix .",
57667
+ "lint:fix-unsafe": "biome check --fix --unsafe .",
57668
+ format: "biome format --write .",
57669
+ typecheck: "tsc --noEmit",
57670
+ "dev:quick": "./scripts/dev-quick-start.sh",
57671
+ "dev:all": "./scripts/dev-quick-start.sh all",
57672
+ metrics: "bun run scripts/workflow-metrics.ts",
57673
+ validate: "bun run typecheck && bun run lint && bun test && bun run build",
57674
+ "install:hooks": "./.githooks/install.sh",
57675
+ prepare: `node -e "try{require('child_process').execSync('git rev-parse --git-dir',{stdio:'ignore'});require('child_process').execSync('bash .githooks/install.sh',{stdio:'inherit'})}catch(e){console.warn('[i] Hook install skipped:',e.message)}"`
57676
+ },
57677
+ keywords: [
57678
+ "cli",
57679
+ "claudekit",
57680
+ "boilerplate",
57681
+ "bootstrap",
57682
+ "template"
57683
+ ],
57684
+ author: "ClaudeKit",
57685
+ license: "MIT",
57686
+ engines: {
57687
+ node: ">=18.0.0"
57688
+ },
57689
+ dependencies: {
57690
+ "@clack/prompts": "^0.7.0",
57691
+ "@octokit/rest": "^22.0.0",
57692
+ "better-sqlite3": "^12.6.2",
57693
+ cac: "^6.7.14",
57694
+ chokidar: "^5.0.0",
57695
+ "cli-progress": "^3.12.0",
57696
+ "compare-versions": "^6.1.1",
57697
+ diff: "^8.0.3",
57698
+ express: "^5.2.1",
57699
+ "extract-zip": "^2.0.1",
57700
+ "fs-extra": "^11.2.0",
57701
+ "get-port": "^7.1.0",
57702
+ "gray-matter": "^4.0.3",
57703
+ ignore: "^5.3.2",
57704
+ minimatch: "^10.1.1",
57705
+ open: "^11.0.0",
57706
+ ora: "^8.0.0",
57707
+ "p-limit": "^7.2.0",
57708
+ picocolors: "^1.1.1",
57709
+ picomatch: "^4.0.3",
57710
+ "proper-lockfile": "^4.1.2",
57711
+ semver: "^7.7.3",
57712
+ tar: "^7.4.3",
57713
+ tmp: "^0.2.3",
57714
+ ws: "^8.19.0",
57715
+ zod: "^3.23.8"
57716
+ },
57717
+ devDependencies: {
57718
+ "@biomejs/biome": "^1.9.4",
57719
+ "@semantic-release/changelog": "^6.0.3",
57720
+ "@semantic-release/git": "^10.0.1",
57721
+ "@types/better-sqlite3": "^7.6.13",
57722
+ "@types/bun": "latest",
57723
+ "@types/cli-progress": "^3.11.6",
57724
+ "@types/diff": "^8.0.0",
57725
+ "@types/express": "^5.0.6",
57726
+ "@types/fs-extra": "^11.0.4",
57727
+ "@types/node": "^22.19.7",
57728
+ "@types/picomatch": "^4.0.2",
57729
+ "@types/proper-lockfile": "^4.1.4",
57730
+ "@types/semver": "^7.7.1",
57731
+ "@types/tar": "^6.1.13",
57732
+ "@types/tmp": "^0.2.6",
57733
+ "@types/ws": "^8.18.1",
57734
+ "conventional-changelog-conventionalcommits": "^9.1.0",
57735
+ "semantic-release": "^24.2.0",
57736
+ typescript: "^5.7.2"
57737
+ }
57738
+ };
57739
+ });
57740
+
57950
57741
  // src/domains/github/github-auth.ts
57951
57742
  import { execSync } from "node:child_process";
57952
57743
 
@@ -58354,7 +58145,7 @@ ${action.title}:`);
58354
58145
  }
58355
58146
 
58356
58147
  // src/domains/error/index.ts
58357
- var init_error2 = () => {};
58148
+ var init_error = () => {};
58358
58149
 
58359
58150
  // src/domains/github/client/error-handler.ts
58360
58151
  async function handleHttpError(error, context) {
@@ -58385,7 +58176,7 @@ Need help? Run with: ${verboseFlag}`);
58385
58176
  `), classified.httpStatus);
58386
58177
  }
58387
58178
  var init_error_handler2 = __esm(() => {
58388
- init_error2();
58179
+ init_error();
58389
58180
  init_types3();
58390
58181
  init_auth_api();
58391
58182
  });
@@ -58506,7 +58297,7 @@ class VersionFormatter {
58506
58297
  static compare(v1, v2) {
58507
58298
  const normV1 = VersionFormatter.normalize(v1);
58508
58299
  const normV2 = VersionFormatter.normalize(v2);
58509
- return import_compare_versions3.compareVersions(normV1, normV2);
58300
+ return import_compare_versions2.compareVersions(normV1, normV2);
58510
58301
  }
58511
58302
  static formatRelativeTime(dateString) {
58512
58303
  if (!dateString)
@@ -58594,20 +58385,20 @@ class VersionFormatter {
58594
58385
  const majorA = Number.parseInt(normA.split(".")[0], 10);
58595
58386
  const majorB = Number.parseInt(normB.split(".")[0], 10);
58596
58387
  if (majorA === 0 && majorB === 0) {
58597
- return import_compare_versions3.compareVersions(normB, normA);
58388
+ return import_compare_versions2.compareVersions(normB, normA);
58598
58389
  }
58599
58390
  if (majorA === 0)
58600
58391
  return 1;
58601
58392
  if (majorB === 0)
58602
58393
  return -1;
58603
- return import_compare_versions3.compareVersions(normB, normA);
58394
+ return import_compare_versions2.compareVersions(normB, normA);
58604
58395
  });
58605
58396
  }
58606
58397
  }
58607
- var import_compare_versions3;
58398
+ var import_compare_versions2;
58608
58399
  var init_version_formatter = __esm(() => {
58609
58400
  init_logger();
58610
- import_compare_versions3 = __toESM(require_umd(), 1);
58401
+ import_compare_versions2 = __toESM(require_umd(), 1);
58611
58402
  });
58612
58403
 
58613
58404
  // src/domains/versioning/release-filter.ts
@@ -59116,16 +58907,64 @@ var init_github_client = __esm(() => {
59116
58907
  init_client();
59117
58908
  });
59118
58909
 
59119
- // src/commands/update/post-update-handler.ts
58910
+ // src/commands/update-cli.ts
59120
58911
  import { exec as exec2, spawn as spawn2 } from "node:child_process";
59121
58912
  import { join as join48 } from "node:path";
59122
58913
  import { promisify as promisify8 } from "node:util";
58914
+ function getDefaultUpdateCliCommandDeps() {
58915
+ return {
58916
+ currentVersion: package_default.version,
58917
+ execAsyncFn: execAsync2,
58918
+ packageManagerDetector: PackageManagerDetector,
58919
+ npmRegistryClient: NpmRegistryClient,
58920
+ promptKitUpdateFn: promptKitUpdate,
58921
+ promptMigrateUpdateFn: promptMigrateUpdate
58922
+ };
58923
+ }
58924
+ function extractCommandStdout(result) {
58925
+ if (typeof result === "string") {
58926
+ return result;
58927
+ }
58928
+ if (result && typeof result.stdout === "string") {
58929
+ return result.stdout;
58930
+ }
58931
+ return "";
58932
+ }
58933
+ function redactCommandForLog(command) {
58934
+ if (!command)
58935
+ return command;
58936
+ const redactedRegistryFlags = command.replace(/(--registry(?:=|\s+))(['"]?)(\S+?)(\2)(?=\s|$)/g, (_match, prefix, quote, url) => `${prefix}${quote}${redactRegistryUrlForLog(url)}${quote}`);
58937
+ return redactedRegistryFlags.replace(/https?:\/\/[^\s"']+/g, (url) => redactRegistryUrlForLog(url));
58938
+ }
58939
+ function buildInitCommand(isGlobal, kit, beta, yes) {
58940
+ const parts = ["ck init"];
58941
+ if (isGlobal)
58942
+ parts.push("-g");
58943
+ if (kit)
58944
+ parts.push(`--kit ${kit}`);
58945
+ if (yes)
58946
+ parts.push("--yes");
58947
+ parts.push("--install-skills");
58948
+ if (beta)
58949
+ parts.push("--beta");
58950
+ return parts.join(" ");
58951
+ }
58952
+ function isBetaVersion(version) {
58953
+ return isPrereleaseVersion(version);
58954
+ }
58955
+ function parseCliVersionFromOutput(output2) {
58956
+ if (!output2)
58957
+ return null;
58958
+ const match = output2.match(/CLI Version:\s*(\S+)/);
58959
+ return match ? match[1] : null;
58960
+ }
59123
58961
  function selectKitForUpdate(params) {
59124
58962
  const { hasLocal, hasGlobal, localKits, globalKits } = params;
59125
58963
  const hasLocalKit = localKits.length > 0 || hasLocal;
59126
58964
  const hasGlobalKit = globalKits.length > 0 || hasGlobal;
59127
- if (!hasLocalKit && !hasGlobalKit)
58965
+ if (!hasLocalKit && !hasGlobalKit) {
59128
58966
  return null;
58967
+ }
59129
58968
  if (hasGlobalKit && !hasLocalKit) {
59130
58969
  const kit2 = globalKits[0] || localKits[0];
59131
58970
  return {
@@ -59152,8 +58991,9 @@ function selectKitForUpdate(params) {
59152
58991
  async function readMetadataFile(claudeDir2) {
59153
58992
  const metadataPath = join48(claudeDir2, "metadata.json");
59154
58993
  try {
59155
- if (!await import_fs_extra5.pathExists(metadataPath))
58994
+ if (!await import_fs_extra5.pathExists(metadataPath)) {
59156
58995
  return null;
58996
+ }
59157
58997
  const content = await import_fs_extra5.readFile(metadataPath, "utf-8");
59158
58998
  const parsed = JSON.parse(content);
59159
58999
  const validated = MetadataSchema.safeParse(parsed);
@@ -59167,19 +59007,6 @@ async function readMetadataFile(claudeDir2) {
59167
59007
  return null;
59168
59008
  }
59169
59009
  }
59170
- function buildInitCommand(isGlobal, kit, beta, yes) {
59171
- const parts = ["ck init"];
59172
- if (isGlobal)
59173
- parts.push("-g");
59174
- if (kit)
59175
- parts.push(`--kit ${kit}`);
59176
- if (yes)
59177
- parts.push("--yes");
59178
- parts.push("--install-skills");
59179
- if (beta)
59180
- parts.push("--beta");
59181
- return parts.join(" ");
59182
- }
59183
59010
  async function fetchLatestReleaseTag(kit, beta) {
59184
59011
  try {
59185
59012
  const { GitHubClient: GitHubClient2 } = await Promise.resolve().then(() => (init_github_client(), exports_github_client));
@@ -59233,11 +59060,14 @@ async function promptKitUpdate(beta, yes, deps) {
59233
59060
  const ckConfig = await loadFullConfigFn(null);
59234
59061
  autoInit = ckConfig.config.updatePipeline?.autoInitAfterUpdate ?? false;
59235
59062
  } catch {}
59236
- if (alreadyAtLatest && !autoInit)
59063
+ if (alreadyAtLatest && !autoInit) {
59237
59064
  return;
59065
+ }
59238
59066
  if (!yes && !autoInit) {
59239
59067
  logger.info("");
59240
- const shouldUpdate = await confirmFn({ message: promptMessage });
59068
+ const shouldUpdate = await confirmFn({
59069
+ message: promptMessage
59070
+ });
59241
59071
  if (isCancelFn(shouldUpdate) || !shouldUpdate) {
59242
59072
  log.info("Skipped kit content update");
59243
59073
  return;
@@ -59375,37 +59205,6 @@ async function promptMigrateUpdate(deps) {
59375
59205
  logger.verbose(`Migrate step skipped: ${error instanceof Error ? error.message : "unknown"}`);
59376
59206
  }
59377
59207
  }
59378
- var import_fs_extra5, execAsync2, SAFE_PROVIDER_NAME;
59379
- var init_post_update_handler = __esm(() => {
59380
- init_ck_config_manager();
59381
- init_metadata_migration();
59382
- init_version_utils();
59383
- init_claudekit_scanner();
59384
- init_logger();
59385
- init_safe_prompts();
59386
- init_types3();
59387
- init_version_comparator();
59388
- import_fs_extra5 = __toESM(require_lib3(), 1);
59389
- execAsync2 = promisify8(exec2);
59390
- SAFE_PROVIDER_NAME = /^[a-z0-9-]+$/;
59391
- });
59392
-
59393
- // src/commands/update-cli.ts
59394
- function getDefaultUpdateCliCommandDeps() {
59395
- return {
59396
- currentVersion: package_default.version,
59397
- execAsyncFn: async (cmd, opts) => {
59398
- const { exec: exec3 } = await import("node:child_process");
59399
- const { promisify: promisify9 } = await import("node:util");
59400
- const result = await promisify9(exec3)(cmd, opts);
59401
- return { stdout: String(result.stdout ?? ""), stderr: String(result.stderr ?? "") };
59402
- },
59403
- packageManagerDetector: PackageManagerDetector,
59404
- npmRegistryClient: NpmRegistryClient,
59405
- promptKitUpdateFn: promptKitUpdate,
59406
- promptMigrateUpdateFn: promptMigrateUpdate
59407
- };
59408
- }
59409
59208
  async function updateCliCommand(options2, deps = getDefaultUpdateCliCommandDeps()) {
59410
59209
  const s = de();
59411
59210
  intro("[>] ClaudeKit CLI - Update");
@@ -59430,31 +59229,64 @@ async function updateCliCommand(options2, deps = getDefaultUpdateCliCommandDeps(
59430
59229
  const userRegistry = await packageManagerDetector.getNpmRegistryUrl();
59431
59230
  if (userRegistry) {
59432
59231
  registryUrl = userRegistry;
59433
- const { redactRegistryUrlForLog: redactRegistryUrlForLog2 } = await Promise.resolve().then(() => (init_npm_registry(), exports_npm_registry));
59434
- logger.verbose(`Using npm configured registry: ${redactRegistryUrlForLog2(registryUrl)}`);
59232
+ logger.verbose(`Using npm configured registry: ${redactRegistryUrlForLog(registryUrl)}`);
59435
59233
  }
59436
59234
  }
59437
59235
  s.start("Checking for updates...");
59438
- const { targetVersion, targetIsPrerelease } = await resolveTargetVersion(opts, {
59439
- npmRegistryClient,
59440
- registryUrl,
59441
- spinnerStop: (msg) => s.stop(msg)
59442
- });
59443
- const outcome = compareCliVersions(currentVersion, targetVersion, opts);
59444
- if (outcome.status === "up-to-date") {
59236
+ let targetVersion = null;
59237
+ const usePrereleaseChannel = opts.dev || opts.beta;
59238
+ if (opts.release && opts.release !== "latest") {
59239
+ try {
59240
+ const exists = await npmRegistryClient.versionExists(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, opts.release, registryUrl);
59241
+ if (!exists) {
59242
+ s.stop("Version not found");
59243
+ throw new CliUpdateError(`Version ${opts.release} does not exist on npm registry. Run 'ck versions' to see available versions.`);
59244
+ }
59245
+ } catch (error) {
59246
+ if (error instanceof CliUpdateError) {
59247
+ throw error;
59248
+ }
59249
+ s.stop("Version check failed");
59250
+ const message = error instanceof Error ? error.message : "Unknown error";
59251
+ logger.verbose(`Release check failed for ${opts.release}: ${message}`);
59252
+ const registryHint = registryUrl ? ` (${redactRegistryUrlForLog(registryUrl)})` : " (default registry)";
59253
+ throw new CliUpdateError(`Failed to verify version ${opts.release} on npm registry${registryHint}. Check registry settings/network connectivity and try again.`);
59254
+ }
59255
+ targetVersion = opts.release;
59256
+ s.stop(`Target version: ${targetVersion}`);
59257
+ } else if (usePrereleaseChannel) {
59258
+ targetVersion = await npmRegistryClient.getDevVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
59259
+ if (!targetVersion) {
59260
+ s.stop("No dev version available");
59261
+ logger.warning("No dev version found. Using latest stable version instead.");
59262
+ targetVersion = await npmRegistryClient.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
59263
+ } else {
59264
+ s.stop(`Latest dev version: ${targetVersion}`);
59265
+ }
59266
+ } else {
59267
+ targetVersion = await npmRegistryClient.getLatestVersion(CLAUDEKIT_CLI_NPM_PACKAGE_NAME, registryUrl);
59268
+ s.stop(`Latest version: ${targetVersion || "unknown"}`);
59269
+ }
59270
+ if (!targetVersion) {
59271
+ throw new CliUpdateError(`Failed to fetch version information from npm registry. Check your internet connection and try again. Manual update: ${packageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME, undefined, registryUrl)}`);
59272
+ }
59273
+ const comparison = import_compare_versions3.compareVersions(currentVersion, targetVersion);
59274
+ const targetIsPrerelease = isPrereleaseVersion(targetVersion);
59275
+ if (comparison === 0) {
59445
59276
  outro(`[+] Already on the latest CLI version (${currentVersion})`);
59446
59277
  await promptKitUpdateFn(targetIsPrerelease, opts.yes);
59447
59278
  await promptMigrateUpdateFn();
59448
59279
  return;
59449
59280
  }
59450
- if (outcome.status === "newer") {
59281
+ const isDevChannelSwitch = (opts.dev || opts.beta) && isBetaVersion(targetVersion) && !isBetaVersion(currentVersion);
59282
+ if (comparison > 0 && !opts.release && !isDevChannelSwitch) {
59451
59283
  outro(`[+] Current version (${currentVersion}) is newer than latest (${targetVersion})`);
59452
59284
  await promptKitUpdateFn(targetIsPrerelease, opts.yes);
59453
59285
  await promptMigrateUpdateFn();
59454
59286
  return;
59455
59287
  }
59456
- const isUpgrade = outcome.changeType === "upgrade";
59457
- const changeType = outcome.changeType;
59288
+ const isUpgrade = comparison < 0 || isDevChannelSwitch;
59289
+ const changeType = isUpgrade ? "upgrade" : "downgrade";
59458
59290
  logger.info(`${isUpgrade ? "[^]" : "[v]"} ${changeType}: ${currentVersion} -> ${targetVersion}`);
59459
59291
  if (opts.check) {
59460
59292
  note(`CLI update available: ${currentVersion} -> ${targetVersion}
@@ -59476,19 +59308,71 @@ Run 'ck update' to install`, "Update Check");
59476
59308
  }
59477
59309
  const updateCmd = packageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME, targetVersion, registryUrl);
59478
59310
  logger.info(`Running: ${redactCommandForLog(updateCmd)}`);
59479
- await runPackageManagerUpdate(updateCmd, pm, {
59480
- execAsyncFn,
59481
- spinnerStart: (msg) => s.start(msg),
59482
- spinnerStop: (msg) => s.stop(msg)
59483
- });
59484
- const activeVersion = await verifyInstalledVersion(targetVersion, updateCmd, {
59485
- execAsyncFn,
59486
- spinnerStart: (msg) => s.start(msg),
59487
- spinnerStop: (msg) => s.stop(msg)
59488
- });
59489
- outro(`[+] Successfully updated ClaudeKit CLI to ${activeVersion}`);
59490
- await promptKitUpdateFn(targetIsPrerelease, opts.yes);
59491
- await promptMigrateUpdateFn();
59311
+ s.start("Updating CLI...");
59312
+ try {
59313
+ await execAsyncFn(updateCmd, {
59314
+ timeout: 120000
59315
+ });
59316
+ s.stop("Update completed");
59317
+ } catch (error) {
59318
+ s.stop("Update failed");
59319
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
59320
+ if (errorMessage.includes("EACCES") || errorMessage.includes("EPERM") || errorMessage.includes("permission") || errorMessage.includes("Access is denied")) {
59321
+ const permHint = pm === "npm" ? `
59322
+
59323
+ Or fix npm permissions: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally` : "";
59324
+ const isWindows3 = process.platform === "win32";
59325
+ const elevationHint = isWindows3 ? `Run your terminal as Administrator and retry: ${updateCmd}` : `sudo ${updateCmd}`;
59326
+ throw new CliUpdateError(`Permission denied. Try: ${elevationHint}${permHint}`);
59327
+ }
59328
+ logger.error(`Update failed: ${errorMessage}`);
59329
+ logger.info(`Try running: ${redactCommandForLog(updateCmd)}`);
59330
+ throw new CliUpdateError(`Update failed: ${errorMessage}
59331
+
59332
+ Manual update: ${updateCmd}`);
59333
+ }
59334
+ s.start("Verifying installation...");
59335
+ try {
59336
+ const versionResult = await execAsyncFn("ck --version", { timeout: 5000 });
59337
+ const stdout = extractCommandStdout(versionResult);
59338
+ const activeVersion = parseCliVersionFromOutput(stdout);
59339
+ if (!activeVersion) {
59340
+ s.stop("Verification failed");
59341
+ const message = `Update completed but could not parse 'ck --version' output.
59342
+ Please restart your terminal and run 'ck --version'. Expected: ${targetVersion}
59343
+
59344
+ Manual update: ${redactCommandForLog(updateCmd)}`;
59345
+ logger.error(message);
59346
+ throw new CliUpdateError(message);
59347
+ }
59348
+ s.stop(`Installed version: ${activeVersion}`);
59349
+ if (activeVersion !== targetVersion) {
59350
+ const mismatchMessage = `Update did not activate the requested version.
59351
+ Expected: ${targetVersion}
59352
+ Active ck: ${activeVersion}
59353
+
59354
+ Likely causes: multiple global installations (npm/bun/pnpm/yarn) or stale shell shim/cache (common on Windows).
59355
+ Run '${redactCommandForLog(updateCmd)}' manually, restart terminal, then check command resolution:
59356
+ - Windows: where ck
59357
+ - macOS/Linux: which -a ck`;
59358
+ logger.error(mismatchMessage);
59359
+ throw new CliUpdateError(mismatchMessage);
59360
+ }
59361
+ outro(`[+] Successfully updated ClaudeKit CLI to ${activeVersion}`);
59362
+ await promptKitUpdateFn(targetIsPrerelease, opts.yes);
59363
+ await promptMigrateUpdateFn();
59364
+ } catch (error) {
59365
+ if (error instanceof CliUpdateError) {
59366
+ throw error;
59367
+ }
59368
+ s.stop("Verification failed");
59369
+ const message = `Update completed but automatic verification failed.
59370
+ Please restart your terminal and run 'ck --version'. Expected: ${targetVersion}
59371
+
59372
+ Manual update: ${redactCommandForLog(updateCmd)}`;
59373
+ logger.error(message);
59374
+ throw new CliUpdateError(message);
59375
+ }
59492
59376
  } catch (error) {
59493
59377
  if (error instanceof CliUpdateError) {
59494
59378
  throw error;
@@ -59498,24 +59382,30 @@ Run 'ck update' to install`, "Update Check");
59498
59382
  throw new CliUpdateError(errorMessage);
59499
59383
  }
59500
59384
  }
59385
+ var import_compare_versions3, import_fs_extra5, execAsync2, CliUpdateError, SAFE_PROVIDER_NAME;
59501
59386
  var init_update_cli = __esm(() => {
59387
+ init_ck_config_manager();
59502
59388
  init_npm_registry();
59503
59389
  init_package_manager_detector();
59390
+ init_metadata_migration();
59391
+ init_version_utils();
59392
+ init_claudekit_scanner();
59504
59393
  init_claudekit_constants();
59505
59394
  init_logger();
59506
59395
  init_safe_prompts();
59507
59396
  init_types3();
59397
+ init_types3();
59508
59398
  init_package();
59509
- init_channel_resolver();
59510
- init_error();
59511
- init_package_manager_runner();
59512
- init_post_update_handler();
59513
- init_registry_client();
59514
- init_version_comparator();
59515
- init_error();
59516
- init_version_comparator();
59517
- init_post_update_handler();
59518
- init_registry_client();
59399
+ import_compare_versions3 = __toESM(require_umd(), 1);
59400
+ import_fs_extra5 = __toESM(require_lib3(), 1);
59401
+ execAsync2 = promisify8(exec2);
59402
+ CliUpdateError = class CliUpdateError extends ClaudeKitError {
59403
+ constructor(message) {
59404
+ super(message, "CLI_UPDATE_ERROR");
59405
+ this.name = "CliUpdateError";
59406
+ }
59407
+ };
59408
+ SAFE_PROVIDER_NAME = /^[a-z0-9-]+$/;
59519
59409
  });
59520
59410
 
59521
59411
  // src/domains/versioning/version-cache.ts
@@ -68453,7 +68343,7 @@ var init_content_validator = __esm(() => {
68453
68343
  import { createHash as createHash6 } from "node:crypto";
68454
68344
  import { existsSync as existsSync66, mkdirSync as mkdirSync4, readFileSync as readFileSync15, readdirSync as readdirSync8, statSync as statSync10 } from "node:fs";
68455
68345
  import { rename as rename9, writeFile as writeFile35 } from "node:fs/promises";
68456
- import { homedir as homedir33 } from "node:os";
68346
+ import { homedir as homedir34 } from "node:os";
68457
68347
  import { basename as basename19, join as join132 } from "node:path";
68458
68348
  function getCachedContext(repoPath) {
68459
68349
  const cachePath = getCacheFilePath(repoPath);
@@ -68528,7 +68418,7 @@ function getCacheFilePath(repoPath) {
68528
68418
  }
68529
68419
  var CACHE_DIR, CACHE_TTL_MS4;
68530
68420
  var init_context_cache_manager = __esm(() => {
68531
- CACHE_DIR = join132(homedir33(), ".claudekit", "cache");
68421
+ CACHE_DIR = join132(homedir34(), ".claudekit", "cache");
68532
68422
  CACHE_TTL_MS4 = 24 * 60 * 60 * 1000;
68533
68423
  });
68534
68424
 
@@ -68982,10 +68872,10 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
68982
68872
  // src/commands/content/phases/photo-generator.ts
68983
68873
  import { execSync as execSync7 } from "node:child_process";
68984
68874
  import { existsSync as existsSync68, mkdirSync as mkdirSync5, readdirSync as readdirSync10 } from "node:fs";
68985
- import { homedir as homedir34 } from "node:os";
68875
+ import { homedir as homedir35 } from "node:os";
68986
68876
  import { join as join134 } from "node:path";
68987
68877
  async function generatePhoto(_content, context, config, platform14, contentId, contentLogger) {
68988
- const mediaDir = join134(config.contentDir.replace(/^~/, homedir34()), "media", String(contentId));
68878
+ const mediaDir = join134(config.contentDir.replace(/^~/, homedir35()), "media", String(contentId));
68989
68879
  if (!existsSync68(mediaDir)) {
68990
68880
  mkdirSync5(mediaDir, { recursive: true });
68991
68881
  }
@@ -69099,7 +68989,7 @@ var init_content_creator = __esm(() => {
69099
68989
 
69100
68990
  // src/commands/content/phases/content-logger.ts
69101
68991
  import { createWriteStream as createWriteStream4, existsSync as existsSync69, mkdirSync as mkdirSync6, statSync as statSync11 } from "node:fs";
69102
- import { homedir as homedir35 } from "node:os";
68992
+ import { homedir as homedir36 } from "node:os";
69103
68993
  import { join as join135 } from "node:path";
69104
68994
 
69105
68995
  class ContentLogger {
@@ -69108,7 +68998,7 @@ class ContentLogger {
69108
68998
  logDir;
69109
68999
  maxBytes;
69110
69000
  constructor(maxBytes = 0) {
69111
- this.logDir = join135(homedir35(), ".claudekit", "logs");
69001
+ this.logDir = join135(homedir36(), ".claudekit", "logs");
69112
69002
  this.maxBytes = maxBytes;
69113
69003
  }
69114
69004
  init() {
@@ -70707,11 +70597,11 @@ var init_setup_wizard = __esm(() => {
70707
70597
 
70708
70598
  // src/commands/content/content-review-commands.ts
70709
70599
  import { existsSync as existsSync73 } from "node:fs";
70710
- import { homedir as homedir36 } from "node:os";
70600
+ import { homedir as homedir37 } from "node:os";
70711
70601
  async function queueContent() {
70712
70602
  const cwd2 = process.cwd();
70713
70603
  const config = await loadContentConfig(cwd2);
70714
- const dbPath = config.dbPath.replace(/^~/, homedir36());
70604
+ const dbPath = config.dbPath.replace(/^~/, homedir37());
70715
70605
  if (!existsSync73(dbPath)) {
70716
70606
  logger.info("No content database found. Run 'ck content setup' first.");
70717
70607
  return;
@@ -70738,7 +70628,7 @@ async function queueContent() {
70738
70628
  async function approveContentCmd(id) {
70739
70629
  const cwd2 = process.cwd();
70740
70630
  const config = await loadContentConfig(cwd2);
70741
- const dbPath = config.dbPath.replace(/^~/, homedir36());
70631
+ const dbPath = config.dbPath.replace(/^~/, homedir37());
70742
70632
  const db = initDatabase(dbPath);
70743
70633
  try {
70744
70634
  approveContent(db, Number.parseInt(id, 10));
@@ -70750,7 +70640,7 @@ async function approveContentCmd(id) {
70750
70640
  async function rejectContentCmd(id, reason) {
70751
70641
  const cwd2 = process.cwd();
70752
70642
  const config = await loadContentConfig(cwd2);
70753
- const dbPath = config.dbPath.replace(/^~/, homedir36());
70643
+ const dbPath = config.dbPath.replace(/^~/, homedir37());
70754
70644
  const db = initDatabase(dbPath);
70755
70645
  try {
70756
70646
  rejectContent(db, Number.parseInt(id, 10), reason);
@@ -70781,7 +70671,7 @@ __export(exports_content_subcommands, {
70781
70671
  approveContentCmd: () => approveContentCmd
70782
70672
  });
70783
70673
  import { existsSync as existsSync74, readFileSync as readFileSync18, unlinkSync as unlinkSync5 } from "node:fs";
70784
- import { homedir as homedir37 } from "node:os";
70674
+ import { homedir as homedir38 } from "node:os";
70785
70675
  import { join as join140 } from "node:path";
70786
70676
  function isDaemonRunning() {
70787
70677
  const lockFile = join140(LOCK_DIR, `${LOCK_NAME2}.lock`);
@@ -70855,7 +70745,7 @@ async function statusContent() {
70855
70745
  } catch {}
70856
70746
  }
70857
70747
  async function logsContent(options2) {
70858
- const logDir = join140(homedir37(), ".claudekit", "logs");
70748
+ const logDir = join140(homedir38(), ".claudekit", "logs");
70859
70749
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
70860
70750
  const logPath = join140(logDir, `content-${dateStr}.log`);
70861
70751
  if (!existsSync74(logPath)) {
@@ -70889,12 +70779,12 @@ var init_content_subcommands = __esm(() => {
70889
70779
  init_setup_wizard();
70890
70780
  init_state_manager();
70891
70781
  init_content_review_commands();
70892
- LOCK_DIR = join140(homedir37(), ".claudekit", "locks");
70782
+ LOCK_DIR = join140(homedir38(), ".claudekit", "locks");
70893
70783
  });
70894
70784
 
70895
70785
  // src/commands/content/content-command.ts
70896
70786
  import { existsSync as existsSync75, mkdirSync as mkdirSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync6 } from "node:fs";
70897
- import { homedir as homedir38 } from "node:os";
70787
+ import { homedir as homedir39 } from "node:os";
70898
70788
  import { join as join141 } from "node:path";
70899
70789
  async function contentCommand(options2) {
70900
70790
  const cwd2 = process.cwd();
@@ -70927,7 +70817,7 @@ async function contentCommand(options2) {
70927
70817
  if (!existsSync75(LOCK_DIR2))
70928
70818
  mkdirSync8(LOCK_DIR2, { recursive: true });
70929
70819
  writeFileSync6(LOCK_FILE, String(process.pid), "utf-8");
70930
- const dbPath = config.dbPath.replace(/^~/, homedir38());
70820
+ const dbPath = config.dbPath.replace(/^~/, homedir39());
70931
70821
  const db = initDatabase(dbPath);
70932
70822
  contentLogger.info(`Database initialised at ${dbPath}`);
70933
70823
  const adapters = initializeAdapters(config);
@@ -71073,7 +70963,7 @@ var init_content_command = __esm(() => {
71073
70963
  init_publisher();
71074
70964
  init_review_manager();
71075
70965
  init_state_manager();
71076
- LOCK_DIR2 = join141(homedir38(), ".claudekit", "locks");
70966
+ LOCK_DIR2 = join141(homedir39(), ".claudekit", "locks");
71077
70967
  LOCK_FILE = join141(LOCK_DIR2, "ck-content.lock");
71078
70968
  });
71079
70969
 
@@ -82939,9 +82829,9 @@ var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
82939
82829
  import { mkdir as mkdir19 } from "node:fs/promises";
82940
82830
  import os5 from "node:os";
82941
82831
  import { join as join75 } from "node:path";
82942
- var LOCK_CONFIGS = {
82943
- short: { stale: 60000, retries: 0 },
82944
- long: { stale: 300000, retries: 0 }
82832
+ var LOCK_CONFIG = {
82833
+ stale: 60000,
82834
+ retries: 0
82945
82835
  };
82946
82836
  var activeLocks = new Set;
82947
82837
  var cleanupRegistered = false;
@@ -82951,7 +82841,8 @@ function getLocksDir() {
82951
82841
  function cleanupLocks() {
82952
82842
  for (const name of activeLocks) {
82953
82843
  try {
82954
- import_proper_lockfile4.default.unlockSync(getLockPaths(name).resource, { realpath: false });
82844
+ const lockPath = join75(getLocksDir(), `${name}.lock`);
82845
+ import_proper_lockfile4.default.unlockSync(lockPath, { realpath: false });
82955
82846
  } catch {
82956
82847
  try {
82957
82848
  logger.verbose(`Failed to cleanup lock: ${name}`);
@@ -82970,24 +82861,13 @@ async function ensureLocksDir() {
82970
82861
  const lockDir = getLocksDir();
82971
82862
  await mkdir19(lockDir, { recursive: true });
82972
82863
  }
82973
- function getLockPaths(lockName) {
82974
- const resource = join75(getLocksDir(), `${lockName}.lock`);
82975
- return { resource, lockfile: `${resource}.lock` };
82976
- }
82977
- async function withProcessLock(lockName, fn, duration = "short") {
82864
+ async function withProcessLock(lockName, fn) {
82978
82865
  registerCleanupHandlers();
82979
82866
  await ensureLocksDir();
82980
- const { resource: lockPath } = getLockPaths(lockName);
82981
- const config = LOCK_CONFIGS[duration];
82867
+ const lockPath = join75(getLocksDir(), `${lockName}.lock`);
82982
82868
  let release;
82983
82869
  try {
82984
- release = await import_proper_lockfile4.default.lock(lockPath, {
82985
- ...config,
82986
- realpath: false,
82987
- onCompromised: duration === "long" ? (err) => {
82988
- logger.warning(`Lock "${lockName}" compromised: ${err.message}. Continuing...`);
82989
- } : undefined
82990
- });
82870
+ release = await import_proper_lockfile4.default.lock(lockPath, { ...LOCK_CONFIG, realpath: false });
82991
82871
  activeLocks.add(lockName);
82992
82872
  return await fn();
82993
82873
  } catch (e2) {
@@ -82997,24 +82877,11 @@ async function withProcessLock(lockName, fn, duration = "short") {
82997
82877
 
82998
82878
  Operation: ${lockName}
82999
82879
  Wait for it to complete or remove lock: ${lockPath}`);
83000
- }
83001
- if (error.code === "ECOMPROMISED") {
83002
- throw new Error(`Lock was compromised (stale or externally removed).
83003
-
83004
- Operation: ${lockName}
83005
- Use --force to clear and restart.`);
83006
82880
  }
83007
82881
  throw e2;
83008
82882
  } finally {
83009
82883
  if (release) {
83010
- try {
83011
- await release();
83012
- } catch (releaseErr) {
83013
- const code = releaseErr.code;
83014
- if (code !== "ERELEASED") {
83015
- logger.warning(`Failed to release lock "${lockName}": ${releaseErr.message}`);
83016
- }
83017
- }
82884
+ await release();
83018
82885
  }
83019
82886
  activeLocks.delete(lockName);
83020
82887
  }
@@ -101875,6 +101742,7 @@ ${import_picocolors38.default.bold(import_picocolors38.default.cyan(result.kitCo
101875
101742
  init_logger();
101876
101743
  import { existsSync as existsSync65 } from "node:fs";
101877
101744
  import { rm as rm16 } from "node:fs/promises";
101745
+ import { homedir as homedir33 } from "node:os";
101878
101746
  import { join as join131 } from "node:path";
101879
101747
  var import_picocolors39 = __toESM(require_picocolors(), 1);
101880
101748
 
@@ -102426,9 +102294,6 @@ async function invokeClaude(options2) {
102426
102294
  "--allowedTools",
102427
102295
  tools
102428
102296
  ];
102429
- if (outputFormat === "stream-json") {
102430
- args.push("--verbose");
102431
- }
102432
102297
  const child = spawn10("claude", args, {
102433
102298
  cwd: options2.cwd,
102434
102299
  stdio: ["pipe", "pipe", "pipe"],
@@ -102474,7 +102339,7 @@ function collectClaudeOutput(child, timeoutSec, verbose = false) {
102474
102339
  });
102475
102340
  }
102476
102341
  function logStreamEvent(chunk) {
102477
- for (const line of chunk.replace(/\r/g, "").split(`
102342
+ for (const line of chunk.split(`
102478
102343
  `).filter(Boolean)) {
102479
102344
  try {
102480
102345
  const event = JSON.parse(line);
@@ -102502,7 +102367,7 @@ function logStreamEvent(chunk) {
102502
102367
  }
102503
102368
  }
102504
102369
  function parseStreamJsonOutput(stdout2) {
102505
- const lines = stdout2.replace(/\r/g, "").split(`
102370
+ const lines = stdout2.split(`
102506
102371
  `).filter(Boolean);
102507
102372
  for (let i = lines.length - 1;i >= 0; i--) {
102508
102373
  try {
@@ -103602,13 +103467,11 @@ async function watchCommand(options2) {
103602
103467
  process.removeListener("SIGINT", shutdown);
103603
103468
  process.removeListener("SIGTERM", shutdown);
103604
103469
  }
103605
- }, "long");
103470
+ });
103606
103471
  } catch (error) {
103607
103472
  const err = error;
103608
103473
  if (err.message?.includes("Another ClaudeKit process")) {
103609
103474
  logger.error("Another ck watch instance is already running. Use --force to override.");
103610
- } else if (err.message?.includes("Lock was compromised")) {
103611
- logger.error("Lock was compromised (stale or externally removed). Use --force to restart.");
103612
103475
  } else {
103613
103476
  watchLog.error("Watch command failed", err);
103614
103477
  console.error(`[ck watch] Fatal: ${err.message}`);
@@ -103691,12 +103554,9 @@ async function resetState(state, projectDir, watchLog) {
103691
103554
  watchLog.info(`Watch state reset (--force) for ${projectDir}`);
103692
103555
  }
103693
103556
  async function forceRemoveLock(watchLog) {
103694
- const { resource, lockfile: lockfile5 } = getLockPaths(LOCK_NAME);
103557
+ const lockPath = join131(homedir33(), ".claudekit", "locks", `${LOCK_NAME}.lock`);
103695
103558
  try {
103696
- await Promise.all([
103697
- rm16(resource, { recursive: true, force: true }),
103698
- rm16(lockfile5, { recursive: true, force: true })
103699
- ]);
103559
+ await rm16(lockPath, { recursive: true, force: true });
103700
103560
  watchLog.info("Removed existing lock file (--force)");
103701
103561
  } catch {}
103702
103562
  }