@xxxyz/dsh-mcp-manager 2.2.1 → 2.2.3
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/client.js +8 -1
- package/lib/index.js +29 -47
- package/package.json +1 -1
- package/show.png +0 -0
package/lib/client.js
CHANGED
|
@@ -404,6 +404,11 @@ const factory = (require) => {
|
|
|
404
404
|
collapsed ? null : pItems.map((s) => {
|
|
405
405
|
const overridden = s.provider === 'dsh-mcp-manager-override'
|
|
406
406
|
const available = !!(s.invocation && s.invocation.modelInvocable)
|
|
407
|
+
// User-level filesystem skills are view-only: they live in
|
|
408
|
+
// the scoped layer which a global-layer override cannot
|
|
409
|
+
// shadow, and the plugin sandbox blocks writing their
|
|
410
|
+
// SKILL.md — so no enable/disable button is offered.
|
|
411
|
+
const userLevel = s.source === 'user-dsh' || s.source === 'user-agents'
|
|
407
412
|
return React.createElement('div', { className: 'mcpm-row', key: s.name },
|
|
408
413
|
React.createElement('div', { className: 'mcpm-row-head' },
|
|
409
414
|
React.createElement('span', { className: 'mcpm-name' }, s.name),
|
|
@@ -412,7 +417,9 @@ const factory = (require) => {
|
|
|
412
417
|
React.createElement('span', { className: 'mcpm-chip live' }, s.provider)),
|
|
413
418
|
React.createElement('div', { className: 'mcpm-sub' }, s.description || ''),
|
|
414
419
|
React.createElement('div', { className: 'mcpm-row-actions' },
|
|
415
|
-
|
|
420
|
+
userLevel
|
|
421
|
+
? React.createElement('span', { className: 'mcpm-note' }, '仅查看(由 DSH 文件系统管理)')
|
|
422
|
+
: React.createElement('button', { className: 'mcpm-btn', disabled: busy === s.name, onClick: () => toggle(s) }, overridden ? '启用' : '禁用')))
|
|
416
423
|
}))
|
|
417
424
|
}))
|
|
418
425
|
}))
|
package/lib/index.js
CHANGED
|
@@ -115,13 +115,12 @@ export default {
|
|
|
115
115
|
for (const name of await readState()) {
|
|
116
116
|
if (overrideSkills.has(name))
|
|
117
117
|
continue;
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
118
|
+
// Pre-2.2.2 migration: user-level skills are view-only now. Drop any
|
|
119
|
+
// stale state entry without touching the file — the sandbox blocks
|
|
120
|
+
// writing ~/.dsh/skills from a profile plugin, and an override could
|
|
121
|
+
// never shadow the scoped-layer filesystem entry anyway.
|
|
122
122
|
const userDef = await findUserSkill(name);
|
|
123
123
|
if (userDef) {
|
|
124
|
-
await editUserSkillInvocation(name, false);
|
|
125
124
|
changed = true;
|
|
126
125
|
continue;
|
|
127
126
|
}
|
|
@@ -143,11 +142,15 @@ export default {
|
|
|
143
142
|
// dsh-skill-filesystem in the agent-preset SCOPED layer, which a scope-less
|
|
144
143
|
// ctx.skills.snapshot({}) (global layer only) never reaches — so the
|
|
145
144
|
// management page would silently hide them. Scan the directory ourselves
|
|
146
|
-
// and merge into skill-list.
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
145
|
+
// and merge into skill-list.
|
|
146
|
+
//
|
|
147
|
+
// Disable/enable is NOT offered for user skills: (a) a rank-0 override in
|
|
148
|
+
// the global layer cannot shadow the scoped layer's filesystem entry
|
|
149
|
+
// (collectFresh merges layers; the nearest layer wins); (b) writing the
|
|
150
|
+
// SKILL.md frontmatter is blocked by the fs sandbox (profile plugin,
|
|
151
|
+
// workspace-write mode — ~/.dsh/skills is outside its scope). Users
|
|
152
|
+
// disable such skills by editing `user-invocable: false` in the file
|
|
153
|
+
// directly. DSH_MCP_MANAGER_SKILLS_DIR overrides the directory for tests.
|
|
151
154
|
function userSkillsDir(home, sep) {
|
|
152
155
|
const env = process.env.DSH_MCP_MANAGER_SKILLS_DIR;
|
|
153
156
|
return env && env.trim() ? env.trim() : home + sep + 'skills';
|
|
@@ -288,38 +291,18 @@ export default {
|
|
|
288
291
|
const skills = snap.skills.concat(extra).sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
289
292
|
return { ok: true, skills, complete: snap.complete !== false };
|
|
290
293
|
}
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const raw = await fs.readText(await fs.resolve(def.path)).catch(() => '');
|
|
304
|
-
if (!raw)
|
|
305
|
-
return { ok: false, error: '无法读取技能文件: ' + def.path };
|
|
306
|
-
// Strip any existing invocation flags from the frontmatter block, then
|
|
307
|
-
// re-append the ones matching the requested state. Everything else —
|
|
308
|
-
// body content and other frontmatter keys — is preserved verbatim.
|
|
309
|
-
const fmMatch = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
310
|
-
if (!fmMatch)
|
|
311
|
-
return { ok: false, error: '技能文件缺少 frontmatter: ' + def.path };
|
|
312
|
-
const fmLines = fmMatch[1].split(/\r?\n/);
|
|
313
|
-
const rest = raw.slice(fmMatch[0].length);
|
|
314
|
-
const stripped = fmLines.filter((line) => !/^(user-invocable|disable-model-invocation):/i.test(line.trim()));
|
|
315
|
-
if (!enabled) {
|
|
316
|
-
stripped.push('user-invocable: false');
|
|
317
|
-
stripped.push('disable-model-invocation: true');
|
|
318
|
-
}
|
|
319
|
-
const next = '---\n' + stripped.join('\n') + '\n---' + rest;
|
|
320
|
-
await fs.writeText(await fs.resolve(def.path), next);
|
|
321
|
-
return { ok: true };
|
|
322
|
-
}
|
|
294
|
+
// User-level skills (~/.dsh/skills) are VIEW-ONLY in this page. They are
|
|
295
|
+
// discovered by dsh-skill-filesystem in the agent-preset SCOPED layer; a
|
|
296
|
+
// scope-less snapshot({}) (global layer only) never sees them, so we scan
|
|
297
|
+
// the directory and merge rows into skill-list. Disable/enable is NOT
|
|
298
|
+
// supported for them: (a) the rank-0 override provider lives in the global
|
|
299
|
+
// layer and a scoped read merges the scope chain with the scoped entry
|
|
300
|
+
// winning the duplicate name outright (collectFresh last-wins), so an
|
|
301
|
+
// override cannot hide them from the / menu; (b) rewriting the SKILL.md
|
|
302
|
+
// frontmatter is blocked by the fs sandbox (profile plugin, workspace-write
|
|
303
|
+
// mode — ~/.dsh/skills is outside its scope). Users disable such skills by
|
|
304
|
+
// editing `user-invocable: false` in the file directly.
|
|
305
|
+
const USER_SKILL_VIEW_ONLY_ERROR = '用户级技能由 DSH 文件系统管理,仅支持查看;如需禁用请直接编辑 SKILL.md 的 user-invocable 字段';
|
|
323
306
|
async function skillToggle(args) {
|
|
324
307
|
const name = String(args.name || '').trim();
|
|
325
308
|
if (!name)
|
|
@@ -329,17 +312,16 @@ export default {
|
|
|
329
312
|
await ensureRestored();
|
|
330
313
|
const enabled = args.enabled !== false;
|
|
331
314
|
return withWriteLock(async () => {
|
|
332
|
-
// User-level skills bypass the override provider entirely — editing the
|
|
333
|
-
// SKILL.md frontmatter is what makes the real provider (and thus the
|
|
334
|
-
// / menu) see the change.
|
|
335
315
|
const userDef = await findUserSkill(name);
|
|
336
316
|
if (userDef) {
|
|
337
|
-
//
|
|
317
|
+
// Drop any stale override row created by older versions (pre-2.2.2
|
|
318
|
+
// migration) — it can never shadow the scoped entry anyway, and the
|
|
319
|
+
// toggle for user skills is not supported.
|
|
338
320
|
if (overrideSkills.delete(name)) {
|
|
339
321
|
await saveState([...overrideSkills.keys()]);
|
|
340
322
|
skillProviderControl?.invalidate();
|
|
341
323
|
}
|
|
342
|
-
return
|
|
324
|
+
return { ok: false, error: USER_SKILL_VIEW_ONLY_ERROR };
|
|
343
325
|
}
|
|
344
326
|
if (enabled) {
|
|
345
327
|
if (overrideSkills.delete(name)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xxxyz/dsh-mcp-manager",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "DSH-standard MCP manager plugin: Settings UI + HTTP API + model-facing mcp_manager_* tools. Install with one command: dsh plugin --profile web add @xxxyz/dsh-mcp-manager@latest",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
package/show.png
CHANGED
|
Binary file
|