@tea-agent/loop-agent 0.43.0-next.16 → 0.43.0-next.18

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 (154) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/dist/application/dag/args.js +8 -0
  3. package/dist/build-stamp.json +3 -3
  4. package/dist/cli/command-definitions.js +2 -0
  5. package/dist/cli/program.js +3 -1
  6. package/dist/cli/update/init-surface-notifier.js +2 -0
  7. package/dist/cli/update/policy.js +2 -0
  8. package/dist/commands/cursor-prompt.js +2 -0
  9. package/dist/commands/dag-approve.js +2 -0
  10. package/dist/commands/dag-final-verification.js +2 -0
  11. package/dist/commands/dag-init-hybrid.js +2 -0
  12. package/dist/commands/dag-reconcile-tasks.js +2 -0
  13. package/dist/commands/dag-reject.js +2 -0
  14. package/dist/commands/dag-report.js +2 -0
  15. package/dist/commands/dag-rerun.js +2 -0
  16. package/dist/commands/dag-resume.js +2 -0
  17. package/dist/commands/dag-workflow-compile.js +2 -0
  18. package/dist/commands/dag-workflow-plan.js +2 -0
  19. package/dist/commands/dag-workflow-validate.js +2 -0
  20. package/dist/commands/delegate.js +2 -0
  21. package/dist/commands/examples.js +2 -0
  22. package/dist/commands/import-prd.js +2 -0
  23. package/dist/commands/init-model-catalog.js +2 -0
  24. package/dist/commands/init.js +6 -4
  25. package/dist/commands/instructions.js +2 -0
  26. package/dist/commands/knowledge.js +2 -0
  27. package/dist/commands/loop-benchmark.js +2 -0
  28. package/dist/commands/pi-prompt.js +2 -0
  29. package/dist/commands/pi-reuse-benchmark.js +2 -0
  30. package/dist/commands/promote-run.js +2 -0
  31. package/dist/commands/stats.js +1 -1
  32. package/dist/commands/study-init.js +2 -0
  33. package/dist/commands/task-advance.js +2 -0
  34. package/dist/commands/task-source-prepare.js +2 -0
  35. package/dist/commands/worktree-create.js +2 -0
  36. package/dist/commands/worktree-remove.js +2 -0
  37. package/dist/executors/dag-pi-executor.js +25 -6
  38. package/dist/executors/shell-verification.js +3 -0
  39. package/dist/governance/exec-plans.js +6 -3
  40. package/dist/infrastructure/console/app-data.js +6 -0
  41. package/dist/shared/artifacts-core.js +2 -0
  42. package/dist/shared/git-progress.js +2 -0
  43. package/dist/shared/one-shot-prompt-args.js +2 -0
  44. package/dist/shared/package-metadata.js +6 -4
  45. package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
  46. package/dist/shared/reference-context.js +2 -0
  47. package/dist/task/contract/recover.js +6 -0
  48. package/dist/task/source-prepare/artifact-meta.js +9 -2
  49. package/dist/task/source-prepare/fragment-inventory.js +4 -1
  50. package/dist/task/source-prepare/parse-intent.js +36 -11
  51. package/dist/task/task-demand-routing.js +5 -2
  52. package/dist/worker/console/chat/browser-automation.js +468 -308
  53. package/dist/worker/console/chat/browser-routes.js +175 -57
  54. package/dist/worker/console/chat/explore-tools.js +5 -2
  55. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +115 -20
  56. package/dist/worker/console/chat/pi-runtime.js +9 -1
  57. package/dist/worker/console/chat/routes.js +1 -1
  58. package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
  59. package/dist/worker/console/chat/session-mode.js +1 -1
  60. package/dist/worker/console/chat/tools.js +7 -1
  61. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4NXyedy.js → abnfDiagram-N423BO3Z-B_UDknhR.js} +1 -1
  62. package/dist/worker/console/static/assets/{arc-NZ3qXvBI.js → arc-D6hU0drN.js} +1 -1
  63. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-COZSRvml.js → architectureDiagram-T3A2C74G-DmVikdRK.js} +1 -1
  64. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Ck0Gxi9C.js → blockDiagram-VBNYF7ZC-DydABCRg.js} +1 -1
  65. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BX5HQ4Ox.js → c4Diagram-5PPSVZJV-DrXKC2Jl.js} +1 -1
  66. package/dist/worker/console/static/assets/channel-Drecd94a.js +1 -0
  67. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CoviemSL.js → chunk-2GRJ4B5K-D2-qFxr7.js} +1 -1
  68. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DbOdOkbZ.js → chunk-2Q5K7J3B-ChfeF41P.js} +1 -1
  69. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BsG2pmdQ.js → chunk-5RXB4S5H-Drwrz55x.js} +1 -1
  70. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DGdvrNm8.js → chunk-5VM5RSS4-CAQGErL7.js} +1 -1
  71. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BAy7Yd6y.js → chunk-6Q2QTUOP-DHO38w5U.js} +1 -1
  72. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D9UA7hUb.js → chunk-GF5L2VYU-EYIN0EOI.js} +1 -1
  73. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-DPz7SZ8V.js → chunk-JWPE2WC7-CrFLKqkT.js} +1 -1
  74. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BmuEOIh7.js → chunk-KBJHAD2P-DMchffoo.js} +1 -1
  75. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CIhBWnd8.js → chunk-RYQCIY6F-DaSvtKQa.js} +1 -1
  76. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CScR6mDD.js → chunk-XXDRQBXY-DcW8W9Qj.js} +1 -1
  77. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-8Udu0t8-.js +1 -0
  78. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-8Udu0t8-.js +1 -0
  79. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BjpfWaUr.js → cose-bilkent-JH36ORCC-BUirrMEi.js} +1 -1
  80. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BFQohJgT.js → cynefin-VYW2F7L2-BXzO8iXR.js} +1 -1
  81. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-D3gzRJnS.js → cynefinDiagram-MW4NZA55-DAtgaxIn.js} +1 -1
  82. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-5eojkhoA.js → dagre-VZM6K2ZE-C1re9Noh.js} +1 -1
  83. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CpD8LWu_.js → diagram-7IWD3JNH-N8Kj08J9.js} +1 -1
  84. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B8_4qJ2a.js → diagram-B4RE2ZJO-D6BpSLs3.js} +1 -1
  85. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-HOsXf0eu.js → diagram-LBJQPF4R-C2Vlgnl4.js} +1 -1
  86. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BqwRwiWP.js → diagram-Q27KOJAE-CMbqtVLS.js} +1 -1
  87. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BRVCNZe1.js → diagram-UB23O5K3-A770Eb-0.js} +1 -1
  88. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Cvb1TgGh.js → ebnfDiagram-BXEA7PRR-LV2w_2pT.js} +1 -1
  89. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DS0O0qG9.js → erDiagram-JOGREHBK-bwqf56ah.js} +1 -1
  90. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BHIRvRr3.js → flowDiagram-UKHOOZJN-BnVtHhZh.js} +1 -1
  91. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DcCJ1JWx.js → ganttDiagram-PKOTCBZU-BGVToEqc.js} +1 -1
  92. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-B9ia5ony.js → gitGraphDiagram-DS77QQ5N-DL2l7Vne.js} +1 -1
  93. package/dist/worker/console/static/assets/{index-wXlQohNs.js → index-B_V4wvXs.js} +44 -44
  94. package/dist/worker/console/static/assets/{index-B9goN3S5.css → index-DcudonhZ.css} +1 -1
  95. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-3ogpgegn.js → infoDiagram-6WML65LV-BWIpubOx.js} +1 -1
  96. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-4tgpQ5SL.js → ishikawaDiagram-WSZJBQD7-DjYBD8vv.js} +1 -1
  97. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DNfgHqFx.js → journeyDiagram-NVQOT4AX-C0_mBaHb.js} +1 -1
  98. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Dz7ngC8z.js → kanban-definition-27J2QSJJ-Cy71zbX6.js} +1 -1
  99. package/dist/worker/console/static/assets/{linear-DI7Jv62E.js → linear-Dt3_w3Vn.js} +1 -1
  100. package/dist/worker/console/static/assets/{mermaid.core-CQA4Nzmo.js → mermaid.core-DnNOlfEP.js} +5 -5
  101. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CtsMc8Mf.js → mindmap-definition-FAOFIHXS-DAbTspwq.js} +1 -1
  102. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-ByppE9yH.js → pegDiagram-VL7TDLO6-NNiM141p.js} +1 -1
  103. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B5PtgFgt.js → pieDiagram-7S7Q4E2Y-CN80Z1Do.js} +1 -1
  104. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Cq4p0k2K.js → quadrantDiagram-CIZ2JOQS-Bxyfh0JU.js} +1 -1
  105. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DjfkyljN.js → railroadDiagram-AXF67PYL-BlWnC79M.js} +1 -1
  106. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DzynNRSl.js → requirementDiagram-LRYGKXZP-BrEu4P_e.js} +1 -1
  107. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cj7TCpTJ.js → sankeyDiagram-W5VNT64P-Bt70igBr.js} +1 -1
  108. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-C73C6ykA.js → sequenceDiagram-SI44F4Z6-C8DQR-r9.js} +1 -1
  109. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-BiNLgN2x.js → sizeCapture-X5ZJPWSS-DEMinJAT.js} +1 -1
  110. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-UwvjS64-.js → stateDiagram-OKZ733FA-DDdDBzQc.js} +1 -1
  111. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CyCiS0Lt.js +1 -0
  112. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CC7DH98r.js → swimlanes-SLNWSIFB-G2wcBs3T.js} +2 -2
  113. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-U0lhi6N0.js +8 -0
  114. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-LSBXTR70.js → timeline-definition-Z64GVDOM-Dzn4g2gJ.js} +1 -1
  115. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BAuxWwGP.js → vennDiagram-T6HMQDX7-5v2rP9oO.js} +1 -1
  116. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y--E5_gjZx.js → wardleyDiagram-T6FBY63Y-B4EOx7ew.js} +1 -1
  117. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-dJWNmyzF.js → xychartDiagram-ELKLHX3M-CQ1v8eYP.js} +1 -1
  118. package/dist/worker/console/static/index.html +2 -2
  119. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
  120. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
  121. package/dist/worker/console/static-src/prd-file-import.js +3 -1
  122. package/dist/worker/console/workspace-context.js +6 -1
  123. package/dist/worker/delivery/git-transaction.js +2 -0
  124. package/dist/worker/feature/fullstack-validate.js +2 -0
  125. package/dist/worker/loop-agent/loop-agent-client.js +8 -2
  126. package/dist/worker/materialize/harness-task-materializer.js +4 -1
  127. package/dist/worker/metrics/projector.js +1 -1
  128. package/dist/worker/observability/event-store.js +4 -1
  129. package/dist/worker/observability/read-model.js +4 -1
  130. package/dist/worker/observe/node-transparency.js +23 -1
  131. package/dist/worker/observe/routes.js +4 -0
  132. package/dist/worker/outcomes/declared-artifacts.js +2 -0
  133. package/dist/worker/preflight.js +3 -0
  134. package/dist/worker/task-spec/validate.js +4 -1
  135. package/dist/workflows/dag/decision-envelope.js +2 -0
  136. package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
  137. package/dist/workflows/dag/frontend-verification-trace.js +14 -10
  138. package/dist/workflows/dag/init-hybrid.js +105 -11
  139. package/dist/workflows/dag/interrupt-request.js +2 -0
  140. package/dist/workflows/dag/lifecycle.js +4 -0
  141. package/dist/workflows/dag/node-execution.js +2 -0
  142. package/dist/workflows/dag/reconcile-run.js +2 -0
  143. package/dist/workflows/dag/repair-artifact.js +3 -1
  144. package/dist/workflows/dag/report.js +2 -0
  145. package/dist/workflows/dag/rerun-task.js +2 -0
  146. package/dist/workflows/dag/types.js +21 -6
  147. package/dist/workflows/dag/validate.js +4 -0
  148. package/docs/governance/README.md +1 -0
  149. package/package.json +3 -1
  150. package/dist/worker/console/static/assets/channel-BxdTlb_5.js +0 -1
  151. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-_ByA1Nf8.js +0 -1
  152. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-_ByA1Nf8.js +0 -1
  153. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-nLgMZ0D3.js +0 -1
  154. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BcYqTady.js +0 -8
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ - 修复后端标准与前端研发工作流对同一 PRD 编号风格容忍度不一致:验收标准写作 `AC1`(不加连字符)时后端一次通过、前端却在 DAG 生成期硬失败,且只报 `Invalid` 加一个 JSON 指针;需求 id 现统一规范化为 `AC-1` 形式,非法形态的报错也自带期望格式。
6
+ - 前端实现不再对没有构建步骤的合法项目无意义失败:静态验证改为按序取项目**真实拥有**的检查(`build` → 任务声明的静态 `--verify` → 项目自身 `typecheck`/`check`),不再在 writer 已交付正确且测试全过之后才因缺少 `npm run build` 报失败;两者都没有时仍保持原有 `build` 命令,不以 no-op 伪造验证。lint 继续不进入本工作流。
7
+ - 修复契约重复提交同一需求导致前端 Plan 节点确定性失败(`coverage must partition complete execution groups exactly once`):覆盖率归属前对需求 id 做保序去重。
8
+ - 修复前端 Mock 策略提示词自相矛盾(同时要求“只允许 not-needed”与“有项目证据可选安全策略”)导致 Plan 误选策略、被下游门禁拒绝后整轮失败;硬约束生效时不再输出那句许可性指令。
9
+
10
+ - Operator Chat 新增对话驱动的真实浏览器自动化:右侧「浏览器」面板改为工作区级 iframe 视图并同步共享浏览器状态,登录态与下载隔离保存在仓库外应用数据;模型可操作同一浏览器进行地址导航、搜索、AI 结构化快照与元素操作、标签页、弹窗、滚动、等待和截图;面板轮询不再生成截图与结构化树,浏览保持流畅,自动化不读取或修改仓库文件,也不暴露任意页面脚本执行。
11
+ - 模型驱动的共享浏览器默认改为可见外部窗口,并保留右侧 iframe 预览;地址、搜索和元素操作不再默认生成大截图,搜索从首页逐字填写并提交真实表单,浏览器启动降低自动化指纹,侧边栏轻量同步外部标题与地址并可聚焦窗口,拒绝嵌入的页面也提供外部状态与聚焦入口,用户可在同一持久 profile 中完成站点安全验证。
12
+
5
13
  - 修复前端实现因测试名称没有 VT 编号而反复失败:按测试命令与文件关联执行结果,保留已有测试名称及测试失败阻断。
6
14
 
7
15
  - 整理设置弹窗布局:当前工作区优先、待处理文件紧凑分组、详情按需展开,全局程序信息收拢;窄屏导航改为横向排列。
@@ -10,7 +18,6 @@
10
18
 
11
19
  - 前端实现恢复已有测试维护与执行:优先任务声明,否则复用项目测试入口;没有测试时不强制补框架,避免只构建通过却遗漏旧单测回归。
12
20
 
13
- - Operator Chat 新增对话驱动的侧边栏浏览器自动化:模型可在工作流 / Pi 会话调用 `browser_navigate` / `browser_search` / `browser_inspect` / `browser_act`,把百度等页面打开到右侧浏览器面板,执行静态搜索、GET 表单填充提交、链接点击并返回结构化页面元素;命令通道按工作区隔离,自动化不读取或修改仓库文件,也不执行页面脚本。
14
21
 
15
22
  - 修复前端 Plan 无法提交实现步骤的问题:finalize_plan 支持按 AC 绑定实施动作,缺漏在节点内返回修正,避免空计划反复进入设计审查。
16
23
 
@@ -34,6 +34,8 @@ export function parseDagRunTaskArgs(args, defaultCwd) {
34
34
  let profileExplicit = false;
35
35
  for (let i = 0; i < args.length; i += 1) {
36
36
  const arg = args[i];
37
+ if (arg === undefined)
38
+ break;
37
39
  if (arg === "--output" || arg === "-o") {
38
40
  outputPath = args[++i];
39
41
  if (!outputPath) {
@@ -165,6 +167,8 @@ export function parseDagValidateArgs(args) {
165
167
  let spineTaskId;
166
168
  for (let i = 0; i < args.length; i += 1) {
167
169
  const arg = args[i];
170
+ if (arg === undefined)
171
+ break;
168
172
  if (arg === "--dag") {
169
173
  dagPath = args[++i];
170
174
  if (!dagPath) {
@@ -264,6 +268,8 @@ export function parseRunDagArgs(args, defaultCwd) {
264
268
  let workerAssociation;
265
269
  for (let i = 0; i < args.length; i += 1) {
266
270
  const arg = args[i];
271
+ if (arg === undefined)
272
+ break;
267
273
  if (arg === "--dag") {
268
274
  dagPath = args[++i];
269
275
  }
@@ -398,6 +404,8 @@ export function parseDagReportArgs(args) {
398
404
  let action;
399
405
  for (let i = 0; i < args.length; i += 1) {
400
406
  const arg = args[i];
407
+ if (arg === undefined)
408
+ break;
401
409
  if (arg === "--run-id") {
402
410
  runId = args[++i];
403
411
  continue;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.43.0-next.16",
4
- "gitSha": "237591777d28ec25d8ecb561db2bd0e64380e05c",
5
- "builtAt": "2026-09-11T07:27:48.993Z"
3
+ "version": "0.43.0-next.18",
4
+ "gitSha": "bc11e1415f26468377416cbd2142982dcc6e1dc8",
5
+ "builtAt": "2026-09-12T15:10:11.966Z"
6
6
  }
@@ -67,6 +67,8 @@ export function formatSubcommandUsageError(name, subcommands) {
67
67
  export function parseSummaryFlag(tokens) {
68
68
  for (let i = 0; i < tokens.length; i += 1) {
69
69
  const token = tokens[i];
70
+ if (token === undefined)
71
+ continue;
70
72
  if (token === "--summary") {
71
73
  return tokens[i + 1];
72
74
  }
@@ -96,7 +96,7 @@ function commandChain(command) {
96
96
  async function dispatchRegisteredCommand(commandObject, defaultRepoRoot, rawArgs) {
97
97
  const chain = commandChain(commandObject);
98
98
  const command = chain[0] ?? "";
99
- const [subcommand, ...rest] = chain.length <= 1 ? rawArgs : [chain[1], ...chain.slice(2), ...rawArgs];
99
+ const [subcommand, ...rest] = chain.length <= 1 ? rawArgs : [chain[1] ?? "", ...chain.slice(2), ...rawArgs];
100
100
  const options = collectGlobalOptions(commandObject);
101
101
  const quiet = (command === "doctor" &&
102
102
  [...rest, ...rawArgs].some((token) => token === "--json")) ||
@@ -397,6 +397,8 @@ function compactArgs(args) {
397
397
  function parsePlanSummaryFlag(tokens) {
398
398
  for (let i = 0; i < tokens.length; i += 1) {
399
399
  const token = tokens[i];
400
+ if (token === undefined)
401
+ continue;
400
402
  if (token === "--summary") {
401
403
  return tokens[i + 1];
402
404
  }
@@ -136,6 +136,8 @@ export function resolveInitSurfaceRepoRoot(argv, defaultRepoRoot) {
136
136
  let selected = defaultRepoRoot;
137
137
  for (let index = 0; index < argv.length; index += 1) {
138
138
  const arg = argv[index];
139
+ if (arg === undefined)
140
+ break;
139
141
  if (arg === "--repo-root") {
140
142
  const value = argv[index + 1];
141
143
  if (value && !value.startsWith("-"))
@@ -81,6 +81,8 @@ export function evaluateLatestVersion(input) {
81
81
  function firstCommand(argv) {
82
82
  for (let index = 0; index < argv.length; index += 1) {
83
83
  const arg = argv[index];
84
+ if (arg === undefined)
85
+ break;
84
86
  if (GLOBAL_VALUE_FLAGS.has(arg)) {
85
87
  index += 1;
86
88
  continue;
@@ -64,6 +64,8 @@ export function parseCursorPromptArgs(args) {
64
64
  continue;
65
65
  }
66
66
  const arg = args[i];
67
+ if (arg === undefined)
68
+ break;
67
69
  if (arg === "--stream") {
68
70
  stream = true;
69
71
  }
@@ -11,6 +11,8 @@ export function parseDagApproveArgs(args) {
11
11
  let notes;
12
12
  for (let i = 0; i < args.length; i += 1) {
13
13
  const arg = args[i];
14
+ if (arg === undefined)
15
+ break;
14
16
  if (arg === "--run-id") {
15
17
  runId = args[++i];
16
18
  continue;
@@ -10,6 +10,8 @@ export function parseDagFinalVerificationArgs(args) {
10
10
  let closeoutPath;
11
11
  for (let i = 0; i < args.length; i += 1) {
12
12
  const arg = args[i];
13
+ if (arg === undefined)
14
+ break;
13
15
  if (arg === '--output' || arg === '-o') {
14
16
  outputPath = requiredValue(args[++i], '--output');
15
17
  }
@@ -9,6 +9,8 @@ export function parseDagInitHybridArgs(args) {
9
9
  let outputPath;
10
10
  for (let i = 0; i < args.length; i += 1) {
11
11
  const arg = args[i];
12
+ if (arg === undefined)
13
+ break;
12
14
  if (arg === "--output" || arg === "-o") {
13
15
  outputPath = args[++i];
14
16
  if (!outputPath) {
@@ -20,6 +20,8 @@ export function parseDagReconcileTasksArgs(args) {
20
20
  let markdown = false;
21
21
  for (let i = 0; i < args.length; i += 1) {
22
22
  const arg = args[i];
23
+ if (arg === undefined)
24
+ break;
23
25
  if (arg === '--glob') {
24
26
  glob = requiredValue(args[++i], '--glob');
25
27
  }
@@ -8,6 +8,8 @@ export function parseDagRejectArgs(args) {
8
8
  let reason;
9
9
  for (let i = 0; i < args.length; i += 1) {
10
10
  const arg = args[i];
11
+ if (arg === undefined)
12
+ break;
11
13
  if (arg === "--run-id") {
12
14
  runId = args[++i];
13
15
  continue;
@@ -29,6 +29,8 @@ export function parseDagCloseoutDraftArgs(args) {
29
29
  let outputPath;
30
30
  for (let i = 0; i < args.length; i += 1) {
31
31
  const arg = args[i];
32
+ if (arg === undefined)
33
+ break;
32
34
  const requireValue = (flag) => {
33
35
  const value = args[++i];
34
36
  if (!value || value.startsWith("-")) {
@@ -22,6 +22,8 @@ export function parseDagRerunArgs(args) {
22
22
  const promptOverrideAppendSpecs = [];
23
23
  for (let index = 0; index < args.length; index += 1) {
24
24
  const arg = args[index];
25
+ if (arg === undefined)
26
+ break;
25
27
  if (arg === "--run-id")
26
28
  parentRunId = args[++index];
27
29
  else if (arg.startsWith("--run-id="))
@@ -6,6 +6,8 @@ export function parseDagResumeArgs(args) {
6
6
  let runId;
7
7
  for (let i = 0; i < args.length; i += 1) {
8
8
  const arg = args[i];
9
+ if (arg === undefined)
10
+ break;
9
11
  if (arg === "--run-id") {
10
12
  runId = args[++i];
11
13
  continue;
@@ -12,6 +12,8 @@ export function parseDagWorkflowCompileArgs(args) {
12
12
  let manifestPath;
13
13
  for (let i = 0; i < args.length; i += 1) {
14
14
  const arg = args[i];
15
+ if (arg === undefined)
16
+ break;
15
17
  if (arg === "--workflow") {
16
18
  workflowPath = args[++i];
17
19
  if (!workflowPath) {
@@ -21,6 +21,8 @@ export function parseDagWorkflowPlanArgs(args) {
21
21
  const changedFiles = [];
22
22
  for (let i = 0; i < rest.length; i += 1) {
23
23
  const arg = rest[i];
24
+ if (arg === undefined)
25
+ break;
24
26
  if (arg === "--profile") {
25
27
  const value = rest[++i];
26
28
  if (!value)
@@ -11,6 +11,8 @@ export function parseDagWorkflowValidateArgs(args) {
11
11
  let strictGovernance = false;
12
12
  for (let i = 0; i < args.length; i += 1) {
13
13
  const arg = args[i];
14
+ if (arg === undefined)
15
+ break;
14
16
  if (arg === "--workflow") {
15
17
  workflowPath = args[++i];
16
18
  if (!workflowPath) {
@@ -16,6 +16,8 @@ export function parseDelegateArgs(args) {
16
16
  let autoRun = false;
17
17
  for (let i = 0; i < args.length; i += 1) {
18
18
  const arg = args[i];
19
+ if (arg === undefined)
20
+ break;
19
21
  if (arg === "--base") {
20
22
  base = args[i + 1];
21
23
  if (!base)
@@ -57,6 +57,8 @@ function parseExamplesArgs(args) {
57
57
  let output;
58
58
  for (let i = 0; i < rest.length; i += 1) {
59
59
  const arg = rest[i];
60
+ if (arg === undefined)
61
+ break;
60
62
  if (arg === "--output" || arg === "-o") {
61
63
  output = rest[++i];
62
64
  continue;
@@ -5,6 +5,8 @@ export function parseImportPrdArgs(args) {
5
5
  const positional = [];
6
6
  for (let index = 0; index < args.length; index += 1) {
7
7
  const token = args[index];
8
+ if (token === undefined)
9
+ continue;
8
10
  if (token === "--file" || token === "-f") {
9
11
  options.file = args[index + 1];
10
12
  index += 1;
@@ -252,6 +252,8 @@ export function parseOpenCodeModelReferences(value, credentialProviders = new Se
252
252
  if (!match)
253
253
  continue;
254
254
  const [, provider, modelId] = match;
255
+ if (provider === undefined || modelId === undefined)
256
+ continue;
255
257
  const model = createCatalogEntry({
256
258
  source: "opencode",
257
259
  provider,
@@ -2842,7 +2842,7 @@ function modelMergeTaskFor(pathName, state, allPaths, recordedState) {
2842
2842
  taskId: `init-merge-${sha256Text(pathName).slice(0, 12)}`,
2843
2843
  path: pathName,
2844
2844
  reason: "target file exists but does not match the current loop-agent initialization surface",
2845
- sourcePath: state.sourcePath,
2845
+ sourcePath: state?.sourcePath,
2846
2846
  allowedPaths: [pathName],
2847
2847
  forbiddenPaths: [
2848
2848
  ...allPaths.filter((candidate) => candidate !== pathName),
@@ -2861,9 +2861,9 @@ function modelMergeTaskFor(pathName, state, allPaths, recordedState) {
2861
2861
  ],
2862
2862
  evidence: {
2863
2863
  baseSha256: recordedState?.files[pathName]?.currentSha256,
2864
- currentSha256: state.currentSha256,
2865
- desiredSha256: state.sourceSha256,
2866
- sourceAnchorSha256: state.sourceAnchorSha256,
2864
+ currentSha256: state?.currentSha256,
2865
+ desiredSha256: state?.sourceSha256,
2866
+ sourceAnchorSha256: state?.sourceAnchorSha256,
2867
2867
  },
2868
2868
  };
2869
2869
  }
@@ -3743,6 +3743,8 @@ function parseInitArgs(repoRoot, args) {
3743
3743
  let versionChoice;
3744
3744
  for (let i = 0; i < args.length; i += 1) {
3745
3745
  const arg = args[i];
3746
+ if (arg === undefined)
3747
+ break;
3746
3748
  if ((arg === "instructions" ||
3747
3749
  arg === "doctor" ||
3748
3750
  arg === "model-catalog" ||
@@ -18,6 +18,8 @@ export function parseInstructionsArgs(args) {
18
18
  let json = false;
19
19
  for (let i = 0; i < rest.length; i += 1) {
20
20
  const arg = rest[i];
21
+ if (arg === undefined)
22
+ break;
21
23
  if (arg === "--task") {
22
24
  taskId = rest[++i];
23
25
  if (!taskId)
@@ -68,6 +68,8 @@ export function parseKnowledgeArgs(args) {
68
68
  let markdown = false;
69
69
  for (let i = 0; i < rest.length; i += 1) {
70
70
  const arg = rest[i];
71
+ if (arg === undefined)
72
+ break;
71
73
  if (arg === "--json") {
72
74
  json = true;
73
75
  continue;
@@ -6,6 +6,8 @@ export function parseLoopBenchmarkArgs(args) {
6
6
  let outputPath;
7
7
  for (let i = 0; i < args.length; i += 1) {
8
8
  const arg = args[i];
9
+ if (arg === undefined)
10
+ break;
9
11
  if (arg === "--json") {
10
12
  json = true;
11
13
  continue;
@@ -66,6 +66,8 @@ export function parsePiPromptArgs(args) {
66
66
  continue;
67
67
  }
68
68
  const arg = args[i];
69
+ if (arg === undefined)
70
+ break;
69
71
  if (arg === "--provider") {
70
72
  provider = args[i + 1];
71
73
  if (!provider)
@@ -11,6 +11,8 @@ export function parsePiReuseBenchmarkArgs(args) {
11
11
  let markdown = false;
12
12
  for (let i = 0; i < args.length; i += 1) {
13
13
  const arg = args[i];
14
+ if (arg === undefined)
15
+ break;
14
16
  if (arg === "--json") {
15
17
  json = true;
16
18
  continue;
@@ -6,6 +6,8 @@ export function parsePromoteRunArgs(args) {
6
6
  let runId;
7
7
  for (let i = 0; i < rest.length; i += 1) {
8
8
  const arg = rest[i];
9
+ if (arg === undefined)
10
+ break;
9
11
  if (arg === '--run-id') {
10
12
  runId = rest[++i];
11
13
  if (!runId)
@@ -6,7 +6,7 @@ function percentile(values, p) {
6
6
  return null;
7
7
  const sorted = [...values].sort((a, b) => a - b);
8
8
  const index = Math.ceil((p / 100) * sorted.length) - 1;
9
- return sorted[Math.max(0, index)];
9
+ return sorted[Math.max(0, index)] ?? null;
10
10
  }
11
11
  function formatMs(ms) {
12
12
  if (ms >= 60_000)
@@ -16,6 +16,8 @@ function parseStudyInitArgs(args) {
16
16
  const positional = [];
17
17
  for (let i = 0; i < args.length; i += 1) {
18
18
  const arg = args[i];
19
+ if (arg === undefined)
20
+ break;
19
21
  if (arg === '--reference-repo') {
20
22
  const value = args[i + 1];
21
23
  if (!value)
@@ -84,6 +84,8 @@ export function parseTaskAdvanceArgs(args) {
84
84
  const positional = [];
85
85
  for (let i = 0; i < args.length; i += 1) {
86
86
  const token = args[i];
87
+ if (token === undefined)
88
+ continue;
87
89
  const next = () => {
88
90
  const value = args[i + 1];
89
91
  if (value === undefined || value.startsWith("-")) {
@@ -43,6 +43,8 @@ export function parseTaskSourcePrepareArgs(args) {
43
43
  const positional = [];
44
44
  for (let i = 0; i < args.length; i += 1) {
45
45
  const token = args[i];
46
+ if (token === undefined)
47
+ continue;
46
48
  const next = () => {
47
49
  const value = args[i + 1];
48
50
  if (value === undefined || value.startsWith("-")) {
@@ -7,6 +7,8 @@ export async function runWorktreeCreate(repoRoot, args) {
7
7
  const positionalArgs = [];
8
8
  for (let i = 0; i < args.length; i++) {
9
9
  const token = args[i];
10
+ if (token === undefined)
11
+ continue;
10
12
  if (token === '--base') {
11
13
  base = args[++i];
12
14
  if (!base)
@@ -6,6 +6,8 @@ export async function runWorktreeRemove(repoRoot, args) {
6
6
  const positionalArgs = [];
7
7
  for (let i = 0; i < args.length; i++) {
8
8
  const token = args[i];
9
+ if (token === undefined)
10
+ continue;
9
11
  if (token === '--force') {
10
12
  force = true;
11
13
  }
@@ -4560,6 +4560,27 @@ function buildFrontendPlanWorkload(input) {
4560
4560
  countFrontendPlanTargetSurfaces(input.basePrompt) === 1,
4561
4561
  };
4562
4562
  }
4563
+ /**
4564
+ * Requirement ids the plan coverage layout must own, in first-commit order.
4565
+ *
4566
+ * The contract ledger is append-only and `record_requirement` is incremental, so
4567
+ * the same id can legitimately be committed more than once. Deduplicating here is
4568
+ * load-bearing: `buildFrontendPlanWorkload` seeds one `unclassified` work group per
4569
+ * list entry without re-checking membership, so a repeated id produced two groups,
4570
+ * `buildWorkBatches` emitted the id twice, and the coverage-layout validator then
4571
+ * rejected the layout the runtime had derived itself (members 8 !== owners 7) as
4572
+ * FRONTEND_PLAN_LAYOUT_INVALID with failureCategory tool-policy - killing the run
4573
+ * at the plan node over a completely ordinary ledger.
4574
+ */
4575
+ export function collectFrontendPlanRequirementIds(contractFacts) {
4576
+ return [
4577
+ ...new Set(contractFacts
4578
+ .filter((record) => record.fact?.kind ===
4579
+ "requirement")
4580
+ .map((record) => record.fact?.id)
4581
+ .filter((id) => typeof id === "string")),
4582
+ ];
4583
+ }
4563
4584
  const frontendPlanCoverageLayoutSchema = z.object({
4564
4585
  schemaVersion: z.literal(1),
4565
4586
  bindingSha256: z.string(),
@@ -4901,6 +4922,8 @@ export async function runFrontendPlanSegmentedSessions(input) {
4901
4922
  let lastDurableCount = input.committedFactCount();
4902
4923
  while (index < queue.length) {
4903
4924
  const session = queue[index];
4925
+ if (!session)
4926
+ break;
4904
4927
  if (input.attempt > 1 && input.committedFacts && session.id === "ux-registry" &&
4905
4928
  collectFrontendPlanPhaseMissingFacts({ phase: "ux-registry", requirementIds: allRequirementIds, committedFacts: input.committedFacts() }).length === 0) {
4906
4929
  index += 1;
@@ -5112,7 +5135,7 @@ export async function runFrontendPlanSegmentedSessions(input) {
5112
5135
  if (recovery === "stop")
5113
5136
  return { ...result, ok: false };
5114
5137
  if ((recovery === "output" || (session.atomicRecovery && result.ok)) && input.committedFacts &&
5115
- !(missingPhaseFacts.length === 1 && missingPhaseFacts[0].kind === "plan-requirement") &&
5138
+ !(missingPhaseFacts.length === 1 && missingPhaseFacts[0]?.kind === "plan-requirement") &&
5116
5139
  (session.coverageOnly || isUxRegistrySession || isUxLocalSession || session.id.startsWith("global-mock-data"))) {
5117
5140
  if (missingPhaseFacts.length === 0) {
5118
5141
  // A complete validated slice does not need a successful prose turn.
@@ -6042,11 +6065,7 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep, wr
6042
6065
  // (SPLIT-*) that all have ids — feeding those into the coverage
6043
6066
  // batches made the model record non-frozen plan-requirement ids
6044
6067
  // that finalize's canonical-coverage gate then rejected (r-ext2).
6045
- planRequirementIds = contractFacts
6046
- .filter((record) => record.fact
6047
- ?.kind === "requirement")
6048
- .map((record) => record.fact?.id)
6049
- .filter((id) => typeof id === "string");
6068
+ planRequirementIds = collectFrontendPlanRequirementIds(contractFacts);
6050
6069
  for (const fact of resolveFrontendContractRequirements(contractFacts.map((record) => record.fact))) {
6051
6070
  if (fact.evidence.behavior === "required")
6052
6071
  behaviorRequiredRequirementIds.push(fact.id);
@@ -138,6 +138,9 @@ export function renderVerifyReport(results) {
138
138
  export async function executeCommand(command, defaultTimeoutMs = DEFAULT_VERIFY_TIMEOUT_MS) {
139
139
  return new Promise((resolve, reject) => {
140
140
  const [binary, ...args] = command.args;
141
+ if (binary === undefined) {
142
+ throw new Error("verify command requires a non-empty args array");
143
+ }
141
144
  const timeoutMs = command.timeoutMs ?? defaultTimeoutMs;
142
145
  const startedAt = Date.now();
143
146
  const child = spawn(binary, args, {
@@ -174,7 +174,7 @@ function localIndexReference(rawReference) {
174
174
  .trim()
175
175
  .replace(/^<|>$/g, "")
176
176
  .split(/[?#]/, 1)[0]
177
- .replaceAll("\\", "/");
177
+ ?.replaceAll("\\", "/") ?? "";
178
178
  if (!normalized.endsWith(".md") || normalized.includes("/"))
179
179
  return null;
180
180
  // Naming-convention placeholders (e.g. `YYYY-MM-DD-<topic>.md`) and other
@@ -332,6 +332,8 @@ function findInsertionPointForActiveEntry(lines) {
332
332
  // trailing section (blank-line separated context), or at the end.
333
333
  for (let i = 0; i < lines.length; i += 1) {
334
334
  const line = lines[i];
335
+ if (line === undefined)
336
+ break;
335
337
  if (/^[-*]\s+已归档/.test(line))
336
338
  return i;
337
339
  if (/^[-*]\s+`[^`]+\.md`/.test(line)) {
@@ -357,7 +359,8 @@ function removeIndexEntries(indexContent, file) {
357
359
  const lines = indexContent.split(/\r?\n/);
358
360
  const filtered = lines.filter((line) => {
359
361
  const linkMatch = line.match(/\[[^\]]*\]\(([^)]+)\)/);
360
- if (linkMatch && path.basename(linkMatch[1]) === file)
362
+ const linkTarget = linkMatch?.[1];
363
+ if (linkTarget !== undefined && path.basename(linkTarget) === file)
361
364
  return false;
362
365
  if (line.includes(`\`${file}\``))
363
366
  return false;
@@ -375,7 +378,7 @@ function collapseBlankRuns(lines) {
375
378
  result.push(line);
376
379
  prevBlank = isBlank;
377
380
  }
378
- while (result.length > 0 && result[result.length - 1].trim() === "") {
381
+ while (result.length > 0 && result[result.length - 1]?.trim() === "") {
379
382
  result.pop();
380
383
  }
381
384
  return result;
@@ -45,6 +45,9 @@ export function openConsoleAppData(options) {
45
45
  chats: path.join(repoNamespace, "chats"),
46
46
  chatSessions: path.join(repoNamespace, "chat-sessions"),
47
47
  chatEvents: path.join(repoNamespace, "chat-events"),
48
+ browserProfile: path.join(repoNamespace, "browser-profile"),
49
+ browserDownloads: path.join(repoNamespace, "browser-downloads"),
50
+ browserScreenshots: path.join(repoNamespace, "browser-screenshots"),
48
51
  resourcePreferences: path.join(repoNamespace, "resource-preferences.json"),
49
52
  };
50
53
  for (const dir of [
@@ -60,6 +63,9 @@ export function openConsoleAppData(options) {
60
63
  paths.chats,
61
64
  paths.chatSessions,
62
65
  paths.chatEvents,
66
+ paths.browserProfile,
67
+ paths.browserDownloads,
68
+ paths.browserScreenshots,
63
69
  path.dirname(paths.resourcePreferences),
64
70
  ]) {
65
71
  ensureSecureDir(dir);
@@ -81,6 +81,8 @@ function isUnchangedNewTaskTemplate(step, content) {
81
81
  }
82
82
  function firstRequiredSectionIsEmpty(step, content) {
83
83
  const [, firstSectionHeading] = REQUIRED_HEADINGS[step];
84
+ if (!firstSectionHeading)
85
+ return false;
84
86
  const headingIndex = content.indexOf(firstSectionHeading);
85
87
  if (headingIndex < 0) {
86
88
  return false;
@@ -112,6 +112,8 @@ function globToRegExp(pattern) {
112
112
  let regex = '^';
113
113
  for (let i = 0; i < normalized.length; i += 1) {
114
114
  const char = normalized[i];
115
+ if (char === undefined)
116
+ continue;
115
117
  const next = normalized[i + 1];
116
118
  if (char === '*' && next === '*') {
117
119
  const afterGlobstar = normalized[i + 2];
@@ -8,6 +8,8 @@ export function createOneShotPromptParseAccum() {
8
8
  }
9
9
  export function parseOneShotCommonFlag(args, index, accum) {
10
10
  const arg = args[index];
11
+ if (arg === undefined)
12
+ return { kind: "not-common" };
11
13
  if (arg === "--stdin") {
12
14
  accum.fromStdin = true;
13
15
  return { kind: "consumed", nextIndex: index };
@@ -134,8 +134,10 @@ export function computePackageFingerprint(packageRoot) {
134
134
  const bBuf = Buffer.from(b.relativePath, "utf-8");
135
135
  const minLen = Math.min(aBuf.length, bBuf.length);
136
136
  for (let i = 0; i < minLen; i++) {
137
- if (aBuf[i] !== bBuf[i])
138
- return aBuf[i] - bBuf[i];
137
+ const aByte = aBuf[i];
138
+ const bByte = bBuf[i];
139
+ if (aByte !== bByte)
140
+ return (aByte ?? 0) - (bByte ?? 0);
139
141
  }
140
142
  return aBuf.length - bBuf.length;
141
143
  });
@@ -183,8 +185,8 @@ export function resolveBinPaths(requested, resolvedAt, inputs) {
183
185
  // Search PATH
184
186
  const pathEnv = env.PATH ?? env.Path ?? env.path ?? "";
185
187
  const candidates = resolveFromPath(requested, pathEnv, osPlatform, env.PATHEXT ?? env.Pathext ?? env.pathext, cwd);
186
- if (candidates.length > 0) {
187
- const entry = candidates[0];
188
+ const entry = candidates[0];
189
+ if (entry !== undefined) {
188
190
  assertRegularFile(entry, requested);
189
191
  return { requested, entry, realEntry: realpathSync(entry), resolvedAt };
190
192
  }
@@ -268,7 +268,7 @@ export function sliceUtf8Range(text, offset, maxBytes) {
268
268
  }
269
269
  const buffer = Buffer.from(text, "utf8");
270
270
  let end = Math.min(totalBytes, start + limit);
271
- while (end > start && (buffer[end] & 0b1100_0000) === 0b1000_0000) {
271
+ while (end > start && ((buffer[end] ?? 0) & 0b1100_0000) === 0b1000_0000) {
272
272
  end -= 1;
273
273
  }
274
274
  const slice = buffer.subarray(start, end).toString("utf8");
@@ -186,6 +186,8 @@ function globToRegExp(glob) {
186
186
  let regex = '^';
187
187
  for (let i = 0; i < glob.length; i += 1) {
188
188
  const char = glob[i];
189
+ if (char === undefined)
190
+ continue;
189
191
  if (char === '*') {
190
192
  const next = glob[i + 1];
191
193
  if (next === '*') {