@ifrankwang/openspec-agents 0.138.0 → 0.140.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 +14 -9
- package/assets/skills/api-test/SKILL.md +3 -3
- package/assets/skills/environment-cleanup/SKILL.md +11 -4
- package/assets/workflows/review-simple.yaml +1 -1
- package/assets/workflows/review.yaml +1 -1
- package/assets/workflows/task-simple.yaml +1 -1
- package/assets/workflows/task.yaml +1 -1
- package/package.json +1 -1
- package/src/core/tools/lifecycle.ts +2 -1
- package/src/core/workflow/engine.ts +9 -6
- package/src/core/workflow/status.ts +15 -8
package/.mcp-server/cli.mjs
CHANGED
|
@@ -22211,7 +22211,7 @@ function isTaskGroupSettled(item) {
|
|
|
22211
22211
|
return noTags && childrenSettled;
|
|
22212
22212
|
}
|
|
22213
22213
|
function isFinalTaskGroup(state, item) {
|
|
22214
|
-
return state.workItems.filter((w) => w.id.startsWith("task:") && w.id !== item.id).every(
|
|
22214
|
+
return state.workItems.filter((w) => w.id.startsWith("task:") && w.id !== item.id).every((w) => isTerminalPhase(w.phase) || w.metadata["completed_at"] !== undefined);
|
|
22215
22215
|
}
|
|
22216
22216
|
function isBlockingSeverity(severity) {
|
|
22217
22217
|
return severity !== undefined && BLOCKING_SEVERITIES.includes(severity);
|
|
@@ -27373,9 +27373,9 @@ function renderTerminalPhase(item, state, caller) {
|
|
|
27373
27373
|
"",
|
|
27374
27374
|
`- **完成时间**: ${item.metadata["completed_at"]}`,
|
|
27375
27375
|
"",
|
|
27376
|
-
finalGroup ? "本任务组为最后一个收口任务组,change 收口已完成:变更分支已合并回基准分支,编排已完成并收尾。" :
|
|
27376
|
+
finalGroup ? "本任务组为最后一个收口任务组,change 收口已完成:变更分支已合并回基准分支,编排已完成并收尾。" : `本任务组已完成,变更保留在 change 分支上,待全部任务组完成后统一收口合并。${cancelTaskGroupNote(state)}`,
|
|
27377
27377
|
"",
|
|
27378
|
-
...renderDeploymentNotesSection(state, caller)
|
|
27378
|
+
...renderDeploymentNotesSection(state, item, caller)
|
|
27379
27379
|
].join(`
|
|
27380
27380
|
`);
|
|
27381
27381
|
}
|
|
@@ -27385,16 +27385,21 @@ function renderTerminalPhase(item, state, caller) {
|
|
|
27385
27385
|
"全部审核层已通过。",
|
|
27386
27386
|
finalGroup ? "调用 `opx_orch_complete_task_group` 完成 change 收口(把变更分支合并回基准分支并清理)。" : "调用 `opx_orch_complete_task_group` 完成任务组收尾(变更保留在 change 分支,统一收口时合并)。",
|
|
27387
27387
|
"",
|
|
27388
|
-
...renderDeploymentNotesSection(state, caller)
|
|
27388
|
+
...renderDeploymentNotesSection(state, item, caller)
|
|
27389
27389
|
].join(`
|
|
27390
27390
|
`);
|
|
27391
27391
|
}
|
|
27392
|
-
function
|
|
27392
|
+
function cancelTaskGroupNote(state) {
|
|
27393
|
+
if (!state)
|
|
27394
|
+
return "";
|
|
27395
|
+
return `若某任务组已确认不再执行,当前版本不支持取消任务组,须人工编辑编排 state 文件(openspec/states/${state.changeId}.json)将该任务组的 phase 改为 "cancelled",收口合并才会触发。`;
|
|
27396
|
+
}
|
|
27397
|
+
function renderDeploymentNotesSection(state, item, caller) {
|
|
27393
27398
|
if (!caller?.orchestrator || !state || state.kind === "review")
|
|
27394
27399
|
return [];
|
|
27395
|
-
|
|
27396
|
-
if (!taskGroups.every(isTaskGroupSettled))
|
|
27400
|
+
if (!isFinalTaskGroup(state, item))
|
|
27397
27401
|
return [];
|
|
27402
|
+
const taskGroups = state.workItems.filter((w) => w.id.startsWith("task:"));
|
|
27398
27403
|
const lines = [
|
|
27399
27404
|
"## 部署注意事项汇报",
|
|
27400
27405
|
"",
|
|
@@ -29182,7 +29187,7 @@ async function completeTaskGroupLocked(params, ctx) {
|
|
|
29182
29187
|
if (!isFinalTaskGroup(state, item)) {
|
|
29183
29188
|
item.metadata["completed_at"] = new Date().toISOString();
|
|
29184
29189
|
await writeState(ctx.worktree, state);
|
|
29185
|
-
const doneMessage =
|
|
29190
|
+
const doneMessage = `任务组已完成。本任务组变更保留在 change 分支上,待全部任务组完成后统一收口合并(本次不合并、不销毁 worktree)。若某任务组已确认不再执行,当前版本不支持取消任务组,须人工编辑编排 state 文件(openspec/states/${state.changeId}.json)将该任务组的 phase 改为 "cancelled",收口合并才会触发。`;
|
|
29186
29191
|
return checkboxWarning ? `${doneMessage}
|
|
29187
29192
|
${checkboxWarning}` : doneMessage;
|
|
29188
29193
|
}
|
|
@@ -30424,7 +30429,7 @@ async function ensureDefaultUnattended(args, ctx) {
|
|
|
30424
30429
|
}
|
|
30425
30430
|
} catch {}
|
|
30426
30431
|
}
|
|
30427
|
-
var PKG_VERSION = "0.
|
|
30432
|
+
var PKG_VERSION = "0.140.0";
|
|
30428
30433
|
function buildMcpServer(worktree, opts = {}) {
|
|
30429
30434
|
const mcp = new McpServer({ name: "openspec-agents", version: PKG_VERSION });
|
|
30430
30435
|
for (const [name, spec] of Object.entries(TOOL_SPECS)) {
|
|
@@ -100,15 +100,15 @@ API 测试脚本运行前需获取有效认证凭证。常见模式:
|
|
|
100
100
|
```
|
|
101
101
|
1. **MUST** 启动基础设施(Docker compose 项目名带隔离标识:`docker compose -p <namespace> up -d`,避免与并发 change 的容器冲突;隔离对象不限于数据库——mock 服务、消息队列/缓存等中间件、扫描分析平台等一切为本变更启动的资源均须经隔离标识启动,禁止复用宿主既有实例或共享端口)
|
|
102
102
|
2. **MUST** 准备 SQL 前置数据(写入本 change 的隔离容器内 DB)
|
|
103
|
-
3. **MUST** 启动服务(端口用编排会话建议端口:`--server.port=<建议端口>`,避免并发 change
|
|
103
|
+
3. **MUST** 启动服务(端口用编排会话建议端口:`--server.port=<建议端口>`,避免并发 change 端口冲突),启动后记录服务进程 PID,并确认实际监听端口与会话建议端口一致;不一致视为启动失败,修正端口参数重新启动,禁止让服务落回项目默认端口
|
|
104
104
|
4. API 测试脚本(BASE_URL 使用上述端口)
|
|
105
|
-
5. **MUST** 停止服务并清理隔离环境(`docker compose -p <namespace> down`),随后幂等自检:本 change 隔离标识下无残留容器(`docker compose -p <namespace> ps`
|
|
105
|
+
5. **MUST** 停止服务并清理隔离环境(`docker compose -p <namespace> down`),随后幂等自检:本 change 隔离标识下无残留容器(`docker compose -p <namespace> ps` 为空)、本变更记录的服务进程已退出且隔离端口(建议端口)无进程监听;自检中发现无法确认归属本变更的进程(工作目录不在本变更工作目录内)禁止清理,在结果中标注说明
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
以上第 1、2、3、5 条为 MUST:隔离(独立 compose 项目名、隔离数据库、隔离 mock 服务/中间件/扫描分析平台、建议端口、down 清理)是并发安全硬约束,不适用本文件开头「项目规范优先」的推荐豁免。
|
|
109
109
|
|
|
110
110
|
- SQL 在前:先准备数据,再启动应用确保应用启动时读取到完整数据
|
|
111
|
-
- 隔离标识 `<namespace
|
|
111
|
+
- 隔离标识 `<namespace>`、建议端口与本变更工作目录同来自编排会话上下文
|
|
112
112
|
- 隔离对象不限于数据库:除数据库外,mock 服务、消息队列/缓存等中间件、扫描分析平台等其余为本变更启动的环境资源均须按隔离标识隔离;仅隔离数据库不满足并发安全要求
|
|
113
113
|
- 启动服务:按项目构建文件确定的启动方式(mvn / gradle / npm 等),端口用编排会话建议端口
|
|
114
114
|
- API 脚本:BASE_URL 使用上述建议端口,依赖运行中的服务
|
|
@@ -9,12 +9,19 @@ capabilities: ["cleanup"]
|
|
|
9
9
|
|
|
10
10
|
## 停止残留的服务实例
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
停止本次变更启动的服务实例,禁止误杀其他变更或他人启动的进程:
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- 经进程启动的服务:确认归属本变更后停止,按以下顺序判别
|
|
15
15
|
- 经容器编排启动的服务:按本变更的隔离标识停止对应 compose 项目
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
经进程启动的服务按以下顺序确认归属:
|
|
18
|
+
|
|
19
|
+
1. 优先按启动时记录的进程 PID 停止;停止前核对该 PID 对应进程的启动命令或工作目录仍属于本变更(操作系统可能复用已退出进程的 PID),确认后方可停止
|
|
20
|
+
2. 无 PID 记录时,以会话分配的隔离端口(专属本变更)为唯一定位入口:隔离端口无进程占用即视为无本变更服务残留;有占用时查询该进程的工作目录,位于本变更工作目录内(来源:会话分配的隔离上下文,含隔离标识、建议端口、本变更工作目录)方可停止,不在即禁止停止
|
|
21
|
+
3. 禁止按启动命令关键字全局搜索进程作为定位手段(本变更工作区与主仓库的启动命令相同,无法区分归属)
|
|
22
|
+
4. 无法确认归属本变更的进程(含监听在项目默认端口上的进程)一律不停止、不干扰;目标端口被其他进程占用属于本变更启动失败,应修正端口参数重新以隔离方式启动,禁止为腾出端口而停止任何进程
|
|
23
|
+
|
|
24
|
+
停止确认以被停止的进程已退出为准;端口随后被其他进程占用不构成本变更未停止(如用户或他人进程占用同一端口),不得据此二次清理。
|
|
18
25
|
|
|
19
26
|
## 清理隔离环境
|
|
20
27
|
|
|
@@ -40,7 +47,7 @@ capabilities: ["cleanup"]
|
|
|
40
47
|
|
|
41
48
|
清理完成后自检以下各项,全部无残留即通过:
|
|
42
49
|
|
|
43
|
-
-
|
|
50
|
+
- 无残留的服务进程(以本变更启动的进程已退出为准,端口被其他进程占用不构成本变更未停止)
|
|
44
51
|
- 无残留的隔离容器(隔离标识下 compose ps 为空)
|
|
45
52
|
- 无残留的隔离 mock 服务/中间件(按隔离标识查询不存在或容器已移除)
|
|
46
53
|
- 无残留的隔离扫描分析项目(按隔离标识查询不存在)
|
|
@@ -43,7 +43,7 @@ phases:
|
|
|
43
43
|
- "执行边界缺省整个 worktree(独立审查无分析环节,不生成边界白名单);issue 的 file 字段指向的文件即修复边界,修复这些文件(含回归引入问题)不算越界;可按 issue 的 suggestion 直接执行修复;reviewer 的 boundary_expansion 已并入边界"
|
|
44
44
|
- "对修复未过次数≥2 的 issue 须先完成 5-Why 根因分析再动手,不得跳过分析直接改代码"
|
|
45
45
|
- "修复完成后先 git commit 再提交;提交前按已加载的质量门类 skill 完成本地构建验证,并按维度规范类 skill(style/architecture/performance/security/maintainability 能力类别)对本次修复文件逐项自检,自检结论与工具检查结果一并汇总进 self_check_results"
|
|
46
|
-
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree
|
|
46
|
+
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;验证完成后停止本次启动的实例,不留残留,残留判定遵循已加载清理规范的归属判别,无法确认归属本变更的进程一律不清;禁止为腾出端口或资源而停止、复用或干扰非本会话启动的进程"
|
|
47
47
|
- "确定性质量工具检查出的问题不得以压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等)静默规避:确需压制时,必须在压制处代码注释说明清楚理由,并经 exempt_issue_ids 申请豁免由报源 reviewer 裁定;不得以 fixed_issue_ids 冒充修复"
|
|
48
48
|
- "提交 opx_agent_submit:必传 verdict;修复完成的 issue 经 fixed_issue_ids 上报、不可修 issue 经 exempt_issue_ids 申请豁免"
|
|
49
49
|
constraints:
|
|
@@ -42,7 +42,7 @@ phases:
|
|
|
42
42
|
- "执行边界缺省整个 worktree(独立审查无分析环节,不生成边界白名单);issue 的 file 字段指向的文件即修复边界,修复这些文件(含回归引入问题)不算越界;可按 issue 的 suggestion 直接执行修复;reviewer 的 boundary_expansion 已并入边界"
|
|
43
43
|
- "对修复未过次数≥2 的 issue 须先完成 5-Why 根因分析再动手,不得跳过分析直接改代码"
|
|
44
44
|
- "修复完成后先 git commit 再提交;提交前按已加载的质量门类 skill 完成本地构建验证,并按维度规范类 skill(style/architecture/performance/security/maintainability 能力类别)对本次修复文件逐项自检,自检结论与工具检查结果一并汇总进 self_check_results"
|
|
45
|
-
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree
|
|
45
|
+
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;验证完成后停止本次启动的实例,不留残留,残留判定遵循已加载清理规范的归属判别,无法确认归属本变更的进程一律不清;禁止为腾出端口或资源而停止、复用或干扰非本会话启动的进程"
|
|
46
46
|
- "确定性质量工具检查出的问题不得以压制手段(压制注解/注释抑制/规则排除配置/平台状态标注/构建跳过开关等)静默规避:确需压制时,必须在压制处代码注释说明清楚理由,并经 exempt_issue_ids 申请豁免由报源 reviewer 裁定;不得以 fixed_issue_ids 冒充修复"
|
|
47
47
|
- "提交 opx_agent_submit:必传 verdict;修复完成的 issue 经 fixed_issue_ids 上报、不可修 issue 经 exempt_issue_ids 申请豁免"
|
|
48
48
|
constraints:
|
|
@@ -32,7 +32,7 @@ phases:
|
|
|
32
32
|
- "按 Task 项顺序逐个实现,聚焦当前子任务,不超出执行边界"
|
|
33
33
|
- "实施前识别 spec 描述的一并操作行为组(如状态变更与数据入队这类需同时发生的多个行为);实施后逐项自证每个行为真实生效,禁止以单一状态字段的实现替代其他行为"
|
|
34
34
|
- "涉及数据模型或流程产出变更(含字段/实体承载位置搬迁、AI 生成等流程产物)时,自证须包含关键数据产出断言:产出字段已持久化到 spec 指定承载位置且值完整非空、搬迁承接与同一输入产出基线一致(按已加载接口测试规范执行);禁止仅以流程跑通/接口成功替代"
|
|
35
|
-
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;隔离对象不限于数据库——为本变更启动的 mock
|
|
35
|
+
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;隔离对象不限于数据库——为本变更启动的 mock 服务、消息队列/缓存等中间件、扫描分析平台等一切环境资源均须按隔离标识隔离,禁止复用既有实例或共享端口;启动前发现隔离环境有残留时,先按已加载的清理规范幂等清空再启动;残留判定遵循已加载清理规范的归属判别,无法确认归属本变更的进程一律不清"
|
|
36
36
|
- "涉及接口契约或数据口径变更(按已加载的接口测试规范判定)时,实施过程中即时更新/新建与变更接口对应的 `.http` 测试脚本(已有脚本更新为匹配变更后契约,尚无脚本则新建,并同步 SQL 前置数据脚本),按已加载接口测试规范的完整执行顺序(含 SQL 前置数据准备、隔离启动基础设施与服务、执行 `.http` 脚本)执行接口测试,确保变更内容真实有效;执行结果(附执行顺序与覆盖接口清单)经 test_results 参数提交,作为审查者分级复验的事实输入;修复被驳回 issue 后再次提交前同样须执行"
|
|
37
37
|
- "自证完成后停止本次启动的服务/基础设施实例,不留残留"
|
|
38
38
|
- "环境/基础设施问题(schema 缺失、DDL 未执行、依赖未安装)应通过 migration/初始化脚本等代码层面解决;仅生产级凭据、真实第三方资源、人工运维才走 blocker/豁免"
|
|
@@ -62,7 +62,7 @@ phases:
|
|
|
62
62
|
- "按 Task 项顺序逐个实现,聚焦当前子任务,不超出执行边界"
|
|
63
63
|
- "实施前识别 spec 描述的一并操作行为组(如状态变更与数据入队这类需同时发生的多个行为);实施后逐项自证每个行为真实生效,禁止以单一状态字段的实现替代其他行为"
|
|
64
64
|
- "涉及数据模型或流程产出变更(含字段/实体承载位置搬迁、AI 生成等流程产物)时,自证须包含关键数据产出断言:产出字段已持久化到 spec 指定承载位置且值完整非空、搬迁承接与同一输入产出基线一致(按已加载接口测试规范执行);禁止仅以流程跑通/接口成功替代"
|
|
65
|
-
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;隔离对象不限于数据库——为本变更启动的 mock
|
|
65
|
+
- "自证/验证需启动服务或基础设施时,一律按已加载技术栈 skill 的隔离启动规范以隔离方式启动,隔离标识与建议端口以视图 Worktree 区块为准;隔离对象不限于数据库——为本变更启动的 mock 服务、消息队列/缓存等中间件、扫描分析平台等一切环境资源均须按隔离标识隔离,禁止复用既有实例或共享端口;启动前发现隔离环境有残留时,先按已加载的清理规范幂等清空再启动;残留判定遵循已加载清理规范的归属判别,无法确认归属本变更的进程一律不清"
|
|
66
66
|
- "涉及接口契约或数据口径变更(按已加载的接口测试规范判定)时,实施过程中即时更新/新建与变更接口对应的 `.http` 测试脚本(已有脚本更新为匹配变更后契约,尚无脚本则新建,并同步 SQL 前置数据脚本),按已加载接口测试规范的完整执行顺序(含 SQL 前置数据准备、隔离启动基础设施与服务、执行 `.http` 脚本)执行接口测试,确保变更内容真实有效;执行结果(附执行顺序与覆盖接口清单)经 test_results 参数提交;修复被驳回 issue 后再次提交前同样须执行"
|
|
67
67
|
- "自证完成后停止本次启动的服务/基础设施实例,不留残留"
|
|
68
68
|
- "环境/基础设施问题(schema 缺失、DDL 未执行、依赖未安装)应通过 migration/初始化脚本等代码层面解决;仅生产级凭据、真实第三方资源、人工运维才走 blocker/豁免"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifrankwang/openspec-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.140.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",
|
|
@@ -1322,8 +1322,9 @@ async function completeTaskGroupLocked(params: { change_id: string }, ctx: ToolC
|
|
|
1322
1322
|
// 非最后任务组:门禁 → 勾选 → scope_end → completed_at;无合并、无销毁
|
|
1323
1323
|
item.metadata["completed_at"] = new Date().toISOString()
|
|
1324
1324
|
await writeState(ctx.worktree, state)
|
|
1325
|
+
// 取消限制事实说明与终态视图非最后组文案同措辞(cancelTaskGroupNote)
|
|
1325
1326
|
const doneMessage =
|
|
1326
|
-
|
|
1327
|
+
`任务组已完成。本任务组变更保留在 change 分支上,待全部任务组完成后统一收口合并(本次不合并、不销毁 worktree)。若某任务组已确认不再执行,当前版本不支持取消任务组,须人工编辑编排 state 文件(openspec/states/${state.changeId}.json)将该任务组的 phase 改为 "cancelled",收口合并才会触发。`
|
|
1327
1328
|
return checkboxWarning ? `${doneMessage}\n${checkboxWarning}` : doneMessage
|
|
1328
1329
|
}
|
|
1329
1330
|
|
|
@@ -32,9 +32,10 @@ export function isTerminalPhase(phase: WorkItemPhase): boolean {
|
|
|
32
32
|
return phase === "done" || phase === "cancelled"
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/** 任务组「终态或从未激活」(mode
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
/** 任务组「终态或从未激活」(mode 切换窗口专用判定):done 或 completed_at 已设置即终态;
|
|
36
|
+
* 否则须无执行痕迹(tags 为空)且全部 task children 处于 todo 或终态。
|
|
37
|
+
* 「从未激活」计入收口仅对窗口场景正确(未开工组无进度,切走不丢东西);收口合并判定
|
|
38
|
+
* 不得复用此口径(见 isFinalTaskGroup)。 */
|
|
38
39
|
export function isTaskGroupSettled(item: WorkItem): boolean {
|
|
39
40
|
if (item.phase === "done" || item.metadata["completed_at"] !== undefined) return true
|
|
40
41
|
const noTags = Object.keys(item.tags).length === 0
|
|
@@ -44,12 +45,14 @@ export function isTaskGroupSettled(item: WorkItem): boolean {
|
|
|
44
45
|
return noTags && childrenSettled
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
/** 判断 item 是否为其 change
|
|
48
|
-
*
|
|
48
|
+
/** 判断 item 是否为其 change 的最后一个收口任务组:其余全部任务组均终态(done 或
|
|
49
|
+
* completed_at 已设置)。「从未激活」不计入收口——串行编排下未开工组无任何进度痕迹,
|
|
50
|
+
* 若计入会令首个完成组被误判为最后组而提前合并销毁。complete 的 change 级收口判定与
|
|
51
|
+
* 终态视图文案分流/部署注意区块门禁共用此判定(单一事实源)。 */
|
|
49
52
|
export function isFinalTaskGroup(state: { workItems: WorkItem[] }, item: WorkItem): boolean {
|
|
50
53
|
return state.workItems
|
|
51
54
|
.filter((w) => w.id.startsWith("task:") && w.id !== item.id)
|
|
52
|
-
.every(
|
|
55
|
+
.every((w) => isTerminalPhase(w.phase) || w.metadata["completed_at"] !== undefined)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
export function isBlockingSeverity(severity: string | undefined): boolean {
|
|
@@ -6,7 +6,7 @@ import type { ExemptionRecord } from "../exemptions.ts"
|
|
|
6
6
|
import type { LoadedWorkflow } from "./loader.ts"
|
|
7
7
|
import type { EngineRecommendation } from "./engine.ts"
|
|
8
8
|
import type { DetectChangesResult } from "../git.ts"
|
|
9
|
-
import { getStepVerdict, isTerminalPhase, isBlockingSeverity,
|
|
9
|
+
import { getStepVerdict, isTerminalPhase, isBlockingSeverity, isFinalTaskGroup, phaseStepMismatch, REVIEW_STEP_TO_LAYER, blockingStepChildren } from "./engine.ts"
|
|
10
10
|
import { agentToReviewDimension, agentToReviewLayer, readIssueSource } from "../constants.ts"
|
|
11
11
|
import { resolveChildIssueFields } from "./reset.ts"
|
|
12
12
|
import { taskListOf, issueChildrenOf } from "../task-children.ts"
|
|
@@ -204,9 +204,9 @@ function renderTerminalPhase(item: WorkItem, state?: OrchestrateState, caller?:
|
|
|
204
204
|
"",
|
|
205
205
|
finalGroup
|
|
206
206
|
? "本任务组为最后一个收口任务组,change 收口已完成:变更分支已合并回基准分支,编排已完成并收尾。"
|
|
207
|
-
:
|
|
207
|
+
: `本任务组已完成,变更保留在 change 分支上,待全部任务组完成后统一收口合并。${cancelTaskGroupNote(state)}`,
|
|
208
208
|
"",
|
|
209
|
-
...renderDeploymentNotesSection(state, caller),
|
|
209
|
+
...renderDeploymentNotesSection(state, item, caller),
|
|
210
210
|
].join("\n")
|
|
211
211
|
}
|
|
212
212
|
return [
|
|
@@ -217,18 +217,25 @@ function renderTerminalPhase(item: WorkItem, state?: OrchestrateState, caller?:
|
|
|
217
217
|
? "调用 `opx_orch_complete_task_group` 完成 change 收口(把变更分支合并回基准分支并清理)。"
|
|
218
218
|
: "调用 `opx_orch_complete_task_group` 完成任务组收尾(变更保留在 change 分支,统一收口时合并)。",
|
|
219
219
|
"",
|
|
220
|
-
...renderDeploymentNotesSection(state, caller),
|
|
220
|
+
...renderDeploymentNotesSection(state, item, caller),
|
|
221
221
|
].join("\n")
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/** 非最后组收口文案的取消限制事实说明(与 complete 非最后组返回体同措辞):当前版本无取消任务组
|
|
225
|
+
* 的工具入口,弃做组须人工置 cancelled 后收口合并才会触发。无 state(理论不可达)返回空串。 */
|
|
226
|
+
function cancelTaskGroupNote(state: OrchestrateState | undefined): string {
|
|
227
|
+
if (!state) return ""
|
|
228
|
+
return `若某任务组已确认不再执行,当前版本不支持取消任务组,须人工编辑编排 state 文件(openspec/states/${state.changeId}.json)将该任务组的 phase 改为 "cancelled",收口合并才会触发。`
|
|
229
|
+
}
|
|
230
|
+
|
|
224
231
|
/** 终态视图的「部署注意事项」区块(仅编排视角、change 会话渲染):指引编排者读主仓库规划文档提取
|
|
225
232
|
* 部署要点,并聚合各任务组 self_check_results 申报的「部署注意点:」前缀行(实施补充点,编排者纯转述)。
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
function renderDeploymentNotesSection(state: OrchestrateState | undefined, caller: StatusViewCaller | undefined): string[] {
|
|
233
|
+
* 渲染前提:当前组为最后一个收口任务组(isFinalTaskGroup,其余组均终态且渲染到终态时当前组必已
|
|
234
|
+
* 终态),尚有未收口组时不渲染(两形态维持既有文案)。全部组无实施补充点时省略补充点段(不渲染空段)。 */
|
|
235
|
+
function renderDeploymentNotesSection(state: OrchestrateState | undefined, item: WorkItem, caller: StatusViewCaller | undefined): string[] {
|
|
229
236
|
if (!caller?.orchestrator || !state || state.kind === "review") return []
|
|
237
|
+
if (!isFinalTaskGroup(state, item)) return []
|
|
230
238
|
const taskGroups = state.workItems.filter((w) => w.id.startsWith("task:"))
|
|
231
|
-
if (!taskGroups.every(isTaskGroupSettled)) return []
|
|
232
239
|
const lines = [
|
|
233
240
|
"## 部署注意事项汇报",
|
|
234
241
|
"",
|