@tea-agent/loop-agent 0.39.0-next.2 → 0.39.0-next.20
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 +126 -0
- package/dist/build-stamp.json +2 -2
- package/dist/commands/init-upgrade.js +97 -19
- package/dist/executors/dag-pi-executor.js +42 -4
- package/dist/executors/shell-executor.js +269 -15
- package/dist/shared/operator/capabilities.js +149 -27
- package/dist/task/config-types.js +22 -0
- package/dist/worker/console/chat/mcp-inventory.js +221 -0
- package/dist/worker/console/chat/pi-runtime.js +165 -83
- package/dist/worker/console/chat/repo-walk.js +10 -1
- package/dist/worker/console/chat/routes.js +19 -8
- package/dist/worker/console/chat/semantic-activity.js +17 -5
- package/dist/worker/console/chat/turn-process.js +17 -30
- package/dist/worker/console/harness-pi-model-matrix.js +137 -0
- package/dist/worker/console/operator-actions.js +128 -4
- package/dist/worker/console/operator-user-error.js +19 -0
- package/dist/worker/console/pi-readiness.js +8 -1
- package/dist/worker/console/security.js +20 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DSvF6RXQ.js → abnfDiagram-N423BO3Z-BmOEx0gA.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DuI4ogtJ.js → arc-BGiVVe8b.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DdBbgD4y.js → architectureDiagram-T3A2C74G-nDdu4rgJ.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-xQC2HELm.js → blockDiagram-VBNYF7ZC-Bb5u0BWf.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DPMSgwIZ.js → c4Diagram-5PPSVZJV-BlhC0j94.js} +1 -1
- package/dist/worker/console/static/assets/channel-Tl-FkUqr.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-WTEKTxin.js → chunk-2GRJ4B5K-Ai8_qQXI.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-B6vZ0Pv_.js → chunk-2Q5K7J3B-B9gyCjqX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BrerNAix.js → chunk-5RXB4S5H-Bzbj3zGH.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-D_ch2aaI.js → chunk-5VM5RSS4-BT415PvT.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-VvfacNrq.js → chunk-6Q2QTUOP-D_A5_5QL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-B-uGFIg2.js → chunk-GF5L2VYU-srJkaP3f.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BlysCtod.js → chunk-JWPE2WC7-UYGvEP4l.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BjAUAfcT.js → chunk-KBJHAD2P-B8luBrrz.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-BeZnBmb-.js → chunk-RYQCIY6F-DN7wXZSq.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Bbfe3UJG.js → chunk-XXDRQBXY-DXKyMuKS.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BaehtRk4.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BaehtRk4.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BKJQnYVM.js → cose-bilkent-JH36ORCC-dqvoynXj.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-B1wtI3hU.js → cynefin-VYW2F7L2--PcyL34A.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DCF6DBSu.js → cynefinDiagram-MW4NZA55-DvWs_hTY.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BJyNGRlP.js → dagre-VZM6K2ZE-DxeIxbyO.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B7j1-VsZ.js → diagram-7IWD3JNH-DPCG61Of.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BREJ140a.js → diagram-B4RE2ZJO-CmuU50-U.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CDPHmHGH.js → diagram-LBJQPF4R-B61XLD_v.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BtZLrez1.js → diagram-Q27KOJAE-BB7HTRRY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-mzybu8oU.js → diagram-UB23O5K3-DvkboAIp.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Dk3I2uO6.js → ebnfDiagram-BXEA7PRR-BdJ_y1fL.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BT97u_tQ.js → erDiagram-JOGREHBK-9bUBZTRi.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CMOtYzui.js → flowDiagram-UKHOOZJN-Dw4L4RBa.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DiNydkuY.js → ganttDiagram-PKOTCBZU-Jr82N_QP.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js → gitGraphDiagram-DS77QQ5N-DAz9wFLr.js} +1 -1
- package/dist/worker/console/static/assets/index-B7Y-0g3J.css +1 -0
- package/dist/worker/console/static/assets/index-DkCrqaYg.js +325 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-AsGIGKKB.js → infoDiagram-6WML65LV-CBB5Np7y.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BL8ITZh3.js → ishikawaDiagram-WSZJBQD7-D8IOp94y.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-VPKAUX8M.js → journeyDiagram-NVQOT4AX-Dgd3AHGG.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-BL56hfGp.js → kanban-definition-27J2QSJJ-BmYOxLE9.js} +1 -1
- package/dist/worker/console/static/assets/{linear-BmSG3nIZ.js → linear-DfYTEF6J.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DWGK9kwP.js → mermaid.core-BjuFPRqa.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS--vvKLjo0.js → mindmap-definition-FAOFIHXS-CLyUViGd.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-B41mxb2-.js → pegDiagram-VL7TDLO6-BvX2Di4-.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DTlu77sw.js → pieDiagram-7S7Q4E2Y-BFj0_OLv.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Bk5A7alv.js → quadrantDiagram-CIZ2JOQS-BIUrD_hx.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Csf9jzQy.js → railroadDiagram-AXF67PYL-CHBB48fj.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CeptoSNx.js → requirementDiagram-LRYGKXZP-sJrYw2Sf.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-A-DLCLer.js → sankeyDiagram-W5VNT64P-BzHH6fPR.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-22VbPdOI.js → sequenceDiagram-SI44F4Z6-7QCnelCt.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DWvAyBC9.js → sizeCapture-X5ZJPWSS-sDYSxn72.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-qICZ75yT.js → stateDiagram-OKZ733FA-XpiUdwzm.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-eEhq2A8Y.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-xi7lcMyp.js → swimlanes-SLNWSIFB-DvqgNPzD.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-la8AC7fo.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Bu6Nl6O2.js → timeline-definition-Z64GVDOM-2TyOYNx0.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BzMz4Bn9.js → vennDiagram-T6HMQDX7-B-nM6wM2.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CxaJnzc5.js → wardleyDiagram-T6FBY63Y-B86wPdbr.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-5JK-omQK.js → xychartDiagram-ELKLHX3M-Dr1C4AQz.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +39 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +44 -21
- package/dist/worker/console/static-src/operator-chat/mutation-gate.js +45 -0
- package/dist/worker/console/static-src/operator-chat/resource-diagnostics.js +204 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +15 -0
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +17 -4
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +28 -22
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +26 -1
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +755 -51
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-execution-contract.js +18 -9
- package/dist/workflows/dag/backend-test-gap-fill.js +205 -0
- package/dist/workflows/dag/backend-test-intake-context.js +32 -0
- package/dist/workflows/dag/backend-test-layout.js +133 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +167 -32
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +368 -33
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/backend-test-scenario-param.js +884 -140
- package/dist/workflows/dag/backend-test-scenario-partitions.js +249 -0
- package/dist/workflows/dag/backend-test-writer-completeness.js +100 -56
- package/dist/workflows/dag/contract-validator-registrations.js +3 -1
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +386 -0
- package/dist/workflows/dag/frontend-plan-render.js +90 -0
- package/dist/workflows/dag/frontend-prewrite-gate.js +243 -8
- package/dist/workflows/dag/init-hybrid.js +753 -104
- package/dist/workflows/dag/node-execution.js +61 -2
- package/dist/workflows/dag/retry-policy.js +4 -0
- package/dist/workflows/dag/types.js +74 -0
- package/docs/templates/backend-test-dag.json +60 -35
- package/docs/templates/frontend-implementation-contract.schema.json +9 -2
- package/harness.json +3 -1
- package/package.json +1 -1
- package/skills/frontend-design-review/references/review-checklist.md +2 -0
- package/skills/frontend-implementation/references/design-spec.md +16 -19
- package/skills/frontend-implementation/references/node-contracts.md +9 -6
- package/dist/worker/console/static/assets/channel-DLVz9TYW.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/index-DQxiso1w.js +0 -325
- package/dist/worker/console/static/assets/index-_j0Hzo69.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +0 -8
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* harness.json executors.pi LOW/MED/HIGH 模型矩阵的读写与校验。
|
|
3
|
+
*
|
|
4
|
+
* 该模块只服务于 Console「模型与认证」页的模型矩阵编辑器:
|
|
5
|
+
* - `validatePiModelMatrixTiers`:写入前拒绝空串 / default 哨兵 / 非字符串 /
|
|
6
|
+
* 畸形 provider/model(如 provider/、/model、a//b)。
|
|
7
|
+
* - `readPiModelMatrixProjection`:读全文档并投影三档的 provider/model 或裸
|
|
8
|
+
* model id(供 readiness 结构化投影 piModelMatrix 使用)。
|
|
9
|
+
* - `writePiModelMatrix`:读全文档 → 校验 → 原子写 tmp + fsync + rename,
|
|
10
|
+
* 保留 $schema 与其余所有字段。
|
|
11
|
+
*
|
|
12
|
+
* 本模块在 worker/console(Node 侧),不得被浏览器静态资源直接 import
|
|
13
|
+
* (依赖 node:fs / node:crypto / node:path)。
|
|
14
|
+
*/
|
|
15
|
+
import { randomBytes } from "node:crypto";
|
|
16
|
+
import { open, readFile, rename, writeFile } from "node:fs/promises";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { normalizeExecutorTierValue } from "../../governance/manifest-types.js";
|
|
19
|
+
export const PI_MODEL_TIERS = ["LOW", "MED", "HIGH"];
|
|
20
|
+
/** 校验单档字符串值,返回错误文案;合法返回 undefined。 */
|
|
21
|
+
export function piModelTierValueError(value) {
|
|
22
|
+
if (typeof value !== "string")
|
|
23
|
+
return "模型值必须是字符串";
|
|
24
|
+
if (value.length === 0)
|
|
25
|
+
return "模型值不能为空";
|
|
26
|
+
if (value.trim() !== value)
|
|
27
|
+
return "模型值不能包含首尾空白";
|
|
28
|
+
if (value === "default")
|
|
29
|
+
return "default 是保留哨兵,不能作为模型值";
|
|
30
|
+
// 比 normalizeExecutorTierValue 更严格:拒绝 provider/、/model、a//b。
|
|
31
|
+
if (value.startsWith("/") || value.endsWith("/") || value.includes("//")) {
|
|
32
|
+
return "provider/model 格式非法:不允许 /model、provider/ 或 a//b";
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 写入前校验三档字符串值。任何一档非法即整体拒绝,保证不落盘。
|
|
38
|
+
*/
|
|
39
|
+
export function validatePiModelMatrixTiers(input) {
|
|
40
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
code: "INVALID_INPUT",
|
|
44
|
+
message: "模型矩阵必须是 { LOW, MED, HIGH } 对象",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const record = input;
|
|
48
|
+
const tiers = {};
|
|
49
|
+
for (const tier of PI_MODEL_TIERS) {
|
|
50
|
+
const raw = record[tier];
|
|
51
|
+
const error = piModelTierValueError(raw);
|
|
52
|
+
if (error) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
code: "INVALID_INPUT",
|
|
56
|
+
message: `${tier}: ${error}`,
|
|
57
|
+
tier,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
tiers[tier] = raw;
|
|
61
|
+
}
|
|
62
|
+
return { ok: true, tiers };
|
|
63
|
+
}
|
|
64
|
+
async function readHarnessJson(repoRoot) {
|
|
65
|
+
try {
|
|
66
|
+
const raw = await readFile(path.join(repoRoot, "harness.json"), "utf8");
|
|
67
|
+
const parsed = JSON.parse(raw);
|
|
68
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 投影 harness.json executors.pi 三档(provider/model 或裸 model id)。
|
|
79
|
+
* 缺文件 / 非法 JSON / 未配置档位均优雅降级为缺省,绝不抛错。
|
|
80
|
+
*/
|
|
81
|
+
export async function readPiModelMatrixProjection(repoRoot) {
|
|
82
|
+
const manifest = await readHarnessJson(repoRoot);
|
|
83
|
+
const pi = manifest?.executors?.pi;
|
|
84
|
+
const projection = {};
|
|
85
|
+
if (!pi || typeof pi !== "object")
|
|
86
|
+
return projection;
|
|
87
|
+
for (const tier of PI_MODEL_TIERS) {
|
|
88
|
+
const selection = normalizeExecutorTierValue(pi[tier]);
|
|
89
|
+
if (!selection)
|
|
90
|
+
continue;
|
|
91
|
+
projection[tier] = {
|
|
92
|
+
model: selection.model,
|
|
93
|
+
...(selection.provider ? { provider: selection.provider } : {}),
|
|
94
|
+
value: selection.provider
|
|
95
|
+
? `${selection.provider}/${selection.model}`
|
|
96
|
+
: selection.model,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return projection;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 原子更新 harness.json executors.pi.LOW/MED/HIGH:
|
|
103
|
+
* 读全文档 → 校验 → 保留其余字段 → 写 tmp + fsync + rename。
|
|
104
|
+
*/
|
|
105
|
+
export async function writePiModelMatrix(repoRoot, tiers) {
|
|
106
|
+
const validation = validatePiModelMatrixTiers(tiers);
|
|
107
|
+
if (!validation.ok) {
|
|
108
|
+
throw Object.assign(new Error(validation.message), {
|
|
109
|
+
code: validation.code,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const file = path.join(repoRoot, "harness.json");
|
|
113
|
+
const manifest = await readHarnessJson(repoRoot);
|
|
114
|
+
if (!manifest) {
|
|
115
|
+
throw Object.assign(new Error("harness.json 不存在或不是合法 JSON"), {
|
|
116
|
+
code: "HARNESS_NOT_FOUND",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const executors = (manifest.executors ?? {});
|
|
120
|
+
const pi = (executors.pi ?? {});
|
|
121
|
+
const nextPi = { ...pi };
|
|
122
|
+
for (const tier of PI_MODEL_TIERS) {
|
|
123
|
+
nextPi[tier] = validation.tiers[tier];
|
|
124
|
+
}
|
|
125
|
+
const nextManifest = { ...manifest, executors: { ...executors, pi: nextPi } };
|
|
126
|
+
const body = `${JSON.stringify(nextManifest, null, 2)}\n`;
|
|
127
|
+
const tmp = path.join(repoRoot, `.harness.${process.pid}.${randomBytes(4).toString("hex")}.tmp`);
|
|
128
|
+
await writeFile(tmp, body, { encoding: "utf8" });
|
|
129
|
+
const handle = await open(tmp, "r+");
|
|
130
|
+
try {
|
|
131
|
+
await handle.sync();
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
await handle.close();
|
|
135
|
+
}
|
|
136
|
+
await rename(tmp, file);
|
|
137
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { access, readFile } from "node:fs/promises";
|
|
2
|
-
import { buildOperatorCapabilitiesDocument } from "../../shared/operator/capabilities.js";
|
|
2
|
+
import { buildOperatorCapabilitiesDocument, OFFICIAL_TAIL_ACTION_IDS, } from "../../shared/operator/capabilities.js";
|
|
3
3
|
import { buildOperatorResult, operatorFailed, operatorSucceeded, } from "../../shared/operator/envelope.js";
|
|
4
4
|
import { CANONICAL_TASK_ID_PATTERN, formatLocalBusinessDate, getTaskPaths, loadTaskConfig, } from "../../task/runtime.js";
|
|
5
5
|
import { diffTaskContract, validateDraftForTask, } from "../../task/contract/index.js";
|
|
@@ -11,6 +11,7 @@ import { resolveLatestDagRunIdForTask } from "./resolve-dag-run-for-task.js";
|
|
|
11
11
|
import { repoFingerprintV1 } from "./repo-fingerprint.js";
|
|
12
12
|
import { scheduleOperation, } from "./operation-runner.js";
|
|
13
13
|
import { readinessGateFailure, } from "./pi-readiness.js";
|
|
14
|
+
import { validatePiModelMatrixTiers, writePiModelMatrix, } from "./harness-pi-model-matrix.js";
|
|
14
15
|
import { isAssessmentFreshForDraft } from "./interview/assessment.js";
|
|
15
16
|
import { applyGrillMeAnswer, draftSummary, emptyDraft, isDraftStructurallyComplete, nextGrillMeQuestion, } from "./interview/grill-me.js";
|
|
16
17
|
import { toCanonicalDraftForCli, } from "./draft-store.js";
|
|
@@ -671,6 +672,80 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
671
672
|
const body = await runReadCli(ctx, ["dag", "report", "--run-id", runId, "--json"], "dag report");
|
|
672
673
|
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
673
674
|
}
|
|
675
|
+
case "dagDoctor": {
|
|
676
|
+
const runId = str(p.runId) ?? str(p.dagRunId);
|
|
677
|
+
const args = ["dag", "doctor"];
|
|
678
|
+
if (runId)
|
|
679
|
+
args.push("--run-id", runId);
|
|
680
|
+
const body = await runReadCli(ctx, args, "dag doctor");
|
|
681
|
+
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
682
|
+
}
|
|
683
|
+
case "dagStatus": {
|
|
684
|
+
const runId = str(p.runId) ?? str(p.dagRunId);
|
|
685
|
+
if (!runId)
|
|
686
|
+
return invalid(action, "runId is required");
|
|
687
|
+
const body = await runReadCli(ctx, ["dag", "status", "--run-id", runId], "dag status");
|
|
688
|
+
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
689
|
+
}
|
|
690
|
+
case "workerPoolDoctor": {
|
|
691
|
+
const taskId = str(p.taskId);
|
|
692
|
+
const run = ctx.runCommand ??
|
|
693
|
+
((args, options) => ctx.client.runExternal
|
|
694
|
+
? ctx.client.runExternal(resolveSiblingAgentWorkerBin(), args, options)
|
|
695
|
+
: ctx.client.run(args, options));
|
|
696
|
+
let result;
|
|
697
|
+
try {
|
|
698
|
+
result = await run(["pool", "doctor", "--repo", ctx.repoRoot, "--json"], {
|
|
699
|
+
cwd: ctx.repoRoot,
|
|
700
|
+
artifactName: "read-pool-doctor",
|
|
701
|
+
expectJson: true,
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
catch (error) {
|
|
705
|
+
return {
|
|
706
|
+
kind: "error",
|
|
707
|
+
status: 400,
|
|
708
|
+
body: operatorFailed({
|
|
709
|
+
command: action,
|
|
710
|
+
outcome: "invalid",
|
|
711
|
+
code: "INVALID_INPUT",
|
|
712
|
+
message: `cannot read pool doctor facts: ${error instanceof Error ? error.message : String(error)}`,
|
|
713
|
+
}),
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
if (!result.ok || result.exitCode !== 0 || !result.json) {
|
|
717
|
+
return {
|
|
718
|
+
kind: "error",
|
|
719
|
+
status: 400,
|
|
720
|
+
body: operatorFailed({
|
|
721
|
+
command: action,
|
|
722
|
+
outcome: "invalid",
|
|
723
|
+
code: "INVALID_INPUT",
|
|
724
|
+
message: summarizeReadCliFailure(result),
|
|
725
|
+
}),
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
const inventory = result.json;
|
|
729
|
+
if (!taskId) {
|
|
730
|
+
return {
|
|
731
|
+
kind: "sync",
|
|
732
|
+
status: 200,
|
|
733
|
+
body: operatorSucceeded(action, inventory),
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
const v2 = (inventory.v2 ?? []).filter((entry) => entry.taskId === taskId);
|
|
737
|
+
const legacy = (inventory.legacy ?? []).filter((entry) => entry.taskId === taskId);
|
|
738
|
+
return {
|
|
739
|
+
kind: "sync",
|
|
740
|
+
status: 200,
|
|
741
|
+
body: operatorSucceeded(action, {
|
|
742
|
+
...inventory,
|
|
743
|
+
v2,
|
|
744
|
+
legacy,
|
|
745
|
+
focusedTaskId: taskId,
|
|
746
|
+
}),
|
|
747
|
+
};
|
|
748
|
+
}
|
|
674
749
|
case "status": {
|
|
675
750
|
const taskId = str(p.taskId);
|
|
676
751
|
if (!taskId) {
|
|
@@ -985,7 +1060,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
985
1060
|
}
|
|
986
1061
|
if (operatorAction) {
|
|
987
1062
|
const target = buildOperatorCapabilitiesDocument().actions.find((entry) => entry.action === operatorAction &&
|
|
988
|
-
entry.
|
|
1063
|
+
OFFICIAL_TAIL_ACTION_IDS.has(entry.action) &&
|
|
989
1064
|
entry.humanConfirmation === "required");
|
|
990
1065
|
if (!target)
|
|
991
1066
|
return invalid(action, "operatorAction must name a required official action");
|
|
@@ -2483,12 +2558,61 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2483
2558
|
}),
|
|
2484
2559
|
};
|
|
2485
2560
|
}
|
|
2561
|
+
case "savePiModelMatrix": {
|
|
2562
|
+
// 「模型与认证」页模型矩阵编辑器:三档字符串值经校验后原子写入
|
|
2563
|
+
// harness.json executors.pi,并自动重测 readiness。写路径本身由 HTTP
|
|
2564
|
+
// 层 evaluateMutationGate 拦截(cookie + confirmation 头 + origin)。
|
|
2565
|
+
const matrixInput = p.matrix ?? p;
|
|
2566
|
+
const validation = validatePiModelMatrixTiers(matrixInput);
|
|
2567
|
+
if (!validation.ok) {
|
|
2568
|
+
return {
|
|
2569
|
+
kind: "error",
|
|
2570
|
+
status: 400,
|
|
2571
|
+
body: operatorFailed({
|
|
2572
|
+
command: action,
|
|
2573
|
+
outcome: "invalid",
|
|
2574
|
+
code: validation.code,
|
|
2575
|
+
message: validation.message,
|
|
2576
|
+
...(validation.tier ? { details: { tier: validation.tier } } : {}),
|
|
2577
|
+
}),
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
try {
|
|
2581
|
+
await writePiModelMatrix(ctx.repoRoot, validation.tiers);
|
|
2582
|
+
}
|
|
2583
|
+
catch (error) {
|
|
2584
|
+
return {
|
|
2585
|
+
kind: "error",
|
|
2586
|
+
status: 500,
|
|
2587
|
+
body: operatorFailed({
|
|
2588
|
+
command: action,
|
|
2589
|
+
outcome: "blocked",
|
|
2590
|
+
code: "PI_MODEL_MATRIX_WRITE_FAILED",
|
|
2591
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2592
|
+
}),
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
// 保存成功自动重测 readiness(复用 probePiReadiness),让页面立即
|
|
2596
|
+
// 展示新的 modelsAvailable / modelsMessage / piModelMatrix(AC-4)。
|
|
2597
|
+
const report = ctx.refreshReadiness
|
|
2598
|
+
? await ctx.refreshReadiness()
|
|
2599
|
+
: ctx.getReadiness?.() ?? ctx.readiness;
|
|
2600
|
+
return {
|
|
2601
|
+
kind: "sync",
|
|
2602
|
+
status: 200,
|
|
2603
|
+
body: operatorSucceeded("savePiModelMatrix", {
|
|
2604
|
+
tiers: validation.tiers,
|
|
2605
|
+
readiness: report,
|
|
2606
|
+
}),
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2486
2609
|
default: {
|
|
2487
2610
|
// M5 official-command coverage uses one generic tail for newly registered
|
|
2488
2611
|
// CLI actions. It remains inside dispatchOperatorAction (the sole dispatch
|
|
2489
2612
|
// surface) and only accepts argv arrays declared by the capability schema.
|
|
2490
|
-
|
|
2491
|
-
|
|
2613
|
+
// 2026-08-18: high-frequency entries got real descriptions; membership is
|
|
2614
|
+
// now derived from OFFICIAL_TAIL_ACTION_IDS, not description prefixes.
|
|
2615
|
+
const capability = buildOperatorCapabilitiesDocument().actions.find((entry) => entry.action === action && OFFICIAL_TAIL_ACTION_IDS.has(entry.action));
|
|
2492
2616
|
if (capability) {
|
|
2493
2617
|
const rawArgs = p.args;
|
|
2494
2618
|
if (rawArgs !== undefined &&
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { rewriteRecoveryOperatorError } from "./recovery-error-copy.js";
|
|
2
|
+
/** Mutation-gate raw English messages (worker/console/security.ts) → copy. */
|
|
3
|
+
const MUTATION_GATE_COPY = [
|
|
4
|
+
{
|
|
5
|
+
pattern: /invalid (boot capability|confirmation header) token/i,
|
|
6
|
+
copy: "页面已过期(控制台已重启),请刷新页面(F5)后重试。",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
pattern: /mutation requires boot capability cookie|mutation requires confirmation header token/i,
|
|
10
|
+
copy: "页面状态异常,请刷新页面(F5)后重试。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
pattern: /Host header is required for non-loopback/i,
|
|
14
|
+
copy: "请求主机校验失败:非回环绑定时要求 Host 头,请刷新页面或检查访问地址。",
|
|
15
|
+
},
|
|
16
|
+
];
|
|
2
17
|
/** Map internal spawn/controller errors to actionable Chinese copy. */
|
|
3
18
|
export function formatOperatorUserError(message) {
|
|
4
19
|
const raw = (message ?? "").trim();
|
|
@@ -22,5 +37,9 @@ export function formatOperatorUserError(message) {
|
|
|
22
37
|
if (/force-required|requires --force/i.test(raw)) {
|
|
23
38
|
return "该终态需要强制 Discard。请确认后勾选强制再试。";
|
|
24
39
|
}
|
|
40
|
+
for (const entry of MUTATION_GATE_COPY) {
|
|
41
|
+
if (entry.pattern.test(raw))
|
|
42
|
+
return entry.copy;
|
|
43
|
+
}
|
|
25
44
|
return raw;
|
|
26
45
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { mapSnapshotAvailableModels, resolveHarnessPiExecutorMatrix, } from "./chat/model-resolver.js";
|
|
7
|
+
import { readPiModelMatrixProjection, } from "./harness-pi-model-matrix.js";
|
|
7
8
|
const SETUP_BLOCKED = Object.freeze([
|
|
8
9
|
"newTask",
|
|
9
10
|
"importPrd",
|
|
@@ -221,6 +222,7 @@ export async function discoverPiReadinessProbe(options) {
|
|
|
221
222
|
authReady,
|
|
222
223
|
modelsAvailable,
|
|
223
224
|
interviewSessionOk,
|
|
225
|
+
piAvailableModels: availableModels,
|
|
224
226
|
details: {
|
|
225
227
|
sdkMessage: `Pi SDK 0.80.10 contract available (agentDir=${agentDir})`,
|
|
226
228
|
authMessage: authReady
|
|
@@ -238,13 +240,18 @@ export async function discoverPiReadinessProbe(options) {
|
|
|
238
240
|
* override is injected. Tests inject override for determinism.
|
|
239
241
|
*/
|
|
240
242
|
export async function probePiReadiness(options) {
|
|
243
|
+
const repoRoot = options?.repoRoot ?? process.cwd();
|
|
244
|
+
// 模型矩阵投影与 SDK 探测解耦:即使 SDK 不可用 / 测试注入 override,仍要
|
|
245
|
+
// 投影 harness.json 三档值供模型矩阵编辑器预填(AC-1 / AC-4)。
|
|
246
|
+
const piModelMatrix = await readPiModelMatrixProjection(repoRoot);
|
|
241
247
|
if (options?.override) {
|
|
242
|
-
return buildPiReadinessReport(options.override);
|
|
248
|
+
return buildPiReadinessReport({ ...options.override, piModelMatrix });
|
|
243
249
|
}
|
|
244
250
|
try {
|
|
245
251
|
const probe = await discoverPiReadinessProbe({
|
|
246
252
|
repoRoot: options?.repoRoot,
|
|
247
253
|
});
|
|
254
|
+
probe.piModelMatrix = piModelMatrix;
|
|
248
255
|
if (options?.siblingControllerOk && !probe.details) {
|
|
249
256
|
probe.details = {};
|
|
250
257
|
}
|
|
@@ -54,6 +54,25 @@ function safeEqualToken(a, b) {
|
|
|
54
54
|
* cookie boot token AND custom confirmation header/token + Host/Origin checks +
|
|
55
55
|
* Sec-Fetch-Site not cross-site.
|
|
56
56
|
*/
|
|
57
|
+
/**
|
|
58
|
+
* Loopback origin equivalence: a Console bound to a loopback host accepts
|
|
59
|
+
* page Origins that resolve to the same loopback server — localhost,
|
|
60
|
+
* 127.0.0.1 and [::1] on the SAME port are interchangeable aliases (browsers
|
|
61
|
+
* treat them as distinct sites, so a third-party page can never spoof one).
|
|
62
|
+
* This keeps bookmarks / autocomplete on `localhost:port` working against a
|
|
63
|
+
* Console bound to `127.0.0.1:port` (and vice versa).
|
|
64
|
+
*/
|
|
65
|
+
function loopbackOriginMatches(origin, consoleOrigin) {
|
|
66
|
+
if (origin === consoleOrigin)
|
|
67
|
+
return true;
|
|
68
|
+
const parseLoopback = (value) => {
|
|
69
|
+
const match = /^http:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/i.exec(value);
|
|
70
|
+
return match ? `${match[1].toLowerCase()}${match[2] ?? ""}` : null;
|
|
71
|
+
};
|
|
72
|
+
const originKey = parseLoopback(origin);
|
|
73
|
+
const consoleKey = parseLoopback(consoleOrigin);
|
|
74
|
+
return originKey !== null && consoleKey !== null && originKey === consoleKey;
|
|
75
|
+
}
|
|
57
76
|
export function evaluateMutationGate(req, ctx) {
|
|
58
77
|
const cookieToken = parseCookieHeader(req.headers.cookie, BOOT_CAPABILITY_COOKIE);
|
|
59
78
|
if (!cookieToken) {
|
|
@@ -127,7 +146,7 @@ export function evaluateMutationGate(req, ctx) {
|
|
|
127
146
|
}
|
|
128
147
|
else if (typeof origin !== "string" ||
|
|
129
148
|
origin.length === 0 ||
|
|
130
|
-
origin
|
|
149
|
+
!loopbackOriginMatches(origin, ctx.consoleOrigin)) {
|
|
131
150
|
return {
|
|
132
151
|
status: 403,
|
|
133
152
|
code: "origin-mismatch",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-D_A5_5QL.js";import{p as f}from"./chunk-JWPE2WC7-UYGvEP4l.js";import{_ as n,l as o}from"./mermaid.core-BjuFPRqa.js";import{M as c,b as d}from"./cynefin-VYW2F7L2--PcyL34A.js";import"./index-DkCrqaYg.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-
|
|
1
|
+
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-BjuFPRqa.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|