@tea-agent/loop-agent 0.10.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 (166) hide show
  1. package/AGENTS.md +10 -2
  2. package/CHANGELOG.md +67 -25
  3. package/README.md +82 -11
  4. package/dist/application/dag/args.js +1 -12
  5. package/dist/application/dag/generate-task-dag.js +23 -2
  6. package/dist/application/dag/run-dag.js +1 -27
  7. package/dist/application/dag/validate-dag.js +2 -2
  8. package/dist/application/loop/run-action.js +0 -4
  9. package/dist/cli/command-definitions.js +44 -16
  10. package/dist/cli/program.js +40 -23
  11. package/dist/cli/update/notifier.js +117 -0
  12. package/dist/cli/update/npm-client.js +151 -0
  13. package/dist/cli/update/policy.js +58 -0
  14. package/dist/cli/update/state.js +68 -0
  15. package/dist/cli.js +33 -0
  16. package/dist/commands/cursor-prompt.js +42 -82
  17. package/dist/commands/dag-approve.js +36 -0
  18. package/dist/commands/delegate.js +75 -77
  19. package/dist/commands/doctor.js +0 -18
  20. package/dist/commands/init.js +476 -91
  21. package/dist/commands/instructions.js +7 -10
  22. package/dist/commands/loop.js +4 -20
  23. package/dist/commands/plan.js +50 -0
  24. package/dist/executors/config-core.js +0 -51
  25. package/dist/executors/dag-pi-executor.js +1 -1
  26. package/dist/executors/dag.js +0 -1
  27. package/dist/executors/index.js +0 -2
  28. package/dist/executors/model-routing.js +9 -9
  29. package/dist/executors/shell-executor.js +1 -1
  30. package/dist/governance/checks.js +6 -3
  31. package/dist/governance/exec-plans.js +545 -0
  32. package/dist/governance/manifest-types.js +24 -2
  33. package/dist/infrastructure/harness/loop-action-store.js +0 -3
  34. package/dist/records/harvest.js +2 -23
  35. package/dist/records/one-shot-runs.js +1 -1
  36. package/dist/shared/artifacts-core.js +24 -5
  37. package/dist/shared/output-truncation.js +37 -0
  38. package/dist/shared/package-metadata.js +353 -0
  39. package/dist/{executors/cursor-executor.js → sidecars/cursor-prompt/executor.js} +2 -42
  40. package/dist/sidecars/cursor-prompt/index.js +3 -0
  41. package/dist/sidecars/cursor-prompt/stream.js +121 -0
  42. package/dist/task/config-types.js +28 -12
  43. package/dist/task/delegate.js +9 -21
  44. package/dist/task/runtime.js +1 -2
  45. package/dist/worker/cli.js +29 -2
  46. package/dist/worker/delivery/final-verification.js +47 -11
  47. package/dist/worker/delivery/package.js +63 -10
  48. package/dist/worker/feature/run.js +60 -8
  49. package/dist/worker/loop-agent/loop-agent-client.js +329 -126
  50. package/dist/worker/observability/read-model.js +27 -1
  51. package/dist/worker/observe/static/app.js +326 -45
  52. package/dist/worker/observe/static/index.html +1 -1
  53. package/dist/worker/observe/static/styles.css +5 -4
  54. package/dist/worker/preflight.js +49 -1
  55. package/dist/worker/run-task/run-task.js +22 -12
  56. package/dist/worker/runner/run-ready.js +76 -12
  57. package/dist/worker/task-spec/schema.js +0 -1
  58. package/dist/workflows/dag/convergence/controller.js +1 -1
  59. package/dist/workflows/dag/executor-registry.js +0 -2
  60. package/dist/workflows/dag/init-hybrid.js +402 -25
  61. package/dist/workflows/dag/node-execution.js +61 -7
  62. package/dist/workflows/dag/runner.js +45 -17
  63. package/dist/workflows/dag/scheduler.js +7 -2
  64. package/dist/workflows/dag/sdd-embedded.js +128 -0
  65. package/dist/workflows/dag/skill-instructions.js +5 -4
  66. package/dist/workflows/dag/skill-snapshot.js +527 -0
  67. package/dist/workflows/dag/types.js +42 -9
  68. package/dist/workflows/dag/validate.js +5 -8
  69. package/dist/workflows/loop/actions/dag-action.js +0 -2
  70. package/dist/workflows/loop/actions/shared.js +1 -1
  71. package/dist/workflows/loop/actions.js +14 -31
  72. package/dist/workflows/loop/benchmark.js +1 -1
  73. package/dist/workflows/loop/index.js +1 -1
  74. package/dist/workflows/loop/policy/auto-policy.js +22 -14
  75. package/dist/workflows/loop/policy/path-patterns.js +13 -0
  76. package/docs/README.md +36 -33
  77. package/docs/agent-dag-recovery-playbook.md +1 -1
  78. package/docs/agent-dag-runner.md +2 -2
  79. package/docs/architecture/README.md +26 -0
  80. package/docs/architecture/dag-execution.md +134 -0
  81. package/docs/architecture/evolution.md +52 -0
  82. package/docs/architecture/facts-and-state.md +58 -0
  83. package/docs/architecture/runtime-boundaries.md +45 -17
  84. package/docs/architecture/system-overview.md +93 -0
  85. package/docs/architecture/worker-and-feature.md +81 -0
  86. package/docs/cursor-prompt-sidecar.md +36 -0
  87. package/docs/decisions/README.md +13 -1
  88. package/docs/design/README.md +42 -21
  89. package/docs/development-principles.md +2 -2
  90. package/docs/exec-plans/active/README.md +2 -2
  91. package/docs/exec-plans/completed/README.md +12 -0
  92. package/docs/feature-workflow.md +50 -4
  93. package/docs/harness-methodology-debugging.md +1 -1
  94. package/docs/harness-methodology-tdd.md +3 -3
  95. package/docs/init-surface.manifest.json +60 -25
  96. package/docs/loop-agent-harness.md +28 -4
  97. package/docs/progress/README.md +32 -1
  98. package/docs/reports/README.md +84 -18
  99. package/docs/skills/README.md +2 -1
  100. package/docs/skills/vetted-skill-registry.md +2 -1
  101. package/docs/templates/agent-dag-report.schema.json +6 -6
  102. package/docs/templates/agent-dag.base.json +0 -5
  103. package/docs/templates/agent-dag.final-verification.json +0 -5
  104. package/docs/templates/agent-dag.schema.json +1 -2
  105. package/docs/templates/agent-dag.supervised-implementation.json +1 -6
  106. package/docs/templates/frontend-design-contract.md +33 -0
  107. package/docs/templates/frontend-task-constraints.md +25 -0
  108. package/docs/templates/frontend-task-requirement.md +61 -0
  109. package/docs/templates/harness.schema.json +10 -12
  110. package/docs/templates/hybrid-dag.json +1 -6
  111. package/docs/templates/interactive-ui-round2-experiment.md +1 -1
  112. package/docs/templates/product-line/task.yaml +0 -1
  113. package/docs/templates/project-start-checklist.md +2 -2
  114. package/docs/templates/worker-dogfood-evidence.md +28 -0
  115. package/docs/templates/worker-dogfood-setup.md +20 -0
  116. package/docs/verification-matrix.md +10 -0
  117. package/examples/decision-gate-agent-dag.json +87 -33
  118. package/examples/example-dag.json +0 -5
  119. package/examples/hybrid-loop-agent-dag.json +0 -5
  120. package/harness.json +7 -15
  121. package/package.json +22 -46
  122. package/scripts/check-product-line-docs.sh +10 -7
  123. package/skills/agent-worker/SKILL.md +37 -0
  124. package/skills/agent-worker/references/agent-worker-operator.md +43 -0
  125. package/skills/frontend-design-review/SKILL.md +59 -0
  126. package/skills/frontend-design-review/references/review-checklist.md +37 -0
  127. package/skills/frontend-implementation/SKILL.md +51 -0
  128. package/skills/frontend-implementation/references/code-standards.md +34 -0
  129. package/skills/frontend-implementation/references/design-spec.md +46 -0
  130. package/skills/frontend-implementation/references/node-contracts.md +32 -0
  131. package/skills/frontend-review/SKILL.md +53 -0
  132. package/skills/frontend-review/references/review-findings.md +42 -0
  133. package/skills/frontend-verification/SKILL.md +40 -0
  134. package/skills/frontend-verification/references/verification-checklist.md +56 -0
  135. package/skills/grill-me/SKILL.md +10 -0
  136. package/skills/grill-with-docs/SKILL.md +88 -0
  137. package/skills/grill-with-docs/adr-format.md +47 -0
  138. package/skills/grill-with-docs/context-format.md +60 -0
  139. package/skills/loop-agent/SKILL.md +11 -9
  140. package/skills/loop-agent/references/command-reference.md +13 -15
  141. package/skills/loop-agent/references/docs-converge.md +126 -0
  142. package/skills/loop-agent/references/harness-policy.md +7 -7
  143. package/skills/loop-agent/references/hybrid-dag.md +15 -18
  144. package/skills/loop-agent/references/long-running-loop.md +4 -6
  145. package/skills/loop-agent/references/multi-worktree.md +6 -6
  146. package/skills/loop-agent/references/orchestrator-and-interventions.md +3 -3
  147. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +14 -11
  148. package/skills/loop-agent/references/task-workflow.md +1 -1
  149. package/skills/using-git-worktrees/SKILL.md +215 -0
  150. package/dist/commands/cursor-worker.js +0 -43
  151. package/dist/cursor-worker-entry.js +0 -8
  152. package/dist/executors/cursor-artifacts.js +0 -33
  153. package/dist/executors/cursor-execution-log.js +0 -81
  154. package/dist/executors/cursor-executor-artifacts.js +0 -134
  155. package/dist/executors/cursor-run.js +0 -115
  156. package/dist/executors/cursor-tool.js +0 -94
  157. package/dist/executors/cursor-worker-client.js +0 -223
  158. package/dist/executors/cursor-worker-protocol.js +0 -18
  159. package/dist/executors/cursor-worker-server.js +0 -54
  160. package/dist/executors/cursor-worker.js +0 -3
  161. package/dist/executors/cursor.js +0 -6
  162. package/dist/executors/dag-cursor-executor.js +0 -87
  163. package/dist/workflows/loop/actions/cursor-fix.js +0 -191
  164. package/dist/workflows/loop/policy/cursor-fix-policy.js +0 -31
  165. package/docs/cursor-executor-usage.md +0 -25
  166. package/docs/dynamic-workflow-dag-engine-roadmap.md +0 -1749
@@ -153,23 +153,20 @@ export async function buildInstructions(repoRoot, stage, taskId) {
153
153
  ],
154
154
  }));
155
155
  }
156
- const artifactSteps = [
157
- "analyze",
158
- "plan",
159
- "implement",
160
- "verify",
161
- "retrospective",
162
- ];
163
156
  return refreshInstructionBlockers(withMissingDependencies({
164
157
  ...base,
165
158
  outputPath: path.join(taskDir, "artifacts"),
166
159
  dependencies: [paths.taskConfigPath, paths.statePath],
167
160
  template: {
168
- requiredHeadings: artifactSteps.map((step) => getArtifactRelativePath(step)),
161
+ requiredHeadings: [
162
+ getArtifactRelativePath("implement"),
163
+ getArtifactRelativePath("verify"),
164
+ ],
169
165
  },
170
166
  completionCriteria: [
171
- "artifact content is substantive and not the new-task template",
172
- "verification artifact names exact commands and pass/fail results",
167
+ "修改记录.md and 验证结果.md are promote-run bridge artifacts filled from completed DAG/one-shot evidence",
168
+ "do not hand-write L1 分析报告/实现计划/复盘报告; those are not seeded or required",
169
+ "verification artifact summarizes available completed-run evidence; inspect the run facts for exact shell commands and full output",
173
170
  ],
174
171
  }));
175
172
  }
@@ -7,10 +7,9 @@ function usage() {
7
7
  " loop status <task-id> [--json]",
8
8
  " loop run <task-id> --action shell-verify [--command <cmd>]... [--timeout-ms N] [--cwd <repo-relative-dir>]",
9
9
  " loop run <task-id> --action pi-review [--provider <id>] [--model <id>] [--timeout-ms N] [--cwd <repo-relative-dir>]",
10
- " loop run <task-id> --action cursor-fix [--model <id>] [--timeout-ms N] [--cwd <repo-relative-dir>]",
11
- " loop run <task-id> --action dag [--execute] [--dag <path>] [--run-id <id>] [--max-concurrent N] [--cwd <repo-relative-dir>] [--no-cursor]",
10
+ " loop run <task-id> --action dag [--execute] [--dag <path>] [--run-id <id>] [--max-concurrent N] [--cwd <repo-relative-dir>]",
12
11
  " loop run <task-id> --action workflow [--profile pr-review|--workflow <path>] [--execute] [--run-id <id>] [--changed-file <path>]... [--cwd <repo-relative-dir>]",
13
- " loop run <task-id> --auto [--max-rounds N] [--allow-cursor-fix]",
12
+ " loop run <task-id> --auto [--max-rounds N] [--approval-granted]",
14
13
  " loop record-round <task-id> --action <name> --result <summary> --lesson <summary> --next <summary> --decision <continue|pause|blocked|complete> [--verification <summary>] [--failure-category <category>] [--ref <path>]...",
15
14
  " loop add-signal <task-id> --type <human_followup|approval|scope_changed|review_feedback> --message <text> [--urgent] [--ref <path>]...",
16
15
  " loop closeout <task-id>",
@@ -144,7 +143,7 @@ export async function runLoop(repoRoot, args) {
144
143
  }
145
144
  const record = await runLoopAuto(repoRoot, taskId, {
146
145
  maxRounds,
147
- allowCursorFix: rest.includes("--allow-cursor-fix"),
146
+ approvalGranted: rest.includes("--approval-granted"),
148
147
  });
149
148
  console.log(JSON.stringify(record, null, 2));
150
149
  return;
@@ -174,20 +173,6 @@ export async function runLoop(repoRoot, args) {
174
173
  console.log(JSON.stringify(record, null, 2));
175
174
  return;
176
175
  }
177
- if (action === "cursor-fix") {
178
- const record = await runLoopAction({
179
- action,
180
- repoRoot,
181
- taskId,
182
- options: {
183
- timeoutMs,
184
- cwd: readFlag(rest, "--cwd"),
185
- model: readFlag(rest, "--model"),
186
- },
187
- });
188
- console.log(JSON.stringify(record, null, 2));
189
- return;
190
- }
191
176
  if (action === "dag") {
192
177
  const maxConcurrentRaw = readFlag(rest, "--max-concurrent");
193
178
  let maxConcurrent;
@@ -208,7 +193,6 @@ export async function runLoop(repoRoot, args) {
208
193
  dagPath: readFlag(rest, "--dag"),
209
194
  runId: readFlag(rest, "--run-id"),
210
195
  maxConcurrent,
211
- noCursor: rest.includes("--no-cursor"),
212
196
  },
213
197
  });
214
198
  console.log(JSON.stringify(record, null, 2));
@@ -248,7 +232,7 @@ export async function runLoop(repoRoot, args) {
248
232
  return;
249
233
  }
250
234
  if (action !== "shell-verify") {
251
- throw new Error("loop run currently supports --action shell-verify|pi-review|cursor-fix|dag|workflow");
235
+ throw new Error("loop run currently supports --action shell-verify|pi-review|dag|workflow");
252
236
  }
253
237
  const record = await runLoopAction({
254
238
  action: "shell-verify",
@@ -0,0 +1,50 @@
1
+ import { checkExecPlanIndex, completeExecPlan, createExecPlan, } from "../governance/exec-plans.js";
2
+ import { repoRelativePath } from "../shared/path-refs.js";
3
+ /**
4
+ * Create an active exec-plan and sync the active index.
5
+ *
6
+ * Usage: `loop-agent plan create <plan-id> "<title>"`
7
+ */
8
+ export async function runPlanCreate(repoRoot, planId, title) {
9
+ const result = await createExecPlan(repoRoot, planId, title);
10
+ console.log(JSON.stringify({
11
+ planId: result.planId,
12
+ status: result.status,
13
+ created: repoRelativePath(repoRoot, result.planPath),
14
+ }, null, 2));
15
+ }
16
+ /**
17
+ * Move an active exec-plan to completed and sync both indexes.
18
+ *
19
+ * Usage: `loop-agent plan complete <plan-id> --summary "<summary>"`
20
+ */
21
+ export async function runPlanComplete(repoRoot, planId, options) {
22
+ const result = await completeExecPlan(repoRoot, planId, options);
23
+ console.log(JSON.stringify({
24
+ planId: result.planId,
25
+ status: result.status,
26
+ from: repoRelativePath(repoRoot, result.fromPath),
27
+ to: repoRelativePath(repoRoot, result.toPath),
28
+ activeIndex: repoRelativePath(repoRoot, result.activeIndex),
29
+ completedIndex: repoRelativePath(repoRoot, result.completedIndex),
30
+ }, null, 2));
31
+ }
32
+ /**
33
+ * Check exec-plan index consistency and print the result as JSON.
34
+ *
35
+ * Usage: `loop-agent plan check`
36
+ */
37
+ export async function runPlanCheck(repoRoot) {
38
+ const result = await checkExecPlanIndex(repoRoot);
39
+ console.log(JSON.stringify({
40
+ ok: result.ok,
41
+ issues: result.issues,
42
+ activeFiles: result.activeFiles,
43
+ completedFiles: result.completedFiles,
44
+ }, null, 2));
45
+ if (!result.ok) {
46
+ throw new Error(`exec-plan index check failed (${result.issues.length} issue(s)): ${result.issues
47
+ .map((issue) => issue.message)
48
+ .join("; ")}`);
49
+ }
50
+ }
@@ -1,56 +1,5 @@
1
- import { DEFAULT_CURSOR_MODEL } from './cursor-executor.js';
2
- import { resolveExecutorModelMatrix } from './model-routing.js';
3
1
  export const TASK_COMPLEXITY_TO_DAG = {
4
2
  small: 'LOW',
5
3
  medium: 'MED',
6
4
  large: 'HIGH',
7
5
  };
8
- export function resolveCursorModel(overrides = {}, cursorConfig) {
9
- return overrides.taskModel ?? cursorConfig?.defaultModel ?? DEFAULT_CURSOR_MODEL;
10
- }
11
- export function resolveCursorModelForTaskConfig(taskConfig, cursorConfig) {
12
- if (taskConfig.cursorModel?.trim()) {
13
- return taskConfig.cursorModel.trim();
14
- }
15
- const dagLevel = TASK_COMPLEXITY_TO_DAG[taskConfig.complexity ?? 'medium'];
16
- const matrix = resolveExecutorModelMatrix('cursor', cursorConfig);
17
- return matrix[dagLevel] ?? resolveCursorModel({}, cursorConfig);
18
- }
19
- export function resolveTaskExecutor(taskConfig, override) {
20
- if (override)
21
- return override;
22
- return taskConfig.executor ?? 'pi';
23
- }
24
- export function resolveCursorExecutorConfig(manifest) {
25
- const config = manifest.executors?.cursor;
26
- if (config?.enabled === false)
27
- return undefined;
28
- return config;
29
- }
30
- export function assertCursorExecutorAvailable(manifest) {
31
- const config = resolveCursorExecutorConfig(manifest);
32
- if (!config) {
33
- throw new Error('cursor executor is not registered in harness.json executors.cursor');
34
- }
35
- return config;
36
- }
37
- export function validateCursorTaskPreflight(taskConfig) {
38
- if (taskConfig.executor !== 'cursor')
39
- return;
40
- const allowed = taskConfig.allowedPaths ?? [];
41
- if (allowed.length === 0) {
42
- // Read-only analysis tasks may omit allowedPaths; write tasks must declare scope explicitly.
43
- return;
44
- }
45
- }
46
- export function assertCursorWriteTaskScope(taskConfig, changedPaths) {
47
- if (taskConfig.executor !== 'cursor')
48
- return;
49
- if ((taskConfig.allowedPaths ?? []).length > 0)
50
- return;
51
- const codeChanges = changedPaths.filter((filePath) => !filePath.startsWith('.harness/tasks/'));
52
- if (codeChanges.length > 0) {
53
- throw new Error('cursor write task refused: allowedPaths is empty but git diff contains code changes. ' +
54
- 'Declare allowedPaths explicitly or keep the task read-only.');
55
- }
56
- }
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { writeTextArtifactFile } from "../infrastructure/harness/artifact-store.js";
3
3
  import { executePiStep, } from "./pi-executor.js";
4
- import { redactPromptForLog, truncateOutput } from "./cursor-executor.js";
4
+ import { redactPromptForLog, truncateOutput, } from "../shared/output-truncation.js";
5
5
  import { readGitStatusPorcelain, runPostRunWriteGuard, } from "./shell-write-guard.js";
6
6
  export const DAG_PI_READONLY_TOOLS = ["read", "grep", "find", "ls"];
7
7
  export const DAG_PI_WRITE_TOOLS = [
@@ -1,4 +1,3 @@
1
- export * from "./dag-cursor-executor.js";
2
1
  export * from "../workflows/dag/executor-registry.js";
3
2
  export * from "./dag-pi-executor.js";
4
3
  export * from "./dag-static-executor.js";
@@ -1,7 +1,5 @@
1
1
  export * from "./pi.js";
2
2
  export * from "./pi-sdk.js";
3
- export * from "./cursor.js";
4
- export * from "./cursor-worker.js";
5
3
  export * from "./shell.js";
6
4
  export * from "./static.js";
7
5
  export * from "./dag.js";
@@ -1,22 +1,20 @@
1
1
  import { DEFAULT_DAG_EXECUTOR_MODELS, } from '../workflows/dag/types.js';
2
- export const DEFAULT_DAG_CURSOR_MODEL = "composer-2.5";
3
2
  export const DEFAULT_DAG_MODELS = {
4
3
  HIGH: "gpt-5.5",
5
- MED: "composer-2.5",
6
- LOW: "composer-2.5",
4
+ MED: "glm-5.2",
5
+ LOW: "gpt-5.3-codex-spark",
7
6
  };
8
7
  /**
9
8
  * DAG executor model tier keys that may carry a per-complexity override.
10
9
  */
11
10
  const EXECUTOR_MODEL_TIERS = ["LOW", "MED", "HIGH"];
12
11
  /**
13
- * Resolve the DAG executor model matrix for a single executor from its harness
14
- * `executors.<name>` config.
12
+ * Resolve the DAG executor model matrix for Pi from harness `executors.pi`.
15
13
  *
16
14
  * Priority per tier (LOW/MED/HIGH):
17
15
  * 1. execConfig[tier] (truthy and !== "default" sentinel)
18
16
  * 2. execConfig.defaultModel (truthy and !== "default" sentinel)
19
- * 3. DEFAULT_DAG_EXECUTOR_MODELS[executor][tier]
17
+ * 3. DEFAULT_DAG_EXECUTOR_MODELS.pi[tier]
20
18
  *
21
19
  * The "default" literal (injected by the schema `.default("default")`) and
22
20
  * absent/undefined both mean "no override, fall through".
@@ -38,15 +36,17 @@ export function resolveExecutorModelMatrix(executor, execConfig) {
38
36
  };
39
37
  }
40
38
  /**
41
- * Resolve both pi and cursor DAG executor model matrices from a harness manifest.
42
- * Single entry point for DAG generation and --strict-models baseline resolution.
39
+ * Resolve the Pi DAG executor model matrix from a harness manifest.
43
40
  */
44
41
  export function resolveExecutorModelMatrices(manifest) {
45
42
  return {
46
43
  pi: resolveExecutorModelMatrix("pi", manifest.executors?.pi),
47
- cursor: resolveExecutorModelMatrix("cursor", manifest.executors?.cursor),
48
44
  };
49
45
  }
46
+ /** @deprecated Prefer resolveExecutorModelMatrices; alias kept for call-site clarity. */
47
+ export function resolvePiModelMatrix(manifest) {
48
+ return resolveExecutorModelMatrices(manifest).pi;
49
+ }
50
50
  export function resolveModelSelection(manifest, taskConfig, step, options) {
51
51
  const retryAttempt = options?.retryAttempt ?? 0;
52
52
  if (Object.keys(manifest.modelProfiles ?? {}).length === 0) {
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { writeDagNodeTextArtifact } from "../infrastructure/harness/artifact-store.js";
5
- import { truncateOutput } from "./cursor-executor.js";
5
+ import { truncateOutput } from "../shared/output-truncation.js";
6
6
  import { expandShellPreset, buildVerdictGateShellCommand } from "./shell-presets.js";
7
7
  import { pathsChangedDuringRun, snapshotGitStatusPorcelain, validateShellWriteGuard, } from "./shell-write-guard.js";
8
8
  import { buildShellProcessEnv } from "./shell-verification.js";
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import { repoRelativePath } from '../shared/path-refs.js';
4
4
  import { loadHarnessManifest } from './harness.js';
5
5
  import { auditLoopAgentSkillSafety } from './skill-safety.js';
6
- import { getTaskPaths, getTaskStatus, loadTaskConfig, shouldRunRetrospective } from '../task/runtime.js';
6
+ import { getTaskPaths, getTaskStatus, loadTaskConfig } from '../task/runtime.js';
7
7
  import { buildTaskReadModel } from '../task/read-model.js';
8
8
  const SKIP_DIRS = new Set([
9
9
  '.git',
@@ -244,12 +244,15 @@ export async function checkTaskHandoff(repoRoot, taskId) {
244
244
  message: '任务已 completed,但验证工件未标记完成',
245
245
  });
246
246
  }
247
- if (state.status === 'completed' && shouldRunRetrospective(taskConfig) && !state.artifacts.retrospective) {
247
+ // Standard DAG tasks do not require a retrospective artifact. Preserve an
248
+ // explicit legacy task contract, however, so historical tasks that opted
249
+ // into requireRetrospective do not silently lose their handoff warning.
250
+ if (state.status === 'completed' && taskConfig.requireRetrospective && !state.artifacts.retrospective) {
248
251
  issues.push({
249
252
  type: 'missing-retrospective-artifact',
250
253
  severity: 'warning',
251
254
  file: toRepoRelative(repoRoot, path.join(taskPaths.taskDir, 'artifacts', '复盘报告.md')),
252
- message: '任务应包含 retrospective,但复盘工件未完成',
255
+ message: '任务显式要求 retrospective,但复盘工件未完成',
253
256
  });
254
257
  }
255
258
  if (readModel.promotion.required && !readModel.promotion.ready) {