@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/dist/commands/init.js
CHANGED
|
@@ -13,16 +13,20 @@ const GITIGNORE_BLOCK_END = "# LOOP_AGENT_INIT_END";
|
|
|
13
13
|
const INIT_SURFACE_STATE_PATH = ".harness/init-surface.json";
|
|
14
14
|
const DEFAULT_GOVERNANCE_ROOT = "ai_workspace/loop-agent";
|
|
15
15
|
const CORE_DOC_FILES = [
|
|
16
|
-
"README.md",
|
|
17
|
-
"architecture/runtime-boundaries.md",
|
|
18
|
-
"development-principles.md",
|
|
19
|
-
"feature-workflow.md",
|
|
20
|
-
"verification-matrix.md",
|
|
21
|
-
"loop-agent-harness.md",
|
|
22
|
-
"harness-methodology-tdd.md",
|
|
23
|
-
"harness-methodology-verification.md",
|
|
24
|
-
"harness-methodology-debugging.md",
|
|
16
|
+
{ source: "README.md", target: "README.md" },
|
|
17
|
+
{ source: "architecture/runtime-boundaries.md", target: "architecture/runtime-boundaries.md" },
|
|
18
|
+
{ source: "governance/development-principles.md", target: "development-principles.md" },
|
|
19
|
+
{ source: "governance/feature-workflow.md", target: "feature-workflow.md" },
|
|
20
|
+
{ source: "governance/verification-matrix.md", target: "verification-matrix.md" },
|
|
21
|
+
{ source: "runtime/loop-agent-harness.md", target: "loop-agent-harness.md" },
|
|
22
|
+
{ source: "governance/harness-methodology-tdd.md", target: "harness-methodology-tdd.md" },
|
|
23
|
+
{ source: "governance/harness-methodology-verification.md", target: "harness-methodology-verification.md" },
|
|
24
|
+
{ source: "governance/harness-methodology-debugging.md", target: "harness-methodology-debugging.md" },
|
|
25
|
+
{ source: "templates/README.md", target: "templates/README.md" },
|
|
25
26
|
];
|
|
27
|
+
function coreDocSourceForTarget(target) {
|
|
28
|
+
return CORE_DOC_FILES.find((entry) => entry.target === target)?.source ?? target;
|
|
29
|
+
}
|
|
26
30
|
const GOVERNANCE_README_DIRS = [
|
|
27
31
|
"decisions",
|
|
28
32
|
"design",
|
|
@@ -771,68 +775,59 @@ function buildManagedAgentsBlock(input) {
|
|
|
771
775
|
"### 默认立场",
|
|
772
776
|
"",
|
|
773
777
|
"- 仓库是记录系统:决策、契约、计划、验证、报告和交接应进入可追踪文件。",
|
|
774
|
-
"-
|
|
775
|
-
"- 实现前先搜索现有代码、文档、脚本和测试,避免重复造轮子。",
|
|
778
|
+
"- 一次只推进一个有边界、可验证的工作块;实现前先搜索现有代码、文档、脚本和测试。",
|
|
776
779
|
"- Shell 验证是完成依据;模型建议不能替代命令证据。",
|
|
777
780
|
"- 保留无关的用户改动,不要回退自己没有做的修改。",
|
|
778
781
|
"- 委托模型写入前,必须把写入边界写成结构化 `task.json.allowedPaths` / `task.json.forbiddenPaths`,再审查生成 DAG 的 writer `writeSet`;不要只依赖 `source/执行约束.md` 的自然语言约束。",
|
|
779
|
-
"- 本仓库对 openCode 等主会话的定位是 **Compatibility / Operator Assist**:主会话编排
|
|
782
|
+
"- 本仓库对 openCode 等主会话的定位是 **Compatibility / Operator Assist**:主会话编排 CLI 与只读诊断,**不是**默认实现 agent。",
|
|
780
783
|
"",
|
|
781
784
|
"### 主会话硬约束(Compatibility / Operator Assist)",
|
|
782
785
|
"",
|
|
783
|
-
"主会话(含 openCode、Cursor Chat、其他宿主 agent
|
|
786
|
+
"主会话(含 openCode、Cursor Chat、其他宿主 agent)= **operator-only**;skills 与本文件是纪律文档,**不能**替代 `task.json` / DAG `writeSet` / runtime 执法。",
|
|
784
787
|
"",
|
|
785
788
|
"| 类别 | 规则 |",
|
|
786
789
|
"|---|---|",
|
|
787
|
-
"|
|
|
788
|
-
"|
|
|
789
|
-
"|
|
|
790
|
-
"|
|
|
791
|
-
"| **实现写入** | 业务代码与功能修复 **只** 经受治理 DAG writer(`implement-pi` / `repair-pi` 等)通过 `dag run-task` / `run-dag`(或 worker 子进程调用的同一路径)完成。 |",
|
|
790
|
+
"| **允许** | 已发布 `loop-agent` / `agent-worker` CLI;只读 status/doctor/report/inspect/observe;准备 `source/*` 与 `task.json` 边界;human gate;shell 验证与 handoff。 |",
|
|
791
|
+
"| **禁止** | 绕过 CLI 用宿主 Edit/Write/ApplyPatch 直接改业务实现;CLI/DAG 失败后「救火改文件」;用聊天自述代替 shell 验证。 |",
|
|
792
|
+
"| **失败时** | `dag doctor` / `dag report` / `dag reconcile-run`(及适用 worker reconcile);修正任务源/`task.json`/DAG 后经 CLI 重跑。 |",
|
|
793
|
+
"| **实现写入** | 业务代码 **只** 经受治理 DAG writer(`implement-pi` / `repair-pi`)经 `dag run-task` / `run-dag`。 |",
|
|
792
794
|
"",
|
|
793
795
|
"**永远不要**:`loop-agent` / `agent-worker` 失败 ⇒ 主会话直接改仓库实现。",
|
|
794
796
|
"",
|
|
795
797
|
"### 自然语言入口路由",
|
|
796
798
|
"",
|
|
797
|
-
"用户用中文表达意图时,按以下三类入口路由;只读与写入必须严格区分。",
|
|
798
|
-
"",
|
|
799
799
|
"| 用户表达 | 入口 | 执行动作 |",
|
|
800
800
|
"|---|---|---|",
|
|
801
801
|
"| loop-agent 初始化 / loop agent 初始化 / loop agent初始化 / 初始化 loop-agent | 初始化 | 完成确定性初始化闭环 |",
|
|
802
802
|
"| 初始化更新校验 / 检查初始化更新 / loop-agent 初始化更新校验 / loop agent初始化更新校验 | 更新校验 | 只读报告,不写入 |",
|
|
803
|
-
"| 初始化对齐 / 升级后对齐 / reconcile 初始化 / loop-agent 初始化对齐 | 升级对齐 |
|
|
804
|
-
"| 初始化安全更新 / 应用初始化更新 / loop-agent 初始化安全更新 / loop agent初始化安全更新 | 安全更新 | check-update
|
|
803
|
+
"| 初始化对齐 / 升级后对齐 / reconcile 初始化 / loop-agent 初始化对齐 | 升级对齐 | 自动应用确定性安全动作;活跃 DAG/Worker 或人工决策时零写入 |",
|
|
804
|
+
"| 初始化安全更新 / 应用初始化更新 / loop-agent 初始化安全更新 / loop agent初始化安全更新 | 安全更新 | 先 check-update,再只执行确定性安全动作 |",
|
|
805
805
|
"",
|
|
806
|
-
"
|
|
806
|
+
"**更新校验(只读)**:只读执行下面命令;**不得自动**执行 `apply-safe` 或模型合并。",
|
|
807
807
|
"",
|
|
808
808
|
"```bash",
|
|
809
809
|
"loop-agent init check-update --repo-root . --markdown",
|
|
810
810
|
"```",
|
|
811
811
|
"",
|
|
812
|
-
"
|
|
812
|
+
"**升级对齐**:`loop-agent init reconcile --repo-root .`;存在活跃 DAG/Worker、human decisions 时必须零写入。",
|
|
813
813
|
"",
|
|
814
|
-
"
|
|
814
|
+
"**安全更新**:先 check-update,再 `apply-safe`;surface 缺失才 `--bootstrap-surface`。完成后复查 `init doctor` / `inspect` / `docs audit` 与目标治理检查。",
|
|
815
815
|
"",
|
|
816
816
|
"```bash",
|
|
817
817
|
"loop-agent init check-update --repo-root . --markdown",
|
|
818
818
|
"loop-agent init update --repo-root . --apply-safe",
|
|
819
819
|
"```",
|
|
820
820
|
"",
|
|
821
|
-
"仅当 check-update 报告 surface 缺失时才执行 `loop-agent init update --repo-root . --bootstrap-surface`。",
|
|
822
|
-
"",
|
|
823
821
|
"### 初始化闭环",
|
|
824
822
|
"",
|
|
825
823
|
`当用户要求初始化 loop-agent(“初始化 loop-agent”“loop agent 初始化”“loop agent初始化”“loop-agent 初始化”),或发现 \`README.md\` / \`${input.governanceRoot}/verification-matrix.md\` 仍停留在通用初始化状态时,模型应在同一轮工作中完成初始化闭环,不要把补全文档和验证矩阵留给用户交互。`,
|
|
826
824
|
"",
|
|
827
|
-
"
|
|
825
|
+
"1. 运行 `loop-agent init instructions --repo-root .`。",
|
|
826
|
+
"2. 运行 `loop-agent init --repo-root . --profile full --merge`。",
|
|
827
|
+
`3. 基于真实项目文件补全根 \`README.md\`、\`${input.governanceRoot}/verification-matrix.md\`,必要时适配 \`scripts/ci-tests.sh\`。`,
|
|
828
|
+
"4. 复查 `init doctor` / `inspect` / `docs audit` 与 quick verification。",
|
|
828
829
|
"",
|
|
829
|
-
"
|
|
830
|
-
"2. 运行 `loop-agent init --repo-root . --profile full --merge` 完成确定性脚手架。",
|
|
831
|
-
"3. 立即读取目标项目的 README、manifest/build/config 文件和顶层源码/模块目录,识别项目类型、模块、运行入口和验证命令。",
|
|
832
|
-
`4. 基于真实项目文件补全或修正根 \`README.md\`、\`${input.governanceRoot}/verification-matrix.md\`,必要时适配 \`scripts/ci-tests.sh\`。`,
|
|
833
|
-
"5. 运行 `loop-agent init doctor --repo-root .`、`loop-agent inspect --repo-root .`、`loop-agent docs audit --repo-root .` 和 quick verification。",
|
|
834
|
-
"",
|
|
835
|
-
"如果仓库信息不足,写明“尚未从仓库文件中识别到 ...”以及下一步需要的事实;不要留下泛化占位符,也不要只提示用户稍后手填。",
|
|
830
|
+
"信息不足时写明尚未识别到的事实;不要留下泛化占位符。",
|
|
836
831
|
"",
|
|
837
832
|
"### 文档收敛",
|
|
838
833
|
"",
|
|
@@ -840,21 +835,10 @@ function buildManagedAgentsBlock(input) {
|
|
|
840
835
|
"",
|
|
841
836
|
"### 开始顺序",
|
|
842
837
|
"",
|
|
843
|
-
|
|
844
|
-
"",
|
|
845
|
-
"1. 运行 `pwd`。",
|
|
846
|
-
"2. 阅读 `README.md`。",
|
|
847
|
-
"3. 阅读 `harness.json`。",
|
|
848
|
-
`4. 阅读 \`${input.governanceRoot}/README.md\`。`,
|
|
849
|
-
`5. 实现类工作继续阅读 \`${input.governanceRoot}/development-principles.md\`、\`${input.governanceRoot}/feature-workflow.md\` 和 \`${input.governanceRoot}/verification-matrix.md\`。`,
|
|
850
|
-
`6. 涉及测试、验证声明或调试时继续阅读 \`${input.governanceRoot}/harness-methodology-tdd.md\`、\`${input.governanceRoot}/harness-methodology-verification.md\` 和 \`${input.governanceRoot}/harness-methodology-debugging.md\`。`,
|
|
851
|
-
"7. 查看最近提交、相关 plan/progress/report,并检查 `git status --short --branch`。",
|
|
852
|
-
"8. 运行与本次任务相关的最小基线验证。",
|
|
838
|
+
`pwd → \`README.md\` → \`harness.json\` → \`${input.governanceRoot}/README.md\` → 实现类再读 principles/feature-workflow/verification-matrix;测试纪律读 harness-methodology-*;\`git status\`;最小基线验证。`,
|
|
853
839
|
"",
|
|
854
840
|
"### Agent DAG 路径",
|
|
855
841
|
"",
|
|
856
|
-
"默认使用 Agent DAG 作为实现工作流:",
|
|
857
|
-
"",
|
|
858
842
|
"```bash",
|
|
859
843
|
"loop-agent new-task <task-id> \"任务标题\"",
|
|
860
844
|
"# write .harness/tasks/<task-id>/source/需求.md",
|
|
@@ -864,64 +848,40 @@ function buildManagedAgentsBlock(input) {
|
|
|
864
848
|
"loop-agent run-dag --dag <temp-dir>/<task-id>-dag.json --cwd .",
|
|
865
849
|
"```",
|
|
866
850
|
"",
|
|
867
|
-
"
|
|
868
|
-
"",
|
|
869
|
-
"委托写入前,还要把允许/禁止路径同步到 `.harness/tasks/<task-id>/task.json` 的 `allowedPaths` / `forbiddenPaths` 字段,并在执行前审查生成 DAG 的 writer `writeSet` 是否窄且准确。",
|
|
851
|
+
"`source/需求.md` 与 `source/执行约束.md` 必需;写入前同步 `task.json.allowedPaths` / `task.json.forbiddenPaths` 并审查 writer `writeSet`。",
|
|
870
852
|
"",
|
|
871
853
|
"凡是影响项目公共契约、执行入口、交付流水线、自动化/治理、数据模型、安全或权限模型、跨模块行为、用户可见工作流的改动,都必须在编辑实现文件前先创建任务、写好两个 source 文件、生成 DAG,并审查 DAG/writeSet。",
|
|
872
854
|
"",
|
|
873
|
-
"执行 DAG 前必须审查 profile routing、governance profile、writer 的 `writeSet`、`allowedPaths`、`forbiddenPaths`、shell verification 和 decision gate mode。不要执行占位或过宽的写入范围。",
|
|
874
|
-
"",
|
|
875
855
|
"### 任务类型路由(taskKind)",
|
|
876
856
|
"",
|
|
877
857
|
"- 用户明确提出后端测试、接口/API 测试、pytest,或语境明确为后端的自动化测试时,必须把 `.harness/tasks/<task-id>/task.json` 的 `taskKind` 设置为 `\"backend-test\"`,不得保留默认 `standard`。",
|
|
878
|
-
"- `backend-test` 是 `taskKind`,不是 `--profile` 的可选值;运行 `dag run-task` 时继续使用 `--profile auto
|
|
858
|
+
"- `backend-test` 是 `taskKind`,不是 `--profile` 的可选值;运行 `dag run-task` 时继续使用 `--profile auto`。",
|
|
879
859
|
"- 仅出现“自动化测试”且无法判断前后端时,先阅读任务源与目标项目技术栈再决定,禁止无条件路由到 `backend-test`。",
|
|
880
860
|
"",
|
|
881
861
|
"### 运行看板(只读)",
|
|
882
862
|
"",
|
|
883
|
-
"启动统一 Operator Console(含只读 Inspect):",
|
|
884
|
-
"",
|
|
885
863
|
"```bash",
|
|
886
864
|
"agent-worker console serve --repo . --port 8790",
|
|
887
865
|
"```",
|
|
888
866
|
"",
|
|
889
|
-
"浏览器打开 `http://127.0.0.1:8790/`;检视面为 `http://127.0.0.1:8790/inspect/`。默认绑定本机 `127.0.0.1
|
|
867
|
+
"浏览器打开 `http://127.0.0.1:8790/`;检视面为 `http://127.0.0.1:8790/inspect/`。默认绑定本机 `127.0.0.1`;不要直接暴露到公开网络。`agent-worker observe serve` 仅为兼容入口。",
|
|
890
868
|
"",
|
|
891
869
|
"### DAG 诊断与收口",
|
|
892
870
|
"",
|
|
893
|
-
"
|
|
871
|
+
"用 `loop-agent dag report --run-id <run-id> --markdown` 读 facts;失败/paused 用 `loop-agent dag doctor --run-id <run-id> --markdown`;生命周期对齐用 `loop-agent dag reconcile-run`。失败 run 用 `dag closeout-draft` 生成 failure handoff,不要写成成功 closeout。",
|
|
894
872
|
"",
|
|
895
|
-
"
|
|
896
|
-
"",
|
|
897
|
-
"### 运行态与 Skills",
|
|
898
|
-
"",
|
|
899
|
-
"- `.harness/tasks/` 保存任务状态和 source 材料。",
|
|
900
|
-
"- `.harness/dag-runs/` 与 `.harness/runs/` 保存运行事实;已完成事实只读。",
|
|
901
|
-
"- `.agents/skills/` 保存目标项目本地 skill 指令;本地缺失时 runtime 可回退到 npm 包内置 skills。",
|
|
902
|
-
"- 示例内置在工具中;优先使用 `loop-agent examples list` 和 `loop-agent examples show <name>` 查看,不默认提交到目标仓库。",
|
|
903
|
-
"",
|
|
904
|
-
"### 验证",
|
|
905
|
-
"",
|
|
906
|
-
`使用 \`${input.governanceRoot}/verification-matrix.md\` 选择验证命令。常用门禁:`,
|
|
907
|
-
"",
|
|
908
|
-
"```bash",
|
|
909
|
-
"bash scripts/check-repo.sh",
|
|
910
|
-
"bash scripts/ci-governance.sh",
|
|
911
|
-
"bash scripts/ci-tests.sh",
|
|
912
|
-
"bash scripts/ci.sh",
|
|
913
|
-
"loop-agent inspect",
|
|
914
|
-
"loop-agent doctor",
|
|
915
|
-
"loop-agent docs audit",
|
|
916
|
-
"```",
|
|
873
|
+
"恢复:doctor/report → classify → reconcile/replan → CLI 重跑 → shell verify。**禁止**把主会话直接 Edit 业务代码当作恢复手段。",
|
|
917
874
|
"",
|
|
918
|
-
"
|
|
875
|
+
"### 运行态与验证",
|
|
919
876
|
"",
|
|
920
|
-
"
|
|
877
|
+
"- `.harness/tasks/`、`.harness/dag-runs/`、`.harness/runs/` 保存运行事实;已完成事实只读。",
|
|
878
|
+
"- `.agents/skills/` 为本地 skills;缺失时可回退 npm 包内置。",
|
|
879
|
+
`- 验证命令选择:\`${input.governanceRoot}/verification-matrix.md\`。常用:\`bash scripts/check-repo.sh\`、\`bash scripts/ci.sh\`、\`loop-agent inspect\`、\`loop-agent doctor\`、\`loop-agent docs audit\`。`,
|
|
880
|
+
"- `scripts/ci-tests.sh` 必须反映目标项目真实工具链。Windows 脚本用 Git Bash;仓库引用用 `/`。",
|
|
921
881
|
"",
|
|
922
882
|
"### 交接",
|
|
923
883
|
"",
|
|
924
|
-
|
|
884
|
+
`交接写清变更、原因、验证证据、影响面、风险与下一步;长期结论进入 \`${input.governanceRoot}/progress\`、reports、exec-plans、decisions。`,
|
|
925
885
|
MANAGED_BLOCK_END,
|
|
926
886
|
].join("\n");
|
|
927
887
|
}
|
|
@@ -1373,6 +1333,10 @@ async function buildDesiredSurfaceContent(input) {
|
|
|
1373
1333
|
});
|
|
1374
1334
|
if (generated !== undefined)
|
|
1375
1335
|
return { content: generated };
|
|
1336
|
+
const mappedSourcePath = path.join(input.assetRoot, "docs", coreDocSourceForTarget(doc));
|
|
1337
|
+
if (await exists(mappedSourcePath)) {
|
|
1338
|
+
return { content: await readFile(mappedSourcePath, "utf-8"), sourcePath: mappedSourcePath };
|
|
1339
|
+
}
|
|
1376
1340
|
}
|
|
1377
1341
|
const sourcePath = path.join(input.assetRoot, manifestPath);
|
|
1378
1342
|
if (await exists(sourcePath))
|
|
@@ -1582,6 +1546,10 @@ async function expectedLegacyInitFileSha(input) {
|
|
|
1582
1546
|
if (!input.legacyPath.startsWith("docs/") && !input.legacyPath.startsWith("skills/")) {
|
|
1583
1547
|
return undefined;
|
|
1584
1548
|
}
|
|
1549
|
+
if (input.legacyPath.startsWith("docs/")) {
|
|
1550
|
+
const doc = input.legacyPath.slice("docs/".length);
|
|
1551
|
+
return fileSha256IfExists(path.join(input.assetRoot, "docs", coreDocSourceForTarget(doc)));
|
|
1552
|
+
}
|
|
1585
1553
|
return fileSha256IfExists(path.join(input.assetRoot, input.legacyPath));
|
|
1586
1554
|
}
|
|
1587
1555
|
function collectSafeRetiredDirectories(paths) {
|
|
@@ -1912,6 +1880,7 @@ function buildTargetDocsReadme(input) {
|
|
|
1912
1880
|
"- `progress/README.md` - 进度交接日志 / progress handoff logs",
|
|
1913
1881
|
"- `reports/README.md` - 验证与审计报告 / verification and audit reports",
|
|
1914
1882
|
"- `decisions/README.md` - 架构决策 / architecture decisions",
|
|
1883
|
+
"- `templates/README.md` - 模板入口与类别说明 / template entrypoint and category guide",
|
|
1915
1884
|
"- `templates/` - 可复用的计划、报告与 DAG 模板 / reusable planning, reporting, and DAG templates",
|
|
1916
1885
|
"- `templates/production-readiness-checklist.md` - 低/中风险单仓库 DAG 任务的 production readiness 检查清单 / production readiness checklist for low/medium-risk single-repo DAG work",
|
|
1917
1886
|
"- `templates/worker-dogfood-setup.md` - 发布控制器下的真实 Worker sample setup / real Worker sample setup with a published controller",
|
|
@@ -2016,10 +1985,34 @@ function buildTargetDevelopmentPrinciples(input) {
|
|
|
2016
1985
|
"9. Do not add placeholders as completed implementation.",
|
|
2017
1986
|
"10. Prefer existing local project patterns before adding new abstractions.",
|
|
2018
1987
|
"",
|
|
1988
|
+
"## Task Slicing: Vertical Tracer Bullets First",
|
|
1989
|
+
"",
|
|
1990
|
+
"Principle 1 covers **granularity** (one bounded block). This section covers **shape**: each slice should cross the real integration layers the work needs and leave an independently verifiable narrow loop.",
|
|
1991
|
+
"",
|
|
1992
|
+
"- Every slice needs its own acceptance criteria, verification commands, and failure conditions.",
|
|
1993
|
+
"- Prefer vertical tracer bullets over horizontal layering. Paths like \"schema → API → UI → tests\" are *possible* examples only; do not assume every project has those layers.",
|
|
1994
|
+
"- Horizontal anti-patterns: finish all of one layer before the next; or write every test first, then implement everything.",
|
|
1995
|
+
"- For behavior changes, use one failing test → minimal implementation → green → next behavior. Do not batch all RED then all GREEN.",
|
|
1996
|
+
"- Split large features into multiple independently runnable tasks/DAGs instead of one oversized writer across every layer.",
|
|
1997
|
+
"",
|
|
1998
|
+
"### Autonomy vs Governance (independent layers)",
|
|
1999
|
+
"",
|
|
2000
|
+
"| Dimension | Meaning | How to decide |",
|
|
2001
|
+
"|---|---|---|",
|
|
2002
|
+
"| Autonomy | Whether the slice needs synchronous human judgment, external access, or non-automatable decisions | Declare AFK/HITL in Contract, open questions, or human gate signals |",
|
|
2003
|
+
"| Governance | How strong review, repair, write-set, and verification gates must be | Default `--profile auto`; route to `minimal` / `standard` / `reviewed` / `supervised` by risk and delivery signals |",
|
|
2004
|
+
"",
|
|
2005
|
+
"- AFK does not mean `minimal` is required; ordinary automatable work may land on `standard` or `reviewed`.",
|
|
2006
|
+
"- HITL does not mean choosing `supervised` alone yields a correct human decision; require a concrete pause reason / decision gate.",
|
|
2007
|
+
"- Use `minimal` only for a single narrow writer, deterministic post shell verification, and no escalation signals.",
|
|
2008
|
+
"- High-risk, public-contract, init/runtime/CI/governance surface, or real human judgment gates should escalate via `auto`, or explicitly choose `reviewed` / `supervised`.",
|
|
2009
|
+
"",
|
|
2019
2010
|
"## Target Project Adaptation",
|
|
2020
2011
|
"",
|
|
2021
2012
|
"The initialized scripts provide language-neutral governance. The initialization model should adapt project-specific verification commands after reading the target project's actual files and toolchain.",
|
|
2022
2013
|
"",
|
|
2014
|
+
"Repo-local skills live under `.agents/skills/` (mirrored from the package `skills/` fallback).",
|
|
2015
|
+
"",
|
|
2023
2016
|
].join("\n");
|
|
2024
2017
|
}
|
|
2025
2018
|
function buildTargetFeatureWorkflow(input) {
|
|
@@ -2202,6 +2195,28 @@ function buildGovernanceDirectoryReadme(input) {
|
|
|
2202
2195
|
.split("/")
|
|
2203
2196
|
.map((part) => part.replace(/-/g, " "))
|
|
2204
2197
|
.join(" / ");
|
|
2198
|
+
if (input.dir === "decisions" || input.dir.endsWith("/decisions")) {
|
|
2199
|
+
return [
|
|
2200
|
+
`# ${title}`,
|
|
2201
|
+
"",
|
|
2202
|
+
`This directory stores ${input.projectName} architecture decision records (ADRs).`,
|
|
2203
|
+
"",
|
|
2204
|
+
"## When to write an ADR",
|
|
2205
|
+
"",
|
|
2206
|
+
"Write an ADR only when **all three** are true:",
|
|
2207
|
+
"",
|
|
2208
|
+
"1. **Hard to reverse** — changing the decision later has meaningful cost.",
|
|
2209
|
+
"2. **Surprising without context** — a future reader will ask why this path was chosen.",
|
|
2210
|
+
"3. **Real trade-off** — genuine alternatives existed and one was chosen for specific reasons.",
|
|
2211
|
+
"",
|
|
2212
|
+
"If any condition is missing, skip the ADR. Temporary scheduling, obvious implementation choices, and facts with no alternatives do not belong here.",
|
|
2213
|
+
"",
|
|
2214
|
+
"Use the ADR template under this governance root's `templates/adr.md` (or the package template when projecting). Update this README index when adding a new ADR.",
|
|
2215
|
+
"",
|
|
2216
|
+
"初始化只创建目录契约,不复制 loop-agent 源仓库的历史决策正文。目标项目中的具体 ADR 应由后续任务按真实取舍生成。",
|
|
2217
|
+
"",
|
|
2218
|
+
].join("\n");
|
|
2219
|
+
}
|
|
2205
2220
|
return [
|
|
2206
2221
|
`# ${title}`,
|
|
2207
2222
|
"",
|
|
@@ -2347,11 +2362,11 @@ export async function initializeLoopAgentProject(options) {
|
|
|
2347
2362
|
skipped,
|
|
2348
2363
|
});
|
|
2349
2364
|
for (const doc of CORE_DOC_FILES) {
|
|
2350
|
-
const generated = buildGeneratedCoreDoc({ doc, projectName, governanceRoot });
|
|
2365
|
+
const generated = buildGeneratedCoreDoc({ doc: doc.target, projectName, governanceRoot });
|
|
2351
2366
|
if (generated) {
|
|
2352
2367
|
await writeTextIfMissing({
|
|
2353
2368
|
repoRoot,
|
|
2354
|
-
relativePath: path.join(governanceRoot, doc),
|
|
2369
|
+
relativePath: path.join(governanceRoot, doc.target),
|
|
2355
2370
|
content: generated,
|
|
2356
2371
|
merge,
|
|
2357
2372
|
written,
|
|
@@ -2362,8 +2377,8 @@ export async function initializeLoopAgentProject(options) {
|
|
|
2362
2377
|
await copyFileIfMissing({
|
|
2363
2378
|
assetRoot,
|
|
2364
2379
|
repoRoot,
|
|
2365
|
-
sourceRelativePath: path.join("docs", doc),
|
|
2366
|
-
targetRelativePath: path.join(governanceRoot, doc),
|
|
2380
|
+
sourceRelativePath: path.join("docs", doc.source),
|
|
2381
|
+
targetRelativePath: path.join(governanceRoot, doc.target),
|
|
2367
2382
|
merge,
|
|
2368
2383
|
written,
|
|
2369
2384
|
skipped,
|
package/dist/commands/stats.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { readFile, readdir } from
|
|
2
|
-
import path from
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildContextUsageReport, formatContextUsageReportHuman, parseStatsContextArgs, } from "../application/context-usage/skill-resolution-stats.js";
|
|
3
4
|
function percentile(values, p) {
|
|
4
5
|
if (values.length === 0)
|
|
5
6
|
return null;
|
|
@@ -12,8 +13,8 @@ function formatMs(ms) {
|
|
|
12
13
|
return `${(ms / 60_000).toFixed(1)} min`;
|
|
13
14
|
return `${(ms / 1_000).toFixed(1)}s`;
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
const tasksDir = path.join(repoRoot,
|
|
16
|
+
async function runLegacyStepStats(repoRoot) {
|
|
17
|
+
const tasksDir = path.join(repoRoot, ".harness", "tasks");
|
|
17
18
|
const stepRecords = {};
|
|
18
19
|
let taskDirs = [];
|
|
19
20
|
try {
|
|
@@ -21,20 +22,20 @@ export async function runStats(repoRoot) {
|
|
|
21
22
|
taskDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
22
23
|
}
|
|
23
24
|
catch {
|
|
24
|
-
console.log(
|
|
25
|
+
console.log("no task directories found");
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
28
|
for (const taskId of taskDirs) {
|
|
28
|
-
const jsonlPath = path.join(tasksDir, taskId,
|
|
29
|
+
const jsonlPath = path.join(tasksDir, taskId, "logs", "executor.jsonl");
|
|
29
30
|
try {
|
|
30
|
-
const content = await readFile(jsonlPath,
|
|
31
|
+
const content = await readFile(jsonlPath, "utf-8");
|
|
31
32
|
for (const line of content.split(/\r?\n/)) {
|
|
32
33
|
const trimmed = line.trim();
|
|
33
34
|
if (!trimmed)
|
|
34
35
|
continue;
|
|
35
36
|
try {
|
|
36
37
|
const record = JSON.parse(trimmed);
|
|
37
|
-
if (typeof record.step ===
|
|
38
|
+
if (typeof record.step === "string" && typeof record.durationMs === "number") {
|
|
38
39
|
const step = record.step;
|
|
39
40
|
if (!stepRecords[step])
|
|
40
41
|
stepRecords[step] = [];
|
|
@@ -55,7 +56,7 @@ export async function runStats(repoRoot) {
|
|
|
55
56
|
// skip missing executor.jsonl
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
|
-
const stepOrder = [
|
|
59
|
+
const stepOrder = ["analyze", "plan", "spec", "implement", "verify", "retrospective"];
|
|
59
60
|
let totalRecords = 0;
|
|
60
61
|
let totalTimedOut = 0;
|
|
61
62
|
for (const step of stepOrder) {
|
|
@@ -75,10 +76,38 @@ export async function runStats(repoRoot) {
|
|
|
75
76
|
console.log(` max : ${formatMs(Math.max(...durations))}`);
|
|
76
77
|
if (timedOutCount > 0)
|
|
77
78
|
console.log(` timedOut: ${timedOutCount}`);
|
|
78
|
-
console.log(
|
|
79
|
+
console.log("");
|
|
79
80
|
}
|
|
80
|
-
console.log(`${
|
|
81
|
+
console.log(`${"=".repeat(40)}`);
|
|
81
82
|
console.log(`total runs: ${totalRecords}`);
|
|
82
83
|
if (totalTimedOut > 0)
|
|
83
84
|
console.log(`total timed out: ${totalTimedOut}`);
|
|
84
85
|
}
|
|
86
|
+
async function runContextStats(repoRoot, args) {
|
|
87
|
+
const parsed = parseStatsContextArgs(args);
|
|
88
|
+
const report = await buildContextUsageReport(repoRoot, { last: parsed.last });
|
|
89
|
+
if (parsed.json) {
|
|
90
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(formatContextUsageReportHuman(report));
|
|
94
|
+
}
|
|
95
|
+
if (!report.ok)
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* `stats` — legacy step-duration histogram (default, no subcommand).
|
|
100
|
+
* `stats context [--last N] [--json]` — skill-resolution / outcome telemetry.
|
|
101
|
+
*/
|
|
102
|
+
export async function runStats(repoRoot, args = []) {
|
|
103
|
+
const [subcommand, ...rest] = args;
|
|
104
|
+
if (subcommand === undefined) {
|
|
105
|
+
await runLegacyStepStats(repoRoot);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (subcommand === "context") {
|
|
109
|
+
await runContextStats(repoRoot, rest);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`unknown stats subcommand: ${subcommand}\nusage: stats | stats context [--last <n>] [--json]`);
|
|
113
|
+
}
|
|
@@ -165,7 +165,17 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
165
165
|
resultSchemaVersion: 1,
|
|
166
166
|
envelopeSchemaVersion: 1,
|
|
167
167
|
requiredErrorCodes: ["INVALID_INPUT", "OPERATION_NEEDS_RECONCILE"],
|
|
168
|
-
description: "Repo doctor
|
|
168
|
+
description: "Repo health doctor with machine-readable report and read-only context audit (--context).",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
action: "statsContext",
|
|
172
|
+
cli: "loop-agent stats context --last 50 --json",
|
|
173
|
+
kind: "read",
|
|
174
|
+
inputSchemaVersion: 1,
|
|
175
|
+
resultSchemaVersion: 1,
|
|
176
|
+
envelopeSchemaVersion: 1,
|
|
177
|
+
requiredErrorCodes: ["INVALID_INPUT"],
|
|
178
|
+
description: "Bounded skill-resolution / node-outcome telemetry over recent DAG runs (not compliance rates).",
|
|
169
179
|
},
|
|
170
180
|
{
|
|
171
181
|
action: "dagReport",
|
|
@@ -39,6 +39,8 @@ export function openConsoleAppData(options) {
|
|
|
39
39
|
staged: path.join(repoNamespace, "staged"),
|
|
40
40
|
assessments: path.join(repoNamespace, "assessments"),
|
|
41
41
|
interviews: path.join(repoNamespace, "interviews"),
|
|
42
|
+
chats: path.join(repoNamespace, "chats"),
|
|
43
|
+
chatSessions: path.join(repoNamespace, "chat-sessions"),
|
|
42
44
|
};
|
|
43
45
|
for (const dir of [
|
|
44
46
|
paths.drafts,
|
|
@@ -47,6 +49,8 @@ export function openConsoleAppData(options) {
|
|
|
47
49
|
paths.staged,
|
|
48
50
|
paths.assessments,
|
|
49
51
|
paths.interviews,
|
|
52
|
+
paths.chats,
|
|
53
|
+
paths.chatSessions,
|
|
50
54
|
]) {
|
|
51
55
|
ensureSecureDir(dir);
|
|
52
56
|
}
|