claudekit-cli 3.35.0-dev.29 → 3.35.0-dev.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -50489,10 +50489,16 @@ function parseBooleanLike(input) {
50489
50489
  if (normalized === "") {
50490
50490
  return { ok: true, value: undefined };
50491
50491
  }
50492
- if (normalized === "true" || normalized === "1") {
50492
+ if (normalized === "true") {
50493
50493
  return { ok: true, value: true };
50494
50494
  }
50495
- if (normalized === "false" || normalized === "0") {
50495
+ if (normalized === "false") {
50496
+ return { ok: true, value: false };
50497
+ }
50498
+ if (normalized === "1") {
50499
+ return { ok: true, value: true };
50500
+ }
50501
+ if (normalized === "0") {
50496
50502
  return { ok: true, value: false };
50497
50503
  }
50498
50504
  }
@@ -50533,9 +50539,6 @@ function parseProvidersFromTokens(rawTokens, requiredMessage, maxCountMessage) {
50533
50539
  if (normalizedTokens.length === 0) {
50534
50540
  return { ok: false, error: requiredMessage };
50535
50541
  }
50536
- if (normalizedTokens.length > MAX_PROVIDER_COUNT) {
50537
- return { ok: false, error: maxCountMessage };
50538
- }
50539
50542
  const selectedProviders = [];
50540
50543
  const seen = new Set;
50541
50544
  for (const rawProvider of normalizedTokens) {
@@ -50548,6 +50551,9 @@ function parseProvidersFromTokens(rawTokens, requiredMessage, maxCountMessage) {
50548
50551
  selectedProviders.push(parsed.data);
50549
50552
  }
50550
50553
  }
50554
+ if (selectedProviders.length > MAX_PROVIDER_COUNT) {
50555
+ return { ok: false, error: maxCountMessage };
50556
+ }
50551
50557
  return { ok: true, value: selectedProviders };
50552
50558
  }
50553
50559
  function parseProvidersFromQuery(value) {
@@ -50608,6 +50614,9 @@ function parseConfigSource(input) {
50608
50614
  };
50609
50615
  }
50610
50616
  function getConflictKey(action) {
50617
+ return JSON.stringify([action.provider, action.type, action.item, action.global]);
50618
+ }
50619
+ function getLegacyConflictKey(action) {
50611
50620
  return `${action.provider}:${action.type}:${action.item}:${action.global}`;
50612
50621
  }
50613
50622
  function validatePlanParity(plan) {
@@ -50688,6 +50697,211 @@ async function executePlanDeleteAction(action, options2) {
50688
50697
  function countEnabledTypes(include) {
50689
50698
  return MIGRATION_TYPES.filter((type) => include[type]).length;
50690
50699
  }
50700
+ function inferIncludeFromActions(actions) {
50701
+ const include = {
50702
+ agents: false,
50703
+ commands: false,
50704
+ skills: false,
50705
+ config: false,
50706
+ rules: false
50707
+ };
50708
+ for (const action of actions) {
50709
+ if (action.type === "agent")
50710
+ include.agents = true;
50711
+ else if (action.type === "command")
50712
+ include.commands = true;
50713
+ else if (action.type === "skill")
50714
+ include.skills = true;
50715
+ else if (action.type === "config")
50716
+ include.config = true;
50717
+ else if (action.type === "rules")
50718
+ include.rules = true;
50719
+ }
50720
+ return include;
50721
+ }
50722
+ function getPlanMeta(plan) {
50723
+ const rawMeta = plan.meta;
50724
+ if (!rawMeta || typeof rawMeta !== "object")
50725
+ return null;
50726
+ return rawMeta;
50727
+ }
50728
+ function getIncludeFromPlan(plan) {
50729
+ const meta = getPlanMeta(plan);
50730
+ const hasMetaInclude = meta?.include !== undefined;
50731
+ if (meta?.include && typeof meta.include === "object") {
50732
+ const parsed = meta.include;
50733
+ const include = {
50734
+ agents: parsed.agents === true,
50735
+ commands: parsed.commands === true,
50736
+ skills: parsed.skills === true,
50737
+ config: parsed.config === true,
50738
+ rules: parsed.rules === true
50739
+ };
50740
+ if (countEnabledTypes(include) > 0) {
50741
+ return include;
50742
+ }
50743
+ }
50744
+ const inferred = inferIncludeFromActions(plan.actions);
50745
+ if (!hasMetaInclude) {
50746
+ if (countEnabledTypes(inferred) === 0) {
50747
+ return normalizeIncludeOptions(undefined);
50748
+ }
50749
+ return { ...inferred, skills: true };
50750
+ }
50751
+ return inferred;
50752
+ }
50753
+ function getProvidersFromPlan(plan) {
50754
+ const meta = getPlanMeta(plan);
50755
+ const metaProviders = parseProvidersFromBody(meta?.providers);
50756
+ if (metaProviders.ok && metaProviders.value) {
50757
+ return metaProviders.value;
50758
+ }
50759
+ const providersFromActions = [];
50760
+ const seen = new Set;
50761
+ for (const action of plan.actions) {
50762
+ const parsed = ProviderType.safeParse(action.provider);
50763
+ if (!parsed.success)
50764
+ continue;
50765
+ if (seen.has(parsed.data))
50766
+ continue;
50767
+ seen.add(parsed.data);
50768
+ providersFromActions.push(parsed.data);
50769
+ }
50770
+ return providersFromActions;
50771
+ }
50772
+ function getConfigSourceFromPlan(plan) {
50773
+ const meta = getPlanMeta(plan);
50774
+ if (typeof meta?.source !== "string") {
50775
+ return;
50776
+ }
50777
+ const parsed = parseConfigSource(meta.source);
50778
+ return parsed.ok ? parsed.value : undefined;
50779
+ }
50780
+ function getPlanItemsByType(plan, type) {
50781
+ const meta = getPlanMeta(plan);
50782
+ if (!meta?.items || typeof meta.items !== "object")
50783
+ return [];
50784
+ const list = meta.items[type];
50785
+ if (!Array.isArray(list))
50786
+ return [];
50787
+ const normalized = list.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
50788
+ return Array.from(new Set(normalized));
50789
+ }
50790
+ function providerSupportsType(provider, type) {
50791
+ if (type === "agent")
50792
+ return getProvidersSupporting("agents").includes(provider);
50793
+ if (type === "command")
50794
+ return getProvidersSupporting("commands").includes(provider);
50795
+ if (type === "skill")
50796
+ return getProvidersSupporting("skills").includes(provider);
50797
+ if (type === "config")
50798
+ return getProvidersSupporting("config").includes(provider);
50799
+ return getProvidersSupporting("rules").includes(provider);
50800
+ }
50801
+ function createSkippedActionResult(action, reason) {
50802
+ const provider = action.provider;
50803
+ return {
50804
+ provider,
50805
+ providerDisplayName: providers[provider]?.displayName || action.provider,
50806
+ success: true,
50807
+ path: action.targetPath,
50808
+ skipped: true,
50809
+ skipReason: reason,
50810
+ portableType: action.type,
50811
+ itemName: action.item
50812
+ };
50813
+ }
50814
+ function toDiscoveryCounts(results) {
50815
+ const sets = {
50816
+ agents: new Set,
50817
+ commands: new Set,
50818
+ skills: new Set,
50819
+ config: new Set,
50820
+ rules: new Set
50821
+ };
50822
+ for (const result of results) {
50823
+ const itemKey = result.itemName || result.path || `${result.provider}`;
50824
+ if (result.portableType === "agent")
50825
+ sets.agents.add(itemKey);
50826
+ else if (result.portableType === "command")
50827
+ sets.commands.add(itemKey);
50828
+ else if (result.portableType === "skill")
50829
+ sets.skills.add(itemKey);
50830
+ else if (result.portableType === "config")
50831
+ sets.config.add(itemKey);
50832
+ else if (result.portableType === "rules")
50833
+ sets.rules.add(itemKey);
50834
+ }
50835
+ return {
50836
+ agents: sets.agents.size,
50837
+ commands: sets.commands.size,
50838
+ skills: sets.skills.size,
50839
+ config: sets.config.size,
50840
+ rules: sets.rules.size
50841
+ };
50842
+ }
50843
+ function toExecutionCounts(results) {
50844
+ let installed = 0;
50845
+ let skipped = 0;
50846
+ let failed = 0;
50847
+ for (const result of results) {
50848
+ if (!result.success) {
50849
+ failed += 1;
50850
+ continue;
50851
+ }
50852
+ if (result.skipped) {
50853
+ skipped += 1;
50854
+ continue;
50855
+ }
50856
+ installed += 1;
50857
+ }
50858
+ return { installed, skipped, failed };
50859
+ }
50860
+ function compareSortValues(a3, b3) {
50861
+ if (a3 === b3)
50862
+ return 0;
50863
+ return a3 < b3 ? -1 : 1;
50864
+ }
50865
+ function sortPortableInstallResults(results) {
50866
+ return [...results].sort((left, right) => {
50867
+ const byType = compareSortValues(left.portableType || "", right.portableType || "");
50868
+ if (byType !== 0)
50869
+ return byType;
50870
+ const byItem = compareSortValues(left.itemName || "", right.itemName || "");
50871
+ if (byItem !== 0)
50872
+ return byItem;
50873
+ const byProvider = compareSortValues(left.provider || "", right.provider || "");
50874
+ if (byProvider !== 0)
50875
+ return byProvider;
50876
+ const byPath = compareSortValues(left.path || "", right.path || "");
50877
+ if (byPath !== 0)
50878
+ return byPath;
50879
+ const leftSuccessRank = left.success ? 0 : 1;
50880
+ const rightSuccessRank = right.success ? 0 : 1;
50881
+ if (leftSuccessRank !== rightSuccessRank) {
50882
+ return leftSuccessRank - rightSuccessRank;
50883
+ }
50884
+ const leftSkippedRank = left.skipped ? 1 : 0;
50885
+ const rightSkippedRank = right.skipped ? 1 : 0;
50886
+ if (leftSkippedRank !== rightSkippedRank) {
50887
+ return leftSkippedRank - rightSkippedRank;
50888
+ }
50889
+ return compareSortValues(left.error || "", right.error || "");
50890
+ });
50891
+ }
50892
+ function tagResults(results, portableType, itemName) {
50893
+ const singularType = PLURAL_TO_SINGULAR[portableType];
50894
+ for (const result of results) {
50895
+ result.portableType = singularType;
50896
+ if (itemName) {
50897
+ result.itemName = itemName;
50898
+ } else {
50899
+ const pathSegments = result.path.replace(/\\/g, "/").split("/");
50900
+ const lastSegment = pathSegments[pathSegments.length - 1] || "";
50901
+ result.itemName = lastSegment.replace(/\.[^.]+$/, "") || lastSegment;
50902
+ }
50903
+ }
50904
+ }
50691
50905
  async function discoverMigrationItems(include, configSource) {
50692
50906
  const agentsSource = include.agents ? getAgentSourcePath() : null;
50693
50907
  const commandsSource = include.commands ? getCommandSourcePath() : null;
@@ -50939,11 +51153,26 @@ function registerMigrationRoutes(app) {
50939
51153
  providerConfigs
50940
51154
  };
50941
51155
  const plan = reconcile(input);
50942
- res.status(200).json({ plan });
51156
+ const planWithMeta = {
51157
+ ...plan,
51158
+ meta: {
51159
+ include,
51160
+ providers: selectedProviders,
51161
+ source: configSource,
51162
+ items: {
51163
+ agents: discovered.agents.map((item) => item.name),
51164
+ commands: discovered.commands.map((item) => item.name),
51165
+ skills: discovered.skills.map((item) => item.name),
51166
+ config: discovered.configItem ? [discovered.configItem.name] : [],
51167
+ rules: discovered.ruleItems.map((item) => item.name)
51168
+ }
51169
+ }
51170
+ };
51171
+ res.status(200).json({ plan: planWithMeta });
50943
51172
  } catch (error) {
50944
51173
  res.status(500).json({
50945
51174
  error: "Failed to compute reconcile plan",
50946
- message: error instanceof Error ? error.message : "Unknown error"
51175
+ message: sanitizeUntrusted(error, 260)
50947
51176
  });
50948
51177
  }
50949
51178
  });
@@ -50969,7 +51198,8 @@ function registerMigrationRoutes(app) {
50969
51198
  for (const action of plan.actions) {
50970
51199
  if (action.action === "conflict") {
50971
51200
  const key = getConflictKey(action);
50972
- const resolution = resolutionsMap.get(key);
51201
+ const legacyKey = getLegacyConflictKey(action);
51202
+ const resolution = resolutionsMap.get(key) || resolutionsMap.get(legacyKey);
50973
51203
  if (!resolution) {
50974
51204
  res.status(409).json({
50975
51205
  error: `Unresolved conflict: ${action.provider}/${action.type}/${action.item}`
@@ -50988,14 +51218,9 @@ function registerMigrationRoutes(app) {
50988
51218
  }
50989
51219
  const execActions = plan.actions.filter(shouldExecuteAction);
50990
51220
  const deleteActions = plan.actions.filter((a3) => a3.action === "delete");
50991
- const includeAll = {
50992
- agents: true,
50993
- commands: true,
50994
- skills: true,
50995
- config: true,
50996
- rules: true
50997
- };
50998
- const discovered2 = await discoverMigrationItems(includeAll);
51221
+ const includeFromPlan = getIncludeFromPlan(plan);
51222
+ const configSourceFromPlan = getConfigSourceFromPlan(plan);
51223
+ const discovered2 = await discoverMigrationItems(includeFromPlan, configSourceFromPlan);
50999
51224
  const agentByName = new Map(discovered2.agents.map((item) => [item.name, item]));
51000
51225
  const commandByName = new Map(discovered2.commands.map((item) => [item.name, item]));
51001
51226
  const skillByName = new Map(discovered2.skills.map((item) => [item.name, item]));
@@ -51005,57 +51230,91 @@ function registerMigrationRoutes(app) {
51005
51230
  for (const action of execActions) {
51006
51231
  const provider = action.provider;
51007
51232
  const installOpts = { global: action.global };
51233
+ const actionType = action.type;
51234
+ if (!providerSupportsType(provider, actionType)) {
51235
+ allResults.push(createSkippedActionResult(action, `Provider ${provider} does not support ${action.type}`));
51236
+ continue;
51237
+ }
51008
51238
  if (action.type === "agent") {
51009
51239
  const item = agentByName.get(action.item);
51010
- if (!item || !getProvidersSupporting("agents").includes(provider))
51240
+ if (!item) {
51241
+ allResults.push(createSkippedActionResult(action, `Source agent "${action.item}" not found`));
51011
51242
  continue;
51012
- allResults.push(...await installPortableItems([item], [provider], "agent", installOpts));
51243
+ }
51244
+ const batch = await installPortableItems([item], [provider], "agent", installOpts);
51245
+ tagResults(batch, "agents", action.item);
51246
+ allResults.push(...batch);
51013
51247
  } else if (action.type === "command") {
51014
51248
  const item = commandByName.get(action.item);
51015
- if (!item || !getProvidersSupporting("commands").includes(provider))
51249
+ if (!item) {
51250
+ allResults.push(createSkippedActionResult(action, `Source command "${action.item}" not found`));
51016
51251
  continue;
51017
- allResults.push(...await installPortableItems([item], [provider], "command", installOpts));
51252
+ }
51253
+ const batch = await installPortableItems([item], [provider], "command", installOpts);
51254
+ tagResults(batch, "commands", action.item);
51255
+ allResults.push(...batch);
51018
51256
  } else if (action.type === "skill") {
51019
51257
  const item = skillByName.get(action.item);
51020
- if (!item || !getProvidersSupporting("skills").includes(provider))
51258
+ if (!item) {
51259
+ allResults.push(createSkippedActionResult(action, `Source skill "${action.item}" not found`));
51021
51260
  continue;
51022
- allResults.push(...await installSkillDirectories([item], [provider], installOpts));
51261
+ }
51262
+ const batch = await installSkillDirectories([item], [provider], installOpts);
51263
+ tagResults(batch, "skills", action.item);
51264
+ allResults.push(...batch);
51023
51265
  } else if (action.type === "config") {
51024
51266
  const item = configByName.get(action.item);
51025
- if (!item || !getProvidersSupporting("config").includes(provider))
51267
+ if (!item) {
51268
+ allResults.push(createSkippedActionResult(action, `Source config "${action.item}" not found`));
51026
51269
  continue;
51027
- allResults.push(...await installPortableItems([item], [provider], "config", installOpts));
51270
+ }
51271
+ const batch = await installPortableItems([item], [provider], "config", installOpts);
51272
+ tagResults(batch, "config", action.item);
51273
+ allResults.push(...batch);
51028
51274
  } else if (action.type === "rules") {
51029
51275
  const item = ruleByName.get(action.item);
51030
- if (!item || !getProvidersSupporting("rules").includes(provider))
51276
+ if (!item) {
51277
+ allResults.push(createSkippedActionResult(action, `Source rule "${action.item}" not found`));
51031
51278
  continue;
51032
- allResults.push(...await installPortableItems([item], [provider], "rules", installOpts));
51279
+ }
51280
+ const batch = await installPortableItems([item], [provider], "rules", installOpts);
51281
+ tagResults(batch, "rules", action.item);
51282
+ allResults.push(...batch);
51033
51283
  }
51034
51284
  }
51035
51285
  const plannedSkillActions = execActions.filter((a3) => a3.type === "skill").length;
51036
- if (discovered2.skills.length > 0 && plannedSkillActions === 0) {
51037
- const planProviders = [
51038
- ...new Set(plan.actions.map((a3) => a3.provider))
51039
- ];
51040
- const skillProviders = planProviders.filter((pv) => getProvidersSupporting("skills").includes(pv));
51286
+ if (includeFromPlan.skills && discovered2.skills.length > 0 && plannedSkillActions === 0) {
51287
+ const allowedSkillNames = getPlanItemsByType(plan, "skills");
51288
+ const plannedSkills = allowedSkillNames.length > 0 ? discovered2.skills.filter((skill) => allowedSkillNames.includes(skill.name)) : discovered2.skills;
51289
+ const planProviders = getProvidersFromPlan(plan);
51290
+ const skillProviders = planProviders.filter((provider) => providerSupportsType(provider, "skill"));
51041
51291
  if (skillProviders.length > 0) {
51042
51292
  const globalFromPlan = plan.actions[0]?.global ?? false;
51043
- allResults.push(...await installSkillDirectories(discovered2.skills, skillProviders, {
51044
- global: globalFromPlan
51045
- }));
51293
+ for (const skill of plannedSkills) {
51294
+ const batch = await installSkillDirectories([skill], skillProviders, {
51295
+ global: globalFromPlan
51296
+ });
51297
+ tagResults(batch, "skills", skill.name);
51298
+ allResults.push(...batch);
51299
+ }
51046
51300
  }
51047
51301
  }
51048
51302
  const writtenPaths = new Set(allResults.filter((r2) => r2.success && !r2.skipped && r2.path.length > 0).map((r2) => resolve8(r2.path)));
51049
51303
  for (const deleteAction of deleteActions) {
51050
- allResults.push(await executePlanDeleteAction(deleteAction, { preservePaths: writtenPaths }));
51304
+ const deleteResult = await executePlanDeleteAction(deleteAction, {
51305
+ preservePaths: writtenPaths
51306
+ });
51307
+ deleteResult.portableType = deleteAction.type;
51308
+ deleteResult.itemName = deleteAction.item;
51309
+ allResults.push(deleteResult);
51051
51310
  }
51052
- const installed2 = allResults.filter((r2) => r2.success && !r2.skipped).length;
51053
- const skipped2 = allResults.filter((r2) => r2.skipped).length;
51054
- const failed2 = allResults.filter((r2) => !r2.success).length;
51311
+ const sortedResults2 = sortPortableInstallResults(allResults);
51312
+ const counts2 = toExecutionCounts(sortedResults2);
51055
51313
  res.status(200).json({
51056
- results: allResults,
51314
+ results: sortedResults2,
51057
51315
  warnings: [],
51058
- counts: { installed: installed2, skipped: skipped2, failed: failed2 }
51316
+ counts: counts2,
51317
+ discovery: toDiscoveryCounts(sortedResults2)
51059
51318
  });
51060
51319
  return;
51061
51320
  }
@@ -51126,59 +51385,82 @@ function registerMigrationRoutes(app) {
51126
51385
  if (include.agents && discovered.agents.length > 0) {
51127
51386
  const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("agents").includes(provider));
51128
51387
  if (providersForType.length > 0) {
51129
- results.push(...await installPortableItems(discovered.agents, providersForType, "agent", installOptions));
51388
+ const batches = await Promise.all(discovered.agents.map(async (agent) => {
51389
+ const batch = await installPortableItems([agent], providersForType, "agent", installOptions);
51390
+ tagResults(batch, "agents", agent.name);
51391
+ return batch;
51392
+ }));
51393
+ for (const batch of batches) {
51394
+ results.push(...batch);
51395
+ }
51130
51396
  }
51131
51397
  }
51132
51398
  if (include.commands && discovered.commands.length > 0) {
51133
51399
  const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("commands").includes(provider));
51134
51400
  if (providersForType.length > 0) {
51135
- results.push(...await installPortableItems(discovered.commands, providersForType, "command", installOptions));
51401
+ const batches = await Promise.all(discovered.commands.map(async (command) => {
51402
+ const batch = await installPortableItems([command], providersForType, "command", installOptions);
51403
+ tagResults(batch, "commands", command.name);
51404
+ return batch;
51405
+ }));
51406
+ for (const batch of batches) {
51407
+ results.push(...batch);
51408
+ }
51136
51409
  }
51137
51410
  }
51138
51411
  if (include.skills && discovered.skills.length > 0) {
51139
51412
  const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("skills").includes(provider));
51140
51413
  if (providersForType.length > 0) {
51141
- results.push(...await installSkillDirectories(discovered.skills, providersForType, installOptions));
51414
+ const batches = await Promise.all(discovered.skills.map(async (skill) => {
51415
+ const batch = await installSkillDirectories([skill], providersForType, installOptions);
51416
+ tagResults(batch, "skills", skill.name);
51417
+ return batch;
51418
+ }));
51419
+ for (const batch of batches) {
51420
+ results.push(...batch);
51421
+ }
51142
51422
  }
51143
51423
  }
51144
51424
  if (include.config && discovered.configItem) {
51145
51425
  const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("config").includes(provider));
51146
51426
  if (providersForType.length > 0) {
51147
- results.push(...await installPortableItems([discovered.configItem], providersForType, "config", installOptions));
51427
+ const batch = await installPortableItems([discovered.configItem], providersForType, "config", installOptions);
51428
+ tagResults(batch, "config");
51429
+ results.push(...batch);
51148
51430
  }
51149
51431
  }
51150
51432
  if (include.rules && discovered.ruleItems.length > 0) {
51151
51433
  const providersForType = selectedProviders.filter((provider) => getProvidersSupporting("rules").includes(provider));
51152
51434
  if (providersForType.length > 0) {
51153
- results.push(...await installPortableItems(discovered.ruleItems, providersForType, "rules", installOptions));
51435
+ const batches = await Promise.all(discovered.ruleItems.map(async (rule) => {
51436
+ const batch = await installPortableItems([rule], providersForType, "rules", installOptions);
51437
+ tagResults(batch, "rules", rule.name);
51438
+ return batch;
51439
+ }));
51440
+ for (const batch of batches) {
51441
+ results.push(...batch);
51442
+ }
51154
51443
  }
51155
51444
  }
51156
- const installed = results.filter((item) => item.success && !item.skipped).length;
51157
- const skipped = results.filter((item) => item.skipped).length;
51158
- const failed = results.filter((item) => !item.success).length;
51445
+ const sortedResults = sortPortableInstallResults(results);
51446
+ const counts = toExecutionCounts(sortedResults);
51159
51447
  res.status(200).json({
51160
- results,
51448
+ results: sortedResults,
51161
51449
  warnings,
51162
51450
  effectiveGlobal,
51163
- counts: { installed, skipped, failed },
51164
- discovery: {
51165
- agents: discovered.agents.length,
51166
- commands: discovered.commands.length,
51167
- skills: discovered.skills.length,
51168
- config: discovered.configItem ? 1 : 0,
51169
- rules: discovered.ruleItems.length
51170
- },
51451
+ counts,
51452
+ discovery: toDiscoveryCounts(sortedResults),
51171
51453
  unsupportedByType
51172
51454
  });
51173
51455
  } catch (error) {
51174
51456
  res.status(500).json({
51175
51457
  error: "Failed to execute migration",
51176
- message: error instanceof Error ? error.message : "Unknown error"
51458
+ message: sanitizeUntrusted(error, 260)
51177
51459
  });
51178
51460
  }
51179
51461
  });
51180
51462
  }
51181
- var MIGRATION_TYPES, MAX_PROVIDER_COUNT = 20, MAX_PLAN_ACTIONS = 5000, ALLOWED_CONFIG_SOURCE_KEYS, CONFLICT_RESOLUTION_SCHEMA, RECONCILE_ACTION_SCHEMA, RECONCILE_PLAN_SCHEMA, PLAN_EXECUTE_PAYLOAD_SCHEMA;
51463
+ var MIGRATION_TYPES, MAX_PROVIDER_COUNT = 20, MAX_PLAN_ACTIONS = 5000, ALLOWED_CONFIG_SOURCE_KEYS, CONFLICT_RESOLUTION_SCHEMA, RECONCILE_ACTION_SCHEMA, RECONCILE_PLAN_SCHEMA, PLAN_EXECUTE_PAYLOAD_SCHEMA, PLURAL_TO_SINGULAR;
51182
51464
  var init_migration_routes = __esm(() => {
51183
51465
  init_agents_discovery();
51184
51466
  init_commands_discovery();
@@ -51242,6 +51524,13 @@ var init_migration_routes = __esm(() => {
51242
51524
  plan: RECONCILE_PLAN_SCHEMA,
51243
51525
  resolutions: exports_external.record(CONFLICT_RESOLUTION_SCHEMA).optional().default({})
51244
51526
  }).passthrough();
51527
+ PLURAL_TO_SINGULAR = {
51528
+ agents: "agent",
51529
+ commands: "command",
51530
+ skills: "skill",
51531
+ config: "config",
51532
+ rules: "rules"
51533
+ };
51245
51534
  });
51246
51535
 
51247
51536
  // src/services/claude-data/types.ts
@@ -54025,7 +54314,7 @@ var package_default;
54025
54314
  var init_package = __esm(() => {
54026
54315
  package_default = {
54027
54316
  name: "claudekit-cli",
54028
- version: "3.35.0-dev.29",
54317
+ version: "3.35.0-dev.30",
54029
54318
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
54030
54319
  type: "module",
54031
54320
  repository: {
@@ -59418,7 +59707,7 @@ var init_websocket_manager = __esm(() => {
59418
59707
 
59419
59708
  // src/domains/web-server/server.ts
59420
59709
  import { createServer } from "node:http";
59421
- import { createConnection } from "node:net";
59710
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
59422
59711
  async function createAppServer(options2 = {}) {
59423
59712
  const { port: preferredPort, openBrowser = true, devMode = false } = options2;
59424
59713
  const port = await getPorts({ port: preferredPort || [3456, 3457, 3458, 3459, 3460] });
@@ -59426,76 +59715,89 @@ async function createAppServer(options2 = {}) {
59426
59715
  app.use(import_express2.default.json({ limit: "10mb" }));
59427
59716
  app.use(corsMiddleware);
59428
59717
  registerRoutes(app);
59718
+ const server = createServer(app);
59719
+ server.setTimeout(30000);
59720
+ server.keepAliveTimeout = 65000;
59721
+ server.headersTimeout = 66000;
59429
59722
  if (devMode) {
59430
- await setupViteDevServer(app);
59723
+ await setupViteDevServer(app, server, { failFast: true });
59431
59724
  } else {
59432
59725
  serveStatic(app);
59433
59726
  }
59434
59727
  app.use(errorHandler);
59435
- const server = createServer(app);
59436
- server.setTimeout(30000);
59437
- server.keepAliveTimeout = 65000;
59438
- server.headersTimeout = 66000;
59439
- const wsManager = new WebSocketManager(server);
59440
- const fileWatcher = new FileWatcher({ wsManager });
59441
- fileWatcher.start();
59442
- const portWasInUse = await isPortInUse(port);
59443
- await new Promise((resolve11, reject) => {
59444
- server.listen(port, () => resolve11());
59445
- server.on("error", reject);
59446
- });
59447
- logger.debug(`Server listening on port ${port}`);
59448
- if (openBrowser && !portWasInUse) {
59449
- try {
59450
- await open_default(`http://localhost:${port}`);
59451
- } catch (err) {
59452
- logger.warning(`Failed to open browser: ${err instanceof Error ? err.message : err}`);
59453
- logger.info(`Open http://localhost:${port} manually`);
59728
+ let wsManager = null;
59729
+ let fileWatcher = null;
59730
+ try {
59731
+ wsManager = new WebSocketManager(server);
59732
+ fileWatcher = new FileWatcher({ wsManager });
59733
+ fileWatcher.start();
59734
+ await new Promise((resolve11, reject) => {
59735
+ const onListening = () => {
59736
+ server.off("error", onError);
59737
+ resolve11();
59738
+ };
59739
+ const onError = (error) => {
59740
+ server.off("listening", onListening);
59741
+ reject(error);
59742
+ };
59743
+ server.once("listening", onListening);
59744
+ server.once("error", onError);
59745
+ server.listen(port);
59746
+ });
59747
+ logger.debug(`Server listening on port ${port}`);
59748
+ if (openBrowser) {
59749
+ try {
59750
+ await open_default(`http://localhost:${port}`);
59751
+ } catch (err) {
59752
+ logger.warning(`Failed to open browser: ${err instanceof Error ? err.message : err}`);
59753
+ logger.info(`Open http://localhost:${port} manually`);
59754
+ }
59454
59755
  }
59756
+ } catch (error) {
59757
+ fileWatcher?.stop();
59758
+ wsManager?.close();
59759
+ await closeHttpServer(server);
59760
+ throw error;
59455
59761
  }
59456
59762
  return {
59457
59763
  port,
59458
59764
  server,
59459
59765
  close: async () => {
59460
- fileWatcher.stop();
59461
- wsManager.close();
59462
- return new Promise((resolve11) => {
59463
- if (!server.listening) {
59464
- resolve11();
59465
- return;
59466
- }
59467
- server.close((err) => {
59468
- if (err) {
59469
- logger.debug(`Server close error: ${err.message}`);
59470
- }
59471
- resolve11();
59472
- });
59473
- });
59766
+ fileWatcher?.stop();
59767
+ wsManager?.close();
59768
+ await closeHttpServer(server);
59474
59769
  }
59475
59770
  };
59476
59771
  }
59477
- function isPortInUse(port) {
59478
- return new Promise((resolve11) => {
59479
- const socket = createConnection({ port, host: "127.0.0.1" });
59480
- socket.once("connect", () => {
59481
- socket.destroy();
59482
- resolve11(true);
59483
- });
59484
- socket.once("error", () => {
59485
- socket.destroy();
59486
- resolve11(false);
59772
+ async function closeHttpServer(server) {
59773
+ await new Promise((resolve11) => {
59774
+ if (!server.listening) {
59775
+ resolve11();
59776
+ return;
59777
+ }
59778
+ server.close((err) => {
59779
+ if (err) {
59780
+ logger.debug(`Server close error: ${err.message}`);
59781
+ }
59782
+ resolve11();
59487
59783
  });
59488
59784
  });
59489
59785
  }
59490
- async function setupViteDevServer(app) {
59491
- const uiRoot = new URL("../../ui", import.meta.url).pathname;
59786
+ function resolveUiRootPath() {
59787
+ return fileURLToPath3(new URL("../../ui", import.meta.url));
59788
+ }
59789
+ async function setupViteDevServer(app, httpServer, options2) {
59790
+ const uiRoot = resolveUiRootPath();
59492
59791
  try {
59493
59792
  const viteEntry = `${uiRoot}/node_modules/vite/dist/node/index.js`;
59494
59793
  const { createServer: createViteServer } = await import(viteEntry);
59495
59794
  const vite = await createViteServer({
59496
59795
  configFile: `${uiRoot}/vite.config.ts`,
59497
59796
  root: uiRoot,
59498
- server: { middlewareMode: true },
59797
+ server: {
59798
+ middlewareMode: true,
59799
+ hmr: { server: httpServer }
59800
+ },
59499
59801
  appType: "spa"
59500
59802
  });
59501
59803
  app.use(vite.middlewares);
@@ -59503,8 +59805,7 @@ async function setupViteDevServer(app) {
59503
59805
  } catch (error) {
59504
59806
  const msg = error instanceof Error ? error.message : String(error);
59505
59807
  console.error(`[dashboard] Vite setup failed: ${msg}`);
59506
- const isDev = true;
59507
- if (isDev) {
59808
+ if (options2.failFast) {
59508
59809
  throw error;
59509
59810
  }
59510
59811
  serveStatic(app);
@@ -71541,13 +71842,13 @@ import { execSync as execSync3, spawnSync as spawnSync5 } from "node:child_proce
71541
71842
  import { readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
71542
71843
  import { tmpdir as tmpdir3 } from "node:os";
71543
71844
  import { dirname as dirname14, join as join56 } from "node:path";
71544
- import { fileURLToPath as fileURLToPath3 } from "node:url";
71845
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
71545
71846
  init_environment();
71546
71847
  init_logger();
71547
71848
  init_dist2();
71548
71849
  function getCliVersion4() {
71549
71850
  try {
71550
- const __dirname4 = dirname14(fileURLToPath3(import.meta.url));
71851
+ const __dirname4 = dirname14(fileURLToPath4(import.meta.url));
71551
71852
  const pkgPath = join56(__dirname4, "../../../package.json");
71552
71853
  const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
71553
71854
  return pkg.version || "unknown";