claudekit-cli 3.41.1 → 3.41.2-dev.1

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.enum(GEMINI_MODEL_VALUES);
14883
+ GeminiModelSchema = exports_external.string().default("gemini-3-flash-preview");
14884
14884
  StatuslineModeSchema = exports_external.enum(["full", "compact", "minimal", "none"]);
14885
14885
  StatuslineSectionIdSchema = exports_external.enum([
14886
14886
  "model",
@@ -15193,6 +15193,7 @@ __export(exports_types, {
15193
15193
  GitHubReleaseAssetSchema: () => GitHubReleaseAssetSchema,
15194
15194
  GitHubError: () => GitHubError,
15195
15195
  GeminiModelSchema: () => GeminiModelSchema,
15196
+ GEMINI_MODEL_VALUES: () => GEMINI_MODEL_VALUES,
15196
15197
  FrameworkSchema: () => FrameworkSchema,
15197
15198
  FoldersConfigSchema: () => FoldersConfigSchema,
15198
15199
  ExtractionError: () => ExtractionError,
@@ -47783,6 +47784,14 @@ async function isActionPathAllowed(dirPath, projectId) {
47783
47784
  return false;
47784
47785
  return resolve6(project.path) === dirPath;
47785
47786
  }
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
+ }
47786
47795
  const registeredProjects = await ProjectsRegistryManager.listProjects();
47787
47796
  if (registeredProjects.some((project) => resolve6(project.path) === dirPath)) {
47788
47797
  return true;
@@ -56492,6 +56501,11 @@ var init_skill_routes = __esm(() => {
56492
56501
  });
56493
56502
 
56494
56503
  // src/domains/github/npm-registry.ts
56504
+ var exports_npm_registry = {};
56505
+ __export(exports_npm_registry, {
56506
+ redactRegistryUrlForLog: () => redactRegistryUrlForLog,
56507
+ NpmRegistryClient: () => NpmRegistryClient
56508
+ });
56495
56509
  function redactRegistryUrlForLog(url) {
56496
56510
  if (!url)
56497
56511
  return url;
@@ -57188,170 +57202,120 @@ var init_package_manager_detector = __esm(() => {
57188
57202
  };
57189
57203
  });
57190
57204
 
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
- };
57208
- }
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
- }
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"
57316
57317
  }
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);
57318
+ };
57355
57319
  });
57356
57320
 
57357
57321
  // node_modules/compare-versions/lib/umd/index.js
@@ -57525,6 +57489,362 @@ var init_version_utils = __esm(() => {
57525
57489
  import_compare_versions = __toESM(require_umd(), 1);
57526
57490
  });
57527
57491
 
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
+
57528
57848
  // src/services/file-operations/claudekit-scanner.ts
57529
57849
  import { join as join46 } from "node:path";
57530
57850
  async function scanClaudeKitDirectory(directoryPath) {
@@ -57627,117 +57947,6 @@ var init_claudekit_scanner = __esm(() => {
57627
57947
  import_fs_extra4 = __toESM(require_lib3(), 1);
57628
57948
  });
57629
57949
 
57630
- // package.json
57631
- var package_default;
57632
- var init_package = __esm(() => {
57633
- package_default = {
57634
- name: "claudekit-cli",
57635
- version: "3.41.1",
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
-
57741
57950
  // src/domains/github/github-auth.ts
57742
57951
  import { execSync } from "node:child_process";
57743
57952
 
@@ -58145,7 +58354,7 @@ ${action.title}:`);
58145
58354
  }
58146
58355
 
58147
58356
  // src/domains/error/index.ts
58148
- var init_error = () => {};
58357
+ var init_error2 = () => {};
58149
58358
 
58150
58359
  // src/domains/github/client/error-handler.ts
58151
58360
  async function handleHttpError(error, context) {
@@ -58176,7 +58385,7 @@ Need help? Run with: ${verboseFlag}`);
58176
58385
  `), classified.httpStatus);
58177
58386
  }
58178
58387
  var init_error_handler2 = __esm(() => {
58179
- init_error();
58388
+ init_error2();
58180
58389
  init_types3();
58181
58390
  init_auth_api();
58182
58391
  });
@@ -58297,7 +58506,7 @@ class VersionFormatter {
58297
58506
  static compare(v1, v2) {
58298
58507
  const normV1 = VersionFormatter.normalize(v1);
58299
58508
  const normV2 = VersionFormatter.normalize(v2);
58300
- return import_compare_versions2.compareVersions(normV1, normV2);
58509
+ return import_compare_versions3.compareVersions(normV1, normV2);
58301
58510
  }
58302
58511
  static formatRelativeTime(dateString) {
58303
58512
  if (!dateString)
@@ -58385,20 +58594,20 @@ class VersionFormatter {
58385
58594
  const majorA = Number.parseInt(normA.split(".")[0], 10);
58386
58595
  const majorB = Number.parseInt(normB.split(".")[0], 10);
58387
58596
  if (majorA === 0 && majorB === 0) {
58388
- return import_compare_versions2.compareVersions(normB, normA);
58597
+ return import_compare_versions3.compareVersions(normB, normA);
58389
58598
  }
58390
58599
  if (majorA === 0)
58391
58600
  return 1;
58392
58601
  if (majorB === 0)
58393
58602
  return -1;
58394
- return import_compare_versions2.compareVersions(normB, normA);
58603
+ return import_compare_versions3.compareVersions(normB, normA);
58395
58604
  });
58396
58605
  }
58397
58606
  }
58398
- var import_compare_versions2;
58607
+ var import_compare_versions3;
58399
58608
  var init_version_formatter = __esm(() => {
58400
58609
  init_logger();
58401
- import_compare_versions2 = __toESM(require_umd(), 1);
58610
+ import_compare_versions3 = __toESM(require_umd(), 1);
58402
58611
  });
58403
58612
 
58404
58613
  // src/domains/versioning/release-filter.ts
@@ -58907,64 +59116,16 @@ var init_github_client = __esm(() => {
58907
59116
  init_client();
58908
59117
  });
58909
59118
 
58910
- // src/commands/update-cli.ts
59119
+ // src/commands/update/post-update-handler.ts
58911
59120
  import { exec as exec2, spawn as spawn2 } from "node:child_process";
58912
59121
  import { join as join48 } from "node:path";
58913
59122
  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
- }
58961
59123
  function selectKitForUpdate(params) {
58962
59124
  const { hasLocal, hasGlobal, localKits, globalKits } = params;
58963
59125
  const hasLocalKit = localKits.length > 0 || hasLocal;
58964
59126
  const hasGlobalKit = globalKits.length > 0 || hasGlobal;
58965
- if (!hasLocalKit && !hasGlobalKit) {
59127
+ if (!hasLocalKit && !hasGlobalKit)
58966
59128
  return null;
58967
- }
58968
59129
  if (hasGlobalKit && !hasLocalKit) {
58969
59130
  const kit2 = globalKits[0] || localKits[0];
58970
59131
  return {
@@ -58991,9 +59152,8 @@ function selectKitForUpdate(params) {
58991
59152
  async function readMetadataFile(claudeDir2) {
58992
59153
  const metadataPath = join48(claudeDir2, "metadata.json");
58993
59154
  try {
58994
- if (!await import_fs_extra5.pathExists(metadataPath)) {
59155
+ if (!await import_fs_extra5.pathExists(metadataPath))
58995
59156
  return null;
58996
- }
58997
59157
  const content = await import_fs_extra5.readFile(metadataPath, "utf-8");
58998
59158
  const parsed = JSON.parse(content);
58999
59159
  const validated = MetadataSchema.safeParse(parsed);
@@ -59007,6 +59167,19 @@ async function readMetadataFile(claudeDir2) {
59007
59167
  return null;
59008
59168
  }
59009
59169
  }
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
+ }
59010
59183
  async function fetchLatestReleaseTag(kit, beta) {
59011
59184
  try {
59012
59185
  const { GitHubClient: GitHubClient2 } = await Promise.resolve().then(() => (init_github_client(), exports_github_client));
@@ -59060,14 +59233,11 @@ async function promptKitUpdate(beta, yes, deps) {
59060
59233
  const ckConfig = await loadFullConfigFn(null);
59061
59234
  autoInit = ckConfig.config.updatePipeline?.autoInitAfterUpdate ?? false;
59062
59235
  } catch {}
59063
- if (alreadyAtLatest && !autoInit) {
59236
+ if (alreadyAtLatest && !autoInit)
59064
59237
  return;
59065
- }
59066
59238
  if (!yes && !autoInit) {
59067
59239
  logger.info("");
59068
- const shouldUpdate = await confirmFn({
59069
- message: promptMessage
59070
- });
59240
+ const shouldUpdate = await confirmFn({ message: promptMessage });
59071
59241
  if (isCancelFn(shouldUpdate) || !shouldUpdate) {
59072
59242
  log.info("Skipped kit content update");
59073
59243
  return;
@@ -59205,6 +59375,37 @@ async function promptMigrateUpdate(deps) {
59205
59375
  logger.verbose(`Migrate step skipped: ${error instanceof Error ? error.message : "unknown"}`);
59206
59376
  }
59207
59377
  }
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
+ }
59208
59409
  async function updateCliCommand(options2, deps = getDefaultUpdateCliCommandDeps()) {
59209
59410
  const s = de();
59210
59411
  intro("[>] ClaudeKit CLI - Update");
@@ -59229,64 +59430,31 @@ async function updateCliCommand(options2, deps = getDefaultUpdateCliCommandDeps(
59229
59430
  const userRegistry = await packageManagerDetector.getNpmRegistryUrl();
59230
59431
  if (userRegistry) {
59231
59432
  registryUrl = userRegistry;
59232
- logger.verbose(`Using npm configured registry: ${redactRegistryUrlForLog(registryUrl)}`);
59433
+ const { redactRegistryUrlForLog: redactRegistryUrlForLog2 } = await Promise.resolve().then(() => (init_npm_registry(), exports_npm_registry));
59434
+ logger.verbose(`Using npm configured registry: ${redactRegistryUrlForLog2(registryUrl)}`);
59233
59435
  }
59234
59436
  }
59235
59437
  s.start("Checking for updates...");
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) {
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") {
59276
59445
  outro(`[+] Already on the latest CLI version (${currentVersion})`);
59277
59446
  await promptKitUpdateFn(targetIsPrerelease, opts.yes);
59278
59447
  await promptMigrateUpdateFn();
59279
59448
  return;
59280
59449
  }
59281
- const isDevChannelSwitch = (opts.dev || opts.beta) && isBetaVersion(targetVersion) && !isBetaVersion(currentVersion);
59282
- if (comparison > 0 && !opts.release && !isDevChannelSwitch) {
59450
+ if (outcome.status === "newer") {
59283
59451
  outro(`[+] Current version (${currentVersion}) is newer than latest (${targetVersion})`);
59284
59452
  await promptKitUpdateFn(targetIsPrerelease, opts.yes);
59285
59453
  await promptMigrateUpdateFn();
59286
59454
  return;
59287
59455
  }
59288
- const isUpgrade = comparison < 0 || isDevChannelSwitch;
59289
- const changeType = isUpgrade ? "upgrade" : "downgrade";
59456
+ const isUpgrade = outcome.changeType === "upgrade";
59457
+ const changeType = outcome.changeType;
59290
59458
  logger.info(`${isUpgrade ? "[^]" : "[v]"} ${changeType}: ${currentVersion} -> ${targetVersion}`);
59291
59459
  if (opts.check) {
59292
59460
  note(`CLI update available: ${currentVersion} -> ${targetVersion}
@@ -59308,71 +59476,19 @@ Run 'ck update' to install`, "Update Check");
59308
59476
  }
59309
59477
  const updateCmd = packageManagerDetector.getUpdateCommand(pm, CLAUDEKIT_CLI_NPM_PACKAGE_NAME, targetVersion, registryUrl);
59310
59478
  logger.info(`Running: ${redactCommandForLog(updateCmd)}`);
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
- }
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();
59376
59492
  } catch (error) {
59377
59493
  if (error instanceof CliUpdateError) {
59378
59494
  throw error;
@@ -59382,30 +59498,24 @@ Manual update: ${redactCommandForLog(updateCmd)}`;
59382
59498
  throw new CliUpdateError(errorMessage);
59383
59499
  }
59384
59500
  }
59385
- var import_compare_versions3, import_fs_extra5, execAsync2, CliUpdateError, SAFE_PROVIDER_NAME;
59386
59501
  var init_update_cli = __esm(() => {
59387
- init_ck_config_manager();
59388
59502
  init_npm_registry();
59389
59503
  init_package_manager_detector();
59390
- init_metadata_migration();
59391
- init_version_utils();
59392
- init_claudekit_scanner();
59393
59504
  init_claudekit_constants();
59394
59505
  init_logger();
59395
59506
  init_safe_prompts();
59396
59507
  init_types3();
59397
- init_types3();
59398
59508
  init_package();
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-]+$/;
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();
59409
59519
  });
59410
59520
 
59411
59521
  // src/domains/versioning/version-cache.ts
@@ -68343,7 +68453,7 @@ var init_content_validator = __esm(() => {
68343
68453
  import { createHash as createHash6 } from "node:crypto";
68344
68454
  import { existsSync as existsSync66, mkdirSync as mkdirSync4, readFileSync as readFileSync15, readdirSync as readdirSync8, statSync as statSync10 } from "node:fs";
68345
68455
  import { rename as rename9, writeFile as writeFile35 } from "node:fs/promises";
68346
- import { homedir as homedir34 } from "node:os";
68456
+ import { homedir as homedir33 } from "node:os";
68347
68457
  import { basename as basename19, join as join132 } from "node:path";
68348
68458
  function getCachedContext(repoPath) {
68349
68459
  const cachePath = getCacheFilePath(repoPath);
@@ -68418,7 +68528,7 @@ function getCacheFilePath(repoPath) {
68418
68528
  }
68419
68529
  var CACHE_DIR, CACHE_TTL_MS4;
68420
68530
  var init_context_cache_manager = __esm(() => {
68421
- CACHE_DIR = join132(homedir34(), ".claudekit", "cache");
68531
+ CACHE_DIR = join132(homedir33(), ".claudekit", "cache");
68422
68532
  CACHE_TTL_MS4 = 24 * 60 * 60 * 1000;
68423
68533
  });
68424
68534
 
@@ -68872,10 +68982,10 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
68872
68982
  // src/commands/content/phases/photo-generator.ts
68873
68983
  import { execSync as execSync7 } from "node:child_process";
68874
68984
  import { existsSync as existsSync68, mkdirSync as mkdirSync5, readdirSync as readdirSync10 } from "node:fs";
68875
- import { homedir as homedir35 } from "node:os";
68985
+ import { homedir as homedir34 } from "node:os";
68876
68986
  import { join as join134 } from "node:path";
68877
68987
  async function generatePhoto(_content, context, config, platform14, contentId, contentLogger) {
68878
- const mediaDir = join134(config.contentDir.replace(/^~/, homedir35()), "media", String(contentId));
68988
+ const mediaDir = join134(config.contentDir.replace(/^~/, homedir34()), "media", String(contentId));
68879
68989
  if (!existsSync68(mediaDir)) {
68880
68990
  mkdirSync5(mediaDir, { recursive: true });
68881
68991
  }
@@ -68989,7 +69099,7 @@ var init_content_creator = __esm(() => {
68989
69099
 
68990
69100
  // src/commands/content/phases/content-logger.ts
68991
69101
  import { createWriteStream as createWriteStream4, existsSync as existsSync69, mkdirSync as mkdirSync6, statSync as statSync11 } from "node:fs";
68992
- import { homedir as homedir36 } from "node:os";
69102
+ import { homedir as homedir35 } from "node:os";
68993
69103
  import { join as join135 } from "node:path";
68994
69104
 
68995
69105
  class ContentLogger {
@@ -68998,7 +69108,7 @@ class ContentLogger {
68998
69108
  logDir;
68999
69109
  maxBytes;
69000
69110
  constructor(maxBytes = 0) {
69001
- this.logDir = join135(homedir36(), ".claudekit", "logs");
69111
+ this.logDir = join135(homedir35(), ".claudekit", "logs");
69002
69112
  this.maxBytes = maxBytes;
69003
69113
  }
69004
69114
  init() {
@@ -70597,11 +70707,11 @@ var init_setup_wizard = __esm(() => {
70597
70707
 
70598
70708
  // src/commands/content/content-review-commands.ts
70599
70709
  import { existsSync as existsSync73 } from "node:fs";
70600
- import { homedir as homedir37 } from "node:os";
70710
+ import { homedir as homedir36 } from "node:os";
70601
70711
  async function queueContent() {
70602
70712
  const cwd2 = process.cwd();
70603
70713
  const config = await loadContentConfig(cwd2);
70604
- const dbPath = config.dbPath.replace(/^~/, homedir37());
70714
+ const dbPath = config.dbPath.replace(/^~/, homedir36());
70605
70715
  if (!existsSync73(dbPath)) {
70606
70716
  logger.info("No content database found. Run 'ck content setup' first.");
70607
70717
  return;
@@ -70628,7 +70738,7 @@ async function queueContent() {
70628
70738
  async function approveContentCmd(id) {
70629
70739
  const cwd2 = process.cwd();
70630
70740
  const config = await loadContentConfig(cwd2);
70631
- const dbPath = config.dbPath.replace(/^~/, homedir37());
70741
+ const dbPath = config.dbPath.replace(/^~/, homedir36());
70632
70742
  const db = initDatabase(dbPath);
70633
70743
  try {
70634
70744
  approveContent(db, Number.parseInt(id, 10));
@@ -70640,7 +70750,7 @@ async function approveContentCmd(id) {
70640
70750
  async function rejectContentCmd(id, reason) {
70641
70751
  const cwd2 = process.cwd();
70642
70752
  const config = await loadContentConfig(cwd2);
70643
- const dbPath = config.dbPath.replace(/^~/, homedir37());
70753
+ const dbPath = config.dbPath.replace(/^~/, homedir36());
70644
70754
  const db = initDatabase(dbPath);
70645
70755
  try {
70646
70756
  rejectContent(db, Number.parseInt(id, 10), reason);
@@ -70671,7 +70781,7 @@ __export(exports_content_subcommands, {
70671
70781
  approveContentCmd: () => approveContentCmd
70672
70782
  });
70673
70783
  import { existsSync as existsSync74, readFileSync as readFileSync18, unlinkSync as unlinkSync5 } from "node:fs";
70674
- import { homedir as homedir38 } from "node:os";
70784
+ import { homedir as homedir37 } from "node:os";
70675
70785
  import { join as join140 } from "node:path";
70676
70786
  function isDaemonRunning() {
70677
70787
  const lockFile = join140(LOCK_DIR, `${LOCK_NAME2}.lock`);
@@ -70745,7 +70855,7 @@ async function statusContent() {
70745
70855
  } catch {}
70746
70856
  }
70747
70857
  async function logsContent(options2) {
70748
- const logDir = join140(homedir38(), ".claudekit", "logs");
70858
+ const logDir = join140(homedir37(), ".claudekit", "logs");
70749
70859
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
70750
70860
  const logPath = join140(logDir, `content-${dateStr}.log`);
70751
70861
  if (!existsSync74(logPath)) {
@@ -70779,12 +70889,12 @@ var init_content_subcommands = __esm(() => {
70779
70889
  init_setup_wizard();
70780
70890
  init_state_manager();
70781
70891
  init_content_review_commands();
70782
- LOCK_DIR = join140(homedir38(), ".claudekit", "locks");
70892
+ LOCK_DIR = join140(homedir37(), ".claudekit", "locks");
70783
70893
  });
70784
70894
 
70785
70895
  // src/commands/content/content-command.ts
70786
70896
  import { existsSync as existsSync75, mkdirSync as mkdirSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync6 } from "node:fs";
70787
- import { homedir as homedir39 } from "node:os";
70897
+ import { homedir as homedir38 } from "node:os";
70788
70898
  import { join as join141 } from "node:path";
70789
70899
  async function contentCommand(options2) {
70790
70900
  const cwd2 = process.cwd();
@@ -70817,7 +70927,7 @@ async function contentCommand(options2) {
70817
70927
  if (!existsSync75(LOCK_DIR2))
70818
70928
  mkdirSync8(LOCK_DIR2, { recursive: true });
70819
70929
  writeFileSync6(LOCK_FILE, String(process.pid), "utf-8");
70820
- const dbPath = config.dbPath.replace(/^~/, homedir39());
70930
+ const dbPath = config.dbPath.replace(/^~/, homedir38());
70821
70931
  const db = initDatabase(dbPath);
70822
70932
  contentLogger.info(`Database initialised at ${dbPath}`);
70823
70933
  const adapters = initializeAdapters(config);
@@ -70963,7 +71073,7 @@ var init_content_command = __esm(() => {
70963
71073
  init_publisher();
70964
71074
  init_review_manager();
70965
71075
  init_state_manager();
70966
- LOCK_DIR2 = join141(homedir39(), ".claudekit", "locks");
71076
+ LOCK_DIR2 = join141(homedir38(), ".claudekit", "locks");
70967
71077
  LOCK_FILE = join141(LOCK_DIR2, "ck-content.lock");
70968
71078
  });
70969
71079
 
@@ -81798,16 +81908,53 @@ class SyncEngine {
81798
81908
  }
81799
81909
  }
81800
81910
  }
81911
+ // src/shared/deletion-pattern-expander.ts
81912
+ var LEGACY_COMMAND_PREFIX_BY_KIT = {
81913
+ engineer: "ck",
81914
+ marketing: "mkt"
81915
+ };
81916
+ function getLegacyCommandPrefix(kitType) {
81917
+ if (!kitType)
81918
+ return null;
81919
+ return LEGACY_COMMAND_PREFIX_BY_KIT[kitType] ?? null;
81920
+ }
81921
+ function canExpandLegacyCommandPattern(pattern, prefix) {
81922
+ if (!pattern.startsWith("commands/"))
81923
+ return false;
81924
+ if (pattern.startsWith(`commands/${prefix}/`))
81925
+ return false;
81926
+ const allPrefixes = Object.values(LEGACY_COMMAND_PREFIX_BY_KIT);
81927
+ if (allPrefixes.some((candidate) => candidate && pattern.startsWith(`commands/${candidate}/`))) {
81928
+ return false;
81929
+ }
81930
+ return true;
81931
+ }
81932
+ function expandDeletionPatterns(patterns, kitType) {
81933
+ const prefix = getLegacyCommandPrefix(kitType);
81934
+ if (!prefix || patterns.length === 0) {
81935
+ return [...patterns];
81936
+ }
81937
+ const expanded = new Set;
81938
+ for (const pattern of patterns) {
81939
+ expanded.add(pattern);
81940
+ if (canExpandLegacyCommandPattern(pattern, prefix)) {
81941
+ expanded.add(`commands/${prefix}/${pattern.slice("commands/".length)}`);
81942
+ }
81943
+ }
81944
+ return [...expanded];
81945
+ }
81946
+
81801
81947
  // src/domains/sync/deletion-path-filter.ts
81802
81948
  init_path_resolver();
81803
81949
  var import_picomatch = __toESM(require_picomatch2(), 1);
81804
- function filterDeletionPaths(trackedFiles, deletions) {
81950
+ function filterDeletionPaths(trackedFiles, deletions, kitType) {
81805
81951
  if (!deletions || deletions.length === 0) {
81806
81952
  return trackedFiles;
81807
81953
  }
81954
+ const expandedDeletions = expandDeletionPatterns(deletions, kitType);
81808
81955
  const exactPaths = new Set;
81809
81956
  const globMatchers = [];
81810
- for (const pattern of deletions) {
81957
+ for (const pattern of expandedDeletions) {
81811
81958
  if (PathResolver.isGlobPattern(pattern)) {
81812
81959
  globMatchers.push(import_picomatch.default(pattern));
81813
81960
  } else {
@@ -82792,9 +82939,9 @@ var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
82792
82939
  import { mkdir as mkdir19 } from "node:fs/promises";
82793
82940
  import os5 from "node:os";
82794
82941
  import { join as join75 } from "node:path";
82795
- var LOCK_CONFIG = {
82796
- stale: 60000,
82797
- retries: 0
82942
+ var LOCK_CONFIGS = {
82943
+ short: { stale: 60000, retries: 0 },
82944
+ long: { stale: 300000, retries: 0 }
82798
82945
  };
82799
82946
  var activeLocks = new Set;
82800
82947
  var cleanupRegistered = false;
@@ -82804,8 +82951,7 @@ function getLocksDir() {
82804
82951
  function cleanupLocks() {
82805
82952
  for (const name of activeLocks) {
82806
82953
  try {
82807
- const lockPath = join75(getLocksDir(), `${name}.lock`);
82808
- import_proper_lockfile4.default.unlockSync(lockPath, { realpath: false });
82954
+ import_proper_lockfile4.default.unlockSync(getLockPaths(name).resource, { realpath: false });
82809
82955
  } catch {
82810
82956
  try {
82811
82957
  logger.verbose(`Failed to cleanup lock: ${name}`);
@@ -82824,13 +82970,24 @@ async function ensureLocksDir() {
82824
82970
  const lockDir = getLocksDir();
82825
82971
  await mkdir19(lockDir, { recursive: true });
82826
82972
  }
82827
- async function withProcessLock(lockName, fn) {
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") {
82828
82978
  registerCleanupHandlers();
82829
82979
  await ensureLocksDir();
82830
- const lockPath = join75(getLocksDir(), `${lockName}.lock`);
82980
+ const { resource: lockPath } = getLockPaths(lockName);
82981
+ const config = LOCK_CONFIGS[duration];
82831
82982
  let release;
82832
82983
  try {
82833
- release = await import_proper_lockfile4.default.lock(lockPath, { ...LOCK_CONFIG, realpath: false });
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
+ });
82834
82991
  activeLocks.add(lockName);
82835
82992
  return await fn();
82836
82993
  } catch (e2) {
@@ -82840,11 +82997,24 @@ async function withProcessLock(lockName, fn) {
82840
82997
 
82841
82998
  Operation: ${lockName}
82842
82999
  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.`);
82843
83006
  }
82844
83007
  throw e2;
82845
83008
  } finally {
82846
83009
  if (release) {
82847
- await 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
+ }
82848
83018
  }
82849
83019
  activeLocks.delete(lockName);
82850
83020
  }
@@ -91199,8 +91369,15 @@ function findFileInMetadata(metadata, path14) {
91199
91369
  }
91200
91370
  return null;
91201
91371
  }
91202
- function shouldDeletePath(path14, metadata) {
91203
- const tracked = findFileInMetadata(metadata, path14);
91372
+ function findFileInMetadataForKit(metadata, path14, kitType) {
91373
+ if (!metadata)
91374
+ return null;
91375
+ if (!kitType)
91376
+ return findFileInMetadata(metadata, path14);
91377
+ return metadata.kits?.[kitType]?.files?.find((file) => file.path === path14) ?? null;
91378
+ }
91379
+ function shouldDeletePath(path14, metadata, kitType) {
91380
+ const tracked = findFileInMetadataForKit(metadata, path14, kitType);
91204
91381
  if (!tracked)
91205
91382
  return true;
91206
91383
  return tracked.ownership !== "user";
@@ -91326,8 +91503,8 @@ async function updateMetadataAfterDeletion(claudeDir2, deletedPaths) {
91326
91503
  logger.debug("Failed to write updated metadata.json");
91327
91504
  }
91328
91505
  }
91329
- async function handleDeletions(sourceMetadata, claudeDir2) {
91330
- const deletionPatterns = sourceMetadata.deletions || [];
91506
+ async function handleDeletions(sourceMetadata, claudeDir2, kitType) {
91507
+ const deletionPatterns = expandDeletionPatterns(sourceMetadata.deletions || [], kitType);
91331
91508
  if (deletionPatterns.length === 0) {
91332
91509
  return { deletedPaths: [], preservedPaths: [], errors: [] };
91333
91510
  }
@@ -91343,7 +91520,7 @@ async function handleDeletions(sourceMetadata, claudeDir2) {
91343
91520
  result.errors.push(path14);
91344
91521
  continue;
91345
91522
  }
91346
- if (!shouldDeletePath(path14, userMetadata)) {
91523
+ if (!shouldDeletePath(path14, userMetadata, kitType)) {
91347
91524
  result.preservedPaths.push(path14);
91348
91525
  logger.verbose(`Preserved user file: ${path14}`);
91349
91526
  continue;
@@ -95116,7 +95293,7 @@ async function handleMerge(ctx) {
95116
95293
  }
95117
95294
  try {
95118
95295
  if (sourceMetadata?.deletions && sourceMetadata.deletions.length > 0) {
95119
- const deletionResult = await handleDeletions(sourceMetadata, ctx.claudeDir);
95296
+ const deletionResult = await handleDeletions(sourceMetadata, ctx.claudeDir, ctx.kitType);
95120
95297
  if (deletionResult.deletedPaths.length > 0) {
95121
95298
  logger.info(`Removed ${deletionResult.deletedPaths.length} deprecated file(s)`);
95122
95299
  for (const path15 of deletionResult.deletedPaths) {
@@ -97538,7 +97715,7 @@ async function executeSyncMerge(ctx) {
97538
97715
  } catch (error) {
97539
97716
  logger.debug(`Failed to load source metadata for deletion filtering: ${error}`);
97540
97717
  }
97541
- const filteredTrackedFiles = filterDeletionPaths(trackedFiles, deletions);
97718
+ const filteredTrackedFiles = filterDeletionPaths(trackedFiles, deletions, ctx.kitType);
97542
97719
  if (deletions.length > 0) {
97543
97720
  const filtered = trackedFiles.length - filteredTrackedFiles.length;
97544
97721
  logger.debug(`Filtered ${filtered} files matching ${deletions.length} deletion patterns`);
@@ -98842,7 +99019,7 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
98842
99019
  if (!existsSync56(claudeDir2))
98843
99020
  return;
98844
99021
  try {
98845
- const result = await handleDeletions(sourceMetadata, claudeDir2);
99022
+ const result = await handleDeletions(sourceMetadata, claudeDir2, inferKitTypeFromSourceMetadata(sourceMetadata));
98846
99023
  if (result.deletedPaths.length > 0) {
98847
99024
  logger.verbose(`[migrate] Cleaned up ${result.deletedPaths.length} deprecated path(s): ${result.deletedPaths.join(", ")}`);
98848
99025
  }
@@ -98850,6 +99027,13 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
98850
99027
  logger.warning(`[migrate] Deletion cleanup failed: ${error}`);
98851
99028
  }
98852
99029
  }
99030
+ function inferKitTypeFromSourceMetadata(sourceMetadata) {
99031
+ if (sourceMetadata.name?.includes("marketing"))
99032
+ return "marketing";
99033
+ if (sourceMetadata.name?.includes("engineer"))
99034
+ return "engineer";
99035
+ return;
99036
+ }
98853
99037
  async function migrateCommand(options2) {
98854
99038
  console.log();
98855
99039
  oe(import_picocolors28.default.bgMagenta(import_picocolors28.default.black(" ck migrate ")));
@@ -101691,7 +101875,6 @@ ${import_picocolors38.default.bold(import_picocolors38.default.cyan(result.kitCo
101691
101875
  init_logger();
101692
101876
  import { existsSync as existsSync65 } from "node:fs";
101693
101877
  import { rm as rm16 } from "node:fs/promises";
101694
- import { homedir as homedir33 } from "node:os";
101695
101878
  import { join as join131 } from "node:path";
101696
101879
  var import_picocolors39 = __toESM(require_picocolors(), 1);
101697
101880
 
@@ -102243,6 +102426,9 @@ async function invokeClaude(options2) {
102243
102426
  "--allowedTools",
102244
102427
  tools
102245
102428
  ];
102429
+ if (outputFormat === "stream-json") {
102430
+ args.push("--verbose");
102431
+ }
102246
102432
  const child = spawn10("claude", args, {
102247
102433
  cwd: options2.cwd,
102248
102434
  stdio: ["pipe", "pipe", "pipe"],
@@ -102288,7 +102474,7 @@ function collectClaudeOutput(child, timeoutSec, verbose = false) {
102288
102474
  });
102289
102475
  }
102290
102476
  function logStreamEvent(chunk) {
102291
- for (const line of chunk.split(`
102477
+ for (const line of chunk.replace(/\r/g, "").split(`
102292
102478
  `).filter(Boolean)) {
102293
102479
  try {
102294
102480
  const event = JSON.parse(line);
@@ -102316,7 +102502,7 @@ function logStreamEvent(chunk) {
102316
102502
  }
102317
102503
  }
102318
102504
  function parseStreamJsonOutput(stdout2) {
102319
- const lines = stdout2.split(`
102505
+ const lines = stdout2.replace(/\r/g, "").split(`
102320
102506
  `).filter(Boolean);
102321
102507
  for (let i = lines.length - 1;i >= 0; i--) {
102322
102508
  try {
@@ -103416,11 +103602,13 @@ async function watchCommand(options2) {
103416
103602
  process.removeListener("SIGINT", shutdown);
103417
103603
  process.removeListener("SIGTERM", shutdown);
103418
103604
  }
103419
- });
103605
+ }, "long");
103420
103606
  } catch (error) {
103421
103607
  const err = error;
103422
103608
  if (err.message?.includes("Another ClaudeKit process")) {
103423
103609
  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.");
103424
103612
  } else {
103425
103613
  watchLog.error("Watch command failed", err);
103426
103614
  console.error(`[ck watch] Fatal: ${err.message}`);
@@ -103503,9 +103691,12 @@ async function resetState(state, projectDir, watchLog) {
103503
103691
  watchLog.info(`Watch state reset (--force) for ${projectDir}`);
103504
103692
  }
103505
103693
  async function forceRemoveLock(watchLog) {
103506
- const lockPath = join131(homedir33(), ".claudekit", "locks", `${LOCK_NAME}.lock`);
103694
+ const { resource, lockfile: lockfile5 } = getLockPaths(LOCK_NAME);
103507
103695
  try {
103508
- await rm16(lockPath, { recursive: true, force: true });
103696
+ await Promise.all([
103697
+ rm16(resource, { recursive: true, force: true }),
103698
+ rm16(lockfile5, { recursive: true, force: true })
103699
+ ]);
103509
103700
  watchLog.info("Removed existing lock file (--force)");
103510
103701
  } catch {}
103511
103702
  }