From 2d5918e158a0ab3b4047aea241643dfb8568d881 Mon Sep 17 00:00:00 2001 From: lintianle Date: Wed, 8 Jul 2026 16:51:42 +0800 Subject: [PATCH] test: add Loader export-path guard for dsh-mcp-client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verifies the namespace plugin has no default export and preserves name/inject/Config through Loader.unwrapExports — the same guard pattern as dsh-tool-web, per the packages/AGENTS.md convention. --- docs/module-graph.md | 3 -- .../mcp/mcp-client/tests/load-path.spec.ts | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 packages/mcp/mcp-client/tests/load-path.spec.ts diff --git a/docs/module-graph.md b/docs/module-graph.md index 50d1004f8a..9acef6a556 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -79,9 +79,6 @@ flowchart TD pkg_app_boot["app-boot"] pkg_stdio_agent["stdio-agent"] end - subgraph group_mcp["packages/mcp"] - pkg_mcp_client["mcp-client"] - end subgraph group_code_runtime["packages/code-runtime"] pkg_code_runtime["code-runtime"] end diff --git a/packages/mcp/mcp-client/tests/load-path.spec.ts b/packages/mcp/mcp-client/tests/load-path.spec.ts new file mode 100644 index 0000000000..5507cd5b83 --- /dev/null +++ b/packages/mcp/mcp-client/tests/load-path.spec.ts @@ -0,0 +1,29 @@ +/** + * Real-load-path guard for @deepseek-ai/dsh-mcp-client. `mcp-client` is a + * NAMESPACE plugin with `inject` — so a stray `export default apply` would + * make the cordis Loader's `unwrapExports` (`exports.default ?? exports`) + * collapse the module to the bare `apply` function, DROPPING `inject`. The + * plugin would then read `ctx.tools` without having injected it and throw + * `cannot get property … without inject` the moment it loads (postmortem 0001). + * + * This test unwraps the module through the REAL `Loader.prototype.unwrapExports` + * and verifies the namespace shape is preserved. + */ + +import { describe, expect, it } from 'vitest' +import Loader from '@cordisjs/plugin-loader' +import * as mcpClient from '@deepseek-ai/dsh-mcp-client' + +describe('dsh-mcp-client real-load-path guard', () => { + it('has no default export and keeps name/inject/Config through unwrapExports', () => { + expect('default' in mcpClient).toBe(false) + + const loader = Object.create(Loader.prototype) as Loader + const unwrapped = loader.unwrapExports(mcpClient) as Record + expect(unwrapped).toBe(mcpClient) + expect(unwrapped.name).toBe('mcp-client') + expect(unwrapped.inject).toEqual(['tools']) + expect(typeof unwrapped.apply).toBe('function') + expect(unwrapped.Config).toBeDefined() + }) +})