@drunkcoding/auto-claude 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +68 -2
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2276,6 +2276,21 @@ function activeKinds(catalog, repoRoot) {
2276
2276
  function groupsForKind(catalog, kind) {
2277
2277
  return catalog.groups.filter((g) => pageOf(g) === kind);
2278
2278
  }
2279
+ function findDefaultConflicts(catalog, installedIds) {
2280
+ const out = [];
2281
+ for (const g of catalog.groups) {
2282
+ if (g.kind !== "pick-one") continue;
2283
+ const defaults = g.items.filter((i) => i.default === true);
2284
+ if (defaults.length !== 1) continue;
2285
+ const defaultItem = defaults[0];
2286
+ const driftedSiblings = g.items.filter(
2287
+ (i) => i.id !== defaultItem.id && installedIds.has(i.id)
2288
+ );
2289
+ if (driftedSiblings.length === 0) continue;
2290
+ out.push({ groupId: g.id, groupName: g.name, defaultItem, driftedSiblings });
2291
+ }
2292
+ return out;
2293
+ }
2279
2294
 
2280
2295
  // src/ui/KindPageBreadcrumb.tsx
2281
2296
  import { Box as Box8, Text as Text8 } from "ink";
@@ -2881,7 +2896,7 @@ function formatRow(item, state) {
2881
2896
  return ` ${kindGlyph} ${id}${sep}${status}`;
2882
2897
  }
2883
2898
  async function runDefaultInstall(deps) {
2884
- const result = { ok: 0, failed: 0, skipped: 0 };
2899
+ const result = { ok: 0, failed: 0, skipped: 0, conflicts: 0 };
2885
2900
  if (deps.items.length === 0) {
2886
2901
  deps.log("default: nothing to do (no items flagged default: true)");
2887
2902
  return result;
@@ -2889,6 +2904,53 @@ async function runDefaultInstall(deps) {
2889
2904
  const ordered = orderForInstall(deps.items);
2890
2905
  const states = await deps.detect(ordered);
2891
2906
  const installedIds = new Set(states.filter((s) => s.installed).map((s) => s.itemId));
2907
+ const blockedDefaults = /* @__PURE__ */ new Set();
2908
+ const swapUninstalls = [];
2909
+ const swapBatchDefaults = /* @__PURE__ */ new Set();
2910
+ if (deps.catalog) {
2911
+ const conflicts = findDefaultConflicts(deps.catalog, installedIds);
2912
+ for (const c of conflicts) {
2913
+ for (const sib of c.driftedSiblings) {
2914
+ if (isShellItem(sib) && sib.uninstall) {
2915
+ swapUninstalls.push(sib);
2916
+ swapBatchDefaults.add(c.defaultItem.id);
2917
+ deps.log(paint(
2918
+ `${GLYPHS.info} conflict in "${c.groupName}": ${sib.id} drift from default ${c.defaultItem.id}; uninstalling sibling`,
2919
+ "warn"
2920
+ ));
2921
+ } else {
2922
+ blockedDefaults.add(c.defaultItem.id);
2923
+ deps.log(paint(
2924
+ `${GLYPHS.info} conflict in "${c.groupName}": ${sib.id} installed but has no uninstall command; skipping ${c.defaultItem.id}`,
2925
+ "warn"
2926
+ ));
2927
+ result.conflicts++;
2928
+ }
2929
+ }
2930
+ }
2931
+ }
2932
+ if (swapUninstalls.length > 0) {
2933
+ const wrappedOnEventForSwap = (e) => {
2934
+ if (e.type === "post-prompt") return;
2935
+ deps.onEvent(e);
2936
+ };
2937
+ try {
2938
+ await executeInstall(
2939
+ { selected: [], uninstall: swapUninstalls, scope: "global", repoRoot: deps.repoRoot ?? null },
2940
+ {
2941
+ run: deps.run,
2942
+ onEvent: wrappedOnEventForSwap,
2943
+ dryRun: !!deps.dryRun,
2944
+ record: deps.dryRun ? (cmd) => deps.log(paint(` $ ${cmd}`, "dim")) : void 0
2945
+ }
2946
+ );
2947
+ for (const it of swapUninstalls) installedIds.delete(it.id);
2948
+ } catch (e) {
2949
+ deps.err(paint(`${GLYPHS.fail} swap-uninstall failed: ${e.message}`, "fail"));
2950
+ result.failed++;
2951
+ for (const id of swapBatchDefaults) blockedDefaults.add(id);
2952
+ }
2953
+ }
2892
2954
  for (const item of ordered) {
2893
2955
  if (item.kind === "mcp" && !deps.repoRoot) {
2894
2956
  deps.log(paint(`${GLYPHS.info} ${item.id}: skipped (MCP items require a project repo)`, "dim"));
@@ -2901,6 +2963,9 @@ async function runDefaultInstall(deps) {
2901
2963
  result.ok++;
2902
2964
  continue;
2903
2965
  }
2966
+ if (blockedDefaults.has(item.id)) {
2967
+ continue;
2968
+ }
2904
2969
  deps.log(paint(`${GLYPHS.arrow} ${item.id}`, "cursor"));
2905
2970
  const wrappedOnEvent = (e) => {
2906
2971
  if (e.type === "post-prompt") {
@@ -2928,7 +2993,7 @@ async function runDefaultInstall(deps) {
2928
2993
  }
2929
2994
  const summaryColor = result.failed > 0 ? "fail" : "ok";
2930
2995
  const dryNote = deps.dryRun ? " [dry-run]" : "";
2931
- deps.log(paint(`default${dryNote}: ${result.ok} ok, ${result.failed} failed, ${result.skipped} skipped`, summaryColor));
2996
+ deps.log(paint(`default${dryNote}: ${result.ok} ok, ${result.failed} failed, ${result.skipped} skipped, ${result.conflicts} conflicts`, summaryColor));
2932
2997
  return result;
2933
2998
  }
2934
2999
  async function runDefault(opts = {}) {
@@ -2949,6 +3014,7 @@ async function runDefault(opts = {}) {
2949
3014
  };
2950
3015
  const result = await runDefaultInstall({
2951
3016
  items: defaults,
3017
+ catalog,
2952
3018
  repoRoot,
2953
3019
  detect: (items) => detectStates(items, void 0, repoRoot),
2954
3020
  run: richRun,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drunkcoding/auto-claude",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Curated installer for Claude Code tools and plugins",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.33.4",