@tea-agent/loop-agent 0.39.0-beta.4 → 0.39.0-beta.6

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 (116) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/executors/dag-pi-executor.js +167 -31
  4. package/dist/executors/pi-playwright-cli-tool.js +23 -16
  5. package/dist/executors/shell-executor.js +25 -8
  6. package/dist/shared/dag-failure-category.js +138 -0
  7. package/dist/task/config-types.js +6 -0
  8. package/dist/task/source-references.js +22 -1
  9. package/dist/worker/console/chat/operation-card.js +8 -1
  10. package/dist/worker/console/chat/routes.js +5 -3
  11. package/dist/worker/console/inspect-split.js +18 -0
  12. package/dist/worker/console/operation-run-facts.js +19 -3
  13. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-zsNyvGaH.js → abnfDiagram-N423BO3Z-CfDSkLtp.js} +1 -1
  14. package/dist/worker/console/static/assets/{arc-BDjZ5kE1.js → arc-BlefM6I5.js} +1 -1
  15. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BkgaujnN.js → architectureDiagram-T3A2C74G-C4tHfzHn.js} +1 -1
  16. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CqxOJi0j.js → blockDiagram-VBNYF7ZC-G-G77Rh1.js} +1 -1
  17. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-C2JHLdRi.js → c4Diagram-5PPSVZJV-DWgxmY72.js} +1 -1
  18. package/dist/worker/console/static/assets/channel-DsdX3ZUX.js +1 -0
  19. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DF_YSvOS.js → chunk-2GRJ4B5K-CJQcfbCY.js} +1 -1
  20. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-D3Ort5Vo.js → chunk-2Q5K7J3B-vUPviH9y.js} +1 -1
  21. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-XfAfZeUC.js → chunk-5RXB4S5H-DzRXSTeh.js} +1 -1
  22. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-SLBibhf5.js → chunk-5VM5RSS4-CWfgqm07.js} +1 -1
  23. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Dz29Ye_f.js → chunk-6Q2QTUOP-BtTDauXA.js} +1 -1
  24. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-DB2G4H8V.js → chunk-GF5L2VYU-Bc-NNt84.js} +1 -1
  25. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CIoGkxdu.js → chunk-JWPE2WC7-B_f-emL4.js} +1 -1
  26. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CG78FGkn.js → chunk-KBJHAD2P-DV-jgJ66.js} +1 -1
  27. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-ZDHAvXPd.js → chunk-RYQCIY6F-DMqzn4RZ.js} +1 -1
  28. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BKkkC4VA.js → chunk-XXDRQBXY-CVNtlAm4.js} +1 -1
  29. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CrvCyJ-8.js +1 -0
  30. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CrvCyJ-8.js +1 -0
  31. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-SposUZsO.js → cose-bilkent-JH36ORCC-BBZBhVTd.js} +1 -1
  32. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BSCtQpD7.js → cynefin-VYW2F7L2-DbMU2PZ2.js} +1 -1
  33. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DgFHrw9l.js → cynefinDiagram-MW4NZA55-Dj0v8rjc.js} +1 -1
  34. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BVBasYbj.js → dagre-VZM6K2ZE-BW8R4WvJ.js} +1 -1
  35. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-6r_4rN_c.js → diagram-7IWD3JNH-DEgWz3ld.js} +1 -1
  36. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-JmuaB41P.js → diagram-B4RE2ZJO-BAA01rlR.js} +1 -1
  37. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-xXvAY3sk.js → diagram-LBJQPF4R-Cau6qqpW.js} +1 -1
  38. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D2B3lY2o.js → diagram-Q27KOJAE-8HiPsLos.js} +1 -1
  39. package/dist/worker/console/static/assets/{diagram-UB23O5K3-tK54tMEX.js → diagram-UB23O5K3-CmkXuTYL.js} +1 -1
  40. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CNtELzV-.js → ebnfDiagram-BXEA7PRR-DCV_0seW.js} +1 -1
  41. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-C1xKMKcW.js → erDiagram-JOGREHBK-gckfWESj.js} +1 -1
  42. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CZ7dlPMz.js → flowDiagram-UKHOOZJN-D2mT2BUu.js} +1 -1
  43. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BqGb42Xe.js → ganttDiagram-PKOTCBZU-B_HR5qEw.js} +1 -1
  44. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-D_BlXEtt.js → gitGraphDiagram-DS77QQ5N-BUw4fpSa.js} +1 -1
  45. package/dist/worker/console/static/assets/{index-D5zGX6fG.js → index-DPbsruV5.js} +81 -79
  46. package/dist/worker/console/static/assets/index-DwOGauxU.css +1 -0
  47. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Vce2vmIe.js → infoDiagram-6WML65LV-BSRAqEj0.js} +1 -1
  48. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DDwVBAvI.js → ishikawaDiagram-WSZJBQD7-CLxE8hUp.js} +1 -1
  49. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-y_Ew-wv4.js → journeyDiagram-NVQOT4AX-juFzVXIj.js} +1 -1
  50. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CjXJFp1K.js → kanban-definition-27J2QSJJ-CwLHVhOU.js} +1 -1
  51. package/dist/worker/console/static/assets/{linear-1itMst1Q.js → linear-9LfUyPAs.js} +1 -1
  52. package/dist/worker/console/static/assets/{mermaid.core-C-D3ZRUa.js → mermaid.core-TPPHfQbe.js} +5 -5
  53. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-BiYywmZc.js → mindmap-definition-FAOFIHXS-Dn_Z9RxF.js} +1 -1
  54. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-l2fydNWA.js → pegDiagram-VL7TDLO6-CiEMKTgm.js} +1 -1
  55. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-Dz0hNbYW.js → pieDiagram-7S7Q4E2Y-JASaGxjZ.js} +1 -1
  56. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-BujI_mLZ.js → quadrantDiagram-CIZ2JOQS-ChmH0ply.js} +1 -1
  57. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-pWe84beb.js → railroadDiagram-AXF67PYL-CtyM-HGQ.js} +1 -1
  58. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-ByYu2frg.js → requirementDiagram-LRYGKXZP-BN9y_Bvs.js} +1 -1
  59. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-CoPnilFP.js → sankeyDiagram-W5VNT64P-IyS0GQ1-.js} +1 -1
  60. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-1Md2LnS0.js → sequenceDiagram-SI44F4Z6-DjxGXurN.js} +1 -1
  61. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DqqqAoSH.js → sizeCapture-X5ZJPWSS-Cr3Z0S8y.js} +1 -1
  62. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-C4sGkf--.js → stateDiagram-OKZ733FA-BjJFC6pW.js} +1 -1
  63. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Bq44O9Nt.js +1 -0
  64. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-ByxJrUzW.js → swimlanes-SLNWSIFB-DeMUJQiW.js} +2 -2
  65. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BT4tWyW3.js +8 -0
  66. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-D8MLgM0O.js → timeline-definition-Z64GVDOM-Bc2Rv2Oo.js} +1 -1
  67. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DnBis-wZ.js → vennDiagram-T6HMQDX7-CDhRUeqG.js} +1 -1
  68. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-uuyYT7UO.js → wardleyDiagram-T6FBY63Y-DaN_z3Xy.js} +1 -1
  69. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BjgabhwK.js → xychartDiagram-ELKLHX3M-C1vTLBDG.js} +1 -1
  70. package/dist/worker/console/static/index.html +2 -2
  71. package/dist/worker/console/static-src/app/useRecoveryConsole.js +38 -2
  72. package/dist/worker/console/static-src/app/useRunProgress.js +46 -0
  73. package/dist/worker/console/static-src/operator-chat/cards/failure-category-advice.js +25 -0
  74. package/dist/worker/console/static-src/operator-chat/input-history.js +76 -0
  75. package/dist/worker/console/static-src/operator-chat/turn-submission.js +13 -1
  76. package/dist/worker/console/static-src/operator-chat/useChatStream.js +29 -9
  77. package/dist/worker/console/static-src/operator-chat/useComposer.js +32 -0
  78. package/dist/worker/console/static-src/pages/tasks/run-id-resolution.js +79 -0
  79. package/dist/worker/console/static-src/pages/tasks/run-ownership-verify.js +23 -0
  80. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +110 -0
  81. package/dist/worker/materialize/harness-task-lineage.js +5 -2
  82. package/dist/worker/observability/read-model.js +22 -0
  83. package/dist/workflows/dag/dynamic-runtime/loop-until.js +1 -1
  84. package/dist/workflows/dag/dynamic-runtime/map.js +1 -1
  85. package/dist/workflows/dag/failure-category.js +7 -128
  86. package/dist/workflows/dag/frontend-design-policy.js +12 -7
  87. package/dist/workflows/dag/frontend-implementation-contract.js +10 -5
  88. package/dist/workflows/dag/frontend-plan-render.js +0 -3
  89. package/dist/workflows/dag/frontend-shadow-dual-write.js +51 -10
  90. package/dist/workflows/dag/frontend-test-case-checklist.js +4 -2
  91. package/dist/workflows/dag/frontend-test-case-manifest.js +6 -4
  92. package/dist/workflows/dag/frontend-test-case-quality.js +6 -3
  93. package/dist/workflows/dag/frontend-test-environment-probe.js +10 -7
  94. package/dist/workflows/dag/frontend-test-html-report.js +3 -1
  95. package/dist/workflows/dag/frontend-test-l5-report.js +3 -1
  96. package/dist/workflows/dag/frontend-test-layout.js +159 -0
  97. package/dist/workflows/dag/frontend-test-result-contract.js +28 -14
  98. package/dist/workflows/dag/frontend-test-standard-scenarios.js +3 -1
  99. package/dist/workflows/dag/frontend-typed-event-store.js +13 -0
  100. package/dist/workflows/dag/init-hybrid.js +66 -19
  101. package/dist/workflows/dag/node-execution.js +21 -1
  102. package/dist/workflows/dag/retry-policy.js +32 -0
  103. package/dist/workflows/dag/types.js +12 -0
  104. package/dist/workflows/dag/validate.js +23 -19
  105. package/docs/templates/frontend-test-case-checklist.md +2 -2
  106. package/package.json +1 -1
  107. package/skills/fe-test-ui-scout/SKILL.md +4 -4
  108. package/skills/fe-test-ui-scout/references/ledger-schema.md +1 -1
  109. package/skills/playwright-cli/SKILL.md +1 -1
  110. package/skills/playwright-cli-case-generator/SKILL.md +10 -8
  111. package/dist/worker/console/static/assets/channel-BuqaGKAT.js +0 -1
  112. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DNdSHjH9.js +0 -1
  113. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DNdSHjH9.js +0 -1
  114. package/dist/worker/console/static/assets/index-DBbhESQ_.css +0 -1
  115. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8rmop_9.js +0 -1
  116. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B0ky-kBM.js +0 -8
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Pure DAG failure-category classification shared by the workflows kernel and
3
+ * the Operator Console projection (console sources may not import
4
+ * src/workflows — security-and-tools boundary test).
5
+ *
6
+ * No runtime imports: this module is a leaf safe for both the CLI kernel and
7
+ * the browser bundle.
8
+ */
9
+ export const DAG_NORMALIZED_FAILURE_CATEGORY_VALUES = [
10
+ "success",
11
+ "validation",
12
+ "executor",
13
+ "write-guard",
14
+ "timeout",
15
+ "auth",
16
+ "human-required",
17
+ "human-rejected",
18
+ "shell-command",
19
+ "static-error",
20
+ "decision-envelope",
21
+ "skipped",
22
+ "unknown",
23
+ ];
24
+ const RAW_TO_NORMALIZED = {
25
+ success: "success",
26
+ "write-guard": "write-guard",
27
+ timeout: "timeout",
28
+ // Clean implementer stall with zero writes — still a timeout class for report,
29
+ // but retryable under WRITER_TRANSPORT_RETRY_POLICY.
30
+ "writer-clean-timeout": "timeout",
31
+ "missing-api-key": "auth",
32
+ auth: "auth",
33
+ "human-rejected": "human-rejected",
34
+ "human-required": "human-required",
35
+ "decision-envelope-invalid": "decision-envelope",
36
+ "nonzero-exit": "shell-command",
37
+ "spawn-error": "shell-command",
38
+ "test-timeout": "timeout",
39
+ "static-error": "static-error",
40
+ "invalid-output": "validation",
41
+ "structured-output-truncated": "validation",
42
+ "output-too-large": "validation",
43
+ "structured-repair-exhausted": "validation",
44
+ "governance-blocked": "validation",
45
+ "path-violation": "validation",
46
+ "empty-output": "validation",
47
+ "verify-failure": "validation",
48
+ "test-failure": "validation",
49
+ "verification-plan-stale": "validation",
50
+ network: "executor",
51
+ quota: "executor",
52
+ "rate-limit": "executor",
53
+ unavailable: "executor",
54
+ // Deterministic capability/policy refusal: missing verified launcher JS
55
+ // entry, capability allowlist rejection, or missing bounded write tool
56
+ // profile. These are environment/config defects the operator repairs
57
+ // before rerunning; classify as executor so recovery recommends
58
+ // rerun-after-fix WITHOUT forcing a human-decision gate on
59
+ // standaloneTaskRerun (run-failed same-task rerun).
60
+ "tool-policy": "executor",
61
+ unknown: "unknown",
62
+ };
63
+ /** Status inputs are deliberately `string`: projection layers pass bounded
64
+ * text from CLI JSON; unmatched values simply fall through to unknown. */
65
+ function isFinishedStatus(status) {
66
+ return status === "FINISHED" || status === "finished";
67
+ }
68
+ function isInProgressStatus(status) {
69
+ return (status === "PENDING" ||
70
+ status === "RUNNING" ||
71
+ status === "pending" ||
72
+ status === "running");
73
+ }
74
+ function isFailureStatus(status) {
75
+ return (status === "ERROR" ||
76
+ status === "failed" ||
77
+ status === "partial_failed");
78
+ }
79
+ function mapRawCategory(raw) {
80
+ const direct = RAW_TO_NORMALIZED[raw];
81
+ if (direct)
82
+ return direct;
83
+ const lower = raw.toLowerCase();
84
+ if (lower.includes("timeout"))
85
+ return "timeout";
86
+ if (lower.includes("validation") ||
87
+ lower.includes("invalid") ||
88
+ lower.includes("verification-plan-stale") ||
89
+ lower.includes("plan-stale"))
90
+ return "validation";
91
+ if (lower.includes("auth") || lower.includes("api-key"))
92
+ return "auth";
93
+ if (lower.includes("write-guard") || lower.includes("write_guard"))
94
+ return "write-guard";
95
+ if (lower.includes("decision-envelope") || lower.includes("decision_envelope"))
96
+ return "decision-envelope";
97
+ if (lower.includes("human-rejected"))
98
+ return "human-rejected";
99
+ if (lower.includes("human-required"))
100
+ return "human-required";
101
+ if (lower.includes("static-error"))
102
+ return "static-error";
103
+ if (lower.includes("nonzero-exit") ||
104
+ lower.includes("spawn-error") ||
105
+ lower.includes("shell"))
106
+ return "shell-command";
107
+ return undefined;
108
+ }
109
+ export function isDagFailureCategory(value) {
110
+ return DAG_NORMALIZED_FAILURE_CATEGORY_VALUES.includes(value);
111
+ }
112
+ export function normalizeDagFailureCategory(raw, status) {
113
+ if (status === "SKIPPED") {
114
+ return "skipped";
115
+ }
116
+ if (raw !== undefined) {
117
+ const mapped = mapRawCategory(raw);
118
+ if (mapped) {
119
+ if (mapped === "success") {
120
+ return isFinishedStatus(status) ? "success" : "unknown";
121
+ }
122
+ return mapped;
123
+ }
124
+ }
125
+ if (raw === undefined && isFinishedStatus(status)) {
126
+ return "success";
127
+ }
128
+ if (isInProgressStatus(status)) {
129
+ return "unknown";
130
+ }
131
+ if (isFailureStatus(status)) {
132
+ return "unknown";
133
+ }
134
+ if (raw === "success" && isFinishedStatus(status)) {
135
+ return "success";
136
+ }
137
+ return "unknown";
138
+ }
@@ -101,6 +101,12 @@ export const frontendOpenspecConfigSchema = z.object({
101
101
  /** Batch limits and gate profile for the browser-driven frontend test DAG.
102
102
  * Token fields are post-case stop thresholds, not model-provider hard caps. */
103
103
  export const frontendTestConfigSchema = z.object({
104
+ /**
105
+ * Repository-relative frontend-test artifact root.
106
+ * Default "testcase/frontend". Semantic validation lives in
107
+ * resolveFrontendTestLayout (fail-closed), not in this schema.
108
+ */
109
+ testRoot: z.string().min(1).optional(),
104
110
  maxCasesPerBatch: z.number().int().min(1).max(50).optional(),
105
111
  maxTokensPerCase: z.number().int().positive().optional(),
106
112
  maxTotalTokens: z.number().int().positive().optional(),
@@ -22,6 +22,18 @@ function slugifyName(value) {
22
22
  .replace(/-{2,}/g, "-");
23
23
  return slug || "requirement";
24
24
  }
25
+ /** Stable identity of a manifest document for change detection. Timestamps and
26
+ * byte sizes are excluded: identical content re-imported later must not appear
27
+ * "changed" (the canonical hash includes manifest bytes). */
28
+ function documentIdentity(doc) {
29
+ return `${doc.role}|${doc.name}|${doc.materializedPath}|${doc.sha256}`;
30
+ }
31
+ function sameDocumentSet(left, right) {
32
+ if (left.length !== right.length)
33
+ return false;
34
+ const rightIds = new Set(right.map(documentIdentity));
35
+ return left.every((doc) => rightIds.has(documentIdentity(doc)));
36
+ }
25
37
  function ensureUniqueReferenceName(existing, baseName, extension) {
26
38
  const used = new Set(existing);
27
39
  const candidate = `${baseName}${extension}`;
@@ -149,10 +161,19 @@ export async function importPrdDocument(input) {
149
161
  const documents = [...(existingManifest?.documents ?? [])].filter((entry) => entry.materializedPath !== materializedRelativePath);
150
162
  documents.push(document);
151
163
  documents.sort((left, right) => left.materializedPath.localeCompare(right.materializedPath));
164
+ // Keep `updatedAt` stable across re-imports of the same content: the
165
+ // canonical contract hash includes the manifest bytes, so a fresh
166
+ // timestamp on every identical re-import would make the observed
167
+ // canonical hash drift and fail task verification. Only bump it when the
168
+ // document set actually changed (a new/changed materialized file).
169
+ const documentSetChanged = !existingManifest ||
170
+ !sameDocumentSet(existingManifest.documents, documents);
152
171
  const manifest = {
153
172
  schemaVersion: 1,
154
173
  taskId: input.taskId,
155
- updatedAt: importedAt,
174
+ updatedAt: documentSetChanged
175
+ ? importedAt
176
+ : (existingManifest?.updatedAt ?? importedAt),
156
177
  documents,
157
178
  };
158
179
  await writeSourceManifest(paths.sourceDir, manifest);
@@ -64,7 +64,14 @@ function safeRunSummary(value) {
64
64
  const status = String(node.status ?? "");
65
65
  if (!id || !status)
66
66
  return [];
67
- return [{ id, status }];
67
+ const failureCategory = String(node.failureCategory ?? "");
68
+ return [
69
+ {
70
+ id,
71
+ status,
72
+ ...(failureCategory ? { failureCategory } : {}),
73
+ },
74
+ ];
68
75
  })
69
76
  .slice(0, 20);
70
77
  }
@@ -728,13 +728,15 @@ export async function handlePutDeferredTurn(req, res, deps, sessionId) {
728
728
  return;
729
729
  }
730
730
  const active = deps.events.getActiveTurn(sessionId);
731
- if (!active || !active.abortRequestedAt || active.turnId !== blockedByTurnId) {
731
+ // Queueing binds to the active Turn (running OR stopping); the durable
732
+ // follow-up auto-dispatches when that Turn reaches a terminal state.
733
+ if (!active || active.turnId !== blockedByTurnId) {
732
734
  sendJson(res, 409, {
733
735
  ok: false,
734
736
  accepted: false,
735
737
  error: {
736
- code: "TURN_NOT_STOPPING",
737
- message: "只有仍在停止中的当前 Turn 可以保存停止后发送消息",
738
+ code: "TURN_NOT_ACTIVE",
739
+ message: "没有匹配的运行中 Turn,无法保存待发送消息",
738
740
  },
739
741
  activeTurn: active ? turnSummary(active) : null,
740
742
  });
@@ -80,3 +80,21 @@ export function pickInspectNode(nodes, preferredNodeId) {
80
80
  });
81
81
  return running ?? nodes[0];
82
82
  }
83
+ /**
84
+ * Terminal DagRun effective/status values (mirrors observe read-model
85
+ * TERMINAL_RUN_STATUSES). A run that reached one of these states no longer
86
+ * needs live polling in the console split panel.
87
+ */
88
+ export const TERMINAL_DAG_RUN_STATUSES = new Set([
89
+ "finished",
90
+ "failed",
91
+ "partial_failed",
92
+ "superseded",
93
+ "abandoned",
94
+ ]);
95
+ export function isTerminalDagRun(dag) {
96
+ if (!dag)
97
+ return false;
98
+ const status = String(dag.effectiveStatus ?? dag.status ?? "").toLowerCase();
99
+ return TERMINAL_DAG_RUN_STATUSES.has(status);
100
+ }
@@ -13,6 +13,7 @@
13
13
  * - A run summary is a projection only: it can never change the terminal
14
14
  * operation state decided by the command envelope/exit facts.
15
15
  */
16
+ import { normalizeDagFailureCategory } from "../../shared/dag-failure-category.js";
16
17
  import { scrubSecrets } from "./chat/explore-tools.js";
17
18
  const RUN_SUMMARY_MAX_NODES = 20;
18
19
  const RUN_SUMMARY_MAX_TEXT_CHARS = 600;
@@ -72,7 +73,13 @@ function safeNode(value) {
72
73
  const status = boundedRedactedText(rec.status, 100);
73
74
  if (!id || !status)
74
75
  return undefined;
75
- return { id, status };
76
+ const rawCategory = boundedRedactedText(rec.failureCategory, 200);
77
+ if (!rawCategory)
78
+ return { id, status };
79
+ const category = normalizeDagFailureCategory(rawCategory, status);
80
+ if (category === "success" || category === "skipped")
81
+ return { id, status };
82
+ return { id, status, failureCategory: category };
76
83
  }
77
84
  /** Independent allowlist projection of a structured run summary. */
78
85
  export function safeRunSummaryForProjection(value) {
@@ -117,13 +124,22 @@ export function safeRunSummaryForProjection(value) {
117
124
  }
118
125
  }
119
126
  const verdict = boundedRedactedText(rec.verdict);
120
- const failureCategory = boundedRedactedText(rec.failureCategory);
127
+ const rawFailureCategory = boundedRedactedText(rec.failureCategory, 200);
128
+ // Normalize the run-level category too (2026-08-23): raw codes like
129
+ // missing-api-key / nonzero-exit never matched the browser advice table.
130
+ const failureCategory = rawFailureCategory !== undefined
131
+ ? normalizeDagFailureCategory(rawFailureCategory, status)
132
+ : undefined;
121
133
  return {
122
134
  runId,
123
135
  status,
124
136
  nodes,
125
137
  ...(verdict !== undefined ? { verdict } : {}),
126
- ...(failureCategory !== undefined ? { failureCategory } : {}),
138
+ ...(failureCategory !== undefined &&
139
+ failureCategory !== "success" &&
140
+ failureCategory !== "skipped"
141
+ ? { failureCategory }
142
+ : {}),
127
143
  ...(outOfBounds.length > 0 ? { outOfBounds } : {}),
128
144
  ...(next ? { next } : {}),
129
145
  };
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-Dz29Ye_f.js";import{p as f}from"./chunk-JWPE2WC7-CIoGkxdu.js";import{_ as n,l as o}from"./mermaid.core-C-D3ZRUa.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-BSCtQpD7.js";import"./index-D5zGX6fG.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
1
+ import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-BtTDauXA.js";import{p as f}from"./chunk-JWPE2WC7-B_f-emL4.js";import{_ as n,l as o}from"./mermaid.core-TPPHfQbe.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DbMU2PZ2.js";import"./index-DPbsruV5.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
@@ -1 +1 @@
1
- import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-C-D3ZRUa.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
1
+ import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-TPPHfQbe.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};