dsh-plugin-capabilities 0.3.3 → 0.3.4
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/README.md +1 -1
- package/lib/client.js +3134 -324
- package/lib/client.js.map +4 -4
- package/lib/index.js +49 -9
- package/lib/index.js.map +3 -3
- package/package.json +3 -1
- package/src/client/MarkdownPreview.tsx +21 -0
- package/src/client/SkillsTab.tsx +7 -5
- package/src/client/css.ts +15 -0
- package/src/client/locales.ts +2 -2
- package/src/client/primitives.d.ts +0 -6
- package/src/routes.ts +48 -8
- package/src/skills.test.ts +24 -1
- package/src/skills.ts +23 -0
- package/src/smoke.test.ts +16 -1
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
|
|
3
|
+
import { dirname as dirname4, join as join10 } from "node:path";
|
|
4
4
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5
5
|
|
|
6
6
|
// src/agents.ts
|
|
@@ -174,7 +174,7 @@ function skipVoid(ctx, banNewLines, banComments) {
|
|
|
174
174
|
skipComment(ctx);
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
|
-
function skipUntil(ctx,
|
|
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 ===
|
|
188
|
+
} else if (c === end || c === sep2) {
|
|
189
189
|
return;
|
|
190
190
|
}
|
|
191
191
|
}
|
|
@@ -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 join9, sep } from "node:path";
|
|
774
775
|
|
|
775
776
|
// src/http.ts
|
|
776
777
|
async function readJsonBody(request) {
|
|
@@ -1371,6 +1372,20 @@ function setSkillPolicy(file, enabled) {
|
|
|
1371
1372
|
if (!enabled) kept.push("disable-model-invocation: true", "user-invocable: false");
|
|
1372
1373
|
writeFileSync3(file, `---${newline}${kept.join(newline)}${newline}---${body}`, "utf8");
|
|
1373
1374
|
}
|
|
1375
|
+
function updateSkillFile(file, input) {
|
|
1376
|
+
const text = readFileSync5(file, "utf8");
|
|
1377
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
|
|
1378
|
+
if (match === null) throw new Error("skill file has no frontmatter block");
|
|
1379
|
+
const newline = text.includes("\r\n---") ? "\r\n" : "\n";
|
|
1380
|
+
const lines = match[1].split(/\r?\n/);
|
|
1381
|
+
const kept = lines.filter((line) => !/^(name|description|whenToUse|disable-model-invocation|user-invocable):/.test(line));
|
|
1382
|
+
const head = [`name: ${input.name}`, `description: ${quote(input.description)}`];
|
|
1383
|
+
if (input.whenToUse !== void 0 && input.whenToUse !== "") head.push(`whenToUse: ${quote(input.whenToUse)}`);
|
|
1384
|
+
if (!input.modelInvocable) kept.push("disable-model-invocation: true");
|
|
1385
|
+
if (!input.userInvocable) kept.push("user-invocable: false");
|
|
1386
|
+
const body = input.content.replace(/\r\n/g, "\n").trim();
|
|
1387
|
+
writeFileSync3(file, `---${newline}${[...head, ...kept].join(newline)}${newline}---${newline}${newline}${body}${newline}`, "utf8");
|
|
1388
|
+
}
|
|
1374
1389
|
|
|
1375
1390
|
// src/mcp.ts
|
|
1376
1391
|
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
@@ -1550,10 +1565,25 @@ function removeMcp(profileDirPath, id) {
|
|
|
1550
1565
|
}
|
|
1551
1566
|
|
|
1552
1567
|
// src/routes.ts
|
|
1553
|
-
|
|
1554
|
-
|
|
1568
|
+
function customSkillWritable(dir, dshHome) {
|
|
1569
|
+
const state = pluginStateDir(dshHome);
|
|
1570
|
+
if (dir === state || dir.startsWith(state + sep)) return true;
|
|
1571
|
+
return loadState(dshHome).skillRoots.some((entry) => entry.roots.some((root) => dir === root || dir.startsWith(root + sep)));
|
|
1572
|
+
}
|
|
1573
|
+
function skillWritable(skill, dir, dshHome) {
|
|
1574
|
+
if (dir === void 0) return false;
|
|
1575
|
+
if (skill.source === "user-dsh") return true;
|
|
1576
|
+
return skill.source === "custom" && customSkillWritable(dir, dshHome);
|
|
1577
|
+
}
|
|
1578
|
+
function toSkillRow(skill, dshHome) {
|
|
1555
1579
|
const dir = skill.resourceBase?.kind === "directory" ? skill.resourceBase.path : void 0;
|
|
1556
|
-
return {
|
|
1580
|
+
return {
|
|
1581
|
+
...skill,
|
|
1582
|
+
editable: skillWritable(skill, dir, dshHome),
|
|
1583
|
+
removable: skill.source === "user-dsh",
|
|
1584
|
+
...dir !== void 0 ? { dir } : {},
|
|
1585
|
+
policyEditable: dir !== void 0
|
|
1586
|
+
};
|
|
1557
1587
|
}
|
|
1558
1588
|
function toRootView(entry) {
|
|
1559
1589
|
return { ...entry, live: entry.roots.every((root) => rootExists(root)) };
|
|
@@ -1571,7 +1601,7 @@ function mountCapabilitiesRoutes(host, config) {
|
|
|
1571
1601
|
}
|
|
1572
1602
|
try {
|
|
1573
1603
|
const skills = await host.skills.list();
|
|
1574
|
-
sendJson(response, 200, { skills: skills.map(toSkillRow) });
|
|
1604
|
+
sendJson(response, 200, { skills: skills.map((skill) => toSkillRow(skill, process.env.DSH_HOME)) });
|
|
1575
1605
|
} catch (error) {
|
|
1576
1606
|
sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
1577
1607
|
}
|
|
@@ -1628,7 +1658,17 @@ function mountCapabilitiesRoutes(host, config) {
|
|
|
1628
1658
|
sendJson(response, 400, { error: invalid });
|
|
1629
1659
|
return;
|
|
1630
1660
|
}
|
|
1631
|
-
|
|
1661
|
+
const existing = (await host.skills.list()).find((skill) => skill.name === input.name);
|
|
1662
|
+
if (existing !== void 0) {
|
|
1663
|
+
const dir = existing.resourceBase?.kind === "directory" ? existing.resourceBase.path : void 0;
|
|
1664
|
+
if (!skillWritable(existing, dir, process.env.DSH_HOME)) {
|
|
1665
|
+
sendJson(response, 403, { error: `skills from source '${existing.source}' are read-only` });
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
updateSkillFile(join9(dir, "SKILL.md"), input);
|
|
1669
|
+
} else {
|
|
1670
|
+
writeSkill(input);
|
|
1671
|
+
}
|
|
1632
1672
|
sendJson(response, 200, { ok: true, name: input.name });
|
|
1633
1673
|
} catch (error) {
|
|
1634
1674
|
sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
@@ -2131,7 +2171,7 @@ function mountCapabilitiesRoutes(host, config) {
|
|
|
2131
2171
|
// src/index.ts
|
|
2132
2172
|
var name = "dsh-plugin-capabilities";
|
|
2133
2173
|
function packagedSkillsDir() {
|
|
2134
|
-
return
|
|
2174
|
+
return join10(dirname4(fileURLToPath2(import.meta.url)), "..", "skills");
|
|
2135
2175
|
}
|
|
2136
2176
|
var inject = ["webServer", "skills"];
|
|
2137
2177
|
function apply(ctx, config) {
|