dsh-agent-plugins-market 0.8.0 → 0.8.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.
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/client/client.js +1594 -1732
- package/client/client.js.map +1 -1
- package/lib/application/agent-roles.js +53 -0
- package/lib/application/catalog-context.js +2 -2
- package/lib/application/catalog.js +4 -8
- package/lib/{runtime → application}/deadline.js +1 -1
- package/lib/application/details.js +3 -3
- package/lib/application/json-file.js +43 -0
- package/lib/{runtime → application/lsp}/lsp-direct-config.js +9 -7
- package/lib/application/lsp/lsp-server-state.js +17 -0
- package/lib/{runtime → application/lsp}/lsp-status.js +22 -7
- package/lib/{runtime → application/lsp}/profile-seam.js +1 -1
- package/lib/application/lsp-service.js +5 -5
- package/lib/{runtime → application/mcp}/mcp-backend.js +6 -21
- package/lib/{runtime → application/mcp}/mcp-config.js +4 -4
- package/lib/{runtime → application/mcp}/mcp-direct-config.js +8 -49
- package/lib/{runtime → application/mcp}/mcp-overrides.js +3 -5
- package/lib/{runtime → application/mcp}/mcp-status.js +13 -7
- package/lib/application/mcp-service.js +11 -35
- package/lib/application/panel-resources.js +48 -11
- package/lib/{runtime → application/panels}/user-hooks.js +2 -2
- package/lib/{runtime → application/panels}/user-store.js +2 -2
- package/lib/application/ports.js +1 -0
- package/lib/application/project-agent-roles.js +1 -1
- package/lib/{runtime → application}/server-config.js +7 -17
- package/lib/application/snapshot-cache.js +1 -1
- package/lib/application/source-store.js +3 -4
- package/lib/{runtime → application/state}/state-store.js +5 -7
- package/lib/{runtime → application/state}/storage-migration.js +4 -4
- package/lib/catalog/source-catalog.js +0 -4
- package/lib/contracts/lsp.js +1 -0
- package/lib/contracts/market.js +0 -1
- package/lib/contracts/mcp.js +1 -0
- package/lib/index.js +64 -34
- package/lib/routes.js +2 -9
- package/lib/runtime/{agent-role-router.js → agents/agent-role-router.js} +7 -53
- package/lib/runtime/{subagent-catalog.js → agents/subagent-catalog.js} +24 -16
- package/lib/runtime/core/context.js +31 -0
- package/lib/runtime/{reconciler.js → core/reconciler.js} +5 -5
- package/lib/runtime/host/failure-detail.js +58 -0
- package/lib/runtime/{feedback-tool.js → host/feedback-tool.js} +1 -1
- package/lib/runtime/host/host-locale.js +83 -0
- package/lib/runtime/{settings-namespace.js → host/settings-namespace.js} +44 -66
- package/lib/runtime/host/shell-path.js +196 -0
- package/lib/runtime/{tool-registry-observer.js → host/tool-registry-observer.js} +2 -1
- package/lib/runtime/{lsp-mounts.js → lsp/lsp-mounts.js} +69 -20
- package/lib/runtime/{mcp-client → mcp/bridge}/bridge.js +52 -22
- package/lib/runtime/{mcp-client → mcp/bridge}/connection.js +2 -2
- package/lib/runtime/{mcp-client → mcp/bridge}/oauth.js +1 -1
- package/lib/runtime/{mcp-client → mcp/bridge}/tools.js +2 -2
- package/lib/runtime/{mcp-auth-record.js → mcp/mcp-auth-record.js} +1 -1
- package/lib/runtime/{mcp-mounts.js → mcp/mcp-mounts.js} +14 -7
- package/lib/runtime/{user-commands.js → panels/user-commands.js} +3 -3
- package/lib/runtime/{user-panels.js → panels/user-panels.js} +2 -2
- package/lib/runtime/{commands-mounts.js → surfaces/commands-mounts.js} +7 -7
- package/lib/runtime/{hooks-mounts.js → surfaces/hooks-mounts.js} +2 -2
- package/lib/runtime/{project-runtime.js → surfaces/project-runtime.js} +5 -5
- package/lib/runtime/{skills-provider.js → surfaces/skills-provider.js} +4 -4
- package/lib/types/application/agent-roles.d.ts +30 -0
- package/lib/types/application/catalog.d.ts +4 -7
- package/lib/types/application/details.d.ts +1 -1
- package/lib/types/application/json-file.d.ts +12 -0
- package/lib/types/{runtime → application/lsp}/lsp-direct-config.d.ts +1 -1
- package/lib/types/{runtime → application/lsp}/lsp-status.d.ts +3 -3
- package/lib/types/{runtime → application/mcp}/mcp-backend.d.ts +24 -22
- package/lib/types/{runtime/mcp-client/config.d.ts → application/mcp/mcp-bridge-config.d.ts} +11 -1
- package/lib/types/{runtime → application/mcp}/mcp-config.d.ts +6 -7
- package/lib/types/application/mcp/mcp-direct-config.d.ts +17 -0
- package/lib/types/{runtime → application/mcp}/mcp-overrides.d.ts +1 -1
- package/lib/types/{runtime → application/mcp}/mcp-status.d.ts +7 -7
- package/lib/types/application/mcp-service.d.ts +4 -11
- package/lib/types/application/panel-resources.d.ts +9 -2
- package/lib/types/{runtime → application/panels}/user-hooks.d.ts +1 -1
- package/lib/types/{runtime → application/panels}/user-store.d.ts +1 -1
- package/lib/types/application/ports.d.ts +17 -3
- package/lib/types/application/project-agent-roles.d.ts +1 -1
- package/lib/types/application/queries.d.ts +3 -6
- package/lib/types/{runtime → application}/regions.d.ts +1 -1
- package/lib/types/{runtime → application/state}/state-store.d.ts +2 -2
- package/lib/types/catalog/source-catalog.d.ts +0 -2
- package/lib/types/contracts/lsp-status.d.ts +6 -0
- package/lib/types/contracts/lsp.d.ts +16 -0
- package/lib/types/contracts/market.d.ts +1 -4
- package/lib/types/contracts/mcp-status.d.ts +21 -2
- package/lib/types/contracts/mcp.d.ts +20 -0
- package/lib/types/index.d.ts +87 -1
- package/lib/types/model/types.d.ts +0 -14
- package/lib/types/runtime/{agent-role-router.d.ts → agents/agent-role-router.d.ts} +3 -28
- package/lib/types/runtime/{subagent-catalog.d.ts → agents/subagent-catalog.d.ts} +6 -6
- package/lib/types/runtime/core/context.d.ts +14 -0
- package/lib/types/runtime/{reconcile-scheduler.d.ts → core/reconcile-scheduler.d.ts} +2 -2
- package/lib/types/runtime/{reconciler.d.ts → core/reconciler.d.ts} +8 -8
- package/lib/types/runtime/host/failure-detail.d.ts +6 -0
- package/lib/types/runtime/host/host-locale.d.ts +66 -0
- package/lib/types/runtime/{model-catalog.d.ts → host/model-catalog.d.ts} +1 -1
- package/lib/types/runtime/{settings-namespace.d.ts → host/settings-namespace.d.ts} +42 -32
- package/lib/types/runtime/host/shell-path.d.ts +70 -0
- package/lib/types/runtime/{lsp-mounts.d.ts → lsp/lsp-mounts.d.ts} +17 -11
- package/lib/types/runtime/{mcp-client → mcp/bridge}/bridge.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/connection.d.ts +3 -11
- package/lib/types/runtime/{mcp-client → mcp/bridge}/host-contract.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/oauth.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/transport.d.ts +1 -1
- package/lib/types/runtime/{mcp-auth-record.d.ts → mcp/mcp-auth-record.d.ts} +1 -1
- package/lib/types/runtime/{mcp-credentials.d.ts → mcp/mcp-credentials.d.ts} +1 -1
- package/lib/types/runtime/{mcp-mounts.d.ts → mcp/mcp-mounts.d.ts} +5 -11
- package/lib/types/runtime/{user-commands.d.ts → panels/user-commands.d.ts} +1 -1
- package/lib/types/runtime/{user-panels.d.ts → panels/user-panels.d.ts} +1 -1
- package/lib/types/runtime/{commands-mounts.d.ts → surfaces/commands-mounts.d.ts} +2 -2
- package/lib/types/runtime/{hooks-mounts.d.ts → surfaces/hooks-mounts.d.ts} +1 -1
- package/lib/types/runtime/{project-runtime.d.ts → surfaces/project-runtime.d.ts} +3 -3
- package/lib/types/runtime/{skills-provider.d.ts → surfaces/skills-provider.d.ts} +1 -1
- package/package.json +39 -33
- package/lib/runtime/host-locale.js +0 -89
- package/lib/runtime/legacy-root-migration.js +0 -12
- package/lib/runtime/lsp-server-state.js +0 -19
- package/lib/runtime/mcp-client/json-schema-subset.js +0 -181
- package/lib/types/runtime/host-locale.d.ts +0 -31
- package/lib/types/runtime/legacy-root-migration.d.ts +0 -2
- package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +0 -58
- package/lib/types/runtime/mcp-direct-config.d.ts +0 -39
- /package/lib/{runtime/mcp-client/config.js → application/mcp/mcp-bridge-config.js} +0 -0
- /package/lib/{runtime → application/mcp}/mcp-redaction.js +0 -0
- /package/lib/{runtime → application}/regions.js +0 -0
- /package/lib/runtime/{agent-role-names.js → agents/agent-role-names.js} +0 -0
- /package/lib/runtime/{mount-lifecycle.js → core/mount-lifecycle.js} +0 -0
- /package/lib/runtime/{reconcile-scheduler.js → core/reconcile-scheduler.js} +0 -0
- /package/lib/runtime/{source-auto-update.js → core/source-auto-update.js} +0 -0
- /package/lib/runtime/{timer-seat.js → core/timer-seat.js} +0 -0
- /package/lib/runtime/{model-catalog.js → host/model-catalog.js} +0 -0
- /package/lib/runtime/{plugin-message-source.js → host/plugin-message-source.js} +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/host-contract.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/host-seams.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/plugin-identity.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/projection.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/transport.js +0 -0
- /package/lib/runtime/{mcp-credentials.js → mcp/mcp-credentials.js} +0 -0
- /package/lib/runtime/{dynamic-context.js → surfaces/dynamic-context.js} +0 -0
- /package/lib/types/{runtime → application}/deadline.d.ts +0 -0
- /package/lib/types/{runtime → application/lsp}/lsp-server-state.d.ts +0 -0
- /package/lib/types/{runtime → application/lsp}/profile-seam.d.ts +0 -0
- /package/lib/types/{runtime → application/mcp}/mcp-redaction.d.ts +0 -0
- /package/lib/types/{runtime → application}/server-config.d.ts +0 -0
- /package/lib/types/{runtime → application/state}/storage-migration.d.ts +0 -0
- /package/lib/types/runtime/{agent-role-names.d.ts → agents/agent-role-names.d.ts} +0 -0
- /package/lib/types/runtime/{mount-lifecycle.d.ts → core/mount-lifecycle.d.ts} +0 -0
- /package/lib/types/runtime/{source-auto-update.d.ts → core/source-auto-update.d.ts} +0 -0
- /package/lib/types/runtime/{timer-seat.d.ts → core/timer-seat.d.ts} +0 -0
- /package/lib/types/runtime/{feedback-tool.d.ts → host/feedback-tool.d.ts} +0 -0
- /package/lib/types/runtime/{plugin-message-source.d.ts → host/plugin-message-source.d.ts} +0 -0
- /package/lib/types/runtime/{tool-registry-observer.d.ts → host/tool-registry-observer.d.ts} +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/host-seams.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/plugin-identity.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/projection.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/tools.d.ts +0 -0
- /package/lib/types/runtime/{dynamic-context.d.ts → surfaces/dynamic-context.d.ts} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/** Installed suite and user resources share one inventory; paths never come from HTTP callers. */
|
|
2
|
-
import { realpath, stat
|
|
2
|
+
import { realpath, stat } from 'node:fs/promises';
|
|
3
|
+
import { isDeepStrictEqual as deepEqual } from 'node:util';
|
|
3
4
|
import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write';
|
|
4
5
|
import { defaultMarkdownResources, resourceText } from '../catalog/component-files.js';
|
|
5
6
|
import { pluginRootOf } from '../catalog/plugin-variables.js';
|
|
6
7
|
import { isWithin, suiteDataDir } from '../catalog/paths.js';
|
|
7
8
|
import { stripFrontmatter } from '../catalog/skills-parse.js';
|
|
8
|
-
import { parseFrontmatterRecord } from '
|
|
9
|
+
import { parseFrontmatterRecord } from './panels/user-store.js';
|
|
9
10
|
/**
|
|
10
11
|
* Id of one panel entry backed by a file inside an installed suite's checkout.
|
|
11
12
|
* The leading `[` is what distinguishes a plugin entry from a user-authored
|
|
@@ -18,6 +19,16 @@ export function pluginResourceId(sourceId, suiteId, kind, name) {
|
|
|
18
19
|
export function isPluginResourceId(id) {
|
|
19
20
|
return id.startsWith('[');
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Frontmatter keys beyond the enable switch that a panel control may diff on a
|
|
24
|
+
* plugin document, per kind: the harness invocation pair on skills, and the
|
|
25
|
+
* model-routing keys the persona form edits on agents.
|
|
26
|
+
*/
|
|
27
|
+
const FLIPPABLE_KEYS = {
|
|
28
|
+
skills: ['disable-model-invocation', 'user-invocable'],
|
|
29
|
+
commands: [],
|
|
30
|
+
agents: ['model', 'provider', 'reasoning_effort', 'reasoningEffort']
|
|
31
|
+
};
|
|
21
32
|
export function createPanelResources(catalog, users) {
|
|
22
33
|
return {
|
|
23
34
|
skills: new PanelResources(catalog, users.skills, 'skills'),
|
|
@@ -96,11 +107,12 @@ class PanelResources {
|
|
|
96
107
|
* A plugin resource is writable only when it sits inside the user dimension
|
|
97
108
|
* root; suite checkouts elsewhere on disk stay read-only. The user-panel
|
|
98
109
|
* store lives in the shared Agent layout root instead, so containment is
|
|
99
|
-
* measured against the catalog's root, not the panel directory.
|
|
110
|
+
* measured against the catalog's root, not the panel directory. Callers pass
|
|
111
|
+
* the entry they already fetched: a full inventory scan per call would read
|
|
112
|
+
* every suite document twice per write.
|
|
100
113
|
*/
|
|
101
|
-
async pluginPath(
|
|
102
|
-
|
|
103
|
-
if (entry?.origin !== 'plugin')
|
|
114
|
+
async pluginPath(entry) {
|
|
115
|
+
if (entry.origin !== 'plugin')
|
|
104
116
|
throw new Error('Unknown installed plugin resource');
|
|
105
117
|
if (entry.path.endsWith('.json'))
|
|
106
118
|
throw new Error('Inline manifest resources are read-only; edit their source manifest');
|
|
@@ -113,12 +125,37 @@ class PanelResources {
|
|
|
113
125
|
async update(id, text) {
|
|
114
126
|
if (!isPluginResourceId(id))
|
|
115
127
|
return this.users.update(id, text);
|
|
116
|
-
|
|
117
|
-
|
|
128
|
+
const previous = await this.get(id);
|
|
129
|
+
if (previous === undefined)
|
|
130
|
+
throw new Error('Unknown installed plugin resource');
|
|
131
|
+
this.assertStateFlipOnly(previous.rawText, text);
|
|
132
|
+
await writeFileAtomic(await this.pluginPath(previous), text, { mode: 0o644 });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A suite owns its files' content: the panel may only flip state frontmatter.
|
|
136
|
+
* The document body must stay byte-identical, and the frontmatter diff is
|
|
137
|
+
* confined to `disabled` everywhere, plus {@link FLIPPABLE_KEYS}'s per-kind
|
|
138
|
+
* control keys — the harness invocation pair on skills, model routing on
|
|
139
|
+
* agents.
|
|
140
|
+
*/
|
|
141
|
+
assertStateFlipOnly(previousText, text) {
|
|
142
|
+
if (stripFrontmatter(previousText) !== stripFrontmatter(text))
|
|
143
|
+
throw new Error('plugin resources are read-only; the suite owns their content');
|
|
144
|
+
const before = parseFrontmatterRecord(previousText);
|
|
145
|
+
const after = parseFrontmatterRecord(text);
|
|
146
|
+
const flippable = new Set(['disabled', ...FLIPPABLE_KEYS[this.kind]]);
|
|
147
|
+
for (const key of new Set([...Object.keys(before), ...Object.keys(after)])) {
|
|
148
|
+
if (flippable.has(key))
|
|
149
|
+
continue;
|
|
150
|
+
if (!deepEqual(before[key], after[key])) {
|
|
151
|
+
throw new Error('plugin resources are read-only; only the enable state can be changed');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
118
154
|
}
|
|
119
155
|
async remove(id) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
156
|
+
// Plugin files belong to their suite checkout; install/uninstall manages them.
|
|
157
|
+
if (isPluginResourceId(id))
|
|
158
|
+
throw new Error('plugin resources are managed by their suite; uninstall the suite instead');
|
|
159
|
+
return this.users.remove(id);
|
|
123
160
|
}
|
|
124
161
|
}
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { readFile } from 'node:fs/promises';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { normalizeHookDocuments, standaloneHookDocument } from '
|
|
15
|
-
import { effectiveSurfaces } from '
|
|
14
|
+
import { normalizeHookDocuments, standaloneHookDocument } from '../../catalog/project-hooks.js';
|
|
15
|
+
import { effectiveSurfaces } from '../../model/types.js';
|
|
16
16
|
export const USER_HOOKS_SOURCE = '@user-hooks';
|
|
17
17
|
export const USER_HOOKS_SUITE = 'user-hooks';
|
|
18
18
|
/**
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
* to that directory. Skills also accept the cross-tool directory spelling
|
|
12
12
|
* (`<name>/SKILL.md`) that other Agent tools and the harness's own reader of
|
|
13
13
|
* `~/.agents/skills` author, and read it from the top level only.
|
|
14
|
-
* @module
|
|
14
|
+
* @module application/user-store
|
|
15
15
|
*/
|
|
16
16
|
import { readdir, readFile, rmdir, rm, stat } from 'node:fs/promises';
|
|
17
17
|
import { dirname, join } from 'node:path';
|
|
18
18
|
import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write';
|
|
19
19
|
import { parseDocument, stringify } from 'yaml';
|
|
20
|
-
import { parseSkillFrontmatter, stripFrontmatter } from '
|
|
20
|
+
import { parseSkillFrontmatter, stripFrontmatter } from '../../catalog/skills-parse.js';
|
|
21
21
|
/** Where user panel entries persist: `<agentsRoot>/<kind>/`. */
|
|
22
22
|
export function userEntryDir(agentsRoot, kind) {
|
|
23
23
|
return join(agentsRoot, kind);
|
package/lib/application/ports.js
CHANGED
|
@@ -10,6 +10,7 @@ export const defaultCatalogPorts = {
|
|
|
10
10
|
mcpServerOwner: () => undefined,
|
|
11
11
|
lspStatusSource: { diagnosticsSnapshot: () => new Map(), hasLiveMounts: () => false },
|
|
12
12
|
mcpBackend: async () => 'builtin',
|
|
13
|
+
localePreference: () => 'zh',
|
|
13
14
|
setMcpBackend: async () => {
|
|
14
15
|
throw new Error('the settings service is not mounted');
|
|
15
16
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { defaultMarkdownResources, resourceText } from '../catalog/component-files.js';
|
|
3
3
|
import { pluginRootOf } from '../catalog/plugin-variables.js';
|
|
4
4
|
import { suiteDataDir } from '../catalog/paths.js';
|
|
5
|
-
import { parseAgentRole } from '
|
|
5
|
+
import { parseAgentRole } from './agent-roles.js';
|
|
6
6
|
export async function projectAgentRoles(catalog, parent) {
|
|
7
7
|
const cwd = parent?.session?.header?.cwd;
|
|
8
8
|
if (typeof cwd !== 'string' || cwd === '')
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
1
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
2
|
+
import { readJsonFile, writeJsonDocument } from './json-file.js';
|
|
4
3
|
import { MCP_SCHEMA_ID, validateAgainstSchema, validateMcpJson } from '../catalog/validate.js';
|
|
5
4
|
import { parseLspServers } from '../catalog/lsp-spec.js';
|
|
6
5
|
import { qualifiedSuiteId } from '../catalog/paths.js';
|
|
7
|
-
import { redactMcpConfig } from './mcp-redaction.js';
|
|
6
|
+
import { redactMcpConfig } from './mcp/mcp-redaction.js';
|
|
8
7
|
/**
|
|
9
8
|
* The errors the closed-set package shape produces. A user-owned service does
|
|
10
9
|
* not obey that shape, and the per-transport checks still require what it needs.
|
|
@@ -85,24 +84,15 @@ export function lspConfig(spec) {
|
|
|
85
84
|
return Object.fromEntries(Object.entries(spec).filter(([key]) => key !== 'key'));
|
|
86
85
|
}
|
|
87
86
|
export async function loadLspOverrides(root) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
catch (error) {
|
|
93
|
-
if (error.code === 'ENOENT')
|
|
94
|
-
return {};
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
87
|
+
const raw = await readJsonFile(join(root, 'lsp-overrides.json'));
|
|
88
|
+
if (typeof raw !== 'object' || raw === null)
|
|
89
|
+
return {};
|
|
90
|
+
return Object.fromEntries(Object.entries(raw).map(([id, config]) => [id, validateServerLsp(id.slice(id.lastIndexOf('/') + 1), config)]));
|
|
97
91
|
}
|
|
98
92
|
export async function saveLspOverride(root, id, config) {
|
|
99
93
|
const overrides = await loadLspOverrides(root);
|
|
100
94
|
overrides[id] = config;
|
|
101
|
-
|
|
102
|
-
await writeFileAtomic(path, JSON.stringify(Object.fromEntries(Object.entries(overrides).map(([key, value]) => [key, lspConfig(value)])), null, 2), {
|
|
103
|
-
mode: 0o600,
|
|
104
|
-
dirMode: 0o700
|
|
105
|
-
});
|
|
95
|
+
await writeJsonDocument(join(root, 'lsp-overrides.json'), Object.fromEntries(Object.entries(overrides).map(([key, value]) => [key, lspConfig(value)])));
|
|
106
96
|
}
|
|
107
97
|
export async function applyLspOverrides(root, suites) {
|
|
108
98
|
const overrides = await loadLspOverrides(root);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { join, resolve } from 'node:path';
|
|
13
13
|
import { resolveProjectRoot, STATE_FILE_NAME } from '../catalog/paths.js';
|
|
14
14
|
import { discoverSourceListWithNotes } from '../catalog/source-catalog.js';
|
|
15
|
-
import { loadState } from '
|
|
15
|
+
import { loadState } from './state/state-store.js';
|
|
16
16
|
export const SCAN_CACHE_TTL_MS = 30_000;
|
|
17
17
|
const SCAN_CACHE_MAX_ENTRIES = 8;
|
|
18
18
|
export class SnapshotCache {
|
|
@@ -15,8 +15,7 @@ import { repoName } from '../catalog/manifests.js';
|
|
|
15
15
|
import { deriveSourceIdCandidates, expandHome, sanitizeId, sourceCheckoutDir, sourcesDir } from '../catalog/paths.js';
|
|
16
16
|
import { isDirectory, pathExists } from '../catalog/fs-probes.js';
|
|
17
17
|
import { canonicalGitUrl } from '../catalog/scan-resolvers.js';
|
|
18
|
-
import {
|
|
19
|
-
import { githubCloneUrl, resolveRegion } from '../runtime/regions.js';
|
|
18
|
+
import { githubCloneUrl, resolveRegion } from './regions.js';
|
|
20
19
|
import { resolveSourceKind } from '../model/types.js';
|
|
21
20
|
export class SourceStore {
|
|
22
21
|
context;
|
|
@@ -280,7 +279,7 @@ export class SourceStore {
|
|
|
280
279
|
// source.url) are re-pointed — a foreign remote is left untouched.
|
|
281
280
|
if (source.kind === 'git' || (source.kind === undefined && source.local !== true)) {
|
|
282
281
|
try {
|
|
283
|
-
const region = resolveRegion(await this.ports.downloadRegion(),
|
|
282
|
+
const region = resolveRegion(await this.ports.downloadRegion(), this.ports.localePreference());
|
|
284
283
|
const routed = githubCloneUrl(region, source.url);
|
|
285
284
|
const origin = await gitRemoteUrl(checkout);
|
|
286
285
|
if (origin !== routed && (origin === source.url || origin === githubCloneUrl('china', source.url))) {
|
|
@@ -401,7 +400,7 @@ export class SourceStore {
|
|
|
401
400
|
try {
|
|
402
401
|
// The region routes github.com clones through the China mirror prefix;
|
|
403
402
|
// the proxied URL becomes `origin`, so refreshes follow the same route.
|
|
404
|
-
const region = resolveRegion(await this.ports.downloadRegion(),
|
|
403
|
+
const region = resolveRegion(await this.ports.downloadRegion(), this.ports.localePreference());
|
|
405
404
|
await gitClone(githubCloneUrl(region, source.url), source.branch, checkout, this.context.git);
|
|
406
405
|
return undefined;
|
|
407
406
|
}
|
|
@@ -7,15 +7,13 @@
|
|
|
7
7
|
* like the market profile state this pattern follows. The record shapes live
|
|
8
8
|
* in `src/model/types.ts`; only the reading and writing live here.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { SUITE_SURFACE_KEYS } from '../model/types.js';
|
|
10
|
+
import { readJsonFile, writeJsonDocument } from '../json-file.js';
|
|
11
|
+
import { SUITE_SURFACE_KEYS } from '../../model/types.js';
|
|
13
12
|
export const EMPTY_STATE = { version: 1, sources: [], installed: {} };
|
|
14
13
|
/** Parse persisted state; unreadable or wrong-version files yield a contained empty state. */
|
|
15
14
|
export async function loadState(statePath) {
|
|
16
15
|
try {
|
|
17
|
-
const
|
|
18
|
-
const parsed = JSON.parse(text);
|
|
16
|
+
const parsed = await readJsonFile(statePath);
|
|
19
17
|
if (typeof parsed !== 'object' || parsed === null)
|
|
20
18
|
return EMPTY_STATE;
|
|
21
19
|
const record = parsed;
|
|
@@ -87,7 +85,7 @@ function parseSurfaceOverrides(raw) {
|
|
|
87
85
|
}
|
|
88
86
|
return hasAny ? { surfaces: overrides } : {};
|
|
89
87
|
}
|
|
90
|
-
/** Persist state atomically through the
|
|
88
|
+
/** Persist state atomically through the shared JSON document writer. */
|
|
91
89
|
export async function saveState(statePath, state) {
|
|
92
|
-
await
|
|
90
|
+
await writeJsonDocument(statePath, state);
|
|
93
91
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { constants } from 'node:fs';
|
|
3
3
|
import { copyFile, lstat, mkdir, readdir, readFile, rmdir, unlink } from 'node:fs/promises';
|
|
4
4
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import { expandHome, isWithin, resolveAgentsRoot, resolveDataRoot, resolveDshHome, resolveUserRoot } from '
|
|
5
|
+
import { readJsonFile, writeJsonDocument } from '../json-file.js';
|
|
6
|
+
import { expandHome, isWithin, resolveAgentsRoot, resolveDataRoot, resolveDshHome, resolveUserRoot } from '../../catalog/paths.js';
|
|
7
7
|
async function info(path) {
|
|
8
8
|
try {
|
|
9
9
|
return await lstat(path);
|
|
@@ -156,7 +156,7 @@ async function relocateManagedSourceUrls(userRoot, legacyUserRoot) {
|
|
|
156
156
|
const path = join(userRoot, 'state.json');
|
|
157
157
|
if ((await info(path)) === undefined)
|
|
158
158
|
return;
|
|
159
|
-
const state =
|
|
159
|
+
const state = await readJsonFile(path);
|
|
160
160
|
if (typeof state !== 'object' || state === null || !('sources' in state) || !Array.isArray(state.sources))
|
|
161
161
|
return;
|
|
162
162
|
let changed = false;
|
|
@@ -170,7 +170,7 @@ async function relocateManagedSourceUrls(userRoot, legacyUserRoot) {
|
|
|
170
170
|
changed = true;
|
|
171
171
|
}
|
|
172
172
|
if (changed) {
|
|
173
|
-
await
|
|
173
|
+
await writeJsonDocument(path, state);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
async function collectUnsupportedEntries(path, conflicts) {
|
|
@@ -13,10 +13,6 @@ import { expandHome, sourcesDir } from './paths.js';
|
|
|
13
13
|
import { isDirectory } from './fs-probes.js';
|
|
14
14
|
import { scanSource as scanSourceWithNotes } from './suite-scanner.js';
|
|
15
15
|
import { discoverNativeProjectSuites } from './native-project.js';
|
|
16
|
-
/** Discover suites from the selected configured or project checkouts. */
|
|
17
|
-
export async function discoverSourceList(sources, dimension, dimensionRoot) {
|
|
18
|
-
return (await discoverSourceListWithNotes(sources, dimension, dimensionRoot, true)).suites;
|
|
19
|
-
}
|
|
20
16
|
/**
|
|
21
17
|
* Discover suites plus per-source scan diagnostics for one dimension.
|
|
22
18
|
* @param scanProjectLayouts - whether the project's own native Agent directories
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/contracts/market.js
CHANGED
|
@@ -6,7 +6,6 @@ export const MARKET_ROUTES = {
|
|
|
6
6
|
overview: `${MARKET_API_PREFIX}overview`,
|
|
7
7
|
mcpStatus: `${MARKET_API_PREFIX}mcp-status`,
|
|
8
8
|
addMcpServer: `${MARKET_API_PREFIX}mcp-servers/add`,
|
|
9
|
-
importMcpServers: `${MARKET_API_PREFIX}mcp-servers/import`,
|
|
10
9
|
lspStatus: `${MARKET_API_PREFIX}lsp-status`,
|
|
11
10
|
lspServers: `${MARKET_API_PREFIX}lsp-servers`,
|
|
12
11
|
addLspServer: `${MARKET_API_PREFIX}lsp-servers/add`,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/index.js
CHANGED
|
@@ -1,30 +1,51 @@
|
|
|
1
|
+
import z from '@deepseek-ai/schemastery';
|
|
2
|
+
import { MarketSettingsFields } from './application/mcp/mcp-backend.js';
|
|
1
3
|
import { Catalog } from './application/catalog.js';
|
|
2
|
-
import { settlesWithin } from './
|
|
3
|
-
import { RuntimeReconciler } from './runtime/reconciler.js';
|
|
4
|
-
import { ReconcileScheduler } from './runtime/reconcile-scheduler.js';
|
|
5
|
-
import { MarketSettingsNamespace } from './runtime/settings-namespace.js';
|
|
6
|
-
import { deleteMcpAuthGrant } from './runtime/mcp-auth-record.js';
|
|
7
|
-
import { inspectToolRegistry, toolsServiceOf } from './runtime/tool-registry-observer.js';
|
|
8
|
-
import { migratePluginStorage } from './
|
|
9
|
-
import { mountAgentRoleTool } from './runtime/agent-role-router.js';
|
|
4
|
+
import { settlesWithin } from './application/deadline.js';
|
|
5
|
+
import { RuntimeReconciler } from './runtime/core/reconciler.js';
|
|
6
|
+
import { ReconcileScheduler } from './runtime/core/reconcile-scheduler.js';
|
|
7
|
+
import { MarketSettingsNamespace } from './runtime/host/settings-namespace.js';
|
|
8
|
+
import { deleteMcpAuthGrant } from './runtime/mcp/mcp-auth-record.js';
|
|
9
|
+
import { inspectToolRegistry, toolsServiceOf } from './runtime/host/tool-registry-observer.js';
|
|
10
|
+
import { migratePluginStorage } from './application/state/storage-migration.js';
|
|
11
|
+
import { mountAgentRoleTool } from './runtime/agents/agent-role-router.js';
|
|
10
12
|
import { projectAgentRoles } from './application/project-agent-roles.js';
|
|
11
|
-
import { mountProjectCommands, mountProjectMcp, mountProjectHooks, mountSuiteInstructions } from './runtime/project-runtime.js';
|
|
13
|
+
import { mountProjectCommands, mountProjectMcp, mountProjectHooks, mountSuiteInstructions } from './runtime/surfaces/project-runtime.js';
|
|
12
14
|
import { createPanelResources } from './application/panel-resources.js';
|
|
13
15
|
import { resolveAgentsRoot, resolveDataRoot, resolveUserRoot } from './catalog/paths.js';
|
|
14
16
|
import { mountSuiteRoutes } from './routes.js';
|
|
15
|
-
import { SuiteSkillProvider } from './runtime/skills-provider.js';
|
|
16
|
-
import { shellSeamOf } from './runtime/dynamic-context.js';
|
|
17
|
-
import { loadLspServers } from './
|
|
18
|
-
import { loadDisabledLspServers } from './
|
|
19
|
-
import { bindHostLocale,
|
|
20
|
-
import { createUserPanelStores } from './runtime/user-panels.js';
|
|
21
|
-
import { SourceAutoUpdater } from './runtime/source-auto-update.js';
|
|
22
|
-
import { UserPanelSkillProvider } from './runtime/user-panels.js';
|
|
23
|
-
import { UserCommandMountRegistry } from './runtime/user-commands.js';
|
|
17
|
+
import { SuiteSkillProvider } from './runtime/surfaces/skills-provider.js';
|
|
18
|
+
import { shellSeamOf } from './runtime/surfaces/dynamic-context.js';
|
|
19
|
+
import { loadLspServers } from './application/lsp/lsp-direct-config.js';
|
|
20
|
+
import { loadDisabledLspServers } from './application/lsp/lsp-server-state.js';
|
|
21
|
+
import { bindHostLocale, LOCALE_SETTINGS_ENTRY, readHostLocalePreference, readLocalePreference, setHostLocaleSource } from './runtime/host/host-locale.js';
|
|
22
|
+
import { createUserPanelStores } from './runtime/panels/user-panels.js';
|
|
23
|
+
import { SourceAutoUpdater } from './runtime/core/source-auto-update.js';
|
|
24
|
+
import { UserPanelSkillProvider } from './runtime/panels/user-panels.js';
|
|
25
|
+
import { UserCommandMountRegistry } from './runtime/panels/user-commands.js';
|
|
24
26
|
import { presetSourceRef } from './model/preset-source.js';
|
|
25
27
|
export const name = 'dsh-agent-plugins-market';
|
|
26
28
|
export const inject = ['skills', 'commands'];
|
|
27
|
-
export
|
|
29
|
+
export const Config = z.object({
|
|
30
|
+
userRoot: z.union([z.string(), z.const(undefined)]),
|
|
31
|
+
dataRoot: z.union([z.string(), z.const(undefined)]),
|
|
32
|
+
sources: z.any(),
|
|
33
|
+
git: z.object({
|
|
34
|
+
proxy: z.string(),
|
|
35
|
+
insteadOf: z.dict(z.string(), z.any()),
|
|
36
|
+
timeoutMs: z.natural(),
|
|
37
|
+
cloneRetry: z.boolean(),
|
|
38
|
+
fallbackTarball: z.boolean(),
|
|
39
|
+
allowHttpArchives: z.boolean()
|
|
40
|
+
}),
|
|
41
|
+
mcpEnhanced: MarketSettingsFields.mcpEnhanced.volatile(),
|
|
42
|
+
scanProjectLayouts: MarketSettingsFields.scanProjectLayouts.volatile(),
|
|
43
|
+
downloadRegion: MarketSettingsFields.downloadRegion.volatile(),
|
|
44
|
+
feedbackEnabled: MarketSettingsFields.feedbackEnabled.volatile(),
|
|
45
|
+
autoUpdateSources: MarketSettingsFields.autoUpdateSources.volatile()
|
|
46
|
+
});
|
|
47
|
+
const undefinedRef = { get: () => undefined };
|
|
48
|
+
export async function apply(ctx, config = { mcpEnhanced: undefinedRef, scanProjectLayouts: undefinedRef, downloadRegion: undefinedRef, feedbackEnabled: undefinedRef, autoUpdateSources: undefinedRef }) {
|
|
28
49
|
const userRoot = resolveUserRoot(config.userRoot);
|
|
29
50
|
const dataRoot = resolveDataRoot(config.dataRoot, userRoot);
|
|
30
51
|
const agentsRoot = resolveAgentsRoot();
|
|
@@ -33,24 +54,32 @@ export async function apply(ctx, config = {}) {
|
|
|
33
54
|
throw new Error(`Plugin storage migration conflicts (original files retained): ${migration.conflicts.join(', ')}`);
|
|
34
55
|
let providerControl;
|
|
35
56
|
let userPanelControl;
|
|
36
|
-
// Host runtime copy resolves from the harness `locale.preference` setting
|
|
37
|
-
// the async settings read lands before the first session starts in practice.
|
|
57
|
+
// Host runtime copy resolves from the harness `locale.preference` setting.
|
|
38
58
|
const hostLocale = { t: bindHostLocale(undefined) };
|
|
39
59
|
const refreshHostLocale = () => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
userPanelControl?.invalidate();
|
|
44
|
-
});
|
|
60
|
+
hostLocale.t = bindHostLocale(readLocalePreference());
|
|
61
|
+
providerControl?.invalidate();
|
|
62
|
+
userPanelControl?.invalidate();
|
|
45
63
|
};
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
// The preference is the `locale` entry's live configuration, projected by the
|
|
65
|
+
// host settings service. Resolve that service through the store from this
|
|
66
|
+
// entry's own context, and register the wiring as an effect so it lives
|
|
67
|
+
// exactly as long as this fiber: a context captured from an injection
|
|
68
|
+
// callback throws `cannot get required service "settings" in inactive
|
|
69
|
+
// context` once a profile reload disposes that fiber, and the unhandled
|
|
70
|
+
// rejection ends the host. Re-read once the service lands, because it may
|
|
71
|
+
// mount after this plugin.
|
|
72
|
+
ctx.effect(() => setHostLocaleSource(() => readHostLocalePreference(ctx.get('settings'))), 'dsh-agent-plugins-market: host locale source');
|
|
73
|
+
refreshHostLocale();
|
|
74
|
+
ctx.inject(['settings'], () => {
|
|
52
75
|
refreshHostLocale();
|
|
53
76
|
});
|
|
77
|
+
// A language switch writes the `locale` entry's form; re-read so the copy the
|
|
78
|
+
// market renders follows it without a reload.
|
|
79
|
+
ctx.effect(() => ctx.on('settings/document-updated', (ns) => {
|
|
80
|
+
if (ns === LOCALE_SETTINGS_ENTRY)
|
|
81
|
+
refreshHostLocale();
|
|
82
|
+
}), 'dsh-agent-plugins-market: host locale refresh');
|
|
54
83
|
const runtime = new RuntimeReconciler(ctx, dataRoot, key => hostLocale.t(key));
|
|
55
84
|
// User panel stores (skills / commands / agent personas) and their runtime
|
|
56
85
|
// contributions: one extra skill provider plus one command mount registry.
|
|
@@ -110,7 +139,7 @@ export async function apply(ctx, config = {}) {
|
|
|
110
139
|
};
|
|
111
140
|
// Background source updates: off until the settings switch says otherwise.
|
|
112
141
|
const autoUpdate = new SourceAutoUpdater(ctx, () => catalog.refreshSource());
|
|
113
|
-
const settings = new MarketSettingsNamespace(ctx, dataRoot, hostLocale, {
|
|
142
|
+
const settings = new MarketSettingsNamespace(ctx, config, dataRoot, hostLocale, {
|
|
114
143
|
setScanProjectLayouts: enabled => catalog.setScanProjectLayouts(enabled),
|
|
115
144
|
refreshMcpMounts: () => {
|
|
116
145
|
void Promise.all([scheduler.request(), projectMcp?.refresh()]).catch(() => { });
|
|
@@ -141,7 +170,8 @@ export async function apply(ctx, config = {}) {
|
|
|
141
170
|
lspStatusSource: runtime.lsp,
|
|
142
171
|
mcpBackend: () => settings.backend(),
|
|
143
172
|
setMcpBackend: backend => settings.setBackend(backend),
|
|
144
|
-
downloadRegion: () => settings.downloadRegion()
|
|
173
|
+
downloadRegion: () => settings.downloadRegion(),
|
|
174
|
+
localePreference: () => readLocalePreference() ?? 'zh'
|
|
145
175
|
};
|
|
146
176
|
const catalog = new Catalog({ userRoot, dataRoot, agentsRoot, onChanged, ports, ...(config.git === undefined ? {} : { git: config.git }) });
|
|
147
177
|
await catalog.load();
|
package/lib/routes.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
import { isAbsolute } from 'node:path';
|
|
10
10
|
import { MARKET_ROUTES, userPanelRoute } from './contracts/market.js';
|
|
11
11
|
import { expandHome } from './catalog/paths.js';
|
|
12
|
-
import { sanitizeOverridePatch } from './
|
|
13
|
-
import { readModelCatalog } from './runtime/model-catalog.js';
|
|
12
|
+
import { sanitizeOverridePatch } from './application/mcp/mcp-overrides.js';
|
|
13
|
+
import { readModelCatalog } from './runtime/host/model-catalog.js';
|
|
14
14
|
const MAX_BODY_BYTES = 64 * 1024;
|
|
15
15
|
/** Mount every route; returns the disposer releasing them all. */
|
|
16
16
|
export function mountSuiteRoutes(hostCtx, manager, panels) {
|
|
@@ -93,13 +93,6 @@ export function mountSuiteRoutes(hostCtx, manager, panels) {
|
|
|
93
93
|
await manager.addMcpServer(body.name, body.config);
|
|
94
94
|
return {};
|
|
95
95
|
});
|
|
96
|
-
// Paste import: many services in one write. Each entry reports its own
|
|
97
|
-
// outcome, so one rejected definition never fails the whole paste.
|
|
98
|
-
post(MARKET_ROUTES.importMcpServers, async (body) => {
|
|
99
|
-
const overwrite = body['overwrite'] === true;
|
|
100
|
-
const result = await manager.importMcpServers(body['servers'], overwrite);
|
|
101
|
-
return { imported: result.imported, skipped: result.skipped };
|
|
102
|
-
});
|
|
103
96
|
get(MARKET_ROUTES.lspStatus, async (_request, response) => {
|
|
104
97
|
sendJson(response, 200, await manager.lspStatus());
|
|
105
98
|
});
|
|
@@ -1,62 +1,17 @@
|
|
|
1
1
|
/** Execute user and installed-suite agent cards through the host subagent service. */
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
4
|
-
import { parse as parseYaml } from 'yaml';
|
|
5
4
|
import { mountSubagentCatalog } from './subagent-catalog.js';
|
|
6
5
|
import { namedAgentRoles } from './agent-role-names.js';
|
|
7
|
-
import { expandPluginPaths } from '
|
|
6
|
+
import { expandPluginPaths } from '../../catalog/plugin-variables.js';
|
|
7
|
+
import { parseAgentRole } from '../../application/agent-roles.js';
|
|
8
|
+
export { parseAgentRole };
|
|
8
9
|
export const AGENT_ROLE_TOOL_NAME = 'subagent_role';
|
|
9
10
|
/**
|
|
10
11
|
* Absolute delegation-depth cap applied to every role child. The host default is
|
|
11
12
|
* the same value; keeping it explicit preserves the shipped recursion budget.
|
|
12
13
|
*/
|
|
13
14
|
const MAX_AGENT_ROLE_DEPTH = 3;
|
|
14
|
-
function optionalText(value, key) {
|
|
15
|
-
if (value === undefined)
|
|
16
|
-
return undefined;
|
|
17
|
-
if (typeof value !== 'string' || value.trim() === '')
|
|
18
|
-
throw new Error(`agent metadata ${key} must be a non-empty string`);
|
|
19
|
-
return value.trim();
|
|
20
|
-
}
|
|
21
|
-
/** Strict YAML parsing prevents malformed routing metadata from silently inheriting wider privileges. */
|
|
22
|
-
export function parseAgentRole(text) {
|
|
23
|
-
const match = /^(?:\uFEFF)?---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/.exec(text);
|
|
24
|
-
if (match === null) {
|
|
25
|
-
if (/^(?:\uFEFF)?---(?:\r?\n|$)/.test(text))
|
|
26
|
-
throw new Error('agent frontmatter is not closed');
|
|
27
|
-
return { content: text, disabled: false };
|
|
28
|
-
}
|
|
29
|
-
// A matched block always carries its body; the check keeps the type honest.
|
|
30
|
-
const frontmatter = match[1];
|
|
31
|
-
if (frontmatter === undefined)
|
|
32
|
-
throw new Error('agent frontmatter is not closed');
|
|
33
|
-
const parsed = parseYaml(frontmatter);
|
|
34
|
-
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
35
|
-
throw new Error('agent frontmatter must be a YAML object');
|
|
36
|
-
const metadata = parsed;
|
|
37
|
-
if (metadata.disabled !== undefined && typeof metadata.disabled !== 'boolean')
|
|
38
|
-
throw new Error('agent metadata disabled must be a boolean');
|
|
39
|
-
const model = optionalText(metadata.model, 'model');
|
|
40
|
-
const provider = optionalText(metadata.provider, 'provider');
|
|
41
|
-
const effort = optionalText(metadata.reasoning_effort, 'reasoning_effort');
|
|
42
|
-
const camelEffort = optionalText(metadata.reasoningEffort, 'reasoningEffort');
|
|
43
|
-
if (effort !== undefined && camelEffort !== undefined && effort !== camelEffort)
|
|
44
|
-
throw new Error('agent metadata reasoning_effort and reasoningEffort conflict');
|
|
45
|
-
const reasoningEffort = effort ?? camelEffort;
|
|
46
|
-
const title = optionalText(metadata.name, 'name');
|
|
47
|
-
const description = optionalText(metadata.description, 'description');
|
|
48
|
-
if (model === 'inherit' && provider !== undefined)
|
|
49
|
-
throw new Error('agent model inherit cannot specify a provider');
|
|
50
|
-
return {
|
|
51
|
-
content: text.slice(match[0].length),
|
|
52
|
-
disabled: metadata.disabled === true,
|
|
53
|
-
...(model === undefined || model === 'inherit' ? {} : { model }),
|
|
54
|
-
...(provider === undefined ? {} : { provider }),
|
|
55
|
-
...(reasoningEffort === undefined ? {} : { reasoningEffort }),
|
|
56
|
-
...(title === undefined ? {} : { title }),
|
|
57
|
-
...(description === undefined ? {} : { description })
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
15
|
function parentRouteOf(parent) {
|
|
61
16
|
const agent = parent;
|
|
62
17
|
return agent?.session?.requestHeader?.()?.config ?? agent?.options ?? {};
|
|
@@ -287,11 +242,10 @@ export function mountAgentRoleTool(ctx, listRoles) {
|
|
|
287
242
|
const host = ctx;
|
|
288
243
|
const tool = defineTool({
|
|
289
244
|
name: AGENT_ROLE_TOOL_NAME,
|
|
290
|
-
description: "Delegate a task to a role child
|
|
291
|
-
'the background by default
|
|
292
|
-
'
|
|
293
|
-
|
|
294
|
-
"assertions against the files and relay the result to the user; the child's output is not visible to them. The current catalog lists the available roles and states the usage guidance; when no listed " +
|
|
245
|
+
description: "Delegate a task to a named role child from the session's role catalog: the role's own instructions and its configured model apply, and the child starts without this conversation. Use it proactively for self-contained work — codebase exploration whose raw reads would fill this context, a scoped implementation, a review, or an analysis you can brief in one prompt — and start independent children together in one message. The child runs in " +
|
|
246
|
+
'the background by default and returns a durable subagent id at once, keeping the child available for later turns; when the run settles, the runtime sends the parent a notice carrying its outcome and ' +
|
|
247
|
+
'final reply. A child usually runs for minutes, so continue with independent work instead of waiting. `prompt` must stand alone, since the child cannot see this conversation and a question it asks while it runs goes unanswered. When the notice arrives, verify its ' +
|
|
248
|
+
"assertions against the files and relay the result to the user; the child's output is not visible to them. The current catalog lists the available roles and the full usage guidance; when no listed " +
|
|
295
249
|
"role matches, use the host's own `subagent` tools instead.",
|
|
296
250
|
parameters: {
|
|
297
251
|
agent: { type: 'string', required: true, description: 'Exact callable role name from the current subagent catalog.' },
|