agents-inc 0.153.0 → 0.154.0

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 (116) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/{chunk-EFU6P3B7.js → chunk-2IMYK4WN.js} +3 -3
  3. package/dist/{chunk-U2YSGBHA.js → chunk-4VCWL2IG.js} +33 -16
  4. package/dist/chunk-4VCWL2IG.js.map +1 -0
  5. package/dist/{chunk-ORJ5Y222.js → chunk-5MFJ24VM.js} +90 -24
  6. package/dist/chunk-5MFJ24VM.js.map +1 -0
  7. package/dist/{chunk-TY6CAOL7.js → chunk-7VZV4O6B.js} +3 -3
  8. package/dist/{chunk-4VYALFQZ.js → chunk-AKQ5QISO.js} +6 -6
  9. package/dist/{chunk-U2DNAHFE.js → chunk-AURY6RT6.js} +3 -3
  10. package/dist/{chunk-ACKC577F.js → chunk-B66SC72V.js} +3 -3
  11. package/dist/{chunk-WDAO3RUY.js → chunk-BZ4CZBOM.js} +3 -3
  12. package/dist/{chunk-NXQAY5U7.js → chunk-CBF4ZYV3.js} +4556 -4457
  13. package/dist/chunk-CBF4ZYV3.js.map +1 -0
  14. package/dist/{chunk-JFAUQDZM.js → chunk-CHNA5RVS.js} +3 -3
  15. package/dist/{chunk-2HC2SNRP.js → chunk-DRKSYJZ2.js} +1 -5
  16. package/dist/chunk-DRKSYJZ2.js.map +1 -0
  17. package/dist/{chunk-X5XJ6WKO.js → chunk-FMYHWKGG.js} +45 -4
  18. package/dist/chunk-FMYHWKGG.js.map +1 -0
  19. package/dist/{chunk-K7PJDWER.js → chunk-GUDGCFSF.js} +6 -6
  20. package/dist/{chunk-35VOK7XE.js → chunk-IPJOMAWC.js} +4355 -4355
  21. package/dist/{chunk-35VOK7XE.js.map → chunk-IPJOMAWC.js.map} +1 -1
  22. package/dist/{chunk-VGEBYCQZ.js → chunk-IXEDSKMH.js} +4 -15
  23. package/dist/chunk-IXEDSKMH.js.map +1 -0
  24. package/dist/{chunk-ZNDLUWWD.js → chunk-LA3JPESW.js} +3 -3
  25. package/dist/{chunk-M5HSTNYU.js → chunk-MJFIO5SX.js} +5 -23
  26. package/dist/chunk-MJFIO5SX.js.map +1 -0
  27. package/dist/{chunk-VECFAKM5.js → chunk-NFH6SA62.js} +4 -4
  28. package/dist/{chunk-R4SEU3DF.js → chunk-NKCY2ULI.js} +2 -2
  29. package/dist/{chunk-IO4VEW5U.js → chunk-ONWEOS77.js} +2 -2
  30. package/dist/{chunk-FRWKCE6R.js → chunk-PRJD5MMQ.js} +3 -3
  31. package/dist/{chunk-HEBPKK5L.js → chunk-QQTYMW7N.js} +11 -23
  32. package/dist/chunk-QQTYMW7N.js.map +1 -0
  33. package/dist/{chunk-KET3EVGX.js → chunk-QUDQTO3O.js} +3 -3
  34. package/dist/{chunk-BMGBA6HJ.js → chunk-R7JV22QK.js} +12 -12
  35. package/dist/{chunk-FIHTAFST.js → chunk-TUQF577Z.js} +30 -30
  36. package/dist/{chunk-FIHTAFST.js.map → chunk-TUQF577Z.js.map} +1 -1
  37. package/dist/{chunk-NXGMM5YN.js → chunk-UW44KSYL.js} +3 -3
  38. package/dist/{chunk-WG6V6VJV.js → chunk-WRRP47PY.js} +2 -2
  39. package/dist/{chunk-F7Z5I6GU.js → chunk-XMEIVWAS.js} +4 -4
  40. package/dist/{chunk-REKOWTIB.js → chunk-ZU6DAR4S.js} +42 -8
  41. package/dist/chunk-ZU6DAR4S.js.map +1 -0
  42. package/dist/commands/build/marketplace.js +6 -5
  43. package/dist/commands/build/marketplace.js.map +1 -1
  44. package/dist/commands/build/plugins.js +6 -6
  45. package/dist/commands/compile.js +48 -10
  46. package/dist/commands/compile.js.map +1 -1
  47. package/dist/commands/doctor.js +10 -10
  48. package/dist/commands/edit.js +93 -59
  49. package/dist/commands/edit.js.map +1 -1
  50. package/dist/commands/eject.js +10 -10
  51. package/dist/commands/init.js +29 -29
  52. package/dist/commands/list.js +7 -7
  53. package/dist/commands/search.js +29 -21
  54. package/dist/commands/search.js.map +1 -1
  55. package/dist/commands/uninstall.js +198 -147
  56. package/dist/commands/uninstall.js.map +1 -1
  57. package/dist/commands/update.js +5 -5
  58. package/dist/components/wizard/category-grid.js +3 -3
  59. package/dist/components/wizard/checkbox-grid.js +2 -2
  60. package/dist/components/wizard/domain-selection.js +8 -8
  61. package/dist/components/wizard/run-wizard-session.js +21 -21
  62. package/dist/components/wizard/skill-agent-summary.js +5 -5
  63. package/dist/components/wizard/source-grid.js +3 -3
  64. package/dist/components/wizard/stack-selection.js +5 -5
  65. package/dist/components/wizard/step-agents.js +8 -8
  66. package/dist/components/wizard/step-build.js +7 -7
  67. package/dist/components/wizard/step-confirm.js +8 -8
  68. package/dist/components/wizard/step-sources.js +7 -7
  69. package/dist/components/wizard/step-stack.js +6 -6
  70. package/dist/components/wizard/summary-panel.js +7 -7
  71. package/dist/components/wizard/wizard-layout.js +9 -9
  72. package/dist/components/wizard/wizard.js +20 -20
  73. package/dist/copy-local-skills-WVHJFRPK.js +14 -0
  74. package/dist/hooks/init.js +29 -29
  75. package/dist/load-agent-defs-5OT54J5M.js +15 -0
  76. package/dist/{loader-4U7UCE2Y.js → loader-JIZDTR4G.js} +2 -2
  77. package/dist/recompile-project-agents-VREEPBDV.js +20 -0
  78. package/dist/{source-loader-ZNSYJJCI.js → source-loader-OE6EJFPU.js} +4 -4
  79. package/dist/stores/wizard-store.js +4 -4
  80. package/package.json +1 -1
  81. package/src/schemas/plugin.schema.json +3 -0
  82. package/dist/chunk-2HC2SNRP.js.map +0 -1
  83. package/dist/chunk-HEBPKK5L.js.map +0 -1
  84. package/dist/chunk-M5HSTNYU.js.map +0 -1
  85. package/dist/chunk-NXQAY5U7.js.map +0 -1
  86. package/dist/chunk-ORJ5Y222.js.map +0 -1
  87. package/dist/chunk-REKOWTIB.js.map +0 -1
  88. package/dist/chunk-U2YSGBHA.js.map +0 -1
  89. package/dist/chunk-VGEBYCQZ.js.map +0 -1
  90. package/dist/chunk-X5XJ6WKO.js.map +0 -1
  91. package/dist/copy-local-skills-KF2RAVD3.js +0 -14
  92. package/dist/load-agent-defs-DGXGBU3Q.js +0 -15
  93. package/dist/recompile-project-agents-CJVBAWDJ.js +0 -20
  94. /package/dist/{chunk-EFU6P3B7.js.map → chunk-2IMYK4WN.js.map} +0 -0
  95. /package/dist/{chunk-TY6CAOL7.js.map → chunk-7VZV4O6B.js.map} +0 -0
  96. /package/dist/{chunk-4VYALFQZ.js.map → chunk-AKQ5QISO.js.map} +0 -0
  97. /package/dist/{chunk-U2DNAHFE.js.map → chunk-AURY6RT6.js.map} +0 -0
  98. /package/dist/{chunk-ACKC577F.js.map → chunk-B66SC72V.js.map} +0 -0
  99. /package/dist/{chunk-WDAO3RUY.js.map → chunk-BZ4CZBOM.js.map} +0 -0
  100. /package/dist/{chunk-JFAUQDZM.js.map → chunk-CHNA5RVS.js.map} +0 -0
  101. /package/dist/{chunk-K7PJDWER.js.map → chunk-GUDGCFSF.js.map} +0 -0
  102. /package/dist/{chunk-ZNDLUWWD.js.map → chunk-LA3JPESW.js.map} +0 -0
  103. /package/dist/{chunk-VECFAKM5.js.map → chunk-NFH6SA62.js.map} +0 -0
  104. /package/dist/{chunk-R4SEU3DF.js.map → chunk-NKCY2ULI.js.map} +0 -0
  105. /package/dist/{chunk-IO4VEW5U.js.map → chunk-ONWEOS77.js.map} +0 -0
  106. /package/dist/{chunk-FRWKCE6R.js.map → chunk-PRJD5MMQ.js.map} +0 -0
  107. /package/dist/{chunk-KET3EVGX.js.map → chunk-QUDQTO3O.js.map} +0 -0
  108. /package/dist/{chunk-BMGBA6HJ.js.map → chunk-R7JV22QK.js.map} +0 -0
  109. /package/dist/{chunk-NXGMM5YN.js.map → chunk-UW44KSYL.js.map} +0 -0
  110. /package/dist/{chunk-WG6V6VJV.js.map → chunk-WRRP47PY.js.map} +0 -0
  111. /package/dist/{chunk-F7Z5I6GU.js.map → chunk-XMEIVWAS.js.map} +0 -0
  112. /package/dist/{copy-local-skills-KF2RAVD3.js.map → copy-local-skills-WVHJFRPK.js.map} +0 -0
  113. /package/dist/{load-agent-defs-DGXGBU3Q.js.map → load-agent-defs-5OT54J5M.js.map} +0 -0
  114. /package/dist/{loader-4U7UCE2Y.js.map → loader-JIZDTR4G.js.map} +0 -0
  115. /package/dist/{recompile-project-agents-CJVBAWDJ.js.map → recompile-project-agents-VREEPBDV.js.map} +0 -0
  116. /package/dist/{source-loader-ZNSYJJCI.js.map → source-loader-OE6EJFPU.js.map} +0 -0
@@ -5,28 +5,31 @@ import {
5
5
  import {
6
6
  promptConfirm
7
7
  } from "../chunk-OJJLYHM3.js";
8
- import "../chunk-F7Z5I6GU.js";
9
- import "../chunk-REKOWTIB.js";
10
- import "../chunk-NXGMM5YN.js";
8
+ import "../chunk-XMEIVWAS.js";
9
+ import "../chunk-ZU6DAR4S.js";
10
+ import "../chunk-UW44KSYL.js";
11
11
  import {
12
12
  loadAgentDefs
13
- } from "../chunk-FRWKCE6R.js";
13
+ } from "../chunk-PRJD5MMQ.js";
14
14
  import {
15
15
  listAgentMdFiles
16
- } from "../chunk-FIHTAFST.js";
16
+ } from "../chunk-TUQF577Z.js";
17
17
  import "../chunk-JFLVEFFP.js";
18
18
  import {
19
19
  BaseCommand,
20
20
  EXIT_CODES
21
- } from "../chunk-X5XJ6WKO.js";
22
- import "../chunk-TY6CAOL7.js";
21
+ } from "../chunk-FMYHWKGG.js";
22
+ import "../chunk-7VZV4O6B.js";
23
23
  import "../chunk-K3O3YQYG.js";
24
24
  import {
25
25
  ConfigLoadError,
26
26
  INFO_MESSAGES,
27
27
  SUCCESS_MESSAGES,
28
+ UNINSTALL_PLAN,
28
29
  buildMarketplacePluginRef,
29
30
  claudePluginUninstallBestEffort,
31
+ compiledAgentsKept,
32
+ compiledAgentsRemoval,
30
33
  getProjectPluginsDir,
31
34
  isClaudeCLIAvailable,
32
35
  isHomeDirectory,
@@ -34,6 +37,7 @@ import {
34
37
  listPluginNames,
35
38
  loadProjectConfigFromDir,
36
39
  loadSkillsMatrixFromSource,
40
+ localSkillsRemoval,
37
41
  mutateGlobal,
38
42
  parseMarketplacePluginRef,
39
43
  propagateGlobalRemoval,
@@ -43,15 +47,16 @@ import {
43
47
  registeredProjectsUpdated,
44
48
  resolveInstallPaths,
45
49
  toClaudePluginScope
46
- } from "../chunk-NXQAY5U7.js";
50
+ } from "../chunk-CBF4ZYV3.js";
47
51
  import {
48
52
  directoryExists,
49
53
  fileExists,
50
54
  getErrorMessage,
51
55
  listDirectories,
52
- remove
53
- } from "../chunk-U2YSGBHA.js";
54
- import "../chunk-35VOK7XE.js";
56
+ remove,
57
+ removeDirIfEmpty
58
+ } from "../chunk-4VCWL2IG.js";
59
+ import "../chunk-IPJOMAWC.js";
55
60
  import "../chunk-VASLW636.js";
56
61
  import {
57
62
  CLAUDE_DIR,
@@ -67,39 +72,104 @@ import "../chunk-VZRO7RYT.js";
67
72
  import "react";
68
73
  import { partition } from "remeda";
69
74
  import path from "path";
70
- import { readdir } from "fs/promises";
71
75
  import { Flags } from "@oclif/core";
72
76
  import { Box, Text, useApp } from "ink";
73
77
  import { jsx, jsxs } from "react/jsx-runtime";
74
78
  function buildRemovalPlan(target) {
75
- const sections = [];
76
- if (target.hasPlugins) {
77
- sections.push({ label: "Plugins:", items: [...target.cliPluginNames] });
78
- }
79
- if (target.hasLocalSkills || target.hasLocalAgents) {
80
- const items = [];
81
- if (target.hasLocalSkills) items.push(`${target.skillsDir}/ (matching sources)`);
82
- if (target.hasLocalAgents) items.push(`${target.agentsDir}/ (CLI-compiled)`);
83
- sections.push({ label: "CLI-managed files:", items });
84
- }
85
- if (target.hasClaudeSrcConfig || target.hasClaudeSrcConfigTypes) {
86
- const items = [];
87
- if (target.hasClaudeSrcConfig) {
88
- items.push(`${target.claudeSrcDir}/${STANDARD_FILES.CONFIG_TS}`);
89
- }
90
- if (target.hasClaudeSrcConfigTypes) {
91
- items.push(`${target.claudeSrcDir}/${STANDARD_FILES.CONFIG_TYPES_TS}`);
79
+ const agents = compiledAgentsEntry(target);
80
+ return {
81
+ entries: [
82
+ ...pluginsEntry(target),
83
+ ...localSkillsEntry(target),
84
+ ...agents,
85
+ ...configManifestEntry(target)
86
+ ],
87
+ kept: keptStatements(target, agents)
88
+ };
89
+ }
90
+ function hasAnythingToRemove(plan) {
91
+ return plan.entries.length > 0;
92
+ }
93
+ function pluginsEntry(target) {
94
+ if (!target.hasPlugins) return [];
95
+ return [{ kind: "plugins", pluginsDir: target.pluginsDir, names: [...target.cliPluginNames] }];
96
+ }
97
+ function localSkillsEntry(target) {
98
+ if (!target.hasLocalSkills) return [];
99
+ return [{ kind: "skills", skillsDir: target.skillsDir }];
100
+ }
101
+ function compiledAgentsEntry(target) {
102
+ if (!target.hasLocalAgents) return [];
103
+ if (target.configuredAgents.length === 0) return [];
104
+ return [{ kind: "agents", agentsDir: target.agentsDir, agentNames: target.configuredAgents }];
105
+ }
106
+ function configManifestEntry(target) {
107
+ const fileNames = [
108
+ ...target.hasClaudeSrcConfig ? [STANDARD_FILES.CONFIG_TS] : [],
109
+ ...target.hasClaudeSrcConfigTypes ? [STANDARD_FILES.CONFIG_TYPES_TS] : []
110
+ ];
111
+ if (fileNames.length === 0) return [];
112
+ return [{ kind: "config", claudeSrcDir: target.claudeSrcDir, fileNames }];
113
+ }
114
+ function keptStatements(target, agentRemovals) {
115
+ if (!target.hasLocalAgents) return [];
116
+ if (agentRemovals.length > 0) return [];
117
+ return [compiledAgentsKept(target.agentsDir)];
118
+ }
119
+ function planEntry(plan, kind) {
120
+ return plan.entries.find(
121
+ (entry) => entry.kind === kind
122
+ );
123
+ }
124
+ function describeEntry(entry) {
125
+ switch (entry.kind) {
126
+ case "plugins":
127
+ return { label: UNINSTALL_PLAN.PLUGINS_HEADING, items: entry.names };
128
+ case "skills":
129
+ return {
130
+ label: UNINSTALL_PLAN.CLI_MANAGED_FILES_HEADING,
131
+ items: [localSkillsRemoval(entry.skillsDir)]
132
+ };
133
+ case "agents":
134
+ return {
135
+ label: UNINSTALL_PLAN.CLI_MANAGED_FILES_HEADING,
136
+ items: [compiledAgentsRemoval(entry.agentsDir)]
137
+ };
138
+ case "config":
139
+ return {
140
+ label: UNINSTALL_PLAN.CONFIG_HEADING,
141
+ items: entry.fileNames.map((fileName) => `${entry.claudeSrcDir}/${fileName}`)
142
+ };
143
+ default: {
144
+ const _exhaustive = entry;
145
+ return _exhaustive;
92
146
  }
93
- sections.push({ label: "Config:", items });
94
147
  }
95
- return sections;
96
148
  }
97
- var UninstallConfirm = ({ target, onConfirm, onCancel }) => {
149
+ var PLAN_SECTION_ORDER = [
150
+ UNINSTALL_PLAN.PLUGINS_HEADING,
151
+ UNINSTALL_PLAN.CLI_MANAGED_FILES_HEADING,
152
+ UNINSTALL_PLAN.CONFIG_HEADING
153
+ ];
154
+ function planSections(entries) {
155
+ const described = entries.map(describeEntry);
156
+ return PLAN_SECTION_ORDER.flatMap(
157
+ (label) => sectionWithItems(label, itemsUnder(described, label))
158
+ );
159
+ }
160
+ function itemsUnder(described, label) {
161
+ return described.filter((section) => section.label === label).flatMap((section) => section.items);
162
+ }
163
+ function sectionWithItems(label, items) {
164
+ if (items.length === 0) return [];
165
+ return [{ label, items }];
166
+ }
167
+ var UninstallConfirm = ({ plan, onConfirm, onCancel }) => {
98
168
  const { exit } = useApp();
99
169
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
100
- /* @__PURE__ */ jsx(Text, { bold: true, children: "The following will be removed:" }),
170
+ /* @__PURE__ */ jsx(Text, { bold: true, children: UNINSTALL_PLAN.PREVIEW_HEADING }),
101
171
  /* @__PURE__ */ jsx(Text, { children: " " }),
102
- buildRemovalPlan(target).map((section) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
172
+ planSections(plan.entries).map((section) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
103
173
  /* @__PURE__ */ jsxs(Text, { color: CLI_COLORS.ERROR, children: [
104
174
  " ",
105
175
  section.label
@@ -109,6 +179,10 @@ var UninstallConfirm = ({ target, onConfirm, onCancel }) => {
109
179
  item
110
180
  ] }, item))
111
181
  ] }, section.label)),
182
+ plan.kept.map((statement) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
183
+ /* @__PURE__ */ jsx(Text, { children: " " }),
184
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: statement })
185
+ ] }, statement)),
112
186
  /* @__PURE__ */ jsx(Text, { children: " " }),
113
187
  /* @__PURE__ */ jsx(
114
188
  Confirm,
@@ -151,17 +225,18 @@ var Uninstall = class _Uninstall extends BaseCommand {
151
225
  `Could not read the project config \u2014 plugins and compiled agents it lists may be left behind: ${reason}`
152
226
  )
153
227
  );
154
- if (!hasAnythingToRemove(target)) {
228
+ const plan = buildRemovalPlan(target);
229
+ if (!hasAnythingToRemove(plan)) {
155
230
  this.reportNothingToUninstall();
156
231
  return;
157
232
  }
158
- const confirmed = flags.yes ? this.printRemovalPlan(target) : await this.confirmRemoval(target);
233
+ const confirmed = flags.yes ? this.printRemovalPlan(plan) : await this.confirmRemoval(plan);
159
234
  if (!confirmed) {
160
235
  this.log("");
161
236
  this.log("Uninstall cancelled");
162
237
  this.exit(EXIT_CODES.CANCELLED);
163
238
  }
164
- await this.executeUninstall(target, projectDir);
239
+ await this.executeUninstall(plan, target, projectDir);
165
240
  this.reportSuccess();
166
241
  }
167
242
  printHeader() {
@@ -176,45 +251,32 @@ var Uninstall = class _Uninstall extends BaseCommand {
176
251
  this.log("");
177
252
  this.log(INFO_MESSAGES.NO_CHANGES_MADE);
178
253
  }
179
- printRemovalPlan(target) {
180
- this.log("The following will be removed:");
254
+ printRemovalPlan(plan) {
255
+ this.log(UNINSTALL_PLAN.PREVIEW_HEADING);
181
256
  this.log("");
182
- for (const section of buildRemovalPlan(target)) {
257
+ for (const section of planSections(plan.entries)) {
183
258
  this.log(` ${section.label}`);
184
259
  for (const item of section.items) {
185
260
  this.log(` ${item}`);
186
261
  }
187
262
  }
263
+ for (const statement of plan.kept) {
264
+ this.log("");
265
+ this.log(statement);
266
+ }
188
267
  this.log("");
189
268
  return true;
190
269
  }
191
- async confirmRemoval(target) {
192
- const outcome = await promptConfirm(({ onConfirm, onCancel }) => /* @__PURE__ */ jsx(UninstallConfirm, { target, onConfirm, onCancel }));
270
+ async confirmRemoval(plan) {
271
+ const outcome = await promptConfirm(({ onConfirm, onCancel }) => /* @__PURE__ */ jsx(UninstallConfirm, { plan, onConfirm, onCancel }));
193
272
  return outcome === "confirmed";
194
273
  }
195
- async executeUninstall(target, projectDir) {
274
+ async executeUninstall(plan, target, projectDir) {
196
275
  const isGlobalUninstall = isHomeDirectory(projectDir);
197
276
  const propagation = isGlobalUninstall ? await this.prepareGlobalPropagation(target, projectDir) : null;
198
- if (target.hasPlugins) {
199
- this.log("Uninstalling plugins...");
200
- try {
201
- const pluginResult = await uninstallPlugins(
202
- target,
203
- projectDir,
204
- (name) => this.log(` Uninstalled plugin '${name}'`)
205
- );
206
- this.logSuccess(
207
- `Uninstalled ${pluginResult.totalUninstalled} ${pluginResult.totalUninstalled === 1 ? "plugin" : "plugins"}`
208
- );
209
- } catch (error) {
210
- this.log("Plugin uninstall failed");
211
- this.error(getErrorMessage(error), {
212
- exit: EXIT_CODES.ERROR
213
- });
214
- }
215
- }
277
+ await this.removePlannedPlugins(planEntry(plan, "plugins"), target.config, projectDir);
216
278
  try {
217
- await this.removeLocalFiles(target);
279
+ await this.removeLocalFiles(plan, target);
218
280
  } catch (error) {
219
281
  this.log("Failed to remove local files");
220
282
  this.error(getErrorMessage(error), {
@@ -299,27 +361,14 @@ var Uninstall = class _Uninstall extends BaseCommand {
299
361
  this.logSuccess(SUCCESS_MESSAGES.UNINSTALL_COMPLETE);
300
362
  this.log("");
301
363
  }
302
- async removeLocalFiles(target) {
303
- const skillResult = await removeMatchingSkills(
304
- target,
305
- (dirName) => this.log(` Uninstalled skill '${dirName}'`),
306
- (dirName) => this.warn(`Skipping '${dirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`)
307
- );
308
- if (skillResult.removedCount > 0) {
309
- this.logSuccess(
310
- `Removed ${skillResult.removedCount} CLI-installed ${skillResult.removedCount === 1 ? "skill" : "skills"}`
311
- );
312
- }
313
- const agentResult = await removeMatchingAgents(
314
- target,
315
- (agentName) => this.log(` Uninstalled agent '${agentName}'`)
316
- );
317
- if (agentResult.removedCount > 0) {
318
- this.logSuccess(
319
- `Removed ${agentResult.removedCount} compiled ${agentResult.removedCount === 1 ? "agent" : "agents"}`
320
- );
321
- }
322
- const cleanup = await cleanupEmptyDirs(target);
364
+ /**
365
+ * Each step acts only when the plan carries its entry, so what the user was shown and
366
+ * what this run removes are the same list read twice.
367
+ */
368
+ async removeLocalFiles(plan, target) {
369
+ await this.removePlannedSkills(planEntry(plan, "skills"));
370
+ await this.removePlannedAgents(planEntry(plan, "agents"));
371
+ const cleanup = await cleanupEmptyDirs(target, planEntry(plan, "config"));
323
372
  if (cleanup.claudeSrcDirRemoved) {
324
373
  this.logSuccess(`Removed ${CLAUDE_SRC_DIR}/`);
325
374
  } else if (cleanup.claudeSrcManifestRemoved) {
@@ -331,10 +380,50 @@ var Uninstall = class _Uninstall extends BaseCommand {
331
380
  this.log(`Kept ${CLAUDE_DIR}/ (contains user content)`);
332
381
  }
333
382
  }
383
+ async removePlannedPlugins(entry, config, projectDir) {
384
+ if (!entry) return;
385
+ this.log("Uninstalling plugins...");
386
+ try {
387
+ const pluginResult = await uninstallPlugins(
388
+ entry,
389
+ config,
390
+ projectDir,
391
+ (name) => this.log(` Uninstalled plugin '${name}'`)
392
+ );
393
+ this.logSuccess(
394
+ `Uninstalled ${pluginResult.totalUninstalled} ${pluginResult.totalUninstalled === 1 ? "plugin" : "plugins"}`
395
+ );
396
+ } catch (error) {
397
+ this.log("Plugin uninstall failed");
398
+ this.error(getErrorMessage(error), {
399
+ exit: EXIT_CODES.ERROR
400
+ });
401
+ }
402
+ }
403
+ async removePlannedSkills(entry) {
404
+ if (!entry) return;
405
+ const result = await removeMatchingSkills(
406
+ entry,
407
+ (dirName) => this.log(` Uninstalled skill '${dirName}'`),
408
+ (dirName) => this.warn(`Skipping '${dirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`)
409
+ );
410
+ if (result.removedCount === 0) return;
411
+ this.logSuccess(
412
+ `Removed ${result.removedCount} CLI-installed ${result.removedCount === 1 ? "skill" : "skills"}`
413
+ );
414
+ }
415
+ async removePlannedAgents(entry) {
416
+ if (!entry) return;
417
+ const result = await removeMatchingAgents(
418
+ entry,
419
+ (agentName) => this.log(` Uninstalled agent '${agentName}'`)
420
+ );
421
+ if (result.removedCount === 0) return;
422
+ this.logSuccess(
423
+ `Removed ${result.removedCount} compiled ${result.removedCount === 1 ? "agent" : "agents"}`
424
+ );
425
+ }
334
426
  };
335
- function hasAnythingToRemove(target) {
336
- return target.hasPlugins || target.hasLocalSkills || target.hasLocalAgents || target.hasClaudeSrcConfig || target.hasClaudeSrcConfigTypes;
337
- }
338
427
  function collectConfiguredAgents(config) {
339
428
  if (!config?.agents) return [];
340
429
  return config.agents.map((a) => a.name);
@@ -418,24 +507,15 @@ async function detectUninstallTarget(projectDir, onConfigLoadFailed) {
418
507
  function shouldRemoveSkill(forkedFrom) {
419
508
  return forkedFrom !== null;
420
509
  }
421
- async function removeMatchingSkills(target, onRemoved, onSkipped) {
422
- if (!target.hasLocalSkills) {
423
- return {
424
- removedCount: 0,
425
- skippedCount: 0,
426
- removedNames: [],
427
- skippedNames: [],
428
- dirCleaned: false
429
- };
430
- }
431
- const classified = await classifySkillDirs(target.skillsDir);
510
+ async function removeMatchingSkills(entry, onRemoved, onSkipped) {
511
+ const classified = await classifySkillDirs(entry.skillsDir);
432
512
  const removedNames = await removeClassifiedSkills(
433
513
  classified.toRemove,
434
- target.skillsDir,
514
+ entry.skillsDir,
435
515
  onRemoved
436
516
  );
437
517
  classified.toSkip.forEach((name) => onSkipped?.(name));
438
- const dirCleaned = await cleanupSkillsDir(target.skillsDir, classified.toSkip.length === 0);
518
+ const dirCleaned = await cleanupSkillsDir(entry.skillsDir, classified.toSkip.length === 0);
439
519
  return {
440
520
  removedCount: removedNames.length,
441
521
  skippedCount: classified.toSkip.length,
@@ -466,68 +546,47 @@ async function cleanupSkillsDir(dir, allRemoved) {
466
546
  if (!allRemoved) return false;
467
547
  return removeDirIfEmpty(dir);
468
548
  }
469
- async function removeDirIfEmpty(dir) {
470
- if (!await directoryExists(dir)) return false;
471
- if (!await isDirectoryEmpty(dir)) return false;
472
- await remove(dir);
473
- return true;
474
- }
475
- async function removeMatchingAgents(target, onRemoved) {
476
- if (!target.hasLocalAgents) {
477
- return { removedCount: 0, removedNames: [], dirCleaned: false };
478
- }
479
- if (target.configuredAgents.length === 0) {
480
- return { removedCount: 0, removedNames: [], dirCleaned: false };
481
- }
482
- const agentFiles = await listAgentFiles(target.agentsDir);
483
- const removedNames = agentFiles.map((agentFile) => agentFile.replace(/\.md$/, "")).filter((agentName) => target.configuredAgents.includes(agentName));
549
+ async function removeMatchingAgents(entry, onRemoved) {
550
+ const agentFiles = await listAgentFiles(entry.agentsDir);
551
+ const removedNames = agentFiles.map((agentFile) => agentFile.replace(/\.md$/, "")).filter((agentName) => entry.agentNames.includes(agentName));
484
552
  for (const agentName of removedNames) {
485
- await remove(path.join(target.agentsDir, `${agentName}.md`));
553
+ await remove(path.join(entry.agentsDir, `${agentName}.md`));
486
554
  onRemoved?.(agentName);
487
555
  }
488
- const dirCleaned = await removeDirIfEmpty(target.agentsDir);
556
+ const dirCleaned = await removeDirIfEmpty(entry.agentsDir);
489
557
  return {
490
558
  removedCount: removedNames.length,
491
559
  removedNames,
492
560
  dirCleaned
493
561
  };
494
562
  }
495
- async function uninstallPlugins(target, projectDir, onUninstalled) {
496
- if (!target.hasPlugins) {
497
- return { uninstalledNames: [], totalUninstalled: 0 };
498
- }
563
+ async function uninstallPlugins(entry, config, projectDir, onUninstalled) {
499
564
  const cliAvailable = await isClaudeCLIAvailable();
500
- for (const pluginName of target.cliPluginNames) {
565
+ for (const pluginName of entry.names) {
501
566
  if (cliAvailable) {
502
567
  const skillId = parseMarketplacePluginRef(pluginName);
503
- const skillConfig = target.config?.skills.find((s) => s.id === skillId);
568
+ const skillConfig = config?.skills.find((s) => s.id === skillId);
504
569
  const primaryScope = toClaudePluginScope(skillConfig?.scope);
505
570
  await claudePluginUninstallBestEffort(pluginName, primaryScope, projectDir);
506
571
  }
507
- const pluginPath = path.join(target.pluginsDir, pluginName);
572
+ const pluginPath = path.join(entry.pluginsDir, pluginName);
508
573
  await remove(pluginPath);
509
574
  onUninstalled?.(pluginName);
510
575
  }
511
576
  return {
512
- uninstalledNames: target.cliPluginNames,
513
- totalUninstalled: target.cliPluginNames.length
577
+ uninstalledNames: entry.names,
578
+ totalUninstalled: entry.names.length
514
579
  };
515
580
  }
516
- async function removeConfigManifest(target) {
517
- let manifestRemoved = false;
518
- if (target.hasClaudeSrcConfig) {
519
- await remove(path.join(target.claudeSrcDir, STANDARD_FILES.CONFIG_TS));
520
- manifestRemoved = true;
521
- }
522
- if (target.hasClaudeSrcConfigTypes) {
523
- await remove(path.join(target.claudeSrcDir, STANDARD_FILES.CONFIG_TYPES_TS));
524
- manifestRemoved = true;
525
- }
526
- const dirRemoved = manifestRemoved && await removeDirIfEmpty(target.claudeSrcDir);
527
- return { manifestRemoved, dirRemoved };
581
+ async function removeConfigManifest(entry) {
582
+ if (!entry) return { manifestRemoved: false, dirRemoved: false };
583
+ await Promise.all(
584
+ entry.fileNames.map((fileName) => remove(path.join(entry.claudeSrcDir, fileName)))
585
+ );
586
+ return { manifestRemoved: true, dirRemoved: await removeDirIfEmpty(entry.claudeSrcDir) };
528
587
  }
529
- async function cleanupEmptyDirs(target) {
530
- const manifest = await removeConfigManifest(target);
588
+ async function cleanupEmptyDirs(target, manifestEntry) {
589
+ const manifest = await removeConfigManifest(manifestEntry);
531
590
  const claudeDirRemoved = target.hasClaudeDir && await removeDirIfEmpty(target.claudeDir);
532
591
  const claudeDirKept = !claudeDirRemoved && target.hasClaudeDir && await directoryExists(target.claudeDir);
533
592
  return {
@@ -537,14 +596,6 @@ async function cleanupEmptyDirs(target) {
537
596
  claudeDirKept
538
597
  };
539
598
  }
540
- async function isDirectoryEmpty(dirPath) {
541
- try {
542
- const allEntries = await readdir(dirPath);
543
- return allEntries.length === 0;
544
- } catch {
545
- return true;
546
- }
547
- }
548
599
  async function listAgentFiles(agentsDir) {
549
600
  try {
550
601
  return await listAgentMdFiles(agentsDir);