dsh-plugin-capabilities 0.3.4 → 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 join10 } 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)
@@ -195,7 +195,7 @@ function skipUntil(ctx, sep2, 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,7 +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 join9, sep } from "node:path";
774
+ import { join as join10, sep } from "node:path";
775
775
 
776
776
  // src/http.ts
777
777
  async function readJsonBody(request) {
@@ -949,19 +949,58 @@ function openDirectory(dir) {
949
949
  }
950
950
 
951
951
  // src/repos.ts
952
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, rmSync as rmSync2, statSync as statSync2, symlinkSync } from "node:fs";
953
- 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
+ }
954
993
 
955
994
  // src/state.ts
956
- 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";
957
996
  import { homedir as homedir3 } from "node:os";
958
- import { join as join4 } from "node:path";
997
+ import { join as join5 } from "node:path";
959
998
  import { randomBytes } from "node:crypto";
960
999
  function pluginStateDir(dshHome = process.env.DSH_HOME) {
961
- return join4(dshHome ?? join4(homedir3(), ".dsh"), "dsh-plugin-capabilities");
1000
+ return join5(dshHome ?? join5(homedir3(), ".dsh"), "dsh-plugin-capabilities");
962
1001
  }
963
1002
  function statePath(dshHome) {
964
- return join4(pluginStateDir(dshHome), "state.json");
1003
+ return join5(pluginStateDir(dshHome), "state.json");
965
1004
  }
966
1005
  function emptyState() {
967
1006
  return { skillRoots: [] };
@@ -987,7 +1026,7 @@ function newEntryId(kind) {
987
1026
  return `${kind}-${randomBytes(4).toString("hex")}`;
988
1027
  }
989
1028
  function materialDirFor(entryId, dshHome) {
990
- return join4(pluginStateDir(dshHome), "repos", entryId);
1029
+ return join5(pluginStateDir(dshHome), "repos", entryId);
991
1030
  }
992
1031
  function addSkillRoot(entry, dshHome) {
993
1032
  const state = loadState(dshHome);
@@ -999,13 +1038,10 @@ function addSkillRoot(entry, dshHome) {
999
1038
  function removeSkillRoot(id, dshHome) {
1000
1039
  const state = loadState(dshHome);
1001
1040
  const at = state.skillRoots.findIndex((entry) => entry.id === id);
1002
- if (at === -1) return false;
1041
+ if (at === -1) return void 0;
1003
1042
  const [removed] = state.skillRoots.splice(at, 1);
1004
1043
  saveState(state, dshHome);
1005
- if (removed.materialDir !== void 0) {
1006
- rmSync(removed.materialDir, { recursive: true, force: true, maxRetries: 2 });
1007
- }
1008
- return true;
1044
+ return removed;
1009
1045
  }
1010
1046
  function findRootByUrl(url, dshHome) {
1011
1047
  return loadState(dshHome).skillRoots.find((entry) => entry.url === url);
@@ -1014,7 +1050,7 @@ function findRootByUrl(url, dshHome) {
1014
1050
  // src/tar.ts
1015
1051
  import { gunzipSync } from "node:zlib";
1016
1052
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
1017
- import { dirname as dirname2, join as join5 } from "node:path";
1053
+ import { dirname as dirname2, join as join6 } from "node:path";
1018
1054
  var LIMITS = {
1019
1055
  /** Per-entry cap (a skill repo holds markdown and small assets). */
1020
1056
  entryBytes: 64 * 1024 * 1024,
@@ -1055,7 +1091,7 @@ function safeJoin(target, name2) {
1055
1091
  parts.push(part);
1056
1092
  }
1057
1093
  if (parts.length === 0) return null;
1058
- return join5(target, ...parts);
1094
+ return join6(target, ...parts);
1059
1095
  }
1060
1096
  function paxRecords(content) {
1061
1097
  const out = /* @__PURE__ */ new Map();
@@ -1159,42 +1195,42 @@ function looksLikeSkillFile(file) {
1159
1195
  function holdsSkills(dir) {
1160
1196
  let entries;
1161
1197
  try {
1162
- entries = readdirSync(dir);
1198
+ entries = readdirSync2(dir);
1163
1199
  } catch {
1164
1200
  return false;
1165
1201
  }
1166
- if (existsSync4(join6(dir, "SKILL.md"))) return true;
1202
+ if (existsSync4(join7(dir, "SKILL.md"))) return true;
1167
1203
  for (const name2 of entries) {
1168
- if (name2.endsWith(".md") && looksLikeSkillFile(join6(dir, name2))) return true;
1204
+ if (name2.endsWith(".md") && looksLikeSkillFile(join7(dir, name2))) return true;
1169
1205
  }
1170
1206
  for (const name2 of entries) {
1171
- const child = join6(dir, name2);
1207
+ const child = join7(dir, name2);
1172
1208
  try {
1173
- if (statSync2(child).isDirectory() && existsSync4(join6(child, "SKILL.md"))) return true;
1209
+ if (statSync2(child).isDirectory() && existsSync4(join7(child, "SKILL.md"))) return true;
1174
1210
  } catch {
1175
1211
  }
1176
1212
  }
1177
1213
  return false;
1178
1214
  }
1179
1215
  function detectSkillRoots(checkout) {
1180
- if (existsSync4(join6(checkout, "SKILL.md"))) return { roots: [], single: true };
1216
+ if (existsSync4(join7(checkout, "SKILL.md"))) return { roots: [], single: true };
1181
1217
  const roots = [];
1182
1218
  if (holdsSkills(checkout)) roots.push(checkout);
1183
1219
  let entries;
1184
1220
  try {
1185
- entries = readdirSync(checkout);
1221
+ entries = readdirSync2(checkout);
1186
1222
  } catch {
1187
1223
  return { roots, single: false };
1188
1224
  }
1189
1225
  for (const name2 of entries) {
1190
1226
  if (name2.startsWith(".")) continue;
1191
- const child = join6(checkout, name2);
1227
+ const child = join7(checkout, name2);
1192
1228
  try {
1193
1229
  if (!statSync2(child).isDirectory()) continue;
1194
1230
  } catch {
1195
1231
  continue;
1196
1232
  }
1197
- if (existsSync4(join6(child, "SKILL.md"))) continue;
1233
+ if (existsSync4(join7(child, "SKILL.md"))) continue;
1198
1234
  if (holdsSkills(child)) roots.push(child);
1199
1235
  }
1200
1236
  return { roots, single: false };
@@ -1211,12 +1247,12 @@ async function addLocalRepo(path, dshHome) {
1211
1247
  if (detected.single) {
1212
1248
  const id = newEntryId("local");
1213
1249
  const material = materialDirFor(id, dshHome);
1214
- rmSync2(material, { recursive: true, force: true });
1250
+ removeTree(material);
1215
1251
  mkdirSync3(material, { recursive: true });
1216
1252
  try {
1217
- symlinkSync(resolved, join6(material, "skill"), process.platform === "win32" ? "junction" : "dir");
1253
+ symlinkSync(resolved, join7(material, "skill"), process.platform === "win32" ? "junction" : "dir");
1218
1254
  } catch {
1219
- rmSync2(material, { recursive: true, force: true });
1255
+ removeTree(material);
1220
1256
  throw new Error("single-skill local folders need a directory link; try adding their parent folder instead");
1221
1257
  }
1222
1258
  return addSkillRoot({ id, kind: "local", label: basename(resolved), path: resolved, roots: [material], materialDir: material }, dshHome);
@@ -1236,8 +1272,8 @@ async function addGitRepo(url, options = {}) {
1236
1272
  if (archive.byteLength > TARBALL_MAX_BYTES) throw new Error("repository tarball too large");
1237
1273
  const id = newEntryId("git");
1238
1274
  const material = materialDirFor(id, options.dshHome);
1239
- rmSync2(material, { recursive: true, force: true });
1240
- const checkout = join6(material, "repo");
1275
+ removeTree(material);
1276
+ const checkout = join7(material, "repo");
1241
1277
  try {
1242
1278
  mkdirSync3(checkout, { recursive: true });
1243
1279
  extractTarGz(archive, checkout, { stripComponents: 1 });
@@ -1251,7 +1287,7 @@ async function addGitRepo(url, options = {}) {
1251
1287
  options.dshHome
1252
1288
  );
1253
1289
  } catch (error) {
1254
- rmSync2(material, { recursive: true, force: true });
1290
+ removeTree(material);
1255
1291
  throw error;
1256
1292
  }
1257
1293
  }
@@ -1310,12 +1346,12 @@ function restartOwnedByShell(env = process.env) {
1310
1346
  }
1311
1347
 
1312
1348
  // src/skills.ts
1313
- 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";
1314
1350
  import { homedir as homedir4 } from "node:os";
1315
- import { join as join7 } from "node:path";
1351
+ import { join as join8 } from "node:path";
1316
1352
  var SKILL_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1317
1353
  function userSkillsDir(dshHome = process.env.DSH_HOME) {
1318
- return join7(dshHome ?? join7(homedir4(), ".dsh"), "skills");
1354
+ return join8(dshHome ?? join8(homedir4(), ".dsh"), "skills");
1319
1355
  }
1320
1356
  function quote(value) {
1321
1357
  return JSON.stringify(value);
@@ -1345,12 +1381,12 @@ function validateSkillInput(input) {
1345
1381
  return null;
1346
1382
  }
1347
1383
  function skillDir(name2, dshHome) {
1348
- return join7(userSkillsDir(dshHome), name2);
1384
+ return join8(userSkillsDir(dshHome), name2);
1349
1385
  }
1350
1386
  function writeSkill(input, dshHome) {
1351
1387
  const dir = skillDir(input.name, dshHome);
1352
1388
  mkdirSync4(dir, { recursive: true });
1353
- const file = join7(dir, "SKILL.md");
1389
+ const file = join8(dir, "SKILL.md");
1354
1390
  writeFileSync3(file, serializeSkill(input), "utf8");
1355
1391
  return file;
1356
1392
  }
@@ -1358,7 +1394,7 @@ function deleteSkill(name2, dshHome) {
1358
1394
  if (!SKILL_NAME_RE.test(name2)) return false;
1359
1395
  const dir = skillDir(name2, dshHome);
1360
1396
  if (!existsSync5(dir) || !statSync3(dir).isDirectory()) return false;
1361
- rmSync3(dir, { recursive: true, force: true });
1397
+ rmSync2(dir, { recursive: true, force: true });
1362
1398
  return true;
1363
1399
  }
1364
1400
  function setSkillPolicy(file, enabled) {
@@ -1389,12 +1425,12 @@ function updateSkillFile(file, input) {
1389
1425
 
1390
1426
  // src/mcp.ts
1391
1427
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
1392
- import { join as join8 } from "node:path";
1428
+ import { join as join9 } from "node:path";
1393
1429
  import { parseDocument, Document } from "yaml";
1394
1430
  var MCP_PLUGIN = "@deepseek-ai/dsh-mcp-client";
1395
1431
  var SERVER_NAME_RE = /^[A-Za-z0-9_-]{1,32}$/;
1396
1432
  function loadPatch(profileDirPath) {
1397
- const path = join8(profileDirPath, "cordis.patch.yml");
1433
+ const path = join9(profileDirPath, "cordis.patch.yml");
1398
1434
  const text = existsSync6(path) ? readFileSync6(path, "utf8") : "[]";
1399
1435
  const doc = parseDocument(text);
1400
1436
  const contents = doc.contents;
@@ -1403,7 +1439,7 @@ function loadPatch(profileDirPath) {
1403
1439
  }
1404
1440
  function savePatch(profileDirPath, doc) {
1405
1441
  mkdirSync5(profileDirPath, { recursive: true });
1406
- writeFileSync4(join8(profileDirPath, "cordis.patch.yml"), String(doc), "utf8");
1442
+ writeFileSync4(join9(profileDirPath, "cordis.patch.yml"), String(doc), "utf8");
1407
1443
  }
1408
1444
  function toNode(value) {
1409
1445
  return new Document(value).contents;
@@ -1665,7 +1701,7 @@ function mountCapabilitiesRoutes(host, config) {
1665
1701
  sendJson(response, 403, { error: `skills from source '${existing.source}' are read-only` });
1666
1702
  return;
1667
1703
  }
1668
- updateSkillFile(join9(dir, "SKILL.md"), input);
1704
+ updateSkillFile(join10(dir, "SKILL.md"), input);
1669
1705
  } else {
1670
1706
  writeSkill(input);
1671
1707
  }
@@ -1857,12 +1893,13 @@ function mountCapabilitiesRoutes(host, config) {
1857
1893
  sendJson(response, 400, { error: "id is required" });
1858
1894
  return;
1859
1895
  }
1860
- const ok = removeSkillRoot(body.id);
1861
- if (!ok) {
1896
+ const removed = removeSkillRoot(body.id);
1897
+ if (removed === void 0) {
1862
1898
  sendJson(response, 404, { error: "repository not found" });
1863
1899
  return;
1864
1900
  }
1865
1901
  await config.remountProvider();
1902
+ if (removed.materialDir !== void 0) removeTree(removed.materialDir);
1866
1903
  sendJson(response, 200, { ok: true });
1867
1904
  } catch (error) {
1868
1905
  sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
@@ -2171,7 +2208,7 @@ function mountCapabilitiesRoutes(host, config) {
2171
2208
  // src/index.ts
2172
2209
  var name = "dsh-plugin-capabilities";
2173
2210
  function packagedSkillsDir() {
2174
- return join10(dirname4(fileURLToPath2(import.meta.url)), "..", "skills");
2211
+ return join11(dirname4(fileURLToPath2(import.meta.url)), "..", "skills");
2175
2212
  }
2176
2213
  var inject = ["webServer", "skills"];
2177
2214
  function apply(ctx, config) {