add-skill-kit 3.2.7 → 3.2.8

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.
@@ -1,307 +1,307 @@
1
- /**
2
- * @fileoverview Uninstall command
3
- */
4
-
5
- import fs from "fs";
6
- import path from "path";
7
- import os from "os";
8
- import prompts from "prompts";
9
- import { resolveScope, createBackup } from "../helpers.js";
10
- import { step, stepLine, success, fatal, c, select, isCancel, cancel } from "../ui.js";
11
- import { DRY } from "../config.js";
12
-
13
- /**
14
- * Remove a skill or all skills
15
- * @param {string} skillName - Skill name or "all" to remove everything
16
- */
17
- export async function run(skillName) {
18
- const scope = resolveScope();
19
-
20
- // Check if skills directory exists
21
- if (!fs.existsSync(scope)) {
22
- fatal("No skills directory found");
23
- }
24
-
25
- // Get list of installed skills
26
- const skills = fs.readdirSync(scope)
27
- .filter(item => {
28
- const itemPath = path.join(scope, item);
29
- return fs.statSync(itemPath).isDirectory() && fs.existsSync(path.join(itemPath, "SKILL.md"));
30
- });
31
-
32
- if (skills.length === 0) {
33
- step("No skills installed");
34
- return;
35
- }
36
-
37
- // CASE 1: kit uninstall all Auto-remove everything
38
- if (skillName === "all") {
39
- await removeAllAutomatic(scope, skills);
40
- return;
41
- }
42
-
43
- // CASE 2: kit uninstall (no params) Interactive menu
44
- if (!skillName) {
45
- await interactiveRemove(scope, skills);
46
- return;
47
- }
48
-
49
- // CASE 3: kit uninstall <skill> Remove specific skill
50
- await removeSingleSkill(scope, skillName);
51
- }
52
-
53
- /**
54
- * Interactive menu for skill removal
55
- */
56
- async function interactiveRemove(scope, skills) {
57
- stepLine();
58
- step(`Found ${skills.length} installed skill(s)`);
59
- stepLine();
60
-
61
- const choice = await select({
62
- message: "What would you like to do?",
63
- options: [
64
- { value: "select", label: "Select specific skill", hint: "Choose one skill to remove" },
65
- { value: "all", label: "Remove all skills", hint: "Remove everything (with confirmations)" },
66
- { value: "cancel", label: "Cancel", hint: "Go back" }
67
- ]
68
- });
69
-
70
- if (isCancel(choice) || choice === "cancel") {
71
- cancel("Cancelled");
72
- return;
73
- }
74
-
75
- if (choice === "all") {
76
- await removeAllWithConfirmation(scope, skills);
77
- return;
78
- }
79
-
80
- // Select specific skill
81
- const skillChoice = await select({
82
- message: "Select skill to remove",
83
- options: skills.map(s => ({ value: s, label: s }))
84
- });
85
-
86
- if (isCancel(skillChoice)) {
87
- cancel("Cancelled");
88
- return;
89
- }
90
-
91
- await removeSingleSkill(scope, skillChoice);
92
- }
93
-
94
- /**
95
- * Remove all skills automatically (kit uninstall all)
96
- */
97
- async function removeAllAutomatic(scope, skills) {
98
- stepLine();
99
- step(c.yellow("AUTOMATIC COMPLETE REMOVAL"));
100
- step(c.dim(`Removing ${skills.length} skill(s) + .agent folder + npm dependencies`));
101
- stepLine();
102
-
103
- if (DRY) {
104
- step(`Would remove ${skills.length} skill(s) from: ${scope}`);
105
- step("Would remove .agent folder");
106
- step("Would remove npm dependencies");
107
- return;
108
- }
109
-
110
- // 1. Remove all skills with backup
111
- for (const skill of skills) {
112
- const targetDir = path.join(scope, skill);
113
- createBackup(targetDir, skill);
114
- fs.rmSync(targetDir, { recursive: true, force: true });
115
- step(`✓ Removed: ${skill}`);
116
- }
117
-
118
- // 2. Remove .agent folder
119
- const agentDir = path.dirname(scope);
120
- if (fs.existsSync(agentDir) && path.basename(agentDir) === ".agent") {
121
- fs.rmSync(agentDir, { recursive: true, force: true });
122
- step(" Removed: .agent folder");
123
- }
124
-
125
- // 3. Remove npm dependencies
126
- const cwd = process.cwd();
127
- const nodeModules = path.join(cwd, "node_modules");
128
- const packageJson = path.join(cwd, "package.json");
129
- const packageLock = path.join(cwd, "package-lock.json");
130
-
131
- if (fs.existsSync(nodeModules)) {
132
- fs.rmSync(nodeModules, { recursive: true, force: true });
133
- step(" Removed: node_modules/");
134
- }
135
- if (fs.existsSync(packageJson)) {
136
- fs.rmSync(packageJson);
137
- step(" Removed: package.json");
138
- }
139
- if (fs.existsSync(packageLock)) {
140
- fs.rmSync(packageLock);
141
- step(" Removed: package-lock.json");
142
- }
143
-
144
- // 4. For global installs, ask about ~/.gemini/ cleanup
145
- if (scope.includes(".gemini")) {
146
- stepLine();
147
- step(c.yellow("Global Configuration Cleanup"));
148
- step(c.dim("The entire ~/.gemini/ folder can be removed:"));
149
- step(c.dim(" GEMINI.md (global rules)"));
150
- step(c.dim(" All Antigravity configs"));
151
- step(c.dim(" Cache and backups"));
152
- stepLine();
153
-
154
- const geminiRoot = path.join(require("os").homedir(), ".gemini");
155
- if (fs.existsSync(geminiRoot)) {
156
- // Just remove it automatically in "all" mode
157
- fs.rmSync(geminiRoot, { recursive: true, force: true });
158
- step(" Removed: ~/.gemini/ (complete cleanup)");
159
- }
160
- }
161
-
162
- stepLine();
163
- success("Complete cleanup done - everything removed");
164
- }
165
-
166
- /**
167
- * Remove all skills with step-by-step confirmations (kit uninstall all)
168
- */
169
- async function removeAllWithConfirmation(scope, skills) {
170
- stepLine();
171
- step(`Found ${skills.length} skill(s) to remove:`);
172
- skills.forEach(s => step(` ${s}`, "", "dim"));
173
- stepLine();
174
-
175
- const confirmSkills = await prompts({
176
- type: "confirm",
177
- name: "value",
178
- message: `Remove all ${skills.length} skill(s)?`,
179
- initial: false
180
- });
181
-
182
- if (!confirmSkills.value) {
183
- step("Cancelled");
184
- return;
185
- }
186
-
187
- // Remove each skill with backup
188
- for (const skill of skills) {
189
- const targetDir = path.join(scope, skill);
190
- createBackup(targetDir, skill);
191
- fs.rmSync(targetDir, { recursive: true, force: true });
192
- step(`Removed: ${skill}`);
193
- }
194
-
195
- success(`All ${skills.length} skill(s) removed successfully`);
196
- stepLine();
197
-
198
- // Ask about .agent folder
199
- const agentDir = path.dirname(scope);
200
- if (fs.existsSync(agentDir) && path.basename(agentDir) === ".agent") {
201
- stepLine();
202
- step(c.yellow("Complete Cleanup"));
203
- step(c.dim("The following will also be removed:"));
204
- step(c.dim(" Agents"));
205
- step(c.dim(" Workflows"));
206
- step(c.dim(" Knowledge & Lessons"));
207
- step(c.dim(" All configuration files"));
208
- stepLine();
209
-
210
- const confirmAgent = await prompts({
211
- type: "confirm",
212
- name: "value",
213
- message: "Remove entire .agent folder?",
214
- initial: false
215
- });
216
-
217
- if (confirmAgent.value) {
218
- fs.rmSync(agentDir, { recursive: true, force: true });
219
- success("Complete cleanup done - .agent folder removed");
220
-
221
- // Ask about npm dependencies
222
- stepLine();
223
- step(c.yellow("npm Dependencies Cleanup"));
224
- step(c.dim("The following npm files will also be removed:"));
225
- step(c.dim(" node_modules/"));
226
- step(c.dim(" package.json"));
227
- step(c.dim(" package-lock.json"));
228
- stepLine();
229
-
230
- const confirmNpm = await prompts({
231
- type: "confirm",
232
- name: "value",
233
- message: "Remove npm dependencies?",
234
- initial: false
235
- });
236
-
237
- if (confirmNpm.value) {
238
- const cwd = process.cwd();
239
- const nodeModules = path.join(cwd, "node_modules");
240
- const packageJson = path.join(cwd, "package.json");
241
- const packageLock = path.join(cwd, "package-lock.json");
242
-
243
- if (fs.existsSync(nodeModules)) {
244
- fs.rmSync(nodeModules, { recursive: true, force: true });
245
- step("Removed: node_modules/");
246
- }
247
- if (fs.existsSync(packageJson)) {
248
- fs.rmSync(packageJson);
249
- step("Removed: package.json");
250
- }
251
- if (fs.existsSync(packageLock)) {
252
- fs.rmSync(packageLock);
253
- step("Removed: package-lock.json");
254
- }
255
- success("npm dependencies removed");
256
- } else {
257
- step(c.dim("Kept npm dependencies"));
258
- }
259
- } else {
260
- step(c.dim("Kept .agent folder (agents, workflows, etc.)"));
261
- }
262
- }
263
-
264
- stepLine();
265
- }
266
-
267
- /**
268
- * Remove a single skill
269
- */
270
- async function removeSingleSkill(scope, skillName) {
271
- const targetDir = path.join(scope, skillName);
272
-
273
- if (!fs.existsSync(targetDir)) {
274
- fatal(`Skill not found: ${skillName}`);
275
- }
276
-
277
- if (!fs.existsSync(path.join(targetDir, "SKILL.md"))) {
278
- fatal(`Not a valid skill: ${skillName}`);
279
- }
280
-
281
- stepLine();
282
- step(`Removing skill: ${c.cyan(skillName)}`);
283
-
284
- const confirm = await prompts({
285
- type: "confirm",
286
- name: "value",
287
- message: "Confirm removal?",
288
- initial: false
289
- });
290
-
291
- if (!confirm.value) {
292
- step("Cancelled");
293
- return;
294
- }
295
-
296
- if (DRY) {
297
- step(`Would remove: ${targetDir}`);
298
- return;
299
- }
300
-
301
- const backup = createBackup(targetDir, skillName);
302
- if (backup) step(`Backup created: ${backup}`);
303
-
304
- fs.rmSync(targetDir, { recursive: true, force: true });
305
- success(`Removed: ${skillName}`);
306
- stepLine();
307
- }
1
+ /**
2
+ * @fileoverview Uninstall command
3
+ */
4
+
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+ import prompts from "prompts";
9
+ import { resolveScope, createBackup } from "../helpers.js";
10
+ import { step, stepLine, success, fatal, c, select, isCancel, cancel } from "../ui.js";
11
+ import { DRY } from "../config.js";
12
+
13
+ /**
14
+ * Remove a skill or all skills
15
+ * @param {string} skillName - Skill name or "all" to remove everything
16
+ */
17
+ export async function run(skillName) {
18
+ const scope = resolveScope();
19
+
20
+ // Check if skills directory exists
21
+ if (!fs.existsSync(scope)) {
22
+ fatal("No skills directory found");
23
+ }
24
+
25
+ // Get list of installed skills
26
+ const skills = fs.readdirSync(scope)
27
+ .filter(item => {
28
+ const itemPath = path.join(scope, item);
29
+ return fs.statSync(itemPath).isDirectory() && fs.existsSync(path.join(itemPath, "SKILL.md"));
30
+ });
31
+
32
+ if (skills.length === 0) {
33
+ step("No skills installed");
34
+ return;
35
+ }
36
+
37
+ // CASE 1: kit uninstall all → Auto-remove everything
38
+ if (skillName === "all") {
39
+ await removeAllAutomatic(scope, skills);
40
+ return;
41
+ }
42
+
43
+ // CASE 2: kit uninstall (no params) → Interactive menu
44
+ if (!skillName) {
45
+ await interactiveRemove(scope, skills);
46
+ return;
47
+ }
48
+
49
+ // CASE 3: kit uninstall <skill> → Remove specific skill
50
+ await removeSingleSkill(scope, skillName);
51
+ }
52
+
53
+ /**
54
+ * Interactive menu for skill removal
55
+ */
56
+ async function interactiveRemove(scope, skills) {
57
+ stepLine();
58
+ step(`Found ${skills.length} installed skill(s)`);
59
+ stepLine();
60
+
61
+ const choice = await select({
62
+ message: "What would you like to do?",
63
+ options: [
64
+ { value: "select", label: "Select specific skill", hint: "Choose one skill to remove" },
65
+ { value: "all", label: "Remove all skills", hint: "Remove everything (with confirmations)" },
66
+ { value: "cancel", label: "Cancel", hint: "Go back" }
67
+ ]
68
+ });
69
+
70
+ if (isCancel(choice) || choice === "cancel") {
71
+ cancel("Cancelled");
72
+ return;
73
+ }
74
+
75
+ if (choice === "all") {
76
+ await removeAllWithConfirmation(scope, skills);
77
+ return;
78
+ }
79
+
80
+ // Select specific skill
81
+ const skillChoice = await select({
82
+ message: "Select skill to remove",
83
+ options: skills.map(s => ({ value: s, label: s }))
84
+ });
85
+
86
+ if (isCancel(skillChoice)) {
87
+ cancel("Cancelled");
88
+ return;
89
+ }
90
+
91
+ await removeSingleSkill(scope, skillChoice);
92
+ }
93
+
94
+ /**
95
+ * Remove all skills automatically (kit uninstall all)
96
+ */
97
+ async function removeAllAutomatic(scope, skills) {
98
+ stepLine();
99
+ step(c.yellow("AUTOMATIC COMPLETE REMOVAL"));
100
+ step(c.dim(`Removing ${skills.length} skill(s) + .agent folder + npm dependencies`));
101
+ stepLine();
102
+
103
+ if (DRY) {
104
+ step(`Would remove ${skills.length} skill(s) from: ${scope}`);
105
+ step("Would remove .agent folder");
106
+ step("Would remove npm dependencies");
107
+ return;
108
+ }
109
+
110
+ // 1. Remove all skills with backup
111
+ for (const skill of skills) {
112
+ const targetDir = path.join(scope, skill);
113
+ createBackup(targetDir, skill);
114
+ fs.rmSync(targetDir, { recursive: true, force: true });
115
+ step(`✓ Removed: ${skill}`);
116
+ }
117
+
118
+ // 2. Remove .agent folder
119
+ const agentDir = path.dirname(scope);
120
+ if (fs.existsSync(agentDir) && path.basename(agentDir) === ".agent") {
121
+ fs.rmSync(agentDir, { recursive: true, force: true });
122
+ step("✓ Removed: .agent folder");
123
+ }
124
+
125
+ // 3. Remove npm dependencies
126
+ const cwd = process.cwd();
127
+ const nodeModules = path.join(cwd, "node_modules");
128
+ const packageJson = path.join(cwd, "package.json");
129
+ const packageLock = path.join(cwd, "package-lock.json");
130
+
131
+ if (fs.existsSync(nodeModules)) {
132
+ fs.rmSync(nodeModules, { recursive: true, force: true });
133
+ step("✓ Removed: node_modules/");
134
+ }
135
+ if (fs.existsSync(packageJson)) {
136
+ fs.rmSync(packageJson);
137
+ step("✓ Removed: package.json");
138
+ }
139
+ if (fs.existsSync(packageLock)) {
140
+ fs.rmSync(packageLock);
141
+ step("✓ Removed: package-lock.json");
142
+ }
143
+
144
+ // 4. For global installs, ask about ~/.gemini/ cleanup
145
+ if (scope.includes(".gemini")) {
146
+ stepLine();
147
+ step(c.yellow("Global Configuration Cleanup"));
148
+ step(c.dim("The entire ~/.gemini/ folder can be removed:"));
149
+ step(c.dim(" • GEMINI.md (global rules)"));
150
+ step(c.dim(" • All Antigravity configs"));
151
+ step(c.dim(" • Cache and backups"));
152
+ stepLine();
153
+
154
+ const geminiRoot = path.join(require("os").homedir(), ".gemini");
155
+ if (fs.existsSync(geminiRoot)) {
156
+ // Just remove it automatically in "all" mode
157
+ fs.rmSync(geminiRoot, { recursive: true, force: true });
158
+ step("✓ Removed: ~/.gemini/ (complete cleanup)");
159
+ }
160
+ }
161
+
162
+ stepLine();
163
+ success("Complete cleanup done - everything removed");
164
+ }
165
+
166
+ /**
167
+ * Remove all skills with step-by-step confirmations (kit uninstall → all)
168
+ */
169
+ async function removeAllWithConfirmation(scope, skills) {
170
+ stepLine();
171
+ step(`Found ${skills.length} skill(s) to remove:`);
172
+ skills.forEach(s => step(` • ${s}`, "", "dim"));
173
+ stepLine();
174
+
175
+ const confirmSkills = await prompts({
176
+ type: "confirm",
177
+ name: "value",
178
+ message: `Remove all ${skills.length} skill(s)?`,
179
+ initial: false
180
+ });
181
+
182
+ if (!confirmSkills.value) {
183
+ step("Cancelled");
184
+ return;
185
+ }
186
+
187
+ // Remove each skill with backup
188
+ for (const skill of skills) {
189
+ const targetDir = path.join(scope, skill);
190
+ createBackup(targetDir, skill);
191
+ fs.rmSync(targetDir, { recursive: true, force: true });
192
+ step(`Removed: ${skill}`);
193
+ }
194
+
195
+ success(`All ${skills.length} skill(s) removed successfully`);
196
+ stepLine();
197
+
198
+ // Ask about .agent folder
199
+ const agentDir = path.dirname(scope);
200
+ if (fs.existsSync(agentDir) && path.basename(agentDir) === ".agent") {
201
+ stepLine();
202
+ step(c.yellow("Complete Cleanup"));
203
+ step(c.dim("The following will also be removed:"));
204
+ step(c.dim(" • Agents"));
205
+ step(c.dim(" • Workflows"));
206
+ step(c.dim(" • Knowledge & Lessons"));
207
+ step(c.dim(" • All configuration files"));
208
+ stepLine();
209
+
210
+ const confirmAgent = await prompts({
211
+ type: "confirm",
212
+ name: "value",
213
+ message: "Remove entire .agent folder?",
214
+ initial: false
215
+ });
216
+
217
+ if (confirmAgent.value) {
218
+ fs.rmSync(agentDir, { recursive: true, force: true });
219
+ success("Complete cleanup done - .agent folder removed");
220
+
221
+ // Ask about npm dependencies
222
+ stepLine();
223
+ step(c.yellow("npm Dependencies Cleanup"));
224
+ step(c.dim("The following npm files will also be removed:"));
225
+ step(c.dim(" • node_modules/"));
226
+ step(c.dim(" • package.json"));
227
+ step(c.dim(" • package-lock.json"));
228
+ stepLine();
229
+
230
+ const confirmNpm = await prompts({
231
+ type: "confirm",
232
+ name: "value",
233
+ message: "Remove npm dependencies?",
234
+ initial: false
235
+ });
236
+
237
+ if (confirmNpm.value) {
238
+ const cwd = process.cwd();
239
+ const nodeModules = path.join(cwd, "node_modules");
240
+ const packageJson = path.join(cwd, "package.json");
241
+ const packageLock = path.join(cwd, "package-lock.json");
242
+
243
+ if (fs.existsSync(nodeModules)) {
244
+ fs.rmSync(nodeModules, { recursive: true, force: true });
245
+ step("Removed: node_modules/");
246
+ }
247
+ if (fs.existsSync(packageJson)) {
248
+ fs.rmSync(packageJson);
249
+ step("Removed: package.json");
250
+ }
251
+ if (fs.existsSync(packageLock)) {
252
+ fs.rmSync(packageLock);
253
+ step("Removed: package-lock.json");
254
+ }
255
+ success("npm dependencies removed");
256
+ } else {
257
+ step(c.dim("Kept npm dependencies"));
258
+ }
259
+ } else {
260
+ step(c.dim("Kept .agent folder (agents, workflows, etc.)"));
261
+ }
262
+ }
263
+
264
+ stepLine();
265
+ }
266
+
267
+ /**
268
+ * Remove a single skill
269
+ */
270
+ async function removeSingleSkill(scope, skillName) {
271
+ const targetDir = path.join(scope, skillName);
272
+
273
+ if (!fs.existsSync(targetDir)) {
274
+ fatal(`Skill not found: ${skillName}`);
275
+ }
276
+
277
+ if (!fs.existsSync(path.join(targetDir, "SKILL.md"))) {
278
+ fatal(`Not a valid skill: ${skillName}`);
279
+ }
280
+
281
+ stepLine();
282
+ step(`Removing skill: ${c.cyan(skillName)}`);
283
+
284
+ const confirm = await prompts({
285
+ type: "confirm",
286
+ name: "value",
287
+ message: "Confirm removal?",
288
+ initial: false
289
+ });
290
+
291
+ if (!confirm.value) {
292
+ step("Cancelled");
293
+ return;
294
+ }
295
+
296
+ if (DRY) {
297
+ step(`Would remove: ${targetDir}`);
298
+ return;
299
+ }
300
+
301
+ const backup = createBackup(targetDir, skillName);
302
+ if (backup) step(`Backup created: ${backup}`);
303
+
304
+ fs.rmSync(targetDir, { recursive: true, force: true });
305
+ success(`Removed: ${skillName}`);
306
+ stepLine();
307
+ }