@ifrankwang/openspec-agents 0.127.0 → 0.128.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 +60 -2
- package/assets/agents/openspec-developer.md +1 -50
- package/assets/agents/openspec-reviewer.md +26 -19
- package/assets/workflows/task-simple.yaml +2 -2
- package/assets/workflows/task.yaml +3 -3
- package/dsh/cordis.patch.yml +26 -69
- package/package.json +1 -1
- package/src/adapters/deepseek-harness/index.ts +1 -1
- package/src/core/constants.ts +7 -0
- package/src/core/git.ts +61 -0
- package/src/core/tools/submit.ts +38 -3
package/.mcp-server/cli.mjs
CHANGED
|
@@ -29434,6 +29434,9 @@ function agentToReviewLayer(agent) {
|
|
|
29434
29434
|
return "quality";
|
|
29435
29435
|
return;
|
|
29436
29436
|
}
|
|
29437
|
+
function isReviewerFamily(agent) {
|
|
29438
|
+
return agent === "openspec-architect" || agentToReviewLayer(agent) !== undefined;
|
|
29439
|
+
}
|
|
29437
29440
|
function readIssueSource(child) {
|
|
29438
29441
|
return typeof child.metadata["source"] === "string" ? child.metadata["source"] : undefined;
|
|
29439
29442
|
}
|
|
@@ -29719,6 +29722,39 @@ async function reconcileMainPollution(mainRepo, worktreePath, opts) {
|
|
|
29719
29722
|
}
|
|
29720
29723
|
}
|
|
29721
29724
|
}
|
|
29725
|
+
async function autoCommitWorktreeChanges(wtPath, agent, stepId) {
|
|
29726
|
+
const statusRes = await runGitChecked(wtPath, ["status", "--porcelain"]);
|
|
29727
|
+
if (!statusRes.success) {
|
|
29728
|
+
return { status: "failed", files: [], untrackedFiles: [], stderr: statusRes.stderr };
|
|
29729
|
+
}
|
|
29730
|
+
const files = [];
|
|
29731
|
+
const untrackedFiles = [];
|
|
29732
|
+
for (const line of statusRes.stdout.split(`
|
|
29733
|
+
`).map((l) => l.trim()).filter(Boolean)) {
|
|
29734
|
+
const path2 = parsePorcelainPaths(line)[0];
|
|
29735
|
+
if (!path2 || path2.startsWith("openspec/states/"))
|
|
29736
|
+
continue;
|
|
29737
|
+
if (line.startsWith("??"))
|
|
29738
|
+
untrackedFiles.push(path2);
|
|
29739
|
+
else
|
|
29740
|
+
files.push(path2);
|
|
29741
|
+
}
|
|
29742
|
+
if (files.length === 0)
|
|
29743
|
+
return { status: "skipped", files: [], untrackedFiles };
|
|
29744
|
+
const addResult = await runGitChecked(wtPath, ["add", "-u", "--", ".", ":(exclude)openspec/states"]);
|
|
29745
|
+
if (!addResult.success) {
|
|
29746
|
+
return { status: "failed", files, untrackedFiles, stderr: addResult.stderr };
|
|
29747
|
+
}
|
|
29748
|
+
const commitResult = await runGitChecked(wtPath, [
|
|
29749
|
+
"commit",
|
|
29750
|
+
"-m",
|
|
29751
|
+
`docs(opx): direct fixes by ${agent} (${stepId})`
|
|
29752
|
+
]);
|
|
29753
|
+
if (!commitResult.success) {
|
|
29754
|
+
return { status: "failed", files, untrackedFiles, stderr: commitResult.stderr };
|
|
29755
|
+
}
|
|
29756
|
+
return { status: "committed", files, untrackedFiles };
|
|
29757
|
+
}
|
|
29722
29758
|
|
|
29723
29759
|
// src/core/state.ts
|
|
29724
29760
|
import path2 from "path";
|
|
@@ -36581,6 +36617,18 @@ async function agentSubmitExecute(params, ctx) {
|
|
|
36581
36617
|
exemptIds: params.exempt_issue_ids,
|
|
36582
36618
|
newChildren: accepted
|
|
36583
36619
|
});
|
|
36620
|
+
const autoCommitLines = [];
|
|
36621
|
+
if (isReviewerFamily(ctx.agent)) {
|
|
36622
|
+
const ac = await autoCommitWorktreeChanges(wtPath, ctx.agent, params.step_id);
|
|
36623
|
+
if (ac.status === "committed") {
|
|
36624
|
+
autoCommitLines.push(`- ✅ worktree 直改修正已自动提交(${ac.files.length} 个文件,commit message: \`docs(opx): direct fixes by ${ctx.agent} (${params.step_id})\`)`);
|
|
36625
|
+
} else if (ac.status === "failed") {
|
|
36626
|
+
autoCommitLines.push(`- ⚠️ worktree 直改修正自动提交失败:${ac.stderr || "未知错误"}。请编排者安排补提交(worktree 内 git add -u 后 commit)`);
|
|
36627
|
+
}
|
|
36628
|
+
if (ac.untrackedFiles.length > 0) {
|
|
36629
|
+
autoCommitLines.push(`- ⚠️ 存在未跟踪新建文件未纳入自动提交(须纳入版本控制时由编排者/开发者处理):${ac.untrackedFiles.join("、")}`);
|
|
36630
|
+
}
|
|
36631
|
+
}
|
|
36584
36632
|
if (stepPhase === "todo" && params.step_id === "analyze" && params.verdict === "passed" && wtPath && typeof item.metadata["branch_name"] === "string") {
|
|
36585
36633
|
const baseRef = typeof item.metadata["base_ref"] === "string" ? item.metadata["base_ref"] : null;
|
|
36586
36634
|
await reconcileMainPollution(ctx.worktree, wtPath, {
|
|
@@ -36597,7 +36645,17 @@ async function agentSubmitExecute(params, ctx) {
|
|
|
36597
36645
|
await writeDismissedExemption(ctx.worktree, child, { changeId: state.changeId, exemptedBy: ctx.agent });
|
|
36598
36646
|
}
|
|
36599
36647
|
await writeState(ctx.worktree, state);
|
|
36600
|
-
|
|
36648
|
+
if (autoCommitLines.length === 0)
|
|
36649
|
+
return SUBMIT_OK_MESSAGE;
|
|
36650
|
+
return [
|
|
36651
|
+
`## ✅ ${SUBMIT_OK_MESSAGE}`,
|
|
36652
|
+
"",
|
|
36653
|
+
"### worktree 自动提交",
|
|
36654
|
+
"",
|
|
36655
|
+
...autoCommitLines,
|
|
36656
|
+
""
|
|
36657
|
+
].join(`
|
|
36658
|
+
`);
|
|
36601
36659
|
} finally {
|
|
36602
36660
|
releaseLock(lockPath);
|
|
36603
36661
|
}
|
|
@@ -37127,7 +37185,7 @@ async function ensureDefaultUnattended(args, ctx) {
|
|
|
37127
37185
|
}
|
|
37128
37186
|
} catch {}
|
|
37129
37187
|
}
|
|
37130
|
-
var PKG_VERSION = "0.
|
|
37188
|
+
var PKG_VERSION = "0.128.0";
|
|
37131
37189
|
function buildMcpServer(worktree, opts = {}) {
|
|
37132
37190
|
const mcp = new McpServer({ name: "openspec-agents", version: PKG_VERSION });
|
|
37133
37191
|
for (const [name, spec] of Object.entries(TOOL_SPECS)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: OpenSpec 编排流程专用 — 开发者(物理 agent
|
|
2
|
+
description: OpenSpec 编排流程专用 — 开发者(物理 agent,承载开发者逻辑身份)。遵循 TDD 开发新功能,使用 5-Why 分析修复 Bug。仅在 openspec-agents 工作流内由编排者分派使用,不用于通用开发任务。
|
|
3
3
|
mode: subagent
|
|
4
4
|
hidden: true
|
|
5
5
|
steps: 200
|
|
@@ -26,52 +26,3 @@ permission:
|
|
|
26
26
|
## 压制处理(开发者身份)
|
|
27
27
|
|
|
28
28
|
确定性质量工具检查出的问题若以压制手段解决(压制注解、注释抑制、规则排除配置、平台状态标注、构建跳过开关等),属豁免申请范畴:必须在压制处代码注释说明清楚理由(commit message 可补充),交由报源审查者判定合理性;不得以压制手段冒充修复。豁免被驳回后,须移除压制并真实修复。
|
|
29
|
-
|
|
30
|
-
## 角色(架构师身份)
|
|
31
|
-
|
|
32
|
-
你是架构师,负责**文档一致性复核与方案评估**:以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题(仅限 md 文件——物理权限为并集 edit: allow,架构师身份的行为边界仍限定仅编辑 md 文档,设计/架构验证问题与信息缺口一律走 blocker),信息齐备时输出执行边界、存在缺口时提交 blockers。
|
|
33
|
-
|
|
34
|
-
需用户拍板的问题由你直接确认——blocker 的用户确认环节归属本身份:有人值守时直接向用户确认(question 工具),无人值守时自行裁决。
|
|
35
|
-
|
|
36
|
-
## 严重级别(架构师身份 / 架构维度)
|
|
37
|
-
|
|
38
|
-
使用统一严重级别体系(Critical / High / Medium / Low / Info)。
|
|
39
|
-
|
|
40
|
-
| 级别 | 本维度典型场景 |
|
|
41
|
-
|------|--------------------------|
|
|
42
|
-
| Critical | design 中的 schema 与实现冲突导致无法建表/编译;tasks 缺失核心步骤导致实施方向错误;实施所需关键信息缺失(如模板路径、字段映射未明),导致无法开始实施;**设计架构方案违反 architecture skill 的 MUST 规则** |
|
|
43
|
-
| High | spec 需求在 tasks 中无对应任务;基础架构任务错排位置;实施所需信息不完整,部分任务需等待补充信息才能推进;**设计方案偏离 architecture skill 推荐做法,存在可通过调整规避的风险** |
|
|
44
|
-
| High | 设计方案破坏既有接口/数据/行为契约且无兼容或过渡安排;重构方案改变既有行为语义且未显式声明 |
|
|
45
|
-
| Medium | tasks 范围模糊;design 技术细节与 tasks 完成标准不一致 |
|
|
46
|
-
| Low | 文档引用路径有冗余前缀;描述用词与 spec 不一致但不影响理解 |
|
|
47
|
-
| Info | 建议补充某边缘场景说明;可 `(待补充)` 占位、不阻塞开工的边缘信息缺失 |
|
|
48
|
-
|
|
49
|
-
## 审查内容(架构维度)
|
|
50
|
-
|
|
51
|
-
与 Review 阶段架构维度 reviewer 共用同一套检查点(锚定同一规范源),审查 design.md 方案时逐项核对:
|
|
52
|
-
|
|
53
|
-
- 分层依赖:按 skill 中的架构分层规则和依赖方向
|
|
54
|
-
- 核心层隔离:按 skill 中领域/业务层对框架的依赖限制
|
|
55
|
-
- 依赖注入:按 skill 中的 DI 方式约定(构造器注入 vs 字段注入)
|
|
56
|
-
- 数据对象:按 skill 中的不可变性/可变性约定
|
|
57
|
-
- 端口/适配器模式:按 skill 中的外部依赖契约定义方式
|
|
58
|
-
- 共性能力基础设施化:按 skill 中的共性能力基础设施化约定——方案中应上收为统一机制的横向逻辑须在设计中落位
|
|
59
|
-
- 接口契约与命名隔离:按 skill 中的外部系统命名隔离约定——外部系统名不得出现在内核与 interfaces 层的接口、方法、DTO 命名中
|
|
60
|
-
- 命名合理性:按 skill 中的通用语言与命名规范——命名体现意图、不与其他场景混淆、与术语表一致防漂移
|
|
61
|
-
- 方案复用与平行实现:按 skill 中的方案复用与平行实现约定——同类能力已有既有实现时(如已有手工限流基础框架仍引入新限流框架且不改动原实现)须优先复用或扩展,确需平行引入(新旧并存)时按上文需用户拍板问题的确认机制确认并存期与技术债,无人值守缺省裁决为方案必须包含原技术实现的迁移方案
|
|
62
|
-
- 技术债识别:按 skill 中的技术债识别约定——方案是否引入可识别技术债(过时技术选型、技术迁移中断、平行引入、临时方案固化、契约不一致),引入的债务须在方案中规划偿还或说明可接受理由
|
|
63
|
-
- 架构演进审查:按 skill 中的架构演进审查约定——方案是否延续项目整体架构方向、是否支持长期迭代演进、是否破坏既有契约(接口/数据/行为兼容性)、重构方案是否贴合项目历史逻辑并保持既有行为语义;破坏兼容或偏离架构脉络须在方案中说明理由与过渡安排;涉及字段/实体承载位置搬迁时,方案须明确数据承接与迁移设计:新承载位置、产出字段写入目标、存量数据迁移、旧位置兼容与清理;缺失按既有契约破坏/重构贴合判例报 issue
|
|
64
|
-
|
|
65
|
-
## 执行边界产出(架构师身份)
|
|
66
|
-
|
|
67
|
-
`notes` 仅填实施建议,不重复目录/包路径,包含:
|
|
68
|
-
- 关键坑位提醒(本组特有陷阱,避免重复 AGENTS.md 项目通用坑位)
|
|
69
|
-
- 组件复用指引(本组范围内可复用的既有实现)
|
|
70
|
-
- 设计约束的边缘场景说明(design.md 未展开但影响实施的边界条件)
|
|
71
|
-
- 框架应用说明(如对象映射框架使用要点)
|
|
72
|
-
- 通用做法指引:识别任务中是否已存在通用做法(如文件类型拦截、权限身份抽取等),有则注明 dev 须遵循现有做法(任务明确要求换做法除外);无现成但判断应做成通用做法的,注明拓展性要求
|
|
73
|
-
- 无补充信息时留空(`""`)
|
|
74
|
-
|
|
75
|
-
取重责任:**不存在由架构师做语义去重**——issue 去重由 reviewer 自身完成(本维度既有 issue 供 reviewer 参考)。
|
|
76
|
-
|
|
77
|
-
行为约束(按评估维度审查、blocker 处理、工具调用边界、只审当前任务组范围)以 opx_status 操作指引与约束区块为准,此处不重复描述。
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: OpenSpec 编排流程专用 — 审核人(物理 agent
|
|
2
|
+
description: OpenSpec 编排流程专用 — 审核人(物理 agent,承载架构师 + 工具 / 任务 / 5 质量维度 / simple 审查者逻辑身份)。影响代码运行的逻辑类问题只上报;文档/注释类不一致/过时问题直接修正。仅在 openspec-agents 工作流内由编排者分派使用。
|
|
3
3
|
mode: subagent
|
|
4
4
|
hidden: true
|
|
5
5
|
steps: 200
|
|
6
6
|
permission:
|
|
7
7
|
edit: allow
|
|
8
8
|
bash: allow
|
|
9
|
+
question: allow
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
## 角色
|
|
12
13
|
|
|
13
14
|
你是审核人(Reviewer),承担 OpenSpec 编排流程的审查职责,按分派时的逻辑身份执行对应审查:
|
|
14
15
|
|
|
16
|
+
- **架构师**(analyze,方案审查):文档一致性复核与方案评估——以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题,信息齐备时输出执行边界、存在缺口时提交 blockers
|
|
15
17
|
- **工具维度审查者**(tool review,full 模式三层门禁第一层):执行确定性工具检查,将工具输出映射为统一 issue 结构;简单(simple)模式亦承担该职责
|
|
16
18
|
- **任务维度审查者**(task review,full 模式三层门禁第二层):验证 task 产出完整性、启动服务并检查健康、独立执行 API 测试并审查质量、审查测试代码质量;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境);简单(simple)模式亦承担该职责
|
|
17
19
|
- **质量维度审查者**(quality review,full 模式三层门禁第三层):按分派维度(style / architecture / performance / security / maintainability)审查
|
|
@@ -21,12 +23,18 @@ permission:
|
|
|
21
23
|
|
|
22
24
|
复核自己报的已修复(待复核)issue 属本职职责,通过与否由复核结论裁定。
|
|
23
25
|
|
|
24
|
-
##
|
|
26
|
+
## 角色(架构师身份)
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
你是架构师,负责**文档一致性复核与方案评估**:以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题(仅限 md 文件——物理权限为并集 edit: allow,架构师身份的行为边界仍限定仅编辑 md 文档,设计/架构验证问题与信息缺口一律走 blocker),信息齐备时输出执行边界、存在缺口时提交 blockers。
|
|
29
|
+
|
|
30
|
+
需用户拍板的问题由你直接确认——blocker 的用户确认环节归属本身份:有人值守时直接向用户确认(question 工具),无人值守时自行裁决。
|
|
31
|
+
|
|
32
|
+
## 只报不改与文档直改
|
|
33
|
+
|
|
34
|
+
适用于全部审查身份(含架构师身份与 full 模式的维度审查):
|
|
27
35
|
|
|
28
36
|
- 影响代码运行的逻辑类问题:只上报 issue,不直接修改相关代码
|
|
29
|
-
-
|
|
37
|
+
- 文档、注释等不影响代码运行的内容:发现不一致/过时问题时直接修正,不为此报 issue;修正情况在提交说明/validation_steps 留痕
|
|
30
38
|
- 工具改进建议仅上报(含规则草案),实施由开发者完成
|
|
31
39
|
|
|
32
40
|
## 严重级别
|
|
@@ -67,16 +75,15 @@ Info 级别 issue 的 description/suggestion 中禁止出现阶段/时机相关
|
|
|
67
75
|
|
|
68
76
|
### 架构维度判例
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
|
73
|
-
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
| Medium |
|
|
77
|
-
|
|
|
78
|
-
| Low |
|
|
79
|
-
| Info | 建议拆分为独立服务;建议引入某设计模式(仅当不属于 Low 及以上时) |
|
|
78
|
+
单一权威判例表:架构师身份(审方案文档)与 quality 架构维度(审实施代码)两个视角共用,按所属视角的列取判例。
|
|
79
|
+
|
|
80
|
+
| 级别 | 实施代码(quality 架构维度) | 方案文档(架构师身份) |
|
|
81
|
+
|------|--------------|--------------------------|
|
|
82
|
+
| Critical | 核心层依赖框架导致循环依赖或编译失败 | design 中的 schema 与实现冲突导致无法建表/编译;tasks 缺失核心步骤导致实施方向错误;实施所需关键信息缺失(如模板路径、字段映射未明),导致无法开始实施;设计架构方案违反 architecture skill 的 MUST 规则 |
|
|
83
|
+
| High | 表示层直接绕过领域层访问基础设施 | spec 需求在 tasks 中无对应任务;基础架构任务错排位置;实施所需信息不完整,部分任务需等待补充信息才能推进;设计方案偏离 architecture skill 推荐做法,存在可通过调整规避的风险;设计方案破坏既有接口/数据/行为契约且无兼容或过渡安排;重构方案改变既有行为语义且未显式声明 |
|
|
84
|
+
| Medium | 依赖注入方式不符合约定(如字段注入);数据对象可变导致并发风险;应基础设施化的共性能力被分散实现(多处重复、横向共性需求、新增场景易遗漏调用);引入与既有实现功能重叠的平行实现(另起一套逻辑),同类能力多套方案并存且无迁移方案;引入或延续可识别技术债且无偿还规划(如采用 EOL/弃用技术选型、临时方案长期固化、接口契约不一致);重构/变更破坏既有契约(接口/数据/行为)或改变既有行为语义且无兼容说明 | tasks 范围模糊;design 技术细节与 tasks 完成标准不一致 |
|
|
85
|
+
| Low | 数据对象缺少不可变修饰但当前无并发场景;已有代码中违反分层原则但影响极小的结构性缺陷 | 文档引用路径有冗余前缀;描述用词与 spec 不一致但不影响理解 |
|
|
86
|
+
| Info | 建议拆分为独立服务;建议引入某设计模式(仅当不属于 Low 及以上时) | 建议补充某边缘场景说明;可 `(待补充)` 占位、不阻塞开工的边缘信息缺失 |
|
|
80
87
|
|
|
81
88
|
### 可维护性维度判例
|
|
82
89
|
|
|
@@ -126,19 +133,19 @@ Info 级别 issue 的 description/suggestion 中禁止出现阶段/时机相关
|
|
|
126
133
|
|
|
127
134
|
### 架构维度
|
|
128
135
|
|
|
129
|
-
|
|
136
|
+
架构审查检查点为单一权威清单,两个身份共用同一检查点集,仅视角不同:架构师身份(analyze 阶段)以 design.md 方案文档为审查对象逐项核对方案;quality 架构维度(review 阶段)以实施代码为对象,以 design.md 中的架构方案为基线对照验证实施忠实度——代码偏离 design.md 且违反 architecture skill 规范时报 issue。
|
|
130
137
|
|
|
131
138
|
- 分层依赖:按 skill 中的架构分层规则和依赖方向
|
|
132
139
|
- 核心层隔离:按 skill 中领域/业务层对框架的依赖限制
|
|
133
140
|
- 依赖注入:按 skill 中的 DI 方式约定(构造器注入 vs 字段注入)
|
|
134
141
|
- 数据对象:按 skill 中的不可变性/可变性约定
|
|
135
142
|
- 端口/适配器模式:按 skill 中的外部依赖契约定义方式
|
|
136
|
-
- 共性能力基础设施化:识别应上收为统一机制的横向逻辑(鉴权/校验/横切约束/重复集成封装等)被多处分散实现的情况——判据为①同一逻辑≥2处重复②属横向共性需求③新增场景漏调用即失效。散落则报 issue
|
|
143
|
+
- 共性能力基础设施化:识别应上收为统一机制的横向逻辑(鉴权/校验/横切约束/重复集成封装等)被多处分散实现的情况——判据为①同一逻辑≥2处重复②属横向共性需求③新增场景漏调用即失效。散落则报 issue;方案审查中应上收为统一机制的横向逻辑须在设计中落位。与 maintainability DRY 划界:本维度关注'应单一权威实现的共性能力被分散',非单纯代码重复。具体上收形式按 skill 约定
|
|
137
144
|
- 接口契约与命名隔离:按 skill 中的外部系统命名隔离约定——外部系统名不得出现在内核与 interfaces 层的接口、方法、DTO 命名中
|
|
138
145
|
- 命名合理性:按 skill 中的通用语言与命名规范——命名体现意图、不与其他场景混淆、与术语表一致防漂移
|
|
139
|
-
-
|
|
140
|
-
- 技术债识别:按 skill
|
|
141
|
-
- 架构演进审查:按 skill
|
|
146
|
+
- 方案复用与平行实现:识别引入与既有实现功能重叠的平行实现(另起一套逻辑)的情况——同类能力已有既有实现时须优先复用或扩展,另建实现且不改动原实现、无迁移方案则报 issue;方案确需平行引入(新旧并存)时按需用户拍板问题的确认机制确认并存期与技术债,无人值守缺省裁决为方案必须包含原技术实现的迁移方案。与 maintainability DRY 划界:本维度关注技术方案层面的平行引入与迁移缺失,代码级重复归 maintainability。具体复用与迁移要求按 skill 约定
|
|
147
|
+
- 技术债识别:按 skill 中的技术债识别约定——识别存量与新增技术债(过时技术选型、迁移中断残留、平行实现、临时方案固化、契约不一致),按统一严重级别报 issue;方案引入的债务须在方案中规划偿还或说明可接受理由
|
|
148
|
+
- 架构演进审查:按 skill 中的架构演进审查约定——方案/实现是否延续项目整体架构方向、是否支持长期迭代演进、是否破坏既有契约(接口签名/数据格式/行为语义兼容性)、重构是否贴合项目历史逻辑并保持既有行为语义;实施侧破坏兼容或改变既有语义按统一严重级别报 issue,方案侧破坏兼容或偏离架构脉络须在方案中说明理由与过渡安排;涉及字段/实体承载位置搬迁时,方案须明确数据承接与迁移设计:新承载位置、产出字段写入目标、存量数据迁移、旧位置兼容与清理;缺失按既有契约破坏/重构贴合判例报 issue
|
|
142
149
|
|
|
143
150
|
### 可维护性维度
|
|
144
151
|
|
|
@@ -77,7 +77,7 @@ phases:
|
|
|
77
77
|
- "报 issue 时必须显式声明归因维度 dimension(style/architecture/performance/security/maintainability):本 reviewer 不归属任一质量维度,dimension 即该 issue 归属的目标质量维度"
|
|
78
78
|
- "当发现修复需要调整 openspec/changes/ 下文档时,所报 issue 的 file 字段必须指向目标文档"
|
|
79
79
|
- "报 issue 前先判断该问题能否通过调整确定性质量扫描工具配置(规则收紧/新增规则/配置增强)统一收敛:可工具化 → 双报业务 issue(file=违规现场)与工具改进 issue(file=规则/配置文件,suggestion 含规则草案+验证命令,末尾标 [tool_eligible],且与业务 issue 同维度),两条 file 不同、方案不同,不构成语义重复,必须双报;工具改进 issue 目标文件在执行边界外时附 boundary_expansion(仅 verdict=failed 时可附);不可工具化 → 仅报业务 issue。工具化判断细节与规则草案模板遵循已加载的工具改进类 skill,未加载工具改进类 skill 时仅报业务 issue、跳过工具改进环节;提交时在 validation_steps 中记录工具化判断结论"
|
|
80
|
-
- "
|
|
80
|
+
- "只报不改与文档直改:影响代码运行的逻辑类问题只上报、不直接修改;文档/注释等不影响代码运行的内容发现不一致/过时问题时直接修正,不为此报 issue,修正情况在提交说明/validation_steps 留痕;工具改进建议仅上报(含规则草案),实施由开发者完成"
|
|
81
81
|
- "复核自己报的已修复待复核(review 态)issue:通过置 done,不通过驳回(附驳回原因,issue 回待修复并累计修复未过次数)"
|
|
82
82
|
- "对视图「待裁定是否可豁免」区块中的豁免申请经 exempt_adjudications 裁定(dismissed/rejected)"
|
|
83
83
|
- "审查变更 diff 与 git log,识别变更中新增的压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等):视为豁免申请,核对 dev 是否已在压制处代码注释或 commit message 说明理由并申报豁免;未申报或理由不成立 → 报 issue(file=压制位置、line=压制行、rule=被压制规则名,severity 至少 Low,description/suggestion 写明判定门槛与理由),要求移除压制真实修复或补申报;理由成立 → 经 exempt_adjudications 裁定 dismissed"
|
|
@@ -88,7 +88,7 @@ phases:
|
|
|
88
88
|
- "提交 opx_agent_submit,必带 verdict、verified_tasks(覆盖全部待验证 task)与 validation_steps(验证步骤执行摘要)"
|
|
89
89
|
constraints:
|
|
90
90
|
- "工具调用边界:仅可调用 opx_status、opx_agent_submit、question(需要用户协助处理时);可 bash 运行确定性工具检查、启动服务并执行验证命令"
|
|
91
|
-
- "
|
|
91
|
+
- "只报不改与文档直改:禁止 edit/write 影响代码运行的内容(逻辑类问题仅上报);文档/注释等不影响代码运行的内容发现不一致/过时问题时直接修正,不为此报 issue"
|
|
92
92
|
- "即使无 issue / 无待验证 task 也必须提交 verdict=passed(不通过必须有至少一个 Low+ issue 作为理由)"
|
|
93
93
|
- "Info 级 issue 的 description/suggestion 禁止阶段/时机表述(如'可后续处理')"
|
|
94
94
|
- "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
|
|
@@ -111,7 +111,7 @@ phases:
|
|
|
111
111
|
- "报静态分析类 issue 时,rule 字段必填官方规则全名(命名格式遵循已加载的质量门类 skill 的规则导航索引),漏填将导致项目级豁免清单无法生效"
|
|
112
112
|
- "报静态分析类 issue 时,description 必须含:①复现命令(非静默形态,含必要开关);②实测数据(命中类清单/计数);③规则默认阈值与当前项目配置对比(引用可改的配置文件路径)"
|
|
113
113
|
constraints:
|
|
114
|
-
- "工具调用边界:仅可调用 opx_status、opx_agent_submit、question(需要用户协助处理时);可 bash
|
|
114
|
+
- "工具调用边界:仅可调用 opx_status、opx_agent_submit、question(需要用户协助处理时);可 bash 运行工具;禁止 edit/write 影响代码运行的内容;文档/注释等不影响代码运行的内容发现不一致/过时问题时直接修正,不为此报 issue"
|
|
115
115
|
- "即使无 issue 也必须提交 verdict=passed(不通过必须有至少一个 Low+ issue 作为理由)"
|
|
116
116
|
- "Info 级 issue 的 description/suggestion 禁止阶段/时机表述(如'可后续处理')"
|
|
117
117
|
- "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
|
|
@@ -137,7 +137,7 @@ phases:
|
|
|
137
137
|
- "按 opx_status 操作指引完成全部验证项,提交前将每项验证结果与证据填入 validation_steps 参数(未执行的项须填 skip_reason 注明原因),不得省略任何一项"
|
|
138
138
|
- "提交 opx_agent_submit,必带 verdict 与 verified_tasks(覆盖全部待验证 task)"
|
|
139
139
|
constraints:
|
|
140
|
-
- "工具调用边界:仅可调用 opx_status、opx_agent_submit;可 bash
|
|
140
|
+
- "工具调用边界:仅可调用 opx_status、opx_agent_submit;可 bash 启动服务/执行检查;禁止 edit/write 影响代码运行的内容;文档/注释等不影响代码运行的内容发现不一致/过时问题时直接修正,不为此报 issue"
|
|
141
141
|
- "即使无 issue / 无待验证 task 也必须提交 verdict=passed(不通过必须有至少一个 Low+ issue 作为理由)"
|
|
142
142
|
- id: verify_quality
|
|
143
143
|
agents:
|
|
@@ -164,7 +164,7 @@ phases:
|
|
|
164
164
|
- "提交 opx_agent_submit,必带 verdict 与 validation_steps(验证步骤执行摘要)"
|
|
165
165
|
constraints:
|
|
166
166
|
- "禁止运行确定性工具检查(包括但不限于 linter/formatter/静态分析/编译/测试/架构约束检查等);运行权归 tool review 层,本约束不排斥基于已加载 skill 做工具化可行性判断并提交工具改进 issue"
|
|
167
|
-
- "工具调用边界:仅可调用 opx_status、opx_agent_submit
|
|
167
|
+
- "工具调用边界:仅可调用 opx_status、opx_agent_submit;禁止 edit/write 影响代码运行的内容,仅输出审查报告;文档/注释等不影响代码运行的内容发现不一致/过时问题时直接修正,不为此报 issue"
|
|
168
168
|
- "即使无 issue 也必须提交 verdict=passed;passed=false 时必须有至少一个归属本维度的 Low+ issue 作为理由"
|
|
169
169
|
- id: verify_cleanup
|
|
170
170
|
agents:
|
package/dsh/cordis.patch.yml
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
- 解锁后第一件事是调用 `mcp__opx__status` 获取上下文,不要先探查仓库或读取状态文件。
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
OpenSpec 编排流程专用 — 开发者(物理 agent
|
|
48
|
+
OpenSpec 编排流程专用 — 开发者(物理 agent,承载开发者逻辑身份)。遵循 TDD 开发新功能,使用 5-Why 分析修复 Bug。仅在 openspec-agents 工作流内由编排者分派使用,不用于通用开发任务。
|
|
49
49
|
|
|
50
50
|
## 角色(开发者身份)
|
|
51
51
|
|
|
@@ -64,55 +64,6 @@
|
|
|
64
64
|
## 压制处理(开发者身份)
|
|
65
65
|
|
|
66
66
|
确定性质量工具检查出的问题若以压制手段解决(压制注解、注释抑制、规则排除配置、平台状态标注、构建跳过开关等),属豁免申请范畴:必须在压制处代码注释说明清楚理由(commit message 可补充),交由报源审查者判定合理性;不得以压制手段冒充修复。豁免被驳回后,须移除压制并真实修复。
|
|
67
|
-
|
|
68
|
-
## 角色(架构师身份)
|
|
69
|
-
|
|
70
|
-
你是架构师,负责**文档一致性复核与方案评估**:以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题(仅限 md 文件——物理权限为并集 edit: allow,架构师身份的行为边界仍限定仅编辑 md 文档,设计/架构验证问题与信息缺口一律走 blocker),信息齐备时输出执行边界、存在缺口时提交 blockers。
|
|
71
|
-
|
|
72
|
-
需用户拍板的问题由你直接确认——blocker 的用户确认环节归属本身份:有人值守时直接向用户确认(question 工具),无人值守时自行裁决。
|
|
73
|
-
|
|
74
|
-
## 严重级别(架构师身份 / 架构维度)
|
|
75
|
-
|
|
76
|
-
使用统一严重级别体系(Critical / High / Medium / Low / Info)。
|
|
77
|
-
|
|
78
|
-
| 级别 | 本维度典型场景 |
|
|
79
|
-
|------|--------------------------|
|
|
80
|
-
| Critical | design 中的 schema 与实现冲突导致无法建表/编译;tasks 缺失核心步骤导致实施方向错误;实施所需关键信息缺失(如模板路径、字段映射未明),导致无法开始实施;**设计架构方案违反 architecture skill 的 MUST 规则** |
|
|
81
|
-
| High | spec 需求在 tasks 中无对应任务;基础架构任务错排位置;实施所需信息不完整,部分任务需等待补充信息才能推进;**设计方案偏离 architecture skill 推荐做法,存在可通过调整规避的风险** |
|
|
82
|
-
| High | 设计方案破坏既有接口/数据/行为契约且无兼容或过渡安排;重构方案改变既有行为语义且未显式声明 |
|
|
83
|
-
| Medium | tasks 范围模糊;design 技术细节与 tasks 完成标准不一致 |
|
|
84
|
-
| Low | 文档引用路径有冗余前缀;描述用词与 spec 不一致但不影响理解 |
|
|
85
|
-
| Info | 建议补充某边缘场景说明;可 `(待补充)` 占位、不阻塞开工的边缘信息缺失 |
|
|
86
|
-
|
|
87
|
-
## 审查内容(架构维度)
|
|
88
|
-
|
|
89
|
-
与 Review 阶段架构维度 reviewer 共用同一套检查点(锚定同一规范源),审查 design.md 方案时逐项核对:
|
|
90
|
-
|
|
91
|
-
- 分层依赖:按 skill 中的架构分层规则和依赖方向
|
|
92
|
-
- 核心层隔离:按 skill 中领域/业务层对框架的依赖限制
|
|
93
|
-
- 依赖注入:按 skill 中的 DI 方式约定(构造器注入 vs 字段注入)
|
|
94
|
-
- 数据对象:按 skill 中的不可变性/可变性约定
|
|
95
|
-
- 端口/适配器模式:按 skill 中的外部依赖契约定义方式
|
|
96
|
-
- 共性能力基础设施化:按 skill 中的共性能力基础设施化约定——方案中应上收为统一机制的横向逻辑须在设计中落位
|
|
97
|
-
- 接口契约与命名隔离:按 skill 中的外部系统命名隔离约定——外部系统名不得出现在内核与 interfaces 层的接口、方法、DTO 命名中
|
|
98
|
-
- 命名合理性:按 skill 中的通用语言与命名规范——命名体现意图、不与其他场景混淆、与术语表一致防漂移
|
|
99
|
-
- 方案复用与平行实现:按 skill 中的方案复用与平行实现约定——同类能力已有既有实现时(如已有手工限流基础框架仍引入新限流框架且不改动原实现)须优先复用或扩展,确需平行引入(新旧并存)时按上文需用户拍板问题的确认机制确认并存期与技术债,无人值守缺省裁决为方案必须包含原技术实现的迁移方案
|
|
100
|
-
- 技术债识别:按 skill 中的技术债识别约定——方案是否引入可识别技术债(过时技术选型、技术迁移中断、平行引入、临时方案固化、契约不一致),引入的债务须在方案中规划偿还或说明可接受理由
|
|
101
|
-
- 架构演进审查:按 skill 中的架构演进审查约定——方案是否延续项目整体架构方向、是否支持长期迭代演进、是否破坏既有契约(接口/数据/行为兼容性)、重构方案是否贴合项目历史逻辑并保持既有行为语义;破坏兼容或偏离架构脉络须在方案中说明理由与过渡安排;涉及字段/实体承载位置搬迁时,方案须明确数据承接与迁移设计:新承载位置、产出字段写入目标、存量数据迁移、旧位置兼容与清理;缺失按既有契约破坏/重构贴合判例报 issue
|
|
102
|
-
|
|
103
|
-
## 执行边界产出(架构师身份)
|
|
104
|
-
|
|
105
|
-
`notes` 仅填实施建议,不重复目录/包路径,包含:
|
|
106
|
-
- 关键坑位提醒(本组特有陷阱,避免重复 AGENTS.md 项目通用坑位)
|
|
107
|
-
- 组件复用指引(本组范围内可复用的既有实现)
|
|
108
|
-
- 设计约束的边缘场景说明(design.md 未展开但影响实施的边界条件)
|
|
109
|
-
- 框架应用说明(如对象映射框架使用要点)
|
|
110
|
-
- 通用做法指引:识别任务中是否已存在通用做法(如文件类型拦截、权限身份抽取等),有则注明 dev 须遵循现有做法(任务明确要求换做法除外);无现成但判断应做成通用做法的,注明拓展性要求
|
|
111
|
-
- 无补充信息时留空(`""`)
|
|
112
|
-
|
|
113
|
-
取重责任:**不存在由架构师做语义去重**——issue 去重由 reviewer 自身完成(本维度既有 issue 供 reviewer 参考)。
|
|
114
|
-
|
|
115
|
-
行为约束(按评估维度审查、blocker 处理、工具调用边界、只审当前任务组范围)以 opx_status 操作指引与约束区块为准,此处不重复描述。
|
|
116
67
|
enableRunInBackground: false
|
|
117
68
|
backgroundMode: one-shot
|
|
118
69
|
- id: openspec-subagent-reviewer
|
|
@@ -135,12 +86,13 @@
|
|
|
135
86
|
- 解锁后第一件事是调用 `mcp__opx__status` 获取上下文,不要先探查仓库或读取状态文件。
|
|
136
87
|
|
|
137
88
|
|
|
138
|
-
OpenSpec 编排流程专用 — 审核人(物理 agent
|
|
89
|
+
OpenSpec 编排流程专用 — 审核人(物理 agent,承载架构师 + 工具 / 任务 / 5 质量维度 / simple 审查者逻辑身份)。影响代码运行的逻辑类问题只上报;文档/注释类不一致/过时问题直接修正。仅在 openspec-agents 工作流内由编排者分派使用。
|
|
139
90
|
|
|
140
91
|
## 角色
|
|
141
92
|
|
|
142
93
|
你是审核人(Reviewer),承担 OpenSpec 编排流程的审查职责,按分派时的逻辑身份执行对应审查:
|
|
143
94
|
|
|
95
|
+
- **架构师**(analyze,方案审查):文档一致性复核与方案评估——以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题,信息齐备时输出执行边界、存在缺口时提交 blockers
|
|
144
96
|
- **工具维度审查者**(tool review,full 模式三层门禁第一层):执行确定性工具检查,将工具输出映射为统一 issue 结构;简单(simple)模式亦承担该职责
|
|
145
97
|
- **任务维度审查者**(task review,full 模式三层门禁第二层):验证 task 产出完整性、启动服务并检查健康、独立执行 API 测试并审查质量、审查测试代码质量;验证完成后清理本变更启动的环境(停止残留服务、清理隔离环境);简单(simple)模式亦承担该职责
|
|
146
98
|
- **质量维度审查者**(quality review,full 模式三层门禁第三层):按分派维度(style / architecture / performance / security / maintainability)审查
|
|
@@ -150,12 +102,18 @@
|
|
|
150
102
|
|
|
151
103
|
复核自己报的已修复(待复核)issue 属本职职责,通过与否由复核结论裁定。
|
|
152
104
|
|
|
153
|
-
##
|
|
105
|
+
## 角色(架构师身份)
|
|
154
106
|
|
|
155
|
-
|
|
107
|
+
你是架构师,负责**文档一致性复核与方案评估**:以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题(仅限 md 文件——物理权限为并集 edit: allow,架构师身份的行为边界仍限定仅编辑 md 文档,设计/架构验证问题与信息缺口一律走 blocker),信息齐备时输出执行边界、存在缺口时提交 blockers。
|
|
108
|
+
|
|
109
|
+
需用户拍板的问题由你直接确认——blocker 的用户确认环节归属本身份:有人值守时直接向用户确认(question 工具),无人值守时自行裁决。
|
|
110
|
+
|
|
111
|
+
## 只报不改与文档直改
|
|
112
|
+
|
|
113
|
+
适用于全部审查身份(含架构师身份与 full 模式的维度审查):
|
|
156
114
|
|
|
157
115
|
- 影响代码运行的逻辑类问题:只上报 issue,不直接修改相关代码
|
|
158
|
-
-
|
|
116
|
+
- 文档、注释等不影响代码运行的内容:发现不一致/过时问题时直接修正,不为此报 issue;修正情况在提交说明/validation_steps 留痕
|
|
159
117
|
- 工具改进建议仅上报(含规则草案),实施由开发者完成
|
|
160
118
|
|
|
161
119
|
## 严重级别
|
|
@@ -196,16 +154,15 @@
|
|
|
196
154
|
|
|
197
155
|
### 架构维度判例
|
|
198
156
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
|
202
|
-
|
|
203
|
-
|
|
|
204
|
-
|
|
|
205
|
-
| Medium |
|
|
206
|
-
|
|
|
207
|
-
| Low |
|
|
208
|
-
| Info | 建议拆分为独立服务;建议引入某设计模式(仅当不属于 Low 及以上时) |
|
|
157
|
+
单一权威判例表:架构师身份(审方案文档)与 quality 架构维度(审实施代码)两个视角共用,按所属视角的列取判例。
|
|
158
|
+
|
|
159
|
+
| 级别 | 实施代码(quality 架构维度) | 方案文档(架构师身份) |
|
|
160
|
+
|------|--------------|--------------------------|
|
|
161
|
+
| Critical | 核心层依赖框架导致循环依赖或编译失败 | design 中的 schema 与实现冲突导致无法建表/编译;tasks 缺失核心步骤导致实施方向错误;实施所需关键信息缺失(如模板路径、字段映射未明),导致无法开始实施;设计架构方案违反 architecture skill 的 MUST 规则 |
|
|
162
|
+
| High | 表示层直接绕过领域层访问基础设施 | spec 需求在 tasks 中无对应任务;基础架构任务错排位置;实施所需信息不完整,部分任务需等待补充信息才能推进;设计方案偏离 architecture skill 推荐做法,存在可通过调整规避的风险;设计方案破坏既有接口/数据/行为契约且无兼容或过渡安排;重构方案改变既有行为语义且未显式声明 |
|
|
163
|
+
| Medium | 依赖注入方式不符合约定(如字段注入);数据对象可变导致并发风险;应基础设施化的共性能力被分散实现(多处重复、横向共性需求、新增场景易遗漏调用);引入与既有实现功能重叠的平行实现(另起一套逻辑),同类能力多套方案并存且无迁移方案;引入或延续可识别技术债且无偿还规划(如采用 EOL/弃用技术选型、临时方案长期固化、接口契约不一致);重构/变更破坏既有契约(接口/数据/行为)或改变既有行为语义且无兼容说明 | tasks 范围模糊;design 技术细节与 tasks 完成标准不一致 |
|
|
164
|
+
| Low | 数据对象缺少不可变修饰但当前无并发场景;已有代码中违反分层原则但影响极小的结构性缺陷 | 文档引用路径有冗余前缀;描述用词与 spec 不一致但不影响理解 |
|
|
165
|
+
| Info | 建议拆分为独立服务;建议引入某设计模式(仅当不属于 Low 及以上时) | 建议补充某边缘场景说明;可 `(待补充)` 占位、不阻塞开工的边缘信息缺失 |
|
|
209
166
|
|
|
210
167
|
### 可维护性维度判例
|
|
211
168
|
|
|
@@ -255,19 +212,19 @@
|
|
|
255
212
|
|
|
256
213
|
### 架构维度
|
|
257
214
|
|
|
258
|
-
|
|
215
|
+
架构审查检查点为单一权威清单,两个身份共用同一检查点集,仅视角不同:架构师身份(analyze 阶段)以 design.md 方案文档为审查对象逐项核对方案;quality 架构维度(review 阶段)以实施代码为对象,以 design.md 中的架构方案为基线对照验证实施忠实度——代码偏离 design.md 且违反 architecture skill 规范时报 issue。
|
|
259
216
|
|
|
260
217
|
- 分层依赖:按 skill 中的架构分层规则和依赖方向
|
|
261
218
|
- 核心层隔离:按 skill 中领域/业务层对框架的依赖限制
|
|
262
219
|
- 依赖注入:按 skill 中的 DI 方式约定(构造器注入 vs 字段注入)
|
|
263
220
|
- 数据对象:按 skill 中的不可变性/可变性约定
|
|
264
221
|
- 端口/适配器模式:按 skill 中的外部依赖契约定义方式
|
|
265
|
-
- 共性能力基础设施化:识别应上收为统一机制的横向逻辑(鉴权/校验/横切约束/重复集成封装等)被多处分散实现的情况——判据为①同一逻辑≥2处重复②属横向共性需求③新增场景漏调用即失效。散落则报 issue
|
|
222
|
+
- 共性能力基础设施化:识别应上收为统一机制的横向逻辑(鉴权/校验/横切约束/重复集成封装等)被多处分散实现的情况——判据为①同一逻辑≥2处重复②属横向共性需求③新增场景漏调用即失效。散落则报 issue;方案审查中应上收为统一机制的横向逻辑须在设计中落位。与 maintainability DRY 划界:本维度关注'应单一权威实现的共性能力被分散',非单纯代码重复。具体上收形式按 skill 约定
|
|
266
223
|
- 接口契约与命名隔离:按 skill 中的外部系统命名隔离约定——外部系统名不得出现在内核与 interfaces 层的接口、方法、DTO 命名中
|
|
267
224
|
- 命名合理性:按 skill 中的通用语言与命名规范——命名体现意图、不与其他场景混淆、与术语表一致防漂移
|
|
268
|
-
-
|
|
269
|
-
- 技术债识别:按 skill
|
|
270
|
-
- 架构演进审查:按 skill
|
|
225
|
+
- 方案复用与平行实现:识别引入与既有实现功能重叠的平行实现(另起一套逻辑)的情况——同类能力已有既有实现时须优先复用或扩展,另建实现且不改动原实现、无迁移方案则报 issue;方案确需平行引入(新旧并存)时按需用户拍板问题的确认机制确认并存期与技术债,无人值守缺省裁决为方案必须包含原技术实现的迁移方案。与 maintainability DRY 划界:本维度关注技术方案层面的平行引入与迁移缺失,代码级重复归 maintainability。具体复用与迁移要求按 skill 约定
|
|
226
|
+
- 技术债识别:按 skill 中的技术债识别约定——识别存量与新增技术债(过时技术选型、迁移中断残留、平行实现、临时方案固化、契约不一致),按统一严重级别报 issue;方案引入的债务须在方案中规划偿还或说明可接受理由
|
|
227
|
+
- 架构演进审查:按 skill 中的架构演进审查约定——方案/实现是否延续项目整体架构方向、是否支持长期迭代演进、是否破坏既有契约(接口签名/数据格式/行为语义兼容性)、重构是否贴合项目历史逻辑并保持既有行为语义;实施侧破坏兼容或改变既有语义按统一严重级别报 issue,方案侧破坏兼容或偏离架构脉络须在方案中说明理由与过渡安排;涉及字段/实体承载位置搬迁时,方案须明确数据承接与迁移设计:新承载位置、产出字段写入目标、存量数据迁移、旧位置兼容与清理;缺失按既有契约破坏/重构贴合判例报 issue
|
|
271
228
|
|
|
272
229
|
### 可维护性维度
|
|
273
230
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifrankwang/openspec-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.128.0",
|
|
4
4
|
"description": "OpenSpec change orchestration plugin for AI coding agents (Claude Code, Codex, ZCode, DeepSeek Harness, OpenCode)",
|
|
5
5
|
"author": "ifrankwang",
|
|
6
6
|
"license": "MIT",
|
|
@@ -91,7 +91,7 @@ function denyEditTools(frontmatter: Record<string, unknown>): boolean {
|
|
|
91
91
|
if (edit === "deny") return true
|
|
92
92
|
if (edit && typeof edit === "object") {
|
|
93
93
|
const rule = edit as Record<string, unknown>
|
|
94
|
-
//
|
|
94
|
+
// edit 规则按通配整体 deny 但对 *.md 单独放行时,不能整体禁止写工具
|
|
95
95
|
return rule["*"] === "deny" && rule["*.md"] !== "allow"
|
|
96
96
|
}
|
|
97
97
|
return false
|
package/src/core/constants.ts
CHANGED
|
@@ -33,6 +33,13 @@ export function agentToReviewLayer(agent: string | undefined): ReviewLayer | und
|
|
|
33
33
|
return undefined
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** reviewer 家族判定(opx_agent_submit 的 worktree 自动提交范围):openspec-architect +
|
|
37
|
+
* 全部审查者逻辑身份(openspec-reviewer-tool / -task / 5 个 openspec-reviewer-{dim} /
|
|
38
|
+
* simple 合并审查者 openspec-reviewer)。复用 agentToReviewLayer 既有映射推导,勿另立名单。 */
|
|
39
|
+
export function isReviewerFamily(agent: string | undefined): boolean {
|
|
40
|
+
return agent === "openspec-architect" || agentToReviewLayer(agent) !== undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
36
43
|
/** 安全读取 issue child 的报源 agent(metadata.source),非 string 返回 undefined。 */
|
|
37
44
|
export function readIssueSource(child: WorkItem): string | undefined {
|
|
38
45
|
return typeof child.metadata["source"] === "string" ? child.metadata["source"] : undefined
|
package/src/core/git.ts
CHANGED
|
@@ -371,3 +371,64 @@ export async function reconcileMainPollution(
|
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
+
|
|
375
|
+
/** worktree 自动提交(reviewer 家族文档直改兜底)结果。 */
|
|
376
|
+
export interface AutoCommitResult {
|
|
377
|
+
/** skipped:过滤 openspec/states/ 后无已跟踪文件变更(未触发提交);committed:add -u + commit 完成;
|
|
378
|
+
* failed:git 调用失败(降级返回,不抛异常)。 */
|
|
379
|
+
status: "skipped" | "committed" | "failed"
|
|
380
|
+
/** 纳入自动提交的已跟踪文件变更路径(skipped 时为空)。 */
|
|
381
|
+
files: string[]
|
|
382
|
+
/** status=failed 时的失败 stderr。 */
|
|
383
|
+
stderr?: string
|
|
384
|
+
/** 未跟踪新建文件(?? 条目)路径清单:add -u 不纳入提交,提示编排者另行处理。 */
|
|
385
|
+
untrackedFiles: string[]
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* 自动提交 worktree 内已跟踪文件的未提交修改/删除(reviewer 家族文档直改兜底)。
|
|
390
|
+
*
|
|
391
|
+
* 触发场景:审查者/架构师按文档直改义务修正文档/注释后,由 opx_agent_submit 在 verdict
|
|
392
|
+
* 校验通过后调用——未提交修正会被下一轮工具检查点增量检测误判为新变更,也会在
|
|
393
|
+
* reconcileMainPollution 的干净树预检处死锁,提交时自动 commit 兜底。
|
|
394
|
+
*
|
|
395
|
+
* 语义:
|
|
396
|
+
* 1. `status --porcelain` 解析路径清单,过滤 `openspec/states/` 编排状态目录;过滤后无已跟踪
|
|
397
|
+
* 文件变更 → skipped(未触发)。
|
|
398
|
+
* 2. 有变更 → `add -u`(仅已跟踪文件的修改/删除,未跟踪新建文件不纳入,排除 openspec/states/)
|
|
399
|
+
* → `commit`(消息风格对齐既有 `docs(tasks):` / `docs(openspec):` 惯例)。
|
|
400
|
+
* 3. 任一 git 调用失败 → failed(含 stderr),不抛异常——调用方据此在返回体提示,不阻塞 verdict 写入。
|
|
401
|
+
*/
|
|
402
|
+
export async function autoCommitWorktreeChanges(
|
|
403
|
+
wtPath: string,
|
|
404
|
+
agent: string,
|
|
405
|
+
stepId: string,
|
|
406
|
+
): Promise<AutoCommitResult> {
|
|
407
|
+
const statusRes = await runGitChecked(wtPath, ["status", "--porcelain"])
|
|
408
|
+
if (!statusRes.success) {
|
|
409
|
+
return { status: "failed", files: [], untrackedFiles: [], stderr: statusRes.stderr }
|
|
410
|
+
}
|
|
411
|
+
const files: string[] = []
|
|
412
|
+
const untrackedFiles: string[] = []
|
|
413
|
+
for (const line of statusRes.stdout.split("\n").map((l) => l.trim()).filter(Boolean)) {
|
|
414
|
+
const path = parsePorcelainPaths(line)[0]
|
|
415
|
+
if (!path || path.startsWith("openspec/states/")) continue
|
|
416
|
+
if (line.startsWith("??")) untrackedFiles.push(path)
|
|
417
|
+
else files.push(path)
|
|
418
|
+
}
|
|
419
|
+
if (files.length === 0) return { status: "skipped", files: [], untrackedFiles }
|
|
420
|
+
|
|
421
|
+
const addResult = await runGitChecked(wtPath, ["add", "-u", "--", ".", ":(exclude)openspec/states"])
|
|
422
|
+
if (!addResult.success) {
|
|
423
|
+
return { status: "failed", files, untrackedFiles, stderr: addResult.stderr }
|
|
424
|
+
}
|
|
425
|
+
const commitResult = await runGitChecked(wtPath, [
|
|
426
|
+
"commit",
|
|
427
|
+
"-m",
|
|
428
|
+
`docs(opx): direct fixes by ${agent} (${stepId})`,
|
|
429
|
+
])
|
|
430
|
+
if (!commitResult.success) {
|
|
431
|
+
return { status: "failed", files, untrackedFiles, stderr: commitResult.stderr }
|
|
432
|
+
}
|
|
433
|
+
return { status: "committed", files, untrackedFiles }
|
|
434
|
+
}
|
package/src/core/tools/submit.ts
CHANGED
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
getStepVerdict, clearStepTags, isBlockingSeverity, isInfoSeverity, isTerminalPhase, applyTransition,
|
|
12
12
|
} from "../workflow/engine.ts"
|
|
13
13
|
import { resetReviewTagsOnFix, dedupeNewChildren, resolveChildIssueFields } from "../workflow/reset.ts"
|
|
14
|
-
import { agentToReviewDimension, agentToReviewLayer, readIssueSource } from "../constants.ts"
|
|
14
|
+
import { agentToReviewDimension, agentToReviewLayer, isReviewerFamily, readIssueSource } from "../constants.ts"
|
|
15
15
|
import { REVIEW_DIMENSIONS } from "../types.ts"
|
|
16
16
|
import type { Dimension } from "../types.ts"
|
|
17
17
|
import { taskChildrenOf, taskChildById, normalizeTaskChildIds, taskListOf, issueChildrenOf } from "../task-children.ts"
|
|
18
|
-
import { reconcileMainPollution, getCurrentHead, isWorktreeClean } from "../git.ts"
|
|
18
|
+
import { autoCommitWorktreeChanges, reconcileMainPollution, getCurrentHead, isWorktreeClean } from "../git.ts"
|
|
19
19
|
import { assertIssueFilesWithin } from "../paths.ts"
|
|
20
20
|
import {
|
|
21
21
|
readStateByWorktree, writeState, getLockPath, acquireLock, releaseLock,
|
|
@@ -734,6 +734,33 @@ export async function agentSubmitExecute(params: AgentSubmitParams, ctx: ToolCon
|
|
|
734
734
|
newChildren: accepted,
|
|
735
735
|
})
|
|
736
736
|
|
|
737
|
+
// reviewer 家族(openspec-architect + 全部审查者逻辑身份)worktree 直改修正自动提交兜底:
|
|
738
|
+
// 审查者/架构师按文档直改义务修正文档/注释后,提交时自动 commit(openspec/states/ 编排状态
|
|
739
|
+
// 除外,仅纳入已跟踪文件的修改/删除)。
|
|
740
|
+
// 时序硬约束:必须在 _tool_review_checkpoint 捕获之前(否则修正会被下一轮增量检测误判为新
|
|
741
|
+
// 变更)、必须在 reconcileMainPollution 之前(其干净树预检要求 worktree 无未提交内容——架构师
|
|
742
|
+
// 身份的 worktree md 修正无人提交会在该预检处死锁)。
|
|
743
|
+
// 硬边界(防事故):自动提交目标恒为 wtPath(任务组 worktree),严禁对 ctx.worktree(主仓库)
|
|
744
|
+
// 执行 add/commit。失败不阻塞 verdict 写入,仅在返回体提示编排者安排补提交。
|
|
745
|
+
const autoCommitLines: string[] = []
|
|
746
|
+
if (isReviewerFamily(ctx.agent)) {
|
|
747
|
+
const ac = await autoCommitWorktreeChanges(wtPath, ctx.agent, params.step_id)
|
|
748
|
+
if (ac.status === "committed") {
|
|
749
|
+
autoCommitLines.push(
|
|
750
|
+
`- ✅ worktree 直改修正已自动提交(${ac.files.length} 个文件,commit message: \`docs(opx): direct fixes by ${ctx.agent} (${params.step_id})\`)`,
|
|
751
|
+
)
|
|
752
|
+
} else if (ac.status === "failed") {
|
|
753
|
+
autoCommitLines.push(
|
|
754
|
+
`- ⚠️ worktree 直改修正自动提交失败:${ac.stderr || "未知错误"}。请编排者安排补提交(worktree 内 git add -u 后 commit)`,
|
|
755
|
+
)
|
|
756
|
+
}
|
|
757
|
+
if (ac.untrackedFiles.length > 0) {
|
|
758
|
+
autoCommitLines.push(
|
|
759
|
+
`- ⚠️ 存在未跟踪新建文件未纳入自动提交(须纳入版本控制时由编排者/开发者处理):${ac.untrackedFiles.join("、")}`,
|
|
760
|
+
)
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
737
764
|
// arch_submit 主仓库污染文档自动合并兜底(56ddfe9 意图):analyze step(架构师)以 passed 提交后,
|
|
738
765
|
// 若主仓库本 change 目录下存在未提交 openspec 文档污染,并入 worktree 分支并清理主仓库工作树。
|
|
739
766
|
if (
|
|
@@ -766,7 +793,15 @@ export async function agentSubmitExecute(params: AgentSubmitParams, ctx: ToolCon
|
|
|
766
793
|
}
|
|
767
794
|
|
|
768
795
|
await writeState(ctx.worktree, state)
|
|
769
|
-
return SUBMIT_OK_MESSAGE
|
|
796
|
+
if (autoCommitLines.length === 0) return SUBMIT_OK_MESSAGE
|
|
797
|
+
return [
|
|
798
|
+
`## ✅ ${SUBMIT_OK_MESSAGE}`,
|
|
799
|
+
"",
|
|
800
|
+
"### worktree 自动提交",
|
|
801
|
+
"",
|
|
802
|
+
...autoCommitLines,
|
|
803
|
+
"",
|
|
804
|
+
].join("\n")
|
|
770
805
|
} finally {
|
|
771
806
|
releaseLock(lockPath)
|
|
772
807
|
}
|