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 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 40+ plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
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-alpha.1` (verificado el 2026-09-25): las dos reglas de typecheck en verde sobre la cara `0.1.6-alpha.2` (este repo es el canario de la familia: no aparecieron errores nuevos), 174 pruebas y la cadena completa de puertas (typecheck / typecheck:ci / test / build / verify / package). La re-verificación de `writePatch` se sostiene en esta línea. Línea base anterior: `dsh-v0.1.7-alpha.1` (verificado el 2026-09-16). |
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>## License
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) का हिस्सा है (40+ प्लगइन, सभी Apache-2.0)। अगर यह उपयोगी लगे, तो **एक स्टार दें** — इससे कोई सुविधा अनलॉक नहीं होती, पर अगला व्यक्ति इसे खोज में आसानी से पा लेता है।
45
+ यह प्लगइन [DSH प्लगइन परिवार](https://github.com/PerryLink) का हिस्सा है (95 प्लगइन, सभी Apache-2.0)। अगर यह उपयोगी लगे, तो **एक स्टार दें** — इससे कोई सुविधा अनलॉक नहीं होती, पर अगला व्यक्ति इसे खोज में आसानी से पा लेता है।
46
46
 
47
- *English:* part of a 40+ plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
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
- | Harness | DeepSeek Harness `dsh-v0.2.1-alpha.1` (2026-09-25 को सत्यापित): `0.1.6-alpha.2` dev/test फ़ेस पर दोनों typecheck रूलर हरे (यह रेपो परिवार का कैनरी है — कोई नई त्रुटि नहीं आई), 174 टेस्ट, और पूर्ण गेट शृंखला (typecheck / typecheck:ci / test / build / verify / package)। `writePatch` का पुनः-सत्यापन इस लाइन पर मान्य है। पिछली आधार रेखा: `dsh-v0.1.7-alpha.1` (2026-09-16 को सत्यापित)। |
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>## License
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 40+ plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
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-alpha.1` (verificado em 2026-09-25): as duas réguas de typecheck verdes na face `0.1.6-alpha.2` (este repositório é o canário da família: nenhum erro novo apareceu), 174 testes e a cadeia completa de portas (typecheck / typecheck:ci / test / build / verify / package). A re-verificação do `writePatch` vale nesta linha. Linha de base anterior: `dsh-v0.1.7-alpha.1` (verificado em 2026-09-16). |
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>## License
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)的一员(40+ 个,全部 Apache-2.0)。如果你在用,**给个 star** —— 它不会解锁任何功能,但会让下一个人在搜索里更容易找到它。
47
+ 这个插件是 [DSH 插件家族](https://github.com/PerryLink)的一员(95 个,全部 Apache-2.0)。如果你在用,**给个 star** —— 它不会解锁任何功能,但会让下一个人在搜索里更容易找到它。
48
48
 
49
- *English:* part of a 40+ plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
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
- | Harness | DeepSeek Harness `dsh-v0.2.1-alpha.1`(2026-09-24 核验):双 typecheck 尺子在 `0.1.6-alpha.2` dev/test 面上双绿(本仓是全族金丝雀,抬线未暴露新错误)、174 项测试、全量门禁链(typecheck / typecheck:ci / test / build / verify / package)。`writePatch` 的写入复验断言在该线上成立。上一基线:`dsh-v0.1.7-alpha.1`(2026-09-16 已核验)。 |
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>## License
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)的一员(40+ 个,全部 Apache-2.0)。如果你在用,**给个 star** —— 它不会解锁任何功能,但会让下一个人在搜索里更容易找到它。
48
+ 这个插件是 [DSH 插件家族](https://github.com/PerryLink)的一员(95 个,全部 Apache-2.0)。如果你在用,**给个 star** —— 它不会解锁任何功能,但会让下一个人在搜索里更容易找到它。
49
49
 
50
- *English:* part of a 40+ plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
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-alpha.1` (verified 2026-09-25): dual typecheck rulers green on the `0.1.6-alpha.2` dev/test face (this repo is the family's canary — no new errors surfaced), 174 tests, and the full gate chain (typecheck / typecheck:ci / test / build / verify / package). The `writePatch` re-verification assertion stands on this line. Previous baseline: `dsh-v0.1.7-alpha.1` (verified 2026-09-16). |
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.27"
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 content = await readFile(filePath, "utf8");
1994
- const normalized = content.endsWith("\n") ? content : `${content}\n`;
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");
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH;;;;;;;;;;;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"}
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.27",
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
- "tsdown": "^0.23.0",
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-alpha.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-alpha.1",
164
- "@deepseek-ai/dsh-app-boot": "0.2.1-alpha.1",
165
- "@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.1",
166
- "@deepseek-ai/dsh-client-connection": "0.2.1-alpha.1",
167
- "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.1",
168
- "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.1",
169
- "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.1",
170
- "@deepseek-ai/dsh-cmdline": "0.2.1-alpha.1",
171
- "@deepseek-ai/dsh-commands": "0.2.1-alpha.1",
172
- "@deepseek-ai/dsh-home-paths": "0.2.1-alpha.1",
173
- "@deepseek-ai/dsh-jobs": "0.2.1-alpha.1",
174
- "@deepseek-ai/dsh-session": "0.2.1-alpha.1",
175
- "@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.1",
176
- "@deepseek-ai/dsh-tools": "0.2.1-alpha.1",
177
- "@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.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.27' }
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 normalized = content.endsWith('\n') ? content : `${content}\n`
70
- const block = normalized.endsWith('\n\n') ? `${fragment}\n` : `\n${fragment}\n`
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).