@tea-agent/loop-agent 0.35.1-beta.0 → 0.35.1-beta.2

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 (179) hide show
  1. package/AGENTS.md +110 -108
  2. package/CHANGELOG.md +24 -26
  3. package/README.md +165 -165
  4. package/bin/agent-worker.js +0 -0
  5. package/bin/loop-agent.js +57 -21
  6. package/dist/application/task-lifecycle/advance.js +0 -1
  7. package/dist/build-stamp.json +6 -0
  8. package/dist/cli/program.js +2 -2
  9. package/dist/commands/cursor-prompt.js +6 -6
  10. package/dist/commands/init-upgrade.js +19 -351
  11. package/dist/commands/init.js +67 -14
  12. package/dist/commands/loop-benchmark.js +11 -11
  13. package/dist/commands/pi-reuse-benchmark.js +16 -16
  14. package/dist/commands/run-dag-progress.js +0 -14
  15. package/dist/commands/task-advance.js +3 -33
  16. package/dist/executors/dag-pi-executor.js +44 -0
  17. package/dist/shared/operator/capabilities.js +1 -38
  18. package/dist/shared/package-metadata.js +42 -0
  19. package/dist/sidecars/cursor-prompt/executor.js +1 -1
  20. package/dist/worker/console/chat/pi-runtime.js +25 -41
  21. package/dist/worker/console/chat/routes.js +4 -27
  22. package/dist/worker/console/operation-runner.js +0 -24
  23. package/dist/worker/console/operator-actions.js +0 -58
  24. package/dist/worker/console/static/assets/index-CvsQgALl.js +56 -0
  25. package/dist/worker/console/static/assets/{index-Dups4sSM.css → index-hJqCPs_g.css} +1 -1
  26. package/dist/worker/console/static/index.html +2 -2
  27. package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -0
  28. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -13
  29. package/dist/worker/console/static-src/operator-chat/useComposer.js +7 -30
  30. package/dist/worker/loop-agent/loop-agent-client.js +17 -3
  31. package/dist/worker/observability/read-model.js +20 -0
  32. package/dist/worker/observe/static/copy.js +67 -67
  33. package/dist/worker/observe/static/dag-layout.d.ts +36 -36
  34. package/dist/worker/observe/static/dom.js +220 -220
  35. package/dist/worker/observe/static/relations.js +133 -133
  36. package/dist/worker/observe/static/run-processing.js +148 -148
  37. package/dist/worker/observe/static/views/batch.js +227 -227
  38. package/dist/worker/observe/static/views/failures.js +143 -143
  39. package/dist/worker/observe/static/views/feature.js +492 -492
  40. package/dist/worker/observe/static/views/run.js +453 -453
  41. package/dist/worker/observe/static/views/shell.js +7 -7
  42. package/dist/worker/observe/static/views/timeline.js +163 -163
  43. package/dist/worker/preflight.js +2 -1
  44. package/dist/workflows/dag/backend-test-scenario-param.js +33 -23
  45. package/dist/workflows/dag/canvas-observer.js +275 -275
  46. package/dist/workflows/dag/contract-output-registry.js +14 -0
  47. package/dist/workflows/dag/contract-validator-registrations.js +8 -0
  48. package/dist/workflows/dag/dynamic-runtime/shared.js +9 -1
  49. package/dist/workflows/dag/frontend-implementation-contract.js +233 -39
  50. package/dist/workflows/dag/frontend-prewrite-gate.js +364 -61
  51. package/dist/workflows/dag/frontend-recovery-plan.js +73 -0
  52. package/dist/workflows/dag/frontend-recovery-root-manifest.js +123 -0
  53. package/dist/workflows/dag/frontend-recovery-run.js +539 -0
  54. package/dist/workflows/dag/frontend-repair.js +219 -18
  55. package/dist/workflows/dag/frontend-verification-trace.js +47 -32
  56. package/dist/workflows/dag/frontend-writer-recovery.js +106 -0
  57. package/dist/workflows/dag/frontend-writer-rollback.js +821 -0
  58. package/dist/workflows/dag/init-hybrid.js +41 -24
  59. package/dist/workflows/dag/node-execution.js +89 -0
  60. package/dist/workflows/dag/recovery-recommendation.js +58 -0
  61. package/dist/workflows/dag/runner.js +245 -11
  62. package/dist/workflows/dag/scheduler.js +257 -3
  63. package/dist/workflows/dag/types.js +130 -2
  64. package/docs/architecture/evolution.md +73 -73
  65. package/docs/architecture/system-overview.md +100 -100
  66. package/docs/architecture/worker-and-feature.md +122 -122
  67. package/docs/skills/README.md +7 -7
  68. package/docs/templates/adr.md +60 -60
  69. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  70. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  71. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  72. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  73. package/docs/templates/agent-dag-report.schema.json +473 -473
  74. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  75. package/docs/templates/backend-test-result.schema.json +99 -99
  76. package/docs/templates/evaluation/agents-map-slim-v1.md +87 -87
  77. package/docs/templates/evaluation/agents-map-verbose-v0.md +153 -153
  78. package/docs/templates/feature-spec.md +53 -53
  79. package/docs/templates/frontend-design-contract.md +42 -42
  80. package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -17
  81. package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -16
  82. package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -16
  83. package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -16
  84. package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -16
  85. package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -16
  86. package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -21
  87. package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -29
  88. package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -28
  89. package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -28
  90. package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -29
  91. package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -27
  92. package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -28
  93. package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -28
  94. package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -27
  95. package/docs/templates/frontend-eval/metrics.md +138 -138
  96. package/docs/templates/frontend-eval/smoke-targets.md +53 -53
  97. package/docs/templates/frontend-task-constraints.md +35 -35
  98. package/docs/templates/frontend-task-requirement.md +70 -70
  99. package/docs/templates/init-evolution-review.md +35 -35
  100. package/docs/templates/init-managed-agents.md +154 -156
  101. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  102. package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
  103. package/docs/templates/knowledge-sync-dag.json +178 -178
  104. package/docs/templates/knowledge-sync-draft.schema.json +71 -71
  105. package/docs/templates/product-line/closeout.yaml +9 -9
  106. package/docs/templates/product-line/design.md +13 -13
  107. package/docs/templates/product-line/links.md +10 -10
  108. package/docs/templates/product-line/requirement.md +17 -17
  109. package/docs/templates/product-line/test-plan.md +7 -7
  110. package/docs/templates/project-start-checklist.md +9 -9
  111. package/docs/templates/qa-report.md +48 -48
  112. package/docs/templates/sprint-contract.md +29 -29
  113. package/docs/templates/worker-dogfood-evidence.md +80 -80
  114. package/docs/templates/worker-dogfood-setup.md +68 -68
  115. package/harness.json +2 -5
  116. package/package.json +2 -2
  117. package/scripts/kb-bootstrap-init-skeleton.sh +0 -0
  118. package/scripts/kb-graph-incremental-prepare.mjs +0 -0
  119. package/scripts/kb-graph-materialize.mjs +105 -105
  120. package/scripts/kb-graph-promote.mjs +164 -164
  121. package/scripts/kb-query.mjs +554 -554
  122. package/skills/agent-worker/SKILL.md +48 -48
  123. package/skills/agent-worker/references/agent-worker-operator.md +159 -159
  124. package/skills/ai-engineering-context/SKILL.md +48 -48
  125. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +0 -0
  126. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +0 -0
  127. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +0 -0
  128. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +0 -0
  129. package/skills/analyze-product-requirements/scripts/compute-source-identity.mjs +0 -0
  130. package/skills/analyze-product-requirements/scripts/test-validators.mjs +0 -0
  131. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +0 -0
  132. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +0 -0
  133. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +0 -0
  134. package/skills/browser-tools/browser-content.js +103 -103
  135. package/skills/browser-tools/browser-cookies.js +35 -35
  136. package/skills/browser-tools/browser-eval.js +53 -53
  137. package/skills/browser-tools/browser-hn-scraper.js +108 -108
  138. package/skills/browser-tools/browser-nav.js +44 -44
  139. package/skills/browser-tools/browser-pick.js +162 -162
  140. package/skills/browser-tools/browser-screenshot.js +34 -34
  141. package/skills/browser-tools/browser-start.js +86 -86
  142. package/skills/browser-tools/package-lock.json +2556 -2556
  143. package/skills/browser-tools/package.json +19 -19
  144. package/skills/code-review-core/SKILL.md +20 -20
  145. package/skills/codebase-scout/SKILL.md +19 -19
  146. package/skills/grill-me/SKILL.md +10 -10
  147. package/skills/local-jacoco-coverage/scripts/run-coverage-analysis.sh +0 -0
  148. package/skills/local-jacoco-coverage/scripts/start-jacoco-agent.sh +0 -0
  149. package/skills/loop-agent/SKILL.md +0 -1
  150. package/skills/loop-agent/references/command-reference.md +639 -641
  151. package/skills/loop-agent/references/docs-converge.md +126 -126
  152. package/skills/loop-agent/references/learned/README.md +21 -21
  153. package/skills/loop-agent/references/pi-prompt.md +23 -23
  154. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
  155. package/skills/playwright-cli/references/element-attributes.md +23 -23
  156. package/skills/playwright-cli/references/playwright-tests.md +39 -39
  157. package/skills/playwright-cli/references/request-mocking.md +87 -87
  158. package/skills/playwright-cli/references/running-code.md +241 -241
  159. package/skills/playwright-cli/references/session-management.md +225 -225
  160. package/skills/playwright-cli/references/storage-state.md +275 -275
  161. package/skills/playwright-cli/references/test-generation.md +433 -433
  162. package/skills/requesting-code-review/SKILL.md +101 -101
  163. package/skills/requesting-code-review/code-reviewer.md +168 -168
  164. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  165. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  166. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  167. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  168. package/skills/systematic-debugging/find-polluter.sh +63 -63
  169. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  170. package/skills/systematic-debugging/test-academic.md +14 -14
  171. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  172. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  173. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  174. package/skills/using-git-worktrees/SKILL.md +215 -215
  175. package/skills/verification-before-completion/SKILL.md +154 -154
  176. package/skills/webapp-testing/SKILL.md +19 -19
  177. package/dist/worker/console/operation-wait.js +0 -241
  178. package/dist/worker/console/static/assets/index-SjjjZnV3.js +0 -56
  179. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
@@ -1,133 +1,133 @@
1
- /** Object relation navigation (Observe UI R5). */
2
- import { el } from "./dom.js";
3
- import { navigate } from "./router.js";
4
-
5
- export function objectExistsInSnapshot(kind, id, snapshot, featureId) {
6
- if (!id) return false;
7
- if (kind === "feature") {
8
- return (snapshot?.features ?? []).some((f) => f.featureId === id);
9
- }
10
- if (kind === "task") {
11
- return (snapshot?.tasks ?? []).some(
12
- (t) => t.taskId === id && (!featureId || t.featureId === featureId),
13
- );
14
- }
15
- if (kind === "batch") {
16
- return (snapshot?.batches ?? []).some((b) => b.batchRunId === id);
17
- }
18
- if (kind === "run") {
19
- return (
20
- (snapshot?.tasks ?? []).some((t) => t.workerRunId === id) ||
21
- (snapshot?.batches ?? []).some((b) =>
22
- (b.tasks ?? []).some((t) => t.workerRunId === id),
23
- )
24
- );
25
- }
26
- if (kind === "dag") {
27
- return (snapshot?.dagRuns ?? []).some((d) => d.dagRunId === id);
28
- }
29
- return false;
30
- }
31
-
32
- export function objectRoutePath(kind, id, featureId) {
33
- if (kind === "feature") return `/feature/${encodeURIComponent(id)}`;
34
- if (kind === "task" && featureId) {
35
- return `/feature/${encodeURIComponent(featureId)}/task/${encodeURIComponent(id)}`;
36
- }
37
- if (kind === "task") return `/task/${encodeURIComponent(id)}`;
38
- if (kind === "batch") return `/batch/${encodeURIComponent(id)}`;
39
- if (kind === "run") return `/run/${encodeURIComponent(id)}`;
40
- if (kind === "dag") return `/dag/${encodeURIComponent(id)}`;
41
- return "/";
42
- }
43
-
44
- /** Hash-route link only when id is present and snapshot contains the object. */
45
- export function objectRouteLink(kind, id, snapshot, featureId) {
46
- if (!id) return el("span", "muted", "缺失");
47
- const exists = objectExistsInSnapshot(kind, id, snapshot, featureId);
48
- if (!exists) return el("span", "muted", id);
49
- const path = objectRoutePath(kind, id, featureId);
50
- const a = el("a", "object-link", id);
51
- a.href = `#${path}`;
52
- a.addEventListener("click", (e) => {
53
- e.preventDefault();
54
- e.stopPropagation();
55
- navigate(path);
56
- });
57
- return a;
58
- }
59
-
60
- export function findFeatureInSnapshot(snapshot, featureId) {
61
- if (!featureId) return undefined;
62
- return (snapshot?.features ?? []).find((f) => f.featureId === featureId);
63
- }
64
-
65
- export function featureLookupState(snapshot, featureId) {
66
- if (!snapshot) return { kind: "unavailable" };
67
- const feature = findFeatureInSnapshot(snapshot, featureId);
68
- return feature ? { kind: "found", feature } : { kind: "missing" };
69
- }
70
-
71
- export const RELATION_KIND_ORDER = ["feature", "task", "batch", "run", "dag"];
72
- export const RELATION_LABELS = {
73
- feature: "Feature",
74
- task: "Task",
75
- batch: "Batch",
76
- run: "Run",
77
- dag: "DAG",
78
- };
79
-
80
- /**
81
- * Build proven relation descriptors only (id present AND object in snapshot).
82
- * Never infers links from identifier naming.
83
- */
84
- export function buildObjectRelations(ids, snapshot) {
85
- const input = ids ?? {};
86
- const candidates = [
87
- { kind: "feature", id: input.featureId },
88
- { kind: "task", id: input.taskId, featureId: input.featureId },
89
- { kind: "batch", id: input.batchRunId },
90
- { kind: "run", id: input.workerRunId },
91
- { kind: "dag", id: input.dagRunId },
92
- ];
93
- const out = [];
94
- for (const kind of RELATION_KIND_ORDER) {
95
- const entry = candidates.find((c) => c.kind === kind);
96
- if (!entry?.id) continue;
97
- if (!objectExistsInSnapshot(kind, entry.id, snapshot, entry.featureId)) continue;
98
- out.push({
99
- kind,
100
- id: entry.id,
101
- label: RELATION_LABELS[kind] ?? kind,
102
- featureId: entry.featureId,
103
- href: `#${objectRoutePath(kind, entry.id, entry.featureId)}`,
104
- path: objectRoutePath(kind, entry.id, entry.featureId),
105
- });
106
- }
107
- return out;
108
- }
109
-
110
- export function renderObjectRelationBar(relations, snapshot) {
111
- const bar = el("div", "object-relation-bar");
112
- bar.setAttribute("aria-label", "对象关联");
113
- const list = Array.isArray(relations)
114
- ? relations
115
- : buildObjectRelations(relations, snapshot);
116
- if (list.length === 0) {
117
- bar.appendChild(el("span", "muted", "暂无已证明的对象关联"));
118
- return bar;
119
- }
120
- list.forEach((rel, i) => {
121
- if (i > 0) bar.appendChild(el("span", "object-relation-sep", "→"));
122
- const item = el("span", "object-relation-item");
123
- item.appendChild(el("span", "object-relation-label", rel.label));
124
- item.appendChild(document.createTextNode(" "));
125
- if (rel.href && rel.id) {
126
- item.appendChild(objectRouteLink(rel.kind, rel.id, snapshot, rel.featureId));
127
- } else {
128
- item.appendChild(el("span", "muted", rel.id ?? "缺失"));
129
- }
130
- bar.appendChild(item);
131
- });
132
- return bar;
133
- }
1
+ /** Object relation navigation (Observe UI R5). */
2
+ import { el } from "./dom.js";
3
+ import { navigate } from "./router.js";
4
+
5
+ export function objectExistsInSnapshot(kind, id, snapshot, featureId) {
6
+ if (!id) return false;
7
+ if (kind === "feature") {
8
+ return (snapshot?.features ?? []).some((f) => f.featureId === id);
9
+ }
10
+ if (kind === "task") {
11
+ return (snapshot?.tasks ?? []).some(
12
+ (t) => t.taskId === id && (!featureId || t.featureId === featureId),
13
+ );
14
+ }
15
+ if (kind === "batch") {
16
+ return (snapshot?.batches ?? []).some((b) => b.batchRunId === id);
17
+ }
18
+ if (kind === "run") {
19
+ return (
20
+ (snapshot?.tasks ?? []).some((t) => t.workerRunId === id) ||
21
+ (snapshot?.batches ?? []).some((b) =>
22
+ (b.tasks ?? []).some((t) => t.workerRunId === id),
23
+ )
24
+ );
25
+ }
26
+ if (kind === "dag") {
27
+ return (snapshot?.dagRuns ?? []).some((d) => d.dagRunId === id);
28
+ }
29
+ return false;
30
+ }
31
+
32
+ export function objectRoutePath(kind, id, featureId) {
33
+ if (kind === "feature") return `/feature/${encodeURIComponent(id)}`;
34
+ if (kind === "task" && featureId) {
35
+ return `/feature/${encodeURIComponent(featureId)}/task/${encodeURIComponent(id)}`;
36
+ }
37
+ if (kind === "task") return `/task/${encodeURIComponent(id)}`;
38
+ if (kind === "batch") return `/batch/${encodeURIComponent(id)}`;
39
+ if (kind === "run") return `/run/${encodeURIComponent(id)}`;
40
+ if (kind === "dag") return `/dag/${encodeURIComponent(id)}`;
41
+ return "/";
42
+ }
43
+
44
+ /** Hash-route link only when id is present and snapshot contains the object. */
45
+ export function objectRouteLink(kind, id, snapshot, featureId) {
46
+ if (!id) return el("span", "muted", "缺失");
47
+ const exists = objectExistsInSnapshot(kind, id, snapshot, featureId);
48
+ if (!exists) return el("span", "muted", id);
49
+ const path = objectRoutePath(kind, id, featureId);
50
+ const a = el("a", "object-link", id);
51
+ a.href = `#${path}`;
52
+ a.addEventListener("click", (e) => {
53
+ e.preventDefault();
54
+ e.stopPropagation();
55
+ navigate(path);
56
+ });
57
+ return a;
58
+ }
59
+
60
+ export function findFeatureInSnapshot(snapshot, featureId) {
61
+ if (!featureId) return undefined;
62
+ return (snapshot?.features ?? []).find((f) => f.featureId === featureId);
63
+ }
64
+
65
+ export function featureLookupState(snapshot, featureId) {
66
+ if (!snapshot) return { kind: "unavailable" };
67
+ const feature = findFeatureInSnapshot(snapshot, featureId);
68
+ return feature ? { kind: "found", feature } : { kind: "missing" };
69
+ }
70
+
71
+ export const RELATION_KIND_ORDER = ["feature", "task", "batch", "run", "dag"];
72
+ export const RELATION_LABELS = {
73
+ feature: "Feature",
74
+ task: "Task",
75
+ batch: "Batch",
76
+ run: "Run",
77
+ dag: "DAG",
78
+ };
79
+
80
+ /**
81
+ * Build proven relation descriptors only (id present AND object in snapshot).
82
+ * Never infers links from identifier naming.
83
+ */
84
+ export function buildObjectRelations(ids, snapshot) {
85
+ const input = ids ?? {};
86
+ const candidates = [
87
+ { kind: "feature", id: input.featureId },
88
+ { kind: "task", id: input.taskId, featureId: input.featureId },
89
+ { kind: "batch", id: input.batchRunId },
90
+ { kind: "run", id: input.workerRunId },
91
+ { kind: "dag", id: input.dagRunId },
92
+ ];
93
+ const out = [];
94
+ for (const kind of RELATION_KIND_ORDER) {
95
+ const entry = candidates.find((c) => c.kind === kind);
96
+ if (!entry?.id) continue;
97
+ if (!objectExistsInSnapshot(kind, entry.id, snapshot, entry.featureId)) continue;
98
+ out.push({
99
+ kind,
100
+ id: entry.id,
101
+ label: RELATION_LABELS[kind] ?? kind,
102
+ featureId: entry.featureId,
103
+ href: `#${objectRoutePath(kind, entry.id, entry.featureId)}`,
104
+ path: objectRoutePath(kind, entry.id, entry.featureId),
105
+ });
106
+ }
107
+ return out;
108
+ }
109
+
110
+ export function renderObjectRelationBar(relations, snapshot) {
111
+ const bar = el("div", "object-relation-bar");
112
+ bar.setAttribute("aria-label", "对象关联");
113
+ const list = Array.isArray(relations)
114
+ ? relations
115
+ : buildObjectRelations(relations, snapshot);
116
+ if (list.length === 0) {
117
+ bar.appendChild(el("span", "muted", "暂无已证明的对象关联"));
118
+ return bar;
119
+ }
120
+ list.forEach((rel, i) => {
121
+ if (i > 0) bar.appendChild(el("span", "object-relation-sep", "→"));
122
+ const item = el("span", "object-relation-item");
123
+ item.appendChild(el("span", "object-relation-label", rel.label));
124
+ item.appendChild(document.createTextNode(" "));
125
+ if (rel.href && rel.id) {
126
+ item.appendChild(objectRouteLink(rel.kind, rel.id, snapshot, rel.featureId));
127
+ } else {
128
+ item.appendChild(el("span", "muted", rel.id ?? "缺失"));
129
+ }
130
+ bar.appendChild(item);
131
+ });
132
+ return bar;
133
+ }
@@ -1,148 +1,148 @@
1
- /** Run step/command/artifact processing and task history rows. */
2
- import {
3
- STEP_LABELS,
4
- ARTIFACT_LABELS,
5
- STEP_ORDER,
6
- ARTIFACT_KEYS,
7
- } from "./constants.js";
8
- import { badge } from "./format.js";
9
- import { navigate } from "./router.js";
10
-
11
- export function stepDisplayLabel(label) {
12
- return STEP_LABELS[label] ?? label;
13
- }
14
-
15
- export function buildStepStates(events) {
16
- const states = new Map();
17
- for (const ev of events) {
18
- if (ev.type === "step.started") {
19
- states.set(ev.label, { status: "running", startedAt: ev.at });
20
- } else if (ev.type === "step.finished") {
21
- states.set(ev.label, {
22
- status: ev.status === "failed" ? "failed" : "succeeded",
23
- durationMs: ev.durationMs,
24
- });
25
- }
26
- }
27
-
28
- const ordered = [...STEP_ORDER];
29
- for (const label of states.keys()) {
30
- if (!ordered.includes(label)) ordered.push(label);
31
- }
32
-
33
- return ordered.map((label) => {
34
- const state = states.get(label);
35
- return {
36
- label,
37
- display: stepDisplayLabel(label),
38
- status: state?.status ?? "pending",
39
- durationMs: state?.durationMs,
40
- };
41
- });
42
- }
43
-
44
- export function stepMarker(status) {
45
- switch (status) {
46
- case "succeeded":
47
- return "✓";
48
- case "running":
49
- return "●";
50
- case "failed":
51
- return "✗";
52
- default:
53
- return "○";
54
- }
55
- }
56
-
57
- export function getCurrentCommand(events) {
58
- const active = new Map();
59
- for (const ev of events) {
60
- if (ev.type === "command.started") {
61
- active.set(ev.label, ev);
62
- } else if (ev.type === "command.finished") {
63
- active.delete(ev.label);
64
- }
65
- }
66
- let latest = null;
67
- for (const cmd of active.values()) {
68
- if (!latest || cmd.at > latest.at) latest = cmd;
69
- }
70
- if (latest?.at) {
71
- const elapsed = Date.now() - Date.parse(latest.at);
72
- latest = { ...latest, elapsedMs: Number.isFinite(elapsed) ? elapsed : 0 };
73
- }
74
- return latest;
75
- }
76
-
77
- export function getOutputTail(events, commandLabel) {
78
- if (!commandLabel) return "";
79
- const chunks = [];
80
- for (const ev of events) {
81
- if (
82
- ev.type === "command.output" &&
83
- ev.label === commandLabel &&
84
- ev.outputPreview
85
- ) {
86
- chunks.push(ev.outputPreview);
87
- }
88
- }
89
- return chunks.join("");
90
- }
91
-
92
- export function collectArtifacts(task, events) {
93
- const arts = new Map();
94
- const add = (label, artifactPath) => {
95
- if (artifactPath && !arts.has(label)) arts.set(label, artifactPath);
96
- };
97
-
98
- if (task?.artifactRefs) {
99
- for (const key of ARTIFACT_KEYS) {
100
- add(ARTIFACT_LABELS[key] ?? key, task.artifactRefs[key]);
101
- }
102
- }
103
-
104
- for (const ev of events) {
105
- if (!ev.artifactRefs) continue;
106
- for (const [key, artifactPath] of Object.entries(ev.artifactRefs)) {
107
- add(ARTIFACT_LABELS[key] ?? key, artifactPath);
108
- }
109
- }
110
-
111
- return arts;
112
- }
113
-
114
- export function findBatchRunIdForTask(snapshot, task) {
115
- if (!snapshot || !task) return null;
116
- const workerRunId = task.workerRunId;
117
- if (!workerRunId) return null;
118
- for (const batch of snapshot.batches ?? []) {
119
- for (const t of batch.tasks ?? []) {
120
- if (t.workerRunId === workerRunId) return batch.batchRunId;
121
- }
122
- }
123
- return null;
124
- }
125
-
126
- export function taskRunHistoryRow(run) {
127
- let runLink = run.workerRunId;
128
- if (run.workerRunId) {
129
- const a = document.createElement("a");
130
- a.href = `#/run/${encodeURIComponent(run.workerRunId)}`;
131
- a.textContent = run.workerRunId;
132
- a.addEventListener("click", (e) => {
133
- e.preventDefault();
134
- navigate(`#/run/${encodeURIComponent(run.workerRunId)}`);
135
- });
136
- runLink = a;
137
- }
138
- return {
139
- cells: [
140
- runLink,
141
- badge(run.status),
142
- run.recordedAt ?? run.finishedAt ?? "—",
143
- run.batchRunId ?? "—",
144
- run.retryOfWorkerRunId ?? "—",
145
- run.failureCategory ?? "—",
146
- ],
147
- };
148
- }
1
+ /** Run step/command/artifact processing and task history rows. */
2
+ import {
3
+ STEP_LABELS,
4
+ ARTIFACT_LABELS,
5
+ STEP_ORDER,
6
+ ARTIFACT_KEYS,
7
+ } from "./constants.js";
8
+ import { badge } from "./format.js";
9
+ import { navigate } from "./router.js";
10
+
11
+ export function stepDisplayLabel(label) {
12
+ return STEP_LABELS[label] ?? label;
13
+ }
14
+
15
+ export function buildStepStates(events) {
16
+ const states = new Map();
17
+ for (const ev of events) {
18
+ if (ev.type === "step.started") {
19
+ states.set(ev.label, { status: "running", startedAt: ev.at });
20
+ } else if (ev.type === "step.finished") {
21
+ states.set(ev.label, {
22
+ status: ev.status === "failed" ? "failed" : "succeeded",
23
+ durationMs: ev.durationMs,
24
+ });
25
+ }
26
+ }
27
+
28
+ const ordered = [...STEP_ORDER];
29
+ for (const label of states.keys()) {
30
+ if (!ordered.includes(label)) ordered.push(label);
31
+ }
32
+
33
+ return ordered.map((label) => {
34
+ const state = states.get(label);
35
+ return {
36
+ label,
37
+ display: stepDisplayLabel(label),
38
+ status: state?.status ?? "pending",
39
+ durationMs: state?.durationMs,
40
+ };
41
+ });
42
+ }
43
+
44
+ export function stepMarker(status) {
45
+ switch (status) {
46
+ case "succeeded":
47
+ return "✓";
48
+ case "running":
49
+ return "●";
50
+ case "failed":
51
+ return "✗";
52
+ default:
53
+ return "○";
54
+ }
55
+ }
56
+
57
+ export function getCurrentCommand(events) {
58
+ const active = new Map();
59
+ for (const ev of events) {
60
+ if (ev.type === "command.started") {
61
+ active.set(ev.label, ev);
62
+ } else if (ev.type === "command.finished") {
63
+ active.delete(ev.label);
64
+ }
65
+ }
66
+ let latest = null;
67
+ for (const cmd of active.values()) {
68
+ if (!latest || cmd.at > latest.at) latest = cmd;
69
+ }
70
+ if (latest?.at) {
71
+ const elapsed = Date.now() - Date.parse(latest.at);
72
+ latest = { ...latest, elapsedMs: Number.isFinite(elapsed) ? elapsed : 0 };
73
+ }
74
+ return latest;
75
+ }
76
+
77
+ export function getOutputTail(events, commandLabel) {
78
+ if (!commandLabel) return "";
79
+ const chunks = [];
80
+ for (const ev of events) {
81
+ if (
82
+ ev.type === "command.output" &&
83
+ ev.label === commandLabel &&
84
+ ev.outputPreview
85
+ ) {
86
+ chunks.push(ev.outputPreview);
87
+ }
88
+ }
89
+ return chunks.join("");
90
+ }
91
+
92
+ export function collectArtifacts(task, events) {
93
+ const arts = new Map();
94
+ const add = (label, artifactPath) => {
95
+ if (artifactPath && !arts.has(label)) arts.set(label, artifactPath);
96
+ };
97
+
98
+ if (task?.artifactRefs) {
99
+ for (const key of ARTIFACT_KEYS) {
100
+ add(ARTIFACT_LABELS[key] ?? key, task.artifactRefs[key]);
101
+ }
102
+ }
103
+
104
+ for (const ev of events) {
105
+ if (!ev.artifactRefs) continue;
106
+ for (const [key, artifactPath] of Object.entries(ev.artifactRefs)) {
107
+ add(ARTIFACT_LABELS[key] ?? key, artifactPath);
108
+ }
109
+ }
110
+
111
+ return arts;
112
+ }
113
+
114
+ export function findBatchRunIdForTask(snapshot, task) {
115
+ if (!snapshot || !task) return null;
116
+ const workerRunId = task.workerRunId;
117
+ if (!workerRunId) return null;
118
+ for (const batch of snapshot.batches ?? []) {
119
+ for (const t of batch.tasks ?? []) {
120
+ if (t.workerRunId === workerRunId) return batch.batchRunId;
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+
126
+ export function taskRunHistoryRow(run) {
127
+ let runLink = run.workerRunId;
128
+ if (run.workerRunId) {
129
+ const a = document.createElement("a");
130
+ a.href = `#/run/${encodeURIComponent(run.workerRunId)}`;
131
+ a.textContent = run.workerRunId;
132
+ a.addEventListener("click", (e) => {
133
+ e.preventDefault();
134
+ navigate(`#/run/${encodeURIComponent(run.workerRunId)}`);
135
+ });
136
+ runLink = a;
137
+ }
138
+ return {
139
+ cells: [
140
+ runLink,
141
+ badge(run.status),
142
+ run.recordedAt ?? run.finishedAt ?? "—",
143
+ run.batchRunId ?? "—",
144
+ run.retryOfWorkerRunId ?? "—",
145
+ run.failureCategory ?? "—",
146
+ ],
147
+ };
148
+ }