@tea-agent/loop-agent 0.39.1 → 0.39.3
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 +4 -1
- package/dist/build-stamp.json +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +14 -1
- package/dist/worker/observe/static/dag-node-purpose.d.ts +6 -0
- package/dist/worker/observe/static/dag-node-purpose.js +203 -0
- package/dist/worker/observe/static/state.js +2 -2
- package/dist/worker/observe/static/styles.css +348 -38
- package/dist/worker/observe/static/views/dag-graph.js +4 -2
- package/dist/worker/observe/static/views/dag-inspector.js +307 -154
- package/dist/worker/observe/static/views/dag.d.ts +13 -0
- package/dist/worker/observe/static/views/dag.js +4 -3
- package/dist/workflows/dag/frontend-implementation-contract.js +89 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
### 重点更新
|
|
6
6
|
|
|
7
|
+
- Console DAG 检查器「提示词重启」面板改为与检查器一致的卡片层级:版本选择复用自定义下拉;编辑模式与页签同款分段按钮;提交按钮用品牌橙药丸并吸底;追加/替换编辑区放到底稿前面,长底稿默认折叠以免把操作挤出视口。
|
|
7
8
|
- Console「操作」模式新增人类专用的“更新并初始化”入口:默认更新 npm `latest` 稳定版,也可明确选择 `next` 预发布版;先 fail-closed 检查活跃 DAG/Worker/Chat/Console 操作与 npm 来源,再精确安装并验证所选版本、仅执行 `init update --apply-safe`,并以 hash-bound handoff 在原端口接棒新 Console。`latest` 保持稳定版且拒绝回退,`next` 仅在人工选择时允许精确 prerelease;渠道写入 operation 审计身份。Inspect 与模型工具均不能触发该写入操作。启动时不再在终端询问更新,页面会在接棒后自动刷新并通过新的 `consoleInstanceId` 识别实例。
|
|
8
9
|
- 修复 Console 四处评审缺陷(合并前收口):① 向导「运行」进度块接通——`runDag` 只返回 operationId,原实现读的 `recovery.dagRunId` 在向导路径永远为空;现在确认页先快照基线 run、进入运行页后轮询 `observeLink`,以 (taskId, operationId) 任一变化为失效信号(operationId 覆盖「重新运行」按钮——它不改变向导步骤;taskId 覆盖运行步骤中手动改任务 ID 的场景,失效时基线一并重置,避免沿用上一任务的 run):新派发/切任务会清掉旧选中 run 并重新解析,**只接受与当前任务基线不同的新 run**;从 Recovery 带回的共享选中 run 先做归属校验——`GET /api/dag-runs/:id` 详情响应新增 `taskId` 投影(源自 run.json 的 `taskContractBinding`→`sourceBinding`→Hybrid 标题,与 observeLink/candidates 同一绑定真源,不受候选列表 limit 截断影响;404 视为失效选中、无绑定视为不可判定),非本任务的 run 不展示;校验全程由 effect 生命周期栅栏保护——任务/运行/选中在异步校验期间变化时,旧响应直接丢弃、不会改写新状态;校验暂不可用时按有界退避(2s→30s,约 2 分钟)自动重试而非被动等待状态变化,重试计划为纯函数并有行为测试;**展示层另有闸门**——进度面板与运行操作只消费「本解析器已采纳/已验证」的 run(组件 state),未验证期间(校验中、重试中、give-up 后)进度面板保持空缺,不会即时或永久显示其他任务的 DAG;「打开检视」「侧栏预览」两个入口同样双重门禁(按钮无已验证 run 即禁用 + 处理器复核 verifiedRunId),共享的 openInspectSplit 解析器不再能带出未验证的外来 run。解析决策本身抽取为纯状态机 `pages/tasks/run-id-resolution.ts`(首跑/重跑/切任务/外来选中/基线门控五类迁移),Effects 只做薄适配,主流程「确认页基线快照 → runDag 派发 → observeLink 轮询 → 新 run 采纳」有完整行为测试。基线快照为三态(成功/权威无运行/暂不可查),**查询失败不会被当成「没有历史运行」**——快照重试期间基线保持未知、探测轮询等待,不会把旧运行误判为新运行;新 run 创建失败或注册较慢时进度面板宁可空缺也不把上一次已终止的 DAG 当作当前运行(轮询上限 5 分钟后安静停止)。② 失败建议数据契约修正——旅程卡原先把原始 run 级 `failureCategory` 直接查归一化建议表(`missing-api-key`/`nonzero-exit` 等永远查不中,节点分类又在安全投影中被丢弃);现在纯分类核心下沉 `src/shared/dag-failure-category.ts`(console↔workflows 双向共享叶,不破坏 console 禁止 import workflows 的边界测试),服务端投影把 run 级与节点级分类都归一化输出(success/skipped 不出),卡片按「失败节点分类优先、run 级兜底」取值,失败卡始终有可操作建议。③ Recovery interrupt 资格轮询在运行中档位同步刷新 run 状态——原先状态只在选中时读一次,运行中的 run 结束后仍永久保持 4 秒快轮询;现在 4 秒档附带轻量 `GET /api/dag-runs/:id` 刷新 `effectiveStatus`,终态后自动退到 30 秒。④ Inspect 紧凑检视一次瞬时刷新失败不再永久显示错误——成功刷新回合会清除上一轮 error 横幅。
|
|
9
10
|
- Operator Chat 输入框两项交互增强:① **↑/↓ 历史输入召回**——每次发送的文本进入输入历史(连续重复折叠、上限 100 条),光标在首行按 ↑ 逐条向旧回溯、按 ↓ 向新前进,越过最新一条时恢复回溯前**未发送的草稿**(草稿不会被历史浏览冲掉);多行文本中部的方向键仍是普通光标移动,IME 组词与 @文件/命令面板打开时不抢占。② **运行中排队下一轮指令**——当前回合运行中 Enter 不再被吞掉,消息作为「排队消息」绑定当前 Turn(服务端 `PUT deferred-turn` 从仅限 stopping 放开为 running/stopping,错误码 `TURN_NOT_STOPPING`→`TURN_NOT_ACTIVE`),当前回合结束(正常完成或停止)后自动发送;排队条提供「立即发送」(停止当前回复并立即发出)、「编辑」(移回输入框改写后再排)、「删除」三种操作,运行中输入框右侧提供排队发送按钮(与停止按钮并列);排队条单行展示(状态 + 省略号预览 + 操作按钮一行),输入框默认一行高(自动增高上限 280px 不变)。
|
|
@@ -60,6 +61,8 @@
|
|
|
60
61
|
|
|
61
62
|
### 改进
|
|
62
63
|
|
|
64
|
+
- 检查器「提示词重启」只读态的提示词卡片会撑满剩余高度并在卡片内滚动,不再在面板底部留下大块空白;失败节点的可编辑布局不变。
|
|
65
|
+
- DAG 节点表「备注」改为节点用途简介(是什么、做什么、目的),不再重复节点 ID;失败节点仍显示错误摘要。检查器标题与图节点悬浮提示同步展示同一句说明。
|
|
63
66
|
- 实验「提示词重启」会为 Pi 节点的每次失败 attempt 保存独立、脱敏且 64 KiB 有界的提示词候选;Inspector 始终展示提示词版本选择框,新 run 会列出冻结原始提示词与全部失败尝试(含自动重试产生的恢复提示词),历史 run 未保存候选时明确说明,成功尝试不混入。提示词卡片右上角提供复制图标并以勾选图标反馈成功;已截断候选复制时明确标记为截断预览,并保持只读、禁止直接提交,避免用不完整提示词发起续跑。选择失败候选会载入「全文替换」编辑器;即使节点后续自动重试成功,历史失败候选仍可只读切换查看。
|
|
64
67
|
- DAG 节点检查器「执行过程」按执行器分流:Pi 仍看 session-events;有命令的 shell 展示 `shell-command-receipt` 与 stdout/stderr;`frontendBrowserToolPreflight` 等内部处理器展示步骤回执(历史 run 可从 capability / attempt 产物合成)。空态不再把 shell/static 误说成「暂无过程日志」。节点输入补充 named handler 名称。脚本仍属于节点输入,不假装已执行。
|
|
65
68
|
- DAG 节点检查器「节点输出」在整段内容为完整 JSON 对象或数组时改为缩进代码块展示,不再把紧凑 `JSON.stringify` 挤成一段 Markdown 段落;截断或非法 JSON、普通 Markdown 仍走原阅读器。
|
|
@@ -69,7 +72,7 @@
|
|
|
69
72
|
- frontend-test 报告解析用例 Markdown 的 `##`/`###` 标题与有序列表(`测试步骤` / `预期结果` / `前置条件与重置`);缺 `测试目的` 时回退到用例 H1,避免主 HTML 出现空步骤。
|
|
70
73
|
- `dag rerun --from-node` 把尚未启动的 writer/map 视为首次执行;frontend-test probe 这种失败的 exclusive shell 可以带着下游未跑节点续跑,不必整图 `standaloneTaskRerun`。
|
|
71
74
|
- Pi SDK 节点在 stall watchdog(默认 15 分钟无 provider 活动)触发后,会先 abort 当前等待,并在同一会话自动发送一次「继续」;仅 abort 已确认且尚未调用 write 工具时恢复,失败仍判 timeout。绝对墙钟超时与 CLI 后端不走这条恢复。
|
|
72
|
-
- DAG
|
|
75
|
+
- DAG 节点检查器「执行过程」时间线默认隐藏原始协议事件(`message_start` / `message_end`),按钮文案为「展开原始协议事件」;用户可点选展开,同会话内选择会保持。
|
|
73
76
|
- Operator Chat 的乐观停止现在把“视觉已停止”和 Turn ownership 分开:Abort 获得可靠终态前明确显示“正在停止”,此时可为原会话保存一条服务端持久化的“停止后发送”消息;后一次覆盖前一次,切换会话、刷新页面或 Console 重启不会丢失,旧 Turn 结束后复用正常 Turn 准入路径自动发送,并以固定 `clientRequestId` 防止重复执行。
|
|
74
77
|
- Operator Chat 修复快速终止时“停止后发送”与普通发送之间的准入空洞:发送路径改读实时 ownership;若 deferred 请求恰好撞上旧 Turn 终态,会先按服务端状态对账,再使用同一 `clientRequestId` 自动转为普通发送,不再要求用户刷新重试或丢失本次提交。
|
|
75
78
|
- `dag rerun-task` 现在会把父 run 最后一轮仍未解决的 `verify-pi` / review 反馈、证据引用和修订轮次带入新完整 DAG;planner、implementer 与 verifier/reviewer 必须修复或举证说明不再适用,不能仅因文件已存在就返回 `already-satisfied`。Console 同步区分「自动修订」「从失败节点恢复」「带反馈重新执行任务」。
|
package/dist/build-stamp.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.39.
|
|
4
|
-
"gitSha": "
|
|
5
|
-
"builtAt": "2026-08-
|
|
3
|
+
"version": "0.39.3",
|
|
4
|
+
"gitSha": "048826da6ab8dba7f01daa635ab582f68c539d06",
|
|
5
|
+
"builtAt": "2026-08-28T09:06:21.116Z"
|
|
6
6
|
}
|
|
@@ -92,6 +92,18 @@ function isAtxHeading(line) {
|
|
|
92
92
|
return null;
|
|
93
93
|
return { level: match[1].length, text: match[2].trim() };
|
|
94
94
|
}
|
|
95
|
+
/** Find the nearest explicit AC heading in a nested Markdown heading path.
|
|
96
|
+
* A subsection such as "异常场景" belongs to its enclosing `#### AC-*` block,
|
|
97
|
+
* even though the subsection heading itself has no ID. */
|
|
98
|
+
function nearestAncestorExplicitAc(headingPath) {
|
|
99
|
+
const ancestors = headingPath.split(" > ").slice(0, -1).reverse();
|
|
100
|
+
for (const heading of ancestors) {
|
|
101
|
+
const matched = matchExplicitAcHeading(heading);
|
|
102
|
+
if (matched)
|
|
103
|
+
return matched;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
95
107
|
function isListItem(line) {
|
|
96
108
|
return /^\s*(?:[-*+]|\d+[.)])\s+(?:\[(?: |x|X)\]\s+)?/.test(line);
|
|
97
109
|
}
|
|
@@ -173,6 +185,7 @@ export function splitDocumentIntoFragments(doc) {
|
|
|
173
185
|
// V4 显式 AC 标题(`#### AC-*`)本身即验收段:标题行的 ID 原样保留。
|
|
174
186
|
const lastHeadingSegment = section.headingPath.split(" > ").pop() ?? section.headingPath;
|
|
175
187
|
const explicitSectionAc = matchExplicitAcHeading(lastHeadingSegment);
|
|
188
|
+
const ancestorExplicitAc = nearestAncestorExplicitAc(section.headingPath);
|
|
176
189
|
const sectionKind = classifySectionHeading(section.headingPath);
|
|
177
190
|
const effectiveKind = explicitSectionAc ? "acceptance" : sectionKind;
|
|
178
191
|
const bodyStart = section.headingPath
|
|
@@ -181,7 +194,7 @@ export function splitDocumentIntoFragments(doc) {
|
|
|
181
194
|
const bodyEnd = section.endLine;
|
|
182
195
|
const bodyLines = lines.slice(Math.max(0, bodyStart - 1), Math.min(bodyEnd, lines.length));
|
|
183
196
|
// 当前验收章节内最近的显式 AC ID(V4 标题或 AC 条目),正文片段继承它。
|
|
184
|
-
let pendingAcId = null;
|
|
197
|
+
let pendingAcId = explicitSectionAc?.id ?? ancestorExplicitAc?.id ?? null;
|
|
185
198
|
const emit = (fragment) => {
|
|
186
199
|
const explicit = fragment.explicitId ?? null;
|
|
187
200
|
let id = explicit;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Short Chinese purpose copy for DAG node IDs shown in the inspector table.
|
|
3
|
+
* Exact IDs first; then conservative suffixes. Never echo the raw nodeId.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const NODE_PURPOSE_BY_ID = {
|
|
7
|
+
"contract-pi": "只读梳理范围、风险与写入边界,产出实现契约,不改代码。",
|
|
8
|
+
"scout-src": "只读侦察源码结构与现有模式,给后续实现找落点,不改文件。",
|
|
9
|
+
"scout-tests": "只读侦察测试与验证入口,标出可复用的检查方式,不改文件。",
|
|
10
|
+
"plan-pi": "根据契约与侦察结果制定实现计划与 writeSet,仍不改业务代码。",
|
|
11
|
+
"plan-revision-pi": "按审查意见修订实现计划,收窄写入范围,不扩大任务边界。",
|
|
12
|
+
"implement-pi": "在允许路径内按计划改代码,完成本轮主实现。",
|
|
13
|
+
"implement-core": "在允许路径内完成核心实现,不越出约定写入范围。",
|
|
14
|
+
"repair-pi": "只修验证暴露出的可修复问题,不重开需求、不扩大 writeSet。",
|
|
15
|
+
"verify-shell": "跑冻结的验证命令,用退出码证明实现是否达标。",
|
|
16
|
+
"soft-verify-shell": "先做软验证,留下证据供过程监督,不立刻判整单失败。",
|
|
17
|
+
"hard-verify-shell": "硬验证:命令必须通过,作为后续审查与收口的事实。",
|
|
18
|
+
"review-pi": "对照需求与 diff 做只读审查,给出通过或需修订。",
|
|
19
|
+
"review-verdict-recovery-pi": "补齐或纠正审查结论格式,确保门禁能读到明确 VERDICT。",
|
|
20
|
+
"review-gate-shell": "确定性门禁:只有审查结论为通过才放行收口。",
|
|
21
|
+
"decision-pi": "汇总本轮证据,给出继续、修订或停止的决策建议。",
|
|
22
|
+
"closeout-pi": "汇总完成证据与交接说明,宣告本轮交付结束。",
|
|
23
|
+
"write-set-audit-pi": "审查计划中的写入范围是否过宽或重叠,给出初审结论。",
|
|
24
|
+
"write-set-audit-format-repair-pi": "只修复写入范围审查的结论格式,不改计划内容。",
|
|
25
|
+
"write-set-format-gate-shell": "检查写入范围审查格式是否有效,未通过则不能开始改代码。",
|
|
26
|
+
"final-write-set-audit-pi": "终审写入范围:确认最终计划可授权 implement-pi。",
|
|
27
|
+
"final-write-set-audit-format-repair-pi": "只修复终审结论格式,保留原审查发现。",
|
|
28
|
+
"write-set-gate-shell": "写入授权门禁:终审通过后才允许实现节点改文件。",
|
|
29
|
+
"process-supervisor-pi": "只读检查实现过程是否偏离契约与验证,提出Bounded 修复建议。",
|
|
30
|
+
"process-gate-shell": "过程监督门禁:根据监督结论决定是否进入 repair。",
|
|
31
|
+
"authority-surface-audit-pi": "审查谁能写状态、哪些面暴露给模型,防止越权通路。",
|
|
32
|
+
"authority-surface-gate-shell": "权限面门禁:审查未通过则不能进入收口。",
|
|
33
|
+
"task-state-reconcile-shell": "核对任务状态与运行事实是否一致,避免用过期状态收口。",
|
|
34
|
+
"requirement-coverage-shell": "检查实现是否覆盖已编号需求,漏项则不能宣称完成。",
|
|
35
|
+
"static-invariant-shell": "跑静态不变量检查,确认约定结构与约束仍成立。",
|
|
36
|
+
"changeset-impact-shell": "评估本轮 diff 的影响面,标出高风险改动。",
|
|
37
|
+
"closeout-artifact-shell": "收集收口所需的确定性产物与证据路径。",
|
|
38
|
+
"final-verify-shell": "收口前最后一轮冻结验证,作为完成权威。",
|
|
39
|
+
"closeout-summary-pi": "把验证与交付事实写成简短交接摘要。",
|
|
40
|
+
|
|
41
|
+
"frontend-contract-pi": "把前端需求整理成可追踪契约:页面、状态、验收与边界。",
|
|
42
|
+
"frontend-scout-pi": "只读侦察前端结构、组件与接口用法,不改文件。",
|
|
43
|
+
"frontend-plan-pi": "选定实现与 Mock/API 策略,输出可执行的前端实现契约补丁。",
|
|
44
|
+
"frontend-design-review-pi": "审查前端计划是否可写:通过则沿用原计划,否则要求修订。",
|
|
45
|
+
"frontend-plan-revision-pi": "按设计审查意见修订前端契约,不扩大范围。",
|
|
46
|
+
"frontend-final-design-review-pi": "复核修订后的前端计划,只有通过才能授权写入。",
|
|
47
|
+
"frontend-prewrite-gate-shell": "写入前门禁:核对契约、覆盖与 Mock 策略,通过才允许改前端。",
|
|
48
|
+
"frontend-lint-baseline-shell": "记录写入前的 lint 基线,供实现后对比,不阻断写入。",
|
|
49
|
+
"frontend-implement-pi": "按已批准契约改前端代码、状态与交互,留在 writeSet 内。",
|
|
50
|
+
"frontend-verify-assess-shell": "跑静态/行为/Mock 验证并评估能否有界修复。",
|
|
51
|
+
"frontend-repair-pi": "只修评估为可修复的前端失败,不重开需求。",
|
|
52
|
+
"frontend-reverify-shell": "修复后用同一套冻结命令复验。",
|
|
53
|
+
"frontend-review-context-shell": "打包真实 diff 与有效验证证据,供审查节点使用。",
|
|
54
|
+
"frontend-review-pi": "对照契约审查前端实现与证据,给出通过或需修订。",
|
|
55
|
+
"frontend-review-gate-shell": "前端审查门禁:结论为通过才进入收口。",
|
|
56
|
+
"frontend-closeout-pi": "汇总前端交付状态(含真实联调是否仍待完成)。",
|
|
57
|
+
"frontend-mock-assess-pi": "评估项目是否具备授权的 Mock 验证能力。",
|
|
58
|
+
"frontend-mock-contract-gate-shell": "Mock 契约门禁:策略与验证命令不一致则阻断。",
|
|
59
|
+
"frontend-mock-verify-shell": "执行已授权的 Mock 验证命令。",
|
|
60
|
+
"frontend-mock-blocked-shell": "缺少授权 Mock 命令时给出确定性阻断说明。",
|
|
61
|
+
|
|
62
|
+
"preflight-frontend-browser-tool-shell": "检查浏览器自动化工具是否可用,失败则不进入用例执行。",
|
|
63
|
+
"prepare-frontend-test-package-shell": "准备前端测试包与标准场景资产。",
|
|
64
|
+
"retrieve-frontend-test-context-pi": "检索页面与验收上下文,供生成用例引用。",
|
|
65
|
+
"materialize-frontend-test-execution-shell": "物化前端测试执行清单与路径。",
|
|
66
|
+
"generate-frontend-functional-cases-pi": "按验收标准生成可执行的前端功能用例。",
|
|
67
|
+
"checklist-and-materialize-manifest-shell": "核对清单并物化用例 manifest。",
|
|
68
|
+
"execute-frontend-cases-map": "按用例清单并行跑浏览器步骤,每条用例一个子节点。",
|
|
69
|
+
"select-frontend-rerun-candidates-shell": "挑出可有界重跑的失败/缺失用例。",
|
|
70
|
+
"rerun-frontend-cases-map": "对入选用例再跑一轮浏览器步骤,以最新证据为准。",
|
|
71
|
+
"generate-backend-md-cases-map": "按模块并行写出 Markdown 用例卡片。",
|
|
72
|
+
"generate-backend-pytest-cases-map": "按模块并行写出对应的 pytest 脚本。",
|
|
73
|
+
"patch-backend-md-cases-map": "按缺口计划并行补丁各模块 Markdown 用例。",
|
|
74
|
+
"patch-backend-pytest-cases-map": "按缺口计划并行补丁各模块 pytest 脚本。",
|
|
75
|
+
"finalize-frontend-test-result-shell": "汇总用例结果,写成统一结论。",
|
|
76
|
+
"frontend-test-reports-shell": "生成前端测试 HTML/Markdown 报告。",
|
|
77
|
+
"frontend-test-result-outcome-gate-shell": "前端测试结果门禁:未达标则不能进入复盘收口。",
|
|
78
|
+
"frontend-test-retrospect-pi": "根据真实执行证据写前端测试复盘。",
|
|
79
|
+
|
|
80
|
+
"validate-backend-test-environment-shell": "检查 Python/pytest 与测试布局是否可跑,失败则不消耗模型。",
|
|
81
|
+
"backend-test-analysis-contract-shell": "固化后端测试分析契约与布局。",
|
|
82
|
+
"backend-test-environment-scout-pi": "侦察后端测试环境与入口,不改业务代码。",
|
|
83
|
+
"backend-test-execution-contract-shell": "冻结后端测试如何执行、产物写到哪里。",
|
|
84
|
+
"generate-backend-md-plan-pi": "生成中文模块索引与用例卡片计划。",
|
|
85
|
+
"materialize-backend-md-module-manifest-shell": "把 Markdown 模块清单落到磁盘。",
|
|
86
|
+
"review-and-revise-backend-md-cases-pi": "独立审查并修订 Markdown 用例。",
|
|
87
|
+
"validate-backend-md-cases-shell": "校验用例章节与 Case ID,结果只记录不阻断。",
|
|
88
|
+
"generate-backend-pytest-plan-pi": "把 Markdown 用例转成 pytest 脚本计划。",
|
|
89
|
+
"materialize-backend-pytest-module-manifest-shell": "物化 pytest 模块与脚本映射。",
|
|
90
|
+
"assess-backend-pytest-collection-shell": "试收集 pytest:能修的缺口才进入 repair。",
|
|
91
|
+
"repair-backend-pytest-collection-pi": "只补齐可归因的缺失 mapped 脚本。",
|
|
92
|
+
"effective-backend-pytest-collection-gate-shell": "收集门禁:映射不齐则不跑业务 pytest。",
|
|
93
|
+
"backend-test-traceability-gate-shell": "核对用例、脚本与验收的追踪关系。",
|
|
94
|
+
"backend-test-case-manifest-shell": "写出本轮有效用例清单事实。",
|
|
95
|
+
"execute-backend-pytest-and-html-report-shell": "单次跑业务 pytest 并生成 HTML/事实报告。",
|
|
96
|
+
"backend-test-report-and-l5-pi": "用中文汇总 advisory、执行事实与结论。",
|
|
97
|
+
"backend-test-outcome-gate-shell": "后端测试结果门禁:失败分类决定能否收口。",
|
|
98
|
+
"backend-test-report-shell": "生成后端测试报告产物。",
|
|
99
|
+
|
|
100
|
+
"knowledge-sync-collect-pi": "收集本轮验证与实现中应回写的知识。",
|
|
101
|
+
"knowledge-sync-draft-pi": "起草知识条目,不直接改权威文档。",
|
|
102
|
+
"knowledge-sync-validate-shell": "校验知识草稿结构与路径边界。",
|
|
103
|
+
"knowledge-sync-apply-pi": "把通过校验的知识写入约定文档。",
|
|
104
|
+
"knowledge-sync-pointer-pi": "更新知识索引或指针,方便下次检索。",
|
|
105
|
+
|
|
106
|
+
"kg-bootstrap-preflight-shell": "图谱开荒前检:确认仓库与工具可用。",
|
|
107
|
+
"kg-bootstrap-inventory-shell": "盘点代码与文档,列出待建图谱对象。",
|
|
108
|
+
"kg-bootstrap-propose-pi": "提出知识图谱节点与关系草案。",
|
|
109
|
+
"kg-bootstrap-validate-shell": "校验图谱草案是否可物化。",
|
|
110
|
+
"kg-bootstrap-review-pi": "审查图谱草案质量与边界。",
|
|
111
|
+
"kg-bootstrap-review-gate-shell": "图谱审查门禁:通过才允许物化。",
|
|
112
|
+
"kg-bootstrap-promote-shell": "把审查通过的图谱草案提升为有效输入。",
|
|
113
|
+
"kg-bootstrap-materialize-shell": "把图谱写入约定产物路径。",
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
function normalizeNodeId(nodeId) {
|
|
117
|
+
return String(nodeId ?? "")
|
|
118
|
+
.trim()
|
|
119
|
+
.split(/[/#]/)[0];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const NODE_PURPOSE_BY_PREFIX = [
|
|
123
|
+
[/^execute-frontend-case-\d+$/, "执行单条前端用例的浏览器步骤,并留下证据。"],
|
|
124
|
+
[/^rerun-frontend-case-/, "重跑入选的前端用例,以本轮证据覆盖上一轮结果。"],
|
|
125
|
+
[/^generate-backend-md-case-/, "为单个后端模块写出 Markdown 用例卡片。"],
|
|
126
|
+
[/^generate-backend-pytest-case-/, "为单个后端模块写出对应的 pytest 脚本。"],
|
|
127
|
+
[/^patch-backend-md-case-/, "按缺口计划补丁单个模块的 Markdown 用例。"],
|
|
128
|
+
[/^patch-backend-pytest-case-/, "按缺口计划补丁单个模块的 pytest 脚本。"],
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
function describeFromPattern(nodeId) {
|
|
132
|
+
const id = nodeId.toLowerCase();
|
|
133
|
+
for (const [pattern, text] of NODE_PURPOSE_BY_PREFIX) {
|
|
134
|
+
if (pattern.test(id)) return text;
|
|
135
|
+
}
|
|
136
|
+
if (id.endsWith("-map") || id.includes("-cases-map")) {
|
|
137
|
+
return "按清单并行展开子节点并汇总结果。";
|
|
138
|
+
}
|
|
139
|
+
if (id.includes("-gate-shell")) {
|
|
140
|
+
return "确定性门禁:核验上游结论,通过才放行后续节点。";
|
|
141
|
+
}
|
|
142
|
+
if (id.endsWith("-shell") && id.includes("verify")) {
|
|
143
|
+
return "跑冻结验证命令,留下可复查的通过/失败证据。";
|
|
144
|
+
}
|
|
145
|
+
if (id.endsWith("-shell") && (id.includes("report") || id.includes("manifest"))) {
|
|
146
|
+
return "把本轮证据整理成报告或清单,不改业务代码。";
|
|
147
|
+
}
|
|
148
|
+
if (id.endsWith("-shell")) {
|
|
149
|
+
return "运行确定性命令并留下证据,不靠模型自由发挥。";
|
|
150
|
+
}
|
|
151
|
+
if (id.includes("scout") && id.endsWith("-pi")) {
|
|
152
|
+
return "只读侦察相关代码或测试,整理给下游使用,不改文件。";
|
|
153
|
+
}
|
|
154
|
+
if (id.includes("repair") && id.endsWith("-pi")) {
|
|
155
|
+
return "在原写入范围内做有界修复,不重开需求。";
|
|
156
|
+
}
|
|
157
|
+
if (id.includes("implement") && id.endsWith("-pi")) {
|
|
158
|
+
return "在允许路径内改代码,完成本节点负责的实现。";
|
|
159
|
+
}
|
|
160
|
+
if ((id.includes("review") || id.includes("audit")) && id.endsWith("-pi")) {
|
|
161
|
+
return "只读审查上游产出,给出通过或需修订的结论。";
|
|
162
|
+
}
|
|
163
|
+
if (id.includes("plan") && id.endsWith("-pi")) {
|
|
164
|
+
return "制定或修订计划/契约,仍不直接改业务代码。";
|
|
165
|
+
}
|
|
166
|
+
if (id.includes("closeout") && id.endsWith("-pi")) {
|
|
167
|
+
return "汇总证据并写出交接说明。";
|
|
168
|
+
}
|
|
169
|
+
if (id.includes("contract") && id.endsWith("-pi")) {
|
|
170
|
+
return "把需求收成可执行契约:范围、验收与边界。";
|
|
171
|
+
}
|
|
172
|
+
if (id.endsWith("-pi")) {
|
|
173
|
+
return "由模型完成该步骤的分析或写入,受 writeSet 与验证约束。";
|
|
174
|
+
}
|
|
175
|
+
return "";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function describeFromExecutor(executor) {
|
|
179
|
+
if (executor === "shell") return "运行确定性命令并留下证据。";
|
|
180
|
+
if (executor === "pi") return "由模型执行该步骤,范围受节点契约约束。";
|
|
181
|
+
if (executor === "static") return "按冻结规则直接给出结果,不调用模型。";
|
|
182
|
+
return "";
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @param {string | null | undefined} nodeId
|
|
187
|
+
* @param {{ executor?: string | null, label?: string | null }} [node]
|
|
188
|
+
*/
|
|
189
|
+
export function describeDagNodePurpose(nodeId, node = {}) {
|
|
190
|
+
const id = normalizeNodeId(nodeId);
|
|
191
|
+
if (!id) return "";
|
|
192
|
+
const exact = NODE_PURPOSE_BY_ID[id];
|
|
193
|
+
if (exact) return exact;
|
|
194
|
+
const patterned = describeFromPattern(id);
|
|
195
|
+
if (patterned) return patterned;
|
|
196
|
+
const label = typeof node.label === "string" ? node.label.trim() : "";
|
|
197
|
+
if (label && label !== id && label.toLowerCase() !== id.toLowerCase()) {
|
|
198
|
+
return label;
|
|
199
|
+
}
|
|
200
|
+
return describeFromExecutor(node.executor) || "";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export { NODE_PURPOSE_BY_ID };
|
|
@@ -82,8 +82,8 @@ export const uiState = {
|
|
|
82
82
|
dagNodeExecutionOutputLoading: false,
|
|
83
83
|
dagNodeExecutionOutputError: null,
|
|
84
84
|
dagNodeExecutionOutputKey: null,
|
|
85
|
-
/** When true,「执行过程」展开 message_start/end
|
|
86
|
-
sessionTimelineShowProtocol:
|
|
85
|
+
/** When true,「执行过程」展开 message_start/end 原始协议事件。默认隐藏,用户可点选展开。 */
|
|
86
|
+
sessionTimelineShowProtocol: false,
|
|
87
87
|
/** Open <details> keys restored across timeline re-renders. */
|
|
88
88
|
sessionTimelineOpenDetails: null,
|
|
89
89
|
lastSnapshot: null,
|