claudekit-cli 3.37.0-dev.3 → 3.37.0-dev.4

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 +184 -34
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -49851,17 +49851,22 @@ var init_config_discovery = __esm(() => {
49851
49851
  // src/commands/portable/hooks-settings-merger.ts
49852
49852
  import { existsSync as existsSync22, mkdirSync, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
49853
49853
  import { basename as basename8, dirname as dirname9, join as join32 } from "node:path";
49854
- async function readHooksFromSettings(settingsPath) {
49854
+ async function inspectHooksSettings(settingsPath) {
49855
49855
  try {
49856
- if (!existsSync22(settingsPath))
49857
- return null;
49856
+ if (!existsSync22(settingsPath)) {
49857
+ return { status: "missing-file" };
49858
+ }
49858
49859
  const raw = await Bun.file(settingsPath).text();
49859
49860
  const parsed = JSON.parse(raw);
49860
- if (!parsed.hooks || typeof parsed.hooks !== "object")
49861
- return null;
49862
- return parsed.hooks;
49863
- } catch {
49864
- return null;
49861
+ if (!parsed.hooks || typeof parsed.hooks !== "object") {
49862
+ return { status: "missing-hooks" };
49863
+ }
49864
+ return { status: "ok", hooks: parsed.hooks };
49865
+ } catch (error) {
49866
+ return {
49867
+ status: "invalid-json",
49868
+ error: error instanceof Error ? error.message : String(error)
49869
+ };
49865
49870
  }
49866
49871
  }
49867
49872
  function rewriteHookPaths(hooks, sourceHooksDir, targetHooksDir) {
@@ -49980,33 +49985,99 @@ function deduplicateMerge(existing, incoming) {
49980
49985
  async function migrateHooksSettings(options2) {
49981
49986
  const { sourceProvider, targetProvider, installedHookFiles, global: isGlobal } = options2;
49982
49987
  if (installedHookFiles.length === 0) {
49983
- return { success: true, backupPath: null, hooksRegistered: 0 };
49988
+ return {
49989
+ status: "no-installed-files",
49990
+ success: true,
49991
+ backupPath: null,
49992
+ hooksRegistered: 0,
49993
+ sourceSettingsPath: null,
49994
+ targetSettingsPath: null
49995
+ };
49984
49996
  }
49985
49997
  const sourceConfig = providers[sourceProvider];
49986
49998
  const targetConfig = providers[targetProvider];
49987
49999
  if (!sourceConfig.settingsJsonPath) {
49988
50000
  return {
50001
+ status: "unsupported-source",
49989
50002
  success: true,
49990
50003
  backupPath: null,
49991
50004
  hooksRegistered: 0,
49992
- message: `Hook settings migration from ${sourceProvider} not supported (no hooks configuration)`
50005
+ message: `Hook settings migration from ${sourceProvider} not supported (no hooks configuration)`,
50006
+ sourceSettingsPath: null,
50007
+ targetSettingsPath: null
49993
50008
  };
49994
50009
  }
49995
50010
  const sourceSettingsPath = isGlobal ? sourceConfig.settingsJsonPath?.globalPath : sourceConfig.settingsJsonPath?.projectPath;
49996
50011
  const targetSettingsPath = isGlobal ? targetConfig.settingsJsonPath?.globalPath : targetConfig.settingsJsonPath?.projectPath;
49997
- if (!sourceSettingsPath || !targetSettingsPath) {
50012
+ if (!sourceSettingsPath) {
49998
50013
  return {
50014
+ status: "unsupported-source",
50015
+ success: true,
50016
+ backupPath: null,
50017
+ hooksRegistered: 0,
50018
+ message: `Hook settings migration from ${sourceProvider} not supported for ${isGlobal ? "global" : "project"} scope`,
50019
+ sourceSettingsPath: null,
50020
+ targetSettingsPath: targetSettingsPath ?? null
50021
+ };
50022
+ }
50023
+ if (!targetSettingsPath) {
50024
+ return {
50025
+ status: "unsupported-target",
49999
50026
  success: false,
50000
50027
  backupPath: null,
50001
50028
  hooksRegistered: 0,
50002
- error: `Provider ${!sourceSettingsPath ? sourceProvider : targetProvider} does not support hooks settings.json`
50029
+ error: `Provider ${targetProvider} does not support hook registration for ${isGlobal ? "global" : "project"} scope`,
50030
+ sourceSettingsPath,
50031
+ targetSettingsPath: null
50003
50032
  };
50004
50033
  }
50005
50034
  const resolvedSourcePath = isGlobal ? sourceSettingsPath : join32(process.cwd(), sourceSettingsPath);
50006
50035
  const resolvedTargetPath = isGlobal ? targetSettingsPath : join32(process.cwd(), targetSettingsPath);
50007
- const sourceHooks = await readHooksFromSettings(resolvedSourcePath);
50036
+ const sourceHooksResult = await inspectHooksSettings(resolvedSourcePath);
50037
+ if (sourceHooksResult.status === "missing-file") {
50038
+ return {
50039
+ status: "source-settings-missing",
50040
+ success: true,
50041
+ backupPath: null,
50042
+ hooksRegistered: 0,
50043
+ message: `Hook files were copied, but source hook registrations were not found at ${resolvedSourcePath}; ${resolvedTargetPath} was not updated.`,
50044
+ sourceSettingsPath: resolvedSourcePath,
50045
+ targetSettingsPath: resolvedTargetPath
50046
+ };
50047
+ }
50048
+ if (sourceHooksResult.status === "missing-hooks") {
50049
+ return {
50050
+ status: "source-hooks-missing",
50051
+ success: true,
50052
+ backupPath: null,
50053
+ hooksRegistered: 0,
50054
+ message: `Hook files were copied, but ${resolvedSourcePath} does not define a hooks section; ${resolvedTargetPath} was not updated.`,
50055
+ sourceSettingsPath: resolvedSourcePath,
50056
+ targetSettingsPath: resolvedTargetPath
50057
+ };
50058
+ }
50059
+ if (sourceHooksResult.status === "invalid-json") {
50060
+ return {
50061
+ status: "source-settings-invalid",
50062
+ success: false,
50063
+ backupPath: null,
50064
+ hooksRegistered: 0,
50065
+ error: `Hook files were copied, but source hook registrations could not be read from ${resolvedSourcePath}: ${sourceHooksResult.error || "invalid JSON"}. ${resolvedTargetPath} was not updated.`,
50066
+ sourceSettingsPath: resolvedSourcePath,
50067
+ targetSettingsPath: resolvedTargetPath
50068
+ };
50069
+ }
50070
+ const sourceHooks = sourceHooksResult.hooks;
50008
50071
  if (!sourceHooks) {
50009
- return { success: true, backupPath: null, hooksRegistered: 0 };
50072
+ return {
50073
+ status: "source-settings-invalid",
50074
+ success: false,
50075
+ backupPath: null,
50076
+ hooksRegistered: 0,
50077
+ error: `Hook files were copied, but source hook registrations could not be read from ${resolvedSourcePath}. ${resolvedTargetPath} was not updated.`,
50078
+ sourceSettingsPath: resolvedSourcePath,
50079
+ targetSettingsPath: resolvedTargetPath
50080
+ };
50010
50081
  }
50011
50082
  const sourceHooksDir = isGlobal ? sourceConfig.hooks?.globalPath ?? "" : sourceConfig.hooks?.projectPath ?? "";
50012
50083
  const targetHooksDir = isGlobal ? targetConfig.hooks?.globalPath ?? "" : targetConfig.hooks?.projectPath ?? "";
@@ -50019,17 +50090,35 @@ async function migrateHooksSettings(options2) {
50019
50090
  }
50020
50091
  }
50021
50092
  if (hooksRegistered === 0) {
50022
- return { success: true, backupPath: null, hooksRegistered: 0 };
50093
+ return {
50094
+ status: "no-matching-hooks",
50095
+ success: true,
50096
+ backupPath: null,
50097
+ hooksRegistered: 0,
50098
+ message: `Hook files were copied, but none of the installed hooks matched registrations from ${resolvedSourcePath}; ${resolvedTargetPath} was not updated.`,
50099
+ sourceSettingsPath: resolvedSourcePath,
50100
+ targetSettingsPath: resolvedTargetPath
50101
+ };
50023
50102
  }
50024
50103
  try {
50025
50104
  const { backupPath } = await mergeHooksIntoSettings(resolvedTargetPath, rewritten);
50026
- return { success: true, backupPath, hooksRegistered };
50105
+ return {
50106
+ status: "registered",
50107
+ success: true,
50108
+ backupPath,
50109
+ hooksRegistered,
50110
+ sourceSettingsPath: resolvedSourcePath,
50111
+ targetSettingsPath: resolvedTargetPath
50112
+ };
50027
50113
  } catch (err) {
50028
50114
  return {
50115
+ status: "merge-failed",
50029
50116
  success: false,
50030
50117
  backupPath: null,
50031
50118
  hooksRegistered: 0,
50032
- error: `Failed to merge hooks into settings.json: ${err instanceof Error ? err.message : String(err)}`
50119
+ error: `Failed to merge hook registrations into ${resolvedTargetPath}: ${err instanceof Error ? err.message : String(err)}`,
50120
+ sourceSettingsPath: resolvedSourcePath,
50121
+ targetSettingsPath: resolvedTargetPath
50033
50122
  };
50034
50123
  }
50035
50124
  }
@@ -52977,6 +53066,46 @@ function tagResults(results, portableType, itemName) {
52977
53066
  }
52978
53067
  }
52979
53068
  }
53069
+ function isHookRegistrationFailure(status) {
53070
+ return status === "source-settings-invalid" || status === "unsupported-target" || status === "merge-failed";
53071
+ }
53072
+ function createHookRegistrationFeedbackResult(provider, mergeResult) {
53073
+ if (mergeResult.status === "registered" || mergeResult.status === "no-installed-files") {
53074
+ return null;
53075
+ }
53076
+ const message = mergeResult.error || mergeResult.message;
53077
+ if (!message)
53078
+ return null;
53079
+ const failed = isHookRegistrationFailure(mergeResult.status);
53080
+ return {
53081
+ provider,
53082
+ providerDisplayName: providers[provider]?.displayName || provider,
53083
+ success: !failed,
53084
+ skipped: !failed,
53085
+ path: mergeResult.targetSettingsPath ?? "",
53086
+ error: failed ? message : undefined,
53087
+ skipReason: failed ? undefined : message,
53088
+ portableType: "hooks",
53089
+ itemName: "hook registration"
53090
+ };
53091
+ }
53092
+ function recordHookRegistrationOutcome(provider, mergeResult, warnings, feedbackResults) {
53093
+ if (mergeResult.success && mergeResult.hooksRegistered > 0) {
53094
+ console.info(`[migrate] Registered ${mergeResult.hooksRegistered} hook(s) in ${provider} settings.json`);
53095
+ return;
53096
+ }
53097
+ const message = mergeResult.error || mergeResult.message;
53098
+ if (message && !warnings.includes(message)) {
53099
+ warnings.push(message);
53100
+ }
53101
+ if (message) {
53102
+ console.warn(`[migrate] ${message}`);
53103
+ }
53104
+ const feedback = createHookRegistrationFeedbackResult(provider, mergeResult);
53105
+ if (feedback) {
53106
+ feedbackResults.push(feedback);
53107
+ }
53108
+ }
52980
53109
  async function discoverMigrationItems(include, configSource) {
52981
53110
  const agentsSource = include.agents ? getAgentSourcePath() : null;
52982
53111
  const commandsSource = include.commands ? getCommandSourcePath() : null;
@@ -53356,7 +53485,9 @@ function registerMigrationRoutes(app) {
53356
53485
  const ruleByName = new Map(discovered2.ruleItems.map((item) => [item.name, item]));
53357
53486
  const hookByName = new Map(discovered2.hookItems.map((item) => [item.name, item]));
53358
53487
  const allResults = [];
53359
- const successfulHookFiles = new Map;
53488
+ const warnings2 = [];
53489
+ const hookRegistrationResults2 = [];
53490
+ const successfulHookFiles2 = new Map;
53360
53491
  for (const action of execActions) {
53361
53492
  const provider = action.provider;
53362
53493
  const installOpts = { global: action.global };
@@ -53420,16 +53551,16 @@ function registerMigrationRoutes(app) {
53420
53551
  tagResults(batch, "hooks", action.item);
53421
53552
  allResults.push(...batch);
53422
53553
  for (const r2 of batch.filter((r3) => r3.success && !r3.skipped)) {
53423
- const entry = successfulHookFiles.get(provider) ?? {
53554
+ const entry = successfulHookFiles2.get(provider) ?? {
53424
53555
  files: [],
53425
53556
  global: action.global
53426
53557
  };
53427
53558
  entry.files.push(basename9(r2.path));
53428
- successfulHookFiles.set(provider, entry);
53559
+ successfulHookFiles2.set(provider, entry);
53429
53560
  }
53430
53561
  }
53431
53562
  }
53432
- for (const [hooksProvider, entry] of successfulHookFiles) {
53563
+ for (const [hooksProvider, entry] of successfulHookFiles2) {
53433
53564
  if (entry.files.length === 0)
53434
53565
  continue;
53435
53566
  const mergeResult = await migrateHooksSettings({
@@ -53438,11 +53569,7 @@ function registerMigrationRoutes(app) {
53438
53569
  installedHookFiles: entry.files,
53439
53570
  global: entry.global
53440
53571
  });
53441
- if (mergeResult.success && mergeResult.hooksRegistered > 0) {
53442
- console.info(`[migrate] Registered ${mergeResult.hooksRegistered} hook(s) in ${hooksProvider} settings.json`);
53443
- } else if (!mergeResult.success) {
53444
- console.warn(`[migrate] Failed to register hooks in ${hooksProvider} settings.json: ${mergeResult.error}`);
53445
- }
53572
+ recordHookRegistrationOutcome(hooksProvider, mergeResult, warnings2, hookRegistrationResults2);
53446
53573
  }
53447
53574
  const allPlanProviders = getProvidersFromPlan(plan);
53448
53575
  const plannedSkillActions = execActions.filter((a3) => a3.type === "skill").length;
@@ -53499,7 +53626,8 @@ function registerMigrationRoutes(app) {
53499
53626
  await updateAppliedManifestVersion(manifest.cliVersion);
53500
53627
  }
53501
53628
  } catch {}
53502
- const sortedResults2 = sortPortableInstallResults(allResults);
53629
+ const responseResults2 = [...allResults, ...hookRegistrationResults2];
53630
+ const sortedResults2 = sortPortableInstallResults(responseResults2);
53503
53631
  const counts2 = toExecutionCounts(sortedResults2);
53504
53632
  const planScopes = [
53505
53633
  ...new Set(plan.actions.map((a3) => a3.global).filter((s) => s !== undefined))
@@ -53508,9 +53636,9 @@ function registerMigrationRoutes(app) {
53508
53636
  annotateResultsWithCollisions(sortedResults2, providerCollisions2);
53509
53637
  res.status(200).json({
53510
53638
  results: sortedResults2,
53511
- warnings: [],
53639
+ warnings: warnings2,
53512
53640
  counts: counts2,
53513
- discovery: toDiscoveryCounts(sortedResults2),
53641
+ discovery: toDiscoveryCounts(allResults),
53514
53642
  providerCollisions: providerCollisions2
53515
53643
  });
53516
53644
  return;
@@ -53568,6 +53696,8 @@ function registerMigrationRoutes(app) {
53568
53696
  }
53569
53697
  const installOptions = { global: effectiveGlobal };
53570
53698
  const results = [];
53699
+ const hookRegistrationResults = [];
53700
+ const successfulHookFiles = new Map;
53571
53701
  const unsupportedByType = {
53572
53702
  agents: include.agents ? selectedProviders.filter((provider) => !getProvidersSupporting("agents").includes(provider)) : [],
53573
53703
  commands: include.commands ? selectedProviders.filter((provider) => !getProvidersSupporting("commands").includes(provider)) : [],
@@ -53642,6 +53772,11 @@ function registerMigrationRoutes(app) {
53642
53772
  const batches = await Promise.all(discovered.hookItems.map(async (hook) => {
53643
53773
  const batch = await installPortableItems([hook], providersForType, "hooks", installOptions);
53644
53774
  tagResults(batch, "hooks", hook.name);
53775
+ for (const result of batch.filter((entry) => entry.success && !entry.skipped)) {
53776
+ const existing = successfulHookFiles.get(result.provider) ?? [];
53777
+ existing.push(basename9(result.path));
53778
+ successfulHookFiles.set(result.provider, existing);
53779
+ }
53645
53780
  return batch;
53646
53781
  }));
53647
53782
  for (const batch of batches) {
@@ -53649,7 +53784,19 @@ function registerMigrationRoutes(app) {
53649
53784
  }
53650
53785
  }
53651
53786
  }
53652
- const sortedResults = sortPortableInstallResults(results);
53787
+ for (const [provider, files] of successfulHookFiles) {
53788
+ if (files.length === 0)
53789
+ continue;
53790
+ const mergeResult = await migrateHooksSettings({
53791
+ sourceProvider: "claude-code",
53792
+ targetProvider: provider,
53793
+ installedHookFiles: files,
53794
+ global: effectiveGlobal
53795
+ });
53796
+ recordHookRegistrationOutcome(provider, mergeResult, warnings, hookRegistrationResults);
53797
+ }
53798
+ const responseResults = [...results, ...hookRegistrationResults];
53799
+ const sortedResults = sortPortableInstallResults(responseResults);
53653
53800
  const counts = toExecutionCounts(sortedResults);
53654
53801
  const providerCollisions = detectProviderPathCollisions(selectedProviders, installOptions);
53655
53802
  annotateResultsWithCollisions(sortedResults, providerCollisions);
@@ -53658,7 +53805,7 @@ function registerMigrationRoutes(app) {
53658
53805
  warnings,
53659
53806
  effectiveGlobal,
53660
53807
  counts,
53661
- discovery: toDiscoveryCounts(sortedResults),
53808
+ discovery: toDiscoveryCounts(results),
53662
53809
  unsupportedByType,
53663
53810
  providerCollisions
53664
53811
  });
@@ -56844,7 +56991,7 @@ var package_default;
56844
56991
  var init_package = __esm(() => {
56845
56992
  package_default = {
56846
56993
  name: "claudekit-cli",
56847
- version: "3.37.0-dev.3",
56994
+ version: "3.37.0-dev.4",
56848
56995
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
56849
56996
  type: "module",
56850
56997
  repository: {
@@ -98382,8 +98529,11 @@ async function migrateCommand(options2) {
98382
98529
  });
98383
98530
  if (mergeResult.success && mergeResult.hooksRegistered > 0) {
98384
98531
  logger.verbose(`Registered ${mergeResult.hooksRegistered} hook(s) in ${hooksProvider} settings.json`);
98385
- } else if (!mergeResult.success) {
98386
- f2.warn(`Failed to register hooks in ${hooksProvider} settings.json: ${mergeResult.error}`);
98532
+ } else {
98533
+ const feedbackMessage = mergeResult.error ?? mergeResult.message;
98534
+ if (feedbackMessage) {
98535
+ f2.warn(feedbackMessage);
98536
+ }
98387
98537
  }
98388
98538
  }
98389
98539
  const plannedSkillActions = plannedExecActions.filter((action) => action.type === "skill").length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.37.0-dev.3",
3
+ "version": "3.37.0-dev.4",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {