@omdp/dsh-connector 0.3.5 → 0.3.7
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 +29 -4
- package/client.js +4 -1
- package/index.js +36 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# @omdp/dsh-connector
|
|
2
2
|
|
|
3
|
-
**MCP 服务器 + 用户 Skills + 魔搭市场浏览三合一设置页**(`v0.3.
|
|
3
|
+
**MCP 服务器 + 用户 Skills + 魔搭市场浏览三合一设置页**(`v0.3.7`)。适合需要在 DSH 里频繁增删改 MCP server / skills、又不想手改 `cordis.patch.yml` 的用户。
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- DeepSeek Harness 带 `web` profile GUI(`npx @deepseek-ai/dsh web`)
|
|
8
8
|
- Node.js `^22.19` 或 `>=24`
|
|
9
9
|
- `@deepseek-ai/schemastery` `3.18.1` / `3.18.2` / `3.18.4`(peer 枚举,供工具过滤的 Config 声明用;无则过滤静默全放行)
|
|
10
|
-
- 已实测 DSH **0.1.5-rc.1**(源码级核查,2026-09-10)、**0.1.5-rc.2** 与 **0.1.6-alpha.1**(源码级 + 运行时冒烟:`/connector/api/*` 正常服务、设置页渲染,2026-09-15,见 `docs/plugin-compatibility.md`)、**0.1.7-rc.1**(0.3.3 适配:修掉 import 期崩溃 + 迁移到 settings 托管配置,2026-09-24)、**0.1.7-rc.2**(0.3.5:rc.1→rc.2 tarball 逐文件 diff 零 API 变化 + rc.2
|
|
11
|
-
- **`@deepseek-ai/dsh` peer 声明 `0.1.7-rc.1 || 0.1.7-rc.2`**(0.3.4 起逐版本枚举,0.3.5 追加 rc.2;规范见 `AGENTS.md` 规范 3)
|
|
10
|
+
- 已实测 DSH **0.1.5-rc.1**(源码级核查,2026-09-10)、**0.1.5-rc.2** 与 **0.1.6-alpha.1**(源码级 + 运行时冒烟:`/connector/api/*` 正常服务、设置页渲染,2026-09-15,见 `docs/plugin-compatibility.md`)、**0.1.7-rc.1**(0.3.3 适配:修掉 import 期崩溃 + 迁移到 settings 托管配置,2026-09-24)、**0.1.7-rc.2**(0.3.5:rc.1→rc.2 tarball 逐文件 diff 零 API 变化 + rc.2 真机回归实测通过;0.3.6 再修 CRLF 解析 + 取当前 profile 补丁路径,2026-09-25)、**0.2.0-rc.1**(0.3.7:`lib/` 逐字节零变化 + 0.2.0 门禁放行 + 沙箱真机装配入树,2026-09-28)
|
|
11
|
+
- **`@deepseek-ai/dsh` peer 声明 `0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1`**(0.3.4 起逐版本枚举,0.3.5 追加 rc.2,0.3.7 追加 0.2.0-rc.1;规范见 `AGENTS.md` 规范 3)
|
|
12
12
|
|
|
13
13
|
## 兼容性门禁(0.3.4 起声明)
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
```json
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"@deepseek-ai/dsh": "0.1.7-rc.1 || 0.1.7-rc.2"
|
|
19
|
+
"@deepseek-ai/dsh": "0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1"
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
|---|---|
|
|
27
27
|
| **`0.1.7-rc.1`**(实测,2026-09-24) | ✅ `evaluatePluginCompatibility()` 返回 `undefined` ⇒ 正常加载,与 0.3.3 行为一致 |
|
|
28
28
|
| **`0.1.7-rc.2`**(实测,2026-09-25) | ✅ 同上:rc.1→rc.2 tarball 逐文件 diff 显示 shell/settings/credentials 的 `lib/` **零变化**(仅 README/package.json 版本号)、app-boot 的变更全部与插件无关;另在 scratch profile(`dsh@0.1.7-rc.2` + 本插件 0.3.4)真机回归 `/connector/api/mcp/filters` → 200 |
|
|
29
|
+
| **`0.2.0-rc.1`**(实测,2026-09-28) | ✅ `lib/` 逐字节零变化(`dsh-web-app`/`dsh-host-webserver` 等本插件依赖面在 rc.2→0.2.0-rc.1 全量文件 SHA1 一致);0.2.0-rc.1 门禁对本插件 0.3.7 判定放行;沙箱真机(官方 `dsh@0.2.0-rc.1` + 本插件)`--dump-config` 装配入树、零拦截 |
|
|
29
30
|
| **`0.1.7` 及更新的、未实测版本** | ⛔ 门禁拦下:启动时**整个 bundle 被跳过**(stderr 打 `skipping profile bundle "@omdp/dsh-connector"`),安装时该行被置灰 |
|
|
30
31
|
| **`≤0.1.6` 及 `0.1.7-alpha.x`** | ➖ **不受影响**:那些版本里**根本没有这个门禁**(经解包 npm tarball 逐版核对,`0.1.5-rc.2`/`0.1.5-rc.3`/`0.1.6-alpha.1`/`0.1.6-alpha.2`/`0.1.7-alpha.1`/`0.1.7-alpha.2` 的 `dsh-app-boot` 里 `evaluatePluginCompatibility` 出现 **0 次**,只有 `0.1.7-rc.1` 出现 4 次),旧运行时读到这条 peer 只是「不认识的声明」,照常加载 |
|
|
31
32
|
|
|
@@ -322,6 +323,30 @@ skills/mcp 列表与详情、证书/Hosted 标识、安装命令、记录来源
|
|
|
322
323
|
|
|
323
324
|
## 变更记录
|
|
324
325
|
|
|
326
|
+
- **0.3.7**(2026-09-28):**追加 DSH `0.2.0-rc.1` 支持**(peer 枚举 `0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1`,代码零改动)。
|
|
327
|
+
背景:DSH 桌面端升级到 `0.2.0-rc.1` 后,门禁把只声明到 `0.1.7-rc.2` 的 0.3.6 拦下 ——
|
|
328
|
+
表现是设置页里 Connector 整项消失、`/connector/api/*` 全部 **404**(`skipping profile bundle`,不是崩溃)。
|
|
329
|
+
核查依据:`0.1.7-rc.2 → 0.2.0-rc.1` 的 npm tarball 逐文件 diff(本插件依赖的
|
|
330
|
+
`dsh-web-app` / `dsh-host-webserver` / `dsh-credentials` / `dsh-settings` / `dsh-tools` / `dsh-mcp-client`
|
|
331
|
+
的 `lib/` **逐字节零变化**);用 0.2.0-rc.1 自带的 `evaluatePluginCompatibility()` 判定新声明为
|
|
332
|
+
**放行**;并沙箱安装官方 `@deepseek-ai/dsh@0.2.0-rc.1` + 本插件跑 `--dump-config` 真机装配入树、零拦截;
|
|
333
|
+
`npm pack` 产物经复核含新枚举。
|
|
334
|
+
- **0.3.6**(2026-09-25):**修两个真机 bug —— CRLF 补丁文件解析 + 编辑错 profile 的补丁文件**。
|
|
335
|
+
1. **CRLF 兼容**:`parseMcpServers()` 的键值正则 `^\s+(\w+):\s*(.*)$` 在 CRLF 文件上必然失配
|
|
336
|
+
(JS 里 `.*` 不匹配 `\r`、`$` 也不匹配 `\r` 之前的位置),于是每行的
|
|
337
|
+
`transport`/`serverName`/`command`/`url` 全部落进 `preserve` 桶:API 返回
|
|
338
|
+
`transport:"" serverName:""`,UI 的「工具过滤」区因 `if (!props.serverName) return null`
|
|
339
|
+
**静默消失**、transport 徽标退化成 `stdio`。修复:解析前用 `toLf()` 归一化换行(连同
|
|
340
|
+
`stripQuotes`/`stripListScalar` 的 `$` 正则一起恢复),写回时也统一成 LF。
|
|
341
|
+
验证:同一份配置文本按 LF / CRLF 两种形态跑解析,修复前 CRLF 五项断言全红、修复后 14/14 通过。
|
|
342
|
+
2. **profile 补丁路径**:`patchPath()` 曾硬编码 `profiles/web/cordis.patch.yml`,在桌面端
|
|
343
|
+
(跑 `profiles/desktop`)会去改 **另一个 profile** 的文件——写下去对自己的 MCP 配置毫无影响,
|
|
344
|
+
UI 提示还把错误路径显示给用户。修复:0.1.7+ 从 `ctx.get('profileContext').patchPath` 取当前
|
|
345
|
+
profile 的真实路径(`dsh-app-boot` 的 `ProfileContext` 契约),无该服务(0.1.5/0.1.6)时保留
|
|
346
|
+
历史路径;`GET /api/mcp` 一并回传 `patchPath`,设置页提示改成显示真实路径。
|
|
347
|
+
触发场景:用户手改(或编辑器保存)`cordis.patch.yml` 使其变成 CRLF,桌面端点开
|
|
348
|
+
「Connector → MCP 服务器」就只剩 4 张光秃秃的卡片。详见
|
|
349
|
+
`notes/2026-09-25/debug/connector-crlf-patch-parser-and-profile-path.md`。
|
|
325
350
|
- **0.3.5**(2026-09-25):**追加 DSH `0.1.7-rc.2` 支持**(peer 枚举 `0.1.7-rc.1 || 0.1.7-rc.2`,代码零改动)。
|
|
326
351
|
背景:DSH 桌面版(DeepSeek Harness desktop)0.1.7-rc.2 上线后,门禁把只声明 `0.1.7-rc.1` 的 0.3.4 拦下
|
|
327
352
|
(`skipping profile bundle`,插件列表显示「异常」)。核查:rc.1→rc.2 npm tarball 逐文件 diff——
|
package/client.js
CHANGED
|
@@ -412,7 +412,10 @@ window.__ModuleLoader__.load({
|
|
|
412
412
|
),
|
|
413
413
|
err ? createElement('div', { className: 'pm_err' }, err) : null,
|
|
414
414
|
createElement('div', { className: 'pm_meta' },
|
|
415
|
-
props.mcp.exists
|
|
415
|
+
props.mcp.exists
|
|
416
|
+
// host 回传真实路径(0.1.7+ 的 profileContext.patchPath);老 host 没这个字段时退回笼统说法。
|
|
417
|
+
? '编辑 ' + (props.mcp.patchPath || '本 profile 的 cordis.patch.yml') + ' 中的 mcp-* 块。保存后重启 dsh 生效。Edit the mcp-* block in cordis.patch.yml; restart dsh to apply.'
|
|
418
|
+
: '未找到 cordis.patch.yml。cordis.patch.yml not found.'),
|
|
416
419
|
rows,
|
|
417
420
|
editing === null
|
|
418
421
|
? createElement('button', { className: 'pm_btn pm_btn ghost', onClick: function () { setEditing({ id: 'mcp-new', customId: '', name: '', transport: 'stdio', serverName: '', url: '', command: '', args: '' }) } }, '+ 添加 MCP 服务器 Add MCP Server')
|
package/index.js
CHANGED
|
@@ -95,6 +95,9 @@ let _legacyScope = null // rc.x: settings.register(...) 返回的 scope
|
|
|
95
95
|
let _legacySvc = null // rc.x: settings 服务(读用 get,写用 update)
|
|
96
96
|
let _settingsSvc = null // 0.1.7+: ctx.settings(迁移写回用,见 ensureLegacyFiltersMigration)
|
|
97
97
|
let _migrationAttempted = false
|
|
98
|
+
// 0.1.7+ 的 profileContext.patchPath:本进程真正在用的 profile 补丁文件。
|
|
99
|
+
// 0.1.5/0.1.6 没有这个服务,回退到历史路径(见 patchPath)。
|
|
100
|
+
let _profilePatchPath = null
|
|
98
101
|
function readToolFilters() {
|
|
99
102
|
try {
|
|
100
103
|
// 优先 0.1.7+ 的活 Ref(.get() 每次返回最新值)
|
|
@@ -191,8 +194,13 @@ function resolveHome() {
|
|
|
191
194
|
: join(homedir(), '.dsh')
|
|
192
195
|
}
|
|
193
196
|
|
|
197
|
+
// 本进程要编辑的 profile 补丁文件。
|
|
198
|
+
// 0.1.7 起 dsh 通过 profileContext 服务提供当前 profile 的绝对路径(desktop / web /
|
|
199
|
+
// 自定义 profile 都不同),必须用它;否则桌面端会去改 profiles/web 的文件 —— 写下去
|
|
200
|
+
// 对桌面端自己的 MCP 配置毫无影响,还会误导 UI 提示(0.3.5 及以前的 bug)。
|
|
201
|
+
// 0.1.5/0.1.6 没有 profileContext:退回历史硬编码路径保持老行为。
|
|
194
202
|
function patchPath() {
|
|
195
|
-
return join(resolveHome(), 'profiles', 'web', 'cordis.patch.yml')
|
|
203
|
+
return _profilePatchPath ?? join(resolveHome(), 'profiles', 'web', 'cordis.patch.yml')
|
|
196
204
|
}
|
|
197
205
|
|
|
198
206
|
function skillsRoot() {
|
|
@@ -235,6 +243,13 @@ function stripQuotes(v) {
|
|
|
235
243
|
return v
|
|
236
244
|
}
|
|
237
245
|
|
|
246
|
+
// Normalize any line ending (CRLF / lone CR) to LF. Every line-based parser here
|
|
247
|
+
// anchors regexes with `$`, which in JS does not match before a `\r`, so a CRLF
|
|
248
|
+
// profile patch silently loses fields instead of failing loudly.
|
|
249
|
+
function toLf(text) {
|
|
250
|
+
return String(text).replace(/\r\n?/g, '\n')
|
|
251
|
+
}
|
|
252
|
+
|
|
238
253
|
// Extract the bare scalar from a YAML block-sequence item line like
|
|
239
254
|
// ` - '--transport'` -> `--transport`. Handles quoted and unquoted values.
|
|
240
255
|
function stripListScalar(line) {
|
|
@@ -265,7 +280,12 @@ const SKIP_KEYS = new Set(['name', 'config'])
|
|
|
265
280
|
* (env blocks, `!!js` lines, any other keys) so a rewrite never drops them.
|
|
266
281
|
*/
|
|
267
282
|
function parseMcpServers(blockText) {
|
|
268
|
-
|
|
283
|
+
// 先统一换行:CRLF 文件里每行都以 `\r` 结尾,而下面的键值正则
|
|
284
|
+
// `^\s+(\w+):\s*(.*)$` 中 `.*` 不匹配 `\r`、`$` 也不匹配 `\r` 之前的位置,
|
|
285
|
+
// 于是一整行的 transport/serverName/command/url 全部匹配失败、统统落进
|
|
286
|
+
// `preserve` —— serverName 空 → UI 工具过滤区静默消失(`if (!props.serverName) return null`)。
|
|
287
|
+
// 归一化后与 LF 文件完全同构,顺带让 stripQuotes/stripListScalar 的 `$` 正则重新生效。
|
|
288
|
+
const lines = toLf(blockText).split('\n')
|
|
269
289
|
const servers = []
|
|
270
290
|
let cur = null
|
|
271
291
|
let curIndent = 0
|
|
@@ -1024,6 +1044,18 @@ async function readBody(req) {
|
|
|
1024
1044
|
}
|
|
1025
1045
|
|
|
1026
1046
|
export function apply(ctx, config) {
|
|
1047
|
+
// ── 绑定本进程的 profile 补丁文件(0.1.7+)──
|
|
1048
|
+
// profileContext 由 dsh 启动器提供,patchPath 就是当前 profile 的
|
|
1049
|
+
// cordis.patch.yml 绝对路径;没有它就只能沿用历史硬编码路径。
|
|
1050
|
+
try {
|
|
1051
|
+
const profile = ctx.get('profileContext')
|
|
1052
|
+
if (profile && typeof profile.patchPath === 'string' && profile.patchPath.length > 0) {
|
|
1053
|
+
_profilePatchPath = profile.patchPath
|
|
1054
|
+
console.info('[dsh-connector] profile patch file:', profile.name ? `${profile.name} -> ${profile.patchPath}` : profile.patchPath)
|
|
1055
|
+
ctx.effect(() => () => { _profilePatchPath = null }, 'connector: release profile patch path')
|
|
1056
|
+
}
|
|
1057
|
+
} catch {}
|
|
1058
|
+
|
|
1027
1059
|
// ── 工具过滤三件套之 (0):判定配置后端 + 快照缓存 ──
|
|
1028
1060
|
// 0.1.7+:config.toolFilters 是 volatile Ref(.get() 每次返回最新值,编辑热生效)。
|
|
1029
1061
|
// rc.x:无 volatile,退回老的 settings.register/get/update(0.3.0 的原始实现)。
|
|
@@ -1106,7 +1138,7 @@ export function apply(ctx, config) {
|
|
|
1106
1138
|
}
|
|
1107
1139
|
const found = findMcpBlock(text)
|
|
1108
1140
|
const servers = found ? parseMcpServers(found.blockText) : []
|
|
1109
|
-
return json(res, 200, { servers, exists: true, version: '0.1.
|
|
1141
|
+
return json(res, 200, { servers, exists: true, version: '0.1.2', patchPath: patchPath() })
|
|
1110
1142
|
}
|
|
1111
1143
|
|
|
1112
1144
|
// POST /api/mcp — replace server entries. Preserve env/!!js from the
|
|
@@ -1141,7 +1173,7 @@ export function apply(ctx, config) {
|
|
|
1141
1173
|
const prev = existing.get(s.id)
|
|
1142
1174
|
return prev ? { ...s, preserve: s.preserve || prev.preserve } : s
|
|
1143
1175
|
})
|
|
1144
|
-
const next = buildPatch(text, servers)
|
|
1176
|
+
const next = toLf(buildPatch(text, servers))
|
|
1145
1177
|
// Validate the entire resulting patch parses as YAML before writing.
|
|
1146
1178
|
// cordis.patch.yml uses `!!js` tags; the parser tolerates them via
|
|
1147
1179
|
// silent log level (values stay raw, nothing printed), so a successful
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omdp/dsh-connector",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Unified DeepSeek Harness connector: edit MCP servers (cordis.patch.yml), user skills (~/.dsh/skills) and browse the ModelScope MCP/Skills marketplaces from one Web UI settings page.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"jsdom": "^24.1.3"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@deepseek-ai/dsh": "0.1.7-rc.1 || 0.1.7-rc.2",
|
|
49
|
+
"@deepseek-ai/dsh": "0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
|
|
50
50
|
"@deepseek-ai/schemastery": "3.18.1 || 3.18.2 || 3.18.4"
|
|
51
51
|
}
|
|
52
52
|
}
|