@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,7 +1,7 @@
1
- /**
2
- * Shell service locator removed in R5 boundary final (BND-02).
3
- * Views import focused modules directly (shell-chrome, kpi, dag-helpers, run-processing).
4
- * This file is retained only so historical bundle paths do not 404; do not reintroduce getShell.
5
- */
6
-
7
- export {};
1
+ /**
2
+ * Shell service locator removed in R5 boundary final (BND-02).
3
+ * Views import focused modules directly (shell-chrome, kpi, dag-helpers, run-processing).
4
+ * This file is retained only so historical bundle paths do not 404; do not reintroduce getShell.
5
+ */
6
+
7
+ export {};
@@ -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
+ }
@@ -1,5 +1,6 @@
1
1
  import { access } from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { normalizeCliVersionLabel } from "../shared/package-metadata.js";
3
4
  import { controllerIdentityExpectationFailure, resolveControllerIdentity, } from "./loop-agent/loop-agent-client.js";
4
5
  export const DEFAULT_CHECK_REPO_TIMEOUT_MS = 300_000;
5
6
  export async function preflightTargetRepo(input) {
@@ -47,7 +48,7 @@ export async function preflightTargetRepo(input) {
47
48
  controllerIdentity: identity,
48
49
  };
49
50
  }
50
- const reportedVersion = version.stdout.trim();
51
+ const reportedVersion = normalizeCliVersionLabel(version.stdout);
51
52
  let controllerIdentity = identity
52
53
  ? { ...identity, reportedVersion }
53
54
  : undefined;
@@ -724,30 +724,40 @@ export function deterministicRewriteScenarioParam(input) {
724
724
  return { ok: true, source: nextSource, detail: "rewritten" };
725
725
  }
726
726
  function validatePythonSyntaxWithoutExecution(source) {
727
- const result = spawnSync("python", ["-c", "import ast,sys; ast.parse(sys.stdin.read())"], {
728
- input: source,
729
- encoding: "utf8",
730
- env: {
731
- ...process.env,
732
- PYTHONDONTWRITEBYTECODE: "1",
733
- PYTHONUTF8: "1",
734
- },
735
- timeout: 15_000,
736
- });
737
- if (result.error) {
738
- return {
739
- ok: false,
740
- detail: `python syntax validation unavailable: ${result.error.message}`,
741
- };
742
- }
743
- if (result.status !== 0) {
744
- const detail = String(result.stderr || result.stdout || "invalid Python syntax")
745
- .trim()
746
- .replace(/\s+/g, " ")
747
- .slice(0, 500);
748
- return { ok: false, detail: `python syntax validation failed: ${detail}` };
727
+ // Prefer `python3` (present on modern POSIX images and macOS); fall back to
728
+ // `python` for older or Windows layouts where only the unversioned shim exists.
729
+ // A missing interpreter must not silently roll back an otherwise-valid
730
+ // deterministic rewrite.
731
+ const candidates = ["python3", "python"];
732
+ let lastError;
733
+ for (const interpreter of candidates) {
734
+ const result = spawnSync(interpreter, ["-c", "import ast,sys; ast.parse(sys.stdin.read())"], {
735
+ input: source,
736
+ encoding: "utf8",
737
+ env: {
738
+ ...process.env,
739
+ PYTHONDONTWRITEBYTECODE: "1",
740
+ PYTHONUTF8: "1",
741
+ },
742
+ timeout: 15_000,
743
+ });
744
+ if (result.error) {
745
+ lastError = result.error.message;
746
+ continue;
747
+ }
748
+ if (result.status !== 0) {
749
+ const detail = String(result.stderr || result.stdout || "invalid Python syntax")
750
+ .trim()
751
+ .replace(/\s+/g, " ")
752
+ .slice(0, 500);
753
+ return { ok: false, detail: `python syntax validation failed: ${detail}` };
754
+ }
755
+ return { ok: true, detail: "python ast.parse PASS" };
749
756
  }
750
- return { ok: true, detail: "python ast.parse PASS" };
757
+ return {
758
+ ok: false,
759
+ detail: `python syntax validation unavailable: ${lastError ?? "python/python3 not found"}`,
760
+ };
751
761
  }
752
762
  export async function applyDeterministicScenarioParamRepairs(input) {
753
763
  const repairable = input.facts.entries.filter((entry) => entry.status === "MISMATCH" && entry.repairability === "repairable");