dsh-agent-plugins-market 0.7.2 → 0.8.1

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 (42) hide show
  1. package/README.md +11 -3
  2. package/README.zh.md +11 -3
  3. package/client/client.js +61 -44
  4. package/client/client.js.map +1 -1
  5. package/lib/application/catalog.js +9 -2
  6. package/lib/catalog/component-files.js +3 -1
  7. package/lib/catalog/native-project.js +1 -1
  8. package/lib/catalog/project-config.js +0 -2
  9. package/lib/catalog/project-hooks.js +12 -7
  10. package/lib/catalog/surfaces.js +17 -10
  11. package/lib/index.js +23 -2
  12. package/lib/model/command-names.js +14 -0
  13. package/lib/model/layouts.js +1 -0
  14. package/lib/runtime/commands-mounts.js +3 -2
  15. package/lib/runtime/hooks-mounts.js +7 -4
  16. package/lib/runtime/mcp-backend.js +3 -2
  17. package/lib/runtime/mcp-direct-config.js +18 -9
  18. package/lib/runtime/plugin-message-source.js +4 -0
  19. package/lib/runtime/project-runtime.js +10 -8
  20. package/lib/runtime/settings-namespace.js +44 -66
  21. package/lib/runtime/user-commands.js +23 -8
  22. package/lib/runtime/user-hooks.js +102 -0
  23. package/lib/runtime/user-panels.js +34 -22
  24. package/lib/runtime/user-store.js +81 -19
  25. package/lib/types/catalog/component-files.d.ts +1 -0
  26. package/lib/types/catalog/project-hooks.d.ts +15 -2
  27. package/lib/types/catalog/surfaces.d.ts +6 -4
  28. package/lib/types/contracts/market.d.ts +5 -1
  29. package/lib/types/index.d.ts +87 -1
  30. package/lib/types/model/command-names.d.ts +12 -0
  31. package/lib/types/model/layouts.d.ts +1 -0
  32. package/lib/types/model/types.d.ts +2 -1
  33. package/lib/types/runtime/mcp-backend.d.ts +20 -13
  34. package/lib/types/runtime/mcp-direct-config.d.ts +1 -5
  35. package/lib/types/runtime/plugin-message-source.d.ts +24 -0
  36. package/lib/types/runtime/settings-namespace.d.ts +41 -31
  37. package/lib/types/runtime/user-commands.d.ts +5 -2
  38. package/lib/types/runtime/user-hooks.d.ts +22 -0
  39. package/lib/types/runtime/user-panels.d.ts +35 -15
  40. package/lib/types/runtime/user-store.d.ts +27 -10
  41. package/package.json +38 -31
  42. package/schemas/com.deepseek.harness/spec.md +1 -1
@@ -22,19 +22,26 @@ export type McpBackend = 'builtin' | 'host';
22
22
  * belong to {@link MARKET_SETTINGS_DEFAULTS}; this schema states them, it does
23
23
  * not own them.
24
24
  */
25
- export declare const MarketSettingsSchema: z<Schemastery.ObjectS<{
26
- mcpEnhanced: z<boolean, boolean>;
27
- scanProjectLayouts: z<boolean, boolean>;
28
- downloadRegion: z<"auto" | "global" | "china", "auto" | "global" | "china">;
29
- feedbackEnabled: z<boolean, boolean>;
30
- autoUpdateSources: z<boolean, boolean>;
31
- }>, Schemastery.ObjectT<{
32
- mcpEnhanced: z<boolean, boolean>;
33
- scanProjectLayouts: z<boolean, boolean>;
34
- downloadRegion: z<"auto" | "global" | "china", "auto" | "global" | "china">;
35
- feedbackEnabled: z<boolean, boolean>;
36
- autoUpdateSources: z<boolean, boolean>;
37
- }>>;
25
+ export declare const MarketSettingsFields: {
26
+ readonly mcpEnhanced: z<boolean, boolean, "defined">;
27
+ readonly scanProjectLayouts: z<boolean, boolean, "defined">;
28
+ readonly downloadRegion: z<"auto" | "global" | "china", "auto" | "global" | "china", "defined">;
29
+ readonly feedbackEnabled: z<boolean, boolean, "defined">;
30
+ readonly autoUpdateSources: z<boolean, boolean, "defined">;
31
+ };
32
+ export declare const MarketSettingsSchema: z<Schemastery.ObjectS<NoInfer<{
33
+ readonly mcpEnhanced: z<boolean, boolean, "defined">;
34
+ readonly scanProjectLayouts: z<boolean, boolean, "defined">;
35
+ readonly downloadRegion: z<"auto" | "global" | "china", "auto" | "global" | "china", "defined">;
36
+ readonly feedbackEnabled: z<boolean, boolean, "defined">;
37
+ readonly autoUpdateSources: z<boolean, boolean, "defined">;
38
+ }>>, Schemastery.ObjectT<NoInfer<{
39
+ readonly mcpEnhanced: z<boolean, boolean, "defined">;
40
+ readonly scanProjectLayouts: z<boolean, boolean, "defined">;
41
+ readonly downloadRegion: z<"auto" | "global" | "china", "auto" | "global" | "china", "defined">;
42
+ readonly feedbackEnabled: z<boolean, boolean, "defined">;
43
+ readonly autoUpdateSources: z<boolean, boolean, "defined">;
44
+ }>>, "plain">;
38
45
  /** Path of the legacy persisted settings file under the plugin data root. */
39
46
  export declare function marketSettingsPath(dataRoot: string): string;
40
47
  /** Read the legacy persisted backend; absent or invalid values read as the default. */
@@ -2,11 +2,7 @@ import { type McpSuiteConfig, type Suite } from '../model/types.js';
2
2
  export declare const USER_MCP_SOURCE = "@user-mcp";
3
3
  export declare const USER_MCP_SUITE = "user-mcp";
4
4
  /**
5
- * User-created services reuse the owned bridge lifecycle without changing host configuration.
6
- *
7
- * The declarations live in the shared Agent layout root
8
- * (`~/.agents/mcp.json`), so a service the user adds by hand is ordinary
9
- * `mcpServers` JSON in the same place other Agent tools look.
5
+ * Load the user's own MCP declaration file.
10
6
  *
11
7
  * The suite always carries an `mcp` document — an absent or malformed
12
8
  * `mcp.json` leaves an empty one — so callers read `.mcp.servers` directly
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Message source this plugin declares for the bodies it injects as follow-up
3
+ * messages: suite command bodies and user command bodies ride the receiving
4
+ * agent's inbox with their producer identity attached. The host's message
5
+ * sources are merge-extensible — each producer declares its own kind through a
6
+ * module augmentation, and consumers fall through unknown kinds.
7
+ * @module runtime/plugin-message-source
8
+ */
9
+ import type { UserMessage } from '@deepseek-ai/dsh-llm';
10
+ /** Producer identity of every follow-up message this plugin injects. */
11
+ export interface PluginMarketSource {
12
+ kind: 'plugin-market';
13
+ /** The injected body is author-written instruction text: a suite or user command body. */
14
+ form: 'instructions';
15
+ }
16
+ declare module '@deepseek-ai/dsh-llm' {
17
+ interface MessageSourceMap {
18
+ 'plugin-market': PluginMarketSource;
19
+ }
20
+ }
21
+ /** Build the source for one follow-up message; fresh per message, no shared state. */
22
+ export declare function pluginMarketSource(): PluginMarketSource;
23
+ /** A follow-up message this plugin injects. */
24
+ export type PluginMarketMessage = UserMessage;
@@ -1,25 +1,39 @@
1
1
  /**
2
- * The host settings namespace this plugin registers.
2
+ * The market settings the host carries in this plugin's own config: the loader
3
+ * projects the entry's `Config` schema into the `dsh-agent-plugins-market`
4
+ * settings namespace, so the Plugins panel's configuration page reads and
5
+ * writes these five switches, and the host updates the volatile references in
6
+ * place on every change (emitting `loader/volatile-update`).
3
7
  *
4
- * The registration is also what makes the host's plugin-config tab serve this
5
- * plugin's card, and it carries the MCP mount backend, the download region,
6
- * the project-layout switch, the experience-feedback tool switch, and the
7
- * background source-update switch. `settings.register`
8
- * throws on a duplicate namespace, so there is exactly one inject block and one
9
- * registration.
10
- *
11
- * The whole callback is failure-contained on purpose: a throw inside it is
12
- * INVISIBLE in the UI (the inject resolves asynchronously and cordis only logs
13
- * it) and silently removes the namespace from `settings.describe`, which is
14
- * what hides the plugin-config card. Every failure mode lands in the logger
15
- * with a loud prefix instead.
8
+ * Every consumer reads through {@link MarketSettingsNamespace.settings} so
9
+ * "the field is absent" has exactly one answer —
10
+ * {@link resolveMarketSettings} — instead of each caller inventing its own
11
+ * fallback for the window before the host applies its first value.
16
12
  *
17
13
  * @module runtime/settings-namespace
18
14
  */
19
15
  import type { Context } from '@deepseek-ai/cordis';
20
16
  import { type DownloadRegionSetting } from '../contracts/settings.js';
21
17
  import type { HostTranslate } from './host-locale.js';
22
- import { type McpBackend } from './mcp-backend.js';
18
+ import type { McpBackend } from './mcp-backend.js';
19
+ /** The five volatile references the entry's config carries for this namespace. */
20
+ export interface MarketSettingRefs {
21
+ mcpEnhanced: {
22
+ get(): boolean | undefined;
23
+ };
24
+ scanProjectLayouts: {
25
+ get(): boolean | undefined;
26
+ };
27
+ downloadRegion: {
28
+ get(): DownloadRegionSetting | undefined;
29
+ };
30
+ feedbackEnabled: {
31
+ get(): boolean | undefined;
32
+ };
33
+ autoUpdateSources: {
34
+ get(): boolean | undefined;
35
+ };
36
+ }
23
37
  /** Runtime reactions the namespace drives. */
24
38
  export interface SettingsNamespaceHost {
25
39
  /** Apply the project-layout discovery switch; rejection is logged and contained. */
@@ -31,10 +45,10 @@ export interface SettingsNamespaceHost {
31
45
  }
32
46
  export declare class MarketSettingsNamespace {
33
47
  private readonly ctx;
48
+ private readonly refs;
34
49
  private readonly dataRoot;
35
50
  private readonly locale;
36
51
  private readonly host;
37
- private scope;
38
52
  private readonly watchers;
39
53
  private feedbackDisposer;
40
54
  /**
@@ -44,31 +58,27 @@ export declare class MarketSettingsNamespace {
44
58
  * switch, or skipped because the host has no tools registry to register on.
45
59
  */
46
60
  private feedbackMountState;
47
- constructor(ctx: Context, dataRoot: string, locale: {
61
+ constructor(ctx: Context, refs: MarketSettingRefs, dataRoot: string, locale: {
48
62
  t: HostTranslate;
49
63
  }, host: SettingsNamespaceHost);
50
- /** Register the namespace; the host resolves it whenever the settings service mounts. */
64
+ /** Subscribe the runtime reactions to live settings updates. */
51
65
  mount(): void;
52
- /** The persisted MCP backend choice; the built-in client until registration lands. */
66
+ /** Release every watcher and unmount the feedback tool. */
67
+ dispose(): void;
68
+ /**
69
+ * The resolved settings, from the volatile references the host updates in place.
70
+ */
71
+ private settings;
72
+ /** The persisted MCP backend choice; the built-in client until the host applies a value. */
53
73
  backend(): Promise<McpBackend>;
54
74
  /**
55
- * Persist a backend choice.
56
- * @throws when the settings service is not mounted.
75
+ * Legacy write path for the backend choice: the value now lives in the host
76
+ * settings document, edited from the Plugins panel's configuration page, so
77
+ * this accepts the request and lets the volatile reference decide.
57
78
  */
58
79
  setBackend(backend: McpBackend): Promise<void>;
59
80
  /** The persisted download-region setting. */
60
81
  downloadRegion(): Promise<DownloadRegionSetting>;
61
- /**
62
- * The resolved settings, whether or not the namespace is registered yet.
63
- *
64
- * Every reader goes through here so "the field is absent" has exactly one
65
- * answer — {@link resolveMarketSettings} — instead of each caller inventing
66
- * its own fallback for the window before registration lands.
67
- */
68
- private settings;
69
- /** Release every watcher and unmount the feedback tool. */
70
- dispose(): void;
71
- private register;
72
82
  /** Apply the background source-update switch. */
73
83
  private syncAutoUpdateSources;
74
84
  private syncProjectLayouts;
@@ -2,8 +2,11 @@
2
2
  * User command mounting: every enabled entry of the user commands panel
3
3
  * registers as a dsh slash command, so user-authored quick replies behave
4
4
  * exactly like suite commands — the body with `$ARGUMENTS` substituted rides
5
- * one follow-up message on the receiving agent. Reconciled on every catalog
6
- * change, keyed `user/<name>`.
5
+ * one follow-up message on the receiving agent. A nested entry registers
6
+ * under its flattened call name (`git/commit` → `git-commit`) while the panel
7
+ * keeps addressing it by path; when two entries flatten to one call name the
8
+ * first registers and the other is reported. Reconciled on every catalog
9
+ * change, keyed by the call name.
7
10
  * @module runtime/user-commands
8
11
  */
9
12
  import type { Context } from '@deepseek-ai/cordis';
@@ -0,0 +1,22 @@
1
+ import { type Suite } from '../model/types.js';
2
+ export declare const USER_HOOKS_SOURCE = "@user-hooks";
3
+ export declare const USER_HOOKS_SUITE = "user-hooks";
4
+ /**
5
+ * The Agent layout root's hook documents, relative to that root and read in
6
+ * order. Later files merge additively over earlier ones, the same order and
7
+ * semantics the project `.agents` layout applies. The first entry is also the
8
+ * suite's manifest path and the file a suite with no documents is addressed by.
9
+ */
10
+ export declare const USER_HOOK_FILES: readonly [string, string];
11
+ /** Resolve one Agent-layout-relative hook document against the layout root. */
12
+ export declare function userHookPath(agentsRoot: string, file: string): string;
13
+ /**
14
+ * Load the user's Agent layout hooks as one synthetic suite.
15
+ *
16
+ * The suite is always built, so one call answers with both the events and the
17
+ * reasons a document was rejected: an absent, malformed, or event-free set of
18
+ * hook files leaves `surfaces.hooks` at 0 and carries the diagnostics.
19
+ * {@link ../application/catalog.ts} merges the suite into the enabled set only
20
+ * when it declares events.
21
+ */
22
+ export declare function loadUserHooksSuite(agentsRoot: string): Promise<Suite>;
@@ -12,15 +12,21 @@
12
12
  * personas follow Claude Code agents frontmatter (`name`, `description`,
13
13
  * optional `whenToUse`, `tools`, `model`, `disabled`).
14
14
  *
15
- * Only the skills panel serves the cross-tool `<name>/SKILL.md` directory
16
- * spelling beside its own flat entries; commands and personas stay flat.
15
+ * Every panel reads the flat `<name>.md` children of its directory. The
16
+ * commands and agent-persona panels also read every `.md` document at any
17
+ * depth, addressing a nested entry by its path relative to the panel
18
+ * directory (`git/commit`, `review/code`), so subdirectories another Agent
19
+ * tool writes are picked up. The skills panel keeps the cross-tool
20
+ * `<name>/SKILL.md` directory spelling and reads it from the top level only,
21
+ * matching the harness's own reader of `~/.agents/skills`.
17
22
  *
18
23
  * An entry's name is the one its document declares — the same name the
19
- * harness reader derives from that file — and the panel addresses, edits, and
20
- * deletes the entry by that name. A document that reader would reject is
21
- * listed disabled with the reason instead of joining the catalog, and a skill
22
- * is switched off by writing that reader's own invocation controls, so the off
23
- * state lives in the file rather than in this provider.
24
+ * harness reader derives from that file — else its document name, and the
25
+ * panel addresses, edits, and deletes the entry by that name. A document that
26
+ * reader would reject is listed disabled with the reason instead of joining
27
+ * the catalog, and a skill is switched off by writing that reader's own
28
+ * invocation controls, so the off state lives in the file rather than in this
29
+ * provider.
24
30
  * @module runtime/user-panels
25
31
  */
26
32
  import type { SkillCandidate, SkillDefinition, SkillLookupOptions, SkillProvider } from '@deepseek-ai/dsh-skill';
@@ -29,7 +35,11 @@ import { type EntryShape, type UserEntryFile } from './user-store.js';
29
35
  export declare const USER_PANEL_SKILL_SOURCE = "user-panel";
30
36
  /** A user panel entry as the HTTP layer serializes it. */
31
37
  export interface UserPanelEntry {
32
- /** Entry name: the name its document declares, else the file's base name (or the skill directory's). */
38
+ /**
39
+ * Entry name: the name its document declares, else its document name — the
40
+ * file's base name, or, on a nested panel, the document's path relative to
41
+ * the panel directory (`git/commit`).
42
+ */
33
43
  name: string;
34
44
  description: string;
35
45
  /** True when the entry is disabled, either by its `disabled` frontmatter key or by a failed validation. */
@@ -47,10 +57,16 @@ export interface UserPanelEntry {
47
57
  }
48
58
  /** How one panel store treats names and on-disk spellings. */
49
59
  export interface UserPanelStoreOptions {
50
- /** Extra name grammar for this panel (runs after USER_ENTRY_NAME). */
60
+ /** Extra grammar one path segment must satisfy (runs after USER_ENTRY_NAME on each segment). */
51
61
  extraNameCheck?: (name: string) => boolean;
52
62
  /** The document spellings this panel serves, most preferred first. */
53
63
  shapes?: readonly EntryShape[];
64
+ /**
65
+ * Read every subdirectory of the panel directory and address an entry by its
66
+ * path relative to that directory. Off for the skills panel, whose reader
67
+ * sees top-level documents only.
68
+ */
69
+ nested?: boolean;
54
70
  /**
55
71
  * Rejection for a document this panel must not register, or `undefined` when
56
72
  * it may. Skills validate against the harness reader that shares their
@@ -72,17 +88,20 @@ export declare class UserPanelStore {
72
88
  private readonly kind;
73
89
  private readonly shapes;
74
90
  private readonly extraNameCheck;
91
+ private readonly namePattern;
92
+ private readonly nested;
75
93
  private readonly validate;
76
94
  private readonly honorInvocationControls;
77
95
  constructor(agentsRoot: string, kind: 'skills' | 'commands' | 'agents', options?: UserPanelStoreOptions);
78
96
  /** The panel's directory under the Agent layout root. */
79
97
  dirPath(): string;
80
98
  private get dir();
99
+ /** The path grammar plus the panel's per-segment extra grammar. */
81
100
  private validName;
82
101
  /**
83
102
  * Resolve the document one entry name addresses. The name a panel entry
84
- * carries is the one its document declares, which is only the file name by
85
- * convention, so a name that matches no path is matched against the
103
+ * carries is the one its document declares, which is only the document path
104
+ * by convention, so a name that matches no path is matched against the
86
105
  * declared names of the served documents.
87
106
  */
88
107
  private document;
@@ -101,7 +120,7 @@ export declare class UserPanelStore {
101
120
  * find or fix it.
102
121
  */
103
122
  private serialize;
104
- /** Create an entry; refuses an occupied name. New entries use the flat spelling. */
123
+ /** Create an entry; refuses an occupied name. New entries use the flat `<name>.md` spelling, creating any parent directories. */
105
124
  create(name: string, text: string): Promise<UserPanelEntry>;
106
125
  /** Replace one entry's content wholesale, keeping the spelling it already has. */
107
126
  update(name: string, text: string): Promise<void>;
@@ -115,11 +134,12 @@ export declare function createUserPanelStores(agentsRoot: string): {
115
134
  agents: UserPanelStore;
116
135
  };
117
136
  /**
118
- * The skills/agents panels accept only harness skill-grammar names
137
+ * The skills/agents panels accept only harness skill-grammar path segments
119
138
  * (`[a-z0-9-]`, no underscores): a candidate name reaching the skill
120
139
  * registry's `get()` with an invalid name is dropped there, and several
121
- * consumers validate strictly, so `_`-named entries would be dead weight.
122
- * Commands keep the looser command grammar (`_` allowed).
140
+ * consumers validate strictly, so `_`-named entries would be dead weight. A
141
+ * nested persona applies this to each segment. Commands keep the looser
142
+ * command grammar (`_` allowed).
123
143
  */
124
144
  export declare function isUserSkillEntryName(name: string): boolean;
125
145
  /**
@@ -5,15 +5,25 @@
5
5
  * frontmatter rules the catalog uses, so user entries look exactly like suite
6
6
  * entries to the runtime mounts.
7
7
  *
8
- * An entry is one document. Skills also accept the cross-tool directory
9
- * spelling (`<name>/SKILL.md`) that other Agent tools and the harness's own
10
- * reader of `~/.agents/skills` author; commands and personas are flat only.
8
+ * An entry is one document. A flat panel reads the immediate `<name>.md`
9
+ * children of its directory; a nested panel (commands and agent personas)
10
+ * reads every `.md` document at any depth and names each by its path relative
11
+ * to that directory. Skills also accept the cross-tool directory spelling
12
+ * (`<name>/SKILL.md`) that other Agent tools and the harness's own reader of
13
+ * `~/.agents/skills` author, and read it from the top level only.
11
14
  * @module runtime/user-store
12
15
  */
13
16
  /** Where user panel entries persist: `<agentsRoot>/<kind>/`. */
14
17
  export declare function userEntryDir(agentsRoot: string, kind: 'skills' | 'commands' | 'agents'): string;
15
- /** `[a-z][a-z0-9_-]*` — the grammar every panel entry name must satisfy. */
18
+ /** `[a-z][a-z0-9_-]*` — one segment of a panel entry name. */
16
19
  export declare const USER_ENTRY_NAME: RegExp;
20
+ /**
21
+ * The path grammar a nested panel entry name satisfies: one or more
22
+ * {@link USER_ENTRY_NAME} segments joined by `/`. It rejects `..`, leading or
23
+ * trailing separators, empty segments, backslashes, and uppercase, so the name
24
+ * stays a path relative to the panel directory.
25
+ */
26
+ export declare const USER_ENTRY_PATH: RegExp;
17
27
  /** The file name of a directory-shaped skill's document. */
18
28
  export declare const SKILL_ENTRY_FILE = "SKILL.md";
19
29
  /**
@@ -42,11 +52,18 @@ export interface EntryDocument {
42
52
  }
43
53
  /**
44
54
  * Resolve one entry name to its document, taking the first shape the path
45
- * exists in. Names outside the entry grammar never touch the filesystem.
55
+ * exists in. A nested panel accepts a path name (`git/commit`); a flat panel
56
+ * accepts a single segment. Names outside the panel's grammar never touch the
57
+ * filesystem.
58
+ */
59
+ export declare function resolveEntryDocument(dir: string, name: string, shapes: readonly EntryShape[], strict?: boolean, nested?: boolean): Promise<EntryDocument | undefined>;
60
+ /**
61
+ * Every entry document the served shapes expose. A flat panel reads immediate
62
+ * children only; a nested panel walks every subdirectory to any depth and
63
+ * names each entry by its path relative to `dir`. Entries are deduplicated by
64
+ * name at the first shape that has it.
46
65
  */
47
- export declare function resolveEntryDocument(dir: string, name: string, shapes: readonly EntryShape[], strict?: boolean): Promise<EntryDocument | undefined>;
48
- /** Every entry document the served shapes expose, deduplicated by name at the first shape that has it. */
49
- export declare function listEntryDocuments(dir: string, strict?: boolean, shapes?: readonly EntryShape[]): Promise<EntryDocument[]>;
66
+ export declare function listEntryDocuments(dir: string, strict?: boolean, shapes?: readonly EntryShape[], nested?: boolean): Promise<EntryDocument[]>;
50
67
  /** Parse full YAML metadata without flattening arrays, mappings, or multiline strings. */
51
68
  export declare function parseFrontmatterRecord(text: string): Record<string, unknown>;
52
69
  /** Read one resolved entry; strict runtime snapshots throw on I/O errors other than a vanished file. */
@@ -79,7 +96,7 @@ export interface UserEntryFile {
79
96
  };
80
97
  }
81
98
  /** List entries across the served shapes; strict runtime snapshots propagate I/O errors instead of publishing partial inventories. */
82
- export declare function listEntryFiles(dir: string, strict?: boolean, shapes?: readonly EntryShape[]): Promise<UserEntryFile[]>;
99
+ export declare function listEntryFiles(dir: string, strict?: boolean, shapes?: readonly EntryShape[], nested?: boolean): Promise<UserEntryFile[]>;
83
100
  /** Create one panel entry's document from its name: `<name>.md`, or `<name>/SKILL.md` in the directory shape. */
84
101
  export declare function writeEntryFile(dir: string, name: string, text: string, shape?: EntryShape): Promise<void>;
85
102
  /** Replace one resolved entry's document in place, wherever it lives. */
@@ -93,6 +110,6 @@ export declare function writeEntryDocument(document: EntryDocument, text: string
93
110
  */
94
111
  export declare function deleteEntryDocument(document: EntryDocument): Promise<void>;
95
112
  /** Whether an entry document with that name exists in any served shape. */
96
- export declare function entryExists(dir: string, name: string, shapes?: readonly EntryShape[]): Promise<boolean>;
113
+ export declare function entryExists(dir: string, name: string, shapes?: readonly EntryShape[], nested?: boolean): Promise<boolean>;
97
114
  /** Serialize a frontmatter block from a shallow record (deterministic key order). */
98
115
  export declare function serializeFrontmatter(meta: Record<string, unknown>): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-agent-plugins-market",
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.7.2",
3
+ "description": "One-stop skills, subagent, MCP and LSP manager inside DeepSeek Harness (DSH), compatible with Claude Code, Codex, Cursor, Kimi and other agent plugin layouts.",
4
+ "version": "0.8.1",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -74,16 +74,17 @@
74
74
  "ai-agents"
75
75
  ],
76
76
  "peerDependencies": {
77
- "@deepseek-ai/cordis": "^4.0.2",
78
- "@deepseek-ai/dsh-attachment": "^0.1.5-rc.2",
79
- "@deepseek-ai/dsh-credentials": "^0.1.5-rc.2",
80
- "@deepseek-ai/dsh-hooks-claude-code": "^0.1.5-rc.2",
81
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
82
- "@deepseek-ai/dsh-mcp-client": "^0.1.5-rc.2",
83
- "@deepseek-ai/dsh-skill": "^0.1.5-rc.2",
84
- "@deepseek-ai/dsh-subprocess": "^0.1.5-rc.2",
85
- "@deepseek-ai/dsh-timeout": "^0.1.5-rc.2",
86
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2"
77
+ "@deepseek-ai/cordis": "~4.0.4",
78
+ "@deepseek-ai/dsh-attachment": "^0.1.7-rc.1",
79
+ "@deepseek-ai/dsh-credentials": "^0.1.7-rc.1",
80
+ "@deepseek-ai/dsh-hooks-claude-code": "^0.1.7-rc.1",
81
+ "@deepseek-ai/dsh-llm": "^0.1.7-rc.1",
82
+ "@deepseek-ai/dsh-mcp-client": "^0.1.7-rc.1",
83
+ "@deepseek-ai/dsh-skill": "^0.1.7-rc.1",
84
+ "@deepseek-ai/dsh-subprocess": "^0.1.7-rc.1",
85
+ "@deepseek-ai/dsh-timeout": "^0.1.7-rc.1",
86
+ "@deepseek-ai/dsh-tools": "^0.1.7-rc.1",
87
+ "@deepseek-ai/dsh-util-workspace-path": "^0.1.7-rc.1"
87
88
  },
88
89
  "peerDependenciesMeta": {
89
90
  "@deepseek-ai/dsh-hooks-claude-code": {
@@ -97,12 +98,12 @@
97
98
  }
98
99
  },
99
100
  "dependencies": {
100
- "@deepseek-ai/dsh-atomic-write": "^0.1.5-rc.2",
101
- "@deepseek-ai/dsh-home-paths": "^0.1.5-rc.2",
102
- "@deepseek-ai/dsh-lsp": "^0.1.5-rc.2",
103
- "@deepseek-ai/dsh-lsp-stdio": "^0.1.5-rc.2",
104
- "@deepseek-ai/dsh-tool-lsp": "^0.1.5-rc.2",
105
- "@deepseek-ai/schemastery": "^3.18.2",
101
+ "@deepseek-ai/dsh-atomic-write": "^0.1.7-rc.1",
102
+ "@deepseek-ai/dsh-home-paths": "^0.1.7-rc.1",
103
+ "@deepseek-ai/dsh-lsp": "^0.1.7-rc.1",
104
+ "@deepseek-ai/dsh-lsp-stdio": "^0.1.7-rc.1",
105
+ "@deepseek-ai/dsh-tool-lsp": "^0.1.7-rc.1",
106
+ "@deepseek-ai/schemastery": "^3.18.4",
106
107
  "@modelcontextprotocol/sdk": "^1.30.0",
107
108
  "ajv": "^8.17.1",
108
109
  "fflate": "^0.8.3",
@@ -117,19 +118,23 @@
117
118
  "@codemirror/language": "^6.12.4",
118
119
  "@codemirror/state": "^6.7.5",
119
120
  "@codemirror/view": "^6.43.12",
120
- "@deepseek-ai/cordis": "^4.0.2",
121
- "@deepseek-ai/dsh-attachment": "0.1.5-rc.2",
122
- "@deepseek-ai/dsh-client-store": "0.1.5-rc.2",
123
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.2",
124
- "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
125
- "@deepseek-ai/dsh-credentials": "0.1.5-rc.2",
126
- "@deepseek-ai/dsh-hooks-claude-code": "0.1.5-rc.2",
127
- "@deepseek-ai/dsh-llm": "0.1.5-rc.2",
128
- "@deepseek-ai/dsh-mcp-client": "0.1.5-rc.2",
129
- "@deepseek-ai/dsh-skill": "0.1.5-rc.2",
130
- "@deepseek-ai/dsh-subprocess": "0.1.5-rc.2",
131
- "@deepseek-ai/dsh-timeout": "0.1.5-rc.2",
132
- "@deepseek-ai/dsh-tools": "0.1.5-rc.2",
121
+ "@deepseek-ai/cordis": "~4.0.4",
122
+ "@deepseek-ai/dsh-attachment": "0.1.7-rc.1",
123
+ "@deepseek-ai/dsh-client-store": "0.1.7-rc.1",
124
+ "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-rc.1",
125
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.1",
126
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.1",
127
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
128
+ "@deepseek-ai/dsh-credentials": "0.1.7-rc.1",
129
+ "@deepseek-ai/dsh-hooks-claude-code": "0.1.7-rc.1",
130
+ "@deepseek-ai/dsh-llm": "0.1.7-rc.1",
131
+ "@deepseek-ai/dsh-mcp-client": "0.1.7-rc.1",
132
+ "@deepseek-ai/dsh-skill": "0.1.7-rc.1",
133
+ "@deepseek-ai/dsh-subprocess": "0.1.7-rc.1",
134
+ "@deepseek-ai/dsh-timeout": "0.1.7-rc.1",
135
+ "@deepseek-ai/dsh-tools": "0.1.7-rc.1",
136
+ "@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.1",
137
+ "@deepseek-ai/cosmokit": "^1.8.5",
133
138
  "@eslint/js": "^10.0.1",
134
139
  "@shikijs/langs": "^4.4.3",
135
140
  "@tsdown/css": "^0.22.14",
@@ -140,6 +145,7 @@
140
145
  "anser": "^2.3.5",
141
146
  "clsx": "^2.1.1",
142
147
  "dependency-cruiser": "^18.4.0",
148
+ "diff": "^9.0.0",
143
149
  "eslint": "^10.9.1",
144
150
  "immer": "^11.1.18",
145
151
  "jsdom": "^30.0.1",
@@ -159,6 +165,7 @@
159
165
  "react": "^18.3.1",
160
166
  "react-dom": "~18.3.1",
161
167
  "shiki": "^4.4.3",
168
+ "simple-icons": "^16.31.0",
162
169
  "tsdown": "^0.22.14",
163
170
  "typescript": "^5.8.3",
164
171
  "typescript-eslint": "^8.67.0",
@@ -27,7 +27,7 @@ Namespace values are the suite's defaults rather than a ceiling the user cannot
27
27
 
28
28
  ## User-owned declarations
29
29
 
30
- `~/.agents/mcp.json` is local data rather than a distributable package. Keys this client does not know are stored back exactly as written, and the package-only rules — a closed server shape, bare command names, plugin-relative paths — do not apply to it. A suite's packaged `mcp.json` keeps every one of them, because a package carrying fields this client cannot honour is one it cannot promise to mount.
30
+ `~/.agents/mcp.json` is local data rather than a distributable package. Keys this client does not know are stored back exactly as written, and the package-only rules — a closed server shape, bare command names, plugin-relative paths — do not apply to it. A suite's packaged `mcp.json` keeps every one of them, because a package carrying fields this client cannot honour is one it cannot promise to mount. `$schema` is optional here: a file another Agent tool wrote is read as this release's dialect when the key is absent, and a declared version this client does not recognize is rejected.
31
31
 
32
32
  The editor reads the same two seats a suite declares, for one server at a time: the portable definition under `mcpServers` and this client's policy under `com.deepseek.harness`. The form writes only the half it owns, so a field it has no control for — a key another client introduced, a policy entry the form does not show — survives both a form edit and a JSON edit. Only the policy entries the user changed are sent on save; an entry the document drops asks for inheritance.
33
33