dsh-agent-plugins-market 0.5.0 → 0.5.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.
Files changed (41) hide show
  1. package/README.md +4 -2
  2. package/README.zh.md +4 -2
  3. package/client/client.js +310 -17
  4. package/client/client.js.map +1 -1
  5. package/lib/application/catalog.js +101 -4
  6. package/lib/application/details.js +4 -1
  7. package/lib/catalog/native-project.js +73 -0
  8. package/lib/catalog/source-catalog.js +12 -3
  9. package/lib/contracts/market.js +4 -1
  10. package/lib/index.js +12 -5
  11. package/lib/model/state.js +19 -1
  12. package/lib/model/types.js +12 -1
  13. package/lib/routes.js +37 -0
  14. package/lib/runtime/commands-mounts.js +15 -6
  15. package/lib/runtime/hooks-mounts.js +3 -2
  16. package/lib/runtime/host-locale.js +54 -0
  17. package/lib/runtime/mcp-config.js +11 -4
  18. package/lib/runtime/mcp-mounts.js +33 -17
  19. package/lib/runtime/mcp-overrides.js +113 -0
  20. package/lib/runtime/mcp-status.js +8 -4
  21. package/lib/runtime/reconciler.js +7 -2
  22. package/lib/runtime/skills-provider.js +22 -13
  23. package/lib/types/application/catalog.d.ts +30 -2
  24. package/lib/types/application/details.d.ts +2 -2
  25. package/lib/types/application/queries.d.ts +5 -1
  26. package/lib/types/catalog/native-project.d.ts +17 -0
  27. package/lib/types/contracts/market.d.ts +26 -0
  28. package/lib/types/index.d.ts +4 -3
  29. package/lib/types/model/state.d.ts +1 -1
  30. package/lib/types/model/types.d.ts +13 -1
  31. package/lib/types/runtime/commands-mounts.d.ts +4 -2
  32. package/lib/types/runtime/host-locale.d.ts +13 -0
  33. package/lib/types/runtime/mcp-config.d.ts +5 -1
  34. package/lib/types/runtime/mcp-mounts.d.ts +12 -3
  35. package/lib/types/runtime/mcp-overrides.d.ts +37 -0
  36. package/lib/types/runtime/mcp-status.d.ts +2 -1
  37. package/lib/types/runtime/reconciler.d.ts +4 -1
  38. package/lib/types/runtime/skills-provider.d.ts +3 -1
  39. package/package.json +1 -1
  40. package/lib/context.js +0 -78
  41. package/lib/types/context.d.ts +0 -13
@@ -1,4 +1,5 @@
1
1
  import type { StdioConfig, StreamableHttpConfig } from '@deepseek-ai/dsh-mcp-client';
2
+ import { type McpSuiteOverrides } from './mcp-overrides.js';
2
3
  import type { Suite } from '../model/types.js';
3
4
  export interface McpMountRequest {
4
5
  suiteId: string;
@@ -11,11 +12,14 @@ export interface McpMountFailure {
11
12
  }
12
13
  /**
13
14
  * Build one mount request per supported mcp.json server.
15
+ * @param overrides user-owned per-server overrides (url/headers/env/args
16
+ * replacement plus enable/disable); applied after source expansion, before
17
+ * mount. Disabled servers are omitted from the result entirely.
14
18
  * @returns mount requests plus per-server failures (unsupported transport,
15
19
  * invalid server key, or derived serverName collision candidates are
16
20
  * checked by the mount registry, not here).
17
21
  */
18
- export declare function toMcpMounts(suite: Suite, pluginDataRoot: string): {
22
+ export declare function toMcpMounts(suite: Suite, pluginDataRoot: string, overrides?: McpSuiteOverrides): {
19
23
  mounts: McpMountRequest[];
20
24
  failures: McpMountFailure[];
21
25
  };
@@ -10,6 +10,7 @@
10
10
  * diagnostic list.
11
11
  */
12
12
  import type { Context } from '@deepseek-ai/cordis';
13
+ import type { McpSuiteOverrides } from './mcp-overrides.js';
13
14
  import type { Suite } from '../model/types.js';
14
15
  export interface McpMountDiagnostic {
15
16
  suiteId: string;
@@ -21,11 +22,19 @@ export declare class McpMountRegistry {
21
22
  private readonly pluginDataRoot;
22
23
  private readonly live;
23
24
  private readonly names;
25
+ private overridesProvider;
26
+ /** Serialize mount and unmount passes so a disable cannot race an in-flight spawn. */
27
+ private reconcileQueue;
24
28
  constructor(ctx: Context, pluginDataRoot: string);
25
- /** Mount/unmount MCP servers to match the enabled suites exactly. */
29
+ /** Install the per-suite overrides provider (suiteId -> overrides). */
30
+ setOverridesProvider(provider: () => Promise<Map<string, McpSuiteOverrides>>): void;
31
+ /** Queue one reconciliation behind any in-flight mount/unmount pass. */
26
32
  reconcile(enabledSuites: Suite[]): Promise<McpMountDiagnostic[]>;
27
- /** Dispose every live mount; used at plugin teardown. */
33
+ /** Mount/unmount MCP servers to match the enabled suites exactly. */
34
+ private reconcileNow;
35
+ /** Dispose every live mount after queued reconciliation passes settle. */
28
36
  disposeAll(): Promise<void>;
29
- private mount;
37
+ /** Mount one precomputed request (source config merged with overrides). */
38
+ private mountWith;
30
39
  private unmount;
31
40
  }
@@ -0,0 +1,37 @@
1
+ import type { McpServerStreamableHttp, McpServerStdio } from '../model/types.js';
2
+ /** Per-server override record; absent fields pass through from the source. */
3
+ export type McpServerOverride = {
4
+ /** Disabled servers are not mounted at all (default enabled). */
5
+ enabled?: boolean;
6
+ /** Replaces the source URL (streamable-http only). */
7
+ url?: string;
8
+ /** Replaces the whole header map (streamable-http only). */
9
+ headers?: Record<string, string>;
10
+ /** Replaces the whole env map (stdio). */
11
+ env?: Record<string, string>;
12
+ /** Replaces the whole args list (stdio). */
13
+ args?: string[];
14
+ };
15
+ /** Overrides for one suite, keyed by mcp.json server key. */
16
+ export type McpSuiteOverrides = Record<string, McpServerOverride>;
17
+ /** The overrides directory under the plugin data root. */
18
+ export declare function overridesDir(dataRoot: string): string;
19
+ /** One suite's override file path. */
20
+ export declare function suiteOverridePath(dataRoot: string, suiteId: string): string;
21
+ /** Load one suite's persisted overrides; unreadable files yield none. */
22
+ export declare function loadSuiteOverrides(dataRoot: string, suiteId: string): Promise<McpSuiteOverrides>;
23
+ /** Persist one suite's overrides atomically-ish (single writer, small file). */
24
+ export declare function saveSuiteOverrides(dataRoot: string, suiteId: string, overrides: McpSuiteOverrides): Promise<void>;
25
+ /** Keep only recognized fields with correct shapes; drop everything else. */
26
+ export declare function sanitizeOverrides(raw: unknown): McpSuiteOverrides;
27
+ /** Validate a client-supplied patch for one server into an override value. */
28
+ export declare function sanitizeOverridePatch(patch: unknown): McpServerOverride | undefined;
29
+ /**
30
+ * Apply one server's overrides onto its source shape. Field replacement is
31
+ * whole-map (headers/env/args), never per-key merge, so removing a key in the
32
+ * UI actually removes it at mount time. Values pass through the ordinary
33
+ * mount-time placeholder pipeline afterwards, so override authors may
34
+ * reference secrets as `${NAME}` or `${NAME:-fallback}` (resolved from the
35
+ * process environment in memory) instead of persisting them here.
36
+ */
37
+ export declare function applyOverride(server: McpServerStdio | McpServerStreamableHttp, override: McpServerOverride | undefined): McpServerStdio | McpServerStreamableHttp;
@@ -1,5 +1,6 @@
1
1
  import type { McpStatusPayload } from '../contracts/mcp-status.js';
2
2
  import { inspectToolRegistry, type McpToolSnapshot } from './tool-registry-observer.js';
3
+ import type { McpSuiteOverrides } from './mcp-overrides.js';
3
4
  import type { Suite } from '../model/types.js';
4
5
  export type { McpStatusEntry, McpStatusPayload, McpStatusKind, McpStatusState } from '../contracts/mcp-status.js';
5
6
  export { inspectToolRegistry };
@@ -10,4 +11,4 @@ interface McpDiagnostic {
10
11
  reason: string;
11
12
  }
12
13
  /** Build status rows from discovered plugin MCP definitions and observed tool names. */
13
- export declare function buildMcpStatus(suites: Suite[], diagnostics: McpDiagnostic[], observed: readonly McpToolSnapshot[]): McpStatusPayload;
14
+ export declare function buildMcpStatus(suites: Suite[], diagnostics: McpDiagnostic[], observed: readonly McpToolSnapshot[], overrides?: Map<string, McpSuiteOverrides>): McpStatusPayload;
@@ -11,6 +11,7 @@ import { type CommandMountDiagnostic } from './commands-mounts.js';
11
11
  import { type HooksMountDiagnostic } from './hooks-mounts.js';
12
12
  import { type McpMountDiagnostic } from './mcp-mounts.js';
13
13
  import type { Suite } from '../model/types.js';
14
+ import { type HostTranslate } from './host-locale.js';
14
15
  /** Diagnostics returned by one runtime reconciliation pass. */
15
16
  export interface RuntimeDiagnostics {
16
17
  mcp: McpMountDiagnostic[];
@@ -25,7 +26,9 @@ export declare class RuntimeReconciler {
25
26
  private readonly mcp;
26
27
  private readonly commands;
27
28
  private readonly hooks;
28
- constructor(ctx: Context, dataRoot: string);
29
+ constructor(ctx: Context, dataRoot: string, t?: HostTranslate);
30
+ /** Install the per-suite MCP overrides provider used at mount time. */
31
+ setMcpOverridesProvider(provider: () => Promise<Map<string, import('./mcp-overrides.js').McpSuiteOverrides>>): void;
29
32
  /** Reconcile all runtime surfaces against one enabled-suite snapshot. */
30
33
  reconcile(enabledSuites: readonly Suite[]): Promise<RuntimeDiagnostics>;
31
34
  /** Dispose all live mounts and registrations. */
@@ -1,11 +1,13 @@
1
1
  import type { SkillCandidate, SkillDefinition, SkillLookupOptions, SkillProvider } from '@deepseek-ai/dsh-skill';
2
2
  import type { Catalog } from '../application/catalog.js';
3
+ import { type HostTranslate } from './host-locale.js';
3
4
  export declare const SUITE_PROJECT_SOURCE = "agent-plugin-project";
4
5
  export declare const SUITE_USER_SOURCE = "agent-plugin-user";
5
6
  export declare class SuiteSkillProvider implements SkillProvider {
6
7
  private readonly manager;
8
+ private readonly t;
7
9
  readonly name = "agent-plugin";
8
- constructor(manager: Catalog);
10
+ constructor(manager: Catalog, t?: HostTranslate);
9
11
  list(options: SkillLookupOptions): Promise<SkillCandidate[]>;
10
12
  /** Parse `agents/*.md` of one suite into agent-definition candidates. */
11
13
  private agentsOf;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-agent-plugins-market",
3
3
  "description": "The standard way to install Claude Code / Codex / Cursor / Kimi plugin marketplace suites in DeepSeek Harness (DSH) — zero conversion, zero file copying. Skills, MCP servers, hooks and slash commands are injected into your dsh sessions at runtime.",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
package/lib/context.js DELETED
@@ -1,78 +0,0 @@
1
- import { deriveServerName } from './runtime/mcp-config.js';
2
- /** Mount the agent_plugins query tool. */
3
- export function mountSuiteContext(ctx, manager) {
4
- const disposers = [];
5
- ctx.inject(['tools'], toolsCtx => {
6
- const tools = toolsCtx;
7
- if (typeof tools.tools?.register !== 'function')
8
- return;
9
- const parameters = {
10
- type: 'object',
11
- properties: {
12
- action: { type: 'string', enum: ['list', 'info'], description: 'list: 列出全部 Agent Plugins;info: 查看单个 Agent Plugins 详情' },
13
- suiteId: { type: 'string', description: 'info 动作时必填:Agent Plugins id' },
14
- sourceId: { type: 'string', description: 'info 动作时可选:Agent Plugins 所属仓库源 id' }
15
- },
16
- required: ['action'],
17
- additionalProperties: false
18
- };
19
- const outputSchema = {
20
- type: 'object',
21
- properties: {
22
- suites: { type: 'array', items: { type: 'object' } },
23
- skills: { type: 'array', items: { type: 'object' } },
24
- mcpServers: { type: 'array', items: { type: 'object' } },
25
- note: { type: 'string' }
26
- }
27
- };
28
- const dispose = tools.tools.register({
29
- name: 'agent_plugins',
30
- description: '查询当前会话启用的 Agent Plugins:列出插件清单、技能与 MCP 工具前缀;技能正文通过 skill 工具加载。',
31
- parameters,
32
- renderIntent: 'generic',
33
- output: {
34
- schema: outputSchema,
35
- render: (_args, value) => {
36
- const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
37
- return [{ type: 'text', text }];
38
- }
39
- },
40
- execute: async (args) => {
41
- const record = args;
42
- const action = record['action'];
43
- if (action === 'list')
44
- return listPayload(await manager.enabledUserSuites());
45
- if (action === 'info')
46
- return infoPayload(await manager.enabledUserSuites(), record);
47
- return { suites: [], skills: [], mcpServers: [], note: `unknown action ${JSON.stringify(action)}` };
48
- }
49
- });
50
- disposers.push(dispose);
51
- });
52
- return () => {
53
- for (const dispose of disposers)
54
- dispose();
55
- };
56
- }
57
- function listPayload(suites) {
58
- return {
59
- suites: suites.map(suite => ({
60
- id: suite.id,
61
- sourceId: suite.sourceId,
62
- name: suite.manifest.name,
63
- version: suite.manifest.version ?? null,
64
- description: suite.manifest.description ?? null,
65
- layout: suite.manifest.layout
66
- })),
67
- skills: suites.flatMap(suite => suite.skills.map(skill => ({ suiteId: suite.id, name: skill.name, description: `[${suite.manifest.name}] ${skill.description}` }))),
68
- mcpServers: suites.flatMap(suite => suite.mcp === undefined ? [] : Object.keys(suite.mcp.servers).map(key => ({ suiteId: suite.id, server: key, tools: `mcp__${deriveServerName(suite.id, key)}__*` }))),
69
- note: '技能正文通过 skill 工具按 name 加载;MCP 工具名形如 mcp__<plugin>__<server>__<tool>。'
70
- };
71
- }
72
- function infoPayload(suites, record) {
73
- const suiteId = record['suiteId'];
74
- const suite = suites.find(entry => entry.id === suiteId);
75
- if (suite === undefined)
76
- return { suites: [], skills: [], mcpServers: [], note: `未找到 Agent Plugins "${String(suiteId)}"(仅列出用户级已启用 Agent Plugins)` };
77
- return listPayload([suite]);
78
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Runtime suite context: the `agent_plugins` query tool.
3
- *
4
- * Skills are injected by the native skill catalog (`dsh-tool-skill` renders
5
- * `ctx.skills` providers into the model's `<available_skills>` catalog), so
6
- * this module does not inject a duplicate session-start message. The tool
7
- * exists for facts the catalog does not carry: enabled plugins per
8
- * dimension, skill names per plugin, and MCP server prefixes.
9
- */
10
- import type { Context } from '@deepseek-ai/cordis';
11
- import type { Catalog } from './application/catalog.js';
12
- /** Mount the agent_plugins query tool. */
13
- export declare function mountSuiteContext(ctx: Context, manager: Catalog): () => void;