@tea-agent/loop-agent 0.35.3 → 0.35.4-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
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.35.4-beta.0] - 2026-08-15
|
|
4
|
+
|
|
5
|
+
> frontend prewrite 阻断误路由修正 + Mock 契约文档落地(beta,发布到 `beta` dist-tag)。
|
|
6
|
+
|
|
7
|
+
### 改进
|
|
8
|
+
|
|
9
|
+
- prewrite 阻断导致的 writer `SKIPPED`(`skippedReason=frontend-prewrite-not-authorized`)失败路由从 `DependencyFailure`/`unblock dependency` 修正为 `ContractMismatch`/`fix-frontend-task-contract-and-regenerate-dag`;`dag report` / `dag doctor` 透传 `skippedReason`,对「Mock 策略契约缺陷需改 task.json + 重新生成 DAG」这类场景给出可操作建议,而非误导性的「解除依赖」
|
|
10
|
+
|
|
11
|
+
### 文档
|
|
12
|
+
|
|
13
|
+
- `docs/templates/frontend-task-constraints.md` 的 Mock 约束从 TODO 改为可落地契约:要求从项目**探索**实际存在的确定性 Mock 验证命令(不硬编码命令名)并声明到 `task.json.frontendMock.verifyCommands`,说明生成期 `allowedMockStrategies` 来源、`mock-strategy-outside-allowed` 是生成期契约问题(修复 = 补契约 + 重新生成 DAG,plan-revision 无法修复)
|
|
14
|
+
- `docs/runtime/frontend-implementation-workflow.md` 的 task.json 输入标准补充 Mock 契约声明、命令探索与失败恢复指引
|
|
4
15
|
|
|
5
16
|
## [0.35.3] - 2026-08-15
|
|
6
17
|
|
package/dist/build-stamp.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.35.
|
|
4
|
-
"gitSha": "
|
|
5
|
-
"builtAt": "2026-08-
|
|
3
|
+
"version": "0.35.4-beta.0",
|
|
4
|
+
"gitSha": "53128a51ad1db646a5fd8184d2de882a1a2211ee",
|
|
5
|
+
"builtAt": "2026-08-15T15:18:26.580Z"
|
|
6
6
|
}
|
|
@@ -44,7 +44,9 @@ function routeToProductLine(input) {
|
|
|
44
44
|
case "decision-envelope":
|
|
45
45
|
return "NeedsHuman";
|
|
46
46
|
case "skipped":
|
|
47
|
-
return "
|
|
47
|
+
return input.skippedReason === "frontend-prewrite-not-authorized"
|
|
48
|
+
? "ContractMismatch"
|
|
49
|
+
: "DependencyFailure";
|
|
48
50
|
case "shell-command":
|
|
49
51
|
if (/\b(ENOENT|PATH|command not found|No such file|not found in PATH|bash: .*: No such file)\b/i.test(raw)) {
|
|
50
52
|
return "EnvFailure";
|
|
@@ -90,9 +92,12 @@ export function routeDagFailure(input) {
|
|
|
90
92
|
if (!productLineFailureCategory)
|
|
91
93
|
return {};
|
|
92
94
|
const recommendedFollowUp = productLineFailureCategory === "ContractMismatch" &&
|
|
93
|
-
|
|
94
|
-
? "frontend-
|
|
95
|
-
:
|
|
95
|
+
input.skippedReason === "frontend-prewrite-not-authorized"
|
|
96
|
+
? "fix-frontend-task-contract-and-regenerate-dag"
|
|
97
|
+
: productLineFailureCategory === "ContractMismatch" &&
|
|
98
|
+
isFrontendDesignGateNode(input.nodeId ?? "")
|
|
99
|
+
? "frontend-plan-revision-and-rerun"
|
|
100
|
+
: FOLLOW_UP_BY_PRODUCT_LINE[productLineFailureCategory];
|
|
96
101
|
return {
|
|
97
102
|
productLineFailureCategory,
|
|
98
103
|
recommendedFollowUp,
|
|
@@ -743,6 +743,7 @@ function findDoctorFailureNode(state) {
|
|
|
743
743
|
nodeId: state.pausedByNodeId,
|
|
744
744
|
status: node?.status,
|
|
745
745
|
rawFailureCategory: node?.failureCategory,
|
|
746
|
+
skippedReason: node?.skippedReason,
|
|
746
747
|
};
|
|
747
748
|
}
|
|
748
749
|
const errorEntry = Object.entries(state.nodes).find(([, node]) => node.status === "ERROR");
|
|
@@ -758,6 +759,7 @@ function findDoctorFailureNode(state) {
|
|
|
758
759
|
nodeId: selected[0],
|
|
759
760
|
status: selected[1].status,
|
|
760
761
|
rawFailureCategory: selected[1].failureCategory,
|
|
762
|
+
skippedReason: selected[1].skippedReason,
|
|
761
763
|
};
|
|
762
764
|
}
|
|
763
765
|
async function readRunOwnedBackendTestClassification(runDir) {
|
|
@@ -786,6 +788,7 @@ async function resolveDoctorFailureRouting(input) {
|
|
|
786
788
|
normalizedFailureCategory: "unknown",
|
|
787
789
|
nodeId: input.nodeId,
|
|
788
790
|
productLineFailureCategory: classifiedCategory,
|
|
791
|
+
skippedReason: input.skippedReason,
|
|
789
792
|
});
|
|
790
793
|
}
|
|
791
794
|
return routeDagFailure(input);
|
|
@@ -807,6 +810,7 @@ async function formatDagDoctorMarkdown(repoRoot, runId) {
|
|
|
807
810
|
rawFailureCategory,
|
|
808
811
|
normalizedFailureCategory: normalizedCategory,
|
|
809
812
|
nodeId: failure.nodeId,
|
|
813
|
+
skippedReason: failure.skippedReason,
|
|
810
814
|
});
|
|
811
815
|
const evidence = failure.nodeId
|
|
812
816
|
? path.join(located.runDir, failure.nodeId, "result.summary.md")
|
|
@@ -441,6 +441,7 @@ export async function buildDagRunReportEntry(input) {
|
|
|
441
441
|
normalizedFailureCategory,
|
|
442
442
|
nodeId,
|
|
443
443
|
executor: node.executor,
|
|
444
|
+
skippedReason: node.skippedReason,
|
|
444
445
|
});
|
|
445
446
|
const followUp = node.status === "ERROR" || node.status === "SKIPPED"
|
|
446
447
|
? recommendFollowUpForFailureCategory(node.failureCategory)
|
|
@@ -505,6 +506,7 @@ export async function buildDagRunReportEntry(input) {
|
|
|
505
506
|
normalizedFailureCategory: normalizeDagFailureCategory(pausedNode.failureCategory, pausedNode.status),
|
|
506
507
|
failureCategory: pausedNode.failureCategory,
|
|
507
508
|
nodeId: input.state.pausedByNodeId,
|
|
509
|
+
skippedReason: pausedNode.skippedReason,
|
|
508
510
|
}
|
|
509
511
|
: firstActionableNode
|
|
510
512
|
? {
|
|
@@ -513,6 +515,7 @@ export async function buildDagRunReportEntry(input) {
|
|
|
513
515
|
normalizeDagFailureCategory(firstActionableNode.failureCategory, firstActionableNode.status),
|
|
514
516
|
failureCategory: firstActionableNode.failureCategory,
|
|
515
517
|
nodeId: firstActionableNode.nodeId,
|
|
518
|
+
skippedReason: input.state.nodes[firstActionableNode.nodeId]?.skippedReason,
|
|
516
519
|
}
|
|
517
520
|
: {
|
|
518
521
|
status: input.state.status,
|
|
@@ -529,6 +532,9 @@ export async function buildDagRunReportEntry(input) {
|
|
|
529
532
|
rawFailureCategory: runRecoverySource.failureCategory,
|
|
530
533
|
normalizedFailureCategory: runRecoverySource.normalizedFailureCategory,
|
|
531
534
|
nodeId: "nodeId" in runRecoverySource ? runRecoverySource.nodeId : undefined,
|
|
535
|
+
skippedReason: "skippedReason" in runRecoverySource
|
|
536
|
+
? runRecoverySource.skippedReason
|
|
537
|
+
: undefined,
|
|
532
538
|
});
|
|
533
539
|
const runFollowUp = input.state.status === "failed" ||
|
|
534
540
|
input.state.status === "partial_failed"
|
|
@@ -18,13 +18,19 @@ TODO
|
|
|
18
18
|
|
|
19
19
|
## Mock 约束(数据型任务)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
21
|
+
本段决定生成期 `allowedMockStrategies` 与冻结的 Mock 验证命令。只有当生成期**能证明任务确实包含 Mock 且有确定性验证命令**时,DAG 才会放行 `native` / `browser-intercept` / `request-adapter`;否则自动收敛为 `not-needed`,design review 若按项目规范改选 `native`,会在 prewrite 被 `mock-strategy-outside-allowed` 拦截、`implement` 被跳过。
|
|
22
|
+
|
|
23
|
+
- **何时必须填**:项目规范(`openspec/project-specs/**`、`ai_workspace/**`、mock 规则或类似 DEC-* 决策)要求/建议 Mock;或需求涉及远端接口且后端未就绪。规范要求 Mock 时,优先 `task.json.frontendMock.policy: "required"`。
|
|
24
|
+
- **命令要探索、不要硬编码**:到项目 `package.json` scripts 里找实际存在的 Mock 相关脚本(如 `mock`、`mock:*`、`dev:mock`,或名字含 mock 的脚本),结合既有 service root 的 handler/fixture/bootstrap 启动方式,确定一条**真实存在、确定、可自终止**(启动→断言→退出 0)的验证命令。常驻 dev server 必须包装成自终止脚本(start→assert→stop),否则 verify shell 会超时 fail-closed。
|
|
25
|
+
- **写入 task.json**:把探索到的命令原样写进 `frontendMock.verifyCommands`(`label` 唯一、`command` 与项目脚本一致)。`label` 会进入冻结命令集,implementation contract 的 `verificationTarget.commandLabel` 必须逐字引用它。
|
|
26
|
+
- **命令来源白名单**:只允许项目 `package.json` 已有脚本、Mock capability seed、或本段声明的 `verifyCommands`;plan/design 阶段不能发明 shell 命令。
|
|
27
|
+
- **Mock/API/schema 规范路径**:TODO
|
|
28
|
+
- **既有 Mock service root、handler/fixture/bootstrap**:TODO
|
|
29
|
+
- **既有 browser/e2e interception 或 request adapter/DI seam**:TODO
|
|
30
|
+
- **production 禁用边界**:TODO
|
|
31
|
+
- **真实请求默认路径与 Mock 显式启用方式**:TODO
|
|
32
|
+
- **`task.json.frontendMock.policy`**:`auto | required | disabled`(规范强制 Mock 用 `required`)
|
|
33
|
+
- **被拦截时怎么修**:`mock-strategy-outside-allowed` / `no authorized Mock verification commands` 是**生成期契约问题,不是 plan 问题**——补 `frontendMock.verifyCommands`(或 `policy: "required"` + 命令)后**重新生成 DAG** 再跑,plan-revision 无法修复它。
|
|
28
34
|
|
|
29
35
|
## allowedPaths
|
|
30
36
|
|