@tea-agent/loop-agent 0.42.0-next.2 → 0.42.0-next.3

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 (193) hide show
  1. package/CHANGELOG.md +242 -1
  2. package/dist/application/dag/generate-task-dag.js +75 -19
  3. package/dist/application/task-lifecycle/advance.js +24 -5
  4. package/dist/application/task-lifecycle/observe.js +171 -17
  5. package/dist/application/task-lifecycle/plan-transitions.js +42 -7
  6. package/dist/application/task-lifecycle/recommendations.js +13 -2
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/cli/command-definitions.js +7 -0
  9. package/dist/cli/program.js +5 -0
  10. package/dist/commands/client-recovery.js +3 -0
  11. package/dist/commands/dag-follow-up.js +138 -0
  12. package/dist/commands/init.js +27 -1
  13. package/dist/commands/task-advance.js +19 -0
  14. package/dist/executors/dag-pi-executor.js +3784 -231
  15. package/dist/executors/pi-executor.js +15 -4
  16. package/dist/executors/pi-read-budget-policy.js +239 -0
  17. package/dist/executors/shell-executor.js +942 -187
  18. package/dist/executors/shell-write-guard.js +7 -0
  19. package/dist/infrastructure/console/operation-store.js +226 -6
  20. package/dist/shared/dag-failure-category.js +12 -0
  21. package/dist/shared/openspec-spec.js +70 -4
  22. package/dist/shared/operator/capabilities.js +7 -0
  23. package/dist/task/config-types.js +34 -5
  24. package/dist/task/contract/adopt.js +4 -0
  25. package/dist/task/contract/import-revision.js +4 -0
  26. package/dist/task/contract/project.js +3 -0
  27. package/dist/task/contract/schema.js +2 -1
  28. package/dist/task/frontend-project-capability.js +203 -20
  29. package/dist/task/runtime.js +5 -2
  30. package/dist/task/source-prepare/build-draft.js +3 -3
  31. package/dist/task/source-prepare/fragment-inventory.js +15 -9
  32. package/dist/task/source-prepare/prepare.js +89 -1
  33. package/dist/task/source-prepare/semantic-intake.js +6 -2
  34. package/dist/task/source-references.js +22 -1
  35. package/dist/worker/console/chat/chat-ui-policy.js +4 -2
  36. package/dist/worker/console/chat/pi-runtime.js +173 -7
  37. package/dist/worker/console/chat/repo-browser.js +10 -3
  38. package/dist/worker/console/chat/routes.js +30 -19
  39. package/dist/worker/console/chat/session-store.js +117 -70
  40. package/dist/worker/console/chat/shortcuts.js +1 -1
  41. package/dist/worker/console/chat/turn-process.js +111 -56
  42. package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
  43. package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
  44. package/dist/worker/console/index.js +3 -0
  45. package/dist/worker/console/operator-actions.js +169 -7
  46. package/dist/worker/console/server.js +3 -0
  47. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DZZ8m3PO.js → abnfDiagram-N423BO3Z-CeznJ4Iw.js} +1 -1
  48. package/dist/worker/console/static/assets/{arc-D6PvaVd-.js → arc-B4u9u7SX.js} +1 -1
  49. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-B_OTOiI8.js → architectureDiagram-T3A2C74G-oghpT81p.js} +1 -1
  50. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Bv6rqHBg.js → blockDiagram-VBNYF7ZC-BPJ5Kvcj.js} +1 -1
  51. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B8eHr0oz.js → c4Diagram-5PPSVZJV-CoIu69pd.js} +1 -1
  52. package/dist/worker/console/static/assets/channel-DmIXqJ6B.js +1 -0
  53. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DYwR0im2.js → chunk-2GRJ4B5K-DtgiAsSc.js} +1 -1
  54. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-D2WPGqXt.js → chunk-2Q5K7J3B-YSu_EVSD.js} +1 -1
  55. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CQISJ_I7.js → chunk-5RXB4S5H-DaRO-NB6.js} +1 -1
  56. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C0o2Du1e.js → chunk-5VM5RSS4-Dh0ZKiGA.js} +1 -1
  57. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-4f8kr-U7.js → chunk-6Q2QTUOP-DOrvbR-H.js} +1 -1
  58. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D_OWvXzX.js → chunk-GF5L2VYU-C3b22LN2.js} +1 -1
  59. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CasdPz5X.js → chunk-JWPE2WC7-CXlqO8l6.js} +1 -1
  60. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Cj8lRrla.js → chunk-KBJHAD2P-BblTBrDu.js} +1 -1
  61. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CUvD1FSd.js → chunk-RYQCIY6F-DswqPALe.js} +1 -1
  62. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CqLw_eqB.js → chunk-XXDRQBXY-CfTwVOlc.js} +1 -1
  63. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-MFV5Qxb5.js +1 -0
  64. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-MFV5Qxb5.js +1 -0
  65. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-ku-WqJPx.js → cose-bilkent-JH36ORCC-bLD8jVFo.js} +1 -1
  66. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-Bq_PYDhl.js → cynefin-VYW2F7L2-BvoG1fh5.js} +1 -1
  67. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BiGZV641.js → cynefinDiagram-MW4NZA55-DEPAdJu3.js} +1 -1
  68. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C4JRlglF.js → dagre-VZM6K2ZE-DmrNvBLy.js} +1 -1
  69. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B0dNeWYG.js → diagram-7IWD3JNH-CdwzIwvs.js} +1 -1
  70. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Cj35YvYM.js → diagram-B4RE2ZJO-CJ3hj-md.js} +1 -1
  71. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-uzQoJ2-8.js → diagram-LBJQPF4R-C6YJT2a4.js} +1 -1
  72. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D1a-Buoz.js → diagram-Q27KOJAE-C_LPfjhX.js} +1 -1
  73. package/dist/worker/console/static/assets/{diagram-UB23O5K3-XjRrLRSs.js → diagram-UB23O5K3-xvsSb5Ie.js} +1 -1
  74. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Da_O24cW.js → ebnfDiagram-BXEA7PRR-Rxp2tKcD.js} +1 -1
  75. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BLJ8jrYU.js → erDiagram-JOGREHBK-DRyLYmZh.js} +1 -1
  76. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-B9GrLjM0.js → flowDiagram-UKHOOZJN-TLSU_D2B.js} +1 -1
  77. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CeJ0TqiK.js → ganttDiagram-PKOTCBZU-DGqeTvHC.js} +1 -1
  78. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js → gitGraphDiagram-DS77QQ5N-BZxyH2wh.js} +1 -1
  79. package/dist/worker/console/static/assets/index-C8V8K9b4.js +451 -0
  80. package/dist/worker/console/static/assets/index-Cnf_KxTQ.css +1 -0
  81. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DB26i3d8.js → infoDiagram-6WML65LV-BsYtzx01.js} +1 -1
  82. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BOGRyeZT.js → ishikawaDiagram-WSZJBQD7-Qr-ezGv-.js} +1 -1
  83. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CZRoBO_6.js → journeyDiagram-NVQOT4AX-DYbB3ibo.js} +1 -1
  84. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-qlWhJyoB.js → kanban-definition-27J2QSJJ-BHJHewZO.js} +1 -1
  85. package/dist/worker/console/static/assets/{linear-CfUiDDB3.js → linear-CmPIPmCG.js} +1 -1
  86. package/dist/worker/console/static/assets/{mermaid.core-BQe6fpqj.js → mermaid.core-F--C1uV0.js} +5 -5
  87. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-zFzWHw64.js → mindmap-definition-FAOFIHXS-YTXfL1st.js} +1 -1
  88. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DFGUqjZO.js → pegDiagram-VL7TDLO6-DdDMYXP9.js} +1 -1
  89. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BB5i0l8Z.js → pieDiagram-7S7Q4E2Y-C3nH4KVd.js} +1 -1
  90. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-obbVZ_X5.js → quadrantDiagram-CIZ2JOQS-kXyxjG7Y.js} +1 -1
  91. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BwdaNzc1.js → railroadDiagram-AXF67PYL-KNzbl-7w.js} +1 -1
  92. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CkTJaugh.js → requirementDiagram-LRYGKXZP-CSwI6dG0.js} +1 -1
  93. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BwJ-hIgq.js → sankeyDiagram-W5VNT64P-Bl1AyuXy.js} +1 -1
  94. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BzSgmm7w.js → sequenceDiagram-SI44F4Z6-2y4EmXQa.js} +1 -1
  95. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Bn3oj5Q1.js → sizeCapture-X5ZJPWSS-E8v8YrMg.js} +1 -1
  96. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-dxhGtL8K.js → stateDiagram-OKZ733FA-eGGlR856.js} +1 -1
  97. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8e4J3at.js +1 -0
  98. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BLpEInya.js → swimlanes-SLNWSIFB-B7g7xc07.js} +2 -2
  99. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Do88I1Nb.js +8 -0
  100. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-ChJGYcXy.js → timeline-definition-Z64GVDOM-DR3VCHBG.js} +1 -1
  101. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DK-qjRer.js → vennDiagram-T6HMQDX7-LUvapZIy.js} +1 -1
  102. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-3qeaWAg-.js → wardleyDiagram-T6FBY63Y-C7GDcaXq.js} +1 -1
  103. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CootlyP9.js → xychartDiagram-ELKLHX3M-CbNAqoGK.js} +1 -1
  104. package/dist/worker/console/static/index.html +2 -2
  105. package/dist/worker/console/static-src/active-run-badge.js +17 -0
  106. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +19 -8
  107. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +15 -7
  108. package/dist/worker/console/workspace-context.js +111 -1
  109. package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
  110. package/dist/worker/observe/static/dag-node-purpose.js +5 -0
  111. package/dist/workflows/dag/contract-validator-registrations.js +1 -2
  112. package/dist/workflows/dag/dag-retry-schema.js +138 -0
  113. package/dist/workflows/dag/frontend-closeout.js +221 -0
  114. package/dist/workflows/dag/frontend-design-policy.js +400 -0
  115. package/dist/workflows/dag/frontend-human-decision.js +182 -0
  116. package/dist/workflows/dag/frontend-implementation-contract.js +907 -162
  117. package/dist/workflows/dag/frontend-plan-render.js +2 -1
  118. package/dist/workflows/dag/frontend-prewrite-gate.js +255 -349
  119. package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
  120. package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
  121. package/dist/workflows/dag/frontend-recovery-controller.js +202 -0
  122. package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
  123. package/dist/workflows/dag/frontend-recovery-plan.js +17 -10
  124. package/dist/workflows/dag/frontend-recovery-run.js +33 -20
  125. package/dist/workflows/dag/frontend-repair.js +1 -432
  126. package/dist/workflows/dag/frontend-review-context.js +261 -15
  127. package/dist/workflows/dag/frontend-review-findings.js +270 -0
  128. package/dist/workflows/dag/frontend-shadow-dual-write.js +914 -0
  129. package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
  130. package/dist/workflows/dag/frontend-shape-facts.js +419 -0
  131. package/dist/workflows/dag/frontend-shape.js +435 -0
  132. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
  133. package/dist/workflows/dag/frontend-split-application-service.js +203 -0
  134. package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
  135. package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
  136. package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
  137. package/dist/workflows/dag/frontend-verification-trace.js +249 -24
  138. package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
  139. package/dist/workflows/dag/frontend-writer-admission.js +285 -0
  140. package/dist/workflows/dag/frontend-writer-status.js +256 -0
  141. package/dist/workflows/dag/init-hybrid.js +677 -492
  142. package/dist/workflows/dag/interrupt-request.js +7 -0
  143. package/dist/workflows/dag/node-execution.js +732 -4
  144. package/dist/workflows/dag/prompt.js +34 -1
  145. package/dist/workflows/dag/recovery-lease.js +80 -0
  146. package/dist/workflows/dag/report.js +37 -1
  147. package/dist/workflows/dag/rerun-feedback.js +256 -1
  148. package/dist/workflows/dag/rerun-plan.js +17 -6
  149. package/dist/workflows/dag/rerun-run.js +23 -0
  150. package/dist/workflows/dag/rerun-task.js +29 -0
  151. package/dist/workflows/dag/retry-policy.js +214 -104
  152. package/dist/workflows/dag/runner.js +433 -126
  153. package/dist/workflows/dag/scheduler.js +114 -16
  154. package/dist/workflows/dag/types.js +239 -12
  155. package/dist/workflows/dag/validate.js +28 -12
  156. package/docs/examples/README.md +5 -0
  157. package/docs/init-surface.manifest.json +30 -12
  158. package/docs/skills/vetted-skill-registry.md +4 -2
  159. package/docs/templates/README.md +2 -0
  160. package/docs/templates/agent-dag-report.schema.json +8 -2
  161. package/docs/templates/agent-dag.schema.json +1 -1
  162. package/docs/templates/frontend-implementation-contract.schema.json +4 -1
  163. package/docs/templates/frontend-implementation-dag.json +89 -0
  164. package/docs/templates/spec-registry.schema.json +45 -0
  165. package/harness.json +1 -1
  166. package/package.json +1 -1
  167. package/skills/frontend-bounded-implement/SKILL.md +15 -14
  168. package/skills/frontend-bounded-implement/references/code-standards.md +19 -0
  169. package/skills/frontend-contract/SKILL.md +23 -0
  170. package/skills/frontend-contract/references/contract-protocol.md +34 -0
  171. package/skills/frontend-design-review/SKILL.md +22 -41
  172. package/skills/frontend-plan/SKILL.md +26 -0
  173. package/skills/frontend-plan/references/decision-contract.md +37 -0
  174. package/skills/frontend-plan/references/design-decisions.md +17 -0
  175. package/skills/frontend-review/SKILL.md +20 -15
  176. package/skills/frontend-review/references/review-findings.md +6 -7
  177. package/skills/frontend-scout/SKILL.md +25 -0
  178. package/skills/frontend-scout/references/design-evidence.md +16 -0
  179. package/skills/frontend-scout/references/scout-evidence.md +23 -0
  180. package/skills/frontend-verification/SKILL.md +1 -1
  181. package/skills/loop-agent/references/command-reference.md +1 -0
  182. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  183. package/dist/worker/console/static/assets/channel-BU5gOilw.js +0 -1
  184. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +0 -1
  185. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +0 -1
  186. package/dist/worker/console/static/assets/index-H9rFJiGL.css +0 -1
  187. package/dist/worker/console/static/assets/index-xwu9GxEc.js +0 -451
  188. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +0 -1
  189. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +0 -8
  190. package/skills/frontend-implementation/SKILL.md +0 -52
  191. package/skills/frontend-implementation/references/code-standards.md +0 -33
  192. package/skills/frontend-implementation/references/design-spec.md +0 -56
  193. package/skills/frontend-implementation/references/node-contracts.md +0 -31
@@ -0,0 +1,138 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { FRONTEND_REVIEW_FINDINGS_PRD_REL, readFrontendReviewFindingsPrd, } from "../workflows/dag/frontend-review-findings.js";
4
+ import { locateDagRun } from "../workflows/dag/lifecycle.js";
5
+ import { createTask, getTaskPaths } from "../task/runtime.js";
6
+ import { importPrdDocument } from "../task/source-references.js";
7
+ function parseFlagValue(rawArgs, flag) {
8
+ const index = rawArgs.indexOf(flag);
9
+ if (index < 0 || index + 1 >= rawArgs.length)
10
+ return undefined;
11
+ return rawArgs[index + 1];
12
+ }
13
+ export function parseDagFollowUpArgs(rawArgs) {
14
+ const positional = rawArgs.filter((arg) => !arg.startsWith("-"));
15
+ const parentRunId = positional[0];
16
+ if (!parentRunId) {
17
+ throw new Error("usage: dag follow-up <parent-run-id> [--task-id <id>] [--execute] [--profile <profile>]");
18
+ }
19
+ return {
20
+ parentRunId,
21
+ taskId: parseFlagValue(rawArgs, "--task-id"),
22
+ execute: rawArgs.includes("--execute"),
23
+ profile: parseFlagValue(rawArgs, "--profile"),
24
+ };
25
+ }
26
+ export function deriveFollowUpTaskId(parentRunId) {
27
+ // Deterministic, valid task id derived from the parent run id.
28
+ return `${parentRunId}-followup`;
29
+ }
30
+ /** CLI entry: parse raw args and run the follow-up flow. */
31
+ export async function runDagFollowUp(repoRoot, rawArgs) {
32
+ const parsed = parseDagFollowUpArgs(rawArgs);
33
+ const result = await runDagFollowUpInternal(repoRoot, parsed.parentRunId, {
34
+ taskId: parsed.taskId,
35
+ execute: parsed.execute,
36
+ profile: parsed.profile,
37
+ });
38
+ console.log(JSON.stringify(result, null, 2));
39
+ if (!result.ok) {
40
+ process.exitCode = result.mode === "blocked" ? 2 : 1;
41
+ }
42
+ }
43
+ export async function runDagFollowUpInternal(repoRoot, parentRunId, options = {}) {
44
+ const located = await locateDagRun(repoRoot, parentRunId);
45
+ if (!located) {
46
+ return {
47
+ ok: false,
48
+ mode: "invalid",
49
+ reason: `dag run not found: ${parentRunId}`,
50
+ };
51
+ }
52
+ const prd = await readFrontendReviewFindingsPrd(located.runDir);
53
+ if (!prd) {
54
+ return {
55
+ ok: false,
56
+ mode: "invalid",
57
+ reason: `no frontend review findings PRD found in run ${parentRunId} (${FRONTEND_REVIEW_FINDINGS_PRD_REL}); the review must have committed request_review_changes`,
58
+ };
59
+ }
60
+ const taskId = options.taskId ?? deriveFollowUpTaskId(parentRunId);
61
+ try {
62
+ await createTask(repoRoot, taskId, `修复 review 发现(parent ${parentRunId})`);
63
+ }
64
+ catch (error) {
65
+ return {
66
+ ok: false,
67
+ mode: "blocked",
68
+ reason: `failed to create task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
69
+ };
70
+ }
71
+ // Materialize the PRD draft into the task's source directory so the task
72
+ // lifecycle can import it as its requirement.
73
+ const prdMaterialized = path.join(getTaskPaths(repoRoot, taskId).sourceDir, "review-findings-prd.md");
74
+ try {
75
+ await mkdir(path.dirname(prdMaterialized), { recursive: true });
76
+ await importPrdDocument({
77
+ repoRoot,
78
+ taskId,
79
+ filePath: path.join(located.runDir, FRONTEND_REVIEW_FINDINGS_PRD_REL),
80
+ name: "review-findings-prd",
81
+ });
82
+ }
83
+ catch (error) {
84
+ return {
85
+ ok: false,
86
+ mode: "blocked",
87
+ reason: `failed to import PRD into task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
88
+ };
89
+ }
90
+ if (!options.execute) {
91
+ return {
92
+ ok: true,
93
+ mode: "created",
94
+ taskId,
95
+ prdPath: prdMaterialized,
96
+ next: {
97
+ kind: "advance",
98
+ command: `loop-agent task advance ${taskId} --task-kind frontend-implementation --json`,
99
+ },
100
+ };
101
+ }
102
+ // Execute: advance through the frontend DAG.
103
+ const { advanceTaskLifecycle } = await import("../application/task-lifecycle/advance.js");
104
+ const profile = options.profile === "auto" ||
105
+ options.profile === "minimal" ||
106
+ options.profile === "standard" ||
107
+ options.profile === "reviewed" ||
108
+ options.profile === "supervised"
109
+ ? options.profile
110
+ : undefined;
111
+ const result = await advanceTaskLifecycle({
112
+ repoRoot,
113
+ taskId,
114
+ taskKind: "frontend-implementation",
115
+ taskKindExplicit: true,
116
+ ...(profile ? { profile, profileExplicit: true } : {}),
117
+ observer: undefined,
118
+ });
119
+ const ok = result.lifecycleState === "run-succeeded" ||
120
+ result.lifecycleState === "awaiting-write-set-approval";
121
+ return {
122
+ ok,
123
+ mode: ok ? "created" : "blocked",
124
+ taskId,
125
+ prdPath: prdMaterialized,
126
+ reason: ok
127
+ ? undefined
128
+ : `advance lifecycleState: ${result.lifecycleState}${result.blockers.length > 0
129
+ ? `; blockers: ${result.blockers.map((b) => b.code).join(", ")}`
130
+ : ""}`,
131
+ next: ok
132
+ ? undefined
133
+ : {
134
+ kind: "advance",
135
+ command: `loop-agent task advance ${taskId} --task-kind frontend-implementation --json`,
136
+ },
137
+ };
138
+ }
@@ -14,6 +14,19 @@ const GITIGNORE_BLOCK_START = "# LOOP_AGENT_INIT_START";
14
14
  const GITIGNORE_BLOCK_END = "# LOOP_AGENT_INIT_END";
15
15
  const INIT_SURFACE_STATE_PATH = ".harness/init-surface.json";
16
16
  const DEFAULT_GOVERNANCE_ROOT = "ai_workspace/loop-agent";
17
+ function buildSpecRegistry() {
18
+ return `${JSON.stringify({
19
+ version: 1,
20
+ roots: [],
21
+ discovery: {
22
+ enabled: true,
23
+ maxDepth: 3,
24
+ maxFiles: 100,
25
+ maxBytes: 1048576,
26
+ timeoutMs: 2000,
27
+ },
28
+ }, null, 2)}\n`;
29
+ }
17
30
  const CORE_DOC_FILES = [
18
31
  { source: "README.md", target: "README.md" },
19
32
  {
@@ -610,7 +623,7 @@ if (
610
623
  (assessment.status === "passed" && assessment.currentExitCode !== 0) ||
611
624
  (assessment.status === "baseline-debt" && assessment.currentExitCode === 0)
612
625
  ) fail();
613
- if (!assessment.baselineRef || assessment.baselineRef.nodeId !== "frontend-lint-baseline-shell") fail();
626
+ if (!assessment.baselineRef || assessment.baselineRef.nodeId !== "frontend-writer-admission-shell") fail();
614
627
  const baselineRaw = readContained(assessment.baselineRef.path);
615
628
  if (sha256(baselineRaw) !== assessment.baselineRef.sha256) fail();
616
629
  let baseline;
@@ -1312,6 +1325,9 @@ async function buildDesiredSurfaceContent(input) {
1312
1325
  }), null, 2)}\n`,
1313
1326
  };
1314
1327
  }
1328
+ if (manifestPath === "docs/spec-registry.json") {
1329
+ return { content: buildSpecRegistry() };
1330
+ }
1315
1331
  if (manifestPath === OPENCODE_TRANSIENT_RETRY_PLUGIN_PATH) {
1316
1332
  return { content: buildOpenCodeTransientRetryPluginSource() };
1317
1333
  }
@@ -1709,6 +1725,8 @@ async function listRelativeFiles(rootPath) {
1709
1725
  async function expectedLegacyInitFileSha(input) {
1710
1726
  if (input.legacyPath.startsWith("docs/")) {
1711
1727
  const doc = input.legacyPath.slice("docs/".length);
1728
+ if (doc === "spec-registry.json")
1729
+ return sha256Text(buildSpecRegistry());
1712
1730
  const generated = buildGeneratedCoreDoc({
1713
1731
  doc,
1714
1732
  projectName: input.projectName,
@@ -2707,6 +2725,14 @@ export async function initializeLoopAgentProject(options) {
2707
2725
  targetRelativePath: path.join(governanceRoot, "templates"),
2708
2726
  written,
2709
2727
  });
2728
+ await writeTextIfMissing({
2729
+ repoRoot,
2730
+ relativePath: path.join(governanceRoot, "spec-registry.json"),
2731
+ content: buildSpecRegistry(),
2732
+ merge,
2733
+ written,
2734
+ skipped,
2735
+ });
2710
2736
  if (profile === "full") {
2711
2737
  // Project repo-local skills live only under `.agents/skills/`.
2712
2738
  // The package still ships `skills/` as the built-in fallback source.
@@ -377,6 +377,25 @@ export async function runTaskAdvance(repoRoot, args) {
377
377
  intervalMs: options.progressIntervalMs,
378
378
  });
379
379
  }
380
+ // Idempotent client-recovery surface install before any DAG run: the Pi
381
+ // context-overflow extension / OpenCode plugins / project .pi settings
382
+ // are normally installed by `loop-agent init`, but an upgraded or
383
+ // non-init-created project may lack them. Installing here (missing-only)
384
+ // ensures the overflow compact+retry recovery path is always present,
385
+ // independent of how the project was created. Best-effort: a failure to
386
+ // install never blocks the run.
387
+ if (options.approveGate && !options.dryRun) {
388
+ try {
389
+ const { runClientRecovery } = await import("./client-recovery.js");
390
+ // mode "project" installs only project-owned surfaces
391
+ // (.pi/extensions + .opencode/plugins + .pi/settings.json),
392
+ // never the user home; installs are missing-only.
393
+ await runClientRecovery({ repoRoot, mode: "project" });
394
+ }
395
+ catch {
396
+ // best-effort; do not fail the run over a recovery-surface install
397
+ }
398
+ }
380
399
  const result = await advanceTaskLifecycle(toUseCaseInput(repoRoot, taskId, options, progress?.observer));
381
400
  const outcome = mapOutcome(result);
382
401
  const gateStop = result.lifecycleState === "awaiting-write-set-approval" &&