@ifrankwang/openspec-agents 0.149.1 → 0.150.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.
- package/.dsh-plugin/opx-tools.mjs +49 -1
- package/.mcp-server/cli.mjs +73 -19
- package/README.md +2 -0
- package/assets/skills/orchestrator/SKILL.md +9 -1
- package/dsh/cordis.patch.yml +317 -224
- package/package.json +1 -1
- package/src/adapters/deepseek-harness/index.ts +150 -33
- package/src/adapters/deepseek-harness/native-tools.ts +3 -3
- package/src/adapters/deepseek-harness/plugin.ts +81 -1
- package/src/types/dsh-runtime.d.ts +20 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifrankwang/openspec-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.150.1",
|
|
4
4
|
"description": "OpenSpec companion plugin for AI coding agents (Claude Code, Codex, ZCode, DeepSeek Harness, OpenCode): a stricter proposal standard plus multi-agent implementation and review, gated to production-grade standards",
|
|
5
5
|
"author": "ifrankwang",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
* - 本包自有的 `openspec-opx-tools` cordis 插件:6 个 opx_* 编排工具注册为 DSH 原生工具,
|
|
11
11
|
* 每次调用从 `exec.agent.session.header.cwd` 取会话项目目录。多项目共用同一插件进程时
|
|
12
12
|
* 各自作用于各自项目(MCP 形态因 worktree 固定在进程启动参数上而做不到,见 patch 注释)。
|
|
13
|
-
* - DSH 官方能力:`@deepseek-ai/dsh-skill-filesystem`(skill
|
|
14
|
-
*
|
|
15
|
-
* `@deepseek-ai/dsh-
|
|
13
|
+
* - DSH 官方能力:`@deepseek-ai/dsh-skill-filesystem`(skill 根)、子代理委派。
|
|
14
|
+
* 子代理的角色提示词与工具集由 `@deepseek-ai/dsh-agent-preset` 声明承载,每个物理子代理
|
|
15
|
+
* 一行 preset + 一行 `@deepseek-ai/dsh-tool-subagent`(以 `agentPreset` 引用前者)——
|
|
16
|
+
* DSH 0.2.1 起 `dsh-tool-subagent` 移除了 `persona` / `toolFilter` / 后台模式配置,
|
|
17
|
+
* 角色与工具组合改由 preset 表达。opx_* 工具不再经 `@deepseek-ai/dsh-mcp-client` 桥接——
|
|
18
|
+
* 原生插件已直接注册工具,patch 内不挂 MCP client。
|
|
16
19
|
*/
|
|
17
20
|
import { writeFileSync, mkdirSync, rmSync, readFileSync, readdirSync } from "node:fs"
|
|
18
21
|
import { join } from "node:path"
|
|
@@ -65,7 +68,14 @@ export const DSH_NATIVE_TOOLS_ROW_ID = "openspec-opx-tools"
|
|
|
65
68
|
*/
|
|
66
69
|
export const DSH_SKILLS_DIR_SEGMENTS = ["assets", "skills"] as const
|
|
67
70
|
|
|
68
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* 原生工具插件与 skill 根的基础 patch。
|
|
73
|
+
*
|
|
74
|
+
* 子代理委派工具**不写成静态 patch 行**:DSH 加载器对同一层的条目并行激活,静态工具行会在
|
|
75
|
+
* preset 声明行注册完成之前校验 `agentPreset`,报 `Unknown agent preset`。改为把
|
|
76
|
+
* toolName ↔ preset id 清单放进插件配置,由插件在 preset 就绪后动态挂载委派工具
|
|
77
|
+
* (见 plugin.ts 的 mountSubagentTools),顺序由代码保证。
|
|
78
|
+
*/
|
|
69
79
|
const DSH_BASE_PATCH_YAML = `# DeepSeek Harness (DSH) bundle patch: expose OpenSpec orchestration tools and skills.
|
|
70
80
|
# The patch is applied as a bundle layer under dsh.profile.bundles.
|
|
71
81
|
# baseUrl 指向 profile 根目录;bundle 安装后位于 profile 的 node_modules 下,
|
|
@@ -95,6 +105,25 @@ interface DshSubagentEntry {
|
|
|
95
105
|
config: Record<string, unknown>
|
|
96
106
|
}
|
|
97
107
|
|
|
108
|
+
/**
|
|
109
|
+
* YAML `!!js` 表达式节点。
|
|
110
|
+
*
|
|
111
|
+
* DSH 的 entry-list 方言把 `!!js <expr>` 解析为延迟求值的表达式(官方 preset 用它做平台分支)。
|
|
112
|
+
* js-yaml 默认 schema 不认识该标签,故以自定义 Type 承载:dump 时输出 `!!js <expr>` 原文。
|
|
113
|
+
*/
|
|
114
|
+
class DshJsExpression {
|
|
115
|
+
constructor(readonly expr: string) {}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** 带 `!!js` 标签的 YAML schema(仅 DSH patch 生成使用)。 */
|
|
119
|
+
const DSH_YAML_SCHEMA = yaml.DEFAULT_SCHEMA.extend([
|
|
120
|
+
new yaml.Type("tag:yaml.org,2002:js", {
|
|
121
|
+
kind: "scalar",
|
|
122
|
+
instanceOf: DshJsExpression,
|
|
123
|
+
represent: (value: unknown) => (value as DshJsExpression).expr,
|
|
124
|
+
}),
|
|
125
|
+
])
|
|
126
|
+
|
|
98
127
|
/** 将 openspec-architect 转换为 openspec_architect 这类 DSH 工具名后缀。 */
|
|
99
128
|
function dshAgentSuffix(name: string): string {
|
|
100
129
|
return name.replace(/^openspec-/, "").replace(/-/g, "_")
|
|
@@ -120,19 +149,88 @@ const DSH_SUBAGENT_TOOL_ACCESS_PREAMBLE = `## DSH 工具接入(必读)
|
|
|
120
149
|
- \`opx_status\`
|
|
121
150
|
- \`opx_agent_submit\`
|
|
122
151
|
- 调用工具时必须携带 \`_agent\` 参数传自身角色名(如 \`openspec-developer\`),否则身份无法判定、会被按编排主代理视角处理。
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
{"toolNames": ["opx_status", "opx_agent_submit"]}
|
|
126
|
-
\`\`\`
|
|
127
|
-
如果计划使用 \`todo_write\` 跟踪任务,也请在同一轮一并解锁。
|
|
128
|
-
- 严禁使用 \`find\` / \`which\` / \`grep\` 等 shell 命令搜索 \`opx\`、\`openspec\`、MCP 配置或安装路径;工具未出现是因为尚未解锁,不是未安装。
|
|
129
|
-
- 解锁后第一件事是调用 \`opx_status\` 获取上下文,不要先探查仓库或读取状态文件。
|
|
152
|
+
- 若工具列表中没有这些工具,不要用 shell 搜索 \`opx\`、\`openspec\`、MCP 配置或安装路径——它们不是被隐藏,而是插件未加载成功,直接向编排者报告。
|
|
153
|
+
- 开始工作前第一件事是调用 \`opx_status\` 获取上下文,不要先探查仓库或读取状态文件。
|
|
130
154
|
`
|
|
131
155
|
|
|
132
|
-
/**
|
|
133
|
-
|
|
156
|
+
/**
|
|
157
|
+
* 每个子代理的 Agent Preset 组合(DSH 0.2.1 起子代理的角色提示词与工具集由 preset 声明,
|
|
158
|
+
* `@deepseek-ai/dsh-tool-subagent` 的 `persona` / `toolFilter` 已移除)。
|
|
159
|
+
*
|
|
160
|
+
* 该组合是子代理可见的完整工具面:opx_* 原生工具由本包在宿主层全局注册,无需在此重复挂载。
|
|
161
|
+
*/
|
|
162
|
+
function dshSubagentPresetPlugins(editAllowed: boolean): Record<string, unknown>[] {
|
|
163
|
+
return [
|
|
164
|
+
{
|
|
165
|
+
id: "agent-instructions",
|
|
166
|
+
name: "@deepseek-ai/dsh-agent-instructions",
|
|
167
|
+
config: { maxBytes: 65536 },
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: "tool-fs",
|
|
171
|
+
name: "@deepseek-ai/dsh-tool-fs",
|
|
172
|
+
...(editAllowed ? {} : { config: { write: false, edit: false } }),
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "tool-fs-search",
|
|
176
|
+
name: "@deepseek-ai/dsh-tool-fs-search",
|
|
177
|
+
config: { sampleOverCapGlobResults: false },
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "tool-bash",
|
|
181
|
+
name: "@deepseek-ai/dsh-tool-bash",
|
|
182
|
+
disabled: new DshJsExpression("process.platform === 'win32'"),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "tool-pwsh",
|
|
186
|
+
name: "@deepseek-ai/dsh-tool-pwsh",
|
|
187
|
+
disabled: new DshJsExpression("process.platform !== 'win32'"),
|
|
188
|
+
},
|
|
189
|
+
{ id: "skill-filesystem", name: "@deepseek-ai/dsh-skill-filesystem" },
|
|
190
|
+
{ id: "tool-skill", name: "@deepseek-ai/dsh-tool-skill" },
|
|
191
|
+
{
|
|
192
|
+
id: "tool-todo",
|
|
193
|
+
name: "@deepseek-ai/dsh-tool-todo",
|
|
194
|
+
config: { allowParallelInProgress: true },
|
|
195
|
+
},
|
|
196
|
+
{ id: "tool-ask-user", name: "@deepseek-ai/dsh-tool-ask-user" },
|
|
197
|
+
{ id: "tool-web", name: "@deepseek-ai/dsh-tool-web", config: { fetch: true, searchTimeoutMs: 60000 } },
|
|
198
|
+
{
|
|
199
|
+
id: "compaction",
|
|
200
|
+
name: "cordis:group",
|
|
201
|
+
group: true,
|
|
202
|
+
isolate: { compaction: true, toolResultPruner: true },
|
|
203
|
+
config: [
|
|
204
|
+
{ id: "compaction-basic", name: "@deepseek-ai/dsh-compaction-basic" },
|
|
205
|
+
{
|
|
206
|
+
id: "tool-result-pruner",
|
|
207
|
+
name: "@deepseek-ai/dsh-compaction-tool-result-pruner",
|
|
208
|
+
config: { thresholdChars: 8192, headChars: 4096, tailChars: 1024 },
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
},
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** 子代理委派规格:工具名 + 引用的 preset id(写入插件配置,供动态挂载使用)。 */
|
|
216
|
+
export interface DshSubagentSpec {
|
|
217
|
+
toolName: string
|
|
218
|
+
agentPreset: string
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** 解析一个子代理的 preset 声明与委派规格。 */
|
|
222
|
+
interface DshSubagentDefinition {
|
|
223
|
+
spec: DshSubagentSpec
|
|
224
|
+
presetEntry: DshSubagentEntry
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 从 assets/agents/*.md 收集 DSH 子代理:每个物理子代理生成一个 Agent Preset 声明行,
|
|
229
|
+
* 以及一份「工具名 + preset id」规格(交给插件动态挂载委派工具)。
|
|
230
|
+
*/
|
|
231
|
+
function collectDshSubagents(): DshSubagentDefinition[] {
|
|
134
232
|
const agentsRoot = resolve("assets", "agents")
|
|
135
|
-
const
|
|
233
|
+
const definitions: DshSubagentDefinition[] = []
|
|
136
234
|
for (const file of readdirSync(agentsRoot)) {
|
|
137
235
|
if (!file.endsWith(".md")) continue
|
|
138
236
|
if (EXCLUDED_AGENTS.has(file)) continue
|
|
@@ -142,34 +240,53 @@ function collectDshSubagentEntries(): DshSubagentEntry[] {
|
|
|
142
240
|
const description = (frontmatter.description as string) ?? ""
|
|
143
241
|
const persona = [DSH_SUBAGENT_TOOL_ACCESS_PREAMBLE, description, body.trim()].filter(Boolean).join("\n\n")
|
|
144
242
|
const suffix = dshAgentSuffix(name)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
243
|
+
const presetId = `openspec-${suffix.replace(/_/g, "-")}`
|
|
244
|
+
definitions.push({
|
|
245
|
+
spec: { toolName: `openspec_${suffix}`, agentPreset: presetId },
|
|
246
|
+
presetEntry: {
|
|
247
|
+
id: `openspec-preset-${suffix}`,
|
|
248
|
+
name: "@deepseek-ai/dsh-agent-preset",
|
|
249
|
+
config: {
|
|
250
|
+
id: presetId,
|
|
251
|
+
name,
|
|
252
|
+
description,
|
|
253
|
+
plugins: [
|
|
254
|
+
{ id: "persona", name: "@deepseek-ai/dsh-persona", config: { prefix: persona } },
|
|
255
|
+
...dshSubagentPresetPlugins(!denyEditTools(frontmatter)),
|
|
256
|
+
],
|
|
257
|
+
},
|
|
157
258
|
},
|
|
158
259
|
})
|
|
159
260
|
}
|
|
160
|
-
return
|
|
261
|
+
return definitions
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** 把子代理规格投影为插件配置里的 `subagents` 块(缩进对齐 openspec-opx-tools 行的 config)。 */
|
|
265
|
+
function subagentsConfigYaml(specs: DshSubagentSpec[]): string {
|
|
266
|
+
if (specs.length === 0) return " subagents: []"
|
|
267
|
+
const dumped = yaml.dump(specs, { lineWidth: -1 }).trimEnd().split("\n")
|
|
268
|
+
return [" subagents:", ...dumped.map((line) => ` ${line}`)].join("\n")
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** 基础 patch:原生工具插件行带上子代理委派规格,供插件在 preset 就绪后动态挂载。 */
|
|
272
|
+
function buildBasePatchYaml(specs: DshSubagentSpec[]): string {
|
|
273
|
+
return DSH_BASE_PATCH_YAML.replace(
|
|
274
|
+
" unattended: true",
|
|
275
|
+
` unattended: true\n${subagentsConfigYaml(specs)}`,
|
|
276
|
+
)
|
|
161
277
|
}
|
|
162
278
|
|
|
163
|
-
/** 生成完整的 DSH cordis patch 内容:基础原生工具插件行 + skill 根 +
|
|
279
|
+
/** 生成完整的 DSH cordis patch 内容:基础原生工具插件行 + skill 根 + 每个子代理的 preset 声明。 */
|
|
164
280
|
export function buildDshPatchContent(): string {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
281
|
+
const definitions = collectDshSubagents()
|
|
282
|
+
const base = buildBasePatchYaml(definitions.map((definition) => definition.spec))
|
|
283
|
+
if (definitions.length === 0) return base
|
|
284
|
+
const presetsYaml = yaml
|
|
285
|
+
.dump(definitions.map((definition) => definition.presetEntry), { schema: DSH_YAML_SCHEMA, lineWidth: -1 })
|
|
169
286
|
.split("\n")
|
|
170
287
|
.map((line) => (line ? ` ${line}` : line))
|
|
171
288
|
.join("\n")
|
|
172
|
-
return `${
|
|
289
|
+
return `${base.trimEnd()}\n${presetsYaml}\n`
|
|
173
290
|
}
|
|
174
291
|
|
|
175
292
|
export type DeepSeekHarnessPluginBuildResult = PluginPackageResult
|
|
@@ -23,9 +23,9 @@ import { jsonSchemaToToolParameters, type ToolParameters } from "./schema-dsl.ts
|
|
|
23
23
|
import { OPX_TOOL_SPECS, OPX_TOOL_NAMES } from "../tool-specs.ts"
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* DSH 工具执行上下文(本插件只消费三处,均已在 DSH 0.2.
|
|
27
|
-
* - agent.session.header.cwd
|
|
28
|
-
*
|
|
26
|
+
* DSH 工具执行上下文(本插件只消费三处,均已在 DSH 0.2.1-rc.2 源码中核实):
|
|
27
|
+
* - agent.session.header.cwd:本次会话的项目目录(会话目录,非进程启动目录)。DSH 0.2.1 起官方
|
|
28
|
+
* 文件工具改用 `ctx.workingDirectory`(会话内可 cd),编排状态按项目根落盘,故仍取 header.cwd。
|
|
29
29
|
* - agent.id:与 agent.session.id 同值(dsh-agent/lib/index.js:510 的 enter() 校验)。
|
|
30
30
|
* - signal:协作式取消信号。
|
|
31
31
|
* 结构用 ambient 声明(src/types/dsh-runtime.d.ts)而非本地手写,避免与官方形状漂移。
|
|
@@ -25,6 +25,19 @@ import { buildNativeToolDefinitions, type DshToolExec } from "./native-tools.ts"
|
|
|
25
25
|
const Config = z.object({
|
|
26
26
|
/** 默认无人值守:会话已初始化且未显式设置时自动开启。默认 true,与 MCP 侧 --unattended 同口径。 */
|
|
27
27
|
unattended: z.boolean().default(true),
|
|
28
|
+
/**
|
|
29
|
+
* 子代理委派规格(工具名 + 引用的 preset id),由构建期写入 patch。
|
|
30
|
+
* 委派工具不写成静态 patch 行:DSH 加载器并行激活同层条目,静态工具行会在 preset 注册前
|
|
31
|
+
* 校验 `agentPreset` 报 Unknown agent preset;改由插件在 preset 就绪后动态挂载。
|
|
32
|
+
*/
|
|
33
|
+
subagents: z
|
|
34
|
+
.array(
|
|
35
|
+
z.object({
|
|
36
|
+
toolName: z.string(),
|
|
37
|
+
agentPreset: z.string(),
|
|
38
|
+
}),
|
|
39
|
+
)
|
|
40
|
+
.default([]),
|
|
28
41
|
})
|
|
29
42
|
|
|
30
43
|
/** cordis 插件名。 */
|
|
@@ -39,7 +52,10 @@ const inject = ["tools"]
|
|
|
39
52
|
* worktree 每次调用从 `exec.agent.session.header.cwd` 取会话项目目录(该字段缺失即报错,不静默回落进程 cwd);
|
|
40
53
|
* `exec.signal` 在每次调用入口检查取消;调用者身份由 `_agent` 入参声明(缺省=编排主代理视角)。
|
|
41
54
|
*/
|
|
42
|
-
function apply(
|
|
55
|
+
function apply(
|
|
56
|
+
ctx: any,
|
|
57
|
+
config: { unattended?: boolean; subagents?: Array<{ toolName: string; agentPreset: string }> } = {},
|
|
58
|
+
): void {
|
|
43
59
|
const unattended = config.unattended !== false
|
|
44
60
|
// 进程 cwd 仅用于「无 agent 上下文的非 agent 调用」兜底;agent 调用缺会话目录时工具直接报错。
|
|
45
61
|
const processCwd = process.cwd()
|
|
@@ -56,6 +72,70 @@ function apply(ctx: any, config: { unattended?: boolean } = {}): void {
|
|
|
56
72
|
}),
|
|
57
73
|
)
|
|
58
74
|
}
|
|
75
|
+
mountSubagentTools(ctx, config.subagents ?? [])
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** 子代理委派工具所属的官方包(保持 external,由 DSH 安装目录在运行时解析)。 */
|
|
79
|
+
const SUBAGENT_TOOL_PACKAGE = "@deepseek-ai/dsh-tool-subagent"
|
|
80
|
+
|
|
81
|
+
/** 等待 preset 声明注册完成的上限:注册在启动阶段完成,正常在毫秒级。 */
|
|
82
|
+
const PRESET_READY_TIMEOUT_MS = 3000
|
|
83
|
+
const PRESET_READY_POLL_MS = 50
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 轮询等待 preset 声明注册完成。
|
|
87
|
+
*
|
|
88
|
+
* `agentPresets.readDocument(id)` 直接读内存声明表:返回成功即表示 preset 行已激活,
|
|
89
|
+
* 此时再挂载委派工具,工具行的加载期校验必然通过。
|
|
90
|
+
*/
|
|
91
|
+
async function waitForPreset(registry: any, presetId: string, timeoutMs = PRESET_READY_TIMEOUT_MS): Promise<boolean> {
|
|
92
|
+
const deadline = Date.now() + timeoutMs
|
|
93
|
+
while (Date.now() < deadline) {
|
|
94
|
+
try {
|
|
95
|
+
await registry.readDocument(presetId)
|
|
96
|
+
return true
|
|
97
|
+
} catch {
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, PRESET_READY_POLL_MS))
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 在 preset 就绪后动态挂载子代理委派工具。
|
|
106
|
+
*
|
|
107
|
+
* 与静态 patch 行的差异只有挂载时机:本函数先等 `agentPresets` 服务可用、再逐个确认 preset
|
|
108
|
+
* 已注册,最后才挂 `@deepseek-ai/dsh-tool-subagent` 实例——消除「工具行先于 preset 行激活」
|
|
109
|
+
* 的加载竞态(DSH 对同层条目并行激活,desktop 多插件下稳定触发)。
|
|
110
|
+
*/
|
|
111
|
+
function mountSubagentTools(ctx: any, specs: Array<{ toolName: string; agentPreset: string }>): void {
|
|
112
|
+
if (specs.length === 0 || typeof ctx.inject !== "function") return
|
|
113
|
+
ctx.inject(["agentPresets"], async (injected: any) => {
|
|
114
|
+
let subagentTool: any
|
|
115
|
+
try {
|
|
116
|
+
subagentTool = await import(SUBAGENT_TOOL_PACKAGE)
|
|
117
|
+
} catch (error) {
|
|
118
|
+
injected.logger?.warn?.(`openspec: 无法加载 ${SUBAGENT_TOOL_PACKAGE},子代理委派工具未挂载:${String(error)}`)
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
for (const spec of specs) {
|
|
122
|
+
if (!(await waitForPreset(injected.agentPresets, spec.agentPreset))) {
|
|
123
|
+
injected.logger?.warn?.(
|
|
124
|
+
`openspec: agent preset "${spec.agentPreset}" 未在 ${PRESET_READY_TIMEOUT_MS}ms 内注册,跳过子代理工具 ${spec.toolName}`,
|
|
125
|
+
)
|
|
126
|
+
continue
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
await injected.plugin(subagentTool, {
|
|
130
|
+
provider: "spawn",
|
|
131
|
+
toolName: spec.toolName,
|
|
132
|
+
agentPreset: spec.agentPreset,
|
|
133
|
+
})
|
|
134
|
+
} catch (error) {
|
|
135
|
+
injected.logger?.warn?.(`openspec: 子代理工具 ${spec.toolName} 挂载失败:${String(error)}`)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
})
|
|
59
139
|
}
|
|
60
140
|
|
|
61
141
|
export { Config, apply, inject, name }
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 本文件不写任何顶层 export/import(保持为全局脚本文件),否则其中的 `declare module`
|
|
11
11
|
* 会被 TypeScript 当作模块增强而非 ambient 声明。
|
|
12
12
|
*
|
|
13
|
-
* 形状依据(DSH 0.2.
|
|
13
|
+
* 形状依据(DSH 0.2.1-rc.2 源码):
|
|
14
14
|
* - defineTool 与 schema DSL:dsh-tools/lib/types/schema.js:274
|
|
15
15
|
* - ctx.tools.register:dsh-tools/README.zh.md:41-57
|
|
16
16
|
* - exec 上下文字段:dsh-tools/lib/types/index.js:790-802(token/callId/rootCallId/name/signal/
|
|
@@ -154,9 +154,27 @@ declare module "@deepseek-ai/dsh-tools" {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
declare module "@deepseek-ai/cordis" {
|
|
157
|
-
/**
|
|
157
|
+
/** 本项目插件用到的 cordis 能力:工具注册表、依赖注入与子插件挂载;其余服务不消费。 */
|
|
158
158
|
export interface Context {
|
|
159
159
|
tools: import("@deepseek-ai/dsh-tools").ToolRegistry
|
|
160
|
+
/**
|
|
161
|
+
* 依赖就绪后执行回调。本插件用它等 `agentPresets` 服务可用,再动态挂载子代理委派工具
|
|
162
|
+
* (DSH 对同层 patch 条目并行激活,静态工具行会先于 preset 声明校验而失败)。
|
|
163
|
+
*/
|
|
164
|
+
inject(deps: readonly string[], callback: (ctx: Context) => unknown): unknown
|
|
165
|
+
/** 挂载子插件。本插件用它挂载官方 `@deepseek-ai/dsh-tool-subagent` 实例。 */
|
|
166
|
+
plugin(plugin: unknown, config?: unknown): unknown
|
|
160
167
|
[key: string]: any
|
|
161
168
|
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
declare module "@deepseek-ai/dsh-tool-subagent" {
|
|
172
|
+
/**
|
|
173
|
+
* 官方子代理委派工具插件(cordis 插件形态:命名导出 name/inject/Config/apply)。
|
|
174
|
+
* 本插件在 preset 就绪后动态挂载它,故只需声明挂载所需的公开形状。
|
|
175
|
+
*/
|
|
176
|
+
export const name: string
|
|
177
|
+
export const inject: readonly string[]
|
|
178
|
+
export const Config: unknown
|
|
179
|
+
export function apply(ctx: unknown, config?: unknown): void
|
|
162
180
|
}
|