dsh-plugin-capabilities 0.3.3 → 0.3.5

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.
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import { existsSync as existsSync7 } from "node:fs";
3
- import { dirname as dirname4, join as join9 } from "node:path";
3
+ import { dirname as dirname4, join as join11 } from "node:path";
4
4
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5
5
 
6
6
  // src/agents.ts
@@ -8,7 +8,7 @@ import { existsSync, readFileSync } from "node:fs";
8
8
  import { homedir } from "node:os";
9
9
  import { join } from "node:path";
10
10
 
11
- // node_modules/smol-toml/dist/date.js
11
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/date.js
12
12
  var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
13
13
  var TomlDate = class _TomlDate extends Date {
14
14
  #hasDate = false;
@@ -100,7 +100,7 @@ var TomlDate = class _TomlDate extends Date {
100
100
  }
101
101
  };
102
102
 
103
- // node_modules/smol-toml/dist/error.js
103
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/error.js
104
104
  function getLineColFromPtr(string, ptr) {
105
105
  let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
106
106
  return [lines.length, lines.pop().length + 1];
@@ -140,7 +140,7 @@ ${codeblock}`, options);
140
140
  }
141
141
  };
142
142
 
143
- // node_modules/smol-toml/dist/util.js
143
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/util.js
144
144
  function indexOfNewline(str, start = 0) {
145
145
  let idx = str.indexOf("\n", start);
146
146
  if (str.charCodeAt(idx - 1) === 13)
@@ -174,7 +174,7 @@ function skipVoid(ctx, banNewLines, banComments) {
174
174
  skipComment(ctx);
175
175
  }
176
176
  }
177
- function skipUntil(ctx, sep, end) {
177
+ function skipUntil(ctx, sep2, end) {
178
178
  let ptr = ctx.p;
179
179
  if (!end) {
180
180
  ptr = indexOfNewline(ctx.s, ptr);
@@ -185,7 +185,7 @@ function skipUntil(ctx, sep, end) {
185
185
  let c = ctx.s.charCodeAt(ctx.p);
186
186
  if (c === 35) {
187
187
  skipComment(ctx);
188
- } else if (c === end || c === sep) {
188
+ } else if (c === end || c === sep2) {
189
189
  return;
190
190
  }
191
191
  }
@@ -195,7 +195,7 @@ function skipUntil(ctx, sep, end) {
195
195
  });
196
196
  }
197
197
 
198
- // node_modules/smol-toml/dist/primitive.js
198
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/primitive.js
199
199
  var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
200
200
  var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
201
201
  var LEADING_ZERO = /^[+-]?0[0-9_]/;
@@ -351,7 +351,7 @@ function parseValue(ctx, integersAsBigInt, end) {
351
351
  return date;
352
352
  }
353
353
 
354
- // node_modules/smol-toml/dist/extract.js
354
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/extract.js
355
355
  function extractValue(ctx, end, integersAsBigInt) {
356
356
  let ptr = ctx.p;
357
357
  let c = ctx.s.charCodeAt(ptr);
@@ -384,7 +384,7 @@ function extractValue(ctx, end, integersAsBigInt) {
384
384
  return parseValue(ctx, integersAsBigInt, end);
385
385
  }
386
386
 
387
- // node_modules/smol-toml/dist/struct.js
387
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/struct.js
388
388
  var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
389
389
  function parseKey(ctx, end = "=") {
390
390
  let start = ctx.p;
@@ -526,7 +526,7 @@ function parseArray(ctx, integersAsBigInt) {
526
526
  });
527
527
  }
528
528
 
529
- // node_modules/smol-toml/dist/parse.js
529
+ // node_modules/.pnpm/smol-toml@1.8.0/node_modules/smol-toml/dist/parse.js
530
530
  function peekTable(key, table, meta, type) {
531
531
  let t = table;
532
532
  let m = meta;
@@ -771,6 +771,7 @@ function profileDir(profile, dshHome = process.env.DSH_HOME) {
771
771
 
772
772
  // src/routes.ts
773
773
  import { mkdirSync as mkdirSync6 } from "node:fs";
774
+ import { join as join10, sep } from "node:path";
774
775
 
775
776
  // src/http.ts
776
777
  async function readJsonBody(request) {
@@ -948,19 +949,58 @@ function openDirectory(dir) {
948
949
  }
949
950
 
950
951
  // src/repos.ts
951
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, rmSync as rmSync2, statSync as statSync2, symlinkSync } from "node:fs";
952
- import { basename, join as join6, resolve } from "node:path";
952
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2, symlinkSync } from "node:fs";
953
+ import { basename, join as join7, resolve } from "node:path";
954
+
955
+ // src/rmtree.ts
956
+ import { chmodSync, readdirSync, rmSync } from "node:fs";
957
+ import { join as join4 } from "node:path";
958
+ var RETRIES = { maxRetries: 10, retryDelay: 200 };
959
+ function clearReadOnly(dir) {
960
+ let entries;
961
+ try {
962
+ entries = readdirSync(dir, { withFileTypes: true });
963
+ } catch {
964
+ return;
965
+ }
966
+ for (const entry of entries) {
967
+ const child = join4(dir, entry.name);
968
+ if (entry.isDirectory()) {
969
+ try {
970
+ chmodSync(child, 511);
971
+ } catch {
972
+ }
973
+ clearReadOnly(child);
974
+ } else if (entry.isFile()) {
975
+ try {
976
+ chmodSync(child, 438);
977
+ } catch {
978
+ }
979
+ }
980
+ }
981
+ try {
982
+ chmodSync(dir, 511);
983
+ } catch {
984
+ }
985
+ }
986
+ function removeTree(path) {
987
+ try {
988
+ clearReadOnly(path);
989
+ } catch {
990
+ }
991
+ rmSync(path, { recursive: true, force: true, ...RETRIES });
992
+ }
953
993
 
954
994
  // src/state.ts
955
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, rmSync, writeFileSync } from "node:fs";
995
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "node:fs";
956
996
  import { homedir as homedir3 } from "node:os";
957
- import { join as join4 } from "node:path";
997
+ import { join as join5 } from "node:path";
958
998
  import { randomBytes } from "node:crypto";
959
999
  function pluginStateDir(dshHome = process.env.DSH_HOME) {
960
- return join4(dshHome ?? join4(homedir3(), ".dsh"), "dsh-plugin-capabilities");
1000
+ return join5(dshHome ?? join5(homedir3(), ".dsh"), "dsh-plugin-capabilities");
961
1001
  }
962
1002
  function statePath(dshHome) {
963
- return join4(pluginStateDir(dshHome), "state.json");
1003
+ return join5(pluginStateDir(dshHome), "state.json");
964
1004
  }
965
1005
  function emptyState() {
966
1006
  return { skillRoots: [] };
@@ -986,7 +1026,7 @@ function newEntryId(kind) {
986
1026
  return `${kind}-${randomBytes(4).toString("hex")}`;
987
1027
  }
988
1028
  function materialDirFor(entryId, dshHome) {
989
- return join4(pluginStateDir(dshHome), "repos", entryId);
1029
+ return join5(pluginStateDir(dshHome), "repos", entryId);
990
1030
  }
991
1031
  function addSkillRoot(entry, dshHome) {
992
1032
  const state = loadState(dshHome);
@@ -998,13 +1038,10 @@ function addSkillRoot(entry, dshHome) {
998
1038
  function removeSkillRoot(id, dshHome) {
999
1039
  const state = loadState(dshHome);
1000
1040
  const at = state.skillRoots.findIndex((entry) => entry.id === id);
1001
- if (at === -1) return false;
1041
+ if (at === -1) return void 0;
1002
1042
  const [removed] = state.skillRoots.splice(at, 1);
1003
1043
  saveState(state, dshHome);
1004
- if (removed.materialDir !== void 0) {
1005
- rmSync(removed.materialDir, { recursive: true, force: true, maxRetries: 2 });
1006
- }
1007
- return true;
1044
+ return removed;
1008
1045
  }
1009
1046
  function findRootByUrl(url, dshHome) {
1010
1047
  return loadState(dshHome).skillRoots.find((entry) => entry.url === url);
@@ -1013,7 +1050,7 @@ function findRootByUrl(url, dshHome) {
1013
1050
  // src/tar.ts
1014
1051
  import { gunzipSync } from "node:zlib";
1015
1052
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
1016
- import { dirname as dirname2, join as join5 } from "node:path";
1053
+ import { dirname as dirname2, join as join6 } from "node:path";
1017
1054
  var LIMITS = {
1018
1055
  /** Per-entry cap (a skill repo holds markdown and small assets). */
1019
1056
  entryBytes: 64 * 1024 * 1024,
@@ -1054,7 +1091,7 @@ function safeJoin(target, name2) {
1054
1091
  parts.push(part);
1055
1092
  }
1056
1093
  if (parts.length === 0) return null;
1057
- return join5(target, ...parts);
1094
+ return join6(target, ...parts);
1058
1095
  }
1059
1096
  function paxRecords(content) {
1060
1097
  const out = /* @__PURE__ */ new Map();
@@ -1158,42 +1195,42 @@ function looksLikeSkillFile(file) {
1158
1195
  function holdsSkills(dir) {
1159
1196
  let entries;
1160
1197
  try {
1161
- entries = readdirSync(dir);
1198
+ entries = readdirSync2(dir);
1162
1199
  } catch {
1163
1200
  return false;
1164
1201
  }
1165
- if (existsSync4(join6(dir, "SKILL.md"))) return true;
1202
+ if (existsSync4(join7(dir, "SKILL.md"))) return true;
1166
1203
  for (const name2 of entries) {
1167
- if (name2.endsWith(".md") && looksLikeSkillFile(join6(dir, name2))) return true;
1204
+ if (name2.endsWith(".md") && looksLikeSkillFile(join7(dir, name2))) return true;
1168
1205
  }
1169
1206
  for (const name2 of entries) {
1170
- const child = join6(dir, name2);
1207
+ const child = join7(dir, name2);
1171
1208
  try {
1172
- if (statSync2(child).isDirectory() && existsSync4(join6(child, "SKILL.md"))) return true;
1209
+ if (statSync2(child).isDirectory() && existsSync4(join7(child, "SKILL.md"))) return true;
1173
1210
  } catch {
1174
1211
  }
1175
1212
  }
1176
1213
  return false;
1177
1214
  }
1178
1215
  function detectSkillRoots(checkout) {
1179
- if (existsSync4(join6(checkout, "SKILL.md"))) return { roots: [], single: true };
1216
+ if (existsSync4(join7(checkout, "SKILL.md"))) return { roots: [], single: true };
1180
1217
  const roots = [];
1181
1218
  if (holdsSkills(checkout)) roots.push(checkout);
1182
1219
  let entries;
1183
1220
  try {
1184
- entries = readdirSync(checkout);
1221
+ entries = readdirSync2(checkout);
1185
1222
  } catch {
1186
1223
  return { roots, single: false };
1187
1224
  }
1188
1225
  for (const name2 of entries) {
1189
1226
  if (name2.startsWith(".")) continue;
1190
- const child = join6(checkout, name2);
1227
+ const child = join7(checkout, name2);
1191
1228
  try {
1192
1229
  if (!statSync2(child).isDirectory()) continue;
1193
1230
  } catch {
1194
1231
  continue;
1195
1232
  }
1196
- if (existsSync4(join6(child, "SKILL.md"))) continue;
1233
+ if (existsSync4(join7(child, "SKILL.md"))) continue;
1197
1234
  if (holdsSkills(child)) roots.push(child);
1198
1235
  }
1199
1236
  return { roots, single: false };
@@ -1210,12 +1247,12 @@ async function addLocalRepo(path, dshHome) {
1210
1247
  if (detected.single) {
1211
1248
  const id = newEntryId("local");
1212
1249
  const material = materialDirFor(id, dshHome);
1213
- rmSync2(material, { recursive: true, force: true });
1250
+ removeTree(material);
1214
1251
  mkdirSync3(material, { recursive: true });
1215
1252
  try {
1216
- symlinkSync(resolved, join6(material, "skill"), process.platform === "win32" ? "junction" : "dir");
1253
+ symlinkSync(resolved, join7(material, "skill"), process.platform === "win32" ? "junction" : "dir");
1217
1254
  } catch {
1218
- rmSync2(material, { recursive: true, force: true });
1255
+ removeTree(material);
1219
1256
  throw new Error("single-skill local folders need a directory link; try adding their parent folder instead");
1220
1257
  }
1221
1258
  return addSkillRoot({ id, kind: "local", label: basename(resolved), path: resolved, roots: [material], materialDir: material }, dshHome);
@@ -1235,8 +1272,8 @@ async function addGitRepo(url, options = {}) {
1235
1272
  if (archive.byteLength > TARBALL_MAX_BYTES) throw new Error("repository tarball too large");
1236
1273
  const id = newEntryId("git");
1237
1274
  const material = materialDirFor(id, options.dshHome);
1238
- rmSync2(material, { recursive: true, force: true });
1239
- const checkout = join6(material, "repo");
1275
+ removeTree(material);
1276
+ const checkout = join7(material, "repo");
1240
1277
  try {
1241
1278
  mkdirSync3(checkout, { recursive: true });
1242
1279
  extractTarGz(archive, checkout, { stripComponents: 1 });
@@ -1250,7 +1287,7 @@ async function addGitRepo(url, options = {}) {
1250
1287
  options.dshHome
1251
1288
  );
1252
1289
  } catch (error) {
1253
- rmSync2(material, { recursive: true, force: true });
1290
+ removeTree(material);
1254
1291
  throw error;
1255
1292
  }
1256
1293
  }
@@ -1309,12 +1346,12 @@ function restartOwnedByShell(env = process.env) {
1309
1346
  }
1310
1347
 
1311
1348
  // src/skills.ts
1312
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
1349
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
1313
1350
  import { homedir as homedir4 } from "node:os";
1314
- import { join as join7 } from "node:path";
1351
+ import { join as join8 } from "node:path";
1315
1352
  var SKILL_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1316
1353
  function userSkillsDir(dshHome = process.env.DSH_HOME) {
1317
- return join7(dshHome ?? join7(homedir4(), ".dsh"), "skills");
1354
+ return join8(dshHome ?? join8(homedir4(), ".dsh"), "skills");
1318
1355
  }
1319
1356
  function quote(value) {
1320
1357
  return JSON.stringify(value);
@@ -1344,12 +1381,12 @@ function validateSkillInput(input) {
1344
1381
  return null;
1345
1382
  }
1346
1383
  function skillDir(name2, dshHome) {
1347
- return join7(userSkillsDir(dshHome), name2);
1384
+ return join8(userSkillsDir(dshHome), name2);
1348
1385
  }
1349
1386
  function writeSkill(input, dshHome) {
1350
1387
  const dir = skillDir(input.name, dshHome);
1351
1388
  mkdirSync4(dir, { recursive: true });
1352
- const file = join7(dir, "SKILL.md");
1389
+ const file = join8(dir, "SKILL.md");
1353
1390
  writeFileSync3(file, serializeSkill(input), "utf8");
1354
1391
  return file;
1355
1392
  }
@@ -1357,7 +1394,7 @@ function deleteSkill(name2, dshHome) {
1357
1394
  if (!SKILL_NAME_RE.test(name2)) return false;
1358
1395
  const dir = skillDir(name2, dshHome);
1359
1396
  if (!existsSync5(dir) || !statSync3(dir).isDirectory()) return false;
1360
- rmSync3(dir, { recursive: true, force: true });
1397
+ rmSync2(dir, { recursive: true, force: true });
1361
1398
  return true;
1362
1399
  }
1363
1400
  function setSkillPolicy(file, enabled) {
@@ -1371,15 +1408,29 @@ function setSkillPolicy(file, enabled) {
1371
1408
  if (!enabled) kept.push("disable-model-invocation: true", "user-invocable: false");
1372
1409
  writeFileSync3(file, `---${newline}${kept.join(newline)}${newline}---${body}`, "utf8");
1373
1410
  }
1411
+ function updateSkillFile(file, input) {
1412
+ const text = readFileSync5(file, "utf8");
1413
+ const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
1414
+ if (match === null) throw new Error("skill file has no frontmatter block");
1415
+ const newline = text.includes("\r\n---") ? "\r\n" : "\n";
1416
+ const lines = match[1].split(/\r?\n/);
1417
+ const kept = lines.filter((line) => !/^(name|description|whenToUse|disable-model-invocation|user-invocable):/.test(line));
1418
+ const head = [`name: ${input.name}`, `description: ${quote(input.description)}`];
1419
+ if (input.whenToUse !== void 0 && input.whenToUse !== "") head.push(`whenToUse: ${quote(input.whenToUse)}`);
1420
+ if (!input.modelInvocable) kept.push("disable-model-invocation: true");
1421
+ if (!input.userInvocable) kept.push("user-invocable: false");
1422
+ const body = input.content.replace(/\r\n/g, "\n").trim();
1423
+ writeFileSync3(file, `---${newline}${[...head, ...kept].join(newline)}${newline}---${newline}${newline}${body}${newline}`, "utf8");
1424
+ }
1374
1425
 
1375
1426
  // src/mcp.ts
1376
1427
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
1377
- import { join as join8 } from "node:path";
1428
+ import { join as join9 } from "node:path";
1378
1429
  import { parseDocument, Document } from "yaml";
1379
1430
  var MCP_PLUGIN = "@deepseek-ai/dsh-mcp-client";
1380
1431
  var SERVER_NAME_RE = /^[A-Za-z0-9_-]{1,32}$/;
1381
1432
  function loadPatch(profileDirPath) {
1382
- const path = join8(profileDirPath, "cordis.patch.yml");
1433
+ const path = join9(profileDirPath, "cordis.patch.yml");
1383
1434
  const text = existsSync6(path) ? readFileSync6(path, "utf8") : "[]";
1384
1435
  const doc = parseDocument(text);
1385
1436
  const contents = doc.contents;
@@ -1388,7 +1439,7 @@ function loadPatch(profileDirPath) {
1388
1439
  }
1389
1440
  function savePatch(profileDirPath, doc) {
1390
1441
  mkdirSync5(profileDirPath, { recursive: true });
1391
- writeFileSync4(join8(profileDirPath, "cordis.patch.yml"), String(doc), "utf8");
1442
+ writeFileSync4(join9(profileDirPath, "cordis.patch.yml"), String(doc), "utf8");
1392
1443
  }
1393
1444
  function toNode(value) {
1394
1445
  return new Document(value).contents;
@@ -1550,10 +1601,25 @@ function removeMcp(profileDirPath, id) {
1550
1601
  }
1551
1602
 
1552
1603
  // src/routes.ts
1553
- var EDITABLE_SOURCE = "user-dsh";
1554
- function toSkillRow(skill) {
1604
+ function customSkillWritable(dir, dshHome) {
1605
+ const state = pluginStateDir(dshHome);
1606
+ if (dir === state || dir.startsWith(state + sep)) return true;
1607
+ return loadState(dshHome).skillRoots.some((entry) => entry.roots.some((root) => dir === root || dir.startsWith(root + sep)));
1608
+ }
1609
+ function skillWritable(skill, dir, dshHome) {
1610
+ if (dir === void 0) return false;
1611
+ if (skill.source === "user-dsh") return true;
1612
+ return skill.source === "custom" && customSkillWritable(dir, dshHome);
1613
+ }
1614
+ function toSkillRow(skill, dshHome) {
1555
1615
  const dir = skill.resourceBase?.kind === "directory" ? skill.resourceBase.path : void 0;
1556
- return { ...skill, editable: skill.source === EDITABLE_SOURCE, ...dir !== void 0 ? { dir } : {}, policyEditable: dir !== void 0 };
1616
+ return {
1617
+ ...skill,
1618
+ editable: skillWritable(skill, dir, dshHome),
1619
+ removable: skill.source === "user-dsh",
1620
+ ...dir !== void 0 ? { dir } : {},
1621
+ policyEditable: dir !== void 0
1622
+ };
1557
1623
  }
1558
1624
  function toRootView(entry) {
1559
1625
  return { ...entry, live: entry.roots.every((root) => rootExists(root)) };
@@ -1571,7 +1637,7 @@ function mountCapabilitiesRoutes(host, config) {
1571
1637
  }
1572
1638
  try {
1573
1639
  const skills = await host.skills.list();
1574
- sendJson(response, 200, { skills: skills.map(toSkillRow) });
1640
+ sendJson(response, 200, { skills: skills.map((skill) => toSkillRow(skill, process.env.DSH_HOME)) });
1575
1641
  } catch (error) {
1576
1642
  sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
1577
1643
  }
@@ -1628,7 +1694,17 @@ function mountCapabilitiesRoutes(host, config) {
1628
1694
  sendJson(response, 400, { error: invalid });
1629
1695
  return;
1630
1696
  }
1631
- writeSkill(input);
1697
+ const existing = (await host.skills.list()).find((skill) => skill.name === input.name);
1698
+ if (existing !== void 0) {
1699
+ const dir = existing.resourceBase?.kind === "directory" ? existing.resourceBase.path : void 0;
1700
+ if (!skillWritable(existing, dir, process.env.DSH_HOME)) {
1701
+ sendJson(response, 403, { error: `skills from source '${existing.source}' are read-only` });
1702
+ return;
1703
+ }
1704
+ updateSkillFile(join10(dir, "SKILL.md"), input);
1705
+ } else {
1706
+ writeSkill(input);
1707
+ }
1632
1708
  sendJson(response, 200, { ok: true, name: input.name });
1633
1709
  } catch (error) {
1634
1710
  sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
@@ -1817,12 +1893,13 @@ function mountCapabilitiesRoutes(host, config) {
1817
1893
  sendJson(response, 400, { error: "id is required" });
1818
1894
  return;
1819
1895
  }
1820
- const ok = removeSkillRoot(body.id);
1821
- if (!ok) {
1896
+ const removed = removeSkillRoot(body.id);
1897
+ if (removed === void 0) {
1822
1898
  sendJson(response, 404, { error: "repository not found" });
1823
1899
  return;
1824
1900
  }
1825
1901
  await config.remountProvider();
1902
+ if (removed.materialDir !== void 0) removeTree(removed.materialDir);
1826
1903
  sendJson(response, 200, { ok: true });
1827
1904
  } catch (error) {
1828
1905
  sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
@@ -2131,7 +2208,7 @@ function mountCapabilitiesRoutes(host, config) {
2131
2208
  // src/index.ts
2132
2209
  var name = "dsh-plugin-capabilities";
2133
2210
  function packagedSkillsDir() {
2134
- return join9(dirname4(fileURLToPath2(import.meta.url)), "..", "skills");
2211
+ return join11(dirname4(fileURLToPath2(import.meta.url)), "..", "skills");
2135
2212
  }
2136
2213
  var inject = ["webServer", "skills"];
2137
2214
  function apply(ctx, config) {