claudekit-cli 3.42.2-dev.3 → 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.3",
3
- "generatedAt": "2026-04-29T14:54:46.000Z",
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.3",
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: {
@@ -102644,7 +102760,6 @@ var COMMAND_ROOTS = [
102644
102760
  "worktree",
102645
102761
  "test",
102646
102762
  "preview",
102647
- "kanban",
102648
102763
  "journal",
102649
102764
  "watzup"
102650
102765
  ];
@@ -107522,6 +107637,9 @@ function createTtyProgressSink(total, context) {
107522
107637
  };
107523
107638
  }
107524
107639
 
107640
+ // src/commands/migrate/migrate-command.ts
107641
+ init_migrate_provider_scopes();
107642
+
107525
107643
  // src/commands/migrate/migrate-scope-resolver.ts
107526
107644
  function resolveMigrationScope(argv, options2) {
107527
107645
  const argSet = new Set(argv);
@@ -107567,6 +107685,7 @@ function resolveMigrationScope(argv, options2) {
107567
107685
 
107568
107686
  // src/commands/migrate/migrate-ui-summary.ts
107569
107687
  init_provider_registry();
107688
+ init_migrate_provider_scopes();
107570
107689
  var PORTABLE_TYPES = [
107571
107690
  { key: "agents", label: "Agents" },
107572
107691
  { key: "commands", label: "Commands" },
@@ -107589,9 +107708,10 @@ function buildPreflightRows(counts, selectedProviders, options2) {
107589
107708
  notes.add(`${providers[provider].displayName}: unsupported`);
107590
107709
  continue;
107591
107710
  }
107592
- const destination = getPortableBasePath(provider, key, { global: options2.actualGlobal });
107711
+ const actualGlobal = resolvePortableGroupGlobal(provider, key, options2.requestedGlobal);
107712
+ const destination = getPortableBasePath(provider, key, { global: actualGlobal });
107593
107713
  if (!destination) {
107594
- const note2 = options2.actualGlobal ? "project-only" : "global-only";
107714
+ const note2 = actualGlobal ? "project-only" : "global-only";
107595
107715
  notes.add(`${providers[provider].displayName}: ${note2}`);
107596
107716
  continue;
107597
107717
  }
@@ -107635,8 +107755,17 @@ function buildTargetSummaryLines(rows) {
107635
107755
  }
107636
107756
  return [...allDestinations.slice(0, 3), `+${allDestinations.length - 3} more destination(s)`];
107637
107757
  }
107638
- function buildProviderScopeSubtitle(selectedProviders, global3) {
107639
- 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";
107640
107769
  if (selectedProviders.length === 1) {
107641
107770
  return `${providers[selectedProviders[0]].displayName} -> ${scope}`;
107642
107771
  }
@@ -108056,8 +108185,7 @@ async function migrateCommand(options2) {
108056
108185
  }
108057
108186
  const codexCommandsRequireGlobal = scope.commands && selectedProviders.includes("codex") && providers.codex.commands !== null && providers.codex.commands.projectPath === null;
108058
108187
  if (codexCommandsRequireGlobal && !installGlobally) {
108059
- installGlobally = true;
108060
- 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."));
108061
108189
  }
108062
108190
  const sourceCounts = {
108063
108191
  agents: agents2.length,
@@ -108076,7 +108204,6 @@ async function migrateCommand(options2) {
108076
108204
  hooksSource
108077
108205
  ].filter((origin) => origin !== null);
108078
108206
  const preflightRows = buildPreflightRows(sourceCounts, selectedProviders, {
108079
- actualGlobal: installGlobally,
108080
108207
  requestedGlobal
108081
108208
  });
108082
108209
  const discoveryParts = [];
@@ -108106,7 +108233,7 @@ async function migrateCommand(options2) {
108106
108233
  console.log();
108107
108234
  console.log(renderSourceTargetHeader({
108108
108235
  sourceLines: buildSourceSummaryLines(sourceCounts, sourceOrigins),
108109
- subtitle: buildProviderScopeSubtitle(selectedProviders, installGlobally),
108236
+ subtitle: buildProviderScopeSubtitle(selectedProviders, requestedGlobal, sourceCounts),
108110
108237
  targetLines: buildTargetSummaryLines(preflightRows),
108111
108238
  title: "ck migrate"
108112
108239
  }).join(`
@@ -108164,13 +108291,14 @@ async function migrateCommand(options2) {
108164
108291
  rules: effectiveRuleItems,
108165
108292
  hooks: effectiveHookItems
108166
108293
  }, selectedProviders);
108167
- const targetStates = await computeTargetStates(selectedProviders, installGlobally);
108168
- const providerConfigs = selectedProviders.map((provider) => ({
108169
- provider,
108170
- global: installGlobally
108171
- }));
108172
- const portableTypes = ["agent", "command", "config", "rules", "hooks"];
108173
- 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);
108174
108302
  const reinstallEmptyDirs = options2.respectDeletions ? false : options2.reinstallEmptyDirs ?? true;
108175
108303
  const plan = reconcile({
108176
108304
  sourceItems: sourceStates,
@@ -108233,7 +108361,6 @@ async function migrateCommand(options2) {
108233
108361
  }
108234
108362
  }
108235
108363
  let allResults = [];
108236
- const installOpts = { global: installGlobally };
108237
108364
  const agentByName = new Map(effectiveAgents.map((item) => [item.name, item]));
108238
108365
  const commandByName = new Map(effectiveCommands.map((item) => [item.name, item]));
108239
108366
  const skillByName = new Map(effectiveSkills.map((item) => [item.name, item]));
@@ -108252,42 +108379,42 @@ async function migrateCommand(options2) {
108252
108379
  const item = agentByName.get(action.item);
108253
108380
  if (!item || !getProvidersSupporting("agents").includes(provider))
108254
108381
  continue;
108255
- writeTasks.push({ item, provider, type: "agent" });
108382
+ writeTasks.push({ item, provider, type: "agent", global: action.global });
108256
108383
  continue;
108257
108384
  }
108258
108385
  if (action.type === "command") {
108259
108386
  const item = commandByName.get(action.item);
108260
108387
  if (!item || !getProvidersSupporting("commands").includes(provider))
108261
108388
  continue;
108262
- writeTasks.push({ item, provider, type: "command" });
108389
+ writeTasks.push({ item, provider, type: "command", global: action.global });
108263
108390
  continue;
108264
108391
  }
108265
108392
  if (action.type === "skill") {
108266
108393
  const item = skillByName.get(action.item);
108267
108394
  if (!item || !getProvidersSupporting("skills").includes(provider))
108268
108395
  continue;
108269
- writeTasks.push({ item, provider, type: "skill" });
108396
+ writeTasks.push({ item, provider, type: "skill", global: action.global });
108270
108397
  continue;
108271
108398
  }
108272
108399
  if (action.type === "config") {
108273
108400
  const item = configByName.get(action.item);
108274
108401
  if (!item || !getProvidersSupporting("config").includes(provider))
108275
108402
  continue;
108276
- writeTasks.push({ item, provider, type: "config" });
108403
+ writeTasks.push({ item, provider, type: "config", global: action.global });
108277
108404
  continue;
108278
108405
  }
108279
108406
  if (action.type === "rules") {
108280
108407
  const item = ruleByName.get(action.item);
108281
108408
  if (!item || !getProvidersSupporting("rules").includes(provider))
108282
108409
  continue;
108283
- writeTasks.push({ item, provider, type: "rules" });
108410
+ writeTasks.push({ item, provider, type: "rules", global: action.global });
108284
108411
  continue;
108285
108412
  }
108286
108413
  if (action.type === "hooks") {
108287
108414
  const item = hookByName.get(action.item);
108288
108415
  if (!item || !getProvidersSupporting("hooks").includes(provider))
108289
108416
  continue;
108290
- writeTasks.push({ item, provider, type: "hooks" });
108417
+ writeTasks.push({ item, provider, type: "hooks", global: action.global });
108291
108418
  }
108292
108419
  }
108293
108420
  const plannedSkillActions = plannedExecActions.filter((action) => action.type === "skill").length;
@@ -108295,22 +108422,31 @@ async function migrateCommand(options2) {
108295
108422
  const skillProviders = selectedProviders.filter((pv) => getProvidersSupporting("skills").includes(pv));
108296
108423
  for (const provider of skillProviders) {
108297
108424
  for (const skill of effectiveSkills) {
108298
- 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
+ });
108299
108431
  }
108300
108432
  }
108301
108433
  }
108302
108434
  const progressSink = createMigrateProgressSink(writeTasks.length + plannedDeleteActions.length);
108303
108435
  const writtenPaths = new Set;
108304
108436
  for (const task of writeTasks) {
108305
- 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);
108306
108439
  allResults.push(...taskResults);
108307
108440
  for (const result of taskResults.filter((entry) => entry.success && !entry.skipped)) {
108308
108441
  if (result.path.length > 0) {
108309
108442
  writtenPaths.add(resolve41(result.path));
108310
108443
  }
108311
108444
  if (task.type === "hooks") {
108312
- const existing = successfulHookFiles.get(task.provider) ?? [];
108313
- 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));
108314
108450
  successfulHookFiles.set(task.provider, existing);
108315
108451
  if (result.path.length > 0) {
108316
108452
  const absExisting = successfulHookAbsPaths.get(task.provider) ?? [];
@@ -108338,9 +108474,9 @@ async function migrateCommand(options2) {
108338
108474
  }
108339
108475
  }
108340
108476
  if (hooksSource && successfulHookFiles.size > 0) {
108341
- for (const hooksProvider of successfulHookFiles.keys()) {
108477
+ for (const [hooksProvider, entry] of successfulHookFiles) {
108342
108478
  const providerCfg = providers[hooksProvider];
108343
- const targetHooksDir = installGlobally ? providerCfg.hooks?.globalPath : providerCfg.hooks?.projectPath;
108479
+ const targetHooksDir = entry.global ? providerCfg.hooks?.globalPath : providerCfg.hooks?.projectPath;
108344
108480
  if (!targetHooksDir)
108345
108481
  continue;
108346
108482
  const companionResult = await copyHooksCompanionDirs(hooksSource, targetHooksDir);
@@ -108362,15 +108498,15 @@ async function migrateCommand(options2) {
108362
108498
  }
108363
108499
  }
108364
108500
  }
108365
- for (const [hooksProvider, files] of successfulHookFiles) {
108366
- if (files.length === 0)
108501
+ for (const [hooksProvider, entry] of successfulHookFiles) {
108502
+ if (entry.files.length === 0)
108367
108503
  continue;
108368
108504
  const mergeResult = await migrateHooksSettings({
108369
108505
  sourceProvider: "claude-code",
108370
108506
  targetProvider: hooksProvider,
108371
- installedHookFiles: files,
108507
+ installedHookFiles: entry.files,
108372
108508
  installedHookAbsolutePaths: successfulHookAbsPaths.get(hooksProvider),
108373
- global: installGlobally
108509
+ global: entry.global
108374
108510
  });
108375
108511
  if (mergeResult.success && mergeResult.hooksRegistered > 0) {
108376
108512
  logger.verbose(`Registered ${mergeResult.hooksRegistered} hook(s) in ${hooksProvider} settings.json`);
@@ -108401,15 +108537,22 @@ async function migrateCommand(options2) {
108401
108537
  const providerConfig = providers[provider];
108402
108538
  if (providerConfig.agents?.writeStrategy !== "codex-toml")
108403
108539
  continue;
108404
- const staleSlugs = await cleanupStaleCodexConfigEntries({
108405
- global: installGlobally,
108406
- provider
108407
- });
108408
- if (staleSlugs.length > 0) {
108409
- const staleSlugSet = new Set(staleSlugs.map((s) => `${s}.toml`));
108410
- const removed = await removeInstallationsByFilter((i) => i.type === "agent" && i.provider === provider && i.global === installGlobally && staleSlugSet.has(basename27(i.path)));
108411
- for (const entry of removed) {
108412
- 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
+ }
108413
108556
  }
108414
108557
  }
108415
108558
  }
@@ -108499,12 +108642,11 @@ async function computeSourceStates(items, selectedProviders) {
108499
108642
  processItems(items.hooks, "hooks");
108500
108643
  return states;
108501
108644
  }
108502
- async function computeTargetStates(selectedProviders, global3) {
108645
+ async function computeTargetStates(providerConfigs) {
108503
108646
  const registry = await readPortableRegistry();
108504
108647
  const relevantEntries = registry.installations.filter((entry) => {
108505
- if (!selectedProviders.includes(entry.provider))
108506
- return false;
108507
- 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)
108508
108650
  return false;
108509
108651
  return entry.type !== "skill";
108510
108652
  });
@@ -108584,7 +108726,9 @@ function buildDryRunFallbackResults(skills, selectedProviders, installGlobally,
108584
108726
  }
108585
108727
  const results = [];
108586
108728
  for (const provider of selectedProviders.filter((entry) => getProvidersSupporting("skills").includes(entry))) {
108587
- const basePath = getPortableBasePath(provider, "skills", { global: installGlobally });
108729
+ const basePath = getPortableBasePath(provider, "skills", {
108730
+ global: resolvePortableTypeGlobal(provider, "skill", installGlobally)
108731
+ });
108588
108732
  if (!basePath)
108589
108733
  continue;
108590
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.3",
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": {