@tea-agent/loop-agent 0.42.0-next.6 → 0.42.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +20 -0
- package/dist/build-stamp.json +3 -3
- package/dist/executors/dag-pi-executor.js +74 -13
- package/dist/executors/shell-executor.js +3 -1
- package/dist/task/source-prepare/fragment-inventory.js +49 -16
- package/dist/task/source-prepare/prepare.js +37 -20
- package/dist/worker/console/chat/model-resolver.js +7 -4
- package/dist/worker/console/chat/pi-runtime.js +60 -5
- package/dist/worker/console/chat/routes.js +69 -46
- package/dist/worker/console/chat/sdd-data-alignment.js +6 -3
- package/dist/worker/console/chat/session-store.js +16 -0
- package/dist/worker/console/pi-readiness.js +3 -2
- package/dist/worker/console/server.js +19 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BJpsGgAv.js → abnfDiagram-N423BO3Z-C6n9_m0P.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DjMFPsEd.js → arc-DQh-IfZ1.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DqdZlr1O.js → architectureDiagram-T3A2C74G-54NnrwUC.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-BmZnfFEO.js → blockDiagram-VBNYF7ZC-pivRALGK.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-3cKberpL.js → c4Diagram-5PPSVZJV-BR7OV2NJ.js} +1 -1
- package/dist/worker/console/static/assets/channel-DsZxrgqe.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-q-0yjQ1h.js → chunk-2GRJ4B5K-B1Aq6BcK.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DnONBaDW.js → chunk-2Q5K7J3B-CbdU0rjo.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-v3a6PCOS.js → chunk-5RXB4S5H-Dqi2GJeD.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-D1kLrlU_.js → chunk-5VM5RSS4-BYn1Hu4R.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BPelzihi.js → chunk-6Q2QTUOP-DRLjDL0k.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-DauNE69H.js → chunk-GF5L2VYU-CY9Xx2jV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-RIg5_bFJ.js → chunk-JWPE2WC7-BNCZs7_z.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BuILuoxs.js → chunk-KBJHAD2P-DZ8AStLL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-VHORV5oW.js → chunk-RYQCIY6F-DsxjYrzz.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BJYr4xHC.js → chunk-XXDRQBXY-Ddx1KC1l.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CuToPeGV.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CuToPeGV.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BS6nuqQn.js → cose-bilkent-JH36ORCC-W9TveCnK.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BBhF0NAT.js → cynefin-VYW2F7L2-l9j_ztZH.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-D1135Ifg.js → cynefinDiagram-MW4NZA55-BMJMKi4G.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-vAOYPUWJ.js → dagre-VZM6K2ZE-Bb4mG9pH.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-DuaSPkfa.js → diagram-7IWD3JNH-BMgL_Qv0.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-mMvXvGU6.js → diagram-B4RE2ZJO-Bvo2T4OQ.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CDIEJtlL.js → diagram-LBJQPF4R-_5kWRN9c.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-Bi_6JvCW.js → diagram-Q27KOJAE-DqdMrltM.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-DAqj57yN.js → diagram-UB23O5K3-CDDYsNkp.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DfWaxNEo.js → ebnfDiagram-BXEA7PRR-c4nfnZUV.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Bt7QqkNG.js → erDiagram-JOGREHBK-DnkUcNMs.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CRRhQwT2.js → flowDiagram-UKHOOZJN-Dz0KGLZE.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DAV1O5B6.js → ganttDiagram-PKOTCBZU-Cj1t1uka.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-0X2Qo4Lp.js → gitGraphDiagram-DS77QQ5N-tp2FrBHd.js} +1 -1
- package/dist/worker/console/static/assets/index-D9Sc0f0y.js +449 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-C5W5eILC.js → infoDiagram-6WML65LV-DQwJS8DH.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-5SfqU-Tb.js → ishikawaDiagram-WSZJBQD7-eimCQWD4.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CKDRcaKf.js → journeyDiagram-NVQOT4AX-Dd9Gbwgv.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Cc7_TuSb.js → kanban-definition-27J2QSJJ-Qve3cyft.js} +1 -1
- package/dist/worker/console/static/assets/{linear-BcQYYmeT.js → linear-UXKSe36Z.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-CwLZPtQo.js → mermaid.core-CWhj4JXN.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-D29M025z.js → mindmap-definition-FAOFIHXS-yTcwf4SJ.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CV-ZAWYe.js → pegDiagram-VL7TDLO6-_7qToaZP.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-C6iPS_o5.js → pieDiagram-7S7Q4E2Y-CXmrKmDm.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-BFCD1sTg.js → quadrantDiagram-CIZ2JOQS-hMmrJyaS.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CztNj4O9.js → railroadDiagram-AXF67PYL-BXw8tCBe.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BWIELSNd.js → requirementDiagram-LRYGKXZP-BmjgnLZl.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-CPtxrjJQ.js → sankeyDiagram-W5VNT64P-Bj77SPpN.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BEWVSFsu.js → sequenceDiagram-SI44F4Z6-B2FDVysL.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DyhzoX_J.js → sizeCapture-X5ZJPWSS-UChNY9ZZ.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-xLox0nu7.js → stateDiagram-OKZ733FA-wbAEkbd7.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-yPoT19ft.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CLC_ow9A.js → swimlanes-SLNWSIFB-DCEkU8HR.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-VWdarchG.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DmJZ4uyY.js → timeline-definition-Z64GVDOM-BGp7H06U.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DD7GGi9Z.js → vennDiagram-T6HMQDX7-DsCIQuWR.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-Bi8PQoGt.js → wardleyDiagram-T6FBY63Y-cRZLP4Xe.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-uKdAY8Dp.js → xychartDiagram-ELKLHX3M-CP0xLR9Y.js} +1 -1
- package/dist/worker/console/static/index.html +1 -1
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -5
- package/dist/worker/console/static-src/operator-chat/input-history.js +8 -6
- package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +10 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +31 -2
- package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -3
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +29 -6
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +8 -2
- package/dist/worker/console/static-src/shell/console-update-reload.js +36 -9
- package/dist/worker/console/static-src/shell/workspace-route.js +11 -0
- package/dist/worker/observe/static/dag-helpers.js +4 -2
- package/dist/worker/observe/static/inspect-workspace.js +23 -0
- package/dist/worker/observe/static/kpi.js +2 -2
- package/dist/worker/observe/static/operator-chrome.d.ts +10 -2
- package/dist/worker/observe/static/operator-chrome.js +37 -23
- package/dist/worker/observe/static/relations.js +2 -2
- package/dist/worker/observe/static/router.d.ts +12 -1
- package/dist/worker/observe/static/router.js +48 -6
- package/dist/worker/observe/static/run-processing.js +4 -2
- package/dist/worker/observe/static/shell-chrome.js +2 -2
- package/dist/worker/observe/static/state.js +5 -0
- package/dist/worker/observe/static/styles.css +95 -0
- package/dist/worker/observe/static/views/dag-inspector.js +14 -7
- package/dist/worker/observe/static/views/dag.js +10 -2
- package/dist/worker/observe/static/views/dags.js +3 -1
- package/dist/worker/observe/static/views/dashboard.js +14 -6
- package/dist/worker/observe/static/views/pool.js +7 -2
- package/dist/worker/observe/static/views/run.js +12 -3
- package/dist/worker/observe/static/views/session-timeline.js +69 -10
- package/dist/worker/observe/static/views/task.js +7 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +40 -9
- package/dist/workflows/dag/backend-test-scenario-param.js +126 -19
- package/dist/workflows/dag/backend-test-scenario-partitions.js +62 -1
- package/dist/workflows/dag/backend-test-writer-completeness.js +7 -3
- package/dist/workflows/dag/frontend-shadow-dual-write.js +33 -6
- package/dist/workflows/dag/init-hybrid.js +175 -27
- package/dist/workflows/dag/node-execution.js +1 -1
- package/dist/workflows/dag/types.js +1 -1
- package/package.json +3 -2
- package/dist/worker/console/static/assets/channel-DWYwciiv.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D6jOf_l4.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D6jOf_l4.js +0 -1
- package/dist/worker/console/static/assets/index-CVdddQsA.js +0 -451
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DS5ZRvJG.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Dvpxn-bf.js +0 -8
|
@@ -35,7 +35,12 @@ import {
|
|
|
35
35
|
parseMarkdownBlocks,
|
|
36
36
|
markdownLinkHref,
|
|
37
37
|
} from "../format.js";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
parseRoute,
|
|
40
|
+
navigate,
|
|
41
|
+
buildHashPath,
|
|
42
|
+
withWorkspaceQuery,
|
|
43
|
+
} from "../router.js";
|
|
39
44
|
import {
|
|
40
45
|
fetchJson,
|
|
41
46
|
artifactUrl,
|
|
@@ -248,6 +253,7 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
248
253
|
uiState.dagInspectorAttempt = null;
|
|
249
254
|
uiState.dagGraphViewportState = null;
|
|
250
255
|
uiState.dagTimelineViewportState = null;
|
|
256
|
+
uiState.dagTimelineAutoScrollEnabled = true;
|
|
251
257
|
}
|
|
252
258
|
// AC-001:同会话内重新进入同一 dagRunId 保持当前图视图模式(不切回逻辑拓扑)。
|
|
253
259
|
uiState.dagGraphViewMode = dagGraphViewModes.get(dagRunId) ?? "topology";
|
|
@@ -364,7 +370,9 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
364
370
|
"page-action-btn",
|
|
365
371
|
"在操作台中止此运行 →",
|
|
366
372
|
);
|
|
367
|
-
interruptLink.href =
|
|
373
|
+
interruptLink.href = withWorkspaceQuery(
|
|
374
|
+
`/#/operate/recovery?dagRunId=${encodeURIComponent(dag.dagRunId)}&intent=interrupt`,
|
|
375
|
+
);
|
|
368
376
|
interruptLink.setAttribute("data-testid", "inspect-dag-interrupt-link");
|
|
369
377
|
interruptLink.title = "只跳转到操作台 Recovery,不会在观测页执行中止";
|
|
370
378
|
primaryEntries.push(["协作中止", interruptLink]);
|
|
@@ -327,7 +327,9 @@ function buildRow(run) {
|
|
|
327
327
|
|
|
328
328
|
const nameTd = document.createElement("td");
|
|
329
329
|
const nameLink = el("a", "dags-name-link", run.title || run.dagRunId);
|
|
330
|
-
nameLink.href =
|
|
330
|
+
nameLink.href = inspectPathToCanonicalHref(
|
|
331
|
+
`/dag/${encodeURIComponent(run.dagRunId)}`,
|
|
332
|
+
);
|
|
331
333
|
nameLink.addEventListener("click", (event) => {
|
|
332
334
|
event.preventDefault();
|
|
333
335
|
event.stopPropagation();
|
|
@@ -35,7 +35,13 @@ import {
|
|
|
35
35
|
parseMarkdownBlocks,
|
|
36
36
|
markdownLinkHref,
|
|
37
37
|
} from "../format.js";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
parseRoute,
|
|
40
|
+
navigate,
|
|
41
|
+
buildHashPath,
|
|
42
|
+
inspectPathToCanonicalHref,
|
|
43
|
+
withWorkspaceQuery,
|
|
44
|
+
} from "../router.js";
|
|
39
45
|
import { fetchJson, artifactUrl, parseArtifactPreviewResponse } from "../api.js";
|
|
40
46
|
import {
|
|
41
47
|
objectRouteLink,
|
|
@@ -118,14 +124,14 @@ async function renderNightStrip() {
|
|
|
118
124
|
|
|
119
125
|
const actions = el("div", "night-strip-actions");
|
|
120
126
|
const detail = el("a", "page-action-btn", "夜间详情");
|
|
121
|
-
detail.href = "
|
|
127
|
+
detail.href = inspectPathToCanonicalHref("/night");
|
|
122
128
|
detail.addEventListener("click", (e) => {
|
|
123
129
|
e.preventDefault();
|
|
124
130
|
navigate("/night");
|
|
125
131
|
});
|
|
126
132
|
actions.appendChild(detail);
|
|
127
133
|
const manage = el("a", "page-action-btn night-strip-manage", "晨审处置 →");
|
|
128
|
-
manage.href = "/#/operate/night";
|
|
134
|
+
manage.href = withWorkspaceQuery("/#/operate/night");
|
|
129
135
|
manage.title = "夜间计划的管理与晨审处置在操作台完成(Inspect 保持只读)";
|
|
130
136
|
actions.appendChild(manage);
|
|
131
137
|
strip.appendChild(actions);
|
|
@@ -528,7 +534,7 @@ export async function renderDashboard(scrollTo) {
|
|
|
528
534
|
workerBlock.appendChild(el("div", "risk-total", String(block.total)));
|
|
529
535
|
workerBlock.appendChild(el("p", "risk-summary", block.summary));
|
|
530
536
|
const link = el("a", "risk-link", "查看异常 Task →");
|
|
531
|
-
link.href = "
|
|
537
|
+
link.href = inspectPathToCanonicalHref("/failures");
|
|
532
538
|
link.addEventListener("click", (event) => {
|
|
533
539
|
event.preventDefault();
|
|
534
540
|
navigate("/failures");
|
|
@@ -556,7 +562,7 @@ export async function renderDashboard(scrollTo) {
|
|
|
556
562
|
const head = el("div", "section-heading-row");
|
|
557
563
|
head.appendChild(el("h3", "section-heading", UI_TEXT.recentDags));
|
|
558
564
|
const allLink = el("a", "section-heading-action", UI_TEXT.viewAllDags);
|
|
559
|
-
allLink.href = "
|
|
565
|
+
allLink.href = inspectPathToCanonicalHref("/dags?page=1&pageSize=20");
|
|
560
566
|
allLink.setAttribute("aria-label", "查看全部 DAG 运行历史");
|
|
561
567
|
allLink.addEventListener("click", (event) => {
|
|
562
568
|
event.preventDefault();
|
|
@@ -686,7 +692,9 @@ function syncTableRow(row, cells) {
|
|
|
686
692
|
function buildDagTimelineItem(dag) {
|
|
687
693
|
const progress = dagProgress(dag);
|
|
688
694
|
const item = el("a", "dag-run-timeline-item");
|
|
689
|
-
item.href =
|
|
695
|
+
item.href = inspectPathToCanonicalHref(
|
|
696
|
+
`/dag/${encodeURIComponent(dag.dagRunId)}`,
|
|
697
|
+
);
|
|
690
698
|
item.title = dag.title || dag.dagRunId;
|
|
691
699
|
item.addEventListener("click", (event) => {
|
|
692
700
|
event.preventDefault();
|
|
@@ -8,7 +8,12 @@ import {
|
|
|
8
8
|
livenessBadge,
|
|
9
9
|
truncateText,
|
|
10
10
|
} from "../format.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
parseRoute,
|
|
13
|
+
navigate,
|
|
14
|
+
buildHashPath,
|
|
15
|
+
inspectPathToCanonicalHref,
|
|
16
|
+
} from "../router.js";
|
|
12
17
|
import { fetchJson } from "../api.js";
|
|
13
18
|
import { objectRouteLink } from "../relations.js";
|
|
14
19
|
import {
|
|
@@ -118,7 +123,7 @@ function taskPath(task) {
|
|
|
118
123
|
|
|
119
124
|
function linkTo(path, label, className) {
|
|
120
125
|
const a = el("a", className || "object-link", label);
|
|
121
|
-
a.href =
|
|
126
|
+
a.href = inspectPathToCanonicalHref(path);
|
|
122
127
|
a.addEventListener("click", (e) => {
|
|
123
128
|
e.preventDefault();
|
|
124
129
|
e.stopPropagation();
|
|
@@ -35,7 +35,12 @@ import {
|
|
|
35
35
|
parseMarkdownBlocks,
|
|
36
36
|
markdownLinkHref,
|
|
37
37
|
} from "../format.js";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
parseRoute,
|
|
40
|
+
navigate,
|
|
41
|
+
buildHashPath,
|
|
42
|
+
inspectPathToCanonicalHref,
|
|
43
|
+
} from "../router.js";
|
|
39
44
|
import {
|
|
40
45
|
fetchJson,
|
|
41
46
|
artifactUrl,
|
|
@@ -176,7 +181,9 @@ export function renderRunDagProgress(task, snapshot) {
|
|
|
176
181
|
"详情",
|
|
177
182
|
(() => {
|
|
178
183
|
const a = el("a", "link", "查看 DAG 详情 →");
|
|
179
|
-
a.href =
|
|
184
|
+
a.href = inspectPathToCanonicalHref(
|
|
185
|
+
`/dag/${encodeURIComponent(dag.dagRunId)}`,
|
|
186
|
+
);
|
|
180
187
|
a.addEventListener("click", (e) => {
|
|
181
188
|
e.preventDefault();
|
|
182
189
|
navigate(`/dag/${encodeURIComponent(dag.dagRunId)}`);
|
|
@@ -295,7 +302,9 @@ export function renderRunPanels(task, events, snapshot) {
|
|
|
295
302
|
li.appendChild(marker);
|
|
296
303
|
if (step.label === "run-dag" && dag?.dagRunId) {
|
|
297
304
|
const link = document.createElement("a");
|
|
298
|
-
link.href =
|
|
305
|
+
link.href = inspectPathToCanonicalHref(
|
|
306
|
+
`/dag/${encodeURIComponent(dag.dagRunId)}`,
|
|
307
|
+
);
|
|
299
308
|
link.className = "step-link";
|
|
300
309
|
link.textContent = "DAG →";
|
|
301
310
|
link.addEventListener("click", (e) => {
|
|
@@ -7,12 +7,72 @@ import { fetchJson } from "../api.js";
|
|
|
7
7
|
import {
|
|
8
8
|
uiState,
|
|
9
9
|
updateDagTimelineViewportState,
|
|
10
|
-
computeFollowLatest,
|
|
11
10
|
} from "../state.js";
|
|
12
11
|
|
|
13
12
|
/** Default visible lines for tool result preview before expand. */
|
|
14
13
|
export const TOOL_RESULT_PREVIEW_LINES = 20;
|
|
15
14
|
|
|
15
|
+
function isTimelineAutoScrollEnabled() {
|
|
16
|
+
return uiState.dagTimelineAutoScrollEnabled !== false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function scrollTimelineToLatest(content) {
|
|
20
|
+
content.scrollLeft = 0;
|
|
21
|
+
content.scrollTop = content.scrollHeight;
|
|
22
|
+
uiState.dagTimelineViewportState = updateDagTimelineViewportState(
|
|
23
|
+
uiState.dagTimelineViewportState,
|
|
24
|
+
uiState.currentDagRunId,
|
|
25
|
+
content.dataset.nodeId,
|
|
26
|
+
content.scrollLeft,
|
|
27
|
+
content.scrollTop,
|
|
28
|
+
true,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Floating, explicit live-follow control for the execution-record viewport. */
|
|
33
|
+
export function createTimelineAutoScrollControl(content) {
|
|
34
|
+
const dock = el("div", "process-timeline-autoscroll-dock");
|
|
35
|
+
const button = document.createElement("button");
|
|
36
|
+
button.type = "button";
|
|
37
|
+
const signal = el("span", "process-timeline-autoscroll-signal");
|
|
38
|
+
signal.setAttribute("aria-hidden", "true");
|
|
39
|
+
const icon = el("i", "ri-arrow-down-line");
|
|
40
|
+
icon.setAttribute("aria-hidden", "true");
|
|
41
|
+
button.appendChild(signal);
|
|
42
|
+
button.appendChild(icon);
|
|
43
|
+
|
|
44
|
+
const sync = () => {
|
|
45
|
+
const enabled = isTimelineAutoScrollEnabled();
|
|
46
|
+
const actionLabel = enabled ? "关闭自动滚动" : "自动滚动";
|
|
47
|
+
button.className = `process-timeline-autoscroll${enabled ? " is-active" : ""}`;
|
|
48
|
+
button.setAttribute("aria-pressed", String(enabled));
|
|
49
|
+
button.setAttribute("aria-label", actionLabel);
|
|
50
|
+
button.setAttribute("data-tooltip", actionLabel);
|
|
51
|
+
icon.className = enabled ? "ri-arrow-down-line" : "ri-pause-mini-fill";
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
button.addEventListener("click", () => {
|
|
55
|
+
const enabled = !isTimelineAutoScrollEnabled();
|
|
56
|
+
uiState.dagTimelineAutoScrollEnabled = enabled;
|
|
57
|
+
if (enabled) scrollTimelineToLatest(content);
|
|
58
|
+
else {
|
|
59
|
+
uiState.dagTimelineViewportState = updateDagTimelineViewportState(
|
|
60
|
+
uiState.dagTimelineViewportState,
|
|
61
|
+
uiState.currentDagRunId,
|
|
62
|
+
content.dataset.nodeId,
|
|
63
|
+
content.scrollLeft,
|
|
64
|
+
content.scrollTop,
|
|
65
|
+
false,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
sync();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
sync();
|
|
72
|
+
dock.appendChild(button);
|
|
73
|
+
return dock;
|
|
74
|
+
}
|
|
75
|
+
|
|
16
76
|
export function normalizeSessionEventFields(event) {
|
|
17
77
|
if (!event || typeof event !== "object") return {};
|
|
18
78
|
const args = event.args ?? event.input ?? event.toolInput;
|
|
@@ -951,6 +1011,7 @@ export function renderSessionTimeline(content, nodeId, options = {}) {
|
|
|
951
1011
|
});
|
|
952
1012
|
toolbar.appendChild(exportBtn);
|
|
953
1013
|
content.appendChild(toolbar);
|
|
1014
|
+
content.appendChild(createTimelineAutoScrollControl(content));
|
|
954
1015
|
|
|
955
1016
|
const timelineItems = filterExecutionRecordItems(
|
|
956
1017
|
buildRichTimelineItems(visible.events, { showProtocol }),
|
|
@@ -1030,23 +1091,18 @@ export function renderSessionTimeline(content, nodeId, options = {}) {
|
|
|
1030
1091
|
content.addEventListener(
|
|
1031
1092
|
"scroll",
|
|
1032
1093
|
() => {
|
|
1033
|
-
const followLatest = computeFollowLatest(
|
|
1034
|
-
content.scrollTop,
|
|
1035
|
-
content.scrollHeight,
|
|
1036
|
-
content.clientHeight,
|
|
1037
|
-
);
|
|
1038
1094
|
uiState.dagTimelineViewportState = updateDagTimelineViewportState(
|
|
1039
1095
|
uiState.dagTimelineViewportState,
|
|
1040
1096
|
uiState.currentDagRunId,
|
|
1041
1097
|
nodeId,
|
|
1042
1098
|
content.scrollLeft,
|
|
1043
1099
|
content.scrollTop,
|
|
1044
|
-
|
|
1100
|
+
isTimelineAutoScrollEnabled(),
|
|
1045
1101
|
);
|
|
1046
1102
|
},
|
|
1047
1103
|
{ passive: true },
|
|
1048
1104
|
);
|
|
1049
|
-
if (
|
|
1105
|
+
if (isTimelineAutoScrollEnabled()) {
|
|
1050
1106
|
content.scrollLeft = timelineState?.scrollLeft ?? 0;
|
|
1051
1107
|
content.scrollTop = content.scrollHeight;
|
|
1052
1108
|
} else {
|
|
@@ -1058,6 +1114,7 @@ export function renderSessionTimeline(content, nodeId, options = {}) {
|
|
|
1058
1114
|
function rerenderSessionTimeline(content, nodeId, options) {
|
|
1059
1115
|
const scrollTop = content.scrollTop;
|
|
1060
1116
|
const scrollLeft = content.scrollLeft;
|
|
1117
|
+
const autoScrollEnabled = isTimelineAutoScrollEnabled();
|
|
1061
1118
|
const preserved = [...content.children].filter((child) =>
|
|
1062
1119
|
String(child.className ?? "")
|
|
1063
1120
|
.split(/\s+/)
|
|
@@ -1066,6 +1123,8 @@ function rerenderSessionTimeline(content, nodeId, options) {
|
|
|
1066
1123
|
while (content.firstChild) content.removeChild(content.firstChild);
|
|
1067
1124
|
for (const child of preserved) content.appendChild(child);
|
|
1068
1125
|
renderSessionTimeline(content, nodeId, options);
|
|
1069
|
-
|
|
1070
|
-
|
|
1126
|
+
if (!autoScrollEnabled) {
|
|
1127
|
+
content.scrollTop = scrollTop;
|
|
1128
|
+
content.scrollLeft = scrollLeft;
|
|
1129
|
+
}
|
|
1071
1130
|
}
|
|
@@ -36,7 +36,12 @@ import {
|
|
|
36
36
|
markdownLinkHref,
|
|
37
37
|
formatLedgerSummary,
|
|
38
38
|
} from "../format.js";
|
|
39
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
parseRoute,
|
|
41
|
+
navigate,
|
|
42
|
+
buildHashPath,
|
|
43
|
+
inspectPathToCanonicalHref,
|
|
44
|
+
} from "../router.js";
|
|
40
45
|
import {
|
|
41
46
|
fetchJson,
|
|
42
47
|
fetchJsonResult,
|
|
@@ -133,7 +138,7 @@ export async function renderTaskDetail(featureId, taskId) {
|
|
|
133
138
|
if (!c?.featureId || !c?.taskId) continue;
|
|
134
139
|
const path = `/feature/${encodeURIComponent(c.featureId)}/task/${encodeURIComponent(c.taskId)}`;
|
|
135
140
|
const a = el("a", "object-link", `${c.featureId}::${c.taskId}`);
|
|
136
|
-
a.href =
|
|
141
|
+
a.href = inspectPathToCanonicalHref(path);
|
|
137
142
|
a.addEventListener("click", (e) => {
|
|
138
143
|
e.preventDefault();
|
|
139
144
|
navigate(path);
|
|
@@ -307,14 +307,18 @@ export function classifyBackendTestCorrespondenceRepair(facts, layout) {
|
|
|
307
307
|
const markdownReasons = [];
|
|
308
308
|
const pytestReasons = [];
|
|
309
309
|
const counts = bindingCounts(entry);
|
|
310
|
-
if (entry.
|
|
311
|
-
|
|
310
|
+
if (entry.cardinality !== "0:1" &&
|
|
311
|
+
entry.testPoints.some((point) => (counts.get(point) ?? 0) !== 1)) {
|
|
312
|
+
// Only ### 测试点 inventory must be bound exactly once. Extra
|
|
313
|
+
// automation-mapping TPs (typical: 横切 listed only under 跨切证据)
|
|
314
|
+
// are pytest-owned docstring/repair defects, not Markdown BLOCKED.
|
|
312
315
|
markdownReasons.push("markdown-test-point-binding-invalid");
|
|
313
316
|
}
|
|
314
317
|
if (entry.declaredScript && entry.declaredScript !== entry.expectedScript) {
|
|
315
318
|
markdownReasons.push("markdown-script-declaration-invalid");
|
|
316
319
|
}
|
|
317
|
-
|
|
320
|
+
const evidenceOnly = isEvidenceOnlyCorrespondenceEntry(entry);
|
|
321
|
+
if (!evidenceOnly && entry.cardinality === "1:0")
|
|
318
322
|
pytestReasons.push("missing-pytest-symbol");
|
|
319
323
|
if (entry.cardinality === "1:N")
|
|
320
324
|
pytestReasons.push("multiple-pytest-symbols");
|
|
@@ -325,12 +329,15 @@ export function classifyBackendTestCorrespondenceRepair(facts, layout) {
|
|
|
325
329
|
if (entry.declaredPrimarySymbol && entry.pytestSymbols.some((symbol) => symbol !== entry.declaredPrimarySymbol)) {
|
|
326
330
|
pytestReasons.push("pytest-primary-symbol-mismatch");
|
|
327
331
|
}
|
|
328
|
-
if (entry.variantTestPoints.some((point) => !entry.parameterIds.includes(point)))
|
|
332
|
+
if (!evidenceOnly && entry.variantTestPoints.some((point) => !entry.parameterIds.includes(point))) {
|
|
329
333
|
pytestReasons.push("variant-parameter-missing");
|
|
330
|
-
|
|
334
|
+
}
|
|
335
|
+
if (!evidenceOnly && entry.assertionTestPoints.some((point) => !entry.mappedTestPoints.includes(point))) {
|
|
331
336
|
pytestReasons.push("assertion-binding-missing");
|
|
332
|
-
|
|
337
|
+
}
|
|
338
|
+
if (!evidenceOnly && entry.crossCuttingTestPoints.some((point) => !entry.mappedTestPoints.includes(point))) {
|
|
333
339
|
pytestReasons.push("cross-cutting-binding-missing");
|
|
340
|
+
}
|
|
334
341
|
if (entry.parameterIds.some((point) => !entry.testPoints.includes(point)))
|
|
335
342
|
pytestReasons.push("pytest-test-point-binding-extra");
|
|
336
343
|
if (entry.payloadAssessment.status === "UNSAFE")
|
|
@@ -339,7 +346,7 @@ export function classifyBackendTestCorrespondenceRepair(facts, layout) {
|
|
|
339
346
|
!["TEST_POINT_BINDING_DUPLICATE", "PAYLOAD_CONTRACT_UNAVAILABLE"].includes(entry.status)) {
|
|
340
347
|
pytestReasons.push(`correspondence-${entry.status.toLowerCase().replaceAll("_", "-")}`);
|
|
341
348
|
}
|
|
342
|
-
if (entry.status === "PAYLOAD_CONTRACT_UNAVAILABLE") {
|
|
349
|
+
if (entry.status === "PAYLOAD_CONTRACT_UNAVAILABLE" && entry.cardinality !== "0:1") {
|
|
343
350
|
markdownReasons.push("markdown-payload-contract-unavailable");
|
|
344
351
|
}
|
|
345
352
|
const paths = orderedUnique([entry.expectedScript, ...entry.actualScripts].filter(safePytestPath));
|
|
@@ -796,6 +803,16 @@ function isEvidenceOnlyMarkdownCase(testCase) {
|
|
|
796
803
|
!hasVariant &&
|
|
797
804
|
hasNonVariant);
|
|
798
805
|
}
|
|
806
|
+
function isEvidenceOnlyCorrespondenceEntry(entry) {
|
|
807
|
+
return (entry.status === "EXACT_1_TO_1" &&
|
|
808
|
+
entry.cardinality === "1:0" &&
|
|
809
|
+
!entry.declaredScript &&
|
|
810
|
+
!entry.declaredPrimarySymbol &&
|
|
811
|
+
entry.variantTestPoints.length === 0 &&
|
|
812
|
+
(entry.assertionTestPoints.length > 0 || entry.crossCuttingTestPoints.length > 0) &&
|
|
813
|
+
entry.pytestSymbols.length === 0 &&
|
|
814
|
+
entry.actualScripts.length === 0);
|
|
815
|
+
}
|
|
799
816
|
function payloadContract(body) {
|
|
800
817
|
const contractValue = automationLabelBody(body, ["Payload Contract", "载荷合同"]);
|
|
801
818
|
const requiredValue = automationLabelBody(body, ["Payload Required Paths", "载荷必需路径"]);
|
|
@@ -804,7 +821,7 @@ function payloadContract(body) {
|
|
|
804
821
|
const tokens = (value) => orderedUnique(value
|
|
805
822
|
.split(/[,;,;]/)
|
|
806
823
|
.map((item) => item.trim())
|
|
807
|
-
.filter((item) => !/^(?:none|无|not-applicable|n\/a)$/i.test(item))
|
|
824
|
+
.filter((item) => !/^(?:none|无|not-applicable|n\/a|true|false)$/i.test(item))
|
|
808
825
|
.filter((item) => /^[A-Za-z_][A-Za-z0-9_.]*$/.test(item)));
|
|
809
826
|
const enumValues = {};
|
|
810
827
|
for (const assignment of enumValue.split(/[,;,;]/).map((item) => item.trim()).filter(Boolean)) {
|
|
@@ -1705,6 +1722,20 @@ def is_direct_transport_call(node):
|
|
|
1705
1722
|
if isinstance(current,ast.Name): receiver_tokens.append(current.id.lower())
|
|
1706
1723
|
return any(token in {'requests','httpx','client','session','api_client','http_client'} or token.endswith('_client') for token in receiver_tokens)
|
|
1707
1724
|
|
|
1725
|
+
HTTP_METHODS={'GET','POST','PUT','PATCH','DELETE','HEAD','OPTIONS'}
|
|
1726
|
+
HTTP_FIXTURE_NAMES={'http','http_client','client','api_client','session'}
|
|
1727
|
+
|
|
1728
|
+
def is_fixture_http_call(node):
|
|
1729
|
+
# R12: http("POST", path, json_body={"title": title}) is a Name-call fixture, not client.post.
|
|
1730
|
+
# R15: http_client(operation, path, json_body={...}) still transports when operation is a parametrized method.
|
|
1731
|
+
if not isinstance(node,ast.Call) or not isinstance(node.func,ast.Name) or not node.args: return False
|
|
1732
|
+
first=node.args[0]
|
|
1733
|
+
if isinstance(first,ast.Constant) and isinstance(first.value,str) and first.value.upper() in HTTP_METHODS:
|
|
1734
|
+
return True
|
|
1735
|
+
func=node.func.id.lower()
|
|
1736
|
+
httpish=func in HTTP_FIXTURE_NAMES or func.endswith('_client')
|
|
1737
|
+
return httpish and isinstance(first,ast.Name)
|
|
1738
|
+
|
|
1708
1739
|
def payload_nodes(fn):
|
|
1709
1740
|
result=[]
|
|
1710
1741
|
assigned={}
|
|
@@ -1727,7 +1758,7 @@ def payload_nodes(fn):
|
|
|
1727
1758
|
# Observe local payload/body variables only when they flow into a direct
|
|
1728
1759
|
# HTTP transport call. Arbitrary setup variables are not target requests.
|
|
1729
1760
|
for node in ast.walk(fn):
|
|
1730
|
-
if not is_direct_transport_call(node): continue
|
|
1761
|
+
if not (is_direct_transport_call(node) or is_fixture_http_call(node)): continue
|
|
1731
1762
|
for keyword in node.keywords:
|
|
1732
1763
|
if keyword.arg in PAYLOAD_NAMES: result.extend(payload_expr_nodes(keyword.value,assigned,parameters))
|
|
1733
1764
|
return result
|