dsh-plugin-teamflow 0.1.4 → 0.1.6
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 +39 -0
- package/README.md +10 -0
- package/lib/client.js +173 -18
- package/lib/host.mjs +693 -337
- package/lib/store.mjs +3 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
> 本插件首次公开发布版本为 **v0.1.0**;发布前的内部迭代(v0.3~v0.13)记录于 `AGENTS.md` §5,对外统一归到 v0.1.0。
|
|
4
4
|
|
|
5
|
+
## [0.1.6] - 2026-09-07
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
- **评测层 L1+L2(prompt/注入改动收益评测)**:每次改 prompt/注入后可直接验证收益——L1 行为级契约测试(直接调用 prompt 工厂断言产出锚点,29 条契约分 HOST-ENFORCED/policy/structural 三级,改 prompt 一眼看出断了哪条、丢哪级保障)+ L2 回放语料一致性门禁(冻结真实形状的 QA-REPORT/ACCEPTANCE/dev 回复/蓝图产物,喂宿主真实解析器做 golden corpus 回归,零 LLM 成本)。语料只增不改,防评测过拟合
|
|
9
|
+
- **dev/qaFix 验证证据块**:开发回复末尾强制「[Verification evidence]」块(命令+退出码+断言计数+失败行引用,或显式 N/A),host 提取存证、阶段详情可见、可与命令日志交叉核对——开发阶段从「单方宣称全绿」升级为「可审计的具体自述」
|
|
10
|
+
- **代码级英文化(为 UI i18n 铺路)**:代码判断/命名全英文(阶段键 prd/design/scaffold/tech/dev/qa/acceptance、任务结构化键 taskKey),中文只留展示层;存量数据提供迁移脚本
|
|
11
|
+
|
|
12
|
+
### 改进
|
|
13
|
+
- **resume 断点续跑状态机化**:两级状态(大阶段 + 子图任务)聚合判定——有 done 尝试的任务即成功(历史失败不算失败),resume 只补跑「聚合后未成功」任务、复用已完成产物;不再读 backlog 子卡(残留失败卡不再污染判定);dev 部分成功时起点精确回开发补跑未完成,全 done 时正确落在 QA/验收
|
|
14
|
+
- **输出单轨制**:QA/验收的完整报告只写在任务夹文件(QA-REPORT.md/ACCEPTANCE.md),子代理回复仅摘要+路径——host 直接导入文件(缺陷表/核对表),杜绝「回复与文件不一致」的双轨问题
|
|
15
|
+
- **验收结论契约强度**:验收报告结论行必须为字面量模板(✅/⚠️/❌/📝 四档)且为文件最后一行;无结论行/空结论行 → 需人工确认(不再默认通过,防质量门禁漏报)
|
|
16
|
+
- **prompt 约束分级**:区分 [HOST-ENFORCED](host 真实强制,如单轨产物/结论行)与 [policy](自律 + 轻提醒),prompt 内不再自称 hard constraint
|
|
17
|
+
- **重试诊断包**:重试时把上次失败详情(outcome/护栏原因/拒绝词命中点/产出尾部)附进 prompt——盲试 → 带因重试;stalled(挂死/空转)不再自动重试
|
|
18
|
+
|
|
19
|
+
### 修复
|
|
20
|
+
- **token 计量适配宿主 session v2**:宿主新版会话已无 `events` 属性,计量读不到 → 流水线卡与图卡无「TOKEN · 官方口径」。修复:多源回退(snapshotEvents/ownEvents)+ usage 双路径(含 stream 内嵌),新 run 计量恢复
|
|
21
|
+
- **护栏挂死误杀**:QA 子代理正常干活却被判「10 分钟无事件」(宿主事件视图失明)——事件读取多源回退 + agent 活动守卫(非 idle 且已动手即不中止)
|
|
22
|
+
- **任务卡 token 统计**:子卡 usage 按 stage 引用直写(并发下不再错位/超计)
|
|
23
|
+
- **存量迁移脚本 taskKey 误判**:合法中文括号结尾的任务键不再被当作历史残留(幂等无损但计数虚高)
|
|
24
|
+
- **验收空结论行/裸否定词漏报**:四档词白名单校验覆盖 accepted 分支
|
|
25
|
+
|
|
26
|
+
### 其他
|
|
27
|
+
- AGENTS.md 注入面瘦身 64%;dsh 0.1.3-alpha.1 兼容性核对(依赖包名更新)
|
|
28
|
+
|
|
29
|
+
## [0.1.5] - 2026-09-01
|
|
30
|
+
|
|
31
|
+
### 新增
|
|
32
|
+
- **patch 档兑现「单 agent 直改 + 自测即交付」**:阶段集精简为确认单 → 单 agent 直改(2 段,无技术方案/QA/验收),开发完成(自测通过)即统一收口提交。UI 微调(按钮换位置/挪控件/改文案/间距/颜色)、常量调整、单点修复、回滚、笔误修正走最轻路径
|
|
33
|
+
|
|
34
|
+
### 改进
|
|
35
|
+
- **需求分诊重构为模型主导**:档位判断交给模型(自然语言语义,天然双语);正则收窄为确定性护栏(架构信号强升/UI 不低于轻量档/显式设计升档)。UI 微调类需求(不改变行为/交互逻辑)不再误判标准档
|
|
36
|
+
- **分诊输出失败自动纠错重试**:只输出开场白无 JSON 时带提示重试一次,仍失败才走正则兜底
|
|
37
|
+
|
|
38
|
+
### 修复
|
|
39
|
+
- **外部中止(aborted)不再误报「预算熔断」**:重启等外部中止单独标记,明确引导断点续跑(补跑失败任务,已完成任务复用)
|
|
40
|
+
- **patch 档不再误跑架构蓝图**(技术方案块补 `enabled('tech')` 门控)
|
|
41
|
+
- **分支名不再被档位词污染**(「显式的用 patch 模式」不再产出 `feat/patch`)
|
|
42
|
+
- **provider 错误细节记录**(阶段失败记录底层错误信息)
|
|
43
|
+
|
|
5
44
|
## [0.1.4] - 2026-08-29
|
|
6
45
|
|
|
7
46
|
### 修复
|
package/README.md
CHANGED
|
@@ -119,6 +119,16 @@ dsh-plugin-teamflow/
|
|
|
119
119
|
- Node.js ≥ 22.18;
|
|
120
120
|
- 依赖宿主提供的 `@deepseek-ai/dsh-*` 与 `react`(peerDependencies,宿主注入,无需单独安装)。
|
|
121
121
|
|
|
122
|
+
opencode### 版本锚定(dsh 宿主兼容性)
|
|
123
|
+
|
|
124
|
+
本插件开发与验证基于 **dsh git master(2026-09-04,≈ 0.1.3-alpha.1 发布线)**;npm 侧最新发布线 `0.1.2-rc.1`(next tag;`latest` 标签滞后为 0.0.1-rc.1,勿以 latest 判断)。`peerDependencies` 保持 `*`(宿主注入,宽松兼容)。
|
|
125
|
+
|
|
126
|
+
2026-09-04 兼容性核对(dsh 0.1.3-alpha.1):session 持久化 v2(write-lease/JSONL 快照/版本化导出)、attachment/file-upload 收口、Windows 子进程隐藏、workspace 全限定路径硬化——**全部兼容,插件无需调整**。
|
|
127
|
+
|
|
128
|
+
插件侧契约约束(dsh 升级后若行为异常先核对本段;锚定版本变更会在此更新):
|
|
129
|
+
- 插件注入的 session 事件(`tool-workflow/agent-start`、`user/message` 带 `source.kind='plugin'`)均在 released 词表内;**未来新增自定义事件类型须带 `ignorable: true`**,已知类型载荷不加 released 词表外键;
|
|
130
|
+
- `@deepseek-ai/dsh-client-modules` 自 0.1.2-rc.1 起替代 `@deepseek-ai/dsh-client-runtime`(后者已从 monorepo 移除)。
|
|
131
|
+
|
|
122
132
|
## 安装(对使用者)
|
|
123
133
|
|
|
124
134
|
```bash
|
package/lib/client.js
CHANGED
|
@@ -308,15 +308,37 @@ window.__ModuleLoader__.load({
|
|
|
308
308
|
interrupted: T.warn,
|
|
309
309
|
superseded: T.text2
|
|
310
310
|
};
|
|
311
|
+
/** 阶段英文键 → 图标/中文展示名(2026-09-06 英文化:journal.phase 为英文键,展示名统一走映射——未来 i18n 换表即换语言)。 */
|
|
311
312
|
const PHASE_ICON = {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
313
|
+
prd: "📋",
|
|
314
|
+
design: "🎨",
|
|
315
|
+
scaffold: "🏗️",
|
|
316
|
+
tech: "📐",
|
|
317
|
+
dev: "💻",
|
|
318
|
+
qa: "🧪",
|
|
319
|
+
acceptance: "✅"
|
|
319
320
|
};
|
|
321
|
+
const PHASE_NAME = {
|
|
322
|
+
prd: "PRD 产品需求",
|
|
323
|
+
design: "UI/UX 设计",
|
|
324
|
+
scaffold: "架构规划",
|
|
325
|
+
tech: "技术方案",
|
|
326
|
+
dev: "开发",
|
|
327
|
+
qa: "QA 测试",
|
|
328
|
+
acceptance: "产品验收"
|
|
329
|
+
};
|
|
330
|
+
const phaseNameOf = (p) => PHASE_NAME[p] || p || "—";
|
|
331
|
+
const phaseIconOf = (p) => PHASE_ICON[p] || "⚙️";
|
|
332
|
+
/** phase 归一:英文键直通;存量中文映射(防御性——新数据全英文)。 */
|
|
333
|
+
const phaseKeyOf = (p) => ({
|
|
334
|
+
"PRD 产品需求": "prd",
|
|
335
|
+
"UI/UX 设计": "design",
|
|
336
|
+
"架构规划": "scaffold",
|
|
337
|
+
"技术方案": "tech",
|
|
338
|
+
"开发": "dev",
|
|
339
|
+
"QA 测试": "qa",
|
|
340
|
+
"产品验收": "acceptance"
|
|
341
|
+
})[p] || String(p || "");
|
|
320
342
|
const RUN_STATUS_TEXT = {
|
|
321
343
|
pending: "等待中",
|
|
322
344
|
running: "进行中",
|
|
@@ -642,7 +664,20 @@ window.__ModuleLoader__.load({
|
|
|
642
664
|
textOverflow: "ellipsis",
|
|
643
665
|
whiteSpace: "nowrap"
|
|
644
666
|
}
|
|
645
|
-
}, s.label),
|
|
667
|
+
}, s.__taskKey || s.label), s.attempts && s.attempts.length > 1 ? h("span", {
|
|
668
|
+
title: `重试 ${s.attempts.length - 1} 次(共 ${s.attempts.length} 次尝试)`,
|
|
669
|
+
style: {
|
|
670
|
+
fontFamily: MONO,
|
|
671
|
+
fontSize: 10,
|
|
672
|
+
fontWeight: 800,
|
|
673
|
+
color: T.warn,
|
|
674
|
+
background: `color-mix(in srgb, ${T.warn} 14%, transparent)`,
|
|
675
|
+
borderRadius: 999,
|
|
676
|
+
padding: "0 6px",
|
|
677
|
+
lineHeight: "15px",
|
|
678
|
+
flex: "0 0 auto"
|
|
679
|
+
}
|
|
680
|
+
}, `↻${s.attempts.length - 1}`) : null, chip(stText(s.status), color, { dot: true }), h("span", { style: {
|
|
646
681
|
color: T.text2,
|
|
647
682
|
fontSize: 11,
|
|
648
683
|
opacity: .5
|
|
@@ -724,12 +759,12 @@ window.__ModuleLoader__.load({
|
|
|
724
759
|
fontWeight: 700,
|
|
725
760
|
background: `linear-gradient(90deg, color-mix(in srgb, ${g.headColor} 13%, transparent), color-mix(in srgb, ${g.headColor} 5%, transparent))`,
|
|
726
761
|
border: `1px solid color-mix(in srgb, ${g.headColor} 30%, transparent)`
|
|
727
|
-
} }, h("span", { style: { fontSize: 13.5 } },
|
|
762
|
+
} }, h("span", { style: { fontSize: 13.5 } }, phaseIconOf(g.phase)), h("span", { style: {
|
|
728
763
|
flex: 1,
|
|
729
764
|
overflow: "hidden",
|
|
730
765
|
textOverflow: "ellipsis",
|
|
731
766
|
whiteSpace: "nowrap"
|
|
732
|
-
} }, g.phase), g.stages.length > 1 ? h("span", { style: {
|
|
767
|
+
} }, phaseNameOf(g.phase)), g.stages.length > 1 ? h("span", { style: {
|
|
733
768
|
fontFamily: MONO,
|
|
734
769
|
fontSize: 10,
|
|
735
770
|
fontWeight: 800,
|
|
@@ -752,26 +787,32 @@ window.__ModuleLoader__.load({
|
|
|
752
787
|
paddingTop: 10
|
|
753
788
|
} }, g.stages.map((s) => FlowStageCard(s, s.seq, onOpen))));
|
|
754
789
|
}
|
|
755
|
-
/** 阶段详情抽屉(卡片点击打开;浮于画布右侧,不参与拖动/缩放)。
|
|
790
|
+
/** 阶段详情抽屉(卡片点击打开;浮于画布右侧,不参与拖动/缩放)。
|
|
791
|
+
* 2026-09-06 状态机化:同任务多次尝试 → 顶部尝试时间线 + 选中展开(默认最新);
|
|
792
|
+
* 单次尝试保持现状(不渲染时间线)。 */
|
|
756
793
|
function StageDetailDrawer({ det, onClose, sessionId, sessions }) {
|
|
794
|
+
const [sel, setSel] = react.default.useState(null);
|
|
757
795
|
const st = det.stage;
|
|
758
796
|
const d = det.data;
|
|
797
|
+
const attempts = d && d.attempts && d.attempts.length > 1 ? d.attempts : null;
|
|
798
|
+
const selIdx = attempts ? sel === null ? attempts.length - 1 : sel : null;
|
|
799
|
+
const cur = attempts ? attempts[selIdx] || d : d;
|
|
759
800
|
const color = st && st.status ? stColor(st.status) : T.text2;
|
|
760
801
|
const ownerSession = d && d.ownerSession ? String(d.ownerSession) : null;
|
|
761
802
|
const mySession = sessionId ? String(sessionId) : null;
|
|
762
803
|
const crossSession = !!ownerSession && !!mySession && ownerSession !== mySession;
|
|
763
|
-
const hasChild = !!(!crossSession &&
|
|
804
|
+
const hasChild = !!(!crossSession && cur && cur.childId && sessions && typeof sessions.openSubagent === "function");
|
|
764
805
|
const openChild = () => {
|
|
765
806
|
if (crossSession || !hasChild) return;
|
|
766
807
|
try {
|
|
767
808
|
sessions.openSubagent({
|
|
768
809
|
parentSessionId: ownerSession || sessionId,
|
|
769
|
-
childSessionId:
|
|
810
|
+
childSessionId: cur.childId,
|
|
770
811
|
mode: "one-shot"
|
|
771
812
|
});
|
|
772
813
|
} catch (e) {}
|
|
773
814
|
};
|
|
774
|
-
const outText =
|
|
815
|
+
const outText = cur && cur.output ? cur.output : cur && cur.summary ? `(该 run 未保存完整正文,展示摘要)\n\n${cur.summary}` : det.err ? `⚠ 加载失败:${det.err}` : det.loading ? "加载中…" : "(无产物正文)";
|
|
775
816
|
const closeBtn = {
|
|
776
817
|
font: "inherit",
|
|
777
818
|
width: 26,
|
|
@@ -820,7 +861,7 @@ window.__ModuleLoader__.load({
|
|
|
820
861
|
padding: "12px 14px",
|
|
821
862
|
borderBottom: `1px solid ${T.border}`,
|
|
822
863
|
background: `linear-gradient(135deg, color-mix(in srgb, ${color} 14%, transparent), transparent 62%)`
|
|
823
|
-
} }, h("span", { style: { fontSize: 17 } },
|
|
864
|
+
} }, h("span", { style: { fontSize: 17 } }, phaseIconOf(st && st.phase)), h("div", { style: {
|
|
824
865
|
flex: 1,
|
|
825
866
|
minWidth: 0
|
|
826
867
|
} }, h("div", {
|
|
@@ -864,7 +905,66 @@ window.__ModuleLoader__.load({
|
|
|
864
905
|
fontFamily: MONO,
|
|
865
906
|
color: T.text,
|
|
866
907
|
lineHeight: 1.65
|
|
867
|
-
} }, usageDetail(
|
|
908
|
+
} }, usageDetail(cur || st || {}))), attempts ? h("div", { style: {
|
|
909
|
+
display: "flex",
|
|
910
|
+
flexDirection: "column",
|
|
911
|
+
gap: 5
|
|
912
|
+
} }, h("span", { style: {
|
|
913
|
+
fontSize: 10.5,
|
|
914
|
+
fontWeight: 700,
|
|
915
|
+
color: T.text2,
|
|
916
|
+
letterSpacing: .3
|
|
917
|
+
} }, `↻ 尝试历史(${attempts.length} 次 · 点击查看该次详情)`), h("div", { style: {
|
|
918
|
+
display: "flex",
|
|
919
|
+
flexDirection: "column",
|
|
920
|
+
gap: 4
|
|
921
|
+
} }, attempts.map((a, idx) => {
|
|
922
|
+
const aColor = a.status === "done" ? T.success : a.status === "failed" ? T.error : T.warn;
|
|
923
|
+
const sel = idx === selIdx;
|
|
924
|
+
return h("div", {
|
|
925
|
+
key: a.seq,
|
|
926
|
+
onClick: () => setSel(idx),
|
|
927
|
+
title: (a.summary || a.outcome || "").slice(0, 200),
|
|
928
|
+
style: {
|
|
929
|
+
cursor: "pointer",
|
|
930
|
+
borderRadius: 9,
|
|
931
|
+
padding: "6px 9px",
|
|
932
|
+
display: "flex",
|
|
933
|
+
gap: 7,
|
|
934
|
+
alignItems: "center",
|
|
935
|
+
border: `1px solid ${sel ? color : T.border}`,
|
|
936
|
+
background: sel ? `color-mix(in srgb, ${color} 10%, transparent)` : T.layer1
|
|
937
|
+
}
|
|
938
|
+
}, h("span", { style: {
|
|
939
|
+
fontFamily: MONO,
|
|
940
|
+
fontSize: 10.5,
|
|
941
|
+
color: T.text2,
|
|
942
|
+
flex: "0 0 52px"
|
|
943
|
+
} }, `#${a.seq}`), h("span", { style: {
|
|
944
|
+
fontSize: 11,
|
|
945
|
+
color: aColor,
|
|
946
|
+
flex: "0 0 64px",
|
|
947
|
+
fontWeight: 700
|
|
948
|
+
} }, a.status === "done" ? "✅ 成功" : a.status === "failed" ? `❌ ${a.outcome || "失败"}` : "⏳ 进行中"), h("span", { style: {
|
|
949
|
+
flex: 1,
|
|
950
|
+
minWidth: 0,
|
|
951
|
+
fontSize: 10.5,
|
|
952
|
+
color: T.text2,
|
|
953
|
+
overflow: "hidden",
|
|
954
|
+
textOverflow: "ellipsis",
|
|
955
|
+
whiteSpace: "nowrap"
|
|
956
|
+
} }, (a.summary || a.outcome || "(无摘要)").slice(0, 80)), h("span", { style: {
|
|
957
|
+
fontFamily: MONO,
|
|
958
|
+
fontSize: 10,
|
|
959
|
+
color: T.text2,
|
|
960
|
+
flex: "0 0 auto"
|
|
961
|
+
} }, a.startedAt ? fmtDur(a.startedAt, a.endedAt) : "—"), h("span", { style: {
|
|
962
|
+
fontFamily: MONO,
|
|
963
|
+
fontSize: 10,
|
|
964
|
+
color: T.text2,
|
|
965
|
+
flex: "0 0 auto"
|
|
966
|
+
} }, a.usage ? fmtTokens(totalTokens(a.usage)) : ""));
|
|
967
|
+
}))) : null, h("div", { style: {
|
|
868
968
|
display: "flex",
|
|
869
969
|
flexDirection: "column",
|
|
870
970
|
gap: 5
|
|
@@ -898,7 +998,37 @@ window.__ModuleLoader__.load({
|
|
|
898
998
|
color: T.text2,
|
|
899
999
|
textAlign: "center",
|
|
900
1000
|
lineHeight: 1.55
|
|
901
|
-
} }, "跳转成功后,请切「对话」tab 查看该子代理的完整会话轨迹") : null), h("div", { style: {
|
|
1001
|
+
} }, "跳转成功后,请切「对话」tab 查看该子代理的完整会话轨迹") : null), st && phaseKeyOf(st.phase) === "dev" ? h("div", { style: {
|
|
1002
|
+
display: "flex",
|
|
1003
|
+
flexDirection: "column",
|
|
1004
|
+
gap: 5
|
|
1005
|
+
} }, h("span", { style: {
|
|
1006
|
+
fontSize: 10.5,
|
|
1007
|
+
fontWeight: 700,
|
|
1008
|
+
color: T.text2,
|
|
1009
|
+
letterSpacing: .3
|
|
1010
|
+
} }, "🔬 验证证据"), cur && cur.verifyEvidence ? h("div", { style: {
|
|
1011
|
+
whiteSpace: "pre-wrap",
|
|
1012
|
+
wordBreak: "break-word",
|
|
1013
|
+
fontSize: 11.5,
|
|
1014
|
+
lineHeight: 1.62,
|
|
1015
|
+
color: T.text,
|
|
1016
|
+
background: `color-mix(in srgb, ${T.layer2} 55%, transparent)`,
|
|
1017
|
+
border: `1px solid ${T.border}`,
|
|
1018
|
+
borderRadius: 10,
|
|
1019
|
+
padding: "10px 12px",
|
|
1020
|
+
maxHeight: 180,
|
|
1021
|
+
overflowY: "auto",
|
|
1022
|
+
fontFamily: MONO
|
|
1023
|
+
} }, cur.verifyEvidence) : h("div", { style: {
|
|
1024
|
+
fontSize: 11,
|
|
1025
|
+
color: T.warn,
|
|
1026
|
+
background: `color-mix(in srgb, ${T.warn} 8%, transparent)`,
|
|
1027
|
+
border: `1px dashed color-mix(in srgb, ${T.warn} 45%, transparent)`,
|
|
1028
|
+
borderRadius: 10,
|
|
1029
|
+
padding: "8px 12px",
|
|
1030
|
+
lineHeight: 1.55
|
|
1031
|
+
} }, "(缺失——契约未兑现,host 已记警告;可与 logs/teamflow/<runId>/ 命令输出日志对照)")) : null, h("div", { style: {
|
|
902
1032
|
display: "flex",
|
|
903
1033
|
flexDirection: "column",
|
|
904
1034
|
gap: 5
|
|
@@ -932,6 +1062,7 @@ window.__ModuleLoader__.load({
|
|
|
932
1062
|
marginBottom: 8
|
|
933
1063
|
} }, "🏭"), "暂无运行中的流水线——让模型调用 teamflow_start,或在上方输入需求");
|
|
934
1064
|
const groups = [];
|
|
1065
|
+
const taskKeyOf = (s) => String(s.taskKey || String(s.label || "").replace(/^开发 · /, "").replace(/((?:第 \d+ 次重试|补跑))$/, "").trim());
|
|
935
1066
|
for (const st of active.stages || []) {
|
|
936
1067
|
let g = groups.length ? groups[groups.length - 1] : null;
|
|
937
1068
|
if (!g || g.phase !== st.phase) {
|
|
@@ -941,7 +1072,31 @@ window.__ModuleLoader__.load({
|
|
|
941
1072
|
};
|
|
942
1073
|
groups.push(g);
|
|
943
1074
|
}
|
|
944
|
-
|
|
1075
|
+
const key = taskKeyOf(st);
|
|
1076
|
+
const prev = g.stages.find((x) => x.__taskKey === key);
|
|
1077
|
+
if (prev) {
|
|
1078
|
+
prev.attempts = prev.attempts || [prev];
|
|
1079
|
+
prev.attempts.push(st);
|
|
1080
|
+
if ((st.seq || 0) > (prev.seq || 0)) {
|
|
1081
|
+
for (const f of [
|
|
1082
|
+
"status",
|
|
1083
|
+
"outcome",
|
|
1084
|
+
"usage",
|
|
1085
|
+
"output",
|
|
1086
|
+
"summary",
|
|
1087
|
+
"childId",
|
|
1088
|
+
"startedAt",
|
|
1089
|
+
"endedAt",
|
|
1090
|
+
"verifyEvidence"
|
|
1091
|
+
]) prev[f] = st[f];
|
|
1092
|
+
prev.seq = st.seq;
|
|
1093
|
+
prev.label = st.label;
|
|
1094
|
+
}
|
|
1095
|
+
} else g.stages.push({
|
|
1096
|
+
...st,
|
|
1097
|
+
__taskKey: key,
|
|
1098
|
+
attempts: [st]
|
|
1099
|
+
});
|
|
945
1100
|
}
|
|
946
1101
|
const wrapRef = react.default.useRef(null);
|
|
947
1102
|
const [vw, setVw] = react.default.useState(900);
|