@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.
- package/AGENTS.md +2 -6
- package/CHANGELOG.md +71 -144
- package/README.md +1 -1
- package/bin/loop-agent.js +1 -37
- package/dist/application/task-lifecycle/advance.js +0 -1
- package/dist/application/task-lifecycle/observe.js +0 -15
- package/dist/application/task-lifecycle/plan-transitions.js +0 -15
- package/dist/cli/command-definitions.js +0 -7
- package/dist/cli/program.js +3 -8
- package/dist/commands/init-upgrade.js +19 -351
- package/dist/commands/init.js +67 -14
- package/dist/commands/run-dag-progress.js +0 -14
- package/dist/commands/task-advance.js +3 -33
- package/dist/executors/dag-pi-executor.js +30 -47
- package/dist/executors/pi-sdk-executor.js +0 -34
- package/dist/executors/shell-executor.js +95 -6
- package/dist/shared/operator/capabilities.js +13 -200
- package/dist/shared/package-metadata.js +0 -42
- package/dist/task/contract/project.js +0 -4
- package/dist/task/source-prepare/completeness.js +0 -53
- package/dist/task/source-prepare/parse-intent.js +12 -82
- package/dist/task/source-prepare/prepare.js +5 -102
- package/dist/task/source-prepare/semantic-intake.js +23 -144
- package/dist/worker/console/chat/artifact-card.js +1 -8
- package/dist/worker/console/chat/chat-event-store.js +0 -152
- package/dist/worker/console/chat/human-gate-card.js +1 -9
- package/dist/worker/console/chat/operation-card.js +2 -71
- package/dist/worker/console/chat/pi-runtime.js +62 -111
- package/dist/worker/console/chat/routes.js +10 -43
- package/dist/worker/console/chat/session-store.js +1 -9
- package/dist/worker/console/chat/shortcuts.js +7 -9
- package/dist/worker/console/chat/turn-process.js +23 -204
- package/dist/worker/console/chat/workspace-landing.js +1 -2
- package/dist/worker/console/operation-runner.js +6 -155
- package/dist/worker/console/operator-actions.js +14 -391
- package/dist/worker/console/operator-user-error.js +0 -4
- package/dist/worker/console/recovery-cta.js +3 -50
- package/dist/worker/console/static/assets/index-HX1pbOyl.css +1 -0
- package/dist/worker/console/static/assets/index-M0BLEBfh.js +56 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -13
- package/dist/worker/console/static-src/app/useOperatorActions.js +2 -4
- package/dist/worker/console/static-src/app/useRecoveryActions.js +56 -65
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +1 -73
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +30 -114
- package/dist/worker/console/static-src/operator-chat/refs.js +0 -3
- package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +13 -67
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -12
- package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -45
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -7
- package/dist/worker/loop-agent/loop-agent-client.js +3 -17
- package/dist/worker/observability/read-model.js +0 -20
- package/dist/worker/observe/spec-evidence.js +8 -3
- package/dist/worker/observe/static/operator-chrome.d.ts +0 -1
- package/dist/worker/observe/static/operator-chrome.js +3 -10
- package/dist/worker/observe/static/views/dag-inspector.js +71 -6
- package/dist/worker/observe/static/views/dag.js +0 -12
- package/dist/worker/preflight.js +1 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +707 -37
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +109 -7
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +345 -24
- package/dist/workflows/dag/backend-test-scenario-param.js +890 -164
- package/dist/workflows/dag/backend-test-writer-completeness.js +47 -16
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -9
- package/dist/workflows/dag/frontend-implementation-contract.js +39 -233
- package/dist/workflows/dag/frontend-prewrite-gate.js +61 -364
- package/dist/workflows/dag/frontend-repair.js +18 -219
- package/dist/workflows/dag/frontend-verification-trace.js +32 -47
- package/dist/workflows/dag/init-hybrid.js +82 -165
- package/dist/workflows/dag/node-execution.js +0 -89
- package/dist/workflows/dag/recovery-recommendation.js +0 -58
- package/dist/workflows/dag/runner.js +15 -333
- package/dist/workflows/dag/scheduler.js +3 -257
- package/dist/workflows/dag/types.js +9 -130
- package/docs/README.md +3 -3
- package/docs/architecture/evolution.md +67 -102
- package/docs/templates/backend-test-dag.json +50 -32
- package/docs/templates/init-managed-agents.md +2 -5
- package/harness.json +2 -2
- package/package.json +3 -9
- package/skills/loop-agent/SKILL.md +0 -1
- package/skills/loop-agent/references/command-reference.md +0 -4
- package/dist/build-stamp.json +0 -6
- package/dist/commands/dag-request-interrupt.js +0 -20
- package/dist/worker/console/chat/assistant-content.js +0 -121
- package/dist/worker/console/chat/semantic-activity.js +0 -477
- package/dist/worker/console/operation-run-facts.js +0 -190
- package/dist/worker/console/operation-wait.js +0 -355
- package/dist/worker/console/recovery-error-copy.js +0 -198
- package/dist/worker/console/static/assets/abnfDiagram-N423BO3Z-DSvF6RXQ.js +0 -1
- package/dist/worker/console/static/assets/arc-DuI4ogtJ.js +0 -1
- package/dist/worker/console/static/assets/architectureDiagram-T3A2C74G-DdBbgD4y.js +0 -36
- package/dist/worker/console/static/assets/blockDiagram-VBNYF7ZC-xQC2HELm.js +0 -132
- package/dist/worker/console/static/assets/c4Diagram-5PPSVZJV-DPMSgwIZ.js +0 -10
- package/dist/worker/console/static/assets/channel-DLVz9TYW.js +0 -1
- package/dist/worker/console/static/assets/chunk-2GRJ4B5K-WTEKTxin.js +0 -1
- package/dist/worker/console/static/assets/chunk-2Q5K7J3B-B6vZ0Pv_.js +0 -1
- package/dist/worker/console/static/assets/chunk-5RXB4S5H-BrerNAix.js +0 -231
- package/dist/worker/console/static/assets/chunk-5VM5RSS4-D_ch2aaI.js +0 -15
- package/dist/worker/console/static/assets/chunk-6Q2QTUOP-VvfacNrq.js +0 -88
- package/dist/worker/console/static/assets/chunk-GF5L2VYU-B-uGFIg2.js +0 -206
- package/dist/worker/console/static/assets/chunk-JWPE2WC7-BlysCtod.js +0 -1
- package/dist/worker/console/static/assets/chunk-KBJHAD2P-BjAUAfcT.js +0 -1
- package/dist/worker/console/static/assets/chunk-RYQCIY6F-BeZnBmb-.js +0 -1
- package/dist/worker/console/static/assets/chunk-XXDRQBXY-Bbfe3UJG.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/cose-bilkent-JH36ORCC-BKJQnYVM.js +0 -1
- package/dist/worker/console/static/assets/cynefin-VYW2F7L2-B1wtI3hU.js +0 -166
- package/dist/worker/console/static/assets/cynefinDiagram-MW4NZA55-DCF6DBSu.js +0 -62
- package/dist/worker/console/static/assets/cytoscape.esm-yzknjiTM.js +0 -321
- package/dist/worker/console/static/assets/dagre-VZM6K2ZE-BJyNGRlP.js +0 -4
- package/dist/worker/console/static/assets/defaultLocale-DX6XiGOO.js +0 -1
- package/dist/worker/console/static/assets/diagram-7IWD3JNH-B7j1-VsZ.js +0 -30
- package/dist/worker/console/static/assets/diagram-B4RE2ZJO-BREJ140a.js +0 -3
- package/dist/worker/console/static/assets/diagram-LBJQPF4R-CDPHmHGH.js +0 -24
- package/dist/worker/console/static/assets/diagram-Q27KOJAE-BtZLrez1.js +0 -24
- package/dist/worker/console/static/assets/diagram-UB23O5K3-mzybu8oU.js +0 -41
- package/dist/worker/console/static/assets/ebnfDiagram-BXEA7PRR-Dk3I2uO6.js +0 -1
- package/dist/worker/console/static/assets/erDiagram-JOGREHBK-BT97u_tQ.js +0 -85
- package/dist/worker/console/static/assets/flowDiagram-UKHOOZJN-CMOtYzui.js +0 -156
- package/dist/worker/console/static/assets/ganttDiagram-PKOTCBZU-DiNydkuY.js +0 -292
- package/dist/worker/console/static/assets/gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js +0 -106
- package/dist/worker/console/static/assets/graph-DOmOIIwC.js +0 -1
- package/dist/worker/console/static/assets/index-DQxiso1w.js +0 -325
- package/dist/worker/console/static/assets/index-_j0Hzo69.css +0 -1
- package/dist/worker/console/static/assets/infoDiagram-6WML65LV-AsGIGKKB.js +0 -2
- package/dist/worker/console/static/assets/init-Gi6I4Gst.js +0 -1
- package/dist/worker/console/static/assets/ishikawaDiagram-WSZJBQD7-BL8ITZh3.js +0 -70
- package/dist/worker/console/static/assets/journeyDiagram-NVQOT4AX-VPKAUX8M.js +0 -139
- package/dist/worker/console/static/assets/kanban-definition-27J2QSJJ-BL56hfGp.js +0 -89
- package/dist/worker/console/static/assets/layout-D-LzfAck.js +0 -1
- package/dist/worker/console/static/assets/linear-BmSG3nIZ.js +0 -1
- package/dist/worker/console/static/assets/map-DxJ2ADlA.js +0 -1
- package/dist/worker/console/static/assets/mermaid.core-DWGK9kwP.js +0 -308
- package/dist/worker/console/static/assets/mindmap-definition-FAOFIHXS--vvKLjo0.js +0 -96
- package/dist/worker/console/static/assets/ordinal-Cboi1Yqb.js +0 -1
- package/dist/worker/console/static/assets/pegDiagram-VL7TDLO6-B41mxb2-.js +0 -1
- package/dist/worker/console/static/assets/pieDiagram-7S7Q4E2Y-DTlu77sw.js +0 -39
- package/dist/worker/console/static/assets/quadrantDiagram-CIZ2JOQS-Bk5A7alv.js +0 -7
- package/dist/worker/console/static/assets/railroadDiagram-AXF67PYL-Csf9jzQy.js +0 -1
- package/dist/worker/console/static/assets/requirementDiagram-LRYGKXZP-CeptoSNx.js +0 -84
- package/dist/worker/console/static/assets/sankeyDiagram-W5VNT64P-A-DLCLer.js +0 -40
- package/dist/worker/console/static/assets/sequenceDiagram-SI44F4Z6-22VbPdOI.js +0 -162
- package/dist/worker/console/static/assets/sizeCapture-X5ZJPWSS-DWvAyBC9.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-OKZ733FA-qICZ75yT.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +0 -1
- package/dist/worker/console/static/assets/swimlanes-SLNWSIFB-xi7lcMyp.js +0 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +0 -8
- package/dist/worker/console/static/assets/timeline-definition-Z64GVDOM-Bu6Nl6O2.js +0 -120
- package/dist/worker/console/static/assets/vennDiagram-T6HMQDX7-BzMz4Bn9.js +0 -34
- package/dist/worker/console/static/assets/wardleyDiagram-T6FBY63Y-CxaJnzc5.js +0 -78
- package/dist/worker/console/static/assets/xychartDiagram-ELKLHX3M-5JK-omQK.js +0 -7
- package/dist/worker/console/static/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/dist/worker/console/static-src/operator-chat/activity-journey.js +0 -125
- package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
- package/dist/worker/console/static-src/operator-chat/activity-references.js +0 -20
- package/dist/worker/console/static-src/operator-chat/slash-palette-layout.js +0 -24
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
- package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
- package/dist/worker/observability/interrupt-eligibility.js +0 -264
- package/dist/workflows/dag/contract-output-registry.js +0 -14
- package/dist/workflows/dag/contract-validator-registrations.js +0 -8
- package/dist/workflows/dag/frontend-recovery-plan.js +0 -73
- package/dist/workflows/dag/frontend-recovery-root-manifest.js +0 -123
- package/dist/workflows/dag/frontend-recovery-run.js +0 -539
- package/dist/workflows/dag/frontend-writer-recovery.js +0 -106
- package/dist/workflows/dag/frontend-writer-rollback.js +0 -821
- package/dist/workflows/dag/interrupt-request.js +0 -559
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { access, readFile } from "node:fs/promises";
|
|
2
2
|
import { buildOperatorCapabilitiesDocument } from "../../shared/operator/capabilities.js";
|
|
3
3
|
import { buildOperatorResult, operatorFailed, operatorSucceeded, } from "../../shared/operator/envelope.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getTaskPaths, loadTaskConfig } from "../../task/runtime.js";
|
|
5
5
|
import { diffTaskContract, validateDraftForTask, } from "../../task/contract/index.js";
|
|
6
6
|
import { stageUtf8Text } from "./app-data.js";
|
|
7
7
|
import { ALL_CONFIRMATION_CHALLENGES, hashDagBytes, } from "./dag-confirmation.js";
|
|
@@ -18,23 +18,18 @@ import { normalizeConsoleWorkflowKind } from "./workflow-kinds.js";
|
|
|
18
18
|
import { deriveTaskIdentityFromPrd, nextTaskIdRevision, } from "./prd-identity.js";
|
|
19
19
|
import { appendEngineeringCliArgs, buildDraftFromTaskIntake, parseEngineeringBoundaryFromParams, } from "./prd-intake-bridge.js";
|
|
20
20
|
import { discoverPrdReferences } from "./prd-reference-discovery.js";
|
|
21
|
-
import { clearSemanticIntakeAttempt
|
|
21
|
+
import { clearSemanticIntakeAttempt } from "../../task/source-prepare/semantic-intake.js";
|
|
22
22
|
import nodePath from "node:path";
|
|
23
23
|
import { resolveSiblingAgentWorkerBin } from "./sibling-controller.js";
|
|
24
24
|
import { projectOperationEventSummary, projectOperationForChat, } from "./chat/chat-event-store.js";
|
|
25
|
-
import { OperationWaitError, waitForOperationChange, } from "./operation-wait.js";
|
|
26
25
|
import { MutationGateReceiptStore } from "./mutation-gate-receipt-store.js";
|
|
27
|
-
import { formatIneligibleRerunMessage } from "./recovery-error-copy.js";
|
|
28
|
-
import { evaluateConsoleDagInterruptEligibility } from "../observability/interrupt-eligibility.js";
|
|
29
|
-
import { INTERRUPT_ERROR_MESSAGES, isInterruptReasonCode, normalizeInterruptReasonDetail, } from "../observability/interrupt-eligibility.js";
|
|
30
26
|
import { assessAutonomousExecutionEligibility, deriveEligibilityFactsFromDagSpec, } from "./dag-execution-receipt.js";
|
|
31
27
|
import { issueHumanGateToken, mutationGatePayloadHash, verifyHumanGateToken, } from "./human-gate-token.js";
|
|
32
28
|
const MUTATION_GATE_ACTIONS = new Set([
|
|
33
29
|
// 2026-08-11: standaloneTaskRerun / workerTaskRetry are autonomous (server
|
|
34
|
-
// run-facts checks). Destructive DAG reconciliation
|
|
35
|
-
//
|
|
30
|
+
// run-facts checks). Destructive DAG reconciliation and Night Scheduler
|
|
31
|
+
// mutations still need the browser Human Gate.
|
|
36
32
|
"dagReconcileRun",
|
|
37
|
-
"dagRequestInterrupt",
|
|
38
33
|
"workerAdmissionPrepare",
|
|
39
34
|
"workerSchedulerAdd",
|
|
40
35
|
"workerSchedulerCancel",
|
|
@@ -47,12 +42,10 @@ const MUTATION_OR_LONG = new Set([
|
|
|
47
42
|
"contractApply",
|
|
48
43
|
"contractAdopt",
|
|
49
44
|
"contractRecover",
|
|
50
|
-
"taskAdvance",
|
|
51
45
|
"dagRunTask",
|
|
52
46
|
"runDag",
|
|
53
47
|
"dagRerun",
|
|
54
48
|
"dagReconcileRun",
|
|
55
|
-
"dagRequestInterrupt",
|
|
56
49
|
"standaloneTaskRerun",
|
|
57
50
|
"workerTaskRetry",
|
|
58
51
|
]);
|
|
@@ -62,15 +55,6 @@ function paramsOf(req) {
|
|
|
62
55
|
function str(v) {
|
|
63
56
|
return typeof v === "string" && v.trim() ? v.trim() : undefined;
|
|
64
57
|
}
|
|
65
|
-
const TASK_ID_PLACEHOLDER_RE = /[<>]|^(?:id|task-?id|your-task-id|todo|tbd)$/i;
|
|
66
|
-
/** Mirror of runtime GENERIC_TASK_SLUGS (not exported there); keep in sync. */
|
|
67
|
-
const GENERIC_SLUG_SET = new Set(["test", "fix", "tmp", "new-task"]);
|
|
68
|
-
const TASK_ADVANCE_ALIAS_ACTIONS = new Set(["promoteRun", "closeoutTask"]);
|
|
69
|
-
function taskIdInputError(taskId) {
|
|
70
|
-
if (!TASK_ID_PLACEHOLDER_RE.test(taskId))
|
|
71
|
-
return undefined;
|
|
72
|
-
return `taskId must be a concrete canonical id; placeholder values are not allowed: ${JSON.stringify(taskId)}`;
|
|
73
|
-
}
|
|
74
58
|
/** Extract write-set gate token from task advance operator JSON. */
|
|
75
59
|
function extractWriteSetGateTokenFromCliJson(json, taskId) {
|
|
76
60
|
if (!json || typeof json !== "object")
|
|
@@ -145,46 +129,13 @@ function gateError(action, code, message, details) {
|
|
|
145
129
|
}),
|
|
146
130
|
};
|
|
147
131
|
}
|
|
148
|
-
/**
|
|
149
|
-
* `dag report --json` is `{ schemaVersion, runs: [...] }` (no Operator `ok`).
|
|
150
|
-
* `runReadCli` used to wrap that as `{ stdout, raw }`, which made the
|
|
151
|
-
* autonomous rerun gate miss `primaryFailure` even after the UI showed the
|
|
152
|
-
* report (2026-08-16). Accept both the native report shape and the wrap.
|
|
153
|
-
*/
|
|
154
|
-
function extractDagReportRunFacts(reportResult, runId) {
|
|
155
|
-
const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value)
|
|
156
|
-
? value
|
|
157
|
-
: undefined;
|
|
158
|
-
const result = asRecord(reportResult);
|
|
159
|
-
const envelope = Array.isArray(result?.runs)
|
|
160
|
-
? result
|
|
161
|
-
: asRecord(result?.raw);
|
|
162
|
-
if (!envelope)
|
|
163
|
-
return undefined;
|
|
164
|
-
const runs = Array.isArray(envelope.runs) ? envelope.runs : [];
|
|
165
|
-
const matched = runs.find((entry) => asRecord(entry)?.runId === runId) ?? runs[0];
|
|
166
|
-
const matchedRec = asRecord(matched);
|
|
167
|
-
if (matchedRec?.primaryFailure) {
|
|
168
|
-
return {
|
|
169
|
-
primaryFailure: asRecord(matchedRec.primaryFailure),
|
|
170
|
-
primaryRecovery: asRecord(matchedRec.primaryRecovery),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
if (envelope.primaryFailure) {
|
|
174
|
-
return {
|
|
175
|
-
primaryFailure: asRecord(envelope.primaryFailure),
|
|
176
|
-
primaryRecovery: asRecord(envelope.primaryRecovery),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
return undefined;
|
|
180
|
-
}
|
|
181
132
|
/**
|
|
182
133
|
* 2026-08-11 R2 run-facts check for standaloneTaskRerun (read-only CLI
|
|
183
134
|
* evidence only — no browser Human Gate). Fails closed when facts are missing.
|
|
184
135
|
*/
|
|
185
136
|
async function assertAutonomousRerunEligible(ctx, runId, taskId) {
|
|
186
137
|
const report = await runReadCli(ctx, ["dag", "report", "--run-id", runId, "--json"], "dag report");
|
|
187
|
-
const reportResult =
|
|
138
|
+
const reportResult = (report.ok ? report.result : undefined);
|
|
188
139
|
const recovery = reportResult?.primaryRecovery;
|
|
189
140
|
if (!report.ok || !reportResult?.primaryFailure || !recovery) {
|
|
190
141
|
return gateError("standaloneTaskRerun", "INVALID_INPUT", "cannot read dagReport run facts; standaloneTaskRerun requires server-side run evidence", { runId });
|
|
@@ -330,9 +281,6 @@ async function runReadCli(ctx, args, command) {
|
|
|
330
281
|
if (env.schemaVersion === 1 && typeof env.ok === "boolean") {
|
|
331
282
|
return env;
|
|
332
283
|
}
|
|
333
|
-
if (raw.schemaVersion === 1 && Array.isArray(raw.runs)) {
|
|
334
|
-
return operatorSucceeded(command, raw);
|
|
335
|
-
}
|
|
336
284
|
if (command === "dag rerun plan" &&
|
|
337
285
|
raw.plan &&
|
|
338
286
|
typeof raw.plan === "object") {
|
|
@@ -344,8 +292,9 @@ async function runReadCli(ctx, args, command) {
|
|
|
344
292
|
? plan.blockedReasons.map(String)
|
|
345
293
|
: [];
|
|
346
294
|
const blockingNodes = Array.isArray(plan.blockingNodes)
|
|
347
|
-
? plan.blockingNodes
|
|
295
|
+
? plan.blockingNodes.map((n) => [n.nodeId, n.reasonCode].filter(Boolean).join(":"))
|
|
348
296
|
: [];
|
|
297
|
+
const reasons = [...blockedReasons, ...blockingNodes].filter(Boolean);
|
|
349
298
|
return buildOperatorResult({
|
|
350
299
|
command,
|
|
351
300
|
ok: false,
|
|
@@ -353,10 +302,9 @@ async function runReadCli(ctx, args, command) {
|
|
|
353
302
|
result: plan,
|
|
354
303
|
error: {
|
|
355
304
|
code: "DAG_RERUN_INELIGIBLE",
|
|
356
|
-
message:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}),
|
|
305
|
+
message: reasons.length > 0
|
|
306
|
+
? `从节点重跑不具备安全资格:${reasons.slice(0, 6).join("; ")}${reasons.length > 6 ? "…" : ""}`
|
|
307
|
+
: "从节点重跑不具备安全资格(eligible=false)",
|
|
360
308
|
details: {
|
|
361
309
|
eligible: false,
|
|
362
310
|
planHash: typeof plan.planHash === "string" ? plan.planHash : undefined,
|
|
@@ -571,90 +519,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
571
519
|
}),
|
|
572
520
|
};
|
|
573
521
|
}
|
|
574
|
-
case "operationWait": {
|
|
575
|
-
const operationId = str(p.operationId);
|
|
576
|
-
if (!operationId)
|
|
577
|
-
return invalid(action, "operationId is required");
|
|
578
|
-
const rawAfterSeq = p.afterSeq ?? 0;
|
|
579
|
-
const afterSeq = typeof rawAfterSeq === "number" ? rawAfterSeq : Number(rawAfterSeq);
|
|
580
|
-
const rawMaxWaitMs = p.maxWaitMs;
|
|
581
|
-
const maxWaitMs = typeof rawMaxWaitMs === "number"
|
|
582
|
-
? rawMaxWaitMs
|
|
583
|
-
: rawMaxWaitMs === undefined
|
|
584
|
-
? undefined
|
|
585
|
-
: Number(rawMaxWaitMs);
|
|
586
|
-
const rawWakeOn = str(p.wakeOn);
|
|
587
|
-
const wakeOn = rawWakeOn === "all" || rawWakeOn === "meaningful" ? rawWakeOn : undefined;
|
|
588
|
-
try {
|
|
589
|
-
const result = await waitForOperationChange({
|
|
590
|
-
operations: ctx.operations,
|
|
591
|
-
events: ctx.events,
|
|
592
|
-
operationId,
|
|
593
|
-
afterSeq,
|
|
594
|
-
maxWaitMs,
|
|
595
|
-
...(wakeOn ? { wakeOn } : {}),
|
|
596
|
-
poll: async () => {
|
|
597
|
-
const current = await ctx.operations.get(operationId);
|
|
598
|
-
const runId = current?.dagRunId ??
|
|
599
|
-
(typeof current?.actionParams?.runId === "string"
|
|
600
|
-
? current.actionParams.runId
|
|
601
|
-
: undefined);
|
|
602
|
-
if (!current || !runId)
|
|
603
|
-
return false;
|
|
604
|
-
const eligibility = await evaluateConsoleDagInterruptEligibility({
|
|
605
|
-
repoRoot: ctx.repoRoot,
|
|
606
|
-
operations: ctx.operations,
|
|
607
|
-
runId,
|
|
608
|
-
});
|
|
609
|
-
if (!eligibility.interrupt)
|
|
610
|
-
return false;
|
|
611
|
-
const targetId = eligibility.targetOperationId ?? current.operationId;
|
|
612
|
-
return syncTargetInterruptProjection({
|
|
613
|
-
operations: ctx.operations,
|
|
614
|
-
events: ctx.events,
|
|
615
|
-
operationId: targetId,
|
|
616
|
-
runId,
|
|
617
|
-
interrupt: eligibility.interrupt,
|
|
618
|
-
});
|
|
619
|
-
},
|
|
620
|
-
});
|
|
621
|
-
return {
|
|
622
|
-
kind: "sync",
|
|
623
|
-
status: 200,
|
|
624
|
-
body: operatorSucceeded(action, result),
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
catch (error) {
|
|
628
|
-
if (error instanceof OperationWaitError) {
|
|
629
|
-
if (error.code === "NOT_FOUND") {
|
|
630
|
-
return {
|
|
631
|
-
kind: "error",
|
|
632
|
-
status: 404,
|
|
633
|
-
body: operatorFailed({
|
|
634
|
-
command: action,
|
|
635
|
-
outcome: "not-found",
|
|
636
|
-
code: "NOT_FOUND",
|
|
637
|
-
message: error.message,
|
|
638
|
-
}),
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
if (error.code === "EVENT_CURSOR_EXPIRED") {
|
|
642
|
-
return {
|
|
643
|
-
kind: "error",
|
|
644
|
-
status: 410,
|
|
645
|
-
body: operatorFailed({
|
|
646
|
-
command: action,
|
|
647
|
-
outcome: "blocked",
|
|
648
|
-
code: "EVENT_CURSOR_EXPIRED",
|
|
649
|
-
message: error.message,
|
|
650
|
-
}),
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
return invalid(action, error.message);
|
|
654
|
-
}
|
|
655
|
-
throw error;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
522
|
case "inspect": {
|
|
659
523
|
const body = await runReadCli(ctx, ["inspect", "--json"], "inspect");
|
|
660
524
|
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
@@ -1322,24 +1186,8 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1322
1186
|
};
|
|
1323
1187
|
}
|
|
1324
1188
|
const reviewPacket = extractReviewPacketFromCliJson(gen.json) ?? {};
|
|
1325
|
-
let parsedDagSpec;
|
|
1326
|
-
try {
|
|
1327
|
-
parsedDagSpec = JSON.parse(dagText);
|
|
1328
|
-
}
|
|
1329
|
-
catch (error) {
|
|
1330
|
-
return {
|
|
1331
|
-
kind: "error",
|
|
1332
|
-
status: 409,
|
|
1333
|
-
body: operatorFailed({
|
|
1334
|
-
command: action,
|
|
1335
|
-
outcome: "blocked",
|
|
1336
|
-
code: "DAG_GENERATION_FAILED",
|
|
1337
|
-
message: `generated DAG is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
1338
|
-
}),
|
|
1339
|
-
};
|
|
1340
|
-
}
|
|
1341
1189
|
const derivedFacts = deriveEligibilityFactsFromDagSpec({
|
|
1342
|
-
dagSpec:
|
|
1190
|
+
dagSpec: JSON.parse(dagText),
|
|
1343
1191
|
allowedPaths,
|
|
1344
1192
|
forbiddenPaths,
|
|
1345
1193
|
});
|
|
@@ -1501,24 +1349,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1501
1349
|
if (!taskId || !clientRequestId) {
|
|
1502
1350
|
return invalid(action, "taskId and clientRequestId are required");
|
|
1503
1351
|
}
|
|
1504
|
-
const taskIdError = taskIdInputError(taskId);
|
|
1505
|
-
if (taskIdError)
|
|
1506
|
-
return invalid(action, taskIdError);
|
|
1507
|
-
// Canonical id gate at admission (2026-08-16): non-canonical ids were
|
|
1508
|
-
// accepted here (validateNewTaskId only warns) and every downstream
|
|
1509
|
-
// advance/import then flailed on the malformed task directory. Fail
|
|
1510
|
-
// fast with a concrete suggested id instead.
|
|
1511
|
-
if (!CANONICAL_TASK_ID_PATTERN.test(taskId)) {
|
|
1512
|
-
const slug = taskId
|
|
1513
|
-
.toLowerCase()
|
|
1514
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
1515
|
-
.replace(/^-+|-+$/g, "")
|
|
1516
|
-
.slice(0, 48);
|
|
1517
|
-
const suggested = slug && !GENERIC_SLUG_SET.has(slug)
|
|
1518
|
-
? `${formatLocalBusinessDate()}-${slug}`
|
|
1519
|
-
: `${formatLocalBusinessDate()}-${slug || "task"}-r2`;
|
|
1520
|
-
return invalid(action, `taskId must be canonical YYYY-MM-DD-<kebab-slug> (local business date); got "${taskId}" — suggested id: "${suggested}" (e.g. 2026-08-16-tool-preview-edge-test); retry newTask with that id`);
|
|
1521
|
-
}
|
|
1522
1352
|
return acceptOperation(ctx, {
|
|
1523
1353
|
action,
|
|
1524
1354
|
actionParams: p,
|
|
@@ -1527,38 +1357,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1527
1357
|
cliArgs: ["task", "advance", taskId, title, "--json"],
|
|
1528
1358
|
});
|
|
1529
1359
|
}
|
|
1530
|
-
case "taskAdvance": {
|
|
1531
|
-
const taskId = str(p.taskId);
|
|
1532
|
-
const clientRequestId = str(req.clientRequestId);
|
|
1533
|
-
if (!taskId || !clientRequestId) {
|
|
1534
|
-
return invalid(action, "taskId and clientRequestId are required");
|
|
1535
|
-
}
|
|
1536
|
-
const taskIdError = taskIdInputError(taskId);
|
|
1537
|
-
if (taskIdError)
|
|
1538
|
-
return invalid(action, taskIdError);
|
|
1539
|
-
const args = ["task", "advance", taskId];
|
|
1540
|
-
const title = str(p.title);
|
|
1541
|
-
if (title)
|
|
1542
|
-
args.push(title);
|
|
1543
|
-
const taskKind = str(p.taskKind);
|
|
1544
|
-
if (taskKind)
|
|
1545
|
-
args.push("--task-kind", taskKind);
|
|
1546
|
-
const featureId = str(p.featureId);
|
|
1547
|
-
if (featureId)
|
|
1548
|
-
args.push("--feature-id", featureId);
|
|
1549
|
-
const profile = str(p.profile);
|
|
1550
|
-
if (profile)
|
|
1551
|
-
args.push("--profile", profile);
|
|
1552
|
-
appendEngineeringCliArgs(args, parseEngineeringBoundaryFromParams(p));
|
|
1553
|
-
args.push("--json");
|
|
1554
|
-
return acceptOperation(ctx, {
|
|
1555
|
-
action,
|
|
1556
|
-
actionParams: p,
|
|
1557
|
-
clientRequestId,
|
|
1558
|
-
taskId,
|
|
1559
|
-
cliArgs: args,
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
1360
|
case "bootstrapFromPrd":
|
|
1563
1361
|
return dispatchBootstrapFromPrd(ctx, p);
|
|
1564
1362
|
case "importPrd": {
|
|
@@ -1569,9 +1367,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1569
1367
|
if (!taskId || !content) {
|
|
1570
1368
|
return invalid(action, "taskId and content are required");
|
|
1571
1369
|
}
|
|
1572
|
-
const taskIdError = taskIdInputError(taskId);
|
|
1573
|
-
if (taskIdError)
|
|
1574
|
-
return invalid(action, taskIdError);
|
|
1575
1370
|
const taskKindRaw = str(p.taskKind)?.trim();
|
|
1576
1371
|
const taskKind = normalizeConsoleWorkflowKind(taskKindRaw, "standard");
|
|
1577
1372
|
const taskKindExplicit = Boolean(taskKindRaw);
|
|
@@ -1625,7 +1420,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1625
1420
|
cwd: ctx.repoRoot,
|
|
1626
1421
|
artifactName: "import-prd-task-advance-intake",
|
|
1627
1422
|
expectJson: true,
|
|
1628
|
-
timeoutMs:
|
|
1423
|
+
timeoutMs: 300_000,
|
|
1629
1424
|
});
|
|
1630
1425
|
const intakeJson = intake.json ?? null;
|
|
1631
1426
|
const intakeOk = intake.ok && intake.exitCode === 0 && !intake.timedOut;
|
|
@@ -1766,9 +1561,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1766
1561
|
if (!taskId || !clientRequestId) {
|
|
1767
1562
|
return invalid(action, "taskId and clientRequestId are required");
|
|
1768
1563
|
}
|
|
1769
|
-
const taskIdError = taskIdInputError(taskId);
|
|
1770
|
-
if (taskIdError)
|
|
1771
|
-
return invalid(action, taskIdError);
|
|
1772
1564
|
const out = await stageUtf8Text(ctx.appData, "", { extension: ".json" });
|
|
1773
1565
|
return acceptOperation(ctx, {
|
|
1774
1566
|
action,
|
|
@@ -2051,99 +1843,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2051
1843
|
],
|
|
2052
1844
|
});
|
|
2053
1845
|
}
|
|
2054
|
-
case "dagInterruptEligibility": {
|
|
2055
|
-
const runId = str(p.runId) ?? str(p.dagRunId);
|
|
2056
|
-
if (!runId)
|
|
2057
|
-
return invalid(action, "runId is required");
|
|
2058
|
-
const eligibility = await evaluateConsoleDagInterruptEligibility({
|
|
2059
|
-
repoRoot: ctx.repoRoot,
|
|
2060
|
-
operations: ctx.operations,
|
|
2061
|
-
runId,
|
|
2062
|
-
});
|
|
2063
|
-
if (eligibility.interrupt && eligibility.targetOperationId) {
|
|
2064
|
-
await syncTargetInterruptProjection({
|
|
2065
|
-
operations: ctx.operations,
|
|
2066
|
-
events: ctx.events,
|
|
2067
|
-
operationId: eligibility.targetOperationId,
|
|
2068
|
-
runId,
|
|
2069
|
-
interrupt: eligibility.interrupt,
|
|
2070
|
-
});
|
|
2071
|
-
}
|
|
2072
|
-
return {
|
|
2073
|
-
kind: "sync",
|
|
2074
|
-
status: 200,
|
|
2075
|
-
body: operatorSucceeded(action, eligibility),
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
case "dagRequestInterrupt": {
|
|
2079
|
-
const runId = str(p.runId);
|
|
2080
|
-
const reasonCode = str(p.reasonCode);
|
|
2081
|
-
const reasonDetail = str(p.reasonDetail) ?? str(p.reason);
|
|
2082
|
-
const clientRequestId = str(req.clientRequestId);
|
|
2083
|
-
if (!runId || !reasonCode || !reasonDetail || !clientRequestId) {
|
|
2084
|
-
return invalid(action, "runId, reasonCode, reasonDetail, and clientRequestId are required");
|
|
2085
|
-
}
|
|
2086
|
-
if (!isInterruptReasonCode(reasonCode)) {
|
|
2087
|
-
return invalid(action, `reasonCode must be one of requirements-changed | suspected-runaway | resource-protection | operator-request | other`);
|
|
2088
|
-
}
|
|
2089
|
-
try {
|
|
2090
|
-
normalizeInterruptReasonDetail(reasonDetail);
|
|
2091
|
-
}
|
|
2092
|
-
catch (error) {
|
|
2093
|
-
return invalid(action, error instanceof Error ? error.message : String(error));
|
|
2094
|
-
}
|
|
2095
|
-
const gated = await consumeMutationGateReceipt(ctx, action, p);
|
|
2096
|
-
if (gated.kind === "error")
|
|
2097
|
-
return gated;
|
|
2098
|
-
if (gated.kind === "idempotent")
|
|
2099
|
-
return gated.result;
|
|
2100
|
-
const eligibility = await evaluateConsoleDagInterruptEligibility({
|
|
2101
|
-
repoRoot: ctx.repoRoot,
|
|
2102
|
-
operations: ctx.operations,
|
|
2103
|
-
runId,
|
|
2104
|
-
});
|
|
2105
|
-
if (!eligibility.eligible || !eligibility.targetOperationId || !eligibility.expectedRunnerIdentity) {
|
|
2106
|
-
const failed = interruptActionFailed(action, eligibility.reasonCodes[0] ?? "RUN_NOT_ACTIVE", eligibility.message);
|
|
2107
|
-
return failed;
|
|
2108
|
-
}
|
|
2109
|
-
const expected = eligibility.expectedRunnerIdentity;
|
|
2110
|
-
const accepted = await acceptOperation(ctx, {
|
|
2111
|
-
action,
|
|
2112
|
-
actionParams: {
|
|
2113
|
-
runId,
|
|
2114
|
-
reasonCode,
|
|
2115
|
-
reasonDetail,
|
|
2116
|
-
targetOperationId: eligibility.targetOperationId,
|
|
2117
|
-
expectedRunnerIdentity: expected,
|
|
2118
|
-
},
|
|
2119
|
-
clientRequestId,
|
|
2120
|
-
cliArgs: [
|
|
2121
|
-
"dag",
|
|
2122
|
-
"request-interrupt",
|
|
2123
|
-
"--run-id",
|
|
2124
|
-
runId,
|
|
2125
|
-
"--request-id",
|
|
2126
|
-
clientRequestId,
|
|
2127
|
-
"--target-operation-id",
|
|
2128
|
-
eligibility.targetOperationId,
|
|
2129
|
-
"--reason-code",
|
|
2130
|
-
reasonCode,
|
|
2131
|
-
"--reason",
|
|
2132
|
-
reasonDetail,
|
|
2133
|
-
"--expected-runner-pid",
|
|
2134
|
-
String(expected.pid),
|
|
2135
|
-
"--expected-runner-hostname",
|
|
2136
|
-
expected.hostname,
|
|
2137
|
-
"--expected-runner-started-at",
|
|
2138
|
-
expected.startedAt,
|
|
2139
|
-
"--expected-controller-fingerprint",
|
|
2140
|
-
expected.controllerFingerprint,
|
|
2141
|
-
"--json",
|
|
2142
|
-
],
|
|
2143
|
-
});
|
|
2144
|
-
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
2145
|
-
return accepted;
|
|
2146
|
-
}
|
|
2147
1846
|
case "dagReconcileRun": {
|
|
2148
1847
|
// S6 Recovery: orphan/interrupted runs — structured reason is the human
|
|
2149
1848
|
// confirmation surface (CLI eligibility still fail-closed).
|
|
@@ -2437,7 +2136,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2437
2136
|
return invalid(action, "action and actionParams are required");
|
|
2438
2137
|
}
|
|
2439
2138
|
if (!MUTATION_GATE_ACTIONS.has(targetAction)) {
|
|
2440
|
-
return invalid(action, "action must be a mutation-gate target (dagReconcileRun |
|
|
2139
|
+
return invalid(action, "action must be a mutation-gate target (dagReconcileRun | workerAdmissionPrepare | workerSchedulerAdd | workerSchedulerCancel | workerSchedulerHarvest | workerSchedulerDiscard)");
|
|
2441
2140
|
}
|
|
2442
2141
|
const secret = ctx.humanGateSecret;
|
|
2443
2142
|
if (!secret) {
|
|
@@ -2496,14 +2195,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2496
2195
|
rawArgs.some((value) => typeof value !== "string"))) {
|
|
2497
2196
|
return invalid(action, "args must be an array of strings");
|
|
2498
2197
|
}
|
|
2499
|
-
if (TASK_ADVANCE_ALIAS_ACTIONS.has(action) && Array.isArray(rawArgs)) {
|
|
2500
|
-
const aliasTaskId = str(rawArgs[0]);
|
|
2501
|
-
const taskIdError = aliasTaskId
|
|
2502
|
-
? taskIdInputError(aliasTaskId)
|
|
2503
|
-
: undefined;
|
|
2504
|
-
if (taskIdError)
|
|
2505
|
-
return invalid(action, taskIdError);
|
|
2506
|
-
}
|
|
2507
2198
|
if (capability.humanConfirmation === "required") {
|
|
2508
2199
|
const confirmationId = str(p.confirmationId);
|
|
2509
2200
|
if (!confirmationId)
|
|
@@ -2583,9 +2274,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2583
2274
|
.replace(/^(loop-agent|agent-worker)\s+/, "")
|
|
2584
2275
|
.split(/\s+/);
|
|
2585
2276
|
const args = [...prefix, ...(rawArgs ?? [])];
|
|
2586
|
-
if (TASK_ADVANCE_ALIAS_ACTIONS.has(action) && !args.includes("--json")) {
|
|
2587
|
-
args.push("--json");
|
|
2588
|
-
}
|
|
2589
2277
|
if (capability.kind === "read") {
|
|
2590
2278
|
if (!args.includes("--json"))
|
|
2591
2279
|
args.push("--json");
|
|
@@ -3008,7 +2696,7 @@ async function dispatchBootstrapFromPrd(ctx, p) {
|
|
|
3008
2696
|
cwd: ctx.repoRoot,
|
|
3009
2697
|
artifactName: "bootstrap-task-advance-intake",
|
|
3010
2698
|
expectJson: true,
|
|
3011
|
-
timeoutMs:
|
|
2699
|
+
timeoutMs: 300_000,
|
|
3012
2700
|
});
|
|
3013
2701
|
const intakeJson = intake.json ?? null;
|
|
3014
2702
|
const intakeOk = intake.ok && intake.exitCode === 0 && !intake.timedOut;
|
|
@@ -3482,71 +3170,6 @@ function invalid(action, message) {
|
|
|
3482
3170
|
}),
|
|
3483
3171
|
};
|
|
3484
3172
|
}
|
|
3485
|
-
function interruptActionFailed(action, code, message) {
|
|
3486
|
-
const blocked = code === "INTERRUPT_ALREADY_PENDING" ||
|
|
3487
|
-
code === "INTERRUPT_NEEDS_RECONCILE" ||
|
|
3488
|
-
code === "RUN_ALREADY_TERMINAL" ||
|
|
3489
|
-
code === "RUN_NOT_CONSOLE_OWNED" ||
|
|
3490
|
-
code === "RUNNER_IDENTITY_MISMATCH" ||
|
|
3491
|
-
code === "RUN_NOT_ACTIVE";
|
|
3492
|
-
return {
|
|
3493
|
-
kind: "error",
|
|
3494
|
-
status: code === "INVALID_INPUT" ? 400 : 409,
|
|
3495
|
-
body: operatorFailed({
|
|
3496
|
-
command: action,
|
|
3497
|
-
outcome: blocked ? "blocked" : "invalid",
|
|
3498
|
-
code,
|
|
3499
|
-
message: message || INTERRUPT_ERROR_MESSAGES[code] || message,
|
|
3500
|
-
}),
|
|
3501
|
-
};
|
|
3502
|
-
}
|
|
3503
|
-
async function syncTargetInterruptProjection(input) {
|
|
3504
|
-
const current = await input.operations.get(input.operationId);
|
|
3505
|
-
if (!current)
|
|
3506
|
-
return false;
|
|
3507
|
-
if (current.interrupt?.status === input.interrupt.status &&
|
|
3508
|
-
current.interrupt?.requestId === input.interrupt.requestId) {
|
|
3509
|
-
return false;
|
|
3510
|
-
}
|
|
3511
|
-
const nextStatus = input.interrupt.status;
|
|
3512
|
-
if (nextStatus !== "requested" &&
|
|
3513
|
-
nextStatus !== "acknowledged" &&
|
|
3514
|
-
nextStatus !== "settled" &&
|
|
3515
|
-
nextStatus !== "needs-reconcile") {
|
|
3516
|
-
return false;
|
|
3517
|
-
}
|
|
3518
|
-
await input.operations.update(input.operationId, {
|
|
3519
|
-
dagRunId: current.dagRunId ?? input.runId,
|
|
3520
|
-
interrupt: {
|
|
3521
|
-
status: nextStatus,
|
|
3522
|
-
...(input.interrupt.requestId
|
|
3523
|
-
? { requestId: input.interrupt.requestId }
|
|
3524
|
-
: {}),
|
|
3525
|
-
...(input.interrupt.reasonCode
|
|
3526
|
-
? { reasonCode: input.interrupt.reasonCode }
|
|
3527
|
-
: {}),
|
|
3528
|
-
...(input.interrupt.requestedAt
|
|
3529
|
-
? { requestedAt: input.interrupt.requestedAt }
|
|
3530
|
-
: {}),
|
|
3531
|
-
...(input.interrupt.acknowledgedAt
|
|
3532
|
-
? { acknowledgedAt: input.interrupt.acknowledgedAt }
|
|
3533
|
-
: {}),
|
|
3534
|
-
...(input.interrupt.settledAt
|
|
3535
|
-
? { settledAt: input.interrupt.settledAt }
|
|
3536
|
-
: {}),
|
|
3537
|
-
...(input.interrupt.outcome ? { outcome: input.interrupt.outcome } : {}),
|
|
3538
|
-
},
|
|
3539
|
-
});
|
|
3540
|
-
input.events.append(input.operationId, {
|
|
3541
|
-
kind: "state",
|
|
3542
|
-
message: `interrupt ${nextStatus}`,
|
|
3543
|
-
data: {
|
|
3544
|
-
interruptStatus: nextStatus,
|
|
3545
|
-
runId: input.runId,
|
|
3546
|
-
},
|
|
3547
|
-
});
|
|
3548
|
-
return true;
|
|
3549
|
-
}
|
|
3550
3173
|
function confirmationErrorStatus(code) {
|
|
3551
3174
|
if (code === "NOT_FOUND")
|
|
3552
3175
|
return 404;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { rewriteRecoveryOperatorError } from "./recovery-error-copy.js";
|
|
2
1
|
/** Map internal spawn/controller errors to actionable Chinese copy. */
|
|
3
2
|
export function formatOperatorUserError(message) {
|
|
4
3
|
const raw = (message ?? "").trim();
|
|
5
4
|
if (!raw)
|
|
6
5
|
return "操作失败";
|
|
7
|
-
const recovery = rewriteRecoveryOperatorError(raw);
|
|
8
|
-
if (recovery)
|
|
9
|
-
return recovery;
|
|
10
6
|
if (/controller identity changed|package fingerprint changed|entry binary sha256 changed/i.test(raw)) {
|
|
11
7
|
return "控制器版本已变更(Console 启动后代码被重新编译)。请重启 Console 后再试,一次会话中途不要升级/重建控制器。";
|
|
12
8
|
}
|