@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
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { realpath } from "node:fs/promises";
3
+ import { controllerIdentityExpectationFailure, resolveControllerIdentity, } from "../loop-agent/loop-agent-client.js";
3
4
  import { buildGlobalSnapshot } from "../observability/read-model.js";
4
5
  import { createSnapshotStore } from "../observability/snapshot-store.js";
5
6
  import { preflightTargetRepo } from "../preflight.js";
@@ -29,6 +30,37 @@ export async function runFeature(options) {
29
30
  let gitTransaction;
30
31
  const gitTasks = [];
31
32
  const expectedArtifacts = expectedArtifactPaths(repoRoot, batchRunId);
33
+ let controllerIdentity;
34
+ try {
35
+ controllerIdentity = resolveControllerIdentity(options.client, options.controllerIdentity);
36
+ }
37
+ catch (error) {
38
+ return failedResult({
39
+ featureId,
40
+ mode: options.dryRun ? "dry-run" : "executed",
41
+ steps: [{ id: "preflight", status: "failed", durationMs: 0, message: errorMessage(error) }],
42
+ limitApplied,
43
+ code: "controller-identity-client-mismatch",
44
+ message: errorMessage(error),
45
+ evidence: [],
46
+ expectedArtifacts,
47
+ controllerIdentity: options.controllerIdentity,
48
+ });
49
+ }
50
+ const identityFailure = controllerIdentityExpectationFailure(controllerIdentity, options.controllerExpectation);
51
+ if (identityFailure) {
52
+ return failedResult({
53
+ featureId,
54
+ mode: options.dryRun ? "dry-run" : "executed",
55
+ steps: [{ id: "preflight", status: "failed", durationMs: 0, message: identityFailure.message }],
56
+ limitApplied,
57
+ code: identityFailure.code,
58
+ message: identityFailure.message,
59
+ evidence: [],
60
+ expectedArtifacts,
61
+ controllerIdentity,
62
+ });
63
+ }
32
64
  progress.step("feature validate");
33
65
  const validation = await timedStep(steps, "validate", async () => dependencies.validateFeature(featureDir));
34
66
  if (!validation.value?.ok) {
@@ -44,6 +76,7 @@ export async function runFeature(options) {
44
76
  evidence: errors.flatMap((error) => error.path ? [error.path] : []),
45
77
  nextCommand: `agent-worker task validate-feature ${JSON.stringify(featureDir)}`,
46
78
  expectedArtifacts,
79
+ controllerIdentity,
47
80
  });
48
81
  }
49
82
  featureId = validation.value.featureId;
@@ -56,11 +89,14 @@ export async function runFeature(options) {
56
89
  client: options.client,
57
90
  runCheckRepo: options.runCheckRepo,
58
91
  ...(options.checkRepoCommand ? { checkRepoCommand: options.checkRepoCommand } : {}),
92
+ ...(options.controllerExpectation ? { expectation: options.controllerExpectation } : {}),
59
93
  }));
60
94
  if (!preflight.value?.ok) {
61
95
  markLastStepFailed(steps, preflight.value && !preflight.value.ok ? preflight.value.message : preflight.error ?? "target repo preflight failed");
62
- return preflightFailure({ featureId, repoRoot, steps, limitApplied, preflight: preflight.value, fallbackMessage: preflight.error, expectedArtifacts });
96
+ return preflightFailure({ featureId, repoRoot, steps, limitApplied, preflight: preflight.value, fallbackMessage: preflight.error, expectedArtifacts,
97
+ controllerIdentity: preflight.value?.controllerIdentity ?? controllerIdentity });
63
98
  }
99
+ controllerIdentity = preflight.value.controllerIdentity ?? controllerIdentity;
64
100
  steps.at(-1).artifacts = preflight.value.commands.map((command) => command.result.artifacts.resultPath);
65
101
  }
66
102
  if (checkpointMode) {
@@ -68,7 +104,8 @@ export async function runFeature(options) {
68
104
  const canonicalFeature = await realpath(featureDir).catch(() => featureDir);
69
105
  const featureRelative = path.relative(canonicalRepo, canonicalFeature);
70
106
  if (featureRelative.startsWith("..") || path.isAbsolute(featureRelative)) {
71
- return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "git-feature-repo-mismatch", message: "Feature Packet must be inside the Git target repo for checkpoint mode", evidence: [featureDir, repoRoot], expectedArtifacts });
107
+ return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "git-feature-repo-mismatch", message: "Feature Packet must be inside the Git target repo for checkpoint mode", evidence: [featureDir, repoRoot], expectedArtifacts,
108
+ controllerIdentity });
72
109
  }
73
110
  if (options.dryRun) {
74
111
  steps.push(planned("git-preflight", `create or reuse agent/${featureId.toLowerCase()} and checkpoint each task`));
@@ -76,14 +113,16 @@ export async function runFeature(options) {
76
113
  else {
77
114
  const gitStep = await timedStep(steps, "git-preflight", async () => dependencies.startGit({ repoRoot, featureId, now }));
78
115
  if (!gitStep.value)
79
- return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "git-preflight-failed", message: gitStep.error ?? "Git transaction preflight failed", evidence: [], expectedArtifacts });
116
+ return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "git-preflight-failed", message: gitStep.error ?? "Git transaction preflight failed", evidence: [], expectedArtifacts,
117
+ controllerIdentity });
80
118
  gitTransaction = gitStep.value;
81
119
  steps.at(-1).artifacts = [gitTransaction.recordPath];
82
120
  }
83
121
  }
84
122
  const beforeStep = await timedStep(steps, "review-before", async () => dependencies.review({ featureDir, repoRoot }));
85
123
  if (!beforeStep.value) {
86
- return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "feature-review-failed", message: beforeStep.error ?? "Feature review failed", evidence: [], expectedArtifacts });
124
+ return failedResult({ featureId, mode: options.dryRun ? "dry-run" : "executed", steps, limitApplied, code: "feature-review-failed", message: beforeStep.error ?? "Feature review failed", evidence: [], expectedArtifacts,
125
+ controllerIdentity });
87
126
  }
88
127
  before = beforeStep.value;
89
128
  const readyTasks = before.tasks.filter((task) => task.status === "Ready").map((task) => task.taskId);
@@ -108,6 +147,7 @@ export async function runFeature(options) {
108
147
  batch: null,
109
148
  gitTasks,
110
149
  limitApplied,
150
+ controllerIdentity,
111
151
  };
112
152
  }
113
153
  if (readyTasks.length > 0 && limitApplied > 0) {
@@ -122,6 +162,8 @@ export async function runFeature(options) {
122
162
  progress,
123
163
  skipTaskPreflight: true,
124
164
  ...(options.piModel ? { piModel: options.piModel } : {}),
165
+ ...(controllerIdentity ? { controllerIdentity } : {}),
166
+ ...(options.controllerExpectation ? { controllerExpectation: options.controllerExpectation } : {}),
125
167
  ...(gitTransaction ? { onTaskFinalized: async (task) => {
126
168
  const gitResult = await dependencies.finalizeGit(gitTransaction, { ...task, keepFailedDiff: options.keepFailedDiff, now });
127
169
  gitTasks.push(gitResult);
@@ -132,7 +174,8 @@ export async function runFeature(options) {
132
174
  batch = runStep.value;
133
175
  if (!batch) {
134
176
  const kept = runStep.error?.startsWith("git-keep-failed-diff:") ?? false;
135
- const failed = failedResult({ featureId, mode: "executed", steps, limitApplied, code: kept ? "git-failed-diff-kept" : "run-ready-failed", message: kept ? "Failed task diff was kept by explicit request; automatic execution stopped" : runStep.error ?? "run-ready failed", evidence: kept ? [runStep.error.slice("git-keep-failed-diff:".length)] : [], before, readyTasks, expectedArtifacts });
177
+ const failed = failedResult({ featureId, mode: "executed", steps, limitApplied, code: kept ? "git-failed-diff-kept" : "run-ready-failed", message: kept ? "Failed task diff was kept by explicit request; automatic execution stopped" : runStep.error ?? "run-ready failed", evidence: kept ? [runStep.error.slice("git-keep-failed-diff:".length)] : [], before, readyTasks, expectedArtifacts,
178
+ controllerIdentity });
136
179
  return kept ? { ...failed, status: "needs-action", gitTasks, artifacts: { ...failed.artifacts, gitTransaction: gitTransaction?.recordPath ?? null } } : failed;
137
180
  }
138
181
  steps.at(-1).artifacts = [batch.batchRunPath];
@@ -147,7 +190,8 @@ export async function runFeature(options) {
147
190
  progress.step("refresh morning report");
148
191
  const report = await timedStep(steps, "morning-report", async () => dependencies.writeReport({ repoRoot, ...(batch ? { batchRunId: batch.batchRunId } : {}), outputPath: morningReportPath }));
149
192
  if (!report.value)
150
- return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "morning-report-failed", message: report.error ?? "morning report failed", evidence: [], before, readyTasks, batch, expectedArtifacts });
193
+ return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "morning-report-failed", message: report.error ?? "morning report failed", evidence: [], before, readyTasks, batch, expectedArtifacts,
194
+ controllerIdentity });
151
195
  steps.at(-1).artifacts = [report.value];
152
196
  const snapshotPath = path.join(getTaskPoolRoot(repoRoot), "observability", "snapshot.json");
153
197
  progress.step("refresh Observe snapshot");
@@ -157,12 +201,14 @@ export async function runFeature(options) {
157
201
  return snapshotPath;
158
202
  });
159
203
  if (!snapshot.value)
160
- return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "observe-snapshot-failed", message: snapshot.error ?? "Observe snapshot failed", evidence: [report.value], before, readyTasks, batch, artifacts: { morningReport: report.value }, expectedArtifacts });
204
+ return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "observe-snapshot-failed", message: snapshot.error ?? "Observe snapshot failed", evidence: [report.value], before, readyTasks, batch, artifacts: { morningReport: report.value }, expectedArtifacts,
205
+ controllerIdentity });
161
206
  steps.at(-1).artifacts = [snapshot.value];
162
207
  progress.step("derive final Feature review");
163
208
  const after = await timedStep(steps, "review-after", async () => dependencies.review({ featureDir, repoRoot }));
164
209
  if (!after.value)
165
- return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "feature-review-failed", message: after.error ?? "final Feature review failed", evidence: [report.value, snapshot.value], before, readyTasks, batch, artifacts: { morningReport: report.value, observeSnapshot: snapshot.value }, expectedArtifacts });
210
+ return failedResult({ featureId, mode: "executed", steps, limitApplied, code: "feature-review-failed", message: after.error ?? "final Feature review failed", evidence: [report.value, snapshot.value], before, readyTasks, batch, artifacts: { morningReport: report.value, observeSnapshot: snapshot.value }, expectedArtifacts,
211
+ controllerIdentity });
166
212
  const taskFailures = batch?.tasks.filter((task) => task.status === "failed") ?? [];
167
213
  const runInfrastructureFailed = batch?.status === "failed";
168
214
  const executionError = runInfrastructureFailed
@@ -190,6 +236,7 @@ export async function runFeature(options) {
190
236
  gitTasks,
191
237
  ...(executionError ? { error: executionError } : {}),
192
238
  limitApplied,
239
+ controllerIdentity,
193
240
  };
194
241
  }
195
242
  export function renderFeatureRun(result) {
@@ -271,6 +318,7 @@ function failedResult(input) {
271
318
  batch: input.batch ?? null,
272
319
  error: { code: input.code, message: input.message, evidence: input.evidence, ...(input.nextCommand ? { nextCommand: input.nextCommand } : {}) },
273
320
  limitApplied: input.limitApplied,
321
+ controllerIdentity: input.controllerIdentity,
274
322
  };
275
323
  }
276
324
  function expectedArtifactPaths(repoRoot, batchRunId) {
@@ -309,5 +357,9 @@ function preflightFailure(input) {
309
357
  evidence: failed?.commands.flatMap((command) => [command.result.artifacts.resultPath]) ?? [],
310
358
  nextCommand: `cd ${JSON.stringify(input.repoRoot)} && loop-agent doctor`,
311
359
  expectedArtifacts: input.expectedArtifacts,
360
+ controllerIdentity: failed?.controllerIdentity ?? input.controllerIdentity,
312
361
  });
313
362
  }
363
+ function errorMessage(error) {
364
+ return error instanceof Error ? error.message : String(error);
365
+ }