@toolr/seedr 0.1.52 → 0.1.54

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 +134 -23
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -21,7 +21,6 @@ import {
21
21
  removeFile,
22
22
  searchItems,
23
23
  skillHandler,
24
- uninstallSkill,
25
24
  writeTextFile
26
25
  } from "./chunk-U2KZAN6F.js";
27
26
 
@@ -165,7 +164,7 @@ function trackInstalls(slug, type, results, scope) {
165
164
  type,
166
165
  tool: result.tool,
167
166
  scope,
168
- version: "0.1.52"
167
+ version: "0.1.54"
169
168
  }),
170
169
  signal: AbortSignal.timeout(4e3)
171
170
  }).catch(() => {
@@ -269,8 +268,8 @@ var agentHandler = {
269
268
  };
270
269
 
271
270
  // src/handlers/hook.ts
272
- import { join as join2 } from "path";
273
- import { mkdir, copyFile, chmod } from "fs/promises";
271
+ import { join as join2, basename } from "path";
272
+ import { mkdir, copyFile, chmod, rm } from "fs/promises";
274
273
  import chalk4 from "chalk";
275
274
  import ora2 from "ora";
276
275
 
@@ -361,8 +360,8 @@ async function installHookForTool(item, tool, scope, _method, cwd) {
361
360
  const tempDir = join2(cwd, ".claude", ".tmp", item.slug);
362
361
  await fetchItemToDestination(item, tempDir);
363
362
  await copyFile(join2(tempDir, scriptFile), destScriptPath);
364
- const { rm } = await import("fs/promises");
365
- await rm(tempDir, { recursive: true, force: true });
363
+ const { rm: rm2 } = await import("fs/promises");
364
+ await rm2(tempDir, { recursive: true, force: true });
366
365
  }
367
366
  await chmod(destScriptPath, 493);
368
367
  const settingsPath = getSettingsPath(scope, cwd);
@@ -417,18 +416,69 @@ async function installHook(item, tools, scope, method, cwd = process.cwd()) {
417
416
  }
418
417
  return results;
419
418
  }
420
- async function uninstallHook(_slug, tool, scope, cwd = process.cwd()) {
419
+ async function uninstallHook(slug, tool, scope, cwd = process.cwd()) {
421
420
  if (tool !== "claude") return false;
422
421
  const settingsPath = getSettingsPath(scope, cwd);
423
422
  if (!await exists(settingsPath)) return false;
424
- return false;
423
+ const item = await getItem(slug, "hook");
424
+ const scriptFile = item ? findScriptFile(item) : null;
425
+ const expectedPath = scriptFile ? getScriptPath(scope, scriptFile) : null;
426
+ const settings = await readJson(settingsPath);
427
+ if (!settings.hooks) return false;
428
+ let removed = false;
429
+ for (const event of Object.keys(settings.hooks)) {
430
+ const entries = settings.hooks[event];
431
+ if (!entries) continue;
432
+ for (let i = entries.length - 1; i >= 0; i--) {
433
+ const entry = entries[i];
434
+ const originalLength = entry.hooks.length;
435
+ entry.hooks = entry.hooks.filter((h) => {
436
+ if (expectedPath && h.command === expectedPath) return false;
437
+ const cmdBasename = basename(h.command, ".sh");
438
+ return cmdBasename !== slug;
439
+ });
440
+ if (entry.hooks.length < originalLength) {
441
+ removed = true;
442
+ }
443
+ if (entry.hooks.length === 0) {
444
+ entries.splice(i, 1);
445
+ }
446
+ }
447
+ if (entries.length === 0) {
448
+ delete settings.hooks[event];
449
+ }
450
+ }
451
+ if (Object.keys(settings.hooks).length === 0) {
452
+ delete settings.hooks;
453
+ }
454
+ if (removed) {
455
+ await writeJson(settingsPath, settings);
456
+ }
457
+ const hooksDir = getHooksDir(scope, cwd);
458
+ const scriptFileName = scriptFile || `${slug}.sh`;
459
+ const scriptFilePath = join2(hooksDir, scriptFileName);
460
+ if (await exists(scriptFilePath)) {
461
+ await rm(scriptFilePath);
462
+ removed = true;
463
+ }
464
+ return removed;
425
465
  }
426
466
  async function getInstalledHooks(tool, scope, cwd = process.cwd()) {
427
467
  if (tool !== "claude") return [];
428
468
  const settingsPath = getSettingsPath(scope, cwd);
429
469
  if (!await exists(settingsPath)) return [];
430
470
  const settings = await readJson(settingsPath);
431
- return Object.keys(settings.hooks || {});
471
+ if (!settings.hooks) return [];
472
+ const slugs = /* @__PURE__ */ new Set();
473
+ for (const entries of Object.values(settings.hooks)) {
474
+ for (const entry of entries) {
475
+ for (const hook of entry.hooks) {
476
+ const slug = basename(hook.command, ".sh");
477
+ slugs.add(slug);
478
+ }
479
+ }
480
+ }
481
+ return Array.from(slugs);
432
482
  }
433
483
  var hookHandler = {
434
484
  type: "hook",
@@ -559,8 +609,52 @@ async function installSettings(item, tools, scope, method, cwd = process.cwd())
559
609
  }
560
610
  return results;
561
611
  }
562
- async function uninstallSettings(_slug, _tool, _scope, _cwd = process.cwd()) {
563
- return false;
612
+ function deepUnmerge(target, source) {
613
+ let changed = false;
614
+ const result = { ...target };
615
+ for (const key of Object.keys(source)) {
616
+ if (!(key in result)) continue;
617
+ const sourceValue = source[key];
618
+ const targetValue = result[key];
619
+ if (sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue !== null && typeof targetValue === "object" && !Array.isArray(targetValue)) {
620
+ const nested = deepUnmerge(
621
+ targetValue,
622
+ sourceValue
623
+ );
624
+ if (nested.changed) {
625
+ changed = true;
626
+ if (Object.keys(nested.result).length === 0) {
627
+ delete result[key];
628
+ } else {
629
+ result[key] = nested.result;
630
+ }
631
+ }
632
+ } else {
633
+ delete result[key];
634
+ changed = true;
635
+ }
636
+ }
637
+ return { result, changed };
638
+ }
639
+ async function uninstallSettings(slug, tool, scope, cwd = process.cwd()) {
640
+ if (tool !== "claude") return false;
641
+ const item = await getItem(slug, "settings");
642
+ if (!item) return false;
643
+ let content;
644
+ try {
645
+ content = await getItemContent(item);
646
+ } catch {
647
+ return false;
648
+ }
649
+ const itemSettings = parseSettings(content);
650
+ const settingsPath = getSettingsPath(scope, cwd);
651
+ if (!await exists(settingsPath)) return false;
652
+ const currentSettings = await readJson(settingsPath);
653
+ const { result, changed } = deepUnmerge(currentSettings, itemSettings);
654
+ if (changed) {
655
+ await writeJson(settingsPath, result);
656
+ }
657
+ return changed;
564
658
  }
565
659
  async function getInstalledSettings(tool, scope, cwd = process.cwd()) {
566
660
  if (tool !== "claude") return [];
@@ -652,9 +746,9 @@ async function installPluginForTool(item, tool, scope, method, cwd) {
652
746
  const pluginId = getPluginId(pluginName, marketplace);
653
747
  await ensureMarketplaceRegistered(marketplace, item);
654
748
  const cachePath = getPluginCachePath(marketplace, pluginName, version);
655
- const { rm } = await import("fs/promises");
749
+ const { rm: rm2 } = await import("fs/promises");
656
750
  await installDirectory(tmpPath, cachePath, "copy");
657
- await rm(tmpPath, { recursive: true, force: true });
751
+ await rm2(tmpPath, { recursive: true, force: true });
658
752
  const now = (/* @__PURE__ */ new Date()).toISOString();
659
753
  const registry = await readJson(INSTALLED_PLUGINS_PATH);
660
754
  registry.version = registry.version || 2;
@@ -1058,21 +1152,25 @@ async function promptConfirm(message, defaultValue = true) {
1058
1152
  }
1059
1153
 
1060
1154
  // src/commands/remove.ts
1061
- async function findInstalledTools(name, scope) {
1155
+ async function findInstalledTools(slug, type, scope) {
1156
+ const handler = getHandler(type);
1157
+ if (!handler) return [];
1062
1158
  const tools = [];
1063
1159
  for (const tool of ALL_TOOLS) {
1064
- const installed = await getInstalledSkills(tool, scope);
1065
- if (installed.includes(name)) {
1160
+ const installed = await handler.listInstalled(tool, scope);
1161
+ if (installed.includes(slug)) {
1066
1162
  tools.push(tool);
1067
1163
  }
1068
1164
  }
1069
1165
  return tools;
1070
1166
  }
1071
- async function removeFromTools(name, tools, scope) {
1167
+ async function removeFromTools(slug, type, tools, scope) {
1168
+ const handler = getHandler(type);
1169
+ if (!handler) return 0;
1072
1170
  let successCount = 0;
1073
1171
  for (const tool of tools) {
1074
1172
  const spinner = ora6(`Removing from ${AI_TOOLS[tool].name}...`).start();
1075
- const removed = await uninstallSkill(name, tool, scope);
1173
+ const removed = await handler.uninstall(slug, tool, scope);
1076
1174
  if (removed) {
1077
1175
  spinner.succeed(chalk10.green(`Removed from ${AI_TOOLS[tool].name}`));
1078
1176
  successCount++;
@@ -1082,7 +1180,7 @@ async function removeFromTools(name, tools, scope) {
1082
1180
  }
1083
1181
  return successCount;
1084
1182
  }
1085
- var removeCommand = new Command3("remove").alias("rm").description("Remove an installed skill").argument("<name>", "Name of the skill to remove").option(
1183
+ var removeCommand = new Command3("remove").alias("rm").description("Remove an installed item (skill, plugin, agent, hook, mcp)").argument("<name>", "Name/slug of the item to remove").option("-t, --type <type>", "Content type: skill, agent, hook, mcp, plugin, settings").option(
1086
1184
  "-a, --agents <tools>",
1087
1185
  "Comma-separated AI tools or 'all'"
1088
1186
  ).option(
@@ -1092,15 +1190,28 @@ var removeCommand = new Command3("remove").alias("rm").description("Remove an in
1092
1190
  ).option("-y, --yes", "Skip confirmation prompts").action(async (name, options) => {
1093
1191
  try {
1094
1192
  const scope = options.scope;
1095
- const tools = options.agents ? parseToolsArg(options.agents, ALL_TOOLS) : await findInstalledTools(name, scope);
1193
+ const type = options.type;
1194
+ if (!type) {
1195
+ console.log(
1196
+ chalk10.yellow(`Please specify the content type with --type (skill, plugin, agent, hook, mcp, settings)`)
1197
+ );
1198
+ process.exit(1);
1199
+ }
1200
+ const handler = getHandler(type);
1201
+ if (!handler) {
1202
+ console.log(chalk10.red(`No handler found for type "${type}"`));
1203
+ process.exit(1);
1204
+ }
1205
+ const tools = options.agents ? parseToolsArg(options.agents, ALL_TOOLS) : await findInstalledTools(name, type, scope);
1096
1206
  if (tools.length === 0) {
1097
1207
  console.log(
1098
- chalk10.yellow(`Skill "${name}" is not installed in ${scope} scope`)
1208
+ chalk10.yellow(`${type} "${name}" is not installed in ${scope} scope`)
1099
1209
  );
1100
1210
  process.exit(0);
1101
1211
  }
1102
1212
  if (!options.yes) {
1103
- console.log(chalk10.cyan("\nWill remove from:"));
1213
+ console.log(chalk10.cyan(`
1214
+ Will remove ${type} "${name}" from:`));
1104
1215
  for (const tool of tools) {
1105
1216
  console.log(` - ${AI_TOOLS[tool].name}`);
1106
1217
  }
@@ -1111,7 +1222,7 @@ var removeCommand = new Command3("remove").alias("rm").description("Remove an in
1111
1222
  process.exit(0);
1112
1223
  }
1113
1224
  }
1114
- const successCount = await removeFromTools(name, tools, scope);
1225
+ const successCount = await removeFromTools(name, type, tools, scope);
1115
1226
  console.log("");
1116
1227
  if (successCount > 0) {
1117
1228
  console.log(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolr/seedr",
3
- "version": "0.1.52",
3
+ "version": "0.1.54",
4
4
  "description": "Seed your projects with AI configurations",
5
5
  "type": "module",
6
6
  "bin": {