@tea-agent/loop-agent 0.44.0-next.12 → 0.44.0-next.13

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 (122) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/commands/init.js +1 -0
  4. package/dist/executors/dag-pi-executor.js +11 -6
  5. package/dist/executors/pi-writer-tool-policy.js +60 -4
  6. package/dist/executors/playwright-cli-launcher.js +31 -45
  7. package/dist/executors/shell-write-guard.js +24 -67
  8. package/dist/governance/exec-plans.js +10 -1
  9. package/dist/task/config-types.js +4 -2
  10. package/dist/task/source-prepare/build-draft.js +1 -0
  11. package/dist/task/source-prepare/path-policy.js +17 -7
  12. package/dist/worker/console/chat/browser-automation.js +343 -38
  13. package/dist/worker/console/chat/browser-content.js +74 -0
  14. package/dist/worker/console/chat/browser-diagnostics.js +250 -0
  15. package/dist/worker/console/chat/browser-evaluation.js +58 -0
  16. package/dist/worker/console/chat/browser-operation-queue.js +19 -0
  17. package/dist/worker/console/chat/browser-pick.js +113 -0
  18. package/dist/worker/console/chat/browser-routes.js +33 -5
  19. package/dist/worker/console/chat/browser-screenshot-result.js +47 -0
  20. package/dist/worker/console/chat/browser-storage.js +89 -0
  21. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +125 -174
  22. package/dist/worker/console/chat/pi-runtime.js +1 -1
  23. package/dist/worker/console/chat/repo-browser.js +80 -2
  24. package/dist/worker/console/chat/repo-preview-kind.js +155 -0
  25. package/dist/worker/console/chat/session-mode.js +1 -1
  26. package/dist/worker/console/chat/session-store.js +4 -2
  27. package/dist/worker/console/chat/tools.js +12 -0
  28. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-r1NAPU_5.js → abnfDiagram-N423BO3Z-BA7qCL_r.js} +1 -1
  29. package/dist/worker/console/static/assets/{arc-dT5T4sVL.js → arc-Df09ajwL.js} +1 -1
  30. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CP_cOq46.js → architectureDiagram-T3A2C74G-CpF9sw5R.js} +1 -1
  31. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-sToEZxEf.js → blockDiagram-VBNYF7ZC-BtPys8ja.js} +1 -1
  32. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DSxwwi2m.js → c4Diagram-5PPSVZJV-DZPnTWqT.js} +1 -1
  33. package/dist/worker/console/static/assets/channel-DiTNLZUm.js +1 -0
  34. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-B9fh0IkF.js → chunk-2GRJ4B5K-BD9D4h1p.js} +1 -1
  35. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CAUNl-A6.js → chunk-2Q5K7J3B-Svn8yBmn.js} +1 -1
  36. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BomeqbNX.js → chunk-5RXB4S5H-B8EbQj-S.js} +1 -1
  37. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BNAuTOLE.js → chunk-5VM5RSS4-tENZpcpF.js} +1 -1
  38. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DfzjRD5y.js → chunk-6Q2QTUOP-DBx71Lco.js} +1 -1
  39. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C3uE-yc2.js → chunk-GF5L2VYU-1v_QamMz.js} +1 -1
  40. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-C3sQMMYr.js → chunk-JWPE2WC7-BAMCNNBG.js} +1 -1
  41. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-D_AtEYQL.js → chunk-KBJHAD2P-BvuEury-.js} +1 -1
  42. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DW4TwhKv.js → chunk-RYQCIY6F-YqFuHp8s.js} +1 -1
  43. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CTQDmJcp.js → chunk-XXDRQBXY-ouI5T7Mr.js} +1 -1
  44. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DgL8aiyZ.js +1 -0
  45. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DgL8aiyZ.js +1 -0
  46. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-iMqPuBsL.js → cose-bilkent-JH36ORCC-Bri0_Izk.js} +1 -1
  47. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DktIuDWs.js → cynefin-VYW2F7L2-e8Vhhi4X.js} +1 -1
  48. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BgVnjyEs.js → cynefinDiagram-MW4NZA55-tSIXGQiJ.js} +1 -1
  49. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CR25E4bu.js → dagre-VZM6K2ZE-Rl-sF5pt.js} +1 -1
  50. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CPM2h5HY.js → diagram-7IWD3JNH-Db6ddPz8.js} +1 -1
  51. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-DqF0x2g1.js → diagram-B4RE2ZJO-Jwd_Xw5S.js} +1 -1
  52. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-G8BYp2eb.js → diagram-LBJQPF4R-CeC_8InC.js} +1 -1
  53. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BbC4kT_D.js → diagram-Q27KOJAE-LKPRaNq8.js} +1 -1
  54. package/dist/worker/console/static/assets/{diagram-UB23O5K3-CKZwZ-G5.js → diagram-UB23O5K3-DlVQytMW.js} +1 -1
  55. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-kJDmheia.js → ebnfDiagram-BXEA7PRR-DnfJZwO-.js} +1 -1
  56. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DFTVHyxB.js → erDiagram-JOGREHBK-3axVSXca.js} +1 -1
  57. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BqdN5_os.js → flowDiagram-UKHOOZJN-xe04-_L-.js} +1 -1
  58. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-SYDjVakh.js → ganttDiagram-PKOTCBZU-hpmRINiD.js} +1 -1
  59. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js → gitGraphDiagram-DS77QQ5N-6HSNz9Ko.js} +1 -1
  60. package/dist/worker/console/static/assets/index-C_8_gWal.css +1 -0
  61. package/dist/worker/console/static/assets/{index-CTMZsDmh.js → index-DybcVXCu.js} +102 -100
  62. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DIeAmJ45.js → infoDiagram-6WML65LV-BF6ksWTX.js} +1 -1
  63. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-oikqUAlo.js → ishikawaDiagram-WSZJBQD7-DXisdeD7.js} +1 -1
  64. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-mKEF_xYT.js → journeyDiagram-NVQOT4AX-BWu65wmu.js} +1 -1
  65. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-BdWJHPnN.js → kanban-definition-27J2QSJJ-hfNhHqAI.js} +1 -1
  66. package/dist/worker/console/static/assets/{linear-DGRlieMH.js → linear-D6HTfQcp.js} +1 -1
  67. package/dist/worker/console/static/assets/{mermaid.core-4P9yPC9c.js → mermaid.core-Iv91R1WP.js} +5 -5
  68. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-5PTSkos6.js → mindmap-definition-FAOFIHXS-CfPChwjR.js} +1 -1
  69. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DONIFpG5.js → pegDiagram-VL7TDLO6-B7TcoqHz.js} +1 -1
  70. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-D_Z4S70M.js → pieDiagram-7S7Q4E2Y-ouyPKMtQ.js} +1 -1
  71. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CAsjh8iY.js → quadrantDiagram-CIZ2JOQS-B9tuyLbh.js} +1 -1
  72. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Cx4Dd6ac.js → railroadDiagram-AXF67PYL-Ck4q9nJs.js} +1 -1
  73. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-cQb7mwyH.js → requirementDiagram-LRYGKXZP-wXLX5Dnp.js} +1 -1
  74. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cd-DhUdf.js → sankeyDiagram-W5VNT64P-D2XWw6_m.js} +1 -1
  75. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-AlKYRgIk.js → sequenceDiagram-SI44F4Z6-DzxKiug4.js} +1 -1
  76. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-CUy_ET4e.js → sizeCapture-X5ZJPWSS-DWUqK5Us.js} +1 -1
  77. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-CTuVe6Sa.js → stateDiagram-OKZ733FA-D5Pa4O5g.js} +1 -1
  78. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-C0QIbqO4.js +1 -0
  79. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-ChFLJb-v.js → swimlanes-SLNWSIFB-VH7cRnsJ.js} +2 -2
  80. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BB9CzRHB.js +8 -0
  81. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DZZeiAPr.js → timeline-definition-Z64GVDOM-C4HM5NoZ.js} +1 -1
  82. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-t4O91cZU.js → vennDiagram-T6HMQDX7-Bu-4hOlA.js} +1 -1
  83. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CV5qGHZu.js → wardleyDiagram-T6FBY63Y-CasFEvvl.js} +1 -1
  84. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DyXbytUI.js → xychartDiagram-ELKLHX3M-D-gpwPSA.js} +1 -1
  85. package/dist/worker/console/static/index.html +2 -2
  86. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +57 -9
  87. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +6 -0
  88. package/dist/worker/console/workspace-context.js +1 -0
  89. package/dist/worker/materialize/harness-task-lineage.js +4 -2
  90. package/dist/worker/observe/static/console-theme.css +33 -29
  91. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +3 -1
  92. package/dist/workflows/dag/backend-test-layout.js +27 -7
  93. package/dist/workflows/dag/backend-test-markdown-workflow.js +3 -1
  94. package/dist/workflows/dag/frontend-test-case-checklist.js +12 -3
  95. package/dist/workflows/dag/frontend-test-environment-probe.js +0 -2
  96. package/dist/workflows/dag/frontend-test-layout.js +41 -12
  97. package/dist/workflows/dag/hybrid/sources.js +21 -2
  98. package/dist/workflows/dag/hybrid/templates/backend-test.js +65 -50
  99. package/dist/workflows/dag/hybrid/templates/frontend-test.js +58 -37
  100. package/dist/workflows/dag/test-artifact-namespace.js +73 -0
  101. package/dist/workflows/dag/validate.js +22 -3
  102. package/docs/templates/README.md +4 -4
  103. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +3 -3
  104. package/docs/templates/backend-test-dag.json +708 -708
  105. package/docs/templates/backend-test-dag.review-cases.prompt.md +3 -3
  106. package/docs/templates/frontend-test-case-checklist.md +2 -2
  107. package/docs/templates/frontend-test-dag.generate-cases.prompt.md +7 -7
  108. package/docs/templates/frontend-test-dag.json +46 -37
  109. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +2 -2
  110. package/docs/templates/frontend-test-dag.retrospect.prompt.md +1 -1
  111. package/docs/templates/frontend-test-dag.review-cases.prompt.md +1 -1
  112. package/package.json +7 -2
  113. package/skills/fe-test-ui-scout/SKILL.md +4 -4
  114. package/skills/fe-test-ui-scout/references/ledger-schema.md +1 -1
  115. package/skills/playwright-cli/SKILL.md +1 -1
  116. package/skills/playwright-cli-case-generator/SKILL.md +4 -4
  117. package/dist/worker/console/static/assets/channel-CyBY_yGk.js +0 -1
  118. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +0 -1
  119. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +0 -1
  120. package/dist/worker/console/static/assets/index-B28Onmfy.css +0 -1
  121. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +0 -1
  122. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +0 -8
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- 供 `review-and-revise-backend-md-cases-pi` 使用。该节点是 `executor: "pi"`、`role: "reviewer"`、`toolProfile: "write"` 的受限 reviewer,只能直接修订 `testcase/md/**`,不得生成 pytest 或修改任务源、生产代码和配置。
5
+ 供 `review-and-revise-backend-md-cases-pi` 使用。该节点是 `executor: "pi"`、`role: "reviewer"`、`toolProfile: "write"` 的受限 reviewer,只能直接修订 `.harness/testcase/md/**`,不得生成 pytest 或修改任务源、生产代码和配置。
6
6
 
7
7
  ## 当前合同
8
8
 
@@ -10,7 +10,7 @@
10
10
 
11
11
  ### 阅读体验
12
12
 
13
- - `testcase/md/README.md` 是简洁入口,包含测试目标、环境、隔离/清理策略、模块汇总和可跳转的用例索引。
13
+ - `.harness/testcase/md/README.md` 是简洁入口,包含测试目标、环境、隔离/清理策略、模块汇总和可跳转的用例索引。
14
14
  - 模块文件采用中文用例卡片;每条以 `## BE-<MODULE>-<NNN>|<中文用例名称>` 开始;`<NNN>` 必须是三位补零序号(`001`,禁止 `01`)。Reviewer 发现两位序号或模块下划线时,必须在标题、README 索引与自动化映射中一致规范化(如 `BE-RESOURCE_NOTES-01` → `BE-RESOURCE-NOTES-001`)。
15
15
  - 新文档优先使用:`测试目的`、`验收标准`、`需求依据`、`前置条件`、`测试数据`、`操作步骤`、`预期结果`、`自动化映射`。
16
16
  - validator 同时接受上述中文分节和历史英文分节;机器 ID、HTTP 方法、路径、字段、枚举、文件名、函数名与 source citation 必须保持精确。
@@ -22,7 +22,7 @@
22
22
  - 对照每条 `需求依据` 和环境报告检查 AC、接口、字段/响应形状、状态码、错误语义、状态转换、正向/异常/边界场景。
23
23
  - 删除无依据场景、合并重复用例、补齐有依据的遗漏;无法确认的内容写入中文证据缺口,不猜测行为或凭据。
24
24
  - 拒绝“符合预期”“正常工作”等模糊结果,以及无意义的中英双写和大段重复 boilerplate。
25
- - 若能确定脚本与函数命名,在 `自动化映射` 中写明计划脚本路径与 pytest 函数/方法名;脚本路径必须等于模块 one-to-one 路径 `testcase/test_<module>.py`,`<module>` 来自当前 Markdown 文件名 stem,不得使用 Case-ID 式模块名(如 `BE-HEALTH.md`)或与模块 stem 不一致的映射。
25
+ - 若能确定脚本与函数命名,在 `自动化映射` 中写明计划脚本路径与 pytest 函数/方法名;脚本路径必须等于模块 one-to-one 路径 `.harness/testcase/test_<module>.py`,`<module>` 来自当前 Markdown 文件名 stem,不得使用 Case-ID 式模块名(如 `BE-HEALTH.md`)或与模块 stem 不一致的映射。
26
26
 
27
27
  ## 推荐输出
28
28
 
@@ -15,7 +15,7 @@ LLM review (when `frontendTest.reviewMode=blocking`) must not invent blocking ru
15
15
  | `unknown-ac` | When task `sourceBinding.requirementIds` lists ACs, every `acIds` entry must be in that set |
16
16
  | `case-id-shape` | `caseId` matches `FE-<FEATURE>-<NNN>-...` (never `AC-FE-*`) |
17
17
  | `case-id-is-ac` | Do not use acceptance id as `caseId` / filename |
18
- | `case-path-mismatch` | `casePath === {casesDir}/{caseId}.md`(默认 `testcase/frontend/cases/{caseId}.md`) |
18
+ | `case-path-mismatch` | `casePath === {casesDir}/{caseId}.md`(默认 `.harness/testcase/frontend/cases/{caseId}.md`) |
19
19
  | `case-file-missing` | `casePath` exists |
20
20
 
21
21
  ## Tool guidance (non-blocking)
@@ -40,5 +40,5 @@ LLM review (when `frontendTest.reviewMode=blocking`) must not invent blocking ru
40
40
 
41
41
  ## Pipeline vs quality
42
42
 
43
- - **Pipeline acceptance**: final `{reportsDir}/frontend-test-retrospect-*.md` exists after result materialize (default `testcase/frontend/reports/`)
43
+ - **Pipeline acceptance**: final `{reportsDir}/frontend-test-retrospect-*.md` exists after result materialize (default `.harness/testcase/frontend/reports/`)
44
44
  - **Quality**: `frontend-test-result-v1.outcome=passed` with 0 blocked/failed (opt-in via `frontendTest.strictOutcomeGate`)
@@ -1,6 +1,6 @@
1
1
  # Generate frontend functional cases
2
2
 
3
- Use `playwright-cli-case-generator`. Read only `testcase/frontend/rag/context.md`, `coverage-map.md`, and existing `testcase/frontend/cases/`; write only that cases directory. Produce Markdown cases, `index.md`, and schema-version-1 `manifest.draft.json` (materialize promotes to `manifest.json`). Do not generate pytest or Playwright source code.
3
+ Use `playwright-cli-case-generator`. Read only `.harness/testcase/frontend/rag/context.md`, `coverage-map.md`, and existing `.harness/testcase/frontend/cases/`; write only that cases directory. Produce Markdown cases, `index.md`, and schema-version-1 `manifest.draft.json` (materialize promotes to `manifest.json`). Do not generate pytest or Playwright source code.
4
4
 
5
5
  ## HARD ID contract (frequent failure)
6
6
 
@@ -11,12 +11,12 @@ Use `playwright-cli-case-generator`. Read only `testcase/frontend/rag/context.md
11
11
 
12
12
  - **Never** set `caseId` to `AC-FE-001` or name the file `AC-FE-001.md`.
13
13
  - **Never** put `FE-LOGIN-001-core` into `acIds`.
14
- - `casePath` must be `testcase/frontend/cases/<caseId>.md`.
15
- - `evidenceDir` must be `testcase/frontend/evidence/<caseId>/`.
14
+ - `casePath` must be `.harness/testcase/frontend/cases/<caseId>.md`.
15
+ - `evidenceDir` must be `.harness/testcase/frontend/evidence/<caseId>/`.
16
16
 
17
17
  Each case is independently executable and includes AC mapping (`acIds`), preconditions, cleanup, a semantic assertion, and its isolated evidence path. Use dimensions `core`, `boundary`, `flow`, or `backend`. Never guess API fields, constraints, SLA, credentials, or unrecorded data. For passed authority, include a successful `playwright-cli find ...` after `open` and before controller post-execution cleanup; `snapshot`, `goto`, `screenshot`, `request`/`console`, and ordinary interactions are not assertions.
18
18
 
19
- Every case must copy the concrete absolute base URL from `testcase/frontend/rag/context.md` only after the environment shell has marked `environmentProbe: reachable`. Do not derive a different origin and do not leave a base-url placeholder.
19
+ Every case must copy the concrete absolute base URL from `.harness/testcase/frontend/rag/context.md` only after the environment shell has marked `environmentProbe: reachable`. Do not derive a different origin and do not leave a base-url placeholder.
20
20
 
21
21
  Every case must start with `playwright-cli open --browser=chrome` followed by that concrete context URL. Do not copy an angle-bracket URL placeholder into a generated executable case line.
22
22
 
@@ -49,15 +49,15 @@ For every executable sub-scenario, state the fixture/reset operation, UI reset o
49
49
 
50
50
  Each case must require the executor to persist, even when blocked:
51
51
 
52
- - `testcase/frontend/evidence/<case-id>/execution.md`
53
- - `testcase/frontend/evidence/<case-id>/case-result.json`
52
+ - `.harness/testcase/frontend/evidence/<case-id>/execution.md`
53
+ - `.harness/testcase/frontend/evidence/<case-id>/case-result.json`
54
54
 
55
55
  `case-result.json` must be valid JSON containing the matching `caseId`, final `status` (`passed`, `failed`, or `blocked`), and an `evidencePaths` array. A rerun must overwrite this same file with its final status and integer `rerunAttempt`; the final report consumes that latest file. A blocked result must include a non-empty `blockedReason`, such as `isolated-test-environment-unavailable` or `token-budget-exhausted`, and must never claim or imply a pass. `execution.md` records attempted or blocked steps, base-URL safety decision, fixture/reset and request-observation availability, timestamps, and the evidence-file list. When available, use fixed headings `### 执行摘要` and `### 实际执行步骤` so the bounded deterministic report extractor can show actual execution facts. Available evidence files are required only when actually produced and must stay under the same case evidence directory.
56
56
 
57
57
 
58
58
  ## Standard scenarios (controller)
59
59
 
60
- - Read `testcase/frontend/rag/standard-scenarios.v1.json` when present.
60
+ - Read `.harness/testcase/frontend/rag/standard-scenarios.v1.json` when present.
61
61
  - Cover each `priority=must` scenario with at least one case or record an explicit GAP in coverage-map.
62
62
  - Each case Markdown SHOULD include `## 测试点` and `## 测试步骤` sections.
63
63
  - Prefer linking cases via `standardScenarioIds` in manifest.draft notes when possible.
@@ -14,7 +14,7 @@
14
14
  "Every generated browser start command uses playwright-cli open --browser=chrome followed by the concrete URL selected by retrieve-frontend-test-context-pi from bound task source/config and written to context.md; the environment shell must mark that URL reachable before generation/execution; executable case lines never retain an angle-bracket URL/ref placeholder; subsequent commands stay in that default session and must not use unverified named-session flags.",
15
15
  "Case children execute serially. Persist each case result, logs and browser evidence before the next child starts.",
16
16
  "A token threshold is a post-case stop check, not a model hard token cap; unstarted cases must be recorded as blocked: token-budget-exhausted.",
17
- "Default pipeline acceptance is the final frontend-test-result-v1 plus testcase/frontend/reports/frontend-test-report.html",
17
+ "Default pipeline acceptance is the final frontend-test-result-v1 plus .harness/testcase/frontend/reports/frontend-test-report.html",
18
18
  "Default frontendTest.reviewMode=off uses mechanical checklist-shell before materialize; set reviewMode=blocking for legacy dual LLM review gate.",
19
19
  "playwright-cli-only: generators and executors may call only skill-declared playwright-cli commands; bare playwright / npx playwright / @playwright/test / Playwright source are forbidden with no native Playwright fallback.",
20
20
  "Browser-tool preflight (preflight-frontend-browser-tool-shell) must reject CODE_AGENT_PI_BACKEND=cli-only, verify the Pi SDK structured custom-tool surface, and confirm the verified playwright-cli launcher + --help open/close/find/snapshot/click contract before any frontend-test Pi node; it does not select or freeze the tested URL; missing capability/CLI fails with zero Pi calls.",
@@ -57,16 +57,16 @@
57
57
  "complexity": "LOW",
58
58
  "writePolicy": "exclusive",
59
59
  "writeSet": [
60
- "testcase/frontend/rag/**"
60
+ ".harness/testcase/frontend/rag/**"
61
61
  ],
62
62
  "allowedPaths": [
63
- "testcase/frontend/rag/**"
63
+ ".harness/testcase/frontend/rag/**"
64
64
  ],
65
65
  "forbiddenPaths": [
66
66
  ".harness/**",
67
67
  "artifacts/**"
68
68
  ],
69
- "outputContract": "Write testcase/frontend/rag/standard-scenarios.v1.json for generate-time standard scenario coverage. Copy docs/templates or harness.json governanceRoot templates (including ai_workspace/loop-agent/templates) when present; otherwise write the minimal STD-FE-SMOKE-ENTRY fallback.",
69
+ "outputContract": "Write .harness/testcase/frontend/rag/standard-scenarios.v1.json for generate-time standard scenario coverage. Copy docs/templates or harness.json governanceRoot templates (including ai_workspace/loop-agent/templates) when present; otherwise write the minimal STD-FE-SMOKE-ENTRY fallback.",
70
70
  "subtask_prompt": "Prepare frontend-test package: materialize standard-scenarios.v1.json into the RAG package from docs/templates, governanceRoot/templates, or the init-projected ai_workspace/loop-agent/templates path.",
71
71
  "shell": {
72
72
  "commands": [],
@@ -86,11 +86,11 @@
86
86
  "complexity": "MED",
87
87
  "writePolicy": "exclusive",
88
88
  "writeSet": [
89
- "testcase/frontend/rag/**"
89
+ ".harness/testcase/frontend/rag/**"
90
90
  ],
91
91
  "allowedPaths": [
92
92
  "REPLACE/WITH/SOURCE/PATH/**",
93
- "testcase/frontend/rag/**"
93
+ ".harness/testcase/frontend/rag/**"
94
94
  ],
95
95
  "forbiddenPaths": [
96
96
  ".harness/**",
@@ -110,17 +110,17 @@
110
110
  "complexity": "LOW",
111
111
  "writePolicy": "exclusive",
112
112
  "writeSet": [
113
- "testcase/frontend/rag/**"
113
+ ".harness/testcase/frontend/rag/**"
114
114
  ],
115
115
  "allowedPaths": [
116
- "testcase/frontend/rag/**"
116
+ ".harness/testcase/frontend/rag/**"
117
117
  ],
118
118
  "forbiddenPaths": [
119
119
  ".harness/**",
120
120
  "artifacts/**"
121
121
  ],
122
122
  "outputContract": "Fail-closed environment preflight: absolute non-production baseUrl + curl HTTP reachability; writes environmentProbe facts; unreachable => blockedReason frontend-base-url-unreachable with errorClass (connection-refused / dns-unresolved / connect-timeout / http-N). Node ERROR so generate/map do not run. Does not start the app.",
123
- "subtask_prompt": "Parse the concrete baseUrl selected by retrieve-frontend-test-context-pi from testcase/frontend/rag/context.md. Reject production, non-http(s), credentials, query and fragment. Probe with curl (HEAD then GET fallback; connect/max-time; no auth/cookie). 2xx/3xx => reachable and continue. Connection refused records errorClass=connection-refused and tells the operator to start the local app then rerun from this node. 4xx/5xx/DNS/timeout/TLS => blockedReason frontend-base-url-unreachable. Missing curl => blockedReason curl-unavailable. Do not start the app.",
123
+ "subtask_prompt": "Parse the concrete baseUrl selected by retrieve-frontend-test-context-pi from .harness/testcase/frontend/rag/context.md. Reject production, non-http(s), credentials, query and fragment. Probe with curl (HEAD then GET fallback; connect/max-time; no auth/cookie). 2xx/3xx => reachable and continue. Connection refused records errorClass=connection-refused and tells the operator to start the local app then rerun from this node. 4xx/5xx/DNS/timeout/TLS => blockedReason frontend-base-url-unreachable. Missing curl => blockedReason curl-unavailable. Do not start the app.",
124
124
  "shell": {
125
125
  "commands": [],
126
126
  "frontendTestEnvironmentProbe": {},
@@ -139,13 +139,13 @@
139
139
  "complexity": "HIGH",
140
140
  "writePolicy": "exclusive",
141
141
  "writeSet": [
142
- "testcase/frontend/cases/FE-*.md",
143
- "testcase/frontend/cases/index.md",
144
- "testcase/frontend/cases/manifest.draft.json"
142
+ ".harness/testcase/frontend/cases/FE-*.md",
143
+ ".harness/testcase/frontend/cases/index.md",
144
+ ".harness/testcase/frontend/cases/manifest.draft.json"
145
145
  ],
146
146
  "allowedPaths": [
147
- "testcase/frontend/rag/**",
148
- "testcase/frontend/cases/**"
147
+ ".harness/testcase/frontend/rag/**",
148
+ ".harness/testcase/frontend/cases/**"
149
149
  ],
150
150
  "forbiddenPaths": [
151
151
  ".harness/**",
@@ -165,11 +165,11 @@
165
165
  "complexity": "LOW",
166
166
  "writePolicy": "exclusive",
167
167
  "writeSet": [
168
- "testcase/frontend/cases/**"
168
+ ".harness/testcase/frontend/cases/**"
169
169
  ],
170
170
  "allowedPaths": [
171
- "testcase/frontend/rag/**",
172
- "testcase/frontend/cases/**"
171
+ ".harness/testcase/frontend/rag/**",
172
+ ".harness/testcase/frontend/cases/**"
173
173
  ],
174
174
  "forbiddenPaths": [
175
175
  ".harness/**",
@@ -233,17 +233,17 @@
233
233
  "outputContract": "Compact JSON <=1200 chars. Browser actions must use structured playwright_cli tool.",
234
234
  "writePolicy": "exclusive",
235
235
  "allowedPaths": [
236
- "testcase/frontend/cases/{{case.caseId}}.md",
237
- "testcase/frontend/rag/context.md",
238
- "testcase/frontend/rag/coverage-map.md",
239
- "testcase/frontend/evidence/{{case.caseId}}/**"
236
+ ".harness/testcase/frontend/cases/{{case.caseId}}.md",
237
+ ".harness/testcase/frontend/rag/context.md",
238
+ ".harness/testcase/frontend/rag/coverage-map.md",
239
+ ".harness/testcase/frontend/evidence/{{case.caseId}}/**"
240
240
  ],
241
241
  "forbiddenPaths": [
242
242
  ".harness/**",
243
243
  "artifacts/**"
244
244
  ],
245
245
  "writeSet": [
246
- "testcase/frontend/evidence/{{case.caseId}}/**"
246
+ ".harness/testcase/frontend/evidence/{{case.caseId}}/**"
247
247
  ],
248
248
  "writeGuardPolicy": "tools-only"
249
249
  }
@@ -259,11 +259,11 @@
259
259
  "complexity": "LOW",
260
260
  "writePolicy": "exclusive",
261
261
  "writeSet": [
262
- "testcase/frontend/evidence/**"
262
+ ".harness/testcase/frontend/evidence/**"
263
263
  ],
264
264
  "allowedPaths": [
265
- "testcase/frontend/cases/**",
266
- "testcase/frontend/evidence/**"
265
+ ".harness/testcase/frontend/cases/**",
266
+ ".harness/testcase/frontend/evidence/**"
267
267
  ],
268
268
  "forbiddenPaths": [
269
269
  ".harness/**",
@@ -273,7 +273,7 @@
273
273
  "subtask_prompt": "Select frontend-test cases eligible for bounded rerun.",
274
274
  "shell": {
275
275
  "commands": [
276
- "node -e \"const fs=require('fs'),path=require('path');const manifestPath='testcase/frontend/cases/manifest.json';if(!fs.existsSync(manifestPath)){process.stdout.write(JSON.stringify({cases:[]}));process.exit(0);}const manifest=JSON.parse(fs.readFileSync(manifestPath,'utf8'));const cases=[];for(const c of (manifest.cases||[])){const evidenceDir=(c.evidenceDir||('testcase/frontend/evidence/'+c.caseId+'/')).replace(/\\/+$/,'')+'/';const resultPath=path.join(evidenceDir,'case-result.json');const execPath=path.join(evidenceDir,'execution.md');let reason=null;let attempt=0;let missing=false;if(!fs.existsSync(resultPath)){missing=true;reason='missing-result-files';}else{try{const r=JSON.parse(fs.readFileSync(resultPath,'utf8'));attempt=Number(r.rerunAttempt||0)||0;if(r.status==='blocked')reason='blocked';if(!r.status){missing=true;reason='missing-result-files';}}catch(e){missing=true;reason='missing-result-files';}}if(!fs.existsSync(execPath)){const st=reason;if(st!=='blocked'){missing=true;reason=reason||'missing-result-files';}}const should=(reason==='blocked'||missing)&&attempt<1;if(should){cases.push({caseId:c.caseId,casePath:c.casePath||('testcase/frontend/cases/'+c.caseId+'.md'),evidenceDir,dimension:c.dimension||'core',acIds:c.acIds||[],rerunAttempt:attempt+1,reason:reason||'blocked'});}}const out={schemaVersion:1,cases};fs.mkdirSync('testcase/frontend/evidence',{recursive:true});fs.writeFileSync('testcase/frontend/evidence/rerun-candidates.json',JSON.stringify(out,null,2)+'\\n');process.stdout.write(JSON.stringify({cases}));"
276
+ "node -e \"const fs=require('fs'),path=require('path');const manifestPath='.harness/testcase/frontend/cases/manifest.json';if(!fs.existsSync(manifestPath)){process.stdout.write(JSON.stringify({cases:[]}));process.exit(0);}const manifest=JSON.parse(fs.readFileSync(manifestPath,'utf8'));const cases=[];for(const c of (manifest.cases||[])){const evidenceDir=(c.evidenceDir||('.harness/testcase/frontend/evidence/'+c.caseId+'/')).replace(/\\/+$/,'')+'/';const resultPath=path.join(evidenceDir,'case-result.json');const execPath=path.join(evidenceDir,'execution.md');let reason=null;let attempt=0;let missing=false;if(!fs.existsSync(resultPath)){missing=true;reason='missing-result-files';}else{try{const r=JSON.parse(fs.readFileSync(resultPath,'utf8'));attempt=Number(r.rerunAttempt||0)||0;if(r.status==='blocked')reason='blocked';if(!r.status){missing=true;reason='missing-result-files';}}catch(e){missing=true;reason='missing-result-files';}}if(!fs.existsSync(execPath)){const st=reason;if(st!=='blocked'){missing=true;reason=reason||'missing-result-files';}}const should=(reason==='blocked'||missing)&&attempt<1;if(should){cases.push({caseId:c.caseId,casePath:c.casePath||('.harness/testcase/frontend/cases/'+c.caseId+'.md'),evidenceDir,dimension:c.dimension||'core',acIds:c.acIds||[],rerunAttempt:attempt+1,reason:reason||'blocked'});}}const out={schemaVersion:1,cases};fs.mkdirSync('.harness/testcase/frontend/evidence',{recursive:true});fs.writeFileSync('.harness/testcase/frontend/evidence/rerun-candidates.json',JSON.stringify(out,null,2)+'\\n');process.stdout.write(JSON.stringify({cases}));"
277
277
  ],
278
278
  "cwd": ".",
279
279
  "timeoutMs": 120000
@@ -328,17 +328,17 @@
328
328
  "outputContract": "Compact JSON <=1200 chars. Browser actions must use structured playwright_cli tool.",
329
329
  "writePolicy": "exclusive",
330
330
  "allowedPaths": [
331
- "testcase/frontend/cases/{{case.caseId}}.md",
332
- "testcase/frontend/rag/context.md",
333
- "testcase/frontend/rag/coverage-map.md",
334
- "testcase/frontend/evidence/{{case.caseId}}/**"
331
+ ".harness/testcase/frontend/cases/{{case.caseId}}.md",
332
+ ".harness/testcase/frontend/rag/context.md",
333
+ ".harness/testcase/frontend/rag/coverage-map.md",
334
+ ".harness/testcase/frontend/evidence/{{case.caseId}}/**"
335
335
  ],
336
336
  "forbiddenPaths": [
337
337
  ".harness/**",
338
338
  "artifacts/**"
339
339
  ],
340
340
  "writeSet": [
341
- "testcase/frontend/evidence/{{case.caseId}}/**"
341
+ ".harness/testcase/frontend/evidence/{{case.caseId}}/**"
342
342
  ],
343
343
  "writeGuardPolicy": "tools-only"
344
344
  }
@@ -354,11 +354,11 @@
354
354
  "complexity": "LOW",
355
355
  "writePolicy": "exclusive",
356
356
  "writeSet": [
357
- "testcase/frontend/evidence/**"
357
+ ".harness/testcase/frontend/evidence/**"
358
358
  ],
359
359
  "allowedPaths": [
360
- "testcase/frontend/cases/**",
361
- "testcase/frontend/evidence/**"
360
+ ".harness/testcase/frontend/cases/**",
361
+ ".harness/testcase/frontend/evidence/**"
362
362
  ],
363
363
  "forbiddenPaths": [
364
364
  ".harness/**",
@@ -383,10 +383,10 @@
383
383
  "complexity": "LOW",
384
384
  "writePolicy": "exclusive",
385
385
  "writeSet": [
386
- "testcase/frontend/reports/**"
386
+ ".harness/testcase/frontend/reports/**"
387
387
  ],
388
388
  "allowedPaths": [
389
- "testcase/frontend/**"
389
+ ".harness/testcase/frontend/**"
390
390
  ],
391
391
  "forbiddenPaths": [
392
392
  ".harness/**",
@@ -403,5 +403,14 @@
403
403
  "timeoutMs": 120000
404
404
  }
405
405
  }
406
- ]
406
+ ],
407
+ "frontendTestLayout": {
408
+ "testRoot": ".harness/testcase/frontend",
409
+ "ragDir": ".harness/testcase/frontend/rag",
410
+ "casesDir": ".harness/testcase/frontend/cases",
411
+ "evidenceDir": ".harness/testcase/frontend/evidence",
412
+ "reportsDir": ".harness/testcase/frontend/reports",
413
+ "fixturesDir": ".harness/testcase/frontend/fixtures",
414
+ "isDefault": true
415
+ }
407
416
  }
@@ -1,6 +1,6 @@
1
1
  # Retrieve frontend test context
2
2
 
3
- Write only `testcase/frontend/rag/context.md` and `coverage-map.md`. Record traceable facts from the task source, routes, components, API/Mock contracts, existing tests and execution contract. Do not invent fields, credentials, limits or test data.
3
+ Write only `.harness/testcase/frontend/rag/context.md` and `coverage-map.md`. Record traceable facts from the task source, routes, components, API/Mock contracts, existing tests and execution contract. Do not invent fields, credentials, limits or test data.
4
4
 
5
5
  ## Runtime Base URL resolution (required)
6
6
 
@@ -17,5 +17,5 @@ Do not claim the environment is reachable until preflight completes. Preflight d
17
17
 
18
18
  ## Standard scenario coverage
19
19
 
20
- - Copy or reference `docs/templates/frontend-test-standard-scenarios.v1.json`, `harness.json` `governanceRoot`/templates, or the init-projected `ai_workspace/loop-agent/templates/frontend-test-standard-scenarios.v1.json` into `testcase/frontend/rag/standard-scenarios.v1.json` when available.
20
+ - Copy or reference `docs/templates/frontend-test-standard-scenarios.v1.json`, `harness.json` `governanceRoot`/templates, or the init-projected `ai_workspace/loop-agent/templates/frontend-test-standard-scenarios.v1.json` into `.harness/testcase/frontend/rag/standard-scenarios.v1.json` when available.
21
21
  - Add `## Standard scenario coverage` to coverage-map.md with planned/n/a for each must scenario.
@@ -1,5 +1,5 @@
1
1
  # Frontend test retrospective
2
2
 
3
- Write a dated report under `testcase/frontend/reports/` (for example `frontend-test-retrospect-<date>.md`) after `frontend-test-result-v1` materialization. Do **not** require outcome=pass; failed, incomplete, and blocked runs still need a report.
3
+ Write a dated report under `.harness/testcase/frontend/reports/` (for example `frontend-test-retrospect-<date>.md`) after `frontend-test-result-v1` materialization. Do **not** require outcome=pass; failed, incomplete, and blocked runs still need a report.
4
4
 
5
5
  Combine a short AC → case → browser-evidence review with the closeout: case coverage, passed/failed/blocked results (including `token-budget-exhausted`), evidence gaps, browser anomalies, residual risks, and an A/B/C/D maturity rating. Cite the deterministic case-evidence validation outcome. Passed cases should reference the successful `find` assertion plus screenshot or equivalent browser evidence and the ordered post-execution cleanup receipt when available; failed/blocked cases need explicit reasons. Blocked cases never count as passed; a missing or malformed `execution.md` / `case-result.json` is a verification gap, not a pass. Do not write under `docs/**`.
@@ -2,4 +2,4 @@
2
2
 
3
3
  Read the RAG files and Markdown cases only. First line must be `VERDICT: pass` or `VERDICT: request-revision`. Report AC coverage, case independence, evidence completeness, unsafe environment/data dependencies, and manifest issues. This verdict is a deterministic safety gate: `request-revision` blocks manifest materialization and browser execution.
4
4
 
5
- Every case must retain the exact browser-start command prefix with the resolved absolute baseUrl from `testcase/frontend/rag/context.md` (prefer task source `config.md`, else `http://localhost:5173`): `playwright-cli open --browser=chrome <resolved-base-url>`; session flags must not precede `open`, and subsequent commands must remain in its default session without `-s=` or assumed named-session binding. Verify every executable sub-scenario specifies fixture/reset, UI reset, fresh snapshot before element refs, a successful `playwright-cli find ...` semantic assertion after `open`, and an evidence write point. `snapshot`, `goto`, `screenshot`, `request`/`console`, and ordinary interactions cannot independently authorize passed. Verify each case requires both `execution.md` and `case-result.json` under its own evidence directory. The JSON result must contain matching `caseId`, `status` (`passed`, `failed`, or `blocked`) and `evidencePaths`; blocked cases must name a non-empty `blockedReason` and cannot count as passed.
5
+ Every case must retain the exact browser-start command prefix with the resolved absolute baseUrl from `.harness/testcase/frontend/rag/context.md` (prefer task source `config.md`, else `http://localhost:5173`): `playwright-cli open --browser=chrome <resolved-base-url>`; session flags must not precede `open`, and subsequent commands must remain in its default session without `-s=` or assumed named-session binding. Verify every executable sub-scenario specifies fixture/reset, UI reset, fresh snapshot before element refs, a successful `playwright-cli find ...` semantic assertion after `open`, and an evidence write point. `snapshot`, `goto`, `screenshot`, `request`/`console`, and ordinary interactions cannot independently authorize passed. Verify each case requires both `execution.md` and `case-result.json` under its own evidence directory. The JSON result must contain matching `caseId`, `status` (`passed`, `failed`, or `blocked`) and `evidencePaths`; blocked cases must name a non-empty `blockedReason` and cannot count as passed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.44.0-next.12",
3
+ "version": "0.44.0-next.13",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -79,19 +79,23 @@
79
79
  "@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
80
80
  "@earendil-works/pi-ai": "0.84.4",
81
81
  "@earendil-works/pi-coding-agent": "0.84.4",
82
+ "@mozilla/readability": "^0.6.0",
83
+ "@playwright/cli": "0.1.20",
82
84
  "@xterm/addon-fit": "^0.11.0",
83
85
  "@xterm/xterm": "^6.0.0",
84
86
  "commander": "^12.1.0",
85
87
  "katex": "^0.16.47",
88
+ "linkedom": "^0.18.13",
86
89
  "mermaid": "^11.16.1",
87
90
  "mysql2": "^3.24.4",
88
91
  "node-pty": "^1.2.0-beta.15",
89
92
  "pg": "^8.23.0",
90
- "playwright-core": "^1.63.0",
93
+ "playwright-core": "1.64.0-alpha-2026-09-14",
91
94
  "rehype-highlight": "^7.0.2",
92
95
  "rehype-katex": "^7.0.1",
93
96
  "remark-math": "^6.0.0",
94
97
  "semver": "^7.8.5",
98
+ "turndown": "^7.2.4",
95
99
  "typebox": "1.3.7",
96
100
  "yaml": "^2.9.0",
97
101
  "zod": "^3.25.76",
@@ -107,6 +111,7 @@
107
111
  "@types/react": "^19.1.8",
108
112
  "@types/react-dom": "^19.1.6",
109
113
  "@types/semver": "^7.7.1",
114
+ "@types/turndown": "^5.0.6",
110
115
  "@vitest/coverage-v8": "^4.1.11",
111
116
  "fast-check": "^4.10.0",
112
117
  "react": "^19.1.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: fe-test-ui-scout
3
- description: 在写 frontend-test Wave PRD/回归目录之前,对真实运行的被测页面做只读锚点侦察,产出并维护 {testRoot}/rag/ui-anchors.md 锚点台账(默认 testcase/frontend/rag/ui-anchors.md)。用 playwright-cli snapshot/find 逐字面验证命中数与唯一性,防止 PRD 验收标准引用不存在或不唯一的文案。触发词:frontend-test、锚点、台账、ui-anchors、侦察、写 PRD 前、snapshot/find 校准、Wave PRD。
3
+ description: 在写 frontend-test Wave PRD/回归目录之前,对真实运行的被测页面做只读锚点侦察,产出并维护 {testRoot}/rag/ui-anchors.md 锚点台账(默认 .harness/testcase/frontend/rag/ui-anchors.md)。用 playwright-cli snapshot/find 逐字面验证命中数与唯一性,防止 PRD 验收标准引用不存在或不唯一的文案。触发词:frontend-test、锚点、台账、ui-anchors、侦察、写 PRD 前、snapshot/find 校准、Wave PRD。
4
4
  references:
5
5
  - path: references/ledger-schema.md
6
6
  required: true
@@ -13,7 +13,7 @@ references:
13
13
  ## 定位
14
14
 
15
15
  写 Wave PRD / 校准回归目录 AC **之前**的前置侦察。产出锚点台账
16
- `{testRoot}/rag/ui-anchors.md`(默认 `testcase/frontend/rag/ui-anchors.md`):每个「页面 × 状态」下真实可见、
16
+ `{testRoot}/rag/ui-anchors.md`(默认 `.harness/testcase/frontend/rag/ui-anchors.md`):每个「页面 × 状态」下真实可见、
17
17
  `find` 可命中的字面清单。PRD 的每条 `find "..."` 断言必须能在台账找到对应行;
18
18
  台账没有的字面禁止写进验收标准。
19
19
 
@@ -23,7 +23,7 @@ references:
23
23
 
24
24
  ## 输入
25
25
 
26
- - 被测 baseUrl(来自 `{testRoot}/rag/context.md` 的 `environmentProbe=reachable` URL;默认 `testcase/frontend/rag/context.md`)
26
+ - 被测 baseUrl(来自 `{testRoot}/rag/context.md` 的 `environmentProbe=reachable` URL;默认 `.harness/testcase/frontend/rag/context.md`)
27
27
  - 目标 Wave 的 AC 清单(回归目录中本 Wave 范围的行)
28
28
  - 既有台账(增量更新,不整表重写)
29
29
 
@@ -56,7 +56,7 @@ references:
56
56
 
57
57
  ## 输出
58
58
 
59
- - `{testRoot}/rag/ui-anchors.md`(增量更新;默认 `testcase/frontend/rag/ui-anchors.md`)
59
+ - `{testRoot}/rag/ui-anchors.md`(增量更新;默认 `.harness/testcase/frontend/rag/ui-anchors.md`)
60
60
  - 侦察小结(对话内输出,不落盘;结论回写 PRD 草稿的锚点引用)
61
61
 
62
62
  ## References
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## 文件位置与命名
4
4
 
5
- - 路径:`{testRoot}/rag/ui-anchors.md`(默认 `testcase/frontend/rag/ui-anchors.md`)
5
+ - 路径:`{testRoot}/rag/ui-anchors.md`(默认 `.harness/testcase/frontend/rag/ui-anchors.md`)
6
6
  - 编码:UTF-8,LF;表格用 GitHub Flavored Markdown。
7
7
  - 台账是**增量账本**:修订不删除历史行;失效行改状态列并注明原因。
8
8
 
@@ -55,7 +55,7 @@ request
55
55
 
56
56
  ## 推荐执行流程
57
57
 
58
- 使用 `{testRoot}/rag/context.md`(默认 `testcase/frontend/rag/context.md`)中已由 environment shell 标记为 `reachable` 的非生产 `baseUrl` 和默认浏览器 session;不得创建 named session。交互前先获取 snapshot,并只使用 snapshot 中可见的 ref 或已知安全 locator。截图写入当前 case 的 `{evidenceDir}/<caseId>/`,canonical 文件名仍是 `final.png`。
58
+ 使用 `{testRoot}/rag/context.md`(默认 `.harness/testcase/frontend/rag/context.md`)中已由 environment shell 标记为 `reachable` 的非生产 `baseUrl` 和默认浏览器 session;不得创建 named session。交互前先获取 snapshot,并只使用 snapshot 中可见的 ref 或已知安全 locator。截图写入当前 case 的 `{evidenceDir}/<caseId>/`,canonical 文件名仍是 `final.png`。
59
59
 
60
60
  ```text
61
61
  playwright-cli open --browser=chrome http://localhost:5173
@@ -13,7 +13,7 @@ description: 根据 FE-test RAG 知识包生成可由受限 playwright_cli runti
13
13
 
14
14
  ## 输入与边界
15
15
 
16
- 默认产物根是 `testcase/frontend/`。若任务配置了 `frontendTest.testRoot`,把下列路径中的 `testcase/frontend/` 整段替换为该根(不要只替换 `testcase/`)。
16
+ 默认产物根是 `.harness/testcase/frontend/`。若任务配置了 `frontendTest.testRoot`,把下列路径中的 `.harness/testcase/frontend/` 整段替换为该根(不要只替换 `.harness/testcase/`)。
17
17
 
18
18
  - 只读取 `{testRoot}/rag/context.md`、`coverage-map.md` 与已有 `{testRoot}/cases/`。
19
19
  - 若存在 `{testRoot}/rag/ui-anchors.md` 锚点台账,必须一并读取并作为 UI 断言的唯一事实源;台账缺失时按 RAG 知识包生成,但不得引用台账外的具体控件字面(缺失信息标 `blocked`)。
@@ -40,8 +40,8 @@ description: 根据 FE-test RAG 知识包生成可由受限 playwright_cli runti
40
40
  (例:`FE-LOGIN-001-core`)。禁止把验收标准写成 caseId。
41
41
  - `acIds` = **验收标准 ID 列表**,形态 `AC-FE-*` / `AC-*`
42
42
  (例:`["AC-FE-001"]`)。禁止把用例 ID 放进 acIds。
43
- - `casePath` 必须等于 `{casesDir}/<caseId>.md`(默认 `testcase/frontend/cases/<caseId>.md`);
44
- `evidenceDir` 必须等于 `{evidenceDir}/<caseId>/`(默认 `testcase/frontend/evidence/<caseId>/`)。
43
+ - `casePath` 必须等于 `{casesDir}/<caseId>.md`(默认 `.harness/testcase/frontend/cases/<caseId>.md`);
44
+ `evidenceDir` 必须等于 `{evidenceDir}/<caseId>/`(默认 `.harness/testcase/frontend/evidence/<caseId>/`)。
45
45
  - `manifest` 使用 `schemaVersion: 1`,每项只含 `caseId`、`casePath`、`dimension`、`acIds`、
46
46
  `evidenceDir`。所有 ID、路径和 evidenceDir 必须唯一,并位于 `{testRoot}/` 内。
47
47
  - `index.md` 按功能点列出 case、维度、AC、数据依赖、API 映射和预期执行状态。
@@ -75,7 +75,7 @@ description: 根据 FE-test RAG 知识包生成可由受限 playwright_cli runti
75
75
  7. 明确的 UI/API 预期与数据清理结果;无法满足的环境或数据依赖必须写为 `blocked`。
76
76
 
77
77
  所有文件型输出均由 controller 绑定到执行节点提供的
78
- `{evidenceDir}/<case-id>/` 工作目录(默认 `testcase/frontend/evidence/<case-id>/`)。截图一律使用 canonical 语法
78
+ `{evidenceDir}/<case-id>/` 工作目录(默认 `.harness/testcase/frontend/evidence/<case-id>/`)。截图一律使用 canonical 语法
79
79
  `playwright-cli screenshot --filename final.png`;如确有从最新 snapshot 解析出的真实元素 ref,写为
80
80
  `playwright-cli screenshot e5 --filename final.png`。`pdf` 必须写为
81
81
  `playwright-cli pdf --filename final.pdf`。`snapshot` 无 filename 时仅返回响应;需要文件时使用
@@ -1 +0,0 @@
1
- import{ag as o,ah as n}from"./mermaid.core-4P9yPC9c.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-C3uE-yc2.js";import{_ as i}from"./mermaid.core-4P9yPC9c.js";import"./chunk-5VM5RSS4-BNAuTOLE.js";import"./chunk-XXDRQBXY-CTQDmJcp.js";import"./chunk-KBJHAD2P-D_AtEYQL.js";import"./chunk-2GRJ4B5K-B9fh0IkF.js";import"./index-CTMZsDmh.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-C3uE-yc2.js";import{_ as i}from"./mermaid.core-4P9yPC9c.js";import"./chunk-5VM5RSS4-BNAuTOLE.js";import"./chunk-XXDRQBXY-CTQDmJcp.js";import"./chunk-KBJHAD2P-D_AtEYQL.js";import"./chunk-2GRJ4B5K-B9fh0IkF.js";import"./index-CTMZsDmh.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};