@tea-agent/loop-agent 0.39.0-next.30 → 0.39.0-next.31

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/build-stamp.json +2 -2
  3. package/dist/executors/pi-playwright-cli-tool.js +43 -11
  4. package/dist/shared/playwright-cli-command-policy.js +15 -0
  5. package/dist/task/source-prepare/parse-intent.js +24 -4
  6. package/dist/worker/console/dag-execution-receipt.js +33 -0
  7. package/dist/worker/console/operator-user-error.js +1 -1
  8. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CiGOV5eG.js → abnfDiagram-N423BO3Z-gauhD9kD.js} +1 -1
  9. package/dist/worker/console/static/assets/{arc-Ds9Gyfd8.js → arc-pm3c2Rsl.js} +1 -1
  10. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C6V6uC98.js → architectureDiagram-T3A2C74G-D_JAg3wH.js} +1 -1
  11. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-DezF7Ol9.js → blockDiagram-VBNYF7ZC-Dk7-ex52.js} +1 -1
  12. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCWk3gCT.js → c4Diagram-5PPSVZJV-Uval9oRI.js} +1 -1
  13. package/dist/worker/console/static/assets/channel-CVrnUdZl.js +1 -0
  14. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DbYr-Cxy.js → chunk-2GRJ4B5K-BSYjHs-v.js} +1 -1
  15. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-XSlusW4G.js → chunk-2Q5K7J3B-KGUuBXI8.js} +1 -1
  16. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BtcKAj9i.js → chunk-5RXB4S5H-JqAtxD9N.js} +1 -1
  17. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BF57lhXj.js → chunk-5VM5RSS4-D6EJOVQK.js} +1 -1
  18. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DJIlR25o.js → chunk-6Q2QTUOP-B1JriSjm.js} +1 -1
  19. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-DklNc7dm.js → chunk-GF5L2VYU-D62b96Jd.js} +1 -1
  20. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-fZNtEdQZ.js → chunk-JWPE2WC7-BsNKEC_r.js} +1 -1
  21. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BBgLqV4h.js → chunk-KBJHAD2P-B56v6-ZP.js} +1 -1
  22. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-Dl9e5n_J.js → chunk-RYQCIY6F-D2KPnd8K.js} +1 -1
  23. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-B0JK51NT.js → chunk-XXDRQBXY-kzKSCaaL.js} +1 -1
  24. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-aX91WTya.js +1 -0
  25. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-aX91WTya.js +1 -0
  26. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-Ch-ajv4O.js → cose-bilkent-JH36ORCC-C6N6KNJd.js} +1 -1
  27. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-xn_NxcfB.js → cynefin-VYW2F7L2-DiyymT2D.js} +1 -1
  28. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DRD0fyga.js → cynefinDiagram-MW4NZA55-BeKAXvf3.js} +1 -1
  29. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-COtnKp4B.js → dagre-VZM6K2ZE-TkIdXfPF.js} +1 -1
  30. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BQp_CAqG.js → diagram-7IWD3JNH-BFmSG3ks.js} +1 -1
  31. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-x0y-vNgq.js → diagram-B4RE2ZJO-DqpJT2Fs.js} +1 -1
  32. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-N2ezwL31.js → diagram-LBJQPF4R-r5ATN43t.js} +1 -1
  33. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-CSaxRH6Q.js → diagram-Q27KOJAE-DEcSCMuR.js} +1 -1
  34. package/dist/worker/console/static/assets/{diagram-UB23O5K3-6Ro7Kpbd.js → diagram-UB23O5K3-VOvYRLVc.js} +1 -1
  35. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CrIIQEAI.js → ebnfDiagram-BXEA7PRR-D7f4Cb1u.js} +1 -1
  36. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DivKcq8g.js → erDiagram-JOGREHBK-ziUf3U0G.js} +1 -1
  37. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BXrfDo8y.js → flowDiagram-UKHOOZJN-BoRdQ-1y.js} +1 -1
  38. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-LTTQmMRJ.js → ganttDiagram-PKOTCBZU-B1-GncNm.js} +1 -1
  39. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DP3o_5qd.js → gitGraphDiagram-DS77QQ5N-CTW-ph8W.js} +1 -1
  40. package/dist/worker/console/static/assets/{index-C2jmYBfu.js → index-DEbyrEfW.js} +2 -2
  41. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-wVfSY1WH.js → infoDiagram-6WML65LV-BFA337tZ.js} +1 -1
  42. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BRKfFL0I.js → ishikawaDiagram-WSZJBQD7-BtEujgRR.js} +1 -1
  43. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DEml3jLb.js → journeyDiagram-NVQOT4AX-C8ZwD2Jp.js} +1 -1
  44. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DTzBmOqN.js → kanban-definition-27J2QSJJ-Ck-z8B11.js} +1 -1
  45. package/dist/worker/console/static/assets/{linear-Cpy1d873.js → linear-CAyXjQjN.js} +1 -1
  46. package/dist/worker/console/static/assets/{mermaid.core-C1cSavOy.js → mermaid.core-CcWKn6tS.js} +5 -5
  47. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-BEBSKvYM.js → mindmap-definition-FAOFIHXS-C2NuDO7E.js} +1 -1
  48. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BrLs4Oac.js → pegDiagram-VL7TDLO6-BFub3PDz.js} +1 -1
  49. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B47AZcLa.js → pieDiagram-7S7Q4E2Y-BJx5THZ5.js} +1 -1
  50. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-s0dVeYR2.js → quadrantDiagram-CIZ2JOQS-DhalkDWV.js} +1 -1
  51. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-lW8aJ7Q6.js → railroadDiagram-AXF67PYL-CVcBM36o.js} +1 -1
  52. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BcHJPf6Q.js → requirementDiagram-LRYGKXZP-D_vy4n0w.js} +1 -1
  53. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DdegpUUf.js → sankeyDiagram-W5VNT64P-DGYdJL1D.js} +1 -1
  54. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BxFWqNv8.js → sequenceDiagram-SI44F4Z6-C1xJFg3k.js} +1 -1
  55. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-cOdUDPbR.js → sizeCapture-X5ZJPWSS-D_Fc43df.js} +1 -1
  56. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-DpxlYl8P.js → stateDiagram-OKZ733FA-BhGbIjbu.js} +1 -1
  57. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DUt1lyFL.js +1 -0
  58. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DQOfurE0.js → swimlanes-SLNWSIFB-DVkNcO-V.js} +2 -2
  59. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BM6SGr7j.js +8 -0
  60. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CIp3tC6V.js → timeline-definition-Z64GVDOM-BQU9ufV0.js} +1 -1
  61. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-C-adIPKn.js → vennDiagram-T6HMQDX7-BCQhRmYB.js} +1 -1
  62. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CiYrar9M.js → wardleyDiagram-T6FBY63Y-DWerOyHO.js} +1 -1
  63. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WHrdTV0-.js → xychartDiagram-ELKLHX3M-DxLeebQU.js} +1 -1
  64. package/dist/worker/console/static/index.html +1 -1
  65. package/dist/worker/loop-agent/loop-agent-client.js +7 -3
  66. package/dist/worker/observe/static/views/failures.js +5 -2
  67. package/dist/workflows/dag/frontend-repair.js +14 -0
  68. package/dist/workflows/dag/frontend-risk.js +15 -2
  69. package/dist/workflows/dag/frontend-test-case-checklist.js +26 -2
  70. package/dist/workflows/dag/frontend-test-case-manifest.js +5 -0
  71. package/dist/workflows/dag/frontend-test-result-contract.js +151 -11
  72. package/dist/workflows/dag/frontend-verification-trace.js +29 -4
  73. package/dist/workflows/dag/init-hybrid.js +90 -14
  74. package/harness.json +2 -2
  75. package/package.json +1 -1
  76. package/skills/fe-test-ui-scout/SKILL.md +65 -0
  77. package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
  78. package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
  79. package/skills/playwright-cli/SKILL.md +22 -0
  80. package/skills/playwright-cli-case-generator/SKILL.md +20 -1
  81. package/dist/worker/console/static/assets/channel-DMvu1nmi.js +0 -1
  82. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DVzM-02m.js +0 -1
  83. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DVzM-02m.js +0 -1
  84. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BwecGAkM.js +0 -1
  85. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D5WW_LbN.js +0 -8
package/CHANGELOG.md CHANGED
@@ -4,9 +4,12 @@
4
4
 
5
5
  ### 重点更新
6
6
 
7
+ - 前端风险分级细分 manifest 触及语义:`allowedPaths` 含 `package.json`/lockfile 或需求文本提到 package.json 不再单独触发 `new-dependency` high-risk(改一行 script、调构建参数的任务不再被顶到强制全门禁并误标高风险),只有任务文本同时出现安装语言(npm install / yarn add / pnpm add / 新增依赖等)才升级;仅路径触及时记 `new-dependency:manifest-path-without-install-language` 拒绝信号,审计可溯。
8
+ - 前端验证 fallback 生成期诚实化:真实项目无可读取的 `package.json` scripts 且未探测到本地 tsc 时,不再注入必然失败的 `npm run typecheck` / `npm run build` / `npm test`(纯静态 / vanilla JS 站点原会在 verify 阶段假失败),改为执行显式 no-op 标记命令(`No frontend verification command configured`,进入冻结命令集可被 contract 引用,trace 如实记录 not-run),并写生成期 advisory 提示用 `--verify` 或执行约束显式声明验证命令后重新生成 DAG。无 repoRoot 的单测 fixture 保留历史 generic fallback。**标记不构成验证证据(fail-closed)**:verification trace 将绑定标记的 target 判为失败、只含标记的 static 证据判为 unavailable,repair 分类归为 non-repairable `contract`,verify 节点以 `frontend verification unavailable` 硬失败阻断 review/closeout——无真实验证命令的 run 无法走完绿灯链。
7
9
  - frontend-test `passed` 回执链改按 dispatch 序号判序(B-HASH-01):`summarizePlaywrightCliReceipts` 先按 `sequence` 排序再判 open→find→cleanup 连续链;并行 `find`/`screenshot` 按完成时间落盘导致的乱序不再误杀执行已通过的 case(Wave 1 实测 4 条 passed 被改判 `browser-command-evidence-missing`)。真 gap / 重复序号仍 fail-closed。
8
10
  - `tool-policy` 失败归一为 `executor`(B-REC-03):前端 preflight 能力拒绝(缺 `@playwright/cli` JS entry、allowlist 拒绝)不再落 `unknown`→`manual-review`+`humanRequired`;`dag report` 给出 `rerun-after-fix`,Console `standaloneTaskRerun` 的 R2 gate 放行 run-failed 同 task 整单重跑,无需人工决策门或 sibling task。
9
11
  - Operator Chrome Band1 模式切换入口补显式 `aria-label`(B-FIND-01,方案 A):`操作`/`观测` mode link 原为 inline-flex 裸文本节点,不参与 name-from-content,a11y snapshot 序列化为无名 link,`find` 无法断言;补 `aria-label` 后实测 `find "观测"` 1 命中、click 后 `find "运行总览"` 1 命中,AC-FE-CHROME-003 恢复可见断言路径。
12
+ - Inspect 异常 Task 页空态文案统一(B-FIND-02):`failures.js` 运行时空态由 `当前没有失败或阻塞的 Task。` 改回与静态 `#failures-empty`、页面标题及回归目录 AC-FE-INS-004 一致的 `当前没有异常 Task`,消除静态/运行时文案漂移;实测新文案 find 1 命中、旧文案 0 命中。
10
13
 
11
14
  - `next-release.yml` 防重复发布守卫补充幂等语义:`mode=recover`(dist-tags.next 已指向出自本 HEAD 的 tarball)时,手动 `workflow_dispatch` 重入不再撞 duplicate publish 硬失败,改为写 summary 后干净退出(§5.1 规则 4);非 recover 的重复发布仍硬失败。
12
15
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "version": "0.38.3",
4
- "gitSha": "07a0a9bcee0b9aa29cafc085485f3aed7ae03cec",
5
- "builtAt": "2026-08-22T12:04:10.935Z"
4
+ "gitSha": "9c8a26e4c446c1e299e8557cbbd19fe1096b4612",
5
+ "builtAt": "2026-08-23T04:17:57.293Z"
6
6
  }
@@ -4,7 +4,7 @@ import { appendFile, lstat, mkdir, readFile, realpath, stat, } from "node:fs/pro
4
4
  import path from "node:path";
5
5
  import { processTreeSpawnOptions, terminateProcessTree, } from "./process-tree.js";
6
6
  import { resolvePlaywrightCliLauncher } from "./playwright-cli-launcher.js";
7
- import { PLAYWRIGHT_CLI_ALLOWED_COMMANDS, isPlaywrightCliCommand, } from "../shared/playwright-cli-command-policy.js";
7
+ import { PLAYWRIGHT_CLI_ALLOWED_COMMANDS, isPlaywrightCliCommand, parsePlaywrightCliFindMatchCount, } from "../shared/playwright-cli-command-policy.js";
8
8
  export { PLAYWRIGHT_CLI_ALLOWED_COMMANDS, isPlaywrightCliCommand, };
9
9
  /** Logical capability name only; execution always uses the verified JS launcher. */
10
10
  export const PLAYWRIGHT_CLI_EXECUTABLE = "playwright-cli";
@@ -144,8 +144,10 @@ export function summarizePlaywrightCliReceipts(receipts) {
144
144
  if (PLAYWRIGHT_CLI_INTERACTION_COMMANDS.has(receipt.command) && succeeded) {
145
145
  hasInteractionOrAssertion = true;
146
146
  }
147
- // A successful find is the only model-visible semantic assertion in v1.
148
- if (receipt.command === "find" && succeeded) {
147
+ // A successful find (or find-unique, its semantic wrapper) is the only
148
+ // model-visible semantic assertion in v1.
149
+ if ((receipt.command === "find" || receipt.command === "find-unique") &&
150
+ succeeded) {
149
151
  hasMeaningfulAssertion = true;
150
152
  if (ordered && sawOpen)
151
153
  sawMeaningfulAssertionAfterOpen = true;
@@ -530,6 +532,17 @@ export function preparePlaywrightCliArgv(input, ctx) {
530
532
  else if (command === "pdf" || command === "snapshot") {
531
533
  args = normalizePdfOrSnapshotArgs(command, rawArgs, ctx);
532
534
  }
535
+ else if (command === "find-unique") {
536
+ // find-unique is a controller-side semantic wrapper: the underlying CLI
537
+ // only knows `find`; uniqueness (matchCount === 1) is judged by the
538
+ // executor after parsing the find output. Require exactly one text
539
+ // literal — a unique-control assertion is meaningless with multiple.
540
+ const literals = rawArgs.filter((arg) => !arg.startsWith("-"));
541
+ if (rawArgs.length !== 1 || literals.length !== 1) {
542
+ throw new PlaywrightCliPolicyError("find-unique-args", "find-unique requires exactly one text literal and no flags");
543
+ }
544
+ args = literals;
545
+ }
533
546
  else {
534
547
  args = rewriteArgsForPaths(command, rawArgs, ctx);
535
548
  }
@@ -825,7 +838,10 @@ export async function executePlaywrightCliCommand(input, ctx, signal) {
825
838
  };
826
839
  }
827
840
  let executable = PLAYWRIGHT_CLI_EXECUTABLE;
828
- let argv = [command, ...args];
841
+ // find-unique executes as the underlying CLI `find` command; uniqueness is
842
+ // a controller-side judgment on the parsed match count.
843
+ const cliCommand = command === "find-unique" ? "find" : command;
844
+ let argv = [cliCommand, ...args];
829
845
  try {
830
846
  await validatePlaywrightCliOutputPath(command, args, ctx);
831
847
  await validatePlaywrightCliInputFiles(command, args, ctx);
@@ -834,7 +850,7 @@ export async function executePlaywrightCliCommand(input, ctx, signal) {
834
850
  if (!ctx.runCommand) {
835
851
  const launcher = resolvePlaywrightCliLauncher(ctx.repoRoot);
836
852
  executable = launcher.executable;
837
- argv = [...launcher.argvPrefix, command, ...args];
853
+ argv = [...launcher.argvPrefix, cliCommand, ...args];
838
854
  }
839
855
  }
840
856
  catch (error) {
@@ -894,6 +910,19 @@ export async function executePlaywrightCliCommand(input, ctx, signal) {
894
910
  }
895
911
  const finishedAt = new Date();
896
912
  const combined = `${runResult.stdout}\n${runResult.stderr}`;
913
+ // find-family commands report their match count in stdout with exit code
914
+ // 0 even on zero matches — parse the count so receipts carry the real
915
+ // assertion signal for finalize-side audits.
916
+ const matchCount = command === "find" || command === "find-unique"
917
+ ? parsePlaywrightCliFindMatchCount(runResult.stdout || "")
918
+ : undefined;
919
+ // find-unique fails closed unless exactly one match was found (including
920
+ // zero and unparseable outputs).
921
+ const findUniqueFailed = command === "find-unique" && matchCount !== 1 && !runResult.timedOut;
922
+ const effectiveExitCode = findUniqueFailed && runResult.exitCode === 0 ? 1 : runResult.exitCode;
923
+ const effectiveStderr = findUniqueFailed
924
+ ? `${runResult.stderr}${runResult.stderr ? "\n" : ""}find-unique: expected exactly 1 match, got ${matchCount === undefined ? "unparseable output" : `${matchCount}`}`
925
+ : runResult.stderr;
897
926
  const receipt = {
898
927
  schemaVersion: 1,
899
928
  caseId: ctx.caseId,
@@ -902,25 +931,28 @@ export async function executePlaywrightCliCommand(input, ctx, signal) {
902
931
  argsRedacted: redactPlaywrightCliArgs(command, args),
903
932
  startedAt: startedAt.toISOString(),
904
933
  finishedAt: finishedAt.toISOString(),
905
- exitCode: runResult.exitCode,
934
+ exitCode: effectiveExitCode,
906
935
  durationMs: finishedAt.getTime() - startedAt.getTime(),
907
936
  outputSha256: createHash("sha256").update(combined).digest("hex"),
908
937
  toolVersion: ctx.toolVersion ?? "unknown",
909
938
  timedOut: runResult.timedOut || undefined,
939
+ ...(matchCount !== undefined ? { matchCount } : {}),
910
940
  errorClass: runResult.timedOut
911
941
  ? "timeout"
912
942
  : runResult.signal === "abort"
913
943
  ? "abort"
914
- : runResult.exitCode === 0
944
+ : effectiveExitCode === 0
915
945
  ? undefined
916
- : "nonzero-exit",
946
+ : findUniqueFailed
947
+ ? "find-unique-count-mismatch"
948
+ : "nonzero-exit",
917
949
  };
918
950
  await appendReceipt(ctx, receipt);
919
951
  return {
920
- ok: runResult.exitCode === 0 && !runResult.timedOut,
921
- exitCode: runResult.exitCode,
952
+ ok: effectiveExitCode === 0 && !runResult.timedOut,
953
+ exitCode: effectiveExitCode,
922
954
  stdout: runResult.stdout,
923
- stderr: runResult.stderr,
955
+ stderr: effectiveStderr,
924
956
  timedOut: runResult.timedOut,
925
957
  receipt,
926
958
  errorClass: receipt.errorClass,
@@ -9,6 +9,7 @@ export const PLAYWRIGHT_CLI_ALLOWED_COMMANDS = [
9
9
  "goto",
10
10
  "snapshot",
11
11
  "find",
12
+ "find-unique",
12
13
  "click",
13
14
  "dblclick",
14
15
  "fill",
@@ -35,6 +36,20 @@ export const PLAYWRIGHT_CLI_ALLOWED_COMMANDS = [
35
36
  "requests",
36
37
  "request",
37
38
  ];
39
+ /**
40
+ * Parse the match count from a playwright-cli find output. The CLI prints
41
+ * `Found N match(es) for "...":` on success and `No matches found for "...".`
42
+ * on zero — both with exit code 0, so the count is the only assertion signal.
43
+ * Returns undefined when the output shape is unrecognized (e.g. error pages).
44
+ */
45
+ export function parsePlaywrightCliFindMatchCount(output) {
46
+ const found = /Found\s+(\d+)\s+match(?:es)?\s+for\b/i.exec(output);
47
+ if (found)
48
+ return Number(found[1]);
49
+ if (/No matches found for\b/i.test(output))
50
+ return 0;
51
+ return undefined;
52
+ }
38
53
  const allowedCommandSet = new Set(PLAYWRIGHT_CLI_ALLOWED_COMMANDS);
39
54
  export function isPlaywrightCliCommand(value) {
40
55
  return allowedCommandSet.has(value);
@@ -35,8 +35,15 @@ const HEADING_ALIASES = {
35
35
  assumptions: new Set(["假设", "assumptions"]),
36
36
  };
37
37
  const OBJECTIVE_MAX_CHARS = 1200;
38
- /** Product Requirement V3/V4 style embedded AC heading, e.g. AC-FE-001 / AC-BE-12 / AC-001. */
39
- const EMBEDDED_AC_HEADING = /^(AC(?:[-_](?:FE|BE|UI|API))?[-_]?\d+(?:[-_]\d+)?)\s*[::]?\s*(.*)$/iu;
38
+ /**
39
+ * Product Requirement V3/V4 style embedded AC heading, e.g. AC-FE-001 /
40
+ * AC-BE-12 / AC-001 — and catalog-qualified feature segments such as
41
+ * AC-FE-INS-001 / AC-FE-CHAT-005 (uppercase letter/digit segments).
42
+ * Catalog ids embedded in bold (“**AC-FE-INS-001**:…”) must bind as-is;
43
+ * falling through to a minted AC-00N historically produced dual ids and
44
+ * acceptanceCoverage.missing noise (2026-08-23 fe-test loop finding 5).
45
+ */
46
+ const EMBEDDED_AC_HEADING = /^(AC(?:[-_](?:FE|BE|UI|API))?[-_]?[A-Z0-9]+(?:[-_][A-Z0-9]+)*)\s*[::]?\s*(.*)$/u;
40
47
  function stripFencedAndComments(text) {
41
48
  // Remove fenced code blocks and HTML comments so headings inside them are ignored.
42
49
  return text
@@ -52,12 +59,25 @@ function normalizeAcceptanceId(raw) {
52
59
  .replace(/^(AC)(FE|BE|UI|API)(?=-|\d)/u, "$1-$2");
53
60
  }
54
61
  function parseEmbeddedAcHeading(headingText) {
55
- const normalized = headingText.trim().replace(/^(?:\d+(?:\.\d+)*[..、]?\s*)+/u, "");
62
+ const normalized = headingText
63
+ .trim()
64
+ // Strip leading section numbers ("2.1、" style) and bold/emphasis
65
+ // wrappers ("**AC-FE-INS-001**") so embedded catalog ids bind.
66
+ .replace(/^(?:\d+(?:\.\d+)*[..、]?\s*)+/u, "")
67
+ .replace(/^\*\*|\*\*$/g, "")
68
+ .replace(/^__|__$/g, "")
69
+ .trim();
56
70
  const match = EMBEDDED_AC_HEADING.exec(normalized);
57
71
  if (!match)
58
72
  return null;
59
73
  const id = normalizeAcceptanceId(match[1]);
60
- const text = match[2]?.trim() || id;
74
+ // Bold-wrapped ids leave their closing marker inside the captured text
75
+ // ("**AC-FE-INS-001**:xxx" captures "**:xxx"); strip emphasis remnants
76
+ // and leading separators so the bound text is clean prose.
77
+ const text = (match[2] ?? "")
78
+ .replace(/^[*_]+\s*/, "")
79
+ .replace(/^\s*[::]\s*/, "")
80
+ .trim() || id;
61
81
  return { id, text };
62
82
  }
63
83
  function normalizeHeadingText(raw) {
@@ -35,6 +35,32 @@ import { hashDagBytes, } from "./dag-confirmation.js";
35
35
  * framework invocations that don't embed the word "verify".
36
36
  */
37
37
  export const STRUCTURED_VERIFICATION_COMMAND_RE = /\b(vitest|jest|playwright|cypress|pytest|py-test|go\s+test|cargo\s+test|npm\s+run\s+(lint|typecheck|test|verify)|npm\s+(test|run\s+test)|check-repo\.sh|loop-agent-standard-verify)\b/i;
38
+ /**
39
+ * Deterministic shell preset keys whose executors are themselves structured
40
+ * verification/gate materializers: their shell.commands[] is empty and the
41
+ * preset alone carries the verification authority (hash-bound artifact
42
+ * gates, evidence validators, report finalize). Mirrors the named-shell
43
+ * handler registry in shell-executor.ts so preset-only workflows
44
+ * (frontend-test finalize/reports, backend-test pipeline, verify-evidence
45
+ * gates) pass the G2 autonomous execution gate without depending on node-id
46
+ * naming conventions.
47
+ */
48
+ export const STRUCTURED_VERIFICATION_SHELL_PRESETS = new Set([
49
+ "frontendTestCaseChecklist",
50
+ "frontendTestCaseManifest",
51
+ "frontendTestEvidenceValidation",
52
+ "frontendTestResultFinalize",
53
+ "frontendTestL5Report",
54
+ "frontendTestHtmlReport",
55
+ "frontendTestReports",
56
+ "backendTestPipeline",
57
+ "verifyEvidence",
58
+ "repairArtifactGate",
59
+ "jacocoCoverage",
60
+ "requirementCoverageGate",
61
+ "jsonArtifactGate",
62
+ "verdictGate",
63
+ ]);
38
64
  export const DEFAULT_EXECUTION_RECEIPT_TTL_MS = 30 * 60 * 1000;
39
65
  function normalizePathEntry(entry) {
40
66
  return entry.trim().replace(/\\/g, "/").replace(/^\.\//, "");
@@ -157,6 +183,13 @@ export function deriveEligibilityFactsFromDagSpec(input) {
157
183
  return false;
158
184
  if (/verify|verification/i.test(task.id ?? ""))
159
185
  return true;
186
+ // Preset-only verification shells (empty commands[]): the preset key is
187
+ // the verification authority (frontend-test finalize, backend-test
188
+ // pipeline, evidence/artifact gates).
189
+ const shellRecord = task.shell;
190
+ const hasVerificationPreset = Object.keys(shellRecord).some((key) => STRUCTURED_VERIFICATION_SHELL_PRESETS.has(key));
191
+ if (hasVerificationPreset)
192
+ return true;
160
193
  const commands = stringList(task.shell.commands);
161
194
  return commands.some((command) => STRUCTURED_VERIFICATION_COMMAND_RE.test(command));
162
195
  });
@@ -23,7 +23,7 @@ export function formatOperatorUserError(message) {
23
23
  if (recovery)
24
24
  return recovery;
25
25
  if (/controller identity changed|package fingerprint changed|entry binary sha256 changed/i.test(raw)) {
26
- return "控制器版本已变更(Console 启动后代码被重新编译)。请重启 Console 后再试,一次会话中途不要升级/重建控制器。";
26
+ return "控制器版本已变更(Console 启动后代码被重新编译,或提交了 package.json / bin / dist / skills 等指纹范围文件)。请重启 Console 进程使其重新加载当前构建后再重试本操作;一次会话中途不要重建控制器。";
27
27
  }
28
28
  if (/Pi session file missing or not openable|cannot reopen chat session .* no persisted Pi session file/i.test(raw)) {
29
29
  return "该对话的 Pi 会话文件已丢失,无法恢复上下文。请新建对话继续(历史记录无法重开)。";
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-DJIlR25o.js";import{p as f}from"./chunk-JWPE2WC7-fZNtEdQZ.js";import{_ as n,l as o}from"./mermaid.core-C1cSavOy.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-xn_NxcfB.js";import"./index-C2jmYBfu.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
+ import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-B1JriSjm.js";import{p as f}from"./chunk-JWPE2WC7-BsNKEC_r.js";import{_ as n,l as o}from"./mermaid.core-CcWKn6tS.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DiyymT2D.js";import"./index-DEbyrEfW.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-C1cSavOy.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};
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-CcWKn6tS.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};