@max-null/dsh-skill-mcp-center 0.6.2 → 0.6.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 CHANGED
@@ -23,6 +23,12 @@ Skill 与 MCP 管理中心:在设置里管理 skills 与 MCP 服务器,右
23
23
 
24
24
  ![设置 → Skill & MCP](docs/shots/skill-mcp-1.png)
25
25
 
26
+ ### 设置页:MCP 开关的效力边界
27
+
28
+ DSH 的 `Loader.write()` 是空实现,面板上的启停只改内存树——所以 MCP 标签页顶部写明「开关只对本次运行生效,重启后恢复」;要长期禁用,给 `cordis.patch.yml` 的对应条目加 `disabled: true`。被面板关掉的条目会在卡片里标「本次运行已停用 · 重启恢复」,而 patch 里持久禁用的条目不标——两种「关」必须能区分:
29
+
30
+ ![MCP 开关的效力边界](docs/shots/mcp-switch-session-only.png)
31
+
26
32
  ### 侧栏:Skill 一览
27
33
 
28
34
  搜索 + 命名空间筛选(全部 / 全局 / 工作区),每条带开关与 `MD`(查看 SKILL.md)。**插件包内自带的 skill 同样列出**,并标出来源插件——下图里 8 个 `ssid-*` 来自 `dsh-skills`,而用户级的 `ssid-release` 没有来源标签,这正是两者的区别:
package/client.js CHANGED
@@ -223,6 +223,8 @@ var zhDict = {
223
223
  provider: "provider \xB7 {name}",
224
224
  addServer: "\uFF0B \u6DFB\u52A0 server",
225
225
  hotApplied: "\u589E\u5220\u6539\u70ED\u751F\u6548\uFF0C\u514D\u91CD\u542F",
226
+ switchSessionOnly: "\u5F00\u5173\u53EA\u5BF9\u672C\u6B21\u8FD0\u884C\u751F\u6548\uFF0C\u91CD\u542F\u540E\u6062\u590D\uFF08\u8981\u957F\u671F\u7981\u7528\uFF0C\u7ED9\u8BE5\u6761\u76EE\u52A0 disabled: true\uFF09",
227
+ switchReverted: "\u672C\u6B21\u8FD0\u884C\u5DF2\u505C\u7528 \xB7 \u91CD\u542F\u6062\u590D",
226
228
  edit: "\u7F16\u8F91",
227
229
  remove: "\u5220\u9664",
228
230
  disableServer: "\u505C\u7528\uFF08\u65AD\u5F00\u5E76\u91CA\u653E context\uFF09",
@@ -288,6 +290,8 @@ var enDict = {
288
290
  provider: "provider \xB7 {name}",
289
291
  addServer: "\uFF0B Add server",
290
292
  hotApplied: "hot-applied, no restart",
293
+ switchSessionOnly: "switch applies to this run only, reverted after restart (to disable for good, add disabled: true to the entry)",
294
+ switchReverted: "disabled for this run \xB7 restored on restart",
291
295
  edit: "Edit",
292
296
  remove: "Remove",
293
297
  disableServer: "Disable (disconnect & free context)",
@@ -659,6 +663,7 @@ function McpView() {
659
663
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-spacer" }),
660
664
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-sub", children: t("hotApplied") })
661
665
  ] }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-sub", style: { marginBottom: 8 }, children: t("switchSessionOnly") }),
662
667
  editing !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ServerForm, { server: editing === "new" ? null : editing, onClose: () => {
663
668
  setEditing(null);
664
669
  }, onSaved: () => {
@@ -690,7 +695,8 @@ function McpView() {
690
695
  }
691
696
  )
692
697
  ] }),
693
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-desc", children: s.transport === "stdio" ? `${s.command ?? ""} ${(s.args ?? []).join(" ")}` : s.url })
698
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-desc", children: s.transport === "stdio" ? `${s.command ?? ""} ${(s.args ?? []).join(" ")}` : s.url }),
699
+ s.disabled && s.sessionToggled === true && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-desc", children: t("switchReverted") })
694
700
  ] }, s.id))
695
701
  ] });
696
702
  }
package/dist/service.d.ts CHANGED
@@ -42,6 +42,13 @@ export interface McpServer {
42
42
  url?: string;
43
43
  headers?: Record<string, string>;
44
44
  disabled: boolean;
45
+ /**
46
+ * True when the switch was changed during this run. Lets the panel say
47
+ * "reverted on restart" only where that is true — an entry disabled in
48
+ * `cordis.patch.yml` stays disabled across restarts and must not be
49
+ * labelled as session-only.
50
+ */
51
+ sessionToggled: boolean;
45
52
  fiberPhase: string | null;
46
53
  }
47
54
  /** One tool a server contributes, as the management surface lists it. */
@@ -146,6 +153,8 @@ export declare function deleteTargetOf(path: string, roots: readonly string[]):
146
153
  export declare class SkillMcpService extends Service {
147
154
  static inject: string[];
148
155
  private readonly officialSkillDirs;
156
+ /** Ids toggled by the panel during this run (in-memory only, by design: the host does not persist it). */
157
+ private readonly sessionToggled;
149
158
  constructor(ctx: Context, config?: SkillConfig);
150
159
  /**
151
160
  * Skill roots that live **inside loaded plugin packages**.
@@ -207,7 +216,7 @@ export declare class SkillMcpService extends Service {
207
216
  updateMcpServer(id: string, config: McpConfig): Promise<void>;
208
217
  /** Remove one server — disconnects and unregisters its tools. */
209
218
  removeMcpServer(id: string): Promise<void>;
210
- /** Enable/disable one server without deleting its config. */
219
+ /** Enable/disable one server without deleting its config. The host does not persist this. */
211
220
  setMcpServerEnabled(id: string, enabled: boolean): Promise<void>;
212
221
  /** Runtime status per server: upstream `mcpStatus` seam when present, else derived. */
213
222
  mcpStatus(): Promise<McpServerStatus[]>;
package/dist/service.js CHANGED
@@ -232,6 +232,8 @@ export function deleteTargetOf(path, roots) {
232
232
  export class SkillMcpService extends Service {
233
233
  static inject = ['loader', 'tools'];
234
234
  officialSkillDirs;
235
+ /** Ids toggled by the panel during this run (in-memory only, by design: the host does not persist it). */
236
+ sessionToggled = new Set();
235
237
  constructor(ctx, config = {}) {
236
238
  super(ctx, 'skillMcp');
237
239
  this.officialSkillDirs = config.officialSkillDirs ?? [];
@@ -404,17 +406,23 @@ export class SkillMcpService extends Service {
404
406
  // plugin `name` ('mcp-client'); one entry = one MCP server.
405
407
  if (entry.options.name !== '@deepseek-ai/dsh-mcp-client')
406
408
  continue;
407
- const cfg = entry.options.config;
409
+ // `!!js` 表达式在 options.config 里保留为 { __jsExpr } 节点,求值结果在 fiber.config 上
410
+ // (与本仓库 pluginSkillRoots 同一个坑)。照 options 读会把表达式当值:
411
+ // command 渲染成 [object Object]、args 变成一串 JSON 转义。fiber 缺失时退回 options。
412
+ const evaluated = entry.fiber?.config;
413
+ const cfg = evaluated ?? entry.options.config;
414
+ const text = (value) => typeof value === 'string' ? value : value === undefined ? undefined : JSON.stringify(value);
408
415
  servers.push({
409
416
  id: entry.id,
410
417
  serverName: cfg?.serverName ?? entry.id,
411
418
  transport: cfg?.transport === 'streamable-http' ? 'streamable-http' : 'stdio',
412
- command: cfg?.command,
413
- args: cfg?.args,
414
- cwd: cfg?.cwd,
415
- url: cfg?.url,
419
+ command: text(cfg?.command),
420
+ args: cfg?.args?.map(arg => text(arg) ?? ''),
421
+ cwd: text(cfg?.cwd),
422
+ url: text(cfg?.url),
416
423
  headers: cfg?.headers,
417
424
  disabled: entry.disabled,
425
+ sessionToggled: this.sessionToggled.has(entry.id),
418
426
  fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state],
419
427
  });
420
428
  }
@@ -436,9 +444,12 @@ export class SkillMcpService extends Service {
436
444
  async removeMcpServer(id) {
437
445
  await this.ctx.loader.remove(id);
438
446
  }
439
- /** Enable/disable one server without deleting its config. */
447
+ /** Enable/disable one server without deleting its config. The host does not persist this. */
440
448
  async setMcpServerEnabled(id, enabled) {
441
449
  await this.ctx.loader.update(id, { disabled: enabled ? null : true });
450
+ // 记「本次运行改过」:Loader 根树的 write 是 no-op(loader lib/index.js 的 `write() {}`),
451
+ // 所以这里改的只是内存态;面板据此显示“重启后恢复”,而不是假装它是持久设置。
452
+ this.sessionToggled.add(id);
442
453
  }
443
454
  /** Runtime status per server: upstream `mcpStatus` seam when present, else derived. */
444
455
  async mcpStatus() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@max-null/dsh-skill-mcp-center",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Skill & MCP management center for DeepSeek Harness — manage skills and MCP servers in Settings, live MCP status in the sidebar",
5
5
  "license": "MIT",
6
6
  "publishConfig": {