@tea-agent/loop-agent 0.4.0 → 0.6.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 +2 -2
- package/CHANGELOG.md +48 -38
- package/README.md +3 -3
- package/dist/application/dag/args.js +9 -1
- package/dist/application/dag/run-dag.js +16 -2
- package/dist/application/dag/validate-dag.js +14 -1
- package/dist/cli/command-definitions.js +22 -4
- package/dist/cli/help.js +3 -2
- package/dist/cli/program.js +7 -5
- package/dist/commands/import-prd.js +76 -0
- package/dist/commands/init.js +230 -32
- package/dist/commands/instructions.js +90 -58
- package/dist/executors/config-core.js +3 -2
- package/dist/executors/dag-pi-executor.js +1 -0
- package/dist/executors/model-routing.js +43 -0
- package/dist/executors/pi-sdk-executor.js +63 -1
- package/dist/governance/manifest-types.js +9 -1
- package/dist/shared/preview.js +39 -0
- package/dist/task/source-references.js +221 -0
- package/dist/worker/cli.js +62 -1
- package/dist/worker/loop-agent/loop-agent-client.js +97 -5
- package/dist/worker/materialize/harness-task-materializer.js +162 -5
- package/dist/worker/observability/event-store.js +82 -0
- package/dist/worker/observability/events.js +79 -0
- package/dist/worker/observability/progress-composite.js +33 -0
- package/dist/worker/observability/read-model.js +1013 -0
- package/dist/worker/observability/snapshot-store.js +43 -0
- package/dist/worker/observability/types.js +1 -0
- package/dist/worker/observe/paths.js +64 -0
- package/dist/worker/observe/routes.js +423 -0
- package/dist/worker/observe/server.js +61 -0
- package/dist/worker/observe/static/app.js +1419 -0
- package/dist/worker/observe/static/index.html +63 -0
- package/dist/worker/observe/static/styles.css +613 -0
- package/dist/worker/pool/failure-routing.js +41 -6
- package/dist/worker/pool/run-store.js +59 -1
- package/dist/worker/progress-reporter.js +0 -18
- package/dist/worker/run-task/run-task.js +327 -92
- package/dist/worker/runner/run-ready.js +112 -4
- package/dist/workflows/dag/event-observer.js +132 -0
- package/dist/workflows/dag/init-hybrid.js +150 -26
- package/dist/workflows/dag/observer-compose.js +52 -0
- package/dist/workflows/dag/skill-instructions.js +4 -0
- package/dist/workflows/dag/types.js +1 -1
- package/dist/workflows/dag/validate.js +3 -2
- package/docs/README.md +2 -0
- package/docs/architecture/runtime-boundaries.md +18 -3
- package/docs/design/README.md +22 -9
- package/docs/exec-plans/active/README.md +6 -1
- package/docs/exec-plans/completed/README.md +12 -0
- package/docs/init-surface.manifest.json +32 -2
- package/docs/loop-agent-harness.md +13 -0
- package/docs/reports/README.md +4 -0
- package/docs/templates/agent-dag.base.json +1 -1
- package/docs/templates/agent-dag.final-verification.json +1 -1
- package/docs/templates/agent-dag.supervised-implementation.json +1 -1
- package/docs/templates/hybrid-dag.json +1 -1
- package/docs/templates/worker-dogfood-evidence.md +52 -0
- package/docs/templates/worker-dogfood-setup.md +48 -0
- package/examples/example-dag.json +1 -1
- package/examples/hybrid-loop-agent-dag.json +1 -1
- package/harness.json +5 -29
- package/package.json +6 -6
- package/skills/loop-agent/SKILL.md +5 -3
- package/skills/loop-agent/references/command-reference.md +12 -3
- package/skills/loop-agent/references/harness-policy.md +7 -3
- package/skills/loop-agent/references/task-workflow.md +8 -3
package/AGENTS.md
CHANGED
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
- `src/`:loop-agent 运行时代码
|
|
69
69
|
- `test/`:Vitest 测试套件
|
|
70
70
|
- `bin/loop-agent.js`:CLI 可执行入口
|
|
71
|
-
- `skills/`:loop-agent 和 DAG 模板引用的本地 skill
|
|
71
|
+
- `skills/`:loop-agent 和 DAG 模板引用的本地 skill 指令与参考资料;`init --profile full` 还会把同一份 skills 镜像到目标项目的 `.agents/skills/`(外部 agent 兼容路径,包内仍只带 `skills/`)。初始化还会向目标项目 `.gitignore` 合并 loop-agent managed block,忽略 `.harness/tasks/*`、`.harness/dag-runs/*`、`.harness/runs/*`、`.harness/init-surface.json`、`.task-pool/`、`.worktrees/` 等运行态事实,但保留 `.harness/prompts/` 和目录占位可共享,不会整目录忽略 `.harness/`。
|
|
72
72
|
- `.harness/`:任务、DAG、run、cache 和 live state 等运行态目录
|
|
73
73
|
- `docs/`:治理文档、计划、报告和模板
|
|
74
74
|
- `website/`:Docusaurus 用户文档站
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
- 优先沿用现有 helper、目录边界和局部模式,再考虑新增抽象。
|
|
82
82
|
- 长期决策写入 `docs/`,不要只留在聊天里。
|
|
83
83
|
- 面向使用者的新增、修改、删除或修复,应同步更新根目录 `CHANGELOG.md`;保持版本级摘要即可,不写过细技术细节。
|
|
84
|
-
- 涉及 `loop-agent init` 或目标项目投影的改动,必须同步考虑目标项目生成物:`AGENTS.md`、`README.md`、`harness.json`、`docs/`、`scripts/`、`skills/`、`.harness/prompts
|
|
84
|
+
- 涉及 `loop-agent init` 或目标项目投影的改动,必须同步考虑目标项目生成物:`AGENTS.md`、`README.md`、`harness.json`、`docs/`、`scripts/`、`skills/`、`.agents/skills/`(skills 镜像)、`.harness/prompts`、`.gitignore`(loop-agent runtime managed block)和 npm 包内置 assets。
|
|
85
85
|
- 涉及初始化能力演化时,按 `docs/init-surface.manifest.json` 与 `scripts/check-init-evolution-needed.sh` 分级处理:小改 advisory,中等 surface-check,高影响才需要模型审查;不要把所有小改动升级成重流程。
|
|
86
86
|
- 通用脚本、skill 和模板可以复制或投影;项目相关 README、验证命令、发布/维护脚本必须基于模板和目标项目真实文件生成,不假定目标项目是 TypeScript、Node、前端、后端或工具项目。
|
|
87
87
|
- 涉及 CLI command、skill entry、runtime boundary、import 方向或发布包范围时,同步更新对应文档、catalog/definition、治理脚本和测试,避免 README、skill reference、CLI help、npm 包内容互相漂移。
|
package/CHANGELOG.md
CHANGED
|
@@ -2,13 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
这里记录每个版本面向使用者的主要变化。保持简短即可:新增、修改、修复或删除了什么,不需要展开实现细节。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## [0.6.0] - 2026-07-10
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
|
|
9
|
+
- Observe UI 中文化:Dashboard 默认突出进行中的 DAG runs(进度、当前节点、已用时),补充 DAG 元信息(title/startedAt/finishedAt/ranks/节点 outputPreview)与 Rank 泳道详情;read-model 只增字段,保持 local-only 只读。
|
|
10
|
+
- Pi SDK DAG 节点在运行中 best-effort 追加 `session-events.jsonl` 至 `.harness/dag-runs/.../<nodeId>/`(过程事件落盘,写失败不影响节点成败;CLI 后端无过程日志)。
|
|
11
|
+
- Observe DAG 详情新增过程时间线:GET `/api/dag-runs/:id/nodes/:nodeId/session-events?after=N` 尾读 `session-events.jsonl`,UI 每 2s 轮询展示工具/助手过程事件(中文标签)。
|
|
12
|
+
- 文档站同步 Observe 指南:`website/docs/guides/observe-ui.md`,并更新 intro / CLI / Agent DAG / 安装与首次运行入口。
|
|
13
|
+
- 新增 `loop-agent import-prd <task-id> --file <path>`:把用户原始 PRD 原样复制到 `source/references/`,写入 `source-manifest.json` 与 `task.json.referenceDocs`,避免 AI 直接改写权威需求。
|
|
14
|
+
- `dag run-task` / hybrid source 加载时会物化 `task.json.referenceDocs` 到 `source/references/`;source 超 2000 字符时仍截断进 prompt,但会保留完整源路径引用(如 `source/需求.md` / `source/references/...`),禁止静默丢弃尾部且不凭空补全。
|
|
15
|
+
- DAG objective / successCriteria 提取兼容 `目标/完成标准/Acceptance References` 等常见标题,并跳过 TaskSpec 元数据行。
|
|
16
|
+
- Worker materialize 生成的 `source/需求.md` 现在带权威声明、`source/references` 路径与 hash 追溯,并把 `acceptance_refs` 展开为短摘要(不再只剩 AC ID);review-gated/supervised 的 `review-pi` 强制三方对照 references + 派生契约 + 实现。
|
|
17
|
+
|
|
18
|
+
### 修复
|
|
19
|
+
|
|
20
|
+
- 修复 GitHub Actions governance job 未安装 `ripgrep`,导致依赖 `rg` 的仓库治理检查失败并跳过 test job 的问题。
|
|
21
|
+
- 修复 Observe UI 历史 worker run 详情 404、未校验 event route identifier 造成的 scoped event path traversal,以及失败的 doctor/closeout evidence step 被错误显示为成功的问题。
|
|
22
|
+
- 修复 Worker provider/executor 配置失败被误导为 `SpecUnclear` 的路由:已知 provider、model、executor、凭证与 thinking-level 配置错误现在归为 `EnvFailure`,并保留原始 DAG/runner 事实。
|
|
23
|
+
|
|
24
|
+
### 新增
|
|
25
|
+
|
|
26
|
+
- 新增 `agent-worker observe` 本地只读可观测 UI:`observe serve` 启动 127.0.0.1 只读 HTTP server(REST + SSE),`observe snapshot` 输出全局快照 JSON;提供 Dashboard / Batch Detail / Run Detail / DAG Detail / Failure Inbox 五个静态视图,可实时查看 batch/task/step/command 进展、stdout/stderr tail、DAG node 状态与失败 report/doctor/handoff 链接。底层为结构化事件流(`.task-pool/observability/`)、`LoopAgentClient` 流式输出与 heartbeat、`loop-agent run-dag --events-jsonl` DAG node 级事件,以及 stale/quiet/timeout-risk liveness 诊断。仅读取运行事实,不提供写操作。
|
|
27
|
+
- 新增 `agent-worker task retry <task-id> --repo <repo>`:仅将 `Failed` Task Pool state 显式 requeue,保留失败运行历史和 handoff,并保证下一次 batch 使用新的 `workerRunId`。`src/worker/**` 同时进入架构边界硬检查,禁止 in-process import CLI、commands 或 application。
|
|
28
|
+
|
|
29
|
+
## [0.5.0] - 2026-07-09
|
|
30
|
+
|
|
31
|
+
### 新增
|
|
32
|
+
|
|
33
|
+
- Agent DAG 模型矩阵现由 `harness.json.executors.<pi|cursor>` 驱动:支持 `defaultModel` 与可选 `LOW`/`MED`/`HIGH`(档位优先于 defaultModel,再回退代码默认)。`dag run-task` 生成 `executorModels` 时读取该配置;`--strict-models` 对照 harness 解析结果。
|
|
34
|
+
- `loop-agent init`(full / minimal)现在会在目标项目 `.gitignore` 合并 loop-agent managed block(`# LOOP_AGENT_INIT_START/END`):忽略 `.harness/tasks/*`、`.harness/dag-runs/*`、`.harness/runs/*`、`.harness/live/`、`.harness/cache/`、`.harness/*.log`、`.harness/init-surface.json`、`.task-pool/`、`.worktrees/` 等个人/会话运行态事实,同时保留 `.harness/prompts/` 和目录占位(`.gitkeep`)可共享。已有 `.gitignore` 时只合并 managed block,不覆盖用户规则;`loop-agent init check-update` 对缺失或过期 block 给出 deterministic `refresh-managed-block`,`update --apply-safe` 可应用;`loop-agent init doctor` 新增 `gitignore loop-agent block` 检查;`docs/init-surface.manifest.json` 登记 `.gitignore`。注意不会整目录忽略 `.harness/`。
|
|
35
|
+
- `loop-agent init --profile full` 现在双写 skills:除了原有的目标项目 `skills/`,还会把同一份 skills 镜像到 `.agents/skills/`(外部 agent 如 OpenCode 的自动发现路径);`skills/` 仍是 loop-agent runtime 的首选主路径,`--profile minimal` 仍同时跳过两处。DAG skill 解析候选路径增加 `cwd/.agents/skills/<name>/SKILL.md`(位于 `skills/` 之后、发布包内置之前),`init doctor` 额外检查 `.agents/skills/loop-agent/SKILL.md`,`docs/init-surface.manifest.json` 记录 `.agents/skills` 相关 surface。
|
|
36
|
+
|
|
37
|
+
### 修改
|
|
38
|
+
|
|
39
|
+
- 废弃顶层 `models` / `modelProfiles` / `modelRouting` 作为 DAG 路由来源:schema 仍兼容旧文件,但默认 `harness.json` 与 `loop-agent init` 新投影不再写出这些字段;`--provider/--model` 改为写入 `executors.pi.defaultModel`。旧目标项目若仍含 `models`,check-update 会将 harness 差异作为 model-merge 任务提示迁移到 `executors`。
|
|
40
|
+
- `loop-agent init` 默认不再向目标项目投影 `executors.cursor`(Cursor 为包开发者可选能力);仅当目标已有 `executors.cursor` 时保留。
|
|
41
|
+
- 去掉 Pi executor 的无用 `requiresApiKey` 投影;`init check-update` / `update --apply-safe` 可对目标项目安全剥离 `executors.pi.requiresApiKey`,Cursor 的 `requiresApiKey` 仍保留。
|
|
42
|
+
|
|
43
|
+
## [0.4.0] - 2026-07-09
|
|
6
44
|
|
|
7
45
|
### 新增
|
|
8
46
|
|
|
9
47
|
- 新增 `agent-worker batch run-ready` 运行时进度反馈:批次启动、每个 task 的 preflight/materialize/dag 生成与校验/run-dag 执行/report 决策阶段会实时打到 stderr,stdout 仍只保留最终 JSON;新增 `--quiet` 选项可关闭进度,解决长任务静默被误判为卡死的问题。
|
|
10
48
|
- 新增 `agent-worker batch run-ready --pi-model <model>` worker 专属 smoke 覆盖:提供时重写生成 DAG 的 `executorModels.pi.{LOW,MED,HIGH}` 全部指向该模型,并对本次 `dag validate` 去掉 `--strict-models`;不改动 `loop-agent` canonical 模型矩阵或 `pi-prompt` 默认模型,典型用于 MED 模型 provider 抽风时让 dogfood smoke 改跑 `gpt-5.3-codex-spark`。
|
|
11
|
-
|
|
12
49
|
- 新增 Worker TaskSpec v0.1 schema、`validateTaskSpec` 三层校验、`risk_level` 到 task complexity 的映射 helper,以及 5 个 dogfood TaskSpec 样例;当前仅作为纯库和样例验证,尚未接入 CLI/runtime。
|
|
13
50
|
- 新增 AcceptanceSpec / TaskGraphSpec schema、Feature graph 校验器和 Ready 队列计算,覆盖 dogfood feature 的验收引用、任务文件一致性、未知依赖、环检测与 ready 判定。
|
|
14
51
|
- 新增 business profile 到 loop-agent profile 的确定性映射、独立 `agent-worker` CLI(`task validate` / `task explain-profile`)和 package bin surface。
|
|
@@ -20,6 +57,7 @@
|
|
|
20
57
|
|
|
21
58
|
### 修复
|
|
22
59
|
|
|
60
|
+
- 修复 observe UI 的真实事件路由、重复 task 历史运行、DAG/Failure Inbox 路由、失败与命令 artifact 链接、liveness 判定和 DAG 事件元数据;同时强制 server 仅绑定 loopback,并限制 artifact API 只读取已知运行产物目录。
|
|
23
61
|
- 修复 Worker batch/materializer 重入幂等、run-error Task Pool evidence/state 持久化、blocked morning report 汇总和 fallback failure routing 标记。
|
|
24
62
|
- 修复 Worker failure closeout draft 写入 `.harness` 被拒的问题,改为写入 `.task-pool/failure-handoffs/`,并将 `.task-pool/` 作为 runtime state 忽略。
|
|
25
63
|
- 修复 Worker 真实模型 DAG 容易被 120s 默认超时误杀的问题:`run-dag` 默认 30 分钟,显式 `TaskSpec.worker.timeout_ms` 最高 2 小时,普通命令仍保持 2 分钟,`check-repo` 保持 5 分钟。
|
|
@@ -40,16 +78,16 @@
|
|
|
40
78
|
|
|
41
79
|
- 文档站结合 `src/` 与 `skills/loop-agent` 补充目标项目初始化、Harness Policy、Task Source 与验证、Loop 与 Sidecar 指南,并扩充 Agent DAG、CLI 与配置参考。
|
|
42
80
|
- 文档站新增 Harness 实践与设计来源资料,收录 Anthropic 长时运行 agent harness、OpenAI Codex harness engineering、腾讯端到端 Harness Engineering 和社区 agent harness 最佳实践,并在 README、治理索引和开发原则中记录其与当前治理思想的关系。
|
|
43
|
-
- 新增 Production Readiness v0.1
|
|
44
|
-
- 新增 DAG production-readiness hardening:`dag validate` / `run-dag` 输出下一步指引,`dag report` 暴露 product-line failure routing
|
|
81
|
+
- 新增 Production Readiness v0.1 治理标准、生产就绪 checklist 模板,以及 2026-07-06 到 2026-07-12 的生产可用硬化 sprint 执行计划,明确低/中风险单 repo DAG 任务的支持范围、非目标、证据要求、失败分类和最终验证门禁。
|
|
82
|
+
- 新增 DAG production-readiness hardening:`dag validate` / `run-dag` 输出下一步指引,`dag report` 暴露 product-line failure routing 与 Operator Next Steps,`dag doctor --run-id --markdown` 输出失败诊断,failed `dag closeout-draft` 生成 Failure Handoff。
|
|
45
83
|
- `dag run-task`、`dag validate`、`run-dag` 的 JSON 输出新增稳定 `message` summary;`dag validate` 额外输出 write set 与 decision gate check 摘要。
|
|
46
|
-
- Dynamic Workflow node 现在可声明 `skills`,编译到 DAG 时会保留到对应 task、动态展开 child task
|
|
84
|
+
- Dynamic Workflow node 现在可声明 `skills`,编译到 DAG 时会保留到对应 task、动态展开 child task 与 loop body task。
|
|
47
85
|
- 新增 repo-local vetted skill registry、首批 role skill wrappers,以及 opt-in `dag validate --strict-skills` audit gate。
|
|
48
86
|
|
|
49
87
|
### 修改
|
|
50
88
|
|
|
51
89
|
- 更新本仓库与目标项目初始化后的 `AGENTS.md` 工作协议,新增文档收敛步骤、结构化 DAG 写入边界要求,以及 runtime boundary / command registry / skill entry / 发布包范围的定向验证指引。
|
|
52
|
-
- `loop-agent init` 生成的目标项目 `AGENTS.md` 同步包含文档收敛、`task.json.allowedPaths` / `task.json.forbiddenPaths`、DAG 失败诊断与 failure handoff
|
|
90
|
+
- `loop-agent init` 生成的目标项目 `AGENTS.md` 同步包含文档收敛、`task.json.allowedPaths` / `task.json.forbiddenPaths`、DAG 失败诊断与 failure handoff 规则,目标项目文档也会显式导出 production readiness checklist、`dag report`、`dag doctor --run-id --markdown` 和失败 run 的 `dag closeout-draft`。
|
|
53
91
|
|
|
54
92
|
### 修复
|
|
55
93
|
|
|
@@ -63,44 +101,16 @@
|
|
|
63
101
|
|
|
64
102
|
### 修改
|
|
65
103
|
|
|
66
|
-
- `harness.json`
|
|
67
|
-
- README
|
|
104
|
+
- `harness.json` 支持以 `adapter: "loop-agent"` 与真实项目名分离,目标项目无需把 `project` 写成 `loop-agent` 才能使用默认 adapter。
|
|
105
|
+
- README 重组为兼容 npm/GitHub 展示和本仓库迭代导航的入口,明确区分快速开始、目标项目初始化、任务运行、核心概念、本仓库开发和发布包内容,并补充新项目初始化时可直接交给模型执行的提示词。
|
|
68
106
|
|
|
69
107
|
### 修复
|
|
70
108
|
|
|
71
|
-
- npm 发布包范围纳入 `docs/architecture/runtime-boundaries.md`,确保 runtime boundary
|
|
109
|
+
- npm 发布包范围纳入 `docs/architecture/runtime-boundaries.md`,确保 runtime boundary 治理文档与 0.2.0 包一起发布。
|
|
72
110
|
- Cursor DAG worker 在构建产物中使用 `.js` worker 入口且不依赖 `tsx`,避免发布包/本地 build 运行 Cursor 节点时先因 worker 入口解析失败。
|
|
73
111
|
|
|
74
112
|
## [0.1.0] - 已发布
|
|
75
113
|
|
|
76
114
|
### 新增
|
|
77
115
|
|
|
78
|
-
- Agent DAG
|
|
79
|
-
- 默认 implementation / repair writer 使用 `executor: "pi"` 加 `toolProfile: "write"`。
|
|
80
|
-
- executor 配置保持 `pi` / `cursor` / `shell` / `static` 四类;Cursor 仍是显式启用的可选 backend。
|
|
81
|
-
- Windows 环境下 shell verification 可自动使用 Git Bash。
|
|
82
|
-
- Dynamic Workflow DAG Engine 的编译、校验、运行与回放命令。
|
|
83
|
-
- 仓库内置 `skills/` 目录,用于 DAG 模板和本项目技能引用。
|
|
84
|
-
- CLI 入口迁移为 commander 驱动的 command tree,顶层 help、子命令 help 和未知命令错误改用 commander 语义,同时保留既有命令能力。
|
|
85
|
-
- `commander` 成为正式运行时依赖。
|
|
86
|
-
- npm 发布包入口加载构建产物 `dist/cli.js`,并携带静态能力资料:`skills/`、顶层治理文档、`docs/templates/`、`examples/`、`harness.json`、`AGENTS.md`、`README.md` 和 `CHANGELOG.md`。
|
|
87
|
-
- DAG skill 指令在目标项目没有本地 skill 时会回退到 npm 包内置 `skills/`,支持发布包作为任意项目的稳定控制器。
|
|
88
|
-
|
|
89
|
-
### 修改
|
|
90
|
-
|
|
91
|
-
- 默认 DAG 和模板从 Cursor-heavy 调整为 Pi read-only + Pi write profile + shell verify。
|
|
92
|
-
- 移除独立 Pi 写入 executor 概念,写入能力改由 `toolProfile: "write"` 表达。
|
|
93
|
-
- 文档、示例和 skill 指引将 Cursor 描述为可选 backend,而不是默认路径。
|
|
94
|
-
- 治理和校验说明改为覆盖所有受控写入 executor,不再只绑定 Cursor。
|
|
95
|
-
- 顺序式 Level 1 workflow 入口从推荐/公开路径中移除,DAG 成为主路径。
|
|
96
|
-
- DAG 默认工程上下文 skill 从 `agent-context` 调整为 `ai-engineering-context`。
|
|
97
|
-
- `npm run dev` 明确为源码调试入口;用 loop-agent 迭代本仓库时应使用已发布的 npm 安装包作为稳定控制器,安装或升级可用 `@latest`,单次任务执行期记录并冻结实际安装版本。
|
|
98
|
-
- 发布包不携带已有 `docs/progress/`、`docs/reports/`、`docs/exec-plans/`、`docs/decisions/` 任务正文;这些目录的正文由目标仓库运行时生成。
|
|
99
|
-
|
|
100
|
-
### 修复
|
|
101
|
-
|
|
102
|
-
- no-Cursor DAG 生成、校验和 runner 测试可以在没有 Cursor 的环境下通过。
|
|
103
|
-
- Windows 路径和 shell 执行相关的跨平台测试问题。
|
|
104
|
-
- `doctor` 的 Pi CLI 探测支持当前 `@earendil-works/pi-coding-agent` 包名,并兼容 Windows npm shim 与跨平台 global npm 安装。
|
|
105
|
-
- DAG draft、final verification 和 closeout draft 的默认临时输出路径改为平台原生临时目录,不再假设 `/tmp` 存在。
|
|
106
|
-
- exec-plan 索引同步检查兼容发布包目录契约 README,不要求 npm 包内 README 链接未打包的源码历史计划正文。
|
|
116
|
+
- 初始发布:Agent DAG 生成/校验/执行、loop-agent harness 治理入口与基础 CLI。
|
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ loop-agent init --repo-root <target-repo> --profile full --merge
|
|
|
51
51
|
loop-agent init doctor --repo-root <target-repo>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
`init instructions` 会输出给模型/Agent 执行完整初始化的指引包,不要求目标项目已有 `harness.json`。默认初始化会 merge 已有 `AGENTS.md`、`harness.json` 和 `docs/`,复制 repo-local `skills
|
|
54
|
+
`init instructions` 会输出给模型/Agent 执行完整初始化的指引包,不要求目标项目已有 `harness.json`。默认初始化会 merge 已有 `AGENTS.md`、`harness.json` 和 `docs/`,复制 repo-local `skills/` 并同步镜像到 `.agents/skills/`(agent 兼容路径,如 OpenCode 自动发现),生成语言无关的治理脚本矩阵、中文根 README 入口、目标项目版治理文档和 `.harness/` 骨架;已有 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`、`.task-pool/`、`.worktrees/` 等个人/会话运行态事实忽略掉,同时保留 `.harness/prompts/` 和目录占位可共享,不会整目录忽略 `.harness/`,也不会覆盖用户已有的 ignore 规则。
|
|
55
55
|
|
|
56
56
|
新初始化会写入 `.harness/init-surface.json`,记录当前 controller 版本、初始化投影文件 hash 和 manifest hash。已用旧版本初始化的目标项目,可以用下面的维护入口对齐新版本初始化能力:
|
|
57
57
|
|
|
@@ -62,7 +62,7 @@ loop-agent init update --repo-root <target-repo> --bootstrap-surface
|
|
|
62
62
|
loop-agent init update --repo-root <target-repo> --apply-safe
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
`check-update` 只读报告 deterministic actions、model merge tasks、human decisions 和 recommended next。`update --bootstrap-surface` 为旧项目补 inferred baseline;`update --apply-safe` 只补缺失文件、目录和 managed block
|
|
65
|
+
`check-update` 只读报告 deterministic actions、model merge tasks、human decisions 和 recommended next。`update --bootstrap-surface` 为旧项目补 inferred baseline;`update --apply-safe` 只补缺失文件、目录和 managed block(包括过期的 `.gitignore` managed block),不覆盖已有但无法确认来源的本地文件。
|
|
66
66
|
|
|
67
67
|
当初始化由模型/Agent 执行时,它应把初始化当成一个自动化闭环:确认真正不能安全默认的 provider/model、治理根目录或凭据/成本问题后,运行 deterministic init,随后立刻读取目标项目真实文件,补全根 README 的项目概览、技术栈/目录结构、开发与验证命令,并同步适配 `docs/verification-matrix.md` 和必要的 `scripts/ci-tests.sh`。
|
|
68
68
|
|
|
@@ -93,7 +93,7 @@ loop-agent pi-prompt --cwd . --tools read,bash,edit,write,grep,find,ls "<包含
|
|
|
93
93
|
- **Agent DAG**:把一次任务拆成 contract、scout、plan、implement、verify、closeout 等可审查节点。
|
|
94
94
|
- **`.harness/`**:记录 task、DAG run、one-shot run、cache 和 live state 等运行态事实。
|
|
95
95
|
- **`harness.json`**:描述项目名、治理根目录、模型路由、executor 和验证脚本。
|
|
96
|
-
- **repo-local skills**:目标项目本地的 `skills
|
|
96
|
+
- **repo-local skills**:目标项目本地的 `skills/`(loop-agent 主路径)优先于发布包内置 skills,便于项目定制 agent 行为;`init --profile full` 还会把同一份 skills 镜像到 `.agents/skills/`,让外部 agent(如 OpenCode)也能自动发现。DAG skill 解析顺序为:用户配置目录 → `skills/` → `.agents/skills/` → 发布包内置。
|
|
97
97
|
- **治理文档**:`docs/` 保存原则、工作流、验证矩阵、runtime 边界、计划和报告。
|
|
98
98
|
- **shell verification**:完成声明必须有可复现命令作为依据,而不是只靠聊天结论。
|
|
99
99
|
|
|
@@ -242,7 +242,7 @@ export function parseDagValidateArgs(args) {
|
|
|
242
242
|
}
|
|
243
243
|
export function parseRunDagArgs(args, defaultCwd) {
|
|
244
244
|
if (args.length === 0) {
|
|
245
|
-
throw new Error("usage: run-dag --dag <path> [--cwd <dir>] [--init-only] [--dry-run] [--max-concurrent N] [--run-id id] [--canvas-path <abs-path> | --canvas <name> [--canvases-dir <dir>]]");
|
|
245
|
+
throw new Error("usage: run-dag --dag <path> [--cwd <dir>] [--init-only] [--dry-run] [--max-concurrent N] [--run-id id] [--canvas-path <abs-path> | --canvas <name> [--canvases-dir <dir>]] [--events-jsonl <path>]");
|
|
246
246
|
}
|
|
247
247
|
let dagPath;
|
|
248
248
|
let cwd;
|
|
@@ -254,6 +254,7 @@ export function parseRunDagArgs(args, defaultCwd) {
|
|
|
254
254
|
let canvasPath;
|
|
255
255
|
let canvasName;
|
|
256
256
|
let canvasesDir;
|
|
257
|
+
let eventsJsonlPath;
|
|
257
258
|
for (let i = 0; i < args.length; i += 1) {
|
|
258
259
|
const arg = args[i];
|
|
259
260
|
if (arg === "--dag") {
|
|
@@ -301,6 +302,12 @@ export function parseRunDagArgs(args, defaultCwd) {
|
|
|
301
302
|
else if (arg.startsWith("--canvases-dir=")) {
|
|
302
303
|
canvasesDir = arg.slice(15);
|
|
303
304
|
}
|
|
305
|
+
else if (arg === "--events-jsonl") {
|
|
306
|
+
eventsJsonlPath = args[++i];
|
|
307
|
+
}
|
|
308
|
+
else if (arg.startsWith("--events-jsonl=")) {
|
|
309
|
+
eventsJsonlPath = arg.slice("--events-jsonl=".length);
|
|
310
|
+
}
|
|
304
311
|
else if (!arg.startsWith("-")) {
|
|
305
312
|
if (!dagPath)
|
|
306
313
|
dagPath = arg;
|
|
@@ -325,6 +332,7 @@ export function parseRunDagArgs(args, defaultCwd) {
|
|
|
325
332
|
canvasPath,
|
|
326
333
|
canvasName,
|
|
327
334
|
canvasesDir,
|
|
335
|
+
eventsJsonlPath,
|
|
328
336
|
};
|
|
329
337
|
}
|
|
330
338
|
export function parseDagReportArgs(args) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { createDagEventObserver } from "../../workflows/dag/event-observer.js";
|
|
3
|
+
import { composeDagRunObservers } from "../../workflows/dag/observer-compose.js";
|
|
2
4
|
import { createDagCanvasObserver, resolveCanvasPath, } from "../../workflows/dag/canvas-observer.js";
|
|
3
5
|
import { loadDagSpecFromFile, runDag } from "../../workflows/dag/runner.js";
|
|
4
6
|
import { assertValidDagSpec, collectForbiddenExecutorIssues, } from "../../workflows/dag/validate.js";
|
|
@@ -62,13 +64,24 @@ export async function runDagUseCase(input) {
|
|
|
62
64
|
const canvas = resolvedCanvasPath
|
|
63
65
|
? createDagCanvasObserver({ canvasPath: resolvedCanvasPath, spec })
|
|
64
66
|
: undefined;
|
|
67
|
+
const eventObserver = input.eventsJsonlPath
|
|
68
|
+
? createDagEventObserver({
|
|
69
|
+
eventsJsonlPath: input.eventsJsonlPath,
|
|
70
|
+
spec,
|
|
71
|
+
})
|
|
72
|
+
: undefined;
|
|
73
|
+
const observer = composeDagRunObservers([
|
|
74
|
+
canvas?.observer,
|
|
75
|
+
eventObserver?.observer,
|
|
76
|
+
]);
|
|
65
77
|
if (input.dryRun) {
|
|
66
78
|
const summary = await runDag(spec, {
|
|
67
79
|
cwd: input.cwd,
|
|
68
80
|
dryRun: true,
|
|
69
81
|
runId: input.runId,
|
|
70
|
-
observer
|
|
82
|
+
observer,
|
|
71
83
|
});
|
|
84
|
+
await eventObserver?.flush();
|
|
72
85
|
const canvasError = await flushCanvasSafely(canvas);
|
|
73
86
|
return {
|
|
74
87
|
mode: "dry-run",
|
|
@@ -89,8 +102,9 @@ export async function runDagUseCase(input) {
|
|
|
89
102
|
dryRun: false,
|
|
90
103
|
maxConcurrent: input.maxConcurrent,
|
|
91
104
|
runId: input.runId,
|
|
92
|
-
observer
|
|
105
|
+
observer,
|
|
93
106
|
});
|
|
107
|
+
await eventObserver?.flush();
|
|
94
108
|
const canvasError = await flushCanvasSafely(canvas);
|
|
95
109
|
if (resolvedCanvasPath) {
|
|
96
110
|
return {
|
|
@@ -6,6 +6,18 @@ import { topoSortToRanks } from "../../workflows/dag/topo.js";
|
|
|
6
6
|
import { runSpineAudit } from "../../governance/spine-audit.js";
|
|
7
7
|
import { resolveDagNodeSkills } from "../../workflows/dag/skills.js";
|
|
8
8
|
import { resolveDagSkillInstructions } from "../../workflows/dag/skill-instructions.js";
|
|
9
|
+
import { loadHarnessManifest } from "../../governance/harness.js";
|
|
10
|
+
import { resolveExecutorModelMatrices } from "../../executors/model-routing.js";
|
|
11
|
+
import { DEFAULT_DAG_EXECUTOR_MODELS } from "../../workflows/dag/types.js";
|
|
12
|
+
async function loadExpectedExecutorModelMatrices(repoRoot) {
|
|
13
|
+
try {
|
|
14
|
+
const manifest = await loadHarnessManifest(repoRoot);
|
|
15
|
+
return resolveExecutorModelMatrices(manifest);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return DEFAULT_DAG_EXECUTOR_MODELS;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
9
21
|
function formatModelMatrixWarnings(warnings) {
|
|
10
22
|
return warnings.map((warning) => ({
|
|
11
23
|
executor: warning.executor,
|
|
@@ -92,7 +104,8 @@ export async function validateDagUseCase(input) {
|
|
|
92
104
|
const rawTaskExecutors = await loadRawTaskExecutorMap(input.dagPath);
|
|
93
105
|
ensureNoForbiddenExecutors(spec, input.forbidExecutors, rawTaskExecutors);
|
|
94
106
|
const validationIssues = validateDagSpec(spec);
|
|
95
|
-
const
|
|
107
|
+
const expectedMatrices = await loadExpectedExecutorModelMatrices(input.repoRoot);
|
|
108
|
+
const warnings = collectExecutorModelWarnings(spec, expectedMatrices);
|
|
96
109
|
const governanceWarnings = collectGovernanceWarnings(validationIssues);
|
|
97
110
|
if (input.strictModelMatrix) {
|
|
98
111
|
ensureStrictModelMatrix(warnings);
|
|
@@ -8,6 +8,7 @@ import { runHandoffCheck } from "../commands/handoff-check.js";
|
|
|
8
8
|
import { runInspect } from "../commands/inspect.js";
|
|
9
9
|
import { runInstructions } from "../commands/instructions.js";
|
|
10
10
|
import { runNewTask } from "../commands/new-task.js";
|
|
11
|
+
import { runImportPrd } from "../commands/import-prd.js";
|
|
11
12
|
import { runPlanList } from "../commands/plan-list.js";
|
|
12
13
|
import { runPromoteRun } from "../commands/promote-run.js";
|
|
13
14
|
import { runSpine } from "../commands/spine.js";
|
|
@@ -30,7 +31,7 @@ import { runDagReject } from "../commands/dag-reject.js";
|
|
|
30
31
|
import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
|
|
31
32
|
import { runDagResume } from "../commands/dag-resume.js";
|
|
32
33
|
import { runDagDecisionInspect, runDagDecisionValidate, } from "../workflows/dag/decision-envelope.js";
|
|
33
|
-
import { runDagDoctor, runDagStatus
|
|
34
|
+
import { runDagDoctor, runDagStatus } from "../workflows/dag/lifecycle.js";
|
|
34
35
|
import { runDagRunTask } from "../commands/dag-run-task.js";
|
|
35
36
|
import { runDagCloseoutDraft, runDagReport } from "../commands/dag-report.js";
|
|
36
37
|
import { runDagFinalVerification } from "../commands/dag-final-verification.js";
|
|
@@ -50,7 +51,12 @@ export function formatSubcommandUsageError(name, subcommands) {
|
|
|
50
51
|
return `usage: ${formatSubcommandUsage(name, subcommands)}`;
|
|
51
52
|
}
|
|
52
53
|
const DOCS_SUBCOMMANDS = ["audit", "archive"];
|
|
53
|
-
const INIT_SUBCOMMANDS = [
|
|
54
|
+
const INIT_SUBCOMMANDS = [
|
|
55
|
+
"instructions",
|
|
56
|
+
"doctor",
|
|
57
|
+
"check-update",
|
|
58
|
+
"update",
|
|
59
|
+
];
|
|
54
60
|
const EXAMPLES_SUBCOMMANDS = ["list", "show", "copy"];
|
|
55
61
|
const CLOSEOUT_SUBCOMMANDS = ["task"];
|
|
56
62
|
const PLAN_SUBCOMMANDS = ["list"];
|
|
@@ -175,6 +181,16 @@ export const COMMAND_DEFINITIONS = [
|
|
|
175
181
|
await runNewTask(repoRoot, taskId, titleParts.join(" ") || undefined);
|
|
176
182
|
},
|
|
177
183
|
},
|
|
184
|
+
{
|
|
185
|
+
name: "import-prd",
|
|
186
|
+
adapter: "required",
|
|
187
|
+
tier: "primary",
|
|
188
|
+
intent: "Copy a user PRD into source/references as an immutable fact source before deriving source/需求.md.",
|
|
189
|
+
usage: "import-prd <task-id> --file <path> [--name requirement] [--role requirement] [--json]",
|
|
190
|
+
handler: async ({ repoRoot, subcommand, rest }) => {
|
|
191
|
+
await runImportPrd(repoRoot, [subcommand, ...rest].filter(Boolean));
|
|
192
|
+
},
|
|
193
|
+
},
|
|
178
194
|
{
|
|
179
195
|
name: "status",
|
|
180
196
|
adapter: "required",
|
|
@@ -481,7 +497,9 @@ export const COMMAND_DEFINITIONS = [
|
|
|
481
497
|
}
|
|
482
498
|
if (subcommand === "decision") {
|
|
483
499
|
const decisionSubcommand = rest[0];
|
|
484
|
-
const decisionArgs = rest
|
|
500
|
+
const decisionArgs = rest
|
|
501
|
+
.slice(1)
|
|
502
|
+
.filter((arg) => Boolean(arg));
|
|
485
503
|
if (decisionSubcommand === "inspect") {
|
|
486
504
|
await runDagDecisionInspect(repoRoot, decisionArgs);
|
|
487
505
|
return;
|
|
@@ -500,7 +518,7 @@ export const COMMAND_DEFINITIONS = [
|
|
|
500
518
|
adapter: "required",
|
|
501
519
|
tier: "primary",
|
|
502
520
|
intent: "Execute a reviewed Agent DAG spec.",
|
|
503
|
-
usage: "run-dag --dag <path> [
|
|
521
|
+
usage: "run-dag --dag <path> [--cwd <dir>] [--init-only] [--dry-run] [--max-concurrent N] [--run-id id] [--canvas-path <abs-path> | --canvas <name> [--canvases-dir <dir>]] [--events-jsonl <path>]",
|
|
504
522
|
handler: async ({ repoRoot, subcommand, rest }) => {
|
|
505
523
|
const runDagArgs = [subcommand, ...rest].filter((arg) => Boolean(arg));
|
|
506
524
|
await runRunDag(repoRoot, runDagArgs);
|
package/dist/cli/help.js
CHANGED
|
@@ -24,8 +24,9 @@ export function formatCommandTierSummary(manifest = CODE_AGENT_COMMAND_MANIFEST)
|
|
|
24
24
|
return [
|
|
25
25
|
"Recommended DAG path:",
|
|
26
26
|
" 1. new-task <task-id> [title]",
|
|
27
|
-
" 2.
|
|
28
|
-
" 3. run-
|
|
27
|
+
" 2. import-prd <task-id> --file <original-prd> # optional but recommended",
|
|
28
|
+
" 3. dag run-task <task-id> --profile auto --strict-models",
|
|
29
|
+
" 4. run-dag --dag <path> --cwd <repo-root>",
|
|
29
30
|
"Operator recovery/closeout: dag status/report/doctor/closeout-draft",
|
|
30
31
|
`Primary commands: ${primary}`,
|
|
31
32
|
`Operator commands: ${operator}`,
|
package/dist/cli/program.js
CHANGED
|
@@ -33,6 +33,7 @@ import { runKnowledge } from "../commands/knowledge.js";
|
|
|
33
33
|
import { runLoop } from "../commands/loop.js";
|
|
34
34
|
import { runLoopBenchmark } from "../commands/loop-benchmark.js";
|
|
35
35
|
import { runNewTask } from "../commands/new-task.js";
|
|
36
|
+
import { runImportPrd } from "../commands/import-prd.js";
|
|
36
37
|
import { runPiReuseBenchmark } from "../commands/pi-reuse-benchmark.js";
|
|
37
38
|
import { parsePiPromptArgs, printPiPromptUsage, runPiPrompt, } from "../commands/pi-prompt.js";
|
|
38
39
|
import { runPlanList } from "../commands/plan-list.js";
|
|
@@ -143,6 +144,9 @@ async function runCommanderAction(ctx, command, subcommand, rest) {
|
|
|
143
144
|
await runNewTask(ctx.repoRoot, taskId, titleParts.join(" ") || undefined);
|
|
144
145
|
return;
|
|
145
146
|
}
|
|
147
|
+
case "import-prd":
|
|
148
|
+
await runImportPrd(ctx.repoRoot, compactArgs([subcommand, ...rest]));
|
|
149
|
+
return;
|
|
146
150
|
case "status": {
|
|
147
151
|
if (!subcommand)
|
|
148
152
|
throw new Error("taskId required");
|
|
@@ -355,10 +359,7 @@ function configureDagValidate(command) {
|
|
|
355
359
|
.option("--strict-models", "fail on model routing warnings")
|
|
356
360
|
.option("--strict-governance", "fail on governance warnings")
|
|
357
361
|
.option("--strict-skills", "fail on missing, errored, truncated, or unresolved skill instructions")
|
|
358
|
-
.option("--forbid-executor <executor>", "forbid executor", (value, previous = []) => [
|
|
359
|
-
...previous,
|
|
360
|
-
value,
|
|
361
|
-
])
|
|
362
|
+
.option("--forbid-executor <executor>", "forbid executor", (value, previous = []) => [...previous, value])
|
|
362
363
|
.option("--spine-task <task-id>", "run spine audit for task id");
|
|
363
364
|
}
|
|
364
365
|
function configureRunDag(command) {
|
|
@@ -373,7 +374,8 @@ function configureRunDag(command) {
|
|
|
373
374
|
.option("--no-cursor", "disable Cursor execution")
|
|
374
375
|
.option("--canvas-path <path>", "absolute canvas output path")
|
|
375
376
|
.option("--canvas <name>", "canvas name")
|
|
376
|
-
.option("--canvases-dir <dir>", "canvas output directory")
|
|
377
|
+
.option("--canvases-dir <dir>", "canvas output directory")
|
|
378
|
+
.option("--events-jsonl <path>", "append DAG node events to a JSONL file");
|
|
377
379
|
}
|
|
378
380
|
function configureDagRunTask(command) {
|
|
379
381
|
command
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { importPrdDocument } from "../task/source-references.js";
|
|
3
|
+
export function parseImportPrdArgs(args) {
|
|
4
|
+
const options = {};
|
|
5
|
+
const positional = [];
|
|
6
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
7
|
+
const token = args[index];
|
|
8
|
+
if (token === "--file" || token === "-f") {
|
|
9
|
+
options.file = args[index + 1];
|
|
10
|
+
index += 1;
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (token === "--name") {
|
|
14
|
+
options.name = args[index + 1];
|
|
15
|
+
index += 1;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (token === "--role") {
|
|
19
|
+
options.role = args[index + 1];
|
|
20
|
+
index += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (token === "--json") {
|
|
24
|
+
options.json = true;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (token.startsWith("-")) {
|
|
28
|
+
throw new Error(`unknown flag ${token}\nusage: import-prd <task-id> --file <path> [--name requirement] [--role requirement] [--json]`);
|
|
29
|
+
}
|
|
30
|
+
positional.push(token);
|
|
31
|
+
}
|
|
32
|
+
const taskId = positional[0];
|
|
33
|
+
if (!taskId) {
|
|
34
|
+
throw new Error("usage: import-prd <task-id> --file <path> [--name requirement] [--role requirement] [--json]");
|
|
35
|
+
}
|
|
36
|
+
if (!options.file) {
|
|
37
|
+
throw new Error("usage: import-prd <task-id> --file <path> [--name requirement] [--role requirement] [--json]");
|
|
38
|
+
}
|
|
39
|
+
return { taskId, options };
|
|
40
|
+
}
|
|
41
|
+
export async function runImportPrd(repoRoot, args) {
|
|
42
|
+
const { taskId, options } = parseImportPrdArgs(args);
|
|
43
|
+
const result = await importPrdDocument({
|
|
44
|
+
repoRoot,
|
|
45
|
+
taskId,
|
|
46
|
+
filePath: options.file,
|
|
47
|
+
name: options.name,
|
|
48
|
+
role: options.role,
|
|
49
|
+
});
|
|
50
|
+
if (options.json) {
|
|
51
|
+
console.log(JSON.stringify({
|
|
52
|
+
ok: true,
|
|
53
|
+
taskId: result.taskId,
|
|
54
|
+
sourcePath: result.sourcePath,
|
|
55
|
+
materializedPath: result.materializedRelativePath,
|
|
56
|
+
materializedAbsolutePath: result.materializedAbsolutePath,
|
|
57
|
+
sha256: result.sha256,
|
|
58
|
+
bytes: result.bytes,
|
|
59
|
+
manifestPath: path
|
|
60
|
+
.relative(repoRoot, result.manifestPath)
|
|
61
|
+
.split(path.sep)
|
|
62
|
+
.join("/"),
|
|
63
|
+
referenceDocs: result.referenceDocs,
|
|
64
|
+
message: "Imported PRD as an immutable source reference. Derive source/需求.md from it; do not rewrite the reference copy.",
|
|
65
|
+
}, null, 2));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
console.log([
|
|
69
|
+
`imported PRD for task ${result.taskId}`,
|
|
70
|
+
` source: ${result.sourcePath}`,
|
|
71
|
+
` materialized: ${result.materializedRelativePath}`,
|
|
72
|
+
` sha256: ${result.sha256}`,
|
|
73
|
+
` manifest: ${path.relative(repoRoot, result.manifestPath).split(path.sep).join("/")}`,
|
|
74
|
+
"Next: write source/需求.md as a derived execution contract with REQ/AC ids that map back to the original PRD. Do not edit source/references/*.",
|
|
75
|
+
].join("\n"));
|
|
76
|
+
}
|