claudekit-cli 3.42.2-dev.4 → 3.42.2-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "3.42.2-dev.4",
3
- "generatedAt": "2026-04-29T21:26:47.128Z",
2
+ "version": "3.42.2-dev.5",
3
+ "generatedAt": "2026-04-30T19:53:41.311Z",
4
4
  "commands": {
5
5
  "agents": {
6
6
  "name": "agents",
package/dist/index.js CHANGED
@@ -7054,7 +7054,7 @@ function convertFmToCodexToml(item) {
7054
7054
  if (modelResult.resolved) {
7055
7055
  lines.push(`model = ${JSON.stringify(modelResult.resolved.model)}`);
7056
7056
  if (modelResult.resolved.effort) {
7057
- lines.push(`# effort = ${JSON.stringify(modelResult.resolved.effort)}`);
7057
+ lines.push(`model_reasoning_effort = ${JSON.stringify(modelResult.resolved.effort)}`);
7058
7058
  }
7059
7059
  } else if (typeof item.frontmatter.model === "string" && item.frontmatter.model.trim().length > 0 && item.frontmatter.model.trim() !== "inherit") {
7060
7060
  lines.push(`# model = ${JSON.stringify(item.frontmatter.model.trim())}`);
@@ -12460,6 +12460,9 @@ function getReasonCopy(code, _ctx) {
12460
12460
  return "Target state unavailable while CK changed — manual review required";
12461
12461
  }
12462
12462
  }
12463
+ function providerConfigAppliesToType(config, type) {
12464
+ return config.types === undefined || config.types.includes(type);
12465
+ }
12463
12466
  var UNKNOWN_CHECKSUM = "unknown";
12464
12467
 
12465
12468
  // src/commands/portable/portable-registry.ts
@@ -51084,6 +51087,74 @@ var init_commands_discovery = __esm(() => {
51084
51087
  SKIP_DIRS2 = ["node_modules", ".git", "dist", "build"];
51085
51088
  });
51086
51089
 
51090
+ // src/commands/migrate/migrate-provider-scopes.ts
51091
+ function portableTypeToGroup(type) {
51092
+ return TYPE_TO_GROUP[type];
51093
+ }
51094
+ function portableGroupToType(group) {
51095
+ return GROUP_TO_TYPE[group];
51096
+ }
51097
+ function getEnabledPortableTypes(include) {
51098
+ return RECONCILE_PORTABLE_TYPES.filter((type) => include[portableTypeToGroup(type)]);
51099
+ }
51100
+ function resolvePortableTypeGlobal(provider, type, requestedGlobal) {
51101
+ if (requestedGlobal)
51102
+ return true;
51103
+ const providerConfig = providers[provider];
51104
+ const group = portableTypeToGroup(type);
51105
+ const pathConfig = providerConfig?.[group];
51106
+ if (pathConfig?.projectPath === null && pathConfig.globalPath !== null) {
51107
+ return true;
51108
+ }
51109
+ return false;
51110
+ }
51111
+ function resolvePortableGroupGlobal(provider, group, requestedGlobal) {
51112
+ return resolvePortableTypeGlobal(provider, portableGroupToType(group), requestedGlobal);
51113
+ }
51114
+ function buildScopedProviderConfigs(selectedProviders, include, requestedGlobal) {
51115
+ const enabledTypes = getEnabledPortableTypes(include);
51116
+ const configs = [];
51117
+ for (const provider of selectedProviders) {
51118
+ const typesByScope = new Map;
51119
+ for (const type of enabledTypes) {
51120
+ const isGlobal = resolvePortableTypeGlobal(provider, type, requestedGlobal);
51121
+ typesByScope.set(isGlobal, [...typesByScope.get(isGlobal) ?? [], type]);
51122
+ }
51123
+ for (const [global3, types4] of typesByScope) {
51124
+ configs.push({ provider, global: global3, types: types4 });
51125
+ }
51126
+ }
51127
+ return configs;
51128
+ }
51129
+ var RECONCILE_PORTABLE_TYPES, TYPE_TO_GROUP, GROUP_TO_TYPE;
51130
+ var init_migrate_provider_scopes = __esm(() => {
51131
+ init_provider_registry();
51132
+ RECONCILE_PORTABLE_TYPES = [
51133
+ "agent",
51134
+ "command",
51135
+ "skill",
51136
+ "config",
51137
+ "rules",
51138
+ "hooks"
51139
+ ];
51140
+ TYPE_TO_GROUP = {
51141
+ agent: "agents",
51142
+ command: "commands",
51143
+ skill: "skills",
51144
+ config: "config",
51145
+ rules: "rules",
51146
+ hooks: "hooks"
51147
+ };
51148
+ GROUP_TO_TYPE = {
51149
+ agents: "agent",
51150
+ commands: "command",
51151
+ skills: "skill",
51152
+ config: "config",
51153
+ rules: "rules",
51154
+ hooks: "hooks"
51155
+ };
51156
+ });
51157
+
51087
51158
  // src/commands/migrate/skill-directory-installer.ts
51088
51159
  import { existsSync as existsSync21 } from "node:fs";
51089
51160
  import { cp, mkdir as mkdir8, rename as rename5, rm as rm4 } from "node:fs/promises";
@@ -54668,11 +54739,13 @@ function buildSourceItemState(item, type, selectedProviders, options2) {
54668
54739
  }
54669
54740
  function buildTypeDirectoryStates(providerConfigs, types4) {
54670
54741
  const results = [];
54671
- for (const { provider, global: isGlobal } of providerConfigs) {
54742
+ for (const { provider, global: isGlobal, types: configTypes } of providerConfigs) {
54672
54743
  const providerConfig = providers[provider];
54673
54744
  if (!providerConfig)
54674
54745
  continue;
54675
54746
  for (const type of types4) {
54747
+ if (configTypes !== undefined && !configTypes.includes(type))
54748
+ continue;
54676
54749
  const pathKey = portableTypeToProviderPathKey(type);
54677
54750
  const pathConfig = providerConfig[pathKey];
54678
54751
  if (!pathConfig)
@@ -54846,16 +54919,26 @@ function makeDirStateKey(provider, type, global3) {
54846
54919
  return JSON.stringify([provider, type, global3]);
54847
54920
  }
54848
54921
  function dedupeProviderConfigs(providerConfigs) {
54849
- const seen = new Set;
54850
- const unique = [];
54922
+ const unique = new Map;
54851
54923
  for (const config of providerConfigs) {
54852
54924
  const key = makeProviderConfigKey(config.provider, config.global);
54853
- if (seen.has(key))
54925
+ const existing = unique.get(key);
54926
+ if (!existing) {
54927
+ unique.set(key, config.types ? { ...config, types: [...config.types] } : { ...config });
54854
54928
  continue;
54855
- seen.add(key);
54856
- unique.push(config);
54929
+ }
54930
+ if (existing.types === undefined || config.types === undefined) {
54931
+ existing.types = undefined;
54932
+ continue;
54933
+ }
54934
+ existing.types = Array.from(new Set([...existing.types, ...config.types]));
54857
54935
  }
54858
- return unique;
54936
+ return Array.from(unique.values());
54937
+ }
54938
+ function providerConfigIsActiveForEntry(providerConfigs, entry, options2 = {}) {
54939
+ if (options2.emptyMeansAll && providerConfigs.length === 0)
54940
+ return true;
54941
+ return providerConfigs.some((config) => config.provider === entry.provider && config.global === entry.global && providerConfigAppliesToType(config, entry.type));
54859
54942
  }
54860
54943
  function buildTargetStateIndex(targetStates) {
54861
54944
  const index = new Map;
@@ -55044,6 +55127,8 @@ function reconcile(input) {
55044
55127
  actions.push(...sectionRenames);
55045
55128
  for (const sourceItem of input.sourceItems) {
55046
55129
  for (const providerConfig of uniqueProviderConfigs) {
55130
+ if (!providerConfigAppliesToType(providerConfig, sourceItem.type))
55131
+ continue;
55047
55132
  const action = determineAction(sourceItem, providerConfig, input, targetStateIndex, deletedIdentityKeys);
55048
55133
  actions.push(action);
55049
55134
  }
@@ -55307,13 +55392,12 @@ function findRegistryEntry(source, providerConfig, registry) {
55307
55392
  function detectOrphans(input, renamedFromKeys) {
55308
55393
  const actions = [];
55309
55394
  const sourceItemKeys = new Set(input.sourceItems.map((s) => makeItemTypeKey(s.item, s.type)));
55310
- const activeProviderKeys = new Set(input.providerConfigs.map((provider) => makeProviderConfigKey(provider.provider, provider.global)));
55395
+ const activeProviderConfigs = dedupeProviderConfigs(input.providerConfigs);
55311
55396
  const hasConfigSource = input.sourceItems.some((source) => source.type === "config");
55312
55397
  for (const entry of input.registry.installations) {
55313
55398
  const key = makeRegistryIdentityKey(entry);
55314
55399
  const sourceItemKey = makeItemTypeKey(entry.item, entry.type);
55315
- const providerKey = makeProviderConfigKey(entry.provider, entry.global);
55316
- if (!activeProviderKeys.has(providerKey))
55400
+ if (!providerConfigIsActiveForEntry(activeProviderConfigs, entry))
55317
55401
  continue;
55318
55402
  if (renamedFromKeys.has(key))
55319
55403
  continue;
@@ -55345,13 +55429,14 @@ function detectRenames(input) {
55345
55429
  return [];
55346
55430
  const applicable = getApplicableEntries(input.manifest.renames, input.registry.appliedManifestVersion, input.manifest.cliVersion);
55347
55431
  const actions = [];
55432
+ const activeProviderConfigs = dedupeProviderConfigs(input.providerConfigs);
55348
55433
  for (const rename8 of applicable) {
55349
55434
  if (hasDotDotSegment(rename8.from) || hasDotDotSegment(rename8.to) || isAbsoluteLike(rename8.from) || isAbsoluteLike(rename8.to)) {
55350
55435
  console.warn(`[!] Skipping suspicious manifest rename: ${rename8.from} -> ${rename8.to}`);
55351
55436
  continue;
55352
55437
  }
55353
55438
  const normalizedFrom = normalizePortablePath(rename8.from);
55354
- const oldEntries = input.registry.installations.filter((e2) => normalizePortablePath(e2.sourcePath) === normalizedFrom);
55439
+ const oldEntries = input.registry.installations.filter((e2) => normalizePortablePath(e2.sourcePath) === normalizedFrom && providerConfigIsActiveForEntry(activeProviderConfigs, e2, { emptyMeansAll: true }));
55355
55440
  for (const oldEntry of oldEntries) {
55356
55441
  const code = "renamed-cleanup";
55357
55442
  actions.push({
@@ -55378,8 +55463,9 @@ function detectPathMigrations(input) {
55378
55463
  return [];
55379
55464
  const applicable = getApplicableEntries(input.manifest.providerPathMigrations, input.registry.appliedManifestVersion, input.manifest.cliVersion);
55380
55465
  const actions = [];
55466
+ const activeProviderConfigs = dedupeProviderConfigs(input.providerConfigs);
55381
55467
  for (const migration of applicable) {
55382
- const affectedEntries = input.registry.installations.filter((e2) => e2.provider === migration.provider && e2.type === migration.type && pathContainsSegments(e2.path, migration.from));
55468
+ const affectedEntries = input.registry.installations.filter((e2) => e2.provider === migration.provider && e2.type === migration.type && pathContainsSegments(e2.path, migration.from) && providerConfigIsActiveForEntry(activeProviderConfigs, e2, { emptyMeansAll: true }));
55383
55469
  for (const entry of affectedEntries) {
55384
55470
  const code = "path-migrated-cleanup";
55385
55471
  actions.push({
@@ -55790,6 +55876,17 @@ function annotateResultsWithCollisions(results, collisions) {
55790
55876
  }
55791
55877
  }
55792
55878
  }
55879
+ function dedupeProviderPathCollisions(collisions) {
55880
+ const unique = new Map;
55881
+ for (const collision of collisions) {
55882
+ const providersKey = [...collision.providers].sort().join("\x00");
55883
+ const key = JSON.stringify([collision.path, collision.portableType, providersKey]);
55884
+ if (!unique.has(key)) {
55885
+ unique.set(key, { ...collision, providers: [...collision.providers] });
55886
+ }
55887
+ }
55888
+ return Array.from(unique.values());
55889
+ }
55793
55890
  var init_migration_result_utils = __esm(() => {
55794
55891
  init_provider_registry();
55795
55892
  });
@@ -56164,6 +56261,19 @@ function providerSupportsType(provider, type) {
56164
56261
  return getProvidersSupporting("hooks").includes(provider);
56165
56262
  return false;
56166
56263
  }
56264
+ function groupProvidersByTypeScope(selectedProviders, type, requestedGlobal) {
56265
+ const grouped = new Map;
56266
+ for (const provider of selectedProviders) {
56267
+ if (!providerSupportsType(provider, type))
56268
+ continue;
56269
+ const global3 = resolvePortableTypeGlobal(provider, type, requestedGlobal);
56270
+ grouped.set(global3, [...grouped.get(global3) ?? [], provider]);
56271
+ }
56272
+ return Array.from(grouped, ([global3, providersForScope]) => ({
56273
+ global: global3,
56274
+ providers: providersForScope
56275
+ }));
56276
+ }
56167
56277
  function createSkippedActionResult(action, reason) {
56168
56278
  const provider = action.provider;
56169
56279
  return {
@@ -56538,17 +56648,12 @@ function registerMigrationRoutes(app) {
56538
56648
  onReadFailure: (entryPath, error) => warnReadFailure("registry-target", entryPath, error)
56539
56649
  });
56540
56650
  const manifest = discovered.sourcePaths.agents ? await loadPortableManifest(discovered.sourcePaths.agents) : null;
56541
- const providerConfigs = selectedProviders.map((provider) => ({
56542
- provider,
56543
- global: globalParam
56544
- }));
56545
- const enabledTypes = ["agent", "command", "skill", "config", "rules", "hooks"].filter((type) => {
56546
- const key = type === "agent" ? "agents" : type === "command" ? "commands" : type === "skill" ? "skills" : type === "config" ? "config" : type === "rules" ? "rules" : "hooks";
56547
- return include[key];
56548
- });
56651
+ const providerConfigs = buildScopedProviderConfigs(selectedProviders, include, globalParam);
56652
+ const enabledTypes = getEnabledPortableTypes(include);
56549
56653
  const typeDirectoryStates = reinstallEmptyDirs ? buildTypeDirectoryStates(providerConfigs.map((p) => ({
56550
56654
  provider: p.provider,
56551
- global: p.global
56655
+ global: p.global,
56656
+ types: p.types
56552
56657
  })), enabledTypes) : undefined;
56553
56658
  const input = {
56554
56659
  sourceItems,
@@ -56596,13 +56701,14 @@ function registerMigrationRoutes(app) {
56596
56701
  for (const item of items) {
56597
56702
  const sourcePath = item.sourcePath ?? item.path ?? "";
56598
56703
  for (const provider of selectedProviders) {
56599
- const registryEntry = registry.installations.find((inst) => inst.item === item.name && inst.type === type && inst.provider === provider && inst.global === globalParam);
56704
+ const candidateGlobal = resolvePortableTypeGlobal(provider, type, globalParam);
56705
+ const registryEntry = registry.installations.find((inst) => inst.item === item.name && inst.type === type && inst.provider === provider && inst.global === candidateGlobal);
56600
56706
  const alreadyInstalled = registryEntry !== undefined;
56601
56707
  candidates.push({
56602
56708
  item: item.name,
56603
56709
  type,
56604
56710
  provider,
56605
- global: globalParam,
56711
+ global: candidateGlobal,
56606
56712
  isDirectoryItem,
56607
56713
  description: item.description,
56608
56714
  sourcePath,
@@ -56690,14 +56796,12 @@ function registerMigrationRoutes(app) {
56690
56796
  sourcePath: h2.sourcePath ?? ""
56691
56797
  })), "hooks", false);
56692
56798
  }
56693
- const providerConfigs = selectedProviders.map((provider) => ({
56694
- provider,
56695
- global: globalParam
56799
+ const providerConfigs = buildScopedProviderConfigs(selectedProviders, include, globalParam).map((config) => ({
56800
+ provider: config.provider,
56801
+ global: config.global,
56802
+ types: config.types
56696
56803
  }));
56697
- const enabledTypes = ["agent", "command", "skill", "config", "rules", "hooks"].filter((type) => {
56698
- const key = type === "agent" ? "agents" : type === "command" ? "commands" : type === "skill" ? "skills" : type === "config" ? "config" : type === "rules" ? "rules" : "hooks";
56699
- return include[key];
56700
- });
56804
+ const enabledTypes = getEnabledPortableTypes(include);
56701
56805
  const typeDirectoryStates = buildTypeDirectoryStates(providerConfigs, enabledTypes);
56702
56806
  res.status(200).json({ candidates, typeDirectoryStates });
56703
56807
  } catch (error) {
@@ -56860,13 +56964,15 @@ function registerMigrationRoutes(app) {
56860
56964
  const plannedSkills = allowedSkillNames.length > 0 ? discovered2.skills.filter((skill) => allowedSkillNames.includes(skill.name)) : executionMode === "install" ? [] : discovered2.skills;
56861
56965
  const skillProviders = allPlanProviders.filter((provider) => providerSupportsType(provider, "skill"));
56862
56966
  if (skillProviders.length > 0) {
56863
- const globalFromPlan = plan.actions[0]?.global ?? false;
56864
56967
  for (const skill of plannedSkills) {
56865
- const batch = await installSkillDirectories([skill], skillProviders, {
56866
- global: globalFromPlan
56867
- });
56868
- tagResults(batch, "skills", skill.name);
56869
- allResults.push(...batch);
56968
+ for (const provider of skillProviders) {
56969
+ const globalFromPlan = plan.actions.find((action) => action.provider === provider && action.type === "skill")?.global ?? false;
56970
+ const batch = await installSkillDirectories([skill], [provider], {
56971
+ global: globalFromPlan
56972
+ });
56973
+ tagResults(batch, "skills", skill.name);
56974
+ allResults.push(...batch);
56975
+ }
56870
56976
  }
56871
56977
  }
56872
56978
  }
@@ -56886,12 +56992,12 @@ function registerMigrationRoutes(app) {
56886
56992
  for (const provider of allPlanProviders) {
56887
56993
  if (providers[provider]?.agents?.writeStrategy !== "codex-toml")
56888
56994
  continue;
56889
- const providerScopes = [
56995
+ const providerScopes2 = [
56890
56996
  ...new Set(plan.actions.filter((a3) => a3.provider === provider).map((a3) => a3.global).filter((g2) => g2 !== undefined))
56891
56997
  ];
56892
- if (providerScopes.length === 0)
56893
- providerScopes.push(false);
56894
- for (const scope of providerScopes) {
56998
+ if (providerScopes2.length === 0)
56999
+ providerScopes2.push(false);
57000
+ for (const scope of providerScopes2) {
56895
57001
  const staleSlugs = await cleanupStaleCodexConfigEntries({
56896
57002
  global: scope,
56897
57003
  provider
@@ -56918,7 +57024,7 @@ function registerMigrationRoutes(app) {
56918
57024
  const planScopes = [
56919
57025
  ...new Set(plan.actions.map((a3) => a3.global).filter((s) => s !== undefined))
56920
57026
  ];
56921
- const providerCollisions2 = planScopes.flatMap((scope) => detectProviderPathCollisions(allPlanProviders, { global: scope }));
57027
+ const providerCollisions2 = dedupeProviderPathCollisions(planScopes.flatMap((scope) => detectProviderPathCollisions(allPlanProviders, { global: scope })));
56922
57028
  annotateResultsWithCollisions(sortedResults2, providerCollisions2);
56923
57029
  res.status(200).json({
56924
57030
  results: sortedResults2,
@@ -56954,10 +57060,10 @@ function registerMigrationRoutes(app) {
56954
57060
  }
56955
57061
  const configSource = sourceParsed.value;
56956
57062
  const codexCommandsRequireGlobal = include.commands && selectedProviders.includes("codex") && providers.codex.commands !== null && providers.codex.commands.projectPath === null;
56957
- const effectiveGlobal = requestedGlobal || codexCommandsRequireGlobal;
57063
+ const effectiveGlobal = requestedGlobal;
56958
57064
  const warnings = [];
56959
57065
  if (codexCommandsRequireGlobal && !requestedGlobal) {
56960
- warnings.push("Codex commands are global-only; scope was automatically switched to global.");
57066
+ warnings.push("Codex commands are global-only; they will be installed globally while other content stays project-local.");
56961
57067
  }
56962
57068
  const discovered = await discoverMigrationItems(include, configSource);
56963
57069
  const hasItems = discovered.agents.length > 0 || discovered.commands.length > 0 || discovered.skills.length > 0 || discovered.configItem !== null || discovered.ruleItems.length > 0 || discovered.hookItems.length > 0;
@@ -56980,7 +57086,6 @@ function registerMigrationRoutes(app) {
56980
57086
  });
56981
57087
  return;
56982
57088
  }
56983
- const installOptions = { global: effectiveGlobal };
56984
57089
  const results = [];
56985
57090
  const hookRegistrationResults = [];
56986
57091
  const successfulHookFiles = new Map;
@@ -56994,10 +57099,11 @@ function registerMigrationRoutes(app) {
56994
57099
  hooks: include.hooks ? selectedProviders.filter((provider) => !getProvidersSupporting("hooks").includes(provider)) : []
56995
57100
  };
56996
57101
  if (include.agents && discovered.agents.length > 0) {
56997
- const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("agents").includes(provider));
56998
- if (providersForType.length > 0) {
57102
+ for (const group of groupProvidersByTypeScope(selectedProviders, "agent", requestedGlobal)) {
56999
57103
  const batches = await Promise.all(discovered.agents.map(async (agent) => {
57000
- const batch = await installPortableItems([agent], providersForType, "agent", installOptions);
57104
+ const batch = await installPortableItems([agent], group.providers, "agent", {
57105
+ global: group.global
57106
+ });
57001
57107
  tagResults(batch, "agents", agent.name);
57002
57108
  return batch;
57003
57109
  }));
@@ -57007,10 +57113,11 @@ function registerMigrationRoutes(app) {
57007
57113
  }
57008
57114
  }
57009
57115
  if (include.commands && discovered.commands.length > 0) {
57010
- const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("commands").includes(provider));
57011
- if (providersForType.length > 0) {
57116
+ for (const group of groupProvidersByTypeScope(selectedProviders, "command", requestedGlobal)) {
57012
57117
  const batches = await Promise.all(discovered.commands.map(async (command) => {
57013
- const batch = await installPortableItems([command], providersForType, "command", installOptions);
57118
+ const batch = await installPortableItems([command], group.providers, "command", {
57119
+ global: group.global
57120
+ });
57014
57121
  tagResults(batch, "commands", command.name);
57015
57122
  return batch;
57016
57123
  }));
@@ -57020,10 +57127,11 @@ function registerMigrationRoutes(app) {
57020
57127
  }
57021
57128
  }
57022
57129
  if (include.skills && discovered.skills.length > 0) {
57023
- const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("skills").includes(provider));
57024
- if (providersForType.length > 0) {
57130
+ for (const group of groupProvidersByTypeScope(selectedProviders, "skill", requestedGlobal)) {
57025
57131
  const batches = await Promise.all(discovered.skills.map(async (skill) => {
57026
- const batch = await installSkillDirectories([skill], providersForType, installOptions);
57132
+ const batch = await installSkillDirectories([skill], group.providers, {
57133
+ global: group.global
57134
+ });
57027
57135
  tagResults(batch, "skills", skill.name);
57028
57136
  return batch;
57029
57137
  }));
@@ -57033,18 +57141,18 @@ function registerMigrationRoutes(app) {
57033
57141
  }
57034
57142
  }
57035
57143
  if (include.config && discovered.configItem) {
57036
- const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("config").includes(provider));
57037
- if (providersForType.length > 0) {
57038
- const batch = await installPortableItems([discovered.configItem], providersForType, "config", installOptions);
57144
+ for (const group of groupProvidersByTypeScope(selectedProviders, "config", requestedGlobal)) {
57145
+ const batch = await installPortableItems([discovered.configItem], group.providers, "config", { global: group.global });
57039
57146
  tagResults(batch, "config");
57040
57147
  results.push(...batch);
57041
57148
  }
57042
57149
  }
57043
57150
  if (include.rules && discovered.ruleItems.length > 0) {
57044
- const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("rules").includes(provider));
57045
- if (providersForType.length > 0) {
57151
+ for (const group of groupProvidersByTypeScope(selectedProviders, "rules", requestedGlobal)) {
57046
57152
  const batches = await Promise.all(discovered.ruleItems.map(async (rule) => {
57047
- const batch = await installPortableItems([rule], providersForType, "rules", installOptions);
57153
+ const batch = await installPortableItems([rule], group.providers, "rules", {
57154
+ global: group.global
57155
+ });
57048
57156
  tagResults(batch, "rules", rule.name);
57049
57157
  return batch;
57050
57158
  }));
@@ -57054,14 +57162,18 @@ function registerMigrationRoutes(app) {
57054
57162
  }
57055
57163
  }
57056
57164
  if (include.hooks && discovered.hookItems.length > 0) {
57057
- const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("hooks").includes(provider));
57058
- if (providersForType.length > 0) {
57165
+ for (const group of groupProvidersByTypeScope(selectedProviders, "hooks", requestedGlobal)) {
57059
57166
  const batches = await Promise.all(discovered.hookItems.map(async (hook) => {
57060
- const batch = await installPortableItems([hook], providersForType, "hooks", installOptions);
57167
+ const batch = await installPortableItems([hook], group.providers, "hooks", {
57168
+ global: group.global
57169
+ });
57061
57170
  tagResults(batch, "hooks", hook.name);
57062
57171
  for (const result of batch.filter((entry) => entry.success && !entry.skipped)) {
57063
- const existing = successfulHookFiles.get(result.provider) ?? [];
57064
- existing.push(basename12(result.path));
57172
+ const existing = successfulHookFiles.get(result.provider) ?? {
57173
+ files: [],
57174
+ global: group.global
57175
+ };
57176
+ existing.files.push(basename12(result.path));
57065
57177
  successfulHookFiles.set(result.provider, existing);
57066
57178
  if (result.path.length > 0) {
57067
57179
  const absExisting = successfulHookAbsPaths.get(result.provider) ?? [];
@@ -57076,22 +57188,25 @@ function registerMigrationRoutes(app) {
57076
57188
  }
57077
57189
  }
57078
57190
  }
57079
- for (const [provider, files] of successfulHookFiles) {
57080
- if (files.length === 0)
57191
+ for (const [provider, entry] of successfulHookFiles) {
57192
+ if (entry.files.length === 0)
57081
57193
  continue;
57082
57194
  const mergeResult = await migrateHooksSettings({
57083
57195
  sourceProvider: "claude-code",
57084
57196
  targetProvider: provider,
57085
- installedHookFiles: files,
57197
+ installedHookFiles: entry.files,
57086
57198
  installedHookAbsolutePaths: successfulHookAbsPaths.get(provider),
57087
- global: effectiveGlobal
57199
+ global: entry.global
57088
57200
  });
57089
57201
  recordHookRegistrationOutcome(provider, mergeResult, warnings, hookRegistrationResults);
57090
57202
  }
57091
57203
  const responseResults = [...results, ...hookRegistrationResults];
57092
57204
  const sortedResults = sortPortableInstallResults(responseResults);
57093
57205
  const counts = toExecutionCounts(sortedResults);
57094
- const providerCollisions = detectProviderPathCollisions(selectedProviders, installOptions);
57206
+ const providerScopes = [
57207
+ ...new Set(buildScopedProviderConfigs(selectedProviders, include, requestedGlobal).map((p) => p.global))
57208
+ ];
57209
+ const providerCollisions = dedupeProviderPathCollisions(providerScopes.flatMap((scope) => detectProviderPathCollisions(selectedProviders, { global: scope })));
57095
57210
  annotateResultsWithCollisions(sortedResults, providerCollisions);
57096
57211
  res.status(200).json({
57097
57212
  results: sortedResults,
@@ -57114,6 +57229,7 @@ var MIGRATION_TYPES, MAX_PROVIDER_COUNT = 20, MAX_PLAN_ACTIONS = 5000, ALLOWED_C
57114
57229
  var init_migration_routes = __esm(() => {
57115
57230
  init_agents_discovery();
57116
57231
  init_commands_discovery();
57232
+ init_migrate_provider_scopes();
57117
57233
  init_skill_directory_installer();
57118
57234
  init_codex_toml_installer();
57119
57235
  init_config_discovery();
@@ -62253,7 +62369,7 @@ var package_default;
62253
62369
  var init_package = __esm(() => {
62254
62370
  package_default = {
62255
62371
  name: "claudekit-cli",
62256
- version: "3.42.2-dev.4",
62372
+ version: "3.42.2-dev.5",
62257
62373
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
62258
62374
  type: "module",
62259
62375
  repository: {
@@ -107521,6 +107637,9 @@ function createTtyProgressSink(total, context) {
107521
107637
  };
107522
107638
  }
107523
107639
 
107640
+ // src/commands/migrate/migrate-command.ts
107641
+ init_migrate_provider_scopes();
107642
+
107524
107643
  // src/commands/migrate/migrate-scope-resolver.ts
107525
107644
  function resolveMigrationScope(argv, options2) {
107526
107645
  const argSet = new Set(argv);
@@ -107566,6 +107685,7 @@ function resolveMigrationScope(argv, options2) {
107566
107685
 
107567
107686
  // src/commands/migrate/migrate-ui-summary.ts
107568
107687
  init_provider_registry();
107688
+ init_migrate_provider_scopes();
107569
107689
  var PORTABLE_TYPES = [
107570
107690
  { key: "agents", label: "Agents" },
107571
107691
  { key: "commands", label: "Commands" },
@@ -107588,9 +107708,10 @@ function buildPreflightRows(counts, selectedProviders, options2) {
107588
107708
  notes.add(`${providers[provider].displayName}: unsupported`);
107589
107709
  continue;
107590
107710
  }
107591
- const destination = getPortableBasePath(provider, key, { global: options2.actualGlobal });
107711
+ const actualGlobal = resolvePortableGroupGlobal(provider, key, options2.requestedGlobal);
107712
+ const destination = getPortableBasePath(provider, key, { global: actualGlobal });
107592
107713
  if (!destination) {
107593
- const note2 = options2.actualGlobal ? "project-only" : "global-only";
107714
+ const note2 = actualGlobal ? "project-only" : "global-only";
107594
107715
  notes.add(`${providers[provider].displayName}: ${note2}`);
107595
107716
  continue;
107596
107717
  }
@@ -107634,8 +107755,17 @@ function buildTargetSummaryLines(rows) {
107634
107755
  }
107635
107756
  return [...allDestinations.slice(0, 3), `+${allDestinations.length - 3} more destination(s)`];
107636
107757
  }
107637
- function buildProviderScopeSubtitle(selectedProviders, global3) {
107638
- const scope = global3 ? "global" : "project";
107758
+ function buildProviderScopeSubtitle(selectedProviders, requestedGlobal, counts) {
107759
+ const activeTypes = PORTABLE_TYPES.filter(({ key }) => !counts || counts[key] > 0);
107760
+ const resolvedScopes = new Set;
107761
+ for (const provider of selectedProviders) {
107762
+ for (const { key } of activeTypes) {
107763
+ if (!providers[provider][key])
107764
+ continue;
107765
+ resolvedScopes.add(resolvePortableGroupGlobal(provider, key, requestedGlobal));
107766
+ }
107767
+ }
107768
+ const scope = resolvedScopes.size > 1 ? "mixed" : resolvedScopes.values().next().value ?? requestedGlobal ? "global" : "project";
107639
107769
  if (selectedProviders.length === 1) {
107640
107770
  return `${providers[selectedProviders[0]].displayName} -> ${scope}`;
107641
107771
  }
@@ -108055,8 +108185,7 @@ async function migrateCommand(options2) {
108055
108185
  }
108056
108186
  const codexCommandsRequireGlobal = scope.commands && selectedProviders.includes("codex") && providers.codex.commands !== null && providers.codex.commands.projectPath === null;
108057
108187
  if (codexCommandsRequireGlobal && !installGlobally) {
108058
- installGlobally = true;
108059
- f2.info(import_picocolors30.default.dim("Codex commands are global-only; scope adjusted to global."));
108188
+ f2.info(import_picocolors30.default.dim("Codex commands are global-only; they will be installed globally while other content stays project-local."));
108060
108189
  }
108061
108190
  const sourceCounts = {
108062
108191
  agents: agents2.length,
@@ -108075,7 +108204,6 @@ async function migrateCommand(options2) {
108075
108204
  hooksSource
108076
108205
  ].filter((origin) => origin !== null);
108077
108206
  const preflightRows = buildPreflightRows(sourceCounts, selectedProviders, {
108078
- actualGlobal: installGlobally,
108079
108207
  requestedGlobal
108080
108208
  });
108081
108209
  const discoveryParts = [];
@@ -108105,7 +108233,7 @@ async function migrateCommand(options2) {
108105
108233
  console.log();
108106
108234
  console.log(renderSourceTargetHeader({
108107
108235
  sourceLines: buildSourceSummaryLines(sourceCounts, sourceOrigins),
108108
- subtitle: buildProviderScopeSubtitle(selectedProviders, installGlobally),
108236
+ subtitle: buildProviderScopeSubtitle(selectedProviders, requestedGlobal, sourceCounts),
108109
108237
  targetLines: buildTargetSummaryLines(preflightRows),
108110
108238
  title: "ck migrate"
108111
108239
  }).join(`
@@ -108163,13 +108291,14 @@ async function migrateCommand(options2) {
108163
108291
  rules: effectiveRuleItems,
108164
108292
  hooks: effectiveHookItems
108165
108293
  }, selectedProviders);
108166
- const targetStates = await computeTargetStates(selectedProviders, installGlobally);
108167
- const providerConfigs = selectedProviders.map((provider) => ({
108168
- provider,
108169
- global: installGlobally
108170
- }));
108171
- const portableTypes = ["agent", "command", "config", "rules", "hooks"];
108172
- const typeDirectoryStates = buildTypeDirectoryStates(selectedProviders.map((provider) => ({ provider, global: installGlobally })), [...portableTypes]);
108294
+ const providerConfigs = buildScopedProviderConfigs(selectedProviders, scope, installGlobally);
108295
+ const targetStates = await computeTargetStates(providerConfigs);
108296
+ const portableTypes = getEnabledPortableTypes(scope).filter((type) => type !== "skill");
108297
+ const typeDirectoryStates = buildTypeDirectoryStates(providerConfigs.map((config) => ({
108298
+ provider: config.provider,
108299
+ global: config.global,
108300
+ types: config.types?.filter((type) => type !== "skill")
108301
+ })), portableTypes);
108173
108302
  const reinstallEmptyDirs = options2.respectDeletions ? false : options2.reinstallEmptyDirs ?? true;
108174
108303
  const plan = reconcile({
108175
108304
  sourceItems: sourceStates,
@@ -108232,7 +108361,6 @@ async function migrateCommand(options2) {
108232
108361
  }
108233
108362
  }
108234
108363
  let allResults = [];
108235
- const installOpts = { global: installGlobally };
108236
108364
  const agentByName = new Map(effectiveAgents.map((item) => [item.name, item]));
108237
108365
  const commandByName = new Map(effectiveCommands.map((item) => [item.name, item]));
108238
108366
  const skillByName = new Map(effectiveSkills.map((item) => [item.name, item]));
@@ -108251,42 +108379,42 @@ async function migrateCommand(options2) {
108251
108379
  const item = agentByName.get(action.item);
108252
108380
  if (!item || !getProvidersSupporting("agents").includes(provider))
108253
108381
  continue;
108254
- writeTasks.push({ item, provider, type: "agent" });
108382
+ writeTasks.push({ item, provider, type: "agent", global: action.global });
108255
108383
  continue;
108256
108384
  }
108257
108385
  if (action.type === "command") {
108258
108386
  const item = commandByName.get(action.item);
108259
108387
  if (!item || !getProvidersSupporting("commands").includes(provider))
108260
108388
  continue;
108261
- writeTasks.push({ item, provider, type: "command" });
108389
+ writeTasks.push({ item, provider, type: "command", global: action.global });
108262
108390
  continue;
108263
108391
  }
108264
108392
  if (action.type === "skill") {
108265
108393
  const item = skillByName.get(action.item);
108266
108394
  if (!item || !getProvidersSupporting("skills").includes(provider))
108267
108395
  continue;
108268
- writeTasks.push({ item, provider, type: "skill" });
108396
+ writeTasks.push({ item, provider, type: "skill", global: action.global });
108269
108397
  continue;
108270
108398
  }
108271
108399
  if (action.type === "config") {
108272
108400
  const item = configByName.get(action.item);
108273
108401
  if (!item || !getProvidersSupporting("config").includes(provider))
108274
108402
  continue;
108275
- writeTasks.push({ item, provider, type: "config" });
108403
+ writeTasks.push({ item, provider, type: "config", global: action.global });
108276
108404
  continue;
108277
108405
  }
108278
108406
  if (action.type === "rules") {
108279
108407
  const item = ruleByName.get(action.item);
108280
108408
  if (!item || !getProvidersSupporting("rules").includes(provider))
108281
108409
  continue;
108282
- writeTasks.push({ item, provider, type: "rules" });
108410
+ writeTasks.push({ item, provider, type: "rules", global: action.global });
108283
108411
  continue;
108284
108412
  }
108285
108413
  if (action.type === "hooks") {
108286
108414
  const item = hookByName.get(action.item);
108287
108415
  if (!item || !getProvidersSupporting("hooks").includes(provider))
108288
108416
  continue;
108289
- writeTasks.push({ item, provider, type: "hooks" });
108417
+ writeTasks.push({ item, provider, type: "hooks", global: action.global });
108290
108418
  }
108291
108419
  }
108292
108420
  const plannedSkillActions = plannedExecActions.filter((action) => action.type === "skill").length;
@@ -108294,22 +108422,31 @@ async function migrateCommand(options2) {
108294
108422
  const skillProviders = selectedProviders.filter((pv) => getProvidersSupporting("skills").includes(pv));
108295
108423
  for (const provider of skillProviders) {
108296
108424
  for (const skill of effectiveSkills) {
108297
- writeTasks.push({ item: skill, provider, type: "skill" });
108425
+ writeTasks.push({
108426
+ item: skill,
108427
+ provider,
108428
+ type: "skill",
108429
+ global: resolvePortableTypeGlobal(provider, "skill", installGlobally)
108430
+ });
108298
108431
  }
108299
108432
  }
108300
108433
  }
108301
108434
  const progressSink = createMigrateProgressSink(writeTasks.length + plannedDeleteActions.length);
108302
108435
  const writtenPaths = new Set;
108303
108436
  for (const task of writeTasks) {
108304
- const taskResults = task.type === "skill" ? annotateInstallResults(await installSkillDirectories([task.item], [task.provider], installOpts), "skill", task.item.name) : annotateInstallResults(await installPortableItems([task.item], [task.provider], task.type, installOpts), task.type, task.item.name);
108437
+ const taskInstallOpts = { global: task.global };
108438
+ const taskResults = task.type === "skill" ? annotateInstallResults(await installSkillDirectories([task.item], [task.provider], taskInstallOpts), "skill", task.item.name) : annotateInstallResults(await installPortableItems([task.item], [task.provider], task.type, taskInstallOpts), task.type, task.item.name);
108305
108439
  allResults.push(...taskResults);
108306
108440
  for (const result of taskResults.filter((entry) => entry.success && !entry.skipped)) {
108307
108441
  if (result.path.length > 0) {
108308
108442
  writtenPaths.add(resolve41(result.path));
108309
108443
  }
108310
108444
  if (task.type === "hooks") {
108311
- const existing = successfulHookFiles.get(task.provider) ?? [];
108312
- existing.push(basename27(result.path));
108445
+ const existing = successfulHookFiles.get(task.provider) ?? {
108446
+ files: [],
108447
+ global: task.global
108448
+ };
108449
+ existing.files.push(basename27(result.path));
108313
108450
  successfulHookFiles.set(task.provider, existing);
108314
108451
  if (result.path.length > 0) {
108315
108452
  const absExisting = successfulHookAbsPaths.get(task.provider) ?? [];
@@ -108337,9 +108474,9 @@ async function migrateCommand(options2) {
108337
108474
  }
108338
108475
  }
108339
108476
  if (hooksSource && successfulHookFiles.size > 0) {
108340
- for (const hooksProvider of successfulHookFiles.keys()) {
108477
+ for (const [hooksProvider, entry] of successfulHookFiles) {
108341
108478
  const providerCfg = providers[hooksProvider];
108342
- const targetHooksDir = installGlobally ? providerCfg.hooks?.globalPath : providerCfg.hooks?.projectPath;
108479
+ const targetHooksDir = entry.global ? providerCfg.hooks?.globalPath : providerCfg.hooks?.projectPath;
108343
108480
  if (!targetHooksDir)
108344
108481
  continue;
108345
108482
  const companionResult = await copyHooksCompanionDirs(hooksSource, targetHooksDir);
@@ -108361,15 +108498,15 @@ async function migrateCommand(options2) {
108361
108498
  }
108362
108499
  }
108363
108500
  }
108364
- for (const [hooksProvider, files] of successfulHookFiles) {
108365
- if (files.length === 0)
108501
+ for (const [hooksProvider, entry] of successfulHookFiles) {
108502
+ if (entry.files.length === 0)
108366
108503
  continue;
108367
108504
  const mergeResult = await migrateHooksSettings({
108368
108505
  sourceProvider: "claude-code",
108369
108506
  targetProvider: hooksProvider,
108370
- installedHookFiles: files,
108507
+ installedHookFiles: entry.files,
108371
108508
  installedHookAbsolutePaths: successfulHookAbsPaths.get(hooksProvider),
108372
- global: installGlobally
108509
+ global: entry.global
108373
108510
  });
108374
108511
  if (mergeResult.success && mergeResult.hooksRegistered > 0) {
108375
108512
  logger.verbose(`Registered ${mergeResult.hooksRegistered} hook(s) in ${hooksProvider} settings.json`);
@@ -108400,15 +108537,22 @@ async function migrateCommand(options2) {
108400
108537
  const providerConfig = providers[provider];
108401
108538
  if (providerConfig.agents?.writeStrategy !== "codex-toml")
108402
108539
  continue;
108403
- const staleSlugs = await cleanupStaleCodexConfigEntries({
108404
- global: installGlobally,
108405
- provider
108406
- });
108407
- if (staleSlugs.length > 0) {
108408
- const staleSlugSet = new Set(staleSlugs.map((s) => `${s}.toml`));
108409
- const removed = await removeInstallationsByFilter((i) => i.type === "agent" && i.provider === provider && i.global === installGlobally && staleSlugSet.has(basename27(i.path)));
108410
- for (const entry of removed) {
108411
- logger.verbose(`[migrate] Cleaned stale registry entry: ${entry.item} (${provider})`);
108540
+ const providerScopes = [
108541
+ ...new Set(plan.actions.filter((action) => action.provider === provider).map((action) => action.global))
108542
+ ];
108543
+ if (providerScopes.length === 0)
108544
+ providerScopes.push(installGlobally);
108545
+ for (const scope2 of providerScopes) {
108546
+ const staleSlugs = await cleanupStaleCodexConfigEntries({
108547
+ global: scope2,
108548
+ provider
108549
+ });
108550
+ if (staleSlugs.length > 0) {
108551
+ const staleSlugSet = new Set(staleSlugs.map((s) => `${s}.toml`));
108552
+ const removed = await removeInstallationsByFilter((i) => i.type === "agent" && i.provider === provider && i.global === scope2 && staleSlugSet.has(basename27(i.path)));
108553
+ for (const entry of removed) {
108554
+ logger.verbose(`[migrate] Cleaned stale registry entry: ${entry.item} (${provider})`);
108555
+ }
108412
108556
  }
108413
108557
  }
108414
108558
  }
@@ -108498,12 +108642,11 @@ async function computeSourceStates(items, selectedProviders) {
108498
108642
  processItems(items.hooks, "hooks");
108499
108643
  return states;
108500
108644
  }
108501
- async function computeTargetStates(selectedProviders, global3) {
108645
+ async function computeTargetStates(providerConfigs) {
108502
108646
  const registry = await readPortableRegistry();
108503
108647
  const relevantEntries = registry.installations.filter((entry) => {
108504
- if (!selectedProviders.includes(entry.provider))
108505
- return false;
108506
- if (entry.global !== global3)
108648
+ const matchingConfig = providerConfigs.some((config) => config.provider === entry.provider && config.global === entry.global && providerConfigAppliesToType(config, entry.type));
108649
+ if (!matchingConfig)
108507
108650
  return false;
108508
108651
  return entry.type !== "skill";
108509
108652
  });
@@ -108583,7 +108726,9 @@ function buildDryRunFallbackResults(skills, selectedProviders, installGlobally,
108583
108726
  }
108584
108727
  const results = [];
108585
108728
  for (const provider of selectedProviders.filter((entry) => getProvidersSupporting("skills").includes(entry))) {
108586
- const basePath = getPortableBasePath(provider, "skills", { global: installGlobally });
108729
+ const basePath = getPortableBasePath(provider, "skills", {
108730
+ global: resolvePortableTypeGlobal(provider, "skill", installGlobally)
108731
+ });
108587
108732
  if (!basePath)
108588
108733
  continue;
108589
108734
  for (const skill of skills) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.42.2-dev.4",
3
+ "version": "3.42.2-dev.5",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {