claudekit-cli 3.22.1 → 3.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +652 -247
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -18468,6 +18468,25 @@ class PathResolver {
18468
18468
  }
18469
18469
  return join(homedir(), ".claude");
18470
18470
  }
18471
+ static getOpenCodeDir(global2, baseDir) {
18472
+ const testHome = PathResolver.getTestHomeDir();
18473
+ if (testHome) {
18474
+ return global2 ? join(testHome, ".config", "opencode") : join(baseDir || testHome, ".opencode");
18475
+ }
18476
+ if (!global2) {
18477
+ return join(baseDir || process.cwd(), ".opencode");
18478
+ }
18479
+ const os = platform();
18480
+ if (os === "win32") {
18481
+ const appData = process.env.APPDATA || join(homedir(), "AppData", "Roaming");
18482
+ return join(appData, "opencode");
18483
+ }
18484
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME;
18485
+ if (xdgConfigHome) {
18486
+ return join(xdgConfigHome, "opencode");
18487
+ }
18488
+ return join(homedir(), ".config", "opencode");
18489
+ }
18471
18490
  static getPathPrefix(global2) {
18472
18491
  return global2 ? "" : ".claude";
18473
18492
  }
@@ -34271,7 +34290,7 @@ async function handleDownload(ctx) {
34271
34290
  };
34272
34291
  }
34273
34292
  // src/commands/init/phases/merge-handler.ts
34274
- import { join as join49 } from "node:path";
34293
+ import { join as join50 } from "node:path";
34275
34294
 
34276
34295
  // src/domains/installation/file-merger.ts
34277
34296
  init_logger();
@@ -36208,9 +36227,6 @@ class InstalledSettingsTracker {
36208
36227
  }
36209
36228
  }
36210
36229
 
36211
- // src/domains/config/merger/merge-engine.ts
36212
- init_logger();
36213
-
36214
36230
  // src/domains/config/merger/diff-calculator.ts
36215
36231
  function truncateCommand(cmd, maxLen = 50) {
36216
36232
  if (cmd.length <= maxLen)
@@ -36409,12 +36425,61 @@ function mergeHooks(sourceHooks, destHooks, result, options) {
36409
36425
  const merged = { ...destHooks };
36410
36426
  const installedHooks = options?.installedSettings?.hooks ?? [];
36411
36427
  const sourceKit = options?.sourceKit;
36428
+ const sourceCommands = new Set;
36429
+ for (const entries of Object.values(sourceHooks)) {
36430
+ extractCommands(entries, sourceCommands);
36431
+ }
36412
36432
  for (const [eventName, sourceEntries] of Object.entries(sourceHooks)) {
36413
36433
  const destEntries = destHooks[eventName] || [];
36414
36434
  merged[eventName] = mergeHookEntries(sourceEntries, destEntries, eventName, result, installedHooks, sourceKit);
36415
36435
  }
36436
+ if (installedHooks.length > 0) {
36437
+ const deprecatedHooks = installedHooks.filter((hook) => !sourceCommands.has(normalizeCommand(hook)));
36438
+ if (deprecatedHooks.length > 0) {
36439
+ result.removedHooks = result.removedHooks ?? [];
36440
+ for (const [eventName, entries] of Object.entries(merged)) {
36441
+ const filtered = removeDeprecatedFromEntries(entries, deprecatedHooks, result);
36442
+ if (filtered.length > 0) {
36443
+ merged[eventName] = filtered;
36444
+ } else {
36445
+ delete merged[eventName];
36446
+ }
36447
+ }
36448
+ }
36449
+ }
36416
36450
  return merged;
36417
36451
  }
36452
+ function removeDeprecatedFromEntries(entries, deprecatedHooks, result) {
36453
+ const deprecatedSet = new Set(deprecatedHooks.map((h2) => normalizeCommand(h2)));
36454
+ const filtered = [];
36455
+ for (const entry of entries) {
36456
+ if ("hooks" in entry && entry.hooks) {
36457
+ const remainingHooks = entry.hooks.filter((h2) => {
36458
+ if (h2.command && deprecatedSet.has(normalizeCommand(h2.command))) {
36459
+ result.hooksRemoved++;
36460
+ result.removedHooks?.push(h2.command);
36461
+ logger.info(`Removed deprecated hook: ${h2.command.slice(0, 60)}...`);
36462
+ return false;
36463
+ }
36464
+ return true;
36465
+ });
36466
+ if (remainingHooks.length > 0) {
36467
+ filtered.push({ ...entry, hooks: remainingHooks });
36468
+ }
36469
+ } else if ("command" in entry) {
36470
+ if (deprecatedSet.has(normalizeCommand(entry.command))) {
36471
+ result.hooksRemoved++;
36472
+ result.removedHooks?.push(entry.command);
36473
+ logger.info(`Removed deprecated hook: ${entry.command.slice(0, 60)}...`);
36474
+ } else {
36475
+ filtered.push(entry);
36476
+ }
36477
+ } else {
36478
+ filtered.push(entry);
36479
+ }
36480
+ }
36481
+ return filtered;
36482
+ }
36418
36483
  function mergeMcp(sourceMcp, destMcp, result, options) {
36419
36484
  if (!sourceMcp)
36420
36485
  return destMcp;
@@ -36491,6 +36556,24 @@ function mergeMcp(sourceMcp, destMcp, result, options) {
36491
36556
  }
36492
36557
  }
36493
36558
  }
36559
+ if (installedServers.length > 0 && merged.servers) {
36560
+ const sourceServerNames = new Set(Object.keys(sourceMcp.servers || {}));
36561
+ const deprecatedServers = installedServers.filter((server) => !sourceServerNames.has(server));
36562
+ if (deprecatedServers.length > 0) {
36563
+ result.removedMcpServers = result.removedMcpServers ?? [];
36564
+ for (const serverName of deprecatedServers) {
36565
+ if (serverName in merged.servers) {
36566
+ delete merged.servers[serverName];
36567
+ result.mcpServersRemoved++;
36568
+ result.removedMcpServers.push(serverName);
36569
+ logger.info(`Removed deprecated MCP server: ${serverName}`);
36570
+ }
36571
+ }
36572
+ if (merged.servers && Object.keys(merged.servers).length === 0) {
36573
+ merged.servers = undefined;
36574
+ }
36575
+ }
36576
+ }
36494
36577
  for (const key of Object.keys(sourceMcp)) {
36495
36578
  if (key !== "servers" && !(key in merged)) {
36496
36579
  merged[key] = sourceMcp[key];
@@ -36504,8 +36587,10 @@ function mergeSettings(source, destination, options) {
36504
36587
  hooksAdded: 0,
36505
36588
  hooksPreserved: 0,
36506
36589
  hooksSkipped: 0,
36590
+ hooksRemoved: 0,
36507
36591
  mcpServersPreserved: 0,
36508
36592
  mcpServersSkipped: 0,
36593
+ mcpServersRemoved: 0,
36509
36594
  conflictsDetected: [],
36510
36595
  newlyInstalledHooks: [],
36511
36596
  newlyInstalledServers: [],
@@ -37715,8 +37800,113 @@ class FileScanner2 {
37715
37800
  // src/services/transformers/commands-prefix/prefix-applier.ts
37716
37801
  init_logger();
37717
37802
  var import_fs_extra13 = __toESM(require_lib(), 1);
37718
- import { lstat as lstat5, mkdir as mkdir16, readdir as readdir11, stat as stat8 } from "node:fs/promises";
37803
+ import { lstat as lstat5, mkdir as mkdir16, readdir as readdir12, stat as stat8 } from "node:fs/promises";
37804
+ import { join as join47 } from "node:path";
37805
+
37806
+ // src/services/transformers/commands-prefix/content-transformer.ts
37807
+ init_logger();
37808
+ import { readFile as readFile17, readdir as readdir11, writeFile as writeFile14 } from "node:fs/promises";
37719
37809
  import { join as join46 } from "node:path";
37810
+ var TRANSFORMABLE_EXTENSIONS = new Set([
37811
+ ".md",
37812
+ ".txt",
37813
+ ".json",
37814
+ ".yaml",
37815
+ ".yml",
37816
+ ".ts",
37817
+ ".js",
37818
+ ".mjs",
37819
+ ".cjs",
37820
+ ".py"
37821
+ ]);
37822
+ var COMMAND_ROOTS = [
37823
+ "plan",
37824
+ "fix",
37825
+ "code",
37826
+ "review",
37827
+ "cook",
37828
+ "brainstorm",
37829
+ "integrate",
37830
+ "bootstrap",
37831
+ "worktree",
37832
+ "scout",
37833
+ "test",
37834
+ "debug",
37835
+ "preview",
37836
+ "kanban",
37837
+ "journal",
37838
+ "watzup"
37839
+ ];
37840
+ function buildCommandPatterns() {
37841
+ const patterns = [];
37842
+ for (const cmd of COMMAND_ROOTS) {
37843
+ patterns.push({
37844
+ regex: new RegExp(`(?<![\\w:])(\\/)${cmd}(:)`, "g"),
37845
+ replacement: "$1ck:$2".replace("$2", `${cmd}:`)
37846
+ });
37847
+ patterns.push({
37848
+ regex: new RegExp(`(?<![\\w:])(\\/)${cmd}(?=[\\s\`"'\\)\\]}>.,;:!?]|$)`, "g"),
37849
+ replacement: `$1ck:${cmd}`
37850
+ });
37851
+ }
37852
+ return patterns;
37853
+ }
37854
+ function transformCommandContent(content) {
37855
+ let changes = 0;
37856
+ let transformed = content;
37857
+ const patterns = buildCommandPatterns();
37858
+ for (const { regex: regex2, replacement } of patterns) {
37859
+ regex2.lastIndex = 0;
37860
+ const matches = transformed.match(regex2);
37861
+ if (matches) {
37862
+ changes += matches.length;
37863
+ regex2.lastIndex = 0;
37864
+ transformed = transformed.replace(regex2, replacement);
37865
+ }
37866
+ }
37867
+ return { transformed, changes };
37868
+ }
37869
+ function shouldTransformFile(filename) {
37870
+ const ext2 = filename.toLowerCase().slice(filename.lastIndexOf("."));
37871
+ return TRANSFORMABLE_EXTENSIONS.has(ext2);
37872
+ }
37873
+ async function transformCommandReferences(directory, options = {}) {
37874
+ let filesTransformed = 0;
37875
+ let totalReplacements = 0;
37876
+ async function processDirectory(dir) {
37877
+ const entries = await readdir11(dir, { withFileTypes: true });
37878
+ for (const entry of entries) {
37879
+ const fullPath = join46(dir, entry.name);
37880
+ if (entry.isDirectory()) {
37881
+ if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
37882
+ continue;
37883
+ }
37884
+ await processDirectory(fullPath);
37885
+ } else if (entry.isFile() && shouldTransformFile(entry.name)) {
37886
+ try {
37887
+ const content = await readFile17(fullPath, "utf-8");
37888
+ const { transformed, changes } = transformCommandContent(content);
37889
+ if (changes > 0) {
37890
+ if (options.dryRun) {
37891
+ logger.debug(`[dry-run] Would transform ${changes} command ref(s) in ${fullPath}`);
37892
+ } else {
37893
+ await writeFile14(fullPath, transformed, "utf-8");
37894
+ if (options.verbose) {
37895
+ logger.verbose(`Transformed ${changes} command ref(s) in ${fullPath}`);
37896
+ }
37897
+ }
37898
+ filesTransformed++;
37899
+ totalReplacements += changes;
37900
+ }
37901
+ } catch (error) {
37902
+ logger.debug(`Skipped ${fullPath}: ${error instanceof Error ? error.message : "unknown"}`);
37903
+ }
37904
+ }
37905
+ }
37906
+ }
37907
+ await processDirectory(directory);
37908
+ return { filesTransformed, totalReplacements };
37909
+ }
37720
37910
 
37721
37911
  // src/services/transformers/commands-prefix/prefix-utils.ts
37722
37912
  init_logger();
@@ -37761,22 +37951,22 @@ function shouldApplyPrefix(options) {
37761
37951
  // src/services/transformers/commands-prefix/prefix-applier.ts
37762
37952
  async function applyPrefix(extractDir) {
37763
37953
  validatePath(extractDir, "extractDir");
37764
- const commandsDir = join46(extractDir, ".claude", "commands");
37954
+ const commandsDir = join47(extractDir, ".claude", "commands");
37765
37955
  if (!await import_fs_extra13.pathExists(commandsDir)) {
37766
37956
  logger.verbose("No commands directory found, skipping prefix application");
37767
37957
  return;
37768
37958
  }
37769
37959
  logger.info("Applying /ck: prefix to slash commands...");
37770
- const backupDir = join46(extractDir, ".commands-backup");
37771
- const tempDir = join46(extractDir, ".commands-prefix-temp");
37960
+ const backupDir = join47(extractDir, ".commands-backup");
37961
+ const tempDir = join47(extractDir, ".commands-prefix-temp");
37772
37962
  try {
37773
- const entries = await readdir11(commandsDir);
37963
+ const entries = await readdir12(commandsDir);
37774
37964
  if (entries.length === 0) {
37775
37965
  logger.verbose("Commands directory is empty, skipping prefix application");
37776
37966
  return;
37777
37967
  }
37778
37968
  if (entries.length === 1 && entries[0] === "ck") {
37779
- const ckDir2 = join46(commandsDir, "ck");
37969
+ const ckDir2 = join47(commandsDir, "ck");
37780
37970
  const ckStat = await stat8(ckDir2);
37781
37971
  if (ckStat.isDirectory()) {
37782
37972
  logger.verbose("Commands already have /ck: prefix, skipping");
@@ -37786,17 +37976,17 @@ async function applyPrefix(extractDir) {
37786
37976
  await import_fs_extra13.copy(commandsDir, backupDir);
37787
37977
  logger.verbose("Created backup of commands directory");
37788
37978
  await mkdir16(tempDir, { recursive: true });
37789
- const ckDir = join46(tempDir, "ck");
37979
+ const ckDir = join47(tempDir, "ck");
37790
37980
  await mkdir16(ckDir, { recursive: true });
37791
37981
  let processedCount = 0;
37792
37982
  for (const entry of entries) {
37793
- const sourcePath = join46(commandsDir, entry);
37983
+ const sourcePath = join47(commandsDir, entry);
37794
37984
  const stats = await lstat5(sourcePath);
37795
37985
  if (stats.isSymbolicLink()) {
37796
37986
  logger.warning(`Skipping symlink for security: ${entry}`);
37797
37987
  continue;
37798
37988
  }
37799
- const destPath = join46(ckDir, entry);
37989
+ const destPath = join47(ckDir, entry);
37800
37990
  await import_fs_extra13.copy(sourcePath, destPath, {
37801
37991
  overwrite: false,
37802
37992
  errorOnExist: true
@@ -37813,7 +38003,17 @@ async function applyPrefix(extractDir) {
37813
38003
  await import_fs_extra13.remove(commandsDir);
37814
38004
  await import_fs_extra13.move(tempDir, commandsDir);
37815
38005
  await import_fs_extra13.remove(backupDir);
37816
- logger.success("Successfully applied /ck: prefix to all commands");
38006
+ logger.success("Successfully reorganized commands to /ck: prefix");
38007
+ const claudeDir = join47(extractDir, ".claude");
38008
+ logger.info("Transforming command references in file contents...");
38009
+ const transformResult = await transformCommandReferences(claudeDir, {
38010
+ verbose: logger.isVerbose()
38011
+ });
38012
+ if (transformResult.totalReplacements > 0) {
38013
+ logger.success(`Transformed ${transformResult.totalReplacements} command ref(s) in ${transformResult.filesTransformed} file(s)`);
38014
+ } else {
38015
+ logger.verbose("No command references needed transformation");
38016
+ }
37817
38017
  } catch (error) {
37818
38018
  if (await import_fs_extra13.pathExists(backupDir)) {
37819
38019
  try {
@@ -37840,21 +38040,21 @@ async function applyPrefix(extractDir) {
37840
38040
  }
37841
38041
 
37842
38042
  // src/services/transformers/commands-prefix/prefix-cleaner.ts
37843
- import { lstat as lstat7, readdir as readdir13 } from "node:fs/promises";
37844
- import { join as join48 } from "node:path";
38043
+ import { lstat as lstat7, readdir as readdir14 } from "node:fs/promises";
38044
+ import { join as join49 } from "node:path";
37845
38045
  init_logger();
37846
38046
  var import_fs_extra15 = __toESM(require_lib(), 1);
37847
38047
 
37848
38048
  // src/services/transformers/commands-prefix/file-processor.ts
37849
- import { lstat as lstat6, readdir as readdir12 } from "node:fs/promises";
37850
- import { join as join47 } from "node:path";
38049
+ import { lstat as lstat6, readdir as readdir13 } from "node:fs/promises";
38050
+ import { join as join48 } from "node:path";
37851
38051
  init_logger();
37852
38052
  var import_fs_extra14 = __toESM(require_lib(), 1);
37853
38053
  async function scanDirectoryFiles(dir) {
37854
38054
  const files = [];
37855
- const entries = await readdir12(dir);
38055
+ const entries = await readdir13(dir);
37856
38056
  for (const entry of entries) {
37857
- const fullPath = join47(dir, entry);
38057
+ const fullPath = join48(dir, entry);
37858
38058
  const stats = await lstat6(fullPath);
37859
38059
  if (stats.isSymbolicLink()) {
37860
38060
  continue;
@@ -37962,8 +38162,8 @@ function logCleanupSummary(deletedCount, preservedCount, dryRun, results) {
37962
38162
  async function cleanupCommandsDirectory(targetDir, isGlobal, options = {}) {
37963
38163
  const { dryRun = false } = options;
37964
38164
  validatePath(targetDir, "targetDir");
37965
- const claudeDir = isGlobal ? targetDir : join48(targetDir, ".claude");
37966
- const commandsDir = join48(claudeDir, "commands");
38165
+ const claudeDir = isGlobal ? targetDir : join49(targetDir, ".claude");
38166
+ const commandsDir = join49(claudeDir, "commands");
37967
38167
  const accumulator = {
37968
38168
  results: [],
37969
38169
  deletedCount: 0,
@@ -37991,13 +38191,13 @@ async function cleanupCommandsDirectory(targetDir, isGlobal, options = {}) {
37991
38191
  logger.verbose("All existing files will be preserved as user-owned");
37992
38192
  return result;
37993
38193
  }
37994
- const entries = await readdir13(commandsDir);
38194
+ const entries = await readdir14(commandsDir);
37995
38195
  if (entries.length === 0) {
37996
38196
  logger.verbose("Commands directory is empty");
37997
38197
  return result;
37998
38198
  }
37999
38199
  for (const entry of entries) {
38000
- const entryPath = join48(commandsDir, entry);
38200
+ const entryPath = join49(commandsDir, entry);
38001
38201
  const stats = await lstat7(entryPath);
38002
38202
  if (stats.isSymbolicLink()) {
38003
38203
  addSymlinkSkip(entry, accumulator);
@@ -38049,7 +38249,7 @@ async function handleMerge(ctx) {
38049
38249
  let customClaudeFiles = [];
38050
38250
  if (!ctx.options.fresh) {
38051
38251
  logger.info("Scanning for custom .claude files...");
38052
- const scanSourceDir = ctx.options.global ? join49(ctx.extractDir, ".claude") : ctx.extractDir;
38252
+ const scanSourceDir = ctx.options.global ? join50(ctx.extractDir, ".claude") : ctx.extractDir;
38053
38253
  const scanTargetSubdir = ctx.options.global ? "" : ".claude";
38054
38254
  customClaudeFiles = await FileScanner2.findCustomFiles(ctx.resolvedDir, scanSourceDir, scanTargetSubdir);
38055
38255
  } else {
@@ -38113,7 +38313,7 @@ async function handleMerge(ctx) {
38113
38313
  return { ...ctx, cancelled: true };
38114
38314
  }
38115
38315
  }
38116
- const sourceDir = ctx.options.global ? join49(ctx.extractDir, ".claude") : ctx.extractDir;
38316
+ const sourceDir = ctx.options.global ? join50(ctx.extractDir, ".claude") : ctx.extractDir;
38117
38317
  await merger.merge(sourceDir, ctx.resolvedDir, ctx.isNonInteractive);
38118
38318
  const fileConflicts = merger.getFileConflicts();
38119
38319
  if (fileConflicts.length > 0 && !ctx.isNonInteractive) {
@@ -38142,7 +38342,7 @@ async function handleMerge(ctx) {
38142
38342
  };
38143
38343
  }
38144
38344
  // src/commands/init/phases/migration-handler.ts
38145
- import { join as join57 } from "node:path";
38345
+ import { join as join58 } from "node:path";
38146
38346
 
38147
38347
  // src/domains/skills/skills-detector.ts
38148
38348
  init_logger();
@@ -38154,8 +38354,8 @@ init_logger();
38154
38354
  // src/domains/skills/skills-manifest.ts
38155
38355
  init_logger();
38156
38356
  import { createHash as createHash2 } from "node:crypto";
38157
- import { readFile as readFile17, readdir as readdir14, writeFile as writeFile14 } from "node:fs/promises";
38158
- import { join as join50, relative as relative9 } from "node:path";
38357
+ import { readFile as readFile18, readdir as readdir15, writeFile as writeFile15 } from "node:fs/promises";
38358
+ import { join as join51, relative as relative9 } from "node:path";
38159
38359
  init_types2();
38160
38360
  var import_fs_extra17 = __toESM(require_lib(), 1);
38161
38361
 
@@ -38179,18 +38379,18 @@ class SkillsManifestManager {
38179
38379
  return manifest;
38180
38380
  }
38181
38381
  static async writeManifest(skillsDir, manifest) {
38182
- const manifestPath = join50(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
38183
- await writeFile14(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
38382
+ const manifestPath = join51(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
38383
+ await writeFile15(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
38184
38384
  logger.debug(`Wrote manifest to: ${manifestPath}`);
38185
38385
  }
38186
38386
  static async readManifest(skillsDir) {
38187
- const manifestPath = join50(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
38387
+ const manifestPath = join51(skillsDir, SkillsManifestManager.MANIFEST_FILENAME);
38188
38388
  if (!await import_fs_extra17.pathExists(manifestPath)) {
38189
38389
  logger.debug(`No manifest found at: ${manifestPath}`);
38190
38390
  return null;
38191
38391
  }
38192
38392
  try {
38193
- const content = await readFile17(manifestPath, "utf-8");
38393
+ const content = await readFile18(manifestPath, "utf-8");
38194
38394
  const data = JSON.parse(content);
38195
38395
  const manifest = SkillsManifestSchema.parse(data);
38196
38396
  logger.debug(`Read manifest from: ${manifestPath}`);
@@ -38201,14 +38401,14 @@ class SkillsManifestManager {
38201
38401
  }
38202
38402
  }
38203
38403
  static async detectStructure(skillsDir) {
38204
- const entries = await readdir14(skillsDir, { withFileTypes: true });
38404
+ const entries = await readdir15(skillsDir, { withFileTypes: true });
38205
38405
  const dirs = entries.filter((entry) => entry.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(entry.name) && !entry.name.startsWith("."));
38206
38406
  if (dirs.length === 0) {
38207
38407
  return "flat";
38208
38408
  }
38209
38409
  for (const dir of dirs.slice(0, 3)) {
38210
- const dirPath = join50(skillsDir, dir.name);
38211
- const subEntries = await readdir14(dirPath, { withFileTypes: true });
38410
+ const dirPath = join51(skillsDir, dir.name);
38411
+ const subEntries = await readdir15(dirPath, { withFileTypes: true });
38212
38412
  const hasSubdirs = subEntries.some((entry) => entry.isDirectory());
38213
38413
  if (hasSubdirs) {
38214
38414
  return "categorized";
@@ -38223,10 +38423,10 @@ class SkillsManifestManager {
38223
38423
  static async scanSkills(skillsDir, structure) {
38224
38424
  const skills = [];
38225
38425
  if (structure === "flat") {
38226
- const entries = await readdir14(skillsDir, { withFileTypes: true });
38426
+ const entries = await readdir15(skillsDir, { withFileTypes: true });
38227
38427
  for (const entry of entries) {
38228
38428
  if (entry.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(entry.name) && !entry.name.startsWith(".")) {
38229
- const skillPath = join50(skillsDir, entry.name);
38429
+ const skillPath = join51(skillsDir, entry.name);
38230
38430
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
38231
38431
  skills.push({
38232
38432
  name: entry.name,
@@ -38235,14 +38435,14 @@ class SkillsManifestManager {
38235
38435
  }
38236
38436
  }
38237
38437
  } else {
38238
- const categories = await readdir14(skillsDir, { withFileTypes: true });
38438
+ const categories = await readdir15(skillsDir, { withFileTypes: true });
38239
38439
  for (const category of categories) {
38240
38440
  if (category.isDirectory() && !BUILD_ARTIFACT_DIRS.includes(category.name) && !category.name.startsWith(".")) {
38241
- const categoryPath = join50(skillsDir, category.name);
38242
- const skillEntries = await readdir14(categoryPath, { withFileTypes: true });
38441
+ const categoryPath = join51(skillsDir, category.name);
38442
+ const skillEntries = await readdir15(categoryPath, { withFileTypes: true });
38243
38443
  for (const skillEntry of skillEntries) {
38244
38444
  if (skillEntry.isDirectory() && !skillEntry.name.startsWith(".")) {
38245
- const skillPath = join50(categoryPath, skillEntry.name);
38445
+ const skillPath = join51(categoryPath, skillEntry.name);
38246
38446
  const hash = await SkillsManifestManager.hashDirectory(skillPath);
38247
38447
  skills.push({
38248
38448
  name: skillEntry.name,
@@ -38262,7 +38462,7 @@ class SkillsManifestManager {
38262
38462
  files.sort();
38263
38463
  for (const file of files) {
38264
38464
  const relativePath = relative9(dirPath, file);
38265
- const content = await readFile17(file);
38465
+ const content = await readFile18(file);
38266
38466
  hash.update(relativePath);
38267
38467
  hash.update(content);
38268
38468
  }
@@ -38270,9 +38470,9 @@ class SkillsManifestManager {
38270
38470
  }
38271
38471
  static async getAllFiles(dirPath) {
38272
38472
  const files = [];
38273
- const entries = await readdir14(dirPath, { withFileTypes: true });
38473
+ const entries = await readdir15(dirPath, { withFileTypes: true });
38274
38474
  for (const entry of entries) {
38275
- const fullPath = join50(dirPath, entry.name);
38475
+ const fullPath = join51(dirPath, entry.name);
38276
38476
  if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name)) {
38277
38477
  continue;
38278
38478
  }
@@ -38393,13 +38593,13 @@ function getPathMapping(skillName, oldBasePath, newBasePath) {
38393
38593
 
38394
38594
  // src/domains/skills/detection/script-detector.ts
38395
38595
  var import_fs_extra18 = __toESM(require_lib(), 1);
38396
- import { readdir as readdir15 } from "node:fs/promises";
38397
- import { join as join51 } from "node:path";
38596
+ import { readdir as readdir16 } from "node:fs/promises";
38597
+ import { join as join52 } from "node:path";
38398
38598
  async function scanDirectory(skillsDir) {
38399
38599
  if (!await import_fs_extra18.pathExists(skillsDir)) {
38400
38600
  return ["flat", []];
38401
38601
  }
38402
- const entries = await readdir15(skillsDir, { withFileTypes: true });
38602
+ const entries = await readdir16(skillsDir, { withFileTypes: true });
38403
38603
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith("."));
38404
38604
  if (dirs.length === 0) {
38405
38605
  return ["flat", []];
@@ -38407,13 +38607,13 @@ async function scanDirectory(skillsDir) {
38407
38607
  let totalSkillLikeCount = 0;
38408
38608
  const allSkills = [];
38409
38609
  for (const dir of dirs) {
38410
- const dirPath = join51(skillsDir, dir.name);
38411
- const subEntries = await readdir15(dirPath, { withFileTypes: true });
38610
+ const dirPath = join52(skillsDir, dir.name);
38611
+ const subEntries = await readdir16(dirPath, { withFileTypes: true });
38412
38612
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
38413
38613
  if (subdirs.length > 0) {
38414
38614
  for (const subdir of subdirs.slice(0, 3)) {
38415
- const subdirPath = join51(dirPath, subdir.name);
38416
- const subdirFiles = await readdir15(subdirPath, { withFileTypes: true });
38615
+ const subdirPath = join52(dirPath, subdir.name);
38616
+ const subdirFiles = await readdir16(subdirPath, { withFileTypes: true });
38417
38617
  const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
38418
38618
  if (hasSkillMarker) {
38419
38619
  totalSkillLikeCount++;
@@ -38569,12 +38769,12 @@ class SkillsMigrationDetector {
38569
38769
  // src/domains/skills/skills-migrator.ts
38570
38770
  init_logger();
38571
38771
  init_types2();
38572
- import { join as join56 } from "node:path";
38772
+ import { join as join57 } from "node:path";
38573
38773
 
38574
38774
  // src/domains/skills/migrator/migration-executor.ts
38575
38775
  init_logger();
38576
- import { copyFile as copyFile4, mkdir as mkdir17, readdir as readdir16, rm as rm3 } from "node:fs/promises";
38577
- import { join as join52 } from "node:path";
38776
+ import { copyFile as copyFile4, mkdir as mkdir17, readdir as readdir17, rm as rm3 } from "node:fs/promises";
38777
+ import { join as join53 } from "node:path";
38578
38778
  var import_fs_extra20 = __toESM(require_lib(), 1);
38579
38779
 
38580
38780
  // src/domains/skills/skills-migration-prompts.ts
@@ -38737,10 +38937,10 @@ Detected changes:`;
38737
38937
  // src/domains/skills/migrator/migration-executor.ts
38738
38938
  async function copySkillDirectory(sourceDir, destDir) {
38739
38939
  await mkdir17(destDir, { recursive: true });
38740
- const entries = await readdir16(sourceDir, { withFileTypes: true });
38940
+ const entries = await readdir17(sourceDir, { withFileTypes: true });
38741
38941
  for (const entry of entries) {
38742
- const sourcePath = join52(sourceDir, entry.name);
38743
- const destPath = join52(destDir, entry.name);
38942
+ const sourcePath = join53(sourceDir, entry.name);
38943
+ const destPath = join53(destDir, entry.name);
38744
38944
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
38745
38945
  continue;
38746
38946
  }
@@ -38755,7 +38955,7 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
38755
38955
  const migrated = [];
38756
38956
  const preserved = [];
38757
38957
  const errors2 = [];
38758
- const tempDir = join52(currentSkillsDir, "..", ".skills-migration-temp");
38958
+ const tempDir = join53(currentSkillsDir, "..", ".skills-migration-temp");
38759
38959
  await mkdir17(tempDir, { recursive: true });
38760
38960
  try {
38761
38961
  for (const mapping of mappings) {
@@ -38776,9 +38976,9 @@ async function executeInternal(mappings, customizations, currentSkillsDir, inter
38776
38976
  }
38777
38977
  }
38778
38978
  const category = mapping.category;
38779
- const targetPath = category ? join52(tempDir, category, skillName) : join52(tempDir, skillName);
38979
+ const targetPath = category ? join53(tempDir, category, skillName) : join53(tempDir, skillName);
38780
38980
  if (category) {
38781
- await mkdir17(join52(tempDir, category), { recursive: true });
38981
+ await mkdir17(join53(tempDir, category), { recursive: true });
38782
38982
  }
38783
38983
  await copySkillDirectory(currentSkillPath, targetPath);
38784
38984
  migrated.push(skillName);
@@ -38844,8 +39044,8 @@ function validateMigrationPath(path11, paramName) {
38844
39044
  init_logger();
38845
39045
  init_types2();
38846
39046
  var import_fs_extra21 = __toESM(require_lib(), 1);
38847
- import { copyFile as copyFile5, mkdir as mkdir18, readdir as readdir17, rm as rm4, stat as stat9 } from "node:fs/promises";
38848
- import { basename as basename2, join as join53, normalize as normalize6 } from "node:path";
39047
+ import { copyFile as copyFile5, mkdir as mkdir18, readdir as readdir18, rm as rm4, stat as stat9 } from "node:fs/promises";
39048
+ import { basename as basename2, join as join54, normalize as normalize6 } from "node:path";
38849
39049
  function validatePath2(path11, paramName) {
38850
39050
  if (!path11 || typeof path11 !== "string") {
38851
39051
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -38871,7 +39071,7 @@ class SkillsBackupManager {
38871
39071
  const timestamp = Date.now();
38872
39072
  const randomSuffix = Math.random().toString(36).substring(2, 8);
38873
39073
  const backupDirName = `${SkillsBackupManager.BACKUP_PREFIX}${timestamp}-${randomSuffix}`;
38874
- const backupDir = parentDir ? join53(parentDir, backupDirName) : join53(skillsDir, "..", backupDirName);
39074
+ const backupDir = parentDir ? join54(parentDir, backupDirName) : join54(skillsDir, "..", backupDirName);
38875
39075
  logger.info(`Creating backup at: ${backupDir}`);
38876
39076
  try {
38877
39077
  await mkdir18(backupDir, { recursive: true });
@@ -38921,8 +39121,8 @@ class SkillsBackupManager {
38921
39121
  return [];
38922
39122
  }
38923
39123
  try {
38924
- const entries = await readdir17(parentDir, { withFileTypes: true });
38925
- const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join53(parentDir, entry.name));
39124
+ const entries = await readdir18(parentDir, { withFileTypes: true });
39125
+ const backups = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(SkillsBackupManager.BACKUP_PREFIX)).map((entry) => join54(parentDir, entry.name));
38926
39126
  backups.sort().reverse();
38927
39127
  return backups;
38928
39128
  } catch (error) {
@@ -38948,10 +39148,10 @@ class SkillsBackupManager {
38948
39148
  return await SkillsBackupManager.getDirectorySize(backupDir);
38949
39149
  }
38950
39150
  static async copyDirectory(sourceDir, destDir) {
38951
- const entries = await readdir17(sourceDir, { withFileTypes: true });
39151
+ const entries = await readdir18(sourceDir, { withFileTypes: true });
38952
39152
  for (const entry of entries) {
38953
- const sourcePath = join53(sourceDir, entry.name);
38954
- const destPath = join53(destDir, entry.name);
39153
+ const sourcePath = join54(sourceDir, entry.name);
39154
+ const destPath = join54(destDir, entry.name);
38955
39155
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.isSymbolicLink()) {
38956
39156
  continue;
38957
39157
  }
@@ -38965,9 +39165,9 @@ class SkillsBackupManager {
38965
39165
  }
38966
39166
  static async getDirectorySize(dirPath) {
38967
39167
  let size = 0;
38968
- const entries = await readdir17(dirPath, { withFileTypes: true });
39168
+ const entries = await readdir18(dirPath, { withFileTypes: true });
38969
39169
  for (const entry of entries) {
38970
- const fullPath = join53(dirPath, entry.name);
39170
+ const fullPath = join54(dirPath, entry.name);
38971
39171
  if (entry.isSymbolicLink()) {
38972
39172
  continue;
38973
39173
  }
@@ -39001,13 +39201,13 @@ import { relative as relative11 } from "node:path";
39001
39201
  // src/domains/skills/customization/hash-calculator.ts
39002
39202
  import { createHash as createHash3 } from "node:crypto";
39003
39203
  import { createReadStream as createReadStream2 } from "node:fs";
39004
- import { readFile as readFile18, readdir as readdir18 } from "node:fs/promises";
39005
- import { join as join54, relative as relative10 } from "node:path";
39204
+ import { readFile as readFile19, readdir as readdir19 } from "node:fs/promises";
39205
+ import { join as join55, relative as relative10 } from "node:path";
39006
39206
  async function getAllFiles(dirPath) {
39007
39207
  const files = [];
39008
- const entries = await readdir18(dirPath, { withFileTypes: true });
39208
+ const entries = await readdir19(dirPath, { withFileTypes: true });
39009
39209
  for (const entry of entries) {
39010
- const fullPath = join54(dirPath, entry.name);
39210
+ const fullPath = join55(dirPath, entry.name);
39011
39211
  if (entry.name.startsWith(".") || BUILD_ARTIFACT_DIRS.includes(entry.name) || entry.isSymbolicLink()) {
39012
39212
  continue;
39013
39213
  }
@@ -39040,7 +39240,7 @@ async function hashDirectory(dirPath) {
39040
39240
  files.sort();
39041
39241
  for (const file of files) {
39042
39242
  const relativePath = relative10(dirPath, file);
39043
- const content = await readFile18(file);
39243
+ const content = await readFile19(file);
39044
39244
  hash.update(relativePath);
39045
39245
  hash.update(content);
39046
39246
  }
@@ -39133,8 +39333,8 @@ async function detectFileChanges(currentSkillPath, baselineSkillPath) {
39133
39333
  // src/domains/skills/customization/scan-reporter.ts
39134
39334
  init_types2();
39135
39335
  var import_fs_extra23 = __toESM(require_lib(), 1);
39136
- import { readdir as readdir19 } from "node:fs/promises";
39137
- import { join as join55, normalize as normalize7 } from "node:path";
39336
+ import { readdir as readdir20 } from "node:fs/promises";
39337
+ import { join as join56, normalize as normalize7 } from "node:path";
39138
39338
  function validatePath3(path11, paramName) {
39139
39339
  if (!path11 || typeof path11 !== "string") {
39140
39340
  throw new SkillsMigrationError(`${paramName} must be a non-empty string`);
@@ -39150,19 +39350,19 @@ async function scanSkillsDirectory(skillsDir) {
39150
39350
  if (!await import_fs_extra23.pathExists(skillsDir)) {
39151
39351
  return ["flat", []];
39152
39352
  }
39153
- const entries = await readdir19(skillsDir, { withFileTypes: true });
39353
+ const entries = await readdir20(skillsDir, { withFileTypes: true });
39154
39354
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith("."));
39155
39355
  if (dirs.length === 0) {
39156
39356
  return ["flat", []];
39157
39357
  }
39158
- const firstDirPath = join55(skillsDir, dirs[0].name);
39159
- const subEntries = await readdir19(firstDirPath, { withFileTypes: true });
39358
+ const firstDirPath = join56(skillsDir, dirs[0].name);
39359
+ const subEntries = await readdir20(firstDirPath, { withFileTypes: true });
39160
39360
  const subdirs = subEntries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
39161
39361
  if (subdirs.length > 0) {
39162
39362
  let skillLikeCount = 0;
39163
39363
  for (const subdir of subdirs.slice(0, 3)) {
39164
- const subdirPath = join55(firstDirPath, subdir.name);
39165
- const subdirFiles = await readdir19(subdirPath, { withFileTypes: true });
39364
+ const subdirPath = join56(firstDirPath, subdir.name);
39365
+ const subdirFiles = await readdir20(subdirPath, { withFileTypes: true });
39166
39366
  const hasSkillMarker = subdirFiles.some((file) => file.isFile() && (file.name === "skill.md" || file.name === "README.md" || file.name === "readme.md" || file.name === "config.json" || file.name === "package.json"));
39167
39367
  if (hasSkillMarker) {
39168
39368
  skillLikeCount++;
@@ -39171,8 +39371,8 @@ async function scanSkillsDirectory(skillsDir) {
39171
39371
  if (skillLikeCount > 0) {
39172
39372
  const skills = [];
39173
39373
  for (const dir of dirs) {
39174
- const categoryPath = join55(skillsDir, dir.name);
39175
- const skillDirs = await readdir19(categoryPath, { withFileTypes: true });
39374
+ const categoryPath = join56(skillsDir, dir.name);
39375
+ const skillDirs = await readdir20(categoryPath, { withFileTypes: true });
39176
39376
  skills.push(...skillDirs.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name));
39177
39377
  }
39178
39378
  return ["categorized", skills];
@@ -39181,17 +39381,17 @@ async function scanSkillsDirectory(skillsDir) {
39181
39381
  return ["flat", dirs.map((dir) => dir.name)];
39182
39382
  }
39183
39383
  async function findSkillPath(skillsDir, skillName) {
39184
- const flatPath = join55(skillsDir, skillName);
39384
+ const flatPath = join56(skillsDir, skillName);
39185
39385
  if (await import_fs_extra23.pathExists(flatPath)) {
39186
39386
  return { path: flatPath, category: undefined };
39187
39387
  }
39188
- const entries = await readdir19(skillsDir, { withFileTypes: true });
39388
+ const entries = await readdir20(skillsDir, { withFileTypes: true });
39189
39389
  for (const entry of entries) {
39190
39390
  if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") {
39191
39391
  continue;
39192
39392
  }
39193
- const categoryPath = join55(skillsDir, entry.name);
39194
- const skillPath = join55(categoryPath, skillName);
39393
+ const categoryPath = join56(skillsDir, entry.name);
39394
+ const skillPath = join56(categoryPath, skillName);
39195
39395
  if (await import_fs_extra23.pathExists(skillPath)) {
39196
39396
  return { path: skillPath, category: entry.name };
39197
39397
  }
@@ -39285,7 +39485,7 @@ class SkillsMigrator {
39285
39485
  }
39286
39486
  }
39287
39487
  if (options.backup && !options.dryRun) {
39288
- const claudeDir = join56(currentSkillsDir, "..");
39488
+ const claudeDir = join57(currentSkillsDir, "..");
39289
39489
  result.backupPath = await SkillsBackupManager.createBackup(currentSkillsDir, claudeDir);
39290
39490
  logger.success(`Backup created at: ${result.backupPath}`);
39291
39491
  }
@@ -39345,7 +39545,7 @@ async function handleMigration(ctx) {
39345
39545
  logger.debug("Skipping skills migration (fresh installation)");
39346
39546
  return ctx;
39347
39547
  }
39348
- const newSkillsDir = join57(ctx.extractDir, ".claude", "skills");
39548
+ const newSkillsDir = join58(ctx.extractDir, ".claude", "skills");
39349
39549
  const currentSkillsDir = PathResolver.buildSkillsPath(ctx.resolvedDir, ctx.options.global);
39350
39550
  if (!await import_fs_extra24.pathExists(newSkillsDir) || !await import_fs_extra24.pathExists(currentSkillsDir)) {
39351
39551
  return ctx;
@@ -39367,13 +39567,156 @@ async function handleMigration(ctx) {
39367
39567
  }
39368
39568
  return ctx;
39369
39569
  }
39570
+ // src/commands/init/phases/opencode-handler.ts
39571
+ import { cp, readdir as readdir22, rm as rm5 } from "node:fs/promises";
39572
+ import { join as join60 } from "node:path";
39573
+
39574
+ // src/services/transformers/opencode-path-transformer.ts
39575
+ init_logger();
39576
+ import { readFile as readFile20, readdir as readdir21, writeFile as writeFile16 } from "node:fs/promises";
39577
+ import { platform as platform10 } from "node:os";
39578
+ import { extname as extname2, join as join59 } from "node:path";
39579
+ var IS_WINDOWS3 = platform10() === "win32";
39580
+ function getOpenCodeGlobalPath() {
39581
+ return IS_WINDOWS3 ? "%APPDATA%/opencode/" : "$HOME/.config/opencode/";
39582
+ }
39583
+ var TRANSFORMABLE_EXTENSIONS2 = new Set([
39584
+ ".md",
39585
+ ".js",
39586
+ ".ts",
39587
+ ".json",
39588
+ ".sh",
39589
+ ".ps1",
39590
+ ".yaml",
39591
+ ".yml",
39592
+ ".toml"
39593
+ ]);
39594
+ function transformOpenCodeContent(content) {
39595
+ let changes = 0;
39596
+ let transformed = content;
39597
+ const globalPath = getOpenCodeGlobalPath();
39598
+ transformed = transformed.replace(/\.\/\.opencode\//g, () => {
39599
+ changes++;
39600
+ return globalPath;
39601
+ });
39602
+ transformed = transformed.replace(/(["'`])\.opencode\//g, (_match, quote) => {
39603
+ changes++;
39604
+ return `${quote}${globalPath}`;
39605
+ });
39606
+ transformed = transformed.replace(/\(\.opencode\//g, () => {
39607
+ changes++;
39608
+ return `(${globalPath}`;
39609
+ });
39610
+ transformed = transformed.replace(/ \.opencode\//g, () => {
39611
+ changes++;
39612
+ return ` ${globalPath}`;
39613
+ });
39614
+ transformed = transformed.replace(/^\.opencode\//gm, () => {
39615
+ changes++;
39616
+ return globalPath;
39617
+ });
39618
+ transformed = transformed.replace(/: \.opencode\//g, () => {
39619
+ changes++;
39620
+ return `: ${globalPath}`;
39621
+ });
39622
+ transformed = transformed.replace(/:\.opencode\//g, () => {
39623
+ changes++;
39624
+ return `:${globalPath}`;
39625
+ });
39626
+ return { transformed, changes };
39627
+ }
39628
+ function shouldTransformFile2(filename) {
39629
+ const ext2 = extname2(filename).toLowerCase();
39630
+ return TRANSFORMABLE_EXTENSIONS2.has(ext2);
39631
+ }
39632
+ async function transformPathsForGlobalOpenCode(directory, options = {}) {
39633
+ let filesTransformed = 0;
39634
+ let totalChanges = 0;
39635
+ let filesSkipped = 0;
39636
+ async function processDirectory2(dir) {
39637
+ const entries = await readdir21(dir, { withFileTypes: true });
39638
+ for (const entry of entries) {
39639
+ const fullPath = join59(dir, entry.name);
39640
+ if (entry.isDirectory()) {
39641
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) {
39642
+ continue;
39643
+ }
39644
+ await processDirectory2(fullPath);
39645
+ } else if (entry.isFile() && shouldTransformFile2(entry.name)) {
39646
+ try {
39647
+ const content = await readFile20(fullPath, "utf-8");
39648
+ const { transformed, changes } = transformOpenCodeContent(content);
39649
+ if (changes > 0) {
39650
+ await writeFile16(fullPath, transformed, "utf-8");
39651
+ filesTransformed++;
39652
+ totalChanges += changes;
39653
+ if (options.verbose) {
39654
+ logger.verbose(`Transformed ${changes} OpenCode path(s) in ${fullPath}`);
39655
+ }
39656
+ }
39657
+ } catch (error) {
39658
+ filesSkipped++;
39659
+ if (options.verbose) {
39660
+ logger.verbose(`Skipping ${fullPath}: ${error instanceof Error ? error.message : "unknown error"}`);
39661
+ }
39662
+ }
39663
+ }
39664
+ }
39665
+ }
39666
+ await processDirectory2(directory);
39667
+ return { filesTransformed, totalChanges, filesSkipped };
39668
+ }
39669
+
39670
+ // src/commands/init/phases/opencode-handler.ts
39671
+ init_logger();
39672
+ var import_fs_extra25 = __toESM(require_lib(), 1);
39673
+ async function handleOpenCode(ctx) {
39674
+ if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir) {
39675
+ return ctx;
39676
+ }
39677
+ const openCodeSource = join60(ctx.extractDir, ".opencode");
39678
+ if (!await import_fs_extra25.pathExists(openCodeSource)) {
39679
+ logger.debug("No .opencode directory in archive, skipping");
39680
+ return ctx;
39681
+ }
39682
+ logger.info("Processing .opencode configuration...");
39683
+ if (ctx.options.global) {
39684
+ const targetDir = PathResolver.getOpenCodeDir(true);
39685
+ logger.verbose(`Relocating .opencode to ${targetDir}`);
39686
+ const transformResult = await transformPathsForGlobalOpenCode(openCodeSource, {
39687
+ verbose: logger.isVerbose()
39688
+ });
39689
+ if (transformResult.totalChanges > 0) {
39690
+ logger.success(`Transformed ${transformResult.totalChanges} OpenCode path(s) in ${transformResult.filesTransformed} file(s)`);
39691
+ }
39692
+ await import_fs_extra25.ensureDir(targetDir);
39693
+ const entries = await readdir22(openCodeSource, { withFileTypes: true });
39694
+ for (const entry of entries) {
39695
+ const sourcePath = join60(openCodeSource, entry.name);
39696
+ const targetPath = join60(targetDir, entry.name);
39697
+ if (await import_fs_extra25.pathExists(targetPath)) {
39698
+ if (!ctx.options.forceOverwrite) {
39699
+ logger.verbose(`Skipping existing: ${entry.name}`);
39700
+ continue;
39701
+ }
39702
+ }
39703
+ await cp(sourcePath, targetPath, { recursive: true });
39704
+ logger.verbose(`Copied: ${entry.name}`);
39705
+ }
39706
+ await rm5(openCodeSource, { recursive: true, force: true });
39707
+ logger.success(`OpenCode config installed to ${targetDir}`);
39708
+ } else {
39709
+ logger.debug("Local mode: .opencode will be placed at project root");
39710
+ }
39711
+ return ctx;
39712
+ }
39370
39713
  // src/domains/config/config-manager.ts
39371
39714
  init_logger();
39372
39715
  import { existsSync as existsSync18 } from "node:fs";
39373
- import { mkdir as mkdir19, readFile as readFile19, rename as rename2, rm as rm5, writeFile as writeFile15 } from "node:fs/promises";
39716
+ import { mkdir as mkdir19, readFile as readFile21, rename as rename2, rm as rm6, writeFile as writeFile17 } from "node:fs/promises";
39374
39717
  import { chmod as chmod2 } from "node:fs/promises";
39375
- import { platform as platform10 } from "node:os";
39376
- import { join as join58 } from "node:path";
39718
+ import { platform as platform11 } from "node:os";
39719
+ import { join as join61 } from "node:path";
39377
39720
  init_types2();
39378
39721
  var PROJECT_CONFIG_FILE = ".ck.json";
39379
39722
 
@@ -39381,7 +39724,7 @@ class ConfigManager {
39381
39724
  static config = null;
39382
39725
  static globalFlag = false;
39383
39726
  static getProjectConfigDir(projectDir, global3) {
39384
- return global3 ? projectDir : join58(projectDir, ".claude");
39727
+ return global3 ? projectDir : join61(projectDir, ".claude");
39385
39728
  }
39386
39729
  static setGlobalFlag(global3) {
39387
39730
  ConfigManager.globalFlag = global3;
@@ -39397,7 +39740,7 @@ class ConfigManager {
39397
39740
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
39398
39741
  try {
39399
39742
  if (existsSync18(configFile)) {
39400
- const content = await readFile19(configFile, "utf-8");
39743
+ const content = await readFile21(configFile, "utf-8");
39401
39744
  const data = JSON.parse(content);
39402
39745
  ConfigManager.config = ConfigSchema.parse(data);
39403
39746
  logger.debug(`Config loaded from ${configFile}`);
@@ -39416,12 +39759,12 @@ class ConfigManager {
39416
39759
  const configFile = PathResolver.getConfigFile(ConfigManager.globalFlag);
39417
39760
  if (!existsSync18(configDir)) {
39418
39761
  await mkdir19(configDir, { recursive: true });
39419
- if (platform10() !== "win32") {
39762
+ if (platform11() !== "win32") {
39420
39763
  await chmod2(configDir, 448);
39421
39764
  }
39422
39765
  }
39423
- await writeFile15(configFile, JSON.stringify(validConfig, null, 2), "utf-8");
39424
- if (platform10() !== "win32") {
39766
+ await writeFile17(configFile, JSON.stringify(validConfig, null, 2), "utf-8");
39767
+ if (platform11() !== "win32") {
39425
39768
  await chmod2(configFile, 384);
39426
39769
  }
39427
39770
  ConfigManager.config = validConfig;
@@ -39448,10 +39791,10 @@ class ConfigManager {
39448
39791
  }
39449
39792
  static async loadProjectConfig(projectDir, global3 = false) {
39450
39793
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
39451
- const configPath = join58(configDir, PROJECT_CONFIG_FILE);
39794
+ const configPath = join61(configDir, PROJECT_CONFIG_FILE);
39452
39795
  try {
39453
39796
  if (existsSync18(configPath)) {
39454
- const content = await readFile19(configPath, "utf-8");
39797
+ const content = await readFile21(configPath, "utf-8");
39455
39798
  const data = JSON.parse(content);
39456
39799
  const folders = FoldersConfigSchema.parse(data.paths || data);
39457
39800
  logger.debug(`Project config loaded from ${configPath}`);
@@ -39464,7 +39807,7 @@ class ConfigManager {
39464
39807
  }
39465
39808
  static async saveProjectConfig(projectDir, folders, global3 = false) {
39466
39809
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
39467
- const configPath = join58(configDir, PROJECT_CONFIG_FILE);
39810
+ const configPath = join61(configDir, PROJECT_CONFIG_FILE);
39468
39811
  try {
39469
39812
  if (!existsSync18(configDir)) {
39470
39813
  await mkdir19(configDir, { recursive: true });
@@ -39472,7 +39815,7 @@ class ConfigManager {
39472
39815
  let existingConfig = {};
39473
39816
  if (existsSync18(configPath)) {
39474
39817
  try {
39475
- const content = await readFile19(configPath, "utf-8");
39818
+ const content = await readFile21(configPath, "utf-8");
39476
39819
  existingConfig = JSON.parse(content);
39477
39820
  } catch (error) {
39478
39821
  logger.debug(`Could not parse existing config, starting fresh: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -39487,7 +39830,7 @@ class ConfigManager {
39487
39830
  ...validFolders
39488
39831
  }
39489
39832
  };
39490
- await writeFile15(configPath, JSON.stringify(mergedConfig, null, 2), "utf-8");
39833
+ await writeFile17(configPath, JSON.stringify(mergedConfig, null, 2), "utf-8");
39491
39834
  logger.debug(`Project config saved to ${configPath}`);
39492
39835
  } catch (error) {
39493
39836
  throw new Error(`Failed to save project config: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -39513,11 +39856,11 @@ class ConfigManager {
39513
39856
  }
39514
39857
  static projectConfigExists(projectDir, global3 = false) {
39515
39858
  const configDir = ConfigManager.getProjectConfigDir(projectDir, global3);
39516
- return existsSync18(join58(configDir, PROJECT_CONFIG_FILE));
39859
+ return existsSync18(join61(configDir, PROJECT_CONFIG_FILE));
39517
39860
  }
39518
39861
  static async migrateNestedConfig(globalDir) {
39519
- const correctPath = join58(globalDir, PROJECT_CONFIG_FILE);
39520
- const incorrectPath = join58(globalDir, ".claude", PROJECT_CONFIG_FILE);
39862
+ const correctPath = join61(globalDir, PROJECT_CONFIG_FILE);
39863
+ const incorrectPath = join61(globalDir, ".claude", PROJECT_CONFIG_FILE);
39521
39864
  if (existsSync18(correctPath)) {
39522
39865
  logger.debug("Config already exists at correct location, skipping migration");
39523
39866
  return false;
@@ -39527,9 +39870,9 @@ class ConfigManager {
39527
39870
  logger.info("Migrating .ck.json from nested location to correct location...");
39528
39871
  await rename2(incorrectPath, correctPath);
39529
39872
  logger.success(`Migrated ${PROJECT_CONFIG_FILE} to ${correctPath}`);
39530
- const nestedClaudeDir = join58(globalDir, ".claude");
39873
+ const nestedClaudeDir = join61(globalDir, ".claude");
39531
39874
  try {
39532
- await rm5(nestedClaudeDir, { recursive: false });
39875
+ await rm6(nestedClaudeDir, { recursive: false });
39533
39876
  logger.debug("Removed empty nested .claude directory");
39534
39877
  } catch (rmError) {
39535
39878
  logger.debug(`Could not remove nested .claude dir (may contain other files): ${rmError instanceof Error ? rmError.message : "Unknown"}`);
@@ -39618,14 +39961,14 @@ Please use only one download method.`);
39618
39961
  };
39619
39962
  }
39620
39963
  // src/commands/init/phases/post-install-handler.ts
39621
- import { join as join61 } from "node:path";
39964
+ import { join as join64 } from "node:path";
39622
39965
 
39623
39966
  // src/domains/installation/setup-wizard.ts
39624
- import { join as join60 } from "node:path";
39967
+ import { join as join63 } from "node:path";
39625
39968
 
39626
39969
  // src/domains/config/config-generator.ts
39627
- var import_fs_extra25 = __toESM(require_lib(), 1);
39628
- import { join as join59 } from "node:path";
39970
+ var import_fs_extra26 = __toESM(require_lib(), 1);
39971
+ import { join as join62 } from "node:path";
39629
39972
  async function generateEnvFile(targetDir, values) {
39630
39973
  const lines = [
39631
39974
  "# Generated by ClaudeKit CLI setup wizard",
@@ -39667,8 +40010,8 @@ async function generateEnvFile(targetDir, values) {
39667
40010
  for (const [key, value] of otherValues) {
39668
40011
  lines.push(`${key}=${value}`);
39669
40012
  }
39670
- const envPath = join59(targetDir, ".env");
39671
- await import_fs_extra25.writeFile(envPath, `${lines.join(`
40013
+ const envPath = join62(targetDir, ".env");
40014
+ await import_fs_extra26.writeFile(envPath, `${lines.join(`
39672
40015
  `)}
39673
40016
  `, { mode: 384 });
39674
40017
  }
@@ -39686,7 +40029,7 @@ function validateApiKey(value, pattern) {
39686
40029
  // src/domains/installation/setup-wizard.ts
39687
40030
  init_logger();
39688
40031
  init_dist2();
39689
- var import_fs_extra26 = __toESM(require_lib(), 1);
40032
+ var import_fs_extra27 = __toESM(require_lib(), 1);
39690
40033
  var ESSENTIAL_CONFIGS = [
39691
40034
  {
39692
40035
  key: "GEMINI_API_KEY",
@@ -39715,7 +40058,7 @@ var ESSENTIAL_CONFIGS = [
39715
40058
  ];
39716
40059
  async function parseEnvFile(path11) {
39717
40060
  try {
39718
- const content = await import_fs_extra26.readFile(path11, "utf-8");
40061
+ const content = await import_fs_extra27.readFile(path11, "utf-8");
39719
40062
  const env2 = {};
39720
40063
  for (const line of content.split(`
39721
40064
  `)) {
@@ -39741,8 +40084,8 @@ async function parseEnvFile(path11) {
39741
40084
  }
39742
40085
  }
39743
40086
  async function checkGlobalConfig() {
39744
- const globalEnvPath = join60(PathResolver.getGlobalKitDir(), ".env");
39745
- if (!await import_fs_extra26.pathExists(globalEnvPath))
40087
+ const globalEnvPath = join63(PathResolver.getGlobalKitDir(), ".env");
40088
+ if (!await import_fs_extra27.pathExists(globalEnvPath))
39746
40089
  return false;
39747
40090
  const env2 = await parseEnvFile(globalEnvPath);
39748
40091
  return Object.keys(env2).length > 0;
@@ -39757,8 +40100,8 @@ async function runSetupWizard(options) {
39757
40100
  let globalEnv = {};
39758
40101
  const hasGlobalConfig = !isGlobal && await checkGlobalConfig();
39759
40102
  if (!isGlobal) {
39760
- const globalEnvPath = join60(PathResolver.getGlobalKitDir(), ".env");
39761
- if (await import_fs_extra26.pathExists(globalEnvPath)) {
40103
+ const globalEnvPath = join63(PathResolver.getGlobalKitDir(), ".env");
40104
+ if (await import_fs_extra27.pathExists(globalEnvPath)) {
39762
40105
  globalEnv = await parseEnvFile(globalEnvPath);
39763
40106
  }
39764
40107
  }
@@ -39820,7 +40163,7 @@ async function runSetupWizard(options) {
39820
40163
  }
39821
40164
  }
39822
40165
  await generateEnvFile(targetDir, values);
39823
- f2.success(`Configuration saved to ${join60(targetDir, ".env")}`);
40166
+ f2.success(`Configuration saved to ${join63(targetDir, ".env")}`);
39824
40167
  return true;
39825
40168
  }
39826
40169
  async function promptForAdditionalGeminiKeys(primaryKey) {
@@ -39870,17 +40213,17 @@ async function promptForAdditionalGeminiKeys(primaryKey) {
39870
40213
 
39871
40214
  // src/commands/init/phases/post-install-handler.ts
39872
40215
  init_logger();
39873
- var import_fs_extra27 = __toESM(require_lib(), 1);
40216
+ var import_fs_extra28 = __toESM(require_lib(), 1);
39874
40217
  async function handlePostInstall(ctx) {
39875
40218
  if (ctx.cancelled || !ctx.extractDir || !ctx.resolvedDir || !ctx.claudeDir) {
39876
40219
  return ctx;
39877
40220
  }
39878
40221
  if (ctx.options.global) {
39879
- const claudeMdSource = join61(ctx.extractDir, "CLAUDE.md");
39880
- const claudeMdDest = join61(ctx.resolvedDir, "CLAUDE.md");
39881
- if (await import_fs_extra27.pathExists(claudeMdSource)) {
39882
- if (!await import_fs_extra27.pathExists(claudeMdDest)) {
39883
- await import_fs_extra27.copy(claudeMdSource, claudeMdDest);
40222
+ const claudeMdSource = join64(ctx.extractDir, "CLAUDE.md");
40223
+ const claudeMdDest = join64(ctx.resolvedDir, "CLAUDE.md");
40224
+ if (await import_fs_extra28.pathExists(claudeMdSource)) {
40225
+ if (!await import_fs_extra28.pathExists(claudeMdDest)) {
40226
+ await import_fs_extra28.copy(claudeMdSource, claudeMdDest);
39884
40227
  logger.success("Copied CLAUDE.md to global directory");
39885
40228
  } else {
39886
40229
  logger.debug("CLAUDE.md already exists in global directory (preserved)");
@@ -39924,8 +40267,8 @@ async function handlePostInstall(ctx) {
39924
40267
  }
39925
40268
  }
39926
40269
  if (!ctx.options.skipSetup && !ctx.isNonInteractive) {
39927
- const envPath = join61(ctx.claudeDir, ".env");
39928
- if (!await import_fs_extra27.pathExists(envPath)) {
40270
+ const envPath = join64(ctx.claudeDir, ".env");
40271
+ if (!await import_fs_extra28.pathExists(envPath)) {
39929
40272
  const shouldSetup = await ctx.prompts.confirm("Set up API keys now? (Gemini API key for ai-multimodal skill, optional webhooks)");
39930
40273
  if (shouldSetup) {
39931
40274
  await runSetupWizard({
@@ -39946,7 +40289,7 @@ Optional: DISCORD_WEBHOOK_URL, TELEGRAM_BOT_TOKEN`, "Configuration skipped");
39946
40289
  }
39947
40290
  // src/commands/init/phases/selection-handler.ts
39948
40291
  import { mkdir as mkdir20 } from "node:fs/promises";
39949
- import { join as join63, resolve as resolve7 } from "node:path";
40292
+ import { join as join66, resolve as resolve7 } from "node:path";
39950
40293
 
39951
40294
  // src/domains/github/kit-access-checker.ts
39952
40295
  init_logger();
@@ -39975,11 +40318,11 @@ async function detectAccessibleKits() {
39975
40318
 
39976
40319
  // src/domains/installation/fresh-installer.ts
39977
40320
  init_logger();
39978
- import { join as join62 } from "node:path";
39979
- var import_fs_extra28 = __toESM(require_lib(), 1);
40321
+ import { join as join65 } from "node:path";
40322
+ var import_fs_extra29 = __toESM(require_lib(), 1);
39980
40323
  var CLAUDEKIT_SUBDIRECTORIES = ["commands", "agents", "skills", "workflows", "hooks"];
39981
40324
  async function handleFreshInstallation(claudeDir, prompts) {
39982
- if (!await import_fs_extra28.pathExists(claudeDir)) {
40325
+ if (!await import_fs_extra29.pathExists(claudeDir)) {
39983
40326
  logger.info(".claude directory does not exist, proceeding with fresh installation");
39984
40327
  return true;
39985
40328
  }
@@ -39994,8 +40337,8 @@ async function handleFreshInstallation(claudeDir, prompts) {
39994
40337
  const { rmSync } = await import("node:fs");
39995
40338
  let removedCount = 0;
39996
40339
  for (const subdir of CLAUDEKIT_SUBDIRECTORIES) {
39997
- const subdirPath = join62(claudeDir, subdir);
39998
- if (await import_fs_extra28.pathExists(subdirPath)) {
40340
+ const subdirPath = join65(claudeDir, subdir);
40341
+ if (await import_fs_extra29.pathExists(subdirPath)) {
39999
40342
  rmSync(subdirPath, { recursive: true, force: true });
40000
40343
  removedCount++;
40001
40344
  logger.debug(`Removed subdirectory: ${subdir}/`);
@@ -40012,7 +40355,7 @@ async function handleFreshInstallation(claudeDir, prompts) {
40012
40355
  // src/commands/init/phases/selection-handler.ts
40013
40356
  init_logger();
40014
40357
  init_types2();
40015
- var import_fs_extra29 = __toESM(require_lib(), 1);
40358
+ var import_fs_extra30 = __toESM(require_lib(), 1);
40016
40359
 
40017
40360
  // src/commands/init/types.ts
40018
40361
  function isSyncContext(ctx) {
@@ -40176,7 +40519,7 @@ async function handleSelection(ctx) {
40176
40519
  return { ...ctx, cancelled: true };
40177
40520
  }
40178
40521
  }
40179
- if (!await import_fs_extra29.pathExists(resolvedDir)) {
40522
+ if (!await import_fs_extra30.pathExists(resolvedDir)) {
40180
40523
  if (ctx.options.global) {
40181
40524
  await mkdir20(resolvedDir, { recursive: true });
40182
40525
  logger.info(`Created global directory: ${resolvedDir}`);
@@ -40188,7 +40531,7 @@ async function handleSelection(ctx) {
40188
40531
  }
40189
40532
  if (!ctx.options.fresh) {
40190
40533
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
40191
- const claudeDir = prefix ? join63(resolvedDir, prefix) : resolvedDir;
40534
+ const claudeDir = prefix ? join66(resolvedDir, prefix) : resolvedDir;
40192
40535
  try {
40193
40536
  const existingMetadata = await readManifest(claudeDir);
40194
40537
  if (existingMetadata?.kits) {
@@ -40220,7 +40563,7 @@ async function handleSelection(ctx) {
40220
40563
  }
40221
40564
  if (ctx.options.fresh) {
40222
40565
  const prefix = PathResolver.getPathPrefix(ctx.options.global);
40223
- const claudeDir = prefix ? join63(resolvedDir, prefix) : resolvedDir;
40566
+ const claudeDir = prefix ? join66(resolvedDir, prefix) : resolvedDir;
40224
40567
  const canProceed = await handleFreshInstallation(claudeDir, ctx.prompts);
40225
40568
  if (!canProceed) {
40226
40569
  return { ...ctx, cancelled: true };
@@ -40238,7 +40581,7 @@ async function handleSelection(ctx) {
40238
40581
  logger.info("Fetching available versions...");
40239
40582
  let currentVersion = null;
40240
40583
  try {
40241
- const metadataPath = ctx.options.global ? join63(PathResolver.getGlobalKitDir(), "metadata.json") : join63(resolvedDir, ".claude", "metadata.json");
40584
+ const metadataPath = ctx.options.global ? join66(PathResolver.getGlobalKitDir(), "metadata.json") : join66(resolvedDir, ".claude", "metadata.json");
40242
40585
  const metadata = await readClaudeKitMetadata(metadataPath);
40243
40586
  currentVersion = metadata?.version || null;
40244
40587
  if (currentVersion) {
@@ -40306,24 +40649,24 @@ async function handleSelection(ctx) {
40306
40649
  };
40307
40650
  }
40308
40651
  // src/commands/init/phases/sync-handler.ts
40309
- import { copyFile as copyFile6, mkdir as mkdir21, open, rename as rename3, stat as stat10, unlink as unlink7, writeFile as writeFile17 } from "node:fs/promises";
40310
- import { dirname as dirname9, join as join64, resolve as resolve8 } from "node:path";
40652
+ import { copyFile as copyFile6, mkdir as mkdir21, open, rename as rename3, stat as stat10, unlink as unlink7, writeFile as writeFile19 } from "node:fs/promises";
40653
+ import { dirname as dirname9, join as join67, resolve as resolve8 } from "node:path";
40311
40654
  init_logger();
40312
- var import_fs_extra30 = __toESM(require_lib(), 1);
40655
+ var import_fs_extra31 = __toESM(require_lib(), 1);
40313
40656
  var import_picocolors19 = __toESM(require_picocolors(), 1);
40314
40657
  async function handleSync(ctx) {
40315
40658
  if (!ctx.options.sync) {
40316
40659
  return ctx;
40317
40660
  }
40318
40661
  const resolvedDir = ctx.options.global ? PathResolver.getGlobalKitDir() : resolve8(ctx.options.dir || ".");
40319
- const claudeDir = ctx.options.global ? resolvedDir : join64(resolvedDir, ".claude");
40320
- if (!await import_fs_extra30.pathExists(claudeDir)) {
40662
+ const claudeDir = ctx.options.global ? resolvedDir : join67(resolvedDir, ".claude");
40663
+ if (!await import_fs_extra31.pathExists(claudeDir)) {
40321
40664
  logger.error("Cannot sync: no .claude directory found");
40322
40665
  ctx.prompts.note("Run 'ck init' without --sync to install first.", "No Installation Found");
40323
40666
  return { ...ctx, cancelled: true };
40324
40667
  }
40325
- const metadataPath = join64(claudeDir, "metadata.json");
40326
- if (!await import_fs_extra30.pathExists(metadataPath)) {
40668
+ const metadataPath = join67(claudeDir, "metadata.json");
40669
+ if (!await import_fs_extra31.pathExists(metadataPath)) {
40327
40670
  logger.error("Cannot sync: no metadata.json found");
40328
40671
  ctx.prompts.note(`Your installation may be from an older version.
40329
40672
  Run 'ck init' to update.`, "Legacy Installation");
@@ -40422,7 +40765,7 @@ function getLockTimeout() {
40422
40765
  var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
40423
40766
  async function acquireSyncLock(global3) {
40424
40767
  const cacheDir = PathResolver.getCacheDir(global3);
40425
- const lockPath = join64(cacheDir, ".sync-lock");
40768
+ const lockPath = join67(cacheDir, ".sync-lock");
40426
40769
  const startTime = Date.now();
40427
40770
  const lockTimeout = getLockTimeout();
40428
40771
  await mkdir21(dirname9(lockPath), { recursive: true });
@@ -40468,7 +40811,7 @@ async function executeSyncMerge(ctx) {
40468
40811
  const releaseLock = await acquireSyncLock(ctx.options.global);
40469
40812
  try {
40470
40813
  const trackedFiles = ctx.syncTrackedFiles;
40471
- const upstreamDir = ctx.options.global ? join64(ctx.extractDir, ".claude") : ctx.extractDir;
40814
+ const upstreamDir = ctx.options.global ? join67(ctx.extractDir, ".claude") : ctx.extractDir;
40472
40815
  logger.info("Analyzing file changes...");
40473
40816
  const plan = await SyncEngine.createSyncPlan(trackedFiles, ctx.claudeDir, upstreamDir);
40474
40817
  displaySyncPlan(plan);
@@ -40487,7 +40830,7 @@ async function executeSyncMerge(ctx) {
40487
40830
  try {
40488
40831
  const sourcePath = await validateSyncPath(upstreamDir, file.path);
40489
40832
  const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
40490
- const targetDir = join64(targetPath, "..");
40833
+ const targetDir = join67(targetPath, "..");
40491
40834
  try {
40492
40835
  await mkdir21(targetDir, { recursive: true });
40493
40836
  } catch (mkdirError) {
@@ -40568,7 +40911,7 @@ async function executeSyncMerge(ctx) {
40568
40911
  try {
40569
40912
  const tempPath = `${currentPath}.tmp.${Date.now()}`;
40570
40913
  try {
40571
- await writeFile17(tempPath, result.result, "utf-8");
40914
+ await writeFile19(tempPath, result.result, "utf-8");
40572
40915
  await rename3(tempPath, currentPath);
40573
40916
  } catch (atomicError) {
40574
40917
  await unlink7(tempPath).catch(() => {});
@@ -40656,9 +40999,9 @@ async function createBackup(claudeDir, files, backupDir) {
40656
40999
  for (const file of files) {
40657
41000
  try {
40658
41001
  const sourcePath = await validateSyncPath(claudeDir, file.path);
40659
- if (await import_fs_extra30.pathExists(sourcePath)) {
41002
+ if (await import_fs_extra31.pathExists(sourcePath)) {
40660
41003
  const targetPath = await validateSyncPath(backupDir, file.path);
40661
- const targetDir = join64(targetPath, "..");
41004
+ const targetDir = join67(targetPath, "..");
40662
41005
  await mkdir21(targetDir, { recursive: true });
40663
41006
  await copyFile6(sourcePath, targetPath);
40664
41007
  }
@@ -40672,7 +41015,7 @@ async function createBackup(claudeDir, files, backupDir) {
40672
41015
  }
40673
41016
  }
40674
41017
  // src/commands/init/phases/transform-handler.ts
40675
- import { join as join68 } from "node:path";
41018
+ import { join as join71 } from "node:path";
40676
41019
 
40677
41020
  // src/services/transformers/folder-path-transformer.ts
40678
41021
  init_logger();
@@ -40681,40 +41024,40 @@ init_types2();
40681
41024
  // src/services/transformers/folder-transform/folder-renamer.ts
40682
41025
  init_logger();
40683
41026
  init_types2();
40684
- var import_fs_extra31 = __toESM(require_lib(), 1);
40685
- import { rename as rename4, rm as rm6 } from "node:fs/promises";
40686
- import { join as join65, relative as relative12 } from "node:path";
41027
+ var import_fs_extra32 = __toESM(require_lib(), 1);
41028
+ import { rename as rename4, rm as rm7 } from "node:fs/promises";
41029
+ import { join as join68, relative as relative12 } from "node:path";
40687
41030
  async function collectDirsToRename(extractDir, folders) {
40688
41031
  const dirsToRename = [];
40689
41032
  if (folders.docs !== DEFAULT_FOLDERS.docs) {
40690
- const docsPath = join65(extractDir, DEFAULT_FOLDERS.docs);
40691
- if (await import_fs_extra31.pathExists(docsPath)) {
41033
+ const docsPath = join68(extractDir, DEFAULT_FOLDERS.docs);
41034
+ if (await import_fs_extra32.pathExists(docsPath)) {
40692
41035
  dirsToRename.push({
40693
41036
  from: docsPath,
40694
- to: join65(extractDir, folders.docs)
41037
+ to: join68(extractDir, folders.docs)
40695
41038
  });
40696
41039
  }
40697
- const claudeDocsPath = join65(extractDir, ".claude", DEFAULT_FOLDERS.docs);
40698
- if (await import_fs_extra31.pathExists(claudeDocsPath)) {
41040
+ const claudeDocsPath = join68(extractDir, ".claude", DEFAULT_FOLDERS.docs);
41041
+ if (await import_fs_extra32.pathExists(claudeDocsPath)) {
40699
41042
  dirsToRename.push({
40700
41043
  from: claudeDocsPath,
40701
- to: join65(extractDir, ".claude", folders.docs)
41044
+ to: join68(extractDir, ".claude", folders.docs)
40702
41045
  });
40703
41046
  }
40704
41047
  }
40705
41048
  if (folders.plans !== DEFAULT_FOLDERS.plans) {
40706
- const plansPath = join65(extractDir, DEFAULT_FOLDERS.plans);
40707
- if (await import_fs_extra31.pathExists(plansPath)) {
41049
+ const plansPath = join68(extractDir, DEFAULT_FOLDERS.plans);
41050
+ if (await import_fs_extra32.pathExists(plansPath)) {
40708
41051
  dirsToRename.push({
40709
41052
  from: plansPath,
40710
- to: join65(extractDir, folders.plans)
41053
+ to: join68(extractDir, folders.plans)
40711
41054
  });
40712
41055
  }
40713
- const claudePlansPath = join65(extractDir, ".claude", DEFAULT_FOLDERS.plans);
40714
- if (await import_fs_extra31.pathExists(claudePlansPath)) {
41056
+ const claudePlansPath = join68(extractDir, ".claude", DEFAULT_FOLDERS.plans);
41057
+ if (await import_fs_extra32.pathExists(claudePlansPath)) {
40715
41058
  dirsToRename.push({
40716
41059
  from: claudePlansPath,
40717
- to: join65(extractDir, ".claude", folders.plans)
41060
+ to: join68(extractDir, ".claude", folders.plans)
40718
41061
  });
40719
41062
  }
40720
41063
  }
@@ -40726,8 +41069,8 @@ async function moveAcrossDevices(src, dest) {
40726
41069
  } catch (e2) {
40727
41070
  if (e2.code === "EXDEV") {
40728
41071
  logger.debug(`Cross-device move detected, using copy+delete: ${src} -> ${dest}`);
40729
- await import_fs_extra31.copy(src, dest, { overwrite: true });
40730
- await rm6(src, { recursive: true, force: true });
41072
+ await import_fs_extra32.copy(src, dest, { overwrite: true });
41073
+ await rm7(src, { recursive: true, force: true });
40731
41074
  } else {
40732
41075
  throw e2;
40733
41076
  }
@@ -40754,8 +41097,8 @@ async function renameFolders(dirsToRename, extractDir, options) {
40754
41097
  // src/services/transformers/folder-transform/path-replacer.ts
40755
41098
  init_logger();
40756
41099
  init_types2();
40757
- import { readFile as readFile21, readdir as readdir20, writeFile as writeFile18 } from "node:fs/promises";
40758
- import { join as join66, relative as relative13 } from "node:path";
41100
+ import { readFile as readFile23, readdir as readdir23, writeFile as writeFile20 } from "node:fs/promises";
41101
+ import { join as join69, relative as relative13 } from "node:path";
40759
41102
  var TRANSFORMABLE_FILE_PATTERNS = [
40760
41103
  ".md",
40761
41104
  ".txt",
@@ -40806,9 +41149,9 @@ function compileReplacements(replacements) {
40806
41149
  async function transformFileContents(dir, compiledReplacements, options) {
40807
41150
  let filesChanged = 0;
40808
41151
  let replacementsCount = 0;
40809
- const entries = await readdir20(dir, { withFileTypes: true });
41152
+ const entries = await readdir23(dir, { withFileTypes: true });
40810
41153
  for (const entry of entries) {
40811
- const fullPath = join66(dir, entry.name);
41154
+ const fullPath = join69(dir, entry.name);
40812
41155
  if (entry.isDirectory()) {
40813
41156
  if (entry.name === "node_modules" || entry.name === ".git") {
40814
41157
  continue;
@@ -40821,7 +41164,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
40821
41164
  if (!shouldTransform)
40822
41165
  continue;
40823
41166
  try {
40824
- const content = await readFile21(fullPath, "utf-8");
41167
+ const content = await readFile23(fullPath, "utf-8");
40825
41168
  let newContent = content;
40826
41169
  let changeCount = 0;
40827
41170
  for (const { regex: regex2, replacement } of compiledReplacements) {
@@ -40837,7 +41180,7 @@ async function transformFileContents(dir, compiledReplacements, options) {
40837
41180
  if (options.dryRun) {
40838
41181
  logger.debug(`[dry-run] Would update ${relative13(dir, fullPath)}: ${changeCount} replacement(s)`);
40839
41182
  } else {
40840
- await writeFile18(fullPath, newContent, "utf-8");
41183
+ await writeFile20(fullPath, newContent, "utf-8");
40841
41184
  logger.debug(`Updated ${relative13(dir, fullPath)}: ${changeCount} replacement(s)`);
40842
41185
  }
40843
41186
  filesChanged++;
@@ -40943,15 +41286,15 @@ async function transformFolderPaths(extractDir, folders, options = {}) {
40943
41286
 
40944
41287
  // src/services/transformers/global-path-transformer.ts
40945
41288
  init_logger();
40946
- import { readFile as readFile22, readdir as readdir21, writeFile as writeFile19 } from "node:fs/promises";
40947
- import { platform as platform11 } from "node:os";
40948
- import { extname as extname2, join as join67 } from "node:path";
40949
- var IS_WINDOWS3 = platform11() === "win32";
40950
- var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
41289
+ import { readFile as readFile24, readdir as readdir24, writeFile as writeFile21 } from "node:fs/promises";
41290
+ import { platform as platform12 } from "node:os";
41291
+ import { extname as extname3, join as join70 } from "node:path";
41292
+ var IS_WINDOWS4 = platform12() === "win32";
41293
+ var HOME_PREFIX = IS_WINDOWS4 ? "%USERPROFILE%" : "$HOME";
40951
41294
  function getHomeDirPrefix() {
40952
41295
  return HOME_PREFIX;
40953
41296
  }
40954
- var TRANSFORMABLE_EXTENSIONS = new Set([
41297
+ var TRANSFORMABLE_EXTENSIONS3 = new Set([
40955
41298
  ".md",
40956
41299
  ".js",
40957
41300
  ".ts",
@@ -40968,7 +41311,7 @@ function transformContent(content) {
40968
41311
  let transformed = content;
40969
41312
  const homePrefix = getHomeDirPrefix();
40970
41313
  const claudePath = `${homePrefix}/.claude/`;
40971
- if (IS_WINDOWS3) {
41314
+ if (IS_WINDOWS4) {
40972
41315
  transformed = transformed.replace(/\$HOME\/\.claude\//g, () => {
40973
41316
  changes++;
40974
41317
  return claudePath;
@@ -40998,7 +41341,7 @@ function transformContent(content) {
40998
41341
  changes++;
40999
41342
  return claudePath;
41000
41343
  });
41001
- if (IS_WINDOWS3) {
41344
+ if (IS_WINDOWS4) {
41002
41345
  transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%\/\.claude\//g, () => {
41003
41346
  changes++;
41004
41347
  return claudePath;
@@ -41042,10 +41385,10 @@ function transformContent(content) {
41042
41385
  });
41043
41386
  return { transformed, changes };
41044
41387
  }
41045
- function shouldTransformFile(filename) {
41046
- const ext2 = extname2(filename).toLowerCase();
41388
+ function shouldTransformFile3(filename) {
41389
+ const ext2 = extname3(filename).toLowerCase();
41047
41390
  const basename3 = filename.split("/").pop() || filename;
41048
- return TRANSFORMABLE_EXTENSIONS.has(ext2) || ALWAYS_TRANSFORM_FILES.has(basename3);
41391
+ return TRANSFORMABLE_EXTENSIONS3.has(ext2) || ALWAYS_TRANSFORM_FILES.has(basename3);
41049
41392
  }
41050
41393
  async function transformPathsForGlobalInstall(directory, options = {}) {
41051
41394
  let filesTransformed = 0;
@@ -41053,20 +41396,20 @@ async function transformPathsForGlobalInstall(directory, options = {}) {
41053
41396
  let filesSkipped = 0;
41054
41397
  const skippedFiles = [];
41055
41398
  async function processDirectory2(dir) {
41056
- const entries = await readdir21(dir, { withFileTypes: true });
41399
+ const entries = await readdir24(dir, { withFileTypes: true });
41057
41400
  for (const entry of entries) {
41058
- const fullPath = join67(dir, entry.name);
41401
+ const fullPath = join70(dir, entry.name);
41059
41402
  if (entry.isDirectory()) {
41060
41403
  if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
41061
41404
  continue;
41062
41405
  }
41063
41406
  await processDirectory2(fullPath);
41064
- } else if (entry.isFile() && shouldTransformFile(entry.name)) {
41407
+ } else if (entry.isFile() && shouldTransformFile3(entry.name)) {
41065
41408
  try {
41066
- const content = await readFile22(fullPath, "utf-8");
41409
+ const content = await readFile24(fullPath, "utf-8");
41067
41410
  const { transformed, changes } = transformContent(content);
41068
41411
  if (changes > 0) {
41069
- await writeFile19(fullPath, transformed, "utf-8");
41412
+ await writeFile21(fullPath, transformed, "utf-8");
41070
41413
  filesTransformed++;
41071
41414
  totalChanges += changes;
41072
41415
  if (options.verbose) {
@@ -41131,7 +41474,7 @@ async function handleTransforms(ctx) {
41131
41474
  logger.debug(ctx.options.global ? "Saved folder configuration to ~/.claude/.ck.json" : "Saved folder configuration to .claude/.ck.json");
41132
41475
  }
41133
41476
  }
41134
- const claudeDir = ctx.options.global ? ctx.resolvedDir : join68(ctx.resolvedDir, ".claude");
41477
+ const claudeDir = ctx.options.global ? ctx.resolvedDir : join71(ctx.resolvedDir, ".claude");
41135
41478
  return {
41136
41479
  ...ctx,
41137
41480
  foldersConfig,
@@ -41169,6 +41512,9 @@ Installing additional kit: ${kit.name}`);
41169
41512
  extractDir: undefined
41170
41513
  };
41171
41514
  ctx = await handleDownload(ctx);
41515
+ if (ctx.cancelled)
41516
+ return ctx;
41517
+ ctx = await handleOpenCode(ctx);
41172
41518
  if (ctx.cancelled)
41173
41519
  return ctx;
41174
41520
  ctx = await handleTransforms(ctx);
@@ -41235,6 +41581,11 @@ async function executeInit(options, prompts) {
41235
41581
  ctx = await handleDownload(ctx);
41236
41582
  if (ctx.cancelled)
41237
41583
  return;
41584
+ if (!isSyncMode) {
41585
+ ctx = await handleOpenCode(ctx);
41586
+ if (ctx.cancelled)
41587
+ return;
41588
+ }
41238
41589
  if (!isSyncMode) {
41239
41590
  ctx = await handleTransforms(ctx);
41240
41591
  if (ctx.cancelled)
@@ -41316,7 +41667,7 @@ var import_picocolors20 = __toESM(require_picocolors(), 1);
41316
41667
  import { resolve as resolve9 } from "node:path";
41317
41668
  init_logger();
41318
41669
  init_types2();
41319
- var import_fs_extra32 = __toESM(require_lib(), 1);
41670
+ var import_fs_extra33 = __toESM(require_lib(), 1);
41320
41671
  async function directorySetup(validOptions, prompts) {
41321
41672
  const isNonInteractive2 = !process.stdin.isTTY || process.env.CI === "true" || process.env.NON_INTERACTIVE === "true";
41322
41673
  const config = await ConfigManager.get();
@@ -41415,8 +41766,8 @@ async function directorySetup(validOptions, prompts) {
41415
41766
  return null;
41416
41767
  }
41417
41768
  }
41418
- if (await import_fs_extra32.pathExists(resolvedDir)) {
41419
- const files = await import_fs_extra32.readdir(resolvedDir);
41769
+ if (await import_fs_extra33.pathExists(resolvedDir)) {
41770
+ const files = await import_fs_extra33.readdir(resolvedDir);
41420
41771
  const isEmpty = files.length === 0;
41421
41772
  if (!isEmpty) {
41422
41773
  if (isNonInteractive2) {
@@ -41452,7 +41803,7 @@ async function handleDirectorySetup(ctx) {
41452
41803
  };
41453
41804
  }
41454
41805
  // src/commands/new/phases/project-creation.ts
41455
- import { join as join69 } from "node:path";
41806
+ import { join as join72 } from "node:path";
41456
41807
  init_logger();
41457
41808
  init_output_manager();
41458
41809
  init_types2();
@@ -41562,7 +41913,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
41562
41913
  output.section("Installing");
41563
41914
  logger.verbose("Installation target", { directory: resolvedDir });
41564
41915
  const merger = new FileMerger;
41565
- const claudeDir = join69(resolvedDir, ".claude");
41916
+ const claudeDir = join72(resolvedDir, ".claude");
41566
41917
  merger.setMultiKitContext(claudeDir, kit);
41567
41918
  if (validOptions.exclude && validOptions.exclude.length > 0) {
41568
41919
  merger.addIgnorePatterns(validOptions.exclude);
@@ -41699,7 +42050,7 @@ init_types2();
41699
42050
  var import_picocolors22 = __toESM(require_picocolors(), 1);
41700
42051
 
41701
42052
  // src/commands/uninstall/installation-detector.ts
41702
- var import_fs_extra33 = __toESM(require_lib(), 1);
42053
+ var import_fs_extra34 = __toESM(require_lib(), 1);
41703
42054
  async function detectInstallations() {
41704
42055
  const installations = [];
41705
42056
  const setup = await getClaudeKitSetup(process.cwd());
@@ -41708,14 +42059,14 @@ async function detectInstallations() {
41708
42059
  installations.push({
41709
42060
  type: "local",
41710
42061
  path: setup.project.path,
41711
- exists: await import_fs_extra33.pathExists(setup.project.path)
42062
+ exists: await import_fs_extra34.pathExists(setup.project.path)
41712
42063
  });
41713
42064
  }
41714
42065
  if (setup.global.path && setup.global.metadata) {
41715
42066
  installations.push({
41716
42067
  type: "global",
41717
42068
  path: setup.global.path,
41718
- exists: await import_fs_extra33.pathExists(setup.global.path)
42069
+ exists: await import_fs_extra34.pathExists(setup.global.path)
41719
42070
  });
41720
42071
  }
41721
42072
  return installations.filter((i) => i.exists);
@@ -41723,13 +42074,13 @@ async function detectInstallations() {
41723
42074
 
41724
42075
  // src/commands/uninstall/removal-handler.ts
41725
42076
  import { readdirSync as readdirSync2, rmSync as rmSync2 } from "node:fs";
41726
- import { join as join71 } from "node:path";
42077
+ import { join as join74 } from "node:path";
41727
42078
  init_logger();
41728
- var import_fs_extra34 = __toESM(require_lib(), 1);
42079
+ var import_fs_extra35 = __toESM(require_lib(), 1);
41729
42080
 
41730
42081
  // src/commands/uninstall/analysis-handler.ts
41731
42082
  import { readdirSync, rmSync } from "node:fs";
41732
- import { dirname as dirname10, join as join70 } from "node:path";
42083
+ import { dirname as dirname10, join as join73 } from "node:path";
41733
42084
  init_logger();
41734
42085
  var import_picocolors21 = __toESM(require_picocolors(), 1);
41735
42086
  function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
@@ -41776,7 +42127,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
41776
42127
  if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
41777
42128
  const kitFiles = metadata.kits[kit].files || [];
41778
42129
  for (const trackedFile of kitFiles) {
41779
- const filePath = join70(installation.path, trackedFile.path);
42130
+ const filePath = join73(installation.path, trackedFile.path);
41780
42131
  if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
41781
42132
  result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
41782
42133
  continue;
@@ -41806,7 +42157,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
41806
42157
  return result;
41807
42158
  }
41808
42159
  for (const trackedFile of allTrackedFiles) {
41809
- const filePath = join70(installation.path, trackedFile.path);
42160
+ const filePath = join73(installation.path, trackedFile.path);
41810
42161
  const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
41811
42162
  if (!ownershipResult.exists)
41812
42163
  continue;
@@ -41866,9 +42217,9 @@ async function removeInstallations(installations, options) {
41866
42217
  let removedCount = 0;
41867
42218
  let cleanedDirs = 0;
41868
42219
  for (const item of analysis.toDelete) {
41869
- const filePath = join71(installation.path, item.path);
41870
- if (await import_fs_extra34.pathExists(filePath)) {
41871
- await import_fs_extra34.remove(filePath);
42220
+ const filePath = join74(installation.path, item.path);
42221
+ if (await import_fs_extra35.pathExists(filePath)) {
42222
+ await import_fs_extra35.remove(filePath);
41872
42223
  removedCount++;
41873
42224
  logger.debug(`Removed: ${item.path}`);
41874
42225
  cleanedDirs += await cleanupEmptyDirectories(filePath, installation.path);
@@ -42037,6 +42388,7 @@ ${import_picocolors22.default.yellow("User modifications will be permanently del
42037
42388
  }
42038
42389
  // src/commands/update-cli.ts
42039
42390
  import { exec as exec7 } from "node:child_process";
42391
+ import { join as join76 } from "node:path";
42040
42392
  import { promisify as promisify7 } from "node:util";
42041
42393
 
42042
42394
  // src/domains/github/npm-registry.ts
@@ -42198,14 +42550,14 @@ init_types2();
42198
42550
  // src/domains/versioning/version-cache.ts
42199
42551
  init_logger();
42200
42552
  import { existsSync as existsSync19 } from "node:fs";
42201
- import { mkdir as mkdir22, readFile as readFile23, writeFile as writeFile20 } from "node:fs/promises";
42202
- import { join as join72 } from "node:path";
42553
+ import { mkdir as mkdir22, readFile as readFile25, writeFile as writeFile22 } from "node:fs/promises";
42554
+ import { join as join75 } from "node:path";
42203
42555
  class VersionCacheManager {
42204
42556
  static CACHE_FILENAME = "version-check.json";
42205
42557
  static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
42206
42558
  static getCacheFile() {
42207
42559
  const cacheDir = PathResolver.getCacheDir(false);
42208
- return join72(cacheDir, VersionCacheManager.CACHE_FILENAME);
42560
+ return join75(cacheDir, VersionCacheManager.CACHE_FILENAME);
42209
42561
  }
42210
42562
  static async load() {
42211
42563
  const cacheFile = VersionCacheManager.getCacheFile();
@@ -42214,7 +42566,7 @@ class VersionCacheManager {
42214
42566
  logger.debug("Version check cache not found");
42215
42567
  return null;
42216
42568
  }
42217
- const content = await readFile23(cacheFile, "utf-8");
42569
+ const content = await readFile25(cacheFile, "utf-8");
42218
42570
  const cache2 = JSON.parse(content);
42219
42571
  if (!cache2.lastCheck || !cache2.currentVersion || !cache2.latestVersion) {
42220
42572
  logger.debug("Invalid cache structure, ignoring");
@@ -42234,7 +42586,7 @@ class VersionCacheManager {
42234
42586
  if (!existsSync19(cacheDir)) {
42235
42587
  await mkdir22(cacheDir, { recursive: true, mode: 448 });
42236
42588
  }
42237
- await writeFile20(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
42589
+ await writeFile22(cacheFile, JSON.stringify(cache2, null, 2), "utf-8");
42238
42590
  logger.debug(`Version check cache saved to ${cacheFile}`);
42239
42591
  } catch (error) {
42240
42592
  logger.debug(`Failed to save version check cache: ${error}`);
@@ -42443,11 +42795,12 @@ init_logger();
42443
42795
  init_types2();
42444
42796
  init_types2();
42445
42797
  var import_compare_versions5 = __toESM(require_umd(), 1);
42798
+ var import_fs_extra36 = __toESM(require_lib(), 1);
42446
42799
  var import_picocolors24 = __toESM(require_picocolors(), 1);
42447
42800
  // package.json
42448
42801
  var package_default = {
42449
42802
  name: "claudekit-cli",
42450
- version: "3.22.1",
42803
+ version: "3.24.0",
42451
42804
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
42452
42805
  type: "module",
42453
42806
  repository: {
@@ -42548,18 +42901,51 @@ class CliUpdateError extends ClaudeKitError {
42548
42901
  }
42549
42902
  var PACKAGE_NAME2 = "claudekit-cli";
42550
42903
  var KIT_UPDATE_REMINDER_HEADER = "Note: 'ck update' only updates the CLI tool itself.";
42904
+ function buildInitCommand(isGlobal, kit) {
42905
+ const parts = ["ck init"];
42906
+ if (isGlobal)
42907
+ parts.push("-g");
42908
+ if (kit)
42909
+ parts.push(`--kit ${kit}`);
42910
+ parts.push("--yes --install-skills");
42911
+ return parts.join(" ");
42912
+ }
42913
+ async function readMetadataFile(claudeDir) {
42914
+ const metadataPath = join76(claudeDir, "metadata.json");
42915
+ try {
42916
+ if (!await import_fs_extra36.pathExists(metadataPath)) {
42917
+ return null;
42918
+ }
42919
+ const content = await import_fs_extra36.readFile(metadataPath, "utf-8");
42920
+ return JSON.parse(content);
42921
+ } catch {
42922
+ return null;
42923
+ }
42924
+ }
42551
42925
  async function displayKitUpdateReminder() {
42552
42926
  try {
42553
42927
  const setup = await getClaudeKitSetup();
42554
42928
  const hasLocal = !!setup.project.metadata;
42555
42929
  const hasGlobal = !!setup.global.metadata;
42556
- const localVersion = setup.project.metadata?.version;
42557
- const globalVersion = setup.global.metadata?.version;
42930
+ const localMetadata = hasLocal ? await readMetadataFile(setup.project.path) : null;
42931
+ const globalMetadata = hasGlobal ? await readMetadataFile(setup.global.path) : null;
42932
+ const localKits = localMetadata ? getInstalledKits(localMetadata) : [];
42933
+ const globalKits = globalMetadata ? getInstalledKits(globalMetadata) : [];
42558
42934
  const versionsToCheck = new Set;
42559
- if (localVersion)
42560
- versionsToCheck.add(localVersion);
42561
- if (globalVersion)
42562
- versionsToCheck.add(globalVersion);
42935
+ if (localMetadata) {
42936
+ for (const kit of localKits) {
42937
+ const version = localMetadata.kits?.[kit]?.version || localMetadata.version;
42938
+ if (version)
42939
+ versionsToCheck.add(version);
42940
+ }
42941
+ }
42942
+ if (globalMetadata) {
42943
+ for (const kit of globalKits) {
42944
+ const version = globalMetadata.kits?.[kit]?.version || globalMetadata.version;
42945
+ if (version)
42946
+ versionsToCheck.add(version);
42947
+ }
42948
+ }
42563
42949
  const versionCheckResults = new Map;
42564
42950
  if (versionsToCheck.size > 0) {
42565
42951
  const checkPromises = [...versionsToCheck].map(async (version) => {
@@ -42571,33 +42957,52 @@ async function displayKitUpdateReminder() {
42571
42957
  versionCheckResults.set(version, result);
42572
42958
  }
42573
42959
  }
42574
- const cmdLocal = "ck init";
42575
- const cmdGlobal = "ck init -g";
42576
- const maxCmdLen = Math.max(cmdLocal.length, cmdGlobal.length);
42960
+ const commands = [];
42961
+ if (localKits.length > 0) {
42962
+ for (const kit of localKits) {
42963
+ const cmd = buildInitCommand(false, kit);
42964
+ const version = localMetadata?.kits?.[kit]?.version || localMetadata?.version;
42965
+ commands.push({
42966
+ cmd,
42967
+ desc: `Update local project (${kit}${version ? `@${version}` : ""})`,
42968
+ version
42969
+ });
42970
+ }
42971
+ } else if (hasLocal) {
42972
+ commands.push({ cmd: "ck init", desc: "Update local project" });
42973
+ } else {
42974
+ commands.push({ cmd: "ck init", desc: "Initialize in current project" });
42975
+ }
42976
+ if (globalKits.length > 0) {
42977
+ for (const kit of globalKits) {
42978
+ const cmd = buildInitCommand(true, kit);
42979
+ const version = globalMetadata?.kits?.[kit]?.version || globalMetadata?.version;
42980
+ commands.push({
42981
+ cmd,
42982
+ desc: `Update global ~/.claude (${kit}${version ? `@${version}` : ""})`,
42983
+ version
42984
+ });
42985
+ }
42986
+ } else if (hasGlobal) {
42987
+ commands.push({ cmd: "ck init -g", desc: "Update global ~/.claude" });
42988
+ } else {
42989
+ commands.push({ cmd: "ck init -g", desc: "Initialize global ~/.claude" });
42990
+ }
42991
+ const maxCmdLen = Math.max(...commands.map((c2) => c2.cmd.length));
42577
42992
  const pad = (cmd) => cmd.padEnd(maxCmdLen);
42578
42993
  const lines = [];
42579
42994
  lines.push(import_picocolors24.default.yellow(KIT_UPDATE_REMINDER_HEADER));
42580
42995
  lines.push("");
42581
42996
  lines.push("To update your ClaudeKit content (skills, commands, workflows):");
42582
- if (hasLocal && localVersion) {
42583
- lines.push(` ${import_picocolors24.default.cyan(pad(cmdLocal))} Update local project (${localVersion})`);
42584
- const localCheck = versionCheckResults.get(localVersion);
42585
- if (localCheck?.updateAvailable) {
42586
- const indent = " ".repeat(maxCmdLen + 4);
42587
- lines.push(`${indent}${import_picocolors24.default.green(`→ ${localCheck.latestVersion} available!`)}`);
42588
- }
42589
- } else {
42590
- lines.push(` ${import_picocolors24.default.cyan(pad(cmdLocal))} Initialize in current project`);
42591
- }
42592
- if (hasGlobal && globalVersion) {
42593
- lines.push(` ${import_picocolors24.default.cyan(pad(cmdGlobal))} Update global ~/.claude (${globalVersion})`);
42594
- const globalCheck = versionCheckResults.get(globalVersion);
42595
- if (globalCheck?.updateAvailable) {
42596
- const indent = " ".repeat(maxCmdLen + 4);
42597
- lines.push(`${indent}${import_picocolors24.default.green(`→ ${globalCheck.latestVersion} available!`)}`);
42997
+ for (const { cmd, desc: desc2, version } of commands) {
42998
+ lines.push(` ${import_picocolors24.default.cyan(pad(cmd))} ${desc2}`);
42999
+ if (version) {
43000
+ const versionCheck = versionCheckResults.get(version);
43001
+ if (versionCheck?.updateAvailable) {
43002
+ const indent = " ".repeat(maxCmdLen + 4);
43003
+ lines.push(`${indent}${import_picocolors24.default.green(`→ ${versionCheck.latestVersion} available!`)}`);
43004
+ }
42598
43005
  }
42599
- } else {
42600
- lines.push(` ${import_picocolors24.default.cyan(pad(cmdGlobal))} Initialize global ~/.claude`);
42601
43006
  }
42602
43007
  logger.info("");
42603
43008
  log.info(lines.join(`
@@ -42872,7 +43277,7 @@ function registerCommands(cli) {
42872
43277
 
42873
43278
  // src/cli/version-display.ts
42874
43279
  import { existsSync as existsSync20, readFileSync as readFileSync6 } from "node:fs";
42875
- import { join as join73 } from "node:path";
43280
+ import { join as join77 } from "node:path";
42876
43281
  init_logger();
42877
43282
  init_types2();
42878
43283
  var packageVersion = package_default.version;
@@ -42906,9 +43311,9 @@ async function displayVersion() {
42906
43311
  let localKitVersion = null;
42907
43312
  let isGlobalOnlyKit = false;
42908
43313
  const globalKitDir = PathResolver.getGlobalKitDir();
42909
- const globalMetadataPath = join73(globalKitDir, "metadata.json");
43314
+ const globalMetadataPath = join77(globalKitDir, "metadata.json");
42910
43315
  const prefix = PathResolver.getPathPrefix(false);
42911
- const localMetadataPath = prefix ? join73(process.cwd(), prefix, "metadata.json") : join73(process.cwd(), "metadata.json");
43316
+ const localMetadataPath = prefix ? join77(process.cwd(), prefix, "metadata.json") : join77(process.cwd(), "metadata.json");
42912
43317
  const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
42913
43318
  if (!isLocalSameAsGlobal && existsSync20(localMetadataPath)) {
42914
43319
  try {