@tea-agent/loop-agent 0.22.0 → 0.23.1
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.md +42 -108
- package/CHANGELOG.md +68 -0
- package/README.md +7 -4
- package/dist/application/context-usage/skill-resolution-stats.js +263 -0
- package/dist/application/dag/generate-task-dag.js +17 -3
- package/dist/cli/command-definitions.js +8 -7
- package/dist/cli/program.js +17 -15
- package/dist/commands/doctor.js +269 -18
- package/dist/commands/init.js +101 -86
- package/dist/commands/stats.js +40 -11
- package/dist/shared/operator/capabilities.js +11 -1
- package/dist/worker/console/app-data.js +4 -0
- package/dist/worker/console/chat/instruction-skills.js +217 -0
- package/dist/worker/console/chat/model-resolver.js +106 -0
- package/dist/worker/console/chat/pi-runtime.js +605 -0
- package/dist/worker/console/chat/resource-loader.js +66 -0
- package/dist/worker/console/chat/routes.js +357 -0
- package/dist/worker/console/chat/session-store.js +238 -0
- package/dist/worker/console/chat/tool-adapter.js +238 -0
- package/dist/worker/console/chat/tools.js +171 -0
- package/dist/worker/console/server.js +55 -0
- package/dist/worker/console/static/assets/index-DVl7Jxt5.js +25 -0
- package/dist/worker/console/static/assets/index-lVcIr9Ju.css +1 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/feature/profile-schema.js +1 -1
- package/dist/workflows/dag/init-hybrid.js +69 -21
- package/dist/workflows/dag/node-execution.js +38 -1
- package/dist/workflows/dag/output-protocol.js +89 -0
- package/dist/workflows/dag/prompt.js +35 -1
- package/dist/workflows/dag/recovery-recommendation.js +45 -0
- package/dist/workflows/dag/report.js +28 -1
- package/dist/workflows/dag/rerun-task.js +1 -1
- package/dist/workflows/dag/scheduler.js +9 -0
- package/dist/workflows/dag/types.js +12 -0
- package/dist/workflows/dag/validate.js +55 -0
- package/docs/README.md +73 -156
- package/docs/architecture/README.md +3 -2
- package/docs/architecture/dag-execution.md +2 -2
- package/docs/architecture/evolution.md +14 -12
- package/docs/architecture/system-overview.md +1 -1
- package/docs/architecture/worker-and-feature.md +3 -3
- package/docs/governance/README.md +15 -0
- package/docs/{harness-methodology-debugging.md → governance/harness-methodology-debugging.md} +27 -3
- package/docs/init-surface.manifest.json +22 -4
- package/docs/operations/README.md +12 -0
- package/docs/{local-development-environment.md → operations/local-development-environment.md} +1 -1
- package/docs/skills/vetted-skill-registry.md +23 -3
- package/docs/templates/README.md +55 -0
- package/docs/templates/evaluation/agents-map-slim-v1.candidate.json +9 -0
- package/docs/templates/evaluation/agents-map-slim-v1.md +87 -0
- package/docs/templates/evaluation/agents-map-verbose-v0.candidate.json +9 -0
- package/docs/templates/evaluation/agents-map-verbose-v0.md +153 -0
- package/docs/templates/hybrid-dag.json +1 -1
- package/docs/templates/progress-log.md +9 -2
- package/harness.json +5 -5
- package/package.json +5 -5
- package/scripts/kb-bootstrap-init-skeleton.sh +2 -2
- package/skills/agent-worker/SKILL.md +1 -1
- package/skills/grill-with-docs/SKILL.md +44 -52
- package/skills/grill-with-docs/adr-format.md +37 -26
- package/skills/grill-with-docs/context-format.md +18 -26
- package/skills/loop-agent/SKILL.md +28 -112
- package/skills/loop-agent/references/command-reference.md +9 -3
- package/skills/loop-agent/references/harness-policy.md +3 -3
- package/skills/loop-agent/references/hybrid-dag.md +1 -1
- package/skills/loop-agent/references/orchestrator-and-interventions.md +1 -1
- package/skills/loop-agent/references/task-workflow.md +2 -0
- package/skills/systematic-debugging/SKILL.md +20 -4
- package/skills/test-driven-development/SKILL.md +10 -3
- package/dist/worker/console/static/assets/index-CUDke82y.js +0 -18
- package/dist/worker/console/static/assets/index-wSEksVSO.css +0 -1
- /package/docs/{harness-methodology-tdd.md → governance/harness-methodology-tdd.md} +0 -0
- /package/docs/{harness-methodology-verification.md → governance/harness-methodology-verification.md} +0 -0
package/AGENTS.md
CHANGED
|
@@ -14,140 +14,74 @@
|
|
|
14
14
|
|
|
15
15
|
- 仓库是记录系统:决策、契约、计划、测试、报告优先落到仓库,而不是停留在聊天里。
|
|
16
16
|
- 一次只推进一个清晰工作块;主会话按 Orient → Select → Contract → Implement → Verify → Handoff 治理,runtime 真实流程以 `src/workflows/` 为准。
|
|
17
|
-
-
|
|
17
|
+
- 先验证基线,再叠加改动;完成定义必须可验证,不能靠删测试、降标准或模糊描述制造“完成”。
|
|
18
18
|
- Do not consider backward compatibility. Ignore legacy code/libraries.
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
- 除非用户明确要求,不要自行引入外部 SDD、spec-first、brainstorming 等方法论的强制设计文档、审批门或专用目录;本仓库的工作流程以本文件和 `docs/` 中的治理规则为准。
|
|
30
|
-
- 对非微小的实现或修复,`exec-plan` 只负责记录 Contract、进度和验证证据,不能替代 Agent DAG。除非用户明确要求 one-shot,或在计划中记录了适用的 escape hatch 与理由,否则在改动实现文件前必须完成 `new-task`、结构化 `allowedPaths` / `forbiddenPaths`、`dag run-task` 和 `dag validate`;随后按已校验的 DAG 执行并审查 writer `writeSet`。
|
|
31
|
-
- 禁止占位实现;除非 contract 明确约定为脚手架且标出后续闭环。
|
|
19
|
+
- 搜索先于实现;受治理 Agent runtime 只有 Pi(`implement-pi` / `repair-pi`);`cursor-prompt` 仅为显式手工 one-shot sidecar。
|
|
20
|
+
- DAG 标准路径:Contract → Scout → Plan → Implement → Verify → Closeout/Handoff。
|
|
21
|
+
- 机器校验契约真源:`docs/init-surface.manifest.json`、`docs/architecture/runtime-boundaries.md`、`src/cli/command-definitions.ts`、`skills/loop-agent/`、`scripts/check-*.sh`;本文件只指路。
|
|
22
|
+
- 本仓库既是源项目也是 init 默认模板;新增能力必须判断 npm 内置 vs `loop-agent init` 投影。
|
|
23
|
+
- 委托写入前必须结构化 `task.json.allowedPaths` / `forbiddenPaths`,并审查 DAG writer `writeSet`。
|
|
24
|
+
- Shell 搜索优先 `rg`,按名找文件优先 `fd`;脚本用 Git Bash / 兼容 Bash。
|
|
25
|
+
- 用 loop-agent 迭代本仓库时,控制器必须来自已发布 npm 包(记录实际版本);启动后不要中途升级;不要用工作区 `npm link` / `npm run dev` 控制可能改 CLI/runtime/package 的任务。
|
|
26
|
+
- 反复出现的约束固化为文档、脚本、检查、测试或模板;禁止占位实现(除非 contract 标明脚手架)。
|
|
27
|
+
- 非微小实现:`exec-plan` 不能替代 Agent DAG;除非用户要求 one-shot 或计划记录 escape hatch,否则改实现前完成 `new-task`、结构化路径、`dag run-task`、`dag validate` 与 writeSet 审查。
|
|
28
|
+
- 不要自行引入外部 SDD/spec-first 等强制平行治理树;以本文件与 `docs/` 为准(ADR 0006)。
|
|
32
29
|
|
|
33
30
|
## 开始顺序
|
|
34
31
|
|
|
35
32
|
改文件前必须先完成:
|
|
36
33
|
|
|
37
|
-
1.
|
|
38
|
-
2.
|
|
39
|
-
3.
|
|
40
|
-
4.
|
|
41
|
-
5.
|
|
42
|
-
6.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- `docs/verification-matrix.md`
|
|
46
|
-
7. 如果任务涉及命令入口、执行流程、executor、初始化投影、skills、脚本矩阵、发布包范围或治理检查,继续阅读:
|
|
47
|
-
- `docs/architecture/runtime-boundaries.md`
|
|
48
|
-
- `docs/loop-agent-harness.md`
|
|
49
|
-
8. 如果任务涉及测试纪律、验证声明或调试,继续阅读:
|
|
50
|
-
- `docs/harness-methodology-tdd.md`
|
|
51
|
-
- `docs/harness-methodology-verification.md`
|
|
52
|
-
- `docs/harness-methodology-debugging.md`
|
|
53
|
-
9. 查看最近提交、相关执行计划、progress/report,确认当前上下文。
|
|
54
|
-
10. 检查 `git status --short --branch`。
|
|
55
|
-
11. 运行本次任务相关的最小基线验证。
|
|
56
|
-
12. 如果用户提到"后端测试"、"接口测试"、"pytest"、"自动化测试",在任务 `task.json` 中设置 `taskKind: "backend-test"` 再 `dag run-task`;不要用 `--profile backend-test`(CLI 不接受该值,专用模板只走 taskKind)。知识回写用 `taskKind: "knowledge-sync"`(须 `featureId`),图谱开荒用 `taskKind: "knowledge-graph-bootstrap"`。`--profile` 仅表示治理强度:`auto|minimal|standard|reviewed|supervised`。
|
|
57
|
-
13. 如果用户提到"看板"、"observe"、"监控面板"、"启动看板",使用 `agent-worker console serve --repo . --port 8790` 启动统一 Operator Console;`/inspect/` 提供只读检视。`agent-worker observe serve --repo . --port 8787` 仅为兼容入口。
|
|
58
|
-
14. 如果用户要求“合并 `<source>` 到 `<target>`”或“合并 origin/main 到当前分支”,先阅读 `docs/branch-merge-guideline.md`,按影响自动选择快速、标准或深度模式;始终冻结 source SHA、审查双方功能、运行 merge-tree、生成 source-SHA 合并报告,并在提交前再次 fetch 防止主干前进。
|
|
34
|
+
1. `pwd` → 读 `README.md`、`harness.json`、`docs/README.md`;有 `CONTEXT.md` 则读术语表。
|
|
35
|
+
2. 实现类工作继续读:`docs/governance/development-principles.md`、`docs/governance/feature-workflow.md`、`docs/governance/verification-matrix.md`。
|
|
36
|
+
3. 涉及命令/executor/init/skills/发布包/治理检查时继续读:`docs/architecture/runtime-boundaries.md`、`docs/runtime/loop-agent-harness.md`。
|
|
37
|
+
4. 涉及测试纪律/验证声明/调试时继续读:`docs/governance/harness-methodology-*.md`。
|
|
38
|
+
5. 查看最近提交、相关 plan/progress/report;`git status --short --branch`;跑最小基线验证。
|
|
39
|
+
6. 后端/接口/pytest → `taskKind: "backend-test"`(不是 `--profile`);知识回写 `knowledge-sync`;图谱开荒 `knowledge-graph-bootstrap`。`--profile` 仅 `auto|minimal|standard|reviewed|supervised`。
|
|
40
|
+
7. 看板/observe → `agent-worker console serve --repo . --port 8790`(`/inspect/` 只读);`observe serve` 仅为兼容入口。
|
|
41
|
+
8. 分支合并 → 先读 `docs/operations/branch-merge-guideline.md`。
|
|
59
42
|
|
|
60
43
|
## 会话协议
|
|
61
44
|
|
|
62
|
-
1. Orient
|
|
63
|
-
2. Select:只选一个清晰工作块;避免把重构、新功能、文档迁移混在一轮里。
|
|
64
|
-
3. Contract:写清本轮交付物、非目标、完成标准、验证方法和失败条件。
|
|
65
|
-
4. Implement:做最小增量实现,同步维护必要文档、脚本和测试。
|
|
66
|
-
5. Verify:优先跑快速反馈,再跑必要的真实路径验证。
|
|
67
|
-
6. Converge Docs:检查 README、AGENTS.md、CHANGELOG.md、docs/README.md、相关治理文档、skills references、website docs、初始化模板和脚本说明是否仍与实际行为一致;只更新与本次变更相关的内容,不做顺手文档迁移。
|
|
68
|
-
7. Handoff:更新 progress/report/plan 中有长期价值的信息,写清风险、剩余项和下一步。
|
|
45
|
+
1. Orient → 2. Select(一块)→ 3. Contract → 4. Implement → 5. Verify → 6. Converge Docs → 7. Handoff。
|
|
69
46
|
|
|
70
|
-
|
|
47
|
+
这不是 DAG 节点序列。复杂实现默认 Agent DAG;主 agent 拆任务、写 contract、结构化路径、审查 DAG/writeSet/profile/shell verification。微小任务可用 one-shot escape hatch 并记录边界与验证证据。
|
|
71
48
|
|
|
72
49
|
## 项目地图
|
|
73
50
|
|
|
74
|
-
- `CONTEXT.md
|
|
75
|
-
- `src/`:loop-agent
|
|
76
|
-
- `
|
|
77
|
-
-
|
|
78
|
-
- `
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
- 保留无关的用户改动,不要回退自己没有做的修改。
|
|
88
|
-
- 优先沿用现有 helper、目录边界和局部模式,再考虑新增抽象。
|
|
89
|
-
- 长期决策写入 `docs/`,不要只留在聊天里。
|
|
90
|
-
- 分支合并遵循 `docs/branch-merge-guideline.md`;快速模式只用于可证明的低风险/no-op 合并,涉及冲突、init/package/runtime/release/public API 时必须升级为标准或深度模式。
|
|
91
|
-
- 后端测试、接口/API 测试、pytest 或明确的后端自动化测试,必须把 `.harness/tasks/<task-id>/task.json` 的 `taskKind` 设置为 `"backend-test"`,不得保留默认 `standard`。`backend-test` 是 `taskKind`,不是 `--profile` 的可选值;`dag run-task` 继续使用 `--profile auto` 选择治理等级。仅说“自动化测试”且前后端不明时,先根据任务源和项目技术栈判断,禁止无条件路由。
|
|
92
|
-
- 本地 Operator Console:`agent-worker console serve --repo . --port 8790`,访问 `http://127.0.0.1:8790/`;其中 `/inspect/` 为只读运行检视。默认绑定本机 `127.0.0.1`;可用 `--host 0.0.0.0` / `--debug`,不要直接暴露到公开网络。
|
|
93
|
-
- 面向使用者的新增、修改、删除或修复,应同步更新根目录 `CHANGELOG.md`;保持版本级摘要即可,不写过细技术细节。
|
|
94
|
-
- 面向用户的中文更新日志、README 和说明文档应使用自然、结果导向的表达:先说明用户能获得什么或问题如何改善,保留必要的命令和产品术语,避免逐字翻译、内部实现细节和无意义的中英混杂。
|
|
95
|
-
- 涉及 `loop-agent init` 或目标项目投影的改动,必须同步考虑目标项目生成物:`AGENTS.md`、`README.md`、`harness.json`、`ai_workspace/loop-agent/`、`scripts/`、`.agents/skills/`、`.harness/prompts`、`.gitignore`(loop-agent runtime managed block)和 npm 包内置 assets;目标项目根 `docs/` 和根 `skills/` 的旧投影需要由 `init update --apply-safe` 安全迁移或退役。
|
|
96
|
-
- 涉及初始化能力演化时,按 `docs/init-surface.manifest.json` 与 `scripts/check-init-evolution-needed.sh` 分级处理:小改 advisory,中等 surface-check,高影响才需要模型审查;不要把所有小改动升级成重流程。
|
|
97
|
-
- 通用脚本、skill 和模板可以复制或投影;项目相关 README、验证命令、发布/维护脚本必须基于模板和目标项目真实文件生成,不假定目标项目是 TypeScript、Node、前端、后端或工具项目。
|
|
98
|
-
- 涉及 CLI command、skill entry、runtime boundary、import 方向或发布包范围时,同步更新对应文档、catalog/definition、治理脚本和测试,避免 README、skill reference、CLI help、npm 包内容互相漂移。
|
|
99
|
-
- 完成相关更新后必须做文档收敛:如果 README、AGENTS.md、CHANGELOG.md、docs、skills、website、初始化生成模板或脚本说明不需要更新,应在交接里写明理由。
|
|
100
|
-
- 不提交占位实现。
|
|
101
|
-
- 没有新鲜验证证据时,不声明工作完成。
|
|
102
|
-
- 发现新 bug、技术债或契约漂移时,写回当前 plan、progress 或 report,而不是只在对话里提一句。
|
|
103
|
-
- 涉及 harness 流程变化时,优先把变化落到 `harness.json`、模板、脚本或治理文档,而不是只改提示词。
|
|
51
|
+
- `CONTEXT.md`:术语表
|
|
52
|
+
- `src/`:运行时;`test/`:Vitest;`bin/loop-agent.js`:CLI
|
|
53
|
+
- `skills/`:源仓库/npm 内置 skills;目标项目只生成 `.agents/skills/`
|
|
54
|
+
- `.harness/`:运行态(tasks/dag-runs/runs 等;init 会 gitignore 运行事实,保留 prompts 与占位)
|
|
55
|
+
- `docs/`:治理;`website/`:用户文档站;`scripts/`:检查与 CI
|
|
56
|
+
|
|
57
|
+
## 工作规则(增量约束)
|
|
58
|
+
|
|
59
|
+
- 保留无关用户改动;优先沿用现有 helper/目录边界。
|
|
60
|
+
- 长期决策写入 `docs/`;面向用户变更更新 `CHANGELOG.md`(结果导向中文)。
|
|
61
|
+
- init/投影变更必须同步目标项目生成物与 package assets;init evolution 按 `docs/init-surface.manifest.json` 分级。
|
|
62
|
+
- CLI/skill entry/runtime boundary/发布包变更同步 catalog、脚本与测试。
|
|
63
|
+
- 没有新鲜验证证据时不声明完成;新债写入 plan/progress/report。
|
|
104
64
|
|
|
105
65
|
## 验证
|
|
106
66
|
|
|
107
|
-
|
|
67
|
+
权威源:`docs/governance/verification-matrix.md`。常用:
|
|
108
68
|
|
|
109
69
|
```bash
|
|
110
|
-
npm run typecheck
|
|
111
|
-
npm test
|
|
112
|
-
npm run build
|
|
70
|
+
npm run typecheck && npm test && npm run build
|
|
113
71
|
node bin/loop-agent.js --help
|
|
114
72
|
bash scripts/check-repo.sh
|
|
115
73
|
bash scripts/ci.sh
|
|
116
74
|
```
|
|
117
75
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
文档站相关变更还需要按范围运行:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
npm run docs:build
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
按变更类型补充定向验证:
|
|
127
|
-
|
|
128
|
-
- 初始化能力或目标项目投影:运行 `test/init-command.test.ts`,并在临时目标项目执行 `loop-agent init --profile full --merge`、`loop-agent init doctor`、`loop-agent inspect`、`loop-agent docs audit` 和目标项目 `bash scripts/check-repo.sh`。
|
|
129
|
-
- init surface 或初始化能力演化:运行 `bash scripts/check-init-evolution-needed.sh` 和 `bash scripts/check-init-surface.sh`;高影响或发布前按需使用 `--strict` 并参考 `skills/init-capability-evolution/` 与 `docs/templates/init-evolution-review.md`。
|
|
130
|
-
- runtime boundary / command registry / skill entry:运行 `bash scripts/check-architecture-boundaries.sh`、`bash scripts/check-command-registry-drift.sh`、`bash scripts/check-skill-entry.sh`,并确保 `bash scripts/check-repo.sh` 覆盖这些检查。
|
|
131
|
-
- 发布包范围:运行 `npm run build`、`node bin/loop-agent.js --help` 和 `npm pack --dry-run`,确认初始化所需静态资料在 package files 中。
|
|
76
|
+
文档站变更:`npm run docs:build`。init / architecture / skill entry / pack 定向验证见 verification-matrix。
|
|
132
77
|
|
|
133
78
|
## 交接
|
|
134
79
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- 改了什么
|
|
138
|
-
- 为什么这样改
|
|
139
|
-
- 执行过哪些验证命令以及结果
|
|
140
|
-
- 是否影响契约、文档、测试或脚本
|
|
141
|
-
- 剩余风险
|
|
142
|
-
- 后续工作
|
|
80
|
+
记录:改了什么、为什么、验证命令与结果、契约/文档/测试影响、剩余风险、后续工作。
|
|
143
81
|
|
|
144
82
|
## 禁止事项
|
|
145
83
|
|
|
146
|
-
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
- 不要假设系统没有某个能力;先搜索再判断。
|
|
151
|
-
- 不要用 stub、假数据通路或注释承诺替代真正交付。
|
|
152
|
-
- 不要把个人机器的绝对路径写入仓库级 `AGENTS.md`、README、模板或发布包资料;个人工具配置应留在用户级配置或本机会话上下文。
|
|
153
|
-
- 不要只更新 loop-agent 本仓库体验而遗漏目标项目初始化体验;新增能力如果不能通过 npm 内置资料或 `loop-agent init` 到达目标项目,必须写清原因和替代入口。
|
|
84
|
+
- 未读相关文档就大改;一次混合无关重构/新功能/文档大迁移。
|
|
85
|
+
- 把对话约束当长期知识;缺验证宣称完成;假设系统没有某能力(先搜索)。
|
|
86
|
+
- stub/假数据通路替代交付;把本机绝对路径写入仓库级 AGENTS/README/模板/发布包。
|
|
87
|
+
- 只更新本仓库体验而遗漏目标项目 init 体验。
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,74 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.23.1] - 2026-07-26
|
|
6
|
+
|
|
7
|
+
### 重点更新
|
|
8
|
+
|
|
9
|
+
- **Console Phase 4 — General Operator Chat**:在 `agent-worker console` 内交付 Pi 驱动的自由对话入口,用自然语言多轮编排 loop-agent / agent-worker;暴露全部 operator action(registry 动态派生)+ 内置探查工具 bash/read/grep/find/ls,仍禁文件写入 coding tool;含两轮代码审查的 P1 修复(builtin tool 注册、schema↔dispatcher 契约、server 生命周期、tool policy 统一)与 followup 修复(缩进、SSE 错误兜底、文档同步、waitForIdle 超时+心跳)
|
|
10
|
+
- DAG 新增显式 failure-aware 依赖语义,允许只读恢复节点容忍上游 ERROR 并读取失败证据执行收敛
|
|
11
|
+
- review verdict 协议重试耗尽后支持确定性规范化,缺失或冲突时仍严格报错
|
|
12
|
+
- 新增 recovery recommendation 稳定下一步分类,为各类失败提供明确的修复或重试路由提示
|
|
13
|
+
- loop-agent doctor 新增机器可读 JSON 报告与只读上下文审计能力
|
|
14
|
+
- loop-agent stats context 提供近端 DAG 运行的上下文用量只读聚合统计
|
|
15
|
+
- AGENTS.md 与 init managed block 采用感知源码的精简策略,保留路由与硬约束不变
|
|
16
|
+
- 全面深化文档治理体系,引入目录状态语义、审查策略与外部方法论单轨融入
|
|
17
|
+
|
|
18
|
+
### 新增
|
|
19
|
+
|
|
20
|
+
- **Console Phase 4 — General Operator Chat(Pi SDK services 模式)**:
|
|
21
|
+
- 后端 `src/worker/console/chat/`:`pi-runtime.ts`(services 模式 SDK 包装 + session 隔离 + 显式注册 builtin 探查工具 `tools:[bash,read,grep,find,ls]`)、`tool-adapter.ts`(operator action → Pi tool schema,动态发现 fail-closed)、`session-store.ts`(Gate 3 per-call 授权 + per-session write chain)、`routes.ts`(SSE 流式 HTTP)、`tools.ts`(全 operator action 动态派生白名单)、`resource-loader.ts`(封闭 ResourceLoader)、`model-resolver.ts`(harness.json 动态解析,无硬编码)、`instruction-skills.ts`(9 个只读 skill 白名单)
|
|
22
|
+
- 前端 `OperatorChat.tsx` + `ChatMarkdown.tsx`:多行 composer、Markdown 气泡、可折叠工具侧栏、停止生成、智能贴底滚动;零依赖 Markdown 渲染
|
|
23
|
+
- 默认模型从 `harness.json executors.pi.MED` 动态解析,按「bare-id 优先 + 有凭证优先」选取 provider(无硬编码回退)
|
|
24
|
+
- 红队验证 V12/V14/V15/V16:文件写入 coding tool 必拒、credential 不回传、高风险 action 无 prepared receipt 必失败、模型伪报 complete 不覆盖 deterministic validation
|
|
25
|
+
- DAG 显式 failureAwareDependsOn 依赖语义,支持只读恢复等价节点显式声明容忍指定上游节点的 ERROR
|
|
26
|
+
- review verdict 协议重试耗尽后的确定性规范化:当恰好存在一个合法受支持且无冲突的 verdict 行时自动规范化为首行
|
|
27
|
+
- recovery recommendation 稳定下一步分类:为 nonzero-exit、protocol-invalid 等各类失败提供稳定的 repair/revision/retry 路由提示
|
|
28
|
+
- loop-agent doctor --json 输出单一可 JSON.parse 的 typed DoctorReport,供人与机器共享同一事实源
|
|
29
|
+
- loop-agent doctor --context 提供只读上下文审计,报告默认策略、技能清单与预算跳过情况
|
|
30
|
+
- loop-agent stats context [--last N] [--json] 只读聚合最近 DAG 运行的技能解析与节点结果
|
|
31
|
+
- 新增 scripts/eval-dogfood-context-engineering-ab.sh,支持复现演练 AGENTS map verbose→slim A/B 协议
|
|
32
|
+
- skill registry 增加 verification placement taxonomy(standalone/embedded/chained/PR-bound)创作词汇
|
|
33
|
+
- 新增 docs/architecture/agents-invariants.md 作为源 AGENTS 与 managed block 不变量合同的单一真源
|
|
34
|
+
- 新增 docs/templates/README.md 并纳入 package / full init / init check-update 面
|
|
35
|
+
- 新增文档治理任务式 README、机器可读 document-catalog.json 与 check-doc-governance.mjs 语义检查器
|
|
36
|
+
- 新增文档审查策略与三档 reviewTier freshness 策略,支持按 UTC 日期边界阻断过期文档
|
|
37
|
+
- 新增设计原则与范式转移起源文章,并发布到网站实践文档
|
|
38
|
+
|
|
39
|
+
### 改进
|
|
40
|
+
|
|
41
|
+
- supervised 模板的 process-supervisor-pi 可显式消费 soft-verify-shell 的 ERROR,使失败进入有界修复收敛链
|
|
42
|
+
- supervised 中间验证未显式配置时不再继承 verifyQuota: full,默认只取配额 1
|
|
43
|
+
- 生成 DAG 的验证命令默认单命令超时由 5 分钟提升为 30 分钟,避免全量测试误判为超时
|
|
44
|
+
- failure-aware 节点可在 upstream_context 中读取被容忍上游 ERROR 的 stdout/stderr 等作为失败证据
|
|
45
|
+
- loop-agent public skill 增加默认预算完整性回归,确保关键 entry 与 required references 在默认预算下完整解析
|
|
46
|
+
- skills/loop-agent/SKILL.md 将 command-reference.md 从 required 调整为按需 reference,保持在默认预算内
|
|
47
|
+
- doctor 与 stats context 的 JSON 模式不再输出 [loop-agent] banner,保证机器输出可直接解析
|
|
48
|
+
- 源仓库 AGENTS.md 与 init managed block 采用感知源码的精简,长解释指向 docs/,保留开工路由与硬约束
|
|
49
|
+
- 调试纪律要求先建立快速确定性反馈回路再进入根因调查;verifier skill 强调不得越过 writer 边界
|
|
50
|
+
- 任务与 TDD 明确采用垂直 tracer bullet(一测试一实现),避免水平层批处理
|
|
51
|
+
- ADR 增加三门槛过滤;CONTEXT.md 明确只承担术语表职责;grill-with-docs 按 governanceRoot 解析 decisions
|
|
52
|
+
- 外部工程方法论按单轨治理融入 docs/skills/init(ADR 0006),不引入平行状态树
|
|
53
|
+
- 文档治理完成当前权威与内容可信度审计,修正设计入口、能力摘要与网站 roadmap 中的归档状态表述
|
|
54
|
+
- 文档治理完成实际归位,工程规则、runtime 手册和维护操作分别进入清晰目录,当前设计与历史设计分开
|
|
55
|
+
- 文档入口版本与状态对齐 @tea-agent/loop-agent@0.22.0
|
|
56
|
+
- Pi 中等复杂度节点默认模型由 glm-5.2 调整为 gpt-5.5;LOW 与 HIGH 路由保持不变
|
|
57
|
+
|
|
58
|
+
### 修复
|
|
59
|
+
|
|
60
|
+
- DAG run-task 持久化 writer 草稿生成前强制要求 managed Task Contract,未管理时在写出前失败并提示人工处理流程
|
|
61
|
+
- Task source 指南修正 verifyCommands 示例为 { label, command, timeoutMs? }[],并补充旧字符串数组迁移说明
|
|
62
|
+
- 根 Vitest 配置排除 .worktrees/** 隔离 checkout,避免显式测试文件参数误收集旧副本
|
|
63
|
+
- 受监督的 DAG 失败收敛机制修复,确保在有监督失败时保持收敛性
|
|
64
|
+
- DAG bootstrap 合约反馈修复,确保引导阶段正确收敛
|
|
65
|
+
- 修复 check-doc-governance.mjs 未忽略 .DS_Store/Thumbs.db 等 OS 生成文件导致仓库目录测试失败的问题
|
|
66
|
+
- 修复 context-engineering 提案中指向 exec-plans/active/ 的过时链接,更新为实际的 completed/ 路径
|
|
67
|
+
- 校准 context-engineering 提案中的实现证据(测试计数与 AGENTS.md 行数)以匹配当前代码实际产出
|
|
68
|
+
- Console Phase 4 Chat 审查 followup:createSession 缩进规整;handleChatPrompt 加 try/catch+finally 兜底 SSE error 与 res.end;waitForIdle 超时 120s→45s 并新增每 10s heartbeat(SSE comment 帧)防代理超时;设计文档 §7.2.1/V25/§13 同步 widening 契约
|
|
69
|
+
- Console Phase 4 Chat P1 审查修复:`createSessionFromServices` 显式传 `tools:[bash,read,grep,find,ls]`(SDK 默认 builtin 不含 grep/find/ls,否则 setActiveToolsByName 静默 no-op);schema↔dispatcher 契约对齐(contractValidate/Diff 用 draftJson、workerTaskRetry 补 featureId、动态发现 fail-closed);server.close() 先 chatRuntime.disposeAll();resource-loader/system prompt 统一到 widening(hasBash:true)
|
|
70
|
+
- CI 治理:7 个 versionConsumer 文档版本漂移 0.22.0→0.23.0;check-task-pool-root.sh allowlist 增补 codify-constraints.md
|
|
71
|
+
|
|
72
|
+
|
|
5
73
|
## [0.22.0] - 2026-07-24
|
|
6
74
|
|
|
7
75
|
### 重点更新
|
package/README.md
CHANGED
|
@@ -127,8 +127,11 @@ agent-worker console doctor --repo .
|
|
|
127
127
|
|
|
128
128
|
- [`AGENTS.md`](AGENTS.md):开工协议与工作规则
|
|
129
129
|
- [`docs/README.md`](docs/README.md):治理文档总索引
|
|
130
|
-
- [`docs/
|
|
131
|
-
- [`docs/
|
|
130
|
+
- [`docs/governance/`](docs/governance/README.md):工程原则、工作流与验证方法
|
|
131
|
+
- [`docs/runtime/`](docs/runtime/README.md):DAG 运行、恢复与 runtime 手册
|
|
132
|
+
- [`docs/operations/`](docs/operations/README.md):本地环境、合并与协作操作
|
|
133
|
+
- [`docs/governance/feature-workflow.md`](docs/governance/feature-workflow.md):会话治理与 runtime workflow
|
|
134
|
+
- [`docs/governance/verification-matrix.md`](docs/governance/verification-matrix.md):验证命令选择
|
|
132
135
|
- [`docs/architecture/`](docs/architecture/README.md):架构、事实与演进边界
|
|
133
136
|
- [`CHANGELOG.md`](CHANGELOG.md):版本变化与 breaking changes
|
|
134
137
|
|
|
@@ -146,7 +149,7 @@ bash scripts/check-repo.sh
|
|
|
146
149
|
|
|
147
150
|
完整门禁和特定环境排障分别见:
|
|
148
151
|
|
|
149
|
-
- [`docs/verification-matrix.md`](docs/verification-matrix.md)
|
|
150
|
-
- [`docs/local-development-environment.md`](docs/local-development-environment.md)
|
|
152
|
+
- [`docs/governance/verification-matrix.md`](docs/governance/verification-matrix.md)
|
|
153
|
+
- [`docs/operations/local-development-environment.md`](docs/operations/local-development-environment.md)
|
|
151
154
|
|
|
152
155
|
发布和初始化 surface 变更还应运行 `npm pack --dry-run` 与 `bash scripts/check-init-surface.sh`。
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only skill-resolution / context-usage aggregation over recent DAG runs.
|
|
3
|
+
*
|
|
4
|
+
* Terminology: this reports resolution / truncation / unresolved-reference
|
|
5
|
+
* distribution and correlated node outcomes. It does NOT claim skill "execution"
|
|
6
|
+
* or model compliance rates — snapshots prove parse+inject only.
|
|
7
|
+
*/
|
|
8
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { isDagSkillSnapshotIntegrityError, readSkillSnapshot, } from "../../workflows/dag/skill-snapshot.js";
|
|
11
|
+
const LIFECYCLES = ["active", "paused", "completed"];
|
|
12
|
+
function emptySkillCounts() {
|
|
13
|
+
return {
|
|
14
|
+
declared: 0,
|
|
15
|
+
resolved: 0,
|
|
16
|
+
missing: 0,
|
|
17
|
+
error: 0,
|
|
18
|
+
entryTruncated: 0,
|
|
19
|
+
referenceTruncated: 0,
|
|
20
|
+
unresolvedByReason: {},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function emptyNodeOutcomes() {
|
|
24
|
+
return {
|
|
25
|
+
FINISHED: 0,
|
|
26
|
+
ERROR: 0,
|
|
27
|
+
SKIPPED: 0,
|
|
28
|
+
PENDING: 0,
|
|
29
|
+
RUNNING: 0,
|
|
30
|
+
other: 0,
|
|
31
|
+
failureCategories: {},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function bumpReason(map, reason) {
|
|
35
|
+
map[reason] = (map[reason] ?? 0) + 1;
|
|
36
|
+
}
|
|
37
|
+
function ensureSkill(skills, name) {
|
|
38
|
+
if (!skills[name])
|
|
39
|
+
skills[name] = emptySkillCounts();
|
|
40
|
+
return skills[name];
|
|
41
|
+
}
|
|
42
|
+
export function parseStatsContextArgs(args) {
|
|
43
|
+
let last = 50;
|
|
44
|
+
let json = false;
|
|
45
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
46
|
+
const token = args[i];
|
|
47
|
+
if (token === "--json" || token === "--json=true") {
|
|
48
|
+
json = true;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (token.startsWith("--json=")) {
|
|
52
|
+
json = token.slice("--json=".length) === "true";
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (token === "--last") {
|
|
56
|
+
const raw = args[i + 1];
|
|
57
|
+
if (!raw || raw.startsWith("-")) {
|
|
58
|
+
throw new Error("usage: stats context [--last <n>] [--json]");
|
|
59
|
+
}
|
|
60
|
+
const parsed = Number.parseInt(raw, 10);
|
|
61
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
62
|
+
throw new Error(`--last must be a positive integer, got: ${raw}`);
|
|
63
|
+
}
|
|
64
|
+
last = parsed;
|
|
65
|
+
i += 1;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (token.startsWith("--last=")) {
|
|
69
|
+
const raw = token.slice("--last=".length);
|
|
70
|
+
const parsed = Number.parseInt(raw, 10);
|
|
71
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
72
|
+
throw new Error(`--last must be a positive integer, got: ${raw}`);
|
|
73
|
+
}
|
|
74
|
+
last = parsed;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`unknown argument: ${token}\nusage: stats context [--last <n>] [--json]`);
|
|
78
|
+
}
|
|
79
|
+
return { last, json };
|
|
80
|
+
}
|
|
81
|
+
async function listRecentDagRuns(repoRoot, last) {
|
|
82
|
+
const matches = [];
|
|
83
|
+
for (const lifecycle of LIFECYCLES) {
|
|
84
|
+
const lifecycleDir = path.join(repoRoot, ".harness", "dag-runs", lifecycle);
|
|
85
|
+
let entries = [];
|
|
86
|
+
try {
|
|
87
|
+
entries = await readdir(lifecycleDir);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
for (const name of entries) {
|
|
93
|
+
if (!name || name === ".gitkeep")
|
|
94
|
+
continue;
|
|
95
|
+
const runDir = path.join(lifecycleDir, name);
|
|
96
|
+
let st;
|
|
97
|
+
try {
|
|
98
|
+
st = await stat(runDir);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (!st.isDirectory())
|
|
104
|
+
continue;
|
|
105
|
+
matches.push({
|
|
106
|
+
runId: name,
|
|
107
|
+
lifecycle,
|
|
108
|
+
runDir,
|
|
109
|
+
mtimeMs: st.mtimeMs,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
matches.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
114
|
+
return matches.slice(0, last);
|
|
115
|
+
}
|
|
116
|
+
async function readOptionalJson(filePath) {
|
|
117
|
+
try {
|
|
118
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function ingestSnapshot(skills, snapshot) {
|
|
125
|
+
for (const profile of snapshot.profiles) {
|
|
126
|
+
for (const skillName of profile.skills) {
|
|
127
|
+
ensureSkill(skills, skillName).declared += 1;
|
|
128
|
+
}
|
|
129
|
+
for (const instruction of profile.resolvedInstructions) {
|
|
130
|
+
const row = ensureSkill(skills, instruction.name);
|
|
131
|
+
if (instruction.resolution === "resolved")
|
|
132
|
+
row.resolved += 1;
|
|
133
|
+
else if (instruction.resolution === "missing")
|
|
134
|
+
row.missing += 1;
|
|
135
|
+
else if (instruction.resolution === "error")
|
|
136
|
+
row.error += 1;
|
|
137
|
+
if (instruction.truncated)
|
|
138
|
+
row.entryTruncated += 1;
|
|
139
|
+
for (const ref of instruction.references ?? []) {
|
|
140
|
+
if (ref.truncated)
|
|
141
|
+
row.referenceTruncated += 1;
|
|
142
|
+
}
|
|
143
|
+
for (const unresolved of instruction.unresolvedReferences ?? []) {
|
|
144
|
+
bumpReason(row.unresolvedByReason, unresolved.reason);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function ingestNodeOutcomes(outcomes, state) {
|
|
150
|
+
for (const node of Object.values(state.nodes ?? {})) {
|
|
151
|
+
const status = node.status;
|
|
152
|
+
if (status === "FINISHED")
|
|
153
|
+
outcomes.FINISHED += 1;
|
|
154
|
+
else if (status === "ERROR")
|
|
155
|
+
outcomes.ERROR += 1;
|
|
156
|
+
else if (status === "SKIPPED")
|
|
157
|
+
outcomes.SKIPPED += 1;
|
|
158
|
+
else if (status === "PENDING")
|
|
159
|
+
outcomes.PENDING += 1;
|
|
160
|
+
else if (status === "RUNNING")
|
|
161
|
+
outcomes.RUNNING += 1;
|
|
162
|
+
else
|
|
163
|
+
outcomes.other += 1;
|
|
164
|
+
if (node.failureCategory) {
|
|
165
|
+
bumpReason(outcomes.failureCategories, node.failureCategory);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Pure-ish builder: filesystem reads only; never writes `.harness/**`.
|
|
171
|
+
*/
|
|
172
|
+
export async function buildContextUsageReport(repoRoot, options = {}) {
|
|
173
|
+
const last = options.last ?? 50;
|
|
174
|
+
const candidates = await listRecentDagRuns(repoRoot, last);
|
|
175
|
+
const skills = {};
|
|
176
|
+
const nodeOutcomes = emptyNodeOutcomes();
|
|
177
|
+
const byLifecycle = {
|
|
178
|
+
active: 0,
|
|
179
|
+
paused: 0,
|
|
180
|
+
completed: 0,
|
|
181
|
+
};
|
|
182
|
+
const findings = [];
|
|
183
|
+
const notes = [
|
|
184
|
+
"skill-resolution telemetry only; does not claim model compliance or skill execution rates",
|
|
185
|
+
"corrupted snapshots are reported as findings and are not silently skipped",
|
|
186
|
+
];
|
|
187
|
+
for (const candidate of candidates) {
|
|
188
|
+
byLifecycle[candidate.lifecycle] += 1;
|
|
189
|
+
const state = await readOptionalJson(path.join(candidate.runDir, "state.json"));
|
|
190
|
+
const runJson = await readOptionalJson(path.join(candidate.runDir, "run.json"));
|
|
191
|
+
const finding = {
|
|
192
|
+
runId: candidate.runId,
|
|
193
|
+
lifecycle: candidate.lifecycle,
|
|
194
|
+
mtimeMs: candidate.mtimeMs,
|
|
195
|
+
runStatus: state?.status,
|
|
196
|
+
contextPolicyId: runJson?.defaults?.contextPolicyId,
|
|
197
|
+
snapshot: "missing",
|
|
198
|
+
};
|
|
199
|
+
if (state)
|
|
200
|
+
ingestNodeOutcomes(nodeOutcomes, state);
|
|
201
|
+
const ref = state?.skillSnapshotRef;
|
|
202
|
+
if (!ref) {
|
|
203
|
+
findings.push(finding);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
const snapshot = await readSkillSnapshot(candidate.runDir, ref);
|
|
208
|
+
finding.snapshot = "ok";
|
|
209
|
+
ingestSnapshot(skills, snapshot);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
finding.snapshot = "corrupted";
|
|
213
|
+
finding.snapshotError = isDagSkillSnapshotIntegrityError(error)
|
|
214
|
+
? error.message
|
|
215
|
+
: error instanceof Error
|
|
216
|
+
? error.message
|
|
217
|
+
: String(error);
|
|
218
|
+
}
|
|
219
|
+
findings.push(finding);
|
|
220
|
+
}
|
|
221
|
+
const corrupted = findings.filter((f) => f.snapshot === "corrupted").length;
|
|
222
|
+
return {
|
|
223
|
+
schemaVersion: 1,
|
|
224
|
+
command: "stats.context",
|
|
225
|
+
ok: corrupted === 0,
|
|
226
|
+
scannedRuns: candidates.length,
|
|
227
|
+
requestedLast: last,
|
|
228
|
+
byLifecycle,
|
|
229
|
+
skills,
|
|
230
|
+
nodeOutcomes,
|
|
231
|
+
findings,
|
|
232
|
+
notes,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
export function formatContextUsageReportHuman(report) {
|
|
236
|
+
const lines = [];
|
|
237
|
+
lines.push(`stats context (last ${report.requestedLast}, scanned ${report.scannedRuns})`);
|
|
238
|
+
lines.push(`lifecycle: active=${report.byLifecycle.active} paused=${report.byLifecycle.paused} completed=${report.byLifecycle.completed}`);
|
|
239
|
+
lines.push(`nodes: FINISHED=${report.nodeOutcomes.FINISHED} ERROR=${report.nodeOutcomes.ERROR} SKIPPED=${report.nodeOutcomes.SKIPPED} PENDING=${report.nodeOutcomes.PENDING} RUNNING=${report.nodeOutcomes.RUNNING}`);
|
|
240
|
+
const skillNames = Object.keys(report.skills).sort();
|
|
241
|
+
if (skillNames.length === 0) {
|
|
242
|
+
lines.push("skills: (none resolved in scanned snapshots)");
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
lines.push("skills:");
|
|
246
|
+
for (const name of skillNames) {
|
|
247
|
+
const s = report.skills[name];
|
|
248
|
+
const budget = s.unresolvedByReason.budget ?? 0;
|
|
249
|
+
lines.push(` ${name}: declared=${s.declared} resolved=${s.resolved} missing=${s.missing} error=${s.error} entryTrunc=${s.entryTruncated} refTrunc=${s.referenceTruncated} budgetSkip=${budget}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const corrupted = report.findings.filter((f) => f.snapshot === "corrupted");
|
|
253
|
+
if (corrupted.length > 0) {
|
|
254
|
+
lines.push(`corrupted snapshots: ${corrupted.length}`);
|
|
255
|
+
for (const finding of corrupted.slice(0, 5)) {
|
|
256
|
+
lines.push(` ${finding.lifecycle}/${finding.runId}: ${finding.snapshotError ?? "unknown"}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const note of report.notes) {
|
|
260
|
+
lines.push(`note: ${note}`);
|
|
261
|
+
}
|
|
262
|
+
return lines.join("\n");
|
|
263
|
+
}
|
|
@@ -68,6 +68,15 @@ function buildNextSteps(taskId, outputPath, cwd) {
|
|
|
68
68
|
`loop-agent dag run-task ${taskId} --execute --cwd ${cwd}`,
|
|
69
69
|
];
|
|
70
70
|
}
|
|
71
|
+
function buildBasicValidationLevel(outputPath) {
|
|
72
|
+
return {
|
|
73
|
+
level: "basic",
|
|
74
|
+
strictGovernance: false,
|
|
75
|
+
strictGovernanceValidationRequiredSeparately: true,
|
|
76
|
+
standaloneStrictGovernanceCommand: `loop-agent dag validate --dag ${outputPath} --strict-models --strict-governance`,
|
|
77
|
+
note: "Internal generation validation is basic only; standalone strict governance validation must be confirmed separately.",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
71
80
|
function isBroadWriteSetEntryForPacket(entry) {
|
|
72
81
|
const normalized = entry.trim().replace(/\\/g, "/").replace(/^\.\//, "");
|
|
73
82
|
if (!normalized || normalized === "." || normalized === "./")
|
|
@@ -168,6 +177,7 @@ async function buildReviewPacket(input) {
|
|
|
168
177
|
? (task.decisionGate.mode ?? "record-only")
|
|
169
178
|
: "disabled",
|
|
170
179
|
})),
|
|
180
|
+
validation: buildBasicValidationLevel(input.dagPath),
|
|
171
181
|
expectedVerification: shellVerification.flatMap((entry) => entry.commands),
|
|
172
182
|
};
|
|
173
183
|
}
|
|
@@ -281,10 +291,12 @@ export async function generateTaskDagUseCase(input) {
|
|
|
281
291
|
profileRouting,
|
|
282
292
|
governanceProfile,
|
|
283
293
|
});
|
|
294
|
+
const validation = buildBasicValidationLevel(outputPath);
|
|
295
|
+
const message = "DAG draft created with basic validation; standalone strict governance validation still requires separate confirmation.";
|
|
284
296
|
if (!shouldRunExecution(parsed)) {
|
|
285
297
|
return {
|
|
286
|
-
mode: "generate+validate",
|
|
287
|
-
message
|
|
298
|
+
mode: "generate+basic-validate",
|
|
299
|
+
message,
|
|
288
300
|
ok: true,
|
|
289
301
|
taskId: initResult.taskId,
|
|
290
302
|
outputPath,
|
|
@@ -296,6 +308,7 @@ export async function generateTaskDagUseCase(input) {
|
|
|
296
308
|
governanceProfile,
|
|
297
309
|
profileRouting,
|
|
298
310
|
reviewPacket,
|
|
311
|
+
validation,
|
|
299
312
|
warnings: validateSummary.warnings,
|
|
300
313
|
next: buildNextSteps(parsed.taskId, outputPath, parsed.cwd),
|
|
301
314
|
};
|
|
@@ -327,7 +340,7 @@ export async function generateTaskDagUseCase(input) {
|
|
|
327
340
|
});
|
|
328
341
|
return {
|
|
329
342
|
mode: resolveExecutionMode(parsed),
|
|
330
|
-
message
|
|
343
|
+
message,
|
|
331
344
|
ok: true,
|
|
332
345
|
taskId: initResult.taskId,
|
|
333
346
|
outputPath,
|
|
@@ -338,6 +351,7 @@ export async function generateTaskDagUseCase(input) {
|
|
|
338
351
|
governanceProfile,
|
|
339
352
|
profileRouting,
|
|
340
353
|
reviewPacket,
|
|
354
|
+
validation,
|
|
341
355
|
warnings: validateSummary.warnings,
|
|
342
356
|
run: runSummary,
|
|
343
357
|
};
|