@ifrankwang/openspec-agents 0.122.1 → 0.124.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.
@@ -36051,6 +36051,14 @@ async function completeTaskGroupExecute(params, ctx) {
36051
36051
  if (unresolvedBlockers.length > 0) {
36052
36052
  throw new Error(`存在 ${unresolvedBlockers.length} 个未解决 blocker,无法完成任务组。`);
36053
36053
  }
36054
+ let checkboxWarning = "";
36055
+ if (worktreePath) {
36056
+ try {
36057
+ await markTaskGroupCheckboxesComplete(worktreePath, params.change_id, state.taskGroupId);
36058
+ } catch (e) {
36059
+ checkboxWarning = `- **tasks.md 复选框勾选失败**: ${e instanceof Error ? e.message : String(e)}(不影响收尾)`;
36060
+ }
36061
+ }
36054
36062
  const mergeTarget = state.baseBranch;
36055
36063
  if (branchName) {
36056
36064
  const mergeResult = await mergeBranchToTarget(ctx.worktree, branchName, mergeTarget);
@@ -36072,7 +36080,9 @@ async function completeTaskGroupExecute(params, ctx) {
36072
36080
  }
36073
36081
  item.metadata["completed_at"] = new Date().toISOString();
36074
36082
  await writeState(ctx.worktree, state);
36075
- return `任务组已完成并合并到 "${mergeTarget}"。`;
36083
+ const doneMessage = `任务组已完成并合并到 "${mergeTarget}"。`;
36084
+ return checkboxWarning ? `${doneMessage}
36085
+ ${checkboxWarning}` : doneMessage;
36076
36086
  }
36077
36087
  async function setUnattendedExecute(params, ctx) {
36078
36088
  assertOrchestrator(ctx, "opx_orch_set_unattended");
@@ -36549,10 +36559,6 @@ async function agentSubmitExecute(params, ctx) {
36549
36559
  baseRef
36550
36560
  });
36551
36561
  }
36552
- if (params.step_id === "verify_task" && params.verdict === "passed" && taskChildrenOf(item).every((c) => isTerminalPhase(c.phase))) {
36553
- const worktreePath = typeof item.metadata["worktree_path"] === "string" ? item.metadata["worktree_path"] : ctx.worktree;
36554
- await markTaskGroupCheckboxesComplete(worktreePath, params.change_id, state.taskGroupId);
36555
- }
36556
36562
  if (params.step_id === "verify_tool" && agentToReviewLayer(ctx.agent) === "tool") {
36557
36563
  const head = await getCurrentHead(wtPath);
36558
36564
  if (head)
@@ -37092,7 +37098,7 @@ async function ensureDefaultUnattended(args, ctx) {
37092
37098
  }
37093
37099
  } catch {}
37094
37100
  }
37095
- var PKG_VERSION = "0.122.1";
37101
+ var PKG_VERSION = "0.124.0";
37096
37102
  function buildMcpServer(worktree, opts = {}) {
37097
37103
  const mcp = new McpServer({ name: "openspec-agents", version: PKG_VERSION });
37098
37104
  for (const [name, spec] of Object.entries(TOOL_SPECS)) {
package/README.md CHANGED
@@ -27,7 +27,7 @@ OpenSpec 把需求、设计、任务拆解成规范文档后,实施阶段仍
27
27
 
28
28
  `implement → quality_review → done`
29
29
 
30
- 面向轻量变更的精简流程:无 analyze 环节(执行边界默认整个 worktree),无 verify_tool / verify_task / verify_cleanup 环节。implement 失败自循环重试;quality_review 由单一审查者合并承担工具检查、任务验证与质量审查(工具改进建议双报机制保留,由开发者实施),失败回 implement 整步重审;开发者提交 implement 成果时强检查工作区干净(不干净拒绝并提示先 commit),收尾为直接合并分支并清理(裸合并,无回归、无环境清理;合并冲突由开发者解决后直接收尾)。tasks.md 复选框不随 simple 流程自动勾选——复选框同步由 full 流程的 verify_task 环节触发,simple 无该环节,任务完成状态以状态文件为准。
30
+ 面向轻量变更的精简流程:无 analyze 环节(执行边界默认整个 worktree),无 verify_tool / verify_task / verify_cleanup 环节。implement 失败自循环重试;quality_review 由单一审查者合并承担工具检查、任务验证与质量审查(工具改进建议双报机制保留,由开发者实施),失败回 implement 整步重审;开发者提交 implement 成果时强检查工作区干净(不干净拒绝并提示先 commit),收尾为直接合并分支并清理(裸合并,无回归、无环境清理;合并冲突由开发者解决后直接收尾)。tasks.md 复选框在任务组收尾(opx_orch_complete_task_group)时统一勾选当前任务组,勾选提交落在 worktree 分支、随合并带回主分支;full 与 simple 行为一致,任务完成状态以状态文件为准。
31
31
 
32
32
  ## 身份与角色
33
33
 
@@ -42,7 +42,7 @@ OpenSpec 把需求、设计、任务拆解成规范文档后,实施阶段仍
42
42
  - **Agent 无关**:内核不绑定具体 Agent,opencode / claude code / codex / zcode / deepseek harness 通过各自原生插件/适配器接入同一套状态机。
43
43
  - **Workflow 驱动**:步骤、角色、门禁在 workflow 中声明,`opx_status` 是下一步调度的唯一事实源。
44
44
  - **多 Agent 团队**:主代理编排,2 个物理子代理承载 9 种逻辑身份分工协作,避免单一大模型从头写到尾失控。
45
- - **强 Review 门禁**:full 模式 tool / task / quality 三层审查 + 收尾验证;simple 模式单一审查者合并审查。问题可回退、可豁免、可检查点决策。
45
+ - **强 Review 门禁**:full 模式 tool / task / quality 三层审查 + 收尾验证;simple 模式单一审查者合并审查。问题可回退、可豁免、可检查点决策。确定性质量工具问题以压制手段解决时视为豁免申请,须说明理由并经审查判定合理性。
46
46
  - **隔离与安全**:每个 change 使用独立 git worktree、资源隔离命名空间,减少相互干扰。
47
47
  - **可观测**:内置进度看板,状态/豁免/并发锁持久化到 `openspec/states/`。
48
48
 
@@ -21,6 +21,10 @@ permission:
21
21
 
22
22
  收尾阶段承担基准分支同步、合并冲突解决、回归复验与隔离环境清理职责;收尾验证中自报 issue 由自己复核收敛(区别于「修复的 issue 进入待复核,终态由提出者裁定」的常规路径)。
23
23
 
24
+ ## 压制处理(开发者身份)
25
+
26
+ 确定性质量工具检查出的问题若以压制手段解决(压制注解、注释抑制、规则排除配置、平台状态标注、构建跳过开关等),属豁免申请范畴:必须在压制处代码注释说明清楚理由(commit message 可补充),交由报源审查者判定合理性;不得以压制手段冒充修复。豁免被驳回后,须移除压制并真实修复。
27
+
24
28
  ## 角色(架构师身份)
25
29
 
26
30
  你是架构师,负责**文档一致性复核与方案评估**:以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题(仅限 md 文件——物理权限为并集 edit: allow,架构师身份的行为边界仍限定仅编辑 md 文档,设计/架构验证问题与信息缺口一律走 blocker),信息齐备时输出执行边界、存在缺口时提交 blockers。
@@ -189,3 +189,7 @@ Info 级别 issue 的 description/suggestion 中禁止出现阶段/时机相关
189
189
  - **确定性工具检查**:工具维度审查者与 simple 合并审查者被允许运行确定性工具检查(代码格式/架构约束/静态分析/单元测试编译/深度扫描),按已加载质量门 skill 的必做清单执行并将输出映射为统一 issue 结构;检查结果纳入审查结论
190
190
  - **任务验证**:任务维度审查者与 simple 合并审查者承担任务验证职责,验证 task 产出完整性、服务健康与 API 测试质量;未通过的 task 经 failed_tasks 上报
191
191
  - **工具改进**:可工具化的质量 pattern 双报业务 issue 与工具改进 issue(规则草案由审查者提供),实施工作由开发者完成,审查者不直接改动规则/配置文件以外的实现
192
+
193
+ ## 压制判定
194
+
195
+ 确定性质量工具检查出的问题若以压制手段解决(压制注解、注释抑制、规则排除配置、平台状态标注、构建跳过开关等),一律视为豁免申请,须判定其合理性:可接受情形(无法消除的框架/第三方限制、有证据的误报,且风险可控、理由充分)→ 认可豁免;不可接受情形(真实缺陷被压制规避、仅图省事、无理由或理由不成立)→ 不认可,须要求移除压制并真实修复。判定时核验压制处的理由(代码注释、commit message);不认可时须给出可见的判定理由(写入问题描述/建议或驳回说明)。此判定适用于承担工具检查的审查身份(工具审查者、simple 合并审查者)。
@@ -397,18 +397,26 @@ SonarQube 规则 6,500+,覆盖 PMD 无法检测的安全漏洞、代码异味
397
397
  git diff --name-only <baseRef>..HEAD | grep -E "(pmd-rules\.xml|sonar-project\.properties|pom\.xml)"
398
398
  ```
399
399
 
400
- 检查本轮 diff 中是否包含质量工具规则/配置文件的改动。若包含,逐一检查以下维度:
400
+ 检查本轮 diff 中是否包含质量工具规则/配置文件的改动,以及代码内压制手段。若包含,逐一检查以下维度:
401
401
 
402
402
  - 规则是否被删除或降级(如 PMD priority 从 1 改为 5,或规则项被整条移除)
403
403
  - 是否新增了过宽的 exclude/include 配置(如排除整个命名空间、跳过核心架构检查)
404
404
  - `pom.xml` 中 `spotless-maven-plugin` / `pmd-maven-plugin` 等质量插件配置是否被弱化(跳过执行、降低阻塞等级)
405
405
  - `pmd-maven-plugin` 的 CPD 配置是否被弱化(`cpd-check` goal 被移除、`<minimumTokens>` 被过度调高、`<excludes>` 或 `excludeFromFailureFile` 过宽排除——均属弱化形态)
406
+ - 代码内压制手段:类/方法级 @SuppressWarnings、@SuppressFBWarnings、NOSONAR 注释、PMD 抑制注解或 excludeFromFailureFile、规则移除/降级、sonar.issue.ignore.multicriteria / sonar.exclusions 过宽排除、平台状态标注(SAFE/WONTFIX/False Positive 等);每条压制映射为至少 Low 的 issue
406
407
 
407
408
  检查结果:
408
409
 
409
410
  - 配置无削弱 → 通过
410
411
  - 配置存在削弱 → 工具层 issue,severity=Medium,每条削弱映射为一个 issue
411
412
 
413
+ ### 7.1 Java 压制形态识别
414
+
415
+ - 代码内压制:类/方法级 @SuppressWarnings、@SuppressFBWarnings、NOSONAR 注释、PMD 抑制注解(如 @SuppressWarnings("PMD.xxx"));类级 @SuppressWarnings 的映射见第 4 节 PMD 映射表,方法级压制同样属压制形态
416
+ - 配置压制:excludeFromFailureFile、规则移除/降级、sonar.issue.ignore.multicriteria / sonar.exclusions 过宽排除
417
+ - 平台状态标注:SAFE/WONTFIX/False Positive 等;Security Hotspot 禁用 NOSONAR 见第 6 节
418
+ - 处理要求:压制须附理由(压制处注释),由审查方判定其合理性;无理由或不合理的压制映射为 issue,每条至少 Low
419
+
412
420
  ## 8. 工具输出 → 统一 issue dimension 映射表
413
421
 
414
422
  每个工具的输出必须翻译为统一 issue 结构,并携带 `dimension` 字段归属于 5 维之一:
@@ -57,9 +57,15 @@ must_do: ["env", "compile", "format", "architecture", "static_analysis", "unit_t
57
57
  - 规则是否被删除或降级
58
58
  - 是否新增了过宽的 exclude/include 配置
59
59
  - 质量工具插件配置是否被弱化(跳过执行、降低阻塞等级)
60
+ - 是否新增压制手段(代码内压制与配置压制)
60
61
 
61
62
  配置无削弱 → 通过;存在削弱 → 工具层 issue。
62
63
 
64
+ ### 7.1 压制识别与处理
65
+
66
+ - 压制形态(技术栈无关):① 代码注解/属性级抑制;② 注释类抑制标记;③ 规则/文件排除配置(含规则移除、降级、过宽 exclude/include);④ 平台状态标注;⑤ 构建/检查跳过开关。
67
+ - 处理要求:压制不消除问题本身,不得单独作为检查通过的依据;变更中新增的压制须附明确理由(压制处注释),由审查方判定其合理性;无理由或不合理的压制按原问题级别记录,且不得低于 Low 级。
68
+
63
69
  ## 8. 降级/无基线口径
64
70
 
65
71
  SCM 数据不可用或历史基线不可靠时,扫描结果无法按变更来源归类,此时全量扫描结果同样按统一 issue 结构、按原始严重级别产出检查结果与 issue 清单,不区分是否本轮变更引入。
@@ -5,6 +5,7 @@
5
5
  # 占位符 {{key}} 经 interpolateText 注入动态值,缺值保留原文。
6
6
  # 注意:simple 无 analyze 环节,execution_boundary 永不写入,step constraints 不得含
7
7
  # {{allowed_directories}} / {{allowed_packages}} / {{notes}} 边界占位符(缺值会原样渲染),执行边界默认整个 worktree。
8
+ # implement/quality_review 的压制约束与 task.yaml 同步维护
8
9
  id: task-simple
9
10
  name: Simple Task Workflow
10
11
  max_retries: 10
@@ -39,6 +40,7 @@ phases:
39
40
  - "提交前按已加载的维度规范类 skill(style/architecture/performance/security/maintainability 能力类别)对本次变更文件逐项自检(聚焦本轮变更文件,不扩散全量代码),自检结论与工具检查结果一并汇总进 self_check_results;修复被驳回 issue 后再次提交前同样须按维度规范类 skill 对变更文件自检后再提交"
40
41
  - "自检须覆盖已加载的维度规范类 skill 的全部检查点,self_check_results 按维度逐项列结论(通过/遗留及理由),禁止仅汇总工具检查结果"
41
42
  - "修复完成的 issue 经 fixed_issue_ids 上报后进入待复核(review)状态,终态由报源 reviewer 复核裁定;不可修 issue 经 exempt_issue_ids 申请豁免(申请后进入待裁定(review)状态,由报源 reviewer 在后续审查轮次裁定,被驳回的 issue 回待修复);Info 级 issue 不阻塞提交,无需申请豁免;全部 blocking issue 均已上报修复或申请豁免后才可 passed 提交推进"
43
+ - "确定性质量工具检查出的问题不得以压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等)静默规避:确需压制时,必须在压制处代码注释说明清楚理由(commit message 可补充),并经 exempt_issue_ids 申请豁免由报源 reviewer 裁定;不得以 fixed_issue_ids 冒充修复;被驳回后须移除压制并真实修复"
42
44
  - "遇外部依赖、凭证、真实输入或必须 stub/降级/跳过验收才能继续时,以 verdict=failed 提交 blocker(含 source_role、task_id、category、description、evidence、attempted_actions、options)"
43
45
  - "提交 opx_agent_submit:passed 时存在未完成或被驳回(open/rejected)的子任务必须全部列入 completed_task_ids(数字 id 如 1、2,或任务编号如 1.1),全部子任务已验证时可省略;不可修 issue 申请豁免(exempt_issue_ids)"
44
46
  constraints:
@@ -48,6 +50,7 @@ phases:
48
50
  - "提交前自检必须覆盖已加载的全部 skill(含维度规范类)检查点,不得以工具检查结果替代维度规范自检"
49
51
  - "需以 verdict=failed + blocker 上报的条件:需求模糊 / design 问题 / 技术阻塞 / 超出执行边界"
50
52
  - "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
53
+ - "禁止以压制手段静默规避确定性质量工具问题:压制必须附明确理由并经豁免申请流程裁定,不得以工具不再报错为由跳过申报"
51
54
  - name: review
52
55
  steps:
53
56
  - id: quality_review
@@ -71,6 +74,7 @@ phases:
71
74
  - "默认只报不改:影响代码运行的逻辑类问题只上报、不直接修改;文档/注释等不影响代码运行的问题可直接修改;工具改进建议仅上报(含规则草案),实施由开发者完成"
72
75
  - "复核自己报的已修复待复核(review 态)issue:通过置 done,不通过驳回(附驳回原因,issue 回待修复并累计修复未过次数)"
73
76
  - "对视图「待裁定是否可豁免」区块中的豁免申请经 exempt_adjudications 裁定(dismissed/rejected)"
77
+ - "审查变更 diff 与 git log,识别变更中新增的压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等):视为豁免申请,核对 dev 是否已在压制处代码注释或 commit message 说明理由并申报豁免;未申报或理由不成立 → 报 issue(file=压制位置、line=压制行、rule=被压制规则名,severity 至少 Low,description/suggestion 写明判定门槛与理由),要求移除压制真实修复或补申报;理由成立 → 经 exempt_adjudications 裁定 dismissed"
74
78
  - "有 task 未通过时必须 verdict=failed 并经 failed_tasks 上报(task_id + reason);passed 时不允许提供 failed_tasks"
75
79
  - "报静态分析类 issue 时,rule 字段必填官方规则全名(命名格式遵循已加载的质量门类 skill 的规则导航索引),漏填将导致项目级豁免清单无法生效"
76
80
  - "报静态分析类 issue 时,description 必须含:①复现命令(非静默形态,含必要开关);②实测数据(命中类清单/计数);③规则默认阈值与当前项目配置对比(引用可改的配置文件路径)"
@@ -82,4 +86,5 @@ phases:
82
86
  - "即使无 issue / 无待验证 task 也必须提交 verdict=passed(不通过必须有至少一个 Low+ issue 作为理由)"
83
87
  - "Info 级 issue 的 description/suggestion 禁止阶段/时机表述(如'可后续处理')"
84
88
  - "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
89
+ - "压制类 issue 严重级别至少 Low"
85
90
  - "有实质变更时,工具检查及 issue 报告覆盖全量代码;非本轮变更文件的工具违规同样必须映射为 issue(命中项目级豁免清单的按 Info,不重新豁免;其余非本轮引入问题按原严重级别上报),不得以不在变更清单或未越界修改为由丢弃"
@@ -71,6 +71,7 @@ phases:
71
71
  - "提交前按已加载的维度规范类 skill(style/architecture/performance/security/maintainability 能力类别)对本次变更文件逐项自检(聚焦本轮变更文件,不扩散全量代码),自检结论与工具检查结果一并汇总进 self_check_results;修复被驳回 issue 后再次提交前同样须按维度规范类 skill 对变更文件自检后再提交"
72
72
  - "自检须覆盖已加载的维度规范类 skill 的全部检查点,self_check_results 按维度逐项列结论(通过/遗留及理由),禁止仅汇总工具检查结果"
73
73
  - "修复完成的 issue 经 fixed_issue_ids 上报后进入待复核(review)状态,终态由对应 reviewer 复核裁定;不可修 issue 经 exempt_issue_ids 申请豁免(申请后进入待裁定(review)状态,由报源 reviewer 在后续审查轮次裁定,被驳回的 issue 回待修复);Info 级 issue 不阻塞提交,无需申请豁免;全部 blocking issue 均已上报修复或申请豁免后才可 passed 提交推进"
74
+ - "确定性质量工具检查出的问题不得以压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等)静默规避:确需压制时,必须在压制处代码注释说明清楚理由(commit message 可补充),并经 exempt_issue_ids 申请豁免由报源 reviewer 裁定;不得以 fixed_issue_ids 冒充修复;被驳回后须移除压制并真实修复"
74
75
  - "遇外部依赖、凭证、真实输入或必须 stub/降级/跳过验收才能继续时,以 verdict=failed 提交 blocker(含 source_role、task_id、category、description、evidence、attempted_actions、options)"
75
76
  - "提交 opx_agent_submit:passed 时存在未完成或被驳回(open/rejected)的子任务必须全部列入 completed_task_ids(数字 id 如 1、2,或任务编号如 1.1),全部子任务已验证时可省略;不可修 issue 申请豁免(exempt_issue_ids)"
76
77
  constraints:
@@ -82,6 +83,7 @@ phases:
82
83
  - "提交前自检必须覆盖已加载的全部 skill(含维度规范类)检查点,不得以工具检查结果替代维度规范自检"
83
84
  - "需以 verdict=failed + blocker 上报的条件:需求模糊 / design 问题 / 技术阻塞 / 超出执行边界"
84
85
  - "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
86
+ - "禁止以压制手段静默规避确定性质量工具问题:压制必须附明确理由并经豁免申请流程裁定,不得以工具不再报错为由跳过申报"
85
87
  - name: review
86
88
  steps:
87
89
  - id: verify_tool
@@ -94,6 +96,7 @@ phases:
94
96
  instructions:
95
97
  - "依据 opx_status 提供的变更检测结果分流:无代码/配置变更且本层无待复核/待裁定项 → 直接提交 passed,不运行全量工具检查,并以一条 step 名首段为 no_change 的 validation_steps 声明本轮整体豁免必做清单(completed=false + 结构化 skip_reason 注明判定依据);无变更但有本层待复核/待裁定项 → 仅复核/裁定待处理项后提交,不跑全量工具扫描;有变更 → 加载质量门类 skill 获取工具清单与映射规则,按已加载质量门 skill 必做清单逐项执行全部确定性工具检查(代码格式/架构约束/静态分析/单元测试编译/深度扫描——按必做清单中的对应项逐项执行并逐项申报),将工具输出映射为统一 issue 结构后提交"
96
98
  - "「有变更」分支先审查上方「本次变更证据」区块的变更文件清单与区间 diff 内容后自行判断:若确认本次变更仅为注释/文档性且无逻辑影响(非注释掉代码、非结构性/格式化变更、非文件重命名),可自行决定跳过全量工具检查直接提交 passed(validation_steps 以 step=no_change 申报整体豁免必做清单);无法确认或含逻辑/结构变更,必须顺序运行全部确定性工具检查;裁量仅免除全量工具扫描,不免除复核/裁定——本层 blocking issue 仍须处理至终态后提交"
99
+ - "审查「本次变更证据」的区间 diff 与 git log,识别变更中新增的压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等):视为豁免申请,核对 dev 是否已在压制处代码注释或 commit message 说明理由并申报豁免;未申报或理由不成立 → 报 issue(file=压制位置、line=压制行、rule=被压制规则名,severity 至少 Low,description/suggestion 写明判定门槛与理由),要求移除压制真实修复或补申报;理由成立 → 经 exempt_adjudications 裁定 dismissed"
97
100
  - "报 issue 时必须显式声明归因维度 dimension(style/architecture/performance/security/maintainability):本 reviewer 不归属任一质量维度,dimension 即该 issue 归属的目标质量维度"
98
101
  - "当发现修复需要调整 openspec/changes/ 下文档时,所报 issue 的 file 字段必须指向目标文档"
99
102
  - "复核本层已修复待复核(review 态)issue:通过置 done,不通过驳回(附驳回原因,issue 回待修复并累计修复未过次数)"
@@ -107,6 +110,7 @@ phases:
107
110
  - "即使无 issue 也必须提交 verdict=passed(不通过必须有至少一个 Low+ issue 作为理由)"
108
111
  - "Info 级 issue 的 description/suggestion 禁止阶段/时机表述(如'可后续处理')"
109
112
  - "禁止以 SonarQube 平台状态修改(SAFE/WONTFIX/False Positive/Confirmed 等)作为豁免手段:平台状态仅作用于当前 SonarQube 项目实例,每次 change 使用独立项目 key,不跨 change 生效;存量问题跨 change 豁免必须经 exempt_issue_ids 申请 → 报源 reviewer 裁定 dismissed 的流程"
113
+ - "压制类 issue 严重级别至少 Low"
110
114
  - "有实质变更时,工具检查及 issue 报告覆盖全量代码;非本轮变更文件的工具违规同样必须映射为 issue(命中项目级豁免清单的按 Info,不重新豁免;其余非本轮引入问题按原严重级别上报),不得以不在变更清单或未越界修改为由丢弃"
111
115
  - id: verify_task
112
116
  agents:
@@ -59,6 +59,10 @@
59
59
 
60
60
  收尾阶段承担基准分支同步、合并冲突解决、回归复验与隔离环境清理职责;收尾验证中自报 issue 由自己复核收敛(区别于「修复的 issue 进入待复核,终态由提出者裁定」的常规路径)。
61
61
 
62
+ ## 压制处理(开发者身份)
63
+
64
+ 确定性质量工具检查出的问题若以压制手段解决(压制注解、注释抑制、规则排除配置、平台状态标注、构建跳过开关等),属豁免申请范畴:必须在压制处代码注释说明清楚理由(commit message 可补充),交由报源审查者判定合理性;不得以压制手段冒充修复。豁免被驳回后,须移除压制并真实修复。
65
+
62
66
  ## 角色(架构师身份)
63
67
 
64
68
  你是架构师,负责**文档一致性复核与方案评估**:以 design.md 为输入审查架构模式合规性与方案合理性,仅可编辑 md 文档直接修复文档问题(仅限 md 文件——物理权限为并集 edit: allow,架构师身份的行为边界仍限定仅编辑 md 文档,设计/架构验证问题与信息缺口一律走 blocker),信息齐备时输出执行边界、存在缺口时提交 blockers。
@@ -312,6 +316,10 @@
312
316
  - **确定性工具检查**:工具维度审查者与 simple 合并审查者被允许运行确定性工具检查(代码格式/架构约束/静态分析/单元测试编译/深度扫描),按已加载质量门 skill 的必做清单执行并将输出映射为统一 issue 结构;检查结果纳入审查结论
313
317
  - **任务验证**:任务维度审查者与 simple 合并审查者承担任务验证职责,验证 task 产出完整性、服务健康与 API 测试质量;未通过的 task 经 failed_tasks 上报
314
318
  - **工具改进**:可工具化的质量 pattern 双报业务 issue 与工具改进 issue(规则草案由审查者提供),实施工作由开发者完成,审查者不直接改动规则/配置文件以外的实现
319
+
320
+ ## 压制判定
321
+
322
+ 确定性质量工具检查出的问题若以压制手段解决(压制注解、注释抑制、规则排除配置、平台状态标注、构建跳过开关等),一律视为豁免申请,须判定其合理性:可接受情形(无法消除的框架/第三方限制、有证据的误报,且风险可控、理由充分)→ 认可豁免;不可接受情形(真实缺陷被压制规避、仅图省事、无理由或理由不成立)→ 不认可,须要求移除压制并真实修复。判定时核验压制处的理由(代码注释、commit message);不认可时须给出可见的判定理由(写入问题描述/建议或驳回说明)。此判定适用于承担工具检查的审查身份(工具审查者、simple 合并审查者)。
315
323
  enableRunInBackground: false
316
324
  backgroundMode: one-shot
317
325
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifrankwang/openspec-agents",
3
- "version": "0.122.1",
3
+ "version": "0.124.0",
4
4
  "type": "module",
5
5
  "main": "./src/core/index.ts",
6
6
  "exports": {
@@ -2,7 +2,7 @@ import path from "path"
2
2
  import type { TaskItem, TaskStatus, WorkflowMode } from "../types.ts"
3
3
  import { BUILD_PHASE_TARGETS, REVIEW_LAYERS, REVIEW_VERIFY_STEPS } from "../types.ts"
4
4
  import { agentToReviewLayer } from "../constants.ts"
5
- import { runGit, runGitChecked, getCurrentBranch, getMergeBase, isWorktreeClean, mergeBranchToTarget, discoverDiskWorktrees, detectMainRepoPollution, detectChanges, type DetectChangesResult } from "../git.ts"
5
+ import { runGit, runGitChecked, getCurrentBranch, getMergeBase, isWorktreeClean, markTaskGroupCheckboxesComplete, mergeBranchToTarget, discoverDiskWorktrees, detectMainRepoPollution, detectChanges, type DetectChangesResult } from "../git.ts"
6
6
  import { readStateByWorktree, readStateByChangeId, writeState, writeContextToWorktree } from "../state.ts"
7
7
  import { generateIsolationNamespace } from "../namespace.ts"
8
8
  import { readExemptions } from "../exemptions.ts"
@@ -663,6 +663,16 @@ export async function completeTaskGroupExecute(params: { change_id: string }, ct
663
663
  throw new Error(`存在 ${unresolvedBlockers.length} 个未解决 blocker,无法完成任务组。`)
664
664
  }
665
665
 
666
+ // tasks.md 复选框统一在收尾勾选(原 G19 语义迁移):仅写 worktree,随合并带回主分支;失败不阻断收尾
667
+ let checkboxWarning = ""
668
+ if (worktreePath) {
669
+ try {
670
+ await markTaskGroupCheckboxesComplete(worktreePath, params.change_id, state.taskGroupId)
671
+ } catch (e) {
672
+ checkboxWarning = `- **tasks.md 复选框勾选失败**: ${e instanceof Error ? e.message : String(e)}(不影响收尾)`
673
+ }
674
+ }
675
+
666
676
  const mergeTarget = state.baseBranch
667
677
  if (branchName) {
668
678
  const mergeResult = await mergeBranchToTarget(ctx.worktree, branchName, mergeTarget)
@@ -684,7 +694,8 @@ export async function completeTaskGroupExecute(params: { change_id: string }, ct
684
694
  }
685
695
  item.metadata["completed_at"] = new Date().toISOString()
686
696
  await writeState(ctx.worktree, state)
687
- return `任务组已完成并合并到 "${mergeTarget}"。`
697
+ const doneMessage = `任务组已完成并合并到 "${mergeTarget}"。`
698
+ return checkboxWarning ? `${doneMessage}\n${checkboxWarning}` : doneMessage
688
699
  }
689
700
 
690
701
  export async function setUnattendedExecute(params: UnattendedParams, ctx: ToolContext): Promise<string> {
@@ -15,7 +15,7 @@ import { agentToReviewDimension, agentToReviewLayer, readIssueSource } from "../
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 { markTaskGroupCheckboxesComplete, reconcileMainPollution, getCurrentHead, isWorktreeClean } from "../git.ts"
18
+ import { reconcileMainPollution, getCurrentHead, isWorktreeClean } from "../git.ts"
19
19
  import { assertIssueFilesWithin } from "../paths.ts"
20
20
  import {
21
21
  readStateByWorktree, writeState, getLockPath, acquireLock, releaseLock,
@@ -750,17 +750,6 @@ export async function agentSubmitExecute(params: AgentSubmitParams, ctx: ToolCon
750
750
  })
751
751
  }
752
752
 
753
- // G19:verify_task passed 且全部 task child 达终态(done)→ 同步 tasks.md 复选框 [ ] → [x]
754
- if (
755
- params.step_id === "verify_task" &&
756
- params.verdict === "passed" &&
757
- taskChildrenOf(item).every((c) => isTerminalPhase(c.phase))
758
- ) {
759
- const worktreePath =
760
- typeof item.metadata["worktree_path"] === "string" ? item.metadata["worktree_path"] : ctx.worktree
761
- await markTaskGroupCheckboxesComplete(worktreePath, params.change_id, state.taskGroupId)
762
- }
763
-
764
753
  // tool review 检查点增量检测(A3):verify_tool 的 reviewer-tool 提交成功后记录当前 HEAD,
765
754
  // 供下次重进 verify_tool 时仅对比「检查点 → 当前 HEAD」区间的变更(无代码/配置变更时直提 passed,
766
755
  // 省去全量工具扫描)。写入位于 submitForStep 成功与 writeState 之间,任何异常路径均不落盘(零状态变更)。