td-ai-tools 1.0.7 → 1.0.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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/bin/cli.js +130 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -36,6 +36,9 @@ npx td-ai-tools install pr-solver horizon-component-library
36
36
  npx td-ai-tools update
37
37
  npx td-ai-tools update --all
38
38
  npx td-ai-tools update pr-solver
39
+ npx td-ai-tools delete
40
+ npx td-ai-tools delete --all
41
+ npx td-ai-tools delete pr-solver
39
42
  ```
40
43
 
41
44
  The installer copies requested items into both agent layouts:
@@ -46,6 +49,8 @@ This keeps the installed assets available to both Claude-style and `.agents`-sty
46
49
 
47
50
  `install` now errors when the target item already exists. Use `update` to replace an existing installed skill or agent pack.
48
51
 
52
+ `delete` removes installed items from both `.claude/` and `.agents/` target directories, and works on any installed skill or agent pack regardless of whether it is in the catalogue.
53
+
49
54
  ## Local Verification
50
55
  Run the local smoke test to package the repo and verify installation into a throwaway project:
51
56
 
package/bin/cli.js CHANGED
@@ -66,6 +66,23 @@ function installSkill(name, { replaceExisting = false } = {}) {
66
66
  return true;
67
67
  }
68
68
 
69
+ function deleteSkill(name) {
70
+ let deletedAny = false;
71
+ for (const target of INSTALL_TARGETS) {
72
+ const dest = path.join(TARGET_ROOT, target.root, 'skills', name);
73
+ if (fs.existsSync(dest)) {
74
+ fs.rmSync(dest, { recursive: true, force: true });
75
+ console.log(` [skill] ${name} deleted from ${target.root}/skills/${name}/`);
76
+ deletedAny = true;
77
+ }
78
+ }
79
+ if (!deletedAny) {
80
+ console.error(` [error] Skill "${name}" is not installed.`);
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+
69
86
  function installAgent(name, { replaceExisting = false } = {}) {
70
87
  const src = path.join(AGENTS_DIR, name);
71
88
  if (!fs.existsSync(src)) {
@@ -88,6 +105,38 @@ function installAgent(name, { replaceExisting = false } = {}) {
88
105
  return true;
89
106
  }
90
107
 
108
+ function deleteAgent(name) {
109
+ let deletedAny = false;
110
+ for (const target of INSTALL_TARGETS) {
111
+ const dest = path.join(TARGET_ROOT, target.root, 'agents', name);
112
+ if (fs.existsSync(dest)) {
113
+ fs.rmSync(dest, { recursive: true, force: true });
114
+ console.log(` [agent] ${name} deleted from ${target.root}/agents/${name}/`);
115
+ deletedAny = true;
116
+ }
117
+ }
118
+ if (!deletedAny) {
119
+ console.error(` [error] Agent pack "${name}" is not installed.`);
120
+ return false;
121
+ }
122
+ return true;
123
+ }
124
+
125
+ function getInstalled(type) {
126
+ const installed = new Set();
127
+ for (const target of INSTALL_TARGETS) {
128
+ const dir = path.join(TARGET_ROOT, target.root, type);
129
+ if (fs.existsSync(dir)) {
130
+ for (const entry of fs.readdirSync(dir)) {
131
+ if (fs.statSync(path.join(dir, entry)).isDirectory()) {
132
+ installed.add(entry);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ return [...installed].sort();
138
+ }
139
+
91
140
  function printList() {
92
141
  const skills = getAvailable(SKILLS_DIR);
93
142
  const agents = getAvailable(AGENTS_DIR);
@@ -113,6 +162,12 @@ function buildMenu() {
113
162
  return [...skills, ...agents];
114
163
  }
115
164
 
165
+ function buildDeleteMenu() {
166
+ const skills = getInstalled('skills').map(name => ({ type: 'skill', name }));
167
+ const agents = getInstalled('agents').map(name => ({ type: 'agent', name }));
168
+ return [...skills, ...agents];
169
+ }
170
+
116
171
  function installItems(items, options = {}) {
117
172
  for (const item of items) {
118
173
  if (item.type === 'skill') installSkill(item.name, options);
@@ -120,6 +175,13 @@ function installItems(items, options = {}) {
120
175
  }
121
176
  }
122
177
 
178
+ function deleteItems(items) {
179
+ for (const item of items) {
180
+ if (item.type === 'skill') deleteSkill(item.name);
181
+ else deleteAgent(item.name);
182
+ }
183
+ }
184
+
123
185
  async function interactiveInstall(mode = 'install') {
124
186
  const menu = buildMenu();
125
187
  if (menu.length === 0) {
@@ -153,6 +215,39 @@ async function interactiveInstall(mode = 'install') {
153
215
  });
154
216
  }
155
217
 
218
+ async function interactiveDelete() {
219
+ const menu = buildDeleteMenu();
220
+ if (menu.length === 0) {
221
+ console.log('No installed skills or agent packs to delete.');
222
+ return;
223
+ }
224
+
225
+ console.log('\nInstalled (enter numbers separated by spaces, or "all"):\n');
226
+ menu.forEach((item, i) => {
227
+ const label = item.type === 'skill' ? 'skill' : 'agent';
228
+ console.log(` [${i + 1}] ${label}: ${item.name}`);
229
+ });
230
+ console.log('');
231
+
232
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
233
+ return new Promise(resolve => {
234
+ rl.question('Select items to delete: ', answer => {
235
+ rl.close();
236
+ const trimmed = answer.trim().toLowerCase();
237
+ let selected;
238
+ if (trimmed === 'all') {
239
+ selected = menu;
240
+ } else {
241
+ const indices = trimmed.split(/\s+/).map(n => parseInt(n, 10) - 1);
242
+ selected = indices.filter(i => i >= 0 && i < menu.length).map(i => menu[i]);
243
+ }
244
+ console.log('');
245
+ deleteItems(selected);
246
+ resolve();
247
+ });
248
+ });
249
+ }
250
+
156
251
  function resolveNames(names) {
157
252
  const skills = getAvailable(SKILLS_DIR);
158
253
  const agents = getAvailable(AGENTS_DIR);
@@ -169,6 +264,22 @@ function resolveNames(names) {
169
264
  return items;
170
265
  }
171
266
 
267
+ function resolveDeleteNames(names) {
268
+ const installedSkills = getInstalled('skills');
269
+ const installedAgents = getInstalled('agents');
270
+ const items = [];
271
+ for (const name of names) {
272
+ if (installedSkills.includes(name)) {
273
+ items.push({ type: 'skill', name });
274
+ } else if (installedAgents.includes(name)) {
275
+ items.push({ type: 'agent', name });
276
+ } else {
277
+ console.error(` [error] "${name}" is not installed.`);
278
+ }
279
+ }
280
+ return items;
281
+ }
282
+
172
283
  async function main() {
173
284
  const args = process.argv.slice(2);
174
285
 
@@ -183,6 +294,9 @@ Usage:
183
294
  npx td-ai-tools update Interactive update (replaces existing items)
184
295
  npx td-ai-tools update --all Update everything
185
296
  npx td-ai-tools update <name...> Update specific skills or agent packs
297
+ npx td-ai-tools delete Interactive delete
298
+ npx td-ai-tools delete --all Delete everything
299
+ npx td-ai-tools delete <name...> Delete specific skills or agent packs
186
300
 
187
301
  Skills are installed to: .claude/skills/<name>/
188
302
  .agents/skills/<name>/
@@ -234,6 +348,22 @@ Agent packs installed to: .claude/agents/<name>/
234
348
  return;
235
349
  }
236
350
 
351
+ if (cmd === 'delete') {
352
+ const rest = args.slice(1);
353
+ if (rest.length === 0) {
354
+ await interactiveDelete();
355
+ return;
356
+ }
357
+ if (rest[0] === '--all') {
358
+ console.log('');
359
+ deleteItems(buildDeleteMenu());
360
+ } else {
361
+ console.log('');
362
+ deleteItems(resolveDeleteNames(rest));
363
+ }
364
+ return;
365
+ }
366
+
237
367
  console.error(`Unknown command: "${cmd}". Run with --help for usage.`);
238
368
  process.exit(1);
239
369
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "td-ai-tools",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Install agent skills and packs into your project",
5
5
  "scripts": {
6
6
  "smoke:install": "./scripts/smoke-install.sh"