@gong-ym/ai-spec-auto 0.2.17 → 0.2.19
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/.agents/orchestration/runtime-state-handoff-spec.md +93 -1
- package/.agents/orchestration/task-orchestrator-run-plan-template.md +83 -2
- package/.agents/roles/common/requirement-analyst.md +25 -0
- package/bin/protocol-workflow.js +6 -1
- package/bin/refresh-command.js +15 -42
- package/package.json +1 -1
|
@@ -237,7 +237,99 @@ frontend-implementer(前端实现专家)
|
|
|
237
237
|
- 追加一条 `run-cancelled` 事件
|
|
238
238
|
- 记录 `timestamps.finished_at`
|
|
239
239
|
|
|
240
|
-
## 7.
|
|
240
|
+
## 7. 上下文传递优化(Context Pass-through)
|
|
241
|
+
|
|
242
|
+
### 7.1 问题背景
|
|
243
|
+
|
|
244
|
+
当前每个专家都需要独立加载以下上下文:
|
|
245
|
+
|
|
246
|
+
- `context/PROJECT.md`
|
|
247
|
+
- `.agents/rules/` 下的项目规则
|
|
248
|
+
- `openspec/changes/<change-id>/` 下的变更文档
|
|
249
|
+
- 前序专家的分析产物
|
|
250
|
+
|
|
251
|
+
这导致:
|
|
252
|
+
|
|
253
|
+
- 重复读取相同文件
|
|
254
|
+
- 每个专家都要重新解析项目规则
|
|
255
|
+
- 上下文信息在多轮对话中逐渐稀释
|
|
256
|
+
|
|
257
|
+
### 7.2 上下文传递机制
|
|
258
|
+
|
|
259
|
+
当发生专家交接时,handoff payload 应携带 `context_payload`:
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"context_payload": {
|
|
264
|
+
"project_facts": {
|
|
265
|
+
"tech_stack": "Vue 3 + TypeScript + Vite",
|
|
266
|
+
"directory_structure": "src/views/, src/components/",
|
|
267
|
+
"api_pattern": "@/utils/request",
|
|
268
|
+
"style_pattern": "主题变量 + Tailwind"
|
|
269
|
+
},
|
|
270
|
+
"current_change": {
|
|
271
|
+
"change_id": "add-product-delete",
|
|
272
|
+
"proposal_path": "openspec/changes/add-product-delete/proposal.md",
|
|
273
|
+
"tasks_path": "openspec/changes/add-product-delete/tasks.md",
|
|
274
|
+
"specs_dir": "openspec/changes/add-product-delete/specs/"
|
|
275
|
+
},
|
|
276
|
+
"previous_analysis": {
|
|
277
|
+
"requirement_summary": "给商品卡片加删除按钮,点击后调用 DELETE API",
|
|
278
|
+
"key_decisions": ["沿用项目 Button 组件", "删除前弹确认框"],
|
|
279
|
+
"open_questions": []
|
|
280
|
+
},
|
|
281
|
+
"rules_snapshot": {
|
|
282
|
+
"loaded_rules": ["01-项目概述.md", "03-项目结构.md", "05-API规范.md", "09-样式规范.md"],
|
|
283
|
+
"key_constraints": ["API 必须使用 @/utils/request 封装", "样式必须使用主题变量"]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 7.3 下游专家行为
|
|
290
|
+
|
|
291
|
+
当收到 `context_payload` 时,下游专家应:
|
|
292
|
+
|
|
293
|
+
1. **优先使用传递的上下文**:不再重复读取已包含的文件
|
|
294
|
+
2. **按需补充读取**:只读取 `context_payload` 中未覆盖的规则
|
|
295
|
+
3. **继承前序分析**:直接引用 `previous_analysis` 中的结论,不重新分析
|
|
296
|
+
|
|
297
|
+
### 7.4 简单需求直接交接
|
|
298
|
+
|
|
299
|
+
当 `delivery_profile = micro` 且 `complexity = low` 时,允许:
|
|
300
|
+
|
|
301
|
+
- `requirement-analyst` 完成后直接产出 `frontend-implementer` 的执行载荷
|
|
302
|
+
- `task-orchestrator` 只做状态记录,不做额外干预
|
|
303
|
+
- 实现专家直接读取 `context_payload` 进入编码
|
|
304
|
+
|
|
305
|
+
## 8. 并行分析阶段(可选)
|
|
306
|
+
|
|
307
|
+
### 8.1 适用场景
|
|
308
|
+
|
|
309
|
+
当复杂需求同时触发多个可选专家时:
|
|
310
|
+
|
|
311
|
+
- `requirement-analyst` 完成基础分析
|
|
312
|
+
- `design-collaborator` 分析设计约束
|
|
313
|
+
- `api-contract-specialist` 分析接口契约
|
|
314
|
+
|
|
315
|
+
### 8.2 并行执行模式
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
requirement-analyst(完成基础分析)
|
|
319
|
+
↓
|
|
320
|
+
├─ design-collaborator(并行分析)
|
|
321
|
+
└─ api-contract-specialist(并行分析)
|
|
322
|
+
↓
|
|
323
|
+
frontend-implementer(合并分析结果后进入实现)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### 8.3 实现约束
|
|
327
|
+
|
|
328
|
+
- 并行专家必须基于同一份 `context_payload`
|
|
329
|
+
- 各专家产出独立文档,不互相依赖
|
|
330
|
+
- `task-orchestrator` 在所有并行专家完成后合并结果
|
|
331
|
+
|
|
332
|
+
## 9. 当前阶段边界
|
|
241
333
|
|
|
242
334
|
当前最小实现只解决:
|
|
243
335
|
|
|
@@ -211,7 +211,34 @@ description: 定义 task-orchestrator 在首次识别任务时必须输出的最
|
|
|
211
211
|
- 多状态联动、真实接口、复杂业务规则、核心模块改造
|
|
212
212
|
- 使用完整产物与完整门禁
|
|
213
213
|
|
|
214
|
-
### 5.6
|
|
214
|
+
### 5.6 简单需求快速通道
|
|
215
|
+
|
|
216
|
+
当 `delivery_profile = micro` 且 `complexity = low` 时,启用快速通道:
|
|
217
|
+
|
|
218
|
+
**简单需求判断标准**(满足全部):
|
|
219
|
+
- 单文件或 2-3 个文件的修改
|
|
220
|
+
- 任务明确(如"加个按钮"、"改个样式"、"加个校验")
|
|
221
|
+
- 不涉及新模块、新路由、新接口
|
|
222
|
+
- 无需设计稿或复杂交互
|
|
223
|
+
- 项目规则中已有明确实现模式
|
|
224
|
+
|
|
225
|
+
**快速通道行为**:
|
|
226
|
+
1. `requirement-analyst` 跳过 `design-analysis` 调用
|
|
227
|
+
2. `proposal.md` 使用极简版(目标、范围、假设,各 1-2 行)
|
|
228
|
+
3. `specs/` 使用极简版(只写变更点,不写完整场景)
|
|
229
|
+
4. `tasks.md` 使用极简版(3-5 条直接可执行任务)
|
|
230
|
+
5. 快速进入实现,不做详细澄清
|
|
231
|
+
|
|
232
|
+
**复杂需求**(命中任一):
|
|
233
|
+
- 涉及多个模块或系统级变更
|
|
234
|
+
- 需要新接口、新状态管理、新路由设计
|
|
235
|
+
- 有设计稿或复杂交互需求
|
|
236
|
+
- 存在技术选型或架构决策
|
|
237
|
+
- 规则不明确,需要大量澄清
|
|
238
|
+
|
|
239
|
+
复杂需求按完整流程执行,不做快速通道优化。
|
|
240
|
+
|
|
241
|
+
### 5.7 micro 的产物规格
|
|
215
242
|
|
|
216
243
|
当 `delivery_profile = micro` 时:
|
|
217
244
|
|
|
@@ -219,7 +246,8 @@ description: 定义 task-orchestrator 在首次识别任务时必须输出的最
|
|
|
219
246
|
- `tasks.md` 使用短版:3-5 条可执行任务
|
|
220
247
|
- `checklist.md` 使用短版:关键检查项、阻断项、是否建议通过
|
|
221
248
|
- `iterations.md` 使用短版:问题、修正动作、残留风险
|
|
222
|
-
-
|
|
249
|
+
- 对于简单需求(见 5.6),`requirement-analyst` 可采用快速通道行为
|
|
250
|
+
- 不允许因为 `micro` 而跳过 OpenSpec 落盘
|
|
223
251
|
|
|
224
252
|
### 5.7 page-development 任务的缺口分类
|
|
225
253
|
|
|
@@ -289,6 +317,59 @@ description: 定义 task-orchestrator 在首次识别任务时必须输出的最
|
|
|
289
317
|
- 先按默认假设进入 requirement-analyst(需求解析专家);若需求收敛阶段发现高风险冲突,再转 suggest 或 manual
|
|
290
318
|
```
|
|
291
319
|
|
|
320
|
+
### 简单需求示例(快速通道)
|
|
321
|
+
|
|
322
|
+
#### 输入
|
|
323
|
+
|
|
324
|
+
```text
|
|
325
|
+
@task-orchestrator(任务主代理) 给商品卡片加个删除按钮
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### 输出
|
|
329
|
+
|
|
330
|
+
```md
|
|
331
|
+
## 任务识别
|
|
332
|
+
- 类型:组件增强
|
|
333
|
+
- 当前输入:给商品卡片加个删除按钮
|
|
334
|
+
- 风险级别:low
|
|
335
|
+
- 复杂度:low(单文件修改,任务明确)
|
|
336
|
+
|
|
337
|
+
## 推荐流程模板
|
|
338
|
+
- `selected_flow(选中的流程模板)`:prd-to-delivery
|
|
339
|
+
- 原因:简单增强任务,适合快速通道
|
|
340
|
+
|
|
341
|
+
## 运行模式
|
|
342
|
+
- `mode(运行模式)`:auto
|
|
343
|
+
|
|
344
|
+
## 交付档位
|
|
345
|
+
- `delivery_profile(交付档位)`:micro
|
|
346
|
+
- `artifact_profile(产物规格)`:compact
|
|
347
|
+
- `complexity(复杂度)`:low
|
|
348
|
+
|
|
349
|
+
## 快速通道
|
|
350
|
+
- 已识别为简单需求,启用快速通道
|
|
351
|
+
- requirement-analyst 跳过 design-analysis
|
|
352
|
+
- 文档采用极简版
|
|
353
|
+
|
|
354
|
+
## 推荐专家
|
|
355
|
+
- 必选:frontend-implementer(前端实现专家)、code-guardian(规范守护者)
|
|
356
|
+
- 可选:requirement-analyst(需求解析专家)
|
|
357
|
+
- 第一跳:requirement-analyst(需求解析专家)
|
|
358
|
+
|
|
359
|
+
## 默认假设
|
|
360
|
+
- 沿用项目现有组件结构和样式规范
|
|
361
|
+
- 删除按钮样式沿用项目 Button 组件
|
|
362
|
+
|
|
363
|
+
## 缺失输入
|
|
364
|
+
- 无
|
|
365
|
+
|
|
366
|
+
## 审批点
|
|
367
|
+
- 暂无
|
|
368
|
+
|
|
369
|
+
## 下一步
|
|
370
|
+
- 直接进入快速通道,requirement-analyst 生成极简文档后快速进入实现
|
|
371
|
+
```
|
|
372
|
+
|
|
292
373
|
## 7. 一句话约束
|
|
293
374
|
|
|
294
375
|
> `task-orchestrator(任务主代理)` 的首轮输出必须先形成结构化 `run-plan(运行计划)`;在 `auto(自动)` 模式下,应先做仓库推断并记录 `assumptions(默认假设)`,不默认回问用户,只有高风险关键分歧才转 `suggest(建议)` 或 `manual(手动)`。
|
|
@@ -43,6 +43,31 @@ handoff_to:
|
|
|
43
43
|
- 输出必须服务后续实现与验收,不写空泛汇报材料
|
|
44
44
|
- 专家不是发明新方案,而是通过 `rules + skills + OpenSpec` 收敛到当前项目可实施方案
|
|
45
45
|
|
|
46
|
+
## 复杂度快速判断
|
|
47
|
+
|
|
48
|
+
**简单需求(快速通道)** - 满足以下全部条件:
|
|
49
|
+
- 单文件或 2-3 个文件的修改
|
|
50
|
+
- 任务明确(如"加个按钮"、"改个样式"、"加个校验")
|
|
51
|
+
- 不涉及新模块、新路由、新接口
|
|
52
|
+
- 无需设计稿或复杂交互
|
|
53
|
+
- 项目规则中已有明确实现模式
|
|
54
|
+
|
|
55
|
+
**快速通道行为**:
|
|
56
|
+
1. 跳过 `design-analysis` 调用
|
|
57
|
+
2. `proposal.md` 使用短版(目标、范围、假设,各 1-2 行)
|
|
58
|
+
3. `specs/` 使用短版(只写变更点,不写完整场景)
|
|
59
|
+
4. `tasks.md` 使用短版(3-5 条直接可执行任务)
|
|
60
|
+
5. 直接进入实现,不做详细澄清
|
|
61
|
+
|
|
62
|
+
**复杂需求(完整分析)** - 命中以下任一条件:
|
|
63
|
+
- 涉及多个模块或系统级变更
|
|
64
|
+
- 需要新接口、新状态管理、新路由设计
|
|
65
|
+
- 有设计稿或复杂交互需求
|
|
66
|
+
- 存在技术选型或架构决策
|
|
67
|
+
- 规则不明确,需要大量澄清
|
|
68
|
+
|
|
69
|
+
**完整分析行为**:按下方"必做步骤"执行完整流程。
|
|
70
|
+
|
|
46
71
|
## 必做步骤
|
|
47
72
|
|
|
48
73
|
1. 读取任务输入、项目背景、`role_rule_contract`、`repo_conventions`
|
package/bin/protocol-workflow.js
CHANGED
|
@@ -431,7 +431,12 @@ async function main(mode, argv) {
|
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
if (options.json) {
|
|
434
|
-
|
|
434
|
+
const output = `${JSON.stringify(result, null, 2)}\n`;
|
|
435
|
+
// 确保 stdout 完整写入后再退出,避免 spawnSync 截断
|
|
436
|
+
process.stdout.write(output);
|
|
437
|
+
if (process.stdout.writableLength > 0) {
|
|
438
|
+
await new Promise((resolve) => process.stdout.once('drain', resolve));
|
|
439
|
+
}
|
|
435
440
|
} else {
|
|
436
441
|
if (mode === 'advance') {
|
|
437
442
|
printStep(result);
|
package/bin/refresh-command.js
CHANGED
|
@@ -115,56 +115,29 @@ function refresh(targetDir, pkgRoot) {
|
|
|
115
115
|
updated.push('openspec/config.yaml.template');
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
// 4. 同步 IDE
|
|
118
|
+
// 4. 同步 IDE 配置文件(跳过指针文件,只同步实际目录)
|
|
119
|
+
// IDE 的 commands/rules/skills 可能是指向 .agents/ 的指针文件(非目录),
|
|
120
|
+
// 这些指针文件不需要替换,因为 .agents/ 已经在步骤 1 中同步过了。
|
|
119
121
|
const ides = ['cursor', 'claude', 'qoder', 'trae', 'opencode'];
|
|
120
122
|
for (const ide of ides) {
|
|
121
123
|
const sourceIdeDir = path.join(sourceDir, `.${ide}`);
|
|
122
124
|
const targetIdeDir = path.join(targetDir, `.${ide}`);
|
|
123
125
|
if (!fs.existsSync(sourceIdeDir) || !fs.existsSync(targetIdeDir)) continue;
|
|
124
126
|
|
|
125
|
-
// 同步
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
} catch (error) {
|
|
136
|
-
skipped.push({ path: `.${ide}/commands/`, reason: error.message });
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 同步 rules(如果是实际文件而非 symlink)
|
|
141
|
-
const srcRulesDir = path.join(sourceIdeDir, 'rules');
|
|
142
|
-
const destRulesDir = path.join(targetIdeDir, 'rules');
|
|
143
|
-
if (fs.existsSync(srcRulesDir) && !isSymlink(destRulesDir)) {
|
|
144
|
-
try {
|
|
145
|
-
if (fs.existsSync(destRulesDir)) {
|
|
146
|
-
fs.rmSync(destRulesDir, { recursive: true, force: true });
|
|
147
|
-
}
|
|
148
|
-
copyDirSync(srcRulesDir, destRulesDir);
|
|
149
|
-
updated.push(`.${ide}/rules/`);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
skipped.push({ path: `.${ide}/rules/`, reason: error.message });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// 同步 skills
|
|
156
|
-
const srcSkillsDir = path.join(sourceIdeDir, 'skills');
|
|
157
|
-
const destSkillsDir = path.join(targetIdeDir, 'skills');
|
|
158
|
-
if (fs.existsSync(srcSkillsDir)) {
|
|
159
|
-
try {
|
|
160
|
-
if (fs.existsSync(destSkillsDir)) {
|
|
161
|
-
fs.rmSync(destSkillsDir, { recursive: true, force: true });
|
|
127
|
+
// 同步 IDE 特有配置文件(如 mcp.json)
|
|
128
|
+
try {
|
|
129
|
+
const sourceEntries = fs.readdirSync(sourceIdeDir);
|
|
130
|
+
for (const entry of sourceEntries) {
|
|
131
|
+
const srcPath = path.join(sourceIdeDir, entry);
|
|
132
|
+
const destPath = path.join(targetIdeDir, entry);
|
|
133
|
+
// 只同步文件,不同步目录(commands/rules/skills 目录由 .agents/ 指针管理)
|
|
134
|
+
if (fs.statSync(srcPath).isFile()) {
|
|
135
|
+
fs.copyFileSync(srcPath, destPath);
|
|
136
|
+
updated.push(`.${ide}/${entry}`);
|
|
162
137
|
}
|
|
163
|
-
copyDirSync(srcSkillsDir, destSkillsDir);
|
|
164
|
-
updated.push(`.${ide}/skills/`);
|
|
165
|
-
} catch (error) {
|
|
166
|
-
skipped.push({ path: `.${ide}/skills/`, reason: error.message });
|
|
167
138
|
}
|
|
139
|
+
} catch (error) {
|
|
140
|
+
skipped.push({ path: `.${ide}/`, reason: error.message });
|
|
168
141
|
}
|
|
169
142
|
}
|
|
170
143
|
|