@tea-agent/loop-agent 0.39.0-beta.6 → 0.39.0-beta.7

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 (89) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/commands/client-recovery.js +3 -0
  4. package/dist/commands/task-advance.js +19 -0
  5. package/dist/executors/dag-pi-executor.js +44 -11
  6. package/dist/executors/pi-executor.js +7 -0
  7. package/dist/executors/shell-executor.js +1 -1
  8. package/dist/shared/dag-failure-category.js +12 -0
  9. package/dist/task/frontend-project-capability.js +19 -0
  10. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CfDSkLtp.js → abnfDiagram-N423BO3Z-bPer1waP.js} +1 -1
  11. package/dist/worker/console/static/assets/{arc-BlefM6I5.js → arc-BLdkwucW.js} +1 -1
  12. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C4tHfzHn.js → architectureDiagram-T3A2C74G-Bw4wo4I1.js} +1 -1
  13. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-G-G77Rh1.js → blockDiagram-VBNYF7ZC-DUUkc0gr.js} +1 -1
  14. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DWgxmY72.js → c4Diagram-5PPSVZJV-BC3O0nob.js} +1 -1
  15. package/dist/worker/console/static/assets/channel-AbFtVnFm.js +1 -0
  16. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CJQcfbCY.js → chunk-2GRJ4B5K-Dd4g2nti.js} +1 -1
  17. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-vUPviH9y.js → chunk-2Q5K7J3B-s2EDm7-n.js} +1 -1
  18. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DzRXSTeh.js → chunk-5RXB4S5H-GqtHM2yQ.js} +1 -1
  19. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CWfgqm07.js → chunk-5VM5RSS4-BzRFrN8j.js} +1 -1
  20. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BtTDauXA.js → chunk-6Q2QTUOP-Bw9nFjCJ.js} +1 -1
  21. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-Bc-NNt84.js → chunk-GF5L2VYU-B4n-03Qm.js} +1 -1
  22. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-B_f-emL4.js → chunk-JWPE2WC7-Dt75ZdBD.js} +1 -1
  23. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DV-jgJ66.js → chunk-KBJHAD2P-B_afMhHB.js} +1 -1
  24. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DMqzn4RZ.js → chunk-RYQCIY6F-Bd8Rqqg9.js} +1 -1
  25. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CVNtlAm4.js → chunk-XXDRQBXY-9boOMji4.js} +1 -1
  26. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-n1yf2Jcv.js +1 -0
  27. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-n1yf2Jcv.js +1 -0
  28. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BBZBhVTd.js → cose-bilkent-JH36ORCC-BtCycfCc.js} +1 -1
  29. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DbMU2PZ2.js → cynefin-VYW2F7L2-eTOts9L1.js} +1 -1
  30. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Dj0v8rjc.js → cynefinDiagram-MW4NZA55-Cibd2mjg.js} +1 -1
  31. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BW8R4WvJ.js → dagre-VZM6K2ZE-CDjDZtDV.js} +1 -1
  32. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-DEgWz3ld.js → diagram-7IWD3JNH-Btexn-JJ.js} +1 -1
  33. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BAA01rlR.js → diagram-B4RE2ZJO-Cyl8sdpM.js} +1 -1
  34. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-Cau6qqpW.js → diagram-LBJQPF4R-Ev-83E1t.js} +1 -1
  35. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-8HiPsLos.js → diagram-Q27KOJAE-41LqE0Mc.js} +1 -1
  36. package/dist/worker/console/static/assets/{diagram-UB23O5K3-CmkXuTYL.js → diagram-UB23O5K3-BC39T5R3.js} +1 -1
  37. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DCV_0seW.js → ebnfDiagram-BXEA7PRR-DzcNRuri.js} +1 -1
  38. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-gckfWESj.js → erDiagram-JOGREHBK-B5Frvvnz.js} +1 -1
  39. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-D2mT2BUu.js → flowDiagram-UKHOOZJN-BapxROIM.js} +1 -1
  40. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-B_HR5qEw.js → ganttDiagram-PKOTCBZU-Cd4d4wQ0.js} +1 -1
  41. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-BUw4fpSa.js → gitGraphDiagram-DS77QQ5N-CrL6buFW.js} +1 -1
  42. package/dist/worker/console/static/assets/{index-DPbsruV5.js → index-DBh_x_Ek.js} +46 -46
  43. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BSRAqEj0.js → infoDiagram-6WML65LV-BrSiNxyd.js} +1 -1
  44. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-CLxE8hUp.js → ishikawaDiagram-WSZJBQD7-gvlvY-n9.js} +1 -1
  45. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-juFzVXIj.js → journeyDiagram-NVQOT4AX-D-YaPzRQ.js} +1 -1
  46. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CwLHVhOU.js → kanban-definition-27J2QSJJ-BsmDv9E_.js} +1 -1
  47. package/dist/worker/console/static/assets/{linear-9LfUyPAs.js → linear-UWaoDN3h.js} +1 -1
  48. package/dist/worker/console/static/assets/{mermaid.core-TPPHfQbe.js → mermaid.core-BlvpGVG8.js} +5 -5
  49. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-Dn_Z9RxF.js → mindmap-definition-FAOFIHXS-CUCIP5CP.js} +1 -1
  50. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CiEMKTgm.js → pegDiagram-VL7TDLO6-CB1aQUAK.js} +1 -1
  51. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-JASaGxjZ.js → pieDiagram-7S7Q4E2Y-BwehHxhf.js} +1 -1
  52. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-ChmH0ply.js → quadrantDiagram-CIZ2JOQS-CFz30APB.js} +1 -1
  53. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CtyM-HGQ.js → railroadDiagram-AXF67PYL-BwNmw1i6.js} +1 -1
  54. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BN9y_Bvs.js → requirementDiagram-LRYGKXZP-jg-tPXlI.js} +1 -1
  55. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-IyS0GQ1-.js → sankeyDiagram-W5VNT64P-BlyReDKl.js} +1 -1
  56. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DjxGXurN.js → sequenceDiagram-SI44F4Z6-DBUzW1f3.js} +1 -1
  57. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Cr3Z0S8y.js → sizeCapture-X5ZJPWSS-BYcI2RAr.js} +1 -1
  58. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BjJFC6pW.js → stateDiagram-OKZ733FA-D7AiyJdo.js} +1 -1
  59. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BBSH5c8m.js +1 -0
  60. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DeMUJQiW.js → swimlanes-SLNWSIFB-BHGt7Kkv.js} +2 -2
  61. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D2F7-U4H.js +8 -0
  62. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Bc2Rv2Oo.js → timeline-definition-Z64GVDOM-OPjooWcX.js} +1 -1
  63. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-CDhRUeqG.js → vennDiagram-T6HMQDX7-ggsWDvrO.js} +1 -1
  64. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DaN_z3Xy.js → wardleyDiagram-T6FBY63Y-DjNe-BjZ.js} +1 -1
  65. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-C1vTLBDG.js → xychartDiagram-ELKLHX3M-Byp63Hei.js} +1 -1
  66. package/dist/worker/console/static/index.html +1 -1
  67. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +29 -1
  68. package/dist/workflows/dag/backend-test-markdown-workflow.js +176 -1
  69. package/dist/workflows/dag/backend-test-pytest-collection.js +87 -4
  70. package/dist/workflows/dag/backend-test-writer-completeness.js +10 -5
  71. package/dist/workflows/dag/frontend-design-policy.js +19 -0
  72. package/dist/workflows/dag/frontend-implementation-contract.js +74 -2
  73. package/dist/workflows/dag/frontend-review-findings.js +238 -0
  74. package/dist/workflows/dag/frontend-shape.js +5 -3
  75. package/dist/workflows/dag/init-hybrid.js +90 -1
  76. package/dist/workflows/dag/node-execution.js +7 -0
  77. package/dist/workflows/dag/report.js +37 -1
  78. package/dist/workflows/dag/rerun-feedback.js +101 -1
  79. package/dist/workflows/dag/retry-policy.js +21 -3
  80. package/dist/workflows/dag/runner.js +46 -1
  81. package/dist/workflows/dag/validate.js +9 -3
  82. package/docs/templates/agent-dag-report.schema.json +8 -2
  83. package/docs/templates/agent-dag.schema.json +1 -1
  84. package/package.json +1 -1
  85. package/dist/worker/console/static/assets/channel-DsdX3ZUX.js +0 -1
  86. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CrvCyJ-8.js +0 -1
  87. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CrvCyJ-8.js +0 -1
  88. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Bq44O9Nt.js +0 -1
  89. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BT4tWyW3.js +0 -8
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ - 前端 review `request_review_changes` 不再被静默当作成功(方向 A):`frontend-review-pi` 提交 typed `request_review_changes` 时,run 终态判定为「未通过」(`partial_failed` + `terminalReason=review-request-changes`,即使全部节点 FINISHED 也不显示成功),committed findings 自动渲染为 run-owned 下游任务 PRD 草稿 `contracts/frontend-review-findings-prd.md`(含 issueCategory/evidenceRefs/findings/restartPhase 指引),并生成 recovery trigger(issueCategory→failureOwner 映射,new-dag)。`deriveDagRerunFeedback` 新增 typed-fact 通道:无文本 verdict、无 convergence 的 frontend 场景也能把 committed `request_review_changes` findings 注入下一轮 `<rerun_feedback>`,问题不再丢失、下一轮从 restartPhase 定点修复而非重复流程。
6
+ - 前端 review findings PRD 草稿携带修复范围路由信号(方向 A 补充):`deriveFrontendReviewFixScope` 从 committed findings 确定性推导建议 shape(单文件无远程 API→micro、同目录集中多文件→small、跨目录/API 信号→standard)与建议 complexity、目标文件、建议 allowedPaths;PRD 标题改为「修复 review 发现(<shape>):<目标文件>」,正文新增「修复范围(供下一轮任务生成路由)」段(含 small 信号词,如「单文件局部修复」「无远程接口」),下一轮任务以该 PRD 生成 DAG 时,`resolveFrontendTaskShape` 能把小修复路由到 micro=7/small=10 节点拓扑,而非默认 11 节点 standard 全流程。
7
+ - 前端 shape 分类 API 否定词覆盖中文空格形式(冒烟暴露边界):`无 API/网络调用`、`无 API` 等表述不再被误判为远程 API 信号(原 `\b(...)\b` 对 CJK 开头无词边界),`resolveFrontendTaskShape` 与 `deriveFrontendReviewFixScope` 的 hasApiSignal 判定同步修正——带「无 API/无接口」声明的单文件小修复正确路由 micro/small,而非误升级 standard。
8
+ - 前端实现契约对 `decision=new` 的退化空 `specReference` 归一化兜底(冒烟暴露 plan invalid-output):模型偶发把 new 组件输出成 `specReference:{path:"",section:"",line:null}`(空对象而非 prompt 要求的 null),原校验直接判 `invalid-output` 触发完整 plan 重试;`frontendImplementationContractSchema` preprocess 新增 `normalizeNewComponentSpecReference`——new 选择携带空 path 的退化 specReference 时按 null 意图归一化为缺省(非空 path 的 `specified` 命中原样保留,真实 new+specReference 仍拒绝),一次格式滑动不再烧掉整个 plan attempt。
5
9
  - 深度合入 origin/main(source e68dfbe1):以 frontend-node typed-tools 拓扑为基底移植 main 硬化——canonical artifact 消费、fail-closed 无验证 marker、风险分级细化(DEPENDENCY_INSTALL_LANGUAGE)、`HARNESS_DAG_RERUN_PROMPT_OVERRIDE` prompt override、Pi SDK 运行时依赖 0.83.0 与 `engines node>=22.19.0`、next-release scripts 入包;废弃节点(verify-assess/reverify/repair-pi/plan-revision/final-design-review/lint-baseline shell)能力确认被当前流程覆盖后裁剪对应实现(repair-gate 机制、lint-baseline shell 类型),plan retry 文案对齐 committed ledger;affected 392 + M2-M9 303 测试全绿,fast 3909/3910、integration 397/398(各 1 个 fn 既有失败)。
6
10
 
7
11
  ### 重点更新
@@ -10,7 +14,10 @@
10
14
  - Operator Chat 输入框两项交互增强:① **↑/↓ 历史输入召回**——每次发送的文本进入输入历史(连续重复折叠、上限 100 条),光标在首行按 ↑ 逐条向旧回溯、按 ↓ 向新前进,越过最新一条时恢复回溯前**未发送的草稿**(草稿不会被历史浏览冲掉);多行文本中部的方向键仍是普通光标移动,IME 组词与 @文件/命令面板打开时不抢占。② **运行中排队下一轮指令**——当前回合运行中 Enter 不再被吞掉,消息作为「排队消息」绑定当前 Turn(服务端 `PUT deferred-turn` 从仅限 stopping 放开为 running/stopping,错误码 `TURN_NOT_STOPPING`→`TURN_NOT_ACTIVE`),当前回合结束(正常完成或停止)后自动发送;排队条提供「立即发送」(停止当前回复并立即发出)、「编辑」(移回输入框改写后再排)、「删除」三种操作,运行中输入框右侧提供排队发送按钮(与停止按钮并列);排队条单行展示(状态 + 省略号预览 + 操作按钮一行),输入框默认一行高(自动增高上限 280px 不变)。
11
15
  - 向导「运行」面板结构化与预期管理(A2/C9):新增实时运行进度块——节点完成计数与百分比进度条(含 progressbar 无障碍语义)、当前运行节点名称与已运行时长、失败节点与错误摘要,数据来自 `/api/dag-runs/:id` 每 5 秒轮询并在终态自动停止;`effectiveStatus=running-suspected-stall` 时显示橙色「疑似停滞」提示条(建议打开检视查看节点活动或到恢复页协作中止/诊断),把 20–40 分钟长跑的「日志噪音等待」变为有阶段感、可判断的等待。原始 SSE 事件日志默认折叠为「原始事件日志(最近 80 条)」,需要排查时再展开。
12
16
  - Console 前端三项体验优化(P0/P2):① Recovery 页 DAG 紧凑检视侧栏(InspectSplitPanel)从一次性快照改为实时刷新——运行中每 5 秒自动拉取节点/事件并新增「进行中/已结束」刷新状态行,到达终态(finished/failed/partial_failed/superseded/abandoned)自动停止轮询,刷新轮不清空既有内容避免闪烁;② Chat 任务旅程卡失败态新增按归一化 failureCategory 的可操作「建议」行(validation/executor/write-guard/timeout/auth/human-required/human-rejected/shell-command/static-error/decision-envelope/unknown 各映射到具体下一步:从失败节点重跑、修正契约后重新生成、跳「模型与认证」页等),不再只报「原因分类为 X」;③ Recovery 页 interrupt 资格轮询退避:选中 run 已终态(含 interrupted)时从 4 秒降到 30 秒,运行中保持 4 秒。
13
- - Console「设置」页新增「模型配置(models.json)」区块:以弹框形式增/改/删 Pi 的模型条目,支持 6 个定义字段(id、name、contextWindow、maxTokens、input、reasoning)。新增时 Provider 用下拉选择、其余字段自动补默认值;编辑时 Provider 只读且仅在原位置就地替换,只改表单内字段、不覆盖配置里页面未展示的其它字段(如 cost/compat);不读写 API key(凭据走 Pi CLI)。编辑已存在的模型不再被移到最后。
17
+ - Console 对话页 Models 面板的模型管理增强:以弹框形式增/改/删 Pi 的模型条目,支持 6 个定义字段(id、name、contextWindow、maxTokens、input、reasoning)。新增时 Provider 用下拉选择、其余字段自动补默认值;编辑时 Provider 只读且仅在原位置就地替换,只改表单内字段、不覆盖配置里页面未展示的其它字段(如 cost/compat);不读写 API key(凭据走 Pi CLI)。编辑已存在的模型不再被移到最后。(该能力仅在对话页提供,设置页不再重复入口。)
18
+ - 修复 `markdown-traceability` pipeline 未将冻结 `backendLayout` 传给 `validateBackendMarkdownTraceability`,自定义 layout 下不再回落默认 `testcase/md` ENOENT;新增回归用例以非默认 nested layout(`testRoot=testcase/elb/remote`、`markdownRel=md`)执行真实 shell pipeline,traceability 从自定义 Markdown 目录读取并 PASS,默认 layout 行为不变。(验证:`npm run typecheck`、`npx vitest run test/backend-test-markdown-workflow.test.ts test/backend-test-layout.test.ts`、`npm run build`、`git diff --check`。)
19
+ - backend-test 快速补强(backend-test-fast-failclosed-attribution):两处 fail-open 缺口已 fail-closed。① 当前轮次 Markdown 作用域严格依赖唯一有效 `## Module Index`——README 缺失 / 不可读 / `## Module Index` 重复(或缺标题)/ 唯一但空或不可解析任一状态,`markdownFiles` 与 coverage `markdownModuleFiles` 均返回空作用域而非回退全目录扫描,历史 `.md` 不再渗入 Case/coverage/partition facts,`resolveBackendTestManifestModules` 新增可区分 `manifestStatus`(valid/missing/unreadable/duplicate/empty-unparsable)与 `moduleIndexHeadingCount`,`validateBackendMarkdownCases` 与 `analyzeBackendTestCaseCoverage` 为非法状态各推 FAIL finding,默认与自定义 `backendTest` 布局一致。② collection 分类器不再凭 `__NNN_*` 裸 import 名称单独判 REPAIRABLE:inventory 构建时预计算每个 mapped script 的裸本地 helper import 证据(`scriptBareImports`),只有「存在同名 generated-local helper asset 且 mapped script 源码确实 import 该裸模块」才判 REPAIRABLE 并给精确 repairPaths;无 helper asset / mapped script 无对应 import / 无法精确归因一律 `BLOCKED`(`missing-generated-local-helper-without-evidence`。真第三方模块缺失保持 BLOCKED,不通过 PYTHONPATH/sys.path/conftest/ImportError fallback 绕行。(验证:`npm run typecheck`、backend-test 四聚焦 vitest、`npm run build`、`git diff --check`。)
20
+ - backend-test 后续修复(backend-test-fast-manifest-import-fix):Markdown 用例校验与 coverage 分析改为按 README `## Module Index` 清单限定本轮有效模块资产——未声明旧 `.md`(如 legacy.md)不再进入 Case/coverage/partition 统计,报告改为显式非静默 unmanifested advisory;“清单声明但文件缺失” fail-closed 明确失败,默认与自定义 `backendTest` 布局统一生效。generated pytest 裸本地 helper import(`from __551_manager_helpers import ...`)在 writer completeness gate 判为 recoverable 并给出精确 mapped 脚本 target path;collection 分类器对可归因到 mapped 资产的裸本地 helper `ModuleNotFoundError` 判 REPAIRABLE 并提供精确 repairPaths,真正第三方依赖缺失仍保持 BLOCKED。不放宽 self-contained、writeSet、forbiddenPaths、skip/xfail、断言与单次业务执行约束(验证:`npm run typecheck`、backend-test 聚焦 vitest、`npm run build`、`git diff --check`)。
14
21
  - 前端风险分级细分 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` 拒绝信号,审计可溯。
15
22
  - 前端验证 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 无法走完绿灯链。
16
23
  - 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。
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.39.0-beta.6",
4
- "gitSha": "740f411873839c25833d8d41d0ee74d0285f7082",
5
- "builtAt": "2026-08-23T14:01:39.565Z"
3
+ "version": "0.39.0-beta.7",
4
+ "gitSha": "7f2b8f56e95923c3bde69fffa0575cfeae065c42",
5
+ "builtAt": "2026-08-24T02:16:38.537Z"
6
6
  }
@@ -1356,12 +1356,15 @@ export async function runClientRecovery(input) {
1356
1356
  }
1357
1357
  const plugin = await installProjectOpenCodePlugin({
1358
1358
  repoRoot: input.repoRoot,
1359
+ onlyIfMissing: true,
1359
1360
  });
1360
1361
  const overflowPlugin = await installProjectOpenCodeOverflowCompactPlugin({
1361
1362
  repoRoot: input.repoRoot,
1363
+ onlyIfMissing: true,
1362
1364
  });
1363
1365
  const piExtension = await installProjectPiContextOverflowExtension({
1364
1366
  repoRoot: input.repoRoot,
1367
+ onlyIfMissing: true,
1365
1368
  });
1366
1369
  const pi = await applyProjectPiSettingsMerge({ repoRoot: input.repoRoot });
1367
1370
  if (mode !== "user") {
@@ -355,6 +355,25 @@ export async function runTaskAdvance(repoRoot, args) {
355
355
  intervalMs: options.progressIntervalMs,
356
356
  });
357
357
  }
358
+ // Idempotent client-recovery surface install before any DAG run: the Pi
359
+ // context-overflow extension / OpenCode plugins / project .pi settings
360
+ // are normally installed by `loop-agent init`, but an upgraded or
361
+ // non-init-created project may lack them. Installing here (missing-only)
362
+ // ensures the overflow compact+retry recovery path is always present,
363
+ // independent of how the project was created. Best-effort: a failure to
364
+ // install never blocks the run.
365
+ if (options.approveGate && !options.dryRun) {
366
+ try {
367
+ const { runClientRecovery } = await import("./client-recovery.js");
368
+ // mode "project" installs only project-owned surfaces
369
+ // (.pi/extensions + .opencode/plugins + .pi/settings.json),
370
+ // never the user home; installs are missing-only.
371
+ await runClientRecovery({ repoRoot, mode: "project" });
372
+ }
373
+ catch {
374
+ // best-effort; do not fail the run over a recovery-surface install
375
+ }
376
+ }
358
377
  const result = await advanceTaskLifecycle(toUseCaseInput(repoRoot, taskId, options, progress?.observer));
359
378
  const outcome = mapOutcome(result);
360
379
  const gateStop = result.lifecycleState === "awaiting-write-set-approval" &&
@@ -26,6 +26,15 @@ import { redactSecrets, truncateUtf8Preview } from "../shared/preview.js";
26
26
  * recoverable partial-write-set (incomplete-write-set) upgrade.
27
27
  */
28
28
  export const WRITER_THINKING_EXHAUSTED_CATEGORY = "writer-thinking-exhausted";
29
+ /**
30
+ * The writer session burned an excessive token budget (a read-edit-test loop
31
+ * that never converged) and still failed. Distinct from empty-output so the
32
+ * report shows the real cause and recovery recommends a fresh compacted run.
33
+ * Not auto-retried by default; operators may rerun after a model switch.
34
+ */
35
+ export const WRITER_BUDGET_EXHAUSTED_CATEGORY = "writer-budget-exhausted";
36
+ /** Token ceiling for a single writer node before it is judged budget-exhausted. */
37
+ export const WRITER_TOKEN_BUDGET = 2_000_000;
29
38
  function readWriterThinkingExhaustionEvidence(result) {
30
39
  const wider = result;
31
40
  return {
@@ -2681,6 +2690,12 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep, wr
2681
2690
  changeManifestChangedFiles !== undefined &&
2682
2691
  changeManifestChangedFiles.length === 0 &&
2683
2692
  writeToolCallCount === 0;
2693
+ // Budget-exhausted: the provider session consumed an extreme amount of
2694
+ // tokens (e.g. an unresolved read-edit-test loop) and still failed. Only
2695
+ // applies on a non-ok writer result; a successful write is never re-labeled.
2696
+ const writerBudgetExhausted = !mapped.ok &&
2697
+ typeof mapped.tokensUsed === "number" &&
2698
+ mapped.tokensUsed > WRITER_TOKEN_BUDGET;
2684
2699
  const targetCleanTransport = !mapped.ok &&
2685
2700
  isTargetTemplateTransientRetryNode(input.task) &&
2686
2701
  rawFailureCategory !== undefined &&
@@ -2724,17 +2739,35 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep, wr
2724
2739
  mapped.failureCategory === "invalid-output" ||
2725
2740
  mapped.failureCategory === WRITER_EMPTY_DIFF_RETRY_CATEGORY)
2726
2741
  ? INCOMPLETE_WRITE_SET_RETRY_CATEGORY
2727
- : // writer-thinking-exhausted: a length-stopped thinking-only attempt with
2728
- // zero write tool calls and zero attributed diff is terminal and
2729
- // non-retryable; recommend a model switch + fresh run. Only applies on
2730
- // the empty-output base category so provider/transport failures keep
2731
- // their original category, and only when the completeness gate did not
2732
- // upgrade to incomplete-write-set above.
2733
- writerThinkingExhausted
2734
- ? WRITER_THINKING_EXHAUSTED_CATEGORY
2735
- : writerCleanTimeout
2736
- ? WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY
2737
- : mapped.failureCategory,
2742
+ : // partial-success-with-context-overflow: the writer hit a context
2743
+ // overflow on its final provider call but had already persisted
2744
+ // real file changes (change-manifest non-empty). Classify it
2745
+ // distinctly so the report shows "code largely done, verification
2746
+ // incomplete" instead of a misleading empty-output / spec issue,
2747
+ // and recovery can rerun from verify/implement with a compacted
2748
+ // session rather than asking the operator for spec clarification.
2749
+ rawFailureCategory === "context-overflow" &&
2750
+ (changeManifestChangedFiles?.length ?? 0) > 0
2751
+ ? "partial-success-with-context-overflow"
2752
+ : // writer-thinking-exhausted: a length-stopped thinking-only attempt with
2753
+ // zero write tool calls and zero attributed diff is terminal and
2754
+ // non-retryable; recommend a model switch + fresh run. Only applies on
2755
+ // the empty-output base category so provider/transport failures keep
2756
+ // their original category, and only when the completeness gate did not
2757
+ // upgrade to incomplete-write-set above.
2758
+ writerThinkingExhausted
2759
+ ? WRITER_THINKING_EXHAUSTED_CATEGORY
2760
+ : writerCleanTimeout
2761
+ ? WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY
2762
+ : // writer-budget-exhausted: the provider session consumed an
2763
+ // excessive amount of tokens (a read-edit-test loop that never
2764
+ // converged) and still failed. Classify distinctly so the
2765
+ // report says the run burned its budget instead of a generic
2766
+ // empty-output, and recovery recommends a fresh compacted
2767
+ // run rather than spec-clarification.
2768
+ writerBudgetExhausted
2769
+ ? WRITER_BUDGET_EXHAUSTED_CATEGORY
2770
+ : mapped.failureCategory,
2738
2771
  durationMs: mapped.durationMs || Date.now() - started,
2739
2772
  };
2740
2773
  }
@@ -1012,6 +1012,13 @@ export function classifyPiFailure(input) {
1012
1012
  if (input.exitCode === 0 && input.assistantText.trim())
1013
1013
  return "success";
1014
1014
  const combined = `${input.stderr}\n${input.stdout}`.toLowerCase();
1015
+ // Context overflow (400 request-too-large / context window exceeded).
1016
+ // Must be detected BEFORE the generic rate-limit/quota phrases: an overflow
1017
+ // error often contains "too many tokens" / "maximum context" which would
1018
+ // otherwise be misread as rate-limit or quota. Kept in sync with
1019
+ // CONTEXT_OVERFLOW_PHRASES in commands/client-recovery.ts.
1020
+ if (/请求上下文过大|context_length_exceeded|context overflow|context length overflow|too many tokens|maximum context|prompt is too long|request_too_large|context window/.test(combined))
1021
+ return "context-overflow";
1015
1022
  // Prefer explicit rate-limit / HTTP 429 before generic "limit" quota phrases.
1016
1023
  // Chinese gateways often say "请求频率已达到限制" without English "rate limit".
1017
1024
  if (/rate.?limit|too many requests|\b429\b|请求频率|频率.*限制|rpm|tpm/.test(combined))
@@ -1068,7 +1068,7 @@ async function executeBackendTestPipeline(input, meta) {
1068
1068
  else if (pipeline === "markdown-traceability") {
1069
1069
  let report;
1070
1070
  try {
1071
- report = await validateBackendMarkdownTraceability(input.cwd);
1071
+ report = await validateBackendMarkdownTraceability(input.cwd, backendLayout);
1072
1072
  }
1073
1073
  catch (error) {
1074
1074
  report = `# Backend Test Traceability\n\n## Status\n\nFAIL\n\n## Findings\n\n- Traceability validation could not complete: ${error instanceof Error ? error.message : String(error)}\n`;
@@ -47,10 +47,22 @@ const RAW_TO_NORMALIZED = {
47
47
  "verify-failure": "validation",
48
48
  "test-failure": "validation",
49
49
  "verification-plan-stale": "validation",
50
+ "read-burst": "validation",
51
+ // Writer persisted real file changes but the final provider call hit a
52
+ // context overflow; verification never ran. Distinct from empty-output so
53
+ // the report shows partial success instead of a spec issue.
54
+ "partial-success-with-context-overflow": "validation",
55
+ // Writer burned an excessive token budget (unconverged read-edit-test loop)
56
+ // and still failed; distinct from empty-output for accurate reporting.
57
+ "writer-budget-exhausted": "validation",
50
58
  network: "executor",
51
59
  quota: "executor",
52
60
  "rate-limit": "executor",
53
61
  unavailable: "executor",
62
+ // Context window overflow (400 request-too-large): the session needs
63
+ // compaction / fresh context before retrying — an executor-side
64
+ // environment condition, not a plan-quality defect.
65
+ "context-overflow": "executor",
54
66
  // Deterministic capability/policy refusal: missing verified launcher JS
55
67
  // entry, capability allowlist rejection, or missing bounded write tool
56
68
  // profile. These are environment/config defects the operator repairs
@@ -133,9 +133,28 @@ export async function listOpenspecDiscovery(repoRoot, options = {}) {
133
133
  .filter(Boolean);
134
134
  const collected = [];
135
135
  let excludedGovernanceCount = 0;
136
+ // Metadata / bookkeeping directories that are not normative design specs:
137
+ // changelogs, ADR/history archives, proposals under review, and scratch
138
+ // state. Reading them inflates the candidate list (and the plan prompt)
139
+ // with files no component selection should cite. A task that genuinely
140
+ // needs one can still reference it explicitly — the prewrite gate
141
+ // candidates come from this discovery, but explicit task-source citations
142
+ // flow through openspecMandatoryPaths independently.
143
+ const DEFAULT_EXCLUDED_SPEC_PREFIXES = [
144
+ "openspec/changes",
145
+ "openspec/project-specs/changes",
146
+ "openspec/project-specs/changelog",
147
+ "openspec/project-specs/history",
148
+ "openspec/project-specs/archive",
149
+ "openspec/project-specs/decisions",
150
+ "openspec/project-specs/proposals",
151
+ ];
136
152
  const isExcluded = (rel) => {
137
153
  if (isGovernanceSubtreePath(rel, governanceRoot))
138
154
  return true;
155
+ if (DEFAULT_EXCLUDED_SPEC_PREFIXES.some((prefix) => rel === prefix || rel.startsWith(prefix + "/"))) {
156
+ return true;
157
+ }
139
158
  return extraExcludedPrefixes.some((prefix) => rel === prefix || rel.startsWith(prefix + "/"));
140
159
  };
141
160
  for (const specDir of options.specRoots ?? [...OPENSPEC_SPEC_DIRS]) {
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-BtTDauXA.js";import{p as f}from"./chunk-JWPE2WC7-B_f-emL4.js";import{_ as n,l as o}from"./mermaid.core-TPPHfQbe.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DbMU2PZ2.js";import"./index-DPbsruV5.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-Bw9nFjCJ.js";import{p as f}from"./chunk-JWPE2WC7-Dt75ZdBD.js";import{_ as n,l as o}from"./mermaid.core-BlvpGVG8.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-eTOts9L1.js";import"./index-DBh_x_Ek.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-TPPHfQbe.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-BlvpGVG8.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};