@ifrankwang/openspec-agents 0.149.0 → 0.150.0
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/.mcp-server/cli.mjs +73 -19
- package/README.md +92 -59
- package/assets/skills/orchestrator/SKILL.md +9 -1
- package/dsh/cordis.patch.yml +320 -220
- package/package.json +2 -2
- package/src/adapters/codex/index.ts +2 -2
- package/src/adapters/deepseek-harness/index.ts +118 -26
- package/src/adapters/deepseek-harness/native-tools.ts +3 -3
- package/src/adapters/plugin-common/index.ts +1 -1
- package/src/types/dsh-runtime.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifrankwang/openspec-agents",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "OpenSpec
|
|
3
|
+
"version": "0.150.0",
|
|
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",
|
|
7
7
|
"homepage": "https://github.com/ifrankwang/openspec-agents#readme",
|
|
@@ -118,12 +118,12 @@ export function buildCodexPlugin(outDir: string = CODEX_PLUGIN_DIR): PluginPacka
|
|
|
118
118
|
mcpServers: "./.mcp.json",
|
|
119
119
|
interface: {
|
|
120
120
|
displayName: "OpenSpec Agents",
|
|
121
|
-
shortDescription: "OpenSpec
|
|
121
|
+
shortDescription: "Production-grade OpenSpec proposals, implementation and review for Codex",
|
|
122
122
|
longDescription: PLUGIN_DESCRIPTION,
|
|
123
123
|
developerName: "ifrankwang",
|
|
124
124
|
category: "Developer Tools",
|
|
125
125
|
capabilities: ["Read", "Write"],
|
|
126
|
-
defaultPrompt: ["Run the OpenSpec
|
|
126
|
+
defaultPrompt: ["Run the OpenSpec proposal, implementation and review workflow."],
|
|
127
127
|
},
|
|
128
128
|
},
|
|
129
129
|
null,
|
|
@@ -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"
|
|
@@ -95,6 +98,25 @@ interface DshSubagentEntry {
|
|
|
95
98
|
config: Record<string, unknown>
|
|
96
99
|
}
|
|
97
100
|
|
|
101
|
+
/**
|
|
102
|
+
* YAML `!!js` 表达式节点。
|
|
103
|
+
*
|
|
104
|
+
* DSH 的 entry-list 方言把 `!!js <expr>` 解析为延迟求值的表达式(官方 preset 用它做平台分支)。
|
|
105
|
+
* js-yaml 默认 schema 不认识该标签,故以自定义 Type 承载:dump 时输出 `!!js <expr>` 原文。
|
|
106
|
+
*/
|
|
107
|
+
class DshJsExpression {
|
|
108
|
+
constructor(readonly expr: string) {}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** 带 `!!js` 标签的 YAML schema(仅 DSH patch 生成使用)。 */
|
|
112
|
+
const DSH_YAML_SCHEMA = yaml.DEFAULT_SCHEMA.extend([
|
|
113
|
+
new yaml.Type("tag:yaml.org,2002:js", {
|
|
114
|
+
kind: "scalar",
|
|
115
|
+
instanceOf: DshJsExpression,
|
|
116
|
+
represent: (value: unknown) => (value as DshJsExpression).expr,
|
|
117
|
+
}),
|
|
118
|
+
])
|
|
119
|
+
|
|
98
120
|
/** 将 openspec-architect 转换为 openspec_architect 这类 DSH 工具名后缀。 */
|
|
99
121
|
function dshAgentSuffix(name: string): string {
|
|
100
122
|
return name.replace(/^openspec-/, "").replace(/-/g, "_")
|
|
@@ -120,16 +142,75 @@ const DSH_SUBAGENT_TOOL_ACCESS_PREAMBLE = `## DSH 工具接入(必读)
|
|
|
120
142
|
- \`opx_status\`
|
|
121
143
|
- \`opx_agent_submit\`
|
|
122
144
|
- 调用工具时必须携带 \`_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\` 获取上下文,不要先探查仓库或读取状态文件。
|
|
145
|
+
- 若工具列表中没有这些工具,不要用 shell 搜索 \`opx\`、\`openspec\`、MCP 配置或安装路径——它们不是被隐藏,而是插件未加载成功,直接向编排者报告。
|
|
146
|
+
- 开始工作前第一件事是调用 \`opx_status\` 获取上下文,不要先探查仓库或读取状态文件。
|
|
130
147
|
`
|
|
131
148
|
|
|
132
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* 每个子代理的 Agent Preset 组合(DSH 0.2.1 起子代理的角色提示词与工具集由 preset 声明,
|
|
151
|
+
* `@deepseek-ai/dsh-tool-subagent` 的 `persona` / `toolFilter` 已移除)。
|
|
152
|
+
*
|
|
153
|
+
* 该组合是子代理可见的完整工具面:opx_* 原生工具由本包在宿主层全局注册,无需在此重复挂载。
|
|
154
|
+
*/
|
|
155
|
+
function dshSubagentPresetPlugins(editAllowed: boolean): Record<string, unknown>[] {
|
|
156
|
+
return [
|
|
157
|
+
{
|
|
158
|
+
id: "agent-instructions",
|
|
159
|
+
name: "@deepseek-ai/dsh-agent-instructions",
|
|
160
|
+
config: { maxBytes: 65536 },
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "tool-fs",
|
|
164
|
+
name: "@deepseek-ai/dsh-tool-fs",
|
|
165
|
+
...(editAllowed ? {} : { config: { write: false, edit: false } }),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "tool-fs-search",
|
|
169
|
+
name: "@deepseek-ai/dsh-tool-fs-search",
|
|
170
|
+
config: { sampleOverCapGlobResults: false },
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "tool-bash",
|
|
174
|
+
name: "@deepseek-ai/dsh-tool-bash",
|
|
175
|
+
disabled: new DshJsExpression("process.platform === 'win32'"),
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "tool-pwsh",
|
|
179
|
+
name: "@deepseek-ai/dsh-tool-pwsh",
|
|
180
|
+
disabled: new DshJsExpression("process.platform !== 'win32'"),
|
|
181
|
+
},
|
|
182
|
+
{ id: "skill-filesystem", name: "@deepseek-ai/dsh-skill-filesystem" },
|
|
183
|
+
{ id: "tool-skill", name: "@deepseek-ai/dsh-tool-skill" },
|
|
184
|
+
{
|
|
185
|
+
id: "tool-todo",
|
|
186
|
+
name: "@deepseek-ai/dsh-tool-todo",
|
|
187
|
+
config: { allowParallelInProgress: true },
|
|
188
|
+
},
|
|
189
|
+
{ id: "tool-ask-user", name: "@deepseek-ai/dsh-tool-ask-user" },
|
|
190
|
+
{ id: "tool-web", name: "@deepseek-ai/dsh-tool-web", config: { fetch: true, searchTimeoutMs: 60000 } },
|
|
191
|
+
{
|
|
192
|
+
id: "compaction",
|
|
193
|
+
name: "cordis:group",
|
|
194
|
+
group: true,
|
|
195
|
+
isolate: { compaction: true, toolResultPruner: true },
|
|
196
|
+
config: [
|
|
197
|
+
{ id: "compaction-basic", name: "@deepseek-ai/dsh-compaction-basic" },
|
|
198
|
+
{
|
|
199
|
+
id: "tool-result-pruner",
|
|
200
|
+
name: "@deepseek-ai/dsh-compaction-tool-result-pruner",
|
|
201
|
+
config: { thresholdChars: 8192, headChars: 4096, tailChars: 1024 },
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 从 assets/agents/*.md 收集 DSH 子代理:每个物理子代理生成一个 Agent Preset 声明行
|
|
210
|
+
* 与一个 `@deepseek-ai/dsh-tool-subagent` 工具行(后者以 `agentPreset` 引用前者)。
|
|
211
|
+
*
|
|
212
|
+
* preset 行必须排在工具行之前:工具行在加载时校验 `agentPreset` 是否已声明。
|
|
213
|
+
*/
|
|
133
214
|
function collectDshSubagentEntries(): DshSubagentEntry[] {
|
|
134
215
|
const agentsRoot = resolve("assets", "agents")
|
|
135
216
|
const entries: DshSubagentEntry[] = []
|
|
@@ -142,30 +223,41 @@ function collectDshSubagentEntries(): DshSubagentEntry[] {
|
|
|
142
223
|
const description = (frontmatter.description as string) ?? ""
|
|
143
224
|
const persona = [DSH_SUBAGENT_TOOL_ACCESS_PREAMBLE, description, body.trim()].filter(Boolean).join("\n\n")
|
|
144
225
|
const suffix = dshAgentSuffix(name)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
226
|
+
const presetId = `openspec-${suffix.replace(/_/g, "-")}`
|
|
227
|
+
entries.push(
|
|
228
|
+
{
|
|
229
|
+
id: `openspec-preset-${suffix}`,
|
|
230
|
+
name: "@deepseek-ai/dsh-agent-preset",
|
|
231
|
+
config: {
|
|
232
|
+
id: presetId,
|
|
233
|
+
name,
|
|
234
|
+
description,
|
|
235
|
+
plugins: [
|
|
236
|
+
{ id: "persona", name: "@deepseek-ai/dsh-persona", config: { prefix: persona } },
|
|
237
|
+
...dshSubagentPresetPlugins(!denyEditTools(frontmatter)),
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: `openspec-subagent-${suffix}`,
|
|
243
|
+
name: "@deepseek-ai/dsh-tool-subagent",
|
|
244
|
+
config: {
|
|
245
|
+
provider: "spawn",
|
|
246
|
+
toolName: `openspec_${suffix}`,
|
|
247
|
+
agentPreset: presetId,
|
|
248
|
+
},
|
|
157
249
|
},
|
|
158
|
-
|
|
250
|
+
)
|
|
159
251
|
}
|
|
160
252
|
return entries
|
|
161
253
|
}
|
|
162
254
|
|
|
163
|
-
/** 生成完整的 DSH cordis patch 内容:基础原生工具插件行 + skill 根 +
|
|
255
|
+
/** 生成完整的 DSH cordis patch 内容:基础原生工具插件行 + skill 根 + 每个子代理的 preset 与 subagent 工具。 */
|
|
164
256
|
export function buildDshPatchContent(): string {
|
|
165
257
|
const subagents = collectDshSubagentEntries()
|
|
166
258
|
if (subagents.length === 0) return DSH_BASE_PATCH_YAML
|
|
167
259
|
const subagentsYaml = yaml
|
|
168
|
-
.dump(subagents, { lineWidth: -1 })
|
|
260
|
+
.dump(subagents, { schema: DSH_YAML_SCHEMA, lineWidth: -1 })
|
|
169
261
|
.split("\n")
|
|
170
262
|
.map((line) => (line ? ` ${line}` : line))
|
|
171
263
|
.join("\n")
|
|
@@ -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)而非本地手写,避免与官方形状漂移。
|
|
@@ -18,7 +18,7 @@ import { parseAgentMd, resolve, EXCLUDED_AGENTS } from "../agent-md.ts"
|
|
|
18
18
|
|
|
19
19
|
export const PLUGIN_NAME = "openspec-agents"
|
|
20
20
|
export const PLUGIN_DESCRIPTION =
|
|
21
|
-
"OpenSpec
|
|
21
|
+
"OpenSpec companion plugin for AI coding agents: a stricter proposal standard plus multi-agent implementation and review, gated to production-grade standards."
|
|
22
22
|
/** plugin.json author(各插件包统一署名项目作者)。 */
|
|
23
23
|
export const PLUGIN_AUTHOR = "ifrankwang"
|
|
24
24
|
|
|
@@ -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/
|