dsh-mcp-panel 0.6.27 → 0.6.29
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/CHANGELOG.md +12 -0
- package/README-es.md +5 -3
- package/README-hi.md +6 -4
- package/README-pt.md +5 -3
- package/README-zh.md +6 -4
- package/README.md +3 -3
- package/lib/index.js +25 -5
- package/lib/types/write.d.ts.map +1 -1
- package/package.json +24 -23
- package/src/probe.ts +1 -1
- package/src/write.ts +22 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.29] - 2026-10-19
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **An empty root `cordis.patch.yml` (`[]`) no longer produces invalid YAML after the first MCP server is added (issue #29).** The append writer removes the `[]` sentinel when the file contains only comments plus an empty root list, then appends the first operation. Real rows and comments are untouched; the fresh-file header no longer writes `[]`.
|
|
8
|
+
|
|
9
|
+
## [0.6.28] - 2026-10-18
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Build tooling and the subprocess seam are no longer installed twice.** `tsdown`/`typescript` moved to devDependencies, and `@deepseek-ai/dsh-subprocess` moved to peer+dev so the host copy is the only runtime copy. A single checker install no longer pulls a 47 MB build chain through this package.
|
|
14
|
+
|
|
3
15
|
## [0.6.27] - 2026-10-18
|
|
4
16
|
|
|
5
17
|
### Fixed
|
package/README-es.md
CHANGED
|
@@ -44,7 +44,7 @@ dsh plugin --profile <name> add dsh-mcp-panel
|
|
|
44
44
|
|
|
45
45
|
Este plugin forma parte de la [familia de plugins DSH](https://github.com/PerryLink) (más de 40, todos Apache-2.0). Si te resulta útil, **dale una estrella**: no desbloquea nada, pero ayuda a que la siguiente persona lo encuentre antes.
|
|
46
46
|
|
|
47
|
-
*English:* part of a
|
|
47
|
+
*English:* part of a 95 plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
|
|
48
48
|
|
|
49
49
|
## What is dsh-mcp-panel?
|
|
50
50
|
|
|
@@ -62,7 +62,7 @@ Cliente oficial = puente, este plugin = consola: lee el estado por el seam `mcp/
|
|
|
62
62
|
|
|
63
63
|
| Superficie | Estado |
|
|
64
64
|
|---|---|
|
|
65
|
-
| Harness | DeepSeek Harness `dsh-v0.2.1-
|
|
65
|
+
| Harness | DeepSeek Harness `dsh-v0.2.1-rc.2` (verificado 2026-10-18): `engines.dsh >=0.2.1-0 <0.3.0`; las rutas de compatibilidad P0 tienen pruebas de regresión. |
|
|
66
66
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
67
67
|
| Plataformas | Web GUI (doble cara: host + navegador) |
|
|
68
68
|
| Modelo | Cualquiera (el panel es de solo lectura; solo la salida de `/mcp` es legible por el modelo) |
|
|
@@ -335,7 +335,9 @@ Este proyecto es uno de los **87 plugins activamente mantenidos** de DeepSeek Ha
|
|
|
335
335
|
|
|
336
336
|
</details>
|
|
337
337
|
|
|
338
|
-
</details
|
|
338
|
+
</details>
|
|
339
|
+
|
|
340
|
+
## License
|
|
339
341
|
|
|
340
342
|
[Apache License 2.0](LICENSE) © 2026 colaboradores de dsh-mcp-panel
|
|
341
343
|
|
package/README-hi.md
CHANGED
|
@@ -42,9 +42,9 @@ dsh plugin --profile <name> add dsh-mcp-panel
|
|
|
42
42
|
|
|
43
43
|
## ⭐ 如果它帮到了你
|
|
44
44
|
|
|
45
|
-
यह प्लगइन [DSH प्लगइन परिवार](https://github.com/PerryLink) का हिस्सा है (
|
|
45
|
+
यह प्लगइन [DSH प्लगइन परिवार](https://github.com/PerryLink) का हिस्सा है (95 प्लगइन, सभी Apache-2.0)। अगर यह उपयोगी लगे, तो **एक स्टार दें** — इससे कोई सुविधा अनलॉक नहीं होती, पर अगला व्यक्ति इसे खोज में आसानी से पा लेता है।
|
|
46
46
|
|
|
47
|
-
*English:* part of a
|
|
47
|
+
*English:* part of a 95 plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
|
|
48
48
|
|
|
49
49
|
## What is dsh-mcp-panel?
|
|
50
50
|
|
|
@@ -62,7 +62,7 @@ DeepSeek Harness के आधिकारिक MCP क्लाइंट क
|
|
|
62
62
|
|
|
63
63
|
| सतह | स्थिति |
|
|
64
64
|
|---|---|
|
|
65
|
-
|
|
|
65
|
+
| हारनेस | DeepSeek Harness `dsh-v0.2.1-rc.2` (2026-10-18 सत्यापित): `engines.dsh >=0.2.1-0 <0.3.0`; P0 संगतता पथ के रिग्रेशन परीक्षण हैं। |
|
|
66
66
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
67
67
|
| प्लेटफ़ॉर्म | Web GUI (दोहरा चेहरा: host + browser) |
|
|
68
68
|
| मॉडल | कोई भी (पैनल रीड-ओनली है; केवल `/mcp` आउटपुट मॉडल-पठनीय है) |
|
|
@@ -335,7 +335,9 @@ pnpm run typecheck && pnpm run typecheck:ci && pnpm test && pnpm run build && pn
|
|
|
335
335
|
|
|
336
336
|
</details>
|
|
337
337
|
|
|
338
|
-
</details
|
|
338
|
+
</details>
|
|
339
|
+
|
|
340
|
+
## License
|
|
339
341
|
|
|
340
342
|
[Apache License 2.0](LICENSE) © 2026 dsh-mcp-panel योगदानकर्ता
|
|
341
343
|
|
package/README-pt.md
CHANGED
|
@@ -44,7 +44,7 @@ dsh plugin --profile <name> add dsh-mcp-panel
|
|
|
44
44
|
|
|
45
45
|
Este plugin faz parte da [família de plugins DSH](https://github.com/PerryLink) (mais de 40, todos Apache-2.0). Se for útil, **deixe uma estrela**: não desbloqueia nada, mas ajuda a próxima pessoa a encontrá-lo.
|
|
46
46
|
|
|
47
|
-
*English:* part of a
|
|
47
|
+
*English:* part of a 95 plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
|
|
48
48
|
|
|
49
49
|
## What is dsh-mcp-panel?
|
|
50
50
|
|
|
@@ -62,7 +62,7 @@ Cliente oficial = ponte, este plugin = console: leia o status pelo seam `mcp/sta
|
|
|
62
62
|
|
|
63
63
|
| Superfície | Status |
|
|
64
64
|
|---|---|
|
|
65
|
-
| Harness | DeepSeek Harness `dsh-v0.2.1-
|
|
65
|
+
| Harness | DeepSeek Harness `dsh-v0.2.1-rc.2` (verificado 2026-10-18): `engines.dsh >=0.2.1-0 <0.3.0`; os caminhos de compatibilidade P0 têm testes de regressão. |
|
|
66
66
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
67
67
|
| Plataformas | Web GUI (duas faces: host + navegador) |
|
|
68
68
|
| Modelo | Qualquer (o painel é somente leitura; só a saída de `/mcp` é legível pelo modelo) |
|
|
@@ -335,7 +335,9 @@ Este projeto é um dos **87 plugins ativamente mantidos** do DeepSeek Harness da
|
|
|
335
335
|
|
|
336
336
|
</details>
|
|
337
337
|
|
|
338
|
-
</details
|
|
338
|
+
</details>
|
|
339
|
+
|
|
340
|
+
## License
|
|
339
341
|
|
|
340
342
|
[Apache License 2.0](LICENSE) © 2026 contribuidores do dsh-mcp-panel
|
|
341
343
|
|
package/README-zh.md
CHANGED
|
@@ -44,9 +44,9 @@ dsh plugin --profile <name> add dsh-mcp-panel
|
|
|
44
44
|
|
|
45
45
|
## ⭐ 如果它帮到了你
|
|
46
46
|
|
|
47
|
-
这个插件是 [DSH 插件家族](https://github.com/PerryLink)的一员(
|
|
47
|
+
这个插件是 [DSH 插件家族](https://github.com/PerryLink)的一员(95 个,全部 Apache-2.0)。如果你在用,**给个 star** —— 它不会解锁任何功能,但会让下一个人在搜索里更容易找到它。
|
|
48
48
|
|
|
49
|
-
*English:* part of a
|
|
49
|
+
*English:* part of a 95 plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
|
|
50
50
|
|
|
51
51
|
## What is dsh-mcp-panel?
|
|
52
52
|
|
|
@@ -64,7 +64,7 @@ dsh plugin --profile <name> add dsh-mcp-panel
|
|
|
64
64
|
|
|
65
65
|
| 维度 | 状态 |
|
|
66
66
|
|---|---|
|
|
67
|
-
|
|
|
67
|
+
| 宿主 | DeepSeek Harness `dsh-v0.2.1-rc.2`(2026-10-18 验证):`engines.dsh >=0.2.1-0 <0.3.0`;P0 兼容路径已有回归测试。 |
|
|
68
68
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
69
69
|
| 平台 | Web GUI(双面:Host + 浏览器) |
|
|
70
70
|
| 模型 | 任意(面板只读;仅 `/mcp` 输出对模型可见) |
|
|
@@ -337,7 +337,9 @@ pnpm run typecheck && pnpm run typecheck:ci && pnpm test && pnpm run build && pn
|
|
|
337
337
|
|
|
338
338
|
</details>
|
|
339
339
|
|
|
340
|
-
</details
|
|
340
|
+
</details>
|
|
341
|
+
|
|
342
|
+
## License
|
|
341
343
|
|
|
342
344
|
[Apache License 2.0](LICENSE) © 2026 dsh-mcp-panel contributors
|
|
343
345
|
|
package/README.md
CHANGED
|
@@ -45,9 +45,9 @@ dsh plugin --profile <name> add dsh-mcp-panel
|
|
|
45
45
|
|
|
46
46
|
## ⭐ 如果它帮到了你
|
|
47
47
|
|
|
48
|
-
这个插件是 [DSH 插件家族](https://github.com/PerryLink)的一员(
|
|
48
|
+
这个插件是 [DSH 插件家族](https://github.com/PerryLink)的一员(95 个,全部 Apache-2.0)。如果你在用,**给个 star** —— 它不会解锁任何功能,但会让下一个人在搜索里更容易找到它。
|
|
49
49
|
|
|
50
|
-
*English:* part of a
|
|
50
|
+
*English:* part of a 95 plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
## What is dsh-mcp-panel?
|
|
@@ -66,7 +66,7 @@ Official client = bridge, this plugin = console: read status through the `mcp/st
|
|
|
66
66
|
|
|
67
67
|
| Surface | Status |
|
|
68
68
|
|---|---|
|
|
69
|
-
| Harness | DeepSeek Harness `dsh-v0.2.1-
|
|
69
|
+
| Harness | DeepSeek Harness `dsh-v0.2.1-rc.2` (verified 2026-10-18): `engines.dsh >=0.2.1-0 <0.3.0`; the P0 compatibility paths have regression tests. |
|
|
70
70
|
| Node | `^22.19.0 \|\| >=24.0.0` |
|
|
71
71
|
| Platforms | Web GUI (dual-face: host + browser) |
|
|
72
72
|
| Model | Any (the panel is read-only; only `/mcp` output is model-readable) |
|
package/lib/index.js
CHANGED
|
@@ -842,7 +842,7 @@ const INITIALIZE_PROTOCOL_VERSION = "2024-11-05";
|
|
|
842
842
|
* advertised version tracks the package version. */
|
|
843
843
|
const PROBE_CLIENT_INFO = {
|
|
844
844
|
name: "dsh-mcp-panel",
|
|
845
|
-
version: "0.6.
|
|
845
|
+
version: "0.6.29"
|
|
846
846
|
};
|
|
847
847
|
/** Display cap for server-reported name/version fields in probe details. */
|
|
848
848
|
const DISPLAY_LIMIT = 80;
|
|
@@ -1947,7 +1947,6 @@ const BACKUP_SUFFIX = ".bak-";
|
|
|
1947
1947
|
/** Fresh-file header when the patch layer does not exist yet. */
|
|
1948
1948
|
const FRESH_FILE_HEADER = `# dsh-mcp-panel managed patch layer (created by the MCP console).
|
|
1949
1949
|
# Operations are APPEND-ONLY: the console never rewrites existing content.
|
|
1950
|
-
[]
|
|
1951
1950
|
`;
|
|
1952
1951
|
/**
|
|
1953
1952
|
* Copy the current patch file to a timestamped backup, append one fragment,
|
|
@@ -1988,11 +1987,32 @@ async function appendPatchFragment(filePath, fragment, backupCount) {
|
|
|
1988
1987
|
bytes
|
|
1989
1988
|
};
|
|
1990
1989
|
}
|
|
1990
|
+
/**
|
|
1991
|
+
* A patch layer that only contains an empty root list (`[]`) plus comments is
|
|
1992
|
+
* not a valid prefix for an appended operation: `[]` ends the YAML document.
|
|
1993
|
+
* Removing that one sentinel is the only rewrite this module performs; any
|
|
1994
|
+
* real row keeps the append-only guarantee.
|
|
1995
|
+
*/
|
|
1996
|
+
function stripEmptyRootList(content) {
|
|
1997
|
+
const lines = content.split("\n");
|
|
1998
|
+
let emptyRoot = false;
|
|
1999
|
+
for (const line of lines) {
|
|
2000
|
+
const trimmed = line.trim();
|
|
2001
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
2002
|
+
if (trimmed === "[]") {
|
|
2003
|
+
emptyRoot = true;
|
|
2004
|
+
continue;
|
|
2005
|
+
}
|
|
2006
|
+
return content;
|
|
2007
|
+
}
|
|
2008
|
+
if (!emptyRoot) return content;
|
|
2009
|
+
return lines.filter((line) => line.trim() !== "[]").join("\n");
|
|
2010
|
+
}
|
|
1991
2011
|
/** Append one fragment with surrounding newlines, normalizing a trailing newline first. */
|
|
1992
2012
|
async function appendFragment(filePath, fragment) {
|
|
1993
|
-
const
|
|
1994
|
-
const normalized =
|
|
1995
|
-
const block = normalized.endsWith("\n\n") ? `${fragment}\n` : `\n${fragment}\n`;
|
|
2013
|
+
const base = stripEmptyRootList(await readFile(filePath, "utf8"));
|
|
2014
|
+
const normalized = base.endsWith("\n") ? base : `${base}\n`;
|
|
2015
|
+
const block = normalized.endsWith("\n\n") || normalized === "" ? `${fragment}\n` : `\n${fragment}\n`;
|
|
1996
2016
|
await writeFile(filePath, `${normalized}${block}`, "utf8");
|
|
1997
2017
|
if (!(await readFile(filePath, "utf8")).includes(fragment)) throw new Error("dsh-mcp-panel: the appended patch fragment could not be read back — the write is suspect; inspect the file before retrying");
|
|
1998
2018
|
return Buffer.byteLength(block, "utf8");
|
package/lib/types/write.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBlE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mcp-panel",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.29",
|
|
4
4
|
"description": "MCP management console for the official DeepSeek Harness MCP client: /mcp command with health diagnostics and pipeline trial calls, a Settings MCP tab with server CRUD (append-only profile-patch fragments, approval-gated writes with automatic backups), a tool trial console over the official tool pipeline, connection status, reconnect counts and sanitized tool inventory, plus an optional Streamable HTTP probe.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -133,7 +133,8 @@
|
|
|
133
133
|
"@deepseek-ai/dsh-client-connection": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0",
|
|
134
134
|
"@deepseek-ai/dsh-api-remotes": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0",
|
|
135
135
|
"@deepseek-ai/dsh-client-locale": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0",
|
|
136
|
-
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0"
|
|
136
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-0 <0.2.0 || >=0.1.7-0 <0.2.0 || >=0.2.0-0 <0.3.0 || >=0.2.1-0 <0.3.0",
|
|
137
|
+
"@deepseek-ai/dsh-subprocess": ">=0.2.1-0 <0.3.0"
|
|
137
138
|
},
|
|
138
139
|
"peerDependenciesMeta": {
|
|
139
140
|
"@deepseek-ai/dsh-client-connection": {
|
|
@@ -150,31 +151,28 @@
|
|
|
150
151
|
}
|
|
151
152
|
},
|
|
152
153
|
"dependencies": {
|
|
153
|
-
"
|
|
154
|
-
"typescript": "^7.0.0",
|
|
155
|
-
"zod": "^4.6.5",
|
|
156
|
-
"@deepseek-ai/dsh-subprocess": "0.2.1-alpha.1"
|
|
154
|
+
"zod": "^4.6.5"
|
|
157
155
|
},
|
|
158
156
|
"devDependencies": {
|
|
159
|
-
"@deepseek-ai/dsh-attachment": "0.2.1-
|
|
157
|
+
"@deepseek-ai/dsh-attachment": "0.2.1-rc.2",
|
|
160
158
|
"@deepseek-ai/cordis": "^4.0.5-alpha.1",
|
|
161
159
|
"@deepseek-ai/cordis-plugin-include": "^1.0.10-alpha.1",
|
|
162
160
|
"@deepseek-ai/cordis-plugin-loader": "^1.0.6-alpha.1",
|
|
163
|
-
"@deepseek-ai/dsh-agent": "0.2.1-
|
|
164
|
-
"@deepseek-ai/dsh-app-boot": "0.2.1-
|
|
165
|
-
"@deepseek-ai/dsh-api-remotes": "0.2.1-
|
|
166
|
-
"@deepseek-ai/dsh-client-connection": "0.2.1-
|
|
167
|
-
"@deepseek-ai/dsh-client-locale": "0.2.1-
|
|
168
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.2.1-
|
|
169
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.2.1-
|
|
170
|
-
"@deepseek-ai/dsh-cmdline": "0.2.1-
|
|
171
|
-
"@deepseek-ai/dsh-commands": "0.2.1-
|
|
172
|
-
"@deepseek-ai/dsh-home-paths": "0.2.1-
|
|
173
|
-
"@deepseek-ai/dsh-jobs": "0.2.1-
|
|
174
|
-
"@deepseek-ai/dsh-session": "0.2.1-
|
|
175
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.1-
|
|
176
|
-
"@deepseek-ai/dsh-tools": "0.2.1-
|
|
177
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.1-
|
|
161
|
+
"@deepseek-ai/dsh-agent": "0.2.1-rc.2",
|
|
162
|
+
"@deepseek-ai/dsh-app-boot": "0.2.1-rc.2",
|
|
163
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.1-rc.2",
|
|
164
|
+
"@deepseek-ai/dsh-client-connection": "0.2.1-rc.2",
|
|
165
|
+
"@deepseek-ai/dsh-client-locale": "0.2.1-rc.2",
|
|
166
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.1-rc.2",
|
|
167
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.2",
|
|
168
|
+
"@deepseek-ai/dsh-cmdline": "0.2.1-rc.2",
|
|
169
|
+
"@deepseek-ai/dsh-commands": "0.2.1-rc.2",
|
|
170
|
+
"@deepseek-ai/dsh-home-paths": "0.2.1-rc.2",
|
|
171
|
+
"@deepseek-ai/dsh-jobs": "0.2.1-rc.2",
|
|
172
|
+
"@deepseek-ai/dsh-session": "0.2.1-rc.2",
|
|
173
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.1-rc.2",
|
|
174
|
+
"@deepseek-ai/dsh-tools": "0.2.1-rc.2",
|
|
175
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
|
|
178
176
|
"@deepseek-ai/schemastery": "^3.18.5-alpha.1",
|
|
179
177
|
"@types/node": "^22.20.3",
|
|
180
178
|
"@types/react": "19.3.0",
|
|
@@ -183,7 +181,10 @@
|
|
|
183
181
|
"oxlint": "1.83.0",
|
|
184
182
|
"react": "19.3.0",
|
|
185
183
|
"react-dom": "19.2.8",
|
|
186
|
-
"vitest": "^5.0.0"
|
|
184
|
+
"vitest": "^5.0.0",
|
|
185
|
+
"tsdown": "^0.23.0",
|
|
186
|
+
"typescript": "^7.0.0",
|
|
187
|
+
"@deepseek-ai/dsh-subprocess": "0.2.1-rc.2"
|
|
187
188
|
},
|
|
188
189
|
"scripts": {
|
|
189
190
|
"build": "node scripts/prepare.mjs",
|
package/src/probe.ts
CHANGED
|
@@ -56,7 +56,7 @@ const INITIALIZE_PROTOCOL_VERSION = '2024-11-05'
|
|
|
56
56
|
/** MCP clientInfo facts; protocol constants, not configuration. Exported so the
|
|
57
57
|
* version-consistency tripwire (`tests/version.spec.ts`) can assert the
|
|
58
58
|
* advertised version tracks the package version. */
|
|
59
|
-
export const PROBE_CLIENT_INFO = { name: 'dsh-mcp-panel', version: '0.6.
|
|
59
|
+
export const PROBE_CLIENT_INFO = { name: 'dsh-mcp-panel', version: '0.6.29' }
|
|
60
60
|
|
|
61
61
|
/** One settled probe: outcome status plus a sanitized one-line detail. */
|
|
62
62
|
export interface ProbeOutcome {
|
package/src/write.ts
CHANGED
|
@@ -20,7 +20,6 @@ const BACKUP_SUFFIX = '.bak-'
|
|
|
20
20
|
/** Fresh-file header when the patch layer does not exist yet. */
|
|
21
21
|
const FRESH_FILE_HEADER = `# dsh-mcp-panel managed patch layer (created by the MCP console).
|
|
22
22
|
# Operations are APPEND-ONLY: the console never rewrites existing content.
|
|
23
|
-
[]
|
|
24
23
|
`
|
|
25
24
|
|
|
26
25
|
/**
|
|
@@ -63,11 +62,31 @@ export async function appendPatchFragment(
|
|
|
63
62
|
return { backupPath, bytes }
|
|
64
63
|
}
|
|
65
64
|
|
|
65
|
+
/**
|
|
66
|
+
* A patch layer that only contains an empty root list (`[]`) plus comments is
|
|
67
|
+
* not a valid prefix for an appended operation: `[]` ends the YAML document.
|
|
68
|
+
* Removing that one sentinel is the only rewrite this module performs; any
|
|
69
|
+
* real row keeps the append-only guarantee.
|
|
70
|
+
*/
|
|
71
|
+
function stripEmptyRootList(content: string): string {
|
|
72
|
+
const lines = content.split('\n')
|
|
73
|
+
let emptyRoot = false
|
|
74
|
+
for (const line of lines) {
|
|
75
|
+
const trimmed = line.trim()
|
|
76
|
+
if (trimmed === '' || trimmed.startsWith('#')) continue
|
|
77
|
+
if (trimmed === '[]') { emptyRoot = true; continue }
|
|
78
|
+
return content
|
|
79
|
+
}
|
|
80
|
+
if (!emptyRoot) return content
|
|
81
|
+
return lines.filter(line => line.trim() !== '[]').join('\n')
|
|
82
|
+
}
|
|
83
|
+
|
|
66
84
|
/** Append one fragment with surrounding newlines, normalizing a trailing newline first. */
|
|
67
85
|
async function appendFragment(filePath: string, fragment: string): Promise<number> {
|
|
68
86
|
const content = await readFile(filePath, 'utf8')
|
|
69
|
-
const
|
|
70
|
-
const
|
|
87
|
+
const base = stripEmptyRootList(content)
|
|
88
|
+
const normalized = base.endsWith('\n') ? base : `${base}\n`
|
|
89
|
+
const block = normalized.endsWith('\n\n') || normalized === '' ? `${fragment}\n` : `\n${fragment}\n`
|
|
71
90
|
await writeFile(filePath, `${normalized}${block}`, 'utf8')
|
|
72
91
|
// Readback: the appended block must survive exactly as written — a partial
|
|
73
92
|
// write would otherwise surface as a "written" success (issue #27 hardening).
|