@tea-agent/loop-agent 0.24.10 → 0.24.11-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.
- package/CHANGELOG.md +12 -0
- package/dist/commands/init.js +2 -16
- package/dist/executors/shell-executor.js +6 -122
- package/dist/worker/cli.js +14 -59
- package/dist/worker/delivery/git-transaction.js +7 -32
- package/dist/worker/delivery/package.js +5 -9
- package/dist/worker/delivery/verification-bundle.js +5 -26
- package/dist/worker/observe/routes.js +0 -17
- package/dist/worker/observe/static/api.js +0 -9
- package/dist/worker/observe/static/constants.js +0 -9
- package/dist/worker/observe/static/state.js +0 -14
- package/dist/worker/observe/static/styles.css +0 -74
- package/dist/worker/observe/static/views/dag-inspector.js +15 -371
- package/dist/worker/outcomes/projector.js +1 -5
- package/dist/worker/runner/run-ready.js +1 -41
- package/dist/workflows/dag/backend-test-markdown-workflow.js +9 -75
- package/dist/workflows/dag/backend-test-result-contract.js +0 -103
- package/dist/workflows/dag/frontend-test-result-contract.js +41 -106
- package/dist/workflows/dag/init-hybrid.js +14 -13
- package/dist/workflows/dag/node-execution.js +2 -3
- package/dist/workflows/dag/types.js +0 -2
- package/dist/workflows/dag/validate.js +2 -3
- package/docs/architecture/worker-and-feature.md +11 -0
- package/docs/init-surface.manifest.json +3 -0
- package/docs/templates/agent-dag.schema.json +9 -0
- package/docs/templates/frontend-implementation-contract.schema.json +2 -2
- package/package.json +1 -1
- package/skills/frontend-bounded-implement/SKILL.md +53 -0
- package/skills/frontend-implementation/SKILL.md +3 -7
- package/skills/frontend-implementation/references/node-contracts.md +2 -2
- package/dist/worker/observe/dag-run-artifacts.js +0 -90
- package/dist/worker/observe/node-input.js +0 -444
|
@@ -2010,80 +2010,6 @@ body.is-resizing-dag-graph {
|
|
|
2010
2010
|
.spec-evidence-section { padding-bottom: var(--space-4); border-bottom: 1px solid var(--hairline); }
|
|
2011
2011
|
.spec-evidence-section + .spec-evidence-section { margin-top: var(--space-4); }
|
|
2012
2012
|
.spec-evidence-section h4 { margin: 0 0 var(--space-2); color: var(--ink); font-size: 12px; font-weight: 700; }
|
|
2013
|
-
|
|
2014
|
-
.node-input-root { display: flex; flex-direction: column; gap: var(--space-3); }
|
|
2015
|
-
.node-input-semantics {
|
|
2016
|
-
margin: 0;
|
|
2017
|
-
font-size: 12px;
|
|
2018
|
-
font-weight: 600;
|
|
2019
|
-
color: var(--muted);
|
|
2020
|
-
}
|
|
2021
|
-
.node-input-section {
|
|
2022
|
-
padding-bottom: var(--space-3);
|
|
2023
|
-
border-bottom: 1px solid var(--hairline);
|
|
2024
|
-
}
|
|
2025
|
-
.node-input-section h4 {
|
|
2026
|
-
margin: 0 0 var(--space-2);
|
|
2027
|
-
color: var(--ink);
|
|
2028
|
-
font-size: 12px;
|
|
2029
|
-
font-weight: 700;
|
|
2030
|
-
}
|
|
2031
|
-
.node-input-section h5 {
|
|
2032
|
-
margin: var(--space-2) 0;
|
|
2033
|
-
font-size: 12px;
|
|
2034
|
-
font-weight: 600;
|
|
2035
|
-
}
|
|
2036
|
-
.node-input-summary {
|
|
2037
|
-
display: grid;
|
|
2038
|
-
grid-template-columns: max-content 1fr;
|
|
2039
|
-
gap: 4px 12px;
|
|
2040
|
-
margin: 0;
|
|
2041
|
-
font-size: 12px;
|
|
2042
|
-
}
|
|
2043
|
-
.node-input-summary dt {
|
|
2044
|
-
margin: 0;
|
|
2045
|
-
color: var(--muted);
|
|
2046
|
-
font-weight: 600;
|
|
2047
|
-
}
|
|
2048
|
-
.node-input-summary dd {
|
|
2049
|
-
margin: 0;
|
|
2050
|
-
color: var(--ink);
|
|
2051
|
-
word-break: break-word;
|
|
2052
|
-
}
|
|
2053
|
-
.node-input-inherited {
|
|
2054
|
-
display: inline-block;
|
|
2055
|
-
margin-left: 4px;
|
|
2056
|
-
padding: 0 6px;
|
|
2057
|
-
border-radius: 999px;
|
|
2058
|
-
background: var(--surface-2, #f3f1ec);
|
|
2059
|
-
color: var(--muted);
|
|
2060
|
-
font-size: 11px;
|
|
2061
|
-
font-weight: 600;
|
|
2062
|
-
}
|
|
2063
|
-
.node-input-code-list,
|
|
2064
|
-
.node-input-command-list {
|
|
2065
|
-
margin: var(--space-2) 0 0;
|
|
2066
|
-
padding-left: 1.2rem;
|
|
2067
|
-
}
|
|
2068
|
-
.node-input-command-list pre {
|
|
2069
|
-
margin: 4px 0;
|
|
2070
|
-
padding: 8px;
|
|
2071
|
-
overflow: auto;
|
|
2072
|
-
background: var(--surface-2, #f3f1ec);
|
|
2073
|
-
border-radius: 6px;
|
|
2074
|
-
font-size: 12px;
|
|
2075
|
-
}
|
|
2076
|
-
.node-input-truncated,
|
|
2077
|
-
.node-input-warning {
|
|
2078
|
-
margin: var(--space-2) 0 0;
|
|
2079
|
-
font-size: 12px;
|
|
2080
|
-
color: var(--muted);
|
|
2081
|
-
}
|
|
2082
|
-
.node-input-error {
|
|
2083
|
-
margin: 0;
|
|
2084
|
-
color: var(--danger, #b42318);
|
|
2085
|
-
font-size: 13px;
|
|
2086
|
-
}
|
|
2087
2013
|
.spec-evidence-summary { margin: var(--space-2) 0 0; color: var(--body); font-size: 12px; line-height: 1.6; }
|
|
2088
2014
|
.spec-evidence-list { display: grid; gap: 6px; margin: var(--space-2) 0 0; padding: 0; list-style: none; }
|
|
2089
2015
|
.spec-evidence-list li { display: flex; align-items: flex-start; gap: 6px; color: var(--body); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
@@ -10,13 +10,12 @@ import {
|
|
|
10
10
|
UI_TEXT,
|
|
11
11
|
} from "../constants.js";
|
|
12
12
|
import { clearNode, el } from "../dom.js";
|
|
13
|
-
import { fetchJson, fetchSpecEvidenceFile
|
|
13
|
+
import { fetchJson, fetchSpecEvidenceFile } from "../api.js";
|
|
14
14
|
import { badge } from "../format.js";
|
|
15
15
|
import { renderMarkdown } from "../markdown-render.js";
|
|
16
16
|
import {
|
|
17
17
|
uiState,
|
|
18
18
|
makeSessionEventIdentity,
|
|
19
|
-
makeDagNodeInputIdentity,
|
|
20
19
|
openSpecEvidenceDetail,
|
|
21
20
|
closeSpecEvidenceDetail,
|
|
22
21
|
updateDagTimelineViewportState,
|
|
@@ -51,13 +50,9 @@ export function selectDagNode(dagRunId, nodeId) {
|
|
|
51
50
|
// into node B's spec-evidence panel (AC-007 regression guard).
|
|
52
51
|
uiState.specEvidenceDetail = null;
|
|
53
52
|
uiState.specEvidenceListEvidence = null;
|
|
54
|
-
uiState.dagNodeInputData = null;
|
|
55
|
-
uiState.dagNodeInputError = null;
|
|
56
|
-
uiState.dagNodeInputLoading = false;
|
|
57
53
|
// Bump the session-event identity token so any in-flight response for the
|
|
58
54
|
// previous node is rejected before it can mutate the current node cache.
|
|
59
55
|
uiState.sessionEventIdentity = makeSessionEventIdentity(dagRunId, nodeId);
|
|
60
|
-
uiState.dagNodeInputIdentity = makeDagNodeInputIdentity(dagRunId, nodeId);
|
|
61
56
|
}
|
|
62
57
|
void import("./dag.js").then((m) => m.renderDagDetail(dagRunId, false));
|
|
63
58
|
}
|
|
@@ -535,337 +530,16 @@ function renderSpecEvidenceDetail(content, dagRunId, nodeId) {
|
|
|
535
530
|
content.appendChild(wrapper);
|
|
536
531
|
}
|
|
537
532
|
|
|
538
|
-
function sourceLabel(source) {
|
|
539
|
-
if (source === "defaults") return "继承默认值";
|
|
540
|
-
if (source === "schema-default") return "schema 默认";
|
|
541
|
-
if (source === "merged") return "合并";
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
function appendMetaRow(dl, label, value, source) {
|
|
546
|
-
if (value == null || value === "") return;
|
|
547
|
-
const dt = el("dt", null, label);
|
|
548
|
-
const dd = el("dd", null, String(value));
|
|
549
|
-
const inherited = sourceLabel(source);
|
|
550
|
-
if (inherited) {
|
|
551
|
-
dd.appendChild(document.createTextNode(" "));
|
|
552
|
-
dd.appendChild(el("span", "node-input-inherited", inherited));
|
|
553
|
-
}
|
|
554
|
-
dl.appendChild(dt);
|
|
555
|
-
dl.appendChild(dd);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
function appendCodeList(parent, title, values) {
|
|
559
|
-
if (!values || values.length === 0) return;
|
|
560
|
-
const section = el("section", "node-input-section");
|
|
561
|
-
section.appendChild(el("h4", null, title));
|
|
562
|
-
const list = el("ul", "node-input-code-list");
|
|
563
|
-
for (const value of values) {
|
|
564
|
-
const item = document.createElement("li");
|
|
565
|
-
const code = document.createElement("code");
|
|
566
|
-
code.textContent = String(value);
|
|
567
|
-
item.appendChild(code);
|
|
568
|
-
list.appendChild(item);
|
|
569
|
-
}
|
|
570
|
-
section.appendChild(list);
|
|
571
|
-
parent.appendChild(section);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function renderDagNodeInputDetail(content, data) {
|
|
575
|
-
const wrap = el("div", "node-input-root");
|
|
576
|
-
wrap.appendChild(
|
|
577
|
-
el("p", "node-input-semantics", UI_TEXT.inputFrozenLabel),
|
|
578
|
-
);
|
|
579
|
-
|
|
580
|
-
if (data.summary) {
|
|
581
|
-
const section = el("section", "node-input-section");
|
|
582
|
-
section.appendChild(el("h4", null, "摘要"));
|
|
583
|
-
const dl = el("dl", "node-input-summary");
|
|
584
|
-
appendMetaRow(
|
|
585
|
-
dl,
|
|
586
|
-
"executor",
|
|
587
|
-
data.summary.executor,
|
|
588
|
-
data.summary.executorSource,
|
|
589
|
-
);
|
|
590
|
-
appendMetaRow(dl, "role", data.summary.role, null);
|
|
591
|
-
appendMetaRow(dl, "complexity", data.summary.complexity, null);
|
|
592
|
-
appendMetaRow(
|
|
593
|
-
dl,
|
|
594
|
-
"writePolicy",
|
|
595
|
-
data.summary.writePolicy,
|
|
596
|
-
data.summary.writePolicySource,
|
|
597
|
-
);
|
|
598
|
-
appendMetaRow(dl, "toolProfile", data.summary.toolProfile, null);
|
|
599
|
-
section.appendChild(dl);
|
|
600
|
-
wrap.appendChild(section);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
if (data.dependency) {
|
|
604
|
-
const section = el("section", "node-input-section");
|
|
605
|
-
section.appendChild(el("h4", null, "依赖"));
|
|
606
|
-
const dl = el("dl", "node-input-summary");
|
|
607
|
-
appendMetaRow(
|
|
608
|
-
dl,
|
|
609
|
-
"depends_on",
|
|
610
|
-
(data.dependency.dependsOn ?? []).join(", ") || "(none)",
|
|
611
|
-
null,
|
|
612
|
-
);
|
|
613
|
-
if (data.dependency.dependsPolicy) {
|
|
614
|
-
appendMetaRow(dl, "dependsPolicy", data.dependency.dependsPolicy, null);
|
|
615
|
-
}
|
|
616
|
-
if ((data.dependency.failureAwareDependsOn ?? []).length > 0) {
|
|
617
|
-
appendMetaRow(
|
|
618
|
-
dl,
|
|
619
|
-
"failureAwareDependsOn",
|
|
620
|
-
data.dependency.failureAwareDependsOn.join(", "),
|
|
621
|
-
null,
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
if (data.dependency.runIf) {
|
|
625
|
-
appendMetaRow(dl, "runIf", data.dependency.runIf, null);
|
|
626
|
-
}
|
|
627
|
-
section.appendChild(dl);
|
|
628
|
-
wrap.appendChild(section);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if (data.prompt) {
|
|
632
|
-
const section = el("section", "node-input-section");
|
|
633
|
-
section.appendChild(el("h4", null, "任务正文"));
|
|
634
|
-
if (data.prompt.source?.path) {
|
|
635
|
-
const meta = el("p", "muted");
|
|
636
|
-
meta.textContent = `source: ${data.prompt.source.path}${
|
|
637
|
-
data.prompt.source.sha256Prefix
|
|
638
|
-
? ` (sha256 ${data.prompt.source.sha256Prefix}…)`
|
|
639
|
-
: ""
|
|
640
|
-
}`;
|
|
641
|
-
section.appendChild(meta);
|
|
642
|
-
}
|
|
643
|
-
section.appendChild(renderMarkdown(data.prompt.text ?? ""));
|
|
644
|
-
if (data.prompt.truncated) {
|
|
645
|
-
section.appendChild(
|
|
646
|
-
el(
|
|
647
|
-
"p",
|
|
648
|
-
"node-input-truncated",
|
|
649
|
-
`已截断,仅显示前 ${data.prompt.maxBytes ?? 0} 字节(UTF-8)。`,
|
|
650
|
-
),
|
|
651
|
-
);
|
|
652
|
-
}
|
|
653
|
-
wrap.appendChild(section);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (data.executorInput) {
|
|
657
|
-
const section = el("section", "node-input-section");
|
|
658
|
-
section.appendChild(el("h4", null, "执行器输入摘要"));
|
|
659
|
-
const dl = el("dl", "node-input-summary");
|
|
660
|
-
appendMetaRow(dl, "kind", data.executorInput.kind, null);
|
|
661
|
-
if (data.executorInput.modelHint) {
|
|
662
|
-
appendMetaRow(dl, "modelHint", data.executorInput.modelHint, null);
|
|
663
|
-
}
|
|
664
|
-
section.appendChild(dl);
|
|
665
|
-
appendCodeList(section, "skills", data.executorInput.skills);
|
|
666
|
-
if (data.executorInput.shell) {
|
|
667
|
-
const shell = data.executorInput.shell;
|
|
668
|
-
const shellDl = el("dl", "node-input-summary");
|
|
669
|
-
appendMetaRow(shellDl, "preset", shell.preset, null);
|
|
670
|
-
appendMetaRow(shellDl, "cwd", shell.cwd, null);
|
|
671
|
-
appendMetaRow(shellDl, "timeoutMs", shell.timeoutMs, null);
|
|
672
|
-
appendMetaRow(
|
|
673
|
-
shellDl,
|
|
674
|
-
"nonZeroExitPolicy",
|
|
675
|
-
shell.nonZeroExitPolicy,
|
|
676
|
-
null,
|
|
677
|
-
);
|
|
678
|
-
appendMetaRow(
|
|
679
|
-
shellDl,
|
|
680
|
-
"gates",
|
|
681
|
-
(shell.gates ?? []).join(", ") || "(none)",
|
|
682
|
-
null,
|
|
683
|
-
);
|
|
684
|
-
section.appendChild(shellDl);
|
|
685
|
-
if ((shell.commands ?? []).length > 0) {
|
|
686
|
-
const list = el("ol", "node-input-command-list");
|
|
687
|
-
for (const command of shell.commands) {
|
|
688
|
-
const item = document.createElement("li");
|
|
689
|
-
const pre = document.createElement("pre");
|
|
690
|
-
const code = document.createElement("code");
|
|
691
|
-
code.textContent = String(command);
|
|
692
|
-
pre.appendChild(code);
|
|
693
|
-
item.appendChild(pre);
|
|
694
|
-
list.appendChild(item);
|
|
695
|
-
}
|
|
696
|
-
section.appendChild(list);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
if (data.executorInput.static) {
|
|
700
|
-
const staticBlock = data.executorInput.static;
|
|
701
|
-
const staticDl = el("dl", "node-input-summary");
|
|
702
|
-
appendMetaRow(staticDl, "status", staticBlock.status, null);
|
|
703
|
-
section.appendChild(staticDl);
|
|
704
|
-
section.appendChild(renderMarkdown(staticBlock.resultPreview ?? ""));
|
|
705
|
-
if (staticBlock.truncated) {
|
|
706
|
-
section.appendChild(
|
|
707
|
-
el(
|
|
708
|
-
"p",
|
|
709
|
-
"node-input-truncated",
|
|
710
|
-
`已截断,仅显示前 ${staticBlock.maxBytes ?? 0} 字节(UTF-8)。`,
|
|
711
|
-
),
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
wrap.appendChild(section);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
if (data.boundaries) {
|
|
719
|
-
const section = el("section", "node-input-section");
|
|
720
|
-
section.appendChild(el("h4", null, "边界与输出契约"));
|
|
721
|
-
const dl = el("dl", "node-input-summary");
|
|
722
|
-
appendMetaRow(dl, "outputMode", data.boundaries.outputMode, null);
|
|
723
|
-
appendMetaRow(
|
|
724
|
-
dl,
|
|
725
|
-
"firstProtocolLine",
|
|
726
|
-
data.boundaries.firstProtocolLine,
|
|
727
|
-
null,
|
|
728
|
-
);
|
|
729
|
-
section.appendChild(dl);
|
|
730
|
-
if (data.boundaries.outputContract) {
|
|
731
|
-
section.appendChild(el("h5", null, "outputContract"));
|
|
732
|
-
section.appendChild(renderMarkdown(data.boundaries.outputContract));
|
|
733
|
-
}
|
|
734
|
-
appendCodeList(section, "allowedPaths", data.boundaries.allowedPaths);
|
|
735
|
-
appendCodeList(section, "forbiddenPaths", data.boundaries.forbiddenPaths);
|
|
736
|
-
appendCodeList(section, "writeSet", data.boundaries.writeSet);
|
|
737
|
-
wrap.appendChild(section);
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
if (data.promptFingerprint?.exists) {
|
|
741
|
-
const section = el("section", "node-input-section");
|
|
742
|
-
section.appendChild(el("h4", null, "Assembled prompt 指纹"));
|
|
743
|
-
const dl = el("dl", "node-input-summary");
|
|
744
|
-
appendMetaRow(
|
|
745
|
-
dl,
|
|
746
|
-
"sha256",
|
|
747
|
-
data.promptFingerprint.sha256Prefix ?? "(parse failed)",
|
|
748
|
-
null,
|
|
749
|
-
);
|
|
750
|
-
appendMetaRow(
|
|
751
|
-
dl,
|
|
752
|
-
"lengthChars",
|
|
753
|
-
data.promptFingerprint.lengthChars,
|
|
754
|
-
null,
|
|
755
|
-
);
|
|
756
|
-
appendMetaRow(dl, "artifact", data.promptFingerprint.artifact, null);
|
|
757
|
-
section.appendChild(dl);
|
|
758
|
-
section.appendChild(
|
|
759
|
-
el("p", "muted", UI_TEXT.inputFingerprintNote),
|
|
760
|
-
);
|
|
761
|
-
wrap.appendChild(section);
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
if ((data.warnings ?? []).length > 0) {
|
|
765
|
-
const section = el("section", "node-input-section");
|
|
766
|
-
section.appendChild(el("h4", null, "警告"));
|
|
767
|
-
for (const warning of data.warnings) {
|
|
768
|
-
section.appendChild(el("p", "node-input-warning", String(warning)));
|
|
769
|
-
}
|
|
770
|
-
wrap.appendChild(section);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
content.appendChild(wrap);
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
function unavailableMessage(reason) {
|
|
777
|
-
if (reason === "unsupported-dynamic-node") {
|
|
778
|
-
return UI_TEXT.inputDynamicUnsupported;
|
|
779
|
-
}
|
|
780
|
-
if (reason === "run-spec-unavailable") {
|
|
781
|
-
return UI_TEXT.inputRunSpecUnavailable;
|
|
782
|
-
}
|
|
783
|
-
if (reason === "task-not-found") {
|
|
784
|
-
return UI_TEXT.inputUnavailable;
|
|
785
|
-
}
|
|
786
|
-
return UI_TEXT.noInput;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
async function renderDagNodeInput(content, dagRunId, node) {
|
|
790
|
-
const nodeId = node.nodeId;
|
|
791
|
-
const identity = makeDagNodeInputIdentity(dagRunId, nodeId);
|
|
792
|
-
uiState.dagNodeInputIdentity = identity;
|
|
793
|
-
uiState.dagNodeInputLoading = true;
|
|
794
|
-
uiState.dagNodeInputError = null;
|
|
795
|
-
|
|
796
|
-
clearNode(content);
|
|
797
|
-
const loading = el("p", "muted", UI_TEXT.inputLoading);
|
|
798
|
-
loading.setAttribute("role", "status");
|
|
799
|
-
loading.setAttribute("aria-live", "polite");
|
|
800
|
-
content.appendChild(loading);
|
|
801
|
-
|
|
802
|
-
const result = await fetchDagNodeInput(dagRunId, nodeId);
|
|
803
|
-
if (
|
|
804
|
-
uiState.dagNodeInputIdentity !== identity ||
|
|
805
|
-
uiState.selectedDagNodeId !== nodeId ||
|
|
806
|
-
uiState.currentDagRunId !== dagRunId ||
|
|
807
|
-
uiState.dagInspectorTab !== "input" ||
|
|
808
|
-
!content.isConnected ||
|
|
809
|
-
content.dataset.dagNodeId !== String(nodeId) ||
|
|
810
|
-
content.dataset.dagRunId !== String(dagRunId)
|
|
811
|
-
) {
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
uiState.dagNodeInputLoading = false;
|
|
816
|
-
clearNode(content);
|
|
817
|
-
|
|
818
|
-
if (!result.ok) {
|
|
819
|
-
const message =
|
|
820
|
-
result.body?.error ||
|
|
821
|
-
(result.status === 0
|
|
822
|
-
? UI_TEXT.inputError
|
|
823
|
-
: `${UI_TEXT.inputError}(HTTP ${result.status})`);
|
|
824
|
-
uiState.dagNodeInputError = message;
|
|
825
|
-
uiState.dagNodeInputData = null;
|
|
826
|
-
const error = el("p", "node-input-error", message);
|
|
827
|
-
error.setAttribute("role", "alert");
|
|
828
|
-
content.appendChild(error);
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
const data = result.body;
|
|
833
|
-
uiState.dagNodeInputData = data;
|
|
834
|
-
uiState.dagNodeInputError = null;
|
|
835
|
-
if (!data?.available) {
|
|
836
|
-
const empty = el(
|
|
837
|
-
"p",
|
|
838
|
-
"empty",
|
|
839
|
-
unavailableMessage(data?.availabilityReason),
|
|
840
|
-
);
|
|
841
|
-
empty.setAttribute("role", "status");
|
|
842
|
-
content.appendChild(empty);
|
|
843
|
-
if ((data?.warnings ?? []).length > 0) {
|
|
844
|
-
for (const warning of data.warnings) {
|
|
845
|
-
content.appendChild(el("p", "node-input-warning", String(warning)));
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
renderDagNodeInputDetail(content, data);
|
|
852
|
-
}
|
|
853
|
-
|
|
854
533
|
function fillDagInspectorContent(content, dagRunId, node) {
|
|
855
534
|
const previousRenderedNode = content.dataset.dagNodeId ?? "";
|
|
856
|
-
const
|
|
857
|
-
const nodeChanged =
|
|
858
|
-
previousRenderedNode !== String(node.nodeId ?? "") ||
|
|
859
|
-
previousRenderedRun !== String(dagRunId ?? "");
|
|
535
|
+
const nodeChanged = previousRenderedNode !== String(node.nodeId ?? "");
|
|
860
536
|
if (nodeChanged) {
|
|
861
537
|
// Drop any open spec-evidence preview + cached list so a stale A detail
|
|
862
538
|
// cannot survive into node B (AC-007 regression guard).
|
|
863
539
|
uiState.specEvidenceDetail = null;
|
|
864
540
|
uiState.specEvidenceListEvidence = null;
|
|
865
|
-
uiState.dagNodeInputData = null;
|
|
866
|
-
uiState.dagNodeInputError = null;
|
|
867
541
|
}
|
|
868
|
-
const activeTab = ["
|
|
542
|
+
const activeTab = ["timeline", "spec-evidence"].includes(
|
|
869
543
|
uiState.dagInspectorTab,
|
|
870
544
|
)
|
|
871
545
|
? uiState.dagInspectorTab
|
|
@@ -874,15 +548,12 @@ async function renderDagNodeInput(content, dagRunId, node) {
|
|
|
874
548
|
content.setAttribute("role", "tabpanel");
|
|
875
549
|
content.setAttribute("aria-labelledby", `dag-inspector-tab-${activeTab}`);
|
|
876
550
|
content.dataset.dagNodeId = String(node.nodeId ?? "");
|
|
877
|
-
content.dataset.dagRunId = String(dagRunId ?? "");
|
|
878
551
|
// Drop timeline-only classes when switching tabs so output layout stays clean.
|
|
879
552
|
content.className = "dag-inspector-content";
|
|
880
553
|
if (activeTab === "spec-evidence") {
|
|
881
554
|
void renderSpecEvidence(content, dagRunId, node.nodeId);
|
|
882
555
|
} else if (activeTab === "timeline") {
|
|
883
556
|
renderSessionTimeline(content, node.nodeId);
|
|
884
|
-
} else if (activeTab === "input") {
|
|
885
|
-
void renderDagNodeInput(content, dagRunId, node);
|
|
886
557
|
} else if (!node.outputPreview && !node.errorPreview) {
|
|
887
558
|
content.appendChild(el("p", "empty", UI_TEXT.noOutput));
|
|
888
559
|
} else {
|
|
@@ -921,7 +592,6 @@ function buildDagInspectorHeader(dagRunId, node) {
|
|
|
921
592
|
header.appendChild(controls);
|
|
922
593
|
|
|
923
594
|
const tabDefs = [
|
|
924
|
-
["input", "节点输入", "ri-login-box-line"],
|
|
925
595
|
["output", "节点输出", "ri-file-text-line"],
|
|
926
596
|
["timeline", "执行过程", "ri-route-line"],
|
|
927
597
|
["spec-evidence", "规范证据", "ri-book-open-line"],
|
|
@@ -990,17 +660,6 @@ function syncDagInspectorHeader(panel, dagRunId, node) {
|
|
|
990
660
|
}
|
|
991
661
|
|
|
992
662
|
function dagInspectorSignature(dagRunId, node) {
|
|
993
|
-
const inputRevision =
|
|
994
|
-
uiState.dagInspectorTab === "input"
|
|
995
|
-
? [
|
|
996
|
-
uiState.dagNodeInputIdentity,
|
|
997
|
-
uiState.dagNodeInputLoading,
|
|
998
|
-
uiState.dagNodeInputError ?? "",
|
|
999
|
-
uiState.dagNodeInputData?.availabilityReason ?? "",
|
|
1000
|
-
uiState.dagNodeInputData?.promptFingerprint?.sha256Prefix ?? "",
|
|
1001
|
-
node.status ?? "",
|
|
1002
|
-
]
|
|
1003
|
-
: null;
|
|
1004
663
|
return JSON.stringify([
|
|
1005
664
|
dagRunId,
|
|
1006
665
|
node.nodeId,
|
|
@@ -1008,7 +667,6 @@ function dagInspectorSignature(dagRunId, node) {
|
|
|
1008
667
|
node.outputPreview ?? "",
|
|
1009
668
|
node.errorPreview ?? "",
|
|
1010
669
|
uiState.dagInspectorTab === "timeline" ? uiState.sessionEventOffset : null,
|
|
1011
|
-
inputRevision,
|
|
1012
670
|
]);
|
|
1013
671
|
}
|
|
1014
672
|
|
|
@@ -1044,30 +702,17 @@ export function renderDagInspector(dagRunId, node, initial = true) {
|
|
|
1044
702
|
syncDagInspectorHeader(panel, dagRunId, node);
|
|
1045
703
|
if (panel.dataset.contentSignature === nextContentSignature) return;
|
|
1046
704
|
const previousNode = existingContent.dataset.dagNodeId ?? "";
|
|
1047
|
-
const
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
? false
|
|
1059
|
-
: nodeChanged ||
|
|
1060
|
-
computeFollowLatest(
|
|
1061
|
-
existingContent.scrollTop,
|
|
1062
|
-
existingContent.scrollHeight,
|
|
1063
|
-
existingContent.clientHeight,
|
|
1064
|
-
);
|
|
1065
|
-
const regionKey = `dag:${dagRunId}:${node.nodeId}:${isInputTab ? "input" : "output"}`;
|
|
1066
|
-
const viewportUpdater = isInputTab
|
|
1067
|
-
? "dagNodeInputViewportState"
|
|
1068
|
-
: "dagNodeOutputViewportState";
|
|
1069
|
-
uiState[viewportUpdater] = updateDagOutputViewportState(
|
|
1070
|
-
uiState[viewportUpdater],
|
|
705
|
+
const nodeChanged = previousNode !== String(node.nodeId ?? "");
|
|
706
|
+
const followLatest =
|
|
707
|
+
nodeChanged ||
|
|
708
|
+
computeFollowLatest(
|
|
709
|
+
existingContent.scrollTop,
|
|
710
|
+
existingContent.scrollHeight,
|
|
711
|
+
existingContent.clientHeight,
|
|
712
|
+
);
|
|
713
|
+
const regionKey = `dag:${dagRunId}:${node.nodeId}:output`;
|
|
714
|
+
uiState.dagNodeOutputViewportState = updateDagOutputViewportState(
|
|
715
|
+
uiState.dagNodeOutputViewportState,
|
|
1071
716
|
regionKey,
|
|
1072
717
|
existingContent.scrollLeft,
|
|
1073
718
|
existingContent.scrollTop,
|
|
@@ -1084,8 +729,7 @@ export function renderDagInspector(dagRunId, node, initial = true) {
|
|
|
1084
729
|
if (followLatest) {
|
|
1085
730
|
existingContent.scrollTop = existingContent.scrollHeight;
|
|
1086
731
|
} else {
|
|
1087
|
-
|
|
1088
|
-
existingContent.scrollTop = nodeChanged ? 0 : (saved?.scrollTop ?? 0);
|
|
732
|
+
existingContent.scrollTop = uiState.dagNodeOutputViewportState.scrollTop;
|
|
1089
733
|
}
|
|
1090
734
|
for (const [index, pre] of [
|
|
1091
735
|
...existingContent.querySelectorAll("pre"),
|
|
@@ -111,12 +111,8 @@ export async function projectOutcome(input) {
|
|
|
111
111
|
if (artifact.sha256 && artifact.sha256 !== recomputed) {
|
|
112
112
|
return contractError(`artifact sha256 mismatch for ${artifact.path}: declared=${artifact.sha256} actual=${recomputed}`);
|
|
113
113
|
}
|
|
114
|
-
// Persist portable repo-relative paths only (Delivery verifyArtifactRefs rejects abs paths).
|
|
115
|
-
const relativePath = path
|
|
116
|
-
.relative(path.resolve(input.repoRoot), resolved)
|
|
117
|
-
.replace(/\\/g, "/");
|
|
118
114
|
validatedArtifacts.push({
|
|
119
|
-
path:
|
|
115
|
+
path: artifact.path.replace(/\\/g, "/"),
|
|
120
116
|
sha256: recomputed,
|
|
121
117
|
...(artifact.kind ? { kind: artifact.kind } : {}),
|
|
122
118
|
...(artifact.schemaId ? { schemaId: artifact.schemaId } : {}),
|
|
@@ -304,51 +304,11 @@ export async function runReadyTasks(options) {
|
|
|
304
304
|
if (result.status !== "succeeded") {
|
|
305
305
|
await options.onTaskFinalized?.({ status: result.status, taskSpec, workerRunId: result.workerRunId, runRecordPath: result.runRecordPath });
|
|
306
306
|
}
|
|
307
|
-
const recordErrorMessage = errorMessage(error);
|
|
308
|
-
// Always project a Pool run fact for record-error so operators can
|
|
309
|
-
// mark-failed / retry without hand-editing Running state.
|
|
310
|
-
try {
|
|
311
|
-
await recordTaskPoolRun({
|
|
312
|
-
repoRoot: options.repoRoot,
|
|
313
|
-
run: {
|
|
314
|
-
schemaVersion: 1,
|
|
315
|
-
batchRunId,
|
|
316
|
-
workerRunId: result.workerRunId,
|
|
317
|
-
taskId: result.businessId,
|
|
318
|
-
featureId: taskSpec.feature_id,
|
|
319
|
-
status: "run-error",
|
|
320
|
-
recordedAt: new Date().toISOString(),
|
|
321
|
-
error: recordErrorMessage,
|
|
322
|
-
runRecordPath: result.runRecordPath,
|
|
323
|
-
...(result.workflow ? { workflow: result.workflow } : {}),
|
|
324
|
-
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
325
|
-
...(retryOfWorkerRunId ? { retryOfWorkerRunId } : {}),
|
|
326
|
-
},
|
|
327
|
-
});
|
|
328
|
-
await writeTaskPoolState(options.repoRoot, {
|
|
329
|
-
schemaVersion: 2,
|
|
330
|
-
featureId: taskSpec.feature_id,
|
|
331
|
-
taskId,
|
|
332
|
-
status: "Failed",
|
|
333
|
-
updatedAt: new Date().toISOString(),
|
|
334
|
-
workerRunId: result.workerRunId,
|
|
335
|
-
lastRunRecordPath: result.runRecordPath,
|
|
336
|
-
failure: {
|
|
337
|
-
category: "EnvFailure",
|
|
338
|
-
recommendedFollowUpKind: "manual-review",
|
|
339
|
-
derivedFollowUpTaskId: `${taskId}-record-error-review`,
|
|
340
|
-
source: "report-decision",
|
|
341
|
-
},
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
catch {
|
|
345
|
-
// Best-effort; batch still reports record-error.
|
|
346
|
-
}
|
|
347
307
|
tasks.push({
|
|
348
308
|
taskId,
|
|
349
309
|
workerRunId: result.workerRunId,
|
|
350
310
|
status: "record-error",
|
|
351
|
-
error:
|
|
311
|
+
error: errorMessage(error),
|
|
352
312
|
runRecordPath: result.runRecordPath,
|
|
353
313
|
});
|
|
354
314
|
break;
|