dsh-mcp-skills 0.2.0 → 0.2.2

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
@@ -67,16 +67,14 @@ dsh plugin --profile web remove dsh-mcp-skills
67
67
  发布到npm
68
68
 
69
69
  ```shell
70
- # 1. 补 package.json 元数据 + 新增 LICENSE 文件
70
+ # 1. 用官方 registry 重新登录(务必带 --registry,否则会登到镜像站)
71
+ npm login --registry=https://registry.npmjs.org --auth-type=web
71
72
  # 2. 确认包名可用
72
73
  npm view dsh-mcp-skills version
73
74
  # 3. 检查 tarball(务必含 cordis.patch.yml)
74
75
  npm pack --dry-run
75
76
  # 4. 发布(稳定版,不要 prerelease)
76
77
  npm publish
77
- # 5. 安装并重启
78
- dsh plugin --profile web add dsh-mcp-skills
79
- dsh web
80
78
  ```
81
79
 
82
80
 
package/lib/client.js CHANGED
@@ -14,6 +14,22 @@ window.__ModuleLoader__.load({
14
14
  let react = require('react')
15
15
  let _deepseek_ai_dsh_client_ui_primitives = require('@deepseek-ai/dsh-client-ui-primitives')
16
16
 
17
+ // Icon exports were renamed across host releases: older builds spell them
18
+ // `Icon<Name>Outline16`, current ones `Icon<Name>OutlineRegular`. Resolve
19
+ // each once so one bundle renders on either host (an undefined component
20
+ // type is React error #130).
21
+ var manageIcon = (name) =>
22
+ _deepseek_ai_dsh_client_ui_primitives['Icon' + name + 'OutlineRegular'] ||
23
+ _deepseek_ai_dsh_client_ui_primitives['Icon' + name + 'Outline16']
24
+ var ManageIcons = {
25
+ edit: manageIcon('Edit'),
26
+ loading: manageIcon('Loading'),
27
+ play: manageIcon('Play'),
28
+ plus: manageIcon('Plus'),
29
+ refresh: manageIcon('Refresh'),
30
+ trash: manageIcon('Trash'),
31
+ }
32
+
17
33
  // ── styles ────────────────────────────────────────────────────────────────
18
34
  var manageStylesId = 'dsh-mcp-skills/manage.module.css'
19
35
  var manageCss =
@@ -56,6 +72,35 @@ window.__ModuleLoader__.load({
56
72
  return error instanceof Error ? error.message : String(error)
57
73
  }
58
74
 
75
+ /** Render a section failure on screen instead of leaving a blank pane. */
76
+ function manageFailure(error) {
77
+ return react_jsx_runtime.jsx('div', {
78
+ className: manageStyles.error,
79
+ children: 'mcp-skills: ' + manageMessageOf(error),
80
+ })
81
+ }
82
+
83
+ /**
84
+ * Keeps one section's render failure visible. The host retires a
85
+ * registration whose component throws (its entry-error supervision
86
+ * channel), which shows up as an empty pane with no console error.
87
+ */
88
+ class ManageBoundary extends react.Component {
89
+ constructor(props) {
90
+ super(props)
91
+ this.state = { error: null }
92
+ }
93
+
94
+ static getDerivedStateFromError(error) {
95
+ return { error: error }
96
+ }
97
+
98
+ render() {
99
+ if (this.state.error !== null) return manageFailure(this.state.error)
100
+ return this.props.children
101
+ }
102
+ }
103
+
59
104
  /** One labeled field row inside a management form. */
60
105
  function ManageField({ label, children }) {
61
106
  return react_jsx_runtime.jsxs('label', {
@@ -316,7 +361,7 @@ window.__ModuleLoader__.load({
316
361
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
317
362
  variant: 'ghost',
318
363
  size: 'sm',
319
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, { size: 14 }),
364
+ icon: react_jsx_runtime.jsx(ManageIcons.refresh, { size: 14 }),
320
365
  disabled: busy,
321
366
  onClick: () => {
322
367
  load()
@@ -326,7 +371,7 @@ window.__ModuleLoader__.load({
326
371
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
327
372
  variant: 'primary',
328
373
  size: 'sm',
329
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
374
+ icon: react_jsx_runtime.jsx(ManageIcons.plus, { size: 14 }),
330
375
  disabled: busy,
331
376
  onClick: () => {
332
377
  if (fileInputRef.current !== null) fileInputRef.current.click()
@@ -387,7 +432,7 @@ window.__ModuleLoader__.load({
387
432
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
388
433
  variant: 'ghost',
389
434
  size: 'sm',
390
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 }),
435
+ icon: react_jsx_runtime.jsx(ManageIcons.trash, { size: 14 }),
391
436
  disabled: busy,
392
437
  onClick: () => {
393
438
  remove(skill.name)
@@ -558,7 +603,7 @@ window.__ModuleLoader__.load({
558
603
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
559
604
  variant: 'ghost',
560
605
  size: 'sm',
561
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, { size: 14 }),
606
+ icon: react_jsx_runtime.jsx(ManageIcons.refresh, { size: 14 }),
562
607
  disabled: busy,
563
608
  onClick: () => {
564
609
  load()
@@ -568,7 +613,7 @@ window.__ModuleLoader__.load({
568
613
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
569
614
  variant: 'primary',
570
615
  size: 'sm',
571
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
616
+ icon: react_jsx_runtime.jsx(ManageIcons.plus, { size: 14 }),
572
617
  onClick: () => {
573
618
  openForm(null)
574
619
  },
@@ -808,8 +853,8 @@ window.__ModuleLoader__.load({
808
853
  size: 'sm',
809
854
  icon:
810
855
  testing === server.name
811
- ? react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, { size: 14 })
812
- : react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, { size: 14 }),
856
+ ? react_jsx_runtime.jsx(ManageIcons.loading, { size: 14 })
857
+ : react_jsx_runtime.jsx(ManageIcons.play, { size: 14 }),
813
858
  disabled: busy || testing !== null,
814
859
  onClick: () => {
815
860
  test(server.name)
@@ -819,7 +864,7 @@ window.__ModuleLoader__.load({
819
864
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
820
865
  variant: 'ghost',
821
866
  size: 'sm',
822
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 }),
867
+ icon: react_jsx_runtime.jsx(ManageIcons.edit, { size: 14 }),
823
868
  disabled: busy || testing !== null,
824
869
  onClick: () => {
825
870
  openForm(server)
@@ -829,7 +874,7 @@ window.__ModuleLoader__.load({
829
874
  react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.Button, {
830
875
  variant: 'ghost',
831
876
  size: 'sm',
832
- icon: react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 }),
877
+ icon: react_jsx_runtime.jsx(ManageIcons.trash, { size: 14 }),
833
878
  disabled: busy || testing !== null,
834
879
  onClick: () => {
835
880
  remove(server.name)
@@ -979,7 +1024,17 @@ window.__ModuleLoader__.load({
979
1024
  )
980
1025
  var t = ctx.locale.bind(MANAGE_NS)
981
1026
  var api = buildManageApi()
982
- var injected = () => ({ api, t })
1027
+ /**
1028
+ * Hand each section its api and locale through the closure: a
1029
+ * registration's `inject` result is spread into props by the host, that
1030
+ * delivery has differed between host releases, and a registration whose
1031
+ * injected value cannot be built is retired without a console error (an
1032
+ * empty pane sitting next to a working nav entry).
1033
+ */
1034
+ var deliver = (Component) => (props) =>
1035
+ react_jsx_runtime.jsx(ManageBoundary, {
1036
+ children: react_jsx_runtime.jsx(Component, { api: api, t: t, close: props !== null && typeof props === 'object' ? props.close : undefined }),
1037
+ })
983
1038
  ctx.slots.inject(
984
1039
  'settings.section',
985
1040
  () =>
@@ -990,9 +1045,8 @@ window.__ModuleLoader__.load({
990
1045
  order: 30,
991
1046
  label: () => t('skills.nav'),
992
1047
  locale: MANAGE_NS,
993
- inject: injected,
994
1048
  },
995
- SkillsSection,
1049
+ deliver(SkillsSection),
996
1050
  ),
997
1051
  )
998
1052
  ctx.slots.inject(
@@ -1005,9 +1059,8 @@ window.__ModuleLoader__.load({
1005
1059
  order: 40,
1006
1060
  label: () => t('mcp.nav'),
1007
1061
  locale: MANAGE_NS,
1008
- inject: injected,
1009
1062
  },
1010
- McpSection,
1063
+ deliver(McpSection),
1011
1064
  ),
1012
1065
  )
1013
1066
  }
package/lib/index.js CHANGED
@@ -19,7 +19,7 @@ export const inject = []
19
19
 
20
20
  const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
21
21
  /** Kept in step with package.json (the smoke test reports it to the server). */
22
- const PLUGIN_VERSION = '0.2.0'
22
+ const PLUGIN_VERSION = '0.2.2'
23
23
  const MCP_CONFIG_FILENAME = 'mcp-servers.yaml'
24
24
  const MCP_PROFILE_ROW_PREFIX = 'mcp-'
25
25
  /** Same grammar as @deepseek-ai/dsh-mcp-client's SERVER_NAME_PATTERN. */
@@ -520,28 +520,50 @@ function scrubbedParentEnv() {
520
520
  * The MCP SDK is an optional peer dependency the host installation provides,
521
521
  * loaded on demand so a missing copy disables only the connection smoke test
522
522
  * instead of breaking the whole plugin at import time.
523
+ *
524
+ * The package was renamed across host releases, so both spellings are tried:
525
+ * `@modelcontextprotocol/client` (current) and `@modelcontextprotocol/sdk`
526
+ * (older). Both expose the same Client/transport API.
523
527
  */
524
528
  let mcpSdkPromise
525
529
  function loadMcpSdk() {
526
530
  if (mcpSdkPromise === undefined) {
527
- mcpSdkPromise = Promise.all([
528
- import('@modelcontextprotocol/sdk/client/index.js'),
529
- import('@modelcontextprotocol/sdk/client/stdio.js'),
530
- import('@modelcontextprotocol/sdk/client/streamableHttp.js'),
531
- ])
532
- .then(([index, stdio, streamableHttp]) => ({
533
- Client: index.Client,
534
- StdioClientTransport: stdio.StdioClientTransport,
535
- StreamableHTTPClientTransport: streamableHttp.StreamableHTTPClientTransport,
536
- }))
537
- .catch((error) => {
531
+ mcpSdkPromise = loadCurrentMcpSdk().catch((currentError) =>
532
+ loadLegacyMcpSdk().catch((legacyError) => {
538
533
  mcpSdkPromise = undefined // let a later call retry after a transient failure
539
- throw new ManageError('mcp-sdk-unavailable', `no MCP SDK in this installation: ${error instanceof Error ? error.message : String(error)}`)
540
- })
534
+ const reason = legacyError instanceof Error ? legacyError.message : String(legacyError)
535
+ const current = currentError instanceof Error ? currentError.message : String(currentError)
536
+ throw new ManageError('mcp-sdk-unavailable', `no MCP SDK in this installation (tried @modelcontextprotocol/client: ${current}; @modelcontextprotocol/sdk: ${reason})`)
537
+ }),
538
+ )
541
539
  }
542
540
  return mcpSdkPromise
543
541
  }
544
542
 
543
+ /** The current `@modelcontextprotocol/client` spelling. */
544
+ async function loadCurrentMcpSdk() {
545
+ const [main, stdio] = await Promise.all([import('@modelcontextprotocol/client'), import('@modelcontextprotocol/client/stdio')])
546
+ return {
547
+ Client: main.Client,
548
+ StdioClientTransport: stdio.StdioClientTransport,
549
+ StreamableHTTPClientTransport: main.StreamableHTTPClientTransport,
550
+ }
551
+ }
552
+
553
+ /** The older `@modelcontextprotocol/sdk` spelling. */
554
+ async function loadLegacyMcpSdk() {
555
+ const [index, stdio, streamableHttp] = await Promise.all([
556
+ import('@modelcontextprotocol/sdk/client/index.js'),
557
+ import('@modelcontextprotocol/sdk/client/stdio.js'),
558
+ import('@modelcontextprotocol/sdk/client/streamableHttp.js'),
559
+ ])
560
+ return {
561
+ Client: index.Client,
562
+ StdioClientTransport: stdio.StdioClientTransport,
563
+ StreamableHTTPClientTransport: streamableHttp.StreamableHTTPClientTransport,
564
+ }
565
+ }
566
+
545
567
  /** Connect to a server and list its tools (connection smoke test). */
546
568
  async function testMcpConnection(server) {
547
569
  const { Client, StdioClientTransport, StreamableHTTPClientTransport } = await loadMcpSdk()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mcp-skills",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "DeepSeek Harness web plugin: settings pages for managing user skills and MCP servers",
5
5
  "type": "module",
6
6
  "repository": {
@@ -41,9 +41,13 @@
41
41
  "yaml": "^2.4.0"
42
42
  },
43
43
  "peerDependencies": {
44
+ "@modelcontextprotocol/client": "^2.0.0",
44
45
  "@modelcontextprotocol/sdk": "^1.30.0"
45
46
  },
46
47
  "peerDependenciesMeta": {
48
+ "@modelcontextprotocol/client": {
49
+ "optional": true
50
+ },
47
51
  "@modelcontextprotocol/sdk": {
48
52
  "optional": true
49
53
  }