@tea-agent/loop-agent 0.13.0-alpha.0 → 0.13.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/AGENTS.md +4 -0
- package/CHANGELOG.md +57 -53
- package/README.md +12 -3
- package/dist/application/dag/generate-task-dag.js +28 -58
- package/dist/application/evaluation/candidate-hash.js +75 -0
- package/dist/application/evaluation/candidate.js +52 -0
- package/dist/application/evaluation/replay.js +289 -0
- package/dist/application/evaluation/types.js +130 -0
- package/dist/cli/command-definitions.js +17 -4
- package/dist/cli/program.js +8 -4
- package/dist/commands/eval.js +235 -0
- package/dist/commands/init.js +131 -24
- package/dist/executors/pi-sdk-executor.js +38 -24
- package/dist/executors/shell-executor.js +226 -15
- package/dist/executors/shell-presets.js +20 -0
- package/dist/executors/shell-verification.js +7 -0
- package/dist/governance/manifest-types.js +1 -0
- package/dist/infrastructure/evaluation/candidate-store.js +439 -0
- package/dist/infrastructure/evaluation/store.js +40 -0
- package/dist/task/config-types.js +23 -0
- package/dist/worker/observe/routes.js +18 -3
- package/dist/worker/observe/spec-evidence.js +1 -1
- package/dist/worker/observe/static/dom.js +160 -1
- package/dist/worker/observe/static/state.js +14 -0
- package/dist/worker/observe/static/views/dag-inspector.js +35 -4
- package/dist/worker/observe/static/views/dag.js +9 -0
- package/dist/worker/observe/static/views/dashboard.js +702 -445
- package/dist/worker/observe/static/views/session-timeline.js +15 -1
- package/dist/workflows/dag/backend-test-analysis-contract.js +120 -0
- package/dist/workflows/dag/backend-test-case-manifest.js +503 -0
- package/dist/workflows/dag/backend-test-execution-contract.js +353 -0
- package/dist/workflows/dag/backend-test-result-contract.js +568 -0
- package/dist/workflows/dag/decision-envelope.js +57 -2
- package/dist/workflows/dag/dynamic-runtime/map.js +90 -2
- package/dist/workflows/dag/frontend-implementation-contract.js +240 -0
- package/dist/workflows/dag/frontend-project-capability.js +309 -0
- package/dist/workflows/dag/frontend-repair.js +341 -0
- package/dist/workflows/dag/frontend-risk.js +161 -0
- package/dist/workflows/dag/frontend-verification-trace.js +190 -0
- package/dist/workflows/dag/init-hybrid.js +2407 -297
- package/dist/workflows/dag/node-execution.js +9 -0
- package/dist/workflows/dag/prompt.js +9 -0
- package/dist/workflows/dag/repair-artifact.js +43 -3
- package/dist/workflows/dag/report.js +35 -1
- package/dist/workflows/dag/runner.js +28 -2
- package/dist/workflows/dag/skill-instructions.js +4 -2
- package/dist/workflows/dag/task-demand-routing.js +383 -0
- package/dist/workflows/dag/types.js +71 -13
- package/dist/workflows/dag/upstream-artifacts.js +1 -0
- package/dist/workflows/dag/validate.js +59 -1
- package/docs/README.md +6 -3
- package/docs/agent-dag-recovery-playbook.md +5 -3
- package/docs/agent-dag-runner.md +3 -3
- package/docs/architecture/README.md +3 -3
- package/docs/architecture/dag-execution.md +1 -1
- package/docs/architecture/evolution.md +13 -13
- package/docs/architecture/facts-and-state.md +1 -1
- package/docs/architecture/runtime-boundaries.md +7 -7
- package/docs/architecture/system-overview.md +3 -3
- package/docs/architecture/worker-and-feature.md +3 -3
- package/docs/design/README.md +124 -42
- package/docs/development-principles.md +4 -4
- package/docs/exec-plans/active/README.md +12 -11
- package/docs/exec-plans/completed/README.md +33 -0
- package/docs/feature-workflow.md +114 -39
- package/docs/init-surface.manifest.json +30 -3
- package/docs/loop-agent-harness.md +9 -8
- package/docs/production-readiness.md +1 -1
- package/docs/progress/README.md +23 -1
- package/docs/reports/README.md +65 -6
- package/docs/skills/vetted-skill-registry.md +2 -0
- package/docs/templates/agent-dag.schema.json +29 -1
- package/docs/templates/agent-dag.supervised-implementation.json +127 -8
- package/docs/templates/backend-test-analysis.schema.json +44 -0
- package/docs/templates/backend-test-case-manifest.schema.json +190 -0
- package/docs/templates/backend-test-dag.classify.prompt.md +75 -0
- package/docs/templates/backend-test-dag.generate-pytest.prompt.md +81 -16
- package/docs/templates/backend-test-dag.json +311 -40
- package/docs/templates/backend-test-dag.retrospect.prompt.md +44 -30
- package/docs/templates/backend-test-dag.review-cases.prompt.md +10 -8
- package/docs/templates/backend-test-execution.schema.json +133 -0
- package/docs/templates/backend-test-result.schema.json +99 -0
- package/docs/templates/branch-merge-report.md +93 -0
- package/docs/templates/frontend-design-contract.md +9 -0
- package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -0
- package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -0
- package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -0
- package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -0
- package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -0
- package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -0
- package/docs/templates/frontend-eval/metrics.md +138 -0
- package/docs/templates/frontend-eval/smoke-targets.md +53 -0
- package/docs/templates/frontend-implementation-contract.schema.json +27 -0
- package/docs/templates/frontend-task-constraints.md +10 -0
- package/docs/templates/frontend-task-requirement.md +9 -0
- package/docs/templates/frontend-test-dag.generate-cases.prompt.md +5 -0
- package/docs/templates/frontend-test-dag.json +23 -0
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +3 -0
- package/docs/templates/frontend-test-dag.retrospect.prompt.md +3 -0
- package/docs/templates/frontend-test-dag.review-cases.prompt.md +3 -0
- package/docs/templates/frontend-test-dag.review-execution.prompt.md +3 -0
- package/docs/templates/knowledge-graph-bootstrap-dag.json +1 -1
- package/docs/templates/knowledge-sync-dag.json +1 -0
- package/docs/verification-matrix.md +4 -1
- package/examples/decision-gate-agent-dag.json +4 -4
- package/examples/hybrid-loop-agent-dag.json +1 -1
- package/package.json +2 -2
- package/scripts/kb-bootstrap-init-skeleton.sh +2 -1
- package/scripts/kb-graph-incremental-prepare.mjs +19 -5
- package/scripts/kb-graph-promote.mjs +12 -1
- package/skills/ai-engineering-context/SKILL.md +2 -2
- package/skills/analyze-product-dependencies/SKILL.md +67 -0
- package/skills/analyze-product-dependencies/agents/openai.yaml +4 -0
- package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -0
- package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -0
- package/skills/analyze-product-dependencies/references/example.md +76 -0
- package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -0
- package/skills/analyze-product-dependencies/references/input-contract.md +11 -0
- package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -0
- package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -0
- package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -0
- package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -0
- package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -0
- package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -0
- package/skills/analyze-product-requirements/SKILL.md +90 -0
- package/skills/analyze-product-requirements/agents/openai.yaml +4 -0
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -0
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -0
- package/skills/analyze-product-requirements/references/example.md +86 -0
- package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -0
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -0
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -0
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -0
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -0
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -0
- package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -0
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -0
- package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -0
- package/skills/browser-tools/SKILL.md +196 -0
- package/skills/browser-tools/browser-content.js +103 -0
- package/skills/browser-tools/browser-cookies.js +35 -0
- package/skills/browser-tools/browser-eval.js +53 -0
- package/skills/browser-tools/browser-hn-scraper.js +108 -0
- package/skills/browser-tools/browser-nav.js +44 -0
- package/skills/browser-tools/browser-pick.js +162 -0
- package/skills/browser-tools/browser-screenshot.js +34 -0
- package/skills/browser-tools/browser-start.js +86 -0
- package/skills/browser-tools/package-lock.json +2556 -0
- package/skills/browser-tools/package.json +19 -0
- package/skills/frontend-design-review/SKILL.md +6 -1
- package/skills/frontend-design-review/references/review-checklist.md +25 -4
- package/skills/frontend-implementation/SKILL.md +25 -30
- package/skills/frontend-implementation/references/code-standards.md +20 -22
- package/skills/frontend-implementation/references/node-contracts.md +17 -53
- package/skills/frontend-review/SKILL.md +10 -4
- package/skills/frontend-review/references/review-findings.md +8 -3
- package/skills/frontend-verification/SKILL.md +22 -9
- package/skills/frontend-verification/references/verification-checklist.md +17 -5
- package/skills/grill-with-docs/SKILL.md +5 -5
- package/skills/grill-with-docs/adr-format.md +3 -3
- package/skills/init-capability-evolution/SKILL.md +5 -5
- package/skills/loop-agent/SKILL.md +5 -5
- package/skills/loop-agent/references/README.md +3 -3
- package/skills/loop-agent/references/command-reference.md +98 -24
- package/skills/loop-agent/references/docs-converge.md +15 -15
- package/skills/loop-agent/references/harness-policy.md +2 -2
- package/skills/loop-agent/references/hybrid-dag.md +32 -22
- package/skills/loop-agent/references/multi-worktree.md +1 -1
- package/skills/loop-agent/references/orchestrator-and-interventions.md +8 -8
- package/skills/loop-agent/references/task-workflow.md +1 -1
- package/skills/loop-agent/references/verification-and-failure-handling.md +6 -4
- package/skills/playwright-cli/SKILL.md +420 -0
- package/skills/playwright-cli/references/element-attributes.md +23 -0
- package/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/skills/playwright-cli/references/request-mocking.md +87 -0
- package/skills/playwright-cli/references/running-code.md +241 -0
- package/skills/playwright-cli/references/session-management.md +225 -0
- package/skills/playwright-cli/references/storage-state.md +275 -0
- package/skills/playwright-cli/references/test-generation.md +433 -0
- package/skills/playwright-cli/references/tracing.md +139 -0
- package/skills/playwright-cli/references/video-recording.md +143 -0
- package/skills/playwright-cli-case-generator/SKILL.md +74 -0
- package/skills/requesting-code-review/SKILL.md +1 -1
- package/skills/systematic-debugging/CREATION-LOG.md +3 -3
- package/skills/systematic-debugging/SKILL.md +1 -1
- package/skills/systematic-debugging/test-academic.md +1 -1
- package/skills/systematic-debugging/test-pressure-1.md +1 -1
- package/skills/systematic-debugging/test-pressure-2.md +1 -1
- package/skills/systematic-debugging/test-pressure-3.md +1 -1
- package/skills/verification-before-completion/SKILL.md +1 -1
package/AGENTS.md
CHANGED
|
@@ -52,6 +52,8 @@
|
|
|
52
52
|
9. 查看最近提交、相关执行计划、progress/report,确认当前上下文。
|
|
53
53
|
10. 检查 `git status --short --branch`。
|
|
54
54
|
11. 运行本次任务相关的最小基线验证。
|
|
55
|
+
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`。
|
|
56
|
+
13. 如果用户提到"看板"、"observe"、"监控面板"、"启动看板",使用 `agent-worker observe serve --repo . --port 8787` 命令启动。
|
|
55
57
|
|
|
56
58
|
## 会话协议
|
|
57
59
|
|
|
@@ -83,6 +85,8 @@
|
|
|
83
85
|
- 保留无关的用户改动,不要回退自己没有做的修改。
|
|
84
86
|
- 优先沿用现有 helper、目录边界和局部模式,再考虑新增抽象。
|
|
85
87
|
- 长期决策写入 `docs/`,不要只留在聊天里。
|
|
88
|
+
- 后端测试、接口/API 测试、pytest 或明确的后端自动化测试,必须把 `.harness/tasks/<task-id>/task.json` 的 `taskKind` 设置为 `"backend-test"`,不得保留默认 `standard`。`backend-test` 是 `taskKind`,不是 `--profile` 的可选值;`dag run-task` 继续使用 `--profile auto` 选择治理等级。仅说“自动化测试”且前后端不明时,先根据任务源和项目技术栈判断,禁止无条件路由。
|
|
89
|
+
- 本地只读运行看板:`agent-worker observe serve --repo . --port 8787`,访问 `http://127.0.0.1:8787/`;看板只读,默认只绑定本机 `127.0.0.1`,不要直接暴露到公开网络。
|
|
86
90
|
- 面向使用者的新增、修改、删除或修复,应同步更新根目录 `CHANGELOG.md`;保持版本级摘要即可,不写过细技术细节。
|
|
87
91
|
- 面向用户的中文更新日志、README 和说明文档应使用自然、结果导向的表达:先说明用户能获得什么或问题如何改善,保留必要的命令和产品术语,避免逐字翻译、内部实现细节和无意义的中英混杂。
|
|
88
92
|
- 涉及 `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` 安全迁移或退役。
|
package/CHANGELOG.md
CHANGED
|
@@ -2,66 +2,70 @@
|
|
|
2
2
|
|
|
3
3
|
这里记录每个版本对使用者有影响的变化。命令名和配置字段保持原样,其余内容尽量用日常语言说明。
|
|
4
4
|
|
|
5
|
-
## [
|
|
5
|
+
## [0.13.0] - 2026-07-18
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### 重点更新
|
|
8
|
+
|
|
9
|
+
- 前端实现流程更完整:会先确认需求范围和项目能力,再按风险选择执行路径;验证失败时可进行一次有边界的修复,并保留需求、改动和验证结果之间的追踪关系。
|
|
10
|
+
- 后端自动化测试流程更可靠:在生成 pytest 前确认环境和执行范围,检查需求覆盖,并区分产品缺陷、测试问题与环境问题,减少误报和无效重跑。
|
|
11
|
+
- Observe 看板刷新更稳定:轮询时只更新发生变化的内容,保留卡片、焦点、滚动位置和当前节点;节点输出、执行过程和规范证据不会因切换或延迟响应串到其他节点。
|
|
12
|
+
- 旧项目的初始化更新链路得到加强:`init check-update` 能发现新增模板、skills 和托管配置,`init update --apply-safe` 可安全补齐,不覆盖项目自己的内容。
|
|
8
13
|
|
|
9
14
|
### 新增
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
1. 运行 `agent-worker pool doctor --repo <repo> --json` 盘点 v2 / legacy inventory。
|
|
29
|
-
2. 需要迁移时先 `agent-worker pool migrate-state --repo <repo>`(dry-run),确认映射后再 `--apply --owner <owner> --reason <reason>`。
|
|
30
|
-
3. 更新脚本与文档中的 retry 示例为 `task retry <task-id> --feature-id <feature-id> ...`。
|
|
31
|
-
4. Observe / 书签改用 `#/feature/:featureId/task/:taskId`;legacy `#/task/:taskId` 仅在 taskId 全库唯一时兼容。
|
|
32
|
-
5. `runs.jsonl` / `events.jsonl` 不会被 migrate 重写;历史 `workerRunId` 仍可追溯。
|
|
33
|
-
|
|
34
|
-
### 新增
|
|
35
|
-
|
|
36
|
-
- `agent-worker pool doctor`:只读 Task Pool inventory 与迁移证据(exit 0 也可带 findings)。
|
|
37
|
-
- `agent-worker pool migrate-state`:legacy → v2 显式迁移;默认 dry-run,apply 需 owner/reason,失败全回滚并保留审计 artifact。
|
|
38
|
-
- `agent-worker batch plan-ready`:零写入预览 TaskSpec priority 驱动的 selected、deferred 与 blocked 计划。
|
|
39
|
-
|
|
40
|
-
### 变更
|
|
41
|
-
|
|
42
|
-
- Runner Ready Queue、Feature review/run、Follow-up、Delivery / Closeout、morning report / metrics 与 Observe read-model 均按 Feature 作用域消费 state,同名 Task 跨 Feature 不串线。
|
|
43
|
-
- Observe canonical API:`GET /api/features/:featureId/tasks/:taskId[/runs]`;legacy bare task route 在歧义时返回 409 + `candidates`。
|
|
44
|
-
- Feature dry-run / review / next-action、morning report、GlobalSnapshot、Observe 消费同一 Ready Planner projection;前端与投影层不得独立重选或重排 ready tasks。
|
|
15
|
+
|
|
16
|
+
- 新增 `browser-tools` skill,可通过 Chrome DevTools Protocol 完成浏览器启动、导航、内容提取、元素选择、脚本执行、截图和 cookie 操作;`loop-agent init --profile full` 会将其安装到目标项目。
|
|
17
|
+
- 新增前端浏览器测试用例生成能力,可根据需求生成逐条执行的中文用例、索引和清单,并明确标记缺失的接口、边界或测试数据。
|
|
18
|
+
- 新增 Eval Replay 与 Candidate Registry,可重放已完成 DAG 的证据、比较候选结果,并记录候选与运行之间的关联;当前用于评估和审计,不会自动晋升候选。
|
|
19
|
+
- 新增 `agent-worker pool doctor`、`pool migrate-state` 和 `batch plan-ready`,用于检查 Task Pool、预览迁移和查看下一批可执行任务。
|
|
20
|
+
- 新增跨分支合并报告模板,统一记录双方功能、冲突处理、初始化影响、发布包变化、验证结果和回退入口。
|
|
21
|
+
- 初始化后的项目支持更自然的“初始化”“检查初始化更新”“安全更新初始化”表达;检查操作保持只读,安全更新会先检查再应用可确定处理的变更。
|
|
22
|
+
|
|
23
|
+
### 改进
|
|
24
|
+
|
|
25
|
+
- 高置信度的前端实现需求可自动进入前端专用流程;后端、混合需求或证据不足的任务继续使用原治理流程,不会被误分类。
|
|
26
|
+
- 前端 Mock 策略会优先复用项目已有能力,并明确区分“已用 Mock 验证”和“已完成真实接口联调”,避免把模拟结果误报为完整集成通过。
|
|
27
|
+
- 受监督任务在计划需要调整时可自动完成一次只读修订和复审;写入范围不会因此扩大,最终仍需明确通过才能继续。
|
|
28
|
+
- Task Pool、Ready Planner、Feature 评审、批次执行、报告和 Observe 统一按 Feature 识别任务,同名任务不会跨 Feature 串线。
|
|
29
|
+
- `backend-test`、`frontend-implementation`、`knowledge-sync` 等专用流程统一通过 `task.json.taskKind` 选择;`--profile` 只表示治理强度。
|
|
30
|
+
- Pi SDK 升级至 0.80.10,`doctor` 会检查实际运行能力,而不只是模块是否能够加载。
|
|
31
|
+
- Windows 下的 Git Bash、路径处理、自举验证和 Git 密集测试更稳定。
|
|
45
32
|
|
|
46
33
|
### 修复
|
|
47
34
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
35
|
+
- 修复 Observe 看板反复显示加载状态、整块重建页面、节点页签内容中断以及旧请求覆盖当前节点的问题。
|
|
36
|
+
- 修复旧项目安全更新后缺少可靠初始化记录,导致后续版本无法继续判断哪些文件可安全更新的问题。
|
|
37
|
+
- 修复前端需求覆盖检查读取旧计划、验证失败无法进入有界修复,以及存在阻塞证据时仍可能继续写入的问题。
|
|
38
|
+
- 修复动态用例执行恢复后重复运行已完成用例或丢失 Token 预算状态的问题。
|
|
39
|
+
- 修复受监督决策和修复结果在合法 Markdown、空白可选说明或格式轻微偏差下被误判的问题,同时继续拒绝不明确或不符合约束的结果。
|
|
40
|
+
- 修复初始化后的 repo-local skills 安装本地依赖时污染目标仓库的问题;托管 `.gitignore` 现在忽略 `.agents/skills/*/node_modules/`。
|
|
41
|
+
- 修复初始化项目缺少运行目录占位、知识库命令发布文件不完整,以及知识图谱晋升路径校验不足的问题。
|
|
42
|
+
|
|
43
|
+
### 破坏性变更
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
- Task Pool 任务现在使用 `{ featureId, taskId }` 作为身份。`agent-worker task retry` 应携带 `--feature-id`;存在同名任务时,省略该参数会拒绝执行,不再猜测所属 Feature。
|
|
46
|
+
- 旧的扁平 Task Pool state 不会被自动解释或静默迁移,需要显式检查和迁移。
|
|
47
|
+
|
|
48
|
+
### 迁移提示
|
|
49
|
+
|
|
50
|
+
1. 运行 `agent-worker pool doctor --repo <repo> --json` 检查旧 Task Pool 状态。
|
|
51
|
+
2. 先运行 `agent-worker pool migrate-state --repo <repo>` 预览迁移;确认后再添加 `--apply --owner <owner> --reason <reason>`。
|
|
52
|
+
3. 将 retry 命令更新为 `agent-worker task retry <task-id> --feature-id <feature-id> ...`。
|
|
53
|
+
4. 旧项目升级 controller 后,先运行 `loop-agent init check-update`,确认结果后再运行 `loop-agent init update --apply-safe`。
|
|
54
|
+
|
|
55
|
+
## [0.12.0] - 2026-07-16
|
|
52
56
|
|
|
53
57
|
### 新增
|
|
54
58
|
|
|
55
59
|
- 只读 Pi DAG 节点支持 opt-in 安全重试:仅 planner/scout/reviewer/verifier/closeout 角色且无写入能力的 Pi 节点可声明 `retryPolicy`,在同一 run 内重试模型连接中断(`network`)、provider 限流(`rate-limit`)、临时不可用(`unavailable`)或请求 timeout。生成模板默认总尝试 3 次,手工配置最多 5 次,并使用有上限的指数退避。每次 attempt 保留独立证据,节点耗时、Token 与事件数按尝试聚合;后一次成功不会覆盖前一次失败证据。`quota`、`auth`、`invalid-output`、`write-guard` 与未知失败不重试;supervisor、implementer、writer、dynamic、shell、static、docs-only、decision-gate 节点声明策略会在校验阶段失败。未声明策略的历史 DAG 不新增 attempt artifact,行为保持不变。
|
|
56
60
|
- 新增 `taskKind: "backend-test"` 专用 DAG:从需求分析开始,生成并评审后端功能用例,再生成和执行 pytest 自动化,最后产出测试复盘报告;新 DAG 沿用当前 Pi-only runtime、版本化 runtime contract 与既有执行恢复机制。
|
|
57
|
-
- 测试知识回写专用 DAG:`taskKind: "knowledge-sync"`。生成 collect→draft→validate
|
|
58
|
-
- 业务知识图谱开荒 DAG:`taskKind: "knowledge-graph-bootstrap"`(preflight→inventory→propose→validate
|
|
61
|
+
- 测试知识回写专用 DAG:`taskKind: "knowledge-sync"`。生成 collect→draft→validate→**多视角审查(QA/领域/证据)**→apply→pointer;**必须绑定 `featureId`**(`task.json.featureId` 或 hardConstraints / 需求中的 `F-…`),writeSet 收窄到 `features/<featureId>/…`。
|
|
62
|
+
- 业务知识图谱开荒 DAG:`taskKind: "knowledge-graph-bootstrap"`(preflight→inventory→propose→validate→**结构/证据/安全三视角审查+聚合门禁**→promote→materialize);AI 只写 `knowledge/bootstrap/staging/**`。
|
|
59
63
|
- 图谱辅助脚本与 CLI:`loop-agent knowledge query|graph-init|graph-materialize|graph-promote|graph-incremental-prepare`(薄封装 `scripts/kb-*`);`knowledge curate` 仍只负责 repair guidance 提案。
|
|
60
|
-
- B1 骨架、Phase A 查询(by_id / by_feature / search)、merge-new-only 晋升、增量 scope 准备与 materialize 索引;设计文档见 `
|
|
64
|
+
- B1 骨架、Phase A 查询(by_id / by_feature / search)、merge-new-only 晋升、增量 scope 准备与 materialize 索引;设计文档见 `ai_workspace/loop-agent/design/knowledge-*.md` 与 active plan `ai_workspace/loop-agent/exec-plans/active/2026-07-14-knowledge-sync-and-graph.md`。
|
|
61
65
|
|
|
62
66
|
### 修复
|
|
63
67
|
|
|
64
|
-
- `loop-agent init check-update` / `init update --apply-safe` 漏检初始化投影文件:fresh `init --profile full` 通过目录复制把整个 `
|
|
68
|
+
- `loop-agent init check-update` / `init update --apply-safe` 漏检初始化投影文件:fresh `init --profile full` 通过目录复制把整个 `ai_workspace/loop-agent/templates/` 与 `.agents/skills/`(镜像到 `.agents/skills/`)投影到目标项目,但期望 init surface 只跟踪其中一个子集。旧版本(如 0.11.0)初始化的项目升级 controller 后,缺失的 backend-test 模板、agent-dag schema/prompt、`loop-agent` 必需 references 等文件无法被报告或补齐,`check-update` 会错误返回 `ok: true`。现在期望 surface 会自动发现包内 `ai_workspace/loop-agent/templates/` 与 `.agents/skills/` 的所有文件并纳入校验;`check-update` 会报告全部缺失/陈旧 surface;`apply-safe` 会确定性补齐缺失文件,对无法证明 ownership 的旧文件仍保持 fail-safe(给出 model merge / human decision,不覆盖用户内容)。`scripts/check-init-surface.sh` 新增 drift 门,阻止“fresh init 会复制、surface 却不跟踪”的漂移。
|
|
65
69
|
|
|
66
70
|
## [0.11.0] - 2026-07-15
|
|
67
71
|
|
|
@@ -78,23 +82,23 @@
|
|
|
78
82
|
- 新增版本更新提醒。发现新版本时可以直接确认升级;忽略某个版本后不会重复提醒,后续新版本仍会正常提示。可用 `LOOP_AGENT_DISABLE_UPDATE_CHECK=1` 关闭检查。
|
|
79
83
|
- 新增 `loop-agent plan create`、`plan complete` 和 `plan check`,统一维护执行计划及其索引,并在生成 DAG 前发现遗漏或不一致。
|
|
80
84
|
- 目标项目可以选择复用本地 SDD skills,为需求、设计、实现和评审节点补充方法指引;未安装时保持原有流程。
|
|
81
|
-
- 新增 `
|
|
85
|
+
- 新增 `ai_workspace/loop-agent/architecture/` 全景、DAG 执行、Worker/Feature、运行态事实与演进五篇主题文档及目录索引,并在 npm package(不投影到 init)内可达。
|
|
82
86
|
- Worker 和 DAG 运行会固定本次使用的 loop-agent 版本与 skill 配置,避免执行过程中因环境变化产生不一致结果。
|
|
83
87
|
- 新增 `npm run self-host:canary -- --deterministic`,可在隔离环境中检查候选发布包是否能够接管常用 CLI、初始化和 DAG 流程。
|
|
84
88
|
- 新增可选的 `agent-worker` skill,为 Feature、Task、交付和失败恢复提供统一的操作指引。
|
|
85
|
-
- 文档站新增功能导览、架构导读与当前规划入口,并把文档收敛检查固化到
|
|
89
|
+
- 文档站新增功能导览、架构导读与当前规划入口,并把文档收敛检查固化到 `.agents/skills/loop-agent`,减少站上文档与仓库治理文档漂移。
|
|
86
90
|
- 前端 DAG 的 repo-local skills 补齐节点输入、输出、证据和失败规则;前端规范会优先查知识库,失败时回退到当前项目 `openSpec/`。
|
|
87
|
-
- 目标项目旧布局迁移:`init check-update`(只读)报告旧根 `
|
|
91
|
+
- 目标项目旧布局迁移:`init check-update`(只读)报告旧根 `ai_workspace/loop-agent/` / `.agents/skills/` 可安全迁移的 loop-agent owned 文件、空目录和 `harness.json` 中已废弃的模型字段;`init update --apply-safe` 迁移确认未修改的文件、清理空目录并清理废弃字段,本地修改过、来源不明或目标冲突的文件只进入人工决策,不会被覆盖或删除。
|
|
88
92
|
|
|
89
93
|
### 变更
|
|
90
94
|
|
|
91
95
|
- `observe serve` 提高对外访问稳定性:HTTP keep-alive 默认约 65s(避免 Node 5s 默认导致连接池复用失败),SSE 增加 keepalive comment 与 `X-Accel-Buffering: no`;新增 `--debug` 在 stderr 打印请求来源/方法/路径/状态/耗时。
|
|
92
96
|
- `observe serve` 允许显式绑定非 loopback 地址(如 `--host 0.0.0.0`)以便局域网访问;默认仍是 `127.0.0.1`,非本机绑定时会在 stderr 提示无鉴权风险。
|
|
93
|
-
- 根 README 在「核心概念」后增加极简「仓库地图」,方便一眼区分 `src
|
|
94
|
-
- 文档治理收敛:站上「当前规划」与 active plan 同步(无进行中计划时明确写出);`
|
|
95
|
-
- 活文档校准:Dynamic Workflow 路线图页首标明已落地 vs 设计输入(Pi-only);六个月规划第 1–2 月改为 archive/reports 指针;`repository-analysis` 冻结为基线快照,新增 `
|
|
97
|
+
- 根 README 在「核心概念」后增加极简「仓库地图」,方便一眼区分 `src/`、`.agents/skills/`、`.harness/`、`ai_workspace/loop-agent/` 等职责;细节仍以 `AGENTS.md` 与 `ai_workspace/loop-agent/README.md` 为准。
|
|
98
|
+
- 文档治理收敛:站上「当前规划」与 active plan 同步(无进行中计划时明确写出);`ai_workspace/loop-agent/README` 只索引核心契约与产物目录入口,progress/report 全量列表下沉到子目录 README;Dynamic Workflow 路线图迁入 `ai_workspace/loop-agent/design/`;补齐 design 漏索引与 DAG recovery playbook 入口。
|
|
99
|
+
- 活文档校准:Dynamic Workflow 路线图页首标明已落地 vs 设计输入(Pi-only);六个月规划第 1–2 月改为 archive/reports 指针;`repository-analysis` 冻结为基线快照,新增 `ai_workspace/loop-agent/reports/current-capability-summary.md`;落地 ADR 0001–0003(Pi-only、Task Pool 根、双树/docs-converge)。
|
|
96
100
|
- 统一 Feature Packet 的推荐目录和中文说明,相关检查同时兼容现有产品线目录。
|
|
97
|
-
- 目标项目初始化布局收敛:默认把 loop-agent 治理资料生成到 `ai_workspace/loop-agent/`,不再在目标项目根生成 `
|
|
101
|
+
- 目标项目初始化布局收敛:默认把 loop-agent 治理资料生成到 `ai_workspace/loop-agent/`,不再在目标项目根生成 `ai_workspace/loop-agent/`;`--profile full` 只把 repo-local skills 写到 `.agents/skills/`,不再生成根 `.agents/skills/`。
|
|
98
102
|
- `new-task` 不再预种 L1 空报告模板(`分析报告.md` / `实现计划.md` / `复盘报告.md`);任务 `artifacts/` 默认只保留 `修改记录.md` 与 `验证结果.md`,由 `promote-run` 从 completed run 回填。
|
|
99
103
|
- 运行期间修改 skill 不会影响当前任务,新配置会从下一次运行开始生效。
|
|
100
104
|
- Observe 自动刷新时会保留依赖图、检查器和日志的阅读位置,查看长时间任务时不再被频繁打断。
|
|
@@ -133,7 +137,7 @@
|
|
|
133
137
|
|
|
134
138
|
### 修改
|
|
135
139
|
|
|
136
|
-
- `design/` 已并入 `
|
|
140
|
+
- `design/` 已并入 `ai_workspace/loop-agent/design/`,设计资料统一从治理文档目录查找。
|
|
137
141
|
- Agent DAG 默认使用简体中文输出;可通过 `workflowPolicy.dag.outputLanguage: "en"` 切换为英文。
|
|
138
142
|
- Observe 和 Dashboard 更集中地展示运行状态、风险、模型、耗时和下一步,并减少已经结束任务中的无关诊断信息。
|
|
139
143
|
- 新增 `dag reconcile-run`,可在执行器已经停止后安全收尾历史失联的 DAG。
|
|
@@ -241,7 +245,7 @@
|
|
|
241
245
|
### 新增
|
|
242
246
|
|
|
243
247
|
- 可以在 `harness.json` 中为 Pi 和 Cursor 配置默认模型及不同复杂度的模型选择。
|
|
244
|
-
-
|
|
248
|
+
- 完整初始化会把包内 `skills/` 投影到目标项目 `.agents/skills/`,方便不同 Agent 工具发现同一套项目指引。
|
|
245
249
|
|
|
246
250
|
### 修改
|
|
247
251
|
|
package/README.md
CHANGED
|
@@ -45,6 +45,12 @@ loop-agent inspect
|
|
|
45
45
|
|
|
46
46
|
## 初始化目标项目
|
|
47
47
|
|
|
48
|
+
用户可以用自然语言驱动初始化与维护(这三类入口与目标项目 `AGENTS.md` 的“自然语言入口路由”一致):
|
|
49
|
+
|
|
50
|
+
- **初始化**:“初始化 loop-agent”“loop agent 初始化”“loop agent初始化”“loop-agent 初始化” — 执行完整确定性初始化闭环,补全 README/验证矩阵并复查。
|
|
51
|
+
- **更新校验**(只读):“初始化更新校验”“loop agent初始化更新校验”“检查初始化更新” — 只读运行 `loop-agent init check-update --repo-root . --markdown`,汇报动作与风险,不自动写入。
|
|
52
|
+
- **安全更新**(写入型):“初始化安全更新”“loop agent初始化安全更新”“应用初始化更新” — 先 `check-update`,再 `loop-agent init update --apply-safe`;只执行确定性安全动作,human decisions 存在时停下等用户。
|
|
53
|
+
|
|
48
54
|
在新项目中,最简单的用法是让当前 agent 执行初始化。需要更稳的执行约束时,可以使用下面这段完整提示词:
|
|
49
55
|
|
|
50
56
|
```text
|
|
@@ -67,7 +73,7 @@ loop-agent init --repo-root <target-repo> --profile full --merge
|
|
|
67
73
|
loop-agent init doctor --repo-root <target-repo>
|
|
68
74
|
```
|
|
69
75
|
|
|
70
|
-
`init instructions` 会输出给模型/Agent 执行完整初始化的指引包,不要求目标项目已有 `harness.json`。默认初始化会 merge 已有 `AGENTS.md`、`harness.json` 和 loop-agent 治理资料,生成语言无关的治理脚本矩阵、中文根 README 入口、`ai_workspace/loop-agent/` 目标项目治理资料、`.agents/skills/` repo-local skills、`harness.json` IDE schema 指引和 `.harness/` 骨架;不会在目标项目根目录生成 `skills/`,也不会把 loop-agent 生成的治理资料写到根 `docs/`。已有 README 会保留用户正文并插入/更新 loop-agent managed block。初始化还会向 `.gitignore` 合并一个 loop-agent managed block(`# LOOP_AGENT_INIT_START/END`),把 `.harness/tasks/*`、`.harness/dag-runs/*`、`.harness/runs/*`、`.harness/live/`、`.harness/cache/`、`.harness/init-surface.json`、`.harness/task-pool/*`、`.task-pool/`、`.worktrees/`
|
|
76
|
+
`init instructions` 会输出给模型/Agent 执行完整初始化的指引包,不要求目标项目已有 `harness.json`。默认初始化会 merge 已有 `AGENTS.md`、`harness.json` 和 loop-agent 治理资料,生成语言无关的治理脚本矩阵、中文根 README 入口、`ai_workspace/loop-agent/` 目标项目治理资料、`.agents/skills/` repo-local skills、`harness.json` IDE schema 指引和 `.harness/` 骨架;不会在目标项目根目录生成 `skills/`,也不会把 loop-agent 生成的治理资料写到根 `docs/`。已有 README 会保留用户正文并插入/更新 loop-agent managed block。初始化还会向 `.gitignore` 合并一个 loop-agent managed block(`# LOOP_AGENT_INIT_START/END`),把 `.harness/tasks/*`、`.harness/dag-runs/*`、`.harness/runs/*`、`.harness/live/`、`.harness/cache/`、`.harness/init-surface.json`、`.harness/task-pool/*`、`.task-pool/`、`.agents/skills/*/node_modules/`、`.worktrees/` 等个人/会话运行态事实和 repo-local skill 本地依赖忽略掉,同时保留 `.harness/prompts/` 和目录占位可共享,不会整目录忽略 `.harness/`,也不会覆盖用户已有的 ignore 规则。
|
|
71
77
|
|
|
72
78
|
新初始化会写入 `.harness/init-surface.json`,记录当前 controller 版本、初始化投影文件 hash 和 manifest hash。已用旧版本初始化的目标项目,可以用下面的维护入口对齐新版本初始化能力:
|
|
73
79
|
|
|
@@ -95,7 +101,7 @@ loop-agent dag validate --dag <temp-dir>/<task-id>-dag.json --strict-models --st
|
|
|
95
101
|
loop-agent run-dag --dag <temp-dir>/<task-id>-dag.json --cwd .
|
|
96
102
|
```
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
`dag run-task` 会先尊重显式声明的专用 `taskKind`。对于默认 `standard` 任务,它会根据任务标题、`source/需求.md` 和结构化 `allowedPaths` 做保守、确定性的需求分类;只有高置信的前端实现需求才会自动进入前端专用节点链。只读 `frontend-mock-assess-pi` 在计划前读取 Mock/API/schema 证据,并通过确定性 contract gate 选择原生 Mock、浏览器拦截、请求适配层、`not-needed` 或明确阻塞;它只能使用 DAG 生成时已固化的验证入口。可选 `task.json.frontendMock` 可设置 `auto|required|disabled`、既有服务目录和专项验证命令;不安全或不完整的显式 required 合同不会生成 writer。真实请求始终是默认路径,唯一写节点仍是 `frontend-implement-pi`。自动分类不会覆盖显式 profile、`workflowPolicy` 或 supervised quality gate。后端、混合或证据不足的需求继续使用通用模板,也不会自动进入 `backend-test`。Mock 验证只证明前端状态与交互;未实际请求后端时,收尾保留 `Frontend status: mock-validated`、`Real integration: pending`,并给出 `<task-id>-real-api-integration-verify`。该复验任务不会自动创建或执行,需要在后端就绪后显式运行。
|
|
99
105
|
|
|
100
106
|
测试结论写回与业务知识图谱(结构化 Git,非 RAG):
|
|
101
107
|
|
|
@@ -191,8 +197,9 @@ Task Pool **state identity** 进一步固定为 feature-scoped 复合键 `{ feat
|
|
|
191
197
|
## 核心概念
|
|
192
198
|
|
|
193
199
|
- **Agent DAG**:把一次任务拆成 contract、scout、plan、implement、verify、closeout 等可审查节点。
|
|
200
|
+
- **任务源绑定与恢复**:新生成 DAG 会冻结任务源路径、SHA-256 和显式 `REQ/BR/AC`;前端计划漏号时会在 writer 前阻断。运行中断后应修复 task source 并重新生成完整 DAG,不要用二手摘要拼接 impl-only 后半段。
|
|
194
201
|
- **`.harness/`**:记录 task、DAG run、one-shot run、cache 和 live state 等运行态事实。
|
|
195
|
-
- **`harness.json`**:描述项目名、治理根目录、模型路由、executor
|
|
202
|
+
- **`harness.json`**:描述项目名、治理根目录、模型路由、executor 和验证脚本;目标项目中的 `ai_workspace/loop-agent/templates/harness.schema.json` 为 IDE 提供补全和字段说明,运行时仍由 Zod schema 校验。
|
|
196
203
|
- **repo-local skills**:目标项目本地 skills 统一放在 `.agents/skills/`,便于项目定制 agent 行为并让外部 agent 自动发现。DAG skill 解析顺序为:用户配置目录 → `.agents/skills/` → 发布包内置 `skills/`。
|
|
197
204
|
- **可选 SDD skill 嵌入**:如果目标项目在 `.agents/skills/` 中提供 `SDD-requirement-analysis`、`SDD-design-analysis`、`SDD-implementation-test-review`,`dag run-task` 会把它们作为知识与方法补充追加到对应的 Contract、Plan、Implement/Repair、Verify、Review 节点。loop-agent 仍控制 DAG、状态、写入边界、验证和收口;不会自动运行 SDD 初始化/扫描 skill,也不会推进 `ai_workspace` 状态或归档。没有这些 repo-local skills 时,生成结果保持原有默认流程。
|
|
198
205
|
- **run-owned skill snapshot**:新 DAG run 会在任何节点执行前,把本次实际注入 prompt 的 resolved skill profiles 冻结到 run 自己的 `.runtime/skill-snapshot.json`。后续节点、dynamic child、approve/resume 都使用同一份 hash-anchored snapshot;run 内修改 skill 只会从下一次 run 生效。
|
|
@@ -223,6 +230,8 @@ Task Pool **state identity** 进一步固定为 feature-scoped 复合键 `{ feat
|
|
|
223
230
|
## 能力概览
|
|
224
231
|
|
|
225
232
|
- 生成、校验、执行和汇总 Agent DAG。
|
|
233
|
+
- 通过 `eval replay` / `eval report` 对 completed DAG evidence 做 hash-anchored、deterministic 的只读重放比较;M1 不执行模型也不授权候选晋升。
|
|
234
|
+
- 通过 `eval candidate register|show|list|transition` 管理不可变 Candidate Bundle 与 append-only lifecycle(M2 registry MVP);不跑 live Pi/DAG,不移动 incumbent alias。
|
|
226
235
|
- 从任务说明生成标准 DAG,并按依赖顺序运行规划、实现、验证和收口节点。
|
|
227
236
|
- 维护 `loop` 长程任务状态,包括目标、轮次、信号、验证事实和收口草稿。
|
|
228
237
|
- 通过 Pi executor 执行只读规划、评审、诊断和有边界写入(唯一受治理 Agent writer)。
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
1
|
+
import { readFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
import { resolveAutoRoutingProfile, requiresSupervisedQualityGate, } from "../../workflows/dag/governance-profile.js";
|
|
3
5
|
import { resolveShellCommands } from "../../executors/shell-executor.js";
|
|
4
6
|
import { parseDagSpec } from "../../workflows/dag/types.js";
|
|
@@ -6,7 +8,6 @@ import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
|
6
8
|
import { loadHarnessManifest } from "../../governance/harness.js";
|
|
7
9
|
import { assertExecPlanIndexConsistent } from "../../governance/exec-plans.js";
|
|
8
10
|
import { defaultHybridDagOutputPath, initHybridDagFromTask, } from "../../workflows/dag/init-hybrid.js";
|
|
9
|
-
import { loadTaskConfig } from "../../task/runtime.js";
|
|
10
11
|
import { validateDagUseCase } from "./validate-dag.js";
|
|
11
12
|
import { runDagUseCase } from "./run-dag.js";
|
|
12
13
|
const PLACEHOLDER_WRITESET_MARKER = "REPLACE/WITH";
|
|
@@ -202,11 +203,6 @@ export async function generateTaskDagUseCase(input) {
|
|
|
202
203
|
// before any expensive DAG generation or execution. Empty/consistent
|
|
203
204
|
// repos stay compatible so the default DAG flow is unblocked.
|
|
204
205
|
await assertExecPlanIndexConsistent(repoRoot);
|
|
205
|
-
const taskConfig = await loadTaskConfig(repoRoot, parsed.taskId);
|
|
206
|
-
const isFrontendImplementationTask = taskConfig.taskKind === "frontend-implementation";
|
|
207
|
-
const isBackendTestTask = taskConfig.taskKind === "backend-test";
|
|
208
|
-
const isKnowledgeSyncTask = taskConfig.taskKind === "knowledge-sync";
|
|
209
|
-
const isKnowledgeGraphBootstrapTask = taskConfig.taskKind === "knowledge-graph-bootstrap";
|
|
210
206
|
const candidateResult = await initHybridDagFromTask(repoRoot, parsed.taskId, {
|
|
211
207
|
outputPath: parsed.outputPath,
|
|
212
208
|
template: "standard-dag",
|
|
@@ -219,12 +215,16 @@ export async function generateTaskDagUseCase(input) {
|
|
|
219
215
|
codeChange: [],
|
|
220
216
|
reasons: ["dag run-task validate did not report governanceProfile"],
|
|
221
217
|
});
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
profileRouting.
|
|
225
|
-
profileRouting.
|
|
226
|
-
|
|
227
|
-
|
|
218
|
+
const hasExplicitSpecializedTaskKind = candidateResult.templateSelection.source === "taskKind";
|
|
219
|
+
const hasSafeAutomaticTaskSourceRoute = candidateResult.templateSelection.source === "task-source" &&
|
|
220
|
+
profileRouting.selectedByProfile !== "supervised" &&
|
|
221
|
+
profileRouting.selectedTemplate !== "supervised-implementation";
|
|
222
|
+
if (hasExplicitSpecializedTaskKind || hasSafeAutomaticTaskSourceRoute) {
|
|
223
|
+
profileRouting.selectedTemplate = candidateResult.template;
|
|
224
|
+
profileRouting.source = hasExplicitSpecializedTaskKind
|
|
225
|
+
? "taskKind"
|
|
226
|
+
: "task-source";
|
|
227
|
+
profileRouting.routingReasons = candidateResult.templateSelection.reasons;
|
|
228
228
|
if (parsed.profile === "auto") {
|
|
229
229
|
profileRouting.selectedByProfile =
|
|
230
230
|
resolveAutoRoutingProfile(profileRouting.candidateProfile);
|
|
@@ -233,56 +233,14 @@ export async function generateTaskDagUseCase(input) {
|
|
|
233
233
|
profileRouting.selectedByProfile = parsed.profile;
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
|
-
|
|
237
|
-
profileRouting.selectedTemplate = "backend-test-dag";
|
|
238
|
-
profileRouting.source = "taskKind";
|
|
239
|
-
profileRouting.routingReasons = [
|
|
240
|
-
'taskKind "backend-test" selects the dedicated backend test DAG template',
|
|
241
|
-
];
|
|
242
|
-
if (parsed.profile === "auto") {
|
|
243
|
-
profileRouting.selectedByProfile =
|
|
244
|
-
resolveAutoRoutingProfile(profileRouting.candidateProfile);
|
|
245
|
-
}
|
|
246
|
-
else if (parsed.profileExplicit) {
|
|
247
|
-
profileRouting.selectedByProfile = parsed.profile;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
if (isKnowledgeSyncTask) {
|
|
251
|
-
profileRouting.selectedTemplate = "knowledge-sync-dag";
|
|
252
|
-
profileRouting.source = "taskKind";
|
|
253
|
-
profileRouting.routingReasons = [
|
|
254
|
-
'taskKind "knowledge-sync" selects the dedicated knowledge-sync DAG template',
|
|
255
|
-
];
|
|
256
|
-
if (parsed.profile === "auto") {
|
|
257
|
-
profileRouting.selectedByProfile =
|
|
258
|
-
resolveAutoRoutingProfile(profileRouting.candidateProfile);
|
|
259
|
-
}
|
|
260
|
-
else if (parsed.profileExplicit) {
|
|
261
|
-
profileRouting.selectedByProfile = parsed.profile;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
if (isKnowledgeGraphBootstrapTask) {
|
|
265
|
-
profileRouting.selectedTemplate = "knowledge-graph-bootstrap-dag";
|
|
266
|
-
profileRouting.source = "taskKind";
|
|
267
|
-
profileRouting.routingReasons = [
|
|
268
|
-
'taskKind "knowledge-graph-bootstrap" selects the dedicated knowledge-graph bootstrap DAG template',
|
|
269
|
-
];
|
|
270
|
-
if (parsed.profile === "auto") {
|
|
271
|
-
profileRouting.selectedByProfile =
|
|
272
|
-
resolveAutoRoutingProfile(profileRouting.candidateProfile);
|
|
273
|
-
}
|
|
274
|
-
else if (parsed.profileExplicit) {
|
|
275
|
-
profileRouting.selectedByProfile = parsed.profile;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
const initResult = profileRouting.selectedTemplate === "standard-dag"
|
|
236
|
+
const initResult = profileRouting.selectedTemplate === candidateResult.template
|
|
279
237
|
? candidateResult
|
|
280
238
|
: await initHybridDagFromTask(repoRoot, parsed.taskId, {
|
|
281
239
|
outputPath: parsed.outputPath,
|
|
282
240
|
template: profileRouting.selectedTemplate,
|
|
283
241
|
});
|
|
284
242
|
const outputPath = initResult.outputPath;
|
|
285
|
-
const validateSummary = profileRouting.selectedTemplate ===
|
|
243
|
+
const validateSummary = profileRouting.selectedTemplate === candidateResult.template
|
|
286
244
|
? candidateValidateSummary
|
|
287
245
|
: await validateDagUseCase(buildValidateInput(repoRoot, outputPath, parsed));
|
|
288
246
|
const governanceProfile = validateSummary.governanceProfile ?? {
|
|
@@ -317,6 +275,17 @@ export async function generateTaskDagUseCase(input) {
|
|
|
317
275
|
};
|
|
318
276
|
}
|
|
319
277
|
await assertSafeForExecution(outputPath);
|
|
278
|
+
// Mirror worker run-task layout so Observe can find dag-events.jsonl under
|
|
279
|
+
// .harness/task-pool/observability/runs/<runId>/ (CLI path, not Task Pool state).
|
|
280
|
+
const runId = parsed.runId ?? `dag-${Date.now()}-${randomUUID().slice(0, 8)}`;
|
|
281
|
+
const eventsJsonlPath = path.join(parsed.cwd, ".harness", "task-pool", "observability", "runs", runId, "dag-events.jsonl");
|
|
282
|
+
try {
|
|
283
|
+
await mkdir(path.dirname(eventsJsonlPath), { recursive: true });
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
287
|
+
throw new Error(`failed to create dag events directory for observe: ${path.dirname(eventsJsonlPath)}: ${message}`);
|
|
288
|
+
}
|
|
320
289
|
const runSummary = await runDagUseCase({
|
|
321
290
|
repoRoot,
|
|
322
291
|
dagPath: outputPath,
|
|
@@ -324,7 +293,8 @@ export async function generateTaskDagUseCase(input) {
|
|
|
324
293
|
initOnly: parsed.initOnly,
|
|
325
294
|
dryRun: parsed.dryRun,
|
|
326
295
|
maxConcurrent: parsed.maxConcurrent,
|
|
327
|
-
runId
|
|
296
|
+
runId,
|
|
297
|
+
eventsJsonlPath,
|
|
328
298
|
canvasPath: parsed.canvasPath,
|
|
329
299
|
canvasName: parsed.canvasName,
|
|
330
300
|
canvasesDir: parsed.canvasesDir,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** Deterministic JSON stringify: object keys sorted at every level. */
|
|
3
|
+
export function stableStringify(value) {
|
|
4
|
+
return JSON.stringify(canonicalize(value));
|
|
5
|
+
}
|
|
6
|
+
function canonicalize(value) {
|
|
7
|
+
if (value === null || typeof value !== "object") {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
return value.map((item) => canonicalize(item));
|
|
12
|
+
}
|
|
13
|
+
const obj = value;
|
|
14
|
+
const keys = Object.keys(obj).sort();
|
|
15
|
+
const out = {};
|
|
16
|
+
for (const key of keys) {
|
|
17
|
+
out[key] = canonicalize(obj[key]);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
export function normalizeContentSha(value) {
|
|
22
|
+
const trimmed = value.trim();
|
|
23
|
+
const bare = trimmed.startsWith("sha256:")
|
|
24
|
+
? trimmed.slice("sha256:".length)
|
|
25
|
+
: trimmed;
|
|
26
|
+
if (!/^[a-f0-9]{64}$/i.test(bare)) {
|
|
27
|
+
throw new Error(`invalid content sha256: ${value}`);
|
|
28
|
+
}
|
|
29
|
+
return bare.toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
export function formatContentSha(hex) {
|
|
32
|
+
return `sha256:${normalizeContentSha(hex)}`;
|
|
33
|
+
}
|
|
34
|
+
export function normalizeContentRefs(refs) {
|
|
35
|
+
const normalized = refs.map((ref) => ({
|
|
36
|
+
path: ref.path.replace(/\\/g, "/"),
|
|
37
|
+
sha256: normalizeContentSha(ref.sha256),
|
|
38
|
+
}));
|
|
39
|
+
normalized.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
for (const ref of normalized) {
|
|
42
|
+
if (seen.has(ref.path)) {
|
|
43
|
+
throw new Error(`duplicate content ref path: ${ref.path}`);
|
|
44
|
+
}
|
|
45
|
+
seen.add(ref.path);
|
|
46
|
+
}
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Canonical payload for bundleHash.
|
|
51
|
+
* Excludes candidateId, createdAt, description, bundleHash, absolute paths,
|
|
52
|
+
* registry location, and any mutable lifecycle state.
|
|
53
|
+
*/
|
|
54
|
+
export function buildCanonicalBundlePayload(manifest) {
|
|
55
|
+
return {
|
|
56
|
+
schemaVersion: 1,
|
|
57
|
+
candidateKind: manifest.candidateKind,
|
|
58
|
+
parentCandidateId: manifest.parentCandidateId ?? null,
|
|
59
|
+
contentRefs: normalizeContentRefs(manifest.contentRefs),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function computeBundleHash(manifest) {
|
|
63
|
+
const payload = buildCanonicalBundlePayload(manifest);
|
|
64
|
+
const digest = createHash("sha256")
|
|
65
|
+
.update(stableStringify(payload))
|
|
66
|
+
.digest("hex");
|
|
67
|
+
return formatContentSha(digest);
|
|
68
|
+
}
|
|
69
|
+
export function sha256Hex(content) {
|
|
70
|
+
return createHash("sha256").update(content).digest("hex");
|
|
71
|
+
}
|
|
72
|
+
export function eventHashHex(payload) {
|
|
73
|
+
return createHash("sha256").update(stableStringify(payload)).digest("hex");
|
|
74
|
+
}
|
|
75
|
+
export const LIFECYCLE_GENESIS_HASH = "0".repeat(64);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { loadManifestInputFromPath, listCandidateIds, materializeManifest, readCandidateRecord, registerCandidateManifest, transitionCandidateLifecycle, } from "../../infrastructure/evaluation/candidate-store.js";
|
|
2
|
+
export async function registerCandidate(input) {
|
|
3
|
+
const raw = await loadManifestInputFromPath(input.repoRoot, input.manifestPath);
|
|
4
|
+
const manifest = await materializeManifest(input.repoRoot, raw);
|
|
5
|
+
return registerCandidateManifest({
|
|
6
|
+
repoRoot: input.repoRoot,
|
|
7
|
+
manifest,
|
|
8
|
+
now: input.now,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export async function showCandidate(input) {
|
|
12
|
+
return readCandidateRecord(input.repoRoot, input.candidateId);
|
|
13
|
+
}
|
|
14
|
+
export async function listCandidates(input) {
|
|
15
|
+
const ids = await listCandidateIds(input.repoRoot);
|
|
16
|
+
const rows = [];
|
|
17
|
+
for (const candidateId of ids) {
|
|
18
|
+
const record = await readCandidateRecord(input.repoRoot, candidateId);
|
|
19
|
+
rows.push({
|
|
20
|
+
candidateId: record.manifest.candidateId,
|
|
21
|
+
bundleHash: record.manifest.bundleHash,
|
|
22
|
+
candidateKind: record.manifest.candidateKind,
|
|
23
|
+
status: record.status,
|
|
24
|
+
promotionApplied: false,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return rows;
|
|
28
|
+
}
|
|
29
|
+
export async function transitionCandidate(input) {
|
|
30
|
+
return transitionCandidateLifecycle(input);
|
|
31
|
+
}
|
|
32
|
+
export function formatCandidateMarkdown(record) {
|
|
33
|
+
const lines = [
|
|
34
|
+
`# Candidate: ${record.manifest.candidateId}`,
|
|
35
|
+
"",
|
|
36
|
+
`- status: \`${record.status}\``,
|
|
37
|
+
`- kind: \`${record.manifest.candidateKind}\``,
|
|
38
|
+
`- bundleHash: \`${record.manifest.bundleHash}\``,
|
|
39
|
+
`- parent: \`${record.manifest.parentCandidateId ?? "null"}\``,
|
|
40
|
+
`- promotionApplied: \`false\` (registry lifecycle only; no alias/incumbent)`,
|
|
41
|
+
"",
|
|
42
|
+
"## Content refs",
|
|
43
|
+
"",
|
|
44
|
+
...record.manifest.contentRefs.map((ref) => `- \`${ref.path}\` — \`${ref.sha256}\``),
|
|
45
|
+
"",
|
|
46
|
+
"## Lifecycle",
|
|
47
|
+
"",
|
|
48
|
+
...record.events.map((event) => `- #${event.seq} ${event.from ?? "∅"} → ${event.to}: ${event.reason} (${event.at})`),
|
|
49
|
+
"",
|
|
50
|
+
];
|
|
51
|
+
return `${lines.join("\n")}\n`;
|
|
52
|
+
}
|