@tea-agent/loop-agent 0.10.0-alpha.0 → 0.11.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.
Files changed (48) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +39 -47
  3. package/README.md +33 -6
  4. package/dist/application/dag/args.js +2 -3
  5. package/dist/application/dag/generate-task-dag.js +5 -14
  6. package/dist/cli/command-definitions.js +44 -5
  7. package/dist/cli/program.js +37 -3
  8. package/dist/cli/update/notifier.js +117 -0
  9. package/dist/cli/update/npm-client.js +151 -0
  10. package/dist/cli/update/policy.js +58 -0
  11. package/dist/cli/update/state.js +68 -0
  12. package/dist/cli.js +33 -0
  13. package/dist/commands/init.js +432 -58
  14. package/dist/commands/plan.js +50 -0
  15. package/dist/governance/exec-plans.js +545 -0
  16. package/dist/governance/manifest-types.js +0 -5
  17. package/dist/task/config-types.js +0 -1
  18. package/dist/worker/observe/static/app.js +326 -45
  19. package/dist/worker/observe/static/styles.css +1 -0
  20. package/dist/workflows/dag/governance-profile.js +0 -10
  21. package/dist/workflows/dag/init-hybrid.js +5 -201
  22. package/dist/workflows/dag/sdd-embedded.js +128 -0
  23. package/dist/workflows/dag/skill-instructions.js +5 -4
  24. package/docs/README.md +1 -0
  25. package/docs/agent-dag-runner.md +2 -2
  26. package/docs/architecture/runtime-boundaries.md +3 -0
  27. package/docs/design/README.md +1 -0
  28. package/docs/development-principles.md +1 -1
  29. package/docs/exec-plans/active/README.md +2 -2
  30. package/docs/exec-plans/completed/README.md +6 -0
  31. package/docs/feature-workflow.md +27 -21
  32. package/docs/harness-methodology-debugging.md +1 -1
  33. package/docs/harness-methodology-tdd.md +3 -3
  34. package/docs/init-surface.manifest.json +23 -50
  35. package/docs/loop-agent-harness.md +8 -3
  36. package/docs/progress/README.md +6 -0
  37. package/docs/reports/README.md +10 -0
  38. package/docs/templates/project-start-checklist.md +2 -2
  39. package/harness.json +1 -3
  40. package/package.json +3 -3
  41. package/skills/frontend-implementation/SKILL.md +3 -0
  42. package/skills/loop-agent/references/command-reference.md +6 -0
  43. package/skills/loop-agent/references/docs-converge.md +5 -5
  44. package/skills/loop-agent/references/task-workflow.md +1 -1
  45. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +0 -131
  46. package/docs/templates/backend-test-dag.json +0 -213
  47. package/docs/templates/backend-test-dag.retrospect.prompt.md +0 -128
  48. package/docs/templates/backend-test-dag.review-cases.prompt.md +0 -85
@@ -8,6 +8,7 @@ import { BASELINE_FORBIDDEN_PATHS } from "./governance-constants.js";
8
8
  import { resolveAdapter } from "../../adapters/index.js";
9
9
  import { loadHarnessManifest } from "../../governance/harness.js";
10
10
  import { buildAuthoritySurfaceAuditNode, buildAuthoritySurfaceGateNode, resolveAuthoritySurfaceAudit, } from "./authority-surface.js";
11
+ import { applySddEmbeddedEnhancements, probeRepoLocalSddSkills, } from "./sdd-embedded.js";
11
12
  import { getTaskPaths, loadTaskConfig } from "../../task/runtime.js";
12
13
  import { materializeTaskReferenceDocs } from "../../task/source-references.js";
13
14
  import { resolveVerifyPreset } from "../../executors/shell-verification.js";
@@ -535,6 +536,7 @@ export async function loadTaskHybridSources(repoRoot, taskId) {
535
536
  enabledExecutors: resolveEnabledExecutors(manifest.executors),
536
537
  executorModelMatrix: resolveExecutorModelMatrices(manifest),
537
538
  verifyCommands,
539
+ sddEmbeddedSkills: await probeRepoLocalSddSkills(repoRoot),
538
540
  };
539
541
  }
540
542
  function mergeFinalVerifyCommands(repoRoot, taskConfig, adapterCommands) {
@@ -736,6 +738,7 @@ export function buildStandardHybridDagFromTask(sources) {
736
738
  },
737
739
  ],
738
740
  };
741
+ applySddEmbeddedEnhancements(spec, sources.sddEmbeddedSkills ?? new Set());
739
742
  parseDagSpec(spec);
740
743
  assertValidDagSpec(spec);
741
744
  return spec;
@@ -1029,212 +1032,11 @@ function buildFrontendHybridDagFromTask(sources) {
1029
1032
  assertValidDagSpec(spec);
1030
1033
  return spec;
1031
1034
  }
1032
- // ---------------------------------------------------------------------------
1033
- // Backend test DAG template
1034
- // ---------------------------------------------------------------------------
1035
- function buildAnalyzeInputsNode(sources) {
1036
- return {
1037
- id: "analyze-inputs-pi",
1038
- depends_on: [],
1039
- role: "planner",
1040
- executor: "pi",
1041
- complexity: "MED",
1042
- writePolicy: "read-only",
1043
- allowedPaths: commonReadOnlyPaths(sources),
1044
- forbiddenPaths: commonForbiddenPaths(sources),
1045
- outputContract: "Plain Markdown end-to-end test analysis contract (scope, risks, strategy highlights); no file writes.",
1046
- subtask_prompt: [
1047
- "Read the task source materials (需求.md, 开发详设.md and other references) and produce a concise end-to-end test analysis contract.",
1048
- "Cover: backend test scope, risk items, and strategy highlights. Identify key modules, integration points, and boundary conditions.",
1049
- "Read-only: do not modify code, docs, artifacts, or repository files.",
1050
- buildSourceContextBlock(sources),
1051
- ].join("\n\n"),
1052
- };
1053
- }
1054
- function buildGenerateBackendFunctionalCasesNode(sources) {
1055
- return {
1056
- id: "generate-backend-functional-cases-pi",
1057
- depends_on: ["analyze-inputs-pi"],
1058
- role: "implementer",
1059
- executor: "pi",
1060
- toolProfile: "write",
1061
- complexity: "MED",
1062
- writePolicy: "exclusive",
1063
- writeSet: ["testcase/md/**"],
1064
- allowedPaths: ["testcase/md/**"],
1065
- forbiddenPaths: commonForbiddenPaths(sources),
1066
- subtask_prompt: [
1067
- "Based on the upstream test analysis contract, generate structured backend functional test cases in Markdown.",
1068
- "Each test case ID must use the BE-<MODULE>-<NNN> format (e.g. BE-ORDER-001).",
1069
- "Write test case files under testcase/md/. Cover positive paths, negative paths, and boundary conditions.",
1070
- "Stay within writeSet. Do not write root artifacts/**.",
1071
- buildSourceContextBlock(sources),
1072
- ].join("\n\n"),
1073
- };
1074
- }
1075
- function buildReviewBackendCasesNode(sources) {
1076
- return {
1077
- id: "review-backend-cases-pi",
1078
- depends_on: ["generate-backend-functional-cases-pi"],
1079
- role: "reviewer",
1080
- executor: "pi",
1081
- complexity: "HIGH",
1082
- writePolicy: "read-only",
1083
- allowedPaths: commonReadOnlyPaths(sources),
1084
- forbiddenPaths: commonForbiddenPaths(sources),
1085
- outputContract: "Plain Markdown whose first non-empty line is VERDICT: pass or VERDICT: request-revision; followed by Findings and Coverage Assessment. No file writes.",
1086
- subtask_prompt: [
1087
- "Review the generated backend functional test cases for completeness and quality.",
1088
- "First non-empty line must be exactly VERDICT: pass or VERDICT: request-revision.",
1089
- "Check: coverage of requirement acceptance criteria, case ID format (BE-<MODULE>-<NNN>), positive/negative/boundary coverage, and traceability to source requirements.",
1090
- "Any Critical/Important finding must force VERDICT: request-revision. Read-only: do not modify files.",
1091
- buildSourceContextBlock(sources),
1092
- ].join("\n\n"),
1093
- };
1094
- }
1095
- function buildGenerateBackendPytestNode(sources) {
1096
- return {
1097
- id: "generate-backend-pytest-pi",
1098
- depends_on: ["review-backend-cases-pi"],
1099
- role: "implementer",
1100
- executor: "pi",
1101
- toolProfile: "write",
1102
- complexity: "HIGH",
1103
- writePolicy: "exclusive",
1104
- writeSet: ["testcase/**"],
1105
- allowedPaths: ["testcase/**"],
1106
- forbiddenPaths: commonForbiddenPaths(sources),
1107
- subtask_prompt: [
1108
- "Convert the reviewed backend functional test cases into pytest automation code.",
1109
- "Write test files under testcase/. Each functional test case ID (BE-<MODULE>-<NNN>) must map 1:1 to an automated pytest function for traceability.",
1110
- "Every generated test file must start with test_ prefix (e.g. test_order.py) to comply with pytest discovery.",
1111
- "Identify the target project's pytest conventions (conftest.py, fixture patterns, pytest.ini/pyproject.toml config) by reading existing files, but do NOT modify any existing framework files.",
1112
- "Only create NEW test script files. Do NOT modify conftest.py, pytest.ini, pyproject.toml, setup.cfg, __init__.py, or any other existing file.",
1113
- "If a file with the target name already exists under testcase/, add a numeric suffix: test_order.py → test_order_01.py → test_order_02.py. Never overwrite or append to existing files. Each test script must be a standalone file.",
1114
- "Stay within writeSet. Do not write root artifacts/**.",
1115
- buildSourceContextBlock(sources),
1116
- ].join("\n\n"),
1117
- };
1118
- }
1119
- function buildExecuteBackendPytestNode(sources) {
1120
- return {
1121
- id: "execute-backend-pytest-shell",
1122
- depends_on: ["generate-backend-pytest-pi"],
1123
- role: "verifier",
1124
- executor: "shell",
1125
- complexity: "LOW",
1126
- writePolicy: "read-only",
1127
- allowedPaths: commonReadOnlyPaths(sources),
1128
- forbiddenPaths: commonForbiddenPaths(sources),
1129
- outputContract: "Archived pytest stdout/stderr with exit codes and HTML report path; no worktree writes.",
1130
- subtask_prompt: "Run pytest for the backend test suite and capture results.",
1131
- shell: {
1132
- commands: [
1133
- "python -m pytest testcase/ --html=reports/backend-test-report.html -v",
1134
- ],
1135
- verifyEvidence: buildVerifyEvidence({
1136
- phase: "final",
1137
- quota: "full",
1138
- commandSource: "inline",
1139
- fallbackCommands: [
1140
- "python -m pytest testcase/ --html=reports/backend-test-report.html -v",
1141
- ],
1142
- finalFullRequired: true,
1143
- }),
1144
- cwd: ".",
1145
- timeoutMs: 300000,
1146
- },
1147
- };
1148
- }
1149
- function buildTestRetrospectNode(sources) {
1150
- return {
1151
- id: "test-retrospect-pi",
1152
- depends_on: ["execute-backend-pytest-shell"],
1153
- role: "closeout",
1154
- executor: "pi",
1155
- toolProfile: "write",
1156
- complexity: "MED",
1157
- writePolicy: "exclusive",
1158
- writeSet: ["docs/test-reports/**"],
1159
- allowedPaths: ["docs/test-reports/**"],
1160
- forbiddenPaths: commonForbiddenPaths(sources),
1161
- subtask_prompt: [
1162
- "Read upstream review-backend-cases-pi review report and execute-backend-pytest-shell pytest output, then generate a test retrospective report.",
1163
- "Write the report under docs/test-reports/ in Markdown. The report must include:",
1164
- "1) Test coverage summary (total cases, pass rate, failed case analysis)",
1165
- "2) Review findings and their resolution status",
1166
- "3) Maturity rating: A (100% coverage + 100% pass + no Critical findings), B (≥80% coverage + ≥90% pass + Low findings only), C (≥60% coverage + ≥70% pass), D (below C thresholds)",
1167
- "Stay within writeSet. Do not write root artifacts/**.",
1168
- buildSourceContextBlock(sources),
1169
- ].join("\n\n"),
1170
- };
1171
- }
1172
- const BACKEND_TEST_DEFAULTS = {
1173
- ...HYBRID_DEFAULTS,
1174
- writePolicy: "read-only",
1175
- };
1176
- const BACKEND_TEST_SKILLS_BY_ROLE = {
1177
- planner: ["loop-agent"],
1178
- scout: [],
1179
- implementer: ["test-driven-development", "verification-before-completion"],
1180
- reviewer: ["requesting-code-review", "code-review-core"],
1181
- verifier: ["verification-before-completion", "systematic-debugging"],
1182
- closeout: ["loop-agent", "verification-before-completion"],
1183
- };
1184
- function buildBackendTestHybridDag(sources) {
1185
- const { taskConfig } = sources;
1186
- const sourceContext = buildSourceContextBlock(sources);
1187
- const readOnlyPaths = commonReadOnlyPaths(sources);
1188
- const forbiddenPaths = commonForbiddenPaths(sources);
1189
- const globalConstraints = [
1190
- ...taskConfig.hardConstraints,
1191
- ...(sources.constraintMarkdown
1192
- ? [`See 执行约束.md in task source (${sources.taskId})`]
1193
- : []),
1194
- ...STANDARD_GLOBAL_CONSTRAINTS,
1195
- "backend-test-dag nodes must maintain traceability from requirements to functional cases to pytest automation.",
1196
- "Functional test case IDs must use BE-<MODULE>-<NNN> format.",
1197
- "pytest execution must produce HTML reports under reports/.",
1198
- "pytest automation scripts must use test_ filename prefix for pytest discovery.",
1199
- "generate-backend-pytest-pi must only create new test files under testcase/; modifying existing framework files (conftest.py, pytest.ini, pyproject.toml) is forbidden.",
1200
- "If a target test filename already exists under testcase/, add a numeric suffix (_01, _02, ...); never overwrite or append to existing files.",
1201
- "execute-backend-pytest-shell must not modify test assertions or production code to make tests pass; test failures indicate potential implementation issues and must be reported honestly.",
1202
- ];
1203
- const spec = {
1204
- version: 2,
1205
- title: `Backend test DAG: ${taskConfig.title}`,
1206
- outputLanguage: sources.outputLanguage ?? DEFAULT_DAG_OUTPUT_LANGUAGE,
1207
- objective: extractObjective(sources.requirementMarkdown, taskConfig.title),
1208
- successCriteria: extractSuccessCriteria(sources.requirementMarkdown, sources.taskId),
1209
- globalConstraints,
1210
- defaults: {
1211
- ...BACKEND_TEST_DEFAULTS,
1212
- contextProfile: taskConfig.contextProfile,
1213
- },
1214
- skillsByRole: BACKEND_TEST_SKILLS_BY_ROLE,
1215
- executorModels: sources.executorModelMatrix ?? DEFAULT_DAG_EXECUTOR_MODELS,
1216
- tasks: [
1217
- buildAnalyzeInputsNode(sources),
1218
- buildGenerateBackendFunctionalCasesNode(sources),
1219
- buildReviewBackendCasesNode(sources),
1220
- buildGenerateBackendPytestNode(sources),
1221
- buildExecuteBackendPytestNode(sources),
1222
- buildTestRetrospectNode(sources),
1223
- ],
1224
- };
1225
- parseDagSpec(spec);
1226
- assertValidDagSpec(spec);
1227
- return spec;
1228
- }
1229
1035
  export function buildHybridDagFromTask(sources, options = {}) {
1230
1036
  if (sources.taskConfig.taskKind === "frontend-implementation" ||
1231
1037
  options.template === "frontend-implementation") {
1232
1038
  return buildFrontendHybridDagFromTask(sources);
1233
1039
  }
1234
- if (sources.taskConfig.taskKind === "backend-test" ||
1235
- options.template === "backend-test-dag") {
1236
- return buildBackendTestHybridDag(sources);
1237
- }
1238
1040
  const standard = buildStandardHybridDagFromTask(sources);
1239
1041
  const template = options.template ?? "standard-dag";
1240
1042
  if (template === "standard-dag")
@@ -1332,6 +1134,7 @@ function buildReviewGatedHybridDag(standard, sources) {
1332
1134
  const closeout = getTaskOrThrow(spec, "closeout-pi");
1333
1135
  replaceTask(spec, cloneTask(closeout, { depends_on: ["review-gate-shell"] }));
1334
1136
  spec.tasks.splice(spec.tasks.length - 1, 0, buildReviewNode(sources), buildReviewGateNode(sources));
1137
+ applySddEmbeddedEnhancements(spec, sources.sddEmbeddedSkills ?? new Set());
1335
1138
  parseDagSpec(spec);
1336
1139
  assertValidDagSpec(spec);
1337
1140
  return spec;
@@ -1601,6 +1404,7 @@ function buildSupervisedHybridDag(standard, sources) {
1601
1404
  cloneTask(closeout, { depends_on: ["decision-pi"] }),
1602
1405
  ],
1603
1406
  };
1407
+ applySddEmbeddedEnhancements(spec, sources.sddEmbeddedSkills ?? new Set());
1604
1408
  parseDagSpec(spec);
1605
1409
  assertValidDagSpec(spec);
1606
1410
  return spec;
@@ -0,0 +1,128 @@
1
+ import { access } from "node:fs/promises";
2
+ import path from "node:path";
3
+ /**
4
+ * SDD embedded-mode optional enhancement.
5
+ *
6
+ * When the target project ships repo-local `SDD-*` skills (under
7
+ * `.agents/skills/<name>/SKILL.md`), loop-agent can
8
+ * reuse them as knowledge/method references inside individual DAG nodes. This
9
+ * module probes those repo-local paths and, on a hit, appends the matched skill
10
+ * name to the mapped node's `task.skills` (so it flows through the existing
11
+ * run-owned skill snapshot via `resolveDagNodeSkills`) plus a loop-agent-managed
12
+ * embedded-mode constraint block to the node prompt.
13
+ *
14
+ * loop-agent always owns process/state/verification/closeout. SDD state
15
+ * transitions, confirmation gates, and archival are explicitly forbidden inside
16
+ * the embedded-mode block.
17
+ */
18
+ /** The three SDD skills that may be reused as repo-local knowledge. */
19
+ export const SDD_SKILL_NAMES = [
20
+ "SDD-requirement-analysis",
21
+ "SDD-design-analysis",
22
+ "SDD-implementation-test-review",
23
+ ];
24
+ /**
25
+ * DAG node id -> mapped SDD skill name. `verify-pi` is present in standard and
26
+ * review-gated templates; supervised verification stays shell-based. The init skills
27
+ * (`SDD-code-spec-init`, `SDD-project-how-to-spec-init`) are intentionally
28
+ * absent: they are never auto-executed inside a normal feature DAG.
29
+ */
30
+ export const SDD_NODE_SKILL_MAP = {
31
+ "contract-pi": "SDD-requirement-analysis",
32
+ "plan-pi": "SDD-design-analysis",
33
+ "implement-pi": "SDD-implementation-test-review",
34
+ "repair-pi": "SDD-implementation-test-review",
35
+ "verify-pi": "SDD-implementation-test-review",
36
+ "review-pi": "SDD-implementation-test-review",
37
+ };
38
+ /** DAG node id -> SDD phase label injected into the constraint block. */
39
+ export const SDD_NODE_PHASE_LABEL = {
40
+ "contract-pi": "需求",
41
+ "plan-pi": "设计",
42
+ "implement-pi": "实现",
43
+ "repair-pi": "修复",
44
+ "verify-pi": "验证",
45
+ "review-pi": "审查",
46
+ };
47
+ /** Fence tokens used to delimit the embedded-mode constraint block. */
48
+ export const SDD_EMBEDDED_MODE_OPEN = "[SDD-EMBEDDED-MODE]";
49
+ export const SDD_EMBEDDED_MODE_CLOSE = "[/SDD-EMBEDDED-MODE]";
50
+ const SDD_SKILL_CANDIDATE_BASES = [".agents/skills"];
51
+ /**
52
+ * Probe the target project repo for repo-local SDD skills. Only the canonical
53
+ * repo-relative `.agents/skills` base is checked; this deliberately does NOT reuse
54
+ * the skill loader candidate list (which also falls back to user-level and
55
+ * bundled package skills) so user-level/package skills never trigger
56
+ * auto-enhancement.
57
+ *
58
+ * Returns the set of SDD skill names whose `SKILL.md` exists under at least one
59
+ * repo-local base. Returns an empty set when `repoRoot` is absent so callers
60
+ * that do not pass a repo root preserve byte-level default output.
61
+ */
62
+ export async function probeRepoLocalSddSkills(repoRoot) {
63
+ if (!repoRoot)
64
+ return new Set();
65
+ const hits = new Set();
66
+ for (const name of SDD_SKILL_NAMES) {
67
+ for (const base of SDD_SKILL_CANDIDATE_BASES) {
68
+ const candidate = path.join(repoRoot, base, name, "SKILL.md");
69
+ try {
70
+ await access(candidate);
71
+ hits.add(name);
72
+ break;
73
+ }
74
+ catch {
75
+ // not present at this candidate base; try the next
76
+ }
77
+ }
78
+ }
79
+ return hits;
80
+ }
81
+ /**
82
+ * Build the loop-agent-managed embedded-mode constraint block for a node. The
83
+ * block declares DAG-node-boundary priority and forbids SDD state transitions,
84
+ * confirmation gates, working_requirements_status updates, and archival.
85
+ *
86
+ * Returns `null` for unmapped node ids (e.g. scouts, shell gates, closeout).
87
+ */
88
+ export function buildSddEmbeddedConstraintBlock(nodeId) {
89
+ const phase = SDD_NODE_PHASE_LABEL[nodeId];
90
+ if (!phase)
91
+ return null;
92
+ return [
93
+ SDD_EMBEDDED_MODE_OPEN,
94
+ `当前 DAG 节点: ${nodeId},阶段: ${phase}`,
95
+ "loop-agent 拥有流程、状态、验证与收口控制权;SDD skill 仅作 repo-local 知识与方法参考。",
96
+ "禁止:更新 working_requirements_status.md;推进 SDD 阶段;触发 SDD 用户确认;执行归档。",
97
+ "优先级:本节点的读写边界、当前阶段与输出契约优先于任何 SDD 指令冲突。",
98
+ "implement/repair writer 仍必须服从当前 writeSet/allowedPaths/forbiddenPaths;不得把 ai_workspace 加入隐式写范围,也不得解析或写入 SDD 工作区状态机。",
99
+ SDD_EMBEDDED_MODE_CLOSE,
100
+ ].join("\n");
101
+ }
102
+ /**
103
+ * Apply SDD embedded-mode enhancements in place on a fully-constructed DAG spec.
104
+ *
105
+ * For each mapped task whose mapped skill is present in the hit set:
106
+ * - append the skill name to `task.skills` (de-duplicated, order-preserving);
107
+ * - append the constraint block to the end of `task.subtask_prompt` (once).
108
+ *
109
+ * When the hit set is empty this is a no-op, preserving the default DAG byte
110
+ * for byte. The function is idempotent.
111
+ */
112
+ export function applySddEmbeddedEnhancements(spec, hitSkills) {
113
+ if (hitSkills.size === 0)
114
+ return;
115
+ for (const task of spec.tasks) {
116
+ const mapped = SDD_NODE_SKILL_MAP[task.id];
117
+ if (!mapped || !hitSkills.has(mapped))
118
+ continue;
119
+ const existing = task.skills ?? [];
120
+ if (!existing.includes(mapped)) {
121
+ task.skills = [...existing, mapped];
122
+ }
123
+ const block = buildSddEmbeddedConstraintBlock(task.id);
124
+ if (block && !task.subtask_prompt.includes(SDD_EMBEDDED_MODE_OPEN)) {
125
+ task.subtask_prompt = `${task.subtask_prompt}\n\n${block}`;
126
+ }
127
+ }
128
+ }
@@ -41,11 +41,12 @@ function buildSkillCandidatePaths(input) {
41
41
  }
42
42
  const piSkillsDir = path.join(input.homeDir, ".pi", "agent", "skills");
43
43
  candidates.push(normalizeCandidate(path.join(piSkillsDir, input.name, "SKILL.md")), normalizeCandidate(path.join(piSkillsDir, `${input.name}.md`)));
44
- candidates.push(normalizeCandidate(path.join(input.cwd, "skills", input.name, "SKILL.md")));
45
- // Agent-compatible project path (e.g. OpenCode). `skills/` stays the primary
46
- // loop-agent repo-local path; `.agents/skills` is searched after it and before
47
- // bundled skills so a project with only the mirror can still resolve.
44
+ // Canonical target-project repo-local skill path.
48
45
  candidates.push(normalizeCandidate(path.join(input.cwd, ".agents", "skills", input.name, "SKILL.md")));
46
+ // Source-repository compatibility: the loop-agent package itself still ships
47
+ // bundled skills under `skills/`, and local source development may resolve them
48
+ // before the package fallback is found.
49
+ candidates.push(normalizeCandidate(path.join(input.cwd, "skills", input.name, "SKILL.md")));
49
50
  if (input.name === "loop-agent") {
50
51
  candidates.push(normalizeCandidate(path.join(input.cwd, "skill", "SKILL.md")));
51
52
  }
package/docs/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  ## 核心文档
12
12
 
13
+ - `design/2026-07-14-loop-agent-self-update-notifier.md` — loop-agent CLI 自更新提醒设计与实现依据
13
14
  - `development-principles.md` — 仓库开发原则
14
15
  - `architecture/runtime-boundaries.md` — runtime 层边界与依赖方向
15
16
  - `architecture/README.md` — 架构文档目录索引与阅读路径
@@ -21,11 +21,11 @@ loop-agent run-dag --dag <temp-dir>/<task-id>-dag.json --cwd .
21
21
 
22
22
  ## Skills
23
23
 
24
- DAG spec 可声明 `defaults.skills`、`skillsByRole` 与节点级 `skills`。Runner `skills/<skill-name>/SKILL.md` 解析本地指令,并在各节点 `skills.json` artifact 中记录解析元数据。
24
+ DAG spec 可声明 `defaults.skills`、`skillsByRole` 与节点级 `skills`。Runner 优先从目标项目 `.agents/skills/<skill-name>/SKILL.md` 解析本地指令,再回退到包内 `skills/`,并在各节点 `skills.json` artifact 中记录解析元数据。
25
25
 
26
26
  执行前可用 `dag validate --strict-skills` 做 opt-in skill audit;该门禁会在 missing/error/truncated skill 或 unresolved reference 出现时失败。默认 role skill 应来自 `docs/skills/vetted-skill-registry.md` 中记录的 repo-local wrapper。
27
27
 
28
- `loop-agent` skill 位于 `skills/loop-agent/SKILL.md`。遗留根路径 `skill/SKILL.md` 仅为旧 worktree 保留兼容 fallback。
28
+ 目标项目的 `loop-agent` skill 位于 `.agents/skills/loop-agent/SKILL.md`。loop-agent 源仓库和 npm 包内置版本仍位于 `skills/loop-agent/SKILL.md`;遗留根路径 `skill/SKILL.md` 仅为旧 worktree 保留兼容 fallback。
29
29
 
30
30
  ## Artifacts
31
31
 
@@ -161,10 +161,13 @@ Runner / Loop ──(迁移中)──> 逐步改为仅经 Store / Appli
161
161
  |--------|----------|----------|
162
162
  | `scripts/check-architecture-boundaries.sh` | workflow/executor forbidden import,及 Worker → CLI/commands/application import | 新的未 allowlist violation |
163
163
  | `scripts/check-command-registry-drift.sh` | `command-reference.md` 中的 top-level command vs `src/cli/catalog.ts` | 文档引用未注册 command |
164
+ | `scripts/check-exec-plan-index-sync.sh` | `docs/exec-plans/{active,completed}` 目录文件 vs 对应 `README.md` 索引 | 任一 plan 文件未在索引登记 |
164
165
  | `scripts/check-skill-entry.sh` | `loop-agent` / `agent-worker` 的 frontmatter、required references、入口行数与 operator trigger vocabulary | 任一公共 skill 缺失、reference/trigger 漂移或入口超过 hard limit |
165
166
 
166
167
  版本化自举相关 exec plan:`docs/exec-plans/active/2026-07-13-versioned-self-hosting-bootstrap.md`。
167
168
 
169
+ `src/governance/exec-plans.ts` 是 exec-plan 创建、完成与索引校验的共享 TypeScript 事实源:`plan create`/`plan complete`/`plan check` 与 `dag run-task` 前置校验都调用它。`scripts/check-exec-plan-index-sync.sh` 是独立的 shell 最终防线,与 TypeScript checker 并存;两者均不删除或弱化。
170
+
168
171
  ### 验证命令
169
172
 
170
173
  ```bash
@@ -25,6 +25,7 @@
25
25
 
26
26
  | 文档 | 用途 |
27
27
  |---|---|
28
+ | `2026-07-14-loop-agent-self-update-notifier.md` | loop-agent CLI 自更新提醒设计(设计已确认,尚未实现;覆盖用户级状态、npm global 来源证明、精确安装与验证边界) |
28
29
  | `DESIGN-cursor.md` | Observe 暖白运行控制台采用的 Cursor 风格视觉参考与设计 token |
29
30
  | `DESIGN-lovable.md` | Lovable 风格的暖色视觉系统参考 |
30
31
 
@@ -31,7 +31,7 @@ loop-agent 是面向 agentic coding 的工作流 runtime。仓库应保持小而
31
31
 
32
32
  - 源码:`src/`
33
33
  - 测试:`test/`
34
- - Skill 指令:`skills/`
34
+ - Skill 指令:源码仓库和 npm 包内置在 `skills/`,目标项目 repo-local skills 在 `.agents/skills/`
35
35
  - 验证与维护脚本:`scripts/`
36
36
  - 治理与交接产物:`docs/`
37
37
 
@@ -6,6 +6,6 @@
6
6
 
7
7
  当前 active execution plan:
8
8
 
9
- - (无)
9
+ - 暂无。
10
10
 
11
- - 已归档:`../completed/2026-07-12-observe-warm-console-redesign.md`、`../completed/2026-07-14-website-docs-ia-and-converge.md`、`../completed/2026-07-13-versioned-self-hosting-bootstrap.md`、`../completed/2026-07-12-pi-only-agent-runtime.md`、第二月 M2-01~M2-08、`../completed/2026-07-11-observe-dashboard-page-system.md`、`../completed/2026-07-11-observe-dashboard-detail-refinement.md`、`../completed/2026-07-11-observe-terminal-dag-kpi.md`、`../completed/2026-07-11-observe-polling-efficiency.md`、`../completed/2026-07-11-command-performance-guardrails.md` 及更早计划。
11
+ - 已归档:`../completed/2026-07-14-init-canonical-layout.md`、`../completed/2026-07-12-observe-warm-console-redesign.md`、`../completed/2026-07-14-website-docs-ia-and-converge.md`、`../completed/2026-07-13-versioned-self-hosting-bootstrap.md`、`../completed/2026-07-12-pi-only-agent-runtime.md`、第二月 M2-01~M2-08、`../completed/2026-07-11-observe-dashboard-page-system.md`、`../completed/2026-07-11-observe-dashboard-detail-refinement.md`、`../completed/2026-07-11-observe-terminal-dag-kpi.md`、`../completed/2026-07-11-observe-polling-efficiency.md`、`../completed/2026-07-11-command-performance-guardrails.md` 及更早计划。
@@ -4,9 +4,13 @@
4
4
 
5
5
  npm 包携带本 README 作为目录契约。具体 completed plan 属于目标仓库历史,不从 loop-agent 源码历史复制。
6
6
 
7
+ - [`2026-07-14-init-canonical-layout.md`](2026-07-14-init-canonical-layout.md) — 目标项目治理资料统一到 `ai_workspace/loop-agent/` 与 `.agents/skills/`,并为旧布局提供保守安全迁移
8
+ - [`2026-07-14-self-update-notifier-implementation.md`](2026-07-14-self-update-notifier-implementation.md) — 实现 loop-agent CLI 自更新提醒,覆盖拒绝版本、精确安装、npm global 来源证明和验证收口
7
9
  - [`2026-07-12-observe-warm-console-redesign.md`](2026-07-12-observe-warm-console-redesign.md) — 以暖白、细边界和高密度信息架构重构 Observe Dashboard;多轮细节调整后按用户确认收口归档。
8
10
  - [`2026-07-14-website-docs-ia-and-converge.md`](2026-07-14-website-docs-ia-and-converge.md) — Website 文档信息架构、双树边界与 `docs-converge` 同步机制
9
11
  - [`2026-07-14-frontend-spec-source-fallback.md`](2026-07-14-frontend-spec-source-fallback.md) — 统一前端规范来源为知识库优先、失败后强制检索当前项目 `openSpec/`
12
+ - [`2026-07-13-test-environment-stability.md`](2026-07-13-test-environment-stability.md) — 修复 Windows Git Bash、npm CLI 启动与 Git/Delivery 测试资源分类,避免验证节点反复失败并跳过 DAG 收口
13
+ - [`2026-07-13-sdd-embedded-skills.md`](2026-07-13-sdd-embedded-skills.md) — 目标项目 repo-local SDD skills 的可选 DAG 节点嵌入增强,loop-agent 保持流程、状态与写边界控制
10
14
  - [`2026-07-13-frontend-skill-contracts.md`](2026-07-13-frontend-skill-contracts.md) — 补齐前端节点 Skill 的输入、输出、证据与阻断契约,并预留组件/设计知识库接入 TODO
11
15
  - [`2026-07-13-versioned-self-hosting-bootstrap.md`](2026-07-13-versioned-self-hosting-bootstrap.md) — 固定已发布 controller identity、冻结 run-owned skills,并由隔离候选包完成 deterministic self-hosting takeover canary
12
16
  - [`2026-07-12-pi-only-agent-runtime.md`](2026-07-12-pi-only-agent-runtime.md) — 将 DAG、Loop、Delegate 和 Worker 收敛为 Pi-only 受治理 runtime,仅保留独立的 one-shot `cursor-prompt` sidecar
@@ -54,3 +58,5 @@ npm 包携带本 README 作为目录契约。具体 completed plan 属于目标
54
58
  - [`2026-07-10-obs-009.md`](2026-07-10-obs-009.md) — stale、quiet 与 timeout-risk 诊断
55
59
  - [`2026-07-10-obs-010.md`](2026-07-10-obs-010.md) — Failure Inbox、文档、package surface 与 smoke 验证
56
60
  - [`2026-07-10-observe-ui-review-remediation.md`](2026-07-10-observe-ui-review-remediation.md) — 修复 Observe UI 事件链路、历史 run 投影、artifact 安全边界与失败状态展示
61
+
62
+ - [`2026-07-13-exec-plan-lifecycle.md`](2026-07-13-exec-plan-lifecycle.md)
@@ -121,37 +121,27 @@ frontend-contract-pi
121
121
  ```
122
122
 
123
123
  这条链在实现前加入 design gate,并将前端静态验证与行为验证分开建模;当前 MVP 不包含独立 a11y、视觉回归或浏览器自动化 executor。
124
+ 前端 shell 验证优先使用任务源 `需求.md` / `执行约束.md` 中声明的前端验证命令,例如 `npm run typecheck`、`npm run build`、`npm test`;解析不到时再使用 adapter 验证命令和模板 fallback。
124
125
 
125
- 后端测试任务可通过 `task.json.taskKind = "backend-test"` `--profile backend-test` 选择专用模板:
126
+ `verify-shell` 使用 adapter 根据 task verify preset/quota 解析出的最终验证命令,并把新鲜 exit code/stdout/stderr 交给后续只读 verifier。review-gated 模板继续插入:
126
127
 
127
128
  ```text
128
- analyze-inputs-pi
129
- -> generate-backend-functional-cases-pi
130
- -> review-backend-cases-pi
131
- -> generate-backend-pytest-pi
132
- -> execute-backend-pytest-shell
133
- -> test-retrospect-pi
129
+ verify-shell -> verify-pi -> review-pi -> review-gate-shell -> closeout-pi
134
130
  ```
135
131
 
136
- 这条链覆盖后端功能测试从需求分析到复盘评级的全链路流程:
132
+ supervised 模板在实现路径上增加 write-set audit、soft/hard shell 验证、process supervision、有界 repair、decision gates 与可选 convergence retry。
137
133
 
138
- 1. **analyze-inputs-pi**:读取需求.md 和开发详设等参考文档,产出端到端测试分析契约(范围、风险、策略要点)
139
- 2. **generate-backend-functional-cases-pi**:根据契约生成结构化后端功能测试用例(Markdown),用例 ID 带 `BE-` 前缀(如 `BE-ORDER-001`),写入 `test-cases/backend/`
140
- 3. **review-backend-cases-pi**:评审后端功能测试用例,输出审查报告 + `VERDICT: pass` / `VERDICT: request-revision`
141
- 4. **generate-backend-pytest-pi**:将后端功能用例转化为 pytest 自动化代码,写入 `tests/backend/`
142
- 5. **execute-backend-pytest-shell**:执行 `pytest tests/backend/` 并生成 HTML 报告
143
- 6. **test-retrospect-pi**:读取上游审查报告和测试报告,生成复盘报告 + 成熟度评级(A/B/C/D)
134
+ ### 可选 repo-local SDD skill 增强
144
135
 
145
- 前端测试模板(`frontend-test-dag`)后续沿用对称命名即可接入。
146
- 前端 shell 验证优先使用任务源 `需求.md` / `执行约束.md` 中声明的前端验证命令,例如 `npm run typecheck`、`npm run build`、`npm test`;解析不到时再使用 adapter 验证命令和模板 fallback。
136
+ `dag run-task` 会在目标项目的 `.agents/skills/` 中探测三个可选 skill:
147
137
 
148
- `verify-shell` 使用 adapter 根据 task verify preset/quota 解析出的最终验证命令,并把新鲜 exit code/stdout/stderr 交给后续只读 verifier。review-gated 模板继续插入:
138
+ - `SDD-requirement-analysis` `contract-pi`
139
+ - `SDD-design-analysis` → `plan-pi`
140
+ - `SDD-implementation-test-review` → `implement-pi`、`repair-pi`、`verify-pi`、`review-pi`
149
141
 
150
- ```text
151
- verify-shell -> verify-pi -> review-pi -> review-gate-shell -> closeout-pi
152
- ```
142
+ 命中时,skill 通过节点 `skills` 进入现有 resolved instruction 和 run-owned snapshot 链路,并在节点任务中收到 embedded-mode 约束:只为当前 DAG 阶段提供知识、规范与方法,不得更新 `working_requirements_status.md`、推进 SDD 状态、触发 SDD 用户确认或执行归档。节点的读写边界、当前阶段与输出契约优先;writer 仍只允许写入显式 `writeSet`。`SDD-code-spec-init` 与 `SDD-project-how-to-spec-init` 不会在普通功能 DAG 中自动运行。
153
143
 
154
- supervised 模板在实现路径上增加 write-set audit、soft/hard shell 验证、process supervision、有界 repair、decision gates 与可选 convergence retry。
144
+ 探测不到这些 repo-local skills 时,DAG 不追加节点 skill 或约束块,保持当前默认流程。用户级或 npm 包内同名 skill 也不会作为自动启用信号。
155
145
 
156
146
  源码参考:
157
147
 
@@ -159,6 +149,7 @@ supervised 模板在实现路径上增加 write-set audit、soft/hard shell 验
159
149
  - `src/commands/dag-validate.ts`
160
150
  - `src/commands/run-dag.ts`
161
151
  - `src/workflows/dag/init-hybrid.ts`
152
+ - `src/workflows/dag/sdd-embedded.ts`
162
153
  - `src/workflows/dag/runner.ts`
163
154
 
164
155
  监督 agent 仍负责:
@@ -171,6 +162,21 @@ supervised 模板在实现路径上增加 write-set audit、soft/hard shell 验
171
162
 
172
163
  声称 Production Readiness v0.1 的低/中风险单仓库任务,另须遵循 `docs/production-readiness.md` 与 `docs/templates/production-readiness-checklist.md`。该标准冻结支持范围、非目标、必需 DAG 证据、failure routing 字段与最终验证门禁。
173
164
 
165
+ ## Exec-plan 生命周期
166
+
167
+ exec-plan 不是手工文档;它有确定性 CLI 生命周期,并与 `dag run-task` 共享同一索引校验源。
168
+
169
+ ```bash
170
+ loop-agent plan create <plan-id> "<title>"
171
+ loop-agent plan complete <plan-id> --summary "<summary>"
172
+ loop-agent plan check
173
+ ```
174
+
175
+ - `new-task` 不自动绑定 exec-plan;微小任务仍可不创建计划。
176
+ - `plan create` 优先读取目标项目 `<governanceRoot>/templates/exec-plan.md`,不存在时回退到发布包内置模板;create/complete 同步 active/completed 索引,拒绝重复 id、路径穿越与不安全文件名,多文件操作均具备回滚保护。
177
+ - `dag run-task` 在生成 DAG 草稿前运行 `plan check` 同源校验,索引漂移立即失败;空仓库与索引一致的仓库不受影响。
178
+ - `plan list`(只读)与 `docs archive`(兼容入口)保留;`scripts/check-exec-plan-index-sync.sh` 仍作为独立最终防线。
179
+
174
180
  ## 已移除的顺序工作流
175
181
 
176
182
  历史 Level 1 顺序 command surface 已从公开工作流移除。新工作不要用 `loop-agent run analyze|plan|spec|implement|verify|retrospective|auto|loop|continue|study`。
@@ -88,7 +88,7 @@ NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
88
88
 
89
89
  ### Phase 4:实现
90
90
 
91
- 1. **创建失败测试用例** — 遵循 RED-GREEN-REFACTOR(见 `docs/harness-methodology-tdd.md`)
91
+ 1. **创建失败测试用例** — 遵循 RED-GREEN-REFACTOR(见 `harness-methodology-tdd.md`)
92
92
  2. **实现单一修复** — 解决已识别的根因,一次一个改动,不顺手重构
93
93
  3. **验证修复** — 测试通过?其他测试没坏?问题真的解决了?
94
94
  4. **如果修复无效**:
@@ -125,6 +125,6 @@ npm test path/to/test.test.ts
125
125
 
126
126
  ## 参考
127
127
 
128
- - Harness 工作流:`docs/feature-workflow.md`
129
- - 验证矩阵:`docs/verification-matrix.md`
130
- - Sprint Contract 模板:`docs/templates/sprint-contract.md`
128
+ - Harness 工作流:`feature-workflow.md`
129
+ - 验证矩阵:`verification-matrix.md`
130
+ - Sprint Contract 模板:`templates/sprint-contract.md`