@tea-agent/loop-agent 0.13.0-alpha.0 → 0.13.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/AGENTS.md +155 -153
  2. package/CHANGELOG.md +326 -301
  3. package/README.md +345 -326
  4. package/bin/agent-worker.js +22 -22
  5. package/bin/loop-agent.js +21 -21
  6. package/dist/application/dag/generate-task-dag.js +28 -58
  7. package/dist/application/evaluation/candidate-hash.js +75 -0
  8. package/dist/application/evaluation/candidate.js +52 -0
  9. package/dist/application/evaluation/replay.js +289 -0
  10. package/dist/application/evaluation/types.js +130 -0
  11. package/dist/cli/command-definitions.js +17 -4
  12. package/dist/cli/program.js +8 -4
  13. package/dist/commands/cursor-prompt.js +6 -6
  14. package/dist/commands/eval.js +235 -0
  15. package/dist/commands/init.js +544 -506
  16. package/dist/commands/loop-benchmark.js +11 -11
  17. package/dist/commands/pi-reuse-benchmark.js +16 -16
  18. package/dist/executors/pi-sdk-executor.js +38 -24
  19. package/dist/executors/shell-executor.js +34 -2
  20. package/dist/executors/shell-presets.js +20 -0
  21. package/dist/executors/shell-verification.js +7 -0
  22. package/dist/governance/manifest-types.js +1 -0
  23. package/dist/infrastructure/evaluation/candidate-store.js +435 -0
  24. package/dist/infrastructure/evaluation/store.js +40 -0
  25. package/dist/sidecars/cursor-prompt/executor.js +1 -1
  26. package/dist/task/config-types.js +23 -0
  27. package/dist/task/runtime.js +27 -27
  28. package/dist/worker/observe/routes.js +18 -3
  29. package/dist/worker/observe/spec-evidence.js +1 -1
  30. package/dist/worker/observe/static/api.js +46 -46
  31. package/dist/worker/observe/static/app.js +150 -150
  32. package/dist/worker/observe/static/constants.js +148 -148
  33. package/dist/worker/observe/static/copy.js +67 -67
  34. package/dist/worker/observe/static/dag-helpers.js +172 -172
  35. package/dist/worker/observe/static/dag-layout.d.ts +31 -31
  36. package/dist/worker/observe/static/dag-layout.js +83 -83
  37. package/dist/worker/observe/static/dag-model.js +72 -72
  38. package/dist/worker/observe/static/dom.js +61 -61
  39. package/dist/worker/observe/static/format-pool.js +67 -67
  40. package/dist/worker/observe/static/format.js +292 -292
  41. package/dist/worker/observe/static/index.html +308 -308
  42. package/dist/worker/observe/static/kpi.js +94 -94
  43. package/dist/worker/observe/static/relations.js +133 -133
  44. package/dist/worker/observe/static/router.js +93 -93
  45. package/dist/worker/observe/static/run-processing.js +148 -148
  46. package/dist/worker/observe/static/shell-chrome.js +68 -68
  47. package/dist/worker/observe/static/state.js +253 -253
  48. package/dist/worker/observe/static/styles.css +1902 -1902
  49. package/dist/worker/observe/static/views/batch.js +227 -227
  50. package/dist/worker/observe/static/views/dag-graph.js +172 -172
  51. package/dist/worker/observe/static/views/dag-inspector.js +607 -596
  52. package/dist/worker/observe/static/views/dag.js +362 -362
  53. package/dist/worker/observe/static/views/dashboard.js +445 -445
  54. package/dist/worker/observe/static/views/failures.js +143 -143
  55. package/dist/worker/observe/static/views/feature.js +492 -492
  56. package/dist/worker/observe/static/views/pool.js +350 -350
  57. package/dist/worker/observe/static/views/run.js +453 -453
  58. package/dist/worker/observe/static/views/session-timeline.js +205 -205
  59. package/dist/worker/observe/static/views/shell.js +7 -7
  60. package/dist/worker/observe/static/views/task.js +314 -314
  61. package/dist/worker/observe/static/views/timeline.js +163 -163
  62. package/dist/workflows/dag/backend-test-analysis-contract.js +120 -0
  63. package/dist/workflows/dag/canvas-observer.js +275 -275
  64. package/dist/workflows/dag/dynamic-runtime/map.js +90 -2
  65. package/dist/workflows/dag/init-hybrid.js +1415 -200
  66. package/dist/workflows/dag/node-execution.js +9 -0
  67. package/dist/workflows/dag/prompt.js +9 -0
  68. package/dist/workflows/dag/report.js +35 -1
  69. package/dist/workflows/dag/runner.js +28 -2
  70. package/dist/workflows/dag/task-demand-routing.js +383 -0
  71. package/dist/workflows/dag/types.js +50 -13
  72. package/dist/workflows/dag/upstream-artifacts.js +1 -0
  73. package/dist/workflows/dag/validate.js +59 -1
  74. package/docs/README.md +106 -104
  75. package/docs/agent-dag-recovery-playbook.md +195 -193
  76. package/docs/agent-dag-runner.md +67 -67
  77. package/docs/architecture/README.md +26 -26
  78. package/docs/architecture/dag-execution.md +140 -140
  79. package/docs/architecture/evolution.md +54 -54
  80. package/docs/architecture/facts-and-state.md +71 -71
  81. package/docs/architecture/runtime-boundaries.md +191 -191
  82. package/docs/architecture/system-overview.md +93 -93
  83. package/docs/architecture/worker-and-feature.md +85 -85
  84. package/docs/cursor-prompt-sidecar.md +36 -36
  85. package/docs/decisions/README.md +18 -18
  86. package/docs/design/README.md +167 -85
  87. package/docs/development-principles.md +73 -73
  88. package/docs/exec-plans/README.md +6 -6
  89. package/docs/exec-plans/active/README.md +15 -11
  90. package/docs/exec-plans/completed/README.md +85 -74
  91. package/docs/feature-workflow.md +389 -339
  92. package/docs/harness-methodology-debugging.md +153 -153
  93. package/docs/harness-methodology-tdd.md +130 -130
  94. package/docs/harness-methodology-verification.md +27 -27
  95. package/docs/init-surface.manifest.json +289 -280
  96. package/docs/loop-agent-harness.md +142 -141
  97. package/docs/production-readiness.md +96 -96
  98. package/docs/progress/README.md +64 -58
  99. package/docs/reports/README.md +117 -100
  100. package/docs/skills/README.md +7 -7
  101. package/docs/skills/vetted-skill-registry.md +29 -27
  102. package/docs/templates/adr.md +60 -60
  103. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  104. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  105. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
  106. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  107. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  108. package/docs/templates/agent-dag-report.schema.json +473 -473
  109. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  110. package/docs/templates/agent-dag.base.json +190 -190
  111. package/docs/templates/agent-dag.final-verification.json +185 -185
  112. package/docs/templates/agent-dag.schema.json +411 -383
  113. package/docs/templates/agent-dag.supervised-implementation.json +501 -501
  114. package/docs/templates/backend-test-analysis.schema.json +44 -0
  115. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +202 -139
  116. package/docs/templates/backend-test-dag.json +311 -288
  117. package/docs/templates/backend-test-dag.retrospect.prompt.md +125 -125
  118. package/docs/templates/backend-test-dag.review-cases.prompt.md +81 -81
  119. package/docs/templates/exec-plan.md +64 -64
  120. package/docs/templates/feature-spec.md +53 -53
  121. package/docs/templates/frontend-design-contract.md +42 -33
  122. package/docs/templates/frontend-task-constraints.md +35 -25
  123. package/docs/templates/frontend-task-requirement.md +70 -61
  124. package/docs/templates/frontend-test-dag.generate-cases.prompt.md +5 -0
  125. package/docs/templates/frontend-test-dag.json +23 -0
  126. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +3 -0
  127. package/docs/templates/frontend-test-dag.retrospect.prompt.md +3 -0
  128. package/docs/templates/frontend-test-dag.review-cases.prompt.md +3 -0
  129. package/docs/templates/frontend-test-dag.review-execution.prompt.md +3 -0
  130. package/docs/templates/harness.schema.json +221 -221
  131. package/docs/templates/hybrid-dag.json +188 -188
  132. package/docs/templates/init-evolution-review.md +35 -35
  133. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  134. package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
  135. package/docs/templates/knowledge-sync-dag.json +178 -177
  136. package/docs/templates/knowledge-sync-draft.schema.json +71 -71
  137. package/docs/templates/product-line/AGENTS.md +8 -8
  138. package/docs/templates/product-line/README.md +9 -9
  139. package/docs/templates/product-line/acceptance.yaml +14 -14
  140. package/docs/templates/product-line/closeout.yaml +9 -9
  141. package/docs/templates/product-line/design.md +13 -13
  142. package/docs/templates/product-line/links.md +10 -10
  143. package/docs/templates/product-line/requirement.md +17 -17
  144. package/docs/templates/product-line/task-graph.yaml +15 -15
  145. package/docs/templates/product-line/task.yaml +64 -64
  146. package/docs/templates/product-line/test-plan.md +7 -7
  147. package/docs/templates/production-readiness-checklist.md +57 -57
  148. package/docs/templates/progress-log.md +17 -17
  149. package/docs/templates/project-start-checklist.md +9 -9
  150. package/docs/templates/qa-report.md +48 -48
  151. package/docs/templates/sprint-contract.md +29 -29
  152. package/docs/templates/worker-dogfood-evidence.md +80 -80
  153. package/docs/templates/worker-dogfood-setup.md +68 -68
  154. package/docs/verification-matrix.md +70 -67
  155. package/examples/decision-gate-agent-dag.json +177 -177
  156. package/examples/example-dag.json +46 -46
  157. package/examples/hybrid-loop-agent-dag.json +189 -189
  158. package/harness.json +66 -66
  159. package/package.json +88 -52
  160. package/scripts/check-product-line-docs.sh +29 -29
  161. package/scripts/check-task-pool-root.sh +32 -32
  162. package/scripts/kb-bootstrap-init-skeleton.sh +240 -239
  163. package/scripts/kb-graph-incremental-prepare.mjs +386 -372
  164. package/scripts/kb-graph-incremental-prepare.sh +5 -5
  165. package/scripts/kb-graph-materialize.mjs +105 -105
  166. package/scripts/kb-graph-materialize.sh +4 -4
  167. package/scripts/kb-graph-promote.mjs +164 -153
  168. package/scripts/kb-graph-promote.sh +4 -4
  169. package/scripts/kb-query.mjs +554 -554
  170. package/scripts/kb-query.sh +5 -5
  171. package/skills/agent-worker/SKILL.md +39 -39
  172. package/skills/agent-worker/references/agent-worker-operator.md +60 -60
  173. package/skills/ai-engineering-context/SKILL.md +48 -48
  174. package/skills/analyze-product-dependencies/SKILL.md +67 -0
  175. package/skills/analyze-product-dependencies/agents/openai.yaml +4 -0
  176. package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -0
  177. package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -0
  178. package/skills/analyze-product-dependencies/references/example.md +76 -0
  179. package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -0
  180. package/skills/analyze-product-dependencies/references/input-contract.md +11 -0
  181. package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -0
  182. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -0
  183. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -0
  184. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -0
  185. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -0
  186. package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -0
  187. package/skills/analyze-product-requirements/SKILL.md +90 -0
  188. package/skills/analyze-product-requirements/agents/openai.yaml +4 -0
  189. package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -0
  190. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -0
  191. package/skills/analyze-product-requirements/references/example.md +86 -0
  192. package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -0
  193. package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -0
  194. package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -0
  195. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -0
  196. package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -0
  197. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -0
  198. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -0
  199. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -0
  200. package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -0
  201. package/skills/code-review-core/SKILL.md +20 -20
  202. package/skills/codebase-scout/SKILL.md +19 -19
  203. package/skills/frontend-design-review/SKILL.md +66 -61
  204. package/skills/frontend-design-review/references/review-checklist.md +58 -37
  205. package/skills/frontend-implementation/SKILL.md +45 -52
  206. package/skills/frontend-implementation/references/code-standards.md +32 -34
  207. package/skills/frontend-implementation/references/design-spec.md +46 -46
  208. package/skills/frontend-implementation/references/node-contracts.md +76 -63
  209. package/skills/frontend-review/SKILL.md +59 -53
  210. package/skills/frontend-review/references/review-findings.md +47 -42
  211. package/skills/frontend-verification/SKILL.md +53 -40
  212. package/skills/frontend-verification/references/verification-checklist.md +68 -56
  213. package/skills/grill-me/SKILL.md +10 -10
  214. package/skills/grill-with-docs/SKILL.md +88 -88
  215. package/skills/grill-with-docs/adr-format.md +47 -47
  216. package/skills/grill-with-docs/context-format.md +60 -60
  217. package/skills/init-capability-evolution/SKILL.md +70 -70
  218. package/skills/loop-agent/SKILL.md +151 -151
  219. package/skills/loop-agent/references/README.md +67 -67
  220. package/skills/loop-agent/references/command-reference.md +505 -453
  221. package/skills/loop-agent/references/docs-converge.md +126 -126
  222. package/skills/loop-agent/references/harness-policy.md +263 -263
  223. package/skills/loop-agent/references/hybrid-dag.md +238 -233
  224. package/skills/loop-agent/references/learned/README.md +21 -21
  225. package/skills/loop-agent/references/long-running-loop.md +57 -57
  226. package/skills/loop-agent/references/model-routing.md +36 -36
  227. package/skills/loop-agent/references/multi-worktree.md +54 -54
  228. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  229. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
  230. package/skills/loop-agent/references/pi-prompt.md +23 -23
  231. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
  232. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
  233. package/skills/loop-agent/references/task-workflow.md +89 -89
  234. package/skills/loop-agent/references/verification-and-failure-handling.md +139 -139
  235. package/skills/playwright-cli/SKILL.md +420 -0
  236. package/skills/playwright-cli/references/element-attributes.md +23 -0
  237. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  238. package/skills/playwright-cli/references/request-mocking.md +87 -0
  239. package/skills/playwright-cli/references/running-code.md +241 -0
  240. package/skills/playwright-cli/references/session-management.md +225 -0
  241. package/skills/playwright-cli/references/storage-state.md +275 -0
  242. package/skills/playwright-cli/references/test-generation.md +433 -0
  243. package/skills/playwright-cli/references/tracing.md +139 -0
  244. package/skills/playwright-cli/references/video-recording.md +143 -0
  245. package/skills/playwright-cli-case-generator/SKILL.md +74 -0
  246. package/skills/requesting-code-review/SKILL.md +101 -101
  247. package/skills/requesting-code-review/code-reviewer.md +168 -168
  248. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  249. package/skills/systematic-debugging/SKILL.md +296 -296
  250. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  251. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  252. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  253. package/skills/systematic-debugging/find-polluter.sh +63 -63
  254. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  255. package/skills/systematic-debugging/test-academic.md +14 -14
  256. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  257. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  258. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  259. package/skills/test-driven-development/SKILL.md +20 -20
  260. package/skills/using-git-worktrees/SKILL.md +215 -215
  261. package/skills/verification-before-completion/SKILL.md +154 -154
  262. package/skills/webapp-testing/SKILL.md +19 -19
@@ -1,163 +1,163 @@
1
- /** Observe UI view module (R5). */
2
- import {
3
- UI_TEXT,
4
- LIVENESS_LABELS,
5
- ARTIFACT_LABELS,
6
- ARTIFACT_KEYS,
7
- STEP_LABELS,
8
- STEP_ORDER,
9
- DAG_INSPECTOR_DEFAULT_WIDTH,
10
- DAG_INSPECTOR_MIN_WIDTH,
11
- DAG_INSPECTOR_MAX_WIDTH,
12
- DAG_INSPECTOR_RIGHT_OFFSET,
13
- DAG_INSPECTOR_VIEWPORT_MARGIN,
14
- DAG_INSPECTOR_KEYBOARD_STEP,
15
- TERMINAL_RUN_STATUSES,
16
- DAG_EFFECTIVE_STATUS_LABELS,
17
- STATUS_LABELS,
18
- } from "../constants.js";
19
- import { clearNode, el, metaGrid, buildTable } from "../dom.js";
20
- import {
21
- badge,
22
- badgeClass,
23
- statusLabel,
24
- formatTs,
25
- formatMs,
26
- formatDuration,
27
- formatAgo,
28
- dagStatusBadge,
29
- livenessBadge,
30
- displayDurationMs,
31
- derivedDurationMs,
32
- summaryText,
33
- truncateText,
34
- repoBaseName,
35
- parseMarkdownBlocks,
36
- markdownLinkHref,
37
- } from "../format.js";
38
- import { parseRoute, navigate, buildHashPath } from "../router.js";
39
- import {
40
- fetchJson,
41
- artifactUrl,
42
- parseArtifactPreviewResponse,
43
- } from "../api.js";
44
- import {
45
- objectRouteLink,
46
- findFeatureInSnapshot,
47
- featureLookupState,
48
- buildObjectRelations,
49
- renderObjectRelationBar,
50
- } from "../relations.js";
51
- import { copyText, renderRecommendedCommand } from "../copy.js";
52
- import {
53
- isPageVisible,
54
- detailPollDelay,
55
- dashboardPollDelay,
56
- captureDagGraphViewportState,
57
- updateDagGraphViewportState,
58
- updateDagTimelineViewportState,
59
- renderViewState,
60
- mountViewState,
61
- } from "../state.js";
62
- import { uiState } from "../state.js";
63
- import { sortPoolTasks } from "../format-pool.js";
64
- import {
65
- dagMetaVisibility,
66
- isDagRunActive,
67
- dashboardVisibleFeatures,
68
- findDagForRun,
69
- } from "../dag-model.js";
70
- import { layoutDag } from "../dag-layout.js";
71
-
72
- export async function mountBoundedEventTimeline(container, apiBase, title) {
73
- clearNode(container);
74
- container.appendChild(el("h3", "section-heading", title));
75
- const note = el(
76
- "p",
77
- "process-timeline-note",
78
- "有界历史(默认 50 / 最大 200);分页使用 cursor,与 SSE 行号 offset 分离。",
79
- );
80
- container.appendChild(note);
81
- const scroll = el("div", "process-timeline-scroll event-history-scroll");
82
- const listHost = el("div", "event-history-list");
83
- scroll.appendChild(listHost);
84
- container.appendChild(scroll);
85
- const footer = el("div", "event-history-footer");
86
- container.appendChild(footer);
87
-
88
- let nextCursor = null;
89
- let loading = false;
90
- const accumulated = [];
91
-
92
- const renderList = () => {
93
- clearNode(listHost);
94
- if (accumulated.length === 0) {
95
- mountViewState(listHost, "empty", "暂无事件");
96
- return;
97
- }
98
- const ul = el("ul", "process-timeline");
99
- for (let index = 0; index < accumulated.length; index += 1) {
100
- const event = accumulated[index];
101
- const li = el(
102
- "li",
103
- `process-timeline-item process-timeline-event has-time${index === 0 ? " is-first" : ""}${index === accumulated.length - 1 ? " is-last" : ""}`,
104
- );
105
- const rail = el("span", "process-timeline-rail");
106
- rail.appendChild(el("span", "process-timeline-dot"));
107
- li.appendChild(rail);
108
- li.appendChild(
109
- el("span", "process-timeline-time", formatTs(event.at) || "—"),
110
- );
111
- const label = `${event.type ?? "event"}${event.taskId ? ` · ${event.taskId}` : ""}${event.workerRunId ? ` · ${event.workerRunId}` : ""}`;
112
- li.appendChild(el("span", "process-timeline-label", label));
113
- ul.appendChild(li);
114
- }
115
- listHost.appendChild(ul);
116
- };
117
-
118
- const loadPage = async (cursor) => {
119
- if (loading) return;
120
- loading = true;
121
- if (accumulated.length === 0) {
122
- mountViewState(listHost, "loading", "加载事件…");
123
- }
124
- const qs = new URLSearchParams();
125
- qs.set("limit", "50");
126
- if (cursor) qs.set("cursor", cursor);
127
- const page = await fetchJson(`${apiBase}?${qs.toString()}`);
128
- loading = false;
129
- if (!page) {
130
- mountViewState(listHost, "error", "无法加载事件历史。");
131
- return;
132
- }
133
- const events = page.events ?? [];
134
- for (const event of events) accumulated.push(event);
135
- nextCursor = page.nextCursor ?? null;
136
- renderList();
137
- clearNode(footer);
138
- if (page.corruptLineCount > 0) {
139
- footer.appendChild(
140
- renderViewState(
141
- "degraded",
142
- `跳过损坏行 ${page.corruptLineCount} 条(failure-safe)。`,
143
- ),
144
- );
145
- }
146
- if (nextCursor) {
147
- const btn = el(
148
- "button",
149
- "btn-secondary event-history-more",
150
- "加载更早事件",
151
- );
152
- btn.type = "button";
153
- btn.addEventListener("click", () => {
154
- void loadPage(nextCursor);
155
- });
156
- footer.appendChild(btn);
157
- } else if (accumulated.length > 0) {
158
- footer.appendChild(el("p", "muted", "已到历史边界"));
159
- }
160
- };
161
-
162
- await loadPage(null);
163
- }
1
+ /** Observe UI view module (R5). */
2
+ import {
3
+ UI_TEXT,
4
+ LIVENESS_LABELS,
5
+ ARTIFACT_LABELS,
6
+ ARTIFACT_KEYS,
7
+ STEP_LABELS,
8
+ STEP_ORDER,
9
+ DAG_INSPECTOR_DEFAULT_WIDTH,
10
+ DAG_INSPECTOR_MIN_WIDTH,
11
+ DAG_INSPECTOR_MAX_WIDTH,
12
+ DAG_INSPECTOR_RIGHT_OFFSET,
13
+ DAG_INSPECTOR_VIEWPORT_MARGIN,
14
+ DAG_INSPECTOR_KEYBOARD_STEP,
15
+ TERMINAL_RUN_STATUSES,
16
+ DAG_EFFECTIVE_STATUS_LABELS,
17
+ STATUS_LABELS,
18
+ } from "../constants.js";
19
+ import { clearNode, el, metaGrid, buildTable } from "../dom.js";
20
+ import {
21
+ badge,
22
+ badgeClass,
23
+ statusLabel,
24
+ formatTs,
25
+ formatMs,
26
+ formatDuration,
27
+ formatAgo,
28
+ dagStatusBadge,
29
+ livenessBadge,
30
+ displayDurationMs,
31
+ derivedDurationMs,
32
+ summaryText,
33
+ truncateText,
34
+ repoBaseName,
35
+ parseMarkdownBlocks,
36
+ markdownLinkHref,
37
+ } from "../format.js";
38
+ import { parseRoute, navigate, buildHashPath } from "../router.js";
39
+ import {
40
+ fetchJson,
41
+ artifactUrl,
42
+ parseArtifactPreviewResponse,
43
+ } from "../api.js";
44
+ import {
45
+ objectRouteLink,
46
+ findFeatureInSnapshot,
47
+ featureLookupState,
48
+ buildObjectRelations,
49
+ renderObjectRelationBar,
50
+ } from "../relations.js";
51
+ import { copyText, renderRecommendedCommand } from "../copy.js";
52
+ import {
53
+ isPageVisible,
54
+ detailPollDelay,
55
+ dashboardPollDelay,
56
+ captureDagGraphViewportState,
57
+ updateDagGraphViewportState,
58
+ updateDagTimelineViewportState,
59
+ renderViewState,
60
+ mountViewState,
61
+ } from "../state.js";
62
+ import { uiState } from "../state.js";
63
+ import { sortPoolTasks } from "../format-pool.js";
64
+ import {
65
+ dagMetaVisibility,
66
+ isDagRunActive,
67
+ dashboardVisibleFeatures,
68
+ findDagForRun,
69
+ } from "../dag-model.js";
70
+ import { layoutDag } from "../dag-layout.js";
71
+
72
+ export async function mountBoundedEventTimeline(container, apiBase, title) {
73
+ clearNode(container);
74
+ container.appendChild(el("h3", "section-heading", title));
75
+ const note = el(
76
+ "p",
77
+ "process-timeline-note",
78
+ "有界历史(默认 50 / 最大 200);分页使用 cursor,与 SSE 行号 offset 分离。",
79
+ );
80
+ container.appendChild(note);
81
+ const scroll = el("div", "process-timeline-scroll event-history-scroll");
82
+ const listHost = el("div", "event-history-list");
83
+ scroll.appendChild(listHost);
84
+ container.appendChild(scroll);
85
+ const footer = el("div", "event-history-footer");
86
+ container.appendChild(footer);
87
+
88
+ let nextCursor = null;
89
+ let loading = false;
90
+ const accumulated = [];
91
+
92
+ const renderList = () => {
93
+ clearNode(listHost);
94
+ if (accumulated.length === 0) {
95
+ mountViewState(listHost, "empty", "暂无事件");
96
+ return;
97
+ }
98
+ const ul = el("ul", "process-timeline");
99
+ for (let index = 0; index < accumulated.length; index += 1) {
100
+ const event = accumulated[index];
101
+ const li = el(
102
+ "li",
103
+ `process-timeline-item process-timeline-event has-time${index === 0 ? " is-first" : ""}${index === accumulated.length - 1 ? " is-last" : ""}`,
104
+ );
105
+ const rail = el("span", "process-timeline-rail");
106
+ rail.appendChild(el("span", "process-timeline-dot"));
107
+ li.appendChild(rail);
108
+ li.appendChild(
109
+ el("span", "process-timeline-time", formatTs(event.at) || "—"),
110
+ );
111
+ const label = `${event.type ?? "event"}${event.taskId ? ` · ${event.taskId}` : ""}${event.workerRunId ? ` · ${event.workerRunId}` : ""}`;
112
+ li.appendChild(el("span", "process-timeline-label", label));
113
+ ul.appendChild(li);
114
+ }
115
+ listHost.appendChild(ul);
116
+ };
117
+
118
+ const loadPage = async (cursor) => {
119
+ if (loading) return;
120
+ loading = true;
121
+ if (accumulated.length === 0) {
122
+ mountViewState(listHost, "loading", "加载事件…");
123
+ }
124
+ const qs = new URLSearchParams();
125
+ qs.set("limit", "50");
126
+ if (cursor) qs.set("cursor", cursor);
127
+ const page = await fetchJson(`${apiBase}?${qs.toString()}`);
128
+ loading = false;
129
+ if (!page) {
130
+ mountViewState(listHost, "error", "无法加载事件历史。");
131
+ return;
132
+ }
133
+ const events = page.events ?? [];
134
+ for (const event of events) accumulated.push(event);
135
+ nextCursor = page.nextCursor ?? null;
136
+ renderList();
137
+ clearNode(footer);
138
+ if (page.corruptLineCount > 0) {
139
+ footer.appendChild(
140
+ renderViewState(
141
+ "degraded",
142
+ `跳过损坏行 ${page.corruptLineCount} 条(failure-safe)。`,
143
+ ),
144
+ );
145
+ }
146
+ if (nextCursor) {
147
+ const btn = el(
148
+ "button",
149
+ "btn-secondary event-history-more",
150
+ "加载更早事件",
151
+ );
152
+ btn.type = "button";
153
+ btn.addEventListener("click", () => {
154
+ void loadPage(nextCursor);
155
+ });
156
+ footer.appendChild(btn);
157
+ } else if (accumulated.length > 0) {
158
+ footer.appendChild(el("p", "muted", "已到历史边界"));
159
+ }
160
+ };
161
+
162
+ await loadPage(null);
163
+ }
@@ -0,0 +1,120 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { z } from "zod";
5
+ import { writeDagRunJsonArtifact } from "../../infrastructure/harness/artifact-store.js";
6
+ export const BACKEND_TEST_ANALYSIS_SCHEMA_ID = "backend-test-analysis-v1";
7
+ const sourceRefSchema = z.string().min(1);
8
+ const fieldSchema = z.object({
9
+ name: z.string().min(1),
10
+ type: z.string().min(1).optional(),
11
+ required: z.boolean().optional(),
12
+ description: z.string().optional(),
13
+ }).strict();
14
+ const errorCaseSchema = z.object({
15
+ status: z.number().int().min(400).max(599).optional(),
16
+ code: z.string().min(1).optional(),
17
+ messageField: z.string().min(1).optional(),
18
+ description: z.string().min(1),
19
+ }).strict();
20
+ export const backendTestAnalysisContractSchema = z.object({
21
+ schemaVersion: z.literal(1),
22
+ sourceBinding: z.object({
23
+ taskId: z.string().min(1),
24
+ requirementPath: z.string().min(1),
25
+ requirementSha256: z.string().regex(/^[a-f0-9]{64}$/),
26
+ referencePaths: z.array(z.string().min(1)),
27
+ requirementIds: z.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/)),
28
+ }).strict(),
29
+ acceptanceCriteria: z.array(z.object({
30
+ id: z.string().regex(/^AC-[A-Z0-9]+(?:-[A-Z0-9]+)*$/),
31
+ text: z.string().min(1),
32
+ sourceRef: sourceRefSchema,
33
+ }).strict()),
34
+ endpoints: z.array(z.object({
35
+ id: z.string().min(1),
36
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]),
37
+ path: z.string().startsWith("/"),
38
+ requestFields: z.array(fieldSchema),
39
+ responseFields: z.array(fieldSchema),
40
+ successStatuses: z.array(z.number().int().min(100).max(399)),
41
+ errorCases: z.array(errorCaseSchema),
42
+ }).strict()),
43
+ dataModels: z.array(z.object({ id: z.string().min(1), description: z.string().min(1), sourceRef: sourceRefSchema }).strict()),
44
+ businessRules: z.array(z.object({ id: z.string().min(1), text: z.string().min(1), sourceRef: sourceRefSchema }).strict()),
45
+ stateTransitions: z.array(z.object({ from: z.string().min(1), to: z.string().min(1), trigger: z.string().min(1), sourceRef: sourceRefSchema }).strict()),
46
+ boundaryConstraints: z.array(z.object({ field: z.string().min(1), constraint: z.string().min(1), sourceRef: sourceRefSchema }).strict()),
47
+ externalDependencies: z.array(z.object({ name: z.string().min(1), description: z.string().min(1), sourceRef: sourceRefSchema.optional() }).strict()),
48
+ risks: z.array(z.object({ description: z.string().min(1), sourceRef: sourceRefSchema.optional() }).strict()),
49
+ evidenceGaps: z.array(z.object({ description: z.string().min(1), requirementId: z.string().optional(), sourceRef: sourceRefSchema.optional() }).strict()),
50
+ }).strict();
51
+ const SECRET_KEY = /(?:password|passwd|secret|token|api[_-]?key|private[_-]?key|credential|authorization)/i;
52
+ const SECRET_VALUE = /(?:-----BEGIN [A-Z ]*PRIVATE KEY-----|\b(?:sk|ghp|github_pat|xox[baprs]|AKIA)[-_A-Za-z0-9]{12,}\b)/;
53
+ function secretIssues(value, at = "$", issues = []) {
54
+ if (typeof value === "string" && SECRET_VALUE.test(value))
55
+ issues.push(`${at}: secret-like value is forbidden`);
56
+ if (Array.isArray(value))
57
+ value.forEach((item, index) => secretIssues(item, `${at}[${index}]`, issues));
58
+ else if (value && typeof value === "object") {
59
+ for (const [key, child] of Object.entries(value)) {
60
+ if (SECRET_KEY.test(key))
61
+ issues.push(`${at}.${key}: secret-shaped field name is forbidden`);
62
+ secretIssues(child, `${at}.${key}`, issues);
63
+ }
64
+ }
65
+ return issues;
66
+ }
67
+ export function extractStrictJsonObject(text) {
68
+ const trimmed = text.trim();
69
+ if (trimmed.startsWith("{") && trimmed.endsWith("}"))
70
+ return JSON.parse(trimmed);
71
+ const blocks = [...trimmed.matchAll(/```json\s*\n([\s\S]*?)\n```/gi)];
72
+ if (blocks.length !== 1 || trimmed.replace(blocks[0][0], "").trim()) {
73
+ throw new Error("analysis output must be one pure JSON object or one fenced json block with no trailing text");
74
+ }
75
+ return JSON.parse(blocks[0][1]);
76
+ }
77
+ function assertSourceBinding(contract, binding) {
78
+ const requirement = binding.sources.find((source) => source.kind === "requirement");
79
+ const references = binding.sources.filter((source) => source.kind === "reference").map((source) => source.path).sort();
80
+ const actualReferences = [...contract.sourceBinding.referencePaths].sort();
81
+ if (!requirement || contract.sourceBinding.taskId !== binding.taskId || contract.sourceBinding.requirementPath !== requirement.path || contract.sourceBinding.requirementSha256 !== requirement.sha256) {
82
+ throw new Error("analysis source binding does not match DAG requirement source");
83
+ }
84
+ if (JSON.stringify(actualReferences) !== JSON.stringify(references))
85
+ throw new Error("analysis referencePaths do not match DAG source binding");
86
+ if (JSON.stringify(contract.sourceBinding.requirementIds) !== JSON.stringify(binding.requirementIds))
87
+ throw new Error("analysis requirementIds do not match DAG source binding");
88
+ const explicitAc = binding.requirementIds.filter((id) => id.startsWith("AC-"));
89
+ const contractAc = contract.acceptanceCriteria.map((item) => item.id);
90
+ for (const id of explicitAc)
91
+ if (!contractAc.includes(id) && !contract.evidenceGaps.some((gap) => gap.requirementId === id))
92
+ throw new Error(`analysis contract does not cover explicit acceptance criterion ${id}`);
93
+ }
94
+ export async function materializeBackendTestAnalysisContract(input) {
95
+ if (!input.sourceBinding)
96
+ throw new Error("backend-test analysis gate requires DAG sourceBinding");
97
+ if (!/^[a-z0-9][a-z0-9._-]*\.json$/.test(input.artifactName) || !/^[a-z0-9][a-z0-9._-]*$/.test(input.outputDir))
98
+ throw new Error("unsafe structured artifact path");
99
+ const nodePath = path.join(input.runDir, `${input.fromNodeId}.json`);
100
+ const record = JSON.parse(await readFile(nodePath, "utf8"));
101
+ const raw = record.assistantText?.trim() || record.stdout?.trim() || "";
102
+ let parsed;
103
+ try {
104
+ parsed = extractStrictJsonObject(raw);
105
+ }
106
+ catch (error) {
107
+ throw new Error(`invalid-output: ${error instanceof Error ? error.message : String(error)}`);
108
+ }
109
+ const secrets = secretIssues(parsed);
110
+ if (secrets.length)
111
+ throw new Error(`invalid-output: ${secrets.join("; ")}`);
112
+ const result = backendTestAnalysisContractSchema.safeParse(parsed);
113
+ if (!result.success)
114
+ throw new Error(`invalid-output: ${result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ")}`);
115
+ assertSourceBinding(result.data, input.sourceBinding);
116
+ const relativePath = path.posix.join(input.outputDir, input.artifactName);
117
+ const artifactPath = await writeDagRunJsonArtifact(input.runDir, relativePath, result.data);
118
+ const normalized = `${JSON.stringify(result.data, null, 2)}\n`;
119
+ return { path: artifactPath, sha256: createHash("sha256").update(normalized).digest("hex"), schemaId: BACKEND_TEST_ANALYSIS_SCHEMA_ID };
120
+ }