@tea-agent/loop-agent 0.37.0 → 0.37.1-beta.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 (192) hide show
  1. package/AGENTS.md +2 -6
  2. package/CHANGELOG.md +71 -144
  3. package/README.md +1 -1
  4. package/bin/loop-agent.js +1 -37
  5. package/dist/application/task-lifecycle/advance.js +0 -1
  6. package/dist/application/task-lifecycle/observe.js +0 -15
  7. package/dist/application/task-lifecycle/plan-transitions.js +0 -15
  8. package/dist/cli/command-definitions.js +0 -7
  9. package/dist/cli/program.js +3 -8
  10. package/dist/commands/init-upgrade.js +19 -351
  11. package/dist/commands/init.js +67 -14
  12. package/dist/commands/run-dag-progress.js +0 -14
  13. package/dist/commands/task-advance.js +3 -33
  14. package/dist/executors/dag-pi-executor.js +30 -47
  15. package/dist/executors/pi-sdk-executor.js +0 -34
  16. package/dist/executors/shell-executor.js +95 -6
  17. package/dist/shared/operator/capabilities.js +13 -200
  18. package/dist/shared/package-metadata.js +0 -42
  19. package/dist/task/contract/project.js +0 -4
  20. package/dist/task/source-prepare/completeness.js +0 -53
  21. package/dist/task/source-prepare/parse-intent.js +12 -82
  22. package/dist/task/source-prepare/prepare.js +5 -102
  23. package/dist/task/source-prepare/semantic-intake.js +23 -144
  24. package/dist/worker/console/chat/artifact-card.js +1 -8
  25. package/dist/worker/console/chat/chat-event-store.js +0 -152
  26. package/dist/worker/console/chat/human-gate-card.js +1 -9
  27. package/dist/worker/console/chat/operation-card.js +2 -71
  28. package/dist/worker/console/chat/pi-runtime.js +62 -111
  29. package/dist/worker/console/chat/routes.js +10 -43
  30. package/dist/worker/console/chat/session-store.js +1 -9
  31. package/dist/worker/console/chat/shortcuts.js +7 -9
  32. package/dist/worker/console/chat/turn-process.js +23 -204
  33. package/dist/worker/console/chat/workspace-landing.js +1 -2
  34. package/dist/worker/console/operation-runner.js +6 -155
  35. package/dist/worker/console/operator-actions.js +14 -391
  36. package/dist/worker/console/operator-user-error.js +0 -4
  37. package/dist/worker/console/recovery-cta.js +3 -50
  38. package/dist/worker/console/static/assets/index-HX1pbOyl.css +1 -0
  39. package/dist/worker/console/static/assets/index-M0BLEBfh.js +56 -0
  40. package/dist/worker/console/static/index.html +2 -2
  41. package/dist/worker/console/static-src/app/console-types.js +9 -13
  42. package/dist/worker/console/static-src/app/useOperatorActions.js +2 -4
  43. package/dist/worker/console/static-src/app/useRecoveryActions.js +56 -65
  44. package/dist/worker/console/static-src/app/useRecoveryConsole.js +1 -73
  45. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +30 -114
  46. package/dist/worker/console/static-src/operator-chat/refs.js +0 -3
  47. package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
  48. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +13 -67
  49. package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -12
  50. package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -45
  51. package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -7
  52. package/dist/worker/loop-agent/loop-agent-client.js +3 -17
  53. package/dist/worker/observability/read-model.js +0 -20
  54. package/dist/worker/observe/spec-evidence.js +8 -3
  55. package/dist/worker/observe/static/operator-chrome.d.ts +0 -1
  56. package/dist/worker/observe/static/operator-chrome.js +3 -10
  57. package/dist/worker/observe/static/views/dag-inspector.js +71 -6
  58. package/dist/worker/observe/static/views/dag.js +0 -12
  59. package/dist/worker/preflight.js +1 -2
  60. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +707 -37
  61. package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
  62. package/dist/workflows/dag/backend-test-markdown-workflow.js +109 -7
  63. package/dist/workflows/dag/backend-test-module-stem.js +5 -0
  64. package/dist/workflows/dag/backend-test-pytest-collection.js +345 -24
  65. package/dist/workflows/dag/backend-test-scenario-param.js +890 -164
  66. package/dist/workflows/dag/backend-test-writer-completeness.js +47 -16
  67. package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
  68. package/dist/workflows/dag/dynamic-runtime/shared.js +1 -9
  69. package/dist/workflows/dag/frontend-implementation-contract.js +39 -233
  70. package/dist/workflows/dag/frontend-prewrite-gate.js +61 -364
  71. package/dist/workflows/dag/frontend-repair.js +18 -219
  72. package/dist/workflows/dag/frontend-verification-trace.js +32 -47
  73. package/dist/workflows/dag/init-hybrid.js +82 -165
  74. package/dist/workflows/dag/node-execution.js +0 -89
  75. package/dist/workflows/dag/recovery-recommendation.js +0 -58
  76. package/dist/workflows/dag/runner.js +15 -333
  77. package/dist/workflows/dag/scheduler.js +3 -257
  78. package/dist/workflows/dag/types.js +9 -130
  79. package/docs/README.md +3 -3
  80. package/docs/architecture/evolution.md +67 -102
  81. package/docs/templates/backend-test-dag.json +50 -32
  82. package/docs/templates/init-managed-agents.md +2 -5
  83. package/harness.json +2 -2
  84. package/package.json +3 -9
  85. package/skills/loop-agent/SKILL.md +0 -1
  86. package/skills/loop-agent/references/command-reference.md +0 -4
  87. package/dist/build-stamp.json +0 -6
  88. package/dist/commands/dag-request-interrupt.js +0 -20
  89. package/dist/worker/console/chat/assistant-content.js +0 -121
  90. package/dist/worker/console/chat/semantic-activity.js +0 -477
  91. package/dist/worker/console/operation-run-facts.js +0 -190
  92. package/dist/worker/console/operation-wait.js +0 -355
  93. package/dist/worker/console/recovery-error-copy.js +0 -198
  94. package/dist/worker/console/static/assets/abnfDiagram-N423BO3Z-DSvF6RXQ.js +0 -1
  95. package/dist/worker/console/static/assets/arc-DuI4ogtJ.js +0 -1
  96. package/dist/worker/console/static/assets/architectureDiagram-T3A2C74G-DdBbgD4y.js +0 -36
  97. package/dist/worker/console/static/assets/blockDiagram-VBNYF7ZC-xQC2HELm.js +0 -132
  98. package/dist/worker/console/static/assets/c4Diagram-5PPSVZJV-DPMSgwIZ.js +0 -10
  99. package/dist/worker/console/static/assets/channel-DLVz9TYW.js +0 -1
  100. package/dist/worker/console/static/assets/chunk-2GRJ4B5K-WTEKTxin.js +0 -1
  101. package/dist/worker/console/static/assets/chunk-2Q5K7J3B-B6vZ0Pv_.js +0 -1
  102. package/dist/worker/console/static/assets/chunk-5RXB4S5H-BrerNAix.js +0 -231
  103. package/dist/worker/console/static/assets/chunk-5VM5RSS4-D_ch2aaI.js +0 -15
  104. package/dist/worker/console/static/assets/chunk-6Q2QTUOP-VvfacNrq.js +0 -88
  105. package/dist/worker/console/static/assets/chunk-GF5L2VYU-B-uGFIg2.js +0 -206
  106. package/dist/worker/console/static/assets/chunk-JWPE2WC7-BlysCtod.js +0 -1
  107. package/dist/worker/console/static/assets/chunk-KBJHAD2P-BjAUAfcT.js +0 -1
  108. package/dist/worker/console/static/assets/chunk-RYQCIY6F-BeZnBmb-.js +0 -1
  109. package/dist/worker/console/static/assets/chunk-XXDRQBXY-Bbfe3UJG.js +0 -1
  110. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +0 -1
  111. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +0 -1
  112. package/dist/worker/console/static/assets/cose-bilkent-JH36ORCC-BKJQnYVM.js +0 -1
  113. package/dist/worker/console/static/assets/cynefin-VYW2F7L2-B1wtI3hU.js +0 -166
  114. package/dist/worker/console/static/assets/cynefinDiagram-MW4NZA55-DCF6DBSu.js +0 -62
  115. package/dist/worker/console/static/assets/cytoscape.esm-yzknjiTM.js +0 -321
  116. package/dist/worker/console/static/assets/dagre-VZM6K2ZE-BJyNGRlP.js +0 -4
  117. package/dist/worker/console/static/assets/defaultLocale-DX6XiGOO.js +0 -1
  118. package/dist/worker/console/static/assets/diagram-7IWD3JNH-B7j1-VsZ.js +0 -30
  119. package/dist/worker/console/static/assets/diagram-B4RE2ZJO-BREJ140a.js +0 -3
  120. package/dist/worker/console/static/assets/diagram-LBJQPF4R-CDPHmHGH.js +0 -24
  121. package/dist/worker/console/static/assets/diagram-Q27KOJAE-BtZLrez1.js +0 -24
  122. package/dist/worker/console/static/assets/diagram-UB23O5K3-mzybu8oU.js +0 -41
  123. package/dist/worker/console/static/assets/ebnfDiagram-BXEA7PRR-Dk3I2uO6.js +0 -1
  124. package/dist/worker/console/static/assets/erDiagram-JOGREHBK-BT97u_tQ.js +0 -85
  125. package/dist/worker/console/static/assets/flowDiagram-UKHOOZJN-CMOtYzui.js +0 -156
  126. package/dist/worker/console/static/assets/ganttDiagram-PKOTCBZU-DiNydkuY.js +0 -292
  127. package/dist/worker/console/static/assets/gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js +0 -106
  128. package/dist/worker/console/static/assets/graph-DOmOIIwC.js +0 -1
  129. package/dist/worker/console/static/assets/index-DQxiso1w.js +0 -325
  130. package/dist/worker/console/static/assets/index-_j0Hzo69.css +0 -1
  131. package/dist/worker/console/static/assets/infoDiagram-6WML65LV-AsGIGKKB.js +0 -2
  132. package/dist/worker/console/static/assets/init-Gi6I4Gst.js +0 -1
  133. package/dist/worker/console/static/assets/ishikawaDiagram-WSZJBQD7-BL8ITZh3.js +0 -70
  134. package/dist/worker/console/static/assets/journeyDiagram-NVQOT4AX-VPKAUX8M.js +0 -139
  135. package/dist/worker/console/static/assets/kanban-definition-27J2QSJJ-BL56hfGp.js +0 -89
  136. package/dist/worker/console/static/assets/layout-D-LzfAck.js +0 -1
  137. package/dist/worker/console/static/assets/linear-BmSG3nIZ.js +0 -1
  138. package/dist/worker/console/static/assets/map-DxJ2ADlA.js +0 -1
  139. package/dist/worker/console/static/assets/mermaid.core-DWGK9kwP.js +0 -308
  140. package/dist/worker/console/static/assets/mindmap-definition-FAOFIHXS--vvKLjo0.js +0 -96
  141. package/dist/worker/console/static/assets/ordinal-Cboi1Yqb.js +0 -1
  142. package/dist/worker/console/static/assets/pegDiagram-VL7TDLO6-B41mxb2-.js +0 -1
  143. package/dist/worker/console/static/assets/pieDiagram-7S7Q4E2Y-DTlu77sw.js +0 -39
  144. package/dist/worker/console/static/assets/quadrantDiagram-CIZ2JOQS-Bk5A7alv.js +0 -7
  145. package/dist/worker/console/static/assets/railroadDiagram-AXF67PYL-Csf9jzQy.js +0 -1
  146. package/dist/worker/console/static/assets/requirementDiagram-LRYGKXZP-CeptoSNx.js +0 -84
  147. package/dist/worker/console/static/assets/sankeyDiagram-W5VNT64P-A-DLCLer.js +0 -40
  148. package/dist/worker/console/static/assets/sequenceDiagram-SI44F4Z6-22VbPdOI.js +0 -162
  149. package/dist/worker/console/static/assets/sizeCapture-X5ZJPWSS-DWvAyBC9.js +0 -1
  150. package/dist/worker/console/static/assets/stateDiagram-OKZ733FA-qICZ75yT.js +0 -1
  151. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +0 -1
  152. package/dist/worker/console/static/assets/swimlanes-SLNWSIFB-xi7lcMyp.js +0 -2
  153. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +0 -8
  154. package/dist/worker/console/static/assets/timeline-definition-Z64GVDOM-Bu6Nl6O2.js +0 -120
  155. package/dist/worker/console/static/assets/vennDiagram-T6HMQDX7-BzMz4Bn9.js +0 -34
  156. package/dist/worker/console/static/assets/wardleyDiagram-T6FBY63Y-CxaJnzc5.js +0 -78
  157. package/dist/worker/console/static/assets/xychartDiagram-ELKLHX3M-5JK-omQK.js +0 -7
  158. package/dist/worker/console/static/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
  159. package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
  160. package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
  161. package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
  162. package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
  163. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
  164. package/dist/worker/console/static/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
  165. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
  166. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
  167. package/dist/worker/console/static/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
  168. package/dist/worker/console/static/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
  169. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
  170. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
  171. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
  172. package/dist/worker/console/static/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
  173. package/dist/worker/console/static/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
  174. package/dist/worker/console/static/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
  175. package/dist/worker/console/static/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
  176. package/dist/worker/console/static/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
  177. package/dist/worker/console/static/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
  178. package/dist/worker/console/static-src/operator-chat/activity-journey.js +0 -125
  179. package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
  180. package/dist/worker/console/static-src/operator-chat/activity-references.js +0 -20
  181. package/dist/worker/console/static-src/operator-chat/slash-palette-layout.js +0 -24
  182. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
  183. package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
  184. package/dist/worker/observability/interrupt-eligibility.js +0 -264
  185. package/dist/workflows/dag/contract-output-registry.js +0 -14
  186. package/dist/workflows/dag/contract-validator-registrations.js +0 -8
  187. package/dist/workflows/dag/frontend-recovery-plan.js +0 -73
  188. package/dist/workflows/dag/frontend-recovery-root-manifest.js +0 -123
  189. package/dist/workflows/dag/frontend-recovery-run.js +0 -539
  190. package/dist/workflows/dag/frontend-writer-recovery.js +0 -106
  191. package/dist/workflows/dag/frontend-writer-rollback.js +0 -821
  192. package/dist/workflows/dag/interrupt-request.js +0 -559
@@ -6,8 +6,8 @@
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <link rel="stylesheet" href="/inspect/operator-chrome.css" />
8
8
  <title>Loop 操作台 · Operator Console</title>
9
- <script type="module" crossorigin src="/assets/index-DQxiso1w.js"></script>
10
- <link rel="stylesheet" crossorigin href="/assets/index-_j0Hzo69.css">
9
+ <script type="module" crossorigin src="/assets/index-M0BLEBfh.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/assets/index-HX1pbOyl.css">
11
11
  </head>
12
12
  <body>
13
13
  <div id="root"></div>
@@ -1,4 +1,3 @@
1
- import { formatIneligibleRerunMessage, nextActionForIneligibleRerun, } from "../../recovery-error-copy.js";
2
1
  /** Legacy step ids from older sessions map onto the merged contract step. */
3
2
  export function normalizeWizardStep(step) {
4
3
  if (step === "validate" || step === "apply" || step === "spine") {
@@ -58,7 +57,6 @@ export const RECOVERY_FACT_LABEL = {
58
57
  "terminal-failed": "已终止(失败)",
59
58
  "terminal-succeeded": "已终止(成功)",
60
59
  "needs-reconcile": "需要对账",
61
- "running-active": "正在运行",
62
60
  };
63
61
  export const LAYER_VALUE_LABEL = {
64
62
  idle: "空闲",
@@ -110,20 +108,18 @@ export const LONG_RUNNING_ACTIONS = new Set([
110
108
  "runDag",
111
109
  "dagRerun",
112
110
  "dagReconcileRun",
113
- "dagRequestInterrupt",
114
111
  "standaloneTaskRerun",
115
112
  ]);
116
- export function suggestedRecoveryAfterIneligibleRerun(reasons) {
117
- return nextActionForIneligibleRerun(reasons);
118
- }
119
- export function formatDagRerunIneligible(plan, fallbackMessage) {
120
- return formatIneligibleRerunMessage({
121
- blockedReasons: plan.blockedReasons,
122
- blockingNodes: plan.blockingNodes,
123
- fallbackMessage,
124
- });
113
+ export function formatDagRerunIneligible(plan) {
114
+ const fromBlocked = (plan.blockedReasons ?? []).map(String);
115
+ const fromNodes = (plan.blockingNodes ?? []).map((n) => [n.nodeId, n.reasonCode].filter(Boolean).join(":"));
116
+ const reasons = [...fromBlocked, ...fromNodes].filter(Boolean);
117
+ if (reasons.length === 0) {
118
+ return "从节点重跑不具备安全资格(子图含 writer / unsafe shell / decision-gate 等)。可改用「完整重跑任务」,或另选只读安全子图的起始节点。";
119
+ }
120
+ return `从节点重跑不具备安全资格:${reasons.slice(0, 6).join("; ")}${reasons.length > 6 ? "…" : ""}。可改用「完整重跑任务」。`;
125
121
  }
126
- export async function waitForOperation(operationId, timeoutMs = 300_000) {
122
+ export async function waitForOperation(operationId, timeoutMs = 90_000) {
127
123
  const started = Date.now();
128
124
  while (Date.now() - started < timeoutMs) {
129
125
  const res = await fetch(`/api/operator/v1/operations/${encodeURIComponent(operationId)}`, { credentials: "same-origin" });
@@ -6,8 +6,8 @@ import { confirmationToken, CONFIRMATION_HEADER, LONG_RUNNING_ACTIONS, postOpera
6
6
  * seconds server-side (imports + intake). Prevents the "page looks frozen"
7
7
  * gap between click and the terminal flash message. */
8
8
  const ACTION_PROGRESS_COPY = {
9
- bootstrapFromPrd: "正在导入 PRD 并创建任务:归档文档 → 确定性解析 → 语义结构化(MED→HIGH→LOW,每档最多 300 秒,请勿关闭页面)",
10
- importPrd: "正在导入 PRD:归档文档 → 确定性解析 → 语义结构化(MED→HIGH→LOW,每档最多 300 秒,请勿关闭页面)",
9
+ bootstrapFromPrd: "正在导入 PRD 并创建任务:归档文档 → 确定性解析 → 语义结构化(约 10–60 秒,请勿关闭页面)",
10
+ importPrd: "正在导入 PRD:归档文档 → 确定性解析 → 语义结构化(约 10–60 秒,请勿关闭页面)",
11
11
  interviewStart: "正在启动需求访谈…",
12
12
  interviewTurn: "正在提交访谈回答…",
13
13
  interviewSkip: "正在跳过访谈并生成评估…",
@@ -16,8 +16,6 @@ const ACTION_PROGRESS_COPY = {
16
16
  contractApply: "正在应用契约(写入需求与执行约束)…",
17
17
  spineCheck: "正在运行 Spine 审计…",
18
18
  dagGenerate: "正在生成 DAG…",
19
- standaloneTaskRerun: "正在完整重跑任务:服务端校验资格后启动新 run…",
20
- workerTaskRetry: "正在重新排队 Worker Task…",
21
19
  };
22
20
  /** Central operator-action dispatcher: POST /api/operator/v1/operations with
23
21
  * polling, long-running background waits, interview payload handoff and the
@@ -1,35 +1,10 @@
1
1
  import { useCallback } from "react";
2
2
  import { isAutoRecoveryReason } from "../../recovery-selection.js";
3
- import { formatOperatorUserError } from "../../operator-user-error.js";
4
3
  import { formatDagRerunIneligible, postOperator, requestId, } from "./console-types.js";
5
- /** Destructive reconcile still consumes a browser Human Gate receipt.
6
- * Same-task rerun / Worker retry are autonomous and must not enter here. */
7
- async function consumeMutationGateAndRun(input) {
8
- const prep = await input.runAction("prepareMutationGate", {
9
- action: input.action,
10
- actionParams: input.actionParams,
11
- });
12
- if (!input.isActionSuccess(prep))
13
- return;
14
- const receiptSource = (prep?.result ?? prep);
15
- const receipt = receiptSource.receiptId
16
- ? receiptSource
17
- : (receiptSource.result ?? receiptSource);
18
- if (!receipt.receiptId || !receipt.humanGateToken) {
19
- input.setOpError("prepareMutationGate 未返回可消费的 Human Gate receipt");
20
- return;
21
- }
22
- await input.runAction(input.action, {
23
- ...input.actionParams,
24
- confirmationId: receipt.receiptId,
25
- humanGateToken: receipt.humanGateToken,
26
- }, { clientRequestId: input.clientRequestId });
27
- }
28
4
  /** Recovery CTA dispatch: diagnose/report/inspect shortcuts, reason-gated
29
- * confirm flow with dagRerunPlan preflight, autonomous rerun/retry, and
30
- * Human Gate only for destructive reconcile. */
5
+ * confirm flow with dagRerunPlan preflight, and gated reruns/retries. */
31
6
  export function useRecoveryActions(params) {
32
- const { shell, actions, taskId, dagRunId, fromNodeId, featureId, recoveryReason, recoveryReasonTouched, recoveryConfirm, recoveryPlanSummary, interruptReasonCode, setRecoveryConfirm, setRecoveryPlanSummary, setRecoveryReport, setRecoveryReason, setRecoveryReasonTouched, buildCurrentRecoveryReason, openFullCanvas, } = params;
7
+ const { shell, actions, taskId, dagRunId, fromNodeId, featureId, recoveryReason, recoveryReasonTouched, recoveryConfirm, recoveryPlanSummary, setRecoveryConfirm, setRecoveryPlanSummary, setRecoveryReport, setRecoveryReason, setRecoveryReasonTouched, buildCurrentRecoveryReason, openFullCanvas, } = params;
33
8
  const { setOpError, setOpErrorCode, setOpMessage, setBusy } = shell;
34
9
  const { runAction, isActionSuccess } = actions;
35
10
  const handleRecoveryCta = useCallback(async (cta) => {
@@ -108,7 +83,7 @@ export function useRecoveryActions(params) {
108
83
  setOpMessage(null);
109
84
  }
110
85
  else if (plan.eligible === false) {
111
- setOpError(formatOperatorUserError(formatDagRerunIneligible(plan, body.error?.message)));
86
+ setOpError(body.error?.message ?? formatDagRerunIneligible(plan));
112
87
  }
113
88
  else {
114
89
  setOpMessage(body.error?.message ??
@@ -175,7 +150,7 @@ export function useRecoveryActions(params) {
175
150
  planHash = plan.planHash?.trim() || planHash;
176
151
  planEligible = plan.eligible;
177
152
  if (plan.eligible === false) {
178
- setOpError(formatOperatorUserError(formatDagRerunIneligible(plan, planBody?.error?.message)));
153
+ setOpError(planBody?.error?.message ?? formatDagRerunIneligible(plan));
179
154
  return;
180
155
  }
181
156
  if (planBody && planBody.ok === false && !planHash) {
@@ -185,7 +160,7 @@ export function useRecoveryActions(params) {
185
160
  }
186
161
  }
187
162
  if (planEligible === false) {
188
- setOpError(formatOperatorUserError(formatDagRerunIneligible(recoveryPlanSummary ?? {})));
163
+ setOpError(formatDagRerunIneligible(recoveryPlanSummary ?? {}));
189
164
  return;
190
165
  }
191
166
  if (!planHash) {
@@ -201,10 +176,26 @@ export function useRecoveryActions(params) {
201
176
  setOpError("完整重跑任务需要 DAG 运行 ID");
202
177
  return;
203
178
  }
204
- await runAction("standaloneTaskRerun", {
179
+ const actionParams = {
205
180
  runId,
206
181
  reason,
207
182
  ...(taskId.trim() ? { taskId: taskId.trim() } : {}),
183
+ };
184
+ const prep = await runAction("prepareMutationGate", {
185
+ action: "standaloneTaskRerun",
186
+ actionParams,
187
+ });
188
+ if (!isActionSuccess(prep))
189
+ return;
190
+ const receipt = (prep?.result ?? prep);
191
+ if (!receipt.receiptId || !receipt.humanGateToken) {
192
+ setOpError("prepareMutationGate 未返回可消费的 Human Gate receipt");
193
+ return;
194
+ }
195
+ await runAction("standaloneTaskRerun", {
196
+ ...actionParams,
197
+ confirmationId: receipt.receiptId,
198
+ humanGateToken: receipt.humanGateToken,
208
199
  }, { clientRequestId });
209
200
  return;
210
201
  }
@@ -214,35 +205,27 @@ export function useRecoveryActions(params) {
214
205
  setOpError("重新排队 Worker Task 需要任务 ID");
215
206
  return;
216
207
  }
217
- await runAction("workerTaskRetry", {
208
+ const actionParams = {
218
209
  taskId: id,
219
210
  reason,
220
211
  ...(featureId.trim() ? { featureId: featureId.trim() } : {}),
221
- }, { clientRequestId });
222
- return;
223
- }
224
- if (cta.id === "interrupt") {
225
- const runId = dagRunId.trim();
226
- if (!runId) {
227
- setOpError("中止运行需要 DAG 运行 ID");
212
+ };
213
+ const prep = await runAction("prepareMutationGate", {
214
+ action: "workerTaskRetry",
215
+ actionParams,
216
+ });
217
+ if (!isActionSuccess(prep))
228
218
  return;
229
- }
230
- if (reason.trim().length < 10 || reason.trim().length > 500) {
231
- setOpError("中止原因去首尾空白后必须是 10–500 个字符,请手写说明,不要用占位句。");
219
+ const receipt = (prep?.result ?? prep);
220
+ if (!receipt.receiptId || !receipt.humanGateToken) {
221
+ setOpError("prepareMutationGate 未返回可消费的 Human Gate receipt");
232
222
  return;
233
223
  }
234
- await consumeMutationGateAndRun({
235
- runAction,
236
- isActionSuccess,
237
- setOpError,
238
- action: "dagRequestInterrupt",
239
- actionParams: {
240
- runId,
241
- reasonCode: interruptReasonCode.trim() || "operator-request",
242
- reasonDetail: reason,
243
- },
244
- clientRequestId,
245
- });
224
+ await runAction("workerTaskRetry", {
225
+ ...actionParams,
226
+ confirmationId: receipt.receiptId,
227
+ humanGateToken: receipt.humanGateToken,
228
+ }, { clientRequestId });
246
229
  return;
247
230
  }
248
231
  if (cta.id === "reconcile") {
@@ -254,18 +237,27 @@ export function useRecoveryActions(params) {
254
237
  // Default supersede: orphan/interrupted runs should not be resumed.
255
238
  // The browser Human Gate binds the destructive action + reason; the CLI
256
239
  // still fail-closes when runner is not proven dead/stopped.
257
- await consumeMutationGateAndRun({
258
- runAction,
259
- isActionSuccess,
260
- setOpError,
240
+ const actionParams = {
241
+ runId,
242
+ reason,
243
+ reconcileAction: "supersede",
244
+ };
245
+ const prep = await runAction("prepareMutationGate", {
261
246
  action: "dagReconcileRun",
262
- actionParams: {
263
- runId,
264
- reason,
265
- reconcileAction: "supersede",
266
- },
267
- clientRequestId,
247
+ actionParams,
268
248
  });
249
+ if (!isActionSuccess(prep))
250
+ return;
251
+ const receipt = (prep?.result ?? prep);
252
+ if (!receipt.receiptId || !receipt.humanGateToken) {
253
+ setOpError("prepareMutationGate 未返回可消费的 Human Gate receipt");
254
+ return;
255
+ }
256
+ await runAction("dagReconcileRun", {
257
+ ...actionParams,
258
+ confirmationId: receipt.receiptId,
259
+ humanGateToken: receipt.humanGateToken,
260
+ }, { clientRequestId });
269
261
  return;
270
262
  }
271
263
  setOpMessage(`${cta.label}:请经 CLI — ${cta.commandHint ?? ""}`);
@@ -276,7 +268,6 @@ export function useRecoveryActions(params) {
276
268
  recoveryConfirm,
277
269
  recoveryPlanSummary?.planHash,
278
270
  recoveryReason,
279
- interruptReasonCode,
280
271
  runAction,
281
272
  isActionSuccess,
282
273
  setOpError,
@@ -16,16 +16,12 @@ export function useRecoveryConsole(params) {
16
16
  const [recoveryReasonTouched, setRecoveryReasonTouched] = useState(false);
17
17
  const [recoveryPlanSummary, setRecoveryPlanSummary] = useState(null);
18
18
  const [recoveryConfirm, setRecoveryConfirm] = useState(null);
19
- const [interruptIntent, setInterruptIntent] = useState(false);
20
- const [interruptReasonCode, setInterruptReasonCode] = useState("operator-request");
21
- const [interruptEligibility, setInterruptEligibility] = useState(null);
22
19
  const [recoveryRuns, setRecoveryRuns] = useState([]);
23
20
  const [recoveryNodes, setRecoveryNodes] = useState([]);
24
21
  const [recoveryRunsLoading, setRecoveryRunsLoading] = useState(false);
25
22
  const [recoveryNodesLoading, setRecoveryNodesLoading] = useState(false);
26
23
  const [recoveryRunStatus, setRecoveryRunStatus] = useState(null);
27
24
  const [recoveryFailureCategory, setRecoveryFailureCategory] = useState(null);
28
- const [frontendRecovery, setFrontendRecovery] = useState(null);
29
25
  const [manualRunId, setManualRunId] = useState(false);
30
26
  const [manualNodeId, setManualNodeId] = useState(false);
31
27
  const [recoveryReport, setRecoveryReport] = useState(null);
@@ -128,7 +124,6 @@ export function useRecoveryConsole(params) {
128
124
  setRecoveryNodes([]);
129
125
  setRecoveryRunStatus(null);
130
126
  setRecoveryFailureCategory(null);
131
- setFrontendRecovery(null);
132
127
  return;
133
128
  }
134
129
  setRecoveryNodesLoading(true);
@@ -172,13 +167,11 @@ export function useRecoveryConsole(params) {
172
167
  n.failureCategory &&
173
168
  n.failureCategory !== "success")?.failureCategory;
174
169
  setRecoveryFailureCategory(runFailure ?? nodeFailure ?? null);
175
- setFrontendRecovery(body.frontendRecovery ?? null);
176
170
  }
177
171
  catch {
178
172
  setRecoveryNodes([]);
179
173
  setRecoveryRunStatus(null);
180
174
  setRecoveryFailureCategory(null);
181
- setFrontendRecovery(null);
182
175
  }
183
176
  finally {
184
177
  setRecoveryNodesLoading(false);
@@ -211,37 +204,6 @@ export function useRecoveryConsole(params) {
211
204
  return;
212
205
  void loadRecoveryNodes(dagRunId);
213
206
  }, [nav, dagRunId, loadRecoveryNodes]);
214
- useEffect(() => {
215
- if (nav !== "recovery")
216
- return;
217
- const runId = dagRunId.trim();
218
- if (!runId) {
219
- setInterruptEligibility(null);
220
- return;
221
- }
222
- let cancelled = false;
223
- const load = async () => {
224
- const { body } = await postOperator("dagInterruptEligibility", { runId });
225
- if (cancelled)
226
- return;
227
- const result = (body.result ?? body);
228
- setInterruptEligibility({
229
- eligible: result.eligible === true,
230
- ownerKind: result.ownerKind,
231
- message: result.message,
232
- interruptStatus: result.interruptStatus,
233
- reasonCodes: result.reasonCodes,
234
- targetOperationId: result.targetOperationId,
235
- targetOperationState: result.targetOperationState,
236
- });
237
- };
238
- void load();
239
- const timer = window.setInterval(() => void load(), 4000);
240
- return () => {
241
- cancelled = true;
242
- window.clearInterval(timer);
243
- };
244
- }, [nav, dagRunId]);
245
207
  useEffect(() => {
246
208
  if (nav !== "recovery")
247
209
  return;
@@ -267,14 +229,7 @@ export function useRecoveryConsole(params) {
267
229
  dagStatus: recoveryRunStatus,
268
230
  failureCategory: recoveryFailureCategory,
269
231
  });
270
- const recoveryCtas = useMemo(() => {
271
- const ctas = consoleRecoveryCtas(recoveryFact);
272
- if (recoveryFact !== "running-active")
273
- return ctas;
274
- if (interruptEligibility?.eligible)
275
- return ctas;
276
- return ctas.filter((cta) => cta.id !== "interrupt");
277
- }, [recoveryFact, interruptEligibility?.eligible]);
232
+ const recoveryCtas = useMemo(() => consoleRecoveryCtas(recoveryFact), [recoveryFact]);
278
233
  const recoveryLanes = useMemo(() => partitionRecoveryCtas(recoveryCtas), [recoveryCtas]);
279
234
  const recommendedCtaId = useMemo(() => recommendedRecoveryCtaId(recoveryFact), [recoveryFact]);
280
235
  const selectedRecoveryNode = useMemo(() => recoveryNodes.find((n) => n.nodeId === fromNodeId.trim()), [recoveryNodes, fromNodeId]);
@@ -340,7 +295,6 @@ export function useRecoveryConsole(params) {
340
295
  recoveryReasonTouched,
341
296
  recoveryConfirm,
342
297
  recoveryPlanSummary,
343
- interruptReasonCode,
344
298
  setRecoveryConfirm,
345
299
  setRecoveryPlanSummary,
346
300
  setRecoveryReport,
@@ -349,25 +303,6 @@ export function useRecoveryConsole(params) {
349
303
  buildCurrentRecoveryReason,
350
304
  openFullCanvas,
351
305
  });
352
- useEffect(() => {
353
- if (nav !== "recovery" || !interruptIntent)
354
- return;
355
- if (!interruptEligibility?.eligible)
356
- return;
357
- const interruptCta = recoveryCtas.find((cta) => cta.id === "interrupt");
358
- if (!interruptCta)
359
- return;
360
- setRecoveryConfirm(interruptCta);
361
- setRecoveryReason(buildCurrentRecoveryReason(interruptCta.label));
362
- setRecoveryReasonTouched(false);
363
- setInterruptIntent(false);
364
- }, [
365
- nav,
366
- interruptIntent,
367
- interruptEligibility?.eligible,
368
- recoveryCtas,
369
- buildCurrentRecoveryReason,
370
- ]);
371
306
  return {
372
307
  dagRunId,
373
308
  setDagRunId,
@@ -388,8 +323,6 @@ export function useRecoveryConsole(params) {
388
323
  recoveryRunsLoading,
389
324
  recoveryNodesLoading,
390
325
  recoveryRunStatus,
391
- recoveryFailureCategory,
392
- frontendRecovery,
393
326
  manualRunId,
394
327
  setManualRunId,
395
328
  manualNodeId,
@@ -412,11 +345,6 @@ export function useRecoveryConsole(params) {
412
345
  recoveryCtas,
413
346
  recoveryLanes,
414
347
  recommendedCtaId,
415
- interruptIntent,
416
- setInterruptIntent,
417
- interruptReasonCode,
418
- setInterruptReasonCode,
419
- interruptEligibility,
420
348
  recoveryConfirmRef,
421
349
  buildCurrentRecoveryReason,
422
350
  handleRecoveryCta,